effect-cf 0.28.1 → 0.29.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/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  # effect-cf
2
2
 
3
+ ## 0.29.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#108](https://github.com/danieljvdm/effect-cf/pull/108) [`735b6d9`](https://github.com/danieljvdm/effect-cf/commit/735b6d95e4b62c7ade598a7f18ba2d8b4ee60f87) Thanks [@danieljvdm](https://github.com/danieljvdm)! - Require the Effect 4.0.0-rc.110 family — dependency ranges move from `^4.0.0-beta.107 <4.0.0-rc.0` to `^4.0.0-rc.110`.
8
+
9
+ ### Patch Changes
10
+
11
+ - [#66](https://github.com/danieljvdm/effect-cf/pull/66) [`fe34f95`](https://github.com/danieljvdm/effect-cf/commit/fe34f95abc92f4637968186aeebbb8033157c041) Thanks [@danieljvdm](https://github.com/danieljvdm)! - `DurableObjectStorage.transaction` and `transactionSync` now recover the aborting `Exit` by identity instead of re-deriving its type from the untyped `catch` binding. Failures raised inside a transaction keep the same typed error channel, and a failure thrown by the platform itself is still reported as `StorageOperationError`. No public API change.
12
+
3
13
  ## 0.28.1
4
14
 
5
15
  ### Patch Changes
@@ -1,4 +1,4 @@
1
- import { t as DurableObjectState } from "./DurableObjectState-BjkK2kwH.mjs";
1
+ import { t as DurableObjectState } from "./DurableObjectState-DnnLoHV-.mjs";
2
2
  import { fromClient } from "./ComputerArtifacts.mjs";
3
3
  import { t as lookup } from "./ComputerWorkspaceHostRegistry-CY5Fv4Ng.mjs";
4
4
  import { Context, Effect, Layer, Predicate, Schema, Stream } from "effect";
@@ -99,24 +99,28 @@ const fromDurableObjectStorage = (storage) => ({
99
99
  setAlarm: (scheduledTime, options) => tryStoragePromise("setAlarm", () => storage.setAlarm(scheduledTime, options)),
100
100
  deleteAlarm: (options) => tryStoragePromise("deleteAlarm", () => storage.deleteAlarm(options)),
101
101
  transactionSync: (closure) => Effect.context().pipe(Effect.flatMap((context) => Effect.suspend(() => {
102
+ let aborted;
102
103
  try {
103
104
  return Effect.succeed(storage.transactionSync(() => {
104
105
  const exit = Effect.runSyncExitWith(context)(closure());
105
106
  if (Exit.isSuccess(exit)) return exit.value;
107
+ aborted = exit;
106
108
  throw exit;
107
109
  }));
108
110
  } catch (cause) {
109
- if (Exit.isExit(cause) && Exit.isFailure(cause)) return Effect.failCause(cause.cause);
111
+ if (aborted !== void 0 && cause === aborted && Exit.isFailure(aborted)) return Effect.failCause(aborted.cause);
110
112
  return Effect.fail(storageError("transactionSync", cause));
111
113
  }
112
114
  }))),
113
115
  transaction: (closure) => Effect.context().pipe(Effect.flatMap((context) => Effect.callback((resume) => {
116
+ let aborted;
114
117
  storage.transaction(async (txn) => {
115
118
  const exit = await Effect.runPromiseExitWith(context)(closure(fromDurableObjectTransaction(txn)));
116
119
  if (Exit.isSuccess(exit)) return exit.value;
120
+ aborted = exit;
117
121
  throw exit;
118
122
  }).then((value) => resume(Effect.succeed(value)), (cause) => {
119
- if (Exit.isExit(cause) && Exit.isFailure(cause)) resume(Effect.failCause(cause.cause));
123
+ if (aborted !== void 0 && cause === aborted && Exit.isFailure(aborted)) resume(Effect.failCause(aborted.cause));
120
124
  else resume(Effect.fail(storageError("transaction", cause)));
121
125
  });
122
126
  }))),
package/dist/Vitest.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  import { a as WorkerEnvironment, i as WorkerConfig } from "./ErrorMessage-BM0K-Nik.mjs";
2
- import { r as fromDurableObjectState, t as DurableObjectState } from "./DurableObjectState-BjkK2kwH.mjs";
2
+ import { r as fromDurableObjectState, t as DurableObjectState } from "./DurableObjectState-DnnLoHV-.mjs";
3
3
  import { ConfigProvider, Effect, Exit, Layer } from "effect";
4
4
  import { env } from "cloudflare:workers";
5
5
  import { abortAllDurableObjects as abortAllDurableObjects$1, adminSecretsStore as adminSecretsStore$1, applyD1Migrations as applyD1Migrations$1, createExecutionContext, createMessageBatch, createPagesEventContext, createScheduledController, evictAllDurableObjects as evictAllDurableObjects$1, evictDurableObject as evictDurableObject$1, getQueueResult, introspectWorkflow as introspectWorkflow$1, introspectWorkflowInstance as introspectWorkflowInstance$1, listDurableObjectIds as listDurableObjectIds$1, reset as reset$1, runDurableObjectAlarm as runDurableObjectAlarm$1, runInDurableObject as runInDurableObject$1, waitOnExecutionContext } from "cloudflare:test";
package/dist/index.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
2
2
  import { a as WorkerEnvironment, i as WorkerConfig, n as violationsMessage, r as Environment_exports, t as causeMessage } from "./ErrorMessage-BM0K-Nik.mjs";
3
3
  import { a as layer$19, i as Service$2, n as Artifacts_exports, r as Binding_exports } from "./Artifacts-rq3hUKQE.mjs";
4
- import { a as DurableObjectWebSocket_exports, i as fromExecutionContext, n as DurableObjectState_exports, o as fromWebSocket, r as fromDurableObjectState, s as DurableObjectStorage_exports, t as DurableObjectState } from "./DurableObjectState-BjkK2kwH.mjs";
4
+ import { a as DurableObjectWebSocket_exports, i as fromExecutionContext, n as DurableObjectState_exports, o as fromWebSocket, r as fromDurableObjectState, s as DurableObjectStorage_exports, t as DurableObjectState } from "./DurableObjectState-DnnLoHV-.mjs";
5
5
  import { Cause, Clock, Config, ConfigProvider, Context, Data, DateTime, Duration, Effect, Exit, Function as Function$1, Layer, ManagedRuntime, Option, Predicate, Queue, Result, Schema } from "effect";
6
6
  import { FetchHttpClient, HttpClient, HttpClientRequest, HttpEffect, HttpServerRequest, HttpServerResponse } from "effect/unstable/http";
7
7
  import { OtlpExporter, OtlpLogger, OtlpMetrics, OtlpSerialization, OtlpTracer } from "effect/unstable/observability";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "effect-cf",
3
- "version": "0.28.1",
3
+ "version": "0.29.0",
4
4
  "description": "Effect-native primitives for Cloudflare Workers and bindings.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -64,7 +64,7 @@
64
64
  "@cloudflare/containers": "catalog:",
65
65
  "@cloudflare/vitest-pool-workers": "catalog:",
66
66
  "@cloudflare/workers-types": "catalog:",
67
- "@effect/platform-node": "^4.0.0-beta.107 <4.0.0-rc.0",
67
+ "@effect/platform-node": "^4.0.0-rc.110",
68
68
  "@effect/sql-d1": "catalog:",
69
69
  "@effect/sql-pg": "catalog:",
70
70
  "@effect/sql-sqlite-do": "catalog:",
@@ -79,10 +79,10 @@
79
79
  "@cloudflare/computer": "^0.2.0",
80
80
  "@cloudflare/vitest-pool-workers": "^0.21.3",
81
81
  "@cloudflare/workers-types": "^4.20260611.1",
82
- "@effect/sql-d1": "^4.0.0-beta.107 <4.0.0-rc.0",
83
- "@effect/sql-pg": "^4.0.0-beta.107 <4.0.0-rc.0",
84
- "@effect/sql-sqlite-do": "^4.0.0-beta.107 <4.0.0-rc.0",
85
- "effect": "^4.0.0-beta.107 <4.0.0-rc.0"
82
+ "@effect/sql-d1": "^4.0.0-rc.110",
83
+ "@effect/sql-pg": "^4.0.0-rc.110",
84
+ "@effect/sql-sqlite-do": "^4.0.0-rc.110",
85
+ "effect": "^4.0.0-rc.110"
86
86
  },
87
87
  "peerDependenciesMeta": {
88
88
  "@cloudflare/computer": {
@@ -200,6 +200,7 @@ export const make = <
200
200
  // SAFETY: event-layer bypass is used only for initialize; otherwise an absent layer means REvent is never.
201
201
  return Runtime.runEventPromise(
202
202
  this.runtime,
203
+ // @effect-diagnostics-next-line unsafeEffectTypeAssertion:off
203
204
  effect as Effect.Effect<A, E, HandlerContext<ROut>>,
204
205
  );
205
206
  }
@@ -320,7 +320,12 @@ export const fromDurableObjectStorage = (
320
320
  transactionSync: <A, E, R>(closure: () => Effect.Effect<A, E, R>) =>
321
321
  Effect.context<R>().pipe(
322
322
  Effect.flatMap((context) =>
323
- Effect.suspend(() => {
323
+ Effect.suspend((): Effect.Effect<A, E | StorageOperationError> => {
324
+ // Cloudflare rolls the transaction back when the callback throws, so a
325
+ // failed Exit is thrown to abort it. Keep a typed reference to that
326
+ // Exit rather than recovering its type from the untyped catch binding.
327
+ let aborted: Exit.Exit<A, E> | undefined;
328
+
324
329
  try {
325
330
  return Effect.succeed(
326
331
  storage.transactionSync(() => {
@@ -329,18 +334,14 @@ export const fromDurableObjectStorage = (
329
334
  if (Exit.isSuccess(exit)) {
330
335
  return exit.value;
331
336
  }
337
+ aborted = exit;
332
338
 
333
339
  throw exit;
334
340
  }),
335
341
  );
336
342
  } catch (cause) {
337
- if (Exit.isExit(cause) && Exit.isFailure(cause)) {
338
- // SAFETY: Exit.isFailure proves this cause carries the closure's typed E failure.
339
- return Effect.failCause(cause.cause) as Effect.Effect<
340
- A,
341
- E | StorageOperationError,
342
- R
343
- >;
343
+ if (aborted !== undefined && cause === aborted && Exit.isFailure(aborted)) {
344
+ return Effect.failCause(aborted.cause);
344
345
  }
345
346
 
346
347
  return Effect.fail(storageError("transactionSync", cause));
@@ -352,6 +353,10 @@ export const fromDurableObjectStorage = (
352
353
  Effect.context<R>().pipe(
353
354
  Effect.flatMap((context) =>
354
355
  Effect.callback<A, E | StorageOperationError>((resume) => {
356
+ // See `transactionSync`: the thrown Exit aborts Cloudflare's
357
+ // transaction, and holding it here keeps its error type.
358
+ let aborted: Exit.Exit<A, E> | undefined;
359
+
355
360
  void storage
356
361
  .transaction(async (txn) => {
357
362
  const exit = await Effect.runPromiseExitWith(context)(
@@ -361,17 +366,15 @@ export const fromDurableObjectStorage = (
361
366
  if (Exit.isSuccess(exit)) {
362
367
  return exit.value;
363
368
  }
369
+ aborted = exit;
364
370
 
365
371
  throw exit;
366
372
  })
367
373
  .then(
368
374
  (value) => resume(Effect.succeed(value)),
369
375
  (cause) => {
370
- if (Exit.isExit(cause) && Exit.isFailure(cause)) {
371
- // SAFETY: Exit.isFailure proves this cause carries the closure's typed E failure.
372
- resume(
373
- Effect.failCause(cause.cause) as Effect.Effect<A, E | StorageOperationError>,
374
- );
376
+ if (aborted !== undefined && cause === aborted && Exit.isFailure(aborted)) {
377
+ resume(Effect.failCause(aborted.cause));
375
378
  } else {
376
379
  resume(Effect.fail(storageError("transaction", cause)));
377
380
  }
package/src/Worker.ts CHANGED
@@ -392,6 +392,7 @@ export function make<
392
392
  // SAFETY: the public make overloads permit an absent event layer only when REvent is never.
393
393
  return Runtime.runEventPromise(
394
394
  this.runtime,
395
+ // @effect-diagnostics-next-line unsafeEffectTypeAssertion:off
395
396
  effect as Effect.Effect<A, E, RuntimeContext<ROut> | Scope.Scope>,
396
397
  );
397
398
  }
package/src/Workflow.ts CHANGED
@@ -157,6 +157,7 @@ const fromWorkflowStep = (
157
157
  Effect.provideService(
158
158
  Effect.provideContext(
159
159
  // SAFETY: WorkflowStepContext is provided immediately below; context supplies every other R service.
160
+ // @effect-diagnostics-next-line unsafeEffectTypeAssertion:off
160
161
  effect as Effect.Effect<A, E, Exclude<R, WorkflowStepContext>>,
161
162
  context,
162
163
  ),