effect-cf 0.33.0 → 0.34.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.
Files changed (73) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +31 -1079
  3. package/dist/{Artifacts-DnHQA-Ax.d.mts → Artifacts-B3r3RuTB.d.mts} +1 -48
  4. package/dist/{Artifacts-CSIk1Oml.mjs → Artifacts-CBxWGeZB.mjs} +2 -7
  5. package/dist/{Binding-pfilNJmP.mjs → Binding-C82jRhdr.mjs} +1 -2
  6. package/dist/{Binding-xJJJPmiD.d.mts → Binding-DKcLrQCM.d.mts} +0 -45
  7. package/dist/ComputerArtifacts.d.mts +1 -3
  8. package/dist/ComputerArtifacts.mjs +1 -2
  9. package/dist/ComputerWorkspace.d.mts +1 -10
  10. package/dist/ComputerWorkspace.mjs +1 -2
  11. package/dist/ComputerWorkspaceHost.d.mts +1 -9
  12. package/dist/{ContainerNamespace-CFjiLw8b.d.mts → ContainerNamespace-DbLaeFhN.d.mts} +1 -14
  13. package/dist/{DurableObjectState-BpRjz6-q.d.mts → DurableObjectState-CrEunfQ-.d.mts} +82 -252
  14. package/dist/{DurableObjectState-CVLLse69.mjs → DurableObjectState-De4ZojhY.mjs} +1 -39
  15. package/dist/{ErrorMessage-BM0K-Nik.mjs → ErrorMessage-Byx2OgNd.mjs} +0 -1
  16. package/dist/{Hyperdrive-z-9fFz15.d.mts → Hyperdrive-HrwFlZ6x.d.mts} +1 -4
  17. package/dist/HyperdrivePg.d.mts +2 -11
  18. package/dist/HyperdrivePg.mjs +0 -8
  19. package/dist/Sandbox.d.mts +2 -32
  20. package/dist/Sandbox.mjs +2 -11
  21. package/dist/Vitest.d.mts +3 -31
  22. package/dist/Vitest.mjs +2 -17
  23. package/dist/{WorkflowBinding-lBR4_-op.d.mts → WorkflowBinding-BumVQTuW.d.mts} +2 -5
  24. package/dist/index.d.mts +34 -480
  25. package/dist/index.mjs +174 -312
  26. package/package.json +1 -1
  27. package/src/AiGateway.ts +0 -6
  28. package/src/AnalyticsEngine.ts +0 -9
  29. package/src/Artifacts.ts +0 -47
  30. package/src/Binding.ts +0 -8
  31. package/src/BrowserRendering.ts +0 -4
  32. package/src/Cache.ts +0 -19
  33. package/src/CloudflareOtlp.ts +3 -39
  34. package/src/ComputerArtifacts.ts +0 -2
  35. package/src/ComputerWorkspace.ts +0 -9
  36. package/src/ComputerWorkspaceHost.ts +0 -8
  37. package/src/ContainerNamespace.ts +0 -13
  38. package/src/D1.ts +0 -22
  39. package/src/DurableObject.ts +45 -25
  40. package/src/DurableObjectAlarm.ts +6 -210
  41. package/src/DurableObjectDefinition.ts +8 -20
  42. package/src/DurableObjectNamespace.ts +57 -112
  43. package/src/DurableObjectRpcWebSocket.ts +3 -19
  44. package/src/DurableObjectSqlite.ts +0 -12
  45. package/src/DurableObjectState.ts +0 -18
  46. package/src/DurableObjectStorage.ts +2 -35
  47. package/src/DurableObjectWebSocket.ts +0 -31
  48. package/src/Email.ts +0 -12
  49. package/src/Environment.ts +0 -37
  50. package/src/Hyperdrive.ts +0 -3
  51. package/src/HyperdrivePg.ts +0 -9
  52. package/src/Images.ts +0 -5
  53. package/src/Kv.ts +0 -15
  54. package/src/QueueBinding.ts +0 -2
  55. package/src/R2.ts +0 -5
  56. package/src/RpcDefinition.ts +0 -2
  57. package/src/RpcTracing.ts +133 -0
  58. package/src/Sandbox.ts +0 -30
  59. package/src/ServiceBinding.ts +48 -125
  60. package/src/Vectorize.ts +0 -5
  61. package/src/Vitest.ts +0 -28
  62. package/src/WebTransport.ts +0 -15
  63. package/src/Worker.ts +36 -57
  64. package/src/WorkerDefinition.ts +5 -14
  65. package/src/WorkersAi.ts +0 -4
  66. package/src/Workflow.ts +0 -5
  67. package/src/WorkflowBinding.ts +0 -3
  68. package/src/index.ts +1 -0
  69. package/src/internal/Entrypoint.ts +23 -4
  70. package/src/internal/ErrorMessage.ts +0 -1
  71. package/src/internal/RpcInvocation.ts +18 -1
  72. package/src/internal/Runtime.ts +12 -7
  73. package/src/internal/WorkerContext.ts +0 -11
