void 0.7.13 → 0.8.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 (133) hide show
  1. package/dist/{agents-DqkFfc2c.mjs → agents-Dkgafwfr.mjs} +1 -1
  2. package/dist/{auth-cmd-bS88H4Lb.mjs → auth-cmd-B1-7r6ng.mjs} +3 -3
  3. package/dist/{better-auth-shared-D2JaoCs4.mjs → better-auth-shared-CbAF6sOM.mjs} +1 -1
  4. package/dist/{better-auth-shared-HXlHRw02.d.mts → better-auth-shared-Fzyk5yS1.d.mts} +2 -7
  5. package/dist/{cache-DUDCNty6.mjs → cache-CGYC-2LW.mjs} +5 -5
  6. package/dist/{cancel-deploy-DOuSbPwX.mjs → cancel-deploy-B4j31z7d.mjs} +4 -4
  7. package/dist/canonical-json-CEyQaVDa.mjs +13 -0
  8. package/dist/cli/cli.mjs +44 -31
  9. package/dist/{client-C_DYiXeu.mjs → client-C-nH6yz3.mjs} +5 -5
  10. package/dist/{collect-HqAuilH6.mjs → collect-9rO3JFNM.mjs} +1 -1
  11. package/dist/{config-DyUSwbeX.mjs → config--wXmVOoe.mjs} +10 -8
  12. package/dist/{config-CeRQg3Lz.mjs → config-BVEC0lti.mjs} +11 -2
  13. package/dist/{config-CvHtTM0q.mjs → config-hhMYPVRT.mjs} +3 -12
  14. package/dist/{create-project-hvFe6rbI.mjs → create-project-BGnQMy5N.mjs} +44 -18
  15. package/dist/{db-YEYSTfGw.mjs → db-CT5Xg6ds.mjs} +42 -37
  16. package/dist/{delete-XyM_VD9o.mjs → delete-eMGTHHB9.mjs} +5 -5
  17. package/dist/{deploy-CPAEgVQm.mjs → deploy-7EA_lKq9.mjs} +169 -99
  18. package/dist/{discover-CKGQpis8.mjs → discover-C8N1I4tK.mjs} +9 -6
  19. package/dist/{domain-Dvj7u8tr.mjs → domain-UfLrp2vc.mjs} +64 -22
  20. package/dist/{drizzle-Cx7cVwrE.mjs → drizzle-DmaANP4-.mjs} +1 -1
  21. package/dist/{env-Bjl0rzuf.mjs → env-Cvdbbm_N.mjs} +7 -7
  22. package/dist/{env-helpers-Dw95CU8e.d.mts → env-helpers-Bt9yYg5I.d.mts} +1 -1
  23. package/dist/{env-types-BSQghXbx.mjs → env-types-D6qI1ThV.mjs} +8 -19
  24. package/dist/{env-validation-Buy5pe3u.mjs → env-validation-DBJsxZLz.mjs} +4 -4
  25. package/dist/{gen-DU8NIdrH.mjs → gen-Cn2hZ8RR.mjs} +37 -31
  26. package/dist/{handler-DJTuxB10.d.mts → handler-BPhL8AmU.d.mts} +3 -3
  27. package/dist/{headers-CuVHn6Kl.mjs → headers-wAPJigtE.mjs} +3 -3
  28. package/dist/index.d.mts +3 -3
  29. package/dist/index.mjs +273 -104
  30. package/dist/{init-Br5DTaG7.mjs → init-DL6syXuF.mjs} +43 -31
  31. package/dist/{link-DdXqlUiJ.mjs → link-C5x1E-XZ.mjs} +5 -5
  32. package/dist/{list-9Bxa5Odn.mjs → list-ezL7hqDV.mjs} +5 -5
  33. package/dist/{login-C_MfDjhu.mjs → login-CkLr-AaI.mjs} +3 -3
  34. package/dist/{logs-DjqCpEER.mjs → logs-MnGILmLz.mjs} +4 -4
  35. package/dist/{mcp-vA0880_K.mjs → mcp-B84MmVAW.mjs} +3 -3
  36. package/dist/{node-gxRQXIRT.mjs → node-fpywdcbN.mjs} +6 -6
  37. package/dist/{output-D3g5otMC.mjs → output-DeiS4oEX.mjs} +1 -1
  38. package/dist/pages/client.d.mts +1 -1
  39. package/dist/pages/head-client.d.mts +1 -1
  40. package/dist/pages/head.d.mts +1 -1
  41. package/dist/pages/index.d.mts +28 -3
  42. package/dist/pages/index.mjs +6 -5
  43. package/dist/pages/islands-plugin.d.mts +1 -1
  44. package/dist/pages/islands-plugin.mjs +7 -5
  45. package/dist/pages/protocol.d.mts +2 -2
  46. package/dist/pages/protocol.mjs +1 -1
  47. package/dist/{pathe.M-eThtNZ-D-kmWkCS.mjs → pathe.M-eThtNZ-BrPhGF_K.mjs} +1 -1
  48. package/dist/plan-aD3wRDqF.mjs +271 -0
  49. package/dist/{plugin-inference-BexV6LL3.mjs → plugin-inference-Ba1uGdIy.mjs} +26 -20
  50. package/dist/{prepare-BEkH89oX.mjs → prepare-BrAISonG.mjs} +29 -19
  51. package/dist/{preset-CYQh93UF.mjs → preset-BRsCi8ZB.mjs} +10 -8
  52. package/dist/{project-DhB4A8_g.mjs → project-CH9pdo16.mjs} +1 -1
  53. package/dist/{project-cmd-CeXO06hG.mjs → project-cmd-JQUzv3qF.mjs} +10 -10
  54. package/dist/project-paths-CCMrHYQm.mjs +100 -0
  55. package/dist/{project-slug-KRvHQEQI.mjs → project-slug-De4UjtD9.mjs} +0 -1
  56. package/dist/{project-tsconfig-Bfy55qvs.mjs → project-tsconfig-HAGjfY6w.mjs} +10 -5
  57. package/dist/{protocol-D7r_deVZ.d.mts → protocol-mcSsdMij.d.mts} +3 -3
  58. package/dist/providers--_pvxpNN.d.mts +7 -0
  59. package/dist/{resolve-project-DdjLQ2tB.mjs → resolve-project-CNpUbUHd.mjs} +1 -1
  60. package/dist/{rollback-C8OSMxmq.mjs → rollback-CoAAvC18.mjs} +4 -4
  61. package/dist/{route-types-qVL-v-CB.mjs → route-types-jxRfWuCb.mjs} +1 -1
  62. package/dist/{runner-C0d3lJo1.mjs → runner-BkGBfr4e.mjs} +4 -2
  63. package/dist/{runner-pg-Bd_172vF.mjs → runner-pg-BXP0JpHW.mjs} +1 -1
  64. package/dist/runtime/ai.mjs +2 -2
  65. package/dist/runtime/auth.d.mts +1 -1
  66. package/dist/runtime/better-auth-pg.d.mts +1 -1
  67. package/dist/runtime/better-auth-pg.mjs +2 -2
  68. package/dist/runtime/better-auth.d.mts +1 -1
  69. package/dist/runtime/better-auth.mjs +2 -2
  70. package/dist/runtime/client.d.mts +2 -2
  71. package/dist/runtime/client.mjs +1 -1
  72. package/dist/runtime/env-helpers.d.mts +1 -1
  73. package/dist/runtime/env-public-client.d.mts +1 -1
  74. package/dist/runtime/env-public.d.mts +2 -2
  75. package/dist/runtime/env-public.mjs +1 -1
  76. package/dist/runtime/env.mjs +1 -1
  77. package/dist/runtime/fetch-stream.d.mts +1 -1
  78. package/dist/runtime/fetch-stream.mjs +1 -1
  79. package/dist/runtime/fetch.d.mts +1 -1
  80. package/dist/runtime/fetch.mjs +1 -1
  81. package/dist/runtime/handler.d.mts +1 -1
  82. package/dist/runtime/handler.mjs +1 -1
  83. package/dist/runtime/isr.mjs +1 -1
  84. package/dist/runtime/live.d.mts +2 -2
  85. package/dist/runtime/live.mjs +1 -1
  86. package/dist/runtime/migration-handler.d.mts +33 -1
  87. package/dist/runtime/migration-handler.mjs +332 -24
  88. package/dist/runtime/remote/index.mjs +1 -1
  89. package/dist/runtime/sandbox.d.mts +73 -3
  90. package/dist/runtime/sandbox.mjs +239 -3
  91. package/dist/runtime/validator.d.mts +1 -1
  92. package/dist/runtime/ws-server.d.mts +2 -2
  93. package/dist/runtime/ws.d.mts +3 -3
  94. package/dist/{scan-CKpylFj9.mjs → scan-2YmJkYAf.mjs} +4 -3
  95. package/dist/{scan-CkK1Hzpa.mjs → scan-DzzHqtiT.mjs} +82 -43
  96. package/dist/{secret-NDvlqAN2.mjs → secret-mz8t_CML.mjs} +5 -5
  97. package/dist/{skills-SAG0WyVn.mjs → skills-B_ynF4lA.mjs} +3 -3
  98. package/dist/{subcommand-prompt-q9T06dpg.mjs → subcommand-prompt-CPuV7tPW.mjs} +2 -2
  99. package/dist/sveltekit.mjs +1 -1
  100. package/dist/{validate-DW3ViKTA.mjs → validate-CNWm-PsL.mjs} +49 -9
  101. package/dist/{yarn-pnp-6LD6_3Ej.mjs → yarn-pnp-QgEYVC3V.mjs} +1 -1
  102. package/package.json +3 -2
  103. package/schema.json +5 -0
  104. package/skills/void/docs/guide/ai.md +1 -1
  105. package/skills/void/docs/guide/app-types.md +1 -1
  106. package/skills/void/docs/guide/database/postgresql.md +1 -1
  107. package/skills/void/docs/guide/edge/headers.md +1 -1
  108. package/skills/void/docs/guide/edge/static-assets.md +34 -0
  109. package/skills/void/docs/guide/sandboxes.md +3 -2
  110. package/skills/void/docs/guide/ssr.md +25 -2
  111. package/skills/void/docs/integrations/cloudflare.md +5 -3
  112. package/skills/void/docs/integrations/frameworks/overview.md +1 -1
  113. package/skills/void/docs/integrations/nodejs-bun-deno.md +10 -9
  114. package/skills/void/docs/reference/api.md +204 -13
  115. package/skills/void/docs/reference/cli.md +52 -6
  116. package/skills/void/docs/reference/config.md +27 -4
  117. package/skills/void/docs/reference/resource-inference.md +1 -1
  118. /package/dist/{auth-DmuALf16.d.mts → auth-SfRBhXan.d.mts} +0 -0
  119. /package/dist/{auth-migrations-BwLPwRgH.mjs → auth-migrations-BqJoGqGQ.mjs} +0 -0
  120. /package/dist/{cf-access-BW8K93Fm.mjs → cf-access-DKDsgwOU.mjs} +0 -0
  121. /package/dist/{defer-2ARBu8Et.mjs → defer-DkoEwda-.mjs} +0 -0
  122. /package/dist/{dist-q8b2Mjgb.mjs → dist-DR9sIMbM.mjs} +0 -0
  123. /package/dist/{dist-D2L3_KTK.mjs → dist-abzUneor.mjs} +0 -0
  124. /package/dist/{dotenv-HQNhRalS.mjs → dotenv-Bkoqyq9r.mjs} +0 -0
  125. /package/dist/{env-raw-DtfQ9E31.mjs → env-raw-zk5JQKZe.mjs} +0 -0
  126. /package/dist/{fetch-error-DZ868Xq4.d.mts → fetch-error-BbixZ9vW.d.mts} +0 -0
  127. /package/dist/{fetch-error-CEr0ACTl.mjs → fetch-error-rXermVU3.mjs} +0 -0
  128. /package/dist/{head-C7QW7UY1.d.mts → head-CZs8dMxG.d.mts} +0 -0
  129. /package/dist/{log-7ChR5Fbc.mjs → log-CWWZV4V1.mjs} +0 -0
  130. /package/dist/{magic-string.es-DS_lmuBe.mjs → magic-string.es-C1Fb0uxq.mjs} +0 -0
  131. /package/dist/{providers-BlFNPYen.mjs → providers-uC0PJg1c.mjs} +0 -0
  132. /package/dist/{standard-schema-D2qvCEYV.d.mts → standard-schema-WhHcCaqJ.d.mts} +0 -0
  133. /package/dist/{types-DG_Ynnyd.d.mts → types-C8wsi1hv.d.mts} +0 -0
