@shivaedev/effect-changes-prisma 0.5.2 → 0.5.4

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/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.5.4 - 2026-10-25
4
+
5
+ ### Changed
6
+
7
+ - Release with updated workspace dependencies.
8
+
9
+ ## 0.5.3 - 2026-10-24
10
+
11
+ ### Changed
12
+
13
+ - Require Effect and its companion packages at exactly 4.0.5. Generated applications use the same versions.
14
+
3
15
  ## 0.5.2 - 2026-10-18
4
16
 
5
17
  ### Fixed
package/README.md CHANGED
@@ -178,7 +178,7 @@ const save = changes.transaction(
178
178
  );
179
179
  ```
180
180
 
181
- Pass transaction options as the second argument. Without `timeout`, the binding uses the current client's configured transaction timeout; the tested Prisma default is 5,000 milliseconds. The configuration reader also handles an extended client. If that configuration cannot be read, it supplies no deadline of its own; a query finding the transaction closed still stops the body.
181
+ Pass transaction options as the second argument. Without `timeout`, the binding uses the current client's configured transaction timeout; Prisma's default is 5,000 milliseconds. The configuration reader also handles an extended client. If that configuration cannot be read, it supplies no deadline of its own; a query finding the transaction closed still stops the body.
182
182
 
183
183
  The deadline follows the wall clock, so moving Effect's `TestClock` does not expire the transaction. An outer transaction's expiry interrupts a nested body too. A separate transaction started on the base client, or another binding's transaction, has independent expiry; handling its failure can leave the original body's transaction running.
184
184
 
@@ -271,41 +271,16 @@ Import the module that defines the name. There is no root entry point.
271
271
  | `tables.ts` | `RawQueryClient`, `TableWrites`, `tablesOf`, `tableWrites`, `writtenTables` |
272
272
  | `error.ts` | `PrismaError`, `TransactionExpired` |
273
273
 
274
- `PrismaChangesOptions` takes `client`, `models` and the effect-changes channel options other than `owner` and `unowned`: `name`, `key`, `publish`, `onPublishFailure` and `beforeCommit`. The `beforeCommit` hook runs inside the Prisma transaction after the body succeeds, with its recorded changes, before commit. Calls to `use` in the hook use the transaction's scoped `Client`, so they see uncommitted body rows. A hook failure rolls back both body and hook writes and publishes nothing. The binding returns `Client`, `channel`, `use`, `transaction`, `recordWrite` and `Unnamed`.
275
-
276
- ```ts
277
- interface Write {
278
- readonly model: string;
279
- readonly operation: string;
280
- readonly result: unknown;
281
- }
282
-
283
- type UnnamedWrite =
284
- | { readonly model: string; readonly operation: string; readonly reason: "countOnly" }
285
- | { readonly model: string; readonly operation: string; readonly reason: "narrowed"; readonly field: string };
286
-
287
- type CoverageViolation =
288
- | { readonly _tag: "Unrecorded"; readonly table: string; readonly model: string | undefined }
289
- | { readonly _tag: "Unnamed"; readonly write: UnnamedWrite };
290
- ```
291
-
292
- These are the write input and the two diagnostic results. `Coverage<A>` takes `written`, `tables`, `models`, `observations`, `unnamed` and `covers`, as shown in the harness. `TableWrites` is a `ReadonlyMap<string, bigint>`; `RawQueryClient` requires `$queryRawUnsafe(query)`.
293
-
294
- `use` has error type `PrismaError`. `transaction` adds `TransactionExpired | PrismaError` to the body's error type. `PrismaError` carries `cause`; `TransactionExpired` carries `message` and optional `cause`. Transaction options are `maxWait`, `timeout` and `isolationLevel`, whose type is `"ReadUncommitted" | "ReadCommitted" | "RepeatableRead" | "Serializable"`.
295
-
296
- The module export pattern also exposes `model.ts`'s `rowOperations`, `countOperations` and `delegateOf`; `write.ts`'s `interpret`, `Interpreted`, `LooseChanges` and `LooseMap`; and the helpers in [`recording.ts`](https://github.com/ShivaeDev/platform/blob/main/packages/effect-changes-prisma/src/recording.ts), [`expiry.ts`](https://github.com/ShivaeDev/platform/blob/main/packages/effect-changes-prisma/src/expiry.ts) and [`transaction.ts`](https://github.com/ShivaeDev/platform/blob/main/packages/effect-changes-prisma/src/transaction.ts). Application examples use the binding API above.
274
+ `makePrismaChanges` also accepts the effect-changes channel options `onPublishFailure` and `beforeCommit`. The `beforeCommit` hook runs inside the Prisma transaction after the body succeeds, with its recorded changes, before commit. Calls to `use` in the hook use the transaction's scoped `Client`, so they see uncommitted body rows. A hook failure rolls back both body and hook writes and publishes nothing.
297
275
 
298
276
  ### Install, setup and limits
299
277
 
300
278
  ```sh
