create-substrat 0.9.6 → 0.9.8

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/index.js CHANGED
@@ -36,11 +36,11 @@ const TEMPLATE = join(HERE, 'template');
36
36
  // The runtime packages release together off one version line (the changesets `fixed`
37
37
  // group), so one constant is right for all of them. Engines do NOT share a line —
38
38
  // each versions on its own, so one pin per engine, deliberately.
39
- const SUBSTRAT = '^0.111.0';
40
- const ENGINE_WORKORDER = '^0.11.10';
41
- const ENGINE_INVOICING = '^0.10.1';
39
+ const SUBSTRAT = '^0.114.0';
40
+ const ENGINE_WORKORDER = '^0.11.13';
41
+ const ENGINE_INVOICING = '^0.10.4';
42
42
  const BOUNDARY_LINT = '^0.4.2';
43
- const DEV_ISSUER = '^0.1.26';
43
+ const DEV_ISSUER = '^0.1.29';
44
44
 
45
45
  const DOCS = 'https://substrat.net';
46
46
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-substrat",
3
- "version": "0.9.6",
3
+ "version": "0.9.8",
4
4
  "description": "Scaffold a Substrat vertical — `npm create substrat <dir>`.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -20,7 +20,7 @@
20
20
  * not in `.claude/`. `.claude/settings.json` is a three-line adapter that runs it,
21
21
  * and any other client that grows a session hook binds the same way. It also
22
22
  * means the plugin distribution (#753) ships this script unchanged rather than
23
- * forking it: `plugin/substrat/scripts/session-start.mjs` is emitted from this
23
+ * forking it: `plugin/substrat/scripts/session-start.generated.mjs` is emitted from this
24
24
  * file byte-for-byte, and `pnpm lint:plugin --check` fails if the two diverge.
25
25
  *
26
26
  * The plugin copy is what reaches a project scaffolded before this hook existed.
@@ -46,11 +46,13 @@ src/migrations.ts the SqlMigration[] ← module cod
46
46
  src/module.ts the handlers, bound to the declaration ← module code
47
47
  src/provision.ts MODULES, ROLES, grant shapes — node-free ← module code
48
48
  src/seed.ts host, tenants, demo cast, seed world ← harness
49
+ src/personas.ts the dev cast, read by the issuer and the seed ← harness
49
50
  src/routes.ts the routes, DERIVED from the operations ← harness
50
51
  src/server.ts the dev entrypoint (node + persona picker) ← harness
51
52
  src/worker.ts the deployable Cloudflare worker ← harness
52
53
  src/config-do.ts per-instance config store (Cloudflare only) ← harness
53
54
  test/scenario.test.ts the scenario — including the denials
55
+ test/entities.test.ts the registry, held to the tables it migrates
54
56
  ```
55
57
 
56
58
  **A new route is an `http` declaration on its operation, never a handler in an
@@ -156,6 +158,12 @@ same object feeds `operationInputs: operationInputsOf(bikeShopOperations)`, so t
156
158
  schemas the host parses with are the ones the declaration states — they cannot drift,
157
159
  because there is only one of them.
158
160
 
161
+ The permission list works the same way. `SHOP_PERMISSIONS`, the array handed to
162
+ `defineOperations`, is also the `keys` that `src/provision.ts` hands
163
+ `definePermissions({ modules, roles, entityGrants, keys })` — and `definePermissions`
164
+ throws at module load if those keys and `MODULES` disagree in either direction. Hand
165
+ both readers the same array; a second copy is a list that drifts.
166
+
159
167
  **A list read must declare `paged`.** `defineOperations` refuses a bare-array `output`
160
168
  that does not, and it refuses it at module load — so it fires in every build, every
161
169
  test and every dev server rather than in a lint tool that has to find you. A list
@@ -47,7 +47,13 @@ import {
47
47
  SCOPE_SWEEPER_NAME,
48
48
  type ScopeSweeperDo,
49
49
  } from '@substrat-run/adapter-cloudflare';
50
- import { readRoutedNode, RouterAssertionError, type ScopeStub, invocationLog } from '@substrat-run/kernel';
50
+ import {
51
+ PLATFORM_REQUEST_HEADER,
52
+ readRoutedNode,
53
+ RouterAssertionError,
54
+ type ScopeStub,
55
+ invocationLog,
56
+ } from '@substrat-run/kernel';
51
57
  import { mountPlatformSurface } from '@substrat-run/vertical-host';
52
58
  import { MODULES, OWNER_ROLE_KEY, ROLES } from './provision.js';
53
59
  import { SHOP_ENV } from './manifest.js';
@@ -213,7 +219,14 @@ async function stub(c: Context<{ Bindings: Env }>): Promise<ScopeStub> {
213
219
  const node = nodeFor(c.req.raw, c.env);
214
220
  const principal = await authenticatedPrincipal(c.req.raw, c.env);
215
221
  if (!principal) throw new HTTPException(401, { message: await unauthorizedReason(c.env, node) });
216
- return hostFor(c.env).getScope(principal, node.tenantId, node.scopeId);
222
+ return hostFor(c.env).getScope(principal, node.tenantId, node.scopeId, {
223
+ // An operation that called `ctx.requestPlatform` flags its response, and the router
224
+ // drains this scope within seconds instead of at the next sweep. Leave it wired even
225
+ // if nothing requests anything yet: the host calls this only when a committed invoke
226
+ // enqueued at least one intent, so it costs nothing until then, and without it every
227
+ // platform intent waits up to a quarter of an hour.
228
+ onPlatformRequests: () => c.header(PLATFORM_REQUEST_HEADER, '1'),
229
+ });
217
230
  }
218
231
 
219
232
  /**