@@ -1,5 +1,7 @@
1
+ import { t as canonicalJson } from "../canonical-json-CEyQaVDa.mjs";
1
2
  //#region src/runtime/migration-handler.ts
2
- function createMigrationHandler(env, migrations, _dialect, runAuthMigrations) {
3
+ const SUPPORTED_CLASSIFIER_VERSION = 1;
4
+ function createMigrationHandler(env, migrations, _dialect, runAuthMigrations, planBundle) {
3
5
  return async (request) => {
4
6
  const token = request.headers.get("x-void-internal");
5
7
  if (!token || token !== env.__VOID_PROXY_TOKEN) return Response.json({
@@ -7,6 +9,7 @@ function createMigrationHandler(env, migrations, _dialect, runAuthMigrations) {
7
9
  error: "unauthorized",
8
10
  migrations: []
9
11
  }, { status: 401 });
12
+ const url = new URL(request.url);
10
13
  try {
11
14
  const db = env.DB;
12
15
  if (!db) return Response.json({
@@ -14,8 +17,57 @@ function createMigrationHandler(env, migrations, _dialect, runAuthMigrations) {
14
17
  error: "no D1 binding found",
15
18
  migrations: []
16
19
  }, { status: 500 });
17
- const result = await runD1Migrations(db, migrations ?? []);
18
- if (result.ok && runAuthMigrations) await runAuthMigrations();
20
+ if (request.method === "GET" && url.pathname === "/__void/migrate/capabilities") {
21
+ const verified = await verifyPlanBundle(migrations ?? [], planBundle);
22
+ return Response.json({
23
+ classifierVersion: verified.classifierVersion,
24
+ destructiveValidation: verified.destructiveValidation,
25
+ dialect: "sqlite",
26
+ endpoints: {
27
+ app: "/__void/migrate/app",
28
+ auth: runAuthMigrations ? "/__void/migrate/auth" : void 0,
29
+ reconcile: "/__void/migrate/app/attempt/:attemptId"
30
+ },
31
+ migrationListHash: verified.migrationListHash,
32
+ protocolVersion: 2
33
+ });
34
+ }
35
+ if (request.method === "POST" && url.pathname === "/__void/migrate/app") {
36
+ const body = await request.json().catch(() => ({}));
37
+ if (!body.attemptId) return Response.json({
38
+ ok: false,
39
+ protocolVersion: 2,
40
+ error: "attemptId required",
41
+ migrations: []
42
+ }, { status: 400 });
43
+ const result = await runD1AppMigrations(db, migrations ?? [], planBundle, {
44
+ attemptId: body.attemptId,
45
+ deploymentId: body.deploymentId
46
+ });
47
+ const status = result.ok ? 200 : result.error?.startsWith("migration already in progress") ? 409 : 500;
48
+ return Response.json(result, { status });
49
+ }
50
+ if (request.method === "GET" && url.pathname.startsWith("/__void/migrate/app/attempt/")) {
51
+ const result = await reconcileAttempt(db, decodeURIComponent(url.pathname.split("/").pop() ?? ""));
52
+ return Response.json(result, { status: result.ok ? 200 : 409 });
53
+ }
54
+ if (request.method === "POST" && url.pathname === "/__void/migrate/auth") {
55
+ if (runAuthMigrations) await runAuthMigrations();
56
+ return Response.json({
57
+ ok: true,
58
+ protocolVersion: 2
59
+ });
60
+ }
61
+ const result = await runD1LegacyMigrations(db, migrations ?? []);
62
+ if (result.ok && runAuthMigrations) try {
63
+ await runAuthMigrations();
64
+ } catch (err) {
65
+ return Response.json({
66
+ ...result,
67
+ ok: false,
68
+ error: err instanceof Error ? err.message : String(err)
69
+ }, { status: 500 });
70
+ }
19
71
  return Response.json(result);
20
72
  } catch (err) {
21
73
  return Response.json({
@@ -26,10 +78,29 @@ function createMigrationHandler(env, migrations, _dialect, runAuthMigrations) {
26
78
  }
27
79
  };
28
80
  }
29
- /**
30
- * One-time migration: rename legacy `_migrations` table to `_void_migrations`.
31
- * Copies all rows from the old table to the new one, then drops the old table.
32
- */
81
+ async function createTrackingTable(db) {
82
+ await db.prepare(`CREATE TABLE IF NOT EXISTS _void_migrations (
83
+ name TEXT PRIMARY KEY,
84
+ applied_at TEXT NOT NULL
85
+ )`).run();
86
+ }
87
+ async function createAttemptTables(db) {
88
+ await db.batch([db.prepare(`CREATE TABLE IF NOT EXISTS _void_migration_attempts (
89
+ attempt_id TEXT PRIMARY KEY,
90
+ deployment_id TEXT,
91
+ migration_list_hash TEXT NOT NULL,
92
+ planned_names_json TEXT NOT NULL,
93
+ plan_hashes_json TEXT NOT NULL,
94
+ status TEXT NOT NULL CHECK (status IN ('running', 'completed', 'failed', 'unknown')),
95
+ started_at TEXT NOT NULL,
96
+ completed_at TEXT,
97
+ error TEXT
98
+ )`), db.prepare(`CREATE TABLE IF NOT EXISTS _void_migration_lock (
99
+ name TEXT PRIMARY KEY,
100
+ attempt_id TEXT NOT NULL,
101
+ acquired_at TEXT NOT NULL
102
+ )`)]);
103
+ }
33
104
  async function upgradeTrackingTable(db) {
34
105
  const { results } = await db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='_migrations'").all();
35
106
  if (!results || results.length === 0) return;
@@ -42,19 +113,257 @@ async function upgradeTrackingTable(db) {
42
113
  db.prepare(`DROP TABLE _migrations`)
43
114
  ]);
44
115
  }
45
- async function runD1Migrations(db, migrations) {
46
- await db.prepare(`CREATE TABLE IF NOT EXISTS _void_migrations (
47
- name TEXT PRIMARY KEY,
48
- applied_at TEXT NOT NULL
49
- )`).run();
50
- await upgradeTrackingTable(db);
116
+ async function readAppliedSet(db) {
51
117
  const { results } = await db.prepare("SELECT name FROM _void_migrations").all();
52
- const applied = new Set((results ?? []).map((r) => r.name));
118
+ return new Set((results ?? []).map((row) => row.name));
119
+ }
120
+ async function runD1AppMigrations(db, migrations, planBundle, attempt) {
121
+ const verified = await verifyPlanBundle(migrations, planBundle);
122
+ await createAttemptTables(db);
123
+ const now = (/* @__PURE__ */ new Date()).toISOString();
124
+ const lock = await acquireAttemptLock(db, attempt.attemptId, now);
125
+ if (lock !== "acquired") return lock;
126
+ const plannedNames = migrations.map((migration) => migration.name);
127
+ const planHashes = verified.plans.map((plan) => plan.planHash);
128
+ try {
129
+ await db.prepare(`INSERT INTO _void_migration_attempts
130
+ (attempt_id, deployment_id, migration_list_hash, planned_names_json, plan_hashes_json, status, started_at)
131
+ VALUES (?, ?, ?, ?, ?, 'running', ?)`).bind(attempt.attemptId, attempt.deploymentId ?? null, verified.migrationListHash, JSON.stringify(plannedNames), JSON.stringify(planHashes), now).run();
132
+ } catch {
133
+ await releaseAttemptLock(db, attempt.attemptId);
134
+ return reconcileAttempt(db, attempt.attemptId);
135
+ }
136
+ const migrationResults = [];
137
+ const confirmedApplied = [];
138
+ const confirmedSkipped = [];
139
+ const warnings = verified.plans.flatMap((plan) => plan.warnings ?? []);
140
+ let stability = "stable";
141
+ try {
142
+ await createTrackingTable(db);
143
+ await upgradeTrackingTable(db);
144
+ const applied = await readAppliedSet(db);
145
+ for (let index = 0; index < migrations.length; index++) {
146
+ const migration = migrations[index];
147
+ const plan = verified.plans[index];
148
+ if (plan.stability === "legacy") stability = "legacy";
149
+ if (applied.has(migration.name)) {
150
+ confirmedSkipped.push(migration.name);
151
+ migrationResults.push({
152
+ applied: false,
153
+ durationMs: 0,
154
+ name: migration.name,
155
+ stability: plan.stability,
156
+ status: "skipped"
157
+ });
158
+ continue;
159
+ }
160
+ const start = Date.now();
161
+ try {
162
+ await executeMigrationPlan(db, migration, plan);
163
+ applied.add(migration.name);
164
+ confirmedApplied.push(migration.name);
165
+ migrationResults.push({
166
+ applied: true,
167
+ durationMs: Date.now() - start,
168
+ name: migration.name,
169
+ stability: plan.stability,
170
+ status: "applied"
171
+ });
172
+ } catch (err) {
173
+ const error = err instanceof Error ? err.message : String(err);
174
+ migrationResults.push({
175
+ applied: false,
176
+ durationMs: Date.now() - start,
177
+ error,
178
+ name: migration.name,
179
+ stability: plan.stability,
180
+ status: "failed"
181
+ });
182
+ await markAttempt(db, attempt.attemptId, "failed", error);
183
+ await releaseAttemptLock(db, attempt.attemptId);
184
+ return {
185
+ ok: false,
186
+ protocolVersion: 2,
187
+ attemptId: attempt.attemptId,
188
+ confirmedApplied,
189
+ confirmedSkipped,
190
+ error: `migration ${migration.name} failed`,
191
+ migrations: migrationResults,
192
+ stability,
193
+ warnings
194
+ };
195
+ }
196
+ }
197
+ await markAttempt(db, attempt.attemptId, "completed");
198
+ await releaseAttemptLock(db, attempt.attemptId);
199
+ return {
200
+ ok: true,
201
+ protocolVersion: 2,
202
+ attemptId: attempt.attemptId,
203
+ confirmedApplied,
204
+ confirmedSkipped,
205
+ migrations: migrationResults,
206
+ stability,
207
+ warnings
208
+ };
209
+ } catch (err) {
210
+ const error = err instanceof Error ? err.message : String(err);
211
+ await markAttempt(db, attempt.attemptId, "failed", error).catch(() => {});
212
+ await releaseAttemptLock(db, attempt.attemptId).catch(() => {});
213
+ return {
214
+ ok: false,
215
+ protocolVersion: 2,
216
+ attemptId: attempt.attemptId,
217
+ confirmedApplied,
218
+ confirmedSkipped,
219
+ error,
220
+ migrations: migrationResults,
221
+ stability,
222
+ warnings
223
+ };
224
+ }
225
+ }
226
+ async function acquireAttemptLock(db, attemptId, acquiredAt) {
227
+ for (let tries = 0; tries < 2; tries++) try {
228
+ await db.prepare("INSERT INTO _void_migration_lock (name, attempt_id, acquired_at) VALUES (?, ?, ?)").bind("app", attemptId, acquiredAt).run();
229
+ return "acquired";
230
+ } catch {
231
+ const existing = await db.prepare("SELECT attempt_id FROM _void_migration_lock WHERE name = ?").bind("app").first();
232
+ if (existing?.attempt_id === attemptId) return reconcileAttempt(db, attemptId);
233
+ if (existing?.attempt_id) {
234
+ const row = await readAttempt(db, existing.attempt_id);
235
+ if (!row || row.status === "completed" || row.status === "failed" || row.status === "unknown") {
236
+ await releaseAttemptLock(db, existing.attempt_id).catch(() => {});
237
+ continue;
238
+ }
239
+ }
240
+ return {
241
+ ok: false,
242
+ protocolVersion: 2,
243
+ attemptId,
244
+ migrations: [],
245
+ error: `migration already in progress for attempt ${existing?.attempt_id ?? "unknown"}`
246
+ };
247
+ }
248
+ return {
249
+ ok: false,
250
+ protocolVersion: 2,
251
+ attemptId,
252
+ migrations: [],
253
+ error: "migration lock could not be acquired"
254
+ };
255
+ }
256
+ async function executeMigrationPlan(db, migration, plan) {
257
+ const appliedAt = (/* @__PURE__ */ new Date()).toISOString();
258
+ if (plan.kind === "single-statement") {
259
+ await db.batch([db.prepare(migration.sql), db.prepare("INSERT INTO _void_migrations (name, applied_at) VALUES (?, ?)").bind(migration.name, appliedAt)]);
260
+ return;
261
+ }
262
+ if (plan.kind === "breakpoint-framed") {
263
+ await db.batch([...plan.statements.map((statement) => db.prepare(statement)), db.prepare("INSERT INTO _void_migrations (name, applied_at) VALUES (?, ?)").bind(migration.name, appliedAt)]);
264
+ return;
265
+ }
266
+ await db.exec(migration.sql);
267
+ await db.prepare("INSERT OR IGNORE INTO _void_migrations (name, applied_at) VALUES (?, ?)").bind(migration.name, appliedAt).run();
268
+ }
269
+ async function markAttempt(db, attemptId, status, error) {
270
+ await db.prepare(`UPDATE _void_migration_attempts
271
+ SET status = ?, completed_at = ?, error = ?
272
+ WHERE attempt_id = ?`).bind(status, (/* @__PURE__ */ new Date()).toISOString(), error ?? null, attemptId).run();
273
+ }
274
+ async function releaseAttemptLock(db, attemptId) {
275
+ await db.prepare("DELETE FROM _void_migration_lock WHERE name = ? AND attempt_id = ?").bind("app", attemptId).run();
276
+ }
277
+ async function readAttempt(db, attemptId) {
278
+ return db.prepare("SELECT * FROM _void_migration_attempts WHERE attempt_id = ?").bind(attemptId).first();
279
+ }
280
+ async function reconcileAttempt(db, attemptId) {
281
+ await createAttemptTables(db);
282
+ await createTrackingTable(db);
283
+ const row = await readAttempt(db, attemptId);
284
+ if (!row) {
285
+ await releaseAttemptLock(db, attemptId).catch(() => {});
286
+ return {
287
+ ok: false,
288
+ protocolVersion: 2,
289
+ attemptId,
290
+ migrations: [],
291
+ error: "migration attempt not found"
292
+ };
293
+ }
294
+ const plannedNames = JSON.parse(row.planned_names_json);
295
+ const applied = await readAppliedSet(db);
296
+ const confirmed = plannedNames.filter((name) => applied.has(name));
297
+ const complete = confirmed.length === plannedNames.length;
298
+ if (complete && row.status !== "completed") await markAttempt(db, attemptId, "completed").catch(() => {});
299
+ if (!complete && row.status === "running") await markAttempt(db, attemptId, "unknown", row.error ?? "migration outcome unknown").catch(() => {});
300
+ await releaseAttemptLock(db, attemptId).catch(() => {});
301
+ return {
302
+ ok: complete,
303
+ protocolVersion: 2,
304
+ attemptId,
305
+ confirmedApplied: [],
306
+ confirmedSkipped: confirmed,
307
+ migrations: plannedNames.map((name) => ({
308
+ applied: false,
309
+ durationMs: 0,
310
+ name,
311
+ status: applied.has(name) ? "skipped" : "failed"
312
+ })),
313
+ error: complete ? void 0 : row.error ?? "migration outcome unknown",
314
+ stability: "stable"
315
+ };
316
+ }
317
+ async function verifyPlanBundle(migrations, planBundle) {
318
+ if (!planBundle || planBundle.protocolVersion !== 2) throw new Error("migration protocol v2 execution plans are missing");
319
+ if (planBundle.classifierVersion !== SUPPORTED_CLASSIFIER_VERSION || planBundle.destructiveValidation !== "passed") throw new Error("unsupported migration execution plan metadata");
320
+ if (planBundle.plans.length !== migrations.length) throw new Error("migration execution plan count does not match bundled migrations");
321
+ for (let index = 0; index < migrations.length; index++) {
322
+ const migration = migrations[index];
323
+ const plan = planBundle.plans[index];
324
+ if (plan.name !== migration.name || plan.dialect !== "sqlite" || plan.classifierVersion !== SUPPORTED_CLASSIFIER_VERSION) throw new Error(`invalid migration execution plan for ${migration.name}`);
325
+ const sqlHash = await sha256Hex(canonicalSql(migration.sql));
326
+ if (plan.sqlHash !== sqlHash) throw new Error(`migration SQL hash mismatch for ${migration.name}`);
327
+ const planHash = await hashPlan(plan);
328
+ if (plan.planHash !== planHash) throw new Error(`migration plan hash mismatch for ${migration.name}`);
329
+ }
330
+ const migrationListHash = await sha256Hex(canonicalJson(planBundle.plans.map((plan) => [
331
+ plan.name,
332
+ plan.sqlHash,
333
+ plan.planHash
334
+ ])));
335
+ if (planBundle.migrationListHash !== migrationListHash) throw new Error("migration list hash mismatch");
336
+ return planBundle;
337
+ }
338
+ function canonicalSql(sql) {
339
+ return (sql.charCodeAt(0) === 65279 ? sql.slice(1) : sql).replace(/\r\n?/g, "\n");
340
+ }
341
+ async function sha256Hex(value) {
342
+ const bytes = new TextEncoder().encode(value);
343
+ const hash = await crypto.subtle.digest("SHA-256", bytes);
344
+ return `sha256:${[...new Uint8Array(hash)].map((byte) => byte.toString(16).padStart(2, "0")).join("")}`;
345
+ }
346
+ async function hashPlan(plan) {
347
+ const hashInput = {
348
+ classifierVersion: plan.classifierVersion,
349
+ dialect: plan.dialect,
350
+ kind: plan.kind,
351
+ name: plan.name,
352
+ sqlHash: plan.sqlHash,
353
+ stability: plan.stability
354
+ };
355
+ if (plan.kind === "breakpoint-framed") hashInput.statements = plan.statements;
356
+ return sha256Hex(canonicalJson(hashInput));
357
+ }
358
+ async function runD1LegacyMigrations(db, migrations) {
359
+ await createTrackingTable(db);
360
+ await upgradeTrackingTable(db);
361
+ const applied = await readAppliedSet(db);
53
362
  const migrationResults = [];
54
- for (const m of migrations) {
55
- if (applied.has(m.name)) {
363
+ for (const migration of migrations) {
364
+ if (applied.has(migration.name)) {
56
365
  migrationResults.push({
57
- name: m.name,
366
+ name: migration.name,
58
367
  applied: false,
59
368
  durationMs: 0
60
369
  });
@@ -62,19 +371,19 @@ async function runD1Migrations(db, migrations) {
62
371
  }
63
372
  const start = Date.now();
64
373
  try {
65
- const statements = splitMigrationSql(m.sql);
374
+ const statements = splitMigrationSql(migration.sql);
66
375
  if (statements.length === 1) if (isSingleSqlStatement(statements[0])) await db.prepare(statements[0]).run();
67
- else await db.exec(m.sql);
376
+ else await db.exec(migration.sql);
68
377
  else for (const statement of statements) await db.prepare(statement).run();
69
- await db.prepare("INSERT OR IGNORE INTO _void_migrations (name, applied_at) VALUES (?, ?)").bind(m.name, (/* @__PURE__ */ new Date()).toISOString()).run();
378
+ await db.prepare("INSERT OR IGNORE INTO _void_migrations (name, applied_at) VALUES (?, ?)").bind(migration.name, (/* @__PURE__ */ new Date()).toISOString()).run();
70
379
  migrationResults.push({
71
- name: m.name,
380
+ name: migration.name,
72
381
  applied: true,
73
382
  durationMs: Date.now() - start
74
383
  });
75
384
  } catch (err) {
76
385
  migrationResults.push({
77
- name: m.name,
386
+ name: migration.name,
78
387
  applied: false,
79
388
  durationMs: Date.now() - start,
80
389
  error: err instanceof Error ? err.message : String(err)
@@ -82,7 +391,7 @@ async function runD1Migrations(db, migrations) {
82
391
  return {
83
392
  ok: false,
84
393
  migrations: migrationResults,
85
- error: `migration ${m.name} failed`
394
+ error: `migration ${migration.name} failed`
86
395
  };
87
396
  }
88
397
  }
@@ -176,7 +485,6 @@ function isSingleSqlStatement(sql) {
176
485
  if (character === ";") {
177
486
  if (inStatement) {
178
487
  statements++;
179
- if (statements > 1) return false;
180
488
  inStatement = false;
181
489
  }
182
490
  index++;
@@ -1,4 +1,4 @@
1
- import { t as cfAccessHeaders } from "../../cf-access-BW8K93Fm.mjs";
1
+ import { t as cfAccessHeaders } from "../../cf-access-DKDsgwOU.mjs";
2
2
  //#region src/runtime/remote/client.ts
3
3
  /**
4
4
  * HTTP client for the remote bindings proxy (proxy.void.cloud).
@@ -4,14 +4,84 @@ import { Sandbox, SandboxOptions } from "@cloudflare/sandbox";
4
4
  //#region src/runtime/sandbox.d.ts
5
5
  declare const DEFAULT_SANDBOX_ID = "default";
6
6
  declare const DEFAULT_SANDBOX_BINDING = "SANDBOX";
7
- type VoidSandbox = Sandbox;
7
+ declare const SANDBOX_USAGE_QUEUE_BINDING = "USAGE_EVENTS_QUEUE";
8
+ declare const SANDBOX_GATE_BINDING = "__VOID_PROXY";
9
+ declare const HEARTBEAT_MS: number;
8
10
  type VoidSandboxOptions = SandboxOptions & {
9
11
  binding?: string;
10
12
  };
13
+ type SandboxUsageEvent = Readonly<{
14
+ requests: 0;
15
+ responseBytes: 0;
16
+ userId?: string;
17
+ projectId?: string;
18
+ slug?: string;
19
+ sandboxRuntimeSeconds: number;
20
+ sandboxInstanceId: string;
21
+ }>;
22
+ /**
23
+ * Thrown by `getSandbox()` when the platform gate denies a new acquire because
24
+ * the user has hit a concurrency or runtime budget cap. Surface this to the
25
+ * caller so they can render a friendly error; do not retry transparently.
26
+ */
27
+ declare class SandboxLimitError extends Error {
28
+ override readonly name = "SandboxLimitError";
29
+ readonly reason: "concurrency" | "runtime_budget";
30
+ constructor(reason: "concurrency" | "runtime_budget", message?: string);
31
+ }
11
32
  declare function __setSandboxBindingName(bindingName: string): void;
12
- declare function getSandbox<T extends Sandbox = Sandbox>(id?: string, options?: VoidSandboxOptions): T;
33
+ /**
34
+ * Sandbox variant that participates in Void platform metering: it records
35
+ * container runtime seconds into DO storage, emits periodic heartbeats to
36
+ * the usage queue, and notifies the gate when the container stops.
37
+ *
38
+ * Generated code from `void inference` wires user `Sandbox` subclasses to
39
+ * extend this class on platform deploys so per-tenant accounting works
40
+ * without user opt-in. On local dev (no usage-queue / gate bindings), all
41
+ * overrides degrade to no-ops and the sandbox behaves like the upstream
42
+ * `Sandbox` class.
43
+ */
44
+ declare class VoidPlatformSandbox<Env = unknown> extends Sandbox<Env> {
45
+ override onStart(): Promise<void>;
46
+ override alarm(alarmProps?: {
47
+ isRetry: boolean;
48
+ retryCount: number;
49
+ }): Promise<void>;
50
+ override onStop(): Promise<void>;
51
+ override onActivityExpired(): Promise<void>;
52
+ private flushFinal;
53
+ }
54
+ /**
55
+ * Resolve the platform-provided sandbox stub for the given id, optionally
56
+ * coordinating with the platform gate to enforce per-user concurrency and
57
+ * runtime budgets.
58
+ *
59
+ * When the gate binding (`__VOID_PROXY` by default) is present AND the
60
+ * platform's `__PROJECT_ID` + `__VOID_PROXY_TOKEN` identity vars are
61
+ * available, we POST to `https://gate/sandbox/acquire` with the HMAC-signed
62
+ * body the shared proxy auth middleware expects. A `409` response means the
63
+ * user has exceeded a budget — we throw `SandboxLimitError` so the caller
64
+ * can render a clear message. Any other non-OK status (or a thrown transport
65
+ * error from the service binding) is treated as "gate unavailable" and we
66
+ * fall through to returning the stub so a broken gate doesn't break sandbox
67
+ * access entirely.
68
+ *
69
+ * When the gate binding is absent (local dev) or the identity vars are
70
+ * missing (partial deploy), the gate check is skipped entirely and we
71
+ * return the stub directly.
72
+ *
73
+ * The stub is constructed BEFORE calling the gate so we can derive the
74
+ * normalized DO name (`stub.id.name`) and pass it to the gate as the
75
+ * `sandboxId`. This keeps acquire and release using the same key — without
76
+ * it, mixed-case caller ids (e.g. `MyProject-123`) would acquire a lease
77
+ * under the raw id but release it under the normalized lowercase form that
78
+ * `ctx.id.name` reports inside the DO, leaking the lease until TTL.
79
+ * Constructing the stub does NOT start a container — that only happens on
80
+ * the first method call against the stub.
81
+ */
82
+ declare function getSandbox<T extends Sandbox = Sandbox>(id?: string, options?: VoidSandboxOptions): Promise<T>;
13
83
  declare const sandbox: {
14
84
  get: typeof getSandbox;
15
85
  };
16
86
  //#endregion
17
- export { DEFAULT_SANDBOX_BINDING, DEFAULT_SANDBOX_ID, Sandbox, type SandboxOptions, VoidSandbox, VoidSandboxOptions, __setSandboxBindingName, getSandbox, sandbox };
87
+ export { DEFAULT_SANDBOX_BINDING, DEFAULT_SANDBOX_ID, HEARTBEAT_MS, SANDBOX_GATE_BINDING, SANDBOX_USAGE_QUEUE_BINDING, Sandbox, SandboxLimitError, type SandboxOptions, SandboxUsageEvent, VoidPlatformSandbox, VoidSandboxOptions, __setSandboxBindingName, getSandbox, sandbox };