@ofidj/generator-fidj 1.0.1 → 1.0.4
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/README.md +58 -14
- package/bin/create-fidj.cjs +9 -1
- package/generators/app/index.js +57 -15
- package/generators/app/templates/typescript/README.md +12 -2
- package/generators/app/templates/typescript/app.config.json +5 -1
- package/generators/app/templates/typescript/package.json +1 -1
- package/generators/app/templates/typescript/public/fidj-logo.png +0 -0
- package/generators/app/templates/typescript/public/fonts/IBMPlexMono-400-latin-ext.woff2 +0 -0
- package/generators/app/templates/typescript/public/fonts/IBMPlexMono-400-latin.woff2 +0 -0
- package/generators/app/templates/typescript/public/fonts/IBMPlexMono-500-latin-ext.woff2 +0 -0
- package/generators/app/templates/typescript/public/fonts/IBMPlexMono-500-latin.woff2 +0 -0
- package/generators/app/templates/typescript/public/fonts/IBMPlexSans-400_600-latin-ext.woff2 +0 -0
- package/generators/app/templates/typescript/public/fonts/IBMPlexSans-400_600-latin.woff2 +0 -0
- package/generators/app/templates/typescript/public/fonts/InstrumentSerif-400-latin-ext.woff2 +0 -0
- package/generators/app/templates/typescript/public/fonts/InstrumentSerif-400-latin.woff2 +0 -0
- package/generators/app/templates/typescript/scripts/build.mjs +3 -0
- package/generators/app/templates/typescript/scripts/render-content.mjs +2 -2
- package/generators/app/templates/typescript/server/index.ts +10 -1
- package/generators/app/templates/typescript/src/content.ts +128 -37
- package/generators/app/templates/typescript/src/fonts.css +92 -0
- package/generators/app/templates/typescript/src/main.ts +31 -9
- package/generators/app/templates/typescript/src/service-agreement.ts +51 -0
- package/generators/app/templates/typescript/src/style.css +640 -363
- package/generators/app/templates/typescript/src/tokens.css +56 -0
- package/lib/app-module.cjs +6 -1
- package/lib/scaffold.cjs +72 -3
- package/package.json +2 -6
package/README.md
CHANGED
|
@@ -2,10 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
Generate a Fidj-integrated TypeScript app with a short command. Public identity and content are generator inputs; authentication and per-app privacy are reusable template behavior. Node 22 or 24 is the validation matrix.
|
|
4
4
|
|
|
5
|
+
Registry examples require published compatible versions. For current workspace development, supply a built local SDK with `--sdk-path`.
|
|
6
|
+
|
|
5
7
|
## Content app — static hosting
|
|
6
8
|
|
|
7
9
|
```sh
|
|
8
|
-
|
|
10
|
+
npx -y -p @ofidj/generator-fidj -p yo yo @ofidj/fidj my-app --app-id YOUR_FIDJ_ID --title "My App" --welcome "Welcome" --content "<p>About my app</p>" --domain example.com
|
|
9
11
|
cd my-app
|
|
10
12
|
npm install && npm run build-prod
|
|
11
13
|
```
|
|
@@ -18,27 +20,55 @@ Serve `www/` on a static host. It contains your public content, SDK sign-in/acco
|
|
|
18
20
|
|
|
19
21
|
Omit `--content` to generate Studio Notes: a browser client plus Node backend with private persisted notes. The backend revalidates the session and live app roles for every protected request. Owner/Editor may write; other members may read their own notes. This mode requires Node hosting and is separate from the static content app scenario.
|
|
20
22
|
|
|
23
|
+
Departure uses an in-app confirmation that states the membership, consent and notes being removed and preserves the membership when cancelled.
|
|
24
|
+
|
|
21
25
|
Configure the generated privacy adapter so departure from either Studio Notes or Fidj erases the same app data. Notes persist outside disposable output. Failed cleanup stays pending in Fidj and can be retried; completed receipts remain visible. See the generated README for server-side configuration and persistence limits.
|
|
22
26
|
|
|
23
27
|
## CLI and local development
|
|
24
28
|
|
|
25
|
-
The
|
|
29
|
+
The public entry is `yo @ofidj/fidj`; output goes to `<cwd>/<appname>`. Use the `npx` form above or install once:
|
|
30
|
+
|
|
31
|
+
```sh
|
|
32
|
+
npm install --no-save @ofidj/generator-fidj yo
|
|
33
|
+
npx --no-install yo @ofidj/fidj my-app --app-id YOUR_FIDJ_ID
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Repeat a flag for `--highlight` and `--badge`; the values are read from the
|
|
37
|
+
command line, so a comma inside one is safe. The old `app2021` positional command
|
|
38
|
+
and its Ionic/Cordova templates are gone; the `typescript` template is the only
|
|
39
|
+
one.
|
|
40
|
+
|
|
41
|
+
> Maintainers: `bin/create-fidj.cjs` is the same scaffolder without Yeoman, for
|
|
42
|
+
> tooling that runs from a checkout and cannot install `yo` —
|
|
43
|
+
> `scripts/local-stack.py` and `fidj-app`'s `create:local` use it.
|
|
44
|
+
> `test/parity.test.cjs` fails if either door ever gains an input the other
|
|
45
|
+
> lacks. It is not an entry point to hand to anyone building an app.
|
|
26
46
|
|
|
27
47
|
- `--anonymous true|false`: show or hide anonymous entry in content apps (default: `true`). Set `--anonymous false` for a sign-in-only entry flow, as mleweb does.
|
|
48
|
+
- `--highlight "<heading>|<body>"`: add a numbered cell to the sign-in panel, repeatable up to six. These are the app's own selling points, so an app that passes none simply shows its identity — mleweb passes none, Fidj passes four.
|
|
49
|
+
- `--badge <text>`: add a trust badge under the sign-in form, repeatable up to four, 40 characters each. None are supplied by default — "EU-hosted" or "GDPR art. 17 · 20" are claims about a particular app, not about every app the generator makes.
|
|
50
|
+
- `--logo <image>` and `--favicon <image>`: the app's own marks, copied into `public/brand/`. The logo sits beside the app name at the top of the sign-in panel; the favicon goes in the browser tab. Both fall back to the Fidj mark, so neither is ever blank. Accepts `.png`, `.svg`, `.gif`, `.jpg`, `.webp` or `.ico` under 512KB — an animated GIF works as a logo, and as a favicon in the browsers that animate one.
|
|
28
51
|
- `--api-endpoint`: select the API (default: hosted sandbox).
|
|
29
52
|
- `--sdk-path` or `FIDJ_SDK_DIR`: use a built local SDK during coordinated development.
|
|
30
53
|
- `--local` or `FIDJ_LOCAL=true`: use the loopback API/console. Test credentials stay in the validation guide, outside the content app UI. Supply the matching local app ID; `FIDJ_APP_ID` can override it.
|
|
31
54
|
- `--replace`: regenerate only a destination containing `.fidj-generated`; unmarked projects are protected.
|
|
32
55
|
|
|
56
|
+
The generated shell paints from one design system: `src/tokens.css` holds every
|
|
57
|
+
colour, family and radius, and `src/style.css` may not introduce a literal of
|
|
58
|
+
its own. Fonts are self-hosted under `public/fonts` and served from the build
|
|
59
|
+
manifest, so a generated site stays statically hostable and makes no
|
|
60
|
+
third-party request on sign-in. fidj-app consumes the same tokens, which is why
|
|
61
|
+
a style change lands here first.
|
|
62
|
+
|
|
33
63
|
Generation writes `.env.example`, `.env` and public `app.config.json`. Static configuration is embedded at build time: regenerate/rebuild when changing endpoints. Notes server configuration is read at runtime. Do not place secrets in any public configuration or content input.
|
|
34
64
|
|
|
35
|
-
|
|
65
|
+
For unpublished coordinated changes, build the sibling SDK and pass `--sdk-path` with its absolute `dist` path. Committed templates use registry dependency `@ofidj/node ^3.6.24`; a registry-only install is not validated until coordinated versions are published.
|
|
36
66
|
|
|
37
67
|
## Real validation repository
|
|
38
68
|
|
|
39
69
|
[mleweb](https://github.com/mlefree/mleweb) is the thin command-line validation fixture whose generated website is mlefree.com. Its `package.json` passes the original Mario GIF, welcome text and About/CV/contact links directly into this generator. No custom downstream renderer is required. GitHub CI runs the same generation/build path on Node 22/24 and uploads artifacts. Publishing the site to gh-pages, which is what mlefree.com serves, is a separate deliberate job: it runs on mleweb's `master` or on an explicit workflow dispatch, never from a version branch.
|
|
40
70
|
|
|
41
|
-
Run `npm test` for scaffolding/CLI safety tests. Generated projects include TypeScript checking and HTTP integration tests for live authorization and privacy isolation.
|
|
71
|
+
Run `npm test` for scaffolding/CLI safety tests. Generated projects include TypeScript checking and HTTP integration tests for live authorization and privacy isolation. See the [local acceptance walkthrough](../LOCAL-DEVELOPMENT.md). Follow TDD: add/run a failing generator or generated-app test before implementation, make it green, then refactor and rerun regression checks.
|
|
42
72
|
|
|
43
73
|
|
|
44
74
|
## Releasing to npm
|
|
@@ -49,8 +79,8 @@ with `NPM_TOKEN`; this package publishes from the repository root rather than
|
|
|
49
79
|
from a `dist` directory, because it ships its sources.
|
|
50
80
|
|
|
51
81
|
The package contains `bin/`, `lib/` and the `typescript` template only. The
|
|
52
|
-
`app2018` and `app2021` Yeoman templates
|
|
53
|
-
they accounted for 11.8MB of the
|
|
82
|
+
`app2018` and `app2021` Yeoman templates were deleted: nothing read them, and
|
|
83
|
+
they accounted for 11.8MB of the repository. `main` points at
|
|
54
84
|
`lib/scaffold.cjs`, so `require('@ofidj/generator-fidj')` returns `{ scaffold }`
|
|
55
85
|
alongside the `create-fidj` binary.
|
|
56
86
|
|
|
@@ -67,7 +97,7 @@ The generated content app opens on `/#/signin`. Sign in, or choose **Enter anony
|
|
|
67
97
|
Build your application for the `/module/` base URL, then pass its public output to the same generator:
|
|
68
98
|
|
|
69
99
|
```sh
|
|
70
|
-
|
|
100
|
+
npx -y -p @ofidj/generator-fidj -p yo yo @ofidj/fidj my-app --app-id YOUR_FIDJ_ID --title "My App" --welcome "Welcome back" --description "Your app description" --anonymous false --module ./built-console --module-entry 'index.html#/my'
|
|
71
101
|
cd my-app && npm install && npm run build-prod
|
|
72
102
|
```
|
|
73
103
|
|
|
@@ -96,14 +126,28 @@ Generated starters include `npm run privacy:check`: configure the server-only `F
|
|
|
96
126
|
|
|
97
127
|
Readiness confirms this handler only. Register its trusted URL and independent secret with the Fidj API operator; the app owner console can then check the same connection. Group roles granted in Fidj are enforced by the generated backend on each protected operation.
|
|
98
128
|
|
|
99
|
-
##
|
|
129
|
+
## Beta OIDC input
|
|
100
130
|
|
|
101
|
-
`--oidc-issuer`
|
|
131
|
+
`--oidc-issuer` selects the OIDC entry for content/module apps while preserving branding and anonymous-entry configuration. This is beta: the API ships an integrated provider from 3.6.26, but it serves no `/oidc` routes until an operator configures an issuer and signing keys, so confirm the issuer you pass actually answers discovery before offering it.
|
|
102
132
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
133
|
+
A compatible issuer, REST API and registered callback without a fragment are prerequisites. Validate that integration and coordinated SDK publication before offering it to app builders. Notes retains its existing authentication flow; no subject migration is implied.
|
|
134
|
+
|
|
135
|
+
## Required service agreement
|
|
136
|
+
|
|
137
|
+
All generated sign-in and account-creation forms (content, composed Fidj and
|
|
138
|
+
Notes) share an unchecked required agreement checkbox. Both submit buttons stay
|
|
139
|
+
disabled until it is checked. Reading the agreement opens an in-app dialog;
|
|
140
|
+
failed agreement loading keeps sign-in blocked. Anonymous entry, when enabled,
|
|
141
|
+
is not a login and does not record agreement acceptance.
|
|
106
142
|
|
|
107
|
-
|
|
143
|
+
The text and version come from the app's public API metadata, not copied generator
|
|
144
|
+
settings. The API records acceptance before issuing the app token, preserves
|
|
145
|
+
optional choices, and rejects a missing choice or stale version. Repeated login
|
|
146
|
+
with the same version does not duplicate the history. Administrative membership
|
|
147
|
+
creation does not fabricate a user's acceptance.
|
|
108
148
|
|
|
109
|
-
|
|
149
|
+
Before release, the owner sets `configurationAsJSON.serviceAgreement` to
|
|
150
|
+
`{"version":"2026-09-11","text":"Your complete app service agreement"}` through
|
|
151
|
+
`PUT /apps/:appId`, preserving its other configuration fields. Changing the text
|
|
152
|
+
requires a new version. Until configured, the API exposes the explicitly labelled
|
|
153
|
+
`starter-demo-1` demo agreement. No generated-source edit is necessary.
|
package/bin/create-fidj.cjs
CHANGED
|
@@ -13,6 +13,10 @@ try {
|
|
|
13
13
|
welcome: { type: "string" },
|
|
14
14
|
description: { type: "string" },
|
|
15
15
|
content: { type: "string" },
|
|
16
|
+
highlight: { type: "string", multiple: true },
|
|
17
|
+
badge: { type: "string", multiple: true },
|
|
18
|
+
logo: { type: "string" },
|
|
19
|
+
favicon: { type: "string" },
|
|
16
20
|
anonymous: { type: "string" },
|
|
17
21
|
domain: { type: "string" },
|
|
18
22
|
module: { type: "string" },
|
|
@@ -24,7 +28,7 @@ try {
|
|
|
24
28
|
});
|
|
25
29
|
if (values.help || positionals.length !== 1) {
|
|
26
30
|
console.log(
|
|
27
|
-
"Usage: create-fidj <directory> --app-id <fidjId> [--api-endpoint <url>] [--title <text> --welcome <text> --description <text> --content <html> --domain <hostname>] [--module <built-directory> --module-entry <index.html#/route>] [--oidc-issuer https://api.example/oidc] [--anonymous true|false] [--local] [--replace]",
|
|
31
|
+
"Usage: create-fidj <directory> --app-id <fidjId> [--api-endpoint <url>] [--title <text> --welcome <text> --description <text> --content <html> --domain <hostname>] [--highlight '<heading>|<body>' ...] [--badge <text> ...] [--logo <image>] [--favicon <image>] [--module <built-directory> --module-entry <index.html#/route>] [--oidc-issuer https://api.example/oidc] [--anonymous true|false] [--local] [--replace]",
|
|
28
32
|
);
|
|
29
33
|
process.exitCode = values.help ? 0 : 1;
|
|
30
34
|
} else {
|
|
@@ -37,6 +41,10 @@ try {
|
|
|
37
41
|
welcome: values.welcome,
|
|
38
42
|
description: values.description,
|
|
39
43
|
content: values.content,
|
|
44
|
+
highlights: values.highlight,
|
|
45
|
+
badges: values.badge,
|
|
46
|
+
logo: values.logo,
|
|
47
|
+
favicon: values.favicon,
|
|
40
48
|
anonymous: values.anonymous,
|
|
41
49
|
domain: values.domain,
|
|
42
50
|
module: values.module,
|
package/generators/app/index.js
CHANGED
|
@@ -1,23 +1,55 @@
|
|
|
1
1
|
const Generator = require("yeoman-generator");
|
|
2
2
|
const { scaffold } = require("../../lib/scaffold.cjs");
|
|
3
3
|
|
|
4
|
+
// Yeoman and bin/create-fidj.cjs are two doors into the same scaffolder, and
|
|
5
|
+
// they must stay at parity: an input added to one and not the other silently
|
|
6
|
+
// disappears for half the users. test/parity.test.cjs fails when they drift.
|
|
7
|
+
const TEXT_OPTIONS = [
|
|
8
|
+
"app-id",
|
|
9
|
+
"api-endpoint",
|
|
10
|
+
"oidc-issuer",
|
|
11
|
+
"sdk-path",
|
|
12
|
+
"title",
|
|
13
|
+
"welcome",
|
|
14
|
+
"description",
|
|
15
|
+
"content",
|
|
16
|
+
"anonymous",
|
|
17
|
+
"domain",
|
|
18
|
+
"module",
|
|
19
|
+
"module-entry",
|
|
20
|
+
"logo",
|
|
21
|
+
"favicon",
|
|
22
|
+
];
|
|
23
|
+
// Repeatable: --highlight twice yields two cells.
|
|
24
|
+
const LIST_OPTIONS = ["highlight", "badge"];
|
|
25
|
+
const FLAG_OPTIONS = ["local", "replace"];
|
|
26
|
+
|
|
27
|
+
// Yeoman joins a repeated flag into one comma-separated string before any type
|
|
28
|
+
// coercion, and splitting that back is wrong: a highlight body legitimately
|
|
29
|
+
// contains commas ("An install, a fidjId, a few lines"). Read the occurrences
|
|
30
|
+
// from argv, which is exactly what was typed, and fall back to Yeoman's value
|
|
31
|
+
// when the generator is composed programmatically rather than from a command
|
|
32
|
+
// line.
|
|
33
|
+
function repeated(name, fallback, argv = process.argv) {
|
|
34
|
+
const found = [];
|
|
35
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
36
|
+
if (argv[index] === "--" + name && index + 1 < argv.length)
|
|
37
|
+
found.push(argv[index + 1]);
|
|
38
|
+
else if (argv[index].startsWith("--" + name + "="))
|
|
39
|
+
found.push(argv[index].slice(name.length + 3));
|
|
40
|
+
}
|
|
41
|
+
if (found.length) return found;
|
|
42
|
+
if (fallback === undefined) return undefined;
|
|
43
|
+
return Array.isArray(fallback) ? fallback : [fallback];
|
|
44
|
+
}
|
|
45
|
+
|
|
4
46
|
module.exports = class extends Generator {
|
|
5
47
|
constructor(args, opts) {
|
|
6
48
|
super(args, opts);
|
|
7
49
|
this.argument("appname", { type: String, required: false });
|
|
8
|
-
this.option(
|
|
9
|
-
for (const key of
|
|
10
|
-
|
|
11
|
-
"welcome",
|
|
12
|
-
"description",
|
|
13
|
-
"content",
|
|
14
|
-
"domain",
|
|
15
|
-
"sdk-path",
|
|
16
|
-
"anonymous",
|
|
17
|
-
"module",
|
|
18
|
-
"module-entry",
|
|
19
|
-
])
|
|
20
|
-
this.option(key, { type: String });
|
|
50
|
+
for (const key of TEXT_OPTIONS) this.option(key, { type: String });
|
|
51
|
+
for (const key of LIST_OPTIONS) this.option(key, { type: String });
|
|
52
|
+
for (const key of FLAG_OPTIONS) this.option(key, { type: Boolean });
|
|
21
53
|
this.option("api-endpoint", {
|
|
22
54
|
type: String,
|
|
23
55
|
default: "https://api.sandbox.fidj.ovh/v3",
|
|
@@ -55,11 +87,19 @@ module.exports = class extends Generator {
|
|
|
55
87
|
description: this.options.description,
|
|
56
88
|
content: this.options.content,
|
|
57
89
|
anonymous: this.options.anonymous,
|
|
90
|
+
highlights: repeated("highlight", this.options.highlight),
|
|
91
|
+
badges: repeated("badge", this.options.badge),
|
|
92
|
+
logo: this.options.logo,
|
|
93
|
+
favicon: this.options.favicon,
|
|
58
94
|
module: this.options.module,
|
|
59
95
|
moduleEntry: this.options["module-entry"],
|
|
60
96
|
domain: this.options.domain,
|
|
61
|
-
sdkPath: this.options["sdk-path"],
|
|
62
|
-
|
|
97
|
+
sdkPath: this.options["sdk-path"] || process.env.FIDJ_SDK_DIR,
|
|
98
|
+
oidcIssuer: this.options["oidc-issuer"],
|
|
99
|
+
local: this.options.local || process.env.FIDJ_LOCAL === "true",
|
|
100
|
+
replace: this.options.replace,
|
|
101
|
+
appId:
|
|
102
|
+
process.env.FIDJ_APP_ID || this.options["app-id"] || this.answers.appId,
|
|
63
103
|
apiEndpoint: this.options["api-endpoint"],
|
|
64
104
|
});
|
|
65
105
|
this.log(
|
|
@@ -67,3 +107,5 @@ module.exports = class extends Generator {
|
|
|
67
107
|
);
|
|
68
108
|
}
|
|
69
109
|
};
|
|
110
|
+
|
|
111
|
+
module.exports.repeatedOption = repeated;
|
|
@@ -29,7 +29,7 @@ The current unreleased generator requires the matching `@ofidj/node` 3.6.24 SDK.
|
|
|
29
29
|
- `test/server.test.mjs`: fresh HTTP servers verify role changes, revoked/foreign sessions, outage failure, per-user notes and privacy scope.
|
|
30
30
|
- `scripts/build.mjs`: browser and Node builds using [esbuild](https://esbuild.github.io/getting-started/), with a separate TypeScript typecheck.
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
Use TDD: add and run a failing behavior test before implementation (red), make it pass (green), then refactor and run `npm test`. Change maintained template source and regenerate to verify that every fresh app receives the fix.
|
|
33
33
|
|
|
34
34
|
## Privacy scope
|
|
35
35
|
|
|
@@ -41,7 +41,7 @@ The browser SDK stores the app’s session in this origin’s local storage. Use
|
|
|
41
41
|
|
|
42
42
|
## Local scenario
|
|
43
43
|
|
|
44
|
-
|
|
44
|
+
For the Notes fixture only, `LOCAL_DEMO=true` with the loopback API enables synthetic Alex/Maya/Sam sign-in shortcuts. Content/module entries keep test accounts in developer documentation. These accounts must be seeded by your local Fidj API; the starter does not create accounts or seed data remotely. Alex is the owner, and the owner console can grant Maya Editor access.
|
|
45
45
|
|
|
46
46
|
## Entry flow
|
|
47
47
|
|
|
@@ -71,3 +71,13 @@ Keep `FIDJ_DATA_DIR` outside public assets and generated output. Use one writer
|
|
|
71
71
|
After starting the Notes backend with its server-only adapter secret, run `npm run privacy:check`. The signed check confirms export/erase capabilities and writable storage without accessing user records. Override `FIDJ_APP_URL` for a deployed HTTPS backend. Keep this secret out of browser configuration.
|
|
72
72
|
|
|
73
73
|
Run `npm run privacy:rehearse` for an isolated temporary-store HTTP scenario covering live roles, scoped export, persistence, failure and idempotent erasure. It never points at your running data directory. Groups are managed in the Fidj owner console; direct and group roles are checked live by the backend.
|
|
74
|
+
|
|
75
|
+
## Agreement at sign-in
|
|
76
|
+
|
|
77
|
+
Sign-in and account creation require the unchecked service-agreement checkbox.
|
|
78
|
+
Read the app's current text/version from the dialog before accepting. If the
|
|
79
|
+
agreement is not accepted, submitting explains the requirement while preserving
|
|
80
|
+
the form; if the agreement cannot load, the form stays blocked. The API records the accepted
|
|
81
|
+
version per app; optional privacy choices are separate. The app owner must replace
|
|
82
|
+
the default demo agreement using the Fidj app's `configurationAsJSON.serviceAgreement`
|
|
83
|
+
(`version` and `text`) before release. No generated-source edit is needed.
|
|
@@ -6,5 +6,9 @@
|
|
|
6
6
|
"localDemo": false,
|
|
7
7
|
"allowAnonymous": true,
|
|
8
8
|
"moduleEntry": "",
|
|
9
|
-
"description": "A space to explore, with an account that puts you in control."
|
|
9
|
+
"description": "A space to explore, with an account that puts you in control.",
|
|
10
|
+
"highlights": [],
|
|
11
|
+
"badges": [],
|
|
12
|
+
"logo": "./fidj-logo.png",
|
|
13
|
+
"favicon": "./fidj-logo.png"
|
|
10
14
|
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -13,6 +13,9 @@ await Promise.all([
|
|
|
13
13
|
target: "es2022",
|
|
14
14
|
outfile: "dist/public/main.js",
|
|
15
15
|
sourcemap: true,
|
|
16
|
+
// The design system's fonts are copied with public/; esbuild must leave
|
|
17
|
+
// their url()s alone rather than try to resolve them at build time.
|
|
18
|
+
external: ["*.woff2"],
|
|
16
19
|
}),
|
|
17
20
|
build({
|
|
18
21
|
entryPoints: ["server/index.ts"],
|
|
@@ -8,7 +8,7 @@ const escape = (value) =>
|
|
|
8
8
|
);
|
|
9
9
|
export function renderContent(config) {
|
|
10
10
|
// HTML is supplied by the developer at generation time, never by an app visitor.
|
|
11
|
-
return `<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><meta name="referrer" content="no-referrer"><title>${escape(config.title)}</title><link rel="icon" href="
|
|
12
|
-
<header class="topbar"><a class="brand" href="#/content"
|
|
11
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><meta name="referrer" content="no-referrer"><title>${escape(config.title)}</title><link rel="icon" href="${escape(config.favicon)}"><link rel="stylesheet" href="./main.css"></head><body>
|
|
12
|
+
<header class="topbar"><a class="brand" href="#/content"><img src="${escape(config.logo)}" alt="">${escape(config.title)}</a></header>
|
|
13
13
|
<main><template id="public-content"><section class="card public-content"><h1>${escape(config.welcome)}</h1><div>${config.content}</div></section></template><div id="app" aria-live="polite"></div><footer>Built with Fidj · Your choices belong to this app.</footer></main><script type="module" src="./main.js"></script></body></html>`;
|
|
14
14
|
}
|
|
@@ -241,7 +241,16 @@ export function createApp(
|
|
|
241
241
|
"/main.css": ["main.css", "text/css"],
|
|
242
242
|
"/fidj-logo.png": ["fidj-logo.png", "image/png"],
|
|
243
243
|
};
|
|
244
|
-
|
|
244
|
+
// Beyond the named files above, three directories are served from the
|
|
245
|
+
// build manifest: the assembled application module, the design system's
|
|
246
|
+
// self-hosted fonts, and any logo or favicon the app supplied. The
|
|
247
|
+
// manifest only resolves paths the build actually produced.
|
|
248
|
+
if (
|
|
249
|
+
!files[pathname] &&
|
|
250
|
+
(pathname.startsWith("/module/") ||
|
|
251
|
+
pathname.startsWith("/fonts/") ||
|
|
252
|
+
pathname.startsWith("/brand/"))
|
|
253
|
+
) {
|
|
245
254
|
const manifest = JSON.parse(
|
|
246
255
|
await readFile(join(__dirname, "public-files.json"), "utf8"),
|
|
247
256
|
);
|