@restatedev/restate-sdk-clients 1.16.6 → 1.16.8

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/dist/api.d.cts CHANGED
@@ -359,24 +359,40 @@ type RetryFailure = {
359
359
  * observe the existing workflow.
360
360
  *
361
361
  * By default the following failures are retried: network errors (the underlying
362
- * `fetch` rejecting), HTTP `429`, and HTTP `5xx` responses. Override this with
363
- * {@link RetryPolicy.shouldRetry}.
362
+ * `fetch` rejecting) and responses with a transient status (`408`, `425`, `429`,
363
+ * or `5xx`). A terminal error of the invocation is never retried, whatever its status code.
364
+ * Override all of this with {@link RetryPolicy.shouldRetry}.
364
365
  */
365
366
  interface RetryPolicy {
366
367
  /**
367
368
  * Max number of attempts (including the initial), before giving up.
368
369
  *
369
- * Defaults to `6` (the initial attempt plus up to 5 retries).
370
+ * Retrying stops as soon as **either** `maxDuration` or {@link maxAttempts} is reached.
371
+ *
372
+ * Defaults to `6` (the initial attempt plus up to 5 retries). Pass `false` to
373
+ * remove the attempt bound.
374
+ */
375
+ maxAttempts?: number | false;
376
+ /**
377
+ * Max total duration of retries, measured from the first attempt, before
378
+ * giving up. If a number is provided, it is interpreted as milliseconds.
379
+ *
380
+ * This bound is checked only when deciding whether to start another
381
+ * attempt after a failure: it never aborts an in-flight request.
382
+ *
383
+ * Retrying stops as soon as **either** {@link maxDuration} or {@link maxAttempts} is reached.
384
+ *
385
+ * Defaults to 60 seconds. Pass `false` to remove the duration bound.
370
386
  */
371
- maxAttempts?: number;
387
+ maxDuration?: Duration | number | false;
372
388
  /**
373
389
  * Initial backoff interval. If a number is provided, it is interpreted as
374
- * milliseconds. Defaults to `100` milliseconds.
390
+ * milliseconds. Defaults to `250` milliseconds.
375
391
  */
376
392
  initialInterval?: Duration | number;
377
393
  /**
378
394
  * Maximum backoff interval. If a number is provided, it is interpreted as
379
- * milliseconds. Defaults to `2000` milliseconds.
395
+ * milliseconds. Defaults to `3000` milliseconds.
380
396
  */
381
397
  maxInterval?: Duration | number;
382
398
  /**
@@ -384,9 +400,23 @@ interface RetryPolicy {
384
400
  * Defaults to `2`.
385
401
  */
386
402
  exponentiationFactor?: number;
403
+ /**
404
+ * Whether to honor a `Retry-After` response header when the server provides
405
+ * one. When `true` (the default), a `Retry-After` value overrides the computed
406
+ * exponential backoff for that attempt.
407
+ *
408
+ * Set to `false` to always use the exponential backoff and ignore the header.
409
+ *
410
+ * Note that `Retry-After` never extends the number of retries: {@link maxAttempts} and
411
+ * {@link maxDuration} is always respected regardless of this setting.
412
+ *
413
+ * Defaults to `true`.
414
+ */
415
+ respectRetryAfter?: boolean;
387
416
  /**
388
417
  * Decide whether a given failure should be retried. When provided, this
389
- * fully replaces the built-in rule (network / `429` / `5xx`).
418
+ * fully replaces the built-in rule (network / transient `408`/`425`/`429`/`5xx`,
419
+ * excluding invocation-sourced errors).
390
420
  *
391
421
  * The idempotency-key gate still applies to regular invocations; workflow
392
422
  * submissions, attaches, and output retrieval remain eligible without an
@@ -411,8 +441,9 @@ type ConnectionOpts = {
411
441
  */
412
442
  headers?: Record<string, string>;
413
443
  /**
414
- * Opt in to automatic retries of ambiguous ingress failures (network errors,
415
- * HTTP `429`, HTTP `5xx`).
444
+ * Opt in to automatic retries of ambiguous ingress failures (network errors
445
+ * and transient HTTP statuses `408`/`425`/`429`/`5xx`, excluding errors
446
+ * restate attributes to the invocation itself).
416
447
  *
417
448
  * Retries are **disabled by default**. Set `true` to enable the built-in
418
449
  * policy ({@link RetryPolicy}), or pass a {@link RetryPolicy} to tune it.
@@ -1 +1 @@
1
- {"version":3,"file":"api.d.cts","names":[],"sources":["../src/api.ts"],"sourcesContent":[],"mappings":"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"}
1
+ {"version":3,"file":"api.d.cts","names":[],"sources":["../src/api.ts"],"sourcesContent":[],"mappings":"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"}
package/dist/api.d.ts CHANGED
@@ -359,24 +359,40 @@ type RetryFailure = {
359
359
  * observe the existing workflow.
360
360
  *
361
361
  * By default the following failures are retried: network errors (the underlying
362
- * `fetch` rejecting), HTTP `429`, and HTTP `5xx` responses. Override this with
363
- * {@link RetryPolicy.shouldRetry}.
362
+ * `fetch` rejecting) and responses with a transient status (`408`, `425`, `429`,
363
+ * or `5xx`). A terminal error of the invocation is never retried, whatever its status code.
364
+ * Override all of this with {@link RetryPolicy.shouldRetry}.
364
365
  */
365
366
  interface RetryPolicy {
366
367
  /**
367
368
  * Max number of attempts (including the initial), before giving up.
368
369
  *
369
- * Defaults to `6` (the initial attempt plus up to 5 retries).
370
+ * Retrying stops as soon as **either** `maxDuration` or {@link maxAttempts} is reached.
371
+ *
372
+ * Defaults to `6` (the initial attempt plus up to 5 retries). Pass `false` to
373
+ * remove the attempt bound.
374
+ */
375
+ maxAttempts?: number | false;
376
+ /**
377
+ * Max total duration of retries, measured from the first attempt, before
378
+ * giving up. If a number is provided, it is interpreted as milliseconds.
379
+ *
380
+ * This bound is checked only when deciding whether to start another
381
+ * attempt after a failure: it never aborts an in-flight request.
382
+ *
383
+ * Retrying stops as soon as **either** {@link maxDuration} or {@link maxAttempts} is reached.
384
+ *
385
+ * Defaults to 60 seconds. Pass `false` to remove the duration bound.
370
386
  */
371
- maxAttempts?: number;
387
+ maxDuration?: Duration | number | false;
372
388
  /**
373
389
  * Initial backoff interval. If a number is provided, it is interpreted as
374
- * milliseconds. Defaults to `100` milliseconds.
390
+ * milliseconds. Defaults to `250` milliseconds.
375
391
  */
376
392
  initialInterval?: Duration | number;
377
393
  /**
378
394
  * Maximum backoff interval. If a number is provided, it is interpreted as
379
- * milliseconds. Defaults to `2000` milliseconds.
395
+ * milliseconds. Defaults to `3000` milliseconds.
380
396
  */
381
397
  maxInterval?: Duration | number;
382
398
  /**
@@ -384,9 +400,23 @@ interface RetryPolicy {
384
400
  * Defaults to `2`.
385
401
  */
386
402
  exponentiationFactor?: number;
403
+ /**
404
+ * Whether to honor a `Retry-After` response header when the server provides
405
+ * one. When `true` (the default), a `Retry-After` value overrides the computed
406
+ * exponential backoff for that attempt.
407
+ *
408
+ * Set to `false` to always use the exponential backoff and ignore the header.
409
+ *
410
+ * Note that `Retry-After` never extends the number of retries: {@link maxAttempts} and
411
+ * {@link maxDuration} is always respected regardless of this setting.
412
+ *
413
+ * Defaults to `true`.
414
+ */
415
+ respectRetryAfter?: boolean;
387
416
  /**
388
417
  * Decide whether a given failure should be retried. When provided, this
389
- * fully replaces the built-in rule (network / `429` / `5xx`).
418
+ * fully replaces the built-in rule (network / transient `408`/`425`/`429`/`5xx`,
419
+ * excluding invocation-sourced errors).
390
420
  *
391
421
  * The idempotency-key gate still applies to regular invocations; workflow
392
422
  * submissions, attaches, and output retrieval remain eligible without an
@@ -411,8 +441,9 @@ type ConnectionOpts = {
411
441
  */
412
442
  headers?: Record<string, string>;
413
443
  /**
414
- * Opt in to automatic retries of ambiguous ingress failures (network errors,
415
- * HTTP `429`, HTTP `5xx`).
444
+ * Opt in to automatic retries of ambiguous ingress failures (network errors
445
+ * and transient HTTP statuses `408`/`425`/`429`/`5xx`, excluding errors
446
+ * restate attributes to the invocation itself).
416
447
  *
417
448
  * Retries are **disabled by default**. Set `true` to enable the built-in
418
449
  * policy ({@link RetryPolicy}), or pass a {@link RetryPolicy} to tune it.
package/dist/api.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"api.d.ts","names":[],"sources":["../src/api.ts"],"sourcesContent":[],"mappings":"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"}
1
+ {"version":3,"file":"api.d.ts","names":[],"sources":["../src/api.ts"],"sourcesContent":[],"mappings":"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"}
package/dist/api.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"api.js","names":["opts: IngressCallOptions<I, O>","opts: IngressSendOptions<I>"],"sources":["../src/api.ts"],"sourcesContent":["import type {\n Service,\n VirtualObjectDefinitionFrom,\n Workflow,\n VirtualObject,\n ServiceDefinitionFrom,\n WorkflowDefinitionFrom,\n Serde,\n Duration,\n JournalValueCodec,\n} from \"@restatedev/restate-sdk-core\";\nimport { millisOrDurationToMillis } from \"@restatedev/restate-sdk-core\";\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\n\n/**\n * A remote client for a Restate service.\n *\n * Use the following client to interact with services defined\n * - `serviceClient` to create a client for a service.\n * - `workflowClient` to create a client for a workflow.\n * - `objectClient` to create a client for a virtual object.\n *\n */\nexport interface Ingress {\n /**\n * Create a client from a {@link ServiceDefinition}.\n */\n serviceClient<D>(opts: ServiceDefinitionFrom<D>): IngressClient<Service<D>>;\n\n /**\n * Create a client from a {@link WorkflowDefinition}.\n *\n * @param key the key of the workflow.\n */\n workflowClient<D>(\n opts: WorkflowDefinitionFrom<D>,\n key: string\n ): IngressWorkflowClient<Workflow<D>>;\n\n /**\n * Create a client from a {@link VirtualObjectDefinition}.\n * @param key the key of the virtual object.\n */\n objectClient<D>(\n opts: VirtualObjectDefinitionFrom<D>,\n key: string\n ): IngressClient<VirtualObject<D>>;\n\n /**\n * Create a client from a {@link ServiceDefinition}.\n */\n serviceSendClient<D>(\n opts: ServiceDefinitionFrom<D>\n ): IngressSendClient<Service<D>>;\n\n /**\n * Create a client from a {@link VirtualObjectDefinition}.\n */\n objectSendClient<D>(\n opts: VirtualObjectDefinitionFrom<D>,\n key: string\n ): IngressSendClient<VirtualObject<D>>;\n\n /**\n * Resolve an awakeable from the ingress client.\n */\n resolveAwakeable<T>(\n id: string,\n payload?: T,\n payloadSerde?: Serde<T>\n ): Promise<void>;\n\n /**\n * Reject an awakeable from the ingress client.\n */\n rejectAwakeable(id: string, reason: string): Promise<void>;\n\n /**\n * Obtain the result of a service that was asynchronously submitted (via a sendClient).\n *\n * @param send either the send response or the workflow submission as obtained by the respective clients.\n */\n result<T>(\n send: Send<T> | WorkflowSubmission<T>,\n resultSerde?: Serde<T>\n ): Promise<T>;\n\n /** Generic request-response call. Routes directly by service name without a typed definition. */\n call<I = Uint8Array, O = Uint8Array>(opts: {\n service: string;\n handler: string;\n parameter: I;\n key?: string;\n /**\n * Route this call within the given scope. See {@link Ingress.scope}.\n *\n * *NOTE:* This API is experimental. To use it you need a restate-server >= 1.7,\n * configured to enable\n * [service protocol v7](https://github.com/restatedev/restate/blob/main/release-notes/v1.7.0.md#service-protocol-v7)\n * and [flow control](https://github.com/restatedev/restate/blob/main/release-notes/v1.7.0.md#flow-control).\n * For example, start the restate-server with the environment variables\n * `RESTATE_EXPERIMENTAL_ENABLE_PROTOCOL_V7=true` and `RESTATE_EXPERIMENTAL_ENABLE_VQUEUES=true`.\n *\n * @experimental\n */\n scope?: string;\n opts?: Opts<I, O>;\n }): Promise<O>;\n\n /** Generic fire-and-forget send. Routes directly by service name without a typed definition. */\n send<I = Uint8Array>(opts: {\n service: string;\n handler: string;\n parameter: I;\n key?: string;\n /**\n * Route this send within the given scope. See {@link Ingress.scope}.\n *\n * *NOTE:* This API is experimental. To use it you need a restate-server >= 1.7,\n * configured to enable\n * [service protocol v7](https://github.com/restatedev/restate/blob/main/release-notes/v1.7.0.md#service-protocol-v7)\n * and [flow control](https://github.com/restatedev/restate/blob/main/release-notes/v1.7.0.md#flow-control).\n * For example, start the restate-server with the environment variables\n * `RESTATE_EXPERIMENTAL_ENABLE_PROTOCOL_V7=true` and `RESTATE_EXPERIMENTAL_ENABLE_VQUEUES=true`.\n *\n * @experimental\n */\n scope?: string;\n opts?: SendOpts<I>;\n }): Promise<Send>;\n\n /**\n * Returns a {@link ScopedIngress} that routes all calls within the given scope.\n *\n * **NOTE:** This API is in preview and is not enabled by default.\n * To use it in restate-server 1.7, enable the flow control and protocol v7 experimental features,\n * via `RESTATE_EXPERIMENTAL_ENABLE_PROTOCOL_V7=true` and `RESTATE_EXPERIMENTAL_ENABLE_VQUEUES=true`.\n * These can be enabled only on **new clusters**, for more info check out https://docs.restate.dev/services/flow-control#enabling-flow-control.\n * If these experimental features aren't enabled, the invocation won't be ingested and the client request fails.\n *\n * A scope is a sub-grouping of resources (invocations, virtual object instances, workflow\n * instances, concurrency limits) within the Restate cluster.\n * It becomes part of the target identity tuple:\n * - `scope, service, handler, idempotencyKey?`\n * - `scope, virtualObject, objectKey, handler, idempotencyKey?`\n * - `scope, workflow, workflowKey, handler`\n *\n * Under the hood, the scope contributes to the partition key, so all resources in a scope get co-located by the restate-server.\n *\n * Omitting the scope (i.e. using the regular `serviceClient` / `workflowClient` methods)\n * is equivalent to calling with no scope, which is the existing behavior.\n *\n * The scope key must consist only of `[a-zA-Z0-9_.-]` characters, with 1 <= length <= 36 chars.\n *\n * @example\n * ```ts\n * // Route a call into a named scope\n * await ingress.scope(\"tenant-123\").serviceClient(MyService).process(payload);\n *\n * // Idempotency keys are scoped — \"req-1\" in \"tenant-123\" is distinct from \"req-1\" in \"tenant-456\"\n * await ingress.scope(\"tenant-123\").serviceClient(MyService)\n * .process(payload, rpc.opts({ idempotencyKey: \"req-1\" }));\n *\n * // Combine with a limit key to enforce per-scope concurrency limits\n * await ingress.scope(\"tenant-123\").workflowClient(MyWorkflow, \"wf-key\")\n * .run(input, rpc.opts({ limitKey: \"api-key/user42\" }));\n * ```\n *\n * @param scopeKey the scope identifier\n * @see https://docs.restate.dev/services/flow-control\n * @experimental\n */\n scope(scopeKey: string): ScopedIngress;\n}\n\n/**\n * An ingress client for making RPC calls within a specific scope.\n *\n * @see {@link Ingress.scope}\n * @experimental\n * @interface\n */\nexport type ScopedIngress = Pick<\n Ingress,\n | \"serviceClient\"\n | \"serviceSendClient\"\n | \"objectClient\"\n | \"objectSendClient\"\n | \"workflowClient\"\n>;\n\nexport interface IngressCallOptions<I = unknown, O = unknown> {\n /**\n * Key to use for idempotency key.\n *\n * See https://docs.restate.dev/operate/invocation#invoke-a-handler-idempotently for more details.\n */\n idempotencyKey?: string;\n\n /**\n * An optional concurrency limit key within the scope.\n * A limit key can only be used in conjunction with a scope (see {@link Ingress.scope}).\n *\n * **NOTE:** This API is in preview and is not enabled by default.\n * To use it in restate-server 1.7, enable the flow control and protocol v7 experimental features,\n * via `RESTATE_EXPERIMENTAL_ENABLE_PROTOCOL_V7=true` and `RESTATE_EXPERIMENTAL_ENABLE_VQUEUES=true`.\n * These can be enabled only on **new clusters**, for more info check out https://docs.restate.dev/services/flow-control#enabling-flow-control.\n * If these experimental features aren't enabled, the invocation isn't ingested and the client request fails.\n *\n * The limit key enforces hierarchical concurrency limits on invocations sharing the same scope.\n * It can have one or two levels separated by `/` (e.g. `\"tenant1\"` or `\"tenant1/user42\"`).\n * Each level must consist only of `[a-zA-Z0-9_.-]` characters, and 1 <= length <= 36.\n *\n * The limit key is **not** part of the request identity: two calls to the same target with the\n * same scope and object key but different limit keys refer to the **same** resource instance.\n * The limit key only affects concurrency limits, not resource identity.\n *\n * @experimental\n */\n limitKey?: string;\n\n /**\n * Headers to attach to the request.\n */\n headers?: Record<string, string>;\n\n input?: Serde<I>;\n\n output?: Serde<O>;\n\n /**\n * Timeout to be used when executing the request. In milliseconds.\n *\n * Same as {@link https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal#aborting_a_fetch_with_timeout_or_explicit_abort | AbortSignal.timeout()}.\n *\n * This field is exclusive with `signal`, and using both of them will result in a runtime failure.\n */\n timeout?: number;\n\n /**\n * Signal to abort the underlying `fetch` operation. See {@link https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal}.\n *\n * This field is exclusive with `timeout`, and using both of them will result in a runtime failure.\n */\n signal?: AbortSignal;\n}\n\nexport interface IngressSendOptions<I> extends IngressCallOptions<I, void> {\n /**\n * If set, the invocation will be enqueued now to be executed after the provided delay. In milliseconds.\n */\n delay?: number | Duration;\n}\n\nexport class Opts<I, O> {\n /**\n * Create a call configuration from the provided options.\n *\n * @param opts the call configuration\n */\n public static from<I = unknown, O = unknown>(\n opts: IngressCallOptions<I, O>\n ): Opts<I, O> {\n return new Opts(opts);\n }\n\n constructor(readonly opts: IngressCallOptions<I, O>) {}\n}\n\nexport class SendOpts<I = unknown> {\n /**\n * @param opts Create send options\n */\n public static from<I = unknown>(opts: IngressSendOptions<I>): SendOpts<I> {\n return new SendOpts(opts);\n }\n\n delay(): number | undefined {\n if (this.opts.delay !== undefined) {\n return millisOrDurationToMillis(this.opts.delay);\n }\n return undefined;\n }\n\n constructor(readonly opts: IngressSendOptions<I>) {}\n}\n\nexport type InferArgType<P> = P extends [infer A, ...any[]] ? A : unknown;\n\nexport type IngressClient<M> = {\n [K in keyof M as M[K] extends never ? never : K]: M[K] extends (\n arg: any,\n ...args: infer P\n ) => PromiseLike<infer O>\n ? (...args: [...P, ...[opts?: Opts<InferArgType<P>, O>]]) => PromiseLike<O>\n : never;\n};\n\n// eslint-disable-next-line @typescript-eslint/no-namespace\nexport namespace rpc {\n export const opts = <I, O>(opts: IngressCallOptions<I, O>) => Opts.from(opts);\n\n export const sendOpts = <I>(opts: IngressSendOptions<I>) =>\n SendOpts.from(opts);\n}\n\n/**\n * Represents the output of a workflow.\n */\nexport interface Output<O> {\n /**\n * Whether the output is ready.\n */\n ready: boolean;\n\n /**\n * The output of the workflow.\n */\n result: O;\n}\n\n/**\n * Represents a successful workflow submission.\n *\n */\n/* eslint-disable-next-line @typescript-eslint/no-unused-vars */\nexport type WorkflowSubmission<T> = {\n /**\n * The invocation id of the workflow. You can use that id to\n * with the introspection tools (restate cli, logging, metrics)\n *\n */\n readonly invocationId: string;\n /**\n * Whether the workflow was accepted by this request or had already been\n * accepted.\n *\n * When automatic retries are enabled, this may be `PreviouslyAccepted` if an\n * earlier attempt from the same `workflowSubmit` call was accepted but its\n * response was not observed by the client.\n */\n readonly status: \"Accepted\" | \"PreviouslyAccepted\";\n readonly attachable: true;\n};\n\n/**\n * A client for a workflow.\n *\n * This client represents the workflow definition, with the following additional methods:\n * - `workflowSubmit` to submit the workflow.\n * - `workflowAttach` to attach to the workflow and wait for its completion\n * - `workflowOutput` to check if the workflow's output is ready/available.\n *\n * Once a workflow is submitted, it can be attached to, and the output can be retrieved.\n *\n * @typeParam M the type of the workflow.\n */\nexport type IngressWorkflowClient<M> = Omit<\n {\n [K in keyof M as M[K] extends never ? never : K]: M[K] extends (\n arg: any,\n ...args: infer P\n ) => PromiseLike<infer O>\n ? (\n ...args: [...P, ...[opts?: Opts<InferArgType<P>, O>]]\n ) => PromiseLike<O>\n : never;\n } & {\n /**\n * Submit this workflow.\n *\n * This instructs restate to execute the 'run' handler of the workflow, idempotently.\n * The workflow will be executed asynchronously, and the promise will resolve when the workflow has been accepted.\n * Please note that submitting a workflow does not wait for it to completion.\n * When automatic retries are enabled on the connection, the client safely retries\n * ambiguous submission failures using the workflow ID as the request identity.\n *\n * @param argument the same argument type as defined by the 'run' handler.\n */\n workflowSubmit: M extends Record<string, unknown>\n ? M[\"run\"] extends (arg: any, ...args: infer I) => Promise<infer O>\n ? (\n ...args: [...I, ...[opts?: SendOpts<InferArgType<I>>]]\n ) => Promise<WorkflowSubmission<O>>\n : never\n : never;\n\n /**\n * Attach to this workflow.\n *\n * This instructs restate to attach to the workflow and wait for it to complete.\n * It is only possible to 'attach' to a workflow that has been previously submitted.\n * The promise will resolve when the workflow has completed either successfully with a result,\n * or be rejected with an error.\n * This operation is safe to retry many times, and it will always return the same result.\n * When automatic retries are enabled on the connection, the client retries\n * ambiguous attach failures according to the configured retry policy.\n *\n * @returns a promise that resolves when the workflow has completed.\n */\n workflowAttach: M extends Record<string, unknown>\n ? M[\"run\"] extends (...args: any) => Promise<infer O>\n ? (opts?: Opts<void, O>) => Promise<O>\n : never\n : never;\n\n /**\n * Try retrieving the output of this workflow.\n *\n * This instructs restate to check if the workflow's output is ready/available.\n * The returned Output object will have a 'ready' field set to true if the output is ready.\n * If the output is ready, the 'result' field will contain the output.\n * note: that this operation will not wait for the workflow to complete, to do so use 'workflowAttach'.\n * When automatic retries are enabled on the connection, the client retries\n * ambiguous output retrieval failures according to the configured retry policy.\n *\n * @returns a promise that resolves if the workflow's output is ready/available.\n */\n workflowOutput: M extends Record<string, unknown>\n ? M[\"run\"] extends (...args: any) => Promise<infer O>\n ? (opts?: Opts<void, O>) => Promise<Output<O>>\n : never\n : never;\n },\n \"run\"\n>;\n\n/**\n * A send response.\n *\n * @typeParam T the type of the response.\n */\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nexport type Send<T = unknown> = {\n /**\n * The invocation id of the send.\n */\n invocationId: string;\n\n /**\n * The status of the send.\n */\n status: \"Accepted\" | \"PreviouslyAccepted\";\n\n attachable: boolean;\n};\n\nexport type IngressSendClient<M> = {\n [K in keyof M as M[K] extends never ? never : K]: M[K] extends (\n arg: any,\n ...args: infer P\n ) => PromiseLike<infer O>\n ? (\n ...args: [...P, ...[opts?: SendOpts<InferArgType<P>>]]\n ) => Promise<Send<O>>\n : never;\n};\n\n/**\n * An ambiguous ingress failure that may be retried.\n *\n * Passed to {@link RetryPolicy.shouldRetry} so a caller can inspect the failure\n * and decide whether to retry.\n */\nexport type RetryFailure =\n | {\n /** The underlying `fetch` call rejected (connection refused/reset, DNS). */\n readonly kind: \"network\";\n readonly error: unknown;\n }\n | {\n /** The server returned a non-2xx response. */\n readonly kind: \"response\";\n readonly status: number;\n readonly headers: Headers;\n /**\n * The response body, decoded as text, when the response carried a\n * non-empty body; `undefined` otherwise.\n */\n readonly body?: string;\n };\n\n/**\n * Policy controlling automatic retries of ambiguous ingress failures.\n *\n * Retries are **opt-in**: they happen only when a policy is configured (see\n * {@link ConnectionOpts.retry}) and the request is safe to repeat. Regular\n * calls require an `idempotencyKey` (see\n * {@link IngressCallOptions.idempotencyKey}); workflow submissions are\n * idempotent by workflow ID, while workflow attaches and output retrieval only\n * observe the existing workflow.\n *\n * By default the following failures are retried: network errors (the underlying\n * `fetch` rejecting), HTTP `429`, and HTTP `5xx` responses. Override this with\n * {@link RetryPolicy.shouldRetry}.\n */\nexport interface RetryPolicy {\n /**\n * Max number of attempts (including the initial), before giving up.\n *\n * Defaults to `6` (the initial attempt plus up to 5 retries).\n */\n maxAttempts?: number;\n\n /**\n * Initial backoff interval. If a number is provided, it is interpreted as\n * milliseconds. Defaults to `100` milliseconds.\n */\n initialInterval?: Duration | number;\n\n /**\n * Maximum backoff interval. If a number is provided, it is interpreted as\n * milliseconds. Defaults to `2000` milliseconds.\n */\n maxInterval?: Duration | number;\n\n /**\n * Exponentiation factor to use when computing the next retry delay.\n * Defaults to `2`.\n */\n exponentiationFactor?: number;\n\n /**\n * Decide whether a given failure should be retried. When provided, this\n * fully replaces the built-in rule (network / `429` / `5xx`).\n *\n * The idempotency-key gate still applies to regular invocations; workflow\n * submissions, attaches, and output retrieval remain eligible without an\n * idempotency key. The `maxAttempts` cap applies to all of them. This predicate\n * only narrows or broadens *which failures* are retryable within those bounds.\n * Compose with the built-in rule via the exported `defaultShouldRetry`.\n *\n * @param failure the failure being considered\n * @param attempt the zero-based index of the attempt that just failed\n */\n shouldRetry?: (failure: RetryFailure, attempt: number) => boolean;\n}\n\nexport type ConnectionOpts = {\n /**\n * Restate ingress URL.\n * For example: http://localhost:8080\n */\n url: string;\n /**\n * Headers to attach on every request.\n * Use this to attach authentication headers.\n */\n headers?: Record<string, string>;\n\n /**\n * Opt in to automatic retries of ambiguous ingress failures (network errors,\n * HTTP `429`, HTTP `5xx`).\n *\n * Retries are **disabled by default**. Set `true` to enable the built-in\n * policy ({@link RetryPolicy}), or pass a {@link RetryPolicy} to tune it.\n *\n * Even when enabled, regular calls are retried **only** when an\n * `idempotencyKey` is set — without one a retry could double-execute a\n * non-idempotent invocation. Workflow submissions, attaches, and output\n * retrieval are also retried: submissions are idempotent by workflow ID,\n * while attach and output operations only observe the existing workflow. If a\n * submission retry observes a workflow accepted by an earlier attempt, its\n * status is `PreviouslyAccepted`.\n */\n retry?: RetryPolicy | boolean;\n\n /**\n * Default serde to use for ingress payloads when no operation-specific serde\n * is provided. Applies to handler calls, workflow attaches/output polling,\n * awakeable resolution, and attached invocation results.\n *\n * Defaults to `restate.serde.json`.\n */\n serde?: Serde<any>;\n\n /**\n * Codec to use for input/outputs. Check {@link JournalValueCodec} for more details\n *\n * @experimental\n */\n journalValueCodec?: JournalValueCodec;\n\n /**\n * Custom fetch client\n *\n * Allows you to provide a different fetch implementation (e.g., undici fetch for HTTP/2 support).\n *\n * @defaultValue `globalThis.fetch`\n */\n fetch?: typeof globalThis.fetch;\n};\n"],"mappings":";;;AA+PA,IAAa,OAAb,MAAa,KAAW;;;;;;CAMtB,OAAc,KACZ,MACY;AACZ,SAAO,IAAI,KAAK,KAAK;;CAGvB,YAAY,AAASA,MAAgC;EAAhC;;;AAGvB,IAAa,WAAb,MAAa,SAAsB;;;;CAIjC,OAAc,KAAkB,MAA0C;AACxE,SAAO,IAAI,SAAS,KAAK;;CAG3B,QAA4B;AAC1B,MAAI,KAAK,KAAK,UAAU,OACtB,QAAO,yBAAyB,KAAK,KAAK,MAAM;;CAKpD,YAAY,AAASC,MAA6B;EAA7B;;;;;cAgBM,SAAmC,KAAK,KAAK,KAAK;kBAEjD,SAC1B,SAAS,KAAK,KAAK"}
1
+ {"version":3,"file":"api.js","names":["opts: IngressCallOptions<I, O>","opts: IngressSendOptions<I>"],"sources":["../src/api.ts"],"sourcesContent":["import type {\n Service,\n VirtualObjectDefinitionFrom,\n Workflow,\n VirtualObject,\n ServiceDefinitionFrom,\n WorkflowDefinitionFrom,\n Serde,\n Duration,\n JournalValueCodec,\n} from \"@restatedev/restate-sdk-core\";\nimport { millisOrDurationToMillis } from \"@restatedev/restate-sdk-core\";\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\n\n/**\n * A remote client for a Restate service.\n *\n * Use the following client to interact with services defined\n * - `serviceClient` to create a client for a service.\n * - `workflowClient` to create a client for a workflow.\n * - `objectClient` to create a client for a virtual object.\n *\n */\nexport interface Ingress {\n /**\n * Create a client from a {@link ServiceDefinition}.\n */\n serviceClient<D>(opts: ServiceDefinitionFrom<D>): IngressClient<Service<D>>;\n\n /**\n * Create a client from a {@link WorkflowDefinition}.\n *\n * @param key the key of the workflow.\n */\n workflowClient<D>(\n opts: WorkflowDefinitionFrom<D>,\n key: string\n ): IngressWorkflowClient<Workflow<D>>;\n\n /**\n * Create a client from a {@link VirtualObjectDefinition}.\n * @param key the key of the virtual object.\n */\n objectClient<D>(\n opts: VirtualObjectDefinitionFrom<D>,\n key: string\n ): IngressClient<VirtualObject<D>>;\n\n /**\n * Create a client from a {@link ServiceDefinition}.\n */\n serviceSendClient<D>(\n opts: ServiceDefinitionFrom<D>\n ): IngressSendClient<Service<D>>;\n\n /**\n * Create a client from a {@link VirtualObjectDefinition}.\n */\n objectSendClient<D>(\n opts: VirtualObjectDefinitionFrom<D>,\n key: string\n ): IngressSendClient<VirtualObject<D>>;\n\n /**\n * Resolve an awakeable from the ingress client.\n */\n resolveAwakeable<T>(\n id: string,\n payload?: T,\n payloadSerde?: Serde<T>\n ): Promise<void>;\n\n /**\n * Reject an awakeable from the ingress client.\n */\n rejectAwakeable(id: string, reason: string): Promise<void>;\n\n /**\n * Obtain the result of a service that was asynchronously submitted (via a sendClient).\n *\n * @param send either the send response or the workflow submission as obtained by the respective clients.\n */\n result<T>(\n send: Send<T> | WorkflowSubmission<T>,\n resultSerde?: Serde<T>\n ): Promise<T>;\n\n /** Generic request-response call. Routes directly by service name without a typed definition. */\n call<I = Uint8Array, O = Uint8Array>(opts: {\n service: string;\n handler: string;\n parameter: I;\n key?: string;\n /**\n * Route this call within the given scope. See {@link Ingress.scope}.\n *\n * *NOTE:* This API is experimental. To use it you need a restate-server >= 1.7,\n * configured to enable\n * [service protocol v7](https://github.com/restatedev/restate/blob/main/release-notes/v1.7.0.md#service-protocol-v7)\n * and [flow control](https://github.com/restatedev/restate/blob/main/release-notes/v1.7.0.md#flow-control).\n * For example, start the restate-server with the environment variables\n * `RESTATE_EXPERIMENTAL_ENABLE_PROTOCOL_V7=true` and `RESTATE_EXPERIMENTAL_ENABLE_VQUEUES=true`.\n *\n * @experimental\n */\n scope?: string;\n opts?: Opts<I, O>;\n }): Promise<O>;\n\n /** Generic fire-and-forget send. Routes directly by service name without a typed definition. */\n send<I = Uint8Array>(opts: {\n service: string;\n handler: string;\n parameter: I;\n key?: string;\n /**\n * Route this send within the given scope. See {@link Ingress.scope}.\n *\n * *NOTE:* This API is experimental. To use it you need a restate-server >= 1.7,\n * configured to enable\n * [service protocol v7](https://github.com/restatedev/restate/blob/main/release-notes/v1.7.0.md#service-protocol-v7)\n * and [flow control](https://github.com/restatedev/restate/blob/main/release-notes/v1.7.0.md#flow-control).\n * For example, start the restate-server with the environment variables\n * `RESTATE_EXPERIMENTAL_ENABLE_PROTOCOL_V7=true` and `RESTATE_EXPERIMENTAL_ENABLE_VQUEUES=true`.\n *\n * @experimental\n */\n scope?: string;\n opts?: SendOpts<I>;\n }): Promise<Send>;\n\n /**\n * Returns a {@link ScopedIngress} that routes all calls within the given scope.\n *\n * **NOTE:** This API is in preview and is not enabled by default.\n * To use it in restate-server 1.7, enable the flow control and protocol v7 experimental features,\n * via `RESTATE_EXPERIMENTAL_ENABLE_PROTOCOL_V7=true` and `RESTATE_EXPERIMENTAL_ENABLE_VQUEUES=true`.\n * These can be enabled only on **new clusters**, for more info check out https://docs.restate.dev/services/flow-control#enabling-flow-control.\n * If these experimental features aren't enabled, the invocation won't be ingested and the client request fails.\n *\n * A scope is a sub-grouping of resources (invocations, virtual object instances, workflow\n * instances, concurrency limits) within the Restate cluster.\n * It becomes part of the target identity tuple:\n * - `scope, service, handler, idempotencyKey?`\n * - `scope, virtualObject, objectKey, handler, idempotencyKey?`\n * - `scope, workflow, workflowKey, handler`\n *\n * Under the hood, the scope contributes to the partition key, so all resources in a scope get co-located by the restate-server.\n *\n * Omitting the scope (i.e. using the regular `serviceClient` / `workflowClient` methods)\n * is equivalent to calling with no scope, which is the existing behavior.\n *\n * The scope key must consist only of `[a-zA-Z0-9_.-]` characters, with 1 <= length <= 36 chars.\n *\n * @example\n * ```ts\n * // Route a call into a named scope\n * await ingress.scope(\"tenant-123\").serviceClient(MyService).process(payload);\n *\n * // Idempotency keys are scoped — \"req-1\" in \"tenant-123\" is distinct from \"req-1\" in \"tenant-456\"\n * await ingress.scope(\"tenant-123\").serviceClient(MyService)\n * .process(payload, rpc.opts({ idempotencyKey: \"req-1\" }));\n *\n * // Combine with a limit key to enforce per-scope concurrency limits\n * await ingress.scope(\"tenant-123\").workflowClient(MyWorkflow, \"wf-key\")\n * .run(input, rpc.opts({ limitKey: \"api-key/user42\" }));\n * ```\n *\n * @param scopeKey the scope identifier\n * @see https://docs.restate.dev/services/flow-control\n * @experimental\n */\n scope(scopeKey: string): ScopedIngress;\n}\n\n/**\n * An ingress client for making RPC calls within a specific scope.\n *\n * @see {@link Ingress.scope}\n * @experimental\n * @interface\n */\nexport type ScopedIngress = Pick<\n Ingress,\n | \"serviceClient\"\n | \"serviceSendClient\"\n | \"objectClient\"\n | \"objectSendClient\"\n | \"workflowClient\"\n>;\n\nexport interface IngressCallOptions<I = unknown, O = unknown> {\n /**\n * Key to use for idempotency key.\n *\n * See https://docs.restate.dev/operate/invocation#invoke-a-handler-idempotently for more details.\n */\n idempotencyKey?: string;\n\n /**\n * An optional concurrency limit key within the scope.\n * A limit key can only be used in conjunction with a scope (see {@link Ingress.scope}).\n *\n * **NOTE:** This API is in preview and is not enabled by default.\n * To use it in restate-server 1.7, enable the flow control and protocol v7 experimental features,\n * via `RESTATE_EXPERIMENTAL_ENABLE_PROTOCOL_V7=true` and `RESTATE_EXPERIMENTAL_ENABLE_VQUEUES=true`.\n * These can be enabled only on **new clusters**, for more info check out https://docs.restate.dev/services/flow-control#enabling-flow-control.\n * If these experimental features aren't enabled, the invocation isn't ingested and the client request fails.\n *\n * The limit key enforces hierarchical concurrency limits on invocations sharing the same scope.\n * It can have one or two levels separated by `/` (e.g. `\"tenant1\"` or `\"tenant1/user42\"`).\n * Each level must consist only of `[a-zA-Z0-9_.-]` characters, and 1 <= length <= 36.\n *\n * The limit key is **not** part of the request identity: two calls to the same target with the\n * same scope and object key but different limit keys refer to the **same** resource instance.\n * The limit key only affects concurrency limits, not resource identity.\n *\n * @experimental\n */\n limitKey?: string;\n\n /**\n * Headers to attach to the request.\n */\n headers?: Record<string, string>;\n\n input?: Serde<I>;\n\n output?: Serde<O>;\n\n /**\n * Timeout to be used when executing the request. In milliseconds.\n *\n * Same as {@link https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal#aborting_a_fetch_with_timeout_or_explicit_abort | AbortSignal.timeout()}.\n *\n * This field is exclusive with `signal`, and using both of them will result in a runtime failure.\n */\n timeout?: number;\n\n /**\n * Signal to abort the underlying `fetch` operation. See {@link https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal}.\n *\n * This field is exclusive with `timeout`, and using both of them will result in a runtime failure.\n */\n signal?: AbortSignal;\n}\n\nexport interface IngressSendOptions<I> extends IngressCallOptions<I, void> {\n /**\n * If set, the invocation will be enqueued now to be executed after the provided delay. In milliseconds.\n */\n delay?: number | Duration;\n}\n\nexport class Opts<I, O> {\n /**\n * Create a call configuration from the provided options.\n *\n * @param opts the call configuration\n */\n public static from<I = unknown, O = unknown>(\n opts: IngressCallOptions<I, O>\n ): Opts<I, O> {\n return new Opts(opts);\n }\n\n constructor(readonly opts: IngressCallOptions<I, O>) {}\n}\n\nexport class SendOpts<I = unknown> {\n /**\n * @param opts Create send options\n */\n public static from<I = unknown>(opts: IngressSendOptions<I>): SendOpts<I> {\n return new SendOpts(opts);\n }\n\n delay(): number | undefined {\n if (this.opts.delay !== undefined) {\n return millisOrDurationToMillis(this.opts.delay);\n }\n return undefined;\n }\n\n constructor(readonly opts: IngressSendOptions<I>) {}\n}\n\nexport type InferArgType<P> = P extends [infer A, ...any[]] ? A : unknown;\n\nexport type IngressClient<M> = {\n [K in keyof M as M[K] extends never ? never : K]: M[K] extends (\n arg: any,\n ...args: infer P\n ) => PromiseLike<infer O>\n ? (...args: [...P, ...[opts?: Opts<InferArgType<P>, O>]]) => PromiseLike<O>\n : never;\n};\n\n// eslint-disable-next-line @typescript-eslint/no-namespace\nexport namespace rpc {\n export const opts = <I, O>(opts: IngressCallOptions<I, O>) => Opts.from(opts);\n\n export const sendOpts = <I>(opts: IngressSendOptions<I>) =>\n SendOpts.from(opts);\n}\n\n/**\n * Represents the output of a workflow.\n */\nexport interface Output<O> {\n /**\n * Whether the output is ready.\n */\n ready: boolean;\n\n /**\n * The output of the workflow.\n */\n result: O;\n}\n\n/**\n * Represents a successful workflow submission.\n *\n */\n/* eslint-disable-next-line @typescript-eslint/no-unused-vars */\nexport type WorkflowSubmission<T> = {\n /**\n * The invocation id of the workflow. You can use that id to\n * with the introspection tools (restate cli, logging, metrics)\n *\n */\n readonly invocationId: string;\n /**\n * Whether the workflow was accepted by this request or had already been\n * accepted.\n *\n * When automatic retries are enabled, this may be `PreviouslyAccepted` if an\n * earlier attempt from the same `workflowSubmit` call was accepted but its\n * response was not observed by the client.\n */\n readonly status: \"Accepted\" | \"PreviouslyAccepted\";\n readonly attachable: true;\n};\n\n/**\n * A client for a workflow.\n *\n * This client represents the workflow definition, with the following additional methods:\n * - `workflowSubmit` to submit the workflow.\n * - `workflowAttach` to attach to the workflow and wait for its completion\n * - `workflowOutput` to check if the workflow's output is ready/available.\n *\n * Once a workflow is submitted, it can be attached to, and the output can be retrieved.\n *\n * @typeParam M the type of the workflow.\n */\nexport type IngressWorkflowClient<M> = Omit<\n {\n [K in keyof M as M[K] extends never ? never : K]: M[K] extends (\n arg: any,\n ...args: infer P\n ) => PromiseLike<infer O>\n ? (\n ...args: [...P, ...[opts?: Opts<InferArgType<P>, O>]]\n ) => PromiseLike<O>\n : never;\n } & {\n /**\n * Submit this workflow.\n *\n * This instructs restate to execute the 'run' handler of the workflow, idempotently.\n * The workflow will be executed asynchronously, and the promise will resolve when the workflow has been accepted.\n * Please note that submitting a workflow does not wait for it to completion.\n * When automatic retries are enabled on the connection, the client safely retries\n * ambiguous submission failures using the workflow ID as the request identity.\n *\n * @param argument the same argument type as defined by the 'run' handler.\n */\n workflowSubmit: M extends Record<string, unknown>\n ? M[\"run\"] extends (arg: any, ...args: infer I) => Promise<infer O>\n ? (\n ...args: [...I, ...[opts?: SendOpts<InferArgType<I>>]]\n ) => Promise<WorkflowSubmission<O>>\n : never\n : never;\n\n /**\n * Attach to this workflow.\n *\n * This instructs restate to attach to the workflow and wait for it to complete.\n * It is only possible to 'attach' to a workflow that has been previously submitted.\n * The promise will resolve when the workflow has completed either successfully with a result,\n * or be rejected with an error.\n * This operation is safe to retry many times, and it will always return the same result.\n * When automatic retries are enabled on the connection, the client retries\n * ambiguous attach failures according to the configured retry policy.\n *\n * @returns a promise that resolves when the workflow has completed.\n */\n workflowAttach: M extends Record<string, unknown>\n ? M[\"run\"] extends (...args: any) => Promise<infer O>\n ? (opts?: Opts<void, O>) => Promise<O>\n : never\n : never;\n\n /**\n * Try retrieving the output of this workflow.\n *\n * This instructs restate to check if the workflow's output is ready/available.\n * The returned Output object will have a 'ready' field set to true if the output is ready.\n * If the output is ready, the 'result' field will contain the output.\n * note: that this operation will not wait for the workflow to complete, to do so use 'workflowAttach'.\n * When automatic retries are enabled on the connection, the client retries\n * ambiguous output retrieval failures according to the configured retry policy.\n *\n * @returns a promise that resolves if the workflow's output is ready/available.\n */\n workflowOutput: M extends Record<string, unknown>\n ? M[\"run\"] extends (...args: any) => Promise<infer O>\n ? (opts?: Opts<void, O>) => Promise<Output<O>>\n : never\n : never;\n },\n \"run\"\n>;\n\n/**\n * A send response.\n *\n * @typeParam T the type of the response.\n */\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nexport type Send<T = unknown> = {\n /**\n * The invocation id of the send.\n */\n invocationId: string;\n\n /**\n * The status of the send.\n */\n status: \"Accepted\" | \"PreviouslyAccepted\";\n\n attachable: boolean;\n};\n\nexport type IngressSendClient<M> = {\n [K in keyof M as M[K] extends never ? never : K]: M[K] extends (\n arg: any,\n ...args: infer P\n ) => PromiseLike<infer O>\n ? (\n ...args: [...P, ...[opts?: SendOpts<InferArgType<P>>]]\n ) => Promise<Send<O>>\n : never;\n};\n\n/**\n * An ambiguous ingress failure that may be retried.\n *\n * Passed to {@link RetryPolicy.shouldRetry} so a caller can inspect the failure\n * and decide whether to retry.\n */\nexport type RetryFailure =\n | {\n /** The underlying `fetch` call rejected (connection refused/reset, DNS). */\n readonly kind: \"network\";\n readonly error: unknown;\n }\n | {\n /** The server returned a non-2xx response. */\n readonly kind: \"response\";\n readonly status: number;\n readonly headers: Headers;\n /**\n * The response body, decoded as text, when the response carried a\n * non-empty body; `undefined` otherwise.\n */\n readonly body?: string;\n };\n\n/**\n * Policy controlling automatic retries of ambiguous ingress failures.\n *\n * Retries are **opt-in**: they happen only when a policy is configured (see\n * {@link ConnectionOpts.retry}) and the request is safe to repeat. Regular\n * calls require an `idempotencyKey` (see\n * {@link IngressCallOptions.idempotencyKey}); workflow submissions are\n * idempotent by workflow ID, while workflow attaches and output retrieval only\n * observe the existing workflow.\n *\n * By default the following failures are retried: network errors (the underlying\n * `fetch` rejecting) and responses with a transient status (`408`, `425`, `429`,\n * or `5xx`). A terminal error of the invocation is never retried, whatever its status code.\n * Override all of this with {@link RetryPolicy.shouldRetry}.\n */\nexport interface RetryPolicy {\n /**\n * Max number of attempts (including the initial), before giving up.\n *\n * Retrying stops as soon as **either** `maxDuration` or {@link maxAttempts} is reached.\n *\n * Defaults to `6` (the initial attempt plus up to 5 retries). Pass `false` to\n * remove the attempt bound.\n */\n maxAttempts?: number | false;\n\n /**\n * Max total duration of retries, measured from the first attempt, before\n * giving up. If a number is provided, it is interpreted as milliseconds.\n *\n * This bound is checked only when deciding whether to start another\n * attempt after a failure: it never aborts an in-flight request.\n *\n * Retrying stops as soon as **either** {@link maxDuration} or {@link maxAttempts} is reached.\n *\n * Defaults to 60 seconds. Pass `false` to remove the duration bound.\n */\n maxDuration?: Duration | number | false;\n\n /**\n * Initial backoff interval. If a number is provided, it is interpreted as\n * milliseconds. Defaults to `250` milliseconds.\n */\n initialInterval?: Duration | number;\n\n /**\n * Maximum backoff interval. If a number is provided, it is interpreted as\n * milliseconds. Defaults to `3000` milliseconds.\n */\n maxInterval?: Duration | number;\n\n /**\n * Exponentiation factor to use when computing the next retry delay.\n * Defaults to `2`.\n */\n exponentiationFactor?: number;\n\n /**\n * Whether to honor a `Retry-After` response header when the server provides\n * one. When `true` (the default), a `Retry-After` value overrides the computed\n * exponential backoff for that attempt.\n *\n * Set to `false` to always use the exponential backoff and ignore the header.\n *\n * Note that `Retry-After` never extends the number of retries: {@link maxAttempts} and\n * {@link maxDuration} is always respected regardless of this setting.\n *\n * Defaults to `true`.\n */\n respectRetryAfter?: boolean;\n\n /**\n * Decide whether a given failure should be retried. When provided, this\n * fully replaces the built-in rule (network / transient `408`/`425`/`429`/`5xx`,\n * excluding invocation-sourced errors).\n *\n * The idempotency-key gate still applies to regular invocations; workflow\n * submissions, attaches, and output retrieval remain eligible without an\n * idempotency key. The `maxAttempts` cap applies to all of them. This predicate\n * only narrows or broadens *which failures* are retryable within those bounds.\n * Compose with the built-in rule via the exported `defaultShouldRetry`.\n *\n * @param failure the failure being considered\n * @param attempt the zero-based index of the attempt that just failed\n */\n shouldRetry?: (failure: RetryFailure, attempt: number) => boolean;\n}\n\nexport type ConnectionOpts = {\n /**\n * Restate ingress URL.\n * For example: http://localhost:8080\n */\n url: string;\n /**\n * Headers to attach on every request.\n * Use this to attach authentication headers.\n */\n headers?: Record<string, string>;\n\n /**\n * Opt in to automatic retries of ambiguous ingress failures (network errors\n * and transient HTTP statuses `408`/`425`/`429`/`5xx`, excluding errors\n * restate attributes to the invocation itself).\n *\n * Retries are **disabled by default**. Set `true` to enable the built-in\n * policy ({@link RetryPolicy}), or pass a {@link RetryPolicy} to tune it.\n *\n * Even when enabled, regular calls are retried **only** when an\n * `idempotencyKey` is set — without one a retry could double-execute a\n * non-idempotent invocation. Workflow submissions, attaches, and output\n * retrieval are also retried: submissions are idempotent by workflow ID,\n * while attach and output operations only observe the existing workflow. If a\n * submission retry observes a workflow accepted by an earlier attempt, its\n * status is `PreviouslyAccepted`.\n */\n retry?: RetryPolicy | boolean;\n\n /**\n * Default serde to use for ingress payloads when no operation-specific serde\n * is provided. Applies to handler calls, workflow attaches/output polling,\n * awakeable resolution, and attached invocation results.\n *\n * Defaults to `restate.serde.json`.\n */\n serde?: Serde<any>;\n\n /**\n * Codec to use for input/outputs. Check {@link JournalValueCodec} for more details\n *\n * @experimental\n */\n journalValueCodec?: JournalValueCodec;\n\n /**\n * Custom fetch client\n *\n * Allows you to provide a different fetch implementation (e.g., undici fetch for HTTP/2 support).\n *\n * @defaultValue `globalThis.fetch`\n */\n fetch?: typeof globalThis.fetch;\n};\n"],"mappings":";;;AA+PA,IAAa,OAAb,MAAa,KAAW;;;;;;CAMtB,OAAc,KACZ,MACY;AACZ,SAAO,IAAI,KAAK,KAAK;;CAGvB,YAAY,AAASA,MAAgC;EAAhC;;;AAGvB,IAAa,WAAb,MAAa,SAAsB;;;;CAIjC,OAAc,KAAkB,MAA0C;AACxE,SAAO,IAAI,SAAS,KAAK;;CAG3B,QAA4B;AAC1B,MAAI,KAAK,KAAK,UAAU,OACtB,QAAO,yBAAyB,KAAK,KAAK,MAAM;;CAKpD,YAAY,AAASC,MAA6B;EAA7B;;;;;cAgBM,SAAmC,KAAK,KAAK,KAAK;kBAEjD,SAC1B,SAAS,KAAK,KAAK"}
package/dist/ingress.cjs CHANGED
@@ -47,6 +47,7 @@ function optsFromArgs(args) {
47
47
  }
