orez 0.4.24 → 0.4.25

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.
@@ -0,0 +1,55 @@
1
+ /**
2
+ * namespace routing primitives for the Cloudflare Durable Object deploy.
3
+ *
4
+ * a multi-tenant CF/orez deploy shards data into one DO instance per tenant
5
+ * namespace (`ns:<scope>-<id>`) plus a control-plane `singleton`. the worker
6
+ * tiers carry the chosen namespace in a header (and re-stamp it so an inbound
7
+ * value is never trusted) and must validate its shape before routing — an
8
+ * unvalidated namespace would let a client mint unbounded DO instances.
9
+ *
10
+ * the deployed worker entry classes are bundled strings in the consumer's
11
+ * deploy integration (awkward to unit-test), so the routing decision and the
12
+ * security-relevant shape validation live here as pure functions, tested in
13
+ * cf-do-shim.test.ts. consumers import these into their worker shims instead of
14
+ * copy-pasting the validation regex at every routing site.
15
+ */
16
+ export interface NamespaceRoutingOptions {
17
+ /** allowed namespace scope prefixes. default `['proj', 'test']`. */
18
+ scopes?: readonly string[];
19
+ /**
20
+ * namespace values that resolve to the control-plane `singleton` instance,
21
+ * in addition to the empty string (which is always the singleton).
22
+ */
23
+ controlPlaneNamespaces?: readonly string[];
24
+ /** request header the worker tiers carry the namespace in. default `x-orez-ns`. */
25
+ nsHeader?: string;
26
+ }
27
+ /**
28
+ * true when `ns` is a structurally valid tenant namespace: a configured scope
29
+ * prefix followed by a 1-64 char `[A-Za-z0-9_-]` id. this is the gate that
30
+ * keeps a stray header from minting an unbounded DO instance, so every routing
31
+ * site that forwards a namespace should run it.
32
+ */
33
+ export declare function isValidNamespace(ns: string, opts?: NamespaceRoutingOptions): boolean;
34
+ /**
35
+ * resolve a raw namespace string to a DO instance name:
36
+ * - `''` or a control-plane alias -> `'singleton'`
37
+ * - a valid tenant namespace -> `'ns:<ns>'`
38
+ * - anything else -> `null` (caller should reject the request)
39
+ */
40
+ export declare function doInstanceName(ns: string, opts?: NamespaceRoutingOptions): string | null;
41
+ interface HeaderReader {
42
+ get(name: string): string | null;
43
+ }
44
+ /**
45
+ * read the namespace from a request (the configured header, falling back to the
46
+ * `?ns=` query param) and resolve it to a DO instance name. returns `null` for a
47
+ * structurally invalid namespace so the worker can reply 400 instead of routing.
48
+ */
49
+ export declare function doInstanceNameForRequest(request: {
50
+ headers: HeaderReader;
51
+ }, url: {
52
+ searchParams: HeaderReader;
53
+ }, opts?: NamespaceRoutingOptions): string | null;
54
+ export {};
55
+ //# sourceMappingURL=cf-do-shim.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cf-do-shim.d.ts","sourceRoot":"","sources":["../../src/worker/cf-do-shim.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAKH,MAAM,WAAW,uBAAuB;IACtC,oEAAoE;IACpE,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IAC1B;;;OAGG;IACH,sBAAsB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IAC1C,mFAAmF;IACnF,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAWD;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAC9B,EAAE,EAAE,MAAM,EACV,IAAI,GAAE,uBAA4B,GACjC,OAAO,CAET;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAC5B,EAAE,EAAE,MAAM,EACV,IAAI,GAAE,uBAA4B,GACjC,MAAM,GAAG,IAAI,CAKf;AAED,UAAU,YAAY;IACpB,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAA;CACjC;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CACtC,OAAO,EAAE;IAAE,OAAO,EAAE,YAAY,CAAA;CAAE,EAClC,GAAG,EAAE;IAAE,YAAY,EAAE,YAAY,CAAA;CAAE,EACnC,IAAI,GAAE,uBAA4B,GACjC,MAAM,GAAG,IAAI,CAIf"}
@@ -0,0 +1,58 @@
1
+ /**
2
+ * namespace routing primitives for the Cloudflare Durable Object deploy.
3
+ *
4
+ * a multi-tenant CF/orez deploy shards data into one DO instance per tenant
5
+ * namespace (`ns:<scope>-<id>`) plus a control-plane `singleton`. the worker
6
+ * tiers carry the chosen namespace in a header (and re-stamp it so an inbound
7
+ * value is never trusted) and must validate its shape before routing — an
8
+ * unvalidated namespace would let a client mint unbounded DO instances.
9
+ *
10
+ * the deployed worker entry classes are bundled strings in the consumer's
11
+ * deploy integration (awkward to unit-test), so the routing decision and the
12
+ * security-relevant shape validation live here as pure functions, tested in
13
+ * cf-do-shim.test.ts. consumers import these into their worker shims instead of
14
+ * copy-pasting the validation regex at every routing site.
15
+ */
16
+ /** default namespace scope prefixes (`proj-<id>`, `test-<id>`). */
17
+ const DEFAULT_SCOPES = ['proj', 'test'];
18
+ function escapeForRegExp(value) {
19
+ return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
20
+ }
21
+ function namespacePattern(scopes) {
22
+ const group = scopes.map(escapeForRegExp).join('|');
23
+ return new RegExp(`^(?:${group})-[A-Za-z0-9_-]{1,64}$`);
24
+ }
25
+ /**
26
+ * true when `ns` is a structurally valid tenant namespace: a configured scope
27
+ * prefix followed by a 1-64 char `[A-Za-z0-9_-]` id. this is the gate that
28
+ * keeps a stray header from minting an unbounded DO instance, so every routing
29
+ * site that forwards a namespace should run it.
30
+ */
31
+ export function isValidNamespace(ns, opts = {}) {
32
+ return namespacePattern(opts.scopes ?? DEFAULT_SCOPES).test(ns);
33
+ }
34
+ /**
35
+ * resolve a raw namespace string to a DO instance name:
36
+ * - `''` or a control-plane alias -> `'singleton'`
37
+ * - a valid tenant namespace -> `'ns:<ns>'`
38
+ * - anything else -> `null` (caller should reject the request)
39
+ */
40
+ export function doInstanceName(ns, opts = {}) {
41
+ if (!ns)
42
+ return 'singleton';
43
+ if ((opts.controlPlaneNamespaces ?? []).includes(ns))
44
+ return 'singleton';
45
+ if (!isValidNamespace(ns, opts))
46
+ return null;
47
+ return 'ns:' + ns;
48
+ }
49
+ /**
50
+ * read the namespace from a request (the configured header, falling back to the
51
+ * `?ns=` query param) and resolve it to a DO instance name. returns `null` for a
52
+ * structurally invalid namespace so the worker can reply 400 instead of routing.
53
+ */
54
+ export function doInstanceNameForRequest(request, url, opts = {}) {
55
+ const ns = request.headers.get(opts.nsHeader ?? 'x-orez-ns') || url.searchParams.get('ns') || '';
56
+ return doInstanceName(ns, opts);
57
+ }
58
+ //# sourceMappingURL=cf-do-shim.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cf-do-shim.js","sourceRoot":"","sources":["../../src/worker/cf-do-shim.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,mEAAmE;AACnE,MAAM,cAAc,GAAG,CAAC,MAAM,EAAE,MAAM,CAAU,CAAA;AAchD,SAAS,eAAe,CAAC,KAAa;IACpC,OAAO,KAAK,CAAC,OAAO,CAAC,qBAAqB,EAAE,MAAM,CAAC,CAAA;AACrD,CAAC;AAED,SAAS,gBAAgB,CAAC,MAAyB;IACjD,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IACnD,OAAO,IAAI,MAAM,CAAC,OAAO,KAAK,wBAAwB,CAAC,CAAA;AACzD,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAC9B,EAAU,EACV,OAAgC,EAAE;IAElC,OAAO,gBAAgB,CAAC,IAAI,CAAC,MAAM,IAAI,cAAc,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;AACjE,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,cAAc,CAC5B,EAAU,EACV,OAAgC,EAAE;IAElC,IAAI,CAAC,EAAE;QAAE,OAAO,WAAW,CAAA;IAC3B,IAAI,CAAC,IAAI,CAAC,sBAAsB,IAAI,EAAE,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC;QAAE,OAAO,WAAW,CAAA;IACxE,IAAI,CAAC,gBAAgB,CAAC,EAAE,EAAE,IAAI,CAAC;QAAE,OAAO,IAAI,CAAA;IAC5C,OAAO,KAAK,GAAG,EAAE,CAAA;AACnB,CAAC;AAMD;;;;GAIG;AACH,MAAM,UAAU,wBAAwB,CACtC,OAAkC,EAClC,GAAmC,EACnC,OAAgC,EAAE;IAElC,MAAM,EAAE,GACN,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,IAAI,WAAW,CAAC,IAAI,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,CAAA;IACvF,OAAO,cAAc,CAAC,EAAE,EAAE,IAAI,CAAC,CAAA;AACjC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "orez",
3
- "version": "0.4.24",
3
+ "version": "0.4.25",
4
4
  "description": "PGlite-powered zero-sync development backend. No Docker required.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -87,7 +87,7 @@
87
87
  "@electric-sql/pglite": "0.4.1",
88
88
  "@electric-sql/pglite-tools": "^0.3.1",
89
89
  "@pgsql/traverse": "17.2.6",
90
- "bedrock-sqlite": "0.4.24",
90
+ "bedrock-sqlite": "0.4.25",
91
91
  "citty": "^0.2.0",
92
92
  "pg-gateway": "0.3.0-beta.4",
93
93
  "pgsql-parser": "^17.9.11",