@hot-updater/test-utils 1.0.0-rc.16 → 1.0.0-rc.21
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/README.md +104 -17
- package/dist/index.d.mts +236 -158
- package/dist/index.mjs +3051 -1704
- package/dist/node.cjs +210 -0
- package/dist/node.d.cts +49 -4
- package/dist/node.d.mts +49 -4
- package/dist/node.mjs +203 -1
- package/dist/react-native.cjs +177 -0
- package/dist/react-native.d.cts +104 -0
- package/dist/react-native.d.mts +104 -0
- package/dist/react-native.mjs +174 -0
- package/package.json +44 -6
package/dist/node.cjs
CHANGED
|
@@ -36,6 +36,47 @@ let node_net = require("node:net");
|
|
|
36
36
|
node_net = __toESM(node_net, 1);
|
|
37
37
|
let node_http = require("node:http");
|
|
38
38
|
let execa = require("execa");
|
|
39
|
+
//#region src/d1TestDatabase.ts
|
|
40
|
+
/**
|
|
41
|
+
* A D1 database over `node:sqlite`, answering as D1 does, after it runs
|
|
42
|
+
* `statements`, such as a provider's schema: what a D1 executor's specs
|
|
43
|
+
* run on without Cloudflare. `db` is a database the spec opens, such as
|
|
44
|
+
* `new DatabaseSync(":memory:")`.
|
|
45
|
+
*/
|
|
46
|
+
const createD1TestDatabase = (db, statements = []) => {
|
|
47
|
+
for (const sql of statements) db.exec(sql);
|
|
48
|
+
const run = (sql, params) => {
|
|
49
|
+
const statement = db.prepare(sql);
|
|
50
|
+
const values = params;
|
|
51
|
+
return statement.columns().length > 0 ? {
|
|
52
|
+
success: true,
|
|
53
|
+
results: statement.all(...values),
|
|
54
|
+
meta: {}
|
|
55
|
+
} : {
|
|
56
|
+
success: true,
|
|
57
|
+
results: [],
|
|
58
|
+
meta: { changes: Number(statement.run(...values).changes) }
|
|
59
|
+
};
|
|
60
|
+
};
|
|
61
|
+
/** Runs statements atomically, as `batch` does. */
|
|
62
|
+
const batch = (statements) => {
|
|
63
|
+
db.exec("BEGIN IMMEDIATE");
|
|
64
|
+
try {
|
|
65
|
+
const results = statements.map(({ sql, params }) => run(sql, params));
|
|
66
|
+
db.exec("COMMIT");
|
|
67
|
+
return results;
|
|
68
|
+
} catch (error) {
|
|
69
|
+
db.exec("ROLLBACK");
|
|
70
|
+
throw error;
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
return {
|
|
74
|
+
db,
|
|
75
|
+
run,
|
|
76
|
+
batch
|
|
77
|
+
};
|
|
78
|
+
};
|
|
79
|
+
//#endregion
|
|
39
80
|
//#region ../../node_modules/.pnpm/workspace-tools@0.41.7/node_modules/workspace-tools/lib/graph/getPackageDependencies.js
|
|
40
81
|
var require_getPackageDependencies = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
41
82
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
@@ -20413,6 +20454,167 @@ async function cleanupServer(baseUrl, serverProcess, testDbPath) {
|
|
|
20413
20454
|
} catch {}
|
|
20414
20455
|
}
|
|
20415
20456
|
//#endregion
|
|
20457
|
+
//#region src/sqlTestExecutors.ts
|
|
20458
|
+
/** Test executors for the SQL core; provider executors arrive with D1–D3. */
|
|
20459
|
+
const pgliteExecutor = (db) => {
|
|
20460
|
+
const over = (runner) => ({ execute: async ({ sql, params }) => {
|
|
20461
|
+
const result = await runner.query(sql, [...params]);
|
|
20462
|
+
return {
|
|
20463
|
+
rows: result.rows,
|
|
20464
|
+
changes: result.affectedRows ?? 0
|
|
20465
|
+
};
|
|
20466
|
+
} });
|
|
20467
|
+
return {
|
|
20468
|
+
dialect: "postgresql",
|
|
20469
|
+
...over(db),
|
|
20470
|
+
transaction: (fn) => db.transaction((tx) => fn(over(tx)))
|
|
20471
|
+
};
|
|
20472
|
+
};
|
|
20473
|
+
/** One connection, so statements and transactions run one at a time. */
|
|
20474
|
+
const sqliteExecutor = (db) => {
|
|
20475
|
+
let queue = Promise.resolve();
|
|
20476
|
+
const serial = (task) => {
|
|
20477
|
+
const next = queue.then(task);
|
|
20478
|
+
queue = next.catch(() => void 0);
|
|
20479
|
+
return next;
|
|
20480
|
+
};
|
|
20481
|
+
const execute = async ({ sql, params }) => {
|
|
20482
|
+
const statement = db.prepare(sql);
|
|
20483
|
+
const values = params;
|
|
20484
|
+
if (statement.columns().length > 0) return {
|
|
20485
|
+
rows: statement.all(...values),
|
|
20486
|
+
changes: 0
|
|
20487
|
+
};
|
|
20488
|
+
return {
|
|
20489
|
+
rows: [],
|
|
20490
|
+
changes: Number(statement.run(...values).changes)
|
|
20491
|
+
};
|
|
20492
|
+
};
|
|
20493
|
+
return {
|
|
20494
|
+
dialect: "sqlite",
|
|
20495
|
+
execute: (statement) => serial(() => execute(statement)),
|
|
20496
|
+
transaction: (fn) => serial(async () => {
|
|
20497
|
+
db.exec("BEGIN IMMEDIATE");
|
|
20498
|
+
try {
|
|
20499
|
+
const result = await fn({ execute });
|
|
20500
|
+
db.exec("COMMIT");
|
|
20501
|
+
return result;
|
|
20502
|
+
} catch (error) {
|
|
20503
|
+
db.exec("ROLLBACK");
|
|
20504
|
+
throw error;
|
|
20505
|
+
}
|
|
20506
|
+
})
|
|
20507
|
+
};
|
|
20508
|
+
};
|
|
20509
|
+
/**
|
|
20510
|
+
* An executor without interactive transactions, as D1's: writes run as one
|
|
20511
|
+
* atomic batch, here in a SQLite transaction that rolls back on any error.
|
|
20512
|
+
*/
|
|
20513
|
+
const sqliteBatchExecutor = (db) => {
|
|
20514
|
+
const executor = sqliteExecutor(db);
|
|
20515
|
+
return {
|
|
20516
|
+
dialect: "sqlite",
|
|
20517
|
+
execute: executor.execute,
|
|
20518
|
+
transaction: () => {
|
|
20519
|
+
throw new Error("A batch executor has no interactive transactions.");
|
|
20520
|
+
},
|
|
20521
|
+
batch: (statements) => executor.transaction(async (connection) => {
|
|
20522
|
+
const results = [];
|
|
20523
|
+
for (const statement of statements) results.push(await connection.execute(statement));
|
|
20524
|
+
return results;
|
|
20525
|
+
})
|
|
20526
|
+
};
|
|
20527
|
+
};
|
|
20528
|
+
/** PGlite without interactive transactions, as an RPC applying a batch would be. */
|
|
20529
|
+
const pgliteBatchExecutor = (db) => {
|
|
20530
|
+
const executor = pgliteExecutor(db);
|
|
20531
|
+
return {
|
|
20532
|
+
dialect: "postgresql",
|
|
20533
|
+
execute: executor.execute,
|
|
20534
|
+
transaction: () => {
|
|
20535
|
+
throw new Error("A batch executor has no interactive transactions.");
|
|
20536
|
+
},
|
|
20537
|
+
batch: (statements) => executor.transaction(async (connection) => {
|
|
20538
|
+
const results = [];
|
|
20539
|
+
for (const statement of statements) results.push(await connection.execute(statement));
|
|
20540
|
+
return results;
|
|
20541
|
+
})
|
|
20542
|
+
};
|
|
20543
|
+
};
|
|
20544
|
+
const pgExecutor = (pool) => {
|
|
20545
|
+
const over = (runner) => ({ execute: async ({ sql, params }) => {
|
|
20546
|
+
const result = await runner.query(sql, [...params]);
|
|
20547
|
+
return {
|
|
20548
|
+
rows: result.rows,
|
|
20549
|
+
changes: result.rowCount ?? 0
|
|
20550
|
+
};
|
|
20551
|
+
} });
|
|
20552
|
+
return {
|
|
20553
|
+
dialect: "postgresql",
|
|
20554
|
+
...over(pool),
|
|
20555
|
+
async transaction(fn) {
|
|
20556
|
+
const client = await pool.connect();
|
|
20557
|
+
try {
|
|
20558
|
+
await client.query("BEGIN");
|
|
20559
|
+
const result = await fn(over(client));
|
|
20560
|
+
await client.query("COMMIT");
|
|
20561
|
+
return result;
|
|
20562
|
+
} catch (error) {
|
|
20563
|
+
await client.query("ROLLBACK").catch(() => void 0);
|
|
20564
|
+
throw error;
|
|
20565
|
+
} finally {
|
|
20566
|
+
client.release();
|
|
20567
|
+
}
|
|
20568
|
+
}
|
|
20569
|
+
};
|
|
20570
|
+
};
|
|
20571
|
+
/** A pooled PostgreSQL batch: one READ COMMITTED transaction per write, as Supabase's apply RPC runs. */
|
|
20572
|
+
const pgBatchExecutor = (pool) => {
|
|
20573
|
+
const executor = pgExecutor(pool);
|
|
20574
|
+
return {
|
|
20575
|
+
dialect: "postgresql",
|
|
20576
|
+
execute: executor.execute,
|
|
20577
|
+
transaction: () => {
|
|
20578
|
+
throw new Error("A batch executor has no interactive transactions.");
|
|
20579
|
+
},
|
|
20580
|
+
batch: (statements) => executor.transaction(async (connection) => {
|
|
20581
|
+
const results = [];
|
|
20582
|
+
for (const statement of statements) results.push(await connection.execute(statement));
|
|
20583
|
+
return results;
|
|
20584
|
+
})
|
|
20585
|
+
};
|
|
20586
|
+
};
|
|
20587
|
+
const mysqlExecutor = (pool) => {
|
|
20588
|
+
const over = (runner) => ({ execute: async ({ sql, params }) => {
|
|
20589
|
+
const [result] = await runner.query(sql, [...params]);
|
|
20590
|
+
return Array.isArray(result) ? {
|
|
20591
|
+
rows: result,
|
|
20592
|
+
changes: 0
|
|
20593
|
+
} : {
|
|
20594
|
+
rows: [],
|
|
20595
|
+
changes: result.affectedRows
|
|
20596
|
+
};
|
|
20597
|
+
} });
|
|
20598
|
+
return {
|
|
20599
|
+
dialect: "mysql",
|
|
20600
|
+
...over(pool),
|
|
20601
|
+
async transaction(fn) {
|
|
20602
|
+
const connection = await pool.getConnection();
|
|
20603
|
+
try {
|
|
20604
|
+
await connection.beginTransaction();
|
|
20605
|
+
const result = await fn(over(connection));
|
|
20606
|
+
await connection.commit();
|
|
20607
|
+
return result;
|
|
20608
|
+
} catch (error) {
|
|
20609
|
+
await connection.rollback().catch(() => void 0);
|
|
20610
|
+
throw error;
|
|
20611
|
+
} finally {
|
|
20612
|
+
connection.release();
|
|
20613
|
+
}
|
|
20614
|
+
}
|
|
20615
|
+
};
|
|
20616
|
+
};
|
|
20617
|
+
//#endregion
|
|
20416
20618
|
exports.RELEASE_CATALOG_DOWNLOAD_HASH = RELEASE_CATALOG_DOWNLOAD_HASH;
|
|
20417
20619
|
exports.RELEASE_CATALOG_MANIFEST_URIS = RELEASE_CATALOG_MANIFEST_URIS;
|
|
20418
20620
|
exports.RELEASE_CATALOG_STORAGE_FIXTURES = RELEASE_CATALOG_STORAGE_FIXTURES;
|
|
@@ -20422,6 +20624,7 @@ exports.assertDockerComposeAvailable = assertDockerComposeAvailable;
|
|
|
20422
20624
|
exports.assertDockerDaemonAvailable = assertDockerDaemonAvailable;
|
|
20423
20625
|
exports.assertEnvFlagEnabled = assertEnvFlagEnabled;
|
|
20424
20626
|
exports.cleanupServer = cleanupServer;
|
|
20627
|
+
exports.createD1TestDatabase = createD1TestDatabase;
|
|
20425
20628
|
exports.createReleaseCatalogTestStorage = createReleaseCatalogTestStorage;
|
|
20426
20629
|
exports.createTestDbPath = createTestDbPath;
|
|
20427
20630
|
exports.findOpenPort = findOpenPort;
|
|
@@ -20431,11 +20634,18 @@ exports.hasDockerCompose = hasDockerCompose;
|
|
|
20431
20634
|
exports.hasDockerDaemon = hasDockerDaemon;
|
|
20432
20635
|
exports.killPort = killPort;
|
|
20433
20636
|
exports.mockReactNativeProjectRoot = mockReactNativeProjectRoot;
|
|
20637
|
+
exports.mysqlExecutor = mysqlExecutor;
|
|
20638
|
+
exports.pgBatchExecutor = pgBatchExecutor;
|
|
20639
|
+
exports.pgExecutor = pgExecutor;
|
|
20640
|
+
exports.pgliteBatchExecutor = pgliteBatchExecutor;
|
|
20641
|
+
exports.pgliteExecutor = pgliteExecutor;
|
|
20434
20642
|
exports.releaseCatalogArtifact = releaseCatalogArtifact;
|
|
20435
20643
|
exports.releaseCatalogDownloadUrl = releaseCatalogDownloadUrl;
|
|
20436
20644
|
exports.runCheckedCommand = runCheckedCommand;
|
|
20437
20645
|
exports.spawnRuntime = spawnRuntime;
|
|
20438
20646
|
exports.spawnServerProcess = spawnServerProcess;
|
|
20647
|
+
exports.sqliteBatchExecutor = sqliteBatchExecutor;
|
|
20648
|
+
exports.sqliteExecutor = sqliteExecutor;
|
|
20439
20649
|
exports.startHttpTestServer = startHttpTestServer;
|
|
20440
20650
|
exports.stopRuntime = stopRuntime;
|
|
20441
20651
|
exports.waitForHttpOk = waitForHttpOk;
|
package/dist/node.d.cts
CHANGED
|
@@ -1,8 +1,36 @@
|
|
|
1
|
+
import { DatabaseSync } from "node:sqlite";
|
|
1
2
|
import { ChildProcessByStdio } from "node:child_process";
|
|
2
3
|
import { Readable } from "node:stream";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
4
|
+
import { BundleRow, SqlExecutor, StorageAdapter } from "@hot-updater/plugin-core";
|
|
5
|
+
import { ArtifactInfo } from "@hot-updater/protocol";
|
|
5
6
|
import { execa } from "execa";
|
|
7
|
+
import { PGlite } from "@electric-sql/pglite";
|
|
8
|
+
import { Pool } from "mysql2/promise";
|
|
9
|
+
import { Pool as Pool$1 } from "pg";
|
|
10
|
+
//#region src/d1TestDatabase.d.ts
|
|
11
|
+
/** What a D1 statement answers: `results` for a read, `meta.changes` for a write. */
|
|
12
|
+
interface D1TestResult {
|
|
13
|
+
readonly success: true;
|
|
14
|
+
readonly results: readonly unknown[];
|
|
15
|
+
readonly meta: {
|
|
16
|
+
readonly changes?: number;
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* A D1 database over `node:sqlite`, answering as D1 does, after it runs
|
|
21
|
+
* `statements`, such as a provider's schema: what a D1 executor's specs
|
|
22
|
+
* run on without Cloudflare. `db` is a database the spec opens, such as
|
|
23
|
+
* `new DatabaseSync(":memory:")`.
|
|
24
|
+
*/
|
|
25
|
+
declare const createD1TestDatabase: (db: DatabaseSync, statements?: readonly string[]) => {
|
|
26
|
+
db: DatabaseSync;
|
|
27
|
+
run: (sql: string, params: readonly unknown[]) => D1TestResult;
|
|
28
|
+
batch: (statements: readonly {
|
|
29
|
+
sql: string;
|
|
30
|
+
params: readonly unknown[];
|
|
31
|
+
}[]) => D1TestResult[];
|
|
32
|
+
};
|
|
33
|
+
//#endregion
|
|
6
34
|
//#region src/mockReactNativeProjectRoot.d.ts
|
|
7
35
|
interface MockedReactNativeProjectRoot {
|
|
8
36
|
rootDir: string;
|
|
@@ -73,7 +101,7 @@ declare const releaseCatalogArtifact: (bundle: BundleRow) => ArtifactInfo;
|
|
|
73
101
|
/** Install these storage objects in the test server, independently of its DB. */
|
|
74
102
|
declare const RELEASE_CATALOG_STORAGE_FIXTURES: Readonly<Record<string, string>>;
|
|
75
103
|
/** Storage boundary shared by provider and separately spawned server tests. */
|
|
76
|
-
declare const createReleaseCatalogTestStorage: () =>
|
|
104
|
+
declare const createReleaseCatalogTestStorage: () => StorageAdapter;
|
|
77
105
|
//#endregion
|
|
78
106
|
//#region src/setupHandlerIntegrationTestSuite.d.ts
|
|
79
107
|
declare const TEST_ADMIN_AUTH_TOKEN = "hot-updater-test-token";
|
|
@@ -104,4 +132,21 @@ declare function spawnServerProcess(options: {
|
|
|
104
132
|
*/
|
|
105
133
|
declare function cleanupServer(baseUrl: string, serverProcess: ReturnType<typeof execa> | null, testDbPath: string): Promise<void>;
|
|
106
134
|
//#endregion
|
|
107
|
-
|
|
135
|
+
//#region src/sqlTestExecutors.d.ts
|
|
136
|
+
/** Test executors for the SQL core; provider executors arrive with D1–D3. */
|
|
137
|
+
declare const pgliteExecutor: (db: PGlite) => SqlExecutor;
|
|
138
|
+
/** One connection, so statements and transactions run one at a time. */
|
|
139
|
+
declare const sqliteExecutor: (db: DatabaseSync) => SqlExecutor;
|
|
140
|
+
/**
|
|
141
|
+
* An executor without interactive transactions, as D1's: writes run as one
|
|
142
|
+
* atomic batch, here in a SQLite transaction that rolls back on any error.
|
|
143
|
+
*/
|
|
144
|
+
declare const sqliteBatchExecutor: (db: DatabaseSync) => SqlExecutor;
|
|
145
|
+
/** PGlite without interactive transactions, as an RPC applying a batch would be. */
|
|
146
|
+
declare const pgliteBatchExecutor: (db: PGlite) => SqlExecutor;
|
|
147
|
+
declare const pgExecutor: (pool: Pool$1) => SqlExecutor;
|
|
148
|
+
/** A pooled PostgreSQL batch: one READ COMMITTED transaction per write, as Supabase's apply RPC runs. */
|
|
149
|
+
declare const pgBatchExecutor: (pool: Pool$1) => SqlExecutor;
|
|
150
|
+
declare const mysqlExecutor: (pool: Pool) => SqlExecutor;
|
|
151
|
+
//#endregion
|
|
152
|
+
export { D1TestResult, MockedReactNativeProjectRoot, RELEASE_CATALOG_DOWNLOAD_HASH, RELEASE_CATALOG_MANIFEST_URIS, RELEASE_CATALOG_STORAGE_FIXTURES, RuntimeChild, RuntimeLogs, SpawnRuntimeOptions, TEST_ADMIN_AUTH_TOKEN, assertCommandAvailable, assertDockerComposeAvailable, assertDockerDaemonAvailable, assertEnvFlagEnabled, cleanupServer, createD1TestDatabase, createReleaseCatalogTestStorage, createTestDbPath, findOpenPort, formatRuntimeLogs, hasCommand, hasDockerCompose, hasDockerDaemon, killPort, mockReactNativeProjectRoot, mysqlExecutor, pgBatchExecutor, pgExecutor, pgliteBatchExecutor, pgliteExecutor, releaseCatalogArtifact, releaseCatalogDownloadUrl, runCheckedCommand, spawnRuntime, spawnServerProcess, sqliteBatchExecutor, sqliteExecutor, startHttpTestServer, stopRuntime, waitForHttpOk, waitForServer };
|
package/dist/node.d.mts
CHANGED
|
@@ -1,8 +1,36 @@
|
|
|
1
1
|
import { ChildProcessByStdio } from "node:child_process";
|
|
2
2
|
import { execa } from "execa";
|
|
3
|
+
import { DatabaseSync } from "node:sqlite";
|
|
3
4
|
import { Readable } from "node:stream";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
5
|
+
import { BundleRow, SqlExecutor, StorageAdapter } from "@hot-updater/plugin-core";
|
|
6
|
+
import { ArtifactInfo } from "@hot-updater/protocol";
|
|
7
|
+
import { PGlite } from "@electric-sql/pglite";
|
|
8
|
+
import { Pool } from "mysql2/promise";
|
|
9
|
+
import { Pool as Pool$1 } from "pg";
|
|
10
|
+
//#region src/d1TestDatabase.d.ts
|
|
11
|
+
/** What a D1 statement answers: `results` for a read, `meta.changes` for a write. */
|
|
12
|
+
interface D1TestResult {
|
|
13
|
+
readonly success: true;
|
|
14
|
+
readonly results: readonly unknown[];
|
|
15
|
+
readonly meta: {
|
|
16
|
+
readonly changes?: number;
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* A D1 database over `node:sqlite`, answering as D1 does, after it runs
|
|
21
|
+
* `statements`, such as a provider's schema: what a D1 executor's specs
|
|
22
|
+
* run on without Cloudflare. `db` is a database the spec opens, such as
|
|
23
|
+
* `new DatabaseSync(":memory:")`.
|
|
24
|
+
*/
|
|
25
|
+
declare const createD1TestDatabase: (db: DatabaseSync, statements?: readonly string[]) => {
|
|
26
|
+
db: DatabaseSync;
|
|
27
|
+
run: (sql: string, params: readonly unknown[]) => D1TestResult;
|
|
28
|
+
batch: (statements: readonly {
|
|
29
|
+
sql: string;
|
|
30
|
+
params: readonly unknown[];
|
|
31
|
+
}[]) => D1TestResult[];
|
|
32
|
+
};
|
|
33
|
+
//#endregion
|
|
6
34
|
//#region src/mockReactNativeProjectRoot.d.ts
|
|
7
35
|
interface MockedReactNativeProjectRoot {
|
|
8
36
|
rootDir: string;
|
|
@@ -73,7 +101,7 @@ declare const releaseCatalogArtifact: (bundle: BundleRow) => ArtifactInfo;
|
|
|
73
101
|
/** Install these storage objects in the test server, independently of its DB. */
|
|
74
102
|
declare const RELEASE_CATALOG_STORAGE_FIXTURES: Readonly<Record<string, string>>;
|
|
75
103
|
/** Storage boundary shared by provider and separately spawned server tests. */
|
|
76
|
-
declare const createReleaseCatalogTestStorage: () =>
|
|
104
|
+
declare const createReleaseCatalogTestStorage: () => StorageAdapter;
|
|
77
105
|
//#endregion
|
|
78
106
|
//#region src/setupHandlerIntegrationTestSuite.d.ts
|
|
79
107
|
declare const TEST_ADMIN_AUTH_TOKEN = "hot-updater-test-token";
|
|
@@ -104,4 +132,21 @@ declare function spawnServerProcess(options: {
|
|
|
104
132
|
*/
|
|
105
133
|
declare function cleanupServer(baseUrl: string, serverProcess: ReturnType<typeof execa> | null, testDbPath: string): Promise<void>;
|
|
106
134
|
//#endregion
|
|
107
|
-
|
|
135
|
+
//#region src/sqlTestExecutors.d.ts
|
|
136
|
+
/** Test executors for the SQL core; provider executors arrive with D1–D3. */
|
|
137
|
+
declare const pgliteExecutor: (db: PGlite) => SqlExecutor;
|
|
138
|
+
/** One connection, so statements and transactions run one at a time. */
|
|
139
|
+
declare const sqliteExecutor: (db: DatabaseSync) => SqlExecutor;
|
|
140
|
+
/**
|
|
141
|
+
* An executor without interactive transactions, as D1's: writes run as one
|
|
142
|
+
* atomic batch, here in a SQLite transaction that rolls back on any error.
|
|
143
|
+
*/
|
|
144
|
+
declare const sqliteBatchExecutor: (db: DatabaseSync) => SqlExecutor;
|
|
145
|
+
/** PGlite without interactive transactions, as an RPC applying a batch would be. */
|
|
146
|
+
declare const pgliteBatchExecutor: (db: PGlite) => SqlExecutor;
|
|
147
|
+
declare const pgExecutor: (pool: Pool$1) => SqlExecutor;
|
|
148
|
+
/** A pooled PostgreSQL batch: one READ COMMITTED transaction per write, as Supabase's apply RPC runs. */
|
|
149
|
+
declare const pgBatchExecutor: (pool: Pool$1) => SqlExecutor;
|
|
150
|
+
declare const mysqlExecutor: (pool: Pool) => SqlExecutor;
|
|
151
|
+
//#endregion
|
|
152
|
+
export { D1TestResult, MockedReactNativeProjectRoot, RELEASE_CATALOG_DOWNLOAD_HASH, RELEASE_CATALOG_MANIFEST_URIS, RELEASE_CATALOG_STORAGE_FIXTURES, RuntimeChild, RuntimeLogs, SpawnRuntimeOptions, TEST_ADMIN_AUTH_TOKEN, assertCommandAvailable, assertDockerComposeAvailable, assertDockerDaemonAvailable, assertEnvFlagEnabled, cleanupServer, createD1TestDatabase, createReleaseCatalogTestStorage, createTestDbPath, findOpenPort, formatRuntimeLogs, hasCommand, hasDockerCompose, hasDockerDaemon, killPort, mockReactNativeProjectRoot, mysqlExecutor, pgBatchExecutor, pgExecutor, pgliteBatchExecutor, pgliteExecutor, releaseCatalogArtifact, releaseCatalogDownloadUrl, runCheckedCommand, spawnRuntime, spawnServerProcess, sqliteBatchExecutor, sqliteExecutor, startHttpTestServer, stopRuntime, waitForHttpOk, waitForServer };
|
package/dist/node.mjs
CHANGED
|
@@ -12,6 +12,47 @@ import { execa } from "execa";
|
|
|
12
12
|
var __commonJSMin = (cb, mod) => () => (mod || (cb((mod = { exports: {} }).exports, mod), cb = null), mod.exports);
|
|
13
13
|
var __require = /* #__PURE__ */ (() => createRequire(import.meta.url))();
|
|
14
14
|
//#endregion
|
|
15
|
+
//#region src/d1TestDatabase.ts
|
|
16
|
+
/**
|
|
17
|
+
* A D1 database over `node:sqlite`, answering as D1 does, after it runs
|
|
18
|
+
* `statements`, such as a provider's schema: what a D1 executor's specs
|
|
19
|
+
* run on without Cloudflare. `db` is a database the spec opens, such as
|
|
20
|
+
* `new DatabaseSync(":memory:")`.
|
|
21
|
+
*/
|
|
22
|
+
const createD1TestDatabase = (db, statements = []) => {
|
|
23
|
+
for (const sql of statements) db.exec(sql);
|
|
24
|
+
const run = (sql, params) => {
|
|
25
|
+
const statement = db.prepare(sql);
|
|
26
|
+
const values = params;
|
|
27
|
+
return statement.columns().length > 0 ? {
|
|
28
|
+
success: true,
|
|
29
|
+
results: statement.all(...values),
|
|
30
|
+
meta: {}
|
|
31
|
+
} : {
|
|
32
|
+
success: true,
|
|
33
|
+
results: [],
|
|
34
|
+
meta: { changes: Number(statement.run(...values).changes) }
|
|
35
|
+
};
|
|
36
|
+
};
|
|
37
|
+
/** Runs statements atomically, as `batch` does. */
|
|
38
|
+
const batch = (statements) => {
|
|
39
|
+
db.exec("BEGIN IMMEDIATE");
|
|
40
|
+
try {
|
|
41
|
+
const results = statements.map(({ sql, params }) => run(sql, params));
|
|
42
|
+
db.exec("COMMIT");
|
|
43
|
+
return results;
|
|
44
|
+
} catch (error) {
|
|
45
|
+
db.exec("ROLLBACK");
|
|
46
|
+
throw error;
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
return {
|
|
50
|
+
db,
|
|
51
|
+
run,
|
|
52
|
+
batch
|
|
53
|
+
};
|
|
54
|
+
};
|
|
55
|
+
//#endregion
|
|
15
56
|
//#region ../../node_modules/.pnpm/workspace-tools@0.41.7/node_modules/workspace-tools/lib/graph/getPackageDependencies.js
|
|
16
57
|
var require_getPackageDependencies = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
17
58
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
@@ -20389,4 +20430,165 @@ async function cleanupServer(baseUrl, serverProcess, testDbPath) {
|
|
|
20389
20430
|
} catch {}
|
|
20390
20431
|
}
|
|
20391
20432
|
//#endregion
|
|
20392
|
-
|
|
20433
|
+
//#region src/sqlTestExecutors.ts
|
|
20434
|
+
/** Test executors for the SQL core; provider executors arrive with D1–D3. */
|
|
20435
|
+
const pgliteExecutor = (db) => {
|
|
20436
|
+
const over = (runner) => ({ execute: async ({ sql, params }) => {
|
|
20437
|
+
const result = await runner.query(sql, [...params]);
|
|
20438
|
+
return {
|
|
20439
|
+
rows: result.rows,
|
|
20440
|
+
changes: result.affectedRows ?? 0
|
|
20441
|
+
};
|
|
20442
|
+
} });
|
|
20443
|
+
return {
|
|
20444
|
+
dialect: "postgresql",
|
|
20445
|
+
...over(db),
|
|
20446
|
+
transaction: (fn) => db.transaction((tx) => fn(over(tx)))
|
|
20447
|
+
};
|
|
20448
|
+
};
|
|
20449
|
+
/** One connection, so statements and transactions run one at a time. */
|
|
20450
|
+
const sqliteExecutor = (db) => {
|
|
20451
|
+
let queue = Promise.resolve();
|
|
20452
|
+
const serial = (task) => {
|
|
20453
|
+
const next = queue.then(task);
|
|
20454
|
+
queue = next.catch(() => void 0);
|
|
20455
|
+
return next;
|
|
20456
|
+
};
|
|
20457
|
+
const execute = async ({ sql, params }) => {
|
|
20458
|
+
const statement = db.prepare(sql);
|
|
20459
|
+
const values = params;
|
|
20460
|
+
if (statement.columns().length > 0) return {
|
|
20461
|
+
rows: statement.all(...values),
|
|
20462
|
+
changes: 0
|
|
20463
|
+
};
|
|
20464
|
+
return {
|
|
20465
|
+
rows: [],
|
|
20466
|
+
changes: Number(statement.run(...values).changes)
|
|
20467
|
+
};
|
|
20468
|
+
};
|
|
20469
|
+
return {
|
|
20470
|
+
dialect: "sqlite",
|
|
20471
|
+
execute: (statement) => serial(() => execute(statement)),
|
|
20472
|
+
transaction: (fn) => serial(async () => {
|
|
20473
|
+
db.exec("BEGIN IMMEDIATE");
|
|
20474
|
+
try {
|
|
20475
|
+
const result = await fn({ execute });
|
|
20476
|
+
db.exec("COMMIT");
|
|
20477
|
+
return result;
|
|
20478
|
+
} catch (error) {
|
|
20479
|
+
db.exec("ROLLBACK");
|
|
20480
|
+
throw error;
|
|
20481
|
+
}
|
|
20482
|
+
})
|
|
20483
|
+
};
|
|
20484
|
+
};
|
|
20485
|
+
/**
|
|
20486
|
+
* An executor without interactive transactions, as D1's: writes run as one
|
|
20487
|
+
* atomic batch, here in a SQLite transaction that rolls back on any error.
|
|
20488
|
+
*/
|
|
20489
|
+
const sqliteBatchExecutor = (db) => {
|
|
20490
|
+
const executor = sqliteExecutor(db);
|
|
20491
|
+
return {
|
|
20492
|
+
dialect: "sqlite",
|
|
20493
|
+
execute: executor.execute,
|
|
20494
|
+
transaction: () => {
|
|
20495
|
+
throw new Error("A batch executor has no interactive transactions.");
|
|
20496
|
+
},
|
|
20497
|
+
batch: (statements) => executor.transaction(async (connection) => {
|
|
20498
|
+
const results = [];
|
|
20499
|
+
for (const statement of statements) results.push(await connection.execute(statement));
|
|
20500
|
+
return results;
|
|
20501
|
+
})
|
|
20502
|
+
};
|
|
20503
|
+
};
|
|
20504
|
+
/** PGlite without interactive transactions, as an RPC applying a batch would be. */
|
|
20505
|
+
const pgliteBatchExecutor = (db) => {
|
|
20506
|
+
const executor = pgliteExecutor(db);
|
|
20507
|
+
return {
|
|
20508
|
+
dialect: "postgresql",
|
|
20509
|
+
execute: executor.execute,
|
|
20510
|
+
transaction: () => {
|
|
20511
|
+
throw new Error("A batch executor has no interactive transactions.");
|
|
20512
|
+
},
|
|
20513
|
+
batch: (statements) => executor.transaction(async (connection) => {
|
|
20514
|
+
const results = [];
|
|
20515
|
+
for (const statement of statements) results.push(await connection.execute(statement));
|
|
20516
|
+
return results;
|
|
20517
|
+
})
|
|
20518
|
+
};
|
|
20519
|
+
};
|
|
20520
|
+
const pgExecutor = (pool) => {
|
|
20521
|
+
const over = (runner) => ({ execute: async ({ sql, params }) => {
|
|
20522
|
+
const result = await runner.query(sql, [...params]);
|
|
20523
|
+
return {
|
|
20524
|
+
rows: result.rows,
|
|
20525
|
+
changes: result.rowCount ?? 0
|
|
20526
|
+
};
|
|
20527
|
+
} });
|
|
20528
|
+
return {
|
|
20529
|
+
dialect: "postgresql",
|
|
20530
|
+
...over(pool),
|
|
20531
|
+
async transaction(fn) {
|
|
20532
|
+
const client = await pool.connect();
|
|
20533
|
+
try {
|
|
20534
|
+
await client.query("BEGIN");
|
|
20535
|
+
const result = await fn(over(client));
|
|
20536
|
+
await client.query("COMMIT");
|
|
20537
|
+
return result;
|
|
20538
|
+
} catch (error) {
|
|
20539
|
+
await client.query("ROLLBACK").catch(() => void 0);
|
|
20540
|
+
throw error;
|
|
20541
|
+
} finally {
|
|
20542
|
+
client.release();
|
|
20543
|
+
}
|
|
20544
|
+
}
|
|
20545
|
+
};
|
|
20546
|
+
};
|
|
20547
|
+
/** A pooled PostgreSQL batch: one READ COMMITTED transaction per write, as Supabase's apply RPC runs. */
|
|
20548
|
+
const pgBatchExecutor = (pool) => {
|
|
20549
|
+
const executor = pgExecutor(pool);
|
|
20550
|
+
return {
|
|
20551
|
+
dialect: "postgresql",
|
|
20552
|
+
execute: executor.execute,
|
|
20553
|
+
transaction: () => {
|
|
20554
|
+
throw new Error("A batch executor has no interactive transactions.");
|
|
20555
|
+
},
|
|
20556
|
+
batch: (statements) => executor.transaction(async (connection) => {
|
|
20557
|
+
const results = [];
|
|
20558
|
+
for (const statement of statements) results.push(await connection.execute(statement));
|
|
20559
|
+
return results;
|
|
20560
|
+
})
|
|
20561
|
+
};
|
|
20562
|
+
};
|
|
20563
|
+
const mysqlExecutor = (pool) => {
|
|
20564
|
+
const over = (runner) => ({ execute: async ({ sql, params }) => {
|
|
20565
|
+
const [result] = await runner.query(sql, [...params]);
|
|
20566
|
+
return Array.isArray(result) ? {
|
|
20567
|
+
rows: result,
|
|
20568
|
+
changes: 0
|
|
20569
|
+
} : {
|
|
20570
|
+
rows: [],
|
|
20571
|
+
changes: result.affectedRows
|
|
20572
|
+
};
|
|
20573
|
+
} });
|
|
20574
|
+
return {
|
|
20575
|
+
dialect: "mysql",
|
|
20576
|
+
...over(pool),
|
|
20577
|
+
async transaction(fn) {
|
|
20578
|
+
const connection = await pool.getConnection();
|
|
20579
|
+
try {
|
|
20580
|
+
await connection.beginTransaction();
|
|
20581
|
+
const result = await fn(over(connection));
|
|
20582
|
+
await connection.commit();
|
|
20583
|
+
return result;
|
|
20584
|
+
} catch (error) {
|
|
20585
|
+
await connection.rollback().catch(() => void 0);
|
|
20586
|
+
throw error;
|
|
20587
|
+
} finally {
|
|
20588
|
+
connection.release();
|
|
20589
|
+
}
|
|
20590
|
+
}
|
|
20591
|
+
};
|
|
20592
|
+
};
|
|
20593
|
+
//#endregion
|
|
20594
|
+
export { RELEASE_CATALOG_DOWNLOAD_HASH, RELEASE_CATALOG_MANIFEST_URIS, RELEASE_CATALOG_STORAGE_FIXTURES, TEST_ADMIN_AUTH_TOKEN, assertCommandAvailable, assertDockerComposeAvailable, assertDockerDaemonAvailable, assertEnvFlagEnabled, cleanupServer, createD1TestDatabase, createReleaseCatalogTestStorage, createTestDbPath, findOpenPort, formatRuntimeLogs, hasCommand, hasDockerCompose, hasDockerDaemon, killPort, mockReactNativeProjectRoot, mysqlExecutor, pgBatchExecutor, pgExecutor, pgliteBatchExecutor, pgliteExecutor, releaseCatalogArtifact, releaseCatalogDownloadUrl, runCheckedCommand, spawnRuntime, spawnServerProcess, sqliteBatchExecutor, sqliteExecutor, startHttpTestServer, stopRuntime, waitForHttpOk, waitForServer };
|