Skip to content

Commit ead5703

Browse files
committed
Absorb element-modules/packages/element-web-module-api into monorepo
2 parents e30adf4 + ad2e6d3 commit ead5703

46 files changed

Lines changed: 3477 additions & 53 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/npm-publish.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ on:
1010
options:
1111
- playwright-common
1212
- shared-components
13+
- module-api
1314

1415
concurrency: release
1516
jobs:

.github/workflows/tests.yml

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ jobs:
100100
101101
complete:
102102
name: jest-tests
103-
needs: [jest_ew, vitest_sc]
103+
needs: [jest_ew, vitest]
104104
if: always()
105105
runs-on: ubuntu-24.04
106106
permissions:
@@ -120,8 +120,13 @@ jobs:
120120
sha: ${{ github.sha }}
121121
target_url: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}
122122

123-
vitest_sc:
124-
name: Vitest (Shared Components)
123+
vitest:
124+
name: Vitest
125+
strategy:
126+
matrix:
127+
package:
128+
- shared-components
129+
- module-api
125130
runs-on: ubuntu-24.04
126131
steps:
127132
- name: Checkout code
@@ -137,32 +142,32 @@ jobs:
137142
node-version: "lts/*"
138143
cache: "pnpm"
139144

140-
- name: Install Shared Component Deps
141-
working-directory: "packages/shared-components"
145+
- name: Install Deps
142146
run: "pnpm install"
143147

144148
- name: Cache storybook & vitest
145149
uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5
146150
with:
147151
path: |
148-
packages/shared-components/node_modules/.cache
149-
packages/shared-components/node_modules/.vite/vitest
152+
packages/${{ matrix.package }}/node_modules/.cache
153+
packages/${{ matrix.package }}/node_modules/.vite/vitest
150154
key: ${{ hashFiles('pnpm-lock.yaml') }}
151155

152156
- name: Setup playwright
153157
uses: ./.github/actions/setup-playwright
158+
if: matrix.package == 'shared-components'
154159
with:
155160
write-cache: ${{ github.event_name != 'merge_group' }}
156161

157162
- name: Run tests
158-
working-directory: "packages/shared-components"
163+
working-directory: "packages/${{ matrix.package }}"
159164
run: pnpm test:unit --coverage=$ENABLE_COVERAGE
160165

161166
- name: Upload Artifact
162167
if: env.ENABLE_COVERAGE == 'true'
163168
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7
164169
with:
165-
name: coverage-sharedcomponents
170+
name: coverage-${{ matrix.package }}
166171
path: |
167-
packages/shared-components/coverage
168-
!packages/shared-components/coverage/lcov-report
172+
packages/${{ matrix.package }}/coverage
173+
!packages/${{ matrix.package }}/coverage/lcov-report

apps/web/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838
},
3939
"dependencies": {
4040
"@babel/runtime": "^7.12.5",
41-
"@element-hq/element-web-module-api": "catalog:",
41+
"@element-hq/element-web-module-api": "workspace:*",
4242
"@element-hq/web-shared-components": "workspace:*",
4343
"@fontsource/fira-code": "^5",
4444
"@fontsource/inter": "catalog:",

knip.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ export default {
1414
],
1515
ignoreBinaries: ["awk"],
1616
},
17+
"packages/module-api": {},
1718
"apps/web": {
1819
entry: [
1920
"src/serviceworker/index.ts",

packages/module-api/.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
lib/
2+
temp/

packages/module-api/Dockerfile

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
ARG ELEMENT_VERSION=latest@sha256:a84f294ce46e4327ebacecb78bfc94cf6a45c7ffa5104a28f06b5ac69d0b2548
2+
3+
FROM --platform=$BUILDPLATFORM node:lts-alpine@sha256:01743339035a5c3c11a373cd7c83aeab6ed1457b55da6a69e014a95ac4e4700b AS builder
4+
5+
ARG BUILD_CONTEXT
6+
7+
RUN apk add --no-cache jq
8+
9+
WORKDIR /app
10+
COPY package.json yarn.lock ./
11+
# Copy the package.json files of all modules & packages to ensure the frozen workspace lockfile holds up
12+
RUN --mount=type=bind,target=/docker-context \
13+
cd /docker-context/; \
14+
find . -path ./node_modules -prune -o -name "package.json" -mindepth 0 -maxdepth 4 -exec cp --parents "{}" /app/ \;
15+
RUN yarn install --frozen-lockfile --ignore-scripts
16+
COPY tsconfig.json ./
17+
COPY ./$BUILD_CONTEXT ./$BUILD_CONTEXT
18+
RUN cd $BUILD_CONTEXT && yarn vite build
19+
RUN mkdir /modules
20+
RUN cp -r ./$BUILD_CONTEXT/lib/ /modules/$(jq -r '"\(.name)-v\(.version)"' ./$BUILD_CONTEXT/package.json)
21+
22+
FROM ghcr.io/element-hq/element-web:${ELEMENT_VERSION}
23+
24+
COPY --from=builder /modules /modules/

packages/module-api/README.md

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
# @element-hq/element-web-module-api
2+
3+
API surface for extending Element Web in a safe & predictable way.
4+
5+
This project is still in early development but aims to replace matrix-react-sdk-module-api and Element Web deprecated customisations.
6+
7+
## Using the API
8+
9+
Modules are loaded by Element Web at runtime via a dynamic ecmascript import, but can be bundled into a webapp for deployment convenience.
10+
11+
The module's default export MUST be a class which accepts a single argument, an instance of `ModuleApi`.
12+
This class must also bear a static property `moduleApiVersion` which is a semver range string
13+
and a `load` method which is called when the module is to be loaded.
14+
15+
```typescript
16+
import type { Module, Api, ModuleFactory } from "@element-hq/element-web-module-api";
17+
18+
class ExampleModule implements Module {
19+
public static readonly moduleApiVersion = "^0.1.0";
20+
21+
public constructor(private api: Api) {}
22+
23+
public async load(): Promise<void> {
24+
// Your extension code goes here
25+
}
26+
}
27+
28+
export default ExampleModule satisfies ModuleFactory;
29+
```
30+
31+
### Accessing application configuration
32+
33+
The `api` object passed to the module constructor provides access to the application configuration.
34+
You can extend the Config types using declaration merging, though please ensure that you do not trust the types you specify,
35+
and opt for runtime validation due to the dynamic nature of the configuration.
36+
37+
```typescript
38+
// ...
39+
declare module "@element-hq/element-web-module-api" {
40+
interface Config {
41+
"this.is.my.config.key": string;
42+
}
43+
}
44+
45+
class ExampleModule implements Module {
46+
// ...
47+
public async load(): Promise<void> {
48+
const configValue = this.api.config.get("this.is.my.config.key");
49+
// Your extension code goes here
50+
}
51+
}
52+
// ...
53+
```
54+
55+
## Releases
56+
57+
The API is versioned using semver, with the major version incremented for breaking changes.
58+
59+
## Copyright & License
60+
61+
Copyright (c) 2025 New Vector Ltd
62+
63+
This software is multi licensed by New Vector Ltd (Element). It can be used either:
64+
65+
(1) for free under the terms of the GNU Affero General Public License (as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version); OR
66+
67+
(2) under the terms of a paid-for Element Commercial License agreement between you and Element (the terms of which may vary depending on what you and Element have agreed to).
68+
Unless required by applicable law or agreed to in writing, software distributed under the Licenses is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the Licenses for the specific language governing permissions and limitations under the Licenses.

0 commit comments

Comments
 (0)