The golden journey caught the failure this prevents: the Jazz schema loader bundles the author's schema module graph — the schema facade included — and executes it to derive the deployed schema, so re-exporting the provisioning client from the facade perturbed the deployed-schema identity and every client got CatalogueWriteDenied. Provisioning is store lifecycle, not schema authoring; it now ships as its own export with a matching vendored alias, and the facade carries a note pinning the constraint.
- commit
- 18ab3058001a45b3ffdfc12aeb67de18fe3c171e
- parent
- 6ac48908535a61ae01fac9321341682a80d9fc65
- author
- Dami <dami.etoile@gmail.com>
| M | deno.json | 1 | + |
| M | docs/ | 10 | +++++++--- |
| M | package/ | 4 | ++++ |
| M | package/ | 1 | + |
| M | package/ | 14 | ++++---------- |
| M | package/ | 10 | ++-------- |
@@ -15,6 +15,7 @@
1515 "./preact": "./package/preact/mod.ts",1616 "./provision": "./package/commands/provision.ts",1717 "./schema": "./package/schema/mod.ts",18+ "./schema/store": "./package/schema/store.ts",1819 "./recipes/file-handler": "./package/recipes/file-handler.ts",1920 "./recipes/launch-handler": "./package/recipes/launch-handler.ts",2021 "./recipes/protocol-handler": "./package/recipes/protocol-handler.ts",@@ -18,13 +18,17 @@ Two principles govern it:
1818 surface. A flat `s.defineApp` schema has no namespace and therefore may only provision a store it1919 wholly owns.2020 21+Provisioning lives at `@nzip/lofi/schema/store`, deliberately separate from `@nzip/lofi/schema`: the22+schema facade is bundled and executed by the Jazz schema loader when deriving the deployed schema,23+so the authoring surface stays free of the provisioning client.24+2125 ## Classify before you connect2226 2327 With store administration (admin secret, or a provision-scoped ticket URL as `serverUrl` with2428 `adminSecret` omitted):2529 2630 ```ts27-import { readStoreStatus } from "@nzip/lofi/schema";31+import { readStoreStatus } from "@nzip/lofi/schema/store";2832 2933 const status = await readStoreStatus(root, { serverUrl, appId, adminSecret });3034 ```@@ -33,7 +37,7 @@ Without it — any valid sync ticket may call the node's metadata-only preflight
3337 sync-only client learns `no_schema` before ever attaching sync:3438 3539 ```ts36-import { readTicketStoreStatus } from "@nzip/lofi/schema";40+import { readTicketStoreStatus } from "@nzip/lofi/schema/store";3741 3842 const preflight = await readTicketStoreStatus(ticketUrl);3943 // → { state: "deployed", appId, headHash } | { state: "no_schema", appId }@@ -54,7 +58,7 @@ attaching sync to a fresh store.
5458 ## Provision5559 5660 ```ts57-import { provisionStore } from "@nzip/lofi/schema";61+import { provisionStore } from "@nzip/lofi/schema/store";5862 import { permissions, root } from "./schema.ts";5963 6064 const result = await provisionStore({@@ -104,6 +104,7 @@ function renderConfig(projectRoot: string): string {
104104 const accessEntry = join(projectRoot, ".lofi", "package", "access", "mod.ts");105105 const preactEntry = join(projectRoot, ".lofi", "package", "preact", "mod.ts");106106 const schemaEntry = join(projectRoot, ".lofi", "package", "schema", "mod.ts");107+ const schemaStoreEntry = join(projectRoot, ".lofi", "package", "schema", "store.ts");107108 const fileHandlerRecipe = join(projectRoot, ".lofi", "package", "recipes", "file-handler.ts");108109 const launchHandlerRecipe = join(109110 projectRoot,@@ -203,6 +204,9 @@ export default defineConfig({
203204 } },204205 { find: /^jsr:@nzip\\/lofi@[^/]+\\/preact$/, replacement: ${JSON.stringify(preactEntry)} },205206 { find: /^jsr:@nzip\\/lofi@[^/]+\\/access$/, replacement: ${JSON.stringify(accessEntry)} },207+ { find: /^jsr:@nzip\\/lofi@[^/]+\\/schema\\/store$/, replacement: ${208+ JSON.stringify(schemaStoreEntry)209+ } },206210 { find: /^jsr:@nzip\\/lofi@[^/]+\\/schema$/, replacement: ${JSON.stringify(schemaEntry)} },207211 { find: /^jsr:@nzip\\/lofi@[^/]+$/, replacement: ${JSON.stringify(runtimeEntry)} },208212 { find: /^npm:preact@[^/]+\\/hooks$/, replacement: "preact/hooks" },@@ -159,6 +159,7 @@ Deno.test("package manifest and generated version stay coupled", () => {
159159 "./recipes/web-share",160160 "./recipes/window-controls-overlay",161161 "./schema",162+ "./schema/store",162163 "./test",163164 "./testing",164165 ]);@@ -101,16 +101,10 @@ export {
101101 type NestedSchemaDefinition,102102 } from "./nested.ts";103103 104-export {105- provisionStore,106- readStoreStatus,107- readTicketStoreStatus,108- StoreProvisionError,109- type StoreProvisionResult,110- type StoreStatus,111- type StoreTarget,112- type TicketStoreStatus,113-} from "./store.ts";104+// Store provisioning (./store.ts) is deliberately NOT re-exported here: the105+// Jazz schema loader bundles the author's schema module graph — this facade106+// included — and executes it to derive the deployed schema, so this module107+// must stay authoring-only. Import provisioning from "@nzip/lofi/schema/store".114108 115109 /**116110 * Schema-authoring types re-exported from the pinned Jazz 2 DSL for use in@@ -5,14 +5,8 @@
55 import { createDb } from "jazz-tools";66 import { startLocalJazzServer } from "jazz-tools/testing";77 import { assert } from "../runtime/test-assert.ts";8-import {9- nestedAppDeployTarget,10- provisionStore,11- readStoreStatus,12- s,13- StoreProvisionError,14- type StoreTarget,15-} from "./mod.ts";8+import { nestedAppDeployTarget, s } from "./mod.ts";9+import { provisionStore, readStoreStatus, StoreProvisionError, type StoreTarget } from "./store.ts";1610 1711 // The first app on the store.1812 const taskRoot = s.defineNestedApp({