withruntime 0.11.2 → 0.14.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 (171) hide show
  1. package/BLAXEL.md +2 -2
  2. package/COMPATIBILITY.md +74 -9
  3. package/DAYTONA.md +33 -5
  4. package/E2B.md +85 -24
  5. package/README.md +11 -10
  6. package/README.src.md +10 -9
  7. package/VERCEL.md +43 -5
  8. package/compatibility-lock.json +58 -49
  9. package/dist/billing-cli.d.ts +1 -1
  10. package/dist/billing-cli.js +85 -5
  11. package/dist/blaxel/errors.d.ts +14 -0
  12. package/dist/blaxel/errors.js +29 -0
  13. package/dist/blaxel/index.d.ts +2 -2
  14. package/dist/blaxel/index.js +4 -4
  15. package/dist/blaxel/interpreter.d.ts +2 -5
  16. package/dist/blaxel/sandbox.d.ts +15 -6
  17. package/dist/blaxel/sandbox.js +64 -8
  18. package/dist/blaxel/snapshot.d.ts +4 -0
  19. package/dist/blaxel/snapshot.js +4 -0
  20. package/dist/cli/logs.d.ts +21 -0
  21. package/dist/cli/logs.js +188 -0
  22. package/dist/cli-extras.d.ts +3 -3
  23. package/dist/cli-extras.js +17 -12
  24. package/dist/cli-words.d.ts +10 -1
  25. package/dist/cli-words.js +18 -0
  26. package/dist/cli.d.ts +22 -3
  27. package/dist/cli.js +647 -273
  28. package/dist/client.d.ts +2 -4
  29. package/dist/client.js +27 -11
  30. package/dist/cloudflare/errors.d.ts +143 -0
  31. package/dist/cloudflare/errors.js +167 -0
  32. package/dist/cloudflare/index.d.ts +175 -6
  33. package/dist/cloudflare/index.js +416 -26
  34. package/dist/cloudflare/interpreter.d.ts +119 -0
  35. package/dist/cloudflare/interpreter.js +223 -0
  36. package/dist/cloudflare/streams.d.ts +38 -0
  37. package/dist/cloudflare/streams.js +145 -0
  38. package/dist/cloudflare/watch.d.ts +9 -0
  39. package/dist/cloudflare/watch.js +24 -0
  40. package/dist/codesandbox/index.d.ts +216 -28
  41. package/dist/codesandbox/index.js +478 -78
  42. package/dist/compat/core.d.ts +18 -0
  43. package/dist/compat/core.js +29 -0
  44. package/dist/compat/files.d.ts +1 -0
  45. package/dist/compat/files.js +25 -5
  46. package/dist/credentials.d.ts +3 -0
  47. package/dist/credentials.js +15 -0
  48. package/dist/daytona/computer-use.d.ts +13 -4
  49. package/dist/daytona/computer-use.js +66 -8
  50. package/dist/daytona/daytona.d.ts +7 -1
  51. package/dist/daytona/daytona.js +31 -4
  52. package/dist/daytona/errors.d.ts +11 -0
  53. package/dist/daytona/errors.js +18 -0
  54. package/dist/daytona/filesystem.js +2 -1
  55. package/dist/daytona/image.d.ts +13 -9
  56. package/dist/daytona/image.js +18 -12
  57. package/dist/daytona/index.d.ts +1 -1
  58. package/dist/daytona/sandbox.d.ts +8 -2
  59. package/dist/daytona/sandbox.js +16 -2
  60. package/dist/domains/index.d.ts +9 -0
  61. package/dist/domains/index.js +10 -0
  62. package/dist/e2b/commands.d.ts +1 -1
  63. package/dist/e2b/commands.js +6 -7
  64. package/dist/e2b/errors.d.ts +17 -0
  65. package/dist/e2b/errors.js +40 -1
  66. package/dist/e2b/index.d.ts +2 -2
  67. package/dist/e2b/index.js +1 -1
  68. package/dist/e2b/sandbox.d.ts +28 -22
  69. package/dist/e2b/sandbox.js +34 -8
  70. package/dist/e2b/unsupported.js +1 -1
  71. package/dist/errors.d.ts +11 -2
  72. package/dist/errors.js +17 -5
  73. package/dist/freestyle/index.d.ts +285 -37
  74. package/dist/freestyle/index.js +656 -144
  75. package/dist/identity.d.ts +3 -0
  76. package/dist/identity.js +27 -0
  77. package/dist/images/index.d.ts +9 -0
  78. package/dist/images/index.js +10 -0
  79. package/dist/index.d.ts +3 -1
  80. package/dist/ips/index.d.ts +9 -0
  81. package/dist/ips/index.js +10 -0
  82. package/dist/jobs/index.d.ts +9 -0
  83. package/dist/jobs/index.js +10 -0
  84. package/dist/keys.js +2 -0
  85. package/dist/login.js +2 -0
  86. package/dist/machine.d.ts +27 -4
  87. package/dist/machine.js +46 -14
  88. package/dist/mcp.js +144 -20
  89. package/dist/modal/index.d.ts +339 -61
  90. package/dist/modal/index.js +781 -121
  91. package/dist/network-cli.d.ts +3 -1
  92. package/dist/network-cli.js +78 -36
  93. package/dist/networks/index.d.ts +11 -0
  94. package/dist/networks/index.js +10 -0
  95. package/dist/ports/index.d.ts +9 -0
  96. package/dist/ports/index.js +10 -0
  97. package/dist/product-names.d.ts +52 -0
  98. package/dist/product-names.js +164 -0
  99. package/dist/product-renames.d.ts +103 -0
  100. package/dist/product-renames.js +189 -0
  101. package/dist/products/api-keys.d.ts +73 -0
  102. package/dist/products/api-keys.js +23 -0
  103. package/dist/products/apps.d.ts +157 -0
  104. package/dist/products/apps.js +60 -0
  105. package/dist/products/balancers.d.ts +87 -0
  106. package/dist/products/balancers.js +8 -0
  107. package/dist/products/billing.d.ts +41 -0
  108. package/dist/products/billing.js +13 -0
  109. package/dist/products/browser.d.ts +10 -0
  110. package/dist/products/browsers.d.ts +71 -0
  111. package/dist/products/browsers.js +102 -0
  112. package/dist/products/builds.d.ts +156 -0
  113. package/dist/products/builds.js +227 -0
  114. package/dist/products/index.d.ts +5 -16
  115. package/dist/products/index.js +5 -14
  116. package/dist/products/jobs.d.ts +19 -2
  117. package/dist/products/jobs.js +28 -11
  118. package/dist/products/logs.d.ts +245 -0
  119. package/dist/products/logs.js +274 -0
  120. package/dist/products/network-products.d.ts +38 -7
  121. package/dist/products/network-products.js +31 -18
  122. package/dist/products/observability.d.ts +8 -2
  123. package/dist/products/private-network.js +1 -1
  124. package/dist/products/queues.d.ts +149 -0
  125. package/dist/products/queues.js +213 -0
  126. package/dist/products/referrals.d.ts +21 -7
  127. package/dist/products/referrals.js +3 -3
  128. package/dist/products/resources.d.ts +54 -0
  129. package/dist/products/resources.js +122 -0
  130. package/dist/products/secrets.d.ts +29 -3
  131. package/dist/products/secrets.js +47 -18
  132. package/dist/products/signed-requests.d.ts +21 -0
  133. package/dist/products/signed-requests.js +11 -0
  134. package/dist/products/streams.d.ts +73 -0
  135. package/dist/products/streams.js +17 -0
  136. package/dist/products/switching.d.ts +35 -7
  137. package/dist/products/switching.js +4 -3
  138. package/dist/products/volumes.d.ts +6 -0
  139. package/dist/record-cli.d.ts +23 -0
  140. package/dist/record-cli.js +308 -0
  141. package/dist/renamed-products.d.ts +38 -0
  142. package/dist/renamed-products.js +34 -0
  143. package/dist/runloop/index.d.ts +9 -2
  144. package/dist/runloop/index.js +29 -8
  145. package/dist/runloop/sdk.d.ts +131 -0
  146. package/dist/runloop/sdk.js +167 -0
  147. package/dist/sandbox.d.ts +7 -2
  148. package/dist/sandbox.js +41 -11
  149. package/dist/sandboxes/index.d.ts +11 -0
  150. package/dist/sandboxes/index.js +12 -0
  151. package/dist/snapshots/index.d.ts +9 -0
  152. package/dist/snapshots/index.js +11 -0
  153. package/dist/snapshots.d.ts +7 -4
  154. package/dist/sprites/index.d.ts +343 -31
  155. package/dist/sprites/index.js +866 -84
  156. package/dist/ssh.d.ts +1 -1
  157. package/dist/ssh.js +11 -11
  158. package/dist/terminal.d.ts +24 -0
  159. package/dist/terminal.js +32 -0
  160. package/dist/transport.d.ts +18 -1
  161. package/dist/transport.js +80 -6
  162. package/dist/tunnel.js +1 -1
  163. package/dist/types.d.ts +71 -4
  164. package/dist/vercel/sandbox.d.ts +1 -1
  165. package/dist/vercel/sandbox.js +6 -4
  166. package/dist/vercel/snapshot.js +10 -2
  167. package/dist/volumes/index.d.ts +9 -0
  168. package/dist/volumes/index.js +10 -0
  169. package/dist/wallet.d.ts +4 -1
  170. package/dist/wallet.js +2 -1
  171. package/package.json +48 -14
