@prisma-next/extension-pgvector 0.5.0 → 0.6.0-dev.3

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 CHANGED
@@ -13,7 +13,7 @@ This extension pack adds support for the `vector` data type and vector similarit
13
13
  - **CLI Integration**: Provides extension descriptor for `prisma-next.config.ts` configuration
14
14
  - **Runtime Extension**: Registers codecs and operations at runtime for vector column operations
15
15
  - **Pack Ref Export**: Ships a pure `/pack` entrypoint for TypeScript contract authoring without runtime filesystem access
16
- - **Database Dependencies**: Declares the `vector` Postgres extension as a database dependency, which the migration planner emits as a `CREATE EXTENSION IF NOT EXISTS vector` operation and the verifier checks against the schema IR
16
+ - **Baseline Migration**: Ships an on-disk baseline migration in its contract space that installs the `vector` Postgres extension (`CREATE EXTENSION IF NOT EXISTS vector`) when the extension is composed into an application
17
17
 
18
18
  ## Dependencies
19
19
 
@@ -30,15 +30,15 @@ pnpm add @prisma-next/extension-pgvector
30
30
 
31
31
  ## Database Setup
32
32
 
33
- The pgvector extension declares its database requirements as component-owned database dependencies. When using the `prisma-next db init` command, the migration planner automatically includes a `CREATE EXTENSION IF NOT EXISTS vector` operation.
33
+ The pgvector extension ships an on-disk baseline migration in its contract space; applying that migration installs pgvector with `CREATE EXTENSION IF NOT EXISTS vector`. When the extension is composed into an application via `extensionPacks`, `prisma-next db init` and `prisma-next db update` apply the baseline (and any subsequent migrations) automatically.
34
34
 
35
- For manual database setup, ensure the pgvector extension is installed:
35
+ For manual database setup, the equivalent DDL is:
36
36
 
37
37
  ```sql
38
38
  CREATE EXTENSION IF NOT EXISTS vector;
39
39
  ```
40
40
 
41
- The verifier will check for the presence of the `vector` extension in your database schema and report an error if it's missing.
41
+ Ensure the baseline migration (or equivalent DDL) has been applied before running workloads that use vector columns.
42
42
 
43
43
  ## Configuration
44
44
 
@@ -198,10 +198,24 @@ The extension declares the following capabilities:
198
198
 
199
199
  - `pgvector.cosine`: Indicates support for cosine distance and similarity operations
200
200
 
201
+ ## Authoring (maintainers)
202
+
203
+ The extension's contract + baseline migration are emitted on-disk inside this package using the same pipeline application authors use:
204
+
205
+ - `pnpm build:contract-space` — runs `prisma-next contract emit` to produce `src/contract.{json,d.ts}` from the TS source at `src/contract.ts`.
206
+ - `pnpm exec prisma-next migration plan --name <slug>` (run from this package directory) — scaffolds a new migration directory under `migrations/<dirName>/` for schema changes that touch tables / models. **Not chained into `pnpm build`**: `migration plan` is non-idempotent (each invocation generates a new timestamped directory), so it runs manually when the contract source changes. Note: pgvector's contract declares only the parameterised `vector` native type under `storage.types` (no tables / models), so the planner currently refuses to scaffold the baseline migration with `PN-CLI-4020 Contract changed but planner produced no operations` (this is **Path B** authoring per [ADR 212](../../../docs/architecture%20docs/adrs/ADR%20212%20-%20Contract%20spaces.md#contract-space-package-layout)). That directory was hand-authored once (Migration subclass + seed `migration.json` preserving the full `toContract`) and `pnpm tsx migrations/<dirName>/migration.ts` re-emits `ops.json` + `migration.json` deterministically. Future migrations that add tables / models can use `migration plan` directly (Path A).
207
+ - `pnpm tsx migrations/<dirName>/migration.ts` (run from this package directory) — re-emits `ops.json` + `migration.json` from the hand-edited subclass. Use `tsx`, not bare `node`, because the Migration subclass imports relative TypeScript siblings which Node's native loader can't resolve without a TS-aware loader.
208
+ - `migrations/refs/head.json` is hand-pinned with the latest migration's `to` hash + `providedInvariants`.
209
+
210
+ The descriptor at `src/exports/control.ts` then JSON-imports those artefacts and synthesises the framework's `MigrationPackage` shape.
211
+
212
+ See [ADR 212 — Contract spaces](../../../docs/architecture%20docs/adrs/ADR%20212%20-%20Contract%20spaces.md) ("Contract-space package layout") for the canonical layout and rationale.
213
+
201
214
  ## References
202
215
 
