effect-cf 0.28.1 → 0.30.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 +20 -0
- package/README.md +78 -0
- package/dist/{Artifacts-rq3hUKQE.mjs → Artifacts-CSIk1Oml.mjs} +4 -128
- package/dist/Binding-pfilNJmP.mjs +129 -0
- package/dist/ComputerArtifacts.mjs +1 -1
- package/dist/ComputerWorkspace.d.mts +1 -1
- package/dist/ComputerWorkspace.mjs +1 -1
- package/dist/ContainerNamespace-CFjiLw8b.d.mts +155 -0
- package/dist/{DurableObjectState-BjkK2kwH.mjs → DurableObjectState-CepagPkX.mjs} +14 -3
- package/dist/{DurableObjectState-OupNMMUl.d.mts → DurableObjectState-D3k-WRnd.d.mts} +5 -1
- package/dist/Sandbox.d.mts +222 -0
- package/dist/Sandbox.mjs +361 -0
- package/dist/Vitest.d.mts +2 -2
- package/dist/Vitest.mjs +1 -1
- package/dist/{WorkflowBinding-DUZtKCVM.d.mts → WorkflowBinding-CtrmxfdT.d.mts} +1 -1
- package/dist/index.d.mts +45 -195
- package/dist/index.mjs +3 -2
- package/package.json +16 -6
- package/src/DurableObject.ts +1 -0
- package/src/DurableObjectStorage.ts +56 -14
- package/src/Sandbox.ts +1094 -0
- package/src/Worker.ts +1 -0
- package/src/Workflow.ts +1 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
# effect-cf
|
|
2
2
|
|
|
3
|
+
## 0.30.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#110](https://github.com/danieljvdm/effect-cf/pull/110) [`9037864`](https://github.com/danieljvdm/effect-cf/commit/9037864c1acbd15e03b6a71733d49fa123244046) Thanks [@danieljvdm](https://github.com/danieljvdm)! - Add `setAlarmAfter` to Durable Object storage and transaction wrappers for scheduling alarms with Effect `Duration.Input` values.
|
|
8
|
+
|
|
9
|
+
- [#112](https://github.com/danieljvdm/effect-cf/pull/112) [`cbe0206`](https://github.com/danieljvdm/effect-cf/commit/cbe0206557b101c7bb4050e53366e53af9aa8e5f) Thanks [@danieljvdm](https://github.com/danieljvdm)! - Add `effect-cf/sandbox`: an Effect-native client for the Cloudflare Sandbox SDK 1.0 API (`@cloudflare/sandbox@next`, an optional peer dependency loaded lazily on first use).
|
|
10
|
+
|
|
11
|
+
`Sandbox.Tag`/`Sandbox.make` create a typed service for a Sandbox Durable Object namespace binding, and `layer({ binding })` validates the binding from `WorkerEnvironment`. The instance client covers the complete `ISandbox` contract plus lifecycle, preview-port, tunnel, bucket-mount, and backup operations: `exec` returns a process handle with typed log `Stream`s and interruption-aware waits, `watch` decodes file-watch Server-Sent Events into an Effect `Stream`, `readFileStream` streams raw bytes, and terminals are wrapped as Effect handles. Failures are reported as a typed `SandboxOperationError` that preserves the SDK's error classes as `cause`, and `Sandbox.proxyToSandbox` routes preview-URL traffic as an `Option<Response>` Effect.
|
|
12
|
+
|
|
13
|
+
## 0.29.0
|
|
14
|
+
|
|
15
|
+
### Minor Changes
|
|
16
|
+
|
|
17
|
+
- [#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`.
|
|
18
|
+
|
|
19
|
+
### Patch Changes
|
|
20
|
+
|
|
21
|
+
- [#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.
|
|
22
|
+
|
|
3
23
|
## 0.28.1
|
|
4
24
|
|
|
5
25
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -33,6 +33,14 @@ Workspace Git operations additionally require `@platformatic/vfs`,
|
|
|
33
33
|
bun add "@platformatic/vfs@^0.4.0"
|
|
34
34
|
```
|
|
35
35
|
|
|
36
|
+
The Sandbox integration is an optional peer. Install the `@next` release line
|
|
37
|
+
of `@cloudflare/sandbox` (the Sandbox SDK 1.0 API) only in applications that
|
|
38
|
+
import `effect-cf/sandbox`:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
bun add "@cloudflare/sandbox@next"
|
|
42
|
+
```
|
|
43
|
+
|
|
36
44
|
## Goal
|
|
37
45
|
|
|
38
46
|
Cloudflare APIs return promises and expose platform-specific bindings. `effect-cf` wraps those boundaries as `Context`, `Layer`, and `Effect` values so application code stays inside one managed Effect runtime.
|
|
@@ -54,6 +62,7 @@ Runtime creation belongs at Cloudflare entrypoints, not inside binding helpers.
|
|
|
54
62
|
- `effect-cf/computer-workspace` - scoped Effect wrappers for the complete Cloudflare Computer filesystem, Git, runtime, Assets, Artifacts, and Think-compatible client surfaces
|
|
55
63
|
- `effect-cf/computer-artifacts` - session-isolated Artifacts repositories backed by `@cloudflare/computer/artifacts`
|
|
56
64
|
- `effect-cf/computer-workspace-host` - optional Durable Object host mixin, worker-shell backend wiring, and `WorkspaceServiceProxy`
|
|
65
|
+
- `effect-cf/sandbox` - Effect-native client for Cloudflare Sandbox containers: processes with log streams, files and watches, preview URLs, tunnels, terminals, bucket mounts, and backups
|
|
57
66
|
- `Hyperdrive` - typed Hyperdrive binding helper for connection strings and optional Postgres SQL integration
|
|
58
67
|
- `Images` - typed Cloudflare Images binding helper with transformation APIs and optional hosted image operations
|
|
59
68
|
- `Email` - typed Cloudflare Email Service binding helper for `send_email` bindings, with limit validation and typed error codes
|
|
@@ -322,6 +331,75 @@ const stub = Sandboxes.byName("codex").rawUnsafe;
|
|
|
322
331
|
See [`examples/containers/README.md`](../../examples/containers/README.md) for
|
|
323
332
|
the corresponding Wrangler configuration and entrypoint responsibilities.
|
|
324
333
|
|
|
334
|
+
## Sandbox Example
|
|
335
|
+
|
|
336
|
+
`effect-cf/sandbox` wraps the [Cloudflare Sandbox SDK](https://github.com/cloudflare/sandbox-sdk)
|
|
337
|
+
1.0 API (`@cloudflare/sandbox@next`). The Sandbox Durable Object class remains
|
|
338
|
+
owned by `@cloudflare/sandbox`; `effect-cf` wraps the namespace binding used by
|
|
339
|
+
a calling Worker and loads the SDK lazily, so applications without the optional
|
|
340
|
+
peer are unaffected.
|
|
341
|
+
|
|
342
|
+
```ts
|
|
343
|
+
import { Effect, Option } from "effect";
|
|
344
|
+
import { Worker } from "effect-cf";
|
|
345
|
+
import * as Sandbox from "effect-cf/sandbox";
|
|
346
|
+
|
|
347
|
+
export { Sandbox as SandboxDurableObject } from "@cloudflare/sandbox";
|
|
348
|
+
|
|
349
|
+
class Sandboxes extends Sandbox.Tag<Sandboxes>()("Sandboxes") {}
|
|
350
|
+
|
|
351
|
+
const SandboxesLive = Sandboxes.layer({ binding: "Sandbox" });
|
|
352
|
+
|
|
353
|
+
export default Worker.make(SandboxesLive, {
|
|
354
|
+
fetch: Effect.gen(function* () {
|
|
355
|
+
const request = yield* Worker.NativeRequest;
|
|
356
|
+
|
|
357
|
+
// Route preview-URL traffic before any other routing.
|
|
358
|
+
const proxied = yield* Sandbox.proxyToSandbox(request);
|
|
359
|
+
if (Option.isSome(proxied)) {
|
|
360
|
+
return proxied.value;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
const sandbox = yield* Sandboxes.get("my-sandbox");
|
|
364
|
+
const handle = yield* sandbox.exec(["python3", "-c", "print(2 + 2)"]);
|
|
365
|
+
const output = yield* handle.outputText();
|
|
366
|
+
|
|
367
|
+
return new Response(output.stdout);
|
|
368
|
+
}),
|
|
369
|
+
});
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
The instance client mirrors the complete `ISandbox` client contract plus the
|
|
373
|
+
lifecycle, port, tunnel, and backup operations the SDK client proxies to the
|
|
374
|
+
Sandbox Durable Object. `exec` returns a process handle whose `logs` is an
|
|
375
|
+
Effect `Stream` of typed log events; `watch` decodes the SDK's Server-Sent
|
|
376
|
+
Events into a `Stream` of file-watch events; `readFileStream` streams raw
|
|
377
|
+
bytes. Interruptible waits (`waitForExit`, `waitForLog`, `output`,
|
|
378
|
+
`waitForPort`) abort the underlying SDK call when the Effect is interrupted.
|
|
379
|
+
Failures carry a typed `SandboxOperationError` whose `cause` preserves the
|
|
380
|
+
SDK's rich error classes (`ProcessNotFoundError`, `PortNotExposedError`, and
|
|
381
|
+
friends) for inspection.
|
|
382
|
+
|
|
383
|
+
The corresponding `wrangler.jsonc` declares the container image and Durable
|
|
384
|
+
Object binding; note the SDK requires the exported Durable Object class to be
|
|
385
|
+
reachable under the configured `class_name`:
|
|
386
|
+
|
|
387
|
+
```jsonc
|
|
388
|
+
{
|
|
389
|
+
"containers": [
|
|
390
|
+
{
|
|
391
|
+
"class_name": "SandboxDurableObject",
|
|
392
|
+
"image": "./Dockerfile",
|
|
393
|
+
"instance_type": "lite",
|
|
394
|
+
},
|
|
395
|
+
],
|
|
396
|
+
"durable_objects": {
|
|
397
|
+
"bindings": [{ "class_name": "SandboxDurableObject", "name": "Sandbox" }],
|
|
398
|
+
},
|
|
399
|
+
"migrations": [{ "tag": "v1", "new_sqlite_classes": ["SandboxDurableObject"] }],
|
|
400
|
+
}
|
|
401
|
+
```
|
|
402
|
+
|
|
325
403
|
## Queue Example
|
|
326
404
|
|
|
327
405
|
Queues define the message contract once. The same class is the producer service tag and the consumer Worker definition: use `YourQueue.layer({ binding })` to provide a Cloudflare producer binding from `WorkerEnvironment`, and use `.make(...)` for the consumer Worker entrypoint.
|
|
@@ -1,131 +1,7 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
var Binding_exports = /* @__PURE__ */ __exportAll({
|
|
6
|
-
BindingNotFoundError: () => BindingNotFoundError,
|
|
7
|
-
BindingValidationError: () => BindingValidationError,
|
|
8
|
-
Service: () => Service,
|
|
9
|
-
TypeId: () => TypeId,
|
|
10
|
-
layer: () => layer$1
|
|
11
|
-
});
|
|
12
|
-
/** Internal type id marker used by binding helper services. */
|
|
13
|
-
const TypeId = "~effect-cf/Binding";
|
|
14
|
-
/** Error raised when a configured binding does not exist on `env`. */
|
|
15
|
-
var BindingNotFoundError = class extends Data.TaggedError("BindingNotFoundError") {};
|
|
16
|
-
/** Error raised when a binding exists but does not match the expected shape. */
|
|
17
|
-
var BindingValidationError = class extends Data.TaggedError("BindingValidationError") {};
|
|
18
|
-
const defaultExpected = "Cloudflare binding resource";
|
|
19
|
-
const isPropertyTarget = (value) => Predicate.isObjectOrArray(value) || Predicate.isFunction(value);
|
|
20
|
-
const getObjectName = (value) => {
|
|
21
|
-
const tag = (() => {
|
|
22
|
-
try {
|
|
23
|
-
return Object.prototype.toString.call(value).slice(8, -1);
|
|
24
|
-
} catch {
|
|
25
|
-
return Predicate.isFunction(value) ? "function" : "object";
|
|
26
|
-
}
|
|
27
|
-
})();
|
|
28
|
-
const constructorName = (() => {
|
|
29
|
-
try {
|
|
30
|
-
return "constructor" in value && Predicate.isFunction(value.constructor) && Predicate.isString(value.constructor.name) ? value.constructor.name : void 0;
|
|
31
|
-
} catch {
|
|
32
|
-
return;
|
|
33
|
-
}
|
|
34
|
-
})();
|
|
35
|
-
if (tag !== "Object") return tag;
|
|
36
|
-
if (constructorName !== void 0 && constructorName !== "" && constructorName !== "Object") return constructorName;
|
|
37
|
-
return tag;
|
|
38
|
-
};
|
|
39
|
-
const propertyNames = (value) => {
|
|
40
|
-
const names = /* @__PURE__ */ new Set();
|
|
41
|
-
for (const target of [value, Object.getPrototypeOf(value)]) {
|
|
42
|
-
if (target === null || target === Object.prototype || target === Function.prototype) continue;
|
|
43
|
-
try {
|
|
44
|
-
for (const name of Object.getOwnPropertyNames(target)) names.add(name);
|
|
45
|
-
} catch {
|
|
46
|
-
continue;
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
return [...names].filter((name) => name !== "constructor").sort();
|
|
50
|
-
};
|
|
51
|
-
const isMethod = (value, name) => {
|
|
52
|
-
try {
|
|
53
|
-
return Predicate.hasProperty(value, name) && Predicate.isFunction(value[name]);
|
|
54
|
-
} catch {
|
|
55
|
-
return false;
|
|
56
|
-
}
|
|
57
|
-
};
|
|
58
|
-
const describeActual = (value) => {
|
|
59
|
-
if (value === null) return "null";
|
|
60
|
-
if (!isPropertyTarget(value)) {
|
|
61
|
-
if (Predicate.isString(value)) return "string";
|
|
62
|
-
if (Predicate.isNumber(value)) return "number";
|
|
63
|
-
if (Predicate.isBoolean(value)) return "boolean";
|
|
64
|
-
if (Predicate.isBigInt(value)) return "bigint";
|
|
65
|
-
if (Predicate.isSymbol(value)) return "symbol";
|
|
66
|
-
return "undefined";
|
|
67
|
-
}
|
|
68
|
-
const names = propertyNames(value);
|
|
69
|
-
const methods = names.filter((name) => isMethod(value, name));
|
|
70
|
-
const properties = names.filter((name) => !methods.includes(name));
|
|
71
|
-
const details = [methods.length > 0 ? `methods ${methods.join(", ")}` : void 0, properties.length > 0 ? `properties ${properties.join(", ")}` : void 0].filter((detail) => detail !== void 0);
|
|
72
|
-
if (details.length === 0) return getObjectName(value);
|
|
73
|
-
return `${getObjectName(value)} with ${details.join("; ")}`;
|
|
74
|
-
};
|
|
75
|
-
const getBinding = (env, binding, isResource, options) => Effect.gen(function* () {
|
|
76
|
-
if (!isPropertyTarget(env)) {
|
|
77
|
-
const actual = describeActual(env);
|
|
78
|
-
return yield* Effect.fail(new BindingValidationError({
|
|
79
|
-
binding,
|
|
80
|
-
expected: "WorkerEnvironment object",
|
|
81
|
-
actual,
|
|
82
|
-
message: `Cloudflare binding "${binding}" failed validation. Expected WorkerEnvironment object; got ${actual}`
|
|
83
|
-
}));
|
|
84
|
-
}
|
|
85
|
-
const resource = Predicate.hasProperty(env, binding) ? env[binding] : void 0;
|
|
86
|
-
if (resource === void 0) return yield* Effect.fail(new BindingNotFoundError({
|
|
87
|
-
binding,
|
|
88
|
-
message: `Cloudflare binding "${binding}" was not found in WorkerEnvironment`
|
|
89
|
-
}));
|
|
90
|
-
if (!isResource(resource)) {
|
|
91
|
-
const expected = options?.expected ?? defaultExpected;
|
|
92
|
-
const actual = describeActual(resource);
|
|
93
|
-
return yield* Effect.fail(new BindingValidationError({
|
|
94
|
-
binding,
|
|
95
|
-
expected,
|
|
96
|
-
actual,
|
|
97
|
-
message: `Cloudflare binding "${binding}" failed validation. Expected ${expected}; got ${actual}`
|
|
98
|
-
}));
|
|
99
|
-
}
|
|
100
|
-
return resource;
|
|
101
|
-
});
|
|
102
|
-
/**
|
|
103
|
-
* The overloads on {@link layer} and {@link Service} guarantee that
|
|
104
|
-
* `Service = Resource` whenever `wrap` is absent, making the fallback cast
|
|
105
|
-
* safe.
|
|
106
|
-
*/
|
|
107
|
-
const makeBindingLayer = (tag, binding, isResource, wrap, options) => Layer.effect(tag, Effect.gen(function* () {
|
|
108
|
-
const env = yield* WorkerEnvironment;
|
|
109
|
-
const resource = yield* getBinding(env, binding, isResource, options);
|
|
110
|
-
return wrap === void 0 ? resource : wrap(resource);
|
|
111
|
-
}));
|
|
112
|
-
function layer$1(tag, binding, isResource, wrap, options) {
|
|
113
|
-
return makeBindingLayer(tag, binding, isResource, wrap, options);
|
|
114
|
-
}
|
|
115
|
-
const Service = () => {
|
|
116
|
-
function makeService(id, binding, isResource, wrap, options) {
|
|
117
|
-
const tag = Context.Service()(`effect-cf/Binding/${id}`);
|
|
118
|
-
const serviceLayer = makeBindingLayer(tag, binding, isResource, wrap, options);
|
|
119
|
-
return Object.assign(tag, {
|
|
120
|
-
[TypeId]: TypeId,
|
|
121
|
-
id,
|
|
122
|
-
binding,
|
|
123
|
-
layer: serviceLayer
|
|
124
|
-
});
|
|
125
|
-
}
|
|
126
|
-
return makeService;
|
|
127
|
-
};
|
|
128
|
-
//#endregion
|
|
2
|
+
import { t as causeMessage } from "./ErrorMessage-BM0K-Nik.mjs";
|
|
3
|
+
import { r as layer$1 } from "./Binding-pfilNJmP.mjs";
|
|
4
|
+
import { Context, Data, Effect, Predicate, Schema } from "effect";
|
|
129
5
|
//#region src/Artifacts.ts
|
|
130
6
|
var Artifacts_exports = /* @__PURE__ */ __exportAll({
|
|
131
7
|
ArtifactsOperationError: () => ArtifactsOperationError,
|
|
@@ -254,4 +130,4 @@ const Tag = () => (id) => {
|
|
|
254
130
|
});
|
|
255
131
|
};
|
|
256
132
|
//#endregion
|
|
257
|
-
export {
|
|
133
|
+
export { Artifacts_exports as n, ArtifactsOperationError as t };
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
|
|
2
|
+
import { a as WorkerEnvironment } from "./ErrorMessage-BM0K-Nik.mjs";
|
|
3
|
+
import { Context, Data, Effect, Layer, Predicate } from "effect";
|
|
4
|
+
//#region src/Binding.ts
|
|
5
|
+
var Binding_exports = /* @__PURE__ */ __exportAll({
|
|
6
|
+
BindingNotFoundError: () => BindingNotFoundError,
|
|
7
|
+
BindingValidationError: () => BindingValidationError,
|
|
8
|
+
Service: () => Service,
|
|
9
|
+
TypeId: () => TypeId,
|
|
10
|
+
layer: () => layer
|
|
11
|
+
});
|
|
12
|
+
/** Internal type id marker used by binding helper services. */
|
|
13
|
+
const TypeId = "~effect-cf/Binding";
|
|
14
|
+
/** Error raised when a configured binding does not exist on `env`. */
|
|
15
|
+
var BindingNotFoundError = class extends Data.TaggedError("BindingNotFoundError") {};
|
|
16
|
+
/** Error raised when a binding exists but does not match the expected shape. */
|
|
17
|
+
var BindingValidationError = class extends Data.TaggedError("BindingValidationError") {};
|
|
18
|
+
const defaultExpected = "Cloudflare binding resource";
|
|
19
|
+
const isPropertyTarget = (value) => Predicate.isObjectOrArray(value) || Predicate.isFunction(value);
|
|
20
|
+
const getObjectName = (value) => {
|
|
21
|
+
const tag = (() => {
|
|
22
|
+
try {
|
|
23
|
+
return Object.prototype.toString.call(value).slice(8, -1);
|
|
24
|
+
} catch {
|
|
25
|
+
return Predicate.isFunction(value) ? "function" : "object";
|
|
26
|
+
}
|
|
27
|
+
})();
|
|
28
|
+
const constructorName = (() => {
|
|
29
|
+
try {
|
|
30
|
+
return "constructor" in value && Predicate.isFunction(value.constructor) && Predicate.isString(value.constructor.name) ? value.constructor.name : void 0;
|
|
31
|
+
} catch {
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
})();
|
|
35
|
+
if (tag !== "Object") return tag;
|
|
36
|
+
if (constructorName !== void 0 && constructorName !== "" && constructorName !== "Object") return constructorName;
|
|
37
|
+
return tag;
|
|
38
|
+
};
|
|
39
|
+
const propertyNames = (value) => {
|
|
40
|
+
const names = /* @__PURE__ */ new Set();
|
|
41
|
+
for (const target of [value, Object.getPrototypeOf(value)]) {
|
|
42
|
+
if (target === null || target === Object.prototype || target === Function.prototype) continue;
|
|
43
|
+
try {
|
|
44
|
+
for (const name of Object.getOwnPropertyNames(target)) names.add(name);
|
|
45
|
+
} catch {
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return [...names].filter((name) => name !== "constructor").sort();
|
|
50
|
+
};
|
|
51
|
+
const isMethod = (value, name) => {
|
|
52
|
+
try {
|
|
53
|
+
return Predicate.hasProperty(value, name) && Predicate.isFunction(value[name]);
|
|
54
|
+
} catch {
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
const describeActual = (value) => {
|
|
59
|
+
if (value === null) return "null";
|
|
60
|
+
if (!isPropertyTarget(value)) {
|
|
61
|
+
if (Predicate.isString(value)) return "string";
|
|
62
|
+
if (Predicate.isNumber(value)) return "number";
|
|
63
|
+
if (Predicate.isBoolean(value)) return "boolean";
|
|
64
|
+
if (Predicate.isBigInt(value)) return "bigint";
|
|
65
|
+
if (Predicate.isSymbol(value)) return "symbol";
|
|
66
|
+
return "undefined";
|
|
67
|
+
}
|
|
68
|
+
const names = propertyNames(value);
|
|
69
|
+
const methods = names.filter((name) => isMethod(value, name));
|
|
70
|
+
const properties = names.filter((name) => !methods.includes(name));
|
|
71
|
+
const details = [methods.length > 0 ? `methods ${methods.join(", ")}` : void 0, properties.length > 0 ? `properties ${properties.join(", ")}` : void 0].filter((detail) => detail !== void 0);
|
|
72
|
+
if (details.length === 0) return getObjectName(value);
|
|
73
|
+
return `${getObjectName(value)} with ${details.join("; ")}`;
|
|
74
|
+
};
|
|
75
|
+
const getBinding = (env, binding, isResource, options) => Effect.gen(function* () {
|
|
76
|
+
if (!isPropertyTarget(env)) {
|
|
77
|
+
const actual = describeActual(env);
|
|
78
|
+
return yield* Effect.fail(new BindingValidationError({
|
|
79
|
+
binding,
|
|
80
|
+
expected: "WorkerEnvironment object",
|
|
81
|
+
actual,
|
|
82
|
+
message: `Cloudflare binding "${binding}" failed validation. Expected WorkerEnvironment object; got ${actual}`
|
|
83
|
+
}));
|
|
84
|
+
}
|
|
85
|
+
const resource = Predicate.hasProperty(env, binding) ? env[binding] : void 0;
|
|
86
|
+
if (resource === void 0) return yield* Effect.fail(new BindingNotFoundError({
|
|
87
|
+
binding,
|
|
88
|
+
message: `Cloudflare binding "${binding}" was not found in WorkerEnvironment`
|
|
89
|
+
}));
|
|
90
|
+
if (!isResource(resource)) {
|
|
91
|
+
const expected = options?.expected ?? defaultExpected;
|
|
92
|
+
const actual = describeActual(resource);
|
|
93
|
+
return yield* Effect.fail(new BindingValidationError({
|
|
94
|
+
binding,
|
|
95
|
+
expected,
|
|
96
|
+
actual,
|
|
97
|
+
message: `Cloudflare binding "${binding}" failed validation. Expected ${expected}; got ${actual}`
|
|
98
|
+
}));
|
|
99
|
+
}
|
|
100
|
+
return resource;
|
|
101
|
+
});
|
|
102
|
+
/**
|
|
103
|
+
* The overloads on {@link layer} and {@link Service} guarantee that
|
|
104
|
+
* `Service = Resource` whenever `wrap` is absent, making the fallback cast
|
|
105
|
+
* safe.
|
|
106
|
+
*/
|
|
107
|
+
const makeBindingLayer = (tag, binding, isResource, wrap, options) => Layer.effect(tag, Effect.gen(function* () {
|
|
108
|
+
const env = yield* WorkerEnvironment;
|
|
109
|
+
const resource = yield* getBinding(env, binding, isResource, options);
|
|
110
|
+
return wrap === void 0 ? resource : wrap(resource);
|
|
111
|
+
}));
|
|
112
|
+
function layer(tag, binding, isResource, wrap, options) {
|
|
113
|
+
return makeBindingLayer(tag, binding, isResource, wrap, options);
|
|
114
|
+
}
|
|
115
|
+
const Service = () => {
|
|
116
|
+
function makeService(id, binding, isResource, wrap, options) {
|
|
117
|
+
const tag = Context.Service()(`effect-cf/Binding/${id}`);
|
|
118
|
+
const serviceLayer = makeBindingLayer(tag, binding, isResource, wrap, options);
|
|
119
|
+
return Object.assign(tag, {
|
|
120
|
+
[TypeId]: TypeId,
|
|
121
|
+
id,
|
|
122
|
+
binding,
|
|
123
|
+
layer: serviceLayer
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
return makeService;
|
|
127
|
+
};
|
|
128
|
+
//#endregion
|
|
129
|
+
export { Service as n, layer as r, Binding_exports as t };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as ArtifactsOperationError } from "./Artifacts-
|
|
1
|
+
import { t as ArtifactsOperationError } from "./Artifacts-CSIk1Oml.mjs";
|
|
2
2
|
import { Effect, Predicate } from "effect";
|
|
3
3
|
//#region src/ComputerArtifacts.ts
|
|
4
4
|
const artifactsErrorDetails = (cause) => {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ComputerArtifactsClient } from "./ComputerArtifacts.mjs";
|
|
2
|
-
import { t as DurableObjectState } from "./DurableObjectState-
|
|
2
|
+
import { t as DurableObjectState } from "./DurableObjectState-D3k-WRnd.mjs";
|
|
3
3
|
import { Context, Effect, Layer, Schema, Scope, Stream } from "effect";
|
|
4
4
|
import { CommitView, GitClient, GitCloneOptions, GitCommitOptions, GitDiffOptions, GitFetchOptions, GitLogOptions, GitUpdateRefOptions } from "@cloudflare/computer/git";
|
|
5
5
|
import { ExecSyncResult, RuntimeExecOptions, RuntimeGetOptions, RuntimeKillOptions, ShellValue, SkippedEntry, ThinkWorkspaceCompatibility, WorkspaceClient, WorkspaceRuntimeResult, WorkspaceRuntimeValue as WorkspaceRuntimeValue$1 } from "@cloudflare/computer";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as DurableObjectState } from "./DurableObjectState-
|
|
1
|
+
import { t as DurableObjectState } from "./DurableObjectState-CepagPkX.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";
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import { c as WorkerEnvironment, r as BindingValidationError, t as BindingNotFoundError } from "./Binding-xJJJPmiD.mjs";
|
|
2
|
+
import { Context, Effect, Layer, Schema } from "effect";
|
|
3
|
+
declare namespace ContainerNamespace_d_exports {
|
|
4
|
+
export { ContainerInstanceClient, ContainerNamespace, ContainerNamespaceClient, ContainerNamespaceDefinition, ContainerNamespaceResource, ContainerNamespaceService, ContainerNamespaceStaticClient, ContainerOperationError, ContainerReadinessOptions, ContainerSignal, ContainerStartAndWaitForPortsOptions, ContainerStartOptions, ContainerState, ContainerStopSignal, ContainerStub, ContainerStubOf, ContainerWaitOptions, LayerOptions, Tag, TagClass, isContainerNamespaceResource, layer, make, makeClient };
|
|
5
|
+
}
|
|
6
|
+
/** Named signal accepted by Cloudflare Container instances. */
|
|
7
|
+
type ContainerSignal = "SIGKILL" | "SIGINT" | "SIGTERM";
|
|
8
|
+
/** Named or numeric signal accepted by Container `stop()`. */
|
|
9
|
+
type ContainerStopSignal = ContainerSignal | number;
|
|
10
|
+
/** Per-instance Container startup configuration. */
|
|
11
|
+
interface ContainerStartOptions {
|
|
12
|
+
readonly envVars?: Record<string, string>;
|
|
13
|
+
readonly entrypoint?: Array<string>;
|
|
14
|
+
readonly enableInternet?: boolean;
|
|
15
|
+
readonly labels?: Record<string, string>;
|
|
16
|
+
}
|
|
17
|
+
/** Serializable retry settings used while starting a Container. */
|
|
18
|
+
interface ContainerWaitOptions {
|
|
19
|
+
readonly portToCheck: number;
|
|
20
|
+
readonly retries?: number;
|
|
21
|
+
readonly waitInterval?: number;
|
|
22
|
+
}
|
|
23
|
+
/** Serializable timeout settings used while waiting for Container ports. */
|
|
24
|
+
interface ContainerReadinessOptions {
|
|
25
|
+
readonly instanceGetTimeoutMS?: number;
|
|
26
|
+
readonly portReadyTimeoutMS?: number;
|
|
27
|
+
readonly waitInterval?: number;
|
|
28
|
+
}
|
|
29
|
+
/** Options for starting a Container and waiting for its ports. */
|
|
30
|
+
interface ContainerStartAndWaitForPortsOptions {
|
|
31
|
+
readonly startOptions?: ContainerStartOptions;
|
|
32
|
+
readonly ports?: number | Array<number>;
|
|
33
|
+
readonly cancellationOptions?: ContainerReadinessOptions;
|
|
34
|
+
}
|
|
35
|
+
/** Serializable state reported by a Cloudflare Container instance. */
|
|
36
|
+
declare const ContainerState: Schema.Union<readonly [Schema.Struct<{
|
|
37
|
+
readonly lastChange: Schema.Finite;
|
|
38
|
+
readonly status: Schema.Literals<readonly ["running", "stopping", "stopped", "healthy"]>;
|
|
39
|
+
}>, Schema.Struct<{
|
|
40
|
+
readonly lastChange: Schema.Finite;
|
|
41
|
+
readonly status: Schema.Literal<"stopped_with_code">;
|
|
42
|
+
readonly exitCode: Schema.optionalKey<Schema.Int>;
|
|
43
|
+
}>]>;
|
|
44
|
+
type ContainerState = typeof ContainerState.Type;
|
|
45
|
+
/**
|
|
46
|
+
* Native Container stub shape exposed by a Container namespace binding.
|
|
47
|
+
*
|
|
48
|
+
* This is structural so using Container bindings does not make
|
|
49
|
+
* `@cloudflare/containers` a runtime dependency of effect-cf.
|
|
50
|
+
*/
|
|
51
|
+
interface ContainerStub {
|
|
52
|
+
fetch(input: RequestInfo | URL, init?: RequestInit): Promise<Response>;
|
|
53
|
+
getState(): Promise<ContainerState>;
|
|
54
|
+
start(options?: ContainerStartOptions, waitOptions?: ContainerWaitOptions): Promise<void>;
|
|
55
|
+
startAndWaitForPorts(options?: ContainerStartAndWaitForPortsOptions): Promise<void>;
|
|
56
|
+
waitForPort(options: ContainerWaitOptions): Promise<number>;
|
|
57
|
+
stop(signal?: ContainerStopSignal): Promise<void>;
|
|
58
|
+
destroy(): Promise<void>;
|
|
59
|
+
setAllowedHosts(hosts: Array<string>): Promise<void>;
|
|
60
|
+
setDeniedHosts(hosts: Array<string>): Promise<void>;
|
|
61
|
+
allowHost(hostname: string): Promise<void>;
|
|
62
|
+
denyHost(hostname: string): Promise<void>;
|
|
63
|
+
removeAllowedHost(hostname: string): Promise<void>;
|
|
64
|
+
removeDeniedHost(hostname: string): Promise<void>;
|
|
65
|
+
}
|
|
66
|
+
/** Native Container namespace binding shape. */
|
|
67
|
+
interface ContainerNamespaceResource {
|
|
68
|
+
getByName(name: string, options?: globalThis.DurableObjectNamespaceGetDurableObjectOptions): ContainerStub;
|
|
69
|
+
}
|
|
70
|
+
/** Exact native stub type produced by a Container namespace binding. */
|
|
71
|
+
type ContainerStubOf<Namespace extends ContainerNamespaceResource> = ReturnType<Namespace["getByName"]>;
|
|
72
|
+
/** Container namespace binding metadata. */
|
|
73
|
+
interface ContainerNamespaceDefinition {
|
|
74
|
+
/** Binding name as configured in `wrangler.jsonc`. */
|
|
75
|
+
readonly binding: string;
|
|
76
|
+
}
|
|
77
|
+
declare const ContainerOperationError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
|
|
78
|
+
readonly _tag: "ContainerOperationError";
|
|
79
|
+
} & Readonly<A>;
|
|
80
|
+
/** Failure raised when invoking a named Container operation. */
|
|
81
|
+
declare class ContainerOperationError extends ContainerOperationError_base<{
|
|
82
|
+
readonly binding: string;
|
|
83
|
+
readonly instance: string;
|
|
84
|
+
readonly operation: string;
|
|
85
|
+
readonly cause: unknown;
|
|
86
|
+
}> {
|
|
87
|
+
get message(): string;
|
|
88
|
+
}
|
|
89
|
+
/** Effect-wrapped client for one named Container instance. */
|
|
90
|
+
interface ContainerInstanceClient<Stub extends ContainerStub = ContainerStub> {
|
|
91
|
+
readonly rawUnsafe: Effect.Effect<Stub, ContainerOperationError>;
|
|
92
|
+
readonly state: Effect.Effect<ContainerState, ContainerOperationError>;
|
|
93
|
+
readonly fetch: (input: RequestInfo | URL, init?: RequestInit) => Effect.Effect<Response, ContainerOperationError>;
|
|
94
|
+
readonly start: (options?: ContainerStartOptions, waitOptions?: ContainerWaitOptions) => Effect.Effect<void, ContainerOperationError>;
|
|
95
|
+
readonly startAndWaitForPorts: (options?: ContainerStartAndWaitForPortsOptions) => Effect.Effect<void, ContainerOperationError>;
|
|
96
|
+
readonly waitForPort: (options: ContainerWaitOptions) => Effect.Effect<number, ContainerOperationError>;
|
|
97
|
+
readonly stop: (signal?: ContainerStopSignal) => Effect.Effect<void, ContainerOperationError>;
|
|
98
|
+
readonly destroy: Effect.Effect<void, ContainerOperationError>;
|
|
99
|
+
readonly setAllowedHosts: (hosts: ReadonlyArray<string>) => Effect.Effect<void, ContainerOperationError>;
|
|
100
|
+
readonly setDeniedHosts: (hosts: ReadonlyArray<string>) => Effect.Effect<void, ContainerOperationError>;
|
|
101
|
+
readonly allowHost: (hostname: string) => Effect.Effect<void, ContainerOperationError>;
|
|
102
|
+
readonly denyHost: (hostname: string) => Effect.Effect<void, ContainerOperationError>;
|
|
103
|
+
readonly removeAllowedHost: (hostname: string) => Effect.Effect<void, ContainerOperationError>;
|
|
104
|
+
readonly removeDeniedHost: (hostname: string) => Effect.Effect<void, ContainerOperationError>;
|
|
105
|
+
}
|
|
106
|
+
/** Effect client for a Container namespace binding. */
|
|
107
|
+
interface ContainerNamespaceClient<Namespace extends ContainerNamespaceResource = ContainerNamespaceResource> {
|
|
108
|
+
readonly definition: ContainerNamespaceDefinition;
|
|
109
|
+
readonly getByName: (name: string, options?: globalThis.DurableObjectNamespaceGetDurableObjectOptions) => Effect.Effect<ContainerInstanceClient<ContainerStubOf<Namespace>>, ContainerOperationError>;
|
|
110
|
+
readonly byName: (name: string, options?: globalThis.DurableObjectNamespaceGetDurableObjectOptions) => ContainerInstanceClient<ContainerStubOf<Namespace>>;
|
|
111
|
+
readonly rawUnsafe: Effect.Effect<Namespace>;
|
|
112
|
+
}
|
|
113
|
+
type ContainerNamespaceStaticClient<R, Namespace extends ContainerNamespaceResource = ContainerNamespaceResource> = {
|
|
114
|
+
readonly getByName: (name: string, options?: globalThis.DurableObjectNamespaceGetDurableObjectOptions) => Effect.Effect<ContainerInstanceClient<ContainerStubOf<Namespace>>, ContainerOperationError, R>;
|
|
115
|
+
readonly byName: (name: string, options?: globalThis.DurableObjectNamespaceGetDurableObjectOptions) => {
|
|
116
|
+
readonly state: Effect.Effect<ContainerState, ContainerOperationError, R>;
|
|
117
|
+
readonly fetch: (input: RequestInfo | URL, init?: RequestInit) => Effect.Effect<Response, ContainerOperationError, R>;
|
|
118
|
+
readonly start: (options?: ContainerStartOptions, waitOptions?: ContainerWaitOptions) => Effect.Effect<void, ContainerOperationError, R>;
|
|
119
|
+
readonly startAndWaitForPorts: (options?: ContainerStartAndWaitForPortsOptions) => Effect.Effect<void, ContainerOperationError, R>;
|
|
120
|
+
readonly waitForPort: (options: ContainerWaitOptions) => Effect.Effect<number, ContainerOperationError, R>;
|
|
121
|
+
readonly stop: (signal?: ContainerStopSignal) => Effect.Effect<void, ContainerOperationError, R>;
|
|
122
|
+
readonly destroy: Effect.Effect<void, ContainerOperationError, R>;
|
|
123
|
+
readonly setAllowedHosts: (hosts: ReadonlyArray<string>) => Effect.Effect<void, ContainerOperationError, R>;
|
|
124
|
+
readonly setDeniedHosts: (hosts: ReadonlyArray<string>) => Effect.Effect<void, ContainerOperationError, R>;
|
|
125
|
+
readonly allowHost: (hostname: string) => Effect.Effect<void, ContainerOperationError, R>;
|
|
126
|
+
readonly denyHost: (hostname: string) => Effect.Effect<void, ContainerOperationError, R>;
|
|
127
|
+
readonly removeAllowedHost: (hostname: string) => Effect.Effect<void, ContainerOperationError, R>;
|
|
128
|
+
readonly removeDeniedHost: (hostname: string) => Effect.Effect<void, ContainerOperationError, R>;
|
|
129
|
+
readonly rawUnsafe: Effect.Effect<ContainerStubOf<Namespace>, ContainerOperationError, R>;
|
|
130
|
+
};
|
|
131
|
+
readonly rawUnsafe: Effect.Effect<Namespace, never, R>;
|
|
132
|
+
};
|
|
133
|
+
type LayerOptions = {
|
|
134
|
+
readonly binding: string;
|
|
135
|
+
};
|
|
136
|
+
interface TagClass<Self, Id extends string, Namespace extends ContainerNamespaceResource = ContainerNamespaceResource> extends Context.ServiceClass<Self, `effect-cf/Container/${Id}`, ContainerNamespaceClient<Namespace>>, ContainerNamespaceStaticClient<Self, Namespace> {
|
|
137
|
+
readonly id: Id;
|
|
138
|
+
readonly layer: (options: LayerOptions) => Layer.Layer<Self, BindingNotFoundError | BindingValidationError, WorkerEnvironment>;
|
|
139
|
+
}
|
|
140
|
+
declare const isContainerNamespaceResource: <Candidate>(value: Candidate) => value is Candidate & ContainerNamespaceResource;
|
|
141
|
+
declare const makeClient: (definition: ContainerNamespaceDefinition) => <Namespace extends ContainerNamespaceResource>(namespace: Namespace) => ContainerNamespaceClient<Namespace>;
|
|
142
|
+
declare const layer: <Self, Namespace extends ContainerNamespaceResource>(tag: Context.Service<Self, ContainerNamespaceClient<Namespace>>, definition: ContainerNamespaceDefinition) => Layer.Layer<Self, BindingNotFoundError | BindingValidationError, WorkerEnvironment>;
|
|
143
|
+
declare const make: <Id extends string>(id: Id) => TagClass<ContainerNamespaceService<Id>, Id, ContainerNamespaceResource>;
|
|
144
|
+
declare const ContainerNamespaceServiceTypeId: unique symbol;
|
|
145
|
+
/** Nominal service marker for Container namespaces created with {@link make}. */
|
|
146
|
+
interface ContainerNamespaceService<Id extends string> {
|
|
147
|
+
readonly [ContainerNamespaceServiceTypeId]: {
|
|
148
|
+
readonly id: Id;
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
/** Creates a typed Effect service for a Cloudflare Container namespace. */
|
|
152
|
+
declare const Tag: <Self, Namespace extends ContainerNamespaceResource = ContainerNamespaceResource>() => <Id extends string>(id: Id) => TagClass<Self, Id, Namespace>;
|
|
153
|
+
declare const ContainerNamespace: typeof Tag;
|
|
154
|
+
//#endregion
|
|
155
|
+
export { ContainerStartOptions as n, ContainerStopSignal as r, ContainerNamespace_d_exports as t };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
|
|
2
2
|
import { t as causeMessage } from "./ErrorMessage-BM0K-Nik.mjs";
|
|
3
|
-
import { Cause, Context, Data, Effect, Exit, Option, Predicate, Result, Schema } from "effect";
|
|
3
|
+
import { Cause, Clock, Context, Data, Duration, Effect, Exit, Option, Predicate, Result, Schema } from "effect";
|
|
4
4
|
//#region src/DurableObjectStorage.ts
|
|
5
5
|
var DurableObjectStorage_exports = /* @__PURE__ */ __exportAll({
|
|
6
6
|
StorageOperationError: () => StorageOperationError,
|
|
@@ -24,6 +24,11 @@ const tryStoragePromise = (operation, evaluate) => Effect.tryPromise({
|
|
|
24
24
|
try: evaluate,
|
|
25
25
|
catch: (cause) => storageError(operation, cause)
|
|
26
26
|
});
|
|
27
|
+
const setAlarmAfter = Effect.fn("DurableObjectStorage.setAlarmAfter")(function* (operation, setAlarm, delay, options) {
|
|
28
|
+
const now = yield* Clock.currentTimeMillis;
|
|
29
|
+
const delayMillis = Math.ceil(Duration.toMillis(delay));
|
|
30
|
+
yield* tryStoragePromise(operation, () => setAlarm(now + delayMillis, options));
|
|
31
|
+
});
|
|
27
32
|
const fromSqlCursor = (cursor) => ({
|
|
28
33
|
next: () => tryStorageSync("sql.next", () => cursor.next()),
|
|
29
34
|
toArray: () => tryStorageSync("sql.toArray", () => cursor.toArray()),
|
|
@@ -85,6 +90,7 @@ const fromDurableObjectTransaction = (txn) => ({
|
|
|
85
90
|
rollback: () => tryStorageSync("transaction.rollback", () => txn.rollback()),
|
|
86
91
|
getAlarm: (options) => tryStoragePromise("transaction.getAlarm", () => txn.getAlarm(options)),
|
|
87
92
|
setAlarm: (scheduledTime, options) => tryStoragePromise("transaction.setAlarm", () => txn.setAlarm(scheduledTime, options)),
|
|
93
|
+
setAlarmAfter: (delay, options) => setAlarmAfter("transaction.setAlarm", (scheduledTime, options) => txn.setAlarm(scheduledTime, options), delay, options),
|
|
88
94
|
deleteAlarm: (options) => tryStoragePromise("transaction.deleteAlarm", () => txn.deleteAlarm(options))
|
|
89
95
|
});
|
|
90
96
|
/**
|
|
@@ -97,26 +103,31 @@ const fromDurableObjectStorage = (storage) => ({
|
|
|
97
103
|
deleteAll: (options) => tryStoragePromise("deleteAll", () => storage.deleteAll(options)),
|
|
98
104
|
getAlarm: (options) => tryStoragePromise("getAlarm", () => storage.getAlarm(options)),
|
|
99
105
|
setAlarm: (scheduledTime, options) => tryStoragePromise("setAlarm", () => storage.setAlarm(scheduledTime, options)),
|
|
106
|
+
setAlarmAfter: (delay, options) => setAlarmAfter("setAlarm", (scheduledTime, options) => storage.setAlarm(scheduledTime, options), delay, options),
|
|
100
107
|
deleteAlarm: (options) => tryStoragePromise("deleteAlarm", () => storage.deleteAlarm(options)),
|
|
101
108
|
transactionSync: (closure) => Effect.context().pipe(Effect.flatMap((context) => Effect.suspend(() => {
|
|
109
|
+
let aborted;
|
|
102
110
|
try {
|
|
103
111
|
return Effect.succeed(storage.transactionSync(() => {
|
|
104
112
|
const exit = Effect.runSyncExitWith(context)(closure());
|
|
105
113
|
if (Exit.isSuccess(exit)) return exit.value;
|
|
114
|
+
aborted = exit;
|
|
106
115
|
throw exit;
|
|
107
116
|
}));
|
|
108
117
|
} catch (cause) {
|
|
109
|
-
if (
|
|
118
|
+
if (aborted !== void 0 && cause === aborted && Exit.isFailure(aborted)) return Effect.failCause(aborted.cause);
|
|
110
119
|
return Effect.fail(storageError("transactionSync", cause));
|
|
111
120
|
}
|
|
112
121
|
}))),
|
|
113
122
|
transaction: (closure) => Effect.context().pipe(Effect.flatMap((context) => Effect.callback((resume) => {
|
|
123
|
+
let aborted;
|
|
114
124
|
storage.transaction(async (txn) => {
|
|
115
125
|
const exit = await Effect.runPromiseExitWith(context)(closure(fromDurableObjectTransaction(txn)));
|
|
116
126
|
if (Exit.isSuccess(exit)) return exit.value;
|
|
127
|
+
aborted = exit;
|
|
117
128
|
throw exit;
|
|
118
129
|
}).then((value) => resume(Effect.succeed(value)), (cause) => {
|
|
119
|
-
if (
|
|
130
|
+
if (aborted !== void 0 && cause === aborted && Exit.isFailure(aborted)) resume(Effect.failCause(aborted.cause));
|
|
120
131
|
else resume(Effect.fail(storageError("transaction", cause)));
|
|
121
132
|
});
|
|
122
133
|
}))),
|