@@ -1,4 +1,5 @@
1
1
  import { privateNetwork } from "./private-network.js";
2
+ import { signedRequests } from "./signed-requests.js";
2
3
  const enc = encodeURIComponent;
3
4
  /** `runtime.domains`: serve a sandbox's port at your own hostname, with HTTPS. */
4
5
  export function domains(t) {
@@ -43,57 +44,69 @@ export function ports(t) {
43
44
  }),
44
45
  };
45
46
  }
46
- /** `runtime.addresses`: a dedicated outbound address every sandbox of the
47
+ /** `runtime.ips`: a dedicated outbound address every sandbox of the
47
48
  * account sends from, for allow-lists. */
48
- export function addresses(t) {
49
+ export function ips(t) {
49
50
  return {
50
- reserve: (input = {}, options) => t.json({ method: "POST", path: "/v1/addresses", body: input, ...options }),
51
- list: async (options) => (await t.json({ method: "GET", path: "/v1/addresses", ...options }))
52
- .data,
51
+ reserve: (input = {}, options) => t.json({ method: "POST", path: "/v1/ips", body: input, ...options }),
52
+ list: async (options) => (await t.json({ method: "GET", path: "/v1/ips", ...options })).data,
53
53
  release: (addressId, options) => t.json({
54
54
  method: "DELETE",
55
- path: `/v1/addresses/${enc(addressId)}`,
55
+ path: `/v1/ips/${enc(addressId)}`,
56
56
  ...options,
57
57
  }),
58
58
  };
59
59
  }
60
- /** `runtime.tunnel`: a WireGuard tunnel from your own network into your sandboxes. */
61
- export function tunnel(t) {
60
+ /** `runtime.networks.wireguard`: a WireGuard tunnel from your own network into your sandboxes. */
61
+ export function wireguard(t) {
62
62
  return {
63
- get: (options) => t.json({ method: "GET", path: "/v1/tunnel", ...options }),
63
+ get: (options) => t.json({ method: "GET", path: "/v1/networks/wireguard", ...options }),
64
64
  /** Idempotent: returns the tunnel you have. */
65
- create: (input = {}, options) => t.json({ method: "POST", path: "/v1/tunnel", body: input, ...options }),
66
- delete: (options) => t.json({ method: "DELETE", path: "/v1/tunnel", ...options }),
65
+ create: (input = {}, options) => t.json({ method: "POST", path: "/v1/networks/wireguard", body: input, ...options }),
66
+ delete: (options) => t.json({
67
+ method: "DELETE",
68
+ path: "/v1/networks/wireguard",
69
+ ...options,
70
+ }),
67
71
  /** Leave publicKey out and Runtime generates the pair; the private key is
68
72
  * then in `config`, shown once. */
69
73
  addPeer: (input, options) => t.json({
70
74
  method: "POST",
71
- path: "/v1/tunnel/peers",
75
+ path: "/v1/networks/wireguard/peers",
72
76
  body: input,
73
77
  ...options,
74
78
  }),
75
79
  rotatePeer: (peerId, input = {}, options) => t.json({
76
80
  method: "POST",
77
- path: `/v1/tunnel/peers/${enc(peerId)}:rotate`,
81
+ path: `/v1/networks/wireguard/peers/${enc(peerId)}:rotate`,
78
82
  body: input,
79
83
  ...options,
80
84
  }),
81
- removePeer: (peerId, options) => t.json({ method: "DELETE", path: `/v1/tunnel/peers/${enc(peerId)}`, ...options }),
85
+ removePeer: (peerId, options) => t.json({
86
+ method: "DELETE",
87
+ path: `/v1/networks/wireguard/peers/${enc(peerId)}`,
88
+ ...options,
89
+ }),
82
90
  };
83
91
  }
84
- /** `runtime.network`: the network settings of the whole account.
92
+ /** `runtime.networks`: the networks of the whole account: the WireGuard
93
+ * tunnel in, your sandboxes reaching each other, and the proxy out.
85
94
  *
86
- * await runtime.network.upstreamProxy.set({ url: "http://proxy.example.com:3128" });
95
+ * await runtime.networks.upstreamProxy.set({ url: "http://proxy.example.com:3128" });
87
96
  *
88
97
  * `upstreamProxy`: after Runtime's own rules allow a connection, the host
89
98
  * reaches it with CONNECT through your proxy, so your proxy's controls and
90
99
  * logs apply. A proxy that refuses or cannot be reached fails the connection
91
100
  * (upstream-proxy-failed); nothing goes around it. Needs a kept top-up. */
92
- export function network(t) {
93
- const path = "/v1/network/upstream-proxy";
101
+ export function networks(t) {
102
+ const path = "/v1/networks/upstream-proxy";
94
103
  return {
104
+ /** The WireGuard tunnel from your own network into your sandboxes. */
105
+ wireguard: wireguard(t),
95
106
  /** Your sandboxes reaching each other by name (`private-network.ts`). */
96
107
  private: privateNetwork(t),
108
+ /** Your sandboxes' requests signed as Runtime's agents (`signed-requests.ts`). */
109
+ signedRequests: signedRequests(t),
97
110
  upstreamProxy: {
98
111
  /** Send outbound connections through your proxy, replacing any set before. */
99
112
  set: (input, options) => t.json({
@@ -35,7 +35,7 @@ export type SandboxMetrics = {
35
35
  latest: MetricPoint | null;
36
36
  points: MetricPoint[];
37
37
  };
38
- export type WebhookEventType = "sandbox.created" | "sandbox.running" | "sandbox.paused" | "sandbox.woken" | "sandbox.stopped" | "sandbox.start_failed" | "sandbox.wake_failed" | "sandbox.host_unreachable" | "sandbox.host_reachable" | "sandbox.recovered" | "sandbox.recovery_failed" | "snapshot.ready" | "snapshot.failed" | "snapshot.deleted" | "volume.ready" | "volume.failed" | "volume.deleted";
38
+ export type WebhookEventType = "sandbox.created" | "sandbox.running" | "sandbox.paused" | "sandbox.woken" | "sandbox.stopped" | "sandbox.start_failed" | "sandbox.wake_failed" | "sandbox.host_unreachable" | "sandbox.host_reachable" | "sandbox.recovered" | "sandbox.recovery_failed" | "sandbox.files.changed" | "sandbox.out_of_memory" | "sandbox.secret_not_applied" | "snapshot.ready" | "snapshot.failed" | "snapshot.deleted" | "volume.ready" | "volume.failed" | "volume.deleted" | "volume.recovered" | "egress_secret.created" | "egress_secret.updated" | "egress_secret.deleted" | "upstream_proxy.set" | "upstream_proxy.removed";
39
39
  /** An event as /v1/events lists it and a webhook delivers it. */
40
40
  export type RuntimeEvent = {
41
41
  id: string;
@@ -113,7 +113,8 @@ export type UsageExportRow = {
113
113
  name: string | null;
114
114
  kind: string;
115
115
  meter: string;
116
- fundedBy: "credit" | "trial";
116
+ /** credit, the trial's hours, or the month's free usage. */
117
+ fundedBy: "credit" | "trial" | "allowance";
117
118
  startsAt: string;
118
119
  endsAt: string;
119
120
  settledAt: string;
@@ -127,12 +128,17 @@ export type UsageExportRow = {
127
128
  /** Exact JSON text, preserving integers beyond JavaScript's number range. */
128
129
  measurementsJson: string | null;
129
130
  evidence: "measured" | "partial" | "missing" | null;
131
+ /** The resource is deleted and every charge it will ever have settled
132
+ * before finalThrough. A volume's backups bill on until retention ends. */
133
+ final: boolean;
130
134
  };
131
135
  export type UsageExportPage = {
132
136
  since: string;
133
137
  until: string;
134
138
  data: UsageExportRow[];
135
139
  nextCursor: string | null;
140
+ /** No row with settledAt before this can still appear or change. */
141
+ finalThrough: string | null;
136
142
  /** Concatenate pages in order; only the first page includes the header. */
137
143
  csv: string;
138
144
  };
@@ -1,5 +1,5 @@
1
1
  export function privateNetwork(t) {
2
- const path = "/v1/network/private";
2
+ const path = "/v1/networks/private";
3
3
  return {
4
4
  /** On or off, and whether this account may turn it on. */
5
5
  get: (options) => t.json({ method: "GET", path, ...options }),
@@ -0,0 +1,149 @@
1
+ import { Page } from "../page.js";
2
+ import type { RequestOptions, Transport } from "../transport.js";
3
+ /** Private until launch.
4
+ * This is the proposed management contract, not an installed API route.
5
+ * SQS clients use the returned sqs URL with their existing client. */
6
+ export type RecordState = "creating" | "ready" | "updating" | "deleting" | "deleted" | "failed";
7
+ export type RecordResource = {
8
+ id: string;
9
+ name: string;
10
+ labels: Record<string, string>;
11
+ state: RecordState;
12
+ createdAt: string;
13
+ error?: {
14
+ code: string;
15
+ message: string;
16
+ hint: string;
17
+ } | null;
18
+ };
19
+ export type QueueSettings = {
20
+ visibilityTimeoutSeconds: number;
21
+ retentionSeconds: number;
22
+ maxMessageBytes: number;
23
+ delaySeconds: number;
24
+ fifo: boolean;
25
+ deadLetter: {
26
+ queue: string;
27
+ maxReceives: number;
28
+ } | null;
29
+ };
30
+ export type Queue = RecordResource & {
31
+ settings: QueueSettings;
32
+ counts: {
33
+ visible: number;
34
+ inFlight: number;
35
+ delayed: number;
36
+ };
37
+ sqs: string;
38
+ };
39
+ export type CreateQueue = {
40
+ name: string;
41
+ labels?: Record<string, string>;
42
+ settings?: Partial<QueueSettings>;
43
+ };
44
+ export type UpdateQueue = Partial<CreateQueue>;
45
+ export type RecordListQuery = {
46
+ name?: string;
47
+ label?: readonly string[];
48
+ state?: readonly RecordState[];
49
+ limit?: number;
50
+ cursor?: string;
51
+ };
52
+ export type RecordWaitOptions = RequestOptions & {
53
+ pollMs?: number;
54
+ };
55
+ export type QueueAttribute = {
56
+ dataType: string;
57
+ stringValue?: string;
58
+ binaryValue?: string;
59
+ };
60
+ export type SendMessage = {
61
+ body: string;
62
+ attributes?: Record<string, QueueAttribute>;
63
+ delaySeconds?: number;
64
+ groupId?: string;
65
+ dedupId?: string;
66
+ };
67
+ export type ReceiveMessages = {
68
+ max?: number;
69
+ waitSeconds?: number;
70
+ visibilitySeconds?: number;
71
+ };
72
+ export type QueueMessage = SendMessage & {
73
+ id: string;
74
+ receiptHandle: string;
75
+ receives: number;
76
+ };
77
+ export type MessageSent = {
78
+ id: string;
79
+ md5: string;
80
+ sequenceNumber?: string;
81
+ };
82
+ export type ReceiptResult = {
83
+ successful: string[];
84
+ failed: {
85
+ receiptHandle: string;
86
+ code: string;
87
+ message: string;
88
+ hint: string;
89
+ }[];
90
+ };
91
+ /** A consume call handles messages sequentially. max counts handler attempts,
92
+ * including failures. Omit max to run until cancelled. timeoutMs bounds each
93
+ * network call, including settlement after cancellation, not the handler.
94
+ * Choose visibilitySeconds longer than the handler's work; delivery is at least once. */
95
+ export type ConsumeOptions = ReceiveMessages & {
96
+ signal?: AbortSignal;
97
+ timeoutMs?: number;
98
+ };
99
+ export type ConsumeResult = {
100
+ processed: number;
101
+ acknowledged: number;
102
+ retried: number;
103
+ aborted: boolean;
104
+ };
105
+ export type QueueHandler = (message: QueueMessage, signal: AbortSignal) => unknown;
106
+ /** Shared only by the private record products. The server owns field defaults
107
+ * and protocol refusals; the SDK preserves their codes and recovery hints. */
108
+ export declare function recordResources<R extends RecordResource, C, U>(t: Transport, plural: "queues" | "streams"): {
109
+ create: (input: C, options?: RequestOptions) => Promise<R>;
110
+ get: (id: string, options?: RequestOptions) => Promise<R>;
111
+ list: (query?: RecordListQuery, options?: RequestOptions) => Promise<Page<R>>;
112
+ update: (id: string, input: U, options?: RequestOptions) => Promise<R>;
113
+ delete: (id: string, options?: RequestOptions) => Promise<R>;
114
+ /** Poll one resource with a deadline across every read, including retries. */
115
+ wait(id: string, target?: "ready" | "deleted", options?: RecordWaitOptions): Promise<R>;
116
+ };
117
+ /** Private until launch. No public Runtime property is installed here. */
118
+ export declare function queues(t: Transport): {
119
+ send: (id: string, input: SendMessage, options?: RequestOptions) => Promise<MessageSent>;
120
+ receive: (id: string, input?: ReceiveMessages, options?: RequestOptions) => Promise<{
121
+ messages: QueueMessage[];
122
+ }>;
123
+ ack: (id: string, input: {
124
+ receiptHandles: string[];
125
+ }, options?: RequestOptions) => Promise<ReceiptResult>;
126
+ retry: (id: string, input: {
127
+ receiptHandle: string;
128
+ visibilitySeconds: number;
129
+ }, options?: RequestOptions) => Promise<{
130
+ receiptHandle: string;
131
+ visibilitySeconds: number;
132
+ }>;
133
+ /** Receive, handle, then acknowledge. No acknowledgement precedes success.
134
+ * A failed or cancelled handler releases its receipt at once. Aborting
135
+ * during receive can lose its reply; that lease expires without an ack.
136
+ * Settlement ignores the cancelled signal and has a bounded deadline.
137
+ * A lost settlement reply is retried once with the same key, even when
138
+ * transport retries were disabled. A remaining failure is thrown. */
139
+ consume(id: string, handler: QueueHandler, options?: ConsumeOptions): Promise<ConsumeResult>;
140
+ /** Purge returns the resource; follow its state with wait(id). */
141
+ purge: (id: string, options?: RequestOptions) => Promise<Queue>;
142
+ create: (input: CreateQueue, options?: RequestOptions) => Promise<Queue>;
143
+ get: (id: string, options?: RequestOptions) => Promise<Queue>;
144
+ list: (query?: RecordListQuery, options?: RequestOptions) => Promise<Page<Queue>>;
145
+ update: (id: string, input: Partial<CreateQueue>, options?: RequestOptions) => Promise<Queue>;
146
+ delete: (id: string, options?: RequestOptions) => Promise<Queue>;
147
+ /** Poll one resource with a deadline across every read, including retries. */
148
+ wait(id: string, target?: "ready" | "deleted", options?: RecordWaitOptions): Promise<Queue>;
149
+ };
@@ -0,0 +1,213 @@
1
+ import { RuntimeError } from "../errors.js";
2
+ import { Page } from "../page.js";
3
+ import { pause } from "../wait.js";
4
+ /** Stop waiting for user code on abort. Its rejection stays observed even if
5
+ * it finishes later. Handlers should use the signal to stop their own work. */
6
+ function handleMessage(handler, message, signal) {
7
+ return new Promise((resolve) => {
8
+ let finished = false;
9
+ const done = (success) => {
10
+ if (finished)
11
+ return;
12
+ finished = true;
13
+ signal.removeEventListener("abort", abort);
14
+ resolve(success);
15
+ };
16
+ const abort = () => done(false);
17
+ if (signal.aborted) {
18
+ done(false);
19
+ return;
20
+ }
21
+ signal.addEventListener("abort", abort, { once: true });
22
+ // Observe synchronous throws and late rejections by the same path.
23
+ Promise.resolve()
24
+ .then(() => signal.aborted ? false : Promise.resolve(handler(message, signal)).then(() => true))
25
+ .then(done, () => done(false));
26
+ });
27
+ }
28
+ /** Shared only by the private record products. The server owns field defaults
29
+ * and protocol refusals; the SDK preserves their codes and recovery hints. */
30
+ export function recordResources(t, plural) {
31
+ const base = `/v1/${plural}`;
32
+ const path = (id) => `${base}/${encodeURIComponent(id)}`;
33
+ const get = (id, options) => t.json({ ...options, method: "GET", path: path(id) });
34
+ const list = async (query = {}, options) => {
35
+ const page = await t.json({
36
+ ...options,
37
+ method: "GET",
38
+ path: base,
39
+ query,
40
+ });
41
+ return new Page(page.data, page.nextCursor, (cursor) => list({ ...query, cursor }, options));
42
+ };
43
+ return {
44
+ create: (input, options) => t.json({ ...options, method: "POST", path: base, body: input }),
45
+ get,
46
+ list,
47
+ update: (id, input, options) => t.json({ ...options, method: "POST", path: `${path(id)}:update`, body: input }),
48
+ delete: (id, options) => t.json({ ...options, method: "DELETE", path: path(id) }),
49
+ /** Poll one resource with a deadline across every read, including retries. */
50
+ async wait(id, target = "ready", options = {}) {
51
+ const { pollMs = 250, timeoutMs = 300_000, signal } = options;
52
+ if (!Number.isSafeInteger(pollMs) ||
53
+ pollMs < 0 ||
54
+ !Number.isSafeInteger(timeoutMs) ||
55
+ timeoutMs < 0)
56
+ throw new RuntimeError({
57
+ code: "invalid_request",
58
+ status: 0,
59
+ message: "pollMs and timeoutMs must be nonnegative safe integers.",
60
+ hint: "Use milliseconds; zero timeout disables the deadline.",
61
+ });
62
+ const deadline = new AbortController();
63
+ const combined = signal ? AbortSignal.any([signal, deadline.signal]) : deadline.signal;
64
+ const timer = timeoutMs ? setTimeout(() => deadline.abort(), timeoutMs) : undefined;
65
+ try {
66
+ for (;;) {
67
+ combined.throwIfAborted();
68
+ const current = await get(id, {
69
+ signal: combined,
70
+ timeoutMs: 0,
71
+ });
72
+ combined.throwIfAborted();
73
+ if (current.state === "failed" || (current.state === "deleted" && target !== "deleted"))
74
+ throw new RuntimeError({
75
+ code: current.error?.code ?? "unexpected_state",
76
+ status: 0,
77
+ message: current.error?.message ?? `Resource reached ${current.state}.`,
78
+ hint: current.error?.hint ?? "Read the resource before retrying the change.",
79
+ details: { id, target, state: current.state },
80
+ });
81
+ if (current.state === target)
82
+ return current;
83
+ await pause(pollMs, combined);
84
+ }
85
+ }
86
+ catch (cause) {
87
+ if (!combined.aborted)
88
+ throw cause;
89
+ throw new RuntimeError({
90
+ code: "timeout",
91
+ status: 0,
92
+ message: "Waiting ended before the target state was observed.",
93
+ hint: "Read the resource to resume; retry a write with its original idempotency key.",
94
+ cause,
95
+ });
96
+ }
97
+ finally {
98
+ clearTimeout(timer);
99
+ }
100
+ },
101
+ };
102
+ }
103
+ /** Private until launch. No public Runtime property is installed here. */
104
+ export function queues(t) {
105
+ const action = (id, verb, body, options) => t.json({
106
+ ...options,
107
+ method: "POST",
108
+ path: `/v1/queues/${encodeURIComponent(id)}:${verb}`,
109
+ body,
110
+ });
111
+ return {
112
+ ...recordResources(t, "queues"),
113
+ send: (id, input, options) => action(id, "send", input, options),
114
+ receive: (id, input = {}, options) => action(id, "receive", input, options),
115
+ ack: (id, input, options) => action(id, "ack", input, options),
116
+ retry: (id, input, options) => action(id, "retry", input, options),
117
+ /** Receive, handle, then acknowledge. No acknowledgement precedes success.
118
+ * A failed or cancelled handler releases its receipt at once. Aborting
119
+ * during receive can lose its reply; that lease expires without an ack.
120
+ * Settlement ignores the cancelled signal and has a bounded deadline.
121
+ * A lost settlement reply is retried once with the same key, even when
122
+ * transport retries were disabled. A remaining failure is thrown. */
123
+ async consume(id, handler, options = {}) {
124
+ const { max, waitSeconds = 20, visibilitySeconds, timeoutMs = 30_000 } = options;
125
+ for (const [field, value, minimum, maximum] of [
126
+ ["max", max, 0, Number.MAX_SAFE_INTEGER],
127
+ ["waitSeconds", waitSeconds, 0, 20],
128
+ ["visibilitySeconds", visibilitySeconds, 0, 43_200],
129
+ ["timeoutMs", timeoutMs, 1, 2_147_483_647],
130
+ ]) {
131
+ if (value !== undefined &&
132
+ (!Number.isSafeInteger(value) || value < minimum || value > maximum))
133
+ throw new RuntimeError({
134
+ code: "invalid_request",
135
+ status: 0,
136
+ message: `${field} must be an integer from ${minimum} to ${maximum}.`,
137
+ hint: "Correct the consume option; no message was received.",
138
+ });
139
+ }
140
+ const signal = options.signal ?? new AbortController().signal;
141
+ const result = { processed: 0, acknowledged: 0, retried: 0, aborted: false };
142
+ const settle = async (verb, body) => {
143
+ const request = { idempotencyKey: crypto.randomUUID(), timeoutMs };
144
+ try {
145
+ return await action(id, verb, body, request);
146
+ }
147
+ catch (error) {
148
+ if (!(error instanceof RuntimeError) ||
149
+ !["connection_error", "timeout"].includes(error.code))
150
+ throw error;
151
+ return action(id, verb, body, request);
152
+ }
153
+ };
154
+ while (!signal.aborted && (max === undefined || result.processed < max)) {
155
+ let received;
156
+ try {
157
+ received = await action(id, "receive", {
158
+ max: 1,
159
+ waitSeconds,
160
+ ...(visibilitySeconds === undefined ? {} : { visibilitySeconds }),
161
+ }, { signal, timeoutMs, idempotencyKey: crypto.randomUUID() });
162
+ }
163
+ catch (error) {
164
+ if (!signal.aborted)
165
+ throw error;
166
+ break;
167
+ }
168
+ if (received.messages.length > 1)
169
+ throw new RuntimeError({
170
+ code: "invalid_response",
171
+ status: 0,
172
+ message: "Receive returned more than the one message requested.",
173
+ hint: "No message was acknowledged; their visibility leases will expire.",
174
+ });
175
+ const message = received.messages[0];
176
+ if (!message) {
177
+ // Empty short polls must yield to cancellation and avoid a hot loop.
178
+ await pause(100, signal).catch(() => { });
179
+ continue;
180
+ }
181
+ let success = false;
182
+ if (!signal.aborted) {
183
+ result.processed++;
184
+ success = await handleMessage(handler, message, signal);
185
+ }
186
+ if (success && !signal.aborted) {
187
+ const ack = await settle("ack", {
188
+ receiptHandles: [message.receiptHandle],
189
+ });
190
+ const failed = ack.failed[0];
191
+ if (failed || !ack.successful.includes(message.receiptHandle))
192
+ throw new RuntimeError({
193
+ code: failed?.code ?? "invalid_response",
194
+ status: 0,
195
+ message: failed?.message ?? "The receipt was not acknowledged.",
196
+ hint: failed?.hint ??
197
+ "Do not assume delivery completed; this message can be delivered again.",
198
+ details: { receiptHandle: message.receiptHandle },
199
+ });
200
+ result.acknowledged++;
201
+ }
202
+ else {
203
+ await settle("retry", { receiptHandle: message.receiptHandle, visibilitySeconds: 0 });
204
+ result.retried++;
205
+ }
206
+ }
207
+ result.aborted = signal.aborted;
208
+ return result;
209
+ },
210
+ /** Purge returns the resource; follow its state with wait(id). */
211
+ purge: (id, options) => action(id, "purge", {}, options),
212
+ };
213
+ }
@@ -5,13 +5,16 @@ export type ReferralSummary = {
5
5
  code: string;
6
6
  /** Share this: https://withruntime.com/r/<code>. */
7
7
  link: string;
8
- /** The least each side gets: a first top-up is matched, never below this. */
8
+ /** The least each side gets on the referred company's first qualifying
9
+ * payment: a smaller one is matched up to this. */
9
10
  rewardMicros: string;
10
- /** The most each side gets: a first top-up is matched up to this. */
11
+ /** The most each side gets per referred company, all its matched payments
12
+ * together. */
11
13
  maxRewardMicros: string;
12
- /** The smallest first top-up that pays a referral. */
14
+ /** The smallest payment a referral matches. */
13
15
  minPurchaseMicros: string;
14
- /** The most referral credit you can earn in one calendar year (UTC). */
16
+ /** The most referral credit, matches and share together, you can earn in
17
+ * one calendar year (UTC). */
15
18
  yearlyCapMicros: string;
16
19
  enabled: boolean;
17
20
  year: number;
@@ -27,10 +30,21 @@ export type ReferralSummary = {
27
30
  status: "pending" | "paid" | "refused" | "reversed";
28
31
  creditMicros: string;
29
32
  } | null;
33
+ /** Referred companies with a matched payment still standing. */
34
+ payingCompanies: number;
35
+ /** Share credit you kept, all time. */
36
+ shareEarnedMicros: string;
37
+ /** Your share of what a referred company spends from credit it paid for,
38
+ * in basis points: 1000 is 10%. */
39
+ shareBasisPoints: number;
40
+ /** How long the share runs from a company's first matched payment. */
41
+ shareMonths: number;
42
+ /** How long after sign-up a referred company's payments are matched. */
43
+ windowDays: number;
30
44
  };
31
- /** `runtime.referrals.get()`: when a company that signs up with your link makes
32
- * its first top-up of at least $10, you and it each get credit equal to that
33
- * top-up, at least $25 and at most $500. */
45
+ /** `runtime.referrals`: a company that signs up with your link has every
46
+ * payment in its first 30 days matched, up to $1,000, and you get the same;
47
+ * then for 12 months you earn 10% of what it spends from credit it paid for. */
34
48
  export declare function referrals(t: Transport): {
35
49
  get: (options?: RequestOptions) => Promise<ReferralSummary>;
36
50
  };
@@ -1,6 +1,6 @@
1
- /** `runtime.referrals.get()`: when a company that signs up with your link makes
2
- * its first top-up of at least $10, you and it each get credit equal to that
3
- * top-up, at least $25 and at most $500. */
1
+ /** `runtime.referrals`: a company that signs up with your link has every
2
+ * payment in its first 30 days matched, up to $1,000, and you get the same;
3
+ * then for 12 months you earn 10% of what it spends from credit it paid for. */
4
4
  export function referrals(t) {
5
5
  return {
6
6
  get: (options) => t.json({ method: "GET", path: "/v1/referrals", ...options }),
@@ -0,0 +1,54 @@
1
+ import { Page } from "../page.js";
2
+ import type { RequestOptions, Transport } from "../transport.js";
3
+ /** The five verbs every resource product shares (CLOUD.md section 4, "One
4
+ * shape for every interface"; packages/cloud/src/api/resource-product.ts),
5
+ * and following one to a state. A product builds its client on these and
6
+ * adds only its own verbs. */
7
+ export type ResourceRecord = {
8
+ id: string;
9
+ state: string;
10
+ error: {
11
+ code: string;
12
+ message: string;
13
+ } | null;
14
+ };
15
+ export type ResourceListQuery<S extends string = string> = {
16
+ name?: string;
17
+ /** Repeated key:value filters; all must match. */
18
+ label?: readonly string[];
19
+ /** Defaults to the product's live states. */
20
+ state?: readonly S[];
21
+ /** 1 to 100; defaults to 50. */
22
+ limit?: number;
23
+ cursor?: string;
24
+ };
25
+ export type ResourceGetOptions<S extends string = string> = RequestOptions & {
26
+ waitFor?: S;
27
+ /** Server wait, 1 to 60 seconds; defaults to 30. Check the returned state. */
28
+ timeoutSeconds?: number;
29
+ };
30
+ export type ResourceWaitOptions = RequestOptions & {
31
+ /** Whole wait, including retries; defaults to 300000 ms. 0 disables it. */
32
+ timeoutMs?: number;
33
+ /** Delay between reads; defaults to 250 ms. */
34
+ pollMs?: number;
35
+ };
36
+ export type ResourceDeleteOptions = ResourceWaitOptions & {
37
+ wait?: boolean;
38
+ };
39
+ export declare const enc: typeof encodeURIComponent;
40
+ /** One deadline covers the write, retries and every read. A timed-out delete
41
+ * can be retried after a process restart with this same key. */
42
+ export declare function following<T>(options: ResourceWaitOptions, work: (request: RequestOptions, pause: () => Promise<void>) => Promise<T>): Promise<T>;
43
+ /** A resource product's client at `/v1/<path>`. A wait ends at its target
44
+ * or at any of `settled`, which answers with the resource's error. */
45
+ export declare function resource<R extends ResourceRecord, C, U, S extends string = R["state"]>(t: Transport, path: string, settled: readonly S[]): {
46
+ base: string;
47
+ /** Defaults belong to the API, so the SDK does not override them. */
48
+ create: (input: C, options?: RequestOptions) => Promise<R>;
49
+ get: (id: string, options?: ResourceGetOptions<S>) => Promise<R>;
50
+ list: (query?: ResourceListQuery<S>, options?: RequestOptions) => Promise<Page<R>>;
51
+ update: (id: string, input: U, options?: RequestOptions) => Promise<R>;
52
+ wait: (id: string, target: S, options?: ResourceWaitOptions) => Promise<R>;
53
+ delete: (id: string, options?: ResourceDeleteOptions) => Promise<R>;
54
+ };