@prisma-next/extension-cipherstash 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/README.md +153 -0
  2. package/dist/call-classes-CSvD7w8U.mjs +206 -0
  3. package/dist/call-classes-CSvD7w8U.mjs.map +1 -0
  4. package/dist/column-types.d.mts +33 -0
  5. package/dist/column-types.d.mts.map +1 -0
  6. package/dist/column-types.mjs +42 -0
  7. package/dist/column-types.mjs.map +1 -0
  8. package/dist/constants-BDxL9Pe3.d.mts +22 -0
  9. package/dist/constants-BDxL9Pe3.d.mts.map +1 -0
  10. package/dist/constants-B_2TNvUi.mjs +46 -0
  11. package/dist/constants-B_2TNvUi.mjs.map +1 -0
  12. package/dist/control.d.mts +7 -0
  13. package/dist/control.d.mts.map +1 -0
  14. package/dist/control.mjs +430 -0
  15. package/dist/control.mjs.map +1 -0
  16. package/dist/descriptor-meta-BgQfZTAF.mjs +129 -0
  17. package/dist/descriptor-meta-BgQfZTAF.mjs.map +1 -0
  18. package/dist/envelope-P9BxfJNr.mjs +271 -0
  19. package/dist/envelope-P9BxfJNr.mjs.map +1 -0
  20. package/dist/middleware.d.mts +13 -0
  21. package/dist/middleware.d.mts.map +1 -0
  22. package/dist/middleware.mjs +129 -0
  23. package/dist/middleware.mjs.map +1 -0
  24. package/dist/migration.d.mts +141 -0
  25. package/dist/migration.d.mts.map +1 -0
  26. package/dist/migration.mjs +2 -0
  27. package/dist/operation-types.d.mts +49 -0
  28. package/dist/operation-types.d.mts.map +1 -0
  29. package/dist/operation-types.mjs +1 -0
  30. package/dist/pack.d.mts +86 -0
  31. package/dist/pack.d.mts.map +1 -0
  32. package/dist/pack.mjs +2 -0
  33. package/dist/runtime.d.mts +207 -0
  34. package/dist/runtime.d.mts.map +1 -0
  35. package/dist/runtime.mjs +429 -0
  36. package/dist/runtime.mjs.map +1 -0
  37. package/dist/sdk-D5FTGyzp.d.mts +67 -0
  38. package/dist/sdk-D5FTGyzp.d.mts.map +1 -0
  39. package/package.json +69 -0
  40. package/src/contract/authoring.ts +62 -0
  41. package/src/contract/contract.d.ts +149 -0
  42. package/src/contract/contract.json +104 -0
  43. package/src/contract/contract.prisma +46 -0
  44. package/src/execution/abort.ts +143 -0
  45. package/src/execution/codec-runtime.ts +209 -0
  46. package/src/execution/decrypt-all.ts +217 -0
  47. package/src/execution/envelope.ts +263 -0
  48. package/src/execution/operators.ts +211 -0
  49. package/src/execution/parameterized.ts +71 -0
  50. package/src/execution/routing.ts +93 -0
  51. package/src/execution/sdk.ts +68 -0
  52. package/src/exports/column-types.ts +62 -0
  53. package/src/exports/contract-space-typing.ts +86 -0
  54. package/src/exports/control.ts +120 -0
  55. package/src/exports/middleware.ts +24 -0
  56. package/src/exports/migration.ts +43 -0
  57. package/src/exports/operation-types.ts +16 -0
  58. package/src/exports/pack.ts +13 -0
  59. package/src/exports/runtime.ts +110 -0
  60. package/src/extension-metadata/codec-metadata.ts +81 -0
  61. package/src/extension-metadata/constants.ts +70 -0
  62. package/src/extension-metadata/descriptor-meta.ts +76 -0
  63. package/src/middleware/bulk-encrypt.ts +192 -0
  64. package/src/migration/call-classes.ts +350 -0
  65. package/src/migration/cipherstash-codec.ts +157 -0
  66. package/src/migration/eql-bundle.ts +29 -0
  67. package/src/migration/eql-install.generated.ts +5751 -0
  68. package/src/types/operation-types.ts +81 -0
