effect-cf 0.25.2 → 0.26.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,21 @@
1
1
  # effect-cf
2
2
 
3
+ ## 0.26.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#97](https://github.com/danieljvdm/effect-cf/pull/97) [`b7bc27e`](https://github.com/danieljvdm/effect-cf/commit/b7bc27eb03130578e13a593d9efc45bb8d3d5269) Thanks [@danieljvdm](https://github.com/danieljvdm)! - Add first-class Cloudflare Artifacts binding support through the new `Artifacts` module. Namespace lifecycle operations, repository token and fork operations, and Git commit-history, commit, and tree reads are available as typed Effects with validated bindings, structured options and results, tracing spans, and Cloudflare error identifiers.
8
+
9
+ - [#98](https://github.com/danieljvdm/effect-cf/pull/98) [`5b9a05e`](https://github.com/danieljvdm/effect-cf/commit/5b9a05e976f653eb9a9d2003fdd57379d906c871) Thanks [@danieljvdm](https://github.com/danieljvdm)! - Add Effect-native Cloudflare Computer workspaces, scoped execution handles, a Durable Object host mixin, and session-isolated Artifacts clients.
10
+
11
+ - [#94](https://github.com/danieljvdm/effect-cf/pull/94) [`8a7ec63`](https://github.com/danieljvdm/effect-cf/commit/8a7ec630ecb2ddc2b55348cb6c701f5a9ce42d3b) Thanks [@danieljvdm](https://github.com/danieljvdm)! - Add the `WebTransport` module: a truthful WebTransport/HTTP-3 boundary for Workers. `inboundTransport` decodes the HTTP protocol metadata Cloudflare's edge attaches to requests (`httpProtocol`, `clientQuicRtt`, `clientTcpRtt`) with `isHttp3` on top; `capabilities` feature-detects what the runtime provides; and `inboundSessionsUnsupported` is an explicit typed boundary for the inbound WebTransport session API that workerd does not have (cloudflare/workerd#6451).
12
+
13
+ ## 0.25.3
14
+
15
+ ### Patch Changes
16
+
17
+ - [#92](https://github.com/danieljvdm/effect-cf/pull/92) [`f174800`](https://github.com/danieljvdm/effect-cf/commit/f1748004e463d4e54c22e7c77fdea68ff8de7f82) Thanks [@danieljvdm](https://github.com/danieljvdm)! - Flush configured OTLP telemetry after Durable Object alarm handlers, including failed alarms, so buffered telemetry is exported consistently with fetch and native RPC handlers.
18
+
3
19
  ## 0.25.2
4
20
 
5
21
  ### Patch Changes
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # effect-cf
2
2
 
3
- Effect-native Cloudflare primitives for Workers, Durable Objects, Containers, bindings, Cache, KV, D1, Queues, Email, Analytics Engine, Workflows, and Durable Object storage.
3
+ Effect-native Cloudflare primitives for Workers, Durable Objects, Containers, bindings, Cache, KV, D1, R2, Artifacts, Queues, Email, Analytics Engine, Workflows, and Durable Object storage.
4
4
 
5
5
  ## Install
6
6
 
@@ -18,6 +18,21 @@ pnpm add effect-cf "effect@^4.0.0-beta.105"
18
18
  npm install effect-cf "effect@^4.0.0-beta.105"
19
19
  ```
20
20
 
21
+ The Computer workspace integration is an optional peer. Install it only in
22
+ applications that import `ComputerWorkspace`, `ComputerArtifacts`, or
23
+ `effect-cf/computer-workspace-host`:
24
+
25
+ ```bash
26
+ bun add "@cloudflare/computer@^0.2.0"
27
+ ```
28
+
29
+ Workspace Git operations additionally require `@platformatic/vfs`,
30
+ `@cloudflare/computer/git`'s own optional peer:
31
+
32
+ ```bash
33
+ bun add "@platformatic/vfs@^0.4.0"
34
+ ```
35
+
21
36
  ## Goal
22
37
 
23
38
  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.
@@ -35,6 +50,10 @@ Runtime creation belongs at Cloudflare entrypoints, not inside binding helpers.
35
50
  - `Kv` - typed KV namespace helper
36
51
  - `D1` - typed D1 database binding helper with an `@effect/sql-d1` backed SQL layer
37
52
  - `R2` - typed R2 bucket binding helper with Effect-wrapped object and multipart operations
53
+ - `Artifacts` - typed Cloudflare Artifacts namespace and repository helpers, including repository lifecycle, tokens, and Git object reads
54
+ - `ComputerWorkspace` - scoped Effect wrappers for the complete Cloudflare Computer filesystem, Git, runtime, Assets, Artifacts, and Think-compatible client surfaces
55
+ - `ComputerArtifacts` - session-isolated Artifacts repositories backed by `@cloudflare/computer/artifacts`
56
+ - `effect-cf/computer-workspace-host` - optional Durable Object host mixin, worker-shell backend wiring, and `WorkspaceServiceProxy`
38
57
  - `Hyperdrive` - typed Hyperdrive binding helper for connection strings and optional Postgres SQL integration
39
58
  - `Images` - typed Cloudflare Images binding helper with transformation APIs and optional hosted image operations
40
59
  - `Email` - typed Cloudflare Email Service binding helper for `send_email` bindings, with limit validation and typed error codes
@@ -42,6 +61,7 @@ Runtime creation belongs at Cloudflare entrypoints, not inside binding helpers.
42
61
  - `Queue` - typed Queue producer/consumer tags plus client and error types
43
62
  - `Workflow` - typed Workflow entrypoints, steps, starter clients, and instance types
44
63
  - `Rpc` - Cloudflare RPC type helpers and scoped disposal utilities
64
+ - `WebTransport` - truthful WebTransport/HTTP-3 boundary: typed runtime capabilities and decoded inbound protocol metadata
45
65
  - `WorkerConfig` - Effect `Config` helpers backed by Cloudflare `env`
46
66
  - `effect-cf/vitest` - Effect-native runners and scoped test helpers for Cloudflare's Vitest Workers pool
47
67
 
@@ -399,6 +419,166 @@ export const readArtifact = (key: string) =>
399
419
 
400
420
  Use `createMultipartUpload(...)` or `resumeMultipartUpload(...)` for large objects; returned upload handles wrap `uploadPart`, `complete`, and `abort` in Effect.
401
421
 
422
+ ## Artifacts Example
423
+
424
+ Artifacts tags expose every namespace and repository-handle binding operation as an Effect. Configure the binding under Wrangler's `artifacts` field:
425
+
426
+ ```jsonc
427
+ {
428
+ "artifacts": [
429
+ {
430
+ "binding": "ARTIFACTS",
431
+ "namespace": "default",
432
+ // Optional in local development:
433
+ "remote": true,
434
+ },
435
+ ],
436
+ }
437
+ ```
438
+
439
+ ```ts
440
+ import { Effect } from "effect";
441
+ import { Artifacts } from "effect-cf";
442
+
443
+ class Repositories extends Artifacts.Tag<Repositories>()("Repositories") {}
444
+
445
+ export const RepositoriesLayer = Repositories.layer({ binding: "ARTIFACTS" });
446
+
447
+ export const createWorkspace = Effect.gen(function* () {
448
+ const artifacts = yield* Repositories;
449
+ const created = yield* artifacts.create("agent-workspace", {
450
+ description: "Versioned agent workspace",
451
+ setDefaultBranch: "main",
452
+ });
453
+ const repo = yield* artifacts.get(created.name);
454
+ const readToken = yield* repo.createToken("read", 3600);
455
+
456
+ return {
457
+ remote: created.remote,
458
+ token: readToken.plaintext,
459
+ history: yield* repo.log({ ref: "main", limit: 10 }),
460
+ };
461
+ });
462
+ ```
463
+
464
+ `create`, `import`, and `fork` return an initial plaintext token. Treat returned tokens as secrets and avoid logging or persisting them unnecessarily.
465
+
466
+ ## Computer Workspace Example
467
+
468
+ `ComputerWorkspace` exposes the complete `@cloudflare/computer`
469
+ `WorkspaceClient` as Effects. The workspace client and every runtime execution
470
+ handle are owned by an Effect `Scope`, so RPC stubs are disposed when their
471
+ scope closes. The host mixin is a separate optional-dependency entrypoint:
472
+
473
+ ```ts
474
+ import shellCurl from "@cloudflare/computer/shell/curl";
475
+ import { Effect, Schema as S } from "effect";
476
+ import { ComputerWorkspace, DurableObjectDefinition } from "effect-cf";
477
+ import { withComputerWorkspace, WorkspaceServiceProxy } from "effect-cf/computer-workspace-host";
478
+
479
+ export { WorkspaceServiceProxy };
480
+
481
+ const ResearchWorkspace = DurableObjectDefinition.make("ResearchWorkspace", {
482
+ inspect: DurableObjectDefinition.method({ success: S.String }),
483
+ });
484
+
485
+ const ResearchWorkspaceLive = ResearchWorkspace.make(ComputerWorkspace.ComputerWorkspace.layer, {
486
+ rpc: {
487
+ inspect: () =>
488
+ Effect.gen(function* () {
489
+ const workspace = yield* ComputerWorkspace.ComputerWorkspace;
490
+
491
+ // Keep reads bounded when returning their contents over RPC.
492
+ const readme = yield* workspace.readFile("/repo/README.md", {
493
+ byteLength: 256 * 1024,
494
+ });
495
+ const commits = yield* workspace.git.log({ maxCount: 20 });
496
+ const run = yield* workspace.execCollect("git status --short", {
497
+ cwd: "/repo",
498
+ timeoutMillis: 30_000,
499
+ });
500
+
501
+ return `${commits.length}:${run.exitCode}:${readme.length}`;
502
+ }),
503
+ },
504
+ });
505
+
506
+ const HostedResearchWorkspace = withComputerWorkspace(ResearchWorkspaceLive, (_, state, env) => ({
507
+ storage: state.storage,
508
+ sessionId: state.id.toString(),
509
+ gitIdentity: { name: "Research Agent", email: "agent@example.test" },
510
+ artifacts: { binding: env.ARTIFACTS },
511
+ shell: {
512
+ loader: env.WORKER_LOADER,
513
+ hostBinding: "RESEARCH_WORKSPACE",
514
+ hostId: state.id.toString(),
515
+ executionContext: state,
516
+ commands: [shellCurl],
517
+ egress: { mode: "none" },
518
+ },
519
+ }));
520
+
521
+ export class ResearchWorkspaceDurableObject extends HostedResearchWorkspace {}
522
+ ```
523
+
524
+ Serialize checkout mutations such as `clone`, `fetch`, and reset/checkout
525
+ sequences with an Effect `Semaphore` when several RPC methods can update the
526
+ same working tree concurrently. Reads can remain concurrent.
527
+
528
+ The corresponding Wrangler configuration needs SQLite-backed Durable Object
529
+ storage. Worker-shell execution additionally requires the `experimental` flag,
530
+ a Worker Loader binding, the loopback namespace binding named by `hostBinding`,
531
+ and the exact `WorkspaceServiceProxy` export shown above:
532
+
533
+ ```jsonc
534
+ {
535
+ "compatibility_flags": ["nodejs_compat", "experimental"],
536
+ "worker_loaders": [{ "binding": "WORKER_LOADER" }],
537
+ "artifacts": [{ "binding": "ARTIFACTS", "namespace": "default" }],
538
+ "durable_objects": {
539
+ "bindings": [
540
+ {
541
+ "name": "RESEARCH_WORKSPACE",
542
+ "class_name": "ResearchWorkspaceDurableObject",
543
+ },
544
+ ],
545
+ },
546
+ "migrations": [
547
+ {
548
+ "tag": "v1",
549
+ "new_sqlite_classes": ["ResearchWorkspaceDurableObject"],
550
+ },
551
+ ],
552
+ }
553
+ ```
554
+
555
+ Omit `shell` and the Worker Loader configuration when only the SQLite
556
+ filesystem and Git client are needed. Supplying `artifacts` also installs the
557
+ session-scoped client at `workspace.artifacts` and makes the in-shell
558
+ `artifacts` command use the same upstream repository-prefixing convention.
559
+
560
+ Workers can use that session isolation without a Durable Object or workspace:
561
+
562
+ ```ts
563
+ import { Effect } from "effect";
564
+ import { Artifacts, ComputerArtifacts } from "effect-cf";
565
+
566
+ export const createSessionRepo = (binding: Artifacts.ArtifactsBinding, sessionId: string) =>
567
+ Effect.gen(function* () {
568
+ const artifacts = yield* ComputerArtifacts.makeClient(binding, sessionId);
569
+ const created = yield* artifacts.create("build-cache", {
570
+ description: "CI artifacts",
571
+ });
572
+ const token = yield* artifacts.createToken("build-cache", "read", 3600);
573
+
574
+ return { remote: created.remote, token: token.plaintext };
575
+ });
576
+ ```
577
+
578
+ Repository prefixing, list filtering, and the argv API are delegated directly
579
+ to `@cloudflare/computer/artifacts`, keeping this API and the in-shell command
580
+ in agreement.
581
+
402
582
  ## Hyperdrive Example
403
583
 
404
584
  Hyperdrive tags expose the binding `connectionString` directly on the yielded service.
@@ -698,6 +878,36 @@ if (Worker.isWebSocketUpgrade(request)) {
698
878
 
699
879
  Use `DurableObjectRpcWebSocket.layer(...)` for Effect RPC-over-WebSocket transports. It owns protocol parsing and RPC client bookkeeping; use `DurableWebSocket` for general application sockets, rooms, presence, and broadcast flows.
700
880
 
881
+ ## WebTransport and HTTP/3
882
+
883
+ Cloudflare Workers cannot accept inbound WebTransport sessions today: workerd contains no QUIC/HTTP-3 stack, there is no `WebSocketPair`-style session API, and the maintainers state the feature "is not currently on our priority list" ([cloudflare/workerd#6451](https://github.com/cloudflare/workerd/issues/6451), [discussion #6454](https://github.com/cloudflare/workerd/discussions/6454)). Inbound HTTP/3 is a zone-level setting — the edge terminates QUIC and the Worker still receives an ordinary `fetch` Request. Workers and Durable Objects can accept inbound WebSocket connections; Durable Objects additionally support the hibernation WebSocket API.
884
+
885
+ The `WebTransport` module gives that boundary a typed shape rather than pretending otherwise:
886
+
887
+ ```ts
888
+ import { Effect, Option } from "effect";
889
+ import { WebTransport } from "effect-cf";
890
+
891
+ const fetch = Effect.fn("fetch")(function* (request: Request) {
892
+ // Decoded metadata about the browser→edge hop (HTTP/3 does not reach you).
893
+ const transport = WebTransport.inboundTransport(request);
894
+ const viaHttp3 = Option.match(transport, {
895
+ onNone: () => false,
896
+ onSome: WebTransport.isHttp3,
897
+ });
898
+
899
+ // Feature-detected runtime capabilities: { inboundSessions: false, ... }.
900
+ const capabilities = yield* WebTransport.capabilities;
901
+
902
+ // Explicit typed boundary where a future inbound session API would slot in.
903
+ // yield* WebTransport.inboundSessionsUnsupported;
904
+
905
+ return Response.json({ viaHttp3, capabilities });
906
+ });
907
+ ```
908
+
909
+ For clients that prefer WebTransport where it exists and fall back to Cloudflare-supported WebSockets, see the companion [`effect-webtransport`](../effect-webtransport) package's `Fallback` module — `examples/todo-rpc-ws` wires it up end to end.
910
+
701
911
  ## License
702
912
 
703
913
  MIT
@@ -0,0 +1,231 @@
1
+ import { c as WorkerEnvironment, r as BindingValidationError, t as BindingNotFoundError } from "./Binding-COCtoJXa.mjs";
2
+ import { Context, Effect, Layer } from "effect";
3
+ declare namespace Artifacts_d_exports {
4
+ export { ArtifactsBinding, ArtifactsClient, ArtifactsCommit, ArtifactsCreateOptions, ArtifactsCreateRepoResult, ArtifactsCreateTokenResult, ArtifactsDefinition, ArtifactsErrorCode, ArtifactsForkOptions, ArtifactsImportParams, ArtifactsImportSource, ArtifactsImportTarget, ArtifactsImportTargetOptions, ArtifactsListOptions, ArtifactsLogOptions, ArtifactsLogResult, ArtifactsOperation, ArtifactsOperationError, ArtifactsRepoBinding, ArtifactsRepoClient, ArtifactsRepoInfo, ArtifactsRepoListEntry, ArtifactsRepoListResult, ArtifactsRepoStatus, ArtifactsService, ArtifactsTokenInfo, ArtifactsTokenListResult, ArtifactsTokenScope, ArtifactsTokenState, ArtifactsTree, Cursor, LayerOptions, RepoName, Tag, TagClass, artifactsErrorCodes, artifactsErrorNumericCodes, isArtifactsBinding, isArtifactsRepoBinding, layer, make, makeClient };
5
+ }
6
+ /** Artifacts operation represented by {@link ArtifactsOperationError}. */
7
+ type ArtifactsOperation = "createClient" | "create" | "get" | "import" | "list" | "delete" | "createToken" | "listTokens" | "getToken" | "revokeToken" | "fork" | "log" | "readCommit" | "readTree" | "cli";
8
+ /** Documented string error codes returned by Cloudflare Artifacts. */
9
+ declare const artifactsErrorCodes: readonly ["ALREADY_EXISTS", "NOT_FOUND", "IMPORT_IN_PROGRESS", "FORK_IN_PROGRESS", "INVALID_INPUT", "INVALID_REPO_NAME", "INVALID_TTL", "INVALID_URL", "REMOTE_AUTH_REQUIRED", "UPSTREAM_UNAVAILABLE", "MEMORY_LIMIT", "INTERNAL_ERROR"];
10
+ /** Documented numeric error codes returned by Cloudflare Artifacts. */
11
+ declare const artifactsErrorNumericCodes: {
12
+ readonly ALREADY_EXISTS: 10201;
13
+ readonly NOT_FOUND: 10200;
14
+ readonly IMPORT_IN_PROGRESS: 10302;
15
+ readonly FORK_IN_PROGRESS: 10303;
16
+ readonly INVALID_INPUT: 10100;
17
+ readonly INVALID_REPO_NAME: 10101;
18
+ readonly INVALID_TTL: 10103;
19
+ readonly INVALID_URL: 10104;
20
+ readonly REMOTE_AUTH_REQUIRED: 10106;
21
+ readonly UPSTREAM_UNAVAILABLE: 10401;
22
+ readonly MEMORY_LIMIT: 10402;
23
+ readonly INTERNAL_ERROR: 10400;
24
+ };
25
+ /** A documented Cloudflare Artifacts string error code. */
26
+ type ArtifactsErrorCode = CloudflareArtifactsErrorCode;
27
+ declare const ArtifactsOperationError_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 & {
28
+ readonly _tag: "ArtifactsOperationError";
29
+ } & Readonly<A>;
30
+ /** Error raised when a Cloudflare Artifacts operation fails. */
31
+ declare class ArtifactsOperationError extends ArtifactsOperationError_base<{
32
+ readonly binding: string;
33
+ readonly operation: ArtifactsOperation;
34
+ readonly cause: unknown;
35
+ /** Cloudflare string error code, when retained by the runtime. */
36
+ readonly code?: ArtifactsErrorCode | (string & {});
37
+ /** Cloudflare REST-compatible numeric error code, when retained by the runtime. */
38
+ readonly numericCode?: number;
39
+ }> {
40
+ get message(): string;
41
+ }
42
+ /** Typed Cloudflare Artifacts binding definition. */
43
+ interface ArtifactsDefinition {
44
+ /** Binding name from an `artifacts` entry in `wrangler.jsonc`. */
45
+ readonly binding: string;
46
+ }
47
+ /** Repository name containing alphanumeric characters, dots, hyphens, or underscores. */
48
+ type RepoName = string;
49
+ /** Cursor used by repository list pagination. */
50
+ type Cursor = string;
51
+ /** Scope granted to a repository token. */
52
+ type ArtifactsTokenScope = "read" | "write";
53
+ /** Lifecycle state of a repository token. */
54
+ type ArtifactsTokenState = "active" | "expired" | "revoked";
55
+ /** Lifecycle state included with repositories returned by `list()`. */
56
+ type ArtifactsRepoStatus = "ready" | "importing" | "forking";
57
+ /** Stable repository metadata returned by Cloudflare Artifacts. */
58
+ type ArtifactsRepoInfo = CloudflareArtifactsRepoInfo;
59
+ /** Result of creating, importing, or forking a repository. */
60
+ type ArtifactsCreateRepoResult = Readonly<CloudflareArtifactsCreateRepoResult>;
61
+ /** Repository metadata returned by `list()`. */
62
+ interface ArtifactsRepoListEntry extends ArtifactsRepoInfo {
63
+ readonly status: ArtifactsRepoStatus;
64
+ }
65
+ /** Cursor-paginated repository list result. */
66
+ interface ArtifactsRepoListResult {
67
+ readonly repos: ReadonlyArray<ArtifactsRepoListEntry>;
68
+ readonly total: number;
69
+ readonly cursor?: Cursor;
70
+ }
71
+ /** Result of creating a repository token. */
72
+ type ArtifactsCreateTokenResult = CloudflareArtifactsCreateTokenResult;
73
+ /** Repository token metadata, excluding its plaintext secret. */
74
+ type ArtifactsTokenInfo = CloudflareArtifactsTokenInfo;
75
+ /** Repository token list result. */
76
+ type ArtifactsTokenListResult = CloudflareArtifactsTokenListResult;
77
+ /**
78
+ * Commit history returned by `log()`.
79
+ *
80
+ * Cloudflare currently documents this generated type by name but does not
81
+ * publish its fields in the binding reference or Workers type declarations.
82
+ */
83
+ interface ArtifactsLogResult {
84
+ readonly [field: string]: unknown;
85
+ }
86
+ /**
87
+ * Parsed Git commit returned by `readCommit()`.
88
+ *
89
+ * Cloudflare currently documents this generated type by name but does not
90
+ * publish its fields in the binding reference or Workers type declarations.
91
+ */
92
+ interface ArtifactsCommit {
93
+ readonly [field: string]: unknown;
94
+ }
95
+ /**
96
+ * Parsed Git tree returned by `readTree()`.
97
+ *
98
+ * Cloudflare currently documents this generated type by name but does not
99
+ * publish its fields in the binding reference or Workers type declarations.
100
+ */
101
+ interface ArtifactsTree {
102
+ readonly [field: string]: unknown;
103
+ }
104
+ /** Options for `Artifacts.create()`. */
105
+ interface ArtifactsCreateOptions {
106
+ /** Prevent pushes to the repository. */
107
+ readonly readOnly?: boolean;
108
+ readonly description?: string;
109
+ /** Initial default branch name. */
110
+ readonly setDefaultBranch?: string;
111
+ }
112
+ /** Options for cursor-paginating `Artifacts.list()`. */
113
+ interface ArtifactsListOptions {
114
+ /** Page size from 1 through 200. Defaults to 50. */
115
+ readonly limit?: number;
116
+ /** Cursor returned by a previous list result. */
117
+ readonly cursor?: Cursor;
118
+ }
119
+ /** External Git source used by `Artifacts.import()`. */
120
+ interface ArtifactsImportSource {
121
+ /** Full HTTPS URL of the Git repository. */
122
+ readonly url: string;
123
+ /** Source branch. Defaults to the remote's default branch. */
124
+ readonly branch?: string;
125
+ /** Shallow clone depth. */
126
+ readonly depth?: number;
127
+ }
128
+ /** Options for the target of `Artifacts.import()`. */
129
+ interface ArtifactsImportTargetOptions {
130
+ readonly description?: string;
131
+ readonly readOnly?: boolean;
132
+ }
133
+ /** Target repository used by `Artifacts.import()`. */
134
+ interface ArtifactsImportTarget {
135
+ readonly name: RepoName;
136
+ readonly opts?: ArtifactsImportTargetOptions;
137
+ }
138
+ /** Parameters for `Artifacts.import()`. */
139
+ interface ArtifactsImportParams {
140
+ readonly source: ArtifactsImportSource;
141
+ readonly target: ArtifactsImportTarget;
142
+ }
143
+ /** Options for `ArtifactsRepoClient.fork()`. */
144
+ interface ArtifactsForkOptions {
145
+ readonly description?: string;
146
+ readonly readOnly?: boolean;
147
+ /** Only copy the default branch. Defaults to `true`. */
148
+ readonly defaultBranchOnly?: boolean;
149
+ }
150
+ /** Options for `ArtifactsRepoClient.log()`. */
151
+ interface ArtifactsLogOptions {
152
+ /** Branch, tag, or commit hash. */
153
+ readonly ref?: string;
154
+ readonly limit?: number;
155
+ readonly offset?: number;
156
+ }
157
+ /** Runtime repository handle, including methods absent from current shipped Workers types. */
158
+ interface ArtifactsRepoBinding extends ArtifactsRepoInfo {
159
+ /**
160
+ * Create a Git token for the repository.
161
+ *
162
+ * Scope defaults to `"write"`. TTL is measured in seconds, defaults to
163
+ * 86,400, and must be between 60 and 31,536,000.
164
+ */
165
+ readonly createToken: (scope?: ArtifactsTokenScope, ttl?: number) => Promise<ArtifactsCreateTokenResult>;
166
+ readonly listTokens: () => Promise<ArtifactsTokenListResult>;
167
+ readonly revokeToken: (tokenOrId: string) => Promise<boolean>;
168
+ readonly fork: (name: RepoName, options?: ArtifactsForkOptions) => Promise<ArtifactsCreateRepoResult>;
169
+ readonly log: (options?: ArtifactsLogOptions) => Promise<ArtifactsLogResult>;
170
+ readonly readCommit: (hash: string) => Promise<ArtifactsCommit>;
171
+ readonly readTree: (hash: string) => Promise<ArtifactsTree>;
172
+ }
173
+ /** Cloudflare Artifacts namespace binding. */
174
+ interface ArtifactsBinding {
175
+ readonly create: (name: RepoName, options?: ArtifactsCreateOptions) => Promise<ArtifactsCreateRepoResult>;
176
+ readonly get: (name: RepoName) => Promise<ArtifactsRepoBinding>;
177
+ readonly import: (params: ArtifactsImportParams) => Promise<ArtifactsCreateRepoResult>;
178
+ readonly list: (options?: ArtifactsListOptions) => Promise<ArtifactsRepoListResult>;
179
+ readonly delete: (name: RepoName) => Promise<boolean>;
180
+ }
181
+ /** Effect wrapper around a repository handle returned by `Artifacts.get()`. */
182
+ interface ArtifactsRepoClient extends ArtifactsRepoInfo {
183
+ /**
184
+ * Create a Git token for the repository.
185
+ *
186
+ * Scope defaults to `"write"`. TTL is measured in seconds, defaults to
187
+ * 86,400, and must be between 60 and 31,536,000.
188
+ */
189
+ readonly createToken: (scope?: ArtifactsTokenScope, ttl?: number) => Effect.Effect<ArtifactsCreateTokenResult, ArtifactsOperationError>;
190
+ readonly listTokens: Effect.Effect<ArtifactsTokenListResult, ArtifactsOperationError>;
191
+ readonly revokeToken: (tokenOrId: string) => Effect.Effect<boolean, ArtifactsOperationError>;
192
+ readonly fork: (name: RepoName, options?: ArtifactsForkOptions) => Effect.Effect<ArtifactsCreateRepoResult, ArtifactsOperationError>;
193
+ readonly log: (options?: ArtifactsLogOptions) => Effect.Effect<ArtifactsLogResult, ArtifactsOperationError>;
194
+ readonly readCommit: (hash: string) => Effect.Effect<ArtifactsCommit, ArtifactsOperationError>;
195
+ readonly readTree: (hash: string) => Effect.Effect<ArtifactsTree, ArtifactsOperationError>;
196
+ readonly raw: ArtifactsRepoBinding;
197
+ }
198
+ /** Effect wrapper around a Cloudflare Artifacts namespace binding. */
199
+ interface ArtifactsClient {
200
+ readonly create: (name: RepoName, options?: ArtifactsCreateOptions) => Effect.Effect<ArtifactsCreateRepoResult, ArtifactsOperationError>;
201
+ readonly get: (name: RepoName) => Effect.Effect<ArtifactsRepoClient, ArtifactsOperationError>;
202
+ readonly import: (params: ArtifactsImportParams) => Effect.Effect<ArtifactsCreateRepoResult, ArtifactsOperationError>;
203
+ readonly list: (options?: ArtifactsListOptions) => Effect.Effect<ArtifactsRepoListResult, ArtifactsOperationError>;
204
+ readonly delete: (name: RepoName) => Effect.Effect<boolean, ArtifactsOperationError>;
205
+ readonly rawUnsafe: Effect.Effect<ArtifactsBinding>;
206
+ readonly definition: ArtifactsDefinition;
207
+ }
208
+ declare const ArtifactsServiceTypeId: unique symbol;
209
+ /** Nominal service marker for Artifacts services created with {@link make}. */
210
+ interface ArtifactsService<Id extends string> {
211
+ readonly [ArtifactsServiceTypeId]: {
212
+ readonly id: Id;
213
+ };
214
+ }
215
+ type LayerOptions = {
216
+ readonly binding: string;
217
+ };
218
+ interface TagClass<Self, Id extends string> extends Context.ServiceClass<Self, Id, ArtifactsClient> {
219
+ readonly id: Id;
220
+ readonly layer: (options: LayerOptions) => Layer.Layer<Self, BindingNotFoundError | BindingValidationError, WorkerEnvironment>;
221
+ }
222
+ /** Tests whether a value exposes the complete documented Artifacts repo handle API. */
223
+ declare const isArtifactsRepoBinding: (value: unknown) => value is ArtifactsRepoBinding;
224
+ /** Tests whether a value exposes the complete documented Artifacts namespace API. */
225
+ declare const isArtifactsBinding: (value: unknown) => value is ArtifactsBinding;
226
+ declare const makeClient: (definition: ArtifactsDefinition) => (artifacts: ArtifactsBinding) => ArtifactsClient;
227
+ declare const layer: <Self>(tag: Context.Service<Self, ArtifactsClient>, definition: ArtifactsDefinition) => Layer.Layer<Self, BindingNotFoundError | BindingValidationError, WorkerEnvironment>;
228
+ declare const make: <Id extends string>(id: Id) => TagClass<ArtifactsService<Id>, Id>;
229
+ declare const Tag: <Self>() => <Id extends string>(id: Id) => TagClass<Self, Id>;
230
+ //#endregion
231
+ export { ArtifactsOperationError as a, ArtifactsTokenListResult as c, ArtifactsCreateTokenResult as i, Artifacts_d_exports as l, ArtifactsCreateOptions as n, ArtifactsRepoInfo as o, ArtifactsCreateRepoResult as r, ArtifactsTokenInfo as s, ArtifactsBinding as t, RepoName as u };
@@ -0,0 +1,71 @@
1
+ import { t as ArtifactsBinding } from "./Artifacts-DcoXcRP5.mjs";
2
+ import { GitClientFactory } from "@cloudflare/computer/git";
3
+ import { DurableObjectStorageLike, SyncRetryIntent, SyncRetryOptions, SyncRetryScheduler, WithWorkspaceCtor, WorkspaceAttributeValue, WorkspaceAttributes, WorkspaceObserver, WorkspaceOptions, WorkspaceRegisteredBackend, WorkspaceRetryPendingSyncResult, WorkspaceServiceProxy, WorkspaceSpan } from "@cloudflare/computer";
4
+ import { ShellModuleGroup, WorkerShellBackendOptions, WorkerShellLoader, WorkspaceEgressPolicy } from "@cloudflare/computer/backends/worker-shell";
5
+ //#region src/ComputerWorkspaceHost.d.ts
6
+ /** The value of a `worker_loaders` binding. */
7
+ type DynamicWorkerLoader = WorkerShellLoader;
8
+ /** Default author and committer identity for workspace Git operations. */
9
+ interface ComputerWorkspaceGitIdentity {
10
+ readonly name: string;
11
+ readonly email: string;
12
+ }
13
+ /** Session-scoped Artifacts configuration passed through to `Workspace`. */
14
+ interface ComputerWorkspaceArtifactsOptions {
15
+ readonly binding: ArtifactsBinding;
16
+ /**
17
+ * Session prefix for repository names. When omitted, `sessionId` from the
18
+ * enclosing host configuration is used.
19
+ */
20
+ readonly sessionId?: string;
21
+ }
22
+ /**
23
+ * Worker-shell backend options with the loopback workspace wiring named in
24
+ * Durable Object terms.
25
+ */
26
+ interface ComputerWorkspaceShellOptions extends Omit<WorkerShellBackendOptions, "source" | "loader" | "workspace" | "ctx" | "egress"> {
27
+ readonly loader: DynamicWorkerLoader;
28
+ /** Durable Object namespace binding that points back to the wrapped class. */
29
+ readonly hostBinding: string;
30
+ /** Current Durable Object id, normally `ctx.id.toString()`. */
31
+ readonly hostId: string;
32
+ /** Current Durable Object execution context, normally `ctx`. */
33
+ readonly executionContext: unknown;
34
+ /** Dynamic Worker egress policy. Defaults to `{ mode: "none" }`. */
35
+ readonly egress?: WorkspaceEgressPolicy;
36
+ }
37
+ /** Configuration accepted by {@link withComputerWorkspace}. */
38
+ interface ComputerWorkspaceHostConfig {
39
+ /** Native SQLite-backed Durable Object storage (`ctx.storage`). */
40
+ readonly storage: globalThis.DurableObjectStorage | DurableObjectStorageLike;
41
+ /** Stable workspace id used by mounts and as the default Artifacts session. */
42
+ readonly sessionId?: string;
43
+ readonly gitIdentity?: ComputerWorkspaceGitIdentity;
44
+ /** Override the default `createGitClient()` factory. */
45
+ readonly git?: GitClientFactory;
46
+ /** Additional container, Worker JavaScript, shell, or custom backends. */
47
+ readonly backends?: ReadonlyArray<WorkspaceRegisteredBackend>;
48
+ /** Convenience wiring for one Worker Shell backend. */
49
+ readonly shell?: ComputerWorkspaceShellOptions;
50
+ readonly mounts?: WorkspaceOptions["mounts"];
51
+ readonly observer?: WorkspaceOptions["observer"];
52
+ readonly retryScheduler?: WorkspaceOptions["retryScheduler"];
53
+ readonly retry?: WorkspaceOptions["retry"];
54
+ readonly assets?: WorkspaceOptions["assets"];
55
+ readonly artifacts?: ComputerWorkspaceArtifactsOptions;
56
+ readonly now?: WorkspaceOptions["now"];
57
+ readonly useThink?: WorkspaceOptions["useThink"];
58
+ }
59
+ type DurableObjectConstructor = new (...args: Array<any>) => object;
60
+ /**
61
+ * Wraps a Durable Object class with one SQLite-backed Cloudflare Computer
62
+ * workspace and registers that local workspace for {@link ComputerWorkspace}
63
+ * to acquire through its Effect layer.
64
+ *
65
+ * The class must use a `new_sqlite_classes` migration. If `shell` is present,
66
+ * its Worker must also configure a `worker_loaders` binding, enable the
67
+ * `experimental` compatibility flag, and export `WorkspaceServiceProxy`.
68
+ */
69
+ declare const withComputerWorkspace: <TBase extends DurableObjectConstructor>(Base: TBase, config: (self: InstanceType<TBase>, state: globalThis.DurableObjectState, env: ConstructorParameters<TBase>[1]) => ComputerWorkspaceHostConfig) => WithWorkspaceCtor<TBase>;
70
+ //#endregion
71
+ export { ComputerWorkspaceArtifactsOptions, ComputerWorkspaceGitIdentity, ComputerWorkspaceHostConfig, ComputerWorkspaceShellOptions, DynamicWorkerLoader, type ShellModuleGroup, type SyncRetryIntent, type SyncRetryOptions, type SyncRetryScheduler, type WorkspaceAttributeValue, type WorkspaceAttributes, type WorkspaceEgressPolicy, type WorkspaceObserver, type WorkspaceRetryPendingSyncResult, WorkspaceServiceProxy, type WorkspaceSpan, withComputerWorkspace };
@@ -0,0 +1,74 @@
1
+ import { n as register } from "./ComputerWorkspaceHostRegistry-CY5Fv4Ng.mjs";
2
+ import { createGitClient } from "@cloudflare/computer/git";
3
+ import { WorkspaceServiceProxy, withWorkspace } from "@cloudflare/computer";
4
+ import { WorkerShellBackend } from "@cloudflare/computer/backends/worker-shell";
5
+ //#region src/ComputerWorkspaceHost.ts
6
+ const toWorkspaceOptions = (config) => {
7
+ const backends = [...config.backends ?? []];
8
+ if (config.shell !== void 0) {
9
+ const { egress, executionContext, hostBinding, hostId, loader, ...shellOptions } = config.shell;
10
+ backends.push(new WorkerShellBackend({
11
+ ...shellOptions,
12
+ loader,
13
+ workspace: {
14
+ binding: hostBinding,
15
+ id: hostId
16
+ },
17
+ ctx: executionContext,
18
+ egress: egress ?? { mode: "none" }
19
+ }));
20
+ }
21
+ return {
22
+ storage: config.storage,
23
+ git: config.git ?? createGitClient(),
24
+ ...config.gitIdentity === void 0 ? {} : { defaultGitIdentity: config.gitIdentity },
25
+ ...backends.length === 0 ? {} : { backends },
26
+ ...config.sessionId === void 0 ? {} : { sessionId: config.sessionId },
27
+ ...config.mounts === void 0 ? {} : { mounts: config.mounts },
28
+ ...config.observer === void 0 ? {} : { observer: config.observer },
29
+ ...config.retryScheduler === void 0 ? {} : { retryScheduler: config.retryScheduler },
30
+ ...config.retry === void 0 ? {} : { retry: config.retry },
31
+ ...config.assets === void 0 ? {} : { assets: config.assets },
32
+ ...config.artifacts === void 0 ? {} : { artifacts: {
33
+ binding: config.artifacts.binding,
34
+ ...config.artifacts.sessionId === void 0 ? {} : { sessionId: config.artifacts.sessionId }
35
+ } },
36
+ ...config.now === void 0 ? {} : { now: config.now },
37
+ ...config.useThink === void 0 ? {} : { useThink: config.useThink }
38
+ };
39
+ };
40
+ const HostArguments = Symbol("effect-cf/ComputerWorkspaceHost/arguments");
41
+ /**
42
+ * Wraps a Durable Object class with one SQLite-backed Cloudflare Computer
43
+ * workspace and registers that local workspace for {@link ComputerWorkspace}
44
+ * to acquire through its Effect layer.
45
+ *
46
+ * The class must use a `new_sqlite_classes` migration. If `shell` is present,
47
+ * its Worker must also configure a `worker_loaders` binding, enable the
48
+ * `experimental` compatibility flag, and export `WorkspaceServiceProxy`.
49
+ */
50
+ const withComputerWorkspace = (Base, config) => {
51
+ const CapturedBase = class extends Base {
52
+ [HostArguments];
53
+ constructor(...args) {
54
+ super(...args);
55
+ this[HostArguments] = {
56
+ state: args[0],
57
+ env: args[1]
58
+ };
59
+ }
60
+ };
61
+ const WithWorkspace = withWorkspace(CapturedBase, (self) => {
62
+ const { env, state } = self[HostArguments];
63
+ return toWorkspaceOptions(config(self, state, env));
64
+ });
65
+ class WithComputerWorkspace extends WithWorkspace {
66
+ constructor(...args) {
67
+ super(...args);
68
+ register(args[0], this);
69
+ }
70
+ }
71
+ return WithComputerWorkspace;
72
+ };
73
+ //#endregion
74
+ export { WorkspaceServiceProxy, withComputerWorkspace };
@@ -0,0 +1,8 @@
1
+ //#region src/internal/ComputerWorkspaceHostRegistry.ts
2
+ const hosts = /* @__PURE__ */ new WeakMap();
3
+ const register = (state, host) => {
4
+ hosts.set(state, host);
5
+ };
6
+ const lookup = (state) => hosts.get(state);
7
+ //#endregion
8
+ export { register as n, lookup as t };