@pwfabric/cli 0.0.0-stage → 1.0.0-rc.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.
Files changed (171) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +122 -2
  3. package/dist/args.d.ts +12 -0
  4. package/dist/args.d.ts.map +1 -0
  5. package/dist/args.js +43 -0
  6. package/dist/args.js.map +1 -0
  7. package/dist/bin.d.ts +3 -0
  8. package/dist/bin.d.ts.map +1 -0
  9. package/dist/bin.js +10 -0
  10. package/dist/bin.js.map +1 -0
  11. package/dist/commands/add.d.ts +4 -0
  12. package/dist/commands/add.d.ts.map +1 -0
  13. package/dist/commands/add.js +56 -0
  14. package/dist/commands/add.js.map +1 -0
  15. package/dist/commands/build.d.ts +4 -0
  16. package/dist/commands/build.d.ts.map +1 -0
  17. package/dist/commands/build.js +55 -0
  18. package/dist/commands/build.js.map +1 -0
  19. package/dist/commands/create.d.ts +10 -0
  20. package/dist/commands/create.d.ts.map +1 -0
  21. package/dist/commands/create.js +119 -0
  22. package/dist/commands/create.js.map +1 -0
  23. package/dist/commands/dev.d.ts +13 -0
  24. package/dist/commands/dev.d.ts.map +1 -0
  25. package/dist/commands/dev.js +107 -0
  26. package/dist/commands/dev.js.map +1 -0
  27. package/dist/commands/lib/flags.d.ts +11 -0
  28. package/dist/commands/lib/flags.d.ts.map +1 -0
  29. package/dist/commands/lib/flags.js +33 -0
  30. package/dist/commands/lib/flags.js.map +1 -0
  31. package/dist/commands/lib/identity.d.ts +39 -0
  32. package/dist/commands/lib/identity.d.ts.map +1 -0
  33. package/dist/commands/lib/identity.js +120 -0
  34. package/dist/commands/lib/identity.js.map +1 -0
  35. package/dist/commands/lib/project.d.ts +35 -0
  36. package/dist/commands/lib/project.d.ts.map +1 -0
  37. package/dist/commands/lib/project.js +78 -0
  38. package/dist/commands/lib/project.js.map +1 -0
  39. package/dist/commands/lib/report.d.ts +16 -0
  40. package/dist/commands/lib/report.d.ts.map +1 -0
  41. package/dist/commands/lib/report.js +75 -0
  42. package/dist/commands/lib/report.js.map +1 -0
  43. package/dist/commands/lib/starter.d.ts +42 -0
  44. package/dist/commands/lib/starter.d.ts.map +1 -0
  45. package/dist/commands/lib/starter.js +136 -0
  46. package/dist/commands/lib/starter.js.map +1 -0
  47. package/dist/commands/lib/static-server.d.ts +46 -0
  48. package/dist/commands/lib/static-server.d.ts.map +1 -0
  49. package/dist/commands/lib/static-server.js +173 -0
  50. package/dist/commands/lib/static-server.js.map +1 -0
  51. package/dist/commands/pack.d.ts +6 -0
  52. package/dist/commands/pack.d.ts.map +1 -0
  53. package/dist/commands/pack.js +56 -0
  54. package/dist/commands/pack.js.map +1 -0
  55. package/dist/commands/registry.d.ts +8 -0
  56. package/dist/commands/registry.d.ts.map +1 -0
  57. package/dist/commands/registry.js +16 -0
  58. package/dist/commands/registry.js.map +1 -0
  59. package/dist/commands/run.d.ts +15 -0
  60. package/dist/commands/run.d.ts.map +1 -0
  61. package/dist/commands/run.js +79 -0
  62. package/dist/commands/run.js.map +1 -0
  63. package/dist/commands/types.d.ts +35 -0
  64. package/dist/commands/types.d.ts.map +1 -0
  65. package/dist/commands/types.js +10 -0
  66. package/dist/commands/types.js.map +1 -0
  67. package/dist/commands/validate.d.ts +7 -0
  68. package/dist/commands/validate.d.ts.map +1 -0
  69. package/dist/commands/validate.js +33 -0
  70. package/dist/commands/validate.js.map +1 -0
  71. package/dist/dev/assemble.d.ts +48 -0
  72. package/dist/dev/assemble.d.ts.map +1 -0
  73. package/dist/dev/assemble.js +339 -0
  74. package/dist/dev/assemble.js.map +1 -0
  75. package/dist/dev/compile.d.ts +55 -0
  76. package/dist/dev/compile.d.ts.map +1 -0
  77. package/dist/dev/compile.js +215 -0
  78. package/dist/dev/compile.js.map +1 -0
  79. package/dist/dev/csp.d.ts +68 -0
  80. package/dist/dev/csp.d.ts.map +1 -0
  81. package/dist/dev/csp.js +260 -0
  82. package/dist/dev/csp.js.map +1 -0
  83. package/dist/dev/diagnostics.d.ts +22 -0
  84. package/dist/dev/diagnostics.d.ts.map +1 -0
  85. package/dist/dev/diagnostics.js +22 -0
  86. package/dist/dev/diagnostics.js.map +1 -0
  87. package/dist/dev/envelope.d.ts +93 -0
  88. package/dist/dev/envelope.d.ts.map +1 -0
  89. package/dist/dev/envelope.js +154 -0
  90. package/dist/dev/envelope.js.map +1 -0
  91. package/dist/dev/media.d.ts +54 -0
  92. package/dist/dev/media.d.ts.map +1 -0
  93. package/dist/dev/media.js +128 -0
  94. package/dist/dev/media.js.map +1 -0
  95. package/dist/dev/needs-host.d.ts +3 -0
  96. package/dist/dev/needs-host.d.ts.map +1 -0
  97. package/dist/dev/needs-host.js +32 -0
  98. package/dist/dev/needs-host.js.map +1 -0
  99. package/dist/dev/output.d.ts +10 -0
  100. package/dist/dev/output.d.ts.map +1 -0
  101. package/dist/dev/output.js +32 -0
  102. package/dist/dev/output.js.map +1 -0
  103. package/dist/dev/overlay.d.ts +22 -0
  104. package/dist/dev/overlay.d.ts.map +1 -0
  105. package/dist/dev/overlay.js +59 -0
  106. package/dist/dev/overlay.js.map +1 -0
  107. package/dist/dev/server.d.ts +28 -0
  108. package/dist/dev/server.d.ts.map +1 -0
  109. package/dist/dev/server.js +264 -0
  110. package/dist/dev/server.js.map +1 -0
  111. package/dist/dev/shell.d.ts +83 -0
  112. package/dist/dev/shell.d.ts.map +1 -0
  113. package/dist/dev/shell.js +244 -0
  114. package/dist/dev/shell.js.map +1 -0
  115. package/dist/dev/sources.d.ts +46 -0
  116. package/dist/dev/sources.d.ts.map +1 -0
  117. package/dist/dev/sources.js +165 -0
  118. package/dist/dev/sources.js.map +1 -0
  119. package/dist/dev/theme.d.ts +52 -0
  120. package/dist/dev/theme.d.ts.map +1 -0
  121. package/dist/dev/theme.js +185 -0
  122. package/dist/dev/theme.js.map +1 -0
  123. package/dist/dev/types.d.ts +41 -0
  124. package/dist/dev/types.d.ts.map +1 -0
  125. package/dist/dev/types.js +11 -0
  126. package/dist/dev/types.js.map +1 -0
  127. package/dist/dev/watcher.d.ts +30 -0
  128. package/dist/dev/watcher.d.ts.map +1 -0
  129. package/dist/dev/watcher.js +150 -0
  130. package/dist/dev/watcher.js.map +1 -0
  131. package/dist/host/definitions.d.ts +62 -0
  132. package/dist/host/definitions.d.ts.map +1 -0
  133. package/dist/host/definitions.js +136 -0
  134. package/dist/host/definitions.js.map +1 -0
  135. package/dist/host/http.d.ts +40 -0
  136. package/dist/host/http.d.ts.map +1 -0
  137. package/dist/host/http.js +156 -0
  138. package/dist/host/http.js.map +1 -0
  139. package/dist/host/local-host.d.ts +60 -0
  140. package/dist/host/local-host.d.ts.map +1 -0
  141. package/dist/host/local-host.js +420 -0
  142. package/dist/host/local-host.js.map +1 -0
  143. package/dist/host/oidc.d.ts +47 -0
  144. package/dist/host/oidc.d.ts.map +1 -0
  145. package/dist/host/oidc.js +192 -0
  146. package/dist/host/oidc.js.map +1 -0
  147. package/dist/host/query.d.ts +36 -0
  148. package/dist/host/query.d.ts.map +1 -0
  149. package/dist/host/query.js +158 -0
  150. package/dist/host/query.js.map +1 -0
  151. package/dist/host/receipts.d.ts +26 -0
  152. package/dist/host/receipts.d.ts.map +1 -0
  153. package/dist/host/receipts.js +72 -0
  154. package/dist/host/receipts.js.map +1 -0
  155. package/dist/host/records.d.ts +74 -0
  156. package/dist/host/records.d.ts.map +1 -0
  157. package/dist/host/records.js +229 -0
  158. package/dist/host/records.js.map +1 -0
  159. package/dist/host/tokens.d.ts +29 -0
  160. package/dist/host/tokens.d.ts.map +1 -0
  161. package/dist/host/tokens.js +52 -0
  162. package/dist/host/tokens.js.map +1 -0
  163. package/dist/host/types.d.ts +33 -0
  164. package/dist/host/types.d.ts.map +1 -0
  165. package/dist/host/types.js +11 -0
  166. package/dist/host/types.js.map +1 -0
  167. package/dist/index.d.ts +17 -0
  168. package/dist/index.d.ts.map +1 -0
  169. package/dist/index.js +41 -0
  170. package/dist/index.js.map +1 -0
  171. package/package.json +65 -3