@@ -0,0 +1,120 @@
1
+ /**
2
+ * Control-plane descriptor for the CipherStash extension.
3
+ *
4
+ * **On-disk-in-package authoring.** The extension's contract +
5
+ * migrations are emitted by the same pipeline application authors use:
6
+ *
7
+ * `prisma-next contract emit` → `<package>/src/contract/contract.{json,d.ts}`
8
+ * `prisma-next migration plan` → `<package>/migrations/cipherstash/<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/migration-tools/package').MigrationPackage}
14
+ * shape (gaining `dirPath` from `import.meta.url`) for the framework's
15
+ * runner / verifier to consume.
16
+ *
17
+ * Wired surfaces:
18
+ *
19
+ * - `contractSpace.{contractJson,migrations,headRef}` — sourced from
20
+ * the on-disk artefacts emitted by `build:contract-space`.
21
+ * - `types.codecTypes.controlPlaneHooks[CIPHERSTASH_STRING_CODEC_ID]`
22
+ * — the lifecycle hook the SQL planner extracts via
23
+ * `extractCodecControlHooks` and inlines into the application's
24
+ * migration via `planFieldEventOperations`. Implements
25
+ * `add_search_config` / `remove_search_config` / rotate behaviour
26
+ * for `searchable: true` `Encrypted<string>` columns.
27
+ *
28
+ * @see docs/architecture docs/adrs/ADR 211 - Contract spaces.md
29
+ * (on-disk-in-package authoring convention).
30
+ * @see packages/3-extensions/test-contract-space/src/exports/control.ts
31
+ * (reference model).
32
+ */
33
+
34
+ import { fileURLToPath } from 'node:url';
35
+ import type { Contract } from '@prisma-next/contract/types';
36
+ import type { SqlControlExtensionDescriptor } from '@prisma-next/family-sql/control';
37
+ import type { ContractSpace } from '@prisma-next/framework-components/control';
38
+ import type { OnDiskMigrationPackage } from '@prisma-next/migration-tools/package';
39
+ import type { SqlStorage } from '@prisma-next/sql-contract/types';
40
+ import baselineMetadata from '../../migrations/cipherstash/20260601T0000_install_eql_bundle/migration.json' with {
41
+ type: 'json',
42
+ };
43
+ import baselineOps from '../../migrations/cipherstash/20260601T0000_install_eql_bundle/ops.json' with {
44
+ type: 'json',
45
+ };
46
+ import headRef from '../../migrations/cipherstash/refs/head.json' with { type: 'json' };
47
+ import contractJson from '../contract/contract.json' with { type: 'json' };
48
+ import {
49
+ CIPHERSTASH_BASELINE_MIGRATION_NAME,
50
+ CIPHERSTASH_SPACE_ID,
51
+ CIPHERSTASH_STRING_CODEC_ID,
52
+ } from '../extension-metadata/constants';
53
+ import { cipherstashPackMeta } from '../extension-metadata/descriptor-meta';
54
+ import { cipherstashStringCodecHooks } from '../migration/cipherstash-codec';
55
+ import {
56
+ asCipherstashContract,
57
+ asCipherstashMigrationMetadata,
58
+ asCipherstashMigrationOps,
59
+ } from './contract-space-typing';
60
+
61
+ /**
62
+ * Resolve a migration package's on-disk path from this descriptor module's
63
+ * URL. The framework's runner uses `dirPath` for diagnostic messages and
64
+ * to locate sibling files (e.g. `start-contract.json` for non-baseline
65
+ * migrations); pinning it from `import.meta.url` keeps the value correct
66
+ * regardless of where the consuming application installs the package
67
+ * (workspace, node_modules, bundled, etc.).
68
+ */
69
+ function resolveMigrationDirPath(dirName: string): string {
70
+ return fileURLToPath(
71
+ new URL(`../../migrations/${CIPHERSTASH_SPACE_ID}/${dirName}/`, import.meta.url),
72
+ );
73
+ }
74
+
75
+ const baselinePackage: OnDiskMigrationPackage = {
76
+ dirName: CIPHERSTASH_BASELINE_MIGRATION_NAME,
77
+ dirPath: resolveMigrationDirPath(CIPHERSTASH_BASELINE_MIGRATION_NAME),
78
+ metadata: asCipherstashMigrationMetadata(baselineMetadata),
79
+ ops: asCipherstashMigrationOps(baselineOps),
80
+ };
81
+
82
+ const cipherstashContractSpace: ContractSpace<Contract<SqlStorage>> = {
83
+ contractJson: asCipherstashContract(contractJson),
84
+ migrations: [baselinePackage],
85
+ headRef,
86
+ };
87
+
88
+ const cipherstashExtensionDescriptor: SqlControlExtensionDescriptor<'postgres'> = {
89
+ // Spread pack-meta first so it contributes `kind` / `id` / `familyId`
90
+ // / `targetId` / `version` / `authoring` / `types.{codecTypes,storage}`
91
+ // — then overlay the contract-space block and the codec lifecycle
92
+ // hook on top. The two `types.codecTypes` slots (`codecInstances`
93
+ // from pack-meta, `controlPlaneHooks` from this descriptor) coexist
94
+ // on the same path and are merged below.
95
+ ...cipherstashPackMeta,
96
+ contractSpace: cipherstashContractSpace,
97
+ /**
98
+ * Free-form `types.codecTypes.controlPlaneHooks` block — the SQL
99
+ * family's `extractCodecControlHooks` (in `@prisma-next/family-sql/
100
+ * control`) finds hooks via duck-typing on this exact path. Mirrors
101
+ * pgvector's wiring at `packages/3-extensions/pgvector/src/exports/
102
+ * control.ts`.
103
+ */
104
+ types: {
105
+ ...cipherstashPackMeta.types,
106
+ codecTypes: {
107
+ ...cipherstashPackMeta.types.codecTypes,
108
+ controlPlaneHooks: {
109
+ [CIPHERSTASH_STRING_CODEC_ID]: cipherstashStringCodecHooks,
110
+ },
111
+ },
112
+ },
113
+ create: () => ({
114
+ familyId: 'sql' as const,
115
+ targetId: 'postgres' as const,
116
+ }),
117
+ };
118
+
119
+ export { cipherstashExtensionDescriptor };
120
+ export default cipherstashExtensionDescriptor;
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Public middleware surface for the cipherstash extension.
3
+ *
4
+ * Consumers register the bulk-encrypt middleware in their runtime so
5
+ * `EncryptedString` envelopes embedded in `INSERT` / `UPDATE` plans get
6
+ * encrypted in batches before encode runs:
7
+ *
8
+ * ```ts
9
+ * import { createCipherstashRuntimeDescriptor } from '@prisma-next/extension-cipherstash/runtime';
10
+ * import { bulkEncryptMiddleware } from '@prisma-next/extension-cipherstash/middleware';
11
+ *
12
+ * const runtime = createRuntime({
13
+ * extensionPacks: [createCipherstashRuntimeDescriptor({ sdk })],
14
+ * middleware: [bulkEncryptMiddleware(sdk)],
15
+ * });
16
+ * ```
17
+ *
18
+ * `SqlRuntimeExtensionDescriptor` does not own a middleware slot, so
19
+ * the descriptor wrapper (`createCipherstashRuntimeDescriptor`) and
20
+ * the middleware are composed manually by callers — by convention,
21
+ * once per cipherstash SDK binding.
22
+ */
23
+
24
+ export { bulkEncryptMiddleware } from '../middleware/bulk-encrypt';
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Public migration-time entry point for the cipherstash extension.
3
+ *
4
+ * Re-exports the user-callable factory functions used in hand-written
5
+ * migrations (or auto-imported by the planner-generated `migration.ts`)
6
+ * to wire EQL search-config rows alongside structural DDL:
7
+ *
8
+ * ```ts
9
+ * import { Migration, MigrationCLI, createTable } from '@prisma-next/target-postgres/migration';
10
+ * import { cipherstashAddSearchConfig } from '@prisma-next/extension-cipherstash/migration';
11
+ *
12
+ * export default class M extends Migration {
13
+ * override get operations() {
14
+ * return [
15
+ * createTable('public', 'user', [
16
+ * { name: 'email', typeSql: 'eql_v2_encrypted', defaultSql: '', nullable: false },
17
+ * { name: 'id', typeSql: 'text', defaultSql: '', nullable: false },
18
+ * ]),
19
+ * cipherstashAddSearchConfig({ table: 'user', column: 'email', index: 'unique' }),
20
+ * ];
21
+ * }
22
+ * }
23
+ *
24
+ * MigrationCLI.run(import.meta.url, M);
25
+ * ```
26
+ *
27
+ * Identical ergonomics to `createTable` / `setNotNull` etc. from
28
+ * `@prisma-next/target-postgres/migration`. The codec lifecycle hook
29
+ * for `Encrypted<string>` columns calls these factories automatically
30
+ * when planning a contract diff.
31
+ *
32
+ * @see ADR 195 — Planner IR with two renderers.
33
+ * @see ADR 212 — Codec lifecycle hooks.
34
+ */
35
+
36
+ export type {
37
+ CipherstashSearchConfigArgs,
38
+ CipherstashSearchIndex,
39
+ } from '../migration/call-classes';
40
+ export {
41
+ cipherstashAddSearchConfig,
42
+ cipherstashRemoveSearchConfig,
43
+ } from '../migration/call-classes';
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Operation type definitions for the cipherstash extension.
3
+ *
4
+ * Re-export from the types module for the public
5
+ * `@prisma-next/extension-cipherstash/operation-types` subpath. The
6
+ * contract emitter pulls these via the `types.operationTypes` /
7
+ * `types.queryOperationTypes` import declarations on
8
+ * `cipherstashPackMeta` (see `../extension-metadata/descriptor-meta.ts`); user code
9
+ * may also import them directly when authoring TS-side type
10
+ * compositions.
11
+ *
12
+ * @see ADR 211 — Extension operator surface (namespaced replacement
13
+ * operators must project type-visibility through `QueryOperationTypes`).
14
+ */
15
+
16
+ export type { QueryOperationTypes } from '../types/operation-types';
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Pack entry point for the cipherstash extension.
3
+ *
4
+ * Re-exports the SDK-free pack metadata so TS contract authoring
5
+ * (`defineContract({ extensionPacks: { cipherstash: cipherstashPack } })`)
6
+ * can enable the `cipherstash.*` PSL/TS namespace and the storage type
7
+ * registration without pulling in any runtime code (envelope, SDK,
8
+ * codec runtime, middleware).
9
+ *
10
+ * Mirrors `packages/3-extensions/pgvector/src/exports/pack.ts`.
11
+ */
12
+
13
+ export { cipherstashPackMeta as default } from '../extension-metadata/descriptor-meta';
@@ -0,0 +1,110 @@
1
+ /**
2
+ * Runtime-plane entry point for the CipherStash extension.
3
+ *
4
+ * Consumed at query time by application runtimes that need to encode /
5
+ * decode `cipherstash/string@1` columns (envelope class) and talk to the
6
+ * CipherStash SDK shape the codec runtime + bulk-encrypt middleware
7
+ * depend on.
8
+ *
9
+ * The runtime entry point is deliberately separate from `./control`
10
+ * (descriptor, codec lifecycle hook, contract-space artefacts) so apps
11
+ * that only emit migrations against cipherstash never load the runtime,
12
+ * and apps that only run queries never load the migration-time
13
+ * descriptor — the control plane and runtime plane are tree-shakable
14
+ * along this seam.
15
+ *
16
+ * `createCipherstashRuntimeDescriptor({ sdk })` is the recommended
17
+ * composition entry — it bundles the SDK-bound codec, the parameterized
18
+ * codec descriptor, and the runtime-plane `codecInstances` slot into a
19
+ * single `SqlRuntimeExtensionDescriptor<'postgres'>` mirroring
20
+ * pgvector's `runtime.ts` precedent. The bulk-encrypt middleware ships
21
+ * separately at `@prisma-next/extension-cipherstash/middleware` because
22
+ * `SqlRuntimeExtensionDescriptor` does not own a middleware slot;
23
+ * consumers register it via `createRuntime({ middleware:
24
+ * [bulkEncryptMiddleware(sdk)] })`.
25
+ */
26
+
27
+ import type { SqlRuntimeExtensionDescriptor } from '@prisma-next/sql-runtime';
28
+ import { cipherstashQueryOperations } from '../execution/operators';
29
+ import { createParameterizedCodecDescriptors } from '../execution/parameterized';
30
+ import type { CipherstashSdk } from '../execution/sdk';
31
+ import {
32
+ CIPHERSTASH_EXTENSION_VERSION,
33
+ CIPHERSTASH_SPACE_ID,
34
+ } from '../extension-metadata/constants';
35
+
36
+ export type { CipherstashStringCodec } from '../execution/codec-runtime';
37
+ export {
38
+ CIPHERSTASH_STRING_CODEC_ID,
39
+ createCipherstashStringCodec,
40
+ } from '../execution/codec-runtime';
41
+ export type { DecryptAllOptions } from '../execution/decrypt-all';
42
+ export { decryptAll } from '../execution/decrypt-all';
43
+ export type {
44
+ EncryptedStringFromInternalArgs,
45
+ EncryptedStringHandle,
46
+ } from '../execution/envelope';
47
+ export { EncryptedString } from '../execution/envelope';
48
+ export type { CipherstashStringParams } from '../execution/parameterized';
49
+ export {
50
+ createParameterizedCodecDescriptors,
51
+ encryptedStringParamsSchema,
52
+ renderEncryptedStringOutputType,
53
+ } from '../execution/parameterized';
54
+ export type {
55
+ CipherstashBulkDecryptArgs,
56
+ CipherstashBulkEncryptArgs,
57
+ CipherstashRoutingKey,
58
+ CipherstashSdk,
59
+ CipherstashSingleDecryptArgs,
60
+ } from '../execution/sdk';
61
+
62
+ export { CIPHERSTASH_EXTENSION_VERSION };
63
+
64
+ export interface CreateCipherstashRuntimeDescriptorOptions {
65
+ readonly sdk: CipherstashSdk;
66
+ }
67
+
68
+ /**
69
+ * Compose the SDK-bound codec runtime + parameterized codec descriptors
70
+ * + runtime-plane codec-instances metadata into a single
71
+ * `SqlRuntimeExtensionDescriptor<'postgres'>`.
72
+ *
73
+ * The descriptor is per-SDK: cipherstash's codec captures the SDK at
74
+ * `decode` time (read-side single-cell `decrypt`) and the bulk-encrypt
75
+ * middleware captures it at `beforeExecute` time (write-side bulk
76
+ * round-trip). Multi-tenant deployments construct one descriptor per
77
+ * tenant SDK so per-tenant key material never crosses runtimes.
78
+ *
79
+ * Mirrors `packages/3-extensions/pgvector/src/exports/runtime.ts` —
80
+ * pgvector's vectorRuntimeDescriptor is a static default-export because
81
+ * its codec is fully stateless; cipherstash needs the factory wrapper
82
+ * because the codec depends on `sdk`.
83
+ */
84
+ export function createCipherstashRuntimeDescriptor(
85
+ opts: CreateCipherstashRuntimeDescriptorOptions,
86
+ ): SqlRuntimeExtensionDescriptor<'postgres'> {
87
+ const { sdk } = opts;
88
+ const parameterizedDescriptors = createParameterizedCodecDescriptors(sdk);
89
+
90
+ return {
91
+ kind: 'extension' as const,
92
+ id: CIPHERSTASH_SPACE_ID,
93
+ version: CIPHERSTASH_EXTENSION_VERSION,
94
+ familyId: 'sql' as const,
95
+ targetId: 'postgres' as const,
96
+ types: {
97
+ codecTypes: {
98
+ codecDescriptors: parameterizedDescriptors,
99
+ },
100
+ },
101
+ codecs: () => parameterizedDescriptors,
102
+ queryOperations: () => cipherstashQueryOperations(),
103
+ create() {
104
+ return {
105
+ familyId: 'sql' as const,
106
+ targetId: 'postgres' as const,
107
+ };
108
+ },
109
+ };
110
+ }
@@ -0,0 +1,81 @@
1
+ /**
2
+ * SDK-free codec used in pack-meta (`cipherstashPackMeta.types.codecTypes
3
+ * .codecInstances`). Pack-meta consumers only read codec *metadata*
4
+ * (`typeId`, `targetTypes`, `traits`, `renderOutputType`) at contract
5
+ * emit time — they never call `encode`/`decode`.
6
+ *
7
+ * The SDK-bound runtime codec for actual `encode`/`decode` lives in
8
+ * `../execution/codec-runtime`; it is resolved through
9
+ * `RuntimeParameterizedCodecDescriptor.factory` at runtime instead of
10
+ * through pack-meta's `codecInstances`.
11
+ *
12
+ * Keeping the SDK-free metadata in its own module — and *not* importing
13
+ * the runtime `CipherstashStringCodec` class — preserves the control
14
+ * vs runtime split. Control-plane consumers (`exports/control.ts`,
15
+ * `exports/pack.ts`) pull this file but never touch the envelope, the
16
+ * SDK interface, or the bulk-encrypt middleware. The bundling-isolation
17
+ * test pins this property by snapshotting that the control entry's
18
+ * chunk graph does not transitively load `envelope-*.mjs`.
19
+ *
20
+ * `encode`/`decode` throw with a clear hint in the misuse case so
21
+ * accidental wiring of the metadata codec into a real runtime path
22
+ * surfaces immediately instead of silently no-op'ing.
23
+ */
24
+
25
+ import type { JsonValue } from '@prisma-next/contract/types';
26
+ import { type AnyCodecDescriptor, CodecImpl } from '@prisma-next/framework-components/codec';
27
+ import { CIPHERSTASH_STRING_CODEC_ID, EQL_V2_ENCRYPTED_TYPE } from './constants';
28
+
29
+ const METADATA_DESCRIPTOR: AnyCodecDescriptor = {
30
+ codecId: CIPHERSTASH_STRING_CODEC_ID,
31
+ traits: [],
32
+ targetTypes: [EQL_V2_ENCRYPTED_TYPE],
33
+ meta: { db: { sql: { postgres: { nativeType: EQL_V2_ENCRYPTED_TYPE } } } },
34
+ paramsSchema: {
35
+ '~standard': {
36
+ version: 1,
37
+ vendor: 'cipherstash',
38
+ validate: (value: unknown) => ({ value }),
39
+ },
40
+ },
41
+ isParameterized: false,
42
+ renderOutputType: () => 'EncryptedString',
43
+ factory: () => () => {
44
+ throw new Error('cipherstash codec: metadata descriptor factory is not callable');
45
+ },
46
+ };
47
+
48
+ class CipherstashStringCodecMetadata extends CodecImpl<
49
+ typeof CIPHERSTASH_STRING_CODEC_ID,
50
+ readonly [],
51
+ unknown,
52
+ unknown
53
+ > {
54
+ async encode(): Promise<unknown> {
55
+ throw new Error(
56
+ 'cipherstash codec: encode called on the pack-meta metadata codec. ' +
57
+ 'Construct a runtime descriptor via `createCipherstashRuntimeDescriptor({ sdk })` and use that instead.',
58
+ );
59
+ }
60
+
61
+ async decode(): Promise<unknown> {
62
+ throw new Error(
63
+ 'cipherstash codec: decode called on the pack-meta metadata codec. ' +
64
+ 'Construct a runtime descriptor via `createCipherstashRuntimeDescriptor({ sdk })` and use that instead.',
65
+ );
66
+ }
67
+
68
+ encodeJson(): JsonValue {
69
+ return { $encryptedString: '<opaque>' };
70
+ }
71
+
72
+ decodeJson(): unknown {
73
+ throw new Error(
74
+ 'cipherstash codec: decodeJson is not supported; envelopes do not round-trip through JSON.',
75
+ );
76
+ }
77
+ }
78
+
79
+ export const cipherstashStringCodecMetadata = new CipherstashStringCodecMetadata(
80
+ METADATA_DESCRIPTOR,
81
+ );
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Static names and identifiers used across CipherStash's contract space.
3
+ *
4
+ * Centralising the strings here so:
5
+ * - the contract IR (`./contract`), the migration ops (`./migrations`),
6
+ * the head ref (`./head-ref`), and the descriptor (`../exports/control`)
7
+ * all reference the same values without typos;
8
+ * - the `cipherstash:*` invariantId namespace is locked in one place
9
+ * (once published, an invariantId cannot be renamed).
10
+ *
11
+ * The space identifier `'cipherstash'` is what the framework writes to
12
+ * `migrations/cipherstash/` in the user's repo and what the marker table's
13
+ * `space` column carries for CipherStash-owned rows.
14
+ */
15
+
16
+ export const CIPHERSTASH_SPACE_ID = 'cipherstash';
17
+
18
+ /**
19
+ * Version advertised by both `cipherstashPackMeta.version` (control plane)
20
+ * and the SDK-bound `SqlRuntimeExtensionDescriptor` (runtime plane).
21
+ *
22
+ * Single source of truth so the descriptor surfaces and the contract-emit
23
+ * pack metadata cannot drift apart; consumed downstream by capability
24
+ * gating and contract round-trips.
25
+ */
26
+ export const CIPHERSTASH_EXTENSION_VERSION = '0.0.1' as const;
27
+
28
+ /**
29
+ * Codec id the application-side `Encrypted<string>` lowering targets.
30
+ * Lives here so the codec lifecycle hook (which emits
31
+ * `add_search_config` / `remove_search_config` ops on field events) and
32
+ * the descriptor's `controlPlaneHooks` wiring share the same constant.
33
+ */
34
+ export const CIPHERSTASH_STRING_CODEC_ID = 'cipherstash/string@1';
35
+
36
+ /** Schema CipherStash installs its functions/operators/casts/types into. */
37
+ export const EQL_V2_SCHEMA = 'eql_v2';
38
+
39
+ /** Configuration table used by EQL's per-column index configuration. */
40
+ export const EQL_V2_CONFIGURATION_TABLE = 'eql_v2_configuration';
41
+
42
+ /** Enum type backing the `state` column on `eql_v2_configuration`. */
43
+ export const EQL_V2_CONFIGURATION_STATE_TYPE = 'eql_v2_configuration_state';
44
+
45
+ /** JSONB-domain composite type user `Encrypted<string>` columns reference. */
46
+ export const EQL_V2_ENCRYPTED_TYPE = 'eql_v2_encrypted';
47
+
48
+ /**
49
+ * Migration directory name for the baseline.
50
+ *
51
+ * Per the framework's per-space layout convention this name is
52
+ * preserved verbatim when the framework writes the package to
53
+ * `migrations/cipherstash/<this-name>/` in the user's repo.
54
+ */
55
+ export const CIPHERSTASH_BASELINE_MIGRATION_NAME = '20260601T0000_install_eql_bundle';
56
+
57
+ /**
58
+ * `cipherstash:*` invariantIds emitted by the baseline migration. Each
59
+ * `cipherstash:*` id, once published, is immutable: downstream
60
+ * consumers (other extensions, the marker table) reference them by
61
+ * literal string match.
62
+ *
63
+ * Today the baseline emits a single op (`installBundle`); the bundle
64
+ * SQL is the source of truth for every typed object it creates inside
65
+ * the `eql_v2` schema. New bundle versions or additional structural
66
+ * ops will mint new `cipherstash:*` ids alongside this entry.
67
+ */
68
+ export const CIPHERSTASH_INVARIANTS = {
69
+ installBundle: 'cipherstash:install-eql-bundle-v1',
70
+ } as const;
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Pack metadata for the cipherstash extension.
3
+ *
4
+ * Mirrors `packages/3-extensions/pgvector/src/extension-metadata/descriptor-meta.ts` —
5
+ * the metadata block that gets serialized into `contract.json`'s
6
+ * `extensionPacks.cipherstash` slot at emit time.
7
+ *
8
+ * SDK-free: the runtime descriptor layers SDK-bound codec instances on
9
+ * top at execution time. The `codecInstances` slot here uses the
10
+ * metadata-only
11
+ * codec from `./codec-metadata` because pack-meta consumers only read
12
+ * codec metadata (typeId, targetTypes, traits, renderOutputType);
13
+ * runtime encode/decode always go through the SDK-bound codec produced
14
+ * by `RuntimeParameterizedCodecDescriptor.factory` (see
15
+ * `./parameterized`).
16
+ *
17
+ * The control descriptor in `../exports/control.ts` spreads this pack
18
+ * meta so the framework's contract emitter sees `authoring`,
19
+ * `types.codecTypes.codecInstances`, and `types.storage` alongside
20
+ * the contract-space and codec-lifecycle-hooks blocks already wired
21
+ * by the codec lifecycle hook block.
22
+ */
23
+
24
+ import { cipherstashAuthoringTypes } from '../contract/authoring';
25
+ import { cipherstashStringCodecMetadata } from './codec-metadata';
26
+ import {
27
+ CIPHERSTASH_EXTENSION_VERSION,
28
+ CIPHERSTASH_SPACE_ID,
29
+ CIPHERSTASH_STRING_CODEC_ID,
30
+ EQL_V2_ENCRYPTED_TYPE,
31
+ } from './constants';
32
+
33
+ export { CIPHERSTASH_EXTENSION_VERSION };
34
+
35
+ export const cipherstashPackMeta = {
36
+ kind: 'extension',
37
+ id: CIPHERSTASH_SPACE_ID,
38
+ familyId: 'sql',
39
+ targetId: 'postgres',
40
+ version: CIPHERSTASH_EXTENSION_VERSION,
41
+ authoring: {
42
+ type: cipherstashAuthoringTypes,
43
+ },
44
+ types: {
45
+ codecTypes: {
46
+ codecInstances: [cipherstashStringCodecMetadata],
47
+ // `renderOutputType` returns the bare type name `EncryptedString`
48
+ // for parameterized cipherstash columns; the contract emitter
49
+ // needs to import the type alongside that occurrence so the
50
+ // generated `.d.ts` typechecks cleanly. Mirrors pgvector's
51
+ // `Vector` typeImports declaration.
52
+ typeImports: [
53
+ {
54
+ package: '@prisma-next/extension-cipherstash/runtime',
55
+ named: 'EncryptedString',
56
+ alias: 'EncryptedString',
57
+ },
58
+ ],
59
+ },
60
+ queryOperationTypes: {
61
+ import: {
62
+ package: '@prisma-next/extension-cipherstash/operation-types',
63
+ named: 'QueryOperationTypes',
64
+ alias: 'CipherstashQueryOperationTypes',
65
+ },
66
+ },
67
+ storage: [
68
+ {
69
+ typeId: CIPHERSTASH_STRING_CODEC_ID,
70
+ familyId: 'sql',
71
+ targetId: 'postgres',
72
+ nativeType: EQL_V2_ENCRYPTED_TYPE,
73
+ },
74
+ ],
75
+ },
76
+ } as const;