@tabbr/module-cli 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +34 -34
- package/README.md +193 -113
- package/bin/tabbr-module.js +40 -5
- package/package.json +34 -33
- package/src/auth.js +144 -144
- package/src/backend-build.js +74 -0
- package/src/build.js +121 -91
- package/src/config.js +75 -75
- package/src/fetch-types.js +49 -49
- package/src/local.js +62 -0
- package/src/publish.js +31 -29
package/LICENSE
CHANGED
|
@@ -1,34 +1,34 @@
|
|
|
1
|
-
Tabbr Module CLI License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2026 SystemWorks BV. All rights reserved.
|
|
4
|
-
|
|
5
|
-
1. Grant. Subject to the terms below, SystemWorks BV ("Licensor") grants you a
|
|
6
|
-
free, non-exclusive, non-transferable, revocable license to use, copy and
|
|
7
|
-
modify the Tabbr Module CLI (the "Software") solely to develop, test and
|
|
8
|
-
run modules that are deployed on and used with the Tabbr platform operated
|
|
9
|
-
by Licensor.
|
|
10
|
-
|
|
11
|
-
2. Restrictions. You may not:
|
|
12
|
-
a. use the Software, or any part or derivative of it, for any purpose other
|
|
13
|
-
than the one in section 1, including with any platform, product or
|
|
14
|
-
service other than Tabbr;
|
|
15
|
-
b. distribute, sublicense, sell or publish the Software or derivatives of it,
|
|
16
|
-
except as part of a module distributed solely for use on the Tabbr
|
|
17
|
-
platform;
|
|
18
|
-
c. remove or alter this license or any copyright notice.
|
|
19
|
-
|
|
20
|
-
3. Ownership. The Software is licensed, not sold. Licensor retains all rights,
|
|
21
|
-
title and interest in the Software. Modules you write remain yours, but this
|
|
22
|
-
license does not grant any right to the Tabbr platform itself, which is
|
|
23
|
-
governed by its own terms of use.
|
|
24
|
-
|
|
25
|
-
4. Termination. This license ends automatically if you breach it, or when your
|
|
26
|
-
access to the Tabbr platform ends. On termination you must stop using the
|
|
27
|
-
Software.
|
|
28
|
-
|
|
29
|
-
5. No warranty. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND.
|
|
30
|
-
TO THE EXTENT PERMITTED BY LAW, LICENSOR IS NOT LIABLE FOR ANY DAMAGES
|
|
31
|
-
ARISING FROM THE USE OF THE SOFTWARE.
|
|
32
|
-
|
|
33
|
-
6. Governing law. This license is governed by Belgian law. The courts of Ghent
|
|
34
|
-
(Gent), Belgium have exclusive jurisdiction.
|
|
1
|
+
Tabbr Module CLI License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 SystemWorks BV. All rights reserved.
|
|
4
|
+
|
|
5
|
+
1. Grant. Subject to the terms below, SystemWorks BV ("Licensor") grants you a
|
|
6
|
+
free, non-exclusive, non-transferable, revocable license to use, copy and
|
|
7
|
+
modify the Tabbr Module CLI (the "Software") solely to develop, test and
|
|
8
|
+
run modules that are deployed on and used with the Tabbr platform operated
|
|
9
|
+
by Licensor.
|
|
10
|
+
|
|
11
|
+
2. Restrictions. You may not:
|
|
12
|
+
a. use the Software, or any part or derivative of it, for any purpose other
|
|
13
|
+
than the one in section 1, including with any platform, product or
|
|
14
|
+
service other than Tabbr;
|
|
15
|
+
b. distribute, sublicense, sell or publish the Software or derivatives of it,
|
|
16
|
+
except as part of a module distributed solely for use on the Tabbr
|
|
17
|
+
platform;
|
|
18
|
+
c. remove or alter this license or any copyright notice.
|
|
19
|
+
|
|
20
|
+
3. Ownership. The Software is licensed, not sold. Licensor retains all rights,
|
|
21
|
+
title and interest in the Software. Modules you write remain yours, but this
|
|
22
|
+
license does not grant any right to the Tabbr platform itself, which is
|
|
23
|
+
governed by its own terms of use.
|
|
24
|
+
|
|
25
|
+
4. Termination. This license ends automatically if you breach it, or when your
|
|
26
|
+
access to the Tabbr platform ends. On termination you must stop using the
|
|
27
|
+
Software.
|
|
28
|
+
|
|
29
|
+
5. No warranty. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND.
|
|
30
|
+
TO THE EXTENT PERMITTED BY LAW, LICENSOR IS NOT LIABLE FOR ANY DAMAGES
|
|
31
|
+
ARISING FROM THE USE OF THE SOFTWARE.
|
|
32
|
+
|
|
33
|
+
6. Governing law. This license is governed by Belgian law. The courts of Ghent
|
|
34
|
+
(Gent), Belgium have exclusive jurisdiction.
|
package/README.md
CHANGED
|
@@ -1,113 +1,193 @@
|
|
|
1
|
-
# @tabbr/module-cli
|
|
2
|
-
|
|
3
|
-
Builds a Native Federation club-module workspace and publishes it to a tabbr club. Also fetches
|
|
4
|
-
a club's own generated TypeScript typings into your module workspace.
|
|
5
|
-
|
|
6
|
-
The quickest start is the starter project,
|
|
7
|
-
[systemworks-bv/tabbr-module-starter](https://github.com/systemworks-bv/tabbr-module-starter),
|
|
8
|
-
which has this CLI and npm scripts for it set up already.
|
|
9
|
-
|
|
10
|
-
```bash
|
|
11
|
-
npm install -D @tabbr/module-cli
|
|
12
|
-
```
|
|
13
|
-
|
|
14
|
-
## Configuration: tabbr.config.json
|
|
15
|
-
|
|
16
|
-
Every option can be passed on the command line, but normally lives in `tabbr.config.json` in the
|
|
17
|
-
workspace root (option names in camelCase; command-line options win). `init` writes it for you:
|
|
18
|
-
|
|
19
|
-
```bash
|
|
20
|
-
npx tabbr-module init # asks for the club code, module id and title
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
```json
|
|
24
|
-
{
|
|
25
|
-
"club": "ABC",
|
|
26
|
-
"apiHost": "https://api.tabbr.be",
|
|
27
|
-
"moduleId": "club.abc.my-module",
|
|
28
|
-
"title": "My module",
|
|
29
|
-
"exposedModule": "./Module",
|
|
30
|
-
"exportName": "Module"
|
|
31
|
-
}
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
```
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
1
|
+
# @tabbr/module-cli
|
|
2
|
+
|
|
3
|
+
Builds a Native Federation club-module workspace and publishes it to a tabbr club. Also fetches
|
|
4
|
+
a club's own generated TypeScript typings into your module workspace.
|
|
5
|
+
|
|
6
|
+
The quickest start is the starter project,
|
|
7
|
+
[systemworks-bv/tabbr-module-starter](https://github.com/systemworks-bv/tabbr-module-starter),
|
|
8
|
+
which has this CLI and npm scripts for it set up already.
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
npm install -D @tabbr/module-cli
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Configuration: tabbr.config.json
|
|
15
|
+
|
|
16
|
+
Every option can be passed on the command line, but normally lives in `tabbr.config.json` in the
|
|
17
|
+
workspace root (option names in camelCase; command-line options win). `init` writes it for you:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npx tabbr-module init # asks for the club code, module id and a fallback title
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
```json
|
|
24
|
+
{
|
|
25
|
+
"club": "ABC",
|
|
26
|
+
"apiHost": "https://api.tabbr.be",
|
|
27
|
+
"moduleId": "club.abc.my-module",
|
|
28
|
+
"title": "My module",
|
|
29
|
+
"exposedModule": "./Module",
|
|
30
|
+
"exportName": "Module"
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### The title and description of your module
|
|
35
|
+
|
|
36
|
+
The name Tabbr shows for your module (in the settings list and its page header) is translated like the one of its
|
|
37
|
+
own modules: put `module.title` and `module.description` in your translation bundles (nested under your module id,
|
|
38
|
+
e.g. `'module.title': 'My module'`) and list the bundles on your module class so the shell can read them:
|
|
39
|
+
|
|
40
|
+
```ts
|
|
41
|
+
export class Module extends SimpleModuleBase {
|
|
42
|
+
static readonly i18nBundles = I18N_BUNDLES; // the same map you give provideModuleI18n()
|
|
43
|
+
// ...
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
`title` in `tabbr.config.json` is then only the **fallback**: what is shown while there is no translation (a module
|
|
48
|
+
without bundles, a language it lacks). `description` falls back to the module id.
|
|
49
|
+
|
|
50
|
+
## Backend modules
|
|
51
|
+
|
|
52
|
+
A module can also have a **backend** part: TypeScript that runs server-side (not in the browser),
|
|
53
|
+
sandboxed, triggered on a cron schedule or on an entity's create/update - see
|
|
54
|
+
`BackendModuleRuntimeService` in `tabbr-api-server`. Add a `"backend"` block to
|
|
55
|
+
`tabbr.config.json`:
|
|
56
|
+
|
|
57
|
+
```json
|
|
58
|
+
{
|
|
59
|
+
"backend": {
|
|
60
|
+
"entry": "backend/src/index.ts",
|
|
61
|
+
"allowedHosts": ["admin.gliding.app"],
|
|
62
|
+
"localAllowedHosts": ["localhost"],
|
|
63
|
+
"secretFieldNames": ["apiKey"],
|
|
64
|
+
"triggers": [
|
|
65
|
+
{ "type": "CRON", "name": "pollFlights", "cronExpression": "*/5 * * * *", "handler": "pollFlights" },
|
|
66
|
+
{ "type": "ENTITY_HOOK", "name": "onFlightSaved", "entity": "flight", "event": "onUpdate", "handler": "onFlightSaved" }
|
|
67
|
+
]
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
`entry` (default `backend/src/index.ts`) is a normal TypeScript file exporting plain functions:
|
|
73
|
+
|
|
74
|
+
```ts
|
|
75
|
+
export function pollFlights() {
|
|
76
|
+
const result = http.fetchJson('https://admin.gliding.app/club/abc/api/flights.json', {
|
|
77
|
+
headers: { 'X-API-KEY': tabbr.settings.get('apiKey') },
|
|
78
|
+
});
|
|
79
|
+
// ...
|
|
80
|
+
tabbr.settings.set('lastPullAt', new Date().toISOString());
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
- `http.fetchJson(url, options?)` - network access, restricted to `allowedHosts`. `localAllowedHosts` is added to that list
|
|
85
|
+
only by a `publish --local` (e.g. `localhost` for a mock of the external service you develop against) - never by a normal publish.
|
|
86
|
+
- `tabbr.settings.get(key)` / `.set(key, value)` - this module's own per-club settings, including
|
|
87
|
+
its own secrets (never sent back to any settings GET response once saved - `secretFieldNames`).
|
|
88
|
+
- `triggers[].type: "CRON"` runs on the given cron expression (server-local time), with no
|
|
89
|
+
triggering entity. `"ENTITY_HOOK"` runs on the named `entity`'s `event` (`onCreate`/`onUpdate`/
|
|
90
|
+
`onDelete`), with that entity bound under its own name (e.g. `flight`) in the handler's scope.
|
|
91
|
+
- Needs `esbuild` installed in the workspace (`npm install -D esbuild`) - only used at publish
|
|
92
|
+
time, bundled into one dependency-free `bundle.js` the server runs in a GraalVM sandbox, so
|
|
93
|
+
regular npm packages can be imported in your TS but nothing Node-specific (no `fs`, no native
|
|
94
|
+
addons) works at runtime.
|
|
95
|
+
|
|
96
|
+
A "resync now" button (or similar) can fire a `CRON` trigger manually:
|
|
97
|
+
`POST /api/custommodule/{moduleId}/trigger/{triggerName}` (ADMIN).
|
|
98
|
+
|
|
99
|
+
## Usage: publish
|
|
100
|
+
|
|
101
|
+
```
|
|
102
|
+
npx tabbr-module publish [--club ABC] [--module-id club.abc.hello] \
|
|
103
|
+
[--exposed-module ./Module] [--export-name Module] \
|
|
104
|
+
[--icon waving_hand] [--title "Hello"] # --title: fallback text, see above [--cwd .] [--api-host https://api.tabbr.be]
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
You need the ADMIN role in the club you publish to.
|
|
108
|
+
|
|
109
|
+
`--cwd` defaults to the current directory; run the command from your module workspace's root
|
|
110
|
+
(where its `angular.json`/`federation.config.js` live), or pass `--cwd` to point at it.
|
|
111
|
+
|
|
112
|
+
### What it does
|
|
113
|
+
|
|
114
|
+
Builds and publishes whichever parts are present - frontend, backend, or both - in one zip, one
|
|
115
|
+
upload:
|
|
116
|
+
|
|
117
|
+
1. If `angular.json` exists: runs `ng build`, locates the output (via `angular.json`'s
|
|
118
|
+
`build-original` target) and verifies `remoteEntry.json` exists at its root.
|
|
119
|
+
2. If `"backend"` is set in `tabbr.config.json`: bundles the backend entry with `esbuild` into a
|
|
120
|
+
single `bundle.js`, and writes `manifest.json` alongside it from the `backend` config.
|
|
121
|
+
3. Zips it all together - frontend files flat at the zip root (as before), backend files under a
|
|
122
|
+
`backend/` prefix.
|
|
123
|
+
4. Logs you in via a browser redirect to Keycloak (PKCE, no password ever touches this CLI) and
|
|
124
|
+
caches the resulting token at `~/.tabbr/credentials.json` for reuse on later runs.
|
|
125
|
+
5. Uploads the zip to `POST /api/custommodule` with the club in the `X-club` header, which hosts
|
|
126
|
+
the frontend files publicly, stores the backend files privately, and registers the module
|
|
127
|
+
against that club. You need the ADMIN role in that club.
|
|
128
|
+
|
|
129
|
+
### Publishing to a local environment
|
|
130
|
+
|
|
131
|
+
`npx tabbr-module publish --local` publishes into your own local tabbr (the environment behind
|
|
132
|
+
`<club>.local.tabbr.be`) instead of production: it uploads to `https://api.local.tabbr.be` (set
|
|
133
|
+
`"localApiHost"` in `tabbr.config.json` to use another URL) and trusts your mkcert root CA, which Node
|
|
134
|
+
doesn't do on its own (`NODE_EXTRA_CA_CERTS` is set automatically; if mkcert's root CA can't be found,
|
|
135
|
+
set it yourself - `mkcert -CAROOT` shows where it lives). `--club` picks the club in that environment;
|
|
136
|
+
login still goes through the real Keycloak, which local backends validate too.
|
|
137
|
+
|
|
138
|
+
## Usage: fetch-types
|
|
139
|
+
|
|
140
|
+
```
|
|
141
|
+
npx tabbr-module fetch-types [--club ABC] \
|
|
142
|
+
[--out src/types/tabbr/entities.d.ts] [--cwd .] [--api-host https://api.tabbr.be]
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
**Default (no `--entity`)**: fetches `GET /api/club/{club}/entities/types` - every entity this
|
|
146
|
+
club has (custom fields included), as plain TypeScript data interfaces in ONE combined file
|
|
147
|
+
(`src/types/tabbr/entities.d.ts` by default). No script-sandbox globals, so safe to have all of
|
|
148
|
+
them in scope together - meant for typing your own component code (e.g. an `httpResource`'s
|
|
149
|
+
response), not the script editor. This is the easy way to get everything at once.
|
|
150
|
+
|
|
151
|
+
```
|
|
152
|
+
npx tabbr-module fetch-types [--club ABC] --entity flight \
|
|
153
|
+
[--kind HOOK|CALCULATION|DEFAULT_CALCULATION|RELEVANT_CONDITION] \
|
|
154
|
+
[--out src/types/tabbr/flight.hook.d.ts] [--cwd .] [--api-host https://api.tabbr.be]
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
**With `--entity`**: fetches `GET /api/{entity}/meta/script?kind={kind}` instead - the same
|
|
158
|
+
generated ambient `.d.ts` tabbr-ui's own script editor (Monaco) feeds itself for that entity's
|
|
159
|
+
hook/calculation scripts. It types the script sandbox, not your REST responses, and declares
|
|
160
|
+
script-only globals (`current`, `onCreate`, ...) that don't exist in a browser context - see the
|
|
161
|
+
comment header the command writes atop the output file for the full explanation, and for why
|
|
162
|
+
files fetched for different entities/kinds should generally not sit in the same TypeScript
|
|
163
|
+
project as each other (or as the combined `entities.d.ts` above).
|
|
164
|
+
|
|
165
|
+
Fetched files reflect one specific club's live, possibly-custom field configuration (field names,
|
|
166
|
+
custom entities, ...) and are regenerable on demand - add `src/types/tabbr/` (or wherever `--out`
|
|
167
|
+
points) to your workspace's `.gitignore` rather than committing them.
|
|
168
|
+
|
|
169
|
+
## Prerequisite: Keycloak redirect URI
|
|
170
|
+
|
|
171
|
+
Login opens your browser to Keycloak and catches the redirect on a temporary local HTTP server
|
|
172
|
+
(an ephemeral `http://localhost:<port>/callback`). This requires `http://localhost:*` (or your
|
|
173
|
+
chosen fixed port) to be added to the `tabbr` Keycloak client's **Valid Redirect URIs** in the
|
|
174
|
+
Keycloak admin console - a one-time setup step, not something this CLI can configure itself.
|
|
175
|
+
|
|
176
|
+
## Non-goals (v1)
|
|
177
|
+
|
|
178
|
+
No `login`/`logout`/`whoami` subcommands, no multi-club profiles - `publish` covers the
|
|
179
|
+
end-to-end flow on its own.
|
|
180
|
+
|
|
181
|
+
## Releasing
|
|
182
|
+
|
|
183
|
+
Commit your CLI changes first, then from this package:
|
|
184
|
+
|
|
185
|
+
```bash
|
|
186
|
+
npm run release -- patch --dry-run # preview
|
|
187
|
+
npm run release -- patch # or minor / major / an explicit 0.3.0
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
Same flow as the SDK (see `tabbr-module-sdk/README.md`): the script bumps the version, commits,
|
|
191
|
+
tags `cli-v<version>` and pushes; the tag triggers `.github/workflows/publish-module-cli.yml`,
|
|
192
|
+
which publishes via npm Trusted Publishing (owner `systemworks-bv`, repository `gliderdesk`,
|
|
193
|
+
workflow `publish-module-cli.yml`).
|
package/bin/tabbr-module.js
CHANGED
|
@@ -8,6 +8,7 @@ const { buildAndZip } = require('../src/build');
|
|
|
8
8
|
const { publish } = require('../src/publish');
|
|
9
9
|
const { fetchScriptTypes, fetchAllEntityTypes, VALID_KINDS } = require('../src/fetch-types');
|
|
10
10
|
const { CONFIG_FILE, DEFAULT_API_HOST, readConfig, requireClub, runInit } = require('../src/config');
|
|
11
|
+
const { DEFAULT_LOCAL_API_HOST, trustLocalCertificateOrRespawn } = require('../src/local');
|
|
11
12
|
const DEFAULT_KIND = 'HOOK'; // matches the server's own @RequestParam default for /meta/script
|
|
12
13
|
|
|
13
14
|
function parseArgs(argv) {
|
|
@@ -24,6 +25,7 @@ function parseArgs(argv) {
|
|
|
24
25
|
case '--title': args.title = next(); break;
|
|
25
26
|
case '--cwd': args.cwd = path.resolve(next()); break;
|
|
26
27
|
case '--api-host': args.apiHost = next(); break;
|
|
28
|
+
case '--local': args.local = true; break;
|
|
27
29
|
case '--entity': args.entity = next(); break;
|
|
28
30
|
case '--kind': args.kind = next(); break;
|
|
29
31
|
case '--out': args.out = next(); break;
|
|
@@ -44,17 +46,36 @@ Asks for the club code (and module id / title) and writes ${CONFIG_FILE}.
|
|
|
44
46
|
|
|
45
47
|
Usage: tabbr-module publish [options]
|
|
46
48
|
|
|
49
|
+
Builds and publishes whichever parts of the workspace are present, in ONE upload: a frontend (an
|
|
50
|
+
Angular project with a Native Federation "exposes" entry) and/or a backend (a "backend" block in
|
|
51
|
+
${CONFIG_FILE} pointing at TypeScript run server-side - see README.md). At least one must be
|
|
52
|
+
present.
|
|
53
|
+
|
|
47
54
|
Required (command line or ${CONFIG_FILE}):
|
|
48
55
|
--club <CODE> Club code to publish to, e.g. ABC; you need the ADMIN role there
|
|
49
56
|
--module-id <id> Module id, unique within the club, e.g. club.abc.hello
|
|
57
|
+
|
|
58
|
+
Required for a module with a frontend part:
|
|
50
59
|
--exposed-module <./Foo> Key in your federation.config.js "exposes" map
|
|
51
60
|
--export-name <Foo> Named (or default) export implementing PlatformModuleImplementation
|
|
52
61
|
|
|
62
|
+
Backend part (all in ${CONFIG_FILE} under "backend", not as CLI flags):
|
|
63
|
+
entry TS entry point, default "backend/src/index.ts"
|
|
64
|
+
allowedHosts External hosts your module's http.fetchJson() may reach
|
|
65
|
+
secretFieldNames Names of your module's settings keys that hold secrets (masked from
|
|
66
|
+
every settings GET response once saved)
|
|
67
|
+
triggers [{type: "CRON", name, cronExpression, handler} |
|
|
68
|
+
{type: "ENTITY_HOOK", name, entity, event, handler}]
|
|
69
|
+
|
|
53
70
|
Optional:
|
|
54
71
|
--icon <name> Menu icon name
|
|
55
|
-
--title <text>
|
|
56
|
-
--cwd <path>
|
|
72
|
+
--title <text> Fallback title (module.title in your i18n bundle is what is shown)
|
|
73
|
+
--cwd <path> Workspace to build (default: current directory)
|
|
57
74
|
--api-host <url> Tabbr API host (default: ${DEFAULT_API_HOST})
|
|
75
|
+
--local Publish to your own local backend (https://api.local.tabbr.be, i.e. the
|
|
76
|
+
environment behind <club>.local.tabbr.be) instead of production;
|
|
77
|
+
"localApiHost" in ${CONFIG_FILE} overrides the URL. Trusts your mkcert
|
|
78
|
+
root CA automatically.
|
|
58
79
|
|
|
59
80
|
Requires the tabbr Keycloak client's Valid Redirect URIs to include http://localhost:*
|
|
60
81
|
(a Keycloak admin-console setting - see README.md).
|
|
@@ -95,11 +116,12 @@ async function runPublish(args) {
|
|
|
95
116
|
args.club = requireClub(args.club);
|
|
96
117
|
requireFlags(args, {
|
|
97
118
|
moduleId: '--module-id',
|
|
98
|
-
exposedModule: '--exposed-module',
|
|
99
|
-
exportName: '--export-name',
|
|
100
119
|
});
|
|
120
|
+
// exposedModule/exportName are only required for a module with a frontend part (an Angular
|
|
121
|
+
// project at --cwd); buildAndZip/the server reject a module with neither a frontend nor a
|
|
122
|
+
// backend part, so an all-blank publish still fails, just with a clearer error.
|
|
101
123
|
|
|
102
|
-
const zipBuffer = await buildAndZip(args.cwd);
|
|
124
|
+
const zipBuffer = await buildAndZip(args.cwd, args);
|
|
103
125
|
const accessToken = await getAccessToken();
|
|
104
126
|
const result = await publish({
|
|
105
127
|
apiHost: args.apiHost,
|
|
@@ -208,6 +230,12 @@ async function main() {
|
|
|
208
230
|
return;
|
|
209
231
|
}
|
|
210
232
|
const args = { apiHost: DEFAULT_API_HOST, ...readConfig(flags.cwd), ...flags };
|
|
233
|
+
if (args.local && !flags.apiHost) {
|
|
234
|
+
// --local targets your own local backend (https://api.local.tabbr.be, the same one
|
|
235
|
+
// <club>.local.tabbr.be talks to); "localApiHost" in tabbr.config.json overrides it.
|
|
236
|
+
args.apiHost = args.localApiHost || DEFAULT_LOCAL_API_HOST;
|
|
237
|
+
}
|
|
238
|
+
trustLocalCertificateOrRespawn(args.apiHost);
|
|
211
239
|
if (command === 'publish') {
|
|
212
240
|
await runPublish(args);
|
|
213
241
|
} else {
|
|
@@ -217,5 +245,12 @@ async function main() {
|
|
|
217
245
|
|
|
218
246
|
main().catch(err => {
|
|
219
247
|
console.error(err.message || err);
|
|
248
|
+
const code = String(err && err.cause && err.cause.code || '');
|
|
249
|
+
if (/CERT|SELF_SIGNED|UNABLE_TO_(GET|VERIFY)/.test(code)) {
|
|
250
|
+
console.error(
|
|
251
|
+
'\nThe server\'s TLS certificate is not trusted by Node. For a local environment (*.local.tabbr.be) run ' +
|
|
252
|
+
'"mkcert -install" and set NODE_EXTRA_CA_CERTS to the path of mkcert\'s rootCA.pem ("mkcert -CAROOT").'
|
|
253
|
+
);
|
|
254
|
+
}
|
|
220
255
|
process.exit(1);
|
|
221
256
|
});
|
package/package.json
CHANGED
|
@@ -1,33 +1,34 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@tabbr/module-cli",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Set up, build and publish a Native Federation club module to a tabbr club.",
|
|
5
|
-
"license": "SEE LICENSE IN LICENSE",
|
|
6
|
-
"author": "SystemWorks BV",
|
|
7
|
-
"repository": {
|
|
8
|
-
"type": "git",
|
|
9
|
-
"url": "git+https://github.com/systemworks-bv/gliderdesk.git",
|
|
10
|
-
"directory": "tabbr-module-cli"
|
|
11
|
-
},
|
|
12
|
-
"publishConfig": {
|
|
13
|
-
"access": "public",
|
|
14
|
-
"registry": "https://registry.npmjs.org/"
|
|
15
|
-
},
|
|
16
|
-
"bin": {
|
|
17
|
-
"tabbr-module": "bin/tabbr-module.js"
|
|
18
|
-
},
|
|
19
|
-
"files": [
|
|
20
|
-
"bin",
|
|
21
|
-
"src"
|
|
22
|
-
],
|
|
23
|
-
"scripts": {
|
|
24
|
-
"release": "node scripts/release.mjs"
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
"
|
|
32
|
-
|
|
33
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@tabbr/module-cli",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "Set up, build and publish a Native Federation club module to a tabbr club.",
|
|
5
|
+
"license": "SEE LICENSE IN LICENSE",
|
|
6
|
+
"author": "SystemWorks BV",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/systemworks-bv/gliderdesk.git",
|
|
10
|
+
"directory": "tabbr-module-cli"
|
|
11
|
+
},
|
|
12
|
+
"publishConfig": {
|
|
13
|
+
"access": "public",
|
|
14
|
+
"registry": "https://registry.npmjs.org/"
|
|
15
|
+
},
|
|
16
|
+
"bin": {
|
|
17
|
+
"tabbr-module": "bin/tabbr-module.js"
|
|
18
|
+
},
|
|
19
|
+
"files": [
|
|
20
|
+
"bin",
|
|
21
|
+
"src"
|
|
22
|
+
],
|
|
23
|
+
"scripts": {
|
|
24
|
+
"release": "node scripts/release.mjs",
|
|
25
|
+
"publish:local": "yalc publish --push"
|
|
26
|
+
},
|
|
27
|
+
"engines": {
|
|
28
|
+
"node": ">=20"
|
|
29
|
+
},
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"archiver": "^7.0.1",
|
|
32
|
+
"open": "^10.1.0"
|
|
33
|
+
}
|
|
34
|
+
}
|