@prisma-next-idb/runtime-idb 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Prisma IDB
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,116 @@
1
+ import { AsyncIterableResult, RuntimeExecuteOptions, RuntimeMiddleware, RuntimeMiddlewareContext } from "@prisma-next/framework-components/runtime";
2
+ import { IdbQueryPlan, IdbRuntimeAdapterInstance } from "@prisma-next-idb/adapter-idb/runtime";
3
+ import { IdbPlanBody, IdbRuntimeDriverInstance, IdbTransactionScope } from "@prisma-next-idb/driver-idb/runtime";
4
+
5
+ //#region src/idb-middleware.d.ts
6
+ /**
7
+ * IDB-family middleware.
8
+ *
9
+ * Extends the generic `RuntimeMiddleware<IdbPlanBody>` marker. `familyId` is
10
+ * optional so generic cross-family middleware (e.g. telemetry) — which carry
11
+ * no `familyId` — remain assignable. When present, it must be `'idb'`; the
12
+ * runtime can reject mismatches at construction time via
13
+ * `checkMiddlewareCompatibility`.
14
+ *
15
+ * Mirrors the vendor `MongoMiddleware` / `SqlMiddleware` pattern.
16
+ *
17
+ * ## `onRow` backpressure limitation
18
+ *
19
+ * Unlike SQL/Mongo drivers, the IDB driver uses collect-then-yield: all rows
20
+ * are materialized inside the IDB transaction before any are delivered to the
21
+ * middleware pipeline (see ADR 006). This means:
22
+ *
23
+ * - `onRow` fires after the full cursor scan has completed and all rows are in
24
+ * memory. Throwing or aborting inside `onRow` does NOT reduce the number of
25
+ * rows read from the object store.
26
+ * - Use `take(n)` on the query builder to bound materialization, not early
27
+ * exit from `onRow`.
28
+ * - Observation-only hooks (telemetry, cache population, logging) work
29
+ * correctly — they just receive rows from an already-complete scan.
30
+ */
31
+ interface IdbMiddleware extends RuntimeMiddleware<IdbPlanBody> {
32
+ readonly familyId?: "idb";
33
+ }
34
+ //#endregion
35
+ //#region src/idb-runtime.d.ts
36
+ /**
37
+ * Options for creating an IDB runtime instance.
38
+ */
39
+ interface IdbRuntimeOptions {
40
+ /** Instantiated IDB adapter — provides `lower()`. */
41
+ readonly adapter: IdbRuntimeAdapterInstance;
42
+ /** Instantiated IDB driver — provides `execute()` and `close()`. */
43
+ readonly driver: IdbRuntimeDriverInstance;
44
+ /**
45
+ * The resolved IDB contract.
46
+ *
47
+ * Threaded through to the adapter's `lower()` as part of
48
+ * {@link IdbLowererContext} so per-field codec encoding can
49
+ * resolve field→codec mappings from the storage schema. Also used
50
+ * to build the real {@link RuntimeMiddlewareContext} so middleware
51
+ * can inspect contract data.
52
+ */
53
+ readonly contract: Record<string, unknown>;
54
+ /** Optional middleware chain. */
55
+ readonly middleware?: readonly IdbMiddleware[];
56
+ /**
57
+ * Middleware execution context.
58
+ *
59
+ * When omitted, a real context is derived from `contract`.
60
+ */
61
+ readonly ctx?: RuntimeMiddlewareContext;
62
+ }
63
+ /**
64
+ * Public IDB runtime interface.
65
+ *
66
+ * `execute()` accepts an {@link IdbQueryPlan} and returns an
67
+ * `AsyncIterableResult<Row>` — an async iterable that also fulfils as a
68
+ * `Row[]` when awaited.
69
+ */
70
+ interface IdbRuntime {
71
+ execute<Row>(plan: IdbQueryPlan & {
72
+ readonly _row?: Row;
73
+ }, options?: RuntimeExecuteOptions): AsyncIterableResult<Row>;
74
+ /**
75
+ * Open a multi-store IDB transaction and return an `IdbTransactionScope`.
76
+ *
77
+ * The scope's `execute(plan)` runs `IdbAtomicPlan`s directly inside the
78
+ * transaction — middleware is bypassed (Issue #6 fix: cache middleware
79
+ * never fires for reads inside a transaction). `commit()` resolves on
80
+ * `tx.oncomplete`; `rollback()` calls `tx.abort()`.
81
+ *
82
+ * Used by `withMutationScope()` in `client-idb`.
83
+ */
84
+ transaction(storeNames: string[], mode?: IDBTransactionMode): Promise<IdbTransactionScope>;
85
+ /**
86
+ * Verify that the live IDB database's contract marker matches the
87
+ * contract this runtime was created with.
88
+ *
89
+ * Reads the `_prisma_next_marker` store and compares the stored
90
+ * `storageHash` against the contract's `storage.storageHash`.
91
+ * Returns `true` when the marker exists and matches, `false` when
92
+ * the marker is absent or mismatched.
93
+ *
94
+ * Call this after construction and before executing queries to
95
+ * detect schema drift. A missing marker means the database was
96
+ * never initialised (run `db migrate` first). A mismatched marker
97
+ * means the database schema has diverged from the contract.
98
+ */
99
+ verifyMarker(): Promise<boolean>;
100
+ close(): Promise<void>;
101
+ }
102
+ /**
103
+ * Create an IDB runtime instance.
104
+ *
105
+ * @example
106
+ * ```ts
107
+ * const driver = createIDBRuntimeDriver("my-app").create();
108
+ * const runtime = createIdbRuntime({ adapter, driver, contract });
109
+ * await runtime.execute(plan)
110
+ * await runtime.close();
111
+ * ```
112
+ */
113
+ declare function createIdbRuntime(options: IdbRuntimeOptions): IdbRuntime;
114
+ //#endregion
115
+ export { type IdbMiddleware, type IdbRuntime, type IdbRuntimeOptions, createIdbRuntime };
116
+ //# sourceMappingURL=runtime.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime.d.mts","names":[],"sources":["../src/idb-middleware.ts","../src/idb-runtime.ts"],"mappings":";;;;;;;;AA4BA;;;;;;;;AACmB;;;;ACZnB;;;;;;;;;;UDWiB,aAAA,SAAsB,iBAAiB,CAAC,WAAA;EAAA,SAC9C,QAAA;AAAA;;;;AADX;;UCXiB,iBAAA;EDWuC;EAAA,SCT7C,OAAA,EAAS,yBAAA;EDSqC;EAAA,SCP9C,MAAA,EAAQ,wBAAA;EDQA;AAAA;;;;ACZnB;;;;EDYmB,SCER,QAAA,EAAU,MAAA;EAAA;EAAA,SAEV,UAAA,YAAsB,aAAA;EAMhB;;;;;EAAA,SAAN,GAAA,GAAM,wBAAA;AAAA;;;;;;;;UAUA,UAAA;EACf,OAAA,MAAa,IAAA,EAAM,YAAA;IAAA,SAA0B,IAAA,GAAO,GAAA;EAAA,GAAO,OAAA,GAAU,qBAAA,GAAwB,mBAAA,CAAoB,GAAA;EAA9F;;;;;;;;;;EAWnB,WAAA,CAAY,UAAA,YAAsB,IAAA,GAAO,kBAAA,GAAqB,OAAA,CAAQ,mBAAA;EAgBtD;;;;;;;;;;;;;;EADhB,YAAA,IAAgB,OAAA;EAChB,KAAA,IAAS,OAAA;AAAA;;;;;;AAAO;AA2LlB;;;;;iBAAgB,gBAAA,CAAiB,OAAA,EAAS,iBAAA,GAAoB,UAAU"}
@@ -0,0 +1,154 @@
1
+ import { RuntimeCore } from "@prisma-next/framework-components/runtime";
2
+ import { canonicalStringify } from "@prisma-next/utils/canonical-stringify";
3
+ import { hashContent } from "@prisma-next/utils/hash-content";
4
+ //#region src/idb-runtime.ts
5
+ /**
6
+ * Build a real {@link RuntimeMiddlewareContext} from the contract
7
+ * so middleware can inspect contract data (plan meta hashes, model
8
+ * names, storage layout).
9
+ */
10
+ /**
11
+ * Build a real {@link RuntimeMiddlewareContext} from the contract
12
+ * so middleware can inspect contract data (plan meta hashes, model
13
+ * names, storage layout) and compute content hashes for cache keys.
14
+ *
15
+ * `contentHash` mirrors the vendor SQL/Mongo runtimes: it
16
+ * canonicalizes the execution plan's structural identity fields
17
+ * and SHA-512 hashes them via WebCrypto. The resulting digest is
18
+ * a bounded, opaque cache key suitable for middleware like
19
+ * `@prisma-next/middleware-cache`.
20
+ *
21
+ * Non-serializable fields (in-memory filter functions, comparators,
22
+ * `IDBKeyRange` objects) are reduced to their deterministic shape
23
+ * so that two semantically identical plans produce the same hash.
24
+ */
25
+ function buildMiddlewareContext(contract) {
26
+ return {
27
+ contract,
28
+ mode: "permissive",
29
+ planExecutionId: crypto.randomUUID(),
30
+ now: () => Date.now(),
31
+ log: {
32
+ info: () => void 0,
33
+ warn: () => void 0,
34
+ error: () => void 0
35
+ },
36
+ scope: "runtime",
37
+ contentHash: async (exec) => {
38
+ const plan = exec;
39
+ const hashable = {};
40
+ for (const [key, value] of Object.entries(plan)) if (key === "meta") hashable["meta"] = { storageHash: value?.["storageHash"] };
41
+ else if (typeof value === "function") continue;
42
+ else if (typeof IDBKeyRange !== "undefined" && value instanceof IDBKeyRange || isIdbKeyRange(value)) hashable[key] = keyRangeIdentity(value);
43
+ else hashable[key] = value;
44
+ return hashContent(canonicalStringify(hashable));
45
+ }
46
+ };
47
+ }
48
+ /** Check for IDBKeyRange-like objects (e.g. from fake-indexeddb). */
49
+ function isIdbKeyRange(value) {
50
+ return typeof value === "object" && value !== null && "lower" in value && "upper" in value && "lowerOpen" in value && "upperOpen" in value;
51
+ }
52
+ /** Extract a deterministic identity from an IDBKeyRange. */
53
+ function keyRangeIdentity(range) {
54
+ return {
55
+ lower: range.lower,
56
+ upper: range.upper,
57
+ lowerOpen: range.lowerOpen,
58
+ upperOpen: range.upperOpen
59
+ };
60
+ }
61
+ /**
62
+ * IDB runtime — the `RuntimeCore` subclass for IndexedDB.
63
+ *
64
+ * Wires together:
65
+ * - `lower(plan, ctx)` — delegates to `adapter.lower()` with the contract
66
+ * threaded via {@link IdbLowererContext}, producing an `IdbPlanBody`
67
+ * - `runDriver(exec)` — delegates to `driver.execute()` to run the plan against IDB
68
+ * - `execute()` — the concrete template method from `RuntimeCore`
69
+ * - `close()` — closes the IDB connection via `driver.close()`
70
+ */
71
+ var IdbRuntimeImpl = class extends RuntimeCore {
72
+ #adapter;
73
+ #driver;
74
+ #contract;
75
+ constructor(options) {
76
+ const ctx = options.ctx ?? buildMiddlewareContext(options.contract);
77
+ super({
78
+ middleware: [...options.middleware ?? []],
79
+ ctx
80
+ });
81
+ this.#adapter = options.adapter;
82
+ this.#driver = options.driver;
83
+ this.#contract = options.contract;
84
+ }
85
+ /**
86
+ * Lower an IDB query plan to an IDB plan body via the adapter.
87
+ *
88
+ * Threads the contract through {@link IdbLowererContext} so per-field
89
+ * codec encoding can resolve field→codec mappings from the contract's
90
+ * storage schema.
91
+ */
92
+ lower(plan, ctx) {
93
+ const lowererCtx = {
94
+ ...ctx,
95
+ contract: this.#contract
96
+ };
97
+ return this.#adapter.lower(plan, lowererCtx);
98
+ }
99
+ /**
100
+ * Execute a lowered IDB plan body via the driver.
101
+ */
102
+ runDriver(exec) {
103
+ return this.#driver.execute(exec);
104
+ }
105
+ /**
106
+ * Execute an IDB query plan and return a typed async-iterable result.
107
+ *
108
+ * Rows are yielded as-is from the driver (identity pass-through).
109
+ * All current `idb/*` codecs are identity transforms — no per-field
110
+ * decoding is needed. When per-field codec decoding is added (e.g.
111
+ * decoding `idb/date@1` stored values back to `Date` instances, or
112
+ * custom codec output types), it wires up here.
113
+ */
114
+ execute(plan, options) {
115
+ return super.execute(plan, options);
116
+ }
117
+ async transaction(storeNames, mode = "readwrite") {
118
+ return this.#driver.transaction(storeNames, mode);
119
+ }
120
+ async close() {
121
+ await this.#driver.close();
122
+ }
123
+ /**
124
+ * Verify that the live IDB marker matches the contract.
125
+ *
126
+ * Compares the stored `storageHash` against `contract.storage.storageHash`.
127
+ * A fresh database (no marker store) returns `false` — the caller should
128
+ * ensure migrations have been applied before running queries.
129
+ */
130
+ async verifyMarker() {
131
+ const marker = await this.#driver.readMarker();
132
+ if (marker === null) return false;
133
+ const contractHash = this.#contract["storage"]?.["storageHash"];
134
+ return typeof contractHash === "string" && marker.storageHash === contractHash;
135
+ }
136
+ };
137
+ /**
138
+ * Create an IDB runtime instance.
139
+ *
140
+ * @example
141
+ * ```ts
142
+ * const driver = createIDBRuntimeDriver("my-app").create();
143
+ * const runtime = createIdbRuntime({ adapter, driver, contract });
144
+ * await runtime.execute(plan)
145
+ * await runtime.close();
146
+ * ```
147
+ */
148
+ function createIdbRuntime(options) {
149
+ return new IdbRuntimeImpl(options);
150
+ }
151
+ //#endregion
152
+ export { createIdbRuntime };
153
+
154
+ //# sourceMappingURL=runtime.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime.mjs","names":["meta","#adapter","#driver","#contract"],"sources":["../src/idb-runtime.ts"],"sourcesContent":["import type { CodecCallContext } from \"@prisma-next/framework-components/codec\";\nimport {\n AsyncIterableResult,\n RuntimeCore,\n type ExecutionPlan,\n type RuntimeExecuteOptions,\n type RuntimeMiddlewareContext,\n} from \"@prisma-next/framework-components/runtime\";\nimport { canonicalStringify } from \"@prisma-next/utils/canonical-stringify\";\nimport { hashContent } from \"@prisma-next/utils/hash-content\";\nimport type { IdbLowererContext, IdbQueryPlan, IdbRuntimeAdapterInstance } from \"@prisma-next-idb/adapter-idb/runtime\";\nimport type { IdbPlanBody, IdbRuntimeDriverInstance, IdbTransactionScope } from \"@prisma-next-idb/driver-idb/runtime\";\nimport type { IdbMiddleware } from \"./idb-middleware\";\n\n/**\n * Options for creating an IDB runtime instance.\n */\nexport interface IdbRuntimeOptions {\n /** Instantiated IDB adapter — provides `lower()`. */\n readonly adapter: IdbRuntimeAdapterInstance;\n /** Instantiated IDB driver — provides `execute()` and `close()`. */\n readonly driver: IdbRuntimeDriverInstance;\n /**\n * The resolved IDB contract.\n *\n * Threaded through to the adapter's `lower()` as part of\n * {@link IdbLowererContext} so per-field codec encoding can\n * resolve field→codec mappings from the storage schema. Also used\n * to build the real {@link RuntimeMiddlewareContext} so middleware\n * can inspect contract data.\n */\n readonly contract: Record<string, unknown>;\n /** Optional middleware chain. */\n readonly middleware?: readonly IdbMiddleware[];\n /**\n * Middleware execution context.\n *\n * When omitted, a real context is derived from `contract`.\n */\n readonly ctx?: RuntimeMiddlewareContext;\n}\n\n/**\n * Public IDB runtime interface.\n *\n * `execute()` accepts an {@link IdbQueryPlan} and returns an\n * `AsyncIterableResult<Row>` — an async iterable that also fulfils as a\n * `Row[]` when awaited.\n */\nexport interface IdbRuntime {\n execute<Row>(plan: IdbQueryPlan & { readonly _row?: Row }, options?: RuntimeExecuteOptions): AsyncIterableResult<Row>;\n /**\n * Open a multi-store IDB transaction and return an `IdbTransactionScope`.\n *\n * The scope's `execute(plan)` runs `IdbAtomicPlan`s directly inside the\n * transaction — middleware is bypassed (Issue #6 fix: cache middleware\n * never fires for reads inside a transaction). `commit()` resolves on\n * `tx.oncomplete`; `rollback()` calls `tx.abort()`.\n *\n * Used by `withMutationScope()` in `client-idb`.\n */\n transaction(storeNames: string[], mode?: IDBTransactionMode): Promise<IdbTransactionScope>;\n /**\n * Verify that the live IDB database's contract marker matches the\n * contract this runtime was created with.\n *\n * Reads the `_prisma_next_marker` store and compares the stored\n * `storageHash` against the contract's `storage.storageHash`.\n * Returns `true` when the marker exists and matches, `false` when\n * the marker is absent or mismatched.\n *\n * Call this after construction and before executing queries to\n * detect schema drift. A missing marker means the database was\n * never initialised (run `db migrate` first). A mismatched marker\n * means the database schema has diverged from the contract.\n */\n verifyMarker(): Promise<boolean>;\n close(): Promise<void>;\n}\n\n/**\n * Build a real {@link RuntimeMiddlewareContext} from the contract\n * so middleware can inspect contract data (plan meta hashes, model\n * names, storage layout).\n */\n/**\n * Build a real {@link RuntimeMiddlewareContext} from the contract\n * so middleware can inspect contract data (plan meta hashes, model\n * names, storage layout) and compute content hashes for cache keys.\n *\n * `contentHash` mirrors the vendor SQL/Mongo runtimes: it\n * canonicalizes the execution plan's structural identity fields\n * and SHA-512 hashes them via WebCrypto. The resulting digest is\n * a bounded, opaque cache key suitable for middleware like\n * `@prisma-next/middleware-cache`.\n *\n * Non-serializable fields (in-memory filter functions, comparators,\n * `IDBKeyRange` objects) are reduced to their deterministic shape\n * so that two semantically identical plans produce the same hash.\n */\nfunction buildMiddlewareContext(contract: Record<string, unknown>): RuntimeMiddlewareContext {\n return {\n contract,\n mode: \"permissive\",\n // v0.12.0: per-execute correlation id required on the middleware context.\n // The default ctx is built once per runtime; consumers needing per-execute\n // ids should supply their own `ctx`.\n planExecutionId: crypto.randomUUID(),\n now: () => Date.now(),\n log: {\n info: () => undefined,\n warn: () => undefined,\n error: () => undefined,\n },\n // Always \"runtime\": IdbTransactionScope.execute() bypasses the middleware\n // chain entirely, so middleware is only ever invoked from the top-level\n // execute() path, which is exactly the \"runtime\" scope. There is no IDB\n // connection pool, so \"connection\" is not applicable either.\n scope: \"runtime\",\n contentHash: async (exec: ExecutionPlan) => {\n // Reduce the plan to its structural identity for hashing.\n // Exclude functions (IdbRowFilter, IdbRowComparator) and\n // collapse IDBKeyRange to its bounds so deterministic\n // comparisons work.\n const plan = exec as unknown as Record<string, unknown>;\n const hashable: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(plan)) {\n if (key === \"meta\") {\n // meta.storageHash is the primary identity field\n const meta = value as Record<string, unknown> | undefined;\n hashable[\"meta\"] = { storageHash: meta?.[\"storageHash\"] };\n } else if (typeof value === \"function\") {\n // Skip in-memory filters/comparators — not hashable\n continue;\n } else if ((typeof IDBKeyRange !== \"undefined\" && value instanceof IDBKeyRange) || isIdbKeyRange(value)) {\n // Collapse IDBKeyRange to its bounds\n hashable[key] = keyRangeIdentity(value as IDBKeyRange);\n } else {\n hashable[key] = value;\n }\n }\n return hashContent(canonicalStringify(hashable));\n },\n };\n}\n\n/** Check for IDBKeyRange-like objects (e.g. from fake-indexeddb). */\nfunction isIdbKeyRange(value: unknown): value is IDBKeyRange {\n return (\n typeof value === \"object\" &&\n value !== null &&\n \"lower\" in value &&\n \"upper\" in value &&\n \"lowerOpen\" in value &&\n \"upperOpen\" in value\n );\n}\n\n/** Extract a deterministic identity from an IDBKeyRange. */\nfunction keyRangeIdentity(range: IDBKeyRange): Record<string, unknown> {\n return {\n lower: range.lower,\n upper: range.upper,\n lowerOpen: range.lowerOpen,\n upperOpen: range.upperOpen,\n };\n}\n\n/**\n * IDB runtime — the `RuntimeCore` subclass for IndexedDB.\n *\n * Wires together:\n * - `lower(plan, ctx)` — delegates to `adapter.lower()` with the contract\n * threaded via {@link IdbLowererContext}, producing an `IdbPlanBody`\n * - `runDriver(exec)` — delegates to `driver.execute()` to run the plan against IDB\n * - `execute()` — the concrete template method from `RuntimeCore`\n * - `close()` — closes the IDB connection via `driver.close()`\n */\nclass IdbRuntimeImpl extends RuntimeCore<IdbQueryPlan, IdbPlanBody, IdbMiddleware> implements IdbRuntime {\n readonly #adapter: IdbRuntimeAdapterInstance;\n readonly #driver: IdbRuntimeDriverInstance;\n readonly #contract: Record<string, unknown>;\n\n constructor(options: IdbRuntimeOptions) {\n const ctx = options.ctx ?? buildMiddlewareContext(options.contract);\n super({ middleware: [...(options.middleware ?? [])], ctx });\n this.#adapter = options.adapter;\n this.#driver = options.driver;\n this.#contract = options.contract;\n }\n\n /**\n * Lower an IDB query plan to an IDB plan body via the adapter.\n *\n * Threads the contract through {@link IdbLowererContext} so per-field\n * codec encoding can resolve field→codec mappings from the contract's\n * storage schema.\n */\n protected override lower(plan: IdbQueryPlan, ctx: CodecCallContext): Promise<IdbPlanBody> {\n const lowererCtx: IdbLowererContext = {\n ...ctx,\n contract: this.#contract,\n };\n return this.#adapter.lower(plan, lowererCtx);\n }\n\n /**\n * Execute a lowered IDB plan body via the driver.\n */\n protected override runDriver(exec: IdbPlanBody): AsyncIterable<Record<string, unknown>> {\n return this.#driver.execute(exec);\n }\n\n /**\n * Execute an IDB query plan and return a typed async-iterable result.\n *\n * Rows are yielded as-is from the driver (identity pass-through).\n * All current `idb/*` codecs are identity transforms — no per-field\n * decoding is needed. When per-field codec decoding is added (e.g.\n * decoding `idb/date@1` stored values back to `Date` instances, or\n * custom codec output types), it wires up here.\n */\n override execute<Row>(\n plan: IdbQueryPlan & { readonly _row?: Row },\n options?: RuntimeExecuteOptions\n ): AsyncIterableResult<Row> {\n return super.execute(plan, options);\n }\n\n async transaction(storeNames: string[], mode: IDBTransactionMode = \"readwrite\"): Promise<IdbTransactionScope> {\n return this.#driver.transaction(storeNames, mode);\n }\n\n override async close(): Promise<void> {\n await this.#driver.close();\n }\n\n /**\n * Verify that the live IDB marker matches the contract.\n *\n * Compares the stored `storageHash` against `contract.storage.storageHash`.\n * A fresh database (no marker store) returns `false` — the caller should\n * ensure migrations have been applied before running queries.\n */\n async verifyMarker(): Promise<boolean> {\n const marker = await this.#driver.readMarker();\n if (marker === null) return false;\n const contractStorage = this.#contract[\"storage\"] as Record<string, unknown> | undefined;\n const contractHash = contractStorage?.[\"storageHash\"];\n return typeof contractHash === \"string\" && marker.storageHash === contractHash;\n }\n}\n\n/**\n * Create an IDB runtime instance.\n *\n * @example\n * ```ts\n * const driver = createIDBRuntimeDriver(\"my-app\").create();\n * const runtime = createIdbRuntime({ adapter, driver, contract });\n * await runtime.execute(plan)\n * await runtime.close();\n * ```\n */\nexport function createIdbRuntime(options: IdbRuntimeOptions): IdbRuntime {\n return new IdbRuntimeImpl(options);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAoGA,SAAS,uBAAuB,UAA6D;CAC3F,OAAO;EACL;EACA,MAAM;EAIN,iBAAiB,OAAO,WAAW;EACnC,WAAW,KAAK,IAAI;EACpB,KAAK;GACH,YAAY,KAAA;GACZ,YAAY,KAAA;GACZ,aAAa,KAAA;EACf;EAKA,OAAO;EACP,aAAa,OAAO,SAAwB;GAK1C,MAAM,OAAO;GACb,MAAM,WAAoC,CAAC;GAC3C,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,IAAI,GAC5C,IAAI,QAAQ,QAGV,SAAS,UAAU,EAAE,aAAaA,QAAO,eAAe;QACnD,IAAI,OAAO,UAAU,YAE1B;QACK,IAAK,OAAO,gBAAgB,eAAe,iBAAiB,eAAgB,cAAc,KAAK,GAEpG,SAAS,OAAO,iBAAiB,KAAoB;QAErD,SAAS,OAAO;GAGpB,OAAO,YAAY,mBAAmB,QAAQ,CAAC;EACjD;CACF;AACF;;AAGA,SAAS,cAAc,OAAsC;CAC3D,OACE,OAAO,UAAU,YACjB,UAAU,QACV,WAAW,SACX,WAAW,SACX,eAAe,SACf,eAAe;AAEnB;;AAGA,SAAS,iBAAiB,OAA6C;CACrE,OAAO;EACL,OAAO,MAAM;EACb,OAAO,MAAM;EACb,WAAW,MAAM;EACjB,WAAW,MAAM;CACnB;AACF;;;;;;;;;;;AAYA,IAAM,iBAAN,cAA6B,YAA4E;CACvG;CACA;CACA;CAEA,YAAY,SAA4B;EACtC,MAAM,MAAM,QAAQ,OAAO,uBAAuB,QAAQ,QAAQ;EAClE,MAAM;GAAE,YAAY,CAAC,GAAI,QAAQ,cAAc,CAAC,CAAE;GAAG;EAAI,CAAC;EAC1D,KAAKC,WAAW,QAAQ;EACxB,KAAKC,UAAU,QAAQ;EACvB,KAAKC,YAAY,QAAQ;CAC3B;;;;;;;;CASA,MAAyB,MAAoB,KAA6C;EACxF,MAAM,aAAgC;GACpC,GAAG;GACH,UAAU,KAAKA;EACjB;EACA,OAAO,KAAKF,SAAS,MAAM,MAAM,UAAU;CAC7C;;;;CAKA,UAA6B,MAA2D;EACtF,OAAO,KAAKC,QAAQ,QAAQ,IAAI;CAClC;;;;;;;;;;CAWA,QACE,MACA,SAC0B;EAC1B,OAAO,MAAM,QAAQ,MAAM,OAAO;CACpC;CAEA,MAAM,YAAY,YAAsB,OAA2B,aAA2C;EAC5G,OAAO,KAAKA,QAAQ,YAAY,YAAY,IAAI;CAClD;CAEA,MAAe,QAAuB;EACpC,MAAM,KAAKA,QAAQ,MAAM;CAC3B;;;;;;;;CASA,MAAM,eAAiC;EACrC,MAAM,SAAS,MAAM,KAAKA,QAAQ,WAAW;EAC7C,IAAI,WAAW,MAAM,OAAO;EAE5B,MAAM,eADkB,KAAKC,UAAU,UACH,GAAG;EACvC,OAAO,OAAO,iBAAiB,YAAY,OAAO,gBAAgB;CACpE;AACF;;;;;;;;;;;;AAaA,SAAgB,iBAAiB,SAAwC;CACvE,OAAO,IAAI,eAAe,OAAO;AACnC"}
package/package.json ADDED
@@ -0,0 +1,50 @@
1
+ {
2
+ "name": "@prisma-next-idb/runtime-idb",
3
+ "version": "0.1.0",
4
+ "description": "Prisma Next IDB family — runtime (RuntimeCore subclass that wires adapter + driver)",
5
+ "license": "MIT",
6
+ "files": [
7
+ "dist"
8
+ ],
9
+ "keywords": [
10
+ "prisma",
11
+ "prisma-next",
12
+ "indexeddb",
13
+ "offline-first",
14
+ "idb"
15
+ ],
16
+ "repository": {
17
+ "type": "git",
18
+ "url": "git+https://github.com/prisma-idb/idb-client-generator.git",
19
+ "directory": "packages/prisma-next/runtime-idb"
20
+ },
21
+ "homepage": "https://prisma-idb.dev/",
22
+ "bugs": {
23
+ "url": "https://github.com/prisma-idb/idb-client-generator/issues"
24
+ },
25
+ "type": "module",
26
+ "exports": {
27
+ "./runtime": "./dist/runtime.mjs",
28
+ "./package.json": "./package.json"
29
+ },
30
+ "dependencies": {
31
+ "@prisma-next/framework-components": "^0.14.0",
32
+ "@prisma-next/utils": "^0.14.0",
33
+ "@prisma-next-idb/adapter-idb": "0.1.0",
34
+ "@prisma-next-idb/driver-idb": "0.1.0"
35
+ },
36
+ "devDependencies": {
37
+ "fake-indexeddb": "^6.2.5",
38
+ "tsdown": "^0.22.3",
39
+ "typescript": "^6.0.3",
40
+ "vitest": "^4.1.9"
41
+ },
42
+ "scripts": {
43
+ "build": "tsdown",
44
+ "dev": "tsdown --watch",
45
+ "check": "tsc --noEmit",
46
+ "test": "vitest run",
47
+ "lint": "prettier --check . && eslint .",
48
+ "format": "prettier --write ."
49
+ }
50
+ }