@astrale-os/adapter-cloudflare 0.5.0-beta.150 → 0.5.0-beta.152

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,28 @@
1
+ /**
2
+ * Emit one JavaScript literal that shares every structurally identical subtree.
3
+ *
4
+ * Build material reaches a Worker as an inline literal, and JSON has no references, so a flat
5
+ * literal repeats every repeated subtree. A compiled Domain is dominated by pattern automata, and
6
+ * a handful of distinct expressions account for dozens of identical copies of one automaton, so
7
+ * the flat form allocates an order of magnitude more objects than the value actually contains.
8
+ *
9
+ * Sharing changes nothing an observer can see. The literal evaluates to a value that serialises
10
+ * identically, so the material digest taken over it is unchanged, and the material is deeply
11
+ * frozen before anything reads it, so no holder can observe the aliasing.
12
+ */
13
+ export interface SharedLiteral {
14
+ /** `const` declarations for each subtree used more than once, each one after its children. */
15
+ readonly declarations: readonly string[];
16
+ /** The expression for the value itself, referencing those declarations. */
17
+ readonly expression: string;
18
+ }
19
+ export declare function sharedLiteral(value: unknown, prefix?: string): SharedLiteral;
20
+ /**
21
+ * Refuse a literal that does not evaluate back to the value it was built from.
22
+ *
23
+ * Emitting source is the one part of sharing that a type cannot check, so the generator proves its
24
+ * own output instead: a defect becomes a failed build rather than a Worker that boots with the
25
+ * wrong material. The comparison is the serialised form, which is also what the material digest
26
+ * is taken over.
27
+ */
28
+ export declare function verifySharedLiteral(literal: SharedLiteral, expected: unknown): void;
@@ -0,0 +1,136 @@
1
+ /**
2
+ * Emit one JavaScript literal that shares every structurally identical subtree.
3
+ *
4
+ * Build material reaches a Worker as an inline literal, and JSON has no references, so a flat
5
+ * literal repeats every repeated subtree. A compiled Domain is dominated by pattern automata, and
6
+ * a handful of distinct expressions account for dozens of identical copies of one automaton, so
7
+ * the flat form allocates an order of magnitude more objects than the value actually contains.
8
+ *
9
+ * Sharing changes nothing an observer can see. The literal evaluates to a value that serialises
10
+ * identically, so the material digest taken over it is unchanged, and the material is deeply
11
+ * frozen before anything reads it, so no holder can observe the aliasing.
12
+ */
13
+ /**
14
+ * An object literal assigns the prototype for a plain `__proto__` key, where a computed key
15
+ * defines an own property, as JSON does.
16
+ */
17
+ function memberKey(key) {
18
+ return key === '__proto__' ? `[${JSON.stringify(key)}]:` : `${JSON.stringify(key)}:`;
19
+ }
20
+ export function sharedLiteral(value, prefix = '$m') {
21
+ const subtrees = [];
22
+ const references = [];
23
+ const byShape = new Map();
24
+ const byIdentity = new WeakMap();
25
+ /** A piece list, plus the shape text that decides whether two subtrees are the same one. */
26
+ const encode = (input) => {
27
+ const pieces = [];
28
+ const shape = [];
29
+ const open = Array.isArray(input) ? '[' : '{';
30
+ pieces.push(open);
31
+ shape.push(open);
32
+ const keys = Array.isArray(input) ? undefined : Object.keys(input);
33
+ const values = Array.isArray(input)
34
+ ? input
35
+ : (keys ?? []).map((key) => input[key]);
36
+ for (const [index, element] of values.entries()) {
37
+ if (index > 0) {
38
+ pieces.push(',');
39
+ shape.push(',');
40
+ }
41
+ if (keys !== undefined) {
42
+ const member = memberKey(keys[index] ?? '');
43
+ pieces.push(member);
44
+ shape.push(member);
45
+ }
46
+ if (element !== null && typeof element === 'object') {
47
+ const id = identify(element);
48
+ pieces.push({ subtree: id });
49
+ // Quoted JSON text can never start with `#`, so a reference is unambiguous here.
50
+ shape.push(`#${id}`);
51
+ }
52
+ else {
53
+ const text = JSON.stringify(element);
54
+ if (text === undefined) {
55
+ throw new TypeError(`Build material cannot hold a ${typeof element} value.`);
56
+ }
57
+ pieces.push(text);
58
+ shape.push(text);
59
+ }
60
+ }
61
+ const close = Array.isArray(input) ? ']' : '}';
62
+ pieces.push(close);
63
+ shape.push(close);
64
+ return { pieces, shape: shape.join('') };
65
+ };
66
+ const identify = (input) => {
67
+ const known = byIdentity.get(input);
68
+ if (known !== undefined) {
69
+ references[known] += 1;
70
+ return known;
71
+ }
72
+ const { pieces, shape } = encode(input);
73
+ const existing = byShape.get(shape);
74
+ if (existing !== undefined) {
75
+ byIdentity.set(input, existing);
76
+ references[existing] += 1;
77
+ return existing;
78
+ }
79
+ const id = subtrees.length;
80
+ subtrees.push({ pieces });
81
+ references.push(1);
82
+ byShape.set(shape, id);
83
+ byIdentity.set(input, id);
84
+ return id;
85
+ };
86
+ if (value === null || typeof value !== 'object') {
87
+ const text = JSON.stringify(value);
88
+ if (text === undefined)
89
+ throw new TypeError('Build material cannot hold an undefined value.');
90
+ return { declarations: [], expression: text };
91
+ }
92
+ const root = identify(value);
93
+ references[root] -= 1; // The root is the expression itself, not a nested reference.
94
+ // A nested subtree always carries a lower identifier than the one holding it, so ascending
95
+ // order declares every name before its first use.
96
+ const declarations = [];
97
+ const names = new Map();
98
+ const inlined = new Map();
99
+ for (const [id, subtree] of subtrees.entries()) {
100
+ const text = subtree.pieces
101
+ .map((piece) => typeof piece === 'string'
102
+ ? piece
103
+ : (names.get(piece.subtree) ?? inlined.get(piece.subtree) ?? ''))
104
+ .join('');
105
+ if (id !== root && (references[id] ?? 0) > 1) {
106
+ const name = `${prefix}${id}`;
107
+ names.set(id, name);
108
+ declarations.push(`const ${name} = ${text}`);
109
+ }
110
+ else {
111
+ inlined.set(id, text);
112
+ }
113
+ }
114
+ return { declarations, expression: names.get(root) ?? inlined.get(root) ?? 'null' };
115
+ }
116
+ /**
117
+ * Refuse a literal that does not evaluate back to the value it was built from.
118
+ *
119
+ * Emitting source is the one part of sharing that a type cannot check, so the generator proves its
120
+ * own output instead: a defect becomes a failed build rather than a Worker that boots with the
121
+ * wrong material. The comparison is the serialised form, which is also what the material digest
122
+ * is taken over.
123
+ */
124
+ export function verifySharedLiteral(literal, expected) {
125
+ const source = `${literal.declarations.join('\n')}\nreturn ${literal.expression}`;
126
+ let produced;
127
+ try {
128
+ produced = new Function(source)();
129
+ }
130
+ catch (cause) {
131
+ throw new TypeError('Generated Build material literal is not valid JavaScript.', { cause });
132
+ }
133
+ if (JSON.stringify(produced) !== JSON.stringify(expected)) {
134
+ throw new TypeError('Generated Build material literal does not reproduce its material.');
135
+ }
136
+ }
@@ -1,7 +1,14 @@
1
1
  import { generatedMaterial } from '@astrale-os/sdk/deployment/build';
