deepspace 0.3.2 → 0.3.4

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/dist/worker.d.ts CHANGED
@@ -2832,8 +2832,9 @@ declare const COST_RATES: {
2832
2832
  * `[[d1_databases]]` bindings.
2833
2833
  *
2834
2834
  * The auto-provisioner gives apps an empty D1; the app needs to create its
2835
- * own tables before using them. This helper runs ordered SQL fragments under
2836
- * a `PRAGMA user_version` gate so re-running is a no-op:
2835
+ * own tables before using them. This helper runs ordered SQL fragments and
2836
+ * tracks which have applied via a `_dpc_migrations` meta-table so re-running
2837
+ * is a no-op:
2837
2838
  *
2838
2839
  * ```ts
2839
2840
  * import { runMigrations } from 'deepspace/worker'
@@ -2844,16 +2845,28 @@ declare const COST_RATES: {
2844
2845
  * ])
2845
2846
  * ```
2846
2847
  *
2847
- * Each entry in the array is one migration. The runner reads the database's
2848
- * current `user_version`, applies migrations from that index onward, and
2849
- * advances the version. Adding a new migration means appending to the array;
2850
- * never reorder or delete entries.
2848
+ * **SQL formatting requirement:** D1's `exec()` is single-line-per-statement.
2849
+ * Each migration string can hold multiple statements separated by `;`, but
2850
+ * every statement must fit on one line. Multi-line statements (column lists
2851
+ * across newlines) fail with `D1_EXEC_ERROR: incomplete input`. If you need
2852
+ * complex migrations, write each statement on its own line within the string.
2853
+ *
2854
+ * Each entry in the array is one migration. The runner records the index of
2855
+ * each successfully-applied migration in `_dpc_migrations`; subsequent calls
2856
+ * skip rows already recorded. Adding a new migration means appending to the
2857
+ * array; never reorder or delete entries.
2858
+ *
2859
+ * Why a meta-table instead of `PRAGMA user_version`: D1's SQLite authorizer
2860
+ * rejects PRAGMA writes with `SQLITE_AUTH`, even though the same statements
2861
+ * work in raw SQLite. A real table works on any D1 database and stays a
2862
+ * trivial bootstrap (one CREATE TABLE IF NOT EXISTS).
2851
2863
  *
2852
2864
  * Concurrency: D1 serializes statements per database, but two simultaneous
2853
- * `runMigrations` callers could race on the read-then-write of `user_version`.
2854
- * In practice apps invoke this at module/DO startup which is single-threaded
2855
- * per worker isolate; the worst case across isolates is a CREATE TABLE
2856
- * IF NOT EXISTS-equivalent failure — caught and reported with context.
2865
+ * `runMigrations` callers could race the same migration index. The duplicate
2866
+ * INSERT collides on the primary key and the second caller sees the failure
2867
+ * — but the migration itself uses `IF NOT EXISTS` so the schema is correct
2868
+ * either way. Apps invoke this at startup which is single-threaded per
2869
+ * worker isolate; the cross-isolate race is rare and self-healing.
2857
2870
  *
2858
2871
  * This is the simplest possible migration story (option 1 in
2859
2872
  * docs/proposals/binding-auto-provisioning.md). Apps that outgrow it can
@@ -2861,7 +2874,7 @@ declare const COST_RATES: {
2861
2874
  * helper.
2862
2875
  */
2863
2876
  interface RunMigrationsResult {
2864
- /** Version before this run started. */
2877
+ /** Version before this run started. Equals the count of migrations already applied. */
2865
2878
  fromVersion: number;
2866
2879
  /** Version after migrations applied. Equals fromVersion if nothing ran. */
2867
2880
  toVersion: number;
@@ -2872,8 +2885,8 @@ interface RunMigrationsResult {
2872
2885
  * Apply ordered SQL migrations to a D1 database. Idempotent: the next call
2873
2886
  * with the same array is a no-op until the array grows.
2874
2887
  *
2875
- * Throws on any individual migration failure. The user_version is only
2876
- * advanced after a migration succeeds, so a partial failure leaves a
2888
+ * Throws on any individual migration failure. The migrations meta-row is
2889
+ * only inserted after a migration succeeds, so a partial failure leaves a
2877
2890
  * recoverable state — fix the SQL, redeploy, and the failed migration runs
2878
2891
  * on next startup.
2879
2892
  */
package/dist/worker.js CHANGED
@@ -6117,9 +6117,12 @@ var COST_RATES = {
6117
6117
  };
6118
6118
 
6119
6119
  // src/server/utils/d1-migrations.ts
6120
+ var META_TABLE = "_dpc_migrations";
6121
+ var META_BOOTSTRAP_SQL = `CREATE TABLE IF NOT EXISTS ${META_TABLE} (idx INTEGER PRIMARY KEY, applied_at TEXT NOT NULL);`;
6120
6122
  async function runMigrations(db, migrations) {
6121
- const versionRow = await db.prepare("PRAGMA user_version").first();
6122
- const fromVersion = versionRow?.user_version ?? 0;
6123
+ await db.exec(META_BOOTSTRAP_SQL);
6124
+ const row = await db.prepare(`SELECT COUNT(*) AS n FROM ${META_TABLE}`).first();
6125
+ const fromVersion = row?.n ?? 0;
6123
6126
  if (fromVersion >= migrations.length) {
6124
6127
  return { fromVersion, toVersion: fromVersion, applied: 0 };
6125
6128
  }
@@ -6130,10 +6133,10 @@ async function runMigrations(db, migrations) {
6130
6133
  await db.exec(sql);
6131
6134
  } catch (err) {
6132
6135
  const msg = err instanceof Error ? err.message : String(err);
6133
- throw new Error(`Migration ${i} failed (db at user_version=${current}): ${msg}`);
6136
+ throw new Error(`Migration ${i} failed (db at version=${current}): ${msg}`);
6134
6137
  }
6138
+ await db.prepare(`INSERT INTO ${META_TABLE} (idx, applied_at) VALUES (?, ?)`).bind(i, (/* @__PURE__ */ new Date()).toISOString()).run();
6135
6139
  current = i + 1;
6136
- await db.exec(`PRAGMA user_version = ${current}`);
6137
6140
  }
6138
6141
  return { fromVersion, toVersion: current, applied: current - fromVersion };
6139
6142
  }