203
216
  - [pgvector documentation](https://github.com/pgvector/pgvector)
204
217
  - [Prisma Next Architecture Overview](../../../docs/Architecture%20Overview.md)
205
218
  - [Extension Packs Guide](../../../docs/reference/Extension-Packs-Naming-and-Layout.md)
219
+ - [ADR 212 — Contract spaces](../../../docs/architecture%20docs/adrs/ADR%20212%20-%20Contract%20spaces.md)
206
220
 
207
221
  Pack refs (`@prisma-next/extension-pgvector/pack`) are pure data objects generated from the hydrated manifest (`src/core/manifest.ts`), so TypeScript contract builders can enable the pgvector namespace in both emit and no-emit workflows without touching the filesystem.
@@ -1,5 +1,5 @@
1
- import { JsonValue } from "@prisma-next/contract/types";
2
1
  import { AnyCodecDescriptor, CodecCallContext, CodecDescriptorImpl, CodecImpl, CodecInstanceContext } from "@prisma-next/framework-components/codec";
2
+ import { JsonValue } from "@prisma-next/contract/types";
3
3
  import { ExtractCodecTypes } from "@prisma-next/sql-relational-core/ast";
4
4
  import { StandardSchemaV1 } from "@standard-schema/spec";
5
5
 
@@ -60,4 +60,4 @@ type Vector<N extends number = number> = number[] & {
60
60
  type CodecTypes = CodecTypes$1;
61
61
  //#endregion
62
62
  export { Vector as n, CodecTypes as t };
63
- //# sourceMappingURL=codec-types-yMSpEJJM.d.mts.map
63
+ //# sourceMappingURL=codec-types-CQubO6uQ.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"codec-types-yMSpEJJM.d.mts","names":[],"sources":["../src/core/constants.ts","../src/core/codecs.ts","../src/types/codec-types.ts"],"mappings":";;;;;;;;;cAGa,eAAA;;;KCyBR,YAAA;EAAA,SAA0B,MAAA;AAAA;AAAA,cAiBlB,aAAA,SAAsB,SAAA,QAC1B,eAAA;EAAA,SAKE,MAAA;cAEG,UAAA,EAAY,kBAAA,EAAoB,MAAA;EAK5C,YAAA,CAAa,KAAA,oBAAyB,KAAA;EAYhC,MAAA,CAAO,KAAA,YAAiB,IAAA,EAAM,gBAAA,GAAmB,OAAA;EAKjD,MAAA,CAAO,IAAA,UAAc,IAAA,EAAM,gBAAA,GAAmB,OAAA;EAsBpD,UAAA,CAAW,KAAA,aAAkB,SAAA;EAK7B,UAAA,CAAW,IAAA,EAAM,SAAA;AAAA;AAAA,cAMN,kBAAA,SAA2B,mBAAA,CAAoB,YAAA;EAAA,SACxC,OAAA;EAAA,SACA,MAAA;EAAA,SACA,WAAA;EAAA,SACA,IAAA;IAAA;;;;;;;;WACA,YAAA,EAAc,gBAAA,CAAiB,YAAA;EACxC,gBAAA,CAAiB,MAAA,EAAQ,YAAA;EA5C5B;;;EAkDG,OAAA,CAAQ,MAAA,EAAQ,YAAA,IAAgB,GAAA,EAAK,oBAAA,KAAyB,aAAA;AAAA;AAAA,cAkBnE,kBAAA;EAAA,iBAEI,kBAAA;AAAA;AAAA,KAEE,YAAA,GAAa,iBAAA,QAAyB,kBAAA;;;;;;;;AApHY;KCTlD,MAAA;EAAA,SAA0D,cAAA,GAAiB,CAAA;AAAA;AAAA,KAE3E,UAAA,GAAa,YAAA"}
1
+ {"version":3,"file":"codec-types-CQubO6uQ.d.mts","names":[],"sources":["../src/core/constants.ts","../src/core/codecs.ts","../src/types/codec-types.ts"],"mappings":";;;;;;;;;cAGa,eAAA;;;KCyBR,YAAA;EAAA,SAA0B,MAAA;AAAA;AAAA,cAiBlB,aAAA,SAAsB,SAAA,QAC1B,eAAA;EAAA,SAKE,MAAA;cAEG,UAAA,EAAY,kBAAA,EAAoB,MAAA;EAK5C,YAAA,CAAa,KAAA,oBAAyB,KAAA;EAYhC,MAAA,CAAO,KAAA,YAAiB,IAAA,EAAM,gBAAA,GAAmB,OAAA;EAKjD,MAAA,CAAO,IAAA,UAAc,IAAA,EAAM,gBAAA,GAAmB,OAAA;EAsBpD,UAAA,CAAW,KAAA,aAAkB,SAAA;EAK7B,UAAA,CAAW,IAAA,EAAM,SAAA;AAAA;AAAA,cAMN,kBAAA,SAA2B,mBAAA,CAAoB,YAAA;EAAA,SACxC,OAAA;EAAA,SACA,MAAA;EAAA,SACA,WAAA;EAAA,SACA,IAAA;IAAA;;;;;;;;WACA,YAAA,EAAc,gBAAA,CAAiB,YAAA;EACxC,gBAAA,CAAiB,MAAA,EAAQ,YAAA;EA5C5B;;;EAkDG,OAAA,CAAQ,MAAA,EAAQ,YAAA,IAAgB,GAAA,EAAK,oBAAA,KAAyB,aAAA;AAAA;AAAA,cAkBnE,kBAAA;EAAA,iBAEI,kBAAA;AAAA;AAAA,KAEE,YAAA,GAAa,iBAAA,QAAyB,kBAAA;;;;;;;;AApHY;KCTlD,MAAA;EAAA,SAA0D,cAAA,GAAiB,CAAA;AAAA;AAAA,KAE3E,UAAA,GAAa,YAAA"}
@@ -1,2 +1,2 @@
1
- import { n as Vector, t as CodecTypes } from "./codec-types-yMSpEJJM.mjs";
1
+ import { n as Vector, t as CodecTypes } from "./codec-types-CQubO6uQ.mjs";
2
2
  export { type CodecTypes, type Vector };
@@ -1 +1 @@
1
- {"version":3,"file":"control.d.mts","names":[],"sources":["../src/exports/control.ts"],"mappings":";;;cA+DM,2BAAA,EAA6B,6BAAA"}
1
+ {"version":3,"file":"control.d.mts","names":[],"sources":["../src/exports/control.ts"],"mappings":";;;cAsFM,2BAAA,EAA6B,6BAAA"}
package/dist/control.mjs CHANGED
@@ -1,8 +1,133 @@
1
- import { t as VECTOR_CODEC_ID } from "./constants-DX-00vYk.mjs";
2
1
  import { n as pgvectorQueryOperations, t as pgvectorPackMeta } from "./descriptor-meta-DEgJjLLi.mjs";
3
- import { computeStorageHash } from "@prisma-next/contract/hashing";
4
- import { coreHash, profileHash } from "@prisma-next/contract/types";
5
- import { computeMigrationHash } from "@prisma-next/migration-tools/hash";
2
+ import { contractSpaceFromJson } from "@prisma-next/migration-tools/spaces";
3
+ //#region migrations/20260601T0000_install_vector_extension/migration.json
4
+ var migration_default = {
5
+ from: null,
6
+ to: "sha256:382dae5bb1548e62cbc449530ea08a9ce0a0dbb280401e9588642223f33783ae",
7
+ labels: [],
8
+ providedInvariants: ["pgvector:install-vector-v1"],
9
+ createdAt: "2026-06-01T00:00:00.000Z",
10
+ fromContract: null,
11
+ toContract: {
12
+ "schemaVersion": "1",
13
+ "targetFamily": "sql",
14
+ "target": "postgres",
15
+ "profileHash": "sha256:1a8dbe044289f30a1de958fe800cc5a8378b285d2e126a8c44b58864bac2c18e",
16
+ "roots": {},
17
+ "models": {},
18
+ "storage": {
19
+ "storageHash": "sha256:382dae5bb1548e62cbc449530ea08a9ce0a0dbb280401e9588642223f33783ae",
20
+ "tables": {},
21
+ "types": { "vector": {
22
+ "codecId": "pg/vector@1",
23
+ "nativeType": "vector",
24
+ "typeParams": {}
25
+ } }
26
+ },
27
+ "capabilities": {
28
+ "postgres": {
29
+ "jsonAgg": true,
30
+ "lateral": true,
31
+ "limit": true,
32
+ "orderBy": true,
33
+ "returning": true
34
+ },
35
+ "sql": {
36
+ "defaultInInsert": true,
37
+ "enums": true,
38
+ "returning": true
39
+ }
40
+ },
41
+ "extensionPacks": {},
42
+ "meta": {},
43
+ "_generated": {
44
+ "warning": "⚠️ GENERATED FILE - DO NOT EDIT",
45
+ "message": "This file is automatically generated by \"prisma-next contract emit\".",
46
+ "regenerate": "To regenerate, run: prisma-next contract emit"
47
+ }
48
+ },
49
+ hints: {
50
+ "used": [],
51
+ "applied": [],
52
+ "plannerVersion": "2.0.0"
53
+ },
54
+ migrationHash: "sha256:7419a7bfdac708cff9db1b35e48b035b09f3a883f099483e41385738d146622a"
55
+ };
56
+ //#endregion
57
+ //#region migrations/20260601T0000_install_vector_extension/ops.json
58
+ var ops_default = [{
59
+ "id": "pgvector.install-vector-extension",
60
+ "label": "Enable extension \"vector\"",
61
+ "operationClass": "additive",
62
+ "invariantId": "pgvector:install-vector-v1",
63
+ "target": {
64
+ "id": "postgres",
65
+ "details": {
66
+ "schema": "public",
67
+ "objectType": "dependency",
68
+ "name": "vector"
69
+ }
70
+ },
71
+ "precheck": [{
72
+ "description": "verify extension \"vector\" is not already enabled",
73
+ "sql": "SELECT NOT EXISTS (SELECT 1 FROM pg_extension WHERE extname = 'vector')"
74
+ }],
75
+ "execute": [{
76
+ "description": "create extension \"vector\"",
77
+ "sql": "CREATE EXTENSION IF NOT EXISTS vector"
78
+ }],
79
+ "postcheck": [{
80
+ "description": "confirm extension \"vector\" is enabled",
81
+ "sql": "SELECT EXISTS (SELECT 1 FROM pg_extension WHERE extname = 'vector')"
82
+ }]
83
+ }];
84
+ //#endregion
85
+ //#region migrations/refs/head.json
86
+ var head_default = {
87
+ hash: "sha256:382dae5bb1548e62cbc449530ea08a9ce0a0dbb280401e9588642223f33783ae",
88
+ invariants: ["pgvector:install-vector-v1"]
89
+ };
90
+ //#endregion
91
+ //#region src/contract.json
92
+ var contract_default = {
93
+ schemaVersion: "1",
94
+ targetFamily: "sql",
95
+ target: "postgres",
96
+ profileHash: "sha256:1a8dbe044289f30a1de958fe800cc5a8378b285d2e126a8c44b58864bac2c18e",
97
+ roots: {},
98
+ models: {},
99
+ storage: {
100
+ "storageHash": "sha256:382dae5bb1548e62cbc449530ea08a9ce0a0dbb280401e9588642223f33783ae",
101
+ "tables": {},
102
+ "types": { "vector": {
103
+ "codecId": "pg/vector@1",
104
+ "nativeType": "vector",
105
+ "typeParams": {}
106
+ } }
107
+ },
108
+ capabilities: {
109
+ "postgres": {
110
+ "jsonAgg": true,
111
+ "lateral": true,
112
+ "limit": true,
113
+ "orderBy": true,
114
+ "returning": true
115
+ },
116
+ "sql": {
117
+ "defaultInInsert": true,
118
+ "enums": true,
119
+ "returning": true
120
+ }
121
+ },
122
+ extensionPacks: {},
123
+ meta: {},
124
+ _generated: {
125
+ "warning": "⚠️ GENERATED FILE - DO NOT EDIT",
126
+ "message": "This file is automatically generated by \"prisma-next contract emit\".",
127
+ "regenerate": "To regenerate, run: prisma-next contract emit"
128
+ }
129
+ };
130
+ //#endregion
6
131
  //#region src/core/contract-space-constants.ts
7
132
  /**
8
133
  * Static names and identifiers used across pgvector's contract space.
@@ -12,7 +137,7 @@ import { computeMigrationHash } from "@prisma-next/migration-tools/hash";
12
137
  * (`../exports/control`) all reference the same values without typos.
13
138
  *
14
139
  * The space identifier `'pgvector'` is what the framework writes to
15
- * `migrations/pgvector/` in the user's repo and what the marker table's
140
+ * `migrations/` in the user's repo and what the marker table's
16
141
  * `space` column carries for pgvector-owned rows.
17
142
  *
18
143
  * The `pgvector:*` invariantId namespace is locked here — once
@@ -20,153 +145,10 @@ import { computeMigrationHash } from "@prisma-next/migration-tools/hash";
20
145
  * reference it by literal string match.
21
146
  */
22
147
  const PGVECTOR_SPACE_ID = "pgvector";
23
- const PGVECTOR_NATIVE_TYPE = "vector";
24
- const PGVECTOR_BASELINE_MIGRATION_NAME = "20260601T0000_install_vector_extension";
25
- /**
26
- * `pgvector:*` invariantIds emitted by the baseline migration. Each id,
27
- * once published, is immutable: downstream consumers (other extensions,
28
- * the marker table) reference them by literal string match.
29
- */
30
- const PGVECTOR_INVARIANTS = { installVector: "pgvector:install-vector-v1" };
31
- //#endregion
32
- //#region src/core/contract.ts
33
- /**
34
- * pgvector contract space — declares the parameterised native type
35
- * `vector(N)` that user columns can name as `nativeType`.
36
- *
37
- * Unlike CipherStash's typed objects (composite types / domains / enums
38
- * — deferred behind `meta.cipherstashFutureIR` until the IR vocabulary
39
- * gains first-class support), pgvector's `vector` is a parameterised
40
- * native type and *is* representable in today's IR via
41
- * {@link StorageTypeInstance}: `{ codecId, nativeType, typeParams }`.
42
- * The contract registers a representative instance under
43
- * `storage.types.vector` so the verifier sees the type as part of
44
- * pgvector's space contribution and so the pinned `contract.json` on
45
- * disk is materially distinct from an empty space.
46
- *
47
- * Per-column instances on the user's side carry concrete
48
- * `typeParams.length` (e.g. `vector(1536)`); the registration here
49
- * declares the parameterised shape — it is not consumed as a literal
50
- * column type by any user table.
51
- */
52
- const TARGET = "postgres";
53
- const TARGET_FAMILY = "sql";
54
- /**
55
- * Storage body for the contract — pgvector ships no tables of its own;
56
- * the `vector` parameterised native type is registered under
57
- * `storage.types` so pgvector's IR contribution is non-empty and the
58
- * pinned `contract.json` on disk differs materially from an empty
59
- * extension space.
60
- *
61
- * Authored without `storageHash` here so {@link computeStorageHash} can
62
- * digest the canonical body (the hashing pipeline panics if asked to
63
- * hash an object that already carries its own output — see
64
- * `assertDescriptorSelfConsistency`'s storage-hash strip).
65
- */
66
- const storageBody = {
67
- tables: {},
68
- types: { [PGVECTOR_NATIVE_TYPE]: {
69
- codecId: VECTOR_CODEC_ID,
70
- nativeType: PGVECTOR_NATIVE_TYPE,
71
- typeParams: {}
72
- } }
73
- };
74
- /** Content-addressed hash of pgvector's storage IR. */
75
- const PGVECTOR_STORAGE_HASH = computeStorageHash({
76
- target: TARGET,
77
- targetFamily: TARGET_FAMILY,
78
- storage: storageBody
79
- });
80
- /** pgvector's contract value, exposed via the descriptor's `contractSpace.contractJson`. */
81
- const pgvectorContract = {
82
- target: TARGET,
83
- targetFamily: TARGET_FAMILY,
84
- roots: {},
85
- models: {},
86
- capabilities: {},
87
- extensionPacks: {},
88
- meta: {},
89
- profileHash: profileHash("pgvector-extension-profile-v1"),
90
- storage: {
91
- ...storageBody,
92
- storageHash: coreHash(PGVECTOR_STORAGE_HASH)
93
- }
94
- };
95
- //#endregion
96
- //#region src/core/migrations.ts
97
- const pgvectorBaselineOps = [{
98
- id: "pgvector.install-vector-extension",
99
- label: "Enable extension \"vector\"",
100
- operationClass: "additive",
101
- invariantId: PGVECTOR_INVARIANTS.installVector,
102
- target: {
103
- id: "postgres",
104
- details: {
105
- schema: "public",
106
- objectType: "extension",
107
- name: "vector"
108
- }
109
- },
110
- precheck: [{
111
- description: "verify extension \"vector\" is not already enabled",
112
- sql: "SELECT NOT EXISTS (SELECT 1 FROM pg_extension WHERE extname = 'vector')"
113
- }],
114
- execute: [{
115
- description: "create extension \"vector\"",
116
- sql: "CREATE EXTENSION IF NOT EXISTS vector"
117
- }],
118
- postcheck: [{
119
- description: "confirm extension \"vector\" is enabled",
120
- sql: "SELECT EXISTS (SELECT 1 FROM pg_extension WHERE extname = 'vector')"
121
- }]
122
- }];
123
- /** Sorted list of invariantIds the baseline migration provides. */
124
- const PGVECTOR_BASELINE_INVARIANTS = (() => {
125
- const ids = pgvectorBaselineOps.map((op) => op.invariantId).filter((id) => typeof id === "string");
126
- return [...new Set(ids)].sort();
127
- })();
128
- const baselineMetadataWithoutHash = {
129
- from: null,
130
- to: PGVECTOR_STORAGE_HASH,
131
- fromContract: null,
132
- toContract: pgvectorContract,
133
- hints: {
134
- used: [],
135
- applied: [],
136
- plannerVersion: "2.0.0"
137
- },
138
- labels: [],
139
- providedInvariants: PGVECTOR_BASELINE_INVARIANTS,
140
- createdAt: "2026-06-01T00:00:00.000Z"
141
- };
142
- /**
143
- * Baseline migration package the descriptor publishes via
144
- * `contractSpace.migrations`. The framework's emitter writes this to
145
- * `migrations/pgvector/<dirName>/{manifest,ops,contract}.json` in the
146
- * user's repo at `migrate` time.
147
- */
148
- const pgvectorBaselineMigration = {
149
- dirName: PGVECTOR_BASELINE_MIGRATION_NAME,
150
- metadata: {
151
- ...baselineMetadataWithoutHash,
152
- migrationHash: computeMigrationHash(baselineMetadataWithoutHash, pgvectorBaselineOps)
153
- },
154
- ops: pgvectorBaselineOps
155
- };
156
- /**
157
- * Pinned head ref the descriptor publishes. The framework writes this
158
- * verbatim to `migrations/pgvector/refs/head.json` (with `invariants`
159
- * sorted alphabetically per the canonicalisation rules); the runner's
160
- * `findPathWithDecision` step consults `head.json` to decide which
161
- * migrations need to apply.
162
- */
163
- const pgvectorHeadRef = {
164
- hash: PGVECTOR_STORAGE_HASH,
165
- invariants: PGVECTOR_BASELINE_INVARIANTS
166
- };
167
148
  //#endregion
168
149
  //#region src/exports/control.ts
169
150
  const PGVECTOR_CODEC_ID = "pg/vector@1";
151
+ const BASELINE_DIR_NAME = "20260601T0000_install_vector_extension";
170
152
  function buildVectorIdentityValue(typeParams) {
171
153
  const length = typeParams?.["length"];
172
154
  if (typeof length !== "number" || !Number.isInteger(length) || length <= 0) return null;
@@ -180,11 +162,15 @@ const vectorControlPlaneHooks = {
180
162
  },
181
163
  resolveIdentityValue: ({ typeParams }) => buildVectorIdentityValue(typeParams)
182
164
  };
183
- const pgvectorContractSpace = {
184
- contractJson: pgvectorContract,
185
- migrations: [pgvectorBaselineMigration],
186
- headRef: pgvectorHeadRef
187
- };
165
+ const pgvectorContractSpace = contractSpaceFromJson({
166
+ contractJson: contract_default,
167
+ migrations: [{
168
+ dirName: BASELINE_DIR_NAME,
169
+ metadata: migration_default,
170
+ ops: ops_default
171
+ }],
172
+ headRef: head_default
173
+ });
188
174
  const pgvectorExtensionDescriptor = {
189
175
  ...pgvectorPackMeta,
190
176
  id: PGVECTOR_SPACE_ID,
@@ -1 +1 @@
1
- {"version":3,"file":"control.mjs","names":[],"sources":["../src/core/contract-space-constants.ts","../src/core/contract.ts","../src/core/migrations.ts","../src/exports/control.ts"],"sourcesContent":["/**\n * Static names and identifiers used across pgvector's contract space.\n *\n * Centralised here so the contract IR (`./contract`), the baseline\n * migration ops (`./migrations`), the head ref, and the descriptor\n * (`../exports/control`) all reference the same values without typos.\n *\n * The space identifier `'pgvector'` is what the framework writes to\n * `migrations/pgvector/` in the user's repo and what the marker table's\n * `space` column carries for pgvector-owned rows.\n *\n * The `pgvector:*` invariantId namespace is locked here — once\n * published, an invariantId is immutable so downstream consumers can\n * reference it by literal string match.\n */\n\nexport const PGVECTOR_SPACE_ID = 'pgvector' as const;\n\nexport const PGVECTOR_NATIVE_TYPE = 'vector' as const;\n\nexport const PGVECTOR_BASELINE_MIGRATION_NAME = '20260601T0000_install_vector_extension' as const;\n\n/**\n * `pgvector:*` invariantIds emitted by the baseline migration. Each id,\n * once published, is immutable: downstream consumers (other extensions,\n * the marker table) reference them by literal string match.\n */\nexport const PGVECTOR_INVARIANTS = {\n installVector: 'pgvector:install-vector-v1',\n} as const;\n","/**\n * pgvector contract space — declares the parameterised native type\n * `vector(N)` that user columns can name as `nativeType`.\n *\n * Unlike CipherStash's typed objects (composite types / domains / enums\n * — deferred behind `meta.cipherstashFutureIR` until the IR vocabulary\n * gains first-class support), pgvector's `vector` is a parameterised\n * native type and *is* representable in today's IR via\n * {@link StorageTypeInstance}: `{ codecId, nativeType, typeParams }`.\n * The contract registers a representative instance under\n * `storage.types.vector` so the verifier sees the type as part of\n * pgvector's space contribution and so the pinned `contract.json` on\n * disk is materially distinct from an empty space.\n *\n * Per-column instances on the user's side carry concrete\n * `typeParams.length` (e.g. `vector(1536)`); the registration here\n * declares the parameterised shape — it is not consumed as a literal\n * column type by any user table.\n */\n\nimport { computeStorageHash } from '@prisma-next/contract/hashing';\nimport { type Contract, coreHash, profileHash } from '@prisma-next/contract/types';\nimport type { SqlStorage } from '@prisma-next/sql-contract/types';\nimport { VECTOR_CODEC_ID } from './constants';\nimport { PGVECTOR_NATIVE_TYPE } from './contract-space-constants';\n\nconst TARGET = 'postgres' as const;\nconst TARGET_FAMILY = 'sql' as const;\n\n/**\n * Storage body for the contract — pgvector ships no tables of its own;\n * the `vector` parameterised native type is registered under\n * `storage.types` so pgvector's IR contribution is non-empty and the\n * pinned `contract.json` on disk differs materially from an empty\n * extension space.\n *\n * Authored without `storageHash` here so {@link computeStorageHash} can\n * digest the canonical body (the hashing pipeline panics if asked to\n * hash an object that already carries its own output — see\n * `assertDescriptorSelfConsistency`'s storage-hash strip).\n */\nconst storageBody = {\n tables: {},\n types: {\n [PGVECTOR_NATIVE_TYPE]: {\n codecId: VECTOR_CODEC_ID,\n nativeType: PGVECTOR_NATIVE_TYPE,\n typeParams: {},\n },\n },\n};\n\n/** Content-addressed hash of pgvector's storage IR. */\nexport const PGVECTOR_STORAGE_HASH = computeStorageHash({\n target: TARGET,\n targetFamily: TARGET_FAMILY,\n storage: storageBody,\n});\n\n/** pgvector's contract value, exposed via the descriptor's `contractSpace.contractJson`. */\nexport const pgvectorContract: Contract<SqlStorage> = {\n target: TARGET,\n targetFamily: TARGET_FAMILY,\n roots: {},\n models: {},\n capabilities: {},\n extensionPacks: {},\n meta: {},\n profileHash: profileHash('pgvector-extension-profile-v1'),\n storage: {\n ...storageBody,\n storageHash: coreHash(PGVECTOR_STORAGE_HASH),\n },\n};\n","/**\n * pgvector contract space — baseline migration package.\n *\n * An extension's `contractSpace.migrations` is a list of in-memory\n * `MigrationPackage` values whose `ops` carry framework-level\n * `MigrationPlanOperation`s. The SQL family runner reads the additional\n * runtime fields (`target`, `precheck`, `execute`, `postcheck`) at\n * apply time.\n *\n * Ships a single baseline migration whose only op is\n * {@link installVectorExtensionOp} — it carries the\n * `CREATE EXTENSION IF NOT EXISTS vector` DDL plus a postcondition that\n * confirms the extension landed. Mirrors the prior\n * `databaseDependencies.init[0]` shape (precheck / execute / postcheck)\n * but as a `MigrationPackage` op so the framework's per-space runner /\n * verifier can manage it the same way it manages an application's own\n * migrations.\n *\n * The op carries the stable `pgvector:install-vector-v1` invariantId —\n * once published it is immutable.\n */\n\nimport type { SqlMigrationPlanOperation } from '@prisma-next/family-sql/control';\nimport type {\n ContractSpaceHeadRef,\n MigrationPackage,\n MigrationPlanOperation,\n} from '@prisma-next/framework-components/control';\nimport { computeMigrationHash } from '@prisma-next/migration-tools/hash';\nimport { PGVECTOR_STORAGE_HASH, pgvectorContract } from './contract';\nimport { PGVECTOR_BASELINE_MIGRATION_NAME, PGVECTOR_INVARIANTS } from './contract-space-constants';\n\n/**\n * Postgres-style `target.details` shape the SQL runner consumes when\n * executing extension-space ops. pgvector targets only Postgres;\n * locking the target id here keeps the per-op `target` literal narrow\n * without coupling to the Postgres adapter package's\n * `PostgresPlanTargetDetails`.\n */\ntype PostgresTargetDetails = {\n readonly schema: string;\n readonly objectType: 'extension';\n readonly name: string;\n};\n\nconst installVectorExtensionOp: SqlMigrationPlanOperation<unknown> = {\n id: 'pgvector.install-vector-extension',\n label: 'Enable extension \"vector\"',\n operationClass: 'additive',\n invariantId: PGVECTOR_INVARIANTS.installVector,\n target: {\n id: 'postgres',\n details: {\n schema: 'public',\n objectType: 'extension',\n name: 'vector',\n } satisfies PostgresTargetDetails,\n },\n precheck: [\n {\n description: 'verify extension \"vector\" is not already enabled',\n sql: \"SELECT NOT EXISTS (SELECT 1 FROM pg_extension WHERE extname = 'vector')\",\n },\n ],\n execute: [\n {\n description: 'create extension \"vector\"',\n sql: 'CREATE EXTENSION IF NOT EXISTS vector',\n },\n ],\n postcheck: [\n {\n description: 'confirm extension \"vector\" is enabled',\n sql: \"SELECT EXISTS (SELECT 1 FROM pg_extension WHERE extname = 'vector')\",\n },\n ],\n};\n\nconst pgvectorBaselineOps: readonly MigrationPlanOperation[] = [installVectorExtensionOp];\n\n/** Sorted list of invariantIds the baseline migration provides. */\nexport const PGVECTOR_BASELINE_INVARIANTS: readonly string[] = (() => {\n const ids = pgvectorBaselineOps\n .map((op) => op.invariantId)\n .filter((id): id is string => typeof id === 'string');\n return [...new Set(ids)].sort();\n})();\n\nconst baselineMetadataWithoutHash: Omit<MigrationPackage['metadata'], 'migrationHash'> = {\n from: null,\n to: PGVECTOR_STORAGE_HASH,\n fromContract: null,\n toContract: pgvectorContract,\n hints: { used: [], applied: [], plannerVersion: '2.0.0' },\n labels: [],\n providedInvariants: PGVECTOR_BASELINE_INVARIANTS,\n createdAt: '2026-06-01T00:00:00.000Z',\n};\n\n/**\n * Baseline migration package the descriptor publishes via\n * `contractSpace.migrations`. The framework's emitter writes this to\n * `migrations/pgvector/<dirName>/{manifest,ops,contract}.json` in the\n * user's repo at `migrate` time.\n */\nexport const pgvectorBaselineMigration: MigrationPackage = {\n dirName: PGVECTOR_BASELINE_MIGRATION_NAME,\n metadata: {\n ...baselineMetadataWithoutHash,\n migrationHash: computeMigrationHash(baselineMetadataWithoutHash, pgvectorBaselineOps),\n },\n ops: pgvectorBaselineOps,\n};\n\n/**\n * Pinned head ref the descriptor publishes. The framework writes this\n * verbatim to `migrations/pgvector/refs/head.json` (with `invariants`\n * sorted alphabetically per the canonicalisation rules); the runner's\n * `findPathWithDecision` step consults `head.json` to decide which\n * migrations need to apply.\n */\nexport const pgvectorHeadRef: ContractSpaceHeadRef = {\n hash: PGVECTOR_STORAGE_HASH,\n invariants: PGVECTOR_BASELINE_INVARIANTS,\n};\n","/**\n * Control-plane descriptor for the pgvector extension.\n *\n * Exposes a `contractSpace` so the framework's per-space planner /\n * runner / verifier (project: extension-contract-spaces, M1+M2)\n * manages the pgvector extension's database scaffolding the same way\n * it manages an application's own schema. The descriptor is consumed\n * by the framework only at authoring time (`migrate`); apply / verify\n * paths read the user's repo (`migrations/pgvector/...`) instead — see\n * project spec NFR3 / FR2 / FR10.\n *\n * `databaseDependencies` is intentionally absent — pgvector was\n * migrated off the legacy `databaseDependencies.init` mechanism in M4\n * (project spec FR13). The `CREATE EXTENSION IF NOT EXISTS vector`\n * DDL the legacy entry carried now lives as the body of the\n * `installVectorExtension` op inside the baseline migration package\n * (`../core/migrations.ts`). Presence of `contractSpace` is the\n * shipping-strategy gate: the framework loads the contract space and\n * ignores any `databaseDependencies` block (project plan §\n * \"Shipping Strategy\"). M5 removes the field at the framework level.\n */\n\nimport type { Contract } from '@prisma-next/contract/types';\nimport type {\n CodecControlHooks,\n SqlControlExtensionDescriptor,\n} from '@prisma-next/family-sql/control';\nimport type { ContractSpace } from '@prisma-next/framework-components/control';\nimport type { SqlStorage } from '@prisma-next/sql-contract/types';\nimport { pgvectorContract } from '../core/contract';\nimport { PGVECTOR_SPACE_ID } from '../core/contract-space-constants';\nimport { pgvectorPackMeta, pgvectorQueryOperations } from '../core/descriptor-meta';\nimport { pgvectorBaselineMigration, pgvectorHeadRef } from '../core/migrations';\n\nconst PGVECTOR_CODEC_ID = 'pg/vector@1' as const;\n\nfunction buildVectorIdentityValue(typeParams: Record<string, unknown> | undefined): string | null {\n const length = typeParams?.['length'];\n if (typeof length !== 'number' || !Number.isInteger(length) || length <= 0) {\n return null;\n }\n\n const zeroVector = `[${new Array(length).fill('0').join(',')}]`;\n return `'${zeroVector}'::vector`;\n}\n\nconst vectorControlPlaneHooks: CodecControlHooks = {\n expandNativeType: ({ nativeType, typeParams }) => {\n const length = typeParams?.['length'];\n if (typeof length === 'number' && Number.isInteger(length) && length > 0) {\n return `${nativeType}(${length})`;\n }\n return nativeType;\n },\n resolveIdentityValue: ({ typeParams }) => buildVectorIdentityValue(typeParams),\n};\n\nconst pgvectorContractSpace: ContractSpace<Contract<SqlStorage>> = {\n contractJson: pgvectorContract,\n migrations: [pgvectorBaselineMigration],\n headRef: pgvectorHeadRef,\n};\n\nconst pgvectorExtensionDescriptor: SqlControlExtensionDescriptor<'postgres'> = {\n ...pgvectorPackMeta,\n id: PGVECTOR_SPACE_ID,\n contractSpace: pgvectorContractSpace,\n types: {\n ...pgvectorPackMeta.types,\n codecTypes: {\n ...pgvectorPackMeta.types.codecTypes,\n controlPlaneHooks: {\n [PGVECTOR_CODEC_ID]: vectorControlPlaneHooks,\n },\n },\n },\n queryOperations: () => pgvectorQueryOperations(),\n create: () => ({\n familyId: 'sql' as const,\n targetId: 'postgres' as const,\n }),\n};\n\nexport { pgvectorExtensionDescriptor };\nexport default pgvectorExtensionDescriptor;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAgBA,MAAa,oBAAoB;AAEjC,MAAa,uBAAuB;AAEpC,MAAa,mCAAmC;;;;;;AAOhD,MAAa,sBAAsB,EACjC,eAAe,8BAChB;;;;;;;;;;;;;;;;;;;;;;ACHD,MAAM,SAAS;AACf,MAAM,gBAAgB;;;;;;;;;;;;;AActB,MAAM,cAAc;CAClB,QAAQ,EAAE;CACV,OAAO,GACJ,uBAAuB;EACtB,SAAS;EACT,YAAY;EACZ,YAAY,EAAE;EACf,EACF;CACF;;AAGD,MAAa,wBAAwB,mBAAmB;CACtD,QAAQ;CACR,cAAc;CACd,SAAS;CACV,CAAC;;AAGF,MAAa,mBAAyC;CACpD,QAAQ;CACR,cAAc;CACd,OAAO,EAAE;CACT,QAAQ,EAAE;CACV,cAAc,EAAE;CAChB,gBAAgB,EAAE;CAClB,MAAM,EAAE;CACR,aAAa,YAAY,gCAAgC;CACzD,SAAS;EACP,GAAG;EACH,aAAa,SAAS,sBAAsB;EAC7C;CACF;;;ACKD,MAAM,sBAAyD,CAAC;CAhC9D,IAAI;CACJ,OAAO;CACP,gBAAgB;CAChB,aAAa,oBAAoB;CACjC,QAAQ;EACN,IAAI;EACJ,SAAS;GACP,QAAQ;GACR,YAAY;GACZ,MAAM;GACP;EACF;CACD,UAAU,CACR;EACE,aAAa;EACb,KAAK;EACN,CACF;CACD,SAAS,CACP;EACE,aAAa;EACb,KAAK;EACN,CACF;CACD,WAAW,CACT;EACE,aAAa;EACb,KAAK;EACN,CACF;CAGqF,CAAC;;AAGzF,MAAa,sCAAyD;CACpE,MAAM,MAAM,oBACT,KAAK,OAAO,GAAG,YAAY,CAC3B,QAAQ,OAAqB,OAAO,OAAO,SAAS;CACvD,OAAO,CAAC,GAAG,IAAI,IAAI,IAAI,CAAC,CAAC,MAAM;IAC7B;AAEJ,MAAM,8BAAmF;CACvF,MAAM;CACN,IAAI;CACJ,cAAc;CACd,YAAY;CACZ,OAAO;EAAE,MAAM,EAAE;EAAE,SAAS,EAAE;EAAE,gBAAgB;EAAS;CACzD,QAAQ,EAAE;CACV,oBAAoB;CACpB,WAAW;CACZ;;;;;;;AAQD,MAAa,4BAA8C;CACzD,SAAS;CACT,UAAU;EACR,GAAG;EACH,eAAe,qBAAqB,6BAA6B,oBAAoB;EACtF;CACD,KAAK;CACN;;;;;;;;AASD,MAAa,kBAAwC;CACnD,MAAM;CACN,YAAY;CACb;;;AC1FD,MAAM,oBAAoB;AAE1B,SAAS,yBAAyB,YAAgE;CAChG,MAAM,SAAS,aAAa;CAC5B,IAAI,OAAO,WAAW,YAAY,CAAC,OAAO,UAAU,OAAO,IAAI,UAAU,GACvE,OAAO;CAIT,OAAO,IAAI,IADY,IAAI,MAAM,OAAO,CAAC,KAAK,IAAI,CAAC,KAAK,IAAI,CAAC,GACvC;;AAGxB,MAAM,0BAA6C;CACjD,mBAAmB,EAAE,YAAY,iBAAiB;EAChD,MAAM,SAAS,aAAa;EAC5B,IAAI,OAAO,WAAW,YAAY,OAAO,UAAU,OAAO,IAAI,SAAS,GACrE,OAAO,GAAG,WAAW,GAAG,OAAO;EAEjC,OAAO;;CAET,uBAAuB,EAAE,iBAAiB,yBAAyB,WAAW;CAC/E;AAED,MAAM,wBAA6D;CACjE,cAAc;CACd,YAAY,CAAC,0BAA0B;CACvC,SAAS;CACV;AAED,MAAM,8BAAyE;CAC7E,GAAG;CACH,IAAI;CACJ,eAAe;CACf,OAAO;EACL,GAAG,iBAAiB;EACpB,YAAY;GACV,GAAG,iBAAiB,MAAM;GAC1B,mBAAmB,GAChB,oBAAoB,yBACtB;GACF;EACF;CACD,uBAAuB,yBAAyB;CAChD,eAAe;EACb,UAAU;EACV,UAAU;EACX;CACF"}
1
+ {"version":3,"file":"control.mjs","names":["baselineMetadata","baselineOps"],"sources":["../migrations/20260601T0000_install_vector_extension/migration.json","../migrations/20260601T0000_install_vector_extension/ops.json","../migrations/refs/head.json","../src/contract.json","../src/core/contract-space-constants.ts","../src/exports/control.ts"],"sourcesContent":["","","","","/**\n * Static names and identifiers used across pgvector's contract space.\n *\n * Centralised here so the contract IR (`./contract`), the baseline\n * migration ops (`./migrations`), the head ref, and the descriptor\n * (`../exports/control`) all reference the same values without typos.\n *\n * The space identifier `'pgvector'` is what the framework writes to\n * `migrations/` in the user's repo and what the marker table's\n * `space` column carries for pgvector-owned rows.\n *\n * The `pgvector:*` invariantId namespace is locked here — once\n * published, an invariantId is immutable so downstream consumers can\n * reference it by literal string match.\n */\n\nexport const PGVECTOR_SPACE_ID = 'pgvector' as const;\n\nexport const PGVECTOR_NATIVE_TYPE = 'vector' as const;\n\nexport const PGVECTOR_BASELINE_MIGRATION_NAME = '20260601T0000_install_vector_extension' as const;\n\n/**\n * `pgvector:*` invariantIds emitted by the baseline migration. Each id,\n * once published, is immutable: downstream consumers (other extensions,\n * the marker table) reference them by literal string match.\n */\nexport const PGVECTOR_INVARIANTS = {\n installVector: 'pgvector:install-vector-v1',\n} as const;\n","/**\n * Control-plane descriptor for the pgvector extension.\n *\n * **Contract-space package layout.** The extension's contract\n * + migrations are emitted by the same pipeline application authors use:\n *\n * `prisma-next contract emit` → `<package>/src/contract.{json,d.ts}`\n * `prisma-next migration plan` → `<package>/migrations/<dir>/...`\n *\n * The descriptor wires those JSON artefacts via JSON-import declarations\n * so they flow through the consuming application's module resolver\n * without filesystem assumptions, and synthesises the canonical\n * {@link import('@prisma-next/framework-components/control').MigrationPackage}\n * shape for the framework's runner / verifier to consume. Readers in\n * `@prisma-next/migration-tools` add `dirPath` when loading from disk\n * (`OnDiskMigrationPackage`); descriptor-bundled packages do not need\n * it because the framework reads them directly from the descriptor.\n *\n * Wired surfaces:\n *\n * - `contractSpace.{contractJson,migrations,headRef}` — sourced from\n * the on-disk artefacts emitted by `build:contract-space`.\n * - `types.codecTypes.controlPlaneHooks[PGVECTOR_CODEC_ID]` — codec\n * control hooks (`expandNativeType`, `resolveIdentityValue`) the\n * SQL planner extracts via `extractCodecControlHooks` and uses to\n * render `vector(N)` column types and the canonical zero-vector\n * identity literal.\n *\n * @see docs/architecture docs/adrs/ADR 212 - Contract spaces.md\n * (contract-space package layout convention).\n */\n\nimport type { Contract } from '@prisma-next/contract/types';\nimport type {\n CodecControlHooks,\n SqlControlExtensionDescriptor,\n} from '@prisma-next/family-sql/control';\nimport { contractSpaceFromJson } from '@prisma-next/migration-tools/spaces';\nimport type { SqlStorage } from '@prisma-next/sql-contract/types';\nimport baselineMetadata from '../../migrations/20260601T0000_install_vector_extension/migration.json' with {\n type: 'json',\n};\nimport baselineOps from '../../migrations/20260601T0000_install_vector_extension/ops.json' with {\n type: 'json',\n};\nimport headRef from '../../migrations/refs/head.json' with { type: 'json' };\nimport contractJson from '../contract.json' with { type: 'json' };\nimport { PGVECTOR_SPACE_ID } from '../core/contract-space-constants';\nimport { pgvectorPackMeta, pgvectorQueryOperations } from '../core/descriptor-meta';\n\nconst PGVECTOR_CODEC_ID = 'pg/vector@1' as const;\nconst BASELINE_DIR_NAME = '20260601T0000_install_vector_extension';\n\nfunction buildVectorIdentityValue(typeParams: Record<string, unknown> | undefined): string | null {\n const length = typeParams?.['length'];\n if (typeof length !== 'number' || !Number.isInteger(length) || length <= 0) {\n return null;\n }\n\n const zeroVector = `[${new Array(length).fill('0').join(',')}]`;\n return `'${zeroVector}'::vector`;\n}\n\nconst vectorControlPlaneHooks: CodecControlHooks = {\n expandNativeType: ({ nativeType, typeParams }) => {\n const length = typeParams?.['length'];\n if (typeof length === 'number' && Number.isInteger(length) && length > 0) {\n return `${nativeType}(${length})`;\n }\n return nativeType;\n },\n resolveIdentityValue: ({ typeParams }) => buildVectorIdentityValue(typeParams),\n};\n\nconst pgvectorContractSpace = contractSpaceFromJson<Contract<SqlStorage>>({\n contractJson,\n migrations: [\n {\n dirName: BASELINE_DIR_NAME,\n metadata: baselineMetadata,\n ops: baselineOps,\n },\n ],\n headRef,\n});\n\nconst pgvectorExtensionDescriptor: SqlControlExtensionDescriptor<'postgres'> = {\n ...pgvectorPackMeta,\n id: PGVECTOR_SPACE_ID,\n contractSpace: pgvectorContractSpace,\n types: {\n ...pgvectorPackMeta.types,\n codecTypes: {\n ...pgvectorPackMeta.types.codecTypes,\n controlPlaneHooks: {\n [PGVECTOR_CODEC_ID]: vectorControlPlaneHooks,\n },\n },\n },\n queryOperations: () => pgvectorQueryOperations(),\n create: () => ({\n familyId: 'sql' as const,\n targetId: 'postgres' as const,\n }),\n};\n\nexport { pgvectorExtensionDescriptor };\nexport default pgvectorExtensionDescriptor;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AIgBA,MAAa,oBAAoB;;;ACkCjC,MAAM,oBAAoB;AAC1B,MAAM,oBAAoB;AAE1B,SAAS,yBAAyB,YAAgE;CAChG,MAAM,SAAS,aAAa;CAC5B,IAAI,OAAO,WAAW,YAAY,CAAC,OAAO,UAAU,OAAO,IAAI,UAAU,GACvE,OAAO;CAIT,OAAO,IAAI,IADY,IAAI,MAAM,OAAO,CAAC,KAAK,IAAI,CAAC,KAAK,IAAI,CAAC,GACvC;;AAGxB,MAAM,0BAA6C;CACjD,mBAAmB,EAAE,YAAY,iBAAiB;EAChD,MAAM,SAAS,aAAa;EAC5B,IAAI,OAAO,WAAW,YAAY,OAAO,UAAU,OAAO,IAAI,SAAS,GACrE,OAAO,GAAG,WAAW,GAAG,OAAO;EAEjC,OAAO;;CAET,uBAAuB,EAAE,iBAAiB,yBAAyB,WAAW;CAC/E;AAED,MAAM,wBAAwB,sBAA4C;CACxE,cAAA;CACA,YAAY,CACV;EACE,SAAS;EACT,UAAUA;EACV,KAAKC;EACN,CACF;CACD,SAAA;CACD,CAAC;AAEF,MAAM,8BAAyE;CAC7E,GAAG;CACH,IAAI;CACJ,eAAe;CACf,OAAO;EACL,GAAG,iBAAiB;EACpB,YAAY;GACV,GAAG,iBAAiB,MAAM;GAC1B,mBAAmB,GAChB,oBAAoB,yBACtB;GACF;EACF;CACD,uBAAuB,yBAAyB;CAChD,eAAe;EACb,UAAU;EACV,UAAU;EACX;CACF"}
package/dist/pack.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { t as CodecTypes } from "./codec-types-yMSpEJJM.mjs";
1
+ import { t as CodecTypes } from "./codec-types-CQubO6uQ.mjs";
2
2
  import * as _$_prisma_next_framework_components_codec0 from "@prisma-next/framework-components/codec";
3
3
 
4
4
  //#region src/core/descriptor-meta.d.ts
package/package.json CHANGED
@@ -1,33 +1,44 @@
1
1
  {
2
2
  "name": "@prisma-next/extension-pgvector",
3
- "version": "0.5.0",
3
+ "version": "0.6.0-dev.3",
4
4
  "license": "Apache-2.0",
5
5
  "type": "module",
6
6
  "sideEffects": false,
7
7
  "dependencies": {
8
8
  "@standard-schema/spec": "^1.1.0",
9
9
  "arktype": "^2.1.29",
10
- "@prisma-next/contract": "0.5.0",
11
- "@prisma-next/family-sql": "0.5.0",
12
- "@prisma-next/framework-components": "0.5.0",
13
- "@prisma-next/migration-tools": "0.5.0",
14
- "@prisma-next/sql-contract": "0.5.0",
15
- "@prisma-next/sql-operations": "0.5.0",
16
- "@prisma-next/sql-relational-core": "0.5.0",
17
- "@prisma-next/sql-runtime": "0.5.0",
18
- "@prisma-next/contract-authoring": "0.5.0",
19
- "@prisma-next/sql-schema-ir": "0.5.0"
10
+ "@prisma-next/contract": "0.6.0-dev.3",
11
+ "@prisma-next/family-sql": "0.6.0-dev.3",
12
+ "@prisma-next/contract-authoring": "0.6.0-dev.3",
13
+ "@prisma-next/framework-components": "0.6.0-dev.3",
14
+ "@prisma-next/migration-tools": "0.6.0-dev.3",
15
+ "@prisma-next/sql-contract": "0.6.0-dev.3",
16
+ "@prisma-next/sql-operations": "0.6.0-dev.3",
17
+ "@prisma-next/sql-runtime": "0.6.0-dev.3",
18
+ "@prisma-next/sql-schema-ir": "0.6.0-dev.3",
19
+ "@prisma-next/sql-relational-core": "0.6.0-dev.3"
20
20
  },
21
21
  "devDependencies": {
22
22
  "tsdown": "0.22.0",
23
23
  "typescript": "5.9.3",
24
24
  "vitest": "4.1.5",
25
- "@prisma-next/operations": "0.5.0",
26
- "@prisma-next/sql-contract-ts": "0.5.0",
25
+ "@prisma-next/adapter-postgres": "0.6.0-dev.3",
26
+ "@prisma-next/operations": "0.6.0-dev.3",
27
+ "@prisma-next/cli": "0.6.0-dev.3",
28
+ "@prisma-next/sql-contract-ts": "0.6.0-dev.3",
29
+ "@prisma-next/target-postgres": "0.6.0-dev.3",
27
30
  "@prisma-next/test-utils": "0.0.1",
28
31
  "@prisma-next/tsconfig": "0.0.0",
29
32
  "@prisma-next/tsdown": "0.0.0"
30
33
  },
34
+ "peerDependencies": {
35
+ "@prisma-next/adapter-postgres": "0.6.0-dev.3"
36
+ },
37
+ "peerDependenciesMeta": {
38
+ "@prisma-next/adapter-postgres": {
39
+ "optional": true
40
+ }
41
+ },
31
42
  "files": [
32
43
  "dist",
33
44
  "src"
@@ -47,6 +58,7 @@
47
58
  "directory": "packages/3-extensions/pgvector"
48
59
  },
49
60
  "scripts": {
61
+ "build:contract-space": "prisma-next contract emit",
50
62
  "build": "tsdown",
51
63
  "test": "vitest run",
52
64
  "test:coverage": "vitest run --coverage",
@@ -0,0 +1,91 @@
1
+ // ⚠️ GENERATED FILE - DO NOT EDIT
2
+ // This file is automatically generated by 'prisma-next contract emit'.
3
+ // To regenerate, run: prisma-next contract emit
4
+ import type { CodecTypes as PgTypes } from '@prisma-next/target-postgres/codec-types';
5
+ import type { JsonValue } from '@prisma-next/target-postgres/codec-types';
6
+ import type { Char } from '@prisma-next/target-postgres/codec-types';
7
+ import type { Varchar } from '@prisma-next/target-postgres/codec-types';
8
+ import type { Numeric } from '@prisma-next/target-postgres/codec-types';
9
+ import type { Bit } from '@prisma-next/target-postgres/codec-types';
10
+ import type { VarBit } from '@prisma-next/target-postgres/codec-types';
11
+ import type { Timestamp } from '@prisma-next/target-postgres/codec-types';
12
+ import type { Timestamptz } from '@prisma-next/target-postgres/codec-types';
13
+ import type { Time } from '@prisma-next/target-postgres/codec-types';
14
+ import type { Timetz } from '@prisma-next/target-postgres/codec-types';
15
+ import type { Interval } from '@prisma-next/target-postgres/codec-types';
16
+ import type { QueryOperationTypes as PgAdapterQueryOps } from '@prisma-next/adapter-postgres/operation-types';
17
+
18
+ import type {
19
+ ContractWithTypeMaps,
20
+ TypeMaps as TypeMapsType,
21
+ } from '@prisma-next/sql-contract/types';
22
+ import type {
23
+ Contract as ContractType,
24
+ ExecutionHashBase,
25
+ ProfileHashBase,
26
+ StorageHashBase,
27
+ } from '@prisma-next/contract/types';
28
+
29
+ export type StorageHash =
30
+ StorageHashBase<'sha256:382dae5bb1548e62cbc449530ea08a9ce0a0dbb280401e9588642223f33783ae'>;
31
+ export type ExecutionHash = ExecutionHashBase<string>;
32
+ export type ProfileHash =
33
+ ProfileHashBase<'sha256:1a8dbe044289f30a1de958fe800cc5a8378b285d2e126a8c44b58864bac2c18e'>;
34
+
35
+ export type CodecTypes = PgTypes;
36
+ export type LaneCodecTypes = CodecTypes;
37
+ export type QueryOperationTypes = PgAdapterQueryOps<CodecTypes>;
38
+ type DefaultLiteralValue<CodecId extends string, _Encoded> = CodecId extends keyof CodecTypes
39
+ ? CodecTypes[CodecId]['output']
40
+ : _Encoded;
41
+
42
+ export type FieldOutputTypes = Record<string, never>;
43
+ export type FieldInputTypes = Record<string, never>;
44
+ export type TypeMaps = TypeMapsType<
45
+ CodecTypes,
46
+ QueryOperationTypes,
47
+ FieldOutputTypes,
48
+ FieldInputTypes
49
+ >;
50
+
51
+ type ContractBase = ContractType<
52
+ {
53
+ readonly tables: {};
54
+ readonly types: {
55
+ readonly vector: {
56
+ readonly codecId: 'pg/vector@1';
57
+ readonly nativeType: 'vector';
58
+ readonly typeParams: Record<string, never>;
59
+ };
60
+ };
61
+ readonly storageHash: StorageHash;
62
+ },
63
+ Record<string, never>
64
+ > & {
65
+ readonly target: 'postgres';
66
+ readonly targetFamily: 'sql';
67
+ readonly roots: Record<string, string>;
68
+ readonly capabilities: {
69
+ readonly postgres: {
70
+ readonly jsonAgg: true;
71
+ readonly lateral: true;
72
+ readonly limit: true;
73
+ readonly orderBy: true;
74
+ readonly returning: true;
75
+ };
76
+ readonly sql: {
77
+ readonly defaultInInsert: true;
78
+ readonly enums: true;
79
+ readonly returning: true;
80
+ };
81
+ };
82
+ readonly extensionPacks: {};
83
+ readonly meta: {};
84
+
85
+ readonly profileHash: ProfileHash;
86
+ };
87
+
88
+ export type Contract = ContractWithTypeMaps<ContractBase, TypeMaps>;
89
+
90
+ export type Tables = Contract['storage']['tables'];
91
+ export type Models = Contract['models'];
@@ -0,0 +1,40 @@
1
+ {
2
+ "schemaVersion": "1",
3
+ "targetFamily": "sql",
4
+ "target": "postgres",
5
+ "profileHash": "sha256:1a8dbe044289f30a1de958fe800cc5a8378b285d2e126a8c44b58864bac2c18e",
6
+ "roots": {},
7
+ "models": {},
8
+ "storage": {
9
+ "storageHash": "sha256:382dae5bb1548e62cbc449530ea08a9ce0a0dbb280401e9588642223f33783ae",
10
+ "tables": {},
11
+ "types": {
12
+ "vector": {
13
+ "codecId": "pg/vector@1",
14
+ "nativeType": "vector",
15
+ "typeParams": {}
16
+ }
17
+ }
18
+ },
19
+ "capabilities": {
20
+ "postgres": {
21
+ "jsonAgg": true,
22
+ "lateral": true,
23
+ "limit": true,
24
+ "orderBy": true,
25
+ "returning": true
26
+ },
27
+ "sql": {
28
+ "defaultInInsert": true,
29
+ "enums": true,
30
+ "returning": true
31
+ }
32
+ },
33
+ "extensionPacks": {},
34
+ "meta": {},
35
+ "_generated": {
36
+ "warning": "⚠️ GENERATED FILE - DO NOT EDIT",
37
+ "message": "This file is automatically generated by \"prisma-next contract emit\".",
38
+ "regenerate": "To regenerate, run: prisma-next contract emit"
39
+ }
40
+ }
@@ -0,0 +1,67 @@
1
+ /**
2
+ * TS contract source for the `extension-pgvector` package.
3
+ *
4
+ * Authored against the contract-space package layout convention. The
5
+ * same emit pipeline application authors use is applied here:
6
+ *
7
+ * `prisma-next contract emit` → `<package>/src/contract.{json,d.ts}`
8
+ * `prisma-next migration plan` → `<package>/migrations/<dirName>/`
9
+ *
10
+ * The descriptor at `src/exports/control.ts` then wires the emitted
11
+ * JSON artefacts via JSON-import declarations.
12
+ *
13
+ * ## IR coverage
14
+ *
15
+ * pgvector ships **no tables** of its own. The single object the
16
+ * extension contributes to the contract IR is the parameterised native
17
+ * type `vector(N)`, registered under `storage.types`. Per-column
18
+ * instances on the user's side carry concrete `typeParams.length`
19
+ * (e.g. `vector(1536)`); the registration here declares the
20
+ * parameterised shape so the verifier sees `vector` as part of
21
+ * pgvector's space contribution and so the pinned `contract.json` on
22
+ * disk is materially distinct from an empty space.
23
+ *
24
+ * Unlike CipherStash's deferred typed objects (composite types /
25
+ * domains / enums — IR vocabulary deferral, see
26
+ * `packages/3-extensions/cipherstash/src/contract.prisma`),
27
+ * pgvector's `vector` IS representable in today's IR via
28
+ * {@link StorageTypeInstance}.
29
+ *
30
+ * ## Why TS, not PSL
31
+ *
32
+ * The contract-space package layout convention prefers PSL
33
+ * (`src/contract.prisma`). pgvector is the narrow exception called out
34
+ * in the convention: PSL's `types {}` block instantiates parameterised
35
+ * types at app authoring time (`Vector1536 = pgvector.Vector(1536)`)
36
+ * but has no surface for an extension to register the parameterised
37
+ * BASE type itself (the `storage.types.vector` entry with empty
38
+ * `typeParams` shown below). Until PSL grows that surface, this
39
+ * extension keeps its contract source in TS.
40
+ *
41
+ * @see docs/architecture docs/adrs/ADR 212 - Contract spaces.md
42
+ */
43
+
44
+ import sqlFamily from '@prisma-next/family-sql/pack';
45
+ import { defineContract } from '@prisma-next/sql-contract-ts/contract-builder';
46
+ import postgresPack from '@prisma-next/target-postgres/pack';
47
+ import { VECTOR_CODEC_ID } from './core/constants';
48
+ import { PGVECTOR_NATIVE_TYPE } from './core/contract-space-constants';
49
+
50
+ export const contract = defineContract(
51
+ {
52
+ family: sqlFamily,
53
+ target: postgresPack,
54
+ },
55
+ () => ({
56
+ types: {
57
+ [PGVECTOR_NATIVE_TYPE]: {
58
+ codecId: VECTOR_CODEC_ID,
59
+ nativeType: PGVECTOR_NATIVE_TYPE,
60
+ typeParams: {},
61
+ },
62
+ },
63
+ models: {},
64
+ }),
65
+ );
66
+
67
+ export default contract;
@@ -6,7 +6,7 @@
6
6
  * (`../exports/control`) all reference the same values without typos.
7
7
  *
8
8
  * The space identifier `'pgvector'` is what the framework writes to
9
- * `migrations/pgvector/` in the user's repo and what the marker table's
9
+ * `migrations/` in the user's repo and what the marker table's
10
10
  * `space` column carries for pgvector-owned rows.
11
11
  *
12
12
  * The `pgvector:*` invariantId namespace is locked here — once
@@ -1,23 +1,33 @@
1
1
  /**
2
2
  * Control-plane descriptor for the pgvector extension.
3
3
  *
4
- * Exposes a `contractSpace` so the framework's per-space planner /
5
- * runner / verifier (project: extension-contract-spaces, M1+M2)
6
- * manages the pgvector extension's database scaffolding the same way
7
- * it manages an application's own schema. The descriptor is consumed
8
- * by the framework only at authoring time (`migrate`); apply / verify
9
- * paths read the user's repo (`migrations/pgvector/...`) instead — see
10
- * project spec NFR3 / FR2 / FR10.
4
+ * **Contract-space package layout.** The extension's contract
5
+ * + migrations are emitted by the same pipeline application authors use:
11
6
  *
12
- * `databaseDependencies` is intentionally absent — pgvector was
13
- * migrated off the legacy `databaseDependencies.init` mechanism in M4
14
- * (project spec FR13). The `CREATE EXTENSION IF NOT EXISTS vector`
15
- * DDL the legacy entry carried now lives as the body of the
16
- * `installVectorExtension` op inside the baseline migration package
17
- * (`../core/migrations.ts`). Presence of `contractSpace` is the
18
- * shipping-strategy gate: the framework loads the contract space and
19
- * ignores any `databaseDependencies` block (project plan §
20
- * "Shipping Strategy"). M5 removes the field at the framework level.
7
+ * `prisma-next contract emit` `<package>/src/contract.{json,d.ts}`
8
+ * `prisma-next migration plan` `<package>/migrations/<dir>/...`
9
+ *
10
+ * The descriptor wires those JSON artefacts via JSON-import declarations
11
+ * so they flow through the consuming application's module resolver
12
+ * without filesystem assumptions, and synthesises the canonical
13
+ * {@link import('@prisma-next/framework-components/control').MigrationPackage}
14
+ * shape for the framework's runner / verifier to consume. Readers in
15
+ * `@prisma-next/migration-tools` add `dirPath` when loading from disk
16
+ * (`OnDiskMigrationPackage`); descriptor-bundled packages do not need
17
+ * it because the framework reads them directly from the descriptor.
18
+ *
19
+ * Wired surfaces:
20
+ *
21
+ * - `contractSpace.{contractJson,migrations,headRef}` — sourced from
22
+ * the on-disk artefacts emitted by `build:contract-space`.
23
+ * - `types.codecTypes.controlPlaneHooks[PGVECTOR_CODEC_ID]` — codec
24
+ * control hooks (`expandNativeType`, `resolveIdentityValue`) the
25
+ * SQL planner extracts via `extractCodecControlHooks` and uses to
26
+ * render `vector(N)` column types and the canonical zero-vector
27
+ * identity literal.
28
+ *
29
+ * @see docs/architecture docs/adrs/ADR 212 - Contract spaces.md
30
+ * (contract-space package layout convention).
21
31
  */
22
32
 
23
33
  import type { Contract } from '@prisma-next/contract/types';
@@ -25,14 +35,21 @@ import type {
25
35
  CodecControlHooks,
26
36
  SqlControlExtensionDescriptor,
27
37
  } from '@prisma-next/family-sql/control';
28
- import type { ContractSpace } from '@prisma-next/framework-components/control';
38
+ import { contractSpaceFromJson } from '@prisma-next/migration-tools/spaces';
29
39
  import type { SqlStorage } from '@prisma-next/sql-contract/types';
30
- import { pgvectorContract } from '../core/contract';
40
+ import baselineMetadata from '../../migrations/20260601T0000_install_vector_extension/migration.json' with {
41
+ type: 'json',
42
+ };
43
+ import baselineOps from '../../migrations/20260601T0000_install_vector_extension/ops.json' with {
44
+ type: 'json',
45
+ };
46
+ import headRef from '../../migrations/refs/head.json' with { type: 'json' };
47
+ import contractJson from '../contract.json' with { type: 'json' };
31
48
  import { PGVECTOR_SPACE_ID } from '../core/contract-space-constants';
32
49
  import { pgvectorPackMeta, pgvectorQueryOperations } from '../core/descriptor-meta';
33
- import { pgvectorBaselineMigration, pgvectorHeadRef } from '../core/migrations';
34
50
 
35
51
  const PGVECTOR_CODEC_ID = 'pg/vector@1' as const;
52
+ const BASELINE_DIR_NAME = '20260601T0000_install_vector_extension';
36
53
 
37
54
  function buildVectorIdentityValue(typeParams: Record<string, unknown> | undefined): string | null {
38
55
  const length = typeParams?.['length'];
@@ -55,11 +72,17 @@ const vectorControlPlaneHooks: CodecControlHooks = {
55
72
  resolveIdentityValue: ({ typeParams }) => buildVectorIdentityValue(typeParams),
56
73
  };
57
74
 
58
- const pgvectorContractSpace: ContractSpace<Contract<SqlStorage>> = {
59
- contractJson: pgvectorContract,
60
- migrations: [pgvectorBaselineMigration],
61
- headRef: pgvectorHeadRef,
62
- };
75
+ const pgvectorContractSpace = contractSpaceFromJson<Contract<SqlStorage>>({
76
+ contractJson,
77
+ migrations: [
78
+ {
79
+ dirName: BASELINE_DIR_NAME,
80
+ metadata: baselineMetadata,
81
+ ops: baselineOps,
82
+ },
83
+ ],
84
+ headRef,
85
+ });
63
86
 
64
87
  const pgvectorExtensionDescriptor: SqlControlExtensionDescriptor<'postgres'> = {
65
88
  ...pgvectorPackMeta,
@@ -1,74 +0,0 @@
1
- /**
2
- * pgvector contract space — declares the parameterised native type
3
- * `vector(N)` that user columns can name as `nativeType`.
4
- *
5
- * Unlike CipherStash's typed objects (composite types / domains / enums
6
- * — deferred behind `meta.cipherstashFutureIR` until the IR vocabulary
7
- * gains first-class support), pgvector's `vector` is a parameterised
8
- * native type and *is* representable in today's IR via
9
- * {@link StorageTypeInstance}: `{ codecId, nativeType, typeParams }`.
10
- * The contract registers a representative instance under
11
- * `storage.types.vector` so the verifier sees the type as part of
12
- * pgvector's space contribution and so the pinned `contract.json` on
13
- * disk is materially distinct from an empty space.
14
- *
15
- * Per-column instances on the user's side carry concrete
16
- * `typeParams.length` (e.g. `vector(1536)`); the registration here
17
- * declares the parameterised shape — it is not consumed as a literal
18
- * column type by any user table.
19
- */
20
-
21
- import { computeStorageHash } from '@prisma-next/contract/hashing';
22
- import { type Contract, coreHash, profileHash } from '@prisma-next/contract/types';
23
- import type { SqlStorage } from '@prisma-next/sql-contract/types';
24
- import { VECTOR_CODEC_ID } from './constants';
25
- import { PGVECTOR_NATIVE_TYPE } from './contract-space-constants';
26
-
27
- const TARGET = 'postgres' as const;
28
- const TARGET_FAMILY = 'sql' as const;
29
-
30
- /**
31
- * Storage body for the contract — pgvector ships no tables of its own;
32
- * the `vector` parameterised native type is registered under
33
- * `storage.types` so pgvector's IR contribution is non-empty and the
34
- * pinned `contract.json` on disk differs materially from an empty
35
- * extension space.
36
- *
37
- * Authored without `storageHash` here so {@link computeStorageHash} can
38
- * digest the canonical body (the hashing pipeline panics if asked to
39
- * hash an object that already carries its own output — see
40
- * `assertDescriptorSelfConsistency`'s storage-hash strip).
41
- */
42
- const storageBody = {
43
- tables: {},
44
- types: {
45
- [PGVECTOR_NATIVE_TYPE]: {
46
- codecId: VECTOR_CODEC_ID,
47
- nativeType: PGVECTOR_NATIVE_TYPE,
48
- typeParams: {},
49
- },
50
- },
51
- };
52
-
53
- /** Content-addressed hash of pgvector's storage IR. */
54
- export const PGVECTOR_STORAGE_HASH = computeStorageHash({
55
- target: TARGET,
56
- targetFamily: TARGET_FAMILY,
57
- storage: storageBody,
58
- });
59
-
60
- /** pgvector's contract value, exposed via the descriptor's `contractSpace.contractJson`. */
61
- export const pgvectorContract: Contract<SqlStorage> = {
62
- target: TARGET,
63
- targetFamily: TARGET_FAMILY,
64
- roots: {},
65
- models: {},
66
- capabilities: {},
67
- extensionPacks: {},
68
- meta: {},
69
- profileHash: profileHash('pgvector-extension-profile-v1'),
70
- storage: {
71
- ...storageBody,
72
- storageHash: coreHash(PGVECTOR_STORAGE_HASH),
73
- },
74
- };
@@ -1,125 +0,0 @@
1
- /**
2
- * pgvector contract space — baseline migration package.
3
- *
4
- * An extension's `contractSpace.migrations` is a list of in-memory
5
- * `MigrationPackage` values whose `ops` carry framework-level
6
- * `MigrationPlanOperation`s. The SQL family runner reads the additional
7
- * runtime fields (`target`, `precheck`, `execute`, `postcheck`) at
8
- * apply time.
9
- *
10
- * Ships a single baseline migration whose only op is
11
- * {@link installVectorExtensionOp} — it carries the
12
- * `CREATE EXTENSION IF NOT EXISTS vector` DDL plus a postcondition that
13
- * confirms the extension landed. Mirrors the prior
14
- * `databaseDependencies.init[0]` shape (precheck / execute / postcheck)
15
- * but as a `MigrationPackage` op so the framework's per-space runner /
16
- * verifier can manage it the same way it manages an application's own
17
- * migrations.
18
- *
19
- * The op carries the stable `pgvector:install-vector-v1` invariantId —
20
- * once published it is immutable.
21
- */
22
-
23
- import type { SqlMigrationPlanOperation } from '@prisma-next/family-sql/control';
24
- import type {
25
- ContractSpaceHeadRef,
26
- MigrationPackage,
27
- MigrationPlanOperation,
28
- } from '@prisma-next/framework-components/control';
29
- import { computeMigrationHash } from '@prisma-next/migration-tools/hash';
30
- import { PGVECTOR_STORAGE_HASH, pgvectorContract } from './contract';
31
- import { PGVECTOR_BASELINE_MIGRATION_NAME, PGVECTOR_INVARIANTS } from './contract-space-constants';
32
-
33
- /**
34
- * Postgres-style `target.details` shape the SQL runner consumes when
35
- * executing extension-space ops. pgvector targets only Postgres;
36
- * locking the target id here keeps the per-op `target` literal narrow
37
- * without coupling to the Postgres adapter package's
38
- * `PostgresPlanTargetDetails`.
39
- */
40
- type PostgresTargetDetails = {
41
- readonly schema: string;
42
- readonly objectType: 'extension';
43
- readonly name: string;
44
- };
45
-
46
- const installVectorExtensionOp: SqlMigrationPlanOperation<unknown> = {
47
- id: 'pgvector.install-vector-extension',
48
- label: 'Enable extension "vector"',
49
- operationClass: 'additive',
50
- invariantId: PGVECTOR_INVARIANTS.installVector,
51
- target: {
52
- id: 'postgres',
53
- details: {
54
- schema: 'public',
55
- objectType: 'extension',
56
- name: 'vector',
57
- } satisfies PostgresTargetDetails,
58
- },
59
- precheck: [
60
- {
61
- description: 'verify extension "vector" is not already enabled',
62
- sql: "SELECT NOT EXISTS (SELECT 1 FROM pg_extension WHERE extname = 'vector')",
63
- },
64
- ],
65
- execute: [
66
- {
67
- description: 'create extension "vector"',
68
- sql: 'CREATE EXTENSION IF NOT EXISTS vector',
69
- },
70
- ],
71
- postcheck: [
72
- {
73
- description: 'confirm extension "vector" is enabled',
74
- sql: "SELECT EXISTS (SELECT 1 FROM pg_extension WHERE extname = 'vector')",
75
- },
76
- ],
77
- };
78
-
79
- const pgvectorBaselineOps: readonly MigrationPlanOperation[] = [installVectorExtensionOp];
80
-
81
- /** Sorted list of invariantIds the baseline migration provides. */
82
- export const PGVECTOR_BASELINE_INVARIANTS: readonly string[] = (() => {
83
- const ids = pgvectorBaselineOps
84
- .map((op) => op.invariantId)
85
- .filter((id): id is string => typeof id === 'string');
86
- return [...new Set(ids)].sort();
87
- })();
88
-
89
- const baselineMetadataWithoutHash: Omit<MigrationPackage['metadata'], 'migrationHash'> = {
90
- from: null,
91
- to: PGVECTOR_STORAGE_HASH,
92
- fromContract: null,
93
- toContract: pgvectorContract,
94
- hints: { used: [], applied: [], plannerVersion: '2.0.0' },
95
- labels: [],
96
- providedInvariants: PGVECTOR_BASELINE_INVARIANTS,
97
- createdAt: '2026-06-01T00:00:00.000Z',
98
- };
99
-
100
- /**
101
- * Baseline migration package the descriptor publishes via
102
- * `contractSpace.migrations`. The framework's emitter writes this to
103
- * `migrations/pgvector/<dirName>/{manifest,ops,contract}.json` in the
104
- * user's repo at `migrate` time.
105
- */
106
- export const pgvectorBaselineMigration: MigrationPackage = {
107
- dirName: PGVECTOR_BASELINE_MIGRATION_NAME,
108
- metadata: {
109
- ...baselineMetadataWithoutHash,
110
- migrationHash: computeMigrationHash(baselineMetadataWithoutHash, pgvectorBaselineOps),
111
- },
112
- ops: pgvectorBaselineOps,
113
- };
114
-
115
- /**
116
- * Pinned head ref the descriptor publishes. The framework writes this
117
- * verbatim to `migrations/pgvector/refs/head.json` (with `invariants`
118
- * sorted alphabetically per the canonicalisation rules); the runner's
119
- * `findPathWithDecision` step consults `head.json` to decide which
120
- * migrations need to apply.
121
- */
122
- export const pgvectorHeadRef: ContractSpaceHeadRef = {
123
- hash: PGVECTOR_STORAGE_HASH,
124
- invariants: PGVECTOR_BASELINE_INVARIANTS,
125
- };