effect-cf 0.40.2 → 0.40.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # effect-cf
2
2
 
3
+ ## 0.40.3
4
+
5
+ ### Patch Changes
6
+
7
+ - [#157](https://github.com/danieljvdm/effect-cf/pull/157) [`279eecd`](https://github.com/danieljvdm/effect-cf/commit/279eecd1a5ea9112e727497e0aac666142e7a7f8) Thanks [@danieljvdm](https://github.com/danieljvdm)! - Prevent Durable Object SQLite transactions from stalling when a blocked owner timer precedes an Effect scheduler yield. Keep transaction isolation, rollback, and the caller's scheduler after the transaction completes.
8
+
3
9
  ## 0.40.2
4
10
 
5
11
  ### Patch Changes
package/dist/D1.d.mts CHANGED
@@ -2,8 +2,8 @@ import { WorkerEnvironment } from "./Environment.mjs";
2
2
  import { BindingNotFoundError, BindingService, BindingValidationError } from "./Binding.mjs";
3
3
  import * as Layer$1 from "effect/Layer";
4
4
  import { D1Client } from "@effect/sql-d1";
5
- import { Config } from "effect";
6
5
  import { SqlClient } from "effect/unstable/sql";
6
+ import { Config } from "effect";
7
7
  declare namespace D1_d_exports {
8
8
  export { D1Definition, D1Service, D1SqlLayerOptions, Service, TypeId, make };
9
9
  }
@@ -1,16 +1,25 @@
1
1
  import { __exportAll } from "./_virtual/_rolldown/runtime.mjs";
2
2
  import { DurableObjectState } from "./DurableObjectState.mjs";
3
+ import * as Context from "effect/Context";
3
4
  import * as Effect from "effect/Effect";
4
5
  import * as Layer from "effect/Layer";
5
6
  import { SqliteClient } from "@effect/sql-sqlite-do";
7
+ import * as Scheduler from "effect/Scheduler";
8
+ import * as Reactivity from "effect/unstable/reactivity/Reactivity";
9
+ import { SqlClient } from "effect/unstable/sql";
6
10
  //#region src/DurableObjectSqlite.ts
7
11
  var DurableObjectSqlite_exports = /* @__PURE__ */ __exportAll({ layer: () => layer });
8
- const layer = (options) => Layer.unwrap(Effect.gen(function* () {
12
+ const layer = (options) => Layer.effectContext(Effect.gen(function* () {
9
13
  const state = yield* DurableObjectState;
10
- return SqliteClient.layer({
14
+ const client = yield* SqliteClient.make({
11
15
  ...options,
12
16
  storage: state.raw.storage
13
17
  });
14
- }));
18
+ const original = client.withTransaction;
19
+ const scheduler = new Scheduler.MixedScheduler("sync");
20
+ const withTransaction = (body) => original(body).pipe(Effect.provideService(Scheduler.Scheduler, scheduler));
21
+ Object.assign(client, { withTransaction });
22
+ return Context.make(SqliteClient.SqliteClient, client).pipe(Context.add(SqlClient.SqlClient, client));
23
+ })).pipe(Layer.provide(Reactivity.layer));
15
24
  //#endregion
16
25
  export { DurableObjectSqlite_exports, layer };
@@ -2,8 +2,8 @@ import { WorkerEnvironment } from "./Environment.mjs";
2
2
  import { BindingNotFoundError, BindingValidationError } from "./Binding.mjs";
3
3
  import { LayerOptions, TagClass } from "./Hyperdrive.mjs";
4
4
  import * as Layer from "effect/Layer";
5
- import { PgClient } from "@effect/sql-pg";
6
5
  import { SqlClient, SqlError } from "effect/unstable/sql";
6
+ import { PgClient } from "@effect/sql-pg";
7
7
  //#region src/HyperdrivePg.d.ts
8
8
  type PgLayerOptions = Omit<Parameters<typeof PgClient.makeClient>[0], "url" | "host" | "port" | "path" | "ssl" | "database" | "username" | "password" | "stream">;
9
9
  declare const layer: <Self, Id extends string>(tag: TagClass<Self, Id>, binding: LayerOptions, options?: PgLayerOptions) => Layer.Layer<PgClient.PgClient | SqlClient.SqlClient, BindingNotFoundError | BindingValidationError | SqlError.SqlError, WorkerEnvironment>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "effect-cf",
3
- "version": "0.40.2",
3
+ "version": "0.40.3",
4
4
  "description": "Effect-native primitives for Cloudflare Workers and bindings.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -1,7 +1,10 @@
1
1
  import { SqliteClient } from "@effect/sql-sqlite-do";
2
+ import * as Context from "effect/Context";
2
3
  import * as Effect from "effect/Effect";
3
4
  import * as Layer from "effect/Layer";
4
- import type { SqlClient } from "effect/unstable/sql";
5
+ import * as Scheduler from "effect/Scheduler";
6
+ import * as Reactivity from "effect/unstable/reactivity/Reactivity";
7
+ import { SqlClient } from "effect/unstable/sql";
5
8
 
6
9
  import { DurableObjectState } from "./DurableObjectState";
7
10
 
@@ -10,10 +13,22 @@ export type SqliteLayerOptions = Omit<SqliteClient.SqliteClientConfig, "db" | "s
10
13
  export const layer = (
11
14
  options?: SqliteLayerOptions,
12
15
  ): Layer.Layer<SqliteClient.SqliteClient | SqlClient.SqlClient, never, DurableObjectState> =>
13
- Layer.unwrap(
16
+ Layer.effectContext(
14
17
  Effect.gen(function* () {
15
18
  const state = yield* DurableObjectState;
19
+ const client = yield* SqliteClient.make({ ...options, storage: state.raw.storage });
20
+ const original = client.withTransaction;
21
+ const scheduler = new Scheduler.MixedScheduler("sync");
22
+ const withTransaction: SqliteClient.SqliteClient["withTransaction"] = (body) =>
23
+ original(body).pipe(Effect.provideService(Scheduler.Scheduler, scheduler));
16
24
 
17
- return SqliteClient.layer({ ...options, storage: state.raw.storage });
25
+ // Native timers retain their input gate. A blocked parent timer can prevent
26
+ // a transaction's later timer from running, so yield through microtasks until
27
+ // the native transaction settles. Keep the original client and SQL permit.
28
+ Object.assign(client, { withTransaction });
29
+
30
+ return Context.make(SqliteClient.SqliteClient, client).pipe(
31
+ Context.add(SqlClient.SqlClient, client),
32
+ );
18
33
  }),
19
- );
34
+ ).pipe(Layer.provide(Reactivity.layer));