@effect-agent/platform-cloudflare 0.1.0-beta.13 → 0.1.0-beta.130

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.
Files changed (105) hide show
  1. package/dist/Alarm.d.mts +244 -0
  2. package/dist/Alarm.mjs +947 -0
  3. package/dist/Alarm.mjs.map +1 -0
  4. package/dist/BrowserCredentials.d.mts +91 -0
  5. package/dist/BrowserCredentials.mjs +120 -0
  6. package/dist/BrowserCredentials.mjs.map +1 -0
  7. package/dist/BrowserRestCapture.d.mts +34 -0
  8. package/dist/BrowserRestCapture.mjs +238 -0
  9. package/dist/BrowserRestCapture.mjs.map +1 -0
  10. package/dist/BrowserRestCrawl.d.mts +16 -0
  11. package/dist/BrowserRestCrawl.mjs +244 -0
  12. package/dist/BrowserRestCrawl.mjs.map +1 -0
  13. package/dist/BrowserSession-BplIoNfi.mjs +442 -0
  14. package/dist/BrowserSession-BplIoNfi.mjs.map +1 -0
  15. package/dist/BrowserSession-DxCN-5F9.d.mts +109 -0
  16. package/dist/BrowserSession.d.mts +3 -0
  17. package/dist/BrowserSession.mjs +4 -0
  18. package/dist/CloudflareAiGateway.d.mts +64 -0
  19. package/dist/CloudflareAiGateway.mjs +70 -0
  20. package/dist/CloudflareAiGateway.mjs.map +1 -0
  21. package/dist/CloudflareBindings.d.mts +115 -0
  22. package/dist/CloudflareBindings.mjs +113 -0
  23. package/dist/CloudflareBindings.mjs.map +1 -0
  24. package/dist/CloudflareBrowser-DV6kya1H.mjs +495 -0
  25. package/dist/CloudflareBrowser-DV6kya1H.mjs.map +1 -0
  26. package/dist/CloudflareBrowser-Doe1M7R5.d.mts +80 -0
  27. package/dist/CloudflareBrowser.d.mts +2 -0
  28. package/dist/CloudflareBrowser.mjs +2 -0
  29. package/dist/CloudflareCodeMode.d.mts +44 -0
  30. package/dist/CloudflareCodeMode.mjs +616 -0
  31. package/dist/CloudflareCodeMode.mjs.map +1 -0
  32. package/dist/CloudflareConfig-DKXGo8L3.d.mts +106 -0
  33. package/dist/CloudflareConfig.d.mts +2 -0
  34. package/dist/CloudflareConfig.mjs +128 -0
  35. package/dist/CloudflareConfig.mjs.map +1 -0
  36. package/dist/CloudflareMemory.d.mts +142 -0
  37. package/dist/CloudflareMemory.mjs +202 -0
  38. package/dist/CloudflareMemory.mjs.map +1 -0
  39. package/dist/CloudflareScheduling.d.mts +52 -0
  40. package/dist/CloudflareScheduling.mjs +396 -0
  41. package/dist/CloudflareScheduling.mjs.map +1 -0
  42. package/dist/CloudflareSubscriptions.d.mts +87 -0
  43. package/dist/CloudflareSubscriptions.mjs +530 -0
  44. package/dist/CloudflareSubscriptions.mjs.map +1 -0
  45. package/dist/CloudflareThreadClient.d.mts +1752 -0
  46. package/dist/CloudflareThreadClient.mjs +382 -0
  47. package/dist/CloudflareThreadClient.mjs.map +1 -0
  48. package/dist/InteractiveBrowser-BnqY_Y-F.d.mts +228 -0
  49. package/dist/InteractiveBrowser-D-xxDv_f.mjs +1923 -0
  50. package/dist/InteractiveBrowser-D-xxDv_f.mjs.map +1 -0
  51. package/dist/InteractiveBrowser.d.mts +2 -0
  52. package/dist/InteractiveBrowser.mjs +2 -0
  53. package/dist/ThreadObject-CVhZC-7l.mjs +849 -0
  54. package/dist/ThreadObject-CVhZC-7l.mjs.map +1 -0
  55. package/dist/ThreadObject-CcS4Q2iT.d.mts +839 -0
  56. package/dist/ThreadObject.d.mts +2 -0
  57. package/dist/ThreadObject.mjs +3 -0
  58. package/dist/WakeScheduler.d.mts +23 -0
  59. package/dist/WakeScheduler.mjs +57 -0
  60. package/dist/WakeScheduler.mjs.map +1 -0
  61. package/dist/boundary-BguazVkh.mjs +42 -0
  62. package/dist/boundary-BguazVkh.mjs.map +1 -0
  63. package/dist/index.d.mts +15 -1550
  64. package/dist/index.mjs +15 -1716
  65. package/dist/prepared-admission-DU0_T-ev.mjs +73 -0
  66. package/dist/prepared-admission-DU0_T-ev.mjs.map +1 -0
  67. package/dist/rolldown-runtime-D7D4PA-g.mjs +13 -0
  68. package/package.json +1 -56
  69. package/src/Alarm.ts +1979 -0
  70. package/src/BrowserCredentials.ts +146 -0
  71. package/src/BrowserRestCapture.ts +477 -0
  72. package/src/BrowserRestCrawl.ts +540 -0
  73. package/src/BrowserSession.ts +591 -0
  74. package/src/CloudflareAiGateway.ts +170 -0
  75. package/src/CloudflareBindings.ts +199 -0
  76. package/src/CloudflareBrowser.ts +15 -0
  77. package/src/{code-mode-executor.ts → CloudflareCodeMode.ts} +308 -283
  78. package/src/{config.ts → CloudflareConfig.ts} +19 -12
  79. package/src/CloudflareMemory.ts +420 -0
  80. package/src/CloudflareScheduling.ts +747 -0
  81. package/src/CloudflareSubscriptions.ts +1041 -0
  82. package/src/CloudflareThreadClient.ts +809 -0
  83. package/src/InteractiveBrowser.ts +3246 -0
  84. package/src/ThreadObject.ts +1190 -0
  85. package/src/{wake-scheduler.ts → WakeScheduler.ts} +32 -26
  86. package/src/index.ts +14 -23
  87. package/src/internal/boundary.ts +55 -0
  88. package/src/internal/browser-binding.ts +322 -0
  89. package/src/internal/browser-credentials.ts +362 -0
  90. package/src/internal/browser-failure.ts +92 -0
  91. package/src/internal/browser-file-selection.ts +126 -0
  92. package/src/internal/browser-quick-action.ts +857 -0
  93. package/src/internal/browser-session-lifecycle.ts +193 -0
  94. package/src/internal/layers.ts +773 -0
  95. package/src/internal/message-delivery.ts +131 -0
  96. package/src/internal/prepared-admission.ts +116 -0
  97. package/src/internal/progress-wait.ts +121 -0
  98. package/src/internal/transport.ts +44 -0
  99. package/dist/index.mjs.map +0 -1
  100. package/src/alarm.ts +0 -334
  101. package/src/bindings.ts +0 -145
  102. package/src/client.ts +0 -646
  103. package/src/conversation-object.ts +0 -768
  104. package/src/layers.ts +0 -376
  105. package/src/transport.ts +0 -38
