enigma-memory 0.1.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.
Files changed (105) hide show
  1. package/LICENSE +55 -0
  2. package/README.md +379 -0
  3. package/apps/cli/bin/enigma.mjs +1117 -0
  4. package/apps/desktop/src/app.js +1327 -0
  5. package/apps/desktop/src/index.html +1373 -0
  6. package/apps/desktop/src/styles.css +386 -0
  7. package/apps/gateway/bin/enigma-gateway.mjs +52 -0
  8. package/apps/gateway/src/server.mjs +1403 -0
  9. package/apps/native-host/README.md +265 -0
  10. package/apps/native-host/bin/enigma-native-host.mjs +499 -0
  11. package/apps/native-host/manifests/com.enigma.native_host.chrome.json +9 -0
  12. package/apps/native-host/manifests/com.enigma.native_host.edge.json +9 -0
  13. package/apps/native-host/manifests/com.enigma.native_host.firefox.json +9 -0
  14. package/apps/relay/bin/enigma-relay.mjs +52 -0
  15. package/apps/relay/src/server.mjs +1571 -0
  16. package/apps/verifier/bin/enigma-verify.mjs +240 -0
  17. package/deploy/docker-compose.production.example.yml +150 -0
  18. package/deploy/kubernetes/enigma-backend.example.yaml +580 -0
  19. package/package.json +196 -0
  20. package/packages/adapters/PACKAGE_CONTRACT.md +47 -0
  21. package/packages/adapters/src/index.js +183 -0
  22. package/packages/boundary/src/index.js +468 -0
  23. package/packages/connectors/src/index.js +533 -0
  24. package/packages/core/src/index.js +766 -0
  25. package/packages/enterprise/src/index.js +505 -0
  26. package/packages/importers/src/index.js +1083 -0
  27. package/packages/mcp-server/bin/enigma-mcp.mjs +19 -0
  28. package/packages/mcp-server/src/index.js +1185 -0
  29. package/packages/mesh/src/index.js +531 -0
  30. package/packages/metering/PACKAGE_CONTRACT.md +20 -0
  31. package/packages/metering/src/index.js +246 -0
  32. package/packages/optimizer/src/index.js +707 -0
  33. package/packages/passport/src/index.js +651 -0
  34. package/packages/settlement/PACKAGE_CONTRACT.md +28 -0
  35. package/packages/settlement/src/index.js +369 -0
  36. package/packages/storage/PACKAGE_CONTRACT.md +23 -0
  37. package/packages/storage/src/index.js +392 -0
  38. package/packages/vault/src/index.js +904 -0
  39. package/scripts/build-ai-orchestration-plan.mjs +248 -0
  40. package/scripts/build-cloudflare-pages-release-packet.mjs +287 -0
  41. package/scripts/build-cloudflare-token-policy.mjs +239 -0
  42. package/scripts/build-cloudflare-token-request.mjs +314 -0
  43. package/scripts/build-demo-assets.mjs +263 -0
  44. package/scripts/build-edge-backend-workers.mjs +353 -0
  45. package/scripts/build-goal-completion-audit.mjs +398 -0
  46. package/scripts/build-hosted-probe-worker.mjs +191 -0
  47. package/scripts/build-operator-acceptance-packet.mjs +254 -0
  48. package/scripts/build-operator-evidence-starter.mjs +525 -0
  49. package/scripts/build-production-backend-env-kit.mjs +384 -0
  50. package/scripts/build-production-dependency-report.mjs +369 -0
  51. package/scripts/build-production-handoff-packet.mjs +475 -0
  52. package/scripts/build-production-readiness-manifest.mjs +209 -0
  53. package/scripts/build-production-status-board.mjs +297 -0
  54. package/scripts/build-production-storage-migration.mjs +86 -0
  55. package/scripts/build-production-workplan.mjs +371 -0
  56. package/scripts/build-review-packet.mjs +594 -0
  57. package/scripts/check.mjs +419 -0
  58. package/scripts/cloudflare-ops.mjs +1672 -0
  59. package/scripts/cloudflare-secret-env.mjs +128 -0
  60. package/scripts/collect-hosted-backend-live-evidence.mjs +263 -0
  61. package/scripts/infrastructure-readiness.mjs +944 -0
  62. package/scripts/install-enigma-local.mjs +270 -0
  63. package/scripts/memory-optimization-benchmark.mjs +242 -0
  64. package/scripts/monitor-live-endpoints.mjs +358 -0
  65. package/scripts/release-audit.mjs +5588 -0
  66. package/scripts/release-provenance.mjs +250 -0
  67. package/scripts/run-backend-readiness-smoke.mjs +220 -0
  68. package/scripts/validate-backup-restore-drill.mjs +166 -0
  69. package/scripts/validate-cloudflare-credentials.mjs +112 -0
  70. package/scripts/validate-cloudflare-worker-inspect.mjs +179 -0
  71. package/scripts/validate-domain-tls.mjs +248 -0
  72. package/scripts/validate-hosted-backend-live.mjs +319 -0
  73. package/scripts/validate-incident-drill.mjs +221 -0
  74. package/scripts/validate-kms-custody.mjs +235 -0
  75. package/scripts/validate-legal-compliance-approval.mjs +274 -0
  76. package/scripts/validate-monitoring-alerting.mjs +263 -0
  77. package/scripts/validate-network-access-policy.mjs +285 -0
  78. package/scripts/validate-operator-acceptance.mjs +298 -0
  79. package/scripts/validate-production-manifests.mjs +325 -0
  80. package/scripts/validate-public-site-security.mjs +252 -0
  81. package/scripts/validate-security-threat-model.mjs +285 -0
  82. package/scripts/validate-service-settlement.mjs +256 -0
  83. package/scripts/validate-support-sla.mjs +190 -0
  84. package/scripts/validate-tenant-policy-approval.mjs +228 -0
  85. package/scripts/validate-usage-metering.mjs +224 -0
  86. package/scripts/validate-whitepaper-claims.mjs +166 -0
  87. package/specs/boundary-manifest-v1.schema.json +35 -0
  88. package/specs/capsule-v1.schema.json +55 -0
  89. package/specs/claim-boundary-manifest-v1.schema.json +22 -0
  90. package/specs/connector-profile-v1.schema.json +62 -0
  91. package/specs/deletion-tombstone-v1.schema.json +26 -0
  92. package/specs/enterprise-policy-v1.schema.json +59 -0
  93. package/specs/gateway-request-v1.schema.json +32 -0
  94. package/specs/goal-completion-audit-v1.schema.json +70 -0
  95. package/specs/hosted-backend-live-evidence-v1.schema.json +147 -0
  96. package/specs/import-report-v1.schema.json +214 -0
  97. package/specs/infrastructure-readiness-manifest-v1.schema.json +130 -0
  98. package/specs/memory-event-v1.schema.json +42 -0
  99. package/specs/mesh-node-v1.schema.json +126 -0
  100. package/specs/passport-v1.schema.json +50 -0
  101. package/specs/production-handoff-packet-v1.schema.json +149 -0
  102. package/specs/receipt-v1.schema.json +61 -0
  103. package/specs/relay-record-v1.schema.json +43 -0
  104. package/specs/state-checkpoint-v1.schema.json +37 -0
  105. package/specs/trust-bundle-v1.schema.json +56 -0
