@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,229 @@
1
+ /**
2
+ * The app's own records, in memory (data-protocol §5).
3
+ *
4
+ * One collection per entity type declared in `app/definitions/entities.json`,
5
+ * seeded on first use from `app/data/` (see `readSeed`). A record is
6
+ * `{ …fields, id, entityType, createdAt, updatedAt }`, fields spread at the
7
+ * top level like the reference server's.
8
+ *
9
+ * ACCESS, read off the declarations — a deliberately small version of what a
10
+ * hosted session server decides:
11
+ *
12
+ * - `auth.json` `required: true`: every data request needs a session
13
+ * (`401 SIGN_IN_REQUIRED`).
14
+ * - A collection is OWNER-SCOPED when an `access.rules[]` entry names it and
15
+ * is not a public read grant (subject `public`/`anyone`/`visitors`/…, a
16
+ * rule that grants reading and does not say "own"), when the entity
17
+ * declares an owner field (`owner`, `ownerId`, `userId`, `createdBy`, …),
18
+ * or when the entity carries `"scope": "owner"`. An owner-scoped collection
19
+ * needs a session, lists only the caller's rows, and answers another
20
+ * visitor's row as `404`.
21
+ * - Every other collection is shared by the whole app: anyone may read and
22
+ * write it.
23
+ */
24
+ import { randomUUID } from 'node:crypto';
25
+ import { HostError } from './http.js';
26
+ import { readSeed } from './definitions.js';
27
+ import { aggregate, matches, parseFilter, parseSort, sortRows } from './query.js';
28
+ const PUBLIC_SUBJECTS = new Set([
29
+ 'public',
30
+ 'anyone',
31
+ 'anybody',
32
+ 'everyone',
33
+ 'everybody',
34
+ 'all',
35
+ 'visitor',
36
+ 'visitors',
37
+ 'guest',
38
+ 'guests',
39
+ 'anonymous',
40
+ '*',
41
+ ]);
42
+ const READ_VERB = /\b(read|reads|see|sees|view|views|list|lists|browse|browses)\b/i;
43
+ const OWN_WORD = /\b(own|their|his|her|only)\b/i;
44
+ const OWNER_FIELDS = new Set([
45
+ 'owner',
46
+ 'ownerid',
47
+ 'createdby',
48
+ 'createdbyid',
49
+ 'userid',
50
+ 'memberid',
51
+ 'authorid',
52
+ 'principalid',
53
+ 'accountid',
54
+ ]);
55
+ const RESERVED = new Set(['id', 'entityType', 'createdAt', 'updatedAt', '__proto__', 'constructor', 'prototype']);
56
+ const norm = (s) => s.toLowerCase().replace(/[\s_-]/g, '');
57
+ function ownerFieldOf(entity) {
58
+ return entity.fields.find((f) => OWNER_FIELDS.has(norm(f.name)))?.name;
59
+ }
60
+ export function scopeOf(entity, auth) {
61
+ const names = new Set([norm(entity.typeId), ...(entity.displayName ? [norm(entity.displayName)] : [])]);
62
+ const rules = (auth?.access.rules ?? []).filter((r) => names.has(norm(r.model)));
63
+ const publicGrant = rules.some((r) => PUBLIC_SUBJECTS.has(r.subject.trim().toLowerCase()) && READ_VERB.test(r.rule) && !OWN_WORD.test(r.rule));
64
+ if (publicGrant)
65
+ return 'project';
66
+ if (rules.length > 0 || ownerFieldOf(entity) !== undefined || entity.scope === 'owner')
67
+ return 'owner';
68
+ return 'project';
69
+ }
70
+ const isEmpty = (v) => v === undefined || v === null || v === '';
71
+ export class RecordStore {
72
+ root;
73
+ devUser;
74
+ collections = new Map();
75
+ clock = 0;
76
+ constructor(root, devUser) {
77
+ this.root = root;
78
+ this.devUser = devUser;
79
+ }
80
+ reset() {
81
+ this.collections.clear();
82
+ this.clock = 0;
83
+ }
84
+ collection(entity) {
85
+ let rows = this.collections.get(entity.typeId);
86
+ if (rows)
87
+ return rows;
88
+ rows = new Map();
89
+ const now = new Date().toISOString();
90
+ const ownerField = ownerFieldOf(entity);
91
+ for (const seed of readSeed(this.root, entity.typeId)) {
92
+ const id = typeof seed.id === 'string' || typeof seed.id === 'number' ? String(seed.id) : randomUUID();
93
+ const declaredOwner = ownerField ? seed[ownerField] : undefined;
94
+ rows.set(id, {
95
+ record: {
96
+ ...seed,
97
+ id,
98
+ entityType: entity.typeId,
99
+ createdAt: typeof seed.createdAt === 'string' ? seed.createdAt : now,
100
+ updatedAt: typeof seed.updatedAt === 'string' ? seed.updatedAt : now,
101
+ },
102
+ // Seed rows belong to the development user unless they name an owner.
103
+ owner: typeof declaredOwner === 'string' && declaredOwner ? declaredOwner : this.devUser.id,
104
+ touched: ++this.clock,
105
+ });
106
+ }
107
+ this.collections.set(entity.typeId, rows);
108
+ return rows;
109
+ }
110
+ /** Refuses a caller the declarations do not let in; answers the collection's scope. */
111
+ guard({ entity, auth, caller }) {
112
+ if (auth?.required && !caller.principal) {
113
+ throw new HostError(401, 'SIGN_IN_REQUIRED', 'Sign in to use this app.');
114
+ }
115
+ const scope = scopeOf(entity, auth);
116
+ if (scope === 'owner' && !caller.principal) {
117
+ throw new HostError(401, 'SIGN_IN_REQUIRED', `Sign in to see your ${entity.displayName ?? entity.typeId} records.`);
118
+ }
119
+ return scope;
120
+ }
121
+ /** The rows this caller may see, newest change first, after `filter`. */
122
+ visible(target, params) {
123
+ const scope = this.guard(target);
124
+ let filter;
125
+ try {
126
+ filter = parseFilter(params.get('filter'));
127
+ }
128
+ catch {
129
+ throw new HostError(400, 'INVALID_QUERY', 'filter must be a JSON filter object.');
130
+ }
131
+ const rows = [...this.collection(target.entity).values()]
132
+ .filter((s) => scope === 'project' || s.owner === target.caller.principal?.id)
133
+ .sort((a, b) => b.touched - a.touched)
134
+ .map((s) => s.record);
135
+ return { scope, rows: filter ? rows.filter((r) => matches(r, filter)) : rows };
136
+ }
137
+ list(target, params) {
138
+ const { scope, rows } = this.visible(target, params);
139
+ const sort = parseSort(params.get('sort'));
140
+ const ordered = sort.length > 0 ? sortRows(rows, sort) : rows;
141
+ const limitRaw = Number(params.get('limit') ?? '100');
142
+ const offsetRaw = Number(params.get('offset') ?? '0');
143
+ const limit = Number.isFinite(limitRaw) ? Math.min(500, Math.max(1, Math.trunc(limitRaw))) : 100;
144
+ const offset = Number.isFinite(offsetRaw) ? Math.max(0, Math.trunc(offsetRaw)) : 0;
145
+ return {
146
+ data: ordered.slice(offset, offset + limit),
147
+ meta: { total: ordered.length, scope, timestamp: new Date().toISOString() },
148
+ };
149
+ }
150
+ /** `/count` (`plainCount`) or `/aggregate?fn&field`. */
151
+ aggregate(target, params, plainCount) {
152
+ const fn = plainCount ? 'count' : params.get('fn');
153
+ if (fn !== 'count' && fn !== 'sum' && fn !== 'avg') {
154
+ throw new HostError(400, 'INVALID_QUERY', 'fn must be count, sum or avg.');
155
+ }
156
+ const field = plainCount ? undefined : (params.get('field') ?? undefined);
157
+ if (fn !== 'count' && !field)
158
+ throw new HostError(400, 'INVALID_QUERY', `${fn} needs a field.`);
159
+ const { scope, rows } = this.visible(target, params);
160
+ return { data: aggregate(rows, fn, field), meta: { scope, timestamp: new Date().toISOString() } };
161
+ }
162
+ find(target, id) {
163
+ const scope = this.guard(target);
164
+ const stored = this.collection(target.entity).get(id);
165
+ if (!stored || (scope === 'owner' && stored.owner !== target.caller.principal?.id)) {
166
+ throw new HostError(404, 'NOT_FOUND', `No ${target.entity.typeId} record "${id}".`);
167
+ }
168
+ return stored;
169
+ }
170
+ read(target, id) {
171
+ return this.find(target, id).record;
172
+ }
173
+ create(target, body) {
174
+ const { entity, caller } = target;
175
+ const scope = this.guard(target);
176
+ const fields = writable(body);
177
+ const ownerField = ownerFieldOf(entity);
178
+ if (scope === 'owner' && ownerField && isEmpty(fields[ownerField]) && caller.principal) {
179
+ fields[ownerField] = caller.principal.id;
180
+ }
181
+ const missing = entity.fields.filter((f) => f.required && isEmpty(fields[f.name])).map((f) => f.name);
182
+ if (missing.length > 0) {
183
+ throw new HostError(400, 'VALIDATION_FAILED', `Missing required field(s): ${missing.join(', ')}.`);
184
+ }
185
+ const now = new Date().toISOString();
186
+ const id = randomUUID();
187
+ const record = { ...fields, id, entityType: entity.typeId, createdAt: now, updatedAt: now };
188
+ this.collection(entity).set(id, { record, owner: caller.principal?.id, touched: ++this.clock });
189
+ return record;
190
+ }
191
+ update(target, id, body) {
192
+ const stored = this.find(target, id);
193
+ const fields = writable(body);
194
+ const cleared = target.entity.fields
195
+ .filter((f) => f.required && f.name in fields && isEmpty(fields[f.name]))
196
+ .map((f) => f.name);
197
+ if (cleared.length > 0) {
198
+ throw new HostError(400, 'VALIDATION_FAILED', `Required field(s) cannot be empty: ${cleared.join(', ')}.`);
199
+ }
200
+ stored.record = {
201
+ ...stored.record,
202
+ ...fields,
203
+ id,
204
+ entityType: target.entity.typeId,
205
+ updatedAt: new Date().toISOString(),
206
+ };
207
+ stored.touched = ++this.clock;
208
+ return stored.record;
209
+ }
210
+ remove(target, id) {
211
+ this.find(target, id);
212
+ this.collection(target.entity).delete(id);
213
+ }
214
+ }
215
+ /** The record itself is the body; a lone `{ data: { … } }` wrapper is unwrapped. Server-owned members are dropped. */
216
+ function writable(body) {
217
+ const keys = Object.keys(body);
218
+ const inner = body.data;
219
+ const source = keys.length === 1 && keys[0] === 'data' && inner && typeof inner === 'object' && !Array.isArray(inner)
220
+ ? inner
221
+ : body;
222
+ const out = {};
223
+ for (const [k, v] of Object.entries(source)) {
224
+ if (!RESERVED.has(k))
225
+ out[k] = v;
226
+ }
227
+ return out;
228
+ }
229
+ //# sourceMappingURL=records.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"records.js","sourceRoot":"","sources":["../../src/host/records.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Opaque tokens, in memory.
3
+ *
4
+ * Every credential the local host hands out — an app session, an issuer
5
+ * access token, a door token, a refresh token, an authorization code — is 32
6
+ * random bytes, base64url. Only its SHA-256 is kept (as a session server
7
+ * should), so even a heap dump of the development server holds no usable
8
+ * token. Expired entries are dropped when they are looked up.
9
+ */
10
+ export interface Principal {
11
+ readonly id: string;
12
+ readonly email: string;
13
+ readonly displayName: string;
14
+ }
15
+ export declare function newToken(): string;
16
+ export declare class TokenStore<T extends {
17
+ readonly expiresAt: number;
18
+ }> {
19
+ private readonly entries;
20
+ /** Mints a token for `entry` and returns it. */
21
+ issue(entry: T): string;
22
+ /** The live entry for `token`, or undefined (unknown or expired). */
23
+ get(token: string | undefined): T | undefined;
24
+ /** Looks the token up and forgets it — single use. */
25
+ take(token: string | undefined): T | undefined;
26
+ revoke(token: string | undefined): void;
27
+ clear(): void;
28
+ }
29
+ //# sourceMappingURL=tokens.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tokens.d.ts","sourceRoot":"","sources":["../../src/host/tokens.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;CAC7B;AAED,wBAAgB,QAAQ,IAAI,MAAM,CAEjC;AAID,qBAAa,UAAU,CAAC,CAAC,SAAS;IAAE,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;CAAE;IAC9D,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAuB;IAE/C,gDAAgD;IAChD,KAAK,CAAC,KAAK,EAAE,CAAC,GAAG,MAAM;IAMvB,qEAAqE;IACrE,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,CAAC,GAAG,SAAS;IAY7C,sDAAsD;IACtD,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,CAAC,GAAG,SAAS;IAM9C,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI;IAIvC,KAAK,IAAI,IAAI;CAGd"}
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Opaque tokens, in memory.
3
+ *
4
+ * Every credential the local host hands out — an app session, an issuer
5
+ * access token, a door token, a refresh token, an authorization code — is 32
6
+ * random bytes, base64url. Only its SHA-256 is kept (as a session server
7
+ * should), so even a heap dump of the development server holds no usable
8
+ * token. Expired entries are dropped when they are looked up.
9
+ */
10
+ import { createHash, randomBytes } from 'node:crypto';
11
+ export function newToken() {
12
+ return randomBytes(32).toString('base64url');
13
+ }
14
+ const digest = (token) => createHash('sha256').update(token).digest('hex');
15
+ export class TokenStore {
16
+ entries = new Map();
17
+ /** Mints a token for `entry` and returns it. */
18
+ issue(entry) {
19
+ const token = newToken();
20
+ this.entries.set(digest(token), entry);
21
+ return token;
22
+ }
23
+ /** The live entry for `token`, or undefined (unknown or expired). */
24
+ get(token) {
25
+ if (!token)
26
+ return undefined;
27
+ const key = digest(token);
28
+ const entry = this.entries.get(key);
29
+ if (!entry)
30
+ return undefined;
31
+ if (entry.expiresAt <= Date.now()) {
32
+ this.entries.delete(key);
33
+ return undefined;
34
+ }
35
+ return entry;
36
+ }
37
+ /** Looks the token up and forgets it — single use. */
38
+ take(token) {
39
+ const entry = this.get(token);
40
+ if (entry && token)
41
+ this.entries.delete(digest(token));
42
+ return entry;
43
+ }
44
+ revoke(token) {
45
+ if (token)
46
+ this.entries.delete(digest(token));
47
+ }
48
+ clear() {
49
+ this.entries.clear();
50
+ }
51
+ }
52
+ //# sourceMappingURL=tokens.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tokens.js","sourceRoot":"","sources":["../../src/host/tokens.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAQrD,MAAM,UAAU,QAAQ;IACtB,OAAO,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAA;AAC9C,CAAC;AAED,MAAM,MAAM,GAAG,CAAC,KAAa,EAAU,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;AAE1F,MAAM,OAAO,UAAU;IACJ,OAAO,GAAG,IAAI,GAAG,EAAa,CAAA;IAE/C,gDAAgD;IAChD,KAAK,CAAC,KAAQ;QACZ,MAAM,KAAK,GAAG,QAAQ,EAAE,CAAA;QACxB,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC,CAAA;QACtC,OAAO,KAAK,CAAA;IACd,CAAC;IAED,qEAAqE;IACrE,GAAG,CAAC,KAAyB;QAC3B,IAAI,CAAC,KAAK;YAAE,OAAO,SAAS,CAAA;QAC5B,MAAM,GAAG,GAAG,MAAM,CAAC,KAAK,CAAC,CAAA;QACzB,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;QACnC,IAAI,CAAC,KAAK;YAAE,OAAO,SAAS,CAAA;QAC5B,IAAI,KAAK,CAAC,SAAS,IAAI,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;YAClC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;YACxB,OAAO,SAAS,CAAA;QAClB,CAAC;QACD,OAAO,KAAK,CAAA;IACd,CAAC;IAED,sDAAsD;IACtD,IAAI,CAAC,KAAyB;QAC5B,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;QAC7B,IAAI,KAAK,IAAI,KAAK;YAAE,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAA;QACtD,OAAO,KAAK,CAAA;IACd,CAAC;IAED,MAAM,CAAC,KAAyB;QAC9B,IAAI,KAAK;YAAE,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAA;IAC/C,CAAC;IAED,KAAK;QACH,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAA;IACtB,CAAC;CACF"}
@@ -0,0 +1,33 @@
1
+ /**
2
+ * The local host: a small in-process implementation of the session and data
3
+ * protocols (spec/session-protocol.md, spec/data-protocol.md) for development.
4
+ *
5
+ * It is NOT a production server. It keeps records in memory, signs in a
6
+ * single development user without a password, and serves receipts from the
7
+ * pwpack folder. `pwf dev` mounts it under a path prefix on its own HTTP
8
+ * server; tests can mount it on their own.
9
+ */
10
+ import type { IncomingMessage, ServerResponse } from 'node:http';
11
+ export interface LocalHostOptions {
12
+ /** Absolute path of the pwpack folder (receipts, definitions, seed data). */
13
+ readonly root: string;
14
+ /** Path prefix the host is mounted under, e.g. "/_host". */
15
+ readonly prefix: string;
16
+ /** The development user signed in by the dev issuer. */
17
+ readonly user?: {
18
+ readonly id: string;
19
+ readonly name: string;
20
+ readonly email: string;
21
+ };
22
+ }
23
+ export interface LocalHost {
24
+ /** Envelope fields the runner needs to reach this host (session, auth and data URLs). */
25
+ envelopeEntries(origin: string): Readonly<Record<string, unknown>>;
26
+ /** Handles a request under `prefix`; resolves false when the path is not the host's. */
27
+ handle(req: IncomingMessage, res: ServerResponse): Promise<boolean>;
28
+ /** Clears records and sessions. */
29
+ reset(): void;
30
+ }
31
+ /** Implemented in ./local-host.ts. */
32
+ export type CreateLocalHost = (options: LocalHostOptions) => LocalHost;
33
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/host/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAA;AAEhE,MAAM,WAAW,gBAAgB;IAC/B,6EAA6E;IAC7E,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,4DAA4D;IAC5D,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,wDAAwD;IACxD,QAAQ,CAAC,IAAI,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAA;CACvF;AAED,MAAM,WAAW,SAAS;IACxB,yFAAyF;IACzF,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAA;IAClE,wFAAwF;IACxF,MAAM,CAAC,GAAG,EAAE,eAAe,EAAE,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;IACnE,mCAAmC;IACnC,KAAK,IAAI,IAAI,CAAA;CACd;AAED,sCAAsC;AACtC,MAAM,MAAM,eAAe,GAAG,CAAC,OAAO,EAAE,gBAAgB,KAAK,SAAS,CAAA"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * The local host: a small in-process implementation of the session and data
3
+ * protocols (spec/session-protocol.md, spec/data-protocol.md) for development.
4
+ *
5
+ * It is NOT a production server. It keeps records in memory, signs in a
6
+ * single development user without a password, and serves receipts from the
7
+ * pwpack folder. `pwf dev` mounts it under a path prefix on its own HTTP
8
+ * server; tests can mount it on their own.
9
+ */
10
+ export {};
11
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/host/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * `pwf` — the PWFabric command line.
3
+ *
4
+ * Creates, develops, validates, packs and runs PWFabric applications with
5
+ * nothing but the engine's own packages. It never calls a hosted service:
6
+ * there is no login, publish or deploy here.
7
+ */
8
+ import type { CommandIO } from './commands/types.js';
9
+ export { parseArgs } from './args.js';
10
+ export { COMMANDS, findCommand } from './commands/registry.js';
11
+ export type { Command, CommandIO, ParsedArgs } from './commands/types.js';
12
+ export type { DevServer, DevServerOptions, DevBuildResult, StartDevServer } from './dev/types.js';
13
+ export type { LocalHost, LocalHostOptions, CreateLocalHost } from './host/types.js';
14
+ export { createLocalHost } from './host/local-host.js';
15
+ /** Runs one invocation and resolves to its exit code. */
16
+ export declare function main(argv: readonly string[], io: CommandIO): Promise<number>;
17
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAA;AAEpD,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAA;AACrC,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAA;AAC9D,YAAY,EAAE,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAA;AACzE,YAAY,EAAE,SAAS,EAAE,gBAAgB,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AACjG,YAAY,EAAE,SAAS,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AACnF,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;AAUtD,yDAAyD;AACzD,wBAAsB,IAAI,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,EAAE,EAAE,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,CAkBlF"}
package/dist/index.js ADDED
@@ -0,0 +1,41 @@
1
+ /**
2
+ * `pwf` — the PWFabric command line.
3
+ *
4
+ * Creates, develops, validates, packs and runs PWFabric applications with
5
+ * nothing but the engine's own packages. It never calls a hosted service:
6
+ * there is no login, publish or deploy here.
7
+ */
8
+ import { parseArgs } from './args.js';
9
+ import { COMMANDS, findCommand } from './commands/registry.js';
10
+ export { parseArgs } from './args.js';
11
+ export { COMMANDS, findCommand } from './commands/registry.js';
12
+ export { createLocalHost } from './host/local-host.js';
13
+ function help(io) {
14
+ io.out('Usage: pwf <command> [options]');
15
+ io.out('');
16
+ for (const c of COMMANDS)
17
+ io.out(` ${c.name.padEnd(10)} ${c.summary}`);
18
+ io.out('');
19
+ io.out('Run `pwf <command> --help` for the options of one command.');
20
+ }
21
+ /** Runs one invocation and resolves to its exit code. */
22
+ export async function main(argv, io) {
23
+ const { command, args } = parseArgs(argv);
24
+ if (command === undefined || command === 'help') {
25
+ help(io);
26
+ return 0;
27
+ }
28
+ const cmd = findCommand(command);
29
+ if (!cmd) {
30
+ io.err(`pwf: unknown command "${command}"`);
31
+ help(io);
32
+ return 2;
33
+ }
34
+ if (args.flags.help === true) {
35
+ io.out(`Usage: ${cmd.usage}`);
36
+ io.out(cmd.summary);
37
+ return 0;
38
+ }
39
+ return cmd.run(args, io);
40
+ }
41
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAA;AACrC,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAA;AAG9D,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAA;AACrC,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAA;AAI9D,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;AAEtD,SAAS,IAAI,CAAC,EAAa;IACzB,EAAE,CAAC,GAAG,CAAC,gCAAgC,CAAC,CAAA;IACxC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;IACV,KAAK,MAAM,CAAC,IAAI,QAAQ;QAAE,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,CAAC,CAAA;IACvE,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;IACV,EAAE,CAAC,GAAG,CAAC,4DAA4D,CAAC,CAAA;AACtE,CAAC;AAED,yDAAyD;AACzD,MAAM,CAAC,KAAK,UAAU,IAAI,CAAC,IAAuB,EAAE,EAAa;IAC/D,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,SAAS,CAAC,IAAI,CAAC,CAAA;IACzC,IAAI,OAAO,KAAK,SAAS,IAAI,OAAO,KAAK,MAAM,EAAE,CAAC;QAChD,IAAI,CAAC,EAAE,CAAC,CAAA;QACR,OAAO,CAAC,CAAA;IACV,CAAC;IACD,MAAM,GAAG,GAAG,WAAW,CAAC,OAAO,CAAC,CAAA;IAChC,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,EAAE,CAAC,GAAG,CAAC,yBAAyB,OAAO,GAAG,CAAC,CAAA;QAC3C,IAAI,CAAC,EAAE,CAAC,CAAA;QACR,OAAO,CAAC,CAAA;IACV,CAAC;IACD,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,KAAK,IAAI,EAAE,CAAC;QAC7B,EAAE,CAAC,GAAG,CAAC,UAAU,GAAG,CAAC,KAAK,EAAE,CAAC,CAAA;QAC7B,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;QACnB,OAAO,CAAC,CAAA;IACV,CAAC;IACD,OAAO,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC,CAAA;AAC1B,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,68 @@
1
1
  {
2
2
  "name": "@pwfabric/cli",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "version": "1.0.0-rc.0",
4
+ "description": "The PWFabric command line: create, develop, validate, pack and run PWFabric applications without any hosted service",
5
+ "type": "module",
6
+ "bin": {
7
+ "pwf": "./dist/bin.js"
8
+ },
9
+ "main": "./dist/index.js",
10
+ "types": "./dist/index.d.ts",
11
+ "exports": {
12
+ ".": {
13
+ "types": "./dist/index.d.ts",
14
+ "import": "./dist/index.js"
15
+ }
16
+ },
17
+ "files": [
18
+ "dist",
19
+ "LICENSE",
20
+ "README.md"
21
+ ],
22
+ "dependencies": {
23
+ "@pwfabric/contracts": "1.0.0-rc.0",
24
+ "@pwfabric/core": "1.0.0-rc.0",
25
+ "@pwfabric/embed": "1.0.0-rc.0",
26
+ "@pwfabric/pack": "1.0.0-rc.0",
27
+ "@pwfabric/authoring": "1.0.0-rc.0",
28
+ "@pwfabric/runner": "1.0.0-rc.0",
29
+ "@pwfabric/compiler": "1.0.0-rc.0"
30
+ },
31
+ "devDependencies": {
32
+ "@types/node": "^22.0.0",
33
+ "@vitest/coverage-v8": "^2.1.9",
34
+ "ajv": "^8.20.0",
35
+ "ajv-formats": "^3.0.1",
36
+ "jsdom": "^26.0.0",
37
+ "typescript": "^5.4.0",
38
+ "vitest": "^2.0.0"
39
+ },
40
+ "engines": {
41
+ "node": ">=22"
42
+ },
43
+ "publishConfig": {
44
+ "access": "public"
45
+ },
46
+ "repository": {
47
+ "type": "git",
48
+ "url": "https://github.com/pwfabric/pwfabric",
49
+ "directory": "packages/cli"
50
+ },
51
+ "homepage": "https://github.com/pwfabric/pwfabric#readme",
52
+ "bugs": {
53
+ "url": "https://github.com/pwfabric/pwfabric/issues"
54
+ },
55
+ "license": "Apache-2.0",
56
+ "author": "PhiMajor Solutions",
57
+ "scripts": {
58
+ "build": "rm -rf dist tsconfig.tsbuildinfo && tsc",
59
+ "dev": "tsc --watch",
60
+ "test": "vitest run",
61
+ "test:watch": "vitest",
62
+ "test:coverage": "vitest run --coverage",
63
+ "lint": "eslint src",
64
+ "lint:fix": "eslint src --fix",
65
+ "typecheck": "tsc --noEmit",
66
+ "clean": "rm -rf dist"
67
+ }
6
68
  }