@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.
- package/README.md +153 -0
- package/dist/call-classes-CSvD7w8U.mjs +206 -0
- package/dist/call-classes-CSvD7w8U.mjs.map +1 -0
- package/dist/column-types.d.mts +33 -0
- package/dist/column-types.d.mts.map +1 -0
- package/dist/column-types.mjs +42 -0
- package/dist/column-types.mjs.map +1 -0
- package/dist/constants-BDxL9Pe3.d.mts +22 -0
- package/dist/constants-BDxL9Pe3.d.mts.map +1 -0
- package/dist/constants-B_2TNvUi.mjs +46 -0
- package/dist/constants-B_2TNvUi.mjs.map +1 -0
- package/dist/control.d.mts +7 -0
- package/dist/control.d.mts.map +1 -0
- package/dist/control.mjs +430 -0
- package/dist/control.mjs.map +1 -0
- package/dist/descriptor-meta-BgQfZTAF.mjs +129 -0
- package/dist/descriptor-meta-BgQfZTAF.mjs.map +1 -0
- package/dist/envelope-P9BxfJNr.mjs +271 -0
- package/dist/envelope-P9BxfJNr.mjs.map +1 -0
- package/dist/middleware.d.mts +13 -0
- package/dist/middleware.d.mts.map +1 -0
- package/dist/middleware.mjs +129 -0
- package/dist/middleware.mjs.map +1 -0
- package/dist/migration.d.mts +141 -0
- package/dist/migration.d.mts.map +1 -0
- package/dist/migration.mjs +2 -0
- package/dist/operation-types.d.mts +49 -0
- package/dist/operation-types.d.mts.map +1 -0
- package/dist/operation-types.mjs +1 -0
- package/dist/pack.d.mts +86 -0
- package/dist/pack.d.mts.map +1 -0
- package/dist/pack.mjs +2 -0
- package/dist/runtime.d.mts +207 -0
- package/dist/runtime.d.mts.map +1 -0
- package/dist/runtime.mjs +429 -0
- package/dist/runtime.mjs.map +1 -0
- package/dist/sdk-D5FTGyzp.d.mts +67 -0
- package/dist/sdk-D5FTGyzp.d.mts.map +1 -0
- package/package.json +69 -0
- package/src/contract/authoring.ts +62 -0
- package/src/contract/contract.d.ts +149 -0
- package/src/contract/contract.json +104 -0
- package/src/contract/contract.prisma +46 -0
- package/src/execution/abort.ts +143 -0
- package/src/execution/codec-runtime.ts +209 -0
- package/src/execution/decrypt-all.ts +217 -0
- package/src/execution/envelope.ts +263 -0
- package/src/execution/operators.ts +211 -0
- package/src/execution/parameterized.ts +71 -0
- package/src/execution/routing.ts +93 -0
- package/src/execution/sdk.ts +68 -0
- package/src/exports/column-types.ts +62 -0
- package/src/exports/contract-space-typing.ts +86 -0
- package/src/exports/control.ts +120 -0
- package/src/exports/middleware.ts +24 -0
- package/src/exports/migration.ts +43 -0
- package/src/exports/operation-types.ts +16 -0
- package/src/exports/pack.ts +13 -0
- package/src/exports/runtime.ts +110 -0
- package/src/extension-metadata/codec-metadata.ts +81 -0
- package/src/extension-metadata/constants.ts +70 -0
- package/src/extension-metadata/descriptor-meta.ts +76 -0
- package/src/middleware/bulk-encrypt.ts +192 -0
- package/src/migration/call-classes.ts +350 -0
- package/src/migration/cipherstash-codec.ts +157 -0
- package/src/migration/eql-bundle.ts +29 -0
- package/src/migration/eql-install.generated.ts +5751 -0
- 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;
|