48
48
  const IDEMPOTENCY_KEY_HEADER = "idempotency-key";
49
49
  const LIMIT_KEY_HEADER = "x-restate-limit-key";
50
+ const ATTEMPT_HEADER = "x-restateclient-retry-attempt";
50
51
  const getFetch = (opts) => opts.fetch ?? globalThis.fetch;
51
52
  const fetchWithRetries = async (opts, url, init, callOpts, retryPolicy) => {
52
53
  const userSignal = callOpts?.opts.signal;
@@ -54,12 +55,19 @@ const fetchWithRetries = async (opts, url, init, callOpts, retryPolicy) => {
54
55
  if (userSignal !== void 0 && timeout !== void 0) throw new Error("You can't specify both signal and timeout options at the same time");
55
56
  const attemptSignal = () => userSignal ?? (timeout !== void 0 ? AbortSignal.timeout(timeout) : void 0);
56
57
  const shouldRetry = retryPolicy?.shouldRetry ?? require_retry.defaultShouldRetry;
58
+ const startTime = Date.now();
59
+ const nextAttemptFitsBudget = (policy, delay) => Date.now() - startTime + delay < policy.maxDuration;
60
+ const baseHeaders = init.headers ?? {};
57
61
  for (let attempt = 0;; attempt++) {
58
62
  let response;
59
63
  let errorBody;
60
64
  try {
61
65
  response = await getFetch(opts)(url, {
62
66
  ...init,
67
+ headers: {
68
+ ...baseHeaders,
69
+ [ATTEMPT_HEADER]: String(attempt + 1)
70
+ },
63
71
  signal: attemptSignal()
64
72
  });
65
73
  if (response.ok) return new Uint8Array(await response.arrayBuffer());
@@ -69,8 +77,11 @@ const fetchWithRetries = async (opts, url, init, callOpts, retryPolicy) => {
69
77
  kind: "network",
70
78
  error: e
71
79
  }, attempt)) {
72
- await require_retry.abortableSleep(require_retry.backoffDelay(retryPolicy, attempt), userSignal);
73
- continue;
80
+ const delay = require_retry.backoffDelay(retryPolicy, attempt);
81
+ if (nextAttemptFitsBudget(retryPolicy, delay)) {
82
+ await require_retry.abortableSleep(delay, userSignal);
83
+ continue;
84
+ }
74
85
  }
75
86
  throw e;
76
87
  }
@@ -80,9 +91,11 @@ const fetchWithRetries = async (opts, url, init, callOpts, retryPolicy) => {
80
91
  headers: response.headers,
81
92
  body: errorBody || void 0
82
93
  }, attempt)) {
83
- const retryAfter = require_retry.parseRetryAfter(response.headers);
84
- await require_retry.abortableSleep(require_retry.backoffDelay(retryPolicy, attempt, retryAfter), userSignal);
85
- continue;
94
+ const delay = (retryPolicy.respectRetryAfter ? require_retry.parseRetryAfter(response.headers) : void 0) ?? require_retry.backoffDelay(retryPolicy, attempt);
95
+ if (nextAttemptFitsBudget(retryPolicy, delay)) {
96
+ await require_retry.abortableSleep(delay, userSignal);
97
+ continue;
98
+ }
86
99
  }
