datasette-ts 0.0.15 → 0.0.17

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/cli.js CHANGED
@@ -6372,7 +6372,7 @@ function openNodeSqlite(options) {
6372
6372
  sql: sql2,
6373
6373
  args: params ?? []
6374
6374
  });
6375
- const rows = normalizeLibsqlRows2(result);
6375
+ const rows = normalizeLibsqlRows(result);
6376
6376
  const columns = normalizeLibsqlColumns(result, rows);
6377
6377
  return { rows, columns };
6378
6378
  },
@@ -6409,7 +6409,7 @@ function normalizeLibsqlColumns(result, rows) {
6409
6409
  }
6410
6410
  return rows[0] ? Object.keys(rows[0]) : [];
6411
6411
  }
6412
- function normalizeLibsqlRows2(result) {
6412
+ function normalizeLibsqlRows(result) {
6413
6413
  const rows = Array.isArray(result.rows) ? result.rows : [];
6414
6414
  if (!rows.length) {
6415
6415
  return [];
@@ -6471,7 +6471,7 @@ var init_sqlite = __esm({
6471
6471
  });
6472
6472
 
6473
6473
  // src/db/introspection.ts
6474
- function asString2(value, fallback = "") {
6474
+ function asString(value, fallback = "") {
6475
6475
  if (typeof value === "string") {
6476
6476
  return value;
6477
6477
  }
@@ -6480,7 +6480,7 @@ function asString2(value, fallback = "") {
6480
6480
  }
6481
6481
  return String(value);
6482
6482
  }
6483
- function asNumber2(value, fallback = 0) {
6483
+ function asNumber(value, fallback = 0) {
6484
6484
  if (typeof value === "number") {
6485
6485
  return value;
6486
6486
  }
@@ -6490,7 +6490,7 @@ function asNumber2(value, fallback = 0) {
6490
6490
  }
6491
6491
  return fallback;
6492
6492
  }
6493
- function asNullableString2(value) {
6493
+ function asNullableString(value) {
6494
6494
  if (value == null) {
6495
6495
  return null;
6496
6496
  }
@@ -6516,7 +6516,7 @@ async function listTables(client) {
6516
6516
  "select name, type, sql from sqlite_master where type in ('table', 'view') order by name"
6517
6517
  );
6518
6518
  return rows.filter((row) => {
6519
- const name = asString2(row.name);
6519
+ const name = asString(row.name);
6520
6520
  return !name.startsWith(SQLITE_INTERNAL_PREFIX);
6521
6521
  });
6522
6522
  }
@@ -6525,12 +6525,12 @@ async function tableColumns2(client, tableName) {
6525
6525
  `pragma table_info(${escapeIdentifier2(tableName)})`
6526
6526
  );
6527
6527
  return rows.map((row) => ({
6528
- name: asString2(row.name),
6529
- type: asString2(row.type),
6530
- notNull: asNumber2(row.notnull) === 1,
6531
- defaultValue: asNullableString2(row.dflt_value),
6532
- primaryKey: asNumber2(row.pk) > 0,
6533
- primaryKeyIndex: asNumber2(row.pk)
6528
+ name: asString(row.name),
6529
+ type: asString(row.type),
6530
+ notNull: asNumber(row.notnull) === 1,
6531
+ defaultValue: asNullableString(row.dflt_value),
6532
+ primaryKey: asNumber(row.pk) > 0,
6533
+ primaryKeyIndex: asNumber(row.pk)
6534
6534
  }));
6535
6535
  }
6536
6536
  async function tableForeignKeys2(client, tableName) {
@@ -6538,23 +6538,23 @@ async function tableForeignKeys2(client, tableName) {
6538
6538
  `pragma foreign_key_list(${escapeIdentifier2(tableName)})`
6539
6539
  );
6540
6540
  return rows.map((row) => ({
6541
- table: asString2(row.table),
6542
- from: asString2(row.from),
6543
- to: asString2(row.to),
6544
- onUpdate: asString2(row.on_update),
6545
- onDelete: asString2(row.on_delete),
6546
- match: asString2(row.match),
6547
- seq: asNumber2(row.seq),
6548
- id: asNumber2(row.id)
6541
+ table: asString(row.table),
6542
+ from: asString(row.from),
6543
+ to: asString(row.to),
6544
+ onUpdate: asString(row.on_update),
6545
+ onDelete: asString(row.on_delete),
6546
+ match: asString(row.match),
6547
+ seq: asNumber(row.seq),
6548
+ id: asNumber(row.id)
6549
6549
  }));
6550
6550
  }
6551
6551
  async function introspectDatabase2(client) {
6552
6552
  const rows = await listTables(client);
6553
6553
  const tables = {};
6554
6554
  for (const row of rows) {
6555
- const name = asString2(row.name);
6556
- const type = asString2(row.type);
6557
- const sql2 = asNullableString2(row.sql);
6555
+ const name = asString(row.name);
6556
+ const type = asString(row.type);
6557
+ const sql2 = asNullableString(row.sql);
6558
6558
  const virtual = type === "table" && isVirtualTable2(sql2);
6559
6559
  const infoType = type === "view" ? "view" : virtual ? "virtual" : "table";
6560
6560
  const columns = await tableColumns2(client, name);
@@ -23689,38 +23689,117 @@ var init_node4 = __esm({
23689
23689
  import { parseArgs as parseArgs2 } from "node:util";
23690
23690
 
23691
23691
  // src/cli/deploy-cloudflare.ts
23692
- import { mkdir as mkdir2, stat as stat2, writeFile } from "node:fs/promises";
23692
+ import { mkdir as mkdir2, stat as stat2, writeFile as writeFile2 } from "node:fs/promises";
23693
23693
  import { dirname, extname, join, relative, resolve } from "node:path";
23694
23694
  import { fileURLToPath } from "node:url";
23695
23695
  import alchemy from "alchemy";
23696
23696
  import { Assets, D1Database, Worker } from "alchemy/cloudflare";
23697
23697
 
23698
23698
  // scripts/cloudflare-deploy-helpers.mjs
23699
- import { spawn } from "node:child_process";
23700
23699
  import { createHash } from "node:crypto";
23701
- import { createReadStream, createWriteStream } from "node:fs";
23702
- import { mkdir, stat, unlink } from "node:fs/promises";
23703
- import { once } from "node:events";
23700
+ import { createReadStream } from "node:fs";
23701
+ import { mkdir, stat, writeFile } from "node:fs/promises";
23704
23702
  import path from "node:path";
23705
- import { createInterface } from "node:readline";
23706
- import { pipeline } from "node:stream/promises";
23707
23703
  import { pathToFileURL } from "node:url";
23708
23704
  import { createClient } from "@libsql/client";
23709
23705
  async function dumpSqliteForD1(options) {
23710
23706
  const baseName = options.outputName ?? path.basename(options.dbFile, path.extname(options.dbFile));
23711
23707
  const outputPath = path.join(options.outputDir, `${baseName}.sql`);
23712
- const rawPath = path.join(options.outputDir, `${baseName}.raw.sql`);
23713
- const log = typeof options.log === "function" ? options.log : null;
23714
- const progressIntervalMs = typeof options.progressIntervalMs === "number" && Number.isFinite(options.progressIntervalMs) ? options.progressIntervalMs : 5e3;
23708
+ const log = options.log ?? null;
23715
23709
  await mkdir(options.outputDir, { recursive: true });
23716
- await dumpSqliteToFile(options.dbFile, rawPath, { log, progressIntervalMs });
23710
+ log?.("Generating D1 import SQL");
23711
+ const db = createReadonlyClient(options.dbFile);
23717
23712
  try {
23718
- await normalizeDumpFile(rawPath, outputPath, { log });
23713
+ const sql2 = await generateD1Dump(db, log);
23714
+ await writeFile(outputPath, sql2, "utf8");
23715
+ const { size } = await stat(outputPath);
23716
+ log?.(`D1 import SQL ready (${formatBytes(size)})`);
23719
23717
  } finally {
23720
- await unlink(rawPath).catch(() => void 0);
23718
+ db.close();
23721
23719
  }
23722
23720
  return outputPath;
23723
23721
  }
23722
+ async function generateD1Dump(db, log) {
23723
+ const chunks = [];
23724
+ const objects = await executeRows(
23725
+ db,
23726
+ `SELECT type, name, sql, tbl_name
23727
+ FROM sqlite_master
23728
+ WHERE sql IS NOT NULL
23729
+ AND name NOT LIKE 'sqlite_%'
23730
+ ORDER BY
23731
+ CASE type
23732
+ WHEN 'table' THEN 1
23733
+ WHEN 'index' THEN 2
23734
+ WHEN 'trigger' THEN 3
23735
+ WHEN 'view' THEN 4
23736
+ ELSE 5
23737
+ END,
23738
+ name`
23739
+ );
23740
+ const tables = objects.filter((o) => o.type === "table" && !isVirtualTable(o.sql));
23741
+ const views = objects.filter((o) => o.type === "view");
23742
+ const indexes = objects.filter((o) => o.type === "index");
23743
+ const triggers = objects.filter((o) => o.type === "trigger");
23744
+ for (const view of [...views].reverse()) {
23745
+ chunks.push(`DROP VIEW IF EXISTS ${escapeIdentifier(view.name)};`);
23746
+ }
23747
+ for (const table of [...tables].reverse()) {
23748
+ chunks.push(`DROP TABLE IF EXISTS ${escapeIdentifier(table.name)};`);
23749
+ }
23750
+ for (const table of tables) {
23751
+ chunks.push(`${normalizeSql(table.sql)};`);
23752
+ }
23753
+ let totalRows = 0;
23754
+ for (const table of tables) {
23755
+ const rowCount = await dumpTableData(db, table.name, chunks);
23756
+ totalRows += rowCount;
23757
+ }
23758
+ log?.(`Exported ${totalRows.toLocaleString()} rows from ${tables.length} tables`);
23759
+ for (const index of indexes) {
23760
+ if (!index.sql) continue;
23761
+ chunks.push(`${normalizeSql(index.sql)};`);
23762
+ }
23763
+ for (const view of views) {
23764
+ chunks.push(`${normalizeSql(view.sql)};`);
23765
+ }
23766
+ for (const trigger of triggers) {
23767
+ chunks.push(`${normalizeSql(trigger.sql)};`);
23768
+ }
23769
+ return chunks.join("\n") + "\n";
23770
+ }
23771
+ async function dumpTableData(db, tableName, chunks) {
23772
+ const rows = await executeRows(db, `SELECT * FROM ${escapeIdentifier(tableName)}`);
23773
+ if (rows.length === 0) return 0;
23774
+ const columns = Object.keys(rows[0]);
23775
+ const columnList = columns.map(escapeIdentifier).join(", ");
23776
+ for (const row of rows) {
23777
+ const values = columns.map((col) => escapeSqlValue(row[col])).join(", ");
23778
+ chunks.push(`INSERT INTO ${escapeIdentifier(tableName)} (${columnList}) VALUES (${values});`);
23779
+ }
23780
+ return rows.length;
23781
+ }
23782
+ function escapeSqlValue(value) {
23783
+ if (value === null || value === void 0) {
23784
+ return "NULL";
23785
+ }
23786
+ if (typeof value === "bigint") {
23787
+ return String(value);
23788
+ }
23789
+ if (typeof value === "number") {
23790
+ return Number.isFinite(value) ? String(value) : "NULL";
23791
+ }
23792
+ if (typeof value === "boolean") {
23793
+ return value ? "1" : "0";
23794
+ }
23795
+ if (value instanceof Uint8Array || Buffer.isBuffer(value)) {
23796
+ return `X'${Buffer.from(value).toString("hex")}'`;
23797
+ }
23798
+ return `'${String(value).replace(/'/g, "''")}'`;
23799
+ }
23800
+ function normalizeSql(sql2) {
23801
+ return sql2.replace(/\s+/g, " ").trim();
23802
+ }
23724
23803
  async function loadSchemaFromFile(dbFile) {
23725
23804
  const db = createReadonlyClient(dbFile);
23726
23805
  try {
@@ -23730,9 +23809,11 @@ async function loadSchemaFromFile(dbFile) {
23730
23809
  }
23731
23810
  }
23732
23811
  async function loadInspectDataFromFile(dbFile, databaseName) {
23733
- const stats = await stat(dbFile);
23734
- const hash = await hashFile(dbFile);
23735
- const tables = await countTables(dbFile);
23812
+ const [stats, hash, tables] = await Promise.all([
23813
+ stat(dbFile),
23814
+ hashFile(dbFile),
23815
+ countTables(dbFile)
23816
+ ]);
23736
23817
  return {
23737
23818
  [databaseName]: {
23738
23819
  hash,
@@ -23745,22 +23826,21 @@ async function loadInspectDataFromFile(dbFile, databaseName) {
23745
23826
  async function introspectDatabase(db) {
23746
23827
  const rows = await executeRows(
23747
23828
  db,
23748
- "select name, type, sql from sqlite_master where type in ('table', 'view') order by name"
23829
+ "SELECT name, type, sql FROM sqlite_master WHERE type IN ('table', 'view') ORDER BY name"
23749
23830
  );
23750
23831
  const tables = {};
23751
23832
  for (const row of rows) {
23752
- const name = asString(row.name);
23753
- if (name.startsWith("sqlite_")) {
23754
- continue;
23755
- }
23756
- const type = asString(row.type);
23757
- const sql2 = asNullableString(row.sql);
23833
+ const name = String(row.name ?? "");
23834
+ if (name.startsWith("sqlite_")) continue;
23835
+ const type = String(row.type ?? "");
23836
+ const sql2 = row.sql ? String(row.sql) : null;
23758
23837
  const virtual = type === "table" && isVirtualTable(sql2);
23759
23838
  const infoType = type === "view" ? "view" : virtual ? "virtual" : "table";
23760
- const columns = await tableColumns(db, name);
23761
- const foreignKeys = await tableForeignKeys(db, name);
23762
- const primaryKeys = columns.filter((column) => column.primaryKey).sort((a, b) => a.primaryKeyIndex - b.primaryKeyIndex).map((column) => column.name);
23763
- const isFts = isFtsTable(sql2);
23839
+ const [columns, foreignKeys] = await Promise.all([
23840
+ tableColumns(db, name),
23841
+ tableForeignKeys(db, name)
23842
+ ]);
23843
+ const primaryKeys = columns.filter((col) => col.primaryKey).sort((a, b) => a.primaryKeyIndex - b.primaryKeyIndex).map((col) => col.name);
23764
23844
  tables[name] = {
23765
23845
  name,
23766
23846
  type: infoType,
@@ -23768,273 +23848,112 @@ async function introspectDatabase(db) {
23768
23848
  columns,
23769
23849
  primaryKeys,
23770
23850
  foreignKeys,
23771
- isFts
23851
+ isFts: isFtsTable(sql2)
23772
23852
  };
23773
23853
  }
23774
23854
  return { tables };
23775
23855
  }
23776
23856
  async function tableColumns(db, tableName) {
23777
- const rows = await executeRows(db, `pragma table_info(${escapeIdentifier(tableName)})`);
23857
+ const rows = await executeRows(db, `PRAGMA table_info(${escapeIdentifier(tableName)})`);
23778
23858
  return rows.map((row) => ({
23779
- name: asString(row.name),
23780
- type: asString(row.type),
23781
- notNull: asNumber(row.notnull) === 1,
23782
- defaultValue: asNullableString(row.dflt_value),
23783
- primaryKey: asNumber(row.pk) > 0,
23784
- primaryKeyIndex: asNumber(row.pk)
23859
+ name: String(row.name ?? ""),
23860
+ type: String(row.type ?? ""),
23861
+ notNull: Number(row.notnull) === 1,
23862
+ defaultValue: row.dflt_value != null ? String(row.dflt_value) : null,
23863
+ primaryKey: Number(row.pk) > 0,
23864
+ primaryKeyIndex: Number(row.pk)
23785
23865
  }));
23786
23866
  }
23787
23867
  async function tableForeignKeys(db, tableName) {
23788
- const rows = await executeRows(db, `pragma foreign_key_list(${escapeIdentifier(tableName)})`);
23868
+ const rows = await executeRows(db, `PRAGMA foreign_key_list(${escapeIdentifier(tableName)})`);
23789
23869
  return rows.map((row) => ({
23790
- table: asString(row.table),
23791
- from: asString(row.from),
23792
- to: asString(row.to),
23793
- onUpdate: asString(row.on_update),
23794
- onDelete: asString(row.on_delete),
23795
- match: asString(row.match),
23796
- seq: asNumber(row.seq),
23797
- id: asNumber(row.id)
23870
+ table: String(row.table ?? ""),
23871
+ from: String(row.from ?? ""),
23872
+ to: String(row.to ?? ""),
23873
+ onUpdate: String(row.on_update ?? ""),
23874
+ onDelete: String(row.on_delete ?? ""),
23875
+ match: String(row.match ?? ""),
23876
+ seq: Number(row.seq ?? 0),
23877
+ id: Number(row.id ?? 0)
23798
23878
  }));
23799
23879
  }
23800
- function asString(value, fallback = "") {
23801
- if (typeof value === "string") {
23802
- return value;
23803
- }
23804
- if (value == null) {
23805
- return fallback;
23806
- }
23807
- return String(value);
23808
- }
23809
- function asNumber(value, fallback = 0) {
23810
- if (typeof value === "number") {
23811
- return value;
23812
- }
23813
- if (typeof value === "string" && value.trim() !== "") {
23814
- const parsed = Number(value);
23815
- return Number.isNaN(parsed) ? fallback : parsed;
23816
- }
23817
- return fallback;
23818
- }
23819
- function asNullableString(value) {
23820
- if (value == null) {
23821
- return null;
23822
- }
23823
- if (typeof value === "string") {
23824
- return value;
23825
- }
23826
- return String(value);
23827
- }
23828
23880
  function isVirtualTable(sql2) {
23829
- if (!sql2) {
23830
- return false;
23831
- }
23832
- return /create\s+virtual\s+table/i.test(sql2);
23881
+ return sql2 ? /create\s+virtual\s+table/i.test(sql2) : false;
23833
23882
  }
23834
23883
  function isFtsTable(sql2) {
23835
- if (!sql2) {
23836
- return false;
23837
- }
23838
- return /using\s+fts/i.test(sql2);
23884
+ return sql2 ? /using\s+fts/i.test(sql2) : false;
23839
23885
  }
23840
23886
  function escapeIdentifier(name) {
23841
- const escaped = String(name).replace(/"/g, '""');
23842
- return `"${escaped}"`;
23843
- }
23844
- async function normalizeDumpFile(inputPath, outputPath, { log } = {}) {
23845
- const tablesInOrder = [];
23846
- const viewsInOrder = [];
23847
- if (log) {
23848
- log(`Normalizing D1 import SQL: ${outputPath}`);
23849
- }
23850
- await forEachLine(inputPath, (line) => {
23851
- const tableMatch = line.match(/^CREATE TABLE\s+("?[^"]+"?)/i);
23852
- if (tableMatch) {
23853
- tablesInOrder.push(tableMatch[1].replace(/\s*\($/, ""));
23854
- return;
23855
- }
23856
- const viewMatch = line.match(/^CREATE VIEW\s+("?[^"]+"?)/i);
23857
- if (viewMatch) {
23858
- viewsInOrder.push(viewMatch[1].replace(/\s*\($/, ""));
23859
- }
23860
- });
23861
- const outputStream = createWriteStream(outputPath, { encoding: "utf8" });
23862
- for (const viewName of viewsInOrder.reverse()) {
23863
- await writeLine(outputStream, `DROP VIEW IF EXISTS ${viewName};`);
23864
- }
23865
- for (const tableName of tablesInOrder.reverse()) {
23866
- await writeLine(outputStream, `DROP TABLE IF EXISTS ${tableName};`);
23867
- }
23868
- await forEachLine(inputPath, async (line) => {
23869
- if (line === "BEGIN TRANSACTION;" || line === "COMMIT;") {
23870
- return;
23871
- }
23872
- if (line.startsWith("PRAGMA foreign_keys=")) {
23873
- return;
23874
- }
23875
- await writeLine(outputStream, line);
23876
- });
23877
- outputStream.end();
23878
- await once(outputStream, "finish");
23879
- if (log) {
23880
- const { size } = await stat(outputPath);
23881
- log(`D1 import SQL ready (${formatBytes(size)})`);
23882
- }
23883
- }
23884
- async function dumpSqliteToFile(dbFile, outputPath, { log, progressIntervalMs } = {}) {
23885
- if (log) {
23886
- log(`Dumping SQLite database via sqlite3 .dump`);
23887
- }
23888
- const child = spawn("sqlite3", [dbFile, ".dump"], {
23889
- stdio: ["ignore", "pipe", "pipe"]
23890
- });
23891
- let stderr = "";
23892
- if (child.stderr) {
23893
- child.stderr.setEncoding("utf8");
23894
- child.stderr.on("data", (chunk) => {
23895
- stderr += chunk;
23896
- });
23897
- }
23898
- const stdout = child.stdout;
23899
- if (!stdout) {
23900
- const [error] = await once(child, "error");
23901
- throw error ?? new Error("sqlite3 stdout is unavailable.");
23902
- }
23903
- const outputStream = createWriteStream(outputPath, { encoding: "utf8" });
23904
- child.once("error", (error) => {
23905
- stdout.destroy(error);
23906
- outputStream.destroy(error);
23907
- });
23908
- const stopProgress = log ? startProgressLogger(outputPath, log, progressIntervalMs) : () => void 0;
23909
- try {
23910
- await pipeline(stdout, outputStream);
23911
- } finally {
23912
- stopProgress();
23913
- }
23914
- const [code, signal] = await once(child, "close");
23915
- if (code !== 0) {
23916
- const suffix = signal ? ` (signal ${signal})` : "";
23917
- const message = stderr.trim() || `sqlite3 exited with code ${code ?? "unknown"}${suffix}`;
23918
- throw new Error(message);
23919
- }
23920
- if (log) {
23921
- const { size } = await stat(outputPath);
23922
- log(`SQLite dump completed (${formatBytes(size)})`);
23923
- }
23924
- }
23925
- async function forEachLine(filePath, handler) {
23926
- const stream = createReadStream(filePath, { encoding: "utf8" });
23927
- const rl = createInterface({ input: stream, crlfDelay: Infinity });
23928
- try {
23929
- for await (const line of rl) {
23930
- await handler(line);
23931
- }
23932
- } finally {
23933
- rl.close();
23934
- stream.close();
23935
- }
23936
- }
23937
- async function writeLine(stream, line) {
23938
- if (!stream.write(`${line}
23939
- `)) {
23940
- await once(stream, "drain");
23941
- }
23942
- }
23943
- function startProgressLogger(filePath, log, intervalMs) {
23944
- const interval = setInterval(() => {
23945
- void stat(filePath).then((info) => {
23946
- log(`Dump size: ${formatBytes(info.size)}`);
23947
- }).catch(() => void 0);
23948
- }, intervalMs);
23949
- return () => clearInterval(interval);
23887
+ return `"${String(name).replace(/"/g, '""')}"`;
23950
23888
  }
23951
23889
  function formatBytes(bytes) {
23952
- if (!Number.isFinite(bytes) || bytes < 0) {
23953
- return "0 B";
23954
- }
23890
+ if (!Number.isFinite(bytes) || bytes < 0) return "0 B";
23955
23891
  const units = ["B", "KB", "MB", "GB", "TB"];
23956
23892
  let value = bytes;
23957
- let index = 0;
23958
- while (value >= 1024 && index < units.length - 1) {
23893
+ let i = 0;
23894
+ while (value >= 1024 && i < units.length - 1) {
23959
23895
  value /= 1024;
23960
- index += 1;
23896
+ i++;
23961
23897
  }
23962
- const rounded = index === 0 ? value.toFixed(0) : value.toFixed(1);
23963
- return `${rounded} ${units[index]}`;
23898
+ return `${i === 0 ? value.toFixed(0) : value.toFixed(1)} ${units[i]}`;
23964
23899
  }
23965
23900
  async function hashFile(filePath) {
23966
- return new Promise((resolve2, reject) => {
23967
- const hash = createHash("sha256");
23968
- const stream = createReadStream(filePath, { highWaterMark: 1024 * 1024 });
23969
- stream.on("data", (chunk) => hash.update(chunk));
23970
- stream.on("error", reject);
23971
- stream.on("end", () => resolve2(hash.digest("hex")));
23972
- });
23901
+ const hash = createHash("sha256");
23902
+ const stream = createReadStream(filePath, { highWaterMark: 1024 * 1024 });
23903
+ for await (const chunk of stream) {
23904
+ hash.update(chunk);
23905
+ }
23906
+ return hash.digest("hex");
23973
23907
  }
23974
23908
  async function countTables(dbFile) {
23975
23909
  const db = createReadonlyClient(dbFile);
23976
23910
  try {
23977
- const rows = await executeRows(db, "select name from sqlite_master where type = 'table'");
23911
+ const rows = await executeRows(db, "SELECT name FROM sqlite_master WHERE type = 'table'");
23978
23912
  const tables = {};
23979
- for (const row of rows) {
23980
- const tableName = asString(row.name);
23981
- try {
23982
- const countRows = await executeRows(
23983
- db,
23984
- `select count(*) as count from ${escapeIdentifier(tableName)}`
23985
- );
23986
- const countRow = countRows[0];
23987
- const countValue = countRow?.count;
23988
- const count = typeof countValue === "number" ? countValue : Number(countValue ?? 0);
23989
- tables[tableName] = { count: Number.isNaN(count) ? 0 : count };
23990
- } catch {
23991
- tables[tableName] = { count: 0 };
23992
- }
23993
- }
23913
+ await Promise.all(
23914
+ rows.map(async (row) => {
23915
+ const tableName = String(row.name ?? "");
23916
+ try {
23917
+ const [countRow] = await executeRows(
23918
+ db,
23919
+ `SELECT count(*) as count FROM ${escapeIdentifier(tableName)}`
23920
+ );
23921
+ tables[tableName] = { count: Number(countRow?.count ?? 0) };
23922
+ } catch {
23923
+ tables[tableName] = { count: 0 };
23924
+ }
23925
+ })
23926
+ );
23994
23927
  return tables;
23995
23928
  } finally {
23996
23929
  db.close();
23997
23930
  }
23998
23931
  }
23999
23932
  function createReadonlyClient(dbFile) {
24000
- const fileUrl = pathToFileURL(dbFile);
24001
- return createClient({ url: fileUrl.toString() });
23933
+ return createClient({
23934
+ url: pathToFileURL(dbFile).toString(),
23935
+ intMode: "bigint"
23936
+ // Handle integers > MAX_SAFE_INTEGER
23937
+ });
24002
23938
  }
24003
23939
  async function executeRows(db, sql2, args = []) {
24004
23940
  const result = await db.execute({ sql: sql2, args });
24005
- return normalizeLibsqlRows(result);
24006
- }
24007
- function normalizeLibsqlRows(result) {
24008
- const rows = Array.isArray(result?.rows) ? result.rows : [];
24009
- if (!rows.length) {
24010
- return [];
24011
- }
24012
- const firstRow = rows[0];
24013
- if (firstRow && typeof firstRow === "object" && !Array.isArray(firstRow)) {
23941
+ const rows = result?.rows ?? [];
23942
+ if (!rows.length) return [];
23943
+ const first = rows[0];
23944
+ if (first && typeof first === "object" && !Array.isArray(first)) {
24014
23945
  return rows;
24015
23946
  }
24016
- const columns = Array.isArray(result?.columns) ? result.columns.map((column) => {
24017
- if (typeof column === "string") {
24018
- return column;
24019
- }
24020
- if (column && typeof column === "object" && "name" in column) {
24021
- return String(column.name ?? "");
24022
- }
24023
- return "";
24024
- }) : [];
24025
- if (!columns.length) {
24026
- return [];
24027
- }
23947
+ const columns = result?.columns ?? [];
23948
+ if (!columns.length) return [];
24028
23949
  return rows.map((row) => {
24029
23950
  const values = Array.isArray(row) ? row : [];
24030
- const mapped = {};
24031
- for (let index = 0; index < columns.length; index += 1) {
24032
- const column = columns[index];
24033
- if (column) {
24034
- mapped[column] = values[index];
24035
- }
23951
+ const obj = {};
23952
+ for (let i = 0; i < columns.length; i++) {
23953
+ const col = typeof columns[i] === "string" ? columns[i] : columns[i]?.name ?? "";
23954
+ if (col) obj[col] = values[i];
24036
23955
  }
24037
- return mapped;
23956
+ return obj;
24038
23957
  });
24039
23958
  }
24040
23959
 
@@ -24056,25 +23975,14 @@ async function runCloudflareDeploy(args) {
24056
23975
  logStep(`Worker entrypoint: ${workerEntrypoint}`);
24057
23976
  const assetsPath = join(packageRoot, "public");
24058
23977
  await assertFileExists(assetsPath, "assets directory");
24059
- let importFile;
24060
- try {
24061
- logStep("Exporting SQLite for D1 import");
24062
- importFile = await dumpSqliteForD1({
24063
- dbFile: options.dbFile,
24064
- outputDir: options.importsDir,
24065
- outputName: options.d1Name,
24066
- log: logStep,
24067
- progressIntervalMs: 5e3
24068
- });
24069
- logStep(`D1 import file: ${importFile}`);
24070
- } catch (error) {
24071
- if (isSqliteCliMissing(error)) {
24072
- throw new Error(
24073
- "sqlite3 is required to export your database. Install sqlite3 and retry."
24074
- );
24075
- }
24076
- throw error;
24077
- }
23978
+ logStep("Exporting SQLite for D1 import");
23979
+ const importFile = await dumpSqliteForD1({
23980
+ dbFile: options.dbFile,
23981
+ outputDir: options.importsDir,
23982
+ outputName: options.d1Name,
23983
+ log: logStep
23984
+ });
23985
+ logStep(`D1 import file: ${importFile}`);
24078
23986
  logStep("Loading schema");
24079
23987
  const schema = await loadSchemaFromFile(options.dbFile);
24080
23988
  let inspectData = null;
@@ -24326,12 +24234,6 @@ async function assertFileExists(path7, label) {
24326
24234
  throw new Error(`${label} not found: ${path7}`);
24327
24235
  }
24328
24236
  }
24329
- function isSqliteCliMissing(error) {
24330
- if (!error || typeof error !== "object") {
24331
- return false;
24332
- }
24333
- return "code" in error && error.code === "ENOENT";
24334
- }
24335
24237
  function logStep(message) {
24336
24238
  console.log(`[datasette-ts] ${message}`);
24337
24239
  }
@@ -24390,7 +24292,7 @@ async function createEmbeddedWorkerEntrypoint(options) {
24390
24292
  "};",
24391
24293
  ""
24392
24294
  ].join("\n");
24393
- await writeFile(entrypointPath, contents, "utf8");
24295
+ await writeFile2(entrypointPath, contents, "utf8");
24394
24296
  options.log(`Embedded worker entrypoint: ${entrypointPath}`);
24395
24297
  return entrypointPath;
24396
24298
  }
@@ -24400,7 +24302,7 @@ function toPosixPath(value) {
24400
24302
 
24401
24303
  // src/cli/serve.ts
24402
24304
  init_registry();
24403
- import { stat as stat5, writeFile as writeFile2 } from "node:fs/promises";
24305
+ import { stat as stat5, writeFile as writeFile3 } from "node:fs/promises";
24404
24306
  import { join as join2 } from "node:path";
24405
24307
 
24406
24308
  // src/core/inspect.ts
@@ -24573,7 +24475,7 @@ async function runInspectCommand(args) {
24573
24475
  const data = await inspectDatabases(databasePaths);
24574
24476
  const json = JSON.stringify(data, null, 2);
24575
24477
  if (inspectFile) {
24576
- await writeFile2(inspectFile, json, "utf8");
24478
+ await writeFile3(inspectFile, json, "utf8");
24577
24479
  return;
24578
24480
  }
24579
24481
  process.stdout.write(`${json}