@@ -0,0 +1,263 @@
1
+ #!/usr/bin/env node
2
+ import { createHash } from 'node:crypto';
3
+ import { mkdir, writeFile } from 'node:fs/promises';
4
+ import { resolve, relative, sep } from 'node:path';
5
+ import { fileURLToPath } from 'node:url';
6
+
7
+ export const DEMO_ASSETS_MANIFEST_SCHEMA = 'enigma.demo_assets_manifest.v1';
8
+ export const DEMO_ASSET_VERSION = '2026-06-24.demo-assets.v1';
9
+
10
+ const DEFAULT_OUT_DIR = 'docs/demo-assets';
11
+ const SVG_FILE = 'receipt-flow-demo.svg';
12
+ const MANIFEST_FILE = 'demo-assets-manifest.json';
13
+
14
+ const FLOW_STEPS = Object.freeze([
15
+ {
16
+ id: 'vault',
17
+ label: 'Vault',
18
+ subtitle: 'Committed local memory address',
19
+ x: 46,
20
+ y: 98,
21
+ width: 142,
22
+ height: 74,
23
+ color: '#7dd3fc',
24
+ },
25
+ {
26
+ id: 'policy',
27
+ label: 'Policy',
28
+ subtitle: 'Purpose + boundary checks',
29
+ x: 226,
30
+ y: 98,
31
+ width: 142,
32
+ height: 74,
33
+ color: '#c4b5fd',
34
+ },
35
+ {
36
+ id: 'context-pack',
37
+ label: 'Context Pack',
38
+ subtitle: 'Plaintext-minimized payload',
39
+ x: 406,
40
+ y: 98,
41
+ width: 160,
42
+ height: 74,
43
+ color: '#fde68a',
44
+ },
45
+ {
46
+ id: 'model-boundary',
47
+ label: 'Model Boundary',
48
+ subtitle: 'Provider memory treated as cache',
49
+ x: 604,
50
+ y: 98,
51
+ width: 180,
52
+ height: 74,
53
+ color: '#fca5a5',
54
+ },
55
+ {
56
+ id: 'receipt',
57
+ label: 'Receipt',
58
+ subtitle: 'Signed Enigma lifecycle event',
59
+ x: 824,
60
+ y: 98,
61
+ width: 150,
62
+ height: 74,
63
+ color: '#86efac',
64
+ },
65
+ {
66
+ id: 'verifier',
67
+ label: 'Verifier',
68
+ subtitle: 'Offline proof check',
69
+ x: 1014,
70
+ y: 98,
71
+ width: 150,
72
+ height: 74,
73
+ color: '#f9a8d4',
74
+ },
75
+ ]);
76
+
77
+ const CLAIM_BOUNDARY = Object.freeze([
78
+ 'Demo assets are public-safe source artifacts for storyboard and explainer use.',
79
+ 'They illustrate Enigma-controlled vault, policy, context-pack, receipt, and verifier flow only.',
80
+ 'They do not prove provider deletion, model forgetting, compliance certification, hosted readiness, or customer deployment status.',
81
+ ]);
82
+
83
+ class UsageError extends Error {
84
+ constructor(message) {
85
+ super(message);
86
+ this.name = 'UsageError';
87
+ }
88
+ }
89
+
90
+ function parseArgs(argv = process.argv.slice(2)) {
91
+ const out = { outDir: DEFAULT_OUT_DIR, help: false };
92
+ for (let index = 0; index < argv.length;) {
93
+ const token = argv[index];
94
+ if (token === '--help') return { ...out, help: true };
95
+ if (token === '--out-dir') {
96
+ if (index + 1 >= argv.length || argv[index + 1].startsWith('--')) throw new UsageError('--out-dir requires a value');
97
+ out.outDir = argv[index + 1];
98
+ index += 2;
99
+ continue;
100
+ }
101
+ throw new UsageError(`unknown option ${token}`);
102
+ }
103
+ return out;
104
+ }
105
+
106
+ function usage() {
107
+ return `Usage: node scripts/build-demo-assets.mjs [--out-dir docs/demo-assets]\n\nGenerates deterministic, public-safe source demo assets: ${SVG_FILE} and ${MANIFEST_FILE}.\nNo external tools, credentials, network access, or video binaries are required.\n`;
108
+ }
109
+
110
+ function escapeXml(value) {
111
+ return String(value)
112
+ .replaceAll('&', '&amp;')
113
+ .replaceAll('<', '&lt;')
114
+ .replaceAll('>', '&gt;')
115
+ .replaceAll('"', '&quot;');
116
+ }
117
+
118
+ function sha256Hex(bytes) {
119
+ return createHash('sha256').update(bytes).digest('hex');
120
+ }
121
+
122
+ function connectorPath(from, to) {
123
+ const startX = from.x + from.width;
124
+ const startY = from.y + (from.height / 2);
125
+ const endX = to.x;
126
+ const endY = to.y + (to.height / 2);
127
+ const midX = startX + ((endX - startX) / 2);
128
+ return `M ${startX} ${startY} C ${midX} ${startY}, ${midX} ${endY}, ${endX} ${endY}`;
129
+ }
130
+
131
+ function renderStep(step, index) {
132
+ const textX = step.x + 18;
133
+ const titleY = step.y + 32;
134
+ const subtitleY = step.y + 54;
135
+ const delay = `${(index * 0.55).toFixed(2)}s`;
136
+ return ` <g id="step-${escapeXml(step.id)}" class="step" style="--step-color:${step.color}; animation-delay:${delay}">
137
+ <rect x="${step.x}" y="${step.y}" width="${step.width}" height="${step.height}" rx="18" />
138
+ <circle cx="${step.x + 18}" cy="${step.y + 18}" r="5" />
139
+ <text class="label" x="${textX}" y="${titleY}">${escapeXml(step.label)}</text>
140
+ <text class="subtitle" x="${textX}" y="${subtitleY}">${escapeXml(step.subtitle)}</text>
141
+ </g>`;
142
+ }
143
+
144
+ export function buildReceiptFlowSvg() {
145
+ const connectors = FLOW_STEPS.slice(0, -1).map((step, index) => {
146
+ const next = FLOW_STEPS[index + 1];
147
+ return ` <path class="connector connector-${index + 1}" d="${connectorPath(step, next)}" pathLength="1" />`;
148
+ }).join('\n');
149
+ const steps = FLOW_STEPS.map(renderStep).join('\n');
150
+ return `<svg xmlns="http://www.w3.org/2000/svg" role="img" aria-labelledby="title desc" viewBox="0 0 1210 300">
151
+ <title id="title">Enigma receipt flow demo storyboard</title>
152
+ <desc id="desc">Animated source SVG showing Vault to Policy to Context Pack to Model Boundary to Receipt to Verifier.</desc>
153
+ <style>
154
+ :root { color-scheme: light dark; }
155
+ svg { background: #07111f; font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; }
156
+ .frame { fill: #0b1424; stroke: #22304a; stroke-width: 1; }
157
+ .eyebrow { fill: #93a4bd; font-size: 12px; font-weight: 700; letter-spacing: 0.22em; text-transform: uppercase; }
158
+ .headline { fill: #f8fafc; font-size: 28px; font-weight: 760; letter-spacing: -0.03em; }
159
+ .boundary { fill: #111827; stroke: #fca5a5; stroke-dasharray: 7 8; stroke-width: 1.5; opacity: 0.72; }
160
+ .boundary-label { fill: #fecaca; font-size: 12px; font-weight: 700; letter-spacing: 0.12em; text-transform: uppercase; }
161
+ .connector { fill: none; stroke: #64748b; stroke-width: 3; stroke-linecap: round; stroke-dasharray: 1; stroke-dashoffset: 1; animation: draw 4.8s ease-in-out infinite; }
162
+ .connector-1 { animation-delay: 0.15s; }
163
+ .connector-2 { animation-delay: 0.70s; }
164
+ .connector-3 { animation-delay: 1.25s; }
165
+ .connector-4 { animation-delay: 1.80s; }
166
+ .connector-5 { animation-delay: 2.35s; }
167
+ .step rect { fill: #0f172a; stroke: var(--step-color); stroke-width: 1.7; filter: drop-shadow(0 16px 22px rgb(0 0 0 / 0.24)); }
168
+ .step circle { fill: var(--step-color); }
169
+ .step { opacity: 0.45; transform-origin: center; animation: pulse 4.8s ease-in-out infinite; }
170
+ .label { fill: #f8fafc; font-size: 17px; font-weight: 760; letter-spacing: -0.015em; }
171
+ .subtitle { fill: #a7b4c7; font-size: 12px; font-weight: 550; }
172
+ .claim { fill: #8ea0b8; font-size: 12px; font-weight: 560; }
173
+ @keyframes draw { 0%, 10% { stroke-dashoffset: 1; stroke: #475569; } 38%, 78% { stroke-dashoffset: 0; stroke: #e2e8f0; } 100% { stroke-dashoffset: 0; stroke: #64748b; } }
174
+ @keyframes pulse { 0%, 12% { opacity: 0.45; transform: translateY(0); } 28%, 68% { opacity: 1; transform: translateY(-4px); } 100% { opacity: 0.55; transform: translateY(0); } }
175
+ @media (prefers-reduced-motion: reduce) { .connector, .step { animation: none; opacity: 1; } .connector { stroke-dashoffset: 0; } }
176
+ </style>
177
+ <rect class="frame" x="18" y="18" width="1174" height="264" rx="28" />
178
+ <text class="eyebrow" x="46" y="54">Public-safe demo asset</text>
179
+ <text class="headline" x="46" y="84">Enigma receipt flow: controlled state in, offline proof out</text>
180
+ <rect class="boundary" x="586" y="86" width="216" height="100" rx="22" />
181
+ <text class="boundary-label" x="616" y="204">No provider deletion or model-forgetting claim</text>
182
+ ${connectors}
183
+ ${steps}
184
+ <text class="claim" x="46" y="246">Receipts prove Enigma lifecycle events and verifier checks for Enigma-controlled state only.</text>
185
+ </svg>
186
+ `;
187
+ }
188
+
189
+ function manifestFor(files) {
190
+ const entries = files.map((file) => ({
191
+ path: file.path,
192
+ media_type: file.mediaType,
193
+ bytes: Buffer.byteLength(file.contents, 'utf8'),
194
+ sha256: sha256Hex(file.contents),
195
+ role: file.role,
196
+ })).sort((a, b) => a.path.localeCompare(b.path));
197
+ const rootHash = createHash('sha256');
198
+ for (const entry of entries) {
199
+ rootHash.update(entry.path);
200
+ rootHash.update('\0');
201
+ rootHash.update(String(entry.bytes));
202
+ rootHash.update('\0');
203
+ rootHash.update(entry.sha256);
204
+ rootHash.update('\n');
205
+ }
206
+ return {
207
+ schema: DEMO_ASSETS_MANIFEST_SCHEMA,
208
+ version: DEMO_ASSET_VERSION,
209
+ deterministic: true,
210
+ generated_by: 'scripts/build-demo-assets.mjs',
211
+ output_files: entries,
212
+ storyboard_flow: FLOW_STEPS.map((step, index) => ({
213
+ order: index + 1,
214
+ id: step.id,
215
+ label: step.label,
216
+ subtitle: step.subtitle,
217
+ })),
218
+ root_sha256: rootHash.digest('hex'),
219
+ claim_boundary: CLAIM_BOUNDARY,
220
+ };
221
+ }
222
+
223
+ export async function buildDemoAssets(options = {}) {
224
+ const outDir = resolve(options.outDir ?? DEFAULT_OUT_DIR);
225
+ const svg = buildReceiptFlowSvg();
226
+ const manifest = manifestFor([
227
+ {
228
+ path: SVG_FILE,
229
+ mediaType: 'image/svg+xml',
230
+ contents: svg,
231
+ role: 'animated storyboard source',
232
+ },
233
+ ]);
234
+ const manifestJson = `${JSON.stringify(manifest, null, 2)}\n`;
235
+ await mkdir(outDir, { recursive: true });
236
+ await writeFile(resolve(outDir, SVG_FILE), svg, 'utf8');
237
+ await writeFile(resolve(outDir, MANIFEST_FILE), manifestJson, 'utf8');
238
+ return {
239
+ ok: true,
240
+ schema: manifest.schema,
241
+ version: manifest.version,
242
+ out_dir: relative(process.cwd(), outDir).split(sep).join('/') || '.',
243
+ files: [SVG_FILE, MANIFEST_FILE],
244
+ root_sha256: manifest.root_sha256,
245
+ };
246
+ }
247
+
248
+ async function main() {
249
+ const args = parseArgs();
250
+ if (args.help) {
251
+ process.stdout.write(usage());
252
+ return;
253
+ }
254
+ const result = await buildDemoAssets({ outDir: args.outDir });
255
+ process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
256
+ }
257
+
258
+ if (process.argv[1] && fileURLToPath(import.meta.url) === resolve(process.argv[1])) {
259
+ main().catch((error) => {
260
+ process.stderr.write(`${error?.message ?? String(error)}\n`);
261
+ process.exitCode = 1;
262
+ });
263
+ }
@@ -0,0 +1,353 @@
1
+ #!/usr/bin/env node
2
+ import { createHash } from 'node:crypto';
3
+ import { mkdir, writeFile } from 'node:fs/promises';
4
+ import { join, resolve } from 'node:path';
5
+ import { fileURLToPath } from 'node:url';
6
+ import { REQUIRED_REF_KEYS } from './validate-hosted-backend-live.mjs';
7
+
8
+ export const EDGE_BACKEND_WORKER_BUNDLE_SCHEMA = 'enigma.edge_backend_worker_bundle.v1';
9
+
10
+ const COMPATIBILITY_DATE = '2026-06-24';
11
+ const SERVICE_CONFIGS = Object.freeze({
12
+ relay: Object.freeze({
13
+ kind: 'relay',
14
+ service: 'enigma-relay',
15
+ workerName: 'enigma-relay',
16
+ hostPrefix: 'relay',
17
+ privateRoutes: Object.freeze(['/relay/records', '/pairing/challenge', '/pairing/complete']),
18
+ }),
19
+ gateway: Object.freeze({
20
+ kind: 'gateway',
21
+ service: 'enigma-gateway',
22
+ workerName: 'enigma-gateway',
23
+ hostPrefix: 'gateway',
24
+ privateRoutes: Object.freeze(['/policy', '/gateway/evaluate', '/gateway/decision', '/siem/export']),
25
+ }),
26
+ });
27
+ export const EDGE_BACKEND_REF_ENV_NAMES = Object.freeze({
28
+ backend_host: Object.freeze(['ENIGMA_BACKEND_HOST_REF']),
29
+ dns_tls: Object.freeze(['ENIGMA_DNS_TLS_REF', 'ENIGMA_TLS_REF']),
30
+ durable_storage: Object.freeze(['ENIGMA_DURABLE_STORAGE_REF', 'ENIGMA_EXTERNAL_STORAGE_REF']),
31
+ kms_or_secret_custody: Object.freeze(['ENIGMA_KMS_KEY_REF', 'ENIGMA_KMS_REF', 'ENIGMA_SECRETS_MANAGER_REF']),
32
+ backup_restore: Object.freeze(['ENIGMA_BACKUP_TARGET_REF', 'ENIGMA_RESTORE_TARGET_REF']),
33
+ monitoring: Object.freeze(['ENIGMA_MONITORING_REF']),
34
+ siem_or_log_sink: Object.freeze(['ENIGMA_SIEM_REF', 'ENIGMA_AUDIT_SINK_REF', 'ENIGMA_LOG_SINK_REF']),
35
+ operator_acceptance: Object.freeze(['ENIGMA_OPERATOR_ACCEPTANCE_REF', 'ENIGMA_OPERATOR_ACCEPTANCE_EVIDENCE_URI']),
36
+ runtime_auth: Object.freeze(['ENIGMA_RUNTIME_AUTH_REF']),
37
+ admin_auth: Object.freeze(['ENIGMA_ADMIN_AUTH_REF', 'ENIGMA_GATEWAY_ADMIN_AUTH_REF']),
38
+ data_plane_auth: Object.freeze(['ENIGMA_DATA_PLANE_AUTH_REF', 'ENIGMA_GATEWAY_DATA_PLANE_AUTH_REF']),
39
+ network_access_policy: Object.freeze(['ENIGMA_NETWORK_ACCESS_POLICY_REF', 'ENIGMA_NETWORK_POLICY_REF']),
40
+ kms_custody: Object.freeze(['ENIGMA_KMS_CUSTODY_REF', 'ENIGMA_KEY_CUSTODY_REF']),
41
+ tenant_policy_approval: Object.freeze(['ENIGMA_TENANT_POLICY_APPROVAL_REF', 'ENIGMA_TENANT_POLICY_REF']),
42
+ usage_metering: Object.freeze(['ENIGMA_USAGE_METERING_REF', 'ENIGMA_METERING_REF']),
43
+ service_settlement: Object.freeze(['ENIGMA_SERVICE_SETTLEMENT_REF', 'ENIGMA_SETTLEMENT_REF']),
44
+ monitoring_alerting: Object.freeze(['ENIGMA_MONITORING_ALERTING_REF', 'ENIGMA_ALERTING_EVIDENCE_REF']),
45
+ public_site_security: Object.freeze(['ENIGMA_PUBLIC_SITE_SECURITY_REF', 'ENIGMA_SITE_SECURITY_REF']),
46
+ security_threat_model: Object.freeze(['ENIGMA_SECURITY_THREAT_MODEL_REF', 'ENIGMA_THREAT_MODEL_REF']),
47
+ legal_compliance_approval: Object.freeze(['ENIGMA_LEGAL_COMPLIANCE_REF', 'ENIGMA_LEGAL_APPROVAL_REF', 'ENIGMA_LEGAL_COMPLIANCE_APPROVAL_REF']),
48
+ support_sla: Object.freeze(['ENIGMA_SUPPORT_SLA_REF']),
49
+ incident_drill: Object.freeze(['ENIGMA_INCIDENT_DRILL_REF']),
50
+ backup_restore_drill: Object.freeze(['ENIGMA_BACKUP_RESTORE_DRILL_REF']),
51
+ relay_deployment: Object.freeze(['ENIGMA_RELAY_DEPLOYMENT_REF']),
52
+ gateway_deployment: Object.freeze(['ENIGMA_GATEWAY_DEPLOYMENT_REF']),
53
+ });
54
+ const CLAIM_BOUNDARY = Object.freeze([
55
+ 'Edge backend Workers provide public HTTPS liveness/readiness and fail-closed private-route boundaries for urgent bootstrap only.',
56
+ 'Readiness is true only when operator-supplied evidence refs and operator acceptance are configured; the Worker does not create storage, KMS, SIEM, backups, legal approval, or acceptance evidence.',
57
+ 'Private data-plane routes remain closed by default; raw memory, prompts, transcripts, provider responses, credentials, and private keys must not be returned by these Workers.',
58
+ ]);
59
+
60
+ const SECRET_VALUE_RE = /(?:Bearer\s+[A-Za-z0-9._~+/=-]{12,}|Basic\s+[A-Za-z0-9+/=-]{12,}|-----BEGIN [A-Z ]*PRIVATE KEY-----|https?:\/\/[^\s/@]+:[^\s/@]+@|sk-[A-Za-z0-9_-]{16,}|AKIA[0-9A-Z]{16})/iu;
61
+
62
+ function sha256(text) {
63
+ return `sha256:${createHash('sha256').update(text).digest('hex')}`;
64
+ }
65
+
66
+ function domainFrom(options) {
67
+ const domain = String(options.domain ?? 'enigmamemory.com').trim().toLowerCase().replace(/\.$/, '');
68
+ if (!/^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)+$/.test(domain)) throw new Error('--domain must be a valid DNS domain');
69
+ return domain;
70
+ }
71
+
72
+ function wranglerToml(config, domain) {
73
+ return `name = "${config.workerName}"
74
+ main = "worker.mjs"
75
+ compatibility_date = "${COMPATIBILITY_DATE}"
76
+ workers_dev = false
77
+ routes = [
78
+ { pattern = "${config.hostPrefix}.${domain}", custom_domain = true }
79
+ ]
80
+
81
+ [observability]
82
+ enabled = false
83
+ `;
84
+ }
85
+
86
+ export function edgeBackendWorkerSource(configInput, options = {}) {
87
+ const config = typeof configInput === 'string' ? SERVICE_CONFIGS[configInput] : configInput;
88
+ if (!config) throw new Error('service kind must be relay or gateway');
89
+ const requiredRefs = JSON.stringify(REQUIRED_REF_KEYS, null, 2);
90
+ const refEnvNames = JSON.stringify(EDGE_BACKEND_REF_ENV_NAMES, null, 2);
91
+ const boundary = JSON.stringify(CLAIM_BOUNDARY, null, 2);
92
+ const privateRoutes = JSON.stringify(config.privateRoutes, null, 2);
93
+ const generatedAt = JSON.stringify(options.generated_at ?? options.generatedAt ?? new Date(0).toISOString());
94
+ return `const SERVICE_KIND = ${JSON.stringify(config.kind)};
95
+ const SERVICE_NAME = ${JSON.stringify(config.service)};
96
+ const GENERATED_AT = ${generatedAt};
97
+ const REQUIRED_REFS = ${requiredRefs};
98
+ const REF_ENV_NAMES = ${refEnvNames};
99
+ const PRIVATE_ROUTES = ${privateRoutes};
100
+ const CLAIM_BOUNDARY = ${boundary};
101
+
102
+ function json(body, status = 200) {
103
+ return new Response(JSON.stringify(body, null, 2), {
104
+ status,
105
+ headers: {
106
+ 'content-type': 'application/json; charset=utf-8',
107
+ 'cache-control': 'no-store',
108
+ 'x-content-type-options': 'nosniff',
109
+ 'permissions-policy': 'interest-cohort=()'
110
+ }
111
+ });
112
+ }
113
+
114
+ function hasValue(env, name) {
115
+ return typeof env?.[name] === 'string' && env[name].trim().length > 0 && !/^<[^<>]+>$/.test(env[name].trim());
116
+ }
117
+
118
+ function envValue(env, names) {
119
+ for (const name of names) if (hasValue(env, name)) return env[name].trim();
120
+ return null;
121
+ }
122
+
123
+ function configuredRefKeys(env) {
124
+ return REQUIRED_REFS.filter((key) => envValue(env, REF_ENV_NAMES[key] || []));
125
+ }
126
+
127
+ function configuredRefs(env) {
128
+ return Object.fromEntries(REQUIRED_REFS.map((key) => [key, envValue(env, REF_ENV_NAMES[key] || [])]).filter(([, value]) => value !== null));
129
+ }
130
+
131
+
132
+
133
+ function bindingHas(binding, methods) {
134
+ return binding && methods.every((method) => typeof binding[method] === 'function');
135
+ }
136
+
137
+ async function storageBindingCheck(env) {
138
+ const ledger = env?.ENIGMA_LEDGER_DB;
139
+ const auditBindingName = SERVICE_KIND === 'relay' ? 'ENIGMA_RELAY_AUDIT_KV' : 'ENIGMA_GATEWAY_AUDIT_KV';
140
+ const audit = env?.[auditBindingName];
141
+ const ledgerDatabaseBound = bindingHas(ledger, ['prepare']);
142
+ const auditNamespaceBound = bindingHas(audit, ['get', 'put']);
143
+ let ledgerReadOk = false;
144
+ let auditReadOk = false;
145
+ let auditWriteOk = false;
146
+ if (ledgerDatabaseBound) {
147
+ try {
148
+ const row = await ledger.prepare('SELECT 1 AS ok').first();
149
+ ledgerReadOk = row?.ok === 1 || row?.ok === true || row?.OK === 1;
150
+ } catch {
151
+ ledgerReadOk = false;
152
+ }
153
+ }
154
+ if (auditNamespaceBound) {
155
+ try {
156
+ await audit.put('__enigma_bootstrap_readiness__', SERVICE_NAME + ':ok', { expirationTtl: 60 });
157
+ auditWriteOk = true;
158
+ const value = await audit.get('__enigma_bootstrap_readiness__');
159
+ auditReadOk = value === SERVICE_NAME + ':ok';
160
+ } catch {
161
+ auditWriteOk = false;
162
+ auditReadOk = false;
163
+ }
164
+ }
165
+ return {
166
+ name: 'storage_bindings',
167
+ ok: ledgerReadOk && auditWriteOk && auditReadOk,
168
+ ledger_database_bound: ledgerDatabaseBound,
169
+ audit_namespace_bound: auditNamespaceBound,
170
+ ledger_read_ok: ledgerReadOk,
171
+ audit_read_ok: auditReadOk,
172
+ audit_write_ok: auditWriteOk,
173
+ audit_binding: auditBindingName
174
+ };
175
+ }
176
+
177
+ function secretCustodyCheck(env) {
178
+ const sentinelBound = hasValue(env, 'ENIGMA_BOOTSTRAP_SECRET_SENTINEL');
179
+ const hmacBound = hasValue(env, 'ENIGMA_READINESS_HMAC_KEY');
180
+ return { name: 'secret_custody_binding', ok: sentinelBound && hmacBound, sentinel_bound: sentinelBound, readiness_hmac_bound: hmacBound, value_returned: false };
181
+ }
182
+ async function readiness(env) {
183
+ const configured = configuredRefKeys(env);
184
+ const refs = configuredRefs(env);
185
+ const missing = REQUIRED_REFS.filter((key) => !configured.includes(key));
186
+ const decision = typeof env?.ENIGMA_OPERATOR_ACCEPTANCE_DECISION === 'string' ? env.ENIGMA_OPERATOR_ACCEPTANCE_DECISION.trim().toLowerCase() : '';
187
+ const decisionOk = decision === 'go';
188
+ const storageCheck = await storageBindingCheck(env);
189
+ const secretCheck = secretCustodyCheck(env);
190
+ const ok = missing.length === 0 && decisionOk && storageCheck.ok && secretCheck.ok;
191
+ return {
192
+ ok,
193
+ service: SERVICE_NAME,
194
+ service_kind: SERVICE_KIND,
195
+ runtime: 'cloudflare-workers',
196
+ generated_at: GENERATED_AT,
197
+ status: ok ? 'ready' : 'blocked',
198
+ evidence_refs: refs,
199
+ evidence_ref_count: configured.length,
200
+ missing_evidence_refs: missing,
201
+ checks: [
202
+ { name: 'production_evidence_refs', ok: missing.length === 0, required_count: REQUIRED_REFS.length, present_count: configured.length, missing_count: missing.length },
203
+ { name: 'operator_acceptance', ok: decisionOk, expected: 'go', observed: decisionOk ? 'go' : 'missing_or_not_go' },
204
+ storageCheck,
205
+ secretCheck,
206
+ { name: 'private_routes_fail_closed', ok: true, route_count: PRIVATE_ROUTES.length }
207
+ ],
208
+ claim_boundary: CLAIM_BOUNDARY
209
+ };
210
+ }
211
+
212
+ function error(code, message) {
213
+ return { ok: false, service: SERVICE_NAME, error: { code, message }, claim_boundary: CLAIM_BOUNDARY };
214
+ }
215
+
216
+ function plaintextLooking(value, seen = new WeakSet()) {
217
+ if (value === null || value === undefined) return false;
218
+ if (typeof value === 'string') return /raw memory|private prompt|full transcript|decrypted capsule|provider response/iu.test(value);
219
+ if (typeof value !== 'object') return false;
220
+ if (seen.has(value)) return false;
221
+ seen.add(value);
222
+ if (Array.isArray(value)) return value.some((item) => plaintextLooking(item, seen));
223
+ for (const [key, nested] of Object.entries(value)) {
224
+ if (/(?:raw[_-]?memory|plaintext|prompt|completion|transcript|provider[_-]?response|secret|password|token|cookie)/iu.test(key)) return true;
225
+ if (plaintextLooking(nested, seen)) return true;
226
+ }
227
+ return false;
228
+ }
229
+
230
+ async function bodyIsUnsafe(request) {
231
+ if (request.method === 'GET' || request.method === 'HEAD') return false;
232
+ const text = await request.clone().text();
233
+ if (text.length > 65536) return true;
234
+ if (text.length === 0) return false;
235
+ try { return plaintextLooking(JSON.parse(text)); } catch { return true; }
236
+ }
237
+
238
+ export default {
239
+ async fetch(request, env) {
240
+ const url = new URL(request.url);
241
+ if (request.method !== 'GET' && request.method !== 'HEAD' && request.method !== 'POST') return json(error('METHOD_NOT_ALLOWED', 'Only GET, HEAD, and POST are allowed.'), 405);
242
+ if (url.pathname === '/livez') return json({ ok: true, service: SERVICE_NAME, service_kind: SERVICE_KIND, runtime: 'cloudflare-workers', claim_boundary: CLAIM_BOUNDARY });
243
+ if (url.pathname === '/readyz') {
244
+ const body = await readiness(env);
245
+ return json(body, body.ok ? 200 : 503);
246
+ }
247
+ if (PRIVATE_ROUTES.includes(url.pathname)) {
248
+ if (await bodyIsUnsafe(request)) return json(error('PLAINTEXT_REJECTED', 'Request body is not accepted by the public edge bootstrap.'), 400);
249
+ return json(error('PRIVATE_ROUTE_CLOSED', 'Private data-plane route is closed in the public edge bootstrap until full operator deployment is complete.'), 503);
250
+ }
251
+ return json(error('NOT_FOUND', 'Use /livez or /readyz for public health checks.'), 404);
252
+ }
253
+ };
254
+ `;
255
+ }
256
+
257
+ export function validateEdgeBackendWorkerSource(source, configInput) {
258
+ const config = typeof configInput === 'string' ? SERVICE_CONFIGS[configInput] : configInput;
259
+ const text = String(source ?? '');
260
+ const blockers = [];
261
+ if (!config) blockers.push({ path: 'service', message: 'service kind must be relay or gateway' });
262
+ if (!text.includes(`const SERVICE_NAME = ${JSON.stringify(config?.service)}`)) blockers.push({ path: 'source.service', message: 'worker must declare the expected service name' });
263
+ if (!text.includes("url.pathname === '/livez'")) blockers.push({ path: 'source.livez', message: 'worker must route /livez' });
264
+ if (!text.includes("url.pathname === '/readyz'")) blockers.push({ path: 'source.readyz', message: 'worker must route /readyz' });
265
+ if (!text.includes('PRIVATE_ROUTE_CLOSED')) blockers.push({ path: 'source.private_routes', message: 'worker must fail closed for private routes' });
266
+ if (text.includes('hosted_probe_only') || text.includes('pages_edge_probe_only')) blockers.push({ path: 'source.claim', message: 'edge backend worker must not masquerade as probe-only payload' });
267
+ if (SECRET_VALUE_RE.test(text)) blockers.push({ path: 'source.secret', message: 'worker source contains secret-looking literal' });
268
+ for (const key of REQUIRED_REF_KEYS) if (!text.includes(key)) blockers.push({ path: `source.refs.${key}`, message: `worker source missing ${key}` });
269
+ return {
270
+ ok: blockers.length === 0,
271
+ blockers,
272
+ service: config?.service ?? null,
273
+ source_hash: sha256(text),
274
+ required_ref_count: REQUIRED_REF_KEYS.length,
275
+ };
276
+ }
277
+
278
+ export function buildEdgeBackendWorkerBundle(options = {}) {
279
+ const domain = domainFrom(options);
280
+ const services = {};
281
+ for (const config of Object.values(SERVICE_CONFIGS)) {
282
+ const source = edgeBackendWorkerSource(config, options);
283
+ services[config.kind] = {
284
+ service: config.service,
285
+ worker_name: config.workerName,
286
+ hostname: `${config.hostPrefix}.${domain}`,
287
+ default_routes: ['/livez', '/readyz'],
288
+ private_routes: [...config.privateRoutes],
289
+ validation: validateEdgeBackendWorkerSource(source, config),
290
+ files: {
291
+ 'worker.mjs': source,
292
+ 'wrangler.toml': wranglerToml(config, domain),
293
+ },
294
+ deploy_command: `npx wrangler deploy --config ${config.kind}/wrangler.toml`,
295
+ };
296
+ }
297
+ const ok = Object.values(services).every((service) => service.validation.ok);
298
+ return {
299
+ schema: EDGE_BACKEND_WORKER_BUNDLE_SCHEMA,
300
+ generated_at: options.generated_at ?? options.generatedAt ?? new Date().toISOString(),
301
+ ok,
302
+ domain,
303
+ compatibility_date: COMPATIBILITY_DATE,
304
+ services,
305
+ claim_boundary: [...CLAIM_BOUNDARY],
306
+ };
307
+ }
308
+
309
+ function parseArgs(argv = process.argv.slice(2)) {
310
+ const out = { outDir: null, domain: 'enigmamemory.com' };
311
+ for (let index = 0; index < argv.length; index += 1) {
312
+ const arg = argv[index];
313
+ if (arg === '--out-dir') out.outDir = argv[++index];
314
+ else if (arg === '--domain') out.domain = argv[++index];
315
+ else if (arg === '--help') out.help = true;
316
+ else throw new Error(`unknown argument ${arg}`);
317
+ }
318
+ return out;
319
+ }
320
+
321
+ function usage() {
322
+ return 'Usage: node scripts/build-edge-backend-workers.mjs --out-dir <dir> [--domain enigmamemory.com]\n\nBuilds public-safe Cloudflare Worker relay/gateway health backends for urgent edge bootstrap. It creates no cloud resources and does not prove production readiness.\n';
323
+ }
324
+
325
+ async function main() {
326
+ const args = parseArgs();
327
+ if (args.help || !args.outDir) {
328
+ process.stdout.write(usage());
329
+ process.exitCode = args.help ? 0 : 1;
330
+ return;
331
+ }
332
+ const bundle = buildEdgeBackendWorkerBundle({ domain: args.domain });
333
+ const outDir = resolve(args.outDir);
334
+ await mkdir(outDir, { recursive: true });
335
+ for (const [kind, service] of Object.entries(bundle.services)) {
336
+ const serviceDir = join(outDir, kind);
337
+ await mkdir(serviceDir, { recursive: true });
338
+ for (const [filename, text] of Object.entries(service.files)) await writeFile(join(serviceDir, filename), text, 'utf8');
339
+ }
340
+ const manifest = {
341
+ ...bundle,
342
+ services: Object.fromEntries(Object.entries(bundle.services).map(([kind, service]) => [kind, { ...service, files: Object.keys(service.files) }])),
343
+ };
344
+ await writeFile(join(outDir, 'EDGE_BACKEND_WORKERS_MANIFEST.json'), `${JSON.stringify(manifest, null, 2)}\n`, 'utf8');
345
+ process.stdout.write(`${JSON.stringify({ ok: bundle.ok, schema: bundle.schema, out_dir: '<edge-backend-workers-output>', services: Object.keys(bundle.services), claim_boundary: bundle.claim_boundary }, null, 2)}\n`);
346
+ }
347
+
348
+ if (process.argv[1] && fileURLToPath(import.meta.url) === resolve(process.argv[1])) {
349
+ main().catch((error) => {
350
+ process.stderr.write(`${error?.message ?? String(error)}\n`);
351
+ process.exitCode = 1;
352
+ });
353
+ }