87
100
  throw new HttpCallError(response.status, errorBody, `Request failed: ${response.status}\n${errorBody}`);
88
101
  }
@@ -376,17 +389,13 @@ var HttpIngress = class {
376
389
  A service's result is stored only with an idempotencyKey is supplied when invocating the service.`);
377
390
  const headers = { ...this.opts.headers ?? {} };
378
391
  const url = `${this.opts.url}/restate/invocation/${send.invocationId}/attach`;
379
- const httpResponse = await getFetch(this.opts)(url, {
392
+ const retryPolicy = require_retry.resolveRetryPolicy(this.opts.retry);
393
+ const responseBuf = await fetchWithRetries(this.opts, url, {
380
394
  method: "GET",
381
395
  headers
382
- });
383
- if (httpResponse.ok) {
384
- const responseBuf = new Uint8Array(await httpResponse.arrayBuffer());
385
- const decodedBuf = this.opts.journalValueCodec ? await this.opts.journalValueCodec.decode(responseBuf) : responseBuf;
386
- return (resultSerde ?? this.opts.serde ?? __restatedev_restate_sdk_core.serde.json).deserialize(decodedBuf);
387
- }
388
- const body = await httpResponse.text();
389
- throw new HttpCallError(httpResponse.status, body, `Request failed: ${httpResponse.status}\n${body}`);
396
+ }, void 0, retryPolicy);
397
+ const decodedBuf = this.opts.journalValueCodec ? await this.opts.journalValueCodec.decode(responseBuf) : responseBuf;
398
+ return (resultSerde ?? this.opts.serde ?? __restatedev_restate_sdk_core.serde.json).deserialize(decodedBuf);
390
399
  }
