@prisma-next/migration-tools 0.11.0 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -4
- package/dist/{errors-DGYwcwXs.mjs → errors-vFROOhCR.mjs} +46 -21
- package/dist/errors-vFROOhCR.mjs.map +1 -0
- package/dist/exports/aggregate.d.mts +328 -204
- package/dist/exports/aggregate.d.mts.map +1 -1
- package/dist/exports/aggregate.mjs +480 -243
- package/dist/exports/aggregate.mjs.map +1 -1
- package/dist/exports/errors.d.mts +2 -2
- package/dist/exports/errors.d.mts.map +1 -1
- package/dist/exports/errors.mjs +1 -1
- package/dist/exports/graph.d.mts +1 -1
- package/dist/exports/hash.d.mts +8 -9
- package/dist/exports/hash.d.mts.map +1 -1
- package/dist/exports/hash.mjs +1 -1
- package/dist/exports/invariants.d.mts +1 -1
- package/dist/exports/invariants.d.mts.map +1 -1
- package/dist/exports/invariants.mjs +1 -1
- package/dist/exports/io.d.mts +2 -83
- package/dist/exports/io.mjs +1 -1
- package/dist/exports/metadata.d.mts +2 -2
- package/dist/exports/migration-graph.d.mts +9 -2
- package/dist/exports/migration-graph.d.mts.map +1 -0
- package/dist/exports/migration-graph.mjs +3 -2
- package/dist/exports/migration-ts.d.mts.map +1 -1
- package/dist/exports/migration-ts.mjs.map +1 -1
- package/dist/exports/migration.d.mts +5 -6
- package/dist/exports/migration.d.mts.map +1 -1
- package/dist/exports/migration.mjs +14 -32
- package/dist/exports/migration.mjs.map +1 -1
- package/dist/exports/package.d.mts +1 -1
- package/dist/exports/ref-resolution.d.mts +2 -2
- package/dist/exports/ref-resolution.d.mts.map +1 -1
- package/dist/exports/ref-resolution.mjs +1 -1
- package/dist/exports/ref-resolution.mjs.map +1 -1
- package/dist/exports/refs.d.mts +15 -2
- package/dist/exports/refs.d.mts.map +1 -0
- package/dist/exports/refs.mjs +3 -2
- package/dist/exports/spaces.d.mts +31 -132
- package/dist/exports/spaces.d.mts.map +1 -1
- package/dist/exports/spaces.mjs +13 -9
- package/dist/exports/spaces.mjs.map +1 -1
- package/dist/{graph-BrLXqoUc.d.mts → graph-3dLMZp5l.d.mts} +1 -2
- package/dist/graph-3dLMZp5l.d.mts.map +1 -0
- package/dist/graph-membership-BV23F1IV.mjs +15 -0
- package/dist/graph-membership-BV23F1IV.mjs.map +1 -0
- package/dist/{hash-Cr4WIr4Z.mjs → hash--Y7vCpN3.mjs} +8 -9
- package/dist/hash--Y7vCpN3.mjs.map +1 -0
- package/dist/{invariants-0daYEzyo.mjs → invariants-C23nXy1c.mjs} +2 -2
- package/dist/{invariants-0daYEzyo.mjs.map → invariants-C23nXy1c.mjs.map} +1 -1
- package/dist/{io-BPLfzvZe.mjs → io-BGlPOt9b.mjs} +100 -13
- package/dist/io-BGlPOt9b.mjs.map +1 -0
- package/dist/io-BH4G3F-i.d.mts +124 -0
- package/dist/io-BH4G3F-i.d.mts.map +1 -0
- package/dist/metadata-Bp9X04gM.d.mts +2 -0
- package/dist/{migration-graph-nlS4TRpn.mjs → migration-graph-BMAqSfv9.mjs} +6 -26
- package/dist/migration-graph-BMAqSfv9.mjs.map +1 -0
- package/dist/{migration-graph-De0dUZoC.d.mts → migration-graph-CWEM2SLR.d.mts} +6 -6
- package/dist/migration-graph-CWEM2SLR.d.mts.map +1 -0
- package/dist/op-schema-D5qkXfEf.mjs.map +1 -1
- package/dist/{package-DZj8YvD0.d.mts → package-Ca-J_z_0.d.mts} +1 -1
- package/dist/package-Ca-J_z_0.d.mts.map +1 -0
- package/dist/{read-contract-space-contract-DRueB4Aa.mjs → read-contract-space-contract-TbeXuJXL.mjs} +32 -5
- package/dist/read-contract-space-contract-TbeXuJXL.mjs.map +1 -0
- package/dist/{refs-BDHo5l_g.mjs → refs-C-_WUrPw.mjs} +97 -4
- package/dist/refs-C-_WUrPw.mjs.map +1 -0
- package/dist/refs-C7wuYFqZ.d.mts +42 -0
- package/dist/refs-C7wuYFqZ.d.mts.map +1 -0
- package/dist/snapshot-Bazwo13S.mjs +137 -0
- package/dist/snapshot-Bazwo13S.mjs.map +1 -0
- package/dist/verify-contract-spaces-BdysZdQk.d.mts +132 -0
- package/dist/verify-contract-spaces-BdysZdQk.d.mts.map +1 -0
- package/package.json +18 -9
- package/src/aggregate/aggregate.ts +266 -0
- package/src/aggregate/check-integrity.ts +243 -0
- package/src/aggregate/loader.ts +161 -334
- package/src/aggregate/planner-types.ts +14 -14
- package/src/aggregate/planner.ts +20 -23
- package/src/aggregate/project-schema-to-space.ts +3 -8
- package/src/aggregate/strategies/graph-walk.ts +15 -10
- package/src/aggregate/strategies/synth.ts +4 -4
- package/src/aggregate/types.ts +81 -62
- package/src/aggregate/verifier.ts +23 -23
- package/src/assert-descriptor-self-consistency.ts +6 -0
- package/src/compute-extension-space-apply-path.ts +1 -1
- package/src/emit-contract-space-artefacts.ts +4 -3
- package/src/errors.ts +58 -2
- package/src/exports/aggregate.ts +29 -19
- package/src/exports/io.ts +2 -0
- package/src/exports/metadata.ts +1 -1
- package/src/exports/migration-graph.ts +1 -0
- package/src/exports/refs.ts +11 -0
- package/src/exports/spaces.ts +3 -0
- package/src/graph-membership.ts +17 -0
- package/src/graph.ts +0 -1
- package/src/hash.ts +7 -8
- package/src/integrity-violation.ts +114 -0
- package/src/io.ts +139 -14
- package/src/metadata.ts +1 -1
- package/src/migration-base.ts +10 -30
- package/src/migration-graph.ts +7 -35
- package/src/read-contract-space-head-ref.ts +5 -2
- package/src/refs/snapshot.ts +199 -0
- package/src/refs.ts +124 -1
- package/src/space-layout.ts +30 -0
- package/dist/errors-DGYwcwXs.mjs.map +0 -1
- package/dist/exports/io.d.mts.map +0 -1
- package/dist/graph-BrLXqoUc.d.mts.map +0 -1
- package/dist/hash-Cr4WIr4Z.mjs.map +0 -1
- package/dist/io-BPLfzvZe.mjs.map +0 -1
- package/dist/metadata-BFX0xdz8.d.mts +0 -2
- package/dist/migration-graph-De0dUZoC.d.mts.map +0 -1
- package/dist/migration-graph-nlS4TRpn.mjs.map +0 -1
- package/dist/package-DZj8YvD0.d.mts.map +0 -1
- package/dist/read-contract-space-contract-DRueB4Aa.mjs.map +0 -1
- package/dist/refs-BDHo5l_g.mjs.map +0 -1
- package/dist/refs-CDaNerhT.d.mts +0 -16
- package/dist/refs-CDaNerhT.d.mts.map +0 -1
- package/src/aggregate/extract-storage-element-names.ts +0 -75
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { t as computeMigrationHash } from "../hash
|
|
3
|
-
import { t as deriveProvidedInvariants } from "../invariants-
|
|
1
|
+
import { m as errorInvalidOperationEntry } from "../errors-vFROOhCR.mjs";
|
|
2
|
+
import { t as computeMigrationHash } from "../hash--Y7vCpN3.mjs";
|
|
3
|
+
import { t as deriveProvidedInvariants } from "../invariants-C23nXy1c.mjs";
|
|
4
4
|
import { t as MigrationOpSchema } from "../op-schema-D5qkXfEf.mjs";
|
|
5
5
|
import { type } from "arktype";
|
|
6
6
|
import { realpathSync } from "node:fs";
|
|
@@ -8,8 +8,7 @@ import { fileURLToPath } from "node:url";
|
|
|
8
8
|
//#region src/migration-base.ts
|
|
9
9
|
const MigrationMetaSchema = type({
|
|
10
10
|
from: "string > 0 | null",
|
|
11
|
-
to: "string"
|
|
12
|
-
"labels?": type("string").array()
|
|
11
|
+
to: "string"
|
|
13
12
|
});
|
|
14
13
|
/**
|
|
15
14
|
* Base class for migrations.
|
|
@@ -64,12 +63,11 @@ function isDirectEntrypoint(importMetaUrl) {
|
|
|
64
63
|
* operations list, and the previously-scaffolded metadata (if any).
|
|
65
64
|
*
|
|
66
65
|
* When a `migration.json` already exists for this package (the common
|
|
67
|
-
* case: it was scaffolded by `migration plan`), preserve
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
*
|
|
71
|
-
*
|
|
72
|
-
* `migration.ts` run from scratch), synthesize a minimal but
|
|
66
|
+
* case: it was scaffolded by `migration plan`), preserve `createdAt`
|
|
67
|
+
* set there — that field is owned by the CLI scaffolder, not the authored
|
|
68
|
+
* class. Only the `describe()`-derived fields (`from`, `to`) and the
|
|
69
|
+
* operations change as the author iterates. When no metadata exists yet
|
|
70
|
+
* (a bare `migration.ts` run from scratch), synthesize a minimal but
|
|
73
71
|
* schema-conformant record so the resulting package can still be read,
|
|
74
72
|
* verified, and applied.
|
|
75
73
|
*
|
|
@@ -80,10 +78,8 @@ function buildAttestedMetadata(meta, ops, existing) {
|
|
|
80
78
|
const baseMetadata = {
|
|
81
79
|
from: meta.from,
|
|
82
80
|
to: meta.to,
|
|
83
|
-
labels: meta.labels ?? existing?.labels ?? [],
|
|
84
81
|
providedInvariants: deriveProvidedInvariants(ops),
|
|
85
|
-
createdAt: existing?.createdAt ?? (/* @__PURE__ */ new Date()).toISOString()
|
|
86
|
-
hints: normalizeHints(existing?.hints)
|
|
82
|
+
createdAt: existing?.createdAt ?? (/* @__PURE__ */ new Date()).toISOString()
|
|
87
83
|
};
|
|
88
84
|
const migrationHash = computeMigrationHash(baseMetadata, ops);
|
|
89
85
|
return {
|
|
@@ -92,27 +88,13 @@ function buildAttestedMetadata(meta, ops, existing) {
|
|
|
92
88
|
};
|
|
93
89
|
}
|
|
94
90
|
/**
|
|
95
|
-
* Project `existing.hints` down to the known `MigrationHints` shape, dropping
|
|
96
|
-
* any legacy keys that may linger in metadata scaffolded by older CLI
|
|
97
|
-
* versions (e.g. `planningStrategy`). Picking fields explicitly instead of
|
|
98
|
-
* spreading keeps refreshed `migration.json` files schema-clean regardless
|
|
99
|
-
* of what was on disk before.
|
|
100
|
-
*/
|
|
101
|
-
function normalizeHints(existing) {
|
|
102
|
-
return {
|
|
103
|
-
used: existing?.used ?? [],
|
|
104
|
-
applied: existing?.applied ?? [],
|
|
105
|
-
plannerVersion: existing?.plannerVersion ?? "2.0.0"
|
|
106
|
-
};
|
|
107
|
-
}
|
|
108
|
-
/**
|
|
109
91
|
* Pure conversion from a `Migration` instance (plus the previously
|
|
110
92
|
* scaffolded metadata, when one exists on disk) to the in-memory
|
|
111
93
|
* artifacts that downstream tooling persists. Owns metadata validation,
|
|
112
|
-
* metadata synthesis/preservation,
|
|
113
|
-
*
|
|
114
|
-
*
|
|
115
|
-
* `
|
|
94
|
+
* metadata synthesis/preservation, and the content-addressed
|
|
95
|
+
* `migrationHash` computation, but performs no file I/O — callers handle
|
|
96
|
+
* reads (to source `existing`) and writes (to persist `opsJson` /
|
|
97
|
+
* `metadataJson`).
|
|
116
98
|
*/
|
|
117
99
|
function buildMigrationArtifacts(instance, existing) {
|
|
118
100
|
const ops = instance.operations;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"migration.mjs","names":[],"sources":["../../src/migration-base.ts"],"sourcesContent":["import { realpathSync } from 'node:fs';\nimport { fileURLToPath } from 'node:url';\nimport type {\n ControlStack,\n MigrationPlan,\n MigrationPlanOperation,\n} from '@prisma-next/framework-components/control';\nimport { type } from 'arktype';\nimport { errorInvalidOperationEntry } from './errors';\nimport { computeMigrationHash } from './hash';\nimport { deriveProvidedInvariants } from './invariants';\nimport type {
|
|
1
|
+
{"version":3,"file":"migration.mjs","names":[],"sources":["../../src/migration-base.ts"],"sourcesContent":["import { realpathSync } from 'node:fs';\nimport { fileURLToPath } from 'node:url';\nimport type {\n ControlStack,\n MigrationPlan,\n MigrationPlanOperation,\n} from '@prisma-next/framework-components/control';\nimport { type } from 'arktype';\nimport { errorInvalidOperationEntry } from './errors';\nimport { computeMigrationHash } from './hash';\nimport { deriveProvidedInvariants } from './invariants';\nimport type { MigrationMetadata } from './metadata';\nimport { MigrationOpSchema } from './op-schema';\nimport type { MigrationOps } from './package';\n\nexport interface MigrationMeta {\n readonly from: string | null;\n readonly to: string;\n}\n\n// `from` rejects empty strings to mirror `MigrationMetadataSchema` in\n// `./io.ts`. Without this match, an authored migration could `describe()` with\n// `from: ''` and pass `buildMigrationArtifacts`'s validation, only to have\n// `readMigrationPackage` reject the resulting `migration.json` later — the\n// two validators must agree on the legal value space.\nconst MigrationMetaSchema = type({\n from: 'string > 0 | null',\n to: 'string',\n});\n\n/**\n * Base class for migrations.\n *\n * A `Migration` subclass is itself a `MigrationPlan`: CLI commands and the\n * runner can consume it directly via `targetId`, `operations`, `origin`, and\n * `destination`. The metadata-shaped inputs come from `describe()`, which\n * every migration must implement — `migration.json` is required for a\n * migration to be valid.\n */\nexport abstract class Migration<\n TOperation extends MigrationPlanOperation = MigrationPlanOperation,\n TFamilyId extends string = string,\n TTargetId extends string = string,\n> implements MigrationPlan\n{\n abstract readonly targetId: string;\n\n /**\n * Assembled `ControlStack` injected by the orchestrator (`runMigration`).\n *\n * Subclasses (e.g. `PostgresMigration`) read the stack to materialize their\n * adapter once per instance. Optional at the abstract level so unit tests can\n * construct `Migration` instances purely for `operations` / `describe`\n * assertions without needing a real stack; concrete subclasses that need the\n * stack at runtime should narrow the parameter to required.\n */\n protected readonly stack: ControlStack<TFamilyId, TTargetId> | undefined;\n\n constructor(stack?: ControlStack<TFamilyId, TTargetId>) {\n this.stack = stack;\n }\n\n /**\n * Ordered list of operations this migration performs.\n *\n * Implemented as a getter so that subclasses can either precompute the list\n * in their constructor or build it lazily per access.\n */\n abstract get operations(): readonly TOperation[];\n\n /**\n * Metadata inputs used to build `migration.json` and to derive the plan's\n * origin/destination identities. Every migration must provide this —\n * omitting it would produce an invalid on-disk migration package.\n */\n abstract describe(): MigrationMeta;\n\n get origin(): { readonly storageHash: string } | null {\n const from = this.describe().from;\n return from === null ? null : { storageHash: from };\n }\n\n get destination(): { readonly storageHash: string } {\n return { storageHash: this.describe().to };\n }\n}\n\n/**\n * Returns true when `import.meta.url` resolves to the same file that was\n * invoked as the node entrypoint (`process.argv[1]`). Used by\n * `MigrationCLI.run` (in `@prisma-next/cli/migration-cli`) to no-op when\n * the migration module is being imported (e.g. by another script) rather\n * than executed directly.\n */\nexport function isDirectEntrypoint(importMetaUrl: string): boolean {\n const metaFilename = fileURLToPath(importMetaUrl);\n const argv1 = process.argv[1];\n if (!argv1) return false;\n try {\n return realpathSync(metaFilename) === realpathSync(argv1);\n } catch {\n return false;\n }\n}\n\n/**\n * In-memory artifacts produced from a `Migration` instance: the\n * serialized `ops.json` body, the `migration.json` metadata object, and\n * its serialized form. Returned by `buildMigrationArtifacts` so callers\n * (today: `MigrationCLI.run` in `@prisma-next/cli/migration-cli`) can\n * decide how to persist them — write to disk, print in dry-run, ship\n * over the wire — without coupling artifact construction to file I/O.\n *\n * `metadataJson` is `JSON.stringify(metadata, null, 2)` — the canonical\n * on-disk shape that the arktype loader-schema in `./io` validates.\n */\nexport interface MigrationArtifacts {\n readonly opsJson: string;\n readonly metadata: MigrationMetadata;\n readonly metadataJson: string;\n}\n\n/**\n * Build the attested metadata from `describe()`-derived metadata, the\n * operations list, and the previously-scaffolded metadata (if any).\n *\n * When a `migration.json` already exists for this package (the common\n * case: it was scaffolded by `migration plan`), preserve `createdAt`\n * set there — that field is owned by the CLI scaffolder, not the authored\n * class. Only the `describe()`-derived fields (`from`, `to`) and the\n * operations change as the author iterates. When no metadata exists yet\n * (a bare `migration.ts` run from scratch), synthesize a minimal but\n * schema-conformant record so the resulting package can still be read,\n * verified, and applied.\n *\n * The `migrationHash` is recomputed against the current metadata + ops so\n * the on-disk artifacts are always fully attested.\n */\nfunction buildAttestedMetadata(\n meta: MigrationMeta,\n ops: MigrationOps,\n existing: Partial<MigrationMetadata> | null,\n): MigrationMetadata {\n const baseMetadata: Omit<MigrationMetadata, 'migrationHash'> = {\n from: meta.from,\n to: meta.to,\n providedInvariants: deriveProvidedInvariants(ops),\n createdAt: existing?.createdAt ?? new Date().toISOString(),\n };\n\n const migrationHash = computeMigrationHash(baseMetadata, ops);\n return { ...baseMetadata, migrationHash };\n}\n\n/**\n * Pure conversion from a `Migration` instance (plus the previously\n * scaffolded metadata, when one exists on disk) to the in-memory\n * artifacts that downstream tooling persists. Owns metadata validation,\n * metadata synthesis/preservation, and the content-addressed\n * `migrationHash` computation, but performs no file I/O — callers handle\n * reads (to source `existing`) and writes (to persist `opsJson` /\n * `metadataJson`).\n */\nexport function buildMigrationArtifacts(\n instance: Migration,\n existing: Partial<MigrationMetadata> | null,\n): MigrationArtifacts {\n const ops = instance.operations;\n if (!Array.isArray(ops)) {\n throw new Error('operations must be an array');\n }\n\n for (let index = 0; index < ops.length; index++) {\n const result = MigrationOpSchema(ops[index]);\n if (result instanceof type.errors) {\n throw errorInvalidOperationEntry(index, result.summary);\n }\n }\n\n const rawMeta: unknown = instance.describe();\n const parsed = MigrationMetaSchema(rawMeta);\n if (parsed instanceof type.errors) {\n throw new Error(`describe() returned invalid metadata: ${parsed.summary}`);\n }\n\n const metadata = buildAttestedMetadata(parsed, ops, existing);\n\n return {\n opsJson: JSON.stringify(ops, null, 2),\n metadata,\n metadataJson: JSON.stringify(metadata, null, 2),\n };\n}\n"],"mappings":";;;;;;;;AAyBA,MAAM,sBAAsB,KAAK;CAC/B,MAAM;CACN,IAAI;AACN,CAAC;;;;;;;;;;AAWD,IAAsB,YAAtB,MAKA;;;;;;;;;;CAYE;CAEA,YAAY,OAA4C;EACtD,KAAK,QAAQ;CACf;CAiBA,IAAI,SAAkD;EACpD,MAAM,OAAO,KAAK,SAAS,EAAE;EAC7B,OAAO,SAAS,OAAO,OAAO,EAAE,aAAa,KAAK;CACpD;CAEA,IAAI,cAAgD;EAClD,OAAO,EAAE,aAAa,KAAK,SAAS,EAAE,GAAG;CAC3C;AACF;;;;;;;;AASA,SAAgB,mBAAmB,eAAgC;CACjE,MAAM,eAAe,cAAc,aAAa;CAChD,MAAM,QAAQ,QAAQ,KAAK;CAC3B,IAAI,CAAC,OAAO,OAAO;CACnB,IAAI;EACF,OAAO,aAAa,YAAY,MAAM,aAAa,KAAK;CAC1D,QAAQ;EACN,OAAO;CACT;AACF;;;;;;;;;;;;;;;;;AAmCA,SAAS,sBACP,MACA,KACA,UACmB;CACnB,MAAM,eAAyD;EAC7D,MAAM,KAAK;EACX,IAAI,KAAK;EACT,oBAAoB,yBAAyB,GAAG;EAChD,WAAW,UAAU,8BAAa,IAAI,KAAK,GAAE,YAAY;CAC3D;CAEA,MAAM,gBAAgB,qBAAqB,cAAc,GAAG;CAC5D,OAAO;EAAE,GAAG;EAAc;CAAc;AAC1C;;;;;;;;;;AAWA,SAAgB,wBACd,UACA,UACoB;CACpB,MAAM,MAAM,SAAS;CACrB,IAAI,CAAC,MAAM,QAAQ,GAAG,GACpB,MAAM,IAAI,MAAM,6BAA6B;CAG/C,KAAK,IAAI,QAAQ,GAAG,QAAQ,IAAI,QAAQ,SAAS;EAC/C,MAAM,SAAS,kBAAkB,IAAI,MAAM;EAC3C,IAAI,kBAAkB,KAAK,QACzB,MAAM,2BAA2B,OAAO,OAAO,OAAO;CAE1D;CAGA,MAAM,SAAS,oBADU,SAAS,SACO,CAAC;CAC1C,IAAI,kBAAkB,KAAK,QACzB,MAAM,IAAI,MAAM,yCAAyC,OAAO,SAAS;CAG3E,MAAM,WAAW,sBAAsB,QAAQ,KAAK,QAAQ;CAE5D,OAAO;EACL,SAAS,KAAK,UAAU,KAAK,MAAM,CAAC;EACpC;EACA,cAAc,KAAK,UAAU,UAAU,MAAM,CAAC;CAChD;AACF"}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { n as OnDiskMigrationPackage, t as MigrationOps } from "../package-
|
|
1
|
+
import { n as OnDiskMigrationPackage, t as MigrationOps } from "../package-Ca-J_z_0.mjs";
|
|
2
2
|
import { MigrationPackage } from "@prisma-next/framework-components/control";
|
|
3
3
|
export { type MigrationOps, type MigrationPackage, type OnDiskMigrationPackage };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { n as
|
|
1
|
+
import { i as Refs } from "../refs-C7wuYFqZ.mjs";
|
|
2
|
+
import { n as MigrationGraph, t as MigrationEdge } from "../graph-3dLMZp5l.mjs";
|
|
3
3
|
import { Result } from "@prisma-next/utils/result";
|
|
4
4
|
|
|
5
5
|
//#region src/refs/types.d.ts
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ref-resolution.d.mts","names":[],"sources":["../../src/refs/types.ts","../../src/refs/contract-ref.ts","../../src/refs/migration-ref.ts"],"mappings":";;;;;;UAIiB,oBAAA;EAAA,SACN,KAAA,EAAO,cAAA;EAAA,SACP,IAAA,EAAM,
|
|
1
|
+
{"version":3,"file":"ref-resolution.d.mts","names":[],"sources":["../../src/refs/types.ts","../../src/refs/contract-ref.ts","../../src/refs/migration-ref.ts"],"mappings":";;;;;;UAIiB,oBAAA;EAAA,SACN,KAAA,EAAO,cAAA;EAAA,SACP,IAAA,EAAM,IAAI;AAAA;AAAA,KAGT,qBAAA;EAAA,SACG,IAAA;EAAA,SAAuB,KAAA;AAAA;EAAA,SACvB,IAAA;EAAA,SAAsB,OAAA;AAAA;EAAA,SACtB,IAAA;EAAA,SAA+B,OAAA;AAAA;EAAA,SAC/B,IAAA;EAAA,SAAiC,OAAA;AAAA;;UAG/B,WAAA;EAAA,SACN,IAAA;EAAA,SACA,UAAA,EAAY,qBAAqB;AAAA;AAAA,KAGhC,sBAAA;EAAA,SACG,IAAA;EAAA,SAA2B,OAAA;AAAA;EAAA,SAC3B,IAAA;EAAA,SAAuB,KAAA;AAAA;;UAGrB,YAAA;EAAA,SACN,OAAA;EAAA,SACA,aAAA;EAAA,SACA,IAAA;EAAA,SACA,EAAA;EAAA,SACA,UAAA,EAAY,sBAAsB;AAAA;AAAA,UAG5B,qBAAA;EAAA,SACN,IAAA;EAAA,SACA,KAAA;EAAA,SACA,OAAA;AAAA;AAAA,UAGM,sBAAA;EAAA,SACN,IAAA;EAAA,SACA,KAAA;EAAA,SACA,UAAA;EAAA,SACA,OAAA;AAAA;AAAA,UAGM,yBAAA;EAAA,SACN,IAAA;EAAA,SACA,KAAA;EAAA,SACA,eAAA;EAAA,SACA,OAAA;EAAA,SACA,GAAA;AAAA;AAAA,UAGM,0BAAA;EAAA,SACN,IAAA;EAAA,SACA,KAAA;EAAA,SACA,MAAA;AAAA;AAAA,KAGC,kBAAA,GACR,qBAAA,GACA,sBAAA,GACA,yBAAA,GACA,0BAAA;AAAA,iBAiBY,iBAAA,CACd,KAAA,EAAO,cAAA,EACP,OAAA,WACC,aAAa;;;;;;AAjFhB;;;;;;;;iBCkBgB,gBAAA,CACd,KAAA,UACA,GAAA,EAAK,oBAAA,GACJ,MAAA,CAAO,WAAA,EAAa,kBAAA;;;;;;ADrBvB;;;;;;;;;iBEcgB,iBAAA,CACd,KAAA,UACA,GAAA,EAAK,oBAAA,GACJ,MAAA,CAAO,YAAA,EAAc,kBAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ref-resolution.mjs","names":[],"sources":["../../src/refs/types.ts","../../src/refs/contract-ref.ts","../../src/refs/migration-ref.ts"],"sourcesContent":["import type { MigrationEdge, MigrationGraph } from '../graph';\nimport type { Refs } from '../refs';\n\n/** Context required to resolve a contract or migration reference. */\nexport interface RefResolutionContext {\n readonly graph: MigrationGraph;\n readonly refs: Refs;\n}\n\nexport type ContractRefProvenance =\n | { readonly kind: 'hash'; readonly input: string }\n | { readonly kind: 'ref'; readonly refName: string }\n | { readonly kind: 'migration-to'; readonly dirName: string }\n | { readonly kind: 'migration-from'; readonly dirName: string };\n\n/** A resolved contract reference: the target hash and how it was derived. */\nexport interface ContractRef {\n readonly hash: string;\n readonly provenance: ContractRefProvenance;\n}\n\nexport type MigrationRefProvenance =\n | { readonly kind: 'dir-name'; readonly dirName: string }\n | { readonly kind: 'hash'; readonly input: string };\n\n/** A resolved migration reference. */\nexport interface MigrationRef {\n readonly dirName: string;\n readonly migrationHash: string;\n readonly from: string;\n readonly to: string;\n readonly provenance: MigrationRefProvenance;\n}\n\nexport interface RefResolutionNotFound {\n readonly kind: 'not-found';\n readonly input: string;\n readonly grammar: 'contract' | 'migration';\n}\n\nexport interface RefResolutionAmbiguous {\n readonly kind: 'ambiguous';\n readonly input: string;\n readonly candidates: readonly string[];\n readonly grammar: 'contract' | 'migration';\n}\n\nexport interface RefResolutionWrongGrammar {\n readonly kind: 'wrong-grammar';\n readonly input: string;\n readonly expectedGrammar: 'contract' | 'migration';\n readonly message: string;\n readonly fix: string;\n}\n\nexport interface RefResolutionInvalidFormat {\n readonly kind: 'invalid-format';\n readonly input: string;\n readonly reason: string;\n}\n\nexport type RefResolutionError =\n | RefResolutionNotFound\n | RefResolutionAmbiguous\n | RefResolutionWrongGrammar\n | RefResolutionInvalidFormat;\n\nconst FULL_HASH_PATTERN = /^sha256:([0-9a-f]{64}|empty)$/;\nconst HEX_PREFIX_PATTERN = /^(sha256:)?[0-9a-f]{6,}$/;\n\nexport function isFullHash(input: string): boolean {\n return FULL_HASH_PATTERN.test(input);\n}\n\nexport function isHexPrefix(input: string): boolean {\n return HEX_PREFIX_PATTERN.test(input);\n}\n\nexport function normalizeHashPrefix(input: string): string {\n return input.startsWith('sha256:') ? input : `sha256:${input}`;\n}\n\nexport function findEdgeByDirName(\n graph: MigrationGraph,\n dirName: string,\n): MigrationEdge | undefined {\n for (const edges of graph.forwardChain.values()) {\n for (const edge of edges) {\n if (edge.dirName === dirName) return edge;\n }\n }\n return undefined;\n}\n","import type { Result } from '@prisma-next/utils/result';\nimport { notOk, ok } from '@prisma-next/utils/result';\nimport { validateRefName } from '../refs';\nimport type {\n ContractRef,\n ContractRefProvenance,\n RefResolutionContext,\n RefResolutionError,\n} from './types';\nimport { findEdgeByDirName, isFullHash, isHexPrefix, normalizeHashPrefix } from './types';\n\n/**\n * Resolve a user-supplied string to a contract hash using the unified\n * contract-reference grammar.\n *\n * Accepted forms:\n * - Full storage hash (`sha256:<64 hex>` or `sha256:empty`)\n * - Hex prefix (6+ hex chars, must uniquely identify one contract)\n * - Ref name (looked up in the refs index)\n * - Migration directory name (resolves to the migration's `to`-contract)\n * - `<dir>^` (resolves to the migration's `from`-contract)\n */\nexport function parseContractRef(\n input: string,\n ctx: RefResolutionContext,\n): Result<ContractRef, RefResolutionError> {\n if (!input) {\n return notOk({ kind: 'invalid-format', input, reason: 'Reference cannot be empty' });\n }\n\n if (isFullHash(input)) {\n if (ctx.graph.nodes.has(input)) {\n return ok({ hash: input, provenance: { kind: 'hash', input } });\n }\n return notOk({ kind: 'not-found', input, grammar: 'contract' });\n }\n\n if (input.endsWith('^')) {\n const dirName = input.slice(0, -1);\n if (!dirName) {\n return notOk({ kind: 'invalid-format', input, reason: 'Missing directory name before ^' });\n }\n const edge = findEdgeByDirName(ctx.graph, dirName);\n if (edge) {\n return ok({ hash: edge.from, provenance: { kind: 'migration-from', dirName } });\n }\n return notOk({ kind: 'not-found', input, grammar: 'contract' });\n }\n\n type Candidate = { hash: string; provenance: ContractRefProvenance; label: string };\n const candidates: Candidate[] = [];\n\n if (validateRefName(input) && Object.hasOwn(ctx.refs, input)) {\n const ref = ctx.refs[input];\n if (ref) {\n candidates.push({\n hash: ref.hash,\n provenance: { kind: 'ref', refName: input },\n label: `ref \"${input}\"`,\n });\n }\n }\n\n const edge = findEdgeByDirName(ctx.graph, input);\n if (edge) {\n candidates.push({\n hash: edge.to,\n provenance: { kind: 'migration-to', dirName: input },\n label: `migration directory \"${input}\"`,\n });\n }\n\n if (isHexPrefix(input)) {\n const prefix = normalizeHashPrefix(input);\n const matches = [...ctx.graph.nodes].filter((n) => n.startsWith(prefix));\n const [firstMatch] = matches;\n if (matches.length === 1 && firstMatch !== undefined) {\n candidates.push({\n hash: firstMatch,\n provenance: { kind: 'hash', input },\n label: `hash prefix \"${input}\"`,\n });\n } else if (matches.length > 1) {\n return notOk({ kind: 'ambiguous', input, candidates: matches, grammar: 'contract' });\n }\n }\n\n const [firstCandidate] = candidates;\n if (candidates.length === 1 && firstCandidate !== undefined) {\n return ok({ hash: firstCandidate.hash, provenance: firstCandidate.provenance });\n }\n\n if (candidates.length > 1) {\n return notOk({\n kind: 'ambiguous',\n input,\n candidates: candidates.map((c) => c.label),\n grammar: 'contract',\n });\n }\n\n return notOk({ kind: 'not-found', input, grammar: 'contract' });\n}\n","import type { Result } from '@prisma-next/utils/result';\nimport { notOk, ok } from '@prisma-next/utils/result';\nimport { validateRefName } from '../refs';\nimport type { MigrationRef, RefResolutionContext, RefResolutionError } from './types';\nimport { findEdgeByDirName, isFullHash, isHexPrefix, normalizeHashPrefix } from './types';\n\n/**\n * Resolve a user-supplied string to a migration using the migration-reference\n * grammar.\n *\n * Accepted forms:\n * - Migration directory name (e.g. `20260101-add-users`)\n * - Migration hash (full or 6+ hex prefix)\n *\n * Wrong-grammar diagnostics are produced when the input matches a\n * contract-grammar form (ref name, `<dir>^`, contract-only hash) so the\n * user gets a targeted hint rather than a generic \"not found\".\n */\nexport function parseMigrationRef(\n input: string,\n ctx: RefResolutionContext,\n): Result<MigrationRef, RefResolutionError> {\n if (!input) {\n return notOk({ kind: 'invalid-format', input, reason: 'Reference cannot be empty' });\n }\n\n if (input.endsWith('^')) {\n return notOk({\n kind: 'wrong-grammar',\n input,\n expectedGrammar: 'migration',\n message: '`^` syntax addresses contracts, not migrations',\n fix: 'Pass the migration directory name without `^`, or use a contract-accepting flag like `--to` or `--from`.',\n });\n }\n\n if (validateRefName(input) && Object.hasOwn(ctx.refs, input)) {\n return notOk({\n kind: 'wrong-grammar',\n input,\n expectedGrammar: 'migration',\n message: `\"${input}\" is a ref name, not a migration`,\n fix: 'Refs point at contracts, not migrations. Use a migration directory name or migration hash.',\n });\n }\n\n const edge = findEdgeByDirName(ctx.graph, input);\n if (edge) {\n return ok({\n dirName: edge.dirName,\n migrationHash: edge.migrationHash,\n from: edge.from,\n to: edge.to,\n provenance: { kind: 'dir-name', dirName: input },\n });\n }\n\n if (isFullHash(input)) {\n const migEdge = ctx.graph.migrationByHash.get(input);\n if (migEdge) {\n return ok({\n dirName: migEdge.dirName,\n migrationHash: migEdge.migrationHash,\n from: migEdge.from,\n to: migEdge.to,\n provenance: { kind: 'hash', input },\n });\n }\n if (ctx.graph.nodes.has(input)) {\n return notOk({\n kind: 'wrong-grammar',\n input,\n expectedGrammar: 'migration',\n message: 'Hash matched a contract but not a migration',\n fix: 'Use a contract-accepting flag like `--to` or `--from` to reference contracts by hash. Pass `migration show <dir>` for a specific migration.',\n });\n }\n return notOk({ kind: 'not-found', input, grammar: 'migration' });\n }\n\n if (isHexPrefix(input)) {\n const prefix = normalizeHashPrefix(input);\n const migMatches = [...ctx.graph.migrationByHash.entries()].filter(([hash]) =>\n hash.startsWith(prefix),\n );\n\n const [firstMigMatch] = migMatches;\n if (migMatches.length === 1 && firstMigMatch !== undefined) {\n const [, matchedEdge] = firstMigMatch;\n return ok({\n dirName: matchedEdge.dirName,\n migrationHash: matchedEdge.migrationHash,\n from: matchedEdge.from,\n to: matchedEdge.to,\n provenance: { kind: 'hash', input },\n });\n }\n\n if (migMatches.length > 1) {\n return notOk({\n kind: 'ambiguous',\n input,\n candidates: migMatches.map(([hash]) => hash),\n grammar: 'migration',\n });\n }\n\n const contractMatches = [...ctx.graph.nodes].filter((n) => n.startsWith(prefix));\n if (contractMatches.length > 0) {\n return notOk({\n kind: 'wrong-grammar',\n input,\n expectedGrammar: 'migration',\n message: 'Hash matched a contract but not a migration',\n fix: 'Use a contract-accepting flag like `--to` or `--from` to reference contracts by hash. Pass `migration show <dir>` for a specific migration.',\n });\n }\n }\n\n return notOk({ kind: 'not-found', input, grammar: 'migration' });\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ref-resolution.mjs","names":[],"sources":["../../src/refs/types.ts","../../src/refs/contract-ref.ts","../../src/refs/migration-ref.ts"],"sourcesContent":["import type { MigrationEdge, MigrationGraph } from '../graph';\nimport type { Refs } from '../refs';\n\n/** Context required to resolve a contract or migration reference. */\nexport interface RefResolutionContext {\n readonly graph: MigrationGraph;\n readonly refs: Refs;\n}\n\nexport type ContractRefProvenance =\n | { readonly kind: 'hash'; readonly input: string }\n | { readonly kind: 'ref'; readonly refName: string }\n | { readonly kind: 'migration-to'; readonly dirName: string }\n | { readonly kind: 'migration-from'; readonly dirName: string };\n\n/** A resolved contract reference: the target hash and how it was derived. */\nexport interface ContractRef {\n readonly hash: string;\n readonly provenance: ContractRefProvenance;\n}\n\nexport type MigrationRefProvenance =\n | { readonly kind: 'dir-name'; readonly dirName: string }\n | { readonly kind: 'hash'; readonly input: string };\n\n/** A resolved migration reference. */\nexport interface MigrationRef {\n readonly dirName: string;\n readonly migrationHash: string;\n readonly from: string;\n readonly to: string;\n readonly provenance: MigrationRefProvenance;\n}\n\nexport interface RefResolutionNotFound {\n readonly kind: 'not-found';\n readonly input: string;\n readonly grammar: 'contract' | 'migration';\n}\n\nexport interface RefResolutionAmbiguous {\n readonly kind: 'ambiguous';\n readonly input: string;\n readonly candidates: readonly string[];\n readonly grammar: 'contract' | 'migration';\n}\n\nexport interface RefResolutionWrongGrammar {\n readonly kind: 'wrong-grammar';\n readonly input: string;\n readonly expectedGrammar: 'contract' | 'migration';\n readonly message: string;\n readonly fix: string;\n}\n\nexport interface RefResolutionInvalidFormat {\n readonly kind: 'invalid-format';\n readonly input: string;\n readonly reason: string;\n}\n\nexport type RefResolutionError =\n | RefResolutionNotFound\n | RefResolutionAmbiguous\n | RefResolutionWrongGrammar\n | RefResolutionInvalidFormat;\n\nconst FULL_HASH_PATTERN = /^sha256:([0-9a-f]{64}|empty)$/;\nconst HEX_PREFIX_PATTERN = /^(sha256:)?[0-9a-f]{6,}$/;\n\nexport function isFullHash(input: string): boolean {\n return FULL_HASH_PATTERN.test(input);\n}\n\nexport function isHexPrefix(input: string): boolean {\n return HEX_PREFIX_PATTERN.test(input);\n}\n\nexport function normalizeHashPrefix(input: string): string {\n return input.startsWith('sha256:') ? input : `sha256:${input}`;\n}\n\nexport function findEdgeByDirName(\n graph: MigrationGraph,\n dirName: string,\n): MigrationEdge | undefined {\n for (const edges of graph.forwardChain.values()) {\n for (const edge of edges) {\n if (edge.dirName === dirName) return edge;\n }\n }\n return undefined;\n}\n","import type { Result } from '@prisma-next/utils/result';\nimport { notOk, ok } from '@prisma-next/utils/result';\nimport { validateRefName } from '../refs';\nimport type {\n ContractRef,\n ContractRefProvenance,\n RefResolutionContext,\n RefResolutionError,\n} from './types';\nimport { findEdgeByDirName, isFullHash, isHexPrefix, normalizeHashPrefix } from './types';\n\n/**\n * Resolve a user-supplied string to a contract hash using the unified\n * contract-reference grammar.\n *\n * Accepted forms:\n * - Full storage hash (`sha256:<64 hex>` or `sha256:empty`)\n * - Hex prefix (6+ hex chars, must uniquely identify one contract)\n * - Ref name (looked up in the refs index)\n * - Migration directory name (resolves to the migration's `to`-contract)\n * - `<dir>^` (resolves to the migration's `from`-contract)\n */\nexport function parseContractRef(\n input: string,\n ctx: RefResolutionContext,\n): Result<ContractRef, RefResolutionError> {\n if (!input) {\n return notOk({ kind: 'invalid-format', input, reason: 'Reference cannot be empty' });\n }\n\n if (isFullHash(input)) {\n if (ctx.graph.nodes.has(input)) {\n return ok({ hash: input, provenance: { kind: 'hash', input } });\n }\n return notOk({ kind: 'not-found', input, grammar: 'contract' });\n }\n\n if (input.endsWith('^')) {\n const dirName = input.slice(0, -1);\n if (!dirName) {\n return notOk({ kind: 'invalid-format', input, reason: 'Missing directory name before ^' });\n }\n const edge = findEdgeByDirName(ctx.graph, dirName);\n if (edge) {\n return ok({ hash: edge.from, provenance: { kind: 'migration-from', dirName } });\n }\n return notOk({ kind: 'not-found', input, grammar: 'contract' });\n }\n\n type Candidate = { hash: string; provenance: ContractRefProvenance; label: string };\n const candidates: Candidate[] = [];\n\n if (validateRefName(input) && Object.hasOwn(ctx.refs, input)) {\n const ref = ctx.refs[input];\n if (ref) {\n candidates.push({\n hash: ref.hash,\n provenance: { kind: 'ref', refName: input },\n label: `ref \"${input}\"`,\n });\n }\n }\n\n const edge = findEdgeByDirName(ctx.graph, input);\n if (edge) {\n candidates.push({\n hash: edge.to,\n provenance: { kind: 'migration-to', dirName: input },\n label: `migration directory \"${input}\"`,\n });\n }\n\n if (isHexPrefix(input)) {\n const prefix = normalizeHashPrefix(input);\n const matches = [...ctx.graph.nodes].filter((n) => n.startsWith(prefix));\n const [firstMatch] = matches;\n if (matches.length === 1 && firstMatch !== undefined) {\n candidates.push({\n hash: firstMatch,\n provenance: { kind: 'hash', input },\n label: `hash prefix \"${input}\"`,\n });\n } else if (matches.length > 1) {\n return notOk({ kind: 'ambiguous', input, candidates: matches, grammar: 'contract' });\n }\n }\n\n const [firstCandidate] = candidates;\n if (candidates.length === 1 && firstCandidate !== undefined) {\n return ok({ hash: firstCandidate.hash, provenance: firstCandidate.provenance });\n }\n\n if (candidates.length > 1) {\n return notOk({\n kind: 'ambiguous',\n input,\n candidates: candidates.map((c) => c.label),\n grammar: 'contract',\n });\n }\n\n return notOk({ kind: 'not-found', input, grammar: 'contract' });\n}\n","import type { Result } from '@prisma-next/utils/result';\nimport { notOk, ok } from '@prisma-next/utils/result';\nimport { validateRefName } from '../refs';\nimport type { MigrationRef, RefResolutionContext, RefResolutionError } from './types';\nimport { findEdgeByDirName, isFullHash, isHexPrefix, normalizeHashPrefix } from './types';\n\n/**\n * Resolve a user-supplied string to a migration using the migration-reference\n * grammar.\n *\n * Accepted forms:\n * - Migration directory name (e.g. `20260101-add-users`)\n * - Migration hash (full or 6+ hex prefix)\n *\n * Wrong-grammar diagnostics are produced when the input matches a\n * contract-grammar form (ref name, `<dir>^`, contract-only hash) so the\n * user gets a targeted hint rather than a generic \"not found\".\n */\nexport function parseMigrationRef(\n input: string,\n ctx: RefResolutionContext,\n): Result<MigrationRef, RefResolutionError> {\n if (!input) {\n return notOk({ kind: 'invalid-format', input, reason: 'Reference cannot be empty' });\n }\n\n if (input.endsWith('^')) {\n return notOk({\n kind: 'wrong-grammar',\n input,\n expectedGrammar: 'migration',\n message: '`^` syntax addresses contracts, not migrations',\n fix: 'Pass the migration directory name without `^`, or use a contract-accepting flag like `--to` or `--from`.',\n });\n }\n\n if (validateRefName(input) && Object.hasOwn(ctx.refs, input)) {\n return notOk({\n kind: 'wrong-grammar',\n input,\n expectedGrammar: 'migration',\n message: `\"${input}\" is a ref name, not a migration`,\n fix: 'Refs point at contracts, not migrations. Use a migration directory name or migration hash.',\n });\n }\n\n const edge = findEdgeByDirName(ctx.graph, input);\n if (edge) {\n return ok({\n dirName: edge.dirName,\n migrationHash: edge.migrationHash,\n from: edge.from,\n to: edge.to,\n provenance: { kind: 'dir-name', dirName: input },\n });\n }\n\n if (isFullHash(input)) {\n const migEdge = ctx.graph.migrationByHash.get(input);\n if (migEdge) {\n return ok({\n dirName: migEdge.dirName,\n migrationHash: migEdge.migrationHash,\n from: migEdge.from,\n to: migEdge.to,\n provenance: { kind: 'hash', input },\n });\n }\n if (ctx.graph.nodes.has(input)) {\n return notOk({\n kind: 'wrong-grammar',\n input,\n expectedGrammar: 'migration',\n message: 'Hash matched a contract but not a migration',\n fix: 'Use a contract-accepting flag like `--to` or `--from` to reference contracts by hash. Pass `migration show <dir>` for a specific migration.',\n });\n }\n return notOk({ kind: 'not-found', input, grammar: 'migration' });\n }\n\n if (isHexPrefix(input)) {\n const prefix = normalizeHashPrefix(input);\n const migMatches = [...ctx.graph.migrationByHash.entries()].filter(([hash]) =>\n hash.startsWith(prefix),\n );\n\n const [firstMigMatch] = migMatches;\n if (migMatches.length === 1 && firstMigMatch !== undefined) {\n const [, matchedEdge] = firstMigMatch;\n return ok({\n dirName: matchedEdge.dirName,\n migrationHash: matchedEdge.migrationHash,\n from: matchedEdge.from,\n to: matchedEdge.to,\n provenance: { kind: 'hash', input },\n });\n }\n\n if (migMatches.length > 1) {\n return notOk({\n kind: 'ambiguous',\n input,\n candidates: migMatches.map(([hash]) => hash),\n grammar: 'migration',\n });\n }\n\n const contractMatches = [...ctx.graph.nodes].filter((n) => n.startsWith(prefix));\n if (contractMatches.length > 0) {\n return notOk({\n kind: 'wrong-grammar',\n input,\n expectedGrammar: 'migration',\n message: 'Hash matched a contract but not a migration',\n fix: 'Use a contract-accepting flag like `--to` or `--from` to reference contracts by hash. Pass `migration show <dir>` for a specific migration.',\n });\n }\n }\n\n return notOk({ kind: 'not-found', input, grammar: 'migration' });\n}\n"],"mappings":"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"}
|
package/dist/exports/refs.d.mts
CHANGED
|
@@ -1,2 +1,15 @@
|
|
|
1
|
-
import { a as
|
|
2
|
-
|
|
1
|
+
import { a as deleteRef, c as refsByContractHash, d as validateRefName, f as validateRefValue, i as Refs, l as resolveRef, n as RefEntry, o as readRef, p as writeRef, s as readRefs, t as HEAD_REF_NAME, u as resolveRefsByContractHash } from "../refs-C7wuYFqZ.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/refs/snapshot.d.ts
|
|
4
|
+
interface ContractIR {
|
|
5
|
+
readonly contract: unknown;
|
|
6
|
+
readonly contractDts: string;
|
|
7
|
+
}
|
|
8
|
+
declare function writeRefSnapshot(refsDir: string, name: string, snapshot: ContractIR): Promise<void>;
|
|
9
|
+
declare function readRefSnapshot(refsDir: string, name: string): Promise<ContractIR | null>;
|
|
10
|
+
declare function deleteRefSnapshot(refsDir: string, name: string): Promise<void>;
|
|
11
|
+
declare function writeRefPaired(refsDir: string, name: string, entry: RefEntry, snapshot: ContractIR): Promise<void>;
|
|
12
|
+
declare function deleteRefPaired(refsDir: string, name: string): Promise<void>;
|
|
13
|
+
//#endregion
|
|
14
|
+
export { type ContractIR, HEAD_REF_NAME, type RefEntry, type Refs, deleteRef, deleteRefPaired, deleteRefSnapshot, readRef, readRefSnapshot, readRefs, refsByContractHash, resolveRef, resolveRefsByContractHash, validateRefName, validateRefValue, writeRef, writeRefPaired, writeRefSnapshot };
|
|
15
|
+
//# sourceMappingURL=refs.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"refs.d.mts","names":[],"sources":["../../src/refs/snapshot.ts"],"mappings":";;;UAQiB,UAAA;EAAA,SACN,QAAA;EAAA,SACA,WAAW;AAAA;AAAA,iBAkEA,gBAAA,CACpB,OAAA,UACA,IAAA,UACA,QAAA,EAAU,UAAA,GACT,OAAO;AAAA,iBA4BY,eAAA,CAAgB,OAAA,UAAiB,IAAA,WAAe,OAAO,CAAC,UAAA;AAAA,iBAiCxD,iBAAA,CAAkB,OAAA,UAAiB,IAAA,WAAe,OAAO;AAAA,iBASzD,cAAA,CACpB,OAAA,UACA,IAAA,UACA,KAAA,EAAO,QAAA,EACP,QAAA,EAAU,UAAA,GACT,OAAA;AAAA,iBA4BmB,eAAA,CAAgB,OAAA,UAAiB,IAAA,WAAe,OAAO"}
|
package/dist/exports/refs.mjs
CHANGED
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import { c as resolveRefsByContractHash, d as writeRef, i as readRefs, l as validateRefName, n as deleteRef, o as refsByContractHash, r as readRef, s as resolveRef, t as HEAD_REF_NAME, u as validateRefValue } from "../refs-C-_WUrPw.mjs";
|
|
2
|
+
import { a as writeRefSnapshot, i as writeRefPaired, n as deleteRefSnapshot, r as readRefSnapshot, t as deleteRefPaired } from "../snapshot-Bazwo13S.mjs";
|
|
3
|
+
export { HEAD_REF_NAME, deleteRef, deleteRefPaired, deleteRefSnapshot, readRef, readRefSnapshot, readRefs, refsByContractHash, resolveRef, resolveRefsByContractHash, validateRefName, validateRefValue, writeRef, writeRefPaired, writeRefSnapshot };
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import { t as MigrationOps } from "../package-
|
|
1
|
+
import { t as MigrationOps } from "../package-Ca-J_z_0.mjs";
|
|
2
|
+
import { a as VerifyContractSpacesResult, i as VerifyContractSpacesInputs, n as SpaceMarkerRecord, o as listContractSpaceDirectories, r as SpaceVerifierViolation, s as verifyContractSpaces, t as ContractSpaceHeadRecord } from "../verify-contract-spaces-BdysZdQk.mjs";
|
|
3
|
+
import { PreserveEmptyPredicate, StorageSort } from "@prisma-next/contract/hashing";
|
|
2
4
|
import { APP_SPACE_ID, ContractSpace, ContractSpaceHeadRef, ContractSpaceHeadRef as ContractSpaceHeadRef$1 } from "@prisma-next/framework-components/control";
|
|
3
5
|
import { Contract } from "@prisma-next/contract/types";
|
|
4
6
|
|
|
@@ -22,6 +24,8 @@ interface DescriptorSelfConsistencyInputs {
|
|
|
22
24
|
*/
|
|
23
25
|
readonly storage: unknown;
|
|
24
26
|
readonly headRefHash: string;
|
|
27
|
+
readonly shouldPreserveEmpty?: PreserveEmptyPredicate;
|
|
28
|
+
readonly sortStorage?: StorageSort;
|
|
25
29
|
}
|
|
26
30
|
/**
|
|
27
31
|
* Assert that an extension descriptor is self-consistent: the
|
|
@@ -258,136 +262,6 @@ interface ContractSpaceArtefactInputs {
|
|
|
258
262
|
*/
|
|
259
263
|
declare function emitContractSpaceArtefacts(projectMigrationsDir: string, spaceId: string, inputs: ContractSpaceArtefactInputs): Promise<void>;
|
|
260
264
|
//#endregion
|
|
261
|
-
//#region src/verify-contract-spaces.d.ts
|
|
262
|
-
/**
|
|
263
|
-
* List the per-space subdirectories under
|
|
264
|
-
* `<projectRoot>/migrations/`. Returns space-id directory names (sorted
|
|
265
|
-
* alphabetically) — i.e. any non-dot-prefixed subdirectory whose root
|
|
266
|
-
* does **not** contain a `migration.json` manifest. The manifest is the
|
|
267
|
-
* structural marker of a user-authored migration directory (see
|
|
268
|
-
* `readMigrationsDir` in `./io`); directory names themselves belong to
|
|
269
|
-
* the user and are not part of the contract.
|
|
270
|
-
*
|
|
271
|
-
* Returns `[]` if the migrations directory does not exist (greenfield
|
|
272
|
-
* project).
|
|
273
|
-
*
|
|
274
|
-
* Reads only the user's repo. **No descriptor import.** The caller
|
|
275
|
-
* (verifier) feeds the result into {@link verifyContractSpaces} alongside
|
|
276
|
-
* the loaded-space set and the marker rows.
|
|
277
|
-
*/
|
|
278
|
-
declare function listContractSpaceDirectories(projectMigrationsDir: string): Promise<readonly string[]>;
|
|
279
|
-
/**
|
|
280
|
-
* On-disk head value (`(hash, invariants)`) for one contract space.
|
|
281
|
-
* The verifier compares this against the marker row for the same space
|
|
282
|
-
* to detect drift between the user-emitted artefacts and the live DB
|
|
283
|
-
* marker.
|
|
284
|
-
*/
|
|
285
|
-
interface ContractSpaceHeadRecord {
|
|
286
|
-
readonly hash: string;
|
|
287
|
-
readonly invariants: readonly string[];
|
|
288
|
-
}
|
|
289
|
-
/**
|
|
290
|
-
* Marker row read from `prisma_contract.marker` (one per `space`).
|
|
291
|
-
* Caller resolves these via the family runtime's marker reader before
|
|
292
|
-
* invoking {@link verifyContractSpaces}.
|
|
293
|
-
*/
|
|
294
|
-
interface SpaceMarkerRecord {
|
|
295
|
-
readonly hash: string;
|
|
296
|
-
readonly invariants: readonly string[];
|
|
297
|
-
}
|
|
298
|
-
interface VerifyContractSpacesInputs {
|
|
299
|
-
/**
|
|
300
|
-
* Set of contract spaces the project declares: `'app'` plus each
|
|
301
|
-
* extension space in `extensionPacks`. The caller's discovery path
|
|
302
|
-
* never reads the extension descriptor module — it walks the
|
|
303
|
-
* `extensionPacks` configuration in `prisma-next.config.ts` for the
|
|
304
|
-
* space ids.
|
|
305
|
-
*/
|
|
306
|
-
readonly loadedSpaces: ReadonlySet<string>;
|
|
307
|
-
/**
|
|
308
|
-
* Per-space subdirectories observed under
|
|
309
|
-
* `<projectRoot>/migrations/`. Resolved via
|
|
310
|
-
* {@link listContractSpaceDirectories}.
|
|
311
|
-
*/
|
|
312
|
-
readonly spaceDirsOnDisk: readonly string[];
|
|
313
|
-
/**
|
|
314
|
-
* Head ref per space, keyed by space id. Caller reads
|
|
315
|
-
* `<projectRoot>/migrations/<space-id>/contract.json` and
|
|
316
|
-
* `<projectRoot>/migrations/<space-id>/refs/head.json` to construct
|
|
317
|
-
* this map. Spaces with no contract-space dir on disk simply omit a
|
|
318
|
-
* map entry.
|
|
319
|
-
*/
|
|
320
|
-
readonly headRefsBySpace: ReadonlyMap<string, ContractSpaceHeadRecord>;
|
|
321
|
-
/**
|
|
322
|
-
* Marker rows keyed by `space`. Caller reads them from the
|
|
323
|
-
* `prisma_contract.marker` table.
|
|
324
|
-
*/
|
|
325
|
-
readonly markerRowsBySpace: ReadonlyMap<string, SpaceMarkerRecord>;
|
|
326
|
-
}
|
|
327
|
-
type SpaceVerifierViolation = {
|
|
328
|
-
readonly kind: 'declaredButUnmigrated';
|
|
329
|
-
readonly spaceId: string;
|
|
330
|
-
readonly remediation: string;
|
|
331
|
-
} | {
|
|
332
|
-
readonly kind: 'orphanMarker';
|
|
333
|
-
readonly spaceId: string;
|
|
334
|
-
readonly remediation: string;
|
|
335
|
-
} | {
|
|
336
|
-
readonly kind: 'orphanSpaceDir';
|
|
337
|
-
readonly spaceId: string;
|
|
338
|
-
readonly remediation: string;
|
|
339
|
-
} | {
|
|
340
|
-
readonly kind: 'hashMismatch';
|
|
341
|
-
readonly spaceId: string;
|
|
342
|
-
readonly priorHeadHash: string;
|
|
343
|
-
readonly markerHash: string;
|
|
344
|
-
readonly remediation: string;
|
|
345
|
-
} | {
|
|
346
|
-
readonly kind: 'invariantsMismatch';
|
|
347
|
-
readonly spaceId: string;
|
|
348
|
-
readonly onDiskInvariants: readonly string[];
|
|
349
|
-
readonly markerInvariants: readonly string[];
|
|
350
|
-
readonly remediation: string;
|
|
351
|
-
};
|
|
352
|
-
type VerifyContractSpacesResult = {
|
|
353
|
-
readonly ok: true;
|
|
354
|
-
} | {
|
|
355
|
-
readonly ok: false;
|
|
356
|
-
readonly violations: readonly SpaceVerifierViolation[];
|
|
357
|
-
};
|
|
358
|
-
/**
|
|
359
|
-
* Pure structural verifier for the per-space mechanism. Aggregates the
|
|
360
|
-
* three orphan / missing checks plus per-space hash and invariant
|
|
361
|
-
* comparison.
|
|
362
|
-
*
|
|
363
|
-
* Algorithm:
|
|
364
|
-
*
|
|
365
|
-
* - For every extension space declared in `loadedSpaces` (`'app'`
|
|
366
|
-
* excluded — the per-space verifier is scoped to extension members;
|
|
367
|
-
* the app is verified through the aggregate path):
|
|
368
|
-
* - If no contract-space dir on disk → `declaredButUnmigrated`.
|
|
369
|
-
* - Else if `markerRowsBySpace` lacks an entry → no violation here;
|
|
370
|
-
* the live-DB compare done outside this helper is where the
|
|
371
|
-
* absence shows up.
|
|
372
|
-
* - Else compare marker hash / invariants vs. on-disk head hash /
|
|
373
|
-
* invariants → `hashMismatch` / `invariantsMismatch` on drift.
|
|
374
|
-
* - For every contract-space dir on disk that is not in `loadedSpaces` →
|
|
375
|
-
* `orphanSpaceDir`.
|
|
376
|
-
* - For every marker row whose `space` is not in `loadedSpaces` →
|
|
377
|
-
* `orphanMarker`. The app-space marker is always loaded (`'app'` is
|
|
378
|
-
* in `loadedSpaces` by definition).
|
|
379
|
-
*
|
|
380
|
-
* Output is deterministic: violations are sorted first by `kind`
|
|
381
|
-
* (`declaredButUnmigrated` → `orphanMarker` → `orphanSpaceDir` →
|
|
382
|
-
* `hashMismatch` → `invariantsMismatch`) then by `spaceId`. Two callers
|
|
383
|
-
* passing equivalent inputs see byte-identical violation lists.
|
|
384
|
-
*
|
|
385
|
-
* Synchronous, pure, no I/O. **Does not import the extension descriptor**
|
|
386
|
-
* (the inputs are pre-resolved by the caller); the verifier reads only
|
|
387
|
-
* the user repo, not `node_modules`.
|
|
388
|
-
*/
|
|
389
|
-
declare function verifyContractSpaces(inputs: VerifyContractSpacesInputs): VerifyContractSpacesResult;
|
|
390
|
-
//#endregion
|
|
391
265
|
//#region src/gather-disk-contract-space-state.d.ts
|
|
392
266
|
/**
|
|
393
267
|
* Disk-side inputs to {@link import('./verify-contract-spaces').verifyContractSpaces}
|
|
@@ -521,6 +395,31 @@ declare function assertValidSpaceId(spaceId: string): asserts spaceId is ValidSp
|
|
|
521
395
|
* relative shape and is symmetric with `pathe.join`.
|
|
522
396
|
*/
|
|
523
397
|
declare function spaceMigrationDirectory(projectMigrationsDir: string, spaceId: string): string;
|
|
398
|
+
/**
|
|
399
|
+
* Per-space subdirectory name reserved for the ref store
|
|
400
|
+
* (`migrations/<space>/<SPACE_REFS_DIRNAME>/*.json`). Single source of
|
|
401
|
+
* truth: every helper that composes a per-space refs path imports this
|
|
402
|
+
* constant, and the enumerator uses it (via
|
|
403
|
+
* {@link RESERVED_SPACE_SUBDIR_NAMES}) to exclude reserved names from
|
|
404
|
+
* the contract-space candidate list.
|
|
405
|
+
*/
|
|
406
|
+
declare const SPACE_REFS_DIRNAME = "refs";
|
|
407
|
+
/**
|
|
408
|
+
* Names reserved as per-space subdirectories of `migrations/<space>/`.
|
|
409
|
+
* Used by the enumerator to filter contract-space candidates so a
|
|
410
|
+
* reserved name (e.g. a top-level `migrations/refs/` left in the wrong
|
|
411
|
+
* place) is never enumerated as a phantom contract space. Currently
|
|
412
|
+
* holds `SPACE_REFS_DIRNAME`; extend if future per-space layouts add
|
|
413
|
+
* more reserved subdirectories.
|
|
414
|
+
*/
|
|
415
|
+
declare const RESERVED_SPACE_SUBDIR_NAMES: ReadonlySet<string>;
|
|
416
|
+
/**
|
|
417
|
+
* Resolve the per-space refs directory for `spaceMigrationsDir`
|
|
418
|
+
* (typically the value returned by {@link spaceMigrationDirectory}).
|
|
419
|
+
* Composes the canonical {@link SPACE_REFS_DIRNAME} so callers do not
|
|
420
|
+
* hard-code the literal.
|
|
421
|
+
*/
|
|
422
|
+
declare function spaceRefsDirectory(spaceMigrationsDir: string): string;
|
|
524
423
|
//#endregion
|
|
525
|
-
export { APP_SPACE_ID, type ComputeExtensionSpaceApplyPathInputs, type ContractSpaceArtefactInputs, type ContractSpaceHeadRecord, type ContractSpaceHeadRef, type DescriptorSelfConsistencyInputs, type DiskContractSpaceState, type ExtensionSpaceApplyPathOutcome, type SpaceApplyInput, type SpaceMarkerRecord, type SpacePlanInput, type SpacePlanOutput, type SpaceVerifierViolation, type ValidSpaceId, type VerifyContractSpacesInputs, type VerifyContractSpacesResult, assertDescriptorSelfConsistency, assertValidSpaceId, computeExtensionSpaceApplyPath, contractSpaceFromJson, emitContractSpaceArtefacts, gatherDiskContractSpaceState, isValidSpaceId, listContractSpaceDirectories, planAllSpaces, readContractSpaceContract, readContractSpaceHeadRef, spaceMigrationDirectory, verifyContractSpaces };
|
|
424
|
+
export { APP_SPACE_ID, type ComputeExtensionSpaceApplyPathInputs, type ContractSpaceArtefactInputs, type ContractSpaceHeadRecord, type ContractSpaceHeadRef, type DescriptorSelfConsistencyInputs, type DiskContractSpaceState, type ExtensionSpaceApplyPathOutcome, RESERVED_SPACE_SUBDIR_NAMES, SPACE_REFS_DIRNAME, type SpaceApplyInput, type SpaceMarkerRecord, type SpacePlanInput, type SpacePlanOutput, type SpaceVerifierViolation, type ValidSpaceId, type VerifyContractSpacesInputs, type VerifyContractSpacesResult, assertDescriptorSelfConsistency, assertValidSpaceId, computeExtensionSpaceApplyPath, contractSpaceFromJson, emitContractSpaceArtefacts, gatherDiskContractSpaceState, isValidSpaceId, listContractSpaceDirectories, planAllSpaces, readContractSpaceContract, readContractSpaceHeadRef, spaceMigrationDirectory, spaceRefsDirectory, verifyContractSpaces };
|
|
526
425
|
//# sourceMappingURL=spaces.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"spaces.d.mts","names":[],"sources":["../../src/assert-descriptor-self-consistency.ts","../../src/read-contract-space-head-ref.ts","../../src/compute-extension-space-apply-path.ts","../../src/concatenate-space-apply-inputs.ts","../../src/contract-space-from-json.ts","../../src/emit-contract-space-artefacts.ts","../../src/
|
|
1
|
+
{"version":3,"file":"spaces.d.mts","names":[],"sources":["../../src/assert-descriptor-self-consistency.ts","../../src/read-contract-space-head-ref.ts","../../src/compute-extension-space-apply-path.ts","../../src/concatenate-space-apply-inputs.ts","../../src/contract-space-from-json.ts","../../src/emit-contract-space-artefacts.ts","../../src/gather-disk-contract-space-state.ts","../../src/plan-all-spaces.ts","../../src/read-contract-space-contract.ts","../../src/space-layout.ts"],"mappings":"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"}
|
package/dist/exports/spaces.mjs
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { s as readMigrationsDir } from "../io-
|
|
1
|
+
import { a as errorDescriptorHeadHashMismatch, c as errorDuplicateSpaceId } from "../errors-vFROOhCR.mjs";
|
|
2
|
+
import { s as readMigrationsDir } from "../io-BGlPOt9b.mjs";
|
|
3
3
|
import "../constants-DWV9_o2Z.mjs";
|
|
4
|
-
import { l as reconstructGraph, o as findPathWithDecision } from "../migration-graph-
|
|
5
|
-
import { a as APP_SPACE_ID, c as
|
|
4
|
+
import { l as reconstructGraph, o as findPathWithDecision } from "../migration-graph-BMAqSfv9.mjs";
|
|
5
|
+
import { a as APP_SPACE_ID, c as assertValidSpaceId, d as spaceRefsDirectory, i as readContractSpaceHeadRef, l as isValidSpaceId, n as listContractSpaceDirectories, o as RESERVED_SPACE_SUBDIR_NAMES, r as verifyContractSpaces, s as SPACE_REFS_DIRNAME, t as readContractSpaceContract, u as spaceMigrationDirectory } from "../read-contract-space-contract-TbeXuJXL.mjs";
|
|
6
|
+
import { ifDefined } from "@prisma-next/utils/defined";
|
|
6
7
|
import { join } from "pathe";
|
|
7
8
|
import { mkdir, writeFile } from "node:fs/promises";
|
|
8
9
|
import { canonicalizeJson } from "@prisma-next/framework-components/utils";
|
|
@@ -46,7 +47,9 @@ function assertDescriptorSelfConsistency(inputs) {
|
|
|
46
47
|
const recomputed = computeStorageHash({
|
|
47
48
|
target: inputs.target,
|
|
48
49
|
targetFamily: inputs.targetFamily,
|
|
49
|
-
storage: normalizedStorage
|
|
50
|
+
storage: normalizedStorage,
|
|
51
|
+
...ifDefined("shouldPreserveEmpty", inputs.shouldPreserveEmpty),
|
|
52
|
+
...ifDefined("sortStorage", inputs.sortStorage)
|
|
50
53
|
});
|
|
51
54
|
if (recomputed !== inputs.headRefHash) throw errorDescriptorHeadHashMismatch({
|
|
52
55
|
extensionId: inputs.extensionId,
|
|
@@ -83,7 +86,7 @@ async function computeExtensionSpaceApplyPath(inputs) {
|
|
|
83
86
|
const { projectMigrationsDir, spaceId, currentMarkerHash, currentMarkerInvariants } = inputs;
|
|
84
87
|
const contractSpaceHeadRef = await readContractSpaceHeadRef(projectMigrationsDir, spaceId);
|
|
85
88
|
if (contractSpaceHeadRef === null) return { kind: "contractSpaceHeadRefMissing" };
|
|
86
|
-
const packages = await readMigrationsDir(spaceMigrationDirectory(projectMigrationsDir, spaceId));
|
|
89
|
+
const { packages } = await readMigrationsDir(spaceMigrationDirectory(projectMigrationsDir, spaceId));
|
|
87
90
|
const graph = reconstructGraph(packages);
|
|
88
91
|
const fromHash = currentMarkerHash ?? "sha256:empty";
|
|
89
92
|
const required = new Set(contractSpaceHeadRef.invariants.filter((id) => !currentMarkerInvariants.includes(id)));
|
|
@@ -186,7 +189,8 @@ function contractSpaceFromJson(inputs) {
|
|
|
186
189
|
async function emitContractSpaceArtefacts(projectMigrationsDir, spaceId, inputs) {
|
|
187
190
|
assertValidSpaceId(spaceId);
|
|
188
191
|
const dir = join(projectMigrationsDir, spaceId);
|
|
189
|
-
|
|
192
|
+
const refsDir = spaceRefsDirectory(dir);
|
|
193
|
+
await mkdir(refsDir, { recursive: true });
|
|
190
194
|
await writeFile(join(dir, "contract.json"), `${canonicalizeJson(inputs.contract)}\n`);
|
|
191
195
|
await writeFile(join(dir, "contract.d.ts"), inputs.contractDts);
|
|
192
196
|
const sortedInvariants = [...inputs.headRef.invariants].sort();
|
|
@@ -194,7 +198,7 @@ async function emitContractSpaceArtefacts(projectMigrationsDir, spaceId, inputs)
|
|
|
194
198
|
hash: inputs.headRef.hash,
|
|
195
199
|
invariants: sortedInvariants
|
|
196
200
|
});
|
|
197
|
-
await writeFile(join(
|
|
201
|
+
await writeFile(join(refsDir, "head.json"), `${headJson}\n`);
|
|
198
202
|
}
|
|
199
203
|
//#endregion
|
|
200
204
|
//#region src/gather-disk-contract-space-state.ts
|
|
@@ -275,6 +279,6 @@ function planAllSpaces(inputs, planSpace) {
|
|
|
275
279
|
}));
|
|
276
280
|
}
|
|
277
281
|
//#endregion
|
|
278
|
-
export { APP_SPACE_ID, assertDescriptorSelfConsistency, assertValidSpaceId, computeExtensionSpaceApplyPath, contractSpaceFromJson, emitContractSpaceArtefacts, gatherDiskContractSpaceState, isValidSpaceId, listContractSpaceDirectories, planAllSpaces, readContractSpaceContract, readContractSpaceHeadRef, spaceMigrationDirectory, verifyContractSpaces };
|
|
282
|
+
export { APP_SPACE_ID, RESERVED_SPACE_SUBDIR_NAMES, SPACE_REFS_DIRNAME, assertDescriptorSelfConsistency, assertValidSpaceId, computeExtensionSpaceApplyPath, contractSpaceFromJson, emitContractSpaceArtefacts, gatherDiskContractSpaceState, isValidSpaceId, listContractSpaceDirectories, planAllSpaces, readContractSpaceContract, readContractSpaceHeadRef, spaceMigrationDirectory, spaceRefsDirectory, verifyContractSpaces };
|
|
279
283
|
|
|
280
284
|
//# sourceMappingURL=spaces.mjs.map
|