jazz-tools 2.0.0-alpha.51 → 2.0.0-alpha.52
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/bin/docs-index.txt +1 -1
- package/bin/native/jazz-tools-darwin-arm64 +0 -0
- package/bin/native/jazz-tools-darwin-x64 +0 -0
- package/bin/native/jazz-tools-linux-arm64 +0 -0
- package/bin/native/jazz-tools-linux-x64 +0 -0
- package/dist/better-auth-adapter/index.test.js +11 -11
- package/dist/better-auth-adapter/index.test.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +63 -543
- package/dist/cli.js.map +1 -1
- package/dist/codegen/schema-reader.d.ts.map +1 -1
- package/dist/codegen/schema-reader.js +6 -0
- package/dist/codegen/schema-reader.js.map +1 -1
- package/dist/dev/catalogue.d.ts +111 -53
- package/dist/dev/catalogue.d.ts.map +1 -1
- package/dist/dev/catalogue.js +316 -120
- package/dist/dev/catalogue.js.map +1 -1
- package/dist/dev/catalogue.test.js +68 -10
- package/dist/dev/catalogue.test.js.map +1 -1
- package/dist/dev/dev-server.d.ts +16 -3
- package/dist/dev/dev-server.d.ts.map +1 -1
- package/dist/dev/dev-server.js +23 -7
- package/dist/dev/dev-server.js.map +1 -1
- package/dist/dev/dev-server.test.js +8 -6
- package/dist/dev/dev-server.test.js.map +1 -1
- package/dist/dev/expo.test.js +3 -3
- package/dist/dev/expo.test.js.map +1 -1
- package/dist/dev/index.d.ts +1 -1
- package/dist/dev/index.d.ts.map +1 -1
- package/dist/dev/index.js +1 -1
- package/dist/dev/index.js.map +1 -1
- package/dist/dev/managed-runtime.d.ts.map +1 -1
- package/dist/dev/managed-runtime.js +5 -4
- package/dist/dev/managed-runtime.js.map +1 -1
- package/dist/dev/managed-runtime.test.js +11 -4
- package/dist/dev/managed-runtime.test.js.map +1 -1
- package/dist/dev/migrations.d.ts +8 -0
- package/dist/dev/migrations.d.ts.map +1 -0
- package/dist/dev/migrations.js +300 -0
- package/dist/dev/migrations.js.map +1 -0
- package/dist/dev/next.test.js +19 -9
- package/dist/dev/next.test.js.map +1 -1
- package/dist/dev/schema-utils.d.ts +7 -0
- package/dist/dev/schema-utils.d.ts.map +1 -0
- package/dist/dev/schema-utils.js +60 -0
- package/dist/dev/schema-utils.js.map +1 -0
- package/dist/dev/schema-watcher.js +3 -3
- package/dist/dev/schema-watcher.js.map +1 -1
- package/dist/dev/sveltekit.test.js +33 -22
- package/dist/dev/sveltekit.test.js.map +1 -1
- package/dist/dev/vite.test.js +13 -3
- package/dist/dev/vite.test.js.map +1 -1
- package/dist/drivers/types.d.ts +1 -1
- package/dist/drivers/types.d.ts.map +1 -1
- package/dist/dsl.d.ts +9 -1
- package/dist/dsl.d.ts.map +1 -1
- package/dist/dsl.js +8 -2
- package/dist/dsl.js.map +1 -1
- package/dist/dsl.test.js +34 -0
- package/dist/dsl.test.js.map +1 -1
- package/dist/react-core/use-all.d.ts +1 -1
- package/dist/react-core/use-all.d.ts.map +1 -1
- package/dist/react-core/use-all.js.map +1 -1
- package/dist/runtime/browser-broker-client.d.ts +101 -0
- package/dist/runtime/browser-broker-client.d.ts.map +1 -0
- package/dist/runtime/browser-broker-client.js +598 -0
- package/dist/runtime/browser-broker-client.js.map +1 -0
- package/dist/runtime/browser-broker-client.test.d.ts +2 -0
- package/dist/runtime/browser-broker-client.test.d.ts.map +1 -0
- package/dist/runtime/browser-broker-client.test.js +798 -0
- package/dist/runtime/browser-broker-client.test.js.map +1 -0
- package/dist/runtime/browser-broker-errors.d.ts +10 -0
- package/dist/runtime/browser-broker-errors.d.ts.map +1 -0
- package/dist/runtime/browser-broker-errors.js +22 -0
- package/dist/runtime/browser-broker-errors.js.map +1 -0
- package/dist/runtime/browser-broker-protocol.d.ts +196 -0
- package/dist/runtime/browser-broker-protocol.d.ts.map +1 -0
- package/dist/runtime/browser-broker-protocol.js +159 -0
- package/dist/runtime/browser-broker-protocol.js.map +1 -0
- package/dist/runtime/browser-broker-protocol.test.d.ts +2 -0
- package/dist/runtime/browser-broker-protocol.test.d.ts.map +1 -0
- package/dist/runtime/browser-broker-protocol.test.js +67 -0
- package/dist/runtime/browser-broker-protocol.test.js.map +1 -0
- package/dist/runtime/client.d.ts +2 -0
- package/dist/runtime/client.d.ts.map +1 -1
- package/dist/runtime/client.js.map +1 -1
- package/dist/runtime/context.d.ts +3 -0
- package/dist/runtime/context.d.ts.map +1 -1
- package/dist/runtime/db-runtime-module.d.ts +1 -0
- package/dist/runtime/db-runtime-module.d.ts.map +1 -1
- package/dist/runtime/db-runtime-module.js.map +1 -1
- package/dist/runtime/db.d.ts +81 -34
- package/dist/runtime/db.d.ts.map +1 -1
- package/dist/runtime/db.driver-mode.test.js +51 -1
- package/dist/runtime/db.driver-mode.test.js.map +1 -1
- package/dist/runtime/db.js +790 -310
- package/dist/runtime/db.js.map +1 -1
- package/dist/runtime/db.one.test.d.ts +2 -0
- package/dist/runtime/db.one.test.d.ts.map +1 -0
- package/dist/runtime/db.one.test.js +69 -0
- package/dist/runtime/db.one.test.js.map +1 -0
- package/dist/runtime/db.transport.test.js +25 -0
- package/dist/runtime/db.transport.test.js.map +1 -1
- package/dist/runtime/db.worker-bootstrap.test.js +339 -19
- package/dist/runtime/db.worker-bootstrap.test.js.map +1 -1
- package/dist/runtime/index.d.ts +2 -1
- package/dist/runtime/index.d.ts.map +1 -1
- package/dist/runtime/index.js +1 -0
- package/dist/runtime/index.js.map +1 -1
- package/dist/runtime/leader-lock.d.ts +21 -3
- package/dist/runtime/leader-lock.d.ts.map +1 -1
- package/dist/runtime/leader-lock.js +131 -33
- package/dist/runtime/leader-lock.js.map +1 -1
- package/dist/runtime/napi.auth-failure.test.js +1 -1
- package/dist/runtime/napi.auth-failure.test.js.map +1 -1
- package/dist/runtime/napi.for-request.test.js +1 -1
- package/dist/runtime/napi.for-request.test.js.map +1 -1
- package/dist/runtime/napi.integration.test.js +4 -8
- package/dist/runtime/napi.integration.test.js.map +1 -1
- package/dist/runtime/permissions.repro.test.js +1 -1
- package/dist/runtime/permissions.repro.test.js.map +1 -1
- package/dist/runtime/runtime-config.d.ts +1 -0
- package/dist/runtime/runtime-config.d.ts.map +1 -1
- package/dist/runtime/runtime-config.js +11 -5
- package/dist/runtime/runtime-config.js.map +1 -1
- package/dist/runtime/runtime-config.test.d.ts +2 -0
- package/dist/runtime/runtime-config.test.d.ts.map +1 -0
- package/dist/runtime/runtime-config.test.js +21 -0
- package/dist/runtime/runtime-config.test.js.map +1 -0
- package/dist/runtime/schema-fetch.d.ts +5 -0
- package/dist/runtime/schema-fetch.d.ts.map +1 -1
- package/dist/runtime/schema-fetch.js +33 -2
- package/dist/runtime/schema-fetch.js.map +1 -1
- package/dist/runtime/schema-fetch.test.js +31 -0
- package/dist/runtime/schema-fetch.test.js.map +1 -1
- package/dist/runtime/wasm-runtime-module.d.ts +1 -1
- package/dist/runtime/wasm-runtime-module.d.ts.map +1 -1
- package/dist/runtime/wasm-runtime-module.js +6 -2
- package/dist/runtime/wasm-runtime-module.js.map +1 -1
- package/dist/runtime/worker-bridge.d.ts +25 -2
- package/dist/runtime/worker-bridge.d.ts.map +1 -1
- package/dist/runtime/worker-bridge.js +48 -2
- package/dist/runtime/worker-bridge.js.map +1 -1
- package/dist/runtime/worker-bridge.test.d.ts +2 -0
- package/dist/runtime/worker-bridge.test.d.ts.map +1 -0
- package/dist/runtime/worker-bridge.test.js +53 -0
- package/dist/runtime/worker-bridge.test.js.map +1 -0
- package/dist/schema-loader.d.ts.map +1 -1
- package/dist/schema-loader.js +2 -0
- package/dist/schema-loader.js.map +1 -1
- package/dist/schema.d.ts +1 -1
- package/dist/schema.d.ts.map +1 -1
- package/dist/shared/index.d.ts +25 -0
- package/dist/shared/index.d.ts.map +1 -0
- package/dist/shared/index.js +22 -0
- package/dist/shared/index.js.map +1 -0
- package/dist/shared/index.test.d.ts +2 -0
- package/dist/shared/index.test.d.ts.map +1 -0
- package/dist/shared/index.test.js +79 -0
- package/dist/shared/index.test.js.map +1 -0
- package/dist/solid/create-solid-jazz-client-internal.d.ts +13 -0
- package/dist/solid/create-solid-jazz-client-internal.d.ts.map +1 -0
- package/dist/solid/create-solid-jazz-client-internal.js +47 -0
- package/dist/solid/create-solid-jazz-client-internal.js.map +1 -0
- package/dist/solid/create-solid-jazz-client-internal.ssr.js +64 -0
- package/dist/solid/create-solid-jazz-client-internal.ssr.js.map +1 -0
- package/dist/solid/create-solid-jazz-client-internal.test.d.ts +2 -0
- package/dist/solid/create-solid-jazz-client-internal.test.d.ts.map +1 -0
- package/dist/solid/create-solid-jazz-client.d.ts +34 -0
- package/dist/solid/create-solid-jazz-client.d.ts.map +1 -0
- package/dist/solid/create-solid-jazz-client.integration.test.d.ts +2 -0
- package/dist/solid/create-solid-jazz-client.integration.test.d.ts.map +1 -0
- package/dist/solid/create-solid-jazz-client.js +38 -0
- package/dist/solid/create-solid-jazz-client.js.map +1 -0
- package/dist/solid/create-solid-jazz-client.ssr.js +41 -0
- package/dist/solid/create-solid-jazz-client.ssr.js.map +1 -0
- package/dist/solid/index.d.ts +8 -0
- package/dist/solid/index.d.ts.map +1 -0
- package/dist/solid/index.js +7 -0
- package/dist/solid/index.ssr.js +7 -0
- package/dist/solid/provider.d.ts +27 -0
- package/dist/solid/provider.d.ts.map +1 -0
- package/dist/solid/provider.js +44 -0
- package/dist/solid/provider.js.map +1 -0
- package/dist/solid/provider.ssr.js +44 -0
- package/dist/solid/provider.ssr.js.map +1 -0
- package/dist/solid/solid-jazz-client-store.d.ts +11 -0
- package/dist/solid/solid-jazz-client-store.d.ts.map +1 -0
- package/dist/solid/solid-jazz-client-store.js +35 -0
- package/dist/solid/solid-jazz-client-store.js.map +1 -0
- package/dist/solid/solid-jazz-client-store.ssr.js +37 -0
- package/dist/solid/solid-jazz-client-store.ssr.js.map +1 -0
- package/dist/solid/solid-jazz-client-store.test.d.ts +2 -0
- package/dist/solid/solid-jazz-client-store.test.d.ts.map +1 -0
- package/dist/solid/use-all.d.ts +16 -0
- package/dist/solid/use-all.d.ts.map +1 -0
- package/dist/solid/use-all.js +60 -0
- package/dist/solid/use-all.js.map +1 -0
- package/dist/solid/use-all.ssr.js +68 -0
- package/dist/solid/use-all.ssr.js.map +1 -0
- package/dist/solid/use-all.test.d.ts +2 -0
- package/dist/solid/use-all.test.d.ts.map +1 -0
- package/dist/solid/use-local-first-auth.d.ts +11 -0
- package/dist/solid/use-local-first-auth.d.ts.map +1 -0
- package/dist/solid/use-local-first-auth.js +65 -0
- package/dist/solid/use-local-first-auth.js.map +1 -0
- package/dist/solid/use-local-first-auth.ssr.js +83 -0
- package/dist/solid/use-local-first-auth.ssr.js.map +1 -0
- package/dist/solid/use-local-first-auth.test.d.ts +2 -0
- package/dist/solid/use-local-first-auth.test.d.ts.map +1 -0
- package/dist/svelte/use-all.svelte.d.ts +1 -1
- package/dist/svelte/use-all.svelte.d.ts.map +1 -1
- package/dist/svelte/use-all.svelte.js +1 -1
- package/dist/testing/index.d.ts +2 -2
- package/dist/testing/index.d.ts.map +1 -1
- package/dist/testing/index.js +2 -2
- package/dist/testing/index.js.map +1 -1
- package/dist/testing/index.test.js +11 -69
- package/dist/testing/index.test.js.map +1 -1
- package/dist/testing/policy-test-app.d.ts +1 -1
- package/dist/testing/policy-test-app.d.ts.map +1 -1
- package/dist/testing/policy-test-app.js +1 -1
- package/dist/testing/policy-test-app.js.map +1 -1
- package/dist/testing/test-jwt-issuer.d.ts +16 -0
- package/dist/testing/test-jwt-issuer.d.ts.map +1 -0
- package/dist/testing/test-jwt-issuer.js +23 -0
- package/dist/testing/test-jwt-issuer.js.map +1 -0
- package/dist/vue/use-all.d.ts +1 -1
- package/dist/vue/use-all.d.ts.map +1 -1
- package/dist/vue/use-all.js +1 -1
- package/dist/vue/use-all.js.map +1 -1
- package/dist/web/create-jazz-client.d.ts +20 -0
- package/dist/web/create-jazz-client.d.ts.map +1 -0
- package/dist/web/create-jazz-client.js +61 -0
- package/dist/web/create-jazz-client.js.map +1 -0
- package/dist/web/create-jazz-client.test.d.ts +2 -0
- package/dist/web/create-jazz-client.test.d.ts.map +1 -0
- package/dist/web/create-jazz-client.test.js +159 -0
- package/dist/web/create-jazz-client.test.js.map +1 -0
- package/dist/worker/broker-worker-bundle.test.d.ts +2 -0
- package/dist/worker/broker-worker-bundle.test.d.ts.map +1 -0
- package/dist/worker/broker-worker-bundle.test.js +40 -0
- package/dist/worker/broker-worker-bundle.test.js.map +1 -0
- package/dist/worker/jazz-broker-worker.d.ts +2 -0
- package/dist/worker/jazz-broker-worker.d.ts.map +1 -0
- package/dist/worker/jazz-broker-worker.js +1090 -0
- package/dist/worker/jazz-worker.js +62 -2
- package/dist/worker/jazz-worker.js.map +1 -1
- package/dist/worker/jazz-worker.ts +83 -2
- package/package.json +27 -8
- package/dist/runtime/storage-reset-coordinator.d.ts +0 -58
- package/dist/runtime/storage-reset-coordinator.d.ts.map +0 -1
- package/dist/runtime/storage-reset-coordinator.js +0 -402
- package/dist/runtime/storage-reset-coordinator.js.map +0 -1
- package/dist/runtime/tab-leader-election.d.ts +0 -97
- package/dist/runtime/tab-leader-election.d.ts.map +0 -1
- package/dist/runtime/tab-leader-election.js +0 -339
- package/dist/runtime/tab-leader-election.js.map +0 -1
- package/dist/runtime/tab-leader-election.test.d.ts +0 -2
- package/dist/runtime/tab-leader-election.test.d.ts.map +0 -1
- package/dist/runtime/tab-leader-election.test.js +0 -278
- package/dist/runtime/tab-leader-election.test.js.map +0 -1
- package/dist/runtime/tab-sync-protocol.d.ts +0 -55
- package/dist/runtime/tab-sync-protocol.d.ts.map +0 -1
- package/dist/runtime/tab-sync-protocol.js +0 -54
- package/dist/runtime/tab-sync-protocol.js.map +0 -1
- package/dist/testing/local-jazz-server.d.ts +0 -2
- package/dist/testing/local-jazz-server.d.ts.map +0 -1
- package/dist/testing/local-jazz-server.js +0 -2
- package/dist/testing/local-jazz-server.js.map +0 -1
package/dist/cli.js
CHANGED
|
@@ -1,13 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
// CLI for jazz-tools schema tooling
|
|
3
3
|
import { existsSync, readFileSync, realpathSync } from "fs";
|
|
4
|
-
import {
|
|
4
|
+
import { readFile } from "fs/promises";
|
|
5
5
|
import { basename, join, resolve } from "path";
|
|
6
6
|
import { fileURLToPath } from "url";
|
|
7
|
-
import {
|
|
8
|
-
import { collectMissingExplicitPolicyDiagnostics } from "./schema-permissions.js";
|
|
9
|
-
import { columnTypeSignature, computeSchemaHash, createSnapshotTimestampFromPublishedAt, createTimestamp, deploy as deployCatalogue, listSnapshotEntries, listSnapshotEntriesForMigrations, normalizeSchemaHashInput, pushMigration as pushCatalogueMigration, resolveKnownSchemaHash, resolveLocalHistoricalSchema, resolveRemoteHistoricalSchema, resolveStoredStructuralSchemaHash, resolveSnapshotEntry, schemaTransitionRequiresRowTransform, shortSchemaHash, snapshotFilename, tableSchemasEqual, writeSnapshotSchemaForMigrations, } from "./dev/catalogue.js";
|
|
10
|
-
import { fetchPermissionsHead, fetchSchemaHashes, fetchStoredWasmSchema, } from "./runtime/schema-fetch.js";
|
|
7
|
+
import { createMigration as createCatalogueMigration, deploy as deployCatalogue, exportSchema as exportCatalogueSchema, getCurrentSchemaHash, getPermissionsStatus, pushMigration as pushCatalogueMigration, shortSchemaHash, validateProject, } from "./dev/catalogue.js";
|
|
11
8
|
const PERMISSIONS_LIFECYCLE_NOTE = "Permission-only changes do not create schema hashes or require migrations.";
|
|
12
9
|
function parseArgs() {
|
|
13
10
|
const args = process.argv.slice(2);
|
|
@@ -28,44 +25,27 @@ function parseArgs() {
|
|
|
28
25
|
}
|
|
29
26
|
return { command, options: { jazzBin, schemaDir } };
|
|
30
27
|
}
|
|
31
|
-
async function pathExists(path) {
|
|
32
|
-
try {
|
|
33
|
-
await access(path);
|
|
34
|
-
return true;
|
|
35
|
-
}
|
|
36
|
-
catch {
|
|
37
|
-
return false;
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
28
|
export async function validate(options) {
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
console.log(`Loaded current permissions from ${compiled.permissionsFile}.`);
|
|
29
|
+
const result = await validateProject(options);
|
|
30
|
+
console.log(`Loaded structural schema from ${result.schemaFile}.`);
|
|
31
|
+
if (result.permissionsFile) {
|
|
32
|
+
console.log(`Loaded current permissions from ${result.permissionsFile}.`);
|
|
46
33
|
console.log(PERMISSIONS_LIFECYCLE_NOTE);
|
|
47
34
|
console.log("Use `jazz-tools permissions status <appId>` or `jazz-tools deploy <appId>` for auth publication.");
|
|
48
35
|
}
|
|
49
|
-
for (const
|
|
50
|
-
console.warn(`\x1b[33m${
|
|
36
|
+
for (const warning of result.warnings) {
|
|
37
|
+
console.warn(`\x1b[33m${warning}\x1b[0m`);
|
|
51
38
|
}
|
|
52
|
-
console.log(`Validated ${tableCount} table${tableCount === 1 ? "" : "s"} in schema.ts.`);
|
|
39
|
+
console.log(`Validated ${result.tableCount} table${result.tableCount === 1 ? "" : "s"} in schema.ts.`);
|
|
53
40
|
}
|
|
54
41
|
export async function exportSchema(options) {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
process.stdout.write(`${JSON.stringify(schema, null, 2)}\n`);
|
|
58
|
-
return;
|
|
59
|
-
}
|
|
60
|
-
const currentSchema = await loadCurrentSchema(options.schemaDir);
|
|
61
|
-
await ensureLocalSnapshot(options.schemaDir, options.migrationsDir, currentSchema);
|
|
62
|
-
process.stdout.write(`${JSON.stringify(currentSchema.schema, null, 2)}\n`);
|
|
42
|
+
const result = await exportCatalogueSchema(options);
|
|
43
|
+
process.stdout.write(`${JSON.stringify(result.schema, null, 2)}\n`);
|
|
63
44
|
}
|
|
64
45
|
export async function schemaHash(options) {
|
|
65
|
-
const
|
|
66
|
-
console.log(`Loaded structural schema from ${
|
|
67
|
-
|
|
68
|
-
console.log(`Current schema hash: ${shortSchemaHash(hash)}`);
|
|
46
|
+
const result = await getCurrentSchemaHash(options);
|
|
47
|
+
console.log(`Loaded structural schema from ${result.schemaFile}.`);
|
|
48
|
+
console.log(`Current schema hash: ${shortSchemaHash(result.hash)}`);
|
|
69
49
|
}
|
|
70
50
|
// Framework bundlers (Vite, SvelteKit, Next.js, Expo) expose public env vars
|
|
71
51
|
// under their own prefix so the client bundle can read them. The CLI often
|
|
@@ -204,45 +184,6 @@ function resolvePermissionsOptions(args) {
|
|
|
204
184
|
schemaDir,
|
|
205
185
|
};
|
|
206
186
|
}
|
|
207
|
-
function defaultMigrationsDir(schemaDir) {
|
|
208
|
-
return join(schemaDir, "migrations");
|
|
209
|
-
}
|
|
210
|
-
function resolvedMigrationsDir(schemaDir, migrationsDir) {
|
|
211
|
-
return migrationsDir ?? defaultMigrationsDir(schemaDir);
|
|
212
|
-
}
|
|
213
|
-
function snapshotsDir(schemaDir, migrationsDir) {
|
|
214
|
-
return join(resolvedMigrationsDir(schemaDir, migrationsDir), "snapshots");
|
|
215
|
-
}
|
|
216
|
-
async function listLocalSnapshotEntries(schemaDir, migrationsDir) {
|
|
217
|
-
return listSnapshotEntries(snapshotsDir(schemaDir, migrationsDir));
|
|
218
|
-
}
|
|
219
|
-
async function resolveLocalSnapshotEntry(schemaDir, migrationsDir, hash, label) {
|
|
220
|
-
return resolveSnapshotEntry(snapshotsDir(schemaDir, migrationsDir), hash, label);
|
|
221
|
-
}
|
|
222
|
-
async function loadLocalSnapshotSchema(schemaDir, migrationsDir, hash, label) {
|
|
223
|
-
const entry = await resolveLocalSnapshotEntry(schemaDir, migrationsDir, hash, label);
|
|
224
|
-
if (!entry) {
|
|
225
|
-
return null;
|
|
226
|
-
}
|
|
227
|
-
return {
|
|
228
|
-
hash: entry.hash,
|
|
229
|
-
schema: entry.schema,
|
|
230
|
-
};
|
|
231
|
-
}
|
|
232
|
-
async function writeSnapshotSchema(schemaDir, migrationsDir, hash, schema, timestamp = createTimestamp()) {
|
|
233
|
-
const dir = snapshotsDir(schemaDir, migrationsDir);
|
|
234
|
-
await mkdir(dir, { recursive: true });
|
|
235
|
-
const filePath = join(dir, snapshotFilename(hash, timestamp));
|
|
236
|
-
await writeFile(filePath, `${JSON.stringify(schema, null, 2)}\n`);
|
|
237
|
-
return filePath;
|
|
238
|
-
}
|
|
239
|
-
async function ensureLocalSnapshot(schemaDir, migrationsDir, schema) {
|
|
240
|
-
const entries = await listLocalSnapshotEntries(schemaDir, migrationsDir);
|
|
241
|
-
if (entries.some((entry) => entry.hash === schema.hash)) {
|
|
242
|
-
return null;
|
|
243
|
-
}
|
|
244
|
-
return writeSnapshotSchema(schemaDir, migrationsDir, schema.hash, schema.schema);
|
|
245
|
-
}
|
|
246
187
|
function requireSchemaExportServerValue(value, kind) {
|
|
247
188
|
if (value) {
|
|
248
189
|
return value;
|
|
@@ -265,473 +206,57 @@ function requireMigrationServerOptions(options) {
|
|
|
265
206
|
adminSecret: requireSchemaExportServerValue(options.adminSecret, "adminSecret"),
|
|
266
207
|
};
|
|
267
208
|
}
|
|
268
|
-
async function resolveExportedSchemaByHash(options) {
|
|
269
|
-
const schemaHash = normalizeSchemaHashInput(options.schemaHash, "schema hash");
|
|
270
|
-
const local = await loadLocalSnapshotSchema(options.schemaDir, options.migrationsDir, schemaHash, "schema hash");
|
|
271
|
-
if (local) {
|
|
272
|
-
return local.schema;
|
|
273
|
-
}
|
|
274
|
-
const serverUrl = requireSchemaExportServerValue(options.serverUrl ?? resolveEnvVar(SERVER_URL_ENV_VARS), "serverUrl");
|
|
275
|
-
const adminSecret = requireSchemaExportServerValue(options.adminSecret ?? process.env.JAZZ_ADMIN_SECRET, "adminSecret");
|
|
276
|
-
const appId = requireAppId(options.appId);
|
|
277
|
-
const resolvedHash = schemaHash.length === 64
|
|
278
|
-
? schemaHash
|
|
279
|
-
: resolveKnownSchemaHash(schemaHash, "schema hash", (await fetchSchemaHashes(serverUrl, { appId, adminSecret })).hashes);
|
|
280
|
-
const storedSchema = await fetchStoredWasmSchema(serverUrl, {
|
|
281
|
-
appId,
|
|
282
|
-
adminSecret,
|
|
283
|
-
schemaHash: resolvedHash,
|
|
284
|
-
});
|
|
285
|
-
await writeSnapshotSchema(options.schemaDir, options.migrationsDir, resolvedHash, storedSchema.schema, createSnapshotTimestampFromPublishedAt(storedSchema.publishedAt));
|
|
286
|
-
return storedSchema.schema;
|
|
287
|
-
}
|
|
288
|
-
function changedTableNames(fromSchema, toSchema) {
|
|
289
|
-
const names = new Set([...Object.keys(fromSchema), ...Object.keys(toSchema)]);
|
|
290
|
-
return [...names].filter((tableName) => !tableSchemasEqual(fromSchema[tableName], toSchema[tableName]));
|
|
291
|
-
}
|
|
292
|
-
function detectPossibleTableRenames(fromSchema, toSchema) {
|
|
293
|
-
const removedTables = Object.keys(fromSchema)
|
|
294
|
-
.filter((tableName) => !toSchema[tableName])
|
|
295
|
-
.sort();
|
|
296
|
-
const addedTables = Object.keys(toSchema)
|
|
297
|
-
.filter((tableName) => !fromSchema[tableName])
|
|
298
|
-
.sort();
|
|
299
|
-
const matches = removedTables
|
|
300
|
-
.map((oldTableName) => {
|
|
301
|
-
const candidateAddedTables = addedTables.filter((newTableName) => tableSchemasEqual(fromSchema[oldTableName], toSchema[newTableName]));
|
|
302
|
-
return candidateAddedTables.length === 1
|
|
303
|
-
? [oldTableName, candidateAddedTables[0]]
|
|
304
|
-
: undefined;
|
|
305
|
-
})
|
|
306
|
-
.filter((match) => match !== undefined);
|
|
307
|
-
return matches.flatMap(([oldTableName, newTableName], i) => {
|
|
308
|
-
const isDuplicateNewTableMatch = matches.some(([_, otherNewTableName], j) => {
|
|
309
|
-
return i !== j && newTableName === otherNewTableName;
|
|
310
|
-
});
|
|
311
|
-
return !isDuplicateNewTableMatch ? [{ oldTableName, newTableName }] : [];
|
|
312
|
-
});
|
|
313
|
-
}
|
|
314
|
-
function ensurePermissionsProject(compiled) {
|
|
315
|
-
if (!compiled.permissions || !compiled.permissionsFile) {
|
|
316
|
-
throw new Error("No permissions found for this app. Create a permissions.ts file before using permissions commands.");
|
|
317
|
-
}
|
|
318
|
-
return compiled;
|
|
319
|
-
}
|
|
320
|
-
/**
|
|
321
|
-
* If the provided schema exists in the server, returns its hash. Otherwise, throws an error.
|
|
322
|
-
*/
|
|
323
|
-
async function resolveStoredStructuralSchemaHashOrThrow(appId, serverUrl, adminSecret, wasmSchema) {
|
|
324
|
-
const hash = await resolveStoredStructuralSchemaHash(appId, serverUrl, adminSecret, wasmSchema);
|
|
325
|
-
if (!hash) {
|
|
326
|
-
throw new Error("No stored structural schema matches the local schema.ts. Publish the structural schema before pushing permissions.");
|
|
327
|
-
}
|
|
328
|
-
return hash;
|
|
329
|
-
}
|
|
330
|
-
function pickWitnessSchema(schema, tableNames) {
|
|
331
|
-
const uniqueTableNames = [...new Set(tableNames)];
|
|
332
|
-
return Object.fromEntries(uniqueTableNames
|
|
333
|
-
.filter((tableName) => schema[tableName])
|
|
334
|
-
.map((tableName) => [tableName, schema[tableName]]));
|
|
335
|
-
}
|
|
336
|
-
function indentBlock(text, indent) {
|
|
337
|
-
const prefix = " ".repeat(indent);
|
|
338
|
-
return text
|
|
339
|
-
.split("\n")
|
|
340
|
-
.map((line) => (line.length === 0 ? line : `${prefix}${line}`))
|
|
341
|
-
.join("\n");
|
|
342
|
-
}
|
|
343
|
-
function baseBuilderExpression(columnType, references) {
|
|
344
|
-
switch (columnType.type) {
|
|
345
|
-
case "Text":
|
|
346
|
-
return "s.string()";
|
|
347
|
-
case "Boolean":
|
|
348
|
-
return "s.boolean()";
|
|
349
|
-
case "Integer":
|
|
350
|
-
return "s.int()";
|
|
351
|
-
case "Double":
|
|
352
|
-
return "s.float()";
|
|
353
|
-
case "Timestamp":
|
|
354
|
-
return "s.timestamp()";
|
|
355
|
-
case "Bytea":
|
|
356
|
-
return "s.bytes()";
|
|
357
|
-
case "Json":
|
|
358
|
-
return columnType.schema ? `s.json(${JSON.stringify(columnType.schema)})` : "s.json()";
|
|
359
|
-
case "Enum":
|
|
360
|
-
return `s.enum(${columnType.variants.map((variant) => JSON.stringify(variant)).join(", ")})`;
|
|
361
|
-
case "Uuid":
|
|
362
|
-
if (!references) {
|
|
363
|
-
throw new Error("Migration stub generation does not yet support bare UUID columns.");
|
|
364
|
-
}
|
|
365
|
-
return `s.ref(${JSON.stringify(references)})`;
|
|
366
|
-
case "Array":
|
|
367
|
-
return `s.array(${baseBuilderExpression(columnType.element, references)})`;
|
|
368
|
-
case "BigInt":
|
|
369
|
-
throw new Error("Migration stub generation does not yet support BIGINT columns.");
|
|
370
|
-
case "Row":
|
|
371
|
-
throw new Error("Migration stub generation does not yet support row-valued columns.");
|
|
372
|
-
}
|
|
373
|
-
}
|
|
374
|
-
function builderExpressionForColumn(column) {
|
|
375
|
-
const base = baseBuilderExpression(column.column_type, column.references);
|
|
376
|
-
const withOptional = column.nullable ? `${base}.optional()` : base;
|
|
377
|
-
if (column.merge_strategy === "Counter") {
|
|
378
|
-
return `${withOptional}.merge("counter")`;
|
|
379
|
-
}
|
|
380
|
-
return withOptional;
|
|
381
|
-
}
|
|
382
|
-
function renderSchemaWitness(schema) {
|
|
383
|
-
const tableEntries = Object.entries(schema)
|
|
384
|
-
.sort(([left], [right]) => left.localeCompare(right))
|
|
385
|
-
.map(([tableName, tableSchema]) => {
|
|
386
|
-
const columnLines = tableSchema.columns.map((column) => `${JSON.stringify(column.name)}: ${builderExpressionForColumn(column)},`);
|
|
387
|
-
return `${JSON.stringify(tableName)}: s.table({\n${indentBlock(columnLines.join("\n"), 2)}\n})`;
|
|
388
|
-
});
|
|
389
|
-
if (tableEntries.length === 0) {
|
|
390
|
-
return "{}";
|
|
391
|
-
}
|
|
392
|
-
return `{\n${indentBlock(tableEntries.join(",\n"), 2)}\n}`;
|
|
393
|
-
}
|
|
394
|
-
function renderArrayElementExpression(columnType, references) {
|
|
395
|
-
return baseBuilderExpression(columnType, references);
|
|
396
|
-
}
|
|
397
|
-
function renderAddOperationExpression(column, defaultExpression) {
|
|
398
|
-
switch (column.column_type.type) {
|
|
399
|
-
case "Text":
|
|
400
|
-
return `s.add.string({ default: ${defaultExpression} })`;
|
|
401
|
-
case "Boolean":
|
|
402
|
-
return `s.add.boolean({ default: ${defaultExpression} })`;
|
|
403
|
-
case "Integer":
|
|
404
|
-
return `s.add.int({ default: ${defaultExpression} })`;
|
|
405
|
-
case "Double":
|
|
406
|
-
return `s.add.float({ default: ${defaultExpression} })`;
|
|
407
|
-
case "Timestamp":
|
|
408
|
-
return `s.add.timestamp({ default: ${defaultExpression} })`;
|
|
409
|
-
case "Bytea":
|
|
410
|
-
return `s.add.bytes({ default: ${defaultExpression} })`;
|
|
411
|
-
case "Json":
|
|
412
|
-
return column.column_type.schema
|
|
413
|
-
? `s.add.json({ default: ${defaultExpression}, schema: ${JSON.stringify(column.column_type.schema)} })`
|
|
414
|
-
: `s.add.json({ default: ${defaultExpression} })`;
|
|
415
|
-
case "Enum":
|
|
416
|
-
return `s.add.enum(${column.column_type.variants
|
|
417
|
-
.map((variant) => JSON.stringify(variant))
|
|
418
|
-
.join(", ")}, { default: ${defaultExpression} })`;
|
|
419
|
-
case "Uuid":
|
|
420
|
-
if (column.references) {
|
|
421
|
-
return `s.add.ref(${JSON.stringify(column.references)}, { default: ${defaultExpression} })`;
|
|
422
|
-
}
|
|
423
|
-
return `s.add.ref("TODO_TABLE", { default: ${defaultExpression} })`;
|
|
424
|
-
case "Array":
|
|
425
|
-
return `s.add.array({ of: ${renderArrayElementExpression(column.column_type.element, column.references)}, default: ${defaultExpression} })`;
|
|
426
|
-
case "BigInt":
|
|
427
|
-
throw new Error("Migration stub generation does not yet support BIGINT columns.");
|
|
428
|
-
case "Row":
|
|
429
|
-
throw new Error("Migration stub generation does not yet support row-valued columns.");
|
|
430
|
-
}
|
|
431
|
-
}
|
|
432
|
-
function renderDropOperationExpression(column, defaultExpression) {
|
|
433
|
-
switch (column.column_type.type) {
|
|
434
|
-
case "Text":
|
|
435
|
-
return `s.drop.string({ backwardsDefault: ${defaultExpression} })`;
|
|
436
|
-
case "Boolean":
|
|
437
|
-
return `s.drop.boolean({ backwardsDefault: ${defaultExpression} })`;
|
|
438
|
-
case "Integer":
|
|
439
|
-
return `s.drop.int({ backwardsDefault: ${defaultExpression} })`;
|
|
440
|
-
case "Double":
|
|
441
|
-
return `s.drop.float({ backwardsDefault: ${defaultExpression} })`;
|
|
442
|
-
case "Timestamp":
|
|
443
|
-
return `s.drop.timestamp({ backwardsDefault: ${defaultExpression} })`;
|
|
444
|
-
case "Bytea":
|
|
445
|
-
return `s.drop.bytes({ backwardsDefault: ${defaultExpression} })`;
|
|
446
|
-
case "Json":
|
|
447
|
-
return column.column_type.schema
|
|
448
|
-
? `s.drop.json({ backwardsDefault: ${defaultExpression}, schema: ${JSON.stringify(column.column_type.schema)} })`
|
|
449
|
-
: `s.drop.json({ backwardsDefault: ${defaultExpression} })`;
|
|
450
|
-
case "Enum":
|
|
451
|
-
return `s.drop.enum(${column.column_type.variants
|
|
452
|
-
.map((variant) => JSON.stringify(variant))
|
|
453
|
-
.join(", ")}, { backwardsDefault: ${defaultExpression} })`;
|
|
454
|
-
case "Uuid":
|
|
455
|
-
if (column.references) {
|
|
456
|
-
return `s.drop.ref(${JSON.stringify(column.references)}, { backwardsDefault: ${defaultExpression} })`;
|
|
457
|
-
}
|
|
458
|
-
return `s.drop.ref("TODO_TABLE", { backwardsDefault: ${defaultExpression} })`;
|
|
459
|
-
case "Array":
|
|
460
|
-
return `s.drop.array({ of: ${renderArrayElementExpression(column.column_type.element, column.references)}, backwardsDefault: ${defaultExpression} })`;
|
|
461
|
-
case "BigInt":
|
|
462
|
-
throw new Error("Migration stub generation does not yet support BIGINT columns.");
|
|
463
|
-
case "Row":
|
|
464
|
-
throw new Error("Migration stub generation does not yet support row-valued columns.");
|
|
465
|
-
}
|
|
466
|
-
}
|
|
467
|
-
function inferTableSuggestions(tableName, fromTable, toTable) {
|
|
468
|
-
const fromColumns = new Map(fromTable.columns.map((column) => [column.name, column]));
|
|
469
|
-
const toColumns = new Map(toTable.columns.map((column) => [column.name, column]));
|
|
470
|
-
const comments = [];
|
|
471
|
-
const properties = [];
|
|
472
|
-
const removedColumns = [...fromColumns.keys()].filter((name) => !toColumns.has(name));
|
|
473
|
-
const addedColumns = [...toColumns.keys()].filter((name) => !fromColumns.has(name));
|
|
474
|
-
if (removedColumns.length === 1 && addedColumns.length === 1) {
|
|
475
|
-
const removed = fromColumns.get(removedColumns[0]);
|
|
476
|
-
const added = toColumns.get(addedColumns[0]);
|
|
477
|
-
if (removed.nullable === added.nullable &&
|
|
478
|
-
removed.references === added.references &&
|
|
479
|
-
columnTypeSignature(removed.column_type) === columnTypeSignature(added.column_type)) {
|
|
480
|
-
comments.push(`Possible rename detected: ${JSON.stringify(removed.name)} -> ${JSON.stringify(added.name)}.`);
|
|
481
|
-
}
|
|
482
|
-
}
|
|
483
|
-
for (const columnName of addedColumns) {
|
|
484
|
-
const column = toColumns.get(columnName);
|
|
485
|
-
if (column.nullable) {
|
|
486
|
-
properties.push(`${JSON.stringify(columnName)}: ${renderAddOperationExpression(column, "null")},`);
|
|
487
|
-
}
|
|
488
|
-
else {
|
|
489
|
-
comments.push(`Added required column ${JSON.stringify(columnName)} needs an explicit default.`);
|
|
490
|
-
}
|
|
491
|
-
}
|
|
492
|
-
for (const columnName of removedColumns) {
|
|
493
|
-
const column = fromColumns.get(columnName);
|
|
494
|
-
if (column.nullable) {
|
|
495
|
-
properties.push(`${JSON.stringify(columnName)}: ${renderDropOperationExpression(column, "null")},`);
|
|
496
|
-
}
|
|
497
|
-
else {
|
|
498
|
-
comments.push(`Removed required column ${JSON.stringify(columnName)} needs an explicit backwardsDefault.`);
|
|
499
|
-
}
|
|
500
|
-
}
|
|
501
|
-
return {
|
|
502
|
-
tableName,
|
|
503
|
-
comments,
|
|
504
|
-
properties,
|
|
505
|
-
};
|
|
506
|
-
}
|
|
507
|
-
function renderMigrationBody(fromSchema, toSchema) {
|
|
508
|
-
const renameSuggestions = detectPossibleTableRenames(fromSchema, toSchema);
|
|
509
|
-
const renamedOldTables = new Set(renameSuggestions.map((suggestion) => suggestion.oldTableName));
|
|
510
|
-
const renamedNewTables = new Set(renameSuggestions.map((suggestion) => suggestion.newTableName));
|
|
511
|
-
const addedTables = Object.keys(toSchema)
|
|
512
|
-
.filter((tableName) => !fromSchema[tableName])
|
|
513
|
-
.sort();
|
|
514
|
-
const removedTables = Object.keys(fromSchema)
|
|
515
|
-
.filter((tableName) => !toSchema[tableName])
|
|
516
|
-
.sort();
|
|
517
|
-
const explicitAddedTables = addedTables.filter((tableName) => !renamedNewTables.has(tableName));
|
|
518
|
-
const explicitRemovedTables = removedTables.filter((tableName) => !renamedOldTables.has(tableName));
|
|
519
|
-
const changedTables = changedTableNames(fromSchema, toSchema);
|
|
520
|
-
const migratableTables = changedTables.filter((tableName) => fromSchema[tableName] !== undefined && toSchema[tableName] !== undefined);
|
|
521
|
-
const witnessFromTables = [...migratableTables, ...explicitRemovedTables];
|
|
522
|
-
const witnessToTables = [...migratableTables, ...explicitAddedTables];
|
|
523
|
-
for (const renameSuggestion of renameSuggestions) {
|
|
524
|
-
witnessFromTables.push(renameSuggestion.oldTableName);
|
|
525
|
-
witnessToTables.push(renameSuggestion.newTableName);
|
|
526
|
-
}
|
|
527
|
-
const witnessFrom = pickWitnessSchema(fromSchema, witnessFromTables);
|
|
528
|
-
const witnessTo = pickWitnessSchema(toSchema, witnessToTables);
|
|
529
|
-
const lines = [];
|
|
530
|
-
for (const tableName of migratableTables) {
|
|
531
|
-
const fromTable = fromSchema[tableName];
|
|
532
|
-
const toTable = toSchema[tableName];
|
|
533
|
-
const suggestion = inferTableSuggestions(tableName, fromTable, toTable);
|
|
534
|
-
lines.push(`${JSON.stringify(tableName)}: {`);
|
|
535
|
-
for (const comment of suggestion.comments) {
|
|
536
|
-
lines.push(` // TODO: ${comment}`);
|
|
537
|
-
}
|
|
538
|
-
for (const property of suggestion.properties) {
|
|
539
|
-
lines.push(` ${property}`);
|
|
540
|
-
}
|
|
541
|
-
if (suggestion.comments.length === 0 && suggestion.properties.length === 0) {
|
|
542
|
-
lines.push(" // TODO: No safe migration steps were inferred automatically.");
|
|
543
|
-
}
|
|
544
|
-
lines.push("},");
|
|
545
|
-
lines.push("");
|
|
546
|
-
}
|
|
547
|
-
if (lines.length === 0) {
|
|
548
|
-
if (renameSuggestions.length === 0 &&
|
|
549
|
-
explicitAddedTables.length === 0 &&
|
|
550
|
-
explicitRemovedTables.length === 0) {
|
|
551
|
-
lines.push(changedTables.length === 0
|
|
552
|
-
? "// TODO: No schema differences were detected."
|
|
553
|
-
: "// TODO: No column-level migration steps were required for the detected schema changes.");
|
|
554
|
-
}
|
|
555
|
-
}
|
|
556
|
-
return {
|
|
557
|
-
migrateBody: lines.length > 0 ? lines.join("\n").trimEnd() : undefined,
|
|
558
|
-
createTablesBody: explicitAddedTables.length > 0
|
|
559
|
-
? explicitAddedTables.map((tableName) => `${JSON.stringify(tableName)}: true,`).join("\n")
|
|
560
|
-
: undefined,
|
|
561
|
-
dropTablesBody: explicitRemovedTables.length > 0
|
|
562
|
-
? explicitRemovedTables.map((tableName) => `${JSON.stringify(tableName)}: true,`).join("\n")
|
|
563
|
-
: undefined,
|
|
564
|
-
renameTablesBody: renameSuggestions.length > 0
|
|
565
|
-
? renameSuggestions
|
|
566
|
-
.map((renameSuggestion) => `${renameSuggestion.newTableName}: s.renameTableFrom(${JSON.stringify(renameSuggestion.oldTableName)}),`)
|
|
567
|
-
.join("\n")
|
|
568
|
-
: undefined,
|
|
569
|
-
witnessFrom,
|
|
570
|
-
witnessTo,
|
|
571
|
-
};
|
|
572
|
-
}
|
|
573
209
|
async function packageVersion() {
|
|
574
210
|
const packageJson = JSON.parse(await readFile(new URL("../package.json", import.meta.url), "utf8"));
|
|
575
211
|
return packageJson.version ?? "unknown";
|
|
576
212
|
}
|
|
577
|
-
function normalizeMigrationName(name) {
|
|
578
|
-
const normalized = name
|
|
579
|
-
.trim()
|
|
580
|
-
.toLowerCase()
|
|
581
|
-
.replace(/[^a-z0-9]+/g, "-")
|
|
582
|
-
.replace(/^-+|-+$/g, "");
|
|
583
|
-
if (normalized.length === 0) {
|
|
584
|
-
throw new Error("Migration name must contain at least one ASCII letter or digit after normalization.");
|
|
585
|
-
}
|
|
586
|
-
return normalized;
|
|
587
|
-
}
|
|
588
|
-
function migrationFilename(migrationsDir, fromHash, toHash, name = "unnamed", timestamp = createTimestamp()) {
|
|
589
|
-
return join(migrationsDir, `${timestamp}-${name}-${shortSchemaHash(fromHash)}-${shortSchemaHash(toHash)}.ts`);
|
|
590
|
-
}
|
|
591
|
-
function renderMigrationStub(input) {
|
|
592
|
-
const rendered = renderMigrationBody(input.fromSchema, input.toSchema);
|
|
593
|
-
const sections = [];
|
|
594
|
-
if (rendered.renameTablesBody) {
|
|
595
|
-
sections.push(` renameTables: {\n${indentBlock(rendered.renameTablesBody, 4)}\n },`);
|
|
596
|
-
}
|
|
597
|
-
if (rendered.createTablesBody) {
|
|
598
|
-
sections.push(` createTables: {\n${indentBlock(rendered.createTablesBody, 4)}\n },`);
|
|
599
|
-
}
|
|
600
|
-
if (rendered.dropTablesBody) {
|
|
601
|
-
sections.push(` dropTables: {\n${indentBlock(rendered.dropTablesBody, 4)}\n },`);
|
|
602
|
-
}
|
|
603
|
-
if (rendered.migrateBody) {
|
|
604
|
-
sections.push(` migrate: {\n${indentBlock(rendered.migrateBody, 4)}\n },`);
|
|
605
|
-
}
|
|
606
|
-
sections.push(` fromHash: ${JSON.stringify(shortSchemaHash(input.fromHash))},`);
|
|
607
|
-
sections.push(` toHash: ${JSON.stringify(shortSchemaHash(input.toHash))},`);
|
|
608
|
-
sections.push(` from: ${renderSchemaWitness(rendered.witnessFrom)},`);
|
|
609
|
-
sections.push(` to: ${renderSchemaWitness(rendered.witnessTo)},`);
|
|
610
|
-
return `import { schema as s } from "jazz-tools";
|
|
611
|
-
|
|
612
|
-
export default s.defineMigration({
|
|
613
|
-
${sections.join("\n")}
|
|
614
|
-
});
|
|
615
|
-
`;
|
|
616
|
-
}
|
|
617
|
-
function isCommittedSnapshotFileName(fileName) {
|
|
618
|
-
return /^\d{8}T\d{6}-[0-9a-f]{12}\.json$/i.test(fileName);
|
|
619
|
-
}
|
|
620
|
-
async function loadLatestCommittedSnapshot(migrationsDir) {
|
|
621
|
-
const entries = await listSnapshotEntriesForMigrations(migrationsDir);
|
|
622
|
-
const latest = entries
|
|
623
|
-
.filter((entry) => isCommittedSnapshotFileName(entry.fileName))
|
|
624
|
-
.sort((left, right) => left.fileName.localeCompare(right.fileName))
|
|
625
|
-
.at(-1);
|
|
626
|
-
if (!latest) {
|
|
627
|
-
return null;
|
|
628
|
-
}
|
|
629
|
-
return {
|
|
630
|
-
hash: latest.hash,
|
|
631
|
-
schema: latest.schema,
|
|
632
|
-
};
|
|
633
|
-
}
|
|
634
|
-
async function ensureCommittedSnapshot(migrationsDir, schema, timestamp) {
|
|
635
|
-
const entries = await listSnapshotEntriesForMigrations(migrationsDir);
|
|
636
|
-
if (entries.some((entry) => entry.hash === schema.hash && isCommittedSnapshotFileName(entry.fileName))) {
|
|
637
|
-
return null;
|
|
638
|
-
}
|
|
639
|
-
return writeSnapshotSchemaForMigrations(migrationsDir, snapshotFilename(schema.hash, timestamp), schema.schema);
|
|
640
|
-
}
|
|
641
|
-
async function loadCurrentSchema(schemaDir) {
|
|
642
|
-
const compiled = await loadCompiledSchema(schemaDir);
|
|
643
|
-
return {
|
|
644
|
-
hash: await computeSchemaHash(compiled.wasmSchema),
|
|
645
|
-
schema: compiled.wasmSchema,
|
|
646
|
-
};
|
|
647
|
-
}
|
|
648
|
-
async function resolveHistoricalSchemaForCli(migrationsDir, hash, label, appId, serverUrl, adminSecret) {
|
|
649
|
-
const local = await resolveLocalHistoricalSchema(migrationsDir, hash, label);
|
|
650
|
-
if (local) {
|
|
651
|
-
return { hash: local.hash, schema: local.schema };
|
|
652
|
-
}
|
|
653
|
-
return resolveRemoteHistoricalSchema(migrationsDir, hash, label, requireAppId(appId), requireSchemaExportServerValue(serverUrl, "serverUrl"), requireSchemaExportServerValue(adminSecret, "adminSecret"));
|
|
654
|
-
}
|
|
655
213
|
export async function createMigration(options) {
|
|
656
|
-
const
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
let toSchema;
|
|
661
|
-
let shouldWriteCommittedSnapshot = false;
|
|
662
|
-
const timestamp = createTimestamp();
|
|
663
|
-
if (explicitHashFlow) {
|
|
664
|
-
if (options.fromHash) {
|
|
665
|
-
fromSchema = await resolveHistoricalSchemaForCli(options.migrationsDir, options.fromHash, "fromHash", options.appId, options.serverUrl, options.adminSecret);
|
|
666
|
-
}
|
|
667
|
-
else {
|
|
668
|
-
const latest = await loadLatestCommittedSnapshot(options.migrationsDir);
|
|
669
|
-
if (!latest) {
|
|
670
|
-
throw new Error("No committed snapshot found. Provide --fromHash or run `jazz-tools migrations create` once to create an initial snapshot.");
|
|
671
|
-
}
|
|
672
|
-
fromSchema = latest;
|
|
673
|
-
}
|
|
674
|
-
toSchema = options.toHash
|
|
675
|
-
? await resolveHistoricalSchemaForCli(options.migrationsDir, options.toHash, "toHash", options.appId, options.serverUrl, options.adminSecret)
|
|
676
|
-
: currentSchema;
|
|
677
|
-
shouldWriteCommittedSnapshot = !options.toHash;
|
|
678
|
-
}
|
|
679
|
-
else {
|
|
680
|
-
const latest = await loadLatestCommittedSnapshot(options.migrationsDir);
|
|
681
|
-
if (!latest) {
|
|
682
|
-
const snapshotPath = await ensureCommittedSnapshot(options.migrationsDir, currentSchema, timestamp);
|
|
683
|
-
console.log(`Wrote initial schema snapshot: ${snapshotPath}`);
|
|
214
|
+
const result = await createCatalogueMigration(options);
|
|
215
|
+
switch (result.status) {
|
|
216
|
+
case "initial-snapshot":
|
|
217
|
+
console.log("Wrote initial schema snapshot: " + result.snapshotPath);
|
|
684
218
|
console.log("No migration created because there was no previous local schema baseline.");
|
|
685
219
|
return null;
|
|
686
|
-
|
|
687
|
-
if (latest.hash === currentSchema.hash) {
|
|
220
|
+
case "unchanged":
|
|
688
221
|
console.log("No structural schema changes detected.");
|
|
689
222
|
return null;
|
|
223
|
+
case "migration-not-required": {
|
|
224
|
+
const version = await packageVersion();
|
|
225
|
+
console.log("No reviewed migration file needed because this schema change does not require row transformations.");
|
|
226
|
+
console.log("Next step: Run npx jazz-tools@" +
|
|
227
|
+
version +
|
|
228
|
+
" migrations push " +
|
|
229
|
+
(options.appId ?? "<appId>") +
|
|
230
|
+
" " +
|
|
231
|
+
shortSchemaHash(result.fromHash) +
|
|
232
|
+
" " +
|
|
233
|
+
shortSchemaHash(result.toHash));
|
|
234
|
+
return null;
|
|
690
235
|
}
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
236
|
+
case "generated": {
|
|
237
|
+
const version = await packageVersion();
|
|
238
|
+
console.log("Generated: " + result.filePath);
|
|
239
|
+
console.log("");
|
|
240
|
+
console.log("Migration stubs are only for structural schema changes.");
|
|
241
|
+
console.log(PERMISSIONS_LIFECYCLE_NOTE);
|
|
242
|
+
console.log("");
|
|
243
|
+
console.log("Next steps:");
|
|
244
|
+
console.log("1. Fill in migrate.");
|
|
245
|
+
if (result.needsRename) {
|
|
246
|
+
console.log("2. Rename the file by replacing 'unnamed'.");
|
|
247
|
+
}
|
|
248
|
+
console.log((result.needsRename ? "3" : "2") +
|
|
249
|
+
". Run npx jazz-tools@" +
|
|
250
|
+
version +
|
|
251
|
+
" migrations push " +
|
|
252
|
+
(options.appId ?? "<appId>") +
|
|
253
|
+
" " +
|
|
254
|
+
shortSchemaHash(result.fromHash) +
|
|
255
|
+
" " +
|
|
256
|
+
shortSchemaHash(result.toHash));
|
|
257
|
+
return result.filePath;
|
|
702
258
|
}
|
|
703
|
-
|
|
704
|
-
console.log("No reviewed migration file needed because this schema change does not require row transformations.");
|
|
705
|
-
console.log(`Next step: Run npx jazz-tools@${version} migrations push ${options.appId ?? "<appId>"} ${shortSchemaHash(fromSchema.hash)} ${shortSchemaHash(toSchema.hash)}`);
|
|
706
|
-
return null;
|
|
707
|
-
}
|
|
708
|
-
const filePath = migrationFilename(options.migrationsDir, fromSchema.hash, toSchema.hash, options.name ? normalizeMigrationName(options.name) : undefined, timestamp);
|
|
709
|
-
if (await pathExists(filePath)) {
|
|
710
|
-
throw new Error(`Migration stub already exists: ${filePath}`);
|
|
711
|
-
}
|
|
712
|
-
const stub = renderMigrationStub({
|
|
713
|
-
fromHash: fromSchema.hash,
|
|
714
|
-
toHash: toSchema.hash,
|
|
715
|
-
fromSchema: fromSchema.schema,
|
|
716
|
-
toSchema: toSchema.schema,
|
|
717
|
-
});
|
|
718
|
-
await writeFile(filePath, stub);
|
|
719
|
-
if (shouldWriteCommittedSnapshot) {
|
|
720
|
-
await ensureCommittedSnapshot(options.migrationsDir, toSchema, timestamp);
|
|
721
|
-
}
|
|
722
|
-
const version = await packageVersion();
|
|
723
|
-
console.log(`Generated: ${filePath}`);
|
|
724
|
-
console.log("");
|
|
725
|
-
console.log("Migration stubs are only for structural schema changes.");
|
|
726
|
-
console.log(PERMISSIONS_LIFECYCLE_NOTE);
|
|
727
|
-
console.log("");
|
|
728
|
-
console.log("Next steps:");
|
|
729
|
-
console.log("1. Fill in migrate.");
|
|
730
|
-
if (!options.name) {
|
|
731
|
-
console.log("2. Rename the file by replacing 'unnamed'.");
|
|
732
|
-
}
|
|
733
|
-
console.log(`${options.name ? "2" : "3"}. Run npx jazz-tools@${version} migrations push ${options.appId ?? "<appId>"} ${shortSchemaHash(fromSchema.hash)} ${shortSchemaHash(toSchema.hash)}`);
|
|
734
|
-
return filePath;
|
|
259
|
+
}
|
|
735
260
|
}
|
|
736
261
|
export async function pushMigration(options) {
|
|
737
262
|
const { appId, serverUrl, adminSecret } = requireMigrationServerOptions(options);
|
|
@@ -764,29 +289,24 @@ function logDeployWarning(message) {
|
|
|
764
289
|
console.warn(`Warning: ${message}`);
|
|
765
290
|
}
|
|
766
291
|
export async function permissionsStatus(options) {
|
|
767
|
-
const
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
adminSecret: options.adminSecret,
|
|
772
|
-
});
|
|
773
|
-
console.log(`Loaded structural schema from ${compiled.schemaFile}.`);
|
|
774
|
-
console.log(`Loaded current permissions from ${compiled.permissionsFile}.`);
|
|
775
|
-
console.log(`Local structural schema matches stored hash ${shortSchemaHash(localSchemaHash)}.`);
|
|
292
|
+
const result = await getPermissionsStatus(options);
|
|
293
|
+
console.log(`Loaded structural schema from ${result.schemaFile}.`);
|
|
294
|
+
console.log(`Loaded current permissions from ${result.permissionsFile}.`);
|
|
295
|
+
console.log(`Local structural schema matches stored hash ${shortSchemaHash(result.localSchemaHash)}.`);
|
|
776
296
|
console.log(PERMISSIONS_LIFECYCLE_NOTE);
|
|
777
|
-
if (!head) {
|
|
297
|
+
if (!result.head) {
|
|
778
298
|
console.log("Server has no published permissions head yet.");
|
|
779
299
|
console.log("Next push will publish version 1.");
|
|
780
300
|
return;
|
|
781
301
|
}
|
|
782
|
-
console.log(`Server permissions head is ${describePermissionsHead(head)}.`);
|
|
783
|
-
if (head.schemaHash === localSchemaHash) {
|
|
302
|
+
console.log(`Server permissions head is ${describePermissionsHead(result.head)}.`);
|
|
303
|
+
if (result.head.schemaHash === result.localSchemaHash) {
|
|
784
304
|
console.log("Current server permissions already target this structural schema.");
|
|
785
305
|
}
|
|
786
306
|
else {
|
|
787
|
-
console.log(`Current server permissions target ${shortSchemaHash(head.schemaHash)}; pushing will retarget the head to ${shortSchemaHash(localSchemaHash)}.`);
|
|
307
|
+
console.log(`Current server permissions target ${shortSchemaHash(result.head.schemaHash)}; pushing will retarget the head to ${shortSchemaHash(result.localSchemaHash)}.`);
|
|
788
308
|
}
|
|
789
|
-
console.log(`Next push will require parent bundle ${head.bundleObjectId}.`);
|
|
309
|
+
console.log(`Next push will require parent bundle ${result.head.bundleObjectId}.`);
|
|
790
310
|
}
|
|
791
311
|
export async function deploy(options) {
|
|
792
312
|
const result = await deployCatalogue({
|