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.
Files changed (270) hide show
  1. package/bin/docs-index.txt +1 -1
  2. package/bin/native/jazz-tools-darwin-arm64 +0 -0
  3. package/bin/native/jazz-tools-darwin-x64 +0 -0
  4. package/bin/native/jazz-tools-linux-arm64 +0 -0
  5. package/bin/native/jazz-tools-linux-x64 +0 -0
  6. package/dist/better-auth-adapter/index.test.js +11 -11
  7. package/dist/better-auth-adapter/index.test.js.map +1 -1
  8. package/dist/cli.d.ts.map +1 -1
  9. package/dist/cli.js +63 -543
  10. package/dist/cli.js.map +1 -1
  11. package/dist/codegen/schema-reader.d.ts.map +1 -1
  12. package/dist/codegen/schema-reader.js +6 -0
  13. package/dist/codegen/schema-reader.js.map +1 -1
  14. package/dist/dev/catalogue.d.ts +111 -53
  15. package/dist/dev/catalogue.d.ts.map +1 -1
  16. package/dist/dev/catalogue.js +316 -120
  17. package/dist/dev/catalogue.js.map +1 -1
  18. package/dist/dev/catalogue.test.js +68 -10
  19. package/dist/dev/catalogue.test.js.map +1 -1
  20. package/dist/dev/dev-server.d.ts +16 -3
  21. package/dist/dev/dev-server.d.ts.map +1 -1
  22. package/dist/dev/dev-server.js +23 -7
  23. package/dist/dev/dev-server.js.map +1 -1
  24. package/dist/dev/dev-server.test.js +8 -6
  25. package/dist/dev/dev-server.test.js.map +1 -1
  26. package/dist/dev/expo.test.js +3 -3
  27. package/dist/dev/expo.test.js.map +1 -1
  28. package/dist/dev/index.d.ts +1 -1
  29. package/dist/dev/index.d.ts.map +1 -1
  30. package/dist/dev/index.js +1 -1
  31. package/dist/dev/index.js.map +1 -1
  32. package/dist/dev/managed-runtime.d.ts.map +1 -1
  33. package/dist/dev/managed-runtime.js +5 -4
  34. package/dist/dev/managed-runtime.js.map +1 -1
  35. package/dist/dev/managed-runtime.test.js +11 -4
  36. package/dist/dev/managed-runtime.test.js.map +1 -1
  37. package/dist/dev/migrations.d.ts +8 -0
  38. package/dist/dev/migrations.d.ts.map +1 -0
  39. package/dist/dev/migrations.js +300 -0
  40. package/dist/dev/migrations.js.map +1 -0
  41. package/dist/dev/next.test.js +19 -9
  42. package/dist/dev/next.test.js.map +1 -1
  43. package/dist/dev/schema-utils.d.ts +7 -0
  44. package/dist/dev/schema-utils.d.ts.map +1 -0
  45. package/dist/dev/schema-utils.js +60 -0
  46. package/dist/dev/schema-utils.js.map +1 -0
  47. package/dist/dev/schema-watcher.js +3 -3
  48. package/dist/dev/schema-watcher.js.map +1 -1
  49. package/dist/dev/sveltekit.test.js +33 -22
  50. package/dist/dev/sveltekit.test.js.map +1 -1
  51. package/dist/dev/vite.test.js +13 -3
  52. package/dist/dev/vite.test.js.map +1 -1
  53. package/dist/drivers/types.d.ts +1 -1
  54. package/dist/drivers/types.d.ts.map +1 -1
  55. package/dist/dsl.d.ts +9 -1
  56. package/dist/dsl.d.ts.map +1 -1
  57. package/dist/dsl.js +8 -2
  58. package/dist/dsl.js.map +1 -1
  59. package/dist/dsl.test.js +34 -0
  60. package/dist/dsl.test.js.map +1 -1
  61. package/dist/react-core/use-all.d.ts +1 -1
  62. package/dist/react-core/use-all.d.ts.map +1 -1
  63. package/dist/react-core/use-all.js.map +1 -1
  64. package/dist/runtime/browser-broker-client.d.ts +101 -0
  65. package/dist/runtime/browser-broker-client.d.ts.map +1 -0
  66. package/dist/runtime/browser-broker-client.js +598 -0
  67. package/dist/runtime/browser-broker-client.js.map +1 -0
  68. package/dist/runtime/browser-broker-client.test.d.ts +2 -0
  69. package/dist/runtime/browser-broker-client.test.d.ts.map +1 -0
  70. package/dist/runtime/browser-broker-client.test.js +798 -0
  71. package/dist/runtime/browser-broker-client.test.js.map +1 -0
  72. package/dist/runtime/browser-broker-errors.d.ts +10 -0
  73. package/dist/runtime/browser-broker-errors.d.ts.map +1 -0
  74. package/dist/runtime/browser-broker-errors.js +22 -0
  75. package/dist/runtime/browser-broker-errors.js.map +1 -0
  76. package/dist/runtime/browser-broker-protocol.d.ts +196 -0
  77. package/dist/runtime/browser-broker-protocol.d.ts.map +1 -0
  78. package/dist/runtime/browser-broker-protocol.js +159 -0
  79. package/dist/runtime/browser-broker-protocol.js.map +1 -0
  80. package/dist/runtime/browser-broker-protocol.test.d.ts +2 -0
  81. package/dist/runtime/browser-broker-protocol.test.d.ts.map +1 -0
  82. package/dist/runtime/browser-broker-protocol.test.js +67 -0
  83. package/dist/runtime/browser-broker-protocol.test.js.map +1 -0
  84. package/dist/runtime/client.d.ts +2 -0
  85. package/dist/runtime/client.d.ts.map +1 -1
  86. package/dist/runtime/client.js.map +1 -1
  87. package/dist/runtime/context.d.ts +3 -0
  88. package/dist/runtime/context.d.ts.map +1 -1
  89. package/dist/runtime/db-runtime-module.d.ts +1 -0
  90. package/dist/runtime/db-runtime-module.d.ts.map +1 -1
  91. package/dist/runtime/db-runtime-module.js.map +1 -1
  92. package/dist/runtime/db.d.ts +81 -34
  93. package/dist/runtime/db.d.ts.map +1 -1
  94. package/dist/runtime/db.driver-mode.test.js +51 -1
  95. package/dist/runtime/db.driver-mode.test.js.map +1 -1
  96. package/dist/runtime/db.js +790 -310
  97. package/dist/runtime/db.js.map +1 -1
  98. package/dist/runtime/db.one.test.d.ts +2 -0
  99. package/dist/runtime/db.one.test.d.ts.map +1 -0
  100. package/dist/runtime/db.one.test.js +69 -0
  101. package/dist/runtime/db.one.test.js.map +1 -0
  102. package/dist/runtime/db.transport.test.js +25 -0
  103. package/dist/runtime/db.transport.test.js.map +1 -1
  104. package/dist/runtime/db.worker-bootstrap.test.js +339 -19
  105. package/dist/runtime/db.worker-bootstrap.test.js.map +1 -1
  106. package/dist/runtime/index.d.ts +2 -1
  107. package/dist/runtime/index.d.ts.map +1 -1
  108. package/dist/runtime/index.js +1 -0
  109. package/dist/runtime/index.js.map +1 -1
  110. package/dist/runtime/leader-lock.d.ts +21 -3
  111. package/dist/runtime/leader-lock.d.ts.map +1 -1
  112. package/dist/runtime/leader-lock.js +131 -33
  113. package/dist/runtime/leader-lock.js.map +1 -1
  114. package/dist/runtime/napi.auth-failure.test.js +1 -1
  115. package/dist/runtime/napi.auth-failure.test.js.map +1 -1
  116. package/dist/runtime/napi.for-request.test.js +1 -1
  117. package/dist/runtime/napi.for-request.test.js.map +1 -1
  118. package/dist/runtime/napi.integration.test.js +4 -8
  119. package/dist/runtime/napi.integration.test.js.map +1 -1
  120. package/dist/runtime/permissions.repro.test.js +1 -1
  121. package/dist/runtime/permissions.repro.test.js.map +1 -1
  122. package/dist/runtime/runtime-config.d.ts +1 -0
  123. package/dist/runtime/runtime-config.d.ts.map +1 -1
  124. package/dist/runtime/runtime-config.js +11 -5
  125. package/dist/runtime/runtime-config.js.map +1 -1
  126. package/dist/runtime/runtime-config.test.d.ts +2 -0
  127. package/dist/runtime/runtime-config.test.d.ts.map +1 -0
  128. package/dist/runtime/runtime-config.test.js +21 -0
  129. package/dist/runtime/runtime-config.test.js.map +1 -0
  130. package/dist/runtime/schema-fetch.d.ts +5 -0
  131. package/dist/runtime/schema-fetch.d.ts.map +1 -1
  132. package/dist/runtime/schema-fetch.js +33 -2
  133. package/dist/runtime/schema-fetch.js.map +1 -1
  134. package/dist/runtime/schema-fetch.test.js +31 -0
  135. package/dist/runtime/schema-fetch.test.js.map +1 -1
  136. package/dist/runtime/wasm-runtime-module.d.ts +1 -1
  137. package/dist/runtime/wasm-runtime-module.d.ts.map +1 -1
  138. package/dist/runtime/wasm-runtime-module.js +6 -2
  139. package/dist/runtime/wasm-runtime-module.js.map +1 -1
  140. package/dist/runtime/worker-bridge.d.ts +25 -2
  141. package/dist/runtime/worker-bridge.d.ts.map +1 -1
  142. package/dist/runtime/worker-bridge.js +48 -2
  143. package/dist/runtime/worker-bridge.js.map +1 -1
  144. package/dist/runtime/worker-bridge.test.d.ts +2 -0
  145. package/dist/runtime/worker-bridge.test.d.ts.map +1 -0
  146. package/dist/runtime/worker-bridge.test.js +53 -0
  147. package/dist/runtime/worker-bridge.test.js.map +1 -0
  148. package/dist/schema-loader.d.ts.map +1 -1
  149. package/dist/schema-loader.js +2 -0
  150. package/dist/schema-loader.js.map +1 -1
  151. package/dist/schema.d.ts +1 -1
  152. package/dist/schema.d.ts.map +1 -1
  153. package/dist/shared/index.d.ts +25 -0
  154. package/dist/shared/index.d.ts.map +1 -0
  155. package/dist/shared/index.js +22 -0
  156. package/dist/shared/index.js.map +1 -0
  157. package/dist/shared/index.test.d.ts +2 -0
  158. package/dist/shared/index.test.d.ts.map +1 -0
  159. package/dist/shared/index.test.js +79 -0
  160. package/dist/shared/index.test.js.map +1 -0
  161. package/dist/solid/create-solid-jazz-client-internal.d.ts +13 -0
  162. package/dist/solid/create-solid-jazz-client-internal.d.ts.map +1 -0
  163. package/dist/solid/create-solid-jazz-client-internal.js +47 -0
  164. package/dist/solid/create-solid-jazz-client-internal.js.map +1 -0
  165. package/dist/solid/create-solid-jazz-client-internal.ssr.js +64 -0
  166. package/dist/solid/create-solid-jazz-client-internal.ssr.js.map +1 -0
  167. package/dist/solid/create-solid-jazz-client-internal.test.d.ts +2 -0
  168. package/dist/solid/create-solid-jazz-client-internal.test.d.ts.map +1 -0
  169. package/dist/solid/create-solid-jazz-client.d.ts +34 -0
  170. package/dist/solid/create-solid-jazz-client.d.ts.map +1 -0
  171. package/dist/solid/create-solid-jazz-client.integration.test.d.ts +2 -0
  172. package/dist/solid/create-solid-jazz-client.integration.test.d.ts.map +1 -0
  173. package/dist/solid/create-solid-jazz-client.js +38 -0
  174. package/dist/solid/create-solid-jazz-client.js.map +1 -0
  175. package/dist/solid/create-solid-jazz-client.ssr.js +41 -0
  176. package/dist/solid/create-solid-jazz-client.ssr.js.map +1 -0
  177. package/dist/solid/index.d.ts +8 -0
  178. package/dist/solid/index.d.ts.map +1 -0
  179. package/dist/solid/index.js +7 -0
  180. package/dist/solid/index.ssr.js +7 -0
  181. package/dist/solid/provider.d.ts +27 -0
  182. package/dist/solid/provider.d.ts.map +1 -0
  183. package/dist/solid/provider.js +44 -0
  184. package/dist/solid/provider.js.map +1 -0
  185. package/dist/solid/provider.ssr.js +44 -0
  186. package/dist/solid/provider.ssr.js.map +1 -0
  187. package/dist/solid/solid-jazz-client-store.d.ts +11 -0
  188. package/dist/solid/solid-jazz-client-store.d.ts.map +1 -0
  189. package/dist/solid/solid-jazz-client-store.js +35 -0
  190. package/dist/solid/solid-jazz-client-store.js.map +1 -0
  191. package/dist/solid/solid-jazz-client-store.ssr.js +37 -0
  192. package/dist/solid/solid-jazz-client-store.ssr.js.map +1 -0
  193. package/dist/solid/solid-jazz-client-store.test.d.ts +2 -0
  194. package/dist/solid/solid-jazz-client-store.test.d.ts.map +1 -0
  195. package/dist/solid/use-all.d.ts +16 -0
  196. package/dist/solid/use-all.d.ts.map +1 -0
  197. package/dist/solid/use-all.js +60 -0
  198. package/dist/solid/use-all.js.map +1 -0
  199. package/dist/solid/use-all.ssr.js +68 -0
  200. package/dist/solid/use-all.ssr.js.map +1 -0
  201. package/dist/solid/use-all.test.d.ts +2 -0
  202. package/dist/solid/use-all.test.d.ts.map +1 -0
  203. package/dist/solid/use-local-first-auth.d.ts +11 -0
  204. package/dist/solid/use-local-first-auth.d.ts.map +1 -0
  205. package/dist/solid/use-local-first-auth.js +65 -0
  206. package/dist/solid/use-local-first-auth.js.map +1 -0
  207. package/dist/solid/use-local-first-auth.ssr.js +83 -0
  208. package/dist/solid/use-local-first-auth.ssr.js.map +1 -0
  209. package/dist/solid/use-local-first-auth.test.d.ts +2 -0
  210. package/dist/solid/use-local-first-auth.test.d.ts.map +1 -0
  211. package/dist/svelte/use-all.svelte.d.ts +1 -1
  212. package/dist/svelte/use-all.svelte.d.ts.map +1 -1
  213. package/dist/svelte/use-all.svelte.js +1 -1
  214. package/dist/testing/index.d.ts +2 -2
  215. package/dist/testing/index.d.ts.map +1 -1
  216. package/dist/testing/index.js +2 -2
  217. package/dist/testing/index.js.map +1 -1
  218. package/dist/testing/index.test.js +11 -69
  219. package/dist/testing/index.test.js.map +1 -1
  220. package/dist/testing/policy-test-app.d.ts +1 -1
  221. package/dist/testing/policy-test-app.d.ts.map +1 -1
  222. package/dist/testing/policy-test-app.js +1 -1
  223. package/dist/testing/policy-test-app.js.map +1 -1
  224. package/dist/testing/test-jwt-issuer.d.ts +16 -0
  225. package/dist/testing/test-jwt-issuer.d.ts.map +1 -0
  226. package/dist/testing/test-jwt-issuer.js +23 -0
  227. package/dist/testing/test-jwt-issuer.js.map +1 -0
  228. package/dist/vue/use-all.d.ts +1 -1
  229. package/dist/vue/use-all.d.ts.map +1 -1
  230. package/dist/vue/use-all.js +1 -1
  231. package/dist/vue/use-all.js.map +1 -1
  232. package/dist/web/create-jazz-client.d.ts +20 -0
  233. package/dist/web/create-jazz-client.d.ts.map +1 -0
  234. package/dist/web/create-jazz-client.js +61 -0
  235. package/dist/web/create-jazz-client.js.map +1 -0
  236. package/dist/web/create-jazz-client.test.d.ts +2 -0
  237. package/dist/web/create-jazz-client.test.d.ts.map +1 -0
  238. package/dist/web/create-jazz-client.test.js +159 -0
  239. package/dist/web/create-jazz-client.test.js.map +1 -0
  240. package/dist/worker/broker-worker-bundle.test.d.ts +2 -0
  241. package/dist/worker/broker-worker-bundle.test.d.ts.map +1 -0
  242. package/dist/worker/broker-worker-bundle.test.js +40 -0
  243. package/dist/worker/broker-worker-bundle.test.js.map +1 -0
  244. package/dist/worker/jazz-broker-worker.d.ts +2 -0
  245. package/dist/worker/jazz-broker-worker.d.ts.map +1 -0
  246. package/dist/worker/jazz-broker-worker.js +1090 -0
  247. package/dist/worker/jazz-worker.js +62 -2
  248. package/dist/worker/jazz-worker.js.map +1 -1
  249. package/dist/worker/jazz-worker.ts +83 -2
  250. package/package.json +27 -8
  251. package/dist/runtime/storage-reset-coordinator.d.ts +0 -58
  252. package/dist/runtime/storage-reset-coordinator.d.ts.map +0 -1
  253. package/dist/runtime/storage-reset-coordinator.js +0 -402
  254. package/dist/runtime/storage-reset-coordinator.js.map +0 -1
  255. package/dist/runtime/tab-leader-election.d.ts +0 -97
  256. package/dist/runtime/tab-leader-election.d.ts.map +0 -1
  257. package/dist/runtime/tab-leader-election.js +0 -339
  258. package/dist/runtime/tab-leader-election.js.map +0 -1
  259. package/dist/runtime/tab-leader-election.test.d.ts +0 -2
  260. package/dist/runtime/tab-leader-election.test.d.ts.map +0 -1
  261. package/dist/runtime/tab-leader-election.test.js +0 -278
  262. package/dist/runtime/tab-leader-election.test.js.map +0 -1
  263. package/dist/runtime/tab-sync-protocol.d.ts +0 -55
  264. package/dist/runtime/tab-sync-protocol.d.ts.map +0 -1
  265. package/dist/runtime/tab-sync-protocol.js +0 -54
  266. package/dist/runtime/tab-sync-protocol.js.map +0 -1
  267. package/dist/testing/local-jazz-server.d.ts +0 -2
  268. package/dist/testing/local-jazz-server.d.ts.map +0 -1
  269. package/dist/testing/local-jazz-server.js +0 -2
  270. 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 { access, mkdir, readFile, writeFile } from "fs/promises";