@@ -0,0 +1,16 @@
1
+ import { create } from './create.js';
2
+ import { devCommand } from './dev.js';
3
+ import { buildCommand } from './build.js';
4
+ import { validate } from './validate.js';
5
+ import { pack } from './pack.js';
6
+ import { add } from './add.js';
7
+ import { run } from './run.js';
8
+ /**
9
+ * Every `pwf` command. Lanes add their command module here and nowhere else.
10
+ * Order is the order `pwf help` prints.
11
+ */
12
+ export const COMMANDS = [create, devCommand, buildCommand, validate, pack, add, run];
13
+ export function findCommand(name) {
14
+ return COMMANDS.find((c) => c.name === name);
15
+ }
16
+ //# sourceMappingURL=registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/commands/registry.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACpC,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AACrC,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AACzC,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AACxC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAChC,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAA;AAC9B,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAA;AAE9B;;;GAGG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAc,CAAC,MAAM,EAAE,UAAU,EAAE,YAAY,EAAE,QAAQ,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,CAAC,CAAA;AAE/F,MAAM,UAAU,WAAW,CAAC,IAAY;IACtC,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,CAAA;AAC9C,CAAC"}
@@ -0,0 +1,15 @@
1
+ import type { Command, CommandIO, ParsedArgs } from './types.js';
2
+ import { type StaticServer, type StaticSource } from './lib/static-server.js';
3
+ export declare const DEFAULT_RUN_PORT = 4700;
4
+ /** Resolves when the process is asked to stop (Ctrl-C or SIGTERM). */
5
+ export declare function untilSignal(): Promise<void>;
6
+ export declare function parsePort(value: string | undefined): number;
7
+ /** The source to serve: a folder with an `index.html`, or a `.pwapp` archive opened in memory. */
8
+ export declare function openRunSource(path: string): Promise<StaticSource>;
9
+ export interface RunOptions {
10
+ /** Resolves when the server should stop. Default: SIGINT or SIGTERM. */
11
+ readonly until?: (server: StaticServer) => Promise<void>;
12
+ }
13
+ export declare function runRun(args: ParsedArgs, io: CommandIO, options?: RunOptions): Promise<number>;
14
+ export declare const run: Command;
15
+ //# sourceMappingURL=run.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../src/commands/run.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAGhE,OAAO,EAAqB,KAAK,YAAY,EAAE,KAAK,YAAY,EAAE,MAAM,wBAAwB,CAAA;AAEhG,eAAO,MAAM,gBAAgB,OAAO,CAAA;AAEpC,sEAAsE;AACtE,wBAAgB,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAU3C;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAK3D;AAED,kGAAkG;AAClG,wBAAsB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAWvE;AAED,MAAM,WAAW,UAAU;IACzB,wEAAwE;IACxE,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,YAAY,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;CACzD;AAED,wBAAsB,MAAM,CAAC,IAAI,EAAE,UAAU,EAAE,EAAE,EAAE,SAAS,EAAE,OAAO,GAAE,UAAe,GAAG,OAAO,CAAC,MAAM,CAAC,CAevG;AAED,eAAO,MAAM,GAAG,EAAE,OAajB,CAAA"}
@@ -0,0 +1,79 @@
1
+ /**
2
+ * `pwf run <dir|file.pwapp>` — serve a built pwapp locally.
3
+ */
4
+ import { readFile, stat } from 'node:fs/promises';
5
+ import { join } from 'node:path';
6
+ import { readPwpack } from '@pwfabric/pack';
7
+ import { guard, stringFlag, UsageError } from './lib/flags.js';
8
+ import { resolveFrom } from './lib/project.js';
9
+ import { startStaticServer } from './lib/static-server.js';
10
+ export const DEFAULT_RUN_PORT = 4700;
11
+ /** Resolves when the process is asked to stop (Ctrl-C or SIGTERM). */
12
+ export function untilSignal() {
13
+ return new Promise((done) => {
14
+ const stop = () => {
15
+ process.off('SIGINT', stop);
16
+ process.off('SIGTERM', stop);
17
+ done();
18
+ };
19
+ process.on('SIGINT', stop);
20
+ process.on('SIGTERM', stop);
21
+ });
22
+ }
23
+ export function parsePort(value) {
24
+ if (value === undefined)
25
+ return DEFAULT_RUN_PORT;
26
+ const port = Number(value);
27
+ if (!/^\d+$/.test(value) || port > 65535)
28
+ throw new UsageError(`--port "${value}" is not a port number`);
29
+ return port;
30
+ }
31
+ /** The source to serve: a folder with an `index.html`, or a `.pwapp` archive opened in memory. */
32
+ export async function openRunSource(path) {
33
+ const st = await stat(path).catch(() => null);
34
+ if (!st)
35
+ throw new Error(`no such file or folder: ${path}`);
36
+ if (st.isDirectory()) {
37
+ const index = await stat(join(path, 'index.html')).catch(() => null);
38
+ if (!index?.isFile())
39
+ throw new Error(`${path} has no index.html; build the app first (pwf build)`);
40
+ return { dir: path };
41
+ }
42
+ const { files } = await readPwpack(new Uint8Array(await readFile(path)));
43
+ if (!files.has('index.html'))
44
+ throw new Error(`${path} has no index.html at its root; it is not a built pwapp`);
45
+ return { files };
46
+ }
47
+ export async function runRun(args, io, options = {}) {
48
+ const target = args.positionals[0];
49
+ if (target === undefined)
50
+ throw new UsageError('missing <dir|file.pwapp>');
51
+ const port = parsePort(stringFlag(args, 'port'));
52
+ const hostname = stringFlag(args, 'host') ?? '127.0.0.1';
53
+ const source = await openRunSource(resolveFrom(io.cwd, target));
54
+ const server = await startStaticServer({ source, port, hostname });
55
+ io.out(`Serving ${target} at ${server.url}`);
56
+ io.out('Press Ctrl-C to stop.');
57
+ try {
58
+ await (options.until ?? untilSignal)(server);
59
+ }
60
+ finally {
61
+ await server.close();
62
+ }
63
+ return 0;
64
+ }
65
+ export const run = {
66
+ name: 'run',
67
+ summary: 'Serve a built pwapp (folder or .pwapp) on a local port',
68
+ usage: `pwf run <dir|file.pwapp> [--port <n>] [--host <name>]
69
+
70
+ <dir> a built pwapp folder with an index.html (see pwf build)
71
+ <file.pwapp> a packaged pwapp (gzipped tar, read like a .pwpack), served from memory
72
+ --port <n> port to listen on (default ${DEFAULT_RUN_PORT}; 0 picks a free one)
73
+ --host <name> interface to bind (default 127.0.0.1)
74
+
75
+ Page paths without a file extension are answered with index.html, so
76
+ path-routed apps work; a missing asset is a 404.`,
77
+ run: (args, io) => guard('run', io, () => runRun(args, io)),
78
+ };
79
+ //# sourceMappingURL=run.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run.js","sourceRoot":"","sources":["../../src/commands/run.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * The contract every `pwf` command implements.
3
+ *
4
+ * A command is a plain object registered in ./registry.ts. It never calls
5
+ * `process.exit` and never writes to `process.stdout` directly: it writes
6
+ * through the `io` it is given and returns an exit code. That keeps every
7
+ * command testable in-process.
8
+ */
9
+ export interface CommandIO {
10
+ /** Working directory the command runs in (absolute). */
11
+ readonly cwd: string;
12
+ /** Normal output. */
13
+ out(line: string): void;
14
+ /** Diagnostics and errors. */
15
+ err(line: string): void;
16
+ /** Environment variables visible to the command. */
17
+ readonly env: Readonly<Record<string, string | undefined>>;
18
+ }
19
+ export interface ParsedArgs {
20
+ /** Positional arguments after the command name. */
21
+ readonly positionals: readonly string[];
22
+ /** `--flag value` and `--flag=value` become strings; bare `--flag` becomes true. */
23
+ readonly flags: Readonly<Record<string, string | boolean>>;
24
+ }
25
+ export interface Command {
26
+ /** The word after `pwf`, e.g. `create`. */
27
+ readonly name: string;
28
+ /** One line shown by `pwf help`. */
29
+ readonly summary: string;
30
+ /** Usage line, e.g. `pwf create <name> [--dir <path>]`. */
31
+ readonly usage: string;
32
+ /** Runs the command. Resolves to the process exit code (0 = success). */
33
+ run(args: ParsedArgs, io: CommandIO): Promise<number>;
34
+ }
35
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/commands/types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,MAAM,WAAW,SAAS;IACxB,wDAAwD;IACxD,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,qBAAqB;IACrB,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;IACvB,8BAA8B;IAC9B,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;IACvB,oDAAoD;IACpD,QAAQ,CAAC,GAAG,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,CAAA;CAC3D;AAED,MAAM,WAAW,UAAU;IACzB,mDAAmD;IACnD,QAAQ,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,CAAA;IACvC,oFAAoF;IACpF,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAA;CAC3D;AAED,MAAM,WAAW,OAAO;IACtB,2CAA2C;IAC3C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,oCAAoC;IACpC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,2DAA2D;IAC3D,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,yEAAyE;IACzE,GAAG,CAAC,IAAI,EAAE,UAAU,EAAE,EAAE,EAAE,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;CACtD"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * The contract every `pwf` command implements.
3
+ *
4
+ * A command is a plain object registered in ./registry.ts. It never calls
5
+ * `process.exit` and never writes to `process.stdout` directly: it writes
6
+ * through the `io` it is given and returns an exit code. That keeps every
7
+ * command testable in-process.
8
+ */
9
+ export {};
10
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/commands/types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * `pwf validate [dir]` — checks a pwpack folder and its pinned packs.
3
+ */
4
+ import type { Command, CommandIO, ParsedArgs } from './types.js';
5
+ export declare function runValidate(args: ParsedArgs, io: CommandIO): Promise<number>;
6
+ export declare const validate: Command;
7
+ //# sourceMappingURL=validate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../src/commands/validate.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAKhE,wBAAsB,WAAW,CAAC,IAAI,EAAE,UAAU,EAAE,EAAE,EAAE,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,CAalF;AAED,eAAO,MAAM,QAAQ,EAAE,OAYtB,CAAA"}
@@ -0,0 +1,33 @@
1
+ import { boolFlag, guard } from './lib/flags.js';
2
+ import { readProject, resolveFrom } from './lib/project.js';
3
+ import { countLine, printIssues, validateProject } from './lib/report.js';
4
+ export async function runValidate(args, io) {
5
+ const root = resolveFrom(io.cwd, args.positionals[0]);
6
+ const result = await validateProject(root, await readProject(root));
7
+ if (boolFlag(args, 'json')) {
8
+ io.out(JSON.stringify(result, null, 2));
9
+ return result.ok ? 0 : 1;
10
+ }
11
+ const who = result.identity ? `${result.identity.id}@${result.identity.version}` : root;
12
+ printIssues(io, result.issues);
13
+ const summary = `${who}: ${result.ok ? 'valid' : 'invalid'} (${countLine(result.issues)}; layout ${result.layout}; ${result.atoms.length} atoms)`;
14
+ if (result.ok)
15
+ io.out(summary);
16
+ else
17
+ io.err(summary);
18
+ return result.ok ? 0 : 1;
19
+ }
20
+ export const validate = {
21
+ name: 'validate',
22
+ summary: 'Check a pwpack folder and the packs it pins',
23
+ usage: `pwf validate [dir] [--json]
24
+
25
+ dir the pwpack folder (default: the current folder)
26
+ --json print the raw result (ok, issues, identity, layout, atoms)
27
+
28
+ Every packs[] pin is looked up in .pwf/packs/<id>@<version>/: a build that is
29
+ not there is a warning, one whose content hash differs from the pin is an
30
+ error. Exit code 1 when there is any error, 0 otherwise.`,
31
+ run: (args, io) => guard('validate', io, () => runValidate(args, io)),
32
+ };
33
+ //# sourceMappingURL=validate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate.js","sourceRoot":"","sources":["../../src/commands/validate.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAA;AAChD,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAC3D,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAEzE,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,IAAgB,EAAE,EAAa;IAC/D,MAAM,IAAI,GAAG,WAAW,CAAC,EAAE,CAAC,GAAG,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAA;IACrD,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC,IAAI,EAAE,MAAM,WAAW,CAAC,IAAI,CAAC,CAAC,CAAA;IACnE,IAAI,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,CAAC;QAC3B,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAA;QACvC,OAAO,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;IAC1B,CAAC;IACD,MAAM,GAAG,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,QAAQ,CAAC,EAAE,IAAI,MAAM,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,IAAI,CAAA;IACvF,WAAW,CAAC,EAAE,EAAE,MAAM,CAAC,MAAM,CAAC,CAAA;IAC9B,MAAM,OAAO,GAAG,GAAG,GAAG,KAAK,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,KAAK,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,YAAY,MAAM,CAAC,MAAM,KAAK,MAAM,CAAC,KAAK,CAAC,MAAM,SAAS,CAAA;IACjJ,IAAI,MAAM,CAAC,EAAE;QAAE,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;;QACzB,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;IACpB,OAAO,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;AAC1B,CAAC;AAED,MAAM,CAAC,MAAM,QAAQ,GAAY;IAC/B,IAAI,EAAE,UAAU;IAChB,OAAO,EAAE,6CAA6C;IACtD,KAAK,EAAE;;;;;;;yDAOgD;IACvD,GAAG,EAAE,CAAC,IAAI,EAAE,EAAE,EAAE,EAAE,CAAC,KAAK,CAAC,UAAU,EAAE,EAAE,EAAE,GAAG,EAAE,CAAC,WAAW,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;CACtE,CAAA"}
@@ -0,0 +1,48 @@
1
+ import { type CompileCache, type CompiledAtom } from './compile.js';
2
+ import { type AssembleDiagnostic } from './diagnostics.js';
3
+ import { type RuntimeAssets } from './shell.js';
4
+ import { type PackMemo } from './sources.js';
5
+ export interface AssembleOptions {
6
+ /** Markup appended to the shell's `<body>` — the dev server's reload client. Absent in a build. */
7
+ readonly shellExtra?: string;
8
+ /** Envelope files a local host adds (see `LocalHost.envelopeEntries`). */
9
+ readonly envelopeEntries?: Readonly<Record<string, unknown>>;
10
+ /** A compile cache to reuse across builds; default: one on disk under `.pwf/build-cache/`. */
11
+ readonly cache?: CompileCache;
12
+ /** Folder of the on-disk compile cache; `null` keeps it in memory only. */
13
+ readonly cacheDir?: string | null;
14
+ /** `publish.json`'s `publishedAt`; default now. */
15
+ readonly publishedAt?: string;
16
+ /** Runner and renderer bundles; default: the installed engine packages. */
17
+ readonly runtime?: RuntimeAssets;
18
+ /** Pack builds read by an earlier build of the same session. */
19
+ readonly packMemo?: PackMemo;
20
+ }
21
+ export interface AssembleStats {
22
+ readonly pages: number;
23
+ /** Entries in `blocks/manifest.json`. */
24
+ readonly blocks: number;
25
+ /** Entries in `engines/manifest.json`. */
26
+ readonly engines: number;
27
+ /** Atoms of a compiled kind across the app and its packs. */
28
+ readonly atoms: number;
29
+ /** Of those, how many have a module (compiled or shipped precompiled). */
30
+ readonly compiled: number;
31
+ /** Of the compiled, how many came from the cache. */
32
+ readonly fromCache: number;
33
+ readonly failed: number;
34
+ }
35
+ export interface AssembleResult {
36
+ /** No diagnostic is an error. */
37
+ readonly ok: boolean;
38
+ /** The served folder: POSIX path → bytes. Filled as far as the build got, even when not `ok`. */
39
+ readonly files: Map<string, Uint8Array>;
40
+ readonly diagnostics: readonly AssembleDiagnostic[];
41
+ readonly stats: AssembleStats;
42
+ readonly ms: number;
43
+ }
44
+ /** Every name a block atom answers to in a receipt: its id, its manifest name, and its short forms. */
45
+ export declare function blockNames(atom: Pick<CompiledAtom, 'id' | 'manifest'>): string[];
46
+ /** Assembles the pwapp for the app folder at `root`. */
47
+ export declare function assemblePwapp(root: string, options?: AssembleOptions): Promise<AssembleResult>;
48
+ //# sourceMappingURL=assemble.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assemble.d.ts","sourceRoot":"","sources":["../../src/dev/assemble.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAsC,KAAK,YAAY,EAAE,KAAK,YAAY,EAAE,MAAM,cAAc,CAAA;AACvG,OAAO,EAA8B,KAAK,kBAAkB,EAAE,MAAM,kBAAkB,CAAA;AAetF,OAAO,EAQL,KAAK,aAAa,EACnB,MAAM,YAAY,CAAA;AACnB,OAAO,EAA0C,KAAK,QAAQ,EAAmB,MAAM,cAAc,CAAA;AAWrG,MAAM,WAAW,eAAe;IAC9B,mGAAmG;IACnG,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAA;IAC5B,0EAA0E;IAC1E,QAAQ,CAAC,eAAe,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAA;IAC5D,8FAA8F;IAC9F,QAAQ,CAAC,KAAK,CAAC,EAAE,YAAY,CAAA;IAC7B,2EAA2E;IAC3E,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACjC,mDAAmD;IACnD,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAA;IAC7B,2EAA2E;IAC3E,QAAQ,CAAC,OAAO,CAAC,EAAE,aAAa,CAAA;IAChC,gEAAgE;IAChE,QAAQ,CAAC,QAAQ,CAAC,EAAE,QAAQ,CAAA;CAC7B;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,yCAAyC;IACzC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,0CAA0C;IAC1C,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,6DAA6D;IAC7D,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,0EAA0E;IAC1E,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,qDAAqD;IACrD,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CACxB;AAED,MAAM,WAAW,cAAc;IAC7B,iCAAiC;IACjC,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAA;IACpB,iGAAiG;IACjG,QAAQ,CAAC,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAA;IACvC,QAAQ,CAAC,WAAW,EAAE,SAAS,kBAAkB,EAAE,CAAA;IACnD,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAA;IAC7B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;CACpB;AAMD,uGAAuG;AACvG,wBAAgB,UAAU,CAAC,IAAI,EAAE,IAAI,CAAC,YAAY,EAAE,IAAI,GAAG,UAAU,CAAC,GAAG,MAAM,EAAE,CAQhF;AAkBD,wDAAwD;AACxD,wBAAsB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,eAAoB,GAAG,OAAO,CAAC,cAAc,CAAC,CA6RxG"}
@@ -0,0 +1,339 @@
1
+ /**
2
+ * assemblePwapp — a pwpack app folder in, a static pwapp out.
3
+ *
4
+ * Reads the app and the pack builds it pins (from the project's cache),
5
+ * compiles every block, capability and engine atom with the engine's
6
+ * compiler, resolves the app's theme, builds the envelope the runner reads,
7
+ * and lays out the served folder of the pwapp format: shell, runner,
8
+ * renderer, shims, block and engine modules, envelope and `publish.json`.
9
+ *
10
+ * Pure in its output: the same folder, cache and runtime bundles give the
11
+ * same files (only `publish.json`'s `publishedAt` carries a clock, and it can
12
+ * be pinned). Nothing is fetched; every input is on disk.
13
+ */
14
+ import { join } from 'node:path';
15
+ import { hashPack } from '@pwfabric/pack';
16
+ import { atomKindMeta } from '@pwfabric/contracts';
17
+ import { compileSources, createCompileCache } from './compile.js';
18
+ import { hasErrors, sortDiagnostics } from './diagnostics.js';
19
+ import { blockTypesOf, buildConnections, buildProjectJson, deriveNavigation, mergeEnvelopeEntries, moduleFileName, publisherOf, } from './envelope.js';
20
+ import { collectMedia, fillMediaSlots } from './media.js';
21
+ import { deriveCsp, headersFile } from './csp.js';
22
+ import { bootScript, buildShellHtml, importMapText, loadRuntimeAssets, runnerLocaleOf, seedScript, shimsFor, } from './shell.js';
23
+ import { isRecord, jsonOf, loadSources, PWF_DIR } from './sources.js';
24
+ import { appearanceConfigOf, buildThemeCss, resolveAppearance, themeAtomOf, themeWebfonts, webfontStylesheetHref, } from './theme.js';
25
+ const enc = new TextEncoder();
26
+ const json = (value) => enc.encode(JSON.stringify(value, null, 2));
27
+ const hexOf = (hash) => hash.replace(/^sha256:/, '');
28
+ /** Every name a block atom answers to in a receipt: its id, its manifest name, and its short forms. */
29
+ export function blockNames(atom) {
30
+ const names = new Set([atom.id]);
31
+ const name = atom.manifest?.['name'];
32
+ if (typeof name === 'string' && name)
33
+ names.add(name);
34
+ const dot = atom.id.indexOf('.');
35
+ if (dot >= 0)
36
+ names.add(atom.id.slice(dot + 1));
37
+ names.add(atom.id.slice(atom.id.lastIndexOf('.') + 1));
38
+ return [...names];
39
+ }
40
+ function titleOf(plan, id) {
41
+ if (isRecord(plan) && typeof plan['title'] === 'string' && plan['title'].trim())
42
+ return plan['title'].trim();
43
+ const last = id.split('/').pop() ?? id;
44
+ return last
45
+ .split(/[-_]+/)
46
+ .filter(Boolean)
47
+ .map((w) => w[0].toUpperCase() + w.slice(1))
48
+ .join(' ');
49
+ }
50
+ function atomLabel(atom) {
51
+ return atom.source.origin === 'app' ? atom.id : `${atom.id} (${atom.source.id}@${atom.source.version})`;
52
+ }
53
+ const EMPTY_STATS = { pages: 0, blocks: 0, engines: 0, atoms: 0, compiled: 0, fromCache: 0, failed: 0 };
54
+ /** Assembles the pwapp for the app folder at `root`. */
55
+ export async function assemblePwapp(root, options = {}) {
56
+ const started = performance.now();
57
+ const diagnostics = [];
58
+ const files = new Map();
59
+ const done = (stats) => {
60
+ const sorted = sortDiagnostics(diagnostics);
61
+ return { ok: !hasErrors(sorted), files, diagnostics: sorted, stats, ms: Math.round(performance.now() - started) };
62
+ };
63
+ const sources = await loadSources(root, options.packMemo);
64
+ diagnostics.push(...sources.diagnostics);
65
+ const { app, identity } = sources;
66
+ if (!app || !identity)
67
+ return done(EMPTY_STATS);
68
+ if (!identity.app) {
69
+ diagnostics.push({
70
+ severity: 'error',
71
+ code: 'NOT_AN_APP',
72
+ message: 'pwpack.json declares no "app" member, so this folder is a pack, not an app — there is nothing to run',
73
+ path: 'pwpack.json',
74
+ });
75
+ return done(EMPTY_STATS);
76
+ }
77
+ // ── pages ────────────────────────────────────────────────────────
78
+ const reported = new Set(diagnostics.map((d) => d.path));
79
+ const pages = [];
80
+ for (const key of identity.app.surfaceOrder) {
81
+ const path = `app/surfaces/${key}.receipt.json`;
82
+ const bytes = app.folder.files.get(path);
83
+ const value = jsonOf(app.folder, path);
84
+ if (!bytes) {
85
+ if (!reported.has(path)) {
86
+ diagnostics.push({ severity: 'error', code: 'RECEIPT_MISSING', message: `page "${key}" is in app.surfaceOrder but ${path} does not exist`, path });
87
+ }
88
+ continue;
89
+ }
90
+ if (value instanceof Error || !isRecord(value) || !Array.isArray(value['blocks'])) {
91
+ diagnostics.push({
92
+ severity: 'error',
93
+ code: 'RECEIPT_INVALID',
94
+ message: value instanceof Error ? `not JSON: ${value.message}` : 'a receipt is an object with a "blocks" array',
95
+ path,
96
+ });
97
+ continue;
98
+ }
99
+ pages.push({ key, path, bytes, receipt: value });
100
+ }
101
+ const entry = identity.app.entry;
102
+ if (!identity.app.surfaceOrder.includes(entry)) {
103
+ diagnostics.push({ severity: 'error', code: 'ENTRY_NOT_A_PAGE', message: `app.entry "${entry}" is not in app.surfaceOrder`, path: 'pwpack.json' });
104
+ }
105
+ // ── definitions ──────────────────────────────────────────────────
106
+ const definition = (name) => {
107
+ const path = `app/definitions/${name}.json`;
108
+ const value = jsonOf(app.folder, path);
109
+ if (value instanceof Error) {
110
+ diagnostics.push({ severity: 'error', code: 'DEFINITION_INVALID', message: `not JSON: ${value.message}`, path });
111
+ return undefined;
112
+ }
113
+ return value;
114
+ };
115
+ const navigationDoc = definition('navigation');
116
+ const appearanceDoc = definition('appearance');
117
+ const connectionsDoc = definition('connections');
118
+ const authDoc = definition('auth');
119
+ const plan = jsonOf(app.folder, 'app/plan.json');
120
+ // ── compile ──────────────────────────────────────────────────────
121
+ const all = [app, ...sources.packs];
122
+ const cache = options.cache ?? createCompileCache(options.cacheDir === undefined ? join(root, PWF_DIR, 'build-cache') : options.cacheDir);
123
+ const atoms = await compileSources(all, cache);
124
+ // ── themes ───────────────────────────────────────────────────────
125
+ const themes = [];
126
+ for (const source of all) {
127
+ for (const ref of source.validation.atoms) {
128
+ if (ref.kind !== 'ui-appearance')
129
+ continue;
130
+ const theme = themeAtomOf(ref.id, jsonOf(source.folder, ref.relPath), source.label || source.id);
131
+ if (theme)
132
+ themes.push(theme);
133
+ }
134
+ }
135
+ const appearance = resolveAppearance(appearanceDoc, themes, diagnostics);
136
+ // ── blocks ───────────────────────────────────────────────────────
137
+ const byName = new Map();
138
+ for (const atom of atoms) {
139
+ if (atom.kind !== 'block')
140
+ continue;
141
+ for (const name of blockNames(atom)) {
142
+ const list = byName.get(name) ?? [];
143
+ if (!list.includes(atom))
144
+ list.push(atom);
145
+ byName.set(name, list);
146
+ }
147
+ }
148
+ const used = new Set();
149
+ const blockManifest = [];
150
+ const modules = new Map();
151
+ const firstUse = new Map();
152
+ for (const page of pages)
153
+ for (const t of blockTypesOf(page.receipt))
154
+ if (!firstUse.has(t))
155
+ firstUse.set(t, page);
156
+ for (const [type, page] of [...firstUse].sort((a, b) => (a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : 0))) {
157
+ const candidates = byName.get(type) ?? [];
158
+ const atom = candidates[0];
159
+ if (!atom) {
160
+ diagnostics.push({
161
+ severity: 'error',
162
+ code: 'UNKNOWN_BLOCK_TYPE',
163
+ message: `page "${page.key}" places a block of type "${type}", which neither the app nor its pinned packs define`,
164
+ path: page.path,
165
+ });
166
+ continue;
167
+ }
168
+ used.add(atom);
169
+ if (candidates.length > 1) {
170
+ diagnostics.push({
171
+ severity: 'info',
172
+ code: 'BLOCK_TYPE_SHADOWED',
173
+ message: `block type "${type}" resolves to ${atomLabel(atom)}; also defined by ${candidates.slice(1).map(atomLabel).join(', ')}`,
174
+ path: page.path,
175
+ });
176
+ }
177
+ if (!atom.code || !atom.hash) {
178
+ diagnostics.push({
179
+ severity: 'error',
180
+ code: 'BLOCK_NOT_COMPILED',
181
+ message: `block type "${type}" (${atomLabel(atom)}) did not compile (see the compile errors reported for ${atom.relPath})`,
182
+ path: page.path,
183
+ });
184
+ continue;
185
+ }
186
+ const file = `blocks/${moduleFileName(type, hexOf(atom.hash))}`;
187
+ modules.set(file, enc.encode(atom.code));
188
+ blockManifest.push({
189
+ blockType: type,
190
+ moduleUrl: file,
191
+ integrity: hexOf(atom.hash),
192
+ publisher: publisherOf(atom.source.id),
193
+ publisherVerified: false,
194
+ definition: { name: type },
195
+ });
196
+ }
197
+ // ── engines ──────────────────────────────────────────────────────
198
+ const connections = buildConnections(connectionsDoc, diagnostics);
199
+ const engineManifest = [];
200
+ for (const conn of connections?.connections ?? []) {
201
+ const name = conn['name'];
202
+ const wanted = typeof conn['connector'] === 'string' ? conn['connector'] : name;
203
+ const atom = atoms.find((a) => (a.kind === 'connector' || a.kind === 'provider') && a.manifest?.['connection'] === wanted);
204
+ if (!atom)
205
+ continue;
206
+ used.add(atom);
207
+ const kind = atom.kind;
208
+ if (atom.code && atom.hash) {
209
+ const file = `engines/${moduleFileName(atom.id, hexOf(atom.hash))}`;
210
+ modules.set(file, enc.encode(atom.code));
211
+ engineManifest.push({ connection: name, atomId: atom.id, kind, moduleUrl: file, integrity: hexOf(atom.hash) });
212
+ }
213
+ else if (atom.manifest?.['engine'] !== undefined) {
214
+ engineManifest.push({ connection: name, atomId: atom.id, kind, engine: atom.manifest['engine'] });
215
+ }
216
+ else if (atom.status === 'failed') {
217
+ diagnostics.push({
218
+ severity: 'warning',
219
+ code: 'ENGINE_NOT_COMPILED',
220
+ message: `connection "${name}": engine ${atomLabel(atom)} did not compile, so its panels fall back to sample data`,
221
+ path: 'app/definitions/connections.json',
222
+ });
223
+ }
224
+ }
225
+ // ── atom diagnostics ─────────────────────────────────────────────
226
+ // The app's own atoms and the atoms it uses speak at full volume; an unused
227
+ // atom of a pinned pack cannot break this app, so its errors are warnings.
228
+ for (const atom of atoms) {
229
+ const loud = atom.source.origin === 'app' || used.has(atom);
230
+ for (const d of atom.diagnostics) {
231
+ const engineDegrades = atomKindMeta(atom.kind).onFailure === 'degrade';
232
+ diagnostics.push(loud && !engineDegrades ? d : d.severity === 'error' ? { ...d, severity: 'warning' } : d);
233
+ }
234
+ }
235
+ // ── the served folder ────────────────────────────────────────────
236
+ const runtime = options.runtime ?? (await loadRuntimeAssets());
237
+ const config = appearanceConfigOf(appearance);
238
+ const title = titleOf(plan, identity.id);
239
+ const locale = isRecord(plan) && typeof plan['locale'] === 'string' ? plan['locale'] : undefined;
240
+ const shell = (csp) => enc.encode(buildShellHtml({
241
+ title,
242
+ ...(locale !== undefined ? { lang: locale } : {}),
243
+ ...(config ? { appearance: config } : {}),
244
+ ...(options.shellExtra !== undefined ? { bodyExtra: options.shellExtra } : {}),
245
+ ...(csp !== undefined ? { csp } : {}),
246
+ }));
247
+ // Written again with its policy once everything the policy reads is known.
248
+ files.set('index.html', shell());
249
+ files.set('assets/seed.js', enc.encode(seedScript()));
250
+ files.set('assets/boot.js', enc.encode(bootScript(runnerLocaleOf(locale))));
251
+ files.set('assets/runner.js', enc.encode(runtime.runnerJs));
252
+ if (runtime.runnerMap !== undefined)
253
+ files.set('assets/runner.js.map', enc.encode(runtime.runnerMap));
254
+ files.set('assets/embed.js', enc.encode(runtime.embedJs));
255
+ files.set('assets/theme.css', enc.encode(buildThemeCss(config)));
256
+ for (const [name, source] of await shimsFor(runtime.embedJs))
257
+ files.set(`shims/${name}`, enc.encode(source));
258
+ for (const [file, bytes] of [...modules].sort((a, b) => (a[0] < b[0] ? -1 : 1)))
259
+ files.set(file, bytes);
260
+ files.set('blocks/manifest.json', json(blockManifest));
261
+ files.set('engines/manifest.json', json(engineManifest));
262
+ files.set('pwpack/project.json', json(buildProjectJson({ id: identity.id, title, entry, pages, auth: authDoc })));
263
+ for (const page of pages)
264
+ files.set(`pwpack/surfaces/${page.key}.receipt.json`, page.bytes);
265
+ files.set('pwpack/navigation.json', json(isRecord(navigationDoc) ? navigationDoc : deriveNavigation(pages, entry)));
266
+ if (appearance)
267
+ files.set('pwpack/appearance.json', json(appearance));
268
+ // Always written: the runner asks for it on every boot, and an app that
269
+ // declares no connection should not cost the visitor a 404 in the console.
270
+ files.set('pwpack/connections.json', json(connections ?? { connections: [] }));
271
+ const media = collectMedia(app.folder, diagnostics);
272
+ for (const [file, bytes] of media.files)
273
+ files.set(`pwpack/${file}`, bytes);
274
+ mergeEnvelopeEntries(files, options.envelopeEntries, diagnostics);
275
+ // After the host's entries, so a receipt the host rewrote gets its media too.
276
+ for (const page of pages) {
277
+ const path = `pwpack/surfaces/${page.key}.receipt.json`;
278
+ const filled = fillMediaSlots(files.get(path), media.slots.get(page.key));
279
+ if (filled)
280
+ files.set(path, filled);
281
+ }
282
+ // ── the Content Security Policy ──────────────────────────────────
283
+ const servedReceipts = new Map();
284
+ for (const page of pages) {
285
+ const bytes = files.get(`pwpack/surfaces/${page.key}.receipt.json`);
286
+ try {
287
+ servedReceipts.set(page.key, bytes ? JSON.parse(new TextDecoder().decode(bytes)) : page.receipt);
288
+ }
289
+ catch {
290
+ servedReceipts.set(page.key, page.receipt);
291
+ }
292
+ }
293
+ const envelopeAuthBytes = files.get('pwpack/auth.json');
294
+ const csp = deriveCsp({
295
+ importMapText: importMapText(),
296
+ receipts: servedReceipts,
297
+ connections,
298
+ engines: engineManifest,
299
+ envelopeAuth: envelopeAuthBytes ? JSON.parse(new TextDecoder().decode(envelopeAuthBytes)) : undefined,
300
+ authDefinition: authDoc,
301
+ media: media.records,
302
+ webfontHref: webfontStylesheetHref(themeWebfonts(config)),
303
+ });
304
+ files.set('index.html', shell(csp.meta));
305
+ files.set('_headers', enc.encode(headersFile(csp.header)));
306
+ const publishedAtoms = atoms
307
+ .filter((a) => used.has(a))
308
+ .map((a) => {
309
+ const module = blockManifest.find((b) => b.integrity === (a.hash ? hexOf(a.hash) : ''))?.moduleUrl ??
310
+ engineManifest.find((e) => e.atomId === a.id && e.moduleUrl)?.moduleUrl;
311
+ return {
312
+ kind: a.kind,
313
+ id: a.id,
314
+ hash: a.sourceHash,
315
+ ...(module && a.hash ? { module, integrity: hexOf(a.hash) } : {}),
316
+ };
317
+ });
318
+ files.set('publish.json', json({
319
+ formatVersion: '1.0',
320
+ app: { id: identity.id, version: identity.version },
321
+ liveVersion: identity.version,
322
+ publishedAt: options.publishedAt ?? new Date().toISOString(),
323
+ packs: sources.packs.map((p) => ({ id: p.id, version: p.version, hash: p.pinnedHash ?? hashPack(p.folder) })),
324
+ atoms: publishedAtoms,
325
+ ...(media.records.length > 0 ? { media: media.records } : {}),
326
+ csp: { policy: csp.header, ...(csp.unresolved.length > 0 ? { unresolved: csp.unresolved } : {}) },
327
+ }));
328
+ const compiled = atoms.filter((a) => a.status === 'compiled' || a.status === 'precompiled');
329
+ return done({
330
+ pages: pages.length,
331
+ blocks: blockManifest.length,
332
+ engines: engineManifest.length,
333
+ atoms: atoms.length,
334
+ compiled: compiled.length,
335
+ fromCache: compiled.filter((a) => a.fromCache).length,
336
+ failed: atoms.filter((a) => a.status === 'failed').length,
337
+ });
338
+ }
339
+ //# sourceMappingURL=assemble.js.map