datasette-ts 0.0.2 → 0.0.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/cli.js +77 -32
- package/dist/cli.js.map +3 -3
- package/package.json +1 -1
- package/scripts/build.mjs +8 -0
- package/scripts/cloudflare-deploy-helpers.mjs +77 -30
package/package.json
CHANGED
package/scripts/build.mjs
CHANGED
|
@@ -23,6 +23,14 @@ await build({
|
|
|
23
23
|
platform: "node",
|
|
24
24
|
format: "esm",
|
|
25
25
|
target: ["node24"],
|
|
26
|
+
banner: {
|
|
27
|
+
js: [
|
|
28
|
+
"#!/usr/bin/env node",
|
|
29
|
+
'import { createRequire } from "node:module";',
|
|
30
|
+
"const require = createRequire(import.meta.url);",
|
|
31
|
+
"",
|
|
32
|
+
].join("\n"),
|
|
33
|
+
},
|
|
26
34
|
external: sharedExternals,
|
|
27
35
|
});
|
|
28
36
|
|
|
@@ -1,8 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
2
|
import { createHash } from "node:crypto";
|
|
3
|
-
import { createReadStream } from "node:fs";
|
|
4
|
-
import { mkdir, stat,
|
|
3
|
+
import { createReadStream, createWriteStream } from "node:fs";
|
|
4
|
+
import { mkdir, stat, unlink } from "node:fs/promises";
|
|
5
|
+
import { once } from "node:events";
|
|
5
6
|
import path from "node:path";
|
|
7
|
+
import { createInterface } from "node:readline";
|
|
8
|
+
import { pipeline } from "node:stream/promises";
|
|
6
9
|
import { pathToFileURL } from "node:url";
|
|
7
10
|
import { createClient } from "@libsql/client";
|
|
8
11
|
|
|
@@ -10,13 +13,15 @@ export async function dumpSqliteForD1(options) {
|
|
|
10
13
|
const baseName =
|
|
11
14
|
options.outputName ?? path.basename(options.dbFile, path.extname(options.dbFile));
|
|
12
15
|
const outputPath = path.join(options.outputDir, `${baseName}.sql`);
|
|
16
|
+
const rawPath = path.join(options.outputDir, `${baseName}.raw.sql`);
|
|
13
17
|
|
|
14
18
|
await mkdir(options.outputDir, { recursive: true });
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
19
|
+
await dumpSqliteToFile(options.dbFile, rawPath);
|
|
20
|
+
try {
|
|
21
|
+
await normalizeDumpFile(rawPath, outputPath);
|
|
22
|
+
} finally {
|
|
23
|
+
await unlink(rawPath).catch(() => undefined);
|
|
24
|
+
}
|
|
20
25
|
|
|
21
26
|
return outputPath;
|
|
22
27
|
}
|
|
@@ -158,48 +163,90 @@ function escapeIdentifier(name) {
|
|
|
158
163
|
return `"${escaped}"`;
|
|
159
164
|
}
|
|
160
165
|
|
|
161
|
-
function
|
|
162
|
-
const lines = rawDump.split("\n");
|
|
163
|
-
const output = [];
|
|
166
|
+
async function normalizeDumpFile(inputPath, outputPath) {
|
|
164
167
|
const tablesInOrder = [];
|
|
165
168
|
const viewsInOrder = [];
|
|
166
|
-
|
|
169
|
+
await forEachLine(inputPath, (line) => {
|
|
167
170
|
const tableMatch = line.match(/^CREATE TABLE\s+("?[^"]+"?)/i);
|
|
168
171
|
if (tableMatch) {
|
|
169
172
|
tablesInOrder.push(tableMatch[1].replace(/\s*\($/, ""));
|
|
170
|
-
|
|
173
|
+
return;
|
|
171
174
|
}
|
|
172
175
|
const viewMatch = line.match(/^CREATE VIEW\s+("?[^"]+"?)/i);
|
|
173
176
|
if (viewMatch) {
|
|
174
177
|
viewsInOrder.push(viewMatch[1].replace(/\s*\($/, ""));
|
|
175
178
|
}
|
|
176
|
-
}
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
const outputStream = createWriteStream(outputPath, { encoding: "utf8" });
|
|
177
182
|
for (const viewName of viewsInOrder.reverse()) {
|
|
178
|
-
|
|
183
|
+
await writeLine(outputStream, `DROP VIEW IF EXISTS ${viewName};`);
|
|
179
184
|
}
|
|
180
185
|
for (const tableName of tablesInOrder.reverse()) {
|
|
181
|
-
|
|
186
|
+
await writeLine(outputStream, `DROP TABLE IF EXISTS ${tableName};`);
|
|
182
187
|
}
|
|
183
|
-
|
|
188
|
+
await forEachLine(inputPath, async (line) => {
|
|
184
189
|
if (line === "BEGIN TRANSACTION;" || line === "COMMIT;") {
|
|
185
|
-
|
|
190
|
+
return;
|
|
186
191
|
}
|
|
187
192
|
if (line.startsWith("PRAGMA foreign_keys=")) {
|
|
188
|
-
|
|
189
|
-
}
|
|
190
|
-
const tableMatch = line.match(/^CREATE TABLE\s+("?[^"]+"?)/i);
|
|
191
|
-
if (tableMatch) {
|
|
192
|
-
output.push(line);
|
|
193
|
-
continue;
|
|
193
|
+
return;
|
|
194
194
|
}
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
195
|
+
await writeLine(outputStream, line);
|
|
196
|
+
});
|
|
197
|
+
outputStream.end();
|
|
198
|
+
await once(outputStream, "finish");
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
async function dumpSqliteToFile(dbFile, outputPath) {
|
|
202
|
+
const child = spawn("sqlite3", [dbFile, ".dump"], {
|
|
203
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
204
|
+
});
|
|
205
|
+
let stderr = "";
|
|
206
|
+
if (child.stderr) {
|
|
207
|
+
child.stderr.setEncoding("utf8");
|
|
208
|
+
child.stderr.on("data", (chunk) => {
|
|
209
|
+
stderr += chunk;
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
const stdout = child.stdout;
|
|
213
|
+
if (!stdout) {
|
|
214
|
+
const [error] = await once(child, "error");
|
|
215
|
+
throw error ?? new Error("sqlite3 stdout is unavailable.");
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
const outputStream = createWriteStream(outputPath, { encoding: "utf8" });
|
|
219
|
+
child.once("error", (error) => {
|
|
220
|
+
stdout.destroy(error);
|
|
221
|
+
outputStream.destroy(error);
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
await pipeline(stdout, outputStream);
|
|
225
|
+
const [code, signal] = await once(child, "close");
|
|
226
|
+
if (code !== 0) {
|
|
227
|
+
const suffix = signal ? ` (signal ${signal})` : "";
|
|
228
|
+
const message = stderr.trim() || `sqlite3 exited with code ${code ?? "unknown"}${suffix}`;
|
|
229
|
+
throw new Error(message);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
async function forEachLine(filePath, handler) {
|
|
234
|
+
const stream = createReadStream(filePath, { encoding: "utf8" });
|
|
235
|
+
const rl = createInterface({ input: stream, crlfDelay: Infinity });
|
|
236
|
+
try {
|
|
237
|
+
for await (const line of rl) {
|
|
238
|
+
await handler(line);
|
|
199
239
|
}
|
|
200
|
-
|
|
240
|
+
} finally {
|
|
241
|
+
rl.close();
|
|
242
|
+
stream.close();
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
async function writeLine(stream, line) {
|
|
247
|
+
if (!stream.write(`${line}\n`)) {
|
|
248
|
+
await once(stream, "drain");
|
|
201
249
|
}
|
|
202
|
-
return output.join("\n");
|
|
203
250
|
}
|
|
204
251
|
|
|
205
252
|
async function hashFile(filePath) {
|