package/src/Email.ts CHANGED
@@ -13,17 +13,13 @@ import * as ErrorMessage from "./internal/ErrorMessage";
13
13
  const expectedSendEmailBinding = "Send Email binding with send()";
14
14
  const textEncoder = new TextEncoder();
15
15
 
16
- /** Documented Cloudflare Email Sending limits. */
17
16
  export const sendLimits = {
18
- /** Combined `to`, `cc`, and `bcc` addresses per message. */
19
17
  maxRecipients: 50,
20
18
  maxAttachments: 32,
21
- /** Total message size, including attachments. Not enforced client side. */
22
19
  maxMessageBytes: 5 * 1024 * 1024,
23
20
  maxHeaderNameBytes: 100,
24
21
  maxHeaderValueBytes: 2048,
25
22
  maxHeadersBytes: 16 * 1024,
26
- /** Allowlisted custom headers, excluding `X-` prefixed headers. */
27
23
  maxAllowlistHeaders: 20,
28
24
  } as const;
29
25
 
@@ -58,10 +54,8 @@ export const emailErrorCodes = [
58
54
  "E_HEADERS_TOO_MANY",
59
55
  ] as const;
60
56
 
61
- /** A documented Cloudflare Email Sending error code. */
62
57
  export type EmailErrorCode = (typeof emailErrorCodes)[number];
63
58
 
64
- /** Error raised when a Cloudflare Send Email operation fails. */
65
59
  export class EmailOperationError extends Data.TaggedError("EmailOperationError")<{
66
60
  readonly binding: string;
67
61
  readonly operation: string;
@@ -82,7 +76,6 @@ export class EmailOperationError extends Data.TaggedError("EmailOperationError")
82
76
  }
83
77
  }
84
78
 