301
- pnpm add @shivaedev/effect-changes-prisma @shivaedev/effect-changes @prisma/client@7.10.0 effect@4.0.4
279
+ pnpm add @shivaedev/effect-changes-prisma @shivaedev/effect-changes @prisma/client@7.10.0 effect@4.0.5
302
280
  ```
303
281
 
304
- `@prisma/client` and `effect` are peers. Generate and construct the application's Prisma Classic client for PostgreSQL before binding it. Package tests use the generated Prisma client and `@prisma/adapter-pg`; the PostgreSQL integration suite requires `PLATFORM_EFFECT_CHANGES_PRISMA_TEST_DATABASE_URL` and otherwise skips.
282
+ `@prisma/client` and `effect` are peers. Generate and construct the application's Prisma Classic client for PostgreSQL before binding it.
305
283
 
306
284
  - Use the binding's `transaction` for the transaction outcome it observes, and `use` for automatically recorded model writes.
307
285
  - Return the fields the model mapping needs. The count-only and missing-field diagnostics are part of coverage, not a way to infer omitted subjects.
308
286
  - Coverage is a table-level check: one matching recorded change covers a written model's table. Test the correctness of affected subjects separately.
309
- - A test harness's native rollback transaction can contain root binding savepoints that publish before the harness rolls back. Capture publication in tests that must not call a real external sink.
310
-
311
- Read the [north star](https://github.com/ShivaeDev/platform/blob/main/packages/effect-changes-prisma/docs/north-star.md) for design boundaries and the [roadmap](https://github.com/ShivaeDev/platform/blob/main/packages/effect-changes-prisma/docs/roadmap.md) for status and open questions.
package/dist/write.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { Bivariant } from "@shivaedev/types/bivariant.ts";
1
+ import type { Bivariant } from "@shivaedev/types/Bivariant.ts";
2
2
  import { type RowOperation } from "./model.ts";
3
3
  export interface Write {
4
4
  readonly model: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shivaedev/effect-changes-prisma",
3
- "version": "0.5.2",
3
+ "version": "0.5.4",
4
4
  "description": "Commit-bound change channels for Prisma Classic on PostgreSQL only: automatic change recording, publish after $transaction commits, and a test-time coverage check",
5
5
  "homepage": "https://github.com/ShivaeDev/platform/tree/main/packages/effect-changes-prisma#readme",
6
6
  "bugs": {
@@ -24,9 +24,8 @@
24
24
  },
25
25
  "exports": {
26
26
  "./*.ts": {
27
- "types": "./dist/*.d.ts",
28
27
  "source": "./src/*.ts",
29
- "import": "./dist/*.js",
28
+ "types": "./dist/*.d.ts",
30
29
  "default": "./dist/*.js"
31
30
  },
32
31
  "./package.json": "./package.json"
@@ -37,29 +36,27 @@
37
36
  "!src/**/*.test.ts",
38
37
  "!src/**/*.spec.ts",
39
38
  "!src/**/test-support",
40
- "docs",
41
39
  "CHANGELOG.md",
42
40
  "README.md"
43
41
  ],
44
42
  "dependencies": {
45
- "@shivaedev/effect-changes": "0.3.1",
46
- "@shivaedev/types": "0.2.1"
43
+ "@shivaedev/effect-changes": "0.3.2",
44
+ "@shivaedev/types": "0.3.0"
47
45
  },
48
46
  "devDependencies": {
49
47
  "@prisma/adapter-pg": "7.10.0",
50
48
  "@prisma/client": "7.10.0",
51
- "@shivaedev/quality": "0.23.0",
52
- "@shivaedev/test-story": "0.6.0",
49
+ "@shivaedev/quality": "0.38.0",
50
+ "@shivaedev/test-story": "0.19.0",
53
51
  "@types/node": "24.19.2",
54
- "@typescript/native": "npm:typescript@7.0.2",
55
- "effect": "4.0.4",
52
+ "effect": "4.0.5",
56
53
  "prisma": "7.10.0",
57
- "typescript": "npm:@typescript/typescript6@6.0.2",
58
- "vitest": "5.0.3"
54
+ "typescript": "7.0.2",
55
+ "vitest": "5.0.5"
59
56
  },
60
57
  "peerDependencies": {
61
58
  "@prisma/client": "7.10.0",
62
- "effect": "4.0.4"
59
+ "effect": "4.0.5"
63
60
  },
64
61
  "engines": {
65
62
  "node": ">=24"
package/src/write.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { Bivariant } from "@shivaedev/types/bivariant.ts";
1
+ import type { Bivariant } from "@shivaedev/types/Bivariant.ts";
2
2
  import { countOperations, type RowOperation, rowOperations } from "./model.ts";
3
3
 
4
4
  export interface Write {
@@ -1,43 +0,0 @@
1
- # North star
2
-
3
- ## The problem
4
-
5
- A successful Prisma query says that its statement ran. A successful transaction body still does not say that COMMIT succeeded. A deferred constraint can reject the commit, a caller can be interrupted, or Prisma can expire the transaction while the Effect body has more work to do. If an application announces changes from its write methods or from the body's success, it can announce rows that rolled back, miss a commit that landed during interruption, or continue side effects after the database transaction closed.
6
-
7
- The other half of the problem is knowing which writes need an announcement. An application often names changes by an owner, member or domain rather than a table. That meaning belongs to the application. Returned model rows can provide it; a count alone cannot. A test also needs evidence that its writes passed through this path, including SQL that bypasses ordinary model delegates.
8
-
9
- ## The ideal
10
-
11
- An application on Prisma Classic and PostgreSQL has one path for commit-bound changes. It defines its change values and model mappings once, runs Prisma calls through `use`, and wraps an action in `transaction`. The adapter supplies the scoped client and translates the real driver's outcome into the shared effect-changes frame lifecycle. An application with an existing Effect wrapper can feed observed results through `recordWrite` without adopting another query wrapper.
12
-
13
- A mapping classifies a model deliberately: a row names changes, or `null` says its writes need none. A count-only write or a returned row missing a field the mapping needs must be visible to a test rather than quietly producing an invented subject. A PostgreSQL test compares its written tables with `Recorded` observations and its own definition of which change covers a model.
14
-
15
- ## What good looks like
16
-
17
- - COMMIT determines publication. Savepoint release determines merging into an enclosing frame; rollback determines discard.
18
- - Interruption during a body stops that body and rolls back. Interruption during an in-flight COMMIT still waits for the database outcome, so a landed commit can publish.
19
- - A started transaction expiring is distinct from one unable to start. Typed application failures remain available to callers.
20
- - An expired body stops before later side effects. Wall-clock deadlines follow the current Prisma client's timeout rather than the test clock.
21
- - Model meanings remain explicit and typed. An exhaustive map makes an added model require a classification.
22
- - Tests take a baseline on their own transaction before checking table counters, so a reused connection does not give credit or blame for another transaction's writes.
23
-
24
- ## Trade-offs
25
-
26
- When goals conflict, database outcome and interruption correctness win first, then reuse of the shared channel, then explicit application-owned meaning, then proof at the PostgreSQL boundary, then convenience.
27
-
28
- **Commit correctness costs waiting.** A Prisma promise already in flight cannot be treated as rolled back just because the Effect caller stops waiting. The adapter must settle from the driver's result, including after interruption. A more convenient cancellation API cannot invent a different database outcome.
29
-
30
- **Returned rows limit automatic naming.** The mapping uses the row a write returns. Count-only operations and missing fields need an explicit choice by the application; automatically fetching rows would add queries and its own consistency problem. Keep unsupported shapes visible before adding convenience.
31
-
32
- **Coverage is deliberately coarse.** The coverage predicate connects a written table's model to recorded changes. One covering change satisfies that table check. This is a useful guard against a missed path, but subject-level correctness belongs in the application's tests.
33
-
34
- **Prisma adaptation stays narrow.** The shared channel owns buffering, observation and publication policy. This package owns the Promise transaction boundary, the current client, returned-write interpretation and PostgreSQL table-counter helpers. Keep those responsibilities separate so improvements to a channel reach both Prisma and native SQL callers.
35
-
36
- ## What it leaves out
37
-
38
- - A replacement Prisma client, repository layer or migration runner. effect-prisma owns the separate Prisma Next database facade, and effect-sql owns native Effect persistence and migrations.
39
- - The shape of an application's change values, the meaning of their keys, or which subjects a write should name.
40
- - A selected subscription transport, durable delivery policy or deployment topology. The application chooses those around its publication sink.
41
- - Proof that every affected row or subject is announced. The coverage helper checks tables and unnamed writes; application behavior tests check the meaning of the announcements.
42
-
43
- The [roadmap](roadmap.md) holds the unresolved support and API questions. The [framework roadmap](https://github.com/ShivaeDev/platform/blob/main/docs/framework/roadmap.md) owns adoption and delivery decisions that span packages.
package/docs/roadmap.md DELETED
@@ -1,22 +0,0 @@
1
- # Roadmap
2
-
3
- ## Built
4
-
5
- - [x] A Prisma Classic/PostgreSQL binding over effect-changes, with typed model mappings, a scoped `Client`, `use` and an explicit `recordWrite` seam.
6
- - [x] Publication after a successful COMMIT, discard after rollback or failed commit, nested savepoint merge and discard, and publication when COMMIT lands after caller interruption.
7
- - [x] `TransactionExpired` and body interruption at an explicit or configured wall-clock timeout, including linked nested bodies and queries that find a transaction closed. A transaction unable to start remains a `PrismaError`.
8
- - [x] Row-based recording, keyed deduplication, autocommit publication, explicit batches, and unnamed-write reporting for count-only writes and returned rows missing a mapping field.
9
- - [x] Table/model extraction from schema text, PostgreSQL transaction-counter baselines, and a table-level coverage check over recorded observations and unnamed writes.
10
- - [x] Pure, type and real PostgreSQL tests, plus a packed-consumer fixture for published module imports and basic execution. PostgreSQL tests skip without `PLATFORM_EFFECT_CHANGES_PRISMA_TEST_DATABASE_URL`.
11
-
12
- ## Next
13
-
14
- No package implementation milestone has been selected. The next extension should come from a demonstrated Prisma consumer and a decision about the open questions below. Cross-package adoption, composed application validation and deployment delivery policy belong in the [framework roadmap](https://github.com/ShivaeDev/platform/blob/main/docs/framework/roadmap.md).
15
-
16
- ## Open questions
17
-
18
- - How much independent support should this Prisma path receive as the framework's native persistence path develops? It serves Prisma applications; there is no decision here to replace it or retire it.
19
- - Should recording stay at returned top-level model writes, with explicit `recordWrite` and coverage for other paths, or should the adapter observe more ORM behavior? Nested relation writes, cascades and trigger writes need dedicated tests before their coverage behavior is documented.
20
- - Is table-level coverage the intended acceptance bar, or does a consumer need a check that proves every affected subject has a change?
21
- - Should `recording.ts`, `expiry.ts`, `transaction.ts` and the interpretation helpers remain supported extension points? The module export pattern exposes them, while the primary usage path goes through `changes.ts`, `model.ts`, `write.ts`, `coverage.ts`, `tables.ts` and `error.ts`.
22
- - Which PostgreSQL coverage edges need a supported contract: writes followed by TRUNCATE, or identical table names in several schemas? Dedicated tests are needed before either behavior can be promised.