4
+ import { readFile } from "fs/promises";
5
5
  import { basename, join, resolve } from "path";
6
6
  import { fileURLToPath } from "url";
7
- import { loadCompiledSchema } from "./schema-loader.js";
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 compiled = await loadCompiledSchema(options.schemaDir);
42
- const tableCount = compiled.schema.tables.length;
43
- console.log(`Loaded structural schema from ${compiled.schemaFile}.`);
44
- if (compiled.permissionsFile) {
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 diagnostic of collectMissingExplicitPolicyDiagnostics(compiled.schema.tables.map((table) => table.name), compiled.permissions)) {
50
- console.warn(`\x1b[33m${diagnostic.message}\x1b[0m`);
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
- if (options.schemaHash) {
56
- const schema = await resolveExportedSchemaByHash(options);
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 compiled = await loadCompiledSchema(options.schemaDir);
66
- console.log(`Loaded structural schema from ${compiled.schemaFile}.`);
67
- const hash = await computeSchemaHash(compiled.wasmSchema);
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 explicitHashFlow = Boolean(options.fromHash || options.toHash);
657
- await mkdir(options.migrationsDir, { recursive: true });
658
- const currentSchema = !explicitHashFlow || !options.toHash ? await loadCurrentSchema(options.schemaDir) : null;
659
- let fromSchema;
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
- fromSchema = latest;
692
- toSchema = currentSchema;
693
- shouldWriteCommittedSnapshot = true;
694
- }
695
- if (fromSchema.hash === toSchema.hash) {
696
- console.log("No structural schema changes detected.");
697
- return null;
698
- }
699
- if (!schemaTransitionRequiresRowTransform(fromSchema.schema, toSchema.schema)) {
700
- if (shouldWriteCommittedSnapshot) {
701
- await ensureCommittedSnapshot(options.migrationsDir, toSchema, timestamp);
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
- const version = await packageVersion();
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 compiled = ensurePermissionsProject(await loadCompiledSchema(options.schemaDir));
768
- const localSchemaHash = await resolveStoredStructuralSchemaHashOrThrow(options.appId, options.serverUrl, options.adminSecret, compiled.wasmSchema);
769
- const { head } = await fetchPermissionsHead(options.serverUrl, {
770
- appId: options.appId,
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({