391
400
  };
392
401
  function computeDelayAsIso(opts) {
package/dist/ingress.js CHANGED
@@ -45,6 +45,7 @@ function optsFromArgs(args) {
45
45
  }
46
46
  const IDEMPOTENCY_KEY_HEADER = "idempotency-key";
47
47
  const LIMIT_KEY_HEADER = "x-restate-limit-key";
48
+ const ATTEMPT_HEADER = "x-restateclient-retry-attempt";
48
49
  const getFetch = (opts) => opts.fetch ?? globalThis.fetch;
49
50
  const fetchWithRetries = async (opts, url, init, callOpts, retryPolicy) => {
50
51
  const userSignal = callOpts?.opts.signal;
@@ -52,12 +53,19 @@ const fetchWithRetries = async (opts, url, init, callOpts, retryPolicy) => {
52
53
  if (userSignal !== void 0 && timeout !== void 0) throw new Error("You can't specify both signal and timeout options at the same time");
53
54
  const attemptSignal = () => userSignal ?? (timeout !== void 0 ? AbortSignal.timeout(timeout) : void 0);
54
55
  const shouldRetry = retryPolicy?.shouldRetry ?? defaultShouldRetry;
56
+ const startTime = Date.now();
57
+ const nextAttemptFitsBudget = (policy, delay) => Date.now() - startTime + delay < policy.maxDuration;
58
+ const baseHeaders = init.headers ?? {};
55
59
  for (let attempt = 0;; attempt++) {
56
60
  let response;
57
61
  let errorBody;
58
62
  try {
59
63
  response = await getFetch(opts)(url, {
60
64
  ...init,
65
+ headers: {
66
+ ...baseHeaders,
67
+ [ATTEMPT_HEADER]: String(attempt + 1)
68
+ },
61
69
  signal: attemptSignal()
62
70
  });
63
71
  if (response.ok) return new Uint8Array(await response.arrayBuffer());
@@ -67,8 +75,11 @@ const fetchWithRetries = async (opts, url, init, callOpts, retryPolicy) => {
67
75
  kind: "network",
68
76
  error: e
69
77
  }, attempt)) {
70
- await abortableSleep(backoffDelay(retryPolicy, attempt), userSignal);
71
- continue;
78
+ const delay = backoffDelay(retryPolicy, attempt);
79
+ if (nextAttemptFitsBudget(retryPolicy, delay)) {
80
+ await abortableSleep(delay, userSignal);
81
+ continue;
82
+ }
72
83
  }
73
84
  throw e;
74
85
  }
@@ -78,9 +89,11 @@ const fetchWithRetries = async (opts, url, init, callOpts, retryPolicy) => {
78
89
  headers: response.headers,
79
90
  body: errorBody || void 0
80
91
  }, attempt)) {
81
- const retryAfter = parseRetryAfter(response.headers);
82
- await abortableSleep(backoffDelay(retryPolicy, attempt, retryAfter), userSignal);
83
- continue;
92
+ const delay = (retryPolicy.respectRetryAfter ? parseRetryAfter(response.headers) : void 0) ?? backoffDelay(retryPolicy, attempt);
93
+ if (nextAttemptFitsBudget(retryPolicy, delay)) {
94
+ await abortableSleep(delay, userSignal);
95
+ continue;
96
+ }
84
97
  }