@@ -0,0 +1,109 @@
1
+ import { BrowserCredentialAccess, CredentialFillError, CredentialFillResult, FillCredentialRequest } from "./BrowserCredentials.mjs";
2
+ import { A as BrowserRunSessionLifecycle, O as BrowserRunCleanupError, _ as BrowserRunLiveViewRequest, i as BrowserRunHandoffState, k as BrowserRunLifecycleOptions, n as BrowserRunHandoffRequest, r as BrowserRunHandoffResult, v as BrowserRunLiveViewResult } from "./InteractiveBrowser-BnqY_Y-F.mjs";
3
+ import { Cause, Context, Effect, ErrorReporter, Layer, Redacted, Schema, Scope } from "effect";
4
+ import { Browser, Page } from "puppeteer-core/lib/esm/puppeteer/puppeteer-core-browser.js";
5
+ //#region src/internal/browser-failure.d.ts
6
+ declare const BrowserRunFailure_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]; }>) => Cause.YieldableError & {
7
+ readonly _tag: "BrowserRunFailure";
8
+ } & Readonly<A>;
9
+ /** Source-authored stages and classifications only; never retain SDK text or session capabilities. */
10
+ declare class BrowserRunFailure extends BrowserRunFailure_base<{
11
+ readonly operation: string;
12
+ readonly reason: "provider" | "timeout" | "malformed" | "configuration" | "authorization" | "rate-limited" | "pending";
13
+ readonly status?: number;
14
+ readonly cause?: BrowserRunFailure | {
15
+ readonly name: string;
16
+ };
17
+ }> {
18
+ readonly [ErrorReporter.severity]: "Error";
19
+ }
20
+ //#endregion
21
+ //#region src/internal/browser-binding.d.ts
22
+ /** Private attachment ownership is available before asynchronous SDK initialization completes. */
23
+ interface BrowserRunAttachment {
24
+ readonly browser: Promise<Browser>;
25
+ /** Fence SDK dispatch/callbacks and await local socket closure; never terminate the provider. */
26
+ readonly retire: Effect.Effect<void, BrowserRunFailure>;
27
+ }
28
+ declare const BrowserRunBinding_base: Context.ServiceClass<BrowserRunBinding, "@effect-agent/platform-cloudflare/internal/BrowserRunBinding", {
29
+ readonly acquire: (keepAliveMillis: number, operation: "interactive.acquire" | "session.acquire") => Promise<string>;
30
+ readonly connect: (sessionId: string, operation: string, signal?: AbortSignal) => BrowserRunAttachment;
31
+ readonly keepAlive: (sessionId: string) => Effect.Effect<void, BrowserRunFailure>;
32
+ }>;
33
+ /** Native transport port shared by both scoped adapters; the Layer owns the foreign binding. */
34
+ declare class BrowserRunBinding extends BrowserRunBinding_base {
35
+ static layer(browser: Pick<BrowserRun, "fetch">): Layer.Layer<BrowserRunBinding, never, never>;
36
+ }
37
+ declare namespace BrowserSession_d_exports {
38
+ export { BrowserRunHandoffRequest, BrowserRunHandoffResult, BrowserRunHandoffState, BrowserRunLiveViewRequest, BrowserRunLiveViewResult, BrowserSession, BrowserSessionError, BrowserSessionOptions, BrowserSessionReference, BrowserSessions, BrowserSessionsOptions };
39
+ }
40
+ declare const BrowserSessionReference_base: Schema.Class<BrowserSessionReference, Schema.Struct<{
41
+ readonly version: Schema.Literal<1>;
42
+ readonly sessionId: Schema.Redacted<Schema.String>;
43
+ readonly contextId: Schema.Redacted<Schema.NonEmptyString>;
44
+ readonly targetId: Schema.Redacted<Schema.NonEmptyString>;
45
+ readonly expiresAt: Schema.Int;
46
+ readonly commandTimeoutMillis: Schema.Int;
47
+ }>, {}>;
48
+ /** Private host record, not a model capability. Persist together with the owner's controller state. */
49
+ declare class BrowserSessionReference extends BrowserSessionReference_base {}
50
+ declare const BrowserSessionOptions_base: Schema.Class<BrowserSessionOptions, Schema.Struct<{
51
+ readonly maxElapsedMillis: Schema.Int;
52
+ readonly keepAliveMillis: Schema.optionalKey<Schema.Int>;
53
+ readonly commandTimeoutMillis: Schema.optionalKey<Schema.Int>;
54
+ }>, {}>;
55
+ declare class BrowserSessionOptions extends BrowserSessionOptions_base {}
56
+ declare const BrowserSessionError_base: Schema.Class<BrowserSessionError, Schema.TaggedStruct<"BrowserSessionError", {
57
+ readonly reason: Schema.Literals<readonly ["invalid", "expired", "missing-page", "busy", "closed", "provider", "timeout", "cleanup"]>;
58
+ readonly dispatch: Schema.Literals<readonly ["not-dispatched", "possibly-dispatched"]>;
59
+ readonly cleanup: Schema.Literals<readonly ["not-requested", "confirmed", "unconfirmed"]>;
60
+ }>, Cause.YieldableError>;
61
+ /** No SDK text, selectors, page data, or credential values are retained in public failures. */
62
+ declare class BrowserSessionError extends BrowserSessionError_base {}
63
+ /**
64
+ * One local attachment to an application-owned browser. Scope release disconnects; it never
65
+ * transfers ownership or closes a healthy remote session. The owner serializes attachments,
66
+ * fences old attempts, authorizes human access, and calls BrowserSessions.close on expiry/stop.
67
+ * Native callbacks are trusted host code: never retain SDK handles or start unawaited work.
68
+ */
69
+ interface BrowserSession {
70
+ readonly reference: BrowserSessionReference;
71
+ /**
72
+ * Check current authority under the lock before native dispatch. A settled SDK rejection leaves
73
+ * the session available for inspection, but may have changed the website; never retry blindly.
74
+ * Timeout/interruption fences outstanding SDK work and terminates the exact browser.
75
+ */
76
+ readonly run: <A, E, R>(authorize: Effect.Effect<void, E, R>, action: (page: Page) => Promise<A>) => Effect.Effect<A, E | BrowserSessionError, R>;
77
+ /**
78
+ * Resolves host-owned material under fresh credential grants. Never submits or retries a write.
79
+ * Credential timeouts retain acknowledged writes and dispatch evidence alongside cleanup.
80
+ */
81
+ readonly fillCredential: (request: FillCredentialRequest) => Effect.Effect<CredentialFillResult, CredentialFillError | BrowserSessionError, BrowserCredentialAccess>;
82
+ readonly handoff: <E, R>(authorize: Effect.Effect<void, E, R>, request: BrowserRunHandoffRequest) => Effect.Effect<BrowserRunHandoffResult, E | BrowserSessionError, R>;
83
+ readonly getLiveView: <E, R>(authorize: Effect.Effect<void, E, R>, request: BrowserRunLiveViewRequest) => Effect.Effect<BrowserRunLiveViewResult, E | BrowserSessionError, R>;
84
+ readonly getHandoffState: <E, R>(authorize: Effect.Effect<void, E, R>) => Effect.Effect<BrowserRunHandoffState, E | BrowserSessionError, R>;
85
+ }
86
+ interface BrowserSessionsOptions extends BrowserRunLifecycleOptions {
87
+ readonly browser: Pick<BrowserRun, "fetch">;
88
+ }
89
+ declare const BrowserSessions_base: Context.ServiceClass<BrowserSessions, "@effect-agent/platform-cloudflare/BrowserSessions", {
90
+ /**
91
+ * Allocate once and commit its private reference in retain. Failed/uncommitted creation closes
92
+ * the allocation. After retain succeeds the application owns remote cleanup, independent of
93
+ * attempt Scopes. A lost allocation reply can remain indeterminate until provider idle expiry.
94
+ */
95
+ readonly create: <E, R>(options: BrowserSessionOptions, retain: (reference: BrowserSessionReference) => Effect.Effect<void, E, R>) => Effect.Effect<BrowserSessionReference, E | BrowserSessionError, R>;
96
+ /** Attach only the exact saved context/page. Never recreate missing/expired state. */
97
+ readonly attach: (reference: BrowserSessionReference) => Effect.Effect<BrowserSession, BrowserSessionError, Scope.Scope>;
98
+ /** Refresh provider inactivity only; the owner must still enforce its expiresAt. */
99
+ readonly keepAlive: (sessionId: Redacted.Redacted<string>) => Effect.Effect<void, BrowserSessionError>;
100
+ readonly close: (sessionId: Redacted.Redacted<string>) => Effect.Effect<void, BrowserSessionError>;
101
+ }>;
102
+ /** Native Cloudflare sessions; no framework browser workflow, checkpoint transfer, or observation policy. */
103
+ declare class BrowserSessions extends BrowserSessions_base {
104
+ static readonly layerNoDeps: Layer.Layer<BrowserSessions, never, BrowserRunBinding | BrowserRunSessionLifecycle>;
105
+ static layer(options: BrowserSessionsOptions): Layer.Layer<BrowserSessions, BrowserRunCleanupError, import("effect/unstable/http/HttpClient").HttpClient>;
106
+ }
107
+ //#endregion
108
+ export { BrowserSession_d_exports as a, BrowserSessionReference as i, BrowserSessionError as n, BrowserSessions as o, BrowserSessionOptions as r, BrowserSessionsOptions as s, BrowserSession as t };
109
+ //# sourceMappingURL=BrowserSession-DxCN-5F9.d.mts.map
@@ -0,0 +1,3 @@
1
+ import { _ as BrowserRunLiveViewRequest, i as BrowserRunHandoffState, n as BrowserRunHandoffRequest, r as BrowserRunHandoffResult, v as BrowserRunLiveViewResult } from "./InteractiveBrowser-BnqY_Y-F.mjs";
2
+ import { i as BrowserSessionReference, n as BrowserSessionError, o as BrowserSessions, r as BrowserSessionOptions, s as BrowserSessionsOptions, t as BrowserSession } from "./BrowserSession-DxCN-5F9.mjs";
3
+ export { BrowserRunHandoffRequest, BrowserRunHandoffResult, BrowserRunHandoffState, BrowserRunLiveViewRequest, BrowserRunLiveViewResult, BrowserSession, BrowserSessionError, BrowserSessionOptions, BrowserSessionReference, BrowserSessions, BrowserSessionsOptions };
@@ -0,0 +1,4 @@
1
+ import "./BrowserCredentials.mjs";
2
+ import { c as BrowserRunLiveViewResult, n as BrowserRunHandoffResult, r as BrowserRunHandoffState, s as BrowserRunLiveViewRequest, t as BrowserRunHandoffRequest } from "./InteractiveBrowser-D-xxDv_f.mjs";
3
+ import { a as BrowserSessions, n as BrowserSessionOptions, r as BrowserSessionReference, t as BrowserSessionError } from "./BrowserSession-BplIoNfi.mjs";
4
+ export { BrowserRunHandoffRequest, BrowserRunHandoffResult, BrowserRunHandoffState, BrowserRunLiveViewRequest, BrowserRunLiveViewResult, BrowserSessionError, BrowserSessionOptions, BrowserSessionReference, BrowserSessions };
@@ -0,0 +1,64 @@
1
+ import { Layer, Redacted } from "effect";
2
+ import { HttpClient } from "effect/unstable/http";
3
+ declare namespace CloudflareAiGateway_d_exports {
4
+ export { ClientOptions, ProviderOptions, RestOptions, RouteOptions, provide, provider, rest };
5
+ }
6
+ /** Options understood by upstream Effect AI clients; no model or provider wrapper is created. */
7
+ export interface ClientOptions {
8
+ readonly apiUrl: string;
9
+ readonly transformClient: (client: HttpClient.HttpClient) => HttpClient.HttpClient;
10
+ }
11
+ export interface ProviderOptions {
12
+ readonly accountId: string;
13
+ readonly gatewayId: string;
14
+ /** Cloudflare's provider path, such as openai, anthropic, google-ai-studio, or perplexity-ai. */
15
+ readonly provider: string;
16
+ /** Omit only for an unauthenticated gateway with a separately supplied provider key. */
17
+ readonly apiToken?: Redacted.Redacted<string>;
18
+ }
19
+ export interface RestOptions {
20
+ readonly accountId: string;
21
+ readonly gatewayId: string;
22
+ /** Cloudflare API token with Workers AI Read permission. */
23
+ readonly apiToken: Redacted.Redacted<string>;
24
+ /** Matches the paths appended by the upstream Effect client. */
25
+ readonly protocol: "responses" | "chat-completions" | "messages";
26
+ }
27
+ /** Choose exactly one route: a native provider path or an account REST protocol. */
28
+ export type RouteOptions = (ProviderOptions & {
29
+ readonly protocol?: never;
30
+ }) | (RestOptions & {
31
+ readonly provider?: never;
32
+ });
33
+ /**
34
+ * Provider-native proxy for model calls, streaming, embeddings, and hosted tools supported
35
+ * by that provider. Pass the result to the upstream client's layer along with its apiKey
36
+ * for BYOK-in-request, or omit apiKey for Gateway stored keys / Unified Billing.
37
+ * Provider model names and request bodies pass through unchanged. This module is Node-safe.
38
+ * Custom transforms and redirect policies must retain this endpoint and credential boundary.
39
+ */
40
+ export declare const provider: (options: ProviderOptions) => ClientOptions;
41
+ /**
42
+ * Cloudflare's account REST API (not the deprecated /compat API). Use provider-qualified
43
+ * model names, e.g. openai/gpt-4.1 or anthropic/claude-haiku-4.5, and omit provider apiKey.
44
+ * OpenAI clients append /responses or /chat/completions; Anthropic appends /v1/messages.
45
+ * Compatibility remains the responsibility of the selected upstream client and model.
46
+ */
47
+ export declare const rest: (options: RestOptions) => ClientOptions;
48
+ /**
49
+ * Provide a Gateway-configured upstream client directly in a Layer pipeline.
50
+ * Pass the client's `layer` factory, or a callback adding client-specific options.
51
+ * The factory's errors and remaining services (such as HttpClient) stay visible.
52
+ * Model selection and resource ownership remain with the supplied upstream Layers.
53
+ *
54
+ * @example
55
+ * ```ts
56
+ * AnthropicLanguageModel.model("claude-haiku-4-5").pipe(
57
+ * Gateway.provide(AnthropicClient.layer, { ...options, provider: "anthropic" }),
58
+ * )
59
+ * ```
60
+ */
61
+ export declare const provide: <Client, E, R>(clientLayer: (options: ClientOptions) => Layer.Layer<Client, E, R>, options: RouteOptions) => <RIn2, E2, ROut2>(self: Layer.Layer<ROut2, E2, RIn2>) => Layer.Layer<ROut2, E | E2, R | Exclude<RIn2, Client>>;
62
+ //#endregion
63
+ export { CloudflareAiGateway_d_exports as t };
64
+ //# sourceMappingURL=CloudflareAiGateway.d.mts.map
@@ -0,0 +1,70 @@
1
+ import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
2
+ import { Context, Effect, Layer, Option, Redactable, Redacted, Schema } from "effect";
3
+ import { FetchHttpClient, Headers, HttpClient, HttpClientError, HttpClientRequest } from "effect/unstable/http";
4
+ //#region src/CloudflareAiGateway.ts
5
+ var CloudflareAiGateway_exports = /* @__PURE__ */ __exportAll({
6
+ provide: () => provide,
7
+ provider: () => provider,
8
+ rest: () => rest
9
+ });
10
+ const Segment = Schema.NonEmptyString.check(Schema.isMaxLength(256), Schema.isPattern(/^[a-zA-Z0-9_-]+$/));
11
+ const decodeSegment = Schema.decodeUnknownSync(Segment);
12
+ const redactGatewayToken = (headers, tokenHeader) => {
13
+ Object.defineProperty(headers, Redactable.symbolRedactable, {
14
+ configurable: true,
15
+ value: (context) => Headers.redact(headers, [...Context.get(context, Headers.CurrentRedactedNames), tokenHeader])
16
+ });
17
+ };
18
+ const clientOptions = (apiUrl, tokenHeader, apiToken, gatewayId) => Object.freeze({
19
+ apiUrl,
20
+ transformClient: (client) => client.pipe(HttpClient.mapRequestEffect((request) => {
21
+ const url = URL.parse(request.url);
22
+ if (url === null || url.username !== "" || url.password !== "" || !(url.href === apiUrl || url.href.startsWith(`${apiUrl}/`))) return Effect.fail(new HttpClientError.HttpClientError({ reason: new HttpClientError.InvalidUrlError({
23
+ request,
24
+ description: "Request is outside the configured Cloudflare AI Gateway endpoint"
25
+ }) }));
26
+ let prepared = request;
27
+ if (apiToken !== void 0) prepared = HttpClientRequest.setHeader(prepared, tokenHeader, `Bearer ${Redacted.value(apiToken)}`);
28
+ if (gatewayId !== void 0) prepared = HttpClientRequest.setHeader(prepared, "cf-aig-gateway-id", gatewayId);
29
+ return Effect.succeed(prepared);
30
+ }), HttpClient.transformResponse((effect) => Effect.gen(function* () {
31
+ const defaults = yield* Effect.serviceOption(FetchHttpClient.RequestInit);
32
+ return yield* effect.pipe(Effect.provideService(FetchHttpClient.RequestInit, {
33
+ ...Option.getOrElse(defaults, () => ({})),
34
+ redirect: "error"
35
+ }));
36
+ })), HttpClient.transformResponse((effect) => effect.pipe(Effect.tap((response) => Effect.sync(() => redactGatewayToken(response.request.headers, tokenHeader))), Effect.tapError((error) => Effect.sync(() => redactGatewayToken(error.reason.request.headers, tokenHeader))), Effect.updateService(Headers.CurrentRedactedNames, (names) => [...names, tokenHeader]))))
37
+ });
38
+ /**
39
+ * Provider-native proxy for model calls, streaming, embeddings, and hosted tools supported
40
+ * by that provider. Pass the result to the upstream client's layer along with its apiKey
41
+ * for BYOK-in-request, or omit apiKey for Gateway stored keys / Unified Billing.
42
+ * Provider model names and request bodies pass through unchanged. This module is Node-safe.
43
+ * Custom transforms and redirect policies must retain this endpoint and credential boundary.
44
+ */
45
+ const provider = (options) => clientOptions(`https://gateway.ai.cloudflare.com/v1/${decodeSegment(options.accountId)}/${decodeSegment(options.gatewayId)}/${decodeSegment(options.provider)}`, "cf-aig-authorization", options.apiToken);
46
+ /**
47
+ * Cloudflare's account REST API (not the deprecated /compat API). Use provider-qualified
48
+ * model names, e.g. openai/gpt-4.1 or anthropic/claude-haiku-4.5, and omit provider apiKey.
49
+ * OpenAI clients append /responses or /chat/completions; Anthropic appends /v1/messages.
50
+ * Compatibility remains the responsibility of the selected upstream client and model.
51
+ */
52
+ const rest = (options) => clientOptions(`https://api.cloudflare.com/client/v4/accounts/${decodeSegment(options.accountId)}/ai${options.protocol === "messages" ? "" : "/v1"}`, "authorization", options.apiToken, decodeSegment(options.gatewayId));
53
+ /**
54
+ * Provide a Gateway-configured upstream client directly in a Layer pipeline.
55
+ * Pass the client's `layer` factory, or a callback adding client-specific options.
56
+ * The factory's errors and remaining services (such as HttpClient) stay visible.
57
+ * Model selection and resource ownership remain with the supplied upstream Layers.
58
+ *
59
+ * @example
60
+ * ```ts
61
+ * AnthropicLanguageModel.model("claude-haiku-4-5").pipe(
62
+ * Gateway.provide(AnthropicClient.layer, { ...options, provider: "anthropic" }),
63
+ * )
64
+ * ```
65
+ */
66
+ const provide = (clientLayer, options) => Layer.provide(clientLayer(options.provider !== void 0 ? provider(options) : rest(options)));
67
+ //#endregion
68
+ export { provide, provider, rest, CloudflareAiGateway_exports as t };
69
+
70
+ //# sourceMappingURL=CloudflareAiGateway.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CloudflareAiGateway.mjs","names":[],"sources":["../src/CloudflareAiGateway.ts"],"sourcesContent":["import { Context, Effect, Layer, Option, Redactable, Redacted, Schema } from \"effect\";\nimport {\n FetchHttpClient,\n Headers,\n HttpClient,\n HttpClientError,\n HttpClientRequest,\n} from \"effect/unstable/http\";\n\nconst Segment = Schema.NonEmptyString.check(\n Schema.isMaxLength(256),\n Schema.isPattern(/^[a-zA-Z0-9_-]+$/),\n);\n\nconst decodeSegment = Schema.decodeUnknownSync(Segment);\n\n/** Options understood by upstream Effect AI clients; no model or provider wrapper is created. */\nexport interface ClientOptions {\n readonly apiUrl: string;\n readonly transformClient: (client: HttpClient.HttpClient) => HttpClient.HttpClient;\n}\n\nexport interface ProviderOptions {\n readonly accountId: string;\n readonly gatewayId: string;\n /** Cloudflare's provider path, such as openai, anthropic, google-ai-studio, or perplexity-ai. */\n readonly provider: string;\n /** Omit only for an unauthenticated gateway with a separately supplied provider key. */\n readonly apiToken?: Redacted.Redacted<string>;\n}\n\nexport interface RestOptions {\n readonly accountId: string;\n readonly gatewayId: string;\n /** Cloudflare API token with Workers AI Read permission. */\n readonly apiToken: Redacted.Redacted<string>;\n /** Matches the paths appended by the upstream Effect client. */\n readonly protocol: \"responses\" | \"chat-completions\" | \"messages\";\n}\n\n/** Choose exactly one route: a native provider path or an account REST protocol. */\nexport type RouteOptions =\n | (ProviderOptions & { readonly protocol?: never })\n | (RestOptions & { readonly provider?: never });\n\nconst redactGatewayToken = (headers: Headers.Headers, tokenHeader: string): void => {\n // HTTP tracing can copy headers after preprocessing. Attach the public redaction\n // protocol to the final request as well, before a provider builds error details.\n Object.defineProperty(headers, Redactable.symbolRedactable, {\n configurable: true,\n value: (context: Context.Context<never>) =>\n Headers.redact(headers, [...Context.get(context, Headers.CurrentRedactedNames), tokenHeader]),\n });\n};\n\nconst clientOptions = (\n apiUrl: string,\n tokenHeader: \"authorization\" | \"cf-aig-authorization\",\n apiToken: Redacted.Redacted<string> | undefined,\n gatewayId?: string,\n): ClientOptions =>\n Object.freeze({\n apiUrl,\n transformClient: (client: HttpClient.HttpClient) =>\n client.pipe(\n HttpClient.mapRequestEffect((request) => {\n const url = URL.parse(request.url);\n\n // Check the normalized URL too: dot segments must not escape this account or gateway.\n if (\n url === null ||\n url.username !== \"\" ||\n url.password !== \"\" ||\n !(url.href === apiUrl || url.href.startsWith(`${apiUrl}/`))\n ) {\n return Effect.fail(\n new HttpClientError.HttpClientError({\n reason: new HttpClientError.InvalidUrlError({\n request,\n description: \"Request is outside the configured Cloudflare AI Gateway endpoint\",\n }),\n }),\n );\n }\n let prepared = request;\n\n if (apiToken !== undefined) {\n prepared = HttpClientRequest.setHeader(\n prepared,\n tokenHeader,\n `Bearer ${Redacted.value(apiToken)}`,\n );\n }\n if (gatewayId !== undefined) {\n prepared = HttpClientRequest.setHeader(prepared, \"cf-aig-gateway-id\", gatewayId);\n }\n\n return Effect.succeed(prepared);\n }),\n HttpClient.transformResponse((effect) =>\n Effect.gen(function* () {\n const defaults = yield* Effect.serviceOption(FetchHttpClient.RequestInit);\n\n return yield* effect.pipe(\n Effect.provideService(FetchHttpClient.RequestInit, {\n ...Option.getOrElse(defaults, () => ({})),\n redirect: \"error\",\n }),\n );\n }),\n ),\n HttpClient.transformResponse((effect) =>\n effect.pipe(\n Effect.tap((response) =>\n Effect.sync(() => redactGatewayToken(response.request.headers, tokenHeader)),\n ),\n Effect.tapError((error) =>\n Effect.sync(() => redactGatewayToken(error.reason.request.headers, tokenHeader)),\n ),\n Effect.updateService(Headers.CurrentRedactedNames, (names) => [...names, tokenHeader]),\n ),\n ),\n ),\n });\n\n/**\n * Provider-native proxy for model calls, streaming, embeddings, and hosted tools supported\n * by that provider. Pass the result to the upstream client's layer along with its apiKey\n * for BYOK-in-request, or omit apiKey for Gateway stored keys / Unified Billing.\n * Provider model names and request bodies pass through unchanged. This module is Node-safe.\n * Custom transforms and redirect policies must retain this endpoint and credential boundary.\n */\nexport const provider = (options: ProviderOptions): ClientOptions =>\n clientOptions(\n `https://gateway.ai.cloudflare.com/v1/${decodeSegment(options.accountId)}/${decodeSegment(options.gatewayId)}/${decodeSegment(options.provider)}`,\n \"cf-aig-authorization\",\n options.apiToken,\n );\n\n/**\n * Cloudflare's account REST API (not the deprecated /compat API). Use provider-qualified\n * model names, e.g. openai/gpt-4.1 or anthropic/claude-haiku-4.5, and omit provider apiKey.\n * OpenAI clients append /responses or /chat/completions; Anthropic appends /v1/messages.\n * Compatibility remains the responsibility of the selected upstream client and model.\n */\nexport const rest = (options: RestOptions): ClientOptions =>\n clientOptions(\n `https://api.cloudflare.com/client/v4/accounts/${decodeSegment(options.accountId)}/ai${options.protocol === \"messages\" ? \"\" : \"/v1\"}`,\n \"authorization\",\n options.apiToken,\n decodeSegment(options.gatewayId),\n );\n\n/**\n * Provide a Gateway-configured upstream client directly in a Layer pipeline.\n * Pass the client's `layer` factory, or a callback adding client-specific options.\n * The factory's errors and remaining services (such as HttpClient) stay visible.\n * Model selection and resource ownership remain with the supplied upstream Layers.\n *\n * @example\n * ```ts\n * AnthropicLanguageModel.model(\"claude-haiku-4-5\").pipe(\n * Gateway.provide(AnthropicClient.layer, { ...options, provider: \"anthropic\" }),\n * )\n * ```\n */\nexport const provide = <Client, E, R>(\n clientLayer: (options: ClientOptions) => Layer.Layer<Client, E, R>,\n options: RouteOptions,\n) => Layer.provide(clientLayer(options.provider !== undefined ? provider(options) : rest(options)));\n"],"mappings":";;;;;;;;;AASA,MAAM,UAAU,OAAO,eAAe,MACpC,OAAO,YAAY,GAAG,GACtB,OAAO,UAAU,kBAAkB,CACrC;AAEA,MAAM,gBAAgB,OAAO,kBAAkB,OAAO;AA+BtD,MAAM,sBAAsB,SAA0B,gBAA8B;CAGlF,OAAO,eAAe,SAAS,WAAW,kBAAkB;EAC1D,cAAc;EACd,QAAQ,YACN,QAAQ,OAAO,SAAS,CAAC,GAAG,QAAQ,IAAI,SAAS,QAAQ,oBAAoB,GAAG,WAAW,CAAC;CAChG,CAAC;AACH;AAEA,MAAM,iBACJ,QACA,aACA,UACA,cAEA,OAAO,OAAO;CACZ;CACA,kBAAkB,WAChB,OAAO,KACL,WAAW,kBAAkB,YAAY;EACvC,MAAM,MAAM,IAAI,MAAM,QAAQ,GAAG;EAGjC,IACE,QAAQ,QACR,IAAI,aAAa,MACjB,IAAI,aAAa,MACjB,EAAE,IAAI,SAAS,UAAU,IAAI,KAAK,WAAW,GAAG,OAAO,EAAE,IAEzD,OAAO,OAAO,KACZ,IAAI,gBAAgB,gBAAgB,EAClC,QAAQ,IAAI,gBAAgB,gBAAgB;GAC1C;GACA,aAAa;EACf,CAAC,EACH,CAAC,CACH;EAEF,IAAI,WAAW;EAEf,IAAI,aAAa,KAAA,GACf,WAAW,kBAAkB,UAC3B,UACA,aACA,UAAU,SAAS,MAAM,QAAQ,GACnC;EAEF,IAAI,cAAc,KAAA,GAChB,WAAW,kBAAkB,UAAU,UAAU,qBAAqB,SAAS;EAGjF,OAAO,OAAO,QAAQ,QAAQ;CAChC,CAAC,GACD,WAAW,mBAAmB,WAC5B,OAAO,IAAI,aAAa;EACtB,MAAM,WAAW,OAAO,OAAO,cAAc,gBAAgB,WAAW;EAExE,OAAO,OAAO,OAAO,KACnB,OAAO,eAAe,gBAAgB,aAAa;GACjD,GAAG,OAAO,UAAU,iBAAiB,CAAC,EAAE;GACxC,UAAU;EACZ,CAAC,CACH;CACF,CAAC,CACH,GACA,WAAW,mBAAmB,WAC5B,OAAO,KACL,OAAO,KAAK,aACV,OAAO,WAAW,mBAAmB,SAAS,QAAQ,SAAS,WAAW,CAAC,CAC7E,GACA,OAAO,UAAU,UACf,OAAO,WAAW,mBAAmB,MAAM,OAAO,QAAQ,SAAS,WAAW,CAAC,CACjF,GACA,OAAO,cAAc,QAAQ,uBAAuB,UAAU,CAAC,GAAG,OAAO,WAAW,CAAC,CACvF,CACF,CACF;AACJ,CAAC;;;;;;;;AASH,MAAa,YAAY,YACvB,cACE,wCAAwC,cAAc,QAAQ,SAAS,EAAE,GAAG,cAAc,QAAQ,SAAS,EAAE,GAAG,cAAc,QAAQ,QAAQ,KAC9I,wBACA,QAAQ,QACV;;;;;;;AAQF,MAAa,QAAQ,YACnB,cACE,iDAAiD,cAAc,QAAQ,SAAS,EAAE,KAAK,QAAQ,aAAa,aAAa,KAAK,SAC9H,iBACA,QAAQ,UACR,cAAc,QAAQ,SAAS,CACjC;;;;;;;;;;;;;;AAeF,MAAa,WACX,aACA,YACG,MAAM,QAAQ,YAAY,QAAQ,aAAa,KAAA,IAAY,SAAS,OAAO,IAAI,KAAK,OAAO,CAAC,CAAC"}
@@ -0,0 +1,115 @@
1
+ import { Context, Effect, Layer, Schema } from "effect";
2
+ import { ThreadId } from "effect-agent/identifiers";
3
+ import { ProducerId } from "effect-agent/records";
4
+ declare namespace CloudflareBindings_d_exports {
5
+ export { CloudflareBindingError, DurableObjectContext, ThreadObjectClient, ThreadObjectIdentity, ThreadObjectNamespace, ThreadObjectPlacement, ThreadObjectRpc, callThreadObject, threadNamespaceFromEnv, threadNamespaceLayer };
6
+ }
7
+ declare const CloudflareBindingError_base: Schema.Class<CloudflareBindingError, Schema.TaggedStruct<"CloudflareBindingError", {
8
+ readonly binding: Schema.String;
9
+ readonly message: Schema.String;
10
+ }>, import("effect/Cause").YieldableError>;
11
+ /**
12
+ * Cloudflare platform bindings as Effect services (DEPLOY-010: "Cloudflare platform bindings
13
+ * are supplied as Effect services/Layers"). Application code never reads `env` or touches a
14
+ * `DurableObjectState` directly — the Thread Object class constructs these Layers once
15
+ * per incarnation and everything downstream consumes the services.
16
+ */
17
+ /** A Cloudflare platform binding was missing or carried the wrong shape (DEPLOY-003/010). */
18
+ export declare class CloudflareBindingError extends CloudflareBindingError_base {}
19
+ /**
20
+ * The RPC surface one Thread Durable Object exposes to Workers and to sibling
21
+ * Thread Objects. `ThreadObject.make` implements it; the Worker-side client
22
+ * and the cross-Object transport call it through `DurableObjectNamespace` stubs. Every
23
+ * `encoded` value is a Schema-encoded envelope (`client.ts` wire schemas for host entry
24
+ * points, `@effect-agent/storage-cloudflare` port envelopes for `portCall`), so the RPC
25
+ * boundary carries only structured-cloneable JSON. The optional trailing trace context is
26
+ * transient native RPC metadata, stripped by an opted-in effect-cf receiver before decoding
27
+ * the host envelope. It never enters durable state.
28
+ */
29
+ export interface ThreadObjectRpc extends Rpc.DurableObjectBranded {
30
+ /** Admission-limits gate + `DurableAgentRuntime.submit`; answers a `SubmitResponse`. */
31
+ submitEncoded(encoded: unknown, traceContext?: unknown): Promise<unknown>;
32
+ /** Wake-hinted, poll-guaranteed settlement wait; answers an `AwaitSettlementResponse`. */
33
+ submissionStatusEncoded(encoded: unknown, traceContext?: unknown): Promise<unknown>;
34
+ awaitSettlementEncoded(encoded: unknown, traceContext?: unknown): Promise<unknown>;
35
+ /** Event-driven durable progress wait; answers a `ProgressObserved` host response. */
36
+ awaitProgressEncoded(encoded: unknown, traceContext?: unknown): Promise<unknown>;
37
+ /** Best-effort cancellation for one in-flight progress wait. */
38
+ cancelProgressEncoded(encoded: unknown, traceContext?: unknown): Promise<unknown>;
39
+ /** One bounded page of canonical records; answers an `ObservePageResponse`. */
40
+ observePage(encoded: unknown, traceContext?: unknown): Promise<unknown>;
41
+ /** Durable abort intent; answers an `AbortResponse`. */
42
+ abortEncoded(encoded: unknown, traceContext?: unknown): Promise<unknown>;
43
+ /** Durable approval decision (plan §2.6); answers a `ResolveApprovalResponse`. */
44
+ resolveApprovalEncoded(encoded: unknown, traceContext?: unknown): Promise<unknown>;
45
+ /** Authorized DUR-017 Unknown-Outcome resolution; answers a `ResolveUnknownResponse`. */
46
+ resolveUnknownEncoded(encoded: unknown, traceContext?: unknown): Promise<unknown>;
47
+ /** Owner-side cross-Object port endpoint (WP2 envelopes, executed on LOCAL facets). */
48
+ portCall(encoded: unknown): Promise<unknown>;
49
+ /** Droppable liveness hint from another Object: arms an immediate alarm. */
50
+ wake(): Promise<void>;
51
+ }
52
+ /** A logical Thread endpoint may be bound to an application Object without forging its brand. */
53
+ export type ThreadObjectClient = Omit<ThreadObjectRpc, keyof Rpc.DurableObjectBranded>;
54
+ declare const ThreadObjectNamespace_base: Context.ServiceClass<ThreadObjectNamespace, "@effect-agent/platform-cloudflare/ThreadObjectNamespace", {
55
+ readonly get: (threadId: ThreadId) => ThreadObjectClient;
56
+ /** Stable binding name for opted-in native RPC tracing; absent by default. */
57
+ readonly rpcTracing?: string;
58
+ }>;
59
+ /**
60
+ * Deterministic logical Thread placement. The native adapter uses `idFromName(threadId)`;
61
+ * a shared application owner can bind that logical identity into its RPC adapter instead.
62
+ * Lookup performs no I/O and grants no authority. Calls reuse a native target within
63
+ * one invocation; incoming requests and durable retries acquire their own targets.
64
+ */
65
+ export declare class ThreadObjectNamespace extends ThreadObjectNamespace_base {
66
+ static layer(namespace: DurableObjectNamespace<ThreadObjectRpc>, options?: {
67
+ readonly rpcTracing?: string;
68
+ }): Layer.Layer<ThreadObjectNamespace>;
69
+ }
70
+ /** Invoke a placed Thread using the current invocation's native RPC channel. */
71
+ export declare const callThreadObject: <A, E>(threadId: string & import("effect/Brand").Brand<"@effect-agent/core/ThreadId">, invoke: (target: ThreadObjectClient) => Promise<A>, onError: (cause: unknown) => E) => Effect.Effect<A, E, ThreadObjectNamespace>;
72
+ /**
73
+ * Narrow one `env` member to a `DurableObjectNamespace`. `env` is an untyped platform value,
74
+ * and a namespace binding is a host object no Schema can decode, so this is the documented
75
+ * narrowest-boundary check (structural probe for the namespace surface the transport uses);
76
+ * a missing or misshaped binding fails typed before any Layer is built.
77
+ */
78
+ export declare const threadNamespaceFromEnv: (env: unknown, binding: string) => Effect.Effect<DurableObjectNamespace<ThreadObjectRpc>, CloudflareBindingError, never>;
79
+ /**
80
+ * Build the namespace from Worker `env` (fails typed). Enable `rpcTracing` only when the
81
+ * receiver also opts into the effect-cf native RPC trace-context contract.
82
+ */
83
+ export declare const threadNamespaceLayer: (env: unknown, binding: string, options?: {
84
+ readonly rpcTracing?: boolean;
85
+ }) => Layer.Layer<ThreadObjectNamespace, CloudflareBindingError>;
86
+ declare const DurableObjectContext_base: Context.ServiceClass<DurableObjectContext, "@effect-agent/platform-cloudflare/DurableObjectContext", {
87
+ readonly ctx: DurableObjectState;
88
+ readonly env: unknown;
89
+ }>;
90
+ /**
91
+ * The live Durable Object execution context of THIS incarnation. Only Layer construction and
92
+ * the alarm service consume it; important state never lives on it (`ctx.storage` is truth,
93
+ * everything in memory is a cache — deployment spec §11).
94
+ */
95
+ export declare class DurableObjectContext extends DurableObjectContext_base {
96
+ static layer(ctx: DurableObjectState, env: unknown): Layer.Layer<DurableObjectContext>;
97
+ }
98
+ declare const ThreadObjectIdentity_base: Context.ServiceClass<ThreadObjectIdentity, "@effect-agent/platform-cloudflare/ThreadObjectIdentity", {
99
+ readonly threadId: ThreadId;
100
+ readonly producerId: ProducerId;
101
+ }>;
102
+ /**
103
+ * The Thread identity this Object serializes and the producer identity its Attempts
104
+ * write with (`{producerPrefix}:{threadId}`, plan §1.4). Derived once per incarnation
105
+ * from `ctx.id.name` — the Object identity rule guarantees the name IS the Thread ID.
106
+ */
107
+ export declare class ThreadObjectIdentity extends ThreadObjectIdentity_base {}
108
+ declare const ThreadObjectPlacement_base: Context.ServiceClass<ThreadObjectPlacement, "@effect-agent/platform-cloudflare/ThreadObjectPlacement", {
109
+ readonly ownsThread: (threadId: ThreadId) => boolean;
110
+ }>;
111
+ /** Logical Threads whose canonical stores and admission ledger live in this physical Object. */
112
+ export declare class ThreadObjectPlacement extends ThreadObjectPlacement_base {}
113
+ //#endregion
114
+ export { CloudflareBindings_d_exports as t };
115
+ //# sourceMappingURL=CloudflareBindings.d.mts.map
@@ -0,0 +1,113 @@
1
+ import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
2
+ import { Context, Effect, Layer, Predicate, Schema } from "effect";
3
+ import "effect-agent/identifiers";
4
+ import { RpcTargets } from "effect-cf";
5
+ import "effect-agent/records";
6
+ //#region src/CloudflareBindings.ts
7
+ var CloudflareBindings_exports = /* @__PURE__ */ __exportAll({
8
+ CloudflareBindingError: () => CloudflareBindingError,
9
+ DurableObjectContext: () => DurableObjectContext,
10
+ ThreadObjectIdentity: () => ThreadObjectIdentity,
11
+ ThreadObjectNamespace: () => ThreadObjectNamespace,
12
+ ThreadObjectPlacement: () => ThreadObjectPlacement,
13
+ callThreadObject: () => callThreadObject,
14
+ threadNamespaceFromEnv: () => threadNamespaceFromEnv,
15
+ threadNamespaceLayer: () => threadNamespaceLayer
16
+ });
17
+ /**
18
+ * Cloudflare platform bindings as Effect services (DEPLOY-010: "Cloudflare platform bindings
19
+ * are supplied as Effect services/Layers"). Application code never reads `env` or touches a
20
+ * `DurableObjectState` directly — the Thread Object class constructs these Layers once
21
+ * per incarnation and everything downstream consumes the services.
22
+ */
23
+ /** A Cloudflare platform binding was missing or carried the wrong shape (DEPLOY-003/010). */
24
+ var CloudflareBindingError = class extends Schema.TaggedError()("CloudflareBindingError", {
25
+ binding: Schema.String,
26
+ message: Schema.String
27
+ }) {};
28
+ /**
29
+ * Deterministic logical Thread placement. The native adapter uses `idFromName(threadId)`;
30
+ * a shared application owner can bind that logical identity into its RPC adapter instead.
31
+ * Lookup performs no I/O and grants no authority. Calls reuse a native target within
32
+ * one invocation; incoming requests and durable retries acquire their own targets.
33
+ */
34
+ var ThreadObjectNamespace = class ThreadObjectNamespace extends Context.Service()("@effect-agent/platform-cloudflare/ThreadObjectNamespace") {
35
+ static layer(namespace, options = {}) {
36
+ return Layer.succeed(ThreadObjectNamespace)({
37
+ get: (threadId) => namespace.get(namespace.idFromName(threadId)),
38
+ ...options.rpcTracing === void 0 ? {} : { rpcTracing: options.rpcTracing }
39
+ });
40
+ }
41
+ };
42
+ /** Invoke a placed Thread using the current invocation's native RPC channel. */
43
+ const callThreadObject = Effect.fn("callThreadObject")(function* (threadId, invoke, onError) {
44
+ const namespace = yield* ThreadObjectNamespace;
45
+ const target = yield* RpcTargets.get(namespace, threadId, () => namespace.get(threadId)).pipe(Effect.mapError(onError));
46
+ return yield* Effect.tryPromise({
47
+ try: () => invoke(target),
48
+ catch: onError
49
+ }).pipe(Effect.tapCause(() => RpcTargets.invalidate(target)));
50
+ });
51
+ /**
52
+ * Narrow one `env` member to a `DurableObjectNamespace`. `env` is an untyped platform value,
53
+ * and a namespace binding is a host object no Schema can decode, so this is the documented
54
+ * narrowest-boundary check (structural probe for the namespace surface the transport uses);
55
+ * a missing or misshaped binding fails typed before any Layer is built.
56
+ */
57
+ const threadNamespaceFromEnv = Effect.fn("threadNamespaceFromEnv")(function* (env, binding) {
58
+ if (!Predicate.isObjectKeyword(env)) return yield* CloudflareBindingError.make({
59
+ binding,
60
+ message: "The Worker environment is not an object; no bindings are available."
61
+ });
62
+ const candidate = yield* Effect.try({
63
+ try: () => {
64
+ const value = Reflect.get(env, binding);
65
+ if (!Predicate.isObjectKeyword(value)) return void 0;
66
+ const idFromName = Reflect.get(value, "idFromName");
67
+ const get = Reflect.get(value, "get");
68
+ return typeof idFromName === "function" && typeof get === "function" ? value : void 0;
69
+ },
70
+ catch: () => CloudflareBindingError.make({
71
+ binding,
72
+ message: `env.${binding} could not be inspected as a DurableObjectNamespace binding.`
73
+ })
74
+ });
75
+ if (candidate !== void 0) return candidate;
76
+ return yield* CloudflareBindingError.make({
77
+ binding,
78
+ message: `env.${binding} is not a DurableObjectNamespace binding; declare the Thread Object class under this binding in the Worker configuration.`
79
+ });
80
+ });
81
+ /**
82
+ * Build the namespace from Worker `env` (fails typed). Enable `rpcTracing` only when the
83
+ * receiver also opts into the effect-cf native RPC trace-context contract.
84
+ */
85
+ const threadNamespaceLayer = (env, binding, options = {}) => Layer.effect(ThreadObjectNamespace)(Effect.map(threadNamespaceFromEnv(env, binding), (namespace) => ({
86
+ get: (threadId) => namespace.get(namespace.idFromName(threadId)),
87
+ ...options.rpcTracing === true ? { rpcTracing: binding } : {}
88
+ })));
89
+ /**
90
+ * The live Durable Object execution context of THIS incarnation. Only Layer construction and
91
+ * the alarm service consume it; important state never lives on it (`ctx.storage` is truth,
92
+ * everything in memory is a cache — deployment spec §11).
93
+ */
94
+ var DurableObjectContext = class DurableObjectContext extends Context.Service()("@effect-agent/platform-cloudflare/DurableObjectContext") {
95
+ static layer(ctx, env) {
96
+ return Layer.succeed(DurableObjectContext)({
97
+ ctx,
98
+ env
99
+ });
100
+ }
101
+ };
102
+ /**
103
+ * The Thread identity this Object serializes and the producer identity its Attempts
104
+ * write with (`{producerPrefix}:{threadId}`, plan §1.4). Derived once per incarnation
105
+ * from `ctx.id.name` — the Object identity rule guarantees the name IS the Thread ID.
106
+ */
107
+ var ThreadObjectIdentity = class extends Context.Service()("@effect-agent/platform-cloudflare/ThreadObjectIdentity") {};
108
+ /** Logical Threads whose canonical stores and admission ledger live in this physical Object. */
109
+ var ThreadObjectPlacement = class extends Context.Service()("@effect-agent/platform-cloudflare/ThreadObjectPlacement") {};
110
+ //#endregion
111
+ export { CloudflareBindingError, DurableObjectContext, ThreadObjectIdentity, ThreadObjectNamespace, ThreadObjectPlacement, callThreadObject, CloudflareBindings_exports as t, threadNamespaceFromEnv, threadNamespaceLayer };
112
+
113
+ //# sourceMappingURL=CloudflareBindings.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CloudflareBindings.mjs","names":[],"sources":["../src/CloudflareBindings.ts"],"sourcesContent":["import { Context, Effect, Layer, Predicate, Schema } from \"effect\";\nimport { type ThreadId } from \"effect-agent/identifiers\";\nimport { type ProducerId } from \"effect-agent/records\";\nimport { RpcTargets } from \"effect-cf\";\n\n/**\n * Cloudflare platform bindings as Effect services (DEPLOY-010: \"Cloudflare platform bindings\n * are supplied as Effect services/Layers\"). Application code never reads `env` or touches a\n * `DurableObjectState` directly — the Thread Object class constructs these Layers once\n * per incarnation and everything downstream consumes the services.\n */\n\n/** A Cloudflare platform binding was missing or carried the wrong shape (DEPLOY-003/010). */\nexport class CloudflareBindingError extends Schema.TaggedError<CloudflareBindingError>()(\n \"CloudflareBindingError\",\n {\n binding: Schema.String,\n message: Schema.String,\n },\n) {}\n\n/**\n * The RPC surface one Thread Durable Object exposes to Workers and to sibling\n * Thread Objects. `ThreadObject.make` implements it; the Worker-side client\n * and the cross-Object transport call it through `DurableObjectNamespace` stubs. Every\n * `encoded` value is a Schema-encoded envelope (`client.ts` wire schemas for host entry\n * points, `@effect-agent/storage-cloudflare` port envelopes for `portCall`), so the RPC\n * boundary carries only structured-cloneable JSON. The optional trailing trace context is\n * transient native RPC metadata, stripped by an opted-in effect-cf receiver before decoding\n * the host envelope. It never enters durable state.\n */\nexport interface ThreadObjectRpc extends Rpc.DurableObjectBranded {\n /** Admission-limits gate + `DurableAgentRuntime.submit`; answers a `SubmitResponse`. */\n submitEncoded(encoded: unknown, traceContext?: unknown): Promise<unknown>;\n /** Wake-hinted, poll-guaranteed settlement wait; answers an `AwaitSettlementResponse`. */\n submissionStatusEncoded(encoded: unknown, traceContext?: unknown): Promise<unknown>;\n awaitSettlementEncoded(encoded: unknown, traceContext?: unknown): Promise<unknown>;\n /** Event-driven durable progress wait; answers a `ProgressObserved` host response. */\n awaitProgressEncoded(encoded: unknown, traceContext?: unknown): Promise<unknown>;\n /** Best-effort cancellation for one in-flight progress wait. */\n cancelProgressEncoded(encoded: unknown, traceContext?: unknown): Promise<unknown>;\n /** One bounded page of canonical records; answers an `ObservePageResponse`. */\n observePage(encoded: unknown, traceContext?: unknown): Promise<unknown>;\n /** Durable abort intent; answers an `AbortResponse`. */\n abortEncoded(encoded: unknown, traceContext?: unknown): Promise<unknown>;\n /** Durable approval decision (plan §2.6); answers a `ResolveApprovalResponse`. */\n resolveApprovalEncoded(encoded: unknown, traceContext?: unknown): Promise<unknown>;\n /** Authorized DUR-017 Unknown-Outcome resolution; answers a `ResolveUnknownResponse`. */\n resolveUnknownEncoded(encoded: unknown, traceContext?: unknown): Promise<unknown>;\n /** Owner-side cross-Object port endpoint (WP2 envelopes, executed on LOCAL facets). */\n portCall(encoded: unknown): Promise<unknown>;\n /** Droppable liveness hint from another Object: arms an immediate alarm. */\n wake(): Promise<void>;\n}\n\n/** A logical Thread endpoint may be bound to an application Object without forging its brand. */\nexport type ThreadObjectClient = Omit<ThreadObjectRpc, keyof Rpc.DurableObjectBranded>;\n\n/**\n * Deterministic logical Thread placement. The native adapter uses `idFromName(threadId)`;\n * a shared application owner can bind that logical identity into its RPC adapter instead.\n * Lookup performs no I/O and grants no authority. Calls reuse a native target within\n * one invocation; incoming requests and durable retries acquire their own targets.\n */\nexport class ThreadObjectNamespace extends Context.Service<\n ThreadObjectNamespace,\n {\n readonly get: (threadId: ThreadId) => ThreadObjectClient;\n /** Stable binding name for opted-in native RPC tracing; absent by default. */\n readonly rpcTracing?: string;\n }\n>()(\"@effect-agent/platform-cloudflare/ThreadObjectNamespace\") {\n static layer(\n namespace: DurableObjectNamespace<ThreadObjectRpc>,\n options: { readonly rpcTracing?: string } = {},\n ): Layer.Layer<ThreadObjectNamespace> {\n return Layer.succeed(ThreadObjectNamespace)({\n get: (threadId) => namespace.get(namespace.idFromName(threadId)),\n ...(options.rpcTracing === undefined ? {} : { rpcTracing: options.rpcTracing }),\n });\n }\n}\n\n/** Invoke a placed Thread using the current invocation's native RPC channel. */\nexport const callThreadObject = Effect.fn(\"callThreadObject\")(function* <A, E>(\n threadId: ThreadId,\n invoke: (target: ThreadObjectClient) => Promise<A>,\n onError: (cause: unknown) => E,\n): Effect.fn.Return<A, E, ThreadObjectNamespace> {\n const namespace = yield* ThreadObjectNamespace;\n\n const target = yield* RpcTargets.get(namespace, threadId, () => namespace.get(threadId)).pipe(\n Effect.mapError(onError),\n );\n\n return yield* Effect.tryPromise({ try: () => invoke(target), catch: onError }).pipe(\n Effect.tapCause(() => RpcTargets.invalidate(target)),\n );\n});\n\n/**\n * Narrow one `env` member to a `DurableObjectNamespace`. `env` is an untyped platform value,\n * and a namespace binding is a host object no Schema can decode, so this is the documented\n * narrowest-boundary check (structural probe for the namespace surface the transport uses);\n * a missing or misshaped binding fails typed before any Layer is built.\n */\nexport const threadNamespaceFromEnv = Effect.fn(\"threadNamespaceFromEnv\")(function* (\n env: unknown,\n binding: string,\n): Effect.fn.Return<DurableObjectNamespace<ThreadObjectRpc>, CloudflareBindingError> {\n if (!Predicate.isObjectKeyword(env)) {\n return yield* CloudflareBindingError.make({\n binding,\n message: \"The Worker environment is not an object; no bindings are available.\",\n });\n }\n\n const candidate = yield* Effect.try({\n try: () => {\n const value: unknown = Reflect.get(env, binding);\n\n if (!Predicate.isObjectKeyword(value)) return undefined;\n const idFromName: unknown = Reflect.get(value, \"idFromName\");\n const get: unknown = Reflect.get(value, \"get\");\n\n return typeof idFromName === \"function\" && typeof get === \"function\" ? value : undefined;\n },\n catch: () =>\n CloudflareBindingError.make({\n binding,\n message: `env.${binding} could not be inspected as a DurableObjectNamespace binding.`,\n }),\n });\n\n if (candidate !== undefined) {\n // The structural probe above is the entire runtime contract this package relies on;\n // the assertion records that `idFromName`/`get` name a DurableObjectNamespace.\n return candidate as unknown as DurableObjectNamespace<ThreadObjectRpc>;\n }\n\n return yield* CloudflareBindingError.make({\n binding,\n message:\n `env.${binding} is not a DurableObjectNamespace binding; declare the Thread ` +\n \"Object class under this binding in the Worker configuration.\",\n });\n});\n\n/**\n * Build the namespace from Worker `env` (fails typed). Enable `rpcTracing` only when the\n * receiver also opts into the effect-cf native RPC trace-context contract.\n */\nexport const threadNamespaceLayer = (\n env: unknown,\n binding: string,\n options: { readonly rpcTracing?: boolean } = {},\n): Layer.Layer<ThreadObjectNamespace, CloudflareBindingError> =>\n Layer.effect(ThreadObjectNamespace)(\n Effect.map(threadNamespaceFromEnv(env, binding), (namespace) => ({\n get: (threadId) => namespace.get(namespace.idFromName(threadId)),\n ...(options.rpcTracing === true ? { rpcTracing: binding } : {}),\n })),\n );\n\n/**\n * The live Durable Object execution context of THIS incarnation. Only Layer construction and\n * the alarm service consume it; important state never lives on it (`ctx.storage` is truth,\n * everything in memory is a cache — deployment spec §11).\n */\nexport class DurableObjectContext extends Context.Service<\n DurableObjectContext,\n {\n readonly ctx: DurableObjectState;\n readonly env: unknown;\n }\n>()(\"@effect-agent/platform-cloudflare/DurableObjectContext\") {\n static layer(ctx: DurableObjectState, env: unknown): Layer.Layer<DurableObjectContext> {\n return Layer.succeed(DurableObjectContext)({ ctx, env });\n }\n}\n\n/**\n * The Thread identity this Object serializes and the producer identity its Attempts\n * write with (`{producerPrefix}:{threadId}`, plan §1.4). Derived once per incarnation\n * from `ctx.id.name` — the Object identity rule guarantees the name IS the Thread ID.\n */\nexport class ThreadObjectIdentity extends Context.Service<\n ThreadObjectIdentity,\n {\n readonly threadId: ThreadId;\n readonly producerId: ProducerId;\n }\n>()(\"@effect-agent/platform-cloudflare/ThreadObjectIdentity\") {}\n\n/** Logical Threads whose canonical stores and admission ledger live in this physical Object. */\nexport class ThreadObjectPlacement extends Context.Service<\n ThreadObjectPlacement,\n { readonly ownsThread: (threadId: ThreadId) => boolean }\n>()(\"@effect-agent/platform-cloudflare/ThreadObjectPlacement\") {}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAaA,IAAa,yBAAb,cAA4C,OAAO,YAAoC,CAAC,CACtF,0BACA;CACE,SAAS,OAAO;CAChB,SAAS,OAAO;AAClB,CACF,CAAC,CAAC,CAAC;;;;;;;AA6CH,IAAa,wBAAb,MAAa,8BAA8B,QAAQ,QAOjD,CAAC,CAAC,yDAAyD,CAAC,CAAC;CAC7D,OAAO,MACL,WACA,UAA4C,CAAC,GACT;EACpC,OAAO,MAAM,QAAQ,qBAAqB,CAAC,CAAC;GAC1C,MAAM,aAAa,UAAU,IAAI,UAAU,WAAW,QAAQ,CAAC;GAC/D,GAAI,QAAQ,eAAe,KAAA,IAAY,CAAC,IAAI,EAAE,YAAY,QAAQ,WAAW;EAC/E,CAAC;CACH;AACF;;AAGA,MAAa,mBAAmB,OAAO,GAAG,kBAAkB,CAAC,CAAC,WAC5D,UACA,QACA,SAC+C;CAC/C,MAAM,YAAY,OAAO;CAEzB,MAAM,SAAS,OAAO,WAAW,IAAI,WAAW,gBAAgB,UAAU,IAAI,QAAQ,CAAC,CAAC,CAAC,KACvF,OAAO,SAAS,OAAO,CACzB;CAEA,OAAO,OAAO,OAAO,WAAW;EAAE,WAAW,OAAO,MAAM;EAAG,OAAO;CAAQ,CAAC,CAAC,CAAC,KAC7E,OAAO,eAAe,WAAW,WAAW,MAAM,CAAC,CACrD;AACF,CAAC;;;;;;;AAQD,MAAa,yBAAyB,OAAO,GAAG,wBAAwB,CAAC,CAAC,WACxE,KACA,SACmF;CACnF,IAAI,CAAC,UAAU,gBAAgB,GAAG,GAChC,OAAO,OAAO,uBAAuB,KAAK;EACxC;EACA,SAAS;CACX,CAAC;CAGH,MAAM,YAAY,OAAO,OAAO,IAAI;EAClC,WAAW;GACT,MAAM,QAAiB,QAAQ,IAAI,KAAK,OAAO;GAE/C,IAAI,CAAC,UAAU,gBAAgB,KAAK,GAAG,OAAO,KAAA;GAC9C,MAAM,aAAsB,QAAQ,IAAI,OAAO,YAAY;GAC3D,MAAM,MAAe,QAAQ,IAAI,OAAO,KAAK;GAE7C,OAAO,OAAO,eAAe,cAAc,OAAO,QAAQ,aAAa,QAAQ,KAAA;EACjF;EACA,aACE,uBAAuB,KAAK;GAC1B;GACA,SAAS,OAAO,QAAQ;EAC1B,CAAC;CACL,CAAC;CAED,IAAI,cAAc,KAAA,GAGhB,OAAO;CAGT,OAAO,OAAO,uBAAuB,KAAK;EACxC;EACA,SACE,OAAO,QAAQ;CAEnB,CAAC;AACH,CAAC;;;;;AAMD,MAAa,wBACX,KACA,SACA,UAA6C,CAAC,MAE9C,MAAM,OAAO,qBAAqB,CAAC,CACjC,OAAO,IAAI,uBAAuB,KAAK,OAAO,IAAI,eAAe;CAC/D,MAAM,aAAa,UAAU,IAAI,UAAU,WAAW,QAAQ,CAAC;CAC/D,GAAI,QAAQ,eAAe,OAAO,EAAE,YAAY,QAAQ,IAAI,CAAC;AAC/D,EAAE,CACJ;;;;;;AAOF,IAAa,uBAAb,MAAa,6BAA6B,QAAQ,QAMhD,CAAC,CAAC,wDAAwD,CAAC,CAAC;CAC5D,OAAO,MAAM,KAAyB,KAAiD;EACrF,OAAO,MAAM,QAAQ,oBAAoB,CAAC,CAAC;GAAE;GAAK;EAAI,CAAC;CACzD;AACF;;;;;;AAOA,IAAa,uBAAb,cAA0C,QAAQ,QAMhD,CAAC,CAAC,wDAAwD,CAAC,CAAC,CAAC;;AAG/D,IAAa,wBAAb,cAA2C,QAAQ,QAGjD,CAAC,CAAC,yDAAyD,CAAC,CAAC,CAAC"}