create-substrat 0.9.0 → 0.9.2

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.99.0';
40
- const ENGINE_WORKORDER = '^0.10.7';
41
- const ENGINE_INVOICING = '^0.9.15';
39
+ const SUBSTRAT = '^0.102.0';
40
+ const ENGINE_WORKORDER = '^0.11.1';
41
+ const ENGINE_INVOICING = '^0.9.18';
42
42
  const BOUNDARY_LINT = '^0.4.2';
43
- const DEV_ISSUER = '^0.1.14';
43
+ const DEV_ISSUER = '^0.1.17';
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.0",
3
+ "version": "0.9.2",
4
4
  "description": "Scaffold a Substrat vertical — `npm create substrat <dir>`.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -18,7 +18,7 @@
18
18
  "run",
19
19
  "server"
20
20
  ],
21
- "port": 8873,
21
+ "port": 8891,
22
22
  "autoPort": false
23
23
  }
24
24
  ]
@@ -472,7 +472,7 @@ Build confidence in this order, and **show the user the output of each**:
472
472
  pnpm install
473
473
  pnpm test # the scenario, including the denials
474
474
  npx @substrat-run/boundary-lint # the layer rules
475
- pnpm dev # API on :8871 (PORT=… WEB_PORT=… to move it)
475
+ pnpm dev # API on :8891 (PORT=… WEB_PORT=… to move it)
476
476
  ```
477
477
 
478
478
  Then **actually exercise it** — don't just report that the server started. A green scenario
@@ -519,7 +519,7 @@ Two more that each fail silently:
519
519
  `notFoundHandling: "single-page-application"`, a missing `/api/*` entry answers every API
520
520
  call with `index.html` — the app then reports parse errors instead of denials.
521
521
  - **The app calls its own origin** (`fetch('/api' + path)`), never a baked base URL. The Vite
522
- `proxy` block is a dev-only convenience; `VITE_API_URL` or `localhost:8871` works on the
522
+ `proxy` block is a dev-only convenience; `VITE_API_URL` or `localhost:8891` works on the
523
523
  author's machine and reaches nothing from a phone.
524
524
 
525
525
  `substrat push` refuses an `app/` that nothing would serve, so this cannot reach a hostname
@@ -112,10 +112,14 @@ consumers). Rules 1–5 are enforced mechanically by `boundary-lint`.
112
112
  `@substrat-run/kernel` rather than a `SELECT` of your own: both take an `EntityRef`,
113
113
  page like a list read, and decode the envelope for you. `readHistory` also returns the
114
114
  payload, the authorization chain (which checks the operation passed, and under which
115
- grant), the impersonation stamp and the PII class. On the first three, a `null` is a
116
- *fact* rather than data you failed to fetch — the payload was erased, the row predates
117
- authorization recording, nobody was impersonating — so render it as that. Neither
118
- helper checks a permission; you do, before you call it.
115
+ grant), the impersonation stamp, the PII class, the `operation` the event was emitted
116
+ from (the exact `invoke()` string) and the `version` the emitting code was deployed as.
117
+ On all but the PII class, a `null` is a *fact* rather than data you failed to fetch —
118
+ the payload was erased, the row predates authorization recording, nobody was
119
+ impersonating, a consumer emitted it (or the row predates the column), no version
120
+ identity was present — so render it as that. `version` comes from the outbox column
121
+ only, never the envelope, so this helper is the one way to join an event to the push
122
+ that wrote it. Neither helper checks a permission; you do, before you call it.
119
123
  4. **Another module's tables are private.** Never `SELECT` from `workorder_*` etc. — use
120
124
  the engine's exported in-scope functions. This is the rule with no runtime equivalent:
121
125
  the shortcut *works* and silently welds you to an engine's private schema forever. Need
@@ -57,6 +57,11 @@ const staffActor = platformActorId.parse(ulid());
57
57
  // Both ports are bound in THIS file so they move together: `substrat.devServers` names
58
58
  // it for the API and for the issuer alike, and `ISSUER_PORT=… PORT=… pnpm dev` shifts the
59
59
  // pair without either end losing track of the other.
60
+ //
61
+ // The issuer default is 8879 because that is `@substrat-run/dev-issuer`'s OWN default —
62
+ // the `issuer` script passes no `--port`, so this number and the one the issuer actually
63
+ // binds have to be the same or the login round-trip points at nothing. Change one and you
64
+ // must change the other; `ISSUER_PORT=…` moves both at once, which is the supported way.
60
65
  const ISSUER_PORT = Number(process.env.ISSUER_PORT ?? 8879);
61
66
  const login = devLogin({
62
67
  directory: host.admin,
@@ -87,7 +92,11 @@ async function stub(c: Context): Promise<ScopeStub> {
87
92
  // Everything else — including `/api/invoke` and the shared error envelope.
88
93
  mountApi(app, stub);
89
94
 
90
- const PORT = Number(process.env.PORT ?? 8873);
95
+ // 8891, not 8873. The `887x`/`527x` block is reserved for this monorepo's own demos
96
+ // (CLAUDE.md, "Commands"), and 8873 is the shop demo's API — so a scaffolded project used
97
+ // to refuse to boot beside the demo it was read from. A scaffold has no claim on that
98
+ // block; `PORT=…` moves this one.
99
+ const PORT = Number(process.env.PORT ?? 8891);
91
100
  serve({ fetch: app.fetch, port: PORT });
92
101
  console.log(`Bike-shop API on http://localhost:${PORT} — data in ${dataDir}`);
93
102
  console.log(`Sign in at http://localhost:${PORT}/api/auth/login — issuer: ${login.issuer}`);
@@ -73,6 +73,8 @@ export { ConfigDO };
73
73
  * `/internal/delete-scope` removes them. Costs nothing while the roster is empty.
74
74
  */
75
75
  export const SweeperDO = defineScopeSweeperDO<Env>({
76
+ // #1232: the pass reports the version whose code actually ran (the deploy-injected binding).
77
+ versionId: (env) => env.SUBSTRAT_VERSION_ID ?? null,
76
78
  intervalMs: 120_000,
77
79
  host: hostFor,
78
80
  });
@@ -102,6 +104,8 @@ const DEV_NODE: Node = {
102
104
  };
103
105
 
104
106
  interface Env {
107
+ /** Injected at deploy (#1242); absent locally — the sweep record then reads NULL. */
108
+ SUBSTRAT_VERSION_ID?: string;
105
109
  /** One DO per scope — the vertical's only durable store (sandbox-clean). */
106
110
  SCOPE: DurableObjectNamespace;
107
111
  /** The roster-keeping sweep singleton — the deployment's own timer (#461). */