create-substrat 0.9.8 → 0.10.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.
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.114.0';
40
- const ENGINE_WORKORDER = '^0.11.13';
41
- const ENGINE_INVOICING = '^0.10.4';
42
- const BOUNDARY_LINT = '^0.4.2';
43
- const DEV_ISSUER = '^0.1.29';
39
+ const SUBSTRAT = '^0.124.0';
40
+ const ENGINE_WORKORDER = '^0.12.8';
41
+ const ENGINE_INVOICING = '^0.11.8';
42
+ const BOUNDARY_LINT = '^0.5.0';
43
+ const DEV_ISSUER = '^0.2.6';
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.8",
3
+ "version": "0.10.0",
4
4
  "description": "Scaffold a Substrat vertical — `npm create substrat <dir>`.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
package/project-files.js CHANGED
@@ -46,6 +46,9 @@ export const VITEST_CONFIG = `import { defineConfig } from 'vitest/config';
46
46
  export default defineConfig({
47
47
  test: {
48
48
  include: ['test/**/*.test.ts'],
49
+ // The 50-byte LIKE/GLOB pattern limit a Durable Object enforces (#1770) — on by
50
+ // default, so a scaffolded project's own suite sees what production sees.
51
+ setupFiles: ['./test/setup.ts'],
49
52
  },
50
53
  });
51
54
  `;
@@ -53,6 +53,8 @@ src/worker.ts the deployable Cloudflare worker ← harness
53
53
  src/config-do.ts per-instance config store (Cloudflare only) ← harness
54
54
  test/scenario.test.ts the scenario — including the denials
55
55
  test/entities.test.ts the registry, held to the tables it migrates
56
+ test/setup.ts the 50-byte LIKE/GLOB pattern limit, on by default (vitest setupFiles)
57
+ test/sql-limits.test.ts proves the setupFiles wiring itself — goes red if setup.ts stops running
56
58
  ```
57
59
 
58
60
  **A new route is an `http` declaration on its operation, never a handler in an
@@ -48,7 +48,7 @@ import {
48
48
  type ScopeSweeperDo,
49
49
  } from '@substrat-run/adapter-cloudflare';
50
50
  import {
51
- PLATFORM_REQUEST_HEADER,
51
+ kickFlags,
52
52
  readRoutedNode,
53
53
  RouterAssertionError,
54
54
  type ScopeStub,
@@ -220,12 +220,13 @@ async function stub(c: Context<{ Bindings: Env }>): Promise<ScopeStub> {
220
220
  const principal = await authenticatedPrincipal(c.req.raw, c.env);
221
221
  if (!principal) throw new HTTPException(401, { message: await unauthorizedReason(c.env, node) });
222
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'),
223
+ // An operation that called `ctx.requestPlatform`, or committed an event of a type this
224
+ // vertical EXPORTS (whether or not another app imports it yet), flags its response. The
225
+ // router then has the platform act on this scope within seconds instead of at the next
226
+ // sweep. Leave it wired even if nothing uses either yet: the host raises a flag only when a
227
+ // committed invoke did one of the two, so it costs nothing until then, and without it each
228
+ // waits up to a quarter of an hour.
229
+ ...kickFlags((name, value) => c.header(name, value)),
229
230
  });
230
231
  }
231
232
 
@@ -0,0 +1,15 @@
1
+ // The node suite sees the LIKE/GLOB pattern limit a Durable Object enforces (50 bytes), so a
2
+ // pattern that passes here passes deployed too — see apps/docs/concepts/scope-host.md, "SQL
3
+ // limits on ctx.sql". The import's side effect patches better-sqlite3's Database.prototype.
4
+ import { LIKE_PATTERN_LIMIT } from '@substrat-run/adapter-sqlite/testing';
5
+
6
+ declare global {
7
+ var __substratLikeLimitSetup: number | undefined;
8
+ }
9
+
10
+ // A marker test/sql-limits.test.ts asserts before trusting a pattern to throw — so a suite
11
+ // that stops running this file (vitest.config.ts's setupFiles edited or removed, or this file
12
+ // emptied) fails on "setup did not run" instead of silently accepting a pattern a Durable
13
+ // Object would refuse. Derived from the import itself (not a bare `true`), so the assertion
14
+ // also catches an import that resolves to something other than the real helper.
15
+ globalThis.__substratLikeLimitSetup = LIKE_PATTERN_LIMIT;
@@ -0,0 +1,34 @@
1
+ import Database from 'better-sqlite3';
2
+ import { describe, expect, it } from 'vitest';
3
+
4
+ // Proves the WIRING, not just the helper: test/setup.ts (vitest.config.ts's setupFiles) is what
5
+ // makes a pattern over 50 bytes throw here, the same way it throws on a Durable Object. If
6
+ // setupFiles is ever removed, or setup.ts stops importing the helper, this suite must fail
7
+ // loudly rather than quietly accept a pattern deployed production would refuse.
8
+ describe('the 50-byte LIKE/GLOB pattern limit is on by default', () => {
9
+ it('test/setup.ts ran — the marker it derived from the real helper is present', () => {
10
+ expect(globalThis.__substratLikeLimitSetup).toBe(50);
11
+ });
12
+
13
+ it('a 51-byte pattern is refused, the same message a Durable Object gives', () => {
14
+ const db = new Database(':memory:');
15
+ const pattern = `%${'a'.repeat(49)}%`; // 51 bytes
16
+ try {
17
+ expect(() => db.prepare('SELECT ? LIKE ?').pluck().get('x', pattern)).toThrow(
18
+ /LIKE or GLOB pattern too complex/,
19
+ );
20
+ } finally {
21
+ db.close();
22
+ }
23
+ });
24
+
25
+ it('the passing twin: a 50-byte pattern still runs', () => {
26
+ const db = new Database(':memory:');
27
+ const pattern = `%${'a'.repeat(48)}%`; // 50 bytes
28
+ try {
29
+ expect(db.prepare('SELECT ? LIKE ?').pluck().get(`x${'a'.repeat(48)}x`, pattern)).toBe(1);
30
+ } finally {
31
+ db.close();
32
+ }
33
+ });
34
+ });