85
98
  throw new HttpCallError(response.status, errorBody, `Request failed: ${response.status}\n${errorBody}`);
86
99
  }
@@ -374,17 +387,13 @@ var HttpIngress = class {
374
387
  A service's result is stored only with an idempotencyKey is supplied when invocating the service.`);
375
388
  const headers = { ...this.opts.headers ?? {} };
376
389
  const url = `${this.opts.url}/restate/invocation/${send.invocationId}/attach`;
377
- const httpResponse = await getFetch(this.opts)(url, {
390
+ const retryPolicy = resolveRetryPolicy(this.opts.retry);
391
+ const responseBuf = await fetchWithRetries(this.opts, url, {
378
392
  method: "GET",
379
393
  headers
380
- });
381
- if (httpResponse.ok) {
382
- const responseBuf = new Uint8Array(await httpResponse.arrayBuffer());
383
- const decodedBuf = this.opts.journalValueCodec ? await this.opts.journalValueCodec.decode(responseBuf) : responseBuf;
384
- return (resultSerde ?? this.opts.serde ?? serde.json).deserialize(decodedBuf);
385
- }
386
- const body = await httpResponse.text();
387
- throw new HttpCallError(httpResponse.status, body, `Request failed: ${httpResponse.status}\n${body}`);
394
+ }, void 0, retryPolicy);
395
+ const decodedBuf = this.opts.journalValueCodec ? await this.opts.journalValueCodec.decode(responseBuf) : responseBuf;
396
+ return (resultSerde ?? this.opts.serde ?? serde.json).deserialize(decodedBuf);
388
397
  }
389
398
  };
390
399
  function computeDelayAsIso(opts) {