85
- /** A single message field that violates a documented Email Sending limit. */
86
79
  export interface EmailViolation {
87
80
  readonly path: string;
88
81
  readonly message: string;
@@ -90,7 +83,6 @@ export interface EmailViolation {
90
83
  readonly actual?: number;
91
84
  }
92
85
 
93
- /** Error raised when a message violates documented Cloudflare Email Sending limits. */
94
86
  export class EmailValidationError extends Data.TaggedError("EmailValidationError")<{
95
87
  readonly binding: string;
96
88
  readonly operation: string;
@@ -101,9 +93,7 @@ export class EmailValidationError extends Data.TaggedError("EmailValidationError
101
93
  }
102
94
  }
103
95
 
104
- /** Typed Cloudflare Send Email binding definition. */
105
96
  export interface EmailDefinition {
106
- /** Binding name as configured in `wrangler.jsonc`. */
107
97
  readonly binding: string;
108
98
  }
109
99
 
@@ -117,7 +107,6 @@ export type EmailSendError = EmailOperationError | EmailValidationError;
117
107
  type EmailFieldCandidate = Parameters<typeof Predicate.isUnknown>[0];
118
108
 
119
109
  export interface EmailSendOptions {
120
- /** Validates builder messages against documented limits. Defaults to `true`. */
121
110
  readonly validate?: boolean;
122
111
  }
123
112
 
@@ -133,7 +122,6 @@ export interface EmailClient {
133
122
 
134
123
  declare const EmailServiceTypeId: unique symbol;
135
124
 
136
- /** Nominal service marker for Send Email services created with {@link make}. */
137
125
  export interface EmailService<Id extends string> {
138
126
  readonly [EmailServiceTypeId]: {
139
127
  readonly id: Id;
@@ -1,6 +1,5 @@
1
1
  import { Config, ConfigProvider, Context, Effect, type Layer, Predicate } from "effect";
2
2
 
3
- /** Cloudflare worker environment object (`env`). */
4
3
  export type WorkerEnv = Cloudflare.Env;
5
4
 
6
5
  /**
@@ -23,38 +22,9 @@ type ScalarConfigKey = Extract<
23
22
  string
24
23
  >;
25
24
 
26
- /**
27
- * Effect `Config` helpers for scalar Cloudflare vars and secrets declared on
28
- * `Cloudflare.Env`.
29
- *
30
- * Users still author their app config explicitly with Effect `Config`:
31
- *
32
- * ```ts
33
- * import { Config, Effect } from "effect";
34
- * import { WorkerConfig } from "effect-cf";
35
- *
36
- * const AppConfig = Config.all({
37
- * databaseUrl: WorkerConfig.redacted("DATABASE_URL"),
38
- * port: WorkerConfig.integer("PORT").pipe(Config.withDefault(8787)),
39
- * });
40
- *
41
- * const program = Effect.gen(function* () {
42
- * const config = yield* AppConfig;
43
- * // ...
44
- * }).pipe(Effect.provide(WorkerConfig.providerLayer));
45
- * ```
46
- *
47
- * Keys are constrained to scalar `Cloudflare.Env` properties (`string`,
48
- * `number`, or `boolean`, including optional scalar properties). Binding
49
- * objects such as `KVNamespace`, `DurableObjectNamespace`, and service
50
- * bindings are intentionally excluded; keep using the package binding helpers
51
- * for those live resources.
52
- */
53
25
  export namespace WorkerConfig {
54
- /** Scalar env value types supported by the typed config key helpers. */
55
26
  export type Scalar = ScalarConfigValue;
56
27
 
57
- /** Scalar keys available on the current consumer's `Cloudflare.Env`. */
58
28
  export type Key = ScalarConfigKey;
59
29
 
60
30
  /** Read a scalar Cloudflare var or secret as a string. */
@@ -72,7 +42,6 @@ export namespace WorkerConfig {
72
42
  /** Read a scalar Cloudflare var or secret as a boolean. */
73
43
  export const boolean = <const Name extends Key>(name: Name) => Config.boolean(name);
74
44
 
75
- /** Options for building a `ConfigProvider` from a Cloudflare worker `env` object. */
76
45
  export interface ProviderOptions {
77
46
  /**
78
47
  * Keep empty-string env values as explicit `""` config values.
@@ -104,14 +73,9 @@ export namespace WorkerConfig {
104
73
  return ConfigProvider.fromEnvRecord(record, options);
105
74
  };
106
75
 
107
- /**
108
- * Build a `ConfigProvider` from the current `WorkerEnvironment` with a custom
109
- * conversion function.
110
- */
111
76
  export const providerWith = (makeProvider: (env: WorkerEnv) => ConfigProvider.ConfigProvider) =>
112
77
  Effect.map(WorkerEnvironment, makeProvider);
113
78
 
114
- /** Build a `ConfigProvider` from the current `WorkerEnvironment`. */
115
79
  export const provider = providerWith(providerFromEnv);
116
80
 
117
81
  /**
@@ -121,7 +85,6 @@ export namespace WorkerConfig {
121
85
  export const providerLayer: Layer.Layer<never, never, WorkerEnvironment> =
122
86
  ConfigProvider.layer(provider);
123
87
 
124
- /** Build a `ConfigProvider` layer with a custom `env` conversion function. */
125
88
  export const layerWith = (
126
89
  makeProvider: (env: WorkerEnv) => ConfigProvider.ConfigProvider,
127
90
  ): Layer.Layer<never, never, WorkerEnvironment> =>
package/src/Hyperdrive.ts CHANGED
@@ -5,9 +5,7 @@ import type { WorkerEnvironment } from "./Environment";
5
5
 
6
6
  const expectedHyperdrive = "Hyperdrive binding with connectionString";
7
7
 
8
- /** Typed Hyperdrive binding definition. */
9
8
  export interface HyperdriveDefinition {
10
- /** Binding name as configured in `wrangler.jsonc`. */
11
9
  readonly binding: string;
12
10
  }
13
11
 
@@ -19,7 +17,6 @@ export interface HyperdriveClient {
19
17
 
20
18
  declare const HyperdriveServiceTypeId: unique symbol;
21
19
 
22
- /** Nominal service marker for Hyperdrive services created with {@link make}. */
23
20
  export interface HyperdriveService<Id extends string> {
24
21
  readonly [HyperdriveServiceTypeId]: {
25
22
  readonly id: Id;
@@ -6,20 +6,11 @@ import type * as Binding from "./Binding";
6
6
  import type { WorkerEnvironment } from "./Environment";
7
7
  import type * as Hyperdrive from "./Hyperdrive";
8
8
 
9
- /** Hyperdrive owns database pooling, so app-side pool and connection options are not exposed. */
10
9
  export type PgLayerOptions = Omit<
11
10
  Parameters<typeof PgClient.makeClient>[0],
12
11
  "url" | "host" | "port" | "path" | "ssl" | "database" | "username" | "password" | "stream"
13
12
  >;
14
13
 
15
- /**
16
- * Provides `PgClient` and `SqlClient` backed by a Hyperdrive binding.
17
- *
18
- * Note: since Effect `4.0.0-beta.99`, `PgClient.makeClient` connects eagerly,
19
- * so the TCP connection to Hyperdrive is opened when this layer is built.
20
- * In per-request Workers runtimes, build the layer within the request
21
- * lifecycle rather than sharing it across requests.
22
- */
23
14
  export const layer = <Self, Id extends string>(
24
15
  tag: Hyperdrive.TagClass<Self, Id>,
25
16
  binding: Hyperdrive.LayerOptions,
package/src/Images.ts CHANGED
@@ -33,7 +33,6 @@ export type TypeId = typeof TypeId;
33
33
 
34
34
  const expectedImagesBinding = "Images binding with info() and input()";
35
35
 
36
- /** Error raised when a Cloudflare Images operation fails. */
37
36
  export class ImagesOperationError extends Data.TaggedError("ImagesOperationError")<{
38
37
  readonly binding: string;
39
38
  readonly operation: string;
@@ -44,9 +43,7 @@ export class ImagesOperationError extends Data.TaggedError("ImagesOperationError
44
43
  }
45
44
  }
46
45
 
47
- /** Typed Cloudflare Images binding definition. */
48
46
  export interface ImagesDefinition {
49
- /** Binding name as configured in `wrangler.jsonc`. */
50
47
  readonly binding: string;
51
48
  }
52
49
 
@@ -175,7 +172,6 @@ export interface ImagesClient {
175
172
 
176
173
  declare const ImagesServiceTypeId: unique symbol;
177
174
 
178
- /** Nominal service marker for Images services created with {@link make}. */
179
175
  export interface ImagesService<Id extends string> {
180
176
  readonly [ImagesServiceTypeId]: {
181
177
  readonly id: Id;
@@ -206,7 +202,6 @@ const makeSteps = (steps: ReadonlyArray<Step>): Steps => ({
206
202
  steps,
207
203
  });
208
204
 
209
- /** Empty Images transformation pipeline. */
210
205
  export const empty: Steps = makeSteps([]);
211
206
 
212
207
  export const transform: {
package/src/Kv.ts CHANGED
@@ -11,10 +11,8 @@ import * as ErrorMessage from "./internal/ErrorMessage";
11
11
  const expectedKvNamespace =
12
12
  "KV namespace binding with get(), put(), delete(), getWithMetadata(), and list()";
13
13
 
14
- /** KV operation represented by {@link KvOperationError}. */
15
14
  export type KvOperation = "put" | "get" | "getWithMetadata" | "list" | "delete";
16
15
 
17
- /** Error raised when a KV operation fails. */
18
16
  export class KvOperationError extends Data.TaggedError("KvOperationError")<{
19
17
  readonly binding: string;
20
18
  readonly operation: KvOperation;
@@ -25,28 +23,23 @@ export class KvOperationError extends Data.TaggedError("KvOperationError")<{
25
23
  }
26
24
  }
27
25
 
28
- /** `KVNamespace.put` options. */
29
26
  export type KvPutOptions = CloudflareKVNamespacePutOptions;
30
- /** `KVNamespace.list` options with optional metadata decoding schema. */
31
27
  export type KvListOptions<Metadata = unknown> = CloudflareKVNamespaceListOptions & {
32
28
  readonly metadataSchema?: S.Codec<Metadata, unknown>;
33
29
  };
34
30
 
35
- /** Successful value returned by `getWithMetadata`. */
36
31
  export interface KvWithMetadata<Value, Metadata> {
37
32
  readonly value: Value;
38
33
  readonly metadata: Option.Option<Metadata>;
39
34
  readonly cacheStatus: Option.Option<string>;
40
35
  }
41
36
 
42
- /** Decoded key entry returned by `list`. */
43
37
  export interface KvListKey<Key, Metadata = unknown> {
44
38
  readonly name: Key;
45
39
  readonly expiration: Option.Option<number>;
46
40
  readonly metadata: Option.Option<Metadata>;
47
41
  }
48
42
 
49
- /** Decoded result returned by `list`. */
50
43
  export interface KvListResult<Key, Metadata = unknown> {
51
44
  readonly keys: ReadonlyArray<KvListKey<Key, Metadata>>;
52
45
  readonly listComplete: boolean;
@@ -54,15 +47,9 @@ export interface KvListResult<Key, Metadata = unknown> {
54
47
  readonly cacheStatus: Option.Option<string>;
55
48
  }
56
49
 
57
- /**
58
- * Typed KV binding definition.
59
- */
60
50
  export interface KvDefinition<Key, Value, EncodedValue> {
61
- /** Binding name as configured in `wrangler.jsonc`. */
62
51
  readonly binding: string;
63
- /** Codec used to encode/decode keys. */
64
52
  readonly key: S.Codec<Key, string>;
65
- /** Codec used to encode/decode values. */
66
53
  readonly value: S.Codec<Value, EncodedValue>;
67
54
  }
68
55
 
@@ -76,9 +63,7 @@ export interface Definition<
76
63
  EncodedValue = unknown,
77
64
  > {
78
65
  readonly id: Id;
79
- /** Codec used to encode/decode keys. */
80
66
  readonly key: S.Codec<Key, string>;
81
- /** Codec used to encode/decode values. */
82
67
  readonly value: S.Codec<Value, EncodedValue>;
83
68
  }
84
69
 
@@ -27,9 +27,7 @@ const expectedQueueProducer = "Queue producer binding with send(); optional send
27
27
  type QueueCandidate = Parameters<typeof Predicate.isUnknown>[0];
28
28
 
29
29
  export interface QueueBindingDefinition<Message extends RpcDefinition.ServiceFreeSchema> {
30
- /** Binding name as configured in `wrangler.jsonc`. */
31
30
  readonly binding: string;
32
- /** Codec used to encode messages before sending them to Cloudflare Queues. */
33
31
  readonly message: Message;
34
32
  }
35
33
 
package/src/R2.ts CHANGED
@@ -21,7 +21,6 @@ import * as ErrorMessage from "./internal/ErrorMessage";
21
21
  const expectedR2Bucket =
22
22
  "R2 bucket binding with head(), get(), put(), createMultipartUpload(), resumeMultipartUpload(), delete(), and list()";
23
23
 
24
- /** R2 operation represented by {@link R2OperationError}. */
25
24
  export type R2Operation =
26
25
  | "head"
27
26
  | "get"
@@ -39,7 +38,6 @@ export type R2Operation =
39
38
  | "json"
40
39
  | "blob";
41
40
 
42
- /** Error raised when an R2 operation fails. */
43
41
  export class R2OperationError extends Data.TaggedError("R2OperationError")<{
44
42
  readonly binding: string;
45
43
  readonly operation: R2Operation;
@@ -50,9 +48,7 @@ export class R2OperationError extends Data.TaggedError("R2OperationError")<{
50
48
  }
51
49
  }
52
50
 
53
- /** Typed R2 bucket binding definition. */
54
51
  export interface R2Definition {
55
- /** Binding name as configured in `wrangler.jsonc`. */
56
52
  readonly binding: string;
57
53
  }
58
54
 
@@ -133,7 +129,6 @@ export interface R2Client {
133
129
 
134
130
  declare const R2ServiceTypeId: unique symbol;
135
131
 
136
- /** Nominal service marker for R2 services created with {@link make}. */
137
132
  export interface R2Service<Id extends string> {
138
133
  readonly [R2ServiceTypeId]: {
139
134
  readonly id: Id;
@@ -106,7 +106,6 @@ export const encodeWireError = (error: WireValue): WireValue => {
106
106
  }
107
107
  };
108
108
 
109
- /** Restores package RPC errors from the {@link encodeWireError} envelope. */
110
109
  export const decodeWireError = (cause: WireValue): WireValue => {
111
110
  if (!(cause instanceof Error)) {
112
111
  return cause;
@@ -184,7 +183,6 @@ export namespace Method {
184
183
  ? [S.Schema.Type<Head>, ...ArgsFromSchemas<Tail>]
185
184
  : Array<S.Schema.Type<Args[number]>>;
186
185
 
187
- /** Method schemas cross the wire through their canonical JSON codec. */
188
186
  type EncodedArgsFromSchemas<Args extends ReadonlyArray<ServiceFreeSchema>> = {
189
187
  [Index in keyof Args]: S.Json;
190
188
  };
@@ -0,0 +1,133 @@
1
+ import { Cause, Clock, Context, Effect, Exit, Option, References, Schema, Tracer } from "effect";
2
+
3
+ /**
4
+ * Live native RPC metadata. Opted-in receivers reserve a valid trailing value
5
+ * with this tag for transport context; do not use it as a final domain argument.
6
+ * Never store this in durable messages or envelopes.
7
+ */
8
+ export const RpcTraceContext = Schema.Struct({
9
+ _tag: Schema.Literal("effect-cf/RpcTraceContext/v1"),
10
+ traceId: Schema.String.check(Schema.isPattern(/^(?!0{32}$)[0-9a-f]{32}$/)),
11
+ spanId: Schema.String.check(Schema.isPattern(/^(?!0{16}$)[0-9a-f]{16}$/)),
12
+ sampled: Schema.Boolean,
13
+ });
14
+
15
+ export type RpcTraceContext = typeof RpcTraceContext.Type;
16
+
17
+ export interface ReceiverOptions {
18
+ /** Stable service name, never an instance id or capability URL. */
19
+ readonly service: string;
20
+ }
21
+
22
+ /** Per-invocation metadata passed to Worker and DurableObject RunSymbol overrides. */
23
+ export interface RpcInvocationInfo {
24
+ readonly service: string;
25
+ readonly method: string;
26
+ /** Native arguments with valid, opted-in trace metadata removed. Do not log them. */
27
+ readonly args: ReadonlyArray<unknown>;
28
+ /**
29
+ * Set after a definition-backed receiver decodes its arguments, before its
30
+ * handler runs. Absent before decoding and when decoding fails. Do not log it.
31
+ */
32
+ readonly decodedArgs?: ReadonlyArray<unknown>;
33
+ readonly parent?: RpcTraceContext;
34
+ }
35
+
36
+ const isRpcTraceContext = Schema.is(RpcTraceContext);
37
+
38
+ /**
39
+ * Appends the current live parent only for a receiver that has opted in.
40
+ * Call this inside the CLIENT span, immediately before the native invocation.
41
+ * With no valid propagating parent, the original argument array is returned.
42
+ */
43
+ export const withRpcTraceContext = Effect.fnUntraced(function* (
44
+ args: ReadonlyArray<unknown>,
45
+ ): Effect.fn.Return<ReadonlyArray<unknown>> {
46
+ if (yield* Tracer.DisablePropagation) {
47
+ return args;
48
+ }
49
+
50
+ const parent = yield* Effect.serviceOption(Tracer.ParentSpan);
51
+
52
+ if (Option.isNone(parent) || Context.get(parent.value.annotations, Tracer.DisablePropagation)) {
53
+ return args;
54
+ }
55
+
56
+ const context = {
57
+ _tag: "effect-cf/RpcTraceContext/v1",
58
+ traceId: parent.value.traceId,
59
+ spanId: parent.value.spanId,
60
+ sampled: parent.value.sampled,
61
+ };
62
+
63
+ return isRpcTraceContext(context) ? [...args, context] : args;
64
+ });
65
+
66
+ const attributes = (service: string, method: string) => ({
67
+ "sentry.op": "rpc",
68
+ "rpc.system.name": "cloudflare",
69
+ "rpc.method": `${service}/${method}`,
70
+ "server.address": service,
71
+ });
72
+
73
+ const withRpcSpan = <A, E, R>(
74
+ effect: Effect.Effect<A, E, R>,
75
+ service: string,
76
+ method: string,
77
+ options: Tracer.SpanOptionsNoTrace,
78
+ ): Effect.Effect<A, E, Exclude<R, Tracer.ParentSpan>> =>
79
+ Effect.useSpan(
80
+ `${service}/${method}`,
81
+ {
82
+ ...options,
83
+ attributes: attributes(service, method),
84
+ },
85
+ (span) =>
86
+ effect.pipe(
87
+ Effect.withParentSpan(span),
88
+ Effect.onExit((exit) => {
89
+ if (
90
+ Exit.isSuccess(exit) ||
91
+ Cause.hasInterruptsOnly(exit.cause) ||
92
+ span.status._tag === "Ended"
93
+ ) {
94
+ return Effect.void;
95
+ }
96
+
97
+ // OTLP's default cause formatter includes schema inputs and native error
98
+ // messages. End with a safe failure, while returning the original exit.
99
+ return Effect.gen(function* () {
100
+ const timing = yield* References.TracerTimingEnabled;
101
+ const endTime = timing ? yield* Clock.currentTimeNanos : 0n;
102
+
103
+ span.attribute("error.type", "_OTHER");
104
+ span.end(endTime, Exit.fail("RPC failed"));
105
+ });
106
+ }),
107
+ ),
108
+ );
109
+
110
+ /** Wrap the whole call, including native result resolution and success decoding. */
111
+ export const withRpcClientSpan = <A, E, R>(
112
+ effect: Effect.Effect<A, E, R>,
113
+ binding: string,
114
+ method: string,
115
+ ): Effect.Effect<A, E, Exclude<R, Tracer.ParentSpan>> =>
116
+ withRpcSpan(effect, binding, method, {
117
+ kind: "client",
118
+ });
119
+
120
+ /**
121
+ * Optional application instrumentation for the entire receiver effect.
122
+ * Use in a RunSymbol override to include argument decode, handler and encode.
123
+ * Records stable service/method attributes and failure status, not argument or
124
+ * error payloads. The original typed failure still propagates to the caller.
125
+ */
126
+ export const withRpcServerSpan = <A, E, R>(
127
+ effect: Effect.Effect<A, E, R>,
128
+ invocation: RpcInvocationInfo,
129
+ ): Effect.Effect<A, E, Exclude<R, Tracer.ParentSpan>> =>
130
+ withRpcSpan(effect, invocation.service, invocation.method, {
131
+ kind: "server",
132
+ parent: invocation.parent === undefined ? undefined : Tracer.externalSpan(invocation.parent),
133
+ });
package/src/Sandbox.ts CHANGED
@@ -77,13 +77,10 @@ export type {
77
77
  const expectedSandboxNamespace =
78
78
  "Sandbox Durable Object namespace binding with idFromName() and get()";
79
79
 
80
- /** Sandbox namespace binding metadata. */
81
80
  export interface SandboxDefinition {
82
- /** Binding name as configured in `wrangler.jsonc`. */
83
81
  readonly binding: string;
84
82
  }
85
83
 
86
- /** Failure raised when invoking a sandbox operation. */
87
84
  export class SandboxOperationError extends Data.TaggedError("SandboxOperationError")<{
88
85
  readonly binding: string;
89
86
  readonly instance: string;
@@ -110,55 +107,42 @@ export interface SandboxNamespaceResource {
110
107
  ): globalThis.DurableObjectStub;
111
108
  }
112
109
 
113
- /** Result of `writeFile` as reported by the sandbox client. */
114
110
  export type WriteFileResult = Awaited<ReturnType<ISandbox["writeFile"]>>;
115
111
 
116
- /** Result of `readFile` as reported by the sandbox client. */
117
112
  export type ReadFileResult = Awaited<ReturnType<ISandbox["readFile"]>>;
118
113
 
119
- /** Result of `mkdir` as reported by the sandbox client. */
120
114
  export type MkdirResult = Awaited<ReturnType<ISandbox["mkdir"]>>;
121
115
 
122
- /** Result of `deleteFile` as reported by the sandbox client. */
123
116
  export type DeleteFileResult = Awaited<ReturnType<ISandbox["deleteFile"]>>;
124
117
 
125
- /** Result of `renameFile` as reported by the sandbox client. */
126
118
  export type RenameFileResult = Awaited<ReturnType<ISandbox["renameFile"]>>;
127
119
 
128
- /** Result of `moveFile` as reported by the sandbox client. */
129
120
  export type MoveFileResult = Awaited<ReturnType<ISandbox["moveFile"]>>;
130
121
 
131
- /** Result of `listFiles` as reported by the sandbox client. */
132
122
  export type ListFilesResult = Awaited<ReturnType<ISandbox["listFiles"]>>;
133
123
 
134
- /** Result of `exists` as reported by the sandbox client. */
135
124
  export type FileExistsResult = Awaited<ReturnType<ISandbox["exists"]>>;
136
125
 
137
- /** Text encodings accepted by `readFile`. */
138
126
  export type ReadFileEncoding = "utf-8" | "utf8" | "base64";
139
127
 
140
- /** Options accepted by `exposePort`. */
141
128
  export interface ExposePortOptions {
142
129
  readonly name?: string;
143
130
  readonly hostname: string;
144
131
  readonly token?: string;
145
132
  }
146
133
 
147
- /** Preview URL information returned by `exposePort`. */
148
134
  export interface ExposedPort {
149
135
  readonly url: string;
150
136
  readonly port: number;
151
137
  readonly name?: string;
152
138
  }
153
139
 
154
- /** Currently forwardable preview URL returned by `getExposedPorts`. */
155
140
  export interface ExposedPortStatus {
156
141
  readonly url: string;
157
142
  readonly port: number;
158
143
  readonly status: "active";
159
144
  }
160
145
 
161
- /** Structural tunnel API surface exposed by a sandbox client. */
162
146
  export interface SandboxTunnelsResource {
163
147
  get(port: number, options?: TunnelOptions): Promise<TunnelInfo>;
164
148
  list(): Promise<Array<TunnelInfo>>;
@@ -183,7 +167,6 @@ export interface SandboxClientResource extends ISandbox {
183
167
  readonly tunnels: SandboxTunnelsResource;
184
168
  }
185
169
 
186
- /** Effect-wrapped handle for one process started inside a sandbox. */
187
170
  export interface SandboxProcessHandle {
188
171
  readonly id: string;
189
172
  readonly pid: number;
@@ -213,7 +196,6 @@ export interface SandboxProcessHandle {
213
196
  readonly kill: (signal?: number) => Effect.Effect<void, SandboxOperationError>;
214
197
  }
215
198
 
216
- /** Effect-wrapped handle for one interactive terminal inside a sandbox. */
217
199
  export interface SandboxTerminalHandle {
218
200
  readonly id: string;
219
201
  readonly rawUnsafe: Effect.Effect<Terminal>;
@@ -238,7 +220,6 @@ export interface SandboxTerminalHandle {
238
220
  ) => Effect.Effect<Response, SandboxOperationError>;
239
221
  }
240
222
 
241
- /** Effect-wrapped tunnel operations for one sandbox instance. */
242
223
  export interface SandboxTunnelsClient {
243
224
  readonly get: (
244
225
  port: number,
@@ -248,7 +229,6 @@ export interface SandboxTunnelsClient {
248
229
  readonly destroy: (portOrInfo: number | TunnelInfo) => Effect.Effect<void, SandboxOperationError>;
249
230
  }
250
231
 
251
- /** Effect-wrapped client for one named sandbox instance. */
252
232
  export interface SandboxInstanceClient {
253
233
  readonly rawUnsafe: Effect.Effect<SandboxClientResource>;
254
234
  readonly exec: (
@@ -344,7 +324,6 @@ export interface SandboxInstanceClient {
344
324
  readonly destroy: Effect.Effect<void, SandboxOperationError>;
345
325
  }
346
326
 
347
- /** Effect client for a Sandbox Durable Object namespace binding. */
348
327
  export interface SandboxNamespaceClient<
349
328
  Namespace extends SandboxNamespaceResource = SandboxNamespaceResource,
350
329
  > {
@@ -616,13 +595,6 @@ const makeTerminalHandle = (
616
595
  };
617
596
  };
618
597
 
619
- /**
620
- * Wraps an already-created sandbox client (the value returned by
621
- * `getSandbox()` from `@cloudflare/sandbox`) into an Effect client.
622
- *
623
- * Prefer {@link Tag}/{@link make} with a layer for application code; this
624
- * entry point exists for advanced composition and testing.
625
- */
626
598
  export const fromSandboxClient = (
627
599
  client: SandboxClientResource,
628
600
  definition: SandboxDefinition,
@@ -1029,14 +1001,12 @@ export const make = <Id extends string>(id: Id) => Tag<SandboxNamespaceService<I
1029
1001
 
1030
1002
  declare const SandboxNamespaceServiceTypeId: unique symbol;
1031
1003
 
1032
- /** Nominal service marker for Sandbox namespaces created with {@link make}. */
1033
1004
  export interface SandboxNamespaceService<Id extends string> {
1034
1005
  readonly [SandboxNamespaceServiceTypeId]: {
1035
1006
  readonly id: Id;
1036
1007
  };
1037
1008
  }
1038
1009
 
1039
- /** Creates a typed Effect service for a Cloudflare Sandbox namespace. */
1040
1010
  export const Tag =
1041
1011
  <Self, Namespace extends SandboxNamespaceResource = SandboxNamespaceResource>() =>
1042
1012
  <Id extends string>(id: Id) => {