2
+ import { sharedLiteral, verifySharedLiteral } from './literal.js';
2
3
  export function generateExecutionService(options) {
3
4
  const workerSpecifier = options.workerSpecifier ?? '@astrale-os/adapter-cloudflare/worker';
4
5
  const generated = generatedMaterial(options.build);
6
+ // JSON has no references, so a flat literal repeats every repeated subtree. A compiled Domain
7
+ // is dominated by pattern automata, of which a few expressions account for dozens of identical
8
+ // copies, so sharing them cuts what the isolate allocates and seals by an order of magnitude.
9
+ const material = sharedLiteral(generated);
10
+ verifySharedLiteral(material, generated);
11
+ const materialDeclarations = material.declarations.map((line) => ` ${line}\n`).join('');
5
12
  const router = options.router;
6
13
  const routerPredicate = router === undefined
7
14
  ? ''
@@ -36,10 +43,12 @@ type WorkerEnv = CloudflareEnv & CloudflareAdapterBindings & {
36
43
  type RuntimeEnv = Omit<WorkerEnv, 'ASTRALE_SIGNING_IDENTITY'>
37
44
  ${routerPredicate}
38
45
  export default generatedCloudflareWorkerEntry<WorkerEnv, RuntimeEnv>()({
39
- ${frontend}${options.frontendRevision === undefined ? '' : ` frontendRevision: ${JSON.stringify(options.frontendRevision)},\n`}${options.frontendAddressed === undefined ? '' : ` frontendAddressed: ${JSON.stringify(options.frontendAddressed)},\n`} load: async () => ({
40
- runtime: (await import(${JSON.stringify(options.runtimeSpecifier)})).default,
41
- material: ${JSON.stringify(generated)} as unknown as GeneratedBuildMaterial,
42
- }),
46
+ ${frontend}${options.frontendRevision === undefined ? '' : ` frontendRevision: ${JSON.stringify(options.frontendRevision)},\n`}${options.frontendAddressed === undefined ? '' : ` frontendAddressed: ${JSON.stringify(options.frontendAddressed)},\n`} load: async () => {
47
+ ${materialDeclarations} return {
48
+ runtime: (await import(${JSON.stringify(options.runtimeSpecifier)})).default,
49
+ material: ${material.expression} as unknown as GeneratedBuildMaterial,
50
+ }
51
+ },
43
52
  privateKey: (env) => decodeSigningIdentity(env.ASTRALE_SIGNING_IDENTITY),
44
53
  resolveEnvironment: runtimeBindings,
45
54
  resolveUrl: (env, requestOrigin) => env.WORKER_URL ?? env.IDENTITY_ISS ?? requestOrigin,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@astrale-os/adapter-cloudflare",
3
- "version": "0.5.0-beta.150",
3
+ "version": "0.5.0-beta.152",
4
4
  "description": "Deploy an Astrale application through Cloudflare Workers",
5
5
  "keywords": [
6
6
  "adapter",
@@ -53,7 +53,7 @@
53
53
  "registry": "https://registry.npmjs.org/"
54
54
  },
55
55
  "dependencies": {
56
- "@astrale-os/sdk": "0.5.0-beta.147",
56
+ "@astrale-os/sdk": "0.5.0-beta.149",
57
57
  "@noble/hashes": "2.3.0",
58
58
  "hono": "^4.6.20",
59
59
  "jose": "^6.1.3",
@@ -61,6 +61,7 @@
61
61
  },
62
62
  "devDependencies": {
63
63
  "@astrale-os/ox": "0.1.3",
64
+ "@cloudflare/workers-types": "^5.20260820.1",
64
65
  "@types/node": "^22.0.0",
65
66
  "oxfmt": "0.63.0",
66
67
  "oxlint": "1.78.0",
@@ -72,7 +73,7 @@
72
73
  "node": ">=22"
73
74
  },
74
75
  "scripts": {
75
- "typecheck": "tsc --noEmit && tsc --noEmit -p tsconfig.test.json && tsc --noEmit -p __tests__/tsconfig.types.json",
76
+ "typecheck": "tsc --noEmit && tsc --noEmit -p src/worker/tsconfig.json && tsc --noEmit -p tsconfig.test.json && tsc --noEmit -p __tests__/tsconfig.types.json",
76
77
  "test": "vitest run",
77
78
  "lint": "oxlint --disable-nested-config .",
78
79
  "format": "pnpm exec oxfmt --write .",