create-substrat 0.9.9 → 0.10.1
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 +5 -5
- package/package.json +1 -1
- package/project-files.js +3 -0
- package/template/.substrat/playbook.md +3 -3
- package/template/AGENTS.md +5 -2
- package/template/test/setup.ts +15 -0
- package/template/test/sql-limits.test.ts +34 -0
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.
|
|
40
|
-
const ENGINE_WORKORDER = '^0.12.
|
|
41
|
-
const ENGINE_INVOICING = '^0.11.
|
|
42
|
-
const BOUNDARY_LINT = '^0.
|
|
43
|
-
const DEV_ISSUER = '^0.2.
|
|
39
|
+
const SUBSTRAT = '^0.126.0';
|
|
40
|
+
const ENGINE_WORKORDER = '^0.12.10';
|
|
41
|
+
const ENGINE_INVOICING = '^0.11.10';
|
|
42
|
+
const BOUNDARY_LINT = '^0.6.0';
|
|
43
|
+
const DEV_ISSUER = '^0.2.8';
|
|
44
44
|
|
|
45
45
|
const DOCS = 'https://substrat.net';
|
|
46
46
|
|
package/package.json
CHANGED
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
|
`;
|
|
@@ -76,9 +76,9 @@ Every vertical gets this whether or not it uses a single engine:
|
|
|
76
76
|
an operation narrows a permission it already holds onto one entity, and withdraws it,
|
|
77
77
|
with `ctx.grant(principal, perm, entityRef)` / `ctx.revoke(principal, perm, entityRef)`
|
|
78
78
|
— entity-required, delegating (re-checks the caller's own decision), transactional with
|
|
79
|
-
the operation. Neither alternative is this: a `ctx.link` edge
|
|
80
|
-
|
|
81
|
-
org per domain row to get a revoke.
|
|
79
|
+
the operation. Neither alternative is this: a `ctx.link` edge can be moved
|
|
80
|
+
(`ctx.relink`) but never removed, so it is not a revoke, and org membership is
|
|
81
|
+
revocable but coarse-grained. Never mint an org per domain row to get a revoke.
|
|
82
82
|
- **Events + audit** — every mutation emits a kernel-stamped event. Origin fields (tenant,
|
|
83
83
|
scope, actor, time) are stamped by the kernel; your code cannot mislabel one.
|
|
84
84
|
- **Migrations** — journaled per module, applied lazily per scope.
|
package/template/AGENTS.md
CHANGED
|
@@ -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
|
|
@@ -300,8 +302,9 @@ more than it holds), and transactional with the operation. Every later `ctx.chec
|
|
|
300
302
|
the grant, so nothing else has to remember who may touch what.
|
|
301
303
|
|
|
302
304
|
Neither alternative is this, so you can tell a real absence from this one: a `ctx.link`
|
|
303
|
-
edge
|
|
304
|
-
|
|
305
|
+
edge **can be moved but never removed** (`ctx.relink` replaces one parent with another), so
|
|
306
|
+
it is not a revoke, and org membership is revocable but coarse-grained — a whole org, not
|
|
307
|
+
one record. Never mint an org per domain row, or a
|
|
305
308
|
membership table consulted by hand in every handler, to get a revoke. The two-line
|
|
306
309
|
reference is the [todo demo](https://github.com/substrat-run/substrat/tree/main/demos/todo)
|
|
307
310
|
(`src/module.ts`, `todo/share-list` and `todo/revoke-share`).
|
|
@@ -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
|
+
});
|