withruntime 0.11.2 → 0.12.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 (164) 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 +9 -8
  6. package/README.src.md +8 -7
  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 +77 -1
  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 +14 -5
  17. package/dist/blaxel/sandbox.js +63 -7
  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/logs.test.d.ts +1 -0
  23. package/dist/cli/logs.test.js +272 -0
  24. package/dist/cli-extras.d.ts +3 -3
  25. package/dist/cli-extras.js +17 -12
  26. package/dist/cli-words.d.ts +10 -1
  27. package/dist/cli-words.js +18 -0
  28. package/dist/cli.d.ts +5 -1
  29. package/dist/cli.js +405 -204
  30. package/dist/client.d.ts +2 -4
  31. package/dist/client.js +27 -11
  32. package/dist/cloudflare/errors.d.ts +143 -0
  33. package/dist/cloudflare/errors.js +167 -0
  34. package/dist/cloudflare/index.d.ts +175 -6
  35. package/dist/cloudflare/index.js +416 -26
  36. package/dist/cloudflare/interpreter.d.ts +119 -0
  37. package/dist/cloudflare/interpreter.js +223 -0
  38. package/dist/cloudflare/streams.d.ts +38 -0
  39. package/dist/cloudflare/streams.js +145 -0
  40. package/dist/cloudflare/watch.d.ts +9 -0
  41. package/dist/cloudflare/watch.js +24 -0
  42. package/dist/codesandbox/index.d.ts +216 -28
  43. package/dist/codesandbox/index.js +478 -78
  44. package/dist/compat/core.d.ts +18 -0
  45. package/dist/compat/core.js +29 -0
  46. package/dist/compat/files.d.ts +1 -0
  47. package/dist/compat/files.js +25 -5
  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 +6 -0
  51. package/dist/daytona/daytona.js +30 -3
  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 +27 -21
  69. package/dist/e2b/sandbox.js +34 -8
  70. package/dist/e2b/unsupported.js +1 -1
  71. package/dist/errors.d.ts +10 -1
  72. package/dist/errors.js +16 -4
  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 +1 -0
  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 +12 -3
  87. package/dist/machine.js +20 -3
  88. package/dist/mcp.js +1 -1
  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/apps.d.ts +176 -0
  102. package/dist/products/apps.js +165 -0
  103. package/dist/products/billing.d.ts +41 -0
  104. package/dist/products/billing.js +13 -0
  105. package/dist/products/browser.d.ts +10 -0
  106. package/dist/products/browsers.d.ts +71 -0
  107. package/dist/products/browsers.js +102 -0
  108. package/dist/products/builds.d.ts +126 -0
  109. package/dist/products/builds.js +221 -0
  110. package/dist/products/index.d.ts +3 -16
  111. package/dist/products/index.js +3 -14
  112. package/dist/products/jobs.d.ts +17 -0
  113. package/dist/products/jobs.js +27 -10
  114. package/dist/products/logs.d.ts +245 -0
  115. package/dist/products/logs.js +274 -0
  116. package/dist/products/logs.test.d.ts +1 -0
  117. package/dist/products/logs.test.js +343 -0
  118. package/dist/products/network-products.d.ts +38 -7
  119. package/dist/products/network-products.js +31 -18
  120. package/dist/products/observability.d.ts +3 -2
  121. package/dist/products/private-network.js +1 -1
  122. package/dist/products/queues.d.ts +149 -0
  123. package/dist/products/queues.js +213 -0
  124. package/dist/products/referrals.d.ts +21 -7
  125. package/dist/products/referrals.js +3 -3
  126. package/dist/products/secrets.d.ts +7 -3
  127. package/dist/products/secrets.js +39 -18
  128. package/dist/products/signed-requests.d.ts +21 -0
  129. package/dist/products/signed-requests.js +11 -0
  130. package/dist/products/streams.d.ts +73 -0
  131. package/dist/products/streams.js +17 -0
  132. package/dist/products/switching.d.ts +35 -7
  133. package/dist/products/switching.js +4 -3
  134. package/dist/products/volumes.d.ts +3 -0
  135. package/dist/record-cli.d.ts +23 -0
  136. package/dist/record-cli.js +308 -0
  137. package/dist/renamed-products.d.ts +38 -0
  138. package/dist/renamed-products.js +34 -0
  139. package/dist/runloop/index.d.ts +9 -2
  140. package/dist/runloop/index.js +29 -8
  141. package/dist/runloop/sdk.d.ts +131 -0
  142. package/dist/runloop/sdk.js +167 -0
  143. package/dist/sandbox.d.ts +3 -2
  144. package/dist/sandbox.js +14 -9
  145. package/dist/sandboxes/index.d.ts +11 -0
  146. package/dist/sandboxes/index.js +12 -0
  147. package/dist/snapshots/index.d.ts +9 -0
  148. package/dist/snapshots/index.js +11 -0
  149. package/dist/snapshots.d.ts +7 -4
  150. package/dist/sprites/index.d.ts +343 -31
  151. package/dist/sprites/index.js +866 -84
  152. package/dist/ssh.d.ts +1 -1
  153. package/dist/ssh.js +11 -11
  154. package/dist/terminal.d.ts +24 -0
  155. package/dist/terminal.js +32 -0
  156. package/dist/transport.d.ts +15 -1
  157. package/dist/transport.js +56 -3
  158. package/dist/tunnel.js +1 -1
  159. package/dist/types.d.ts +63 -0
  160. package/dist/vercel/sandbox.js +5 -3
  161. package/dist/vercel/snapshot.js +10 -2
  162. package/dist/volumes/index.d.ts +9 -0
  163. package/dist/volumes/index.js +10 -0
  164. package/package.json +48 -2
@@ -9,7 +9,7 @@ export type SwitchProvider = "e2b" | "daytona" | "vercel" | "modal" | "cloudflar
9
9
  export type SwitchingSummary = {
10
10
  /** False while the programme is paused. */
11
11
  enabled: boolean;
12
- /** The most a first top-up is matched to. */
12
+ /** The most the organization's payments are matched to, in total. */
13
13
  maxMicros: string;
14
14
  providers: SwitchProvider[];
15
15
  /** Whether this organization can record a switch now: none recorded, and
@@ -17,14 +17,41 @@ export type SwitchingSummary = {
17
17
  eligible: boolean;
18
18
  switch: {
19
19
  provider: SwitchProvider;
20
- /** superseded: a referral matched the first top-up instead, which is
20
+ /** superseded: a referral matches the payments instead, which is
21
21
  * never less. The two are never both paid. */
22
22
  status: "pending" | "paid" | "superseded" | "refused" | "reversed";
23
- refusedReason: "program_off" | "suspended" | "same_card" | "fraud" | null;
23
+ refusedReason: "program_off" | "suspended" | "same_card" | "fraud" | "too_late" | null;
24
24
  recordedAt: string;
25
- /** The switching credit this organization got and kept. */
25
+ /** The matches this organization got and kept. */
26
26
  creditMicros: string;
27
27
  } | null;
28
+ /** The welcome match: credit an organization adds within 30 days of
29
+ * signing up is matched, up to $1,000 in total. */
30
+ welcome: WelcomeMatch;
31
+ };
32
+ export type WelcomeMatch = {
33
+ /** False while the match is paused. */
34
+ enabled: boolean;
35
+ /** The most the organization's payments are matched to, in total. */
36
+ maxMicros: string;
37
+ /** When the offer ends: 30 days after the organization signed up. */
38
+ endsAt: string;
39
+ /** Whether credit added now would be matched: some is left, before endsAt. */
40
+ eligible: boolean;
41
+ /** Whether credit has been added. */
42
+ toppedUp: boolean;
43
+ /** Null until a payment is decided; paid while a match is kept.
44
+ * superseded: a referral matches the payments instead, which is never
45
+ * less. */
46
+ status: "pending" | "paid" | "superseded" | "refused" | "reversed" | null;
47
+ /** The matches this organization got and kept. */
48
+ creditMicros: string;
49
+ /** The part of maxMicros used so far. Absent from a server before
50
+ * 8 October 2026. */
51
+ usedMicros?: string;
52
+ /** What credit added now could still get; "0" once the offer ends. Absent
53
+ * from a server before 8 October 2026. */
54
+ leftMicros?: string;
28
55
  };
29
56
  export type UsageComparison = {
30
57
  provider: CompareProvider;
@@ -76,8 +103,9 @@ export type UsageComparison = {
76
103
  switching: SwitchingSummary;
77
104
  };
78
105
  /** `runtime.switching`: compare your usage with a rival's published rates,
79
- * and record the rival you are leaving so your first top-up is matched, up to
80
- * $100, once the payment settles. */
106
+ * record the rival you are leaving, and read the welcome match: credit added
107
+ * within 30 days of signing up is matched, up to $1,000 in total, as each
108
+ * payment settles. */
81
109
  export declare function switching(t: Transport): {
82
110
  /** Your settled sandbox usage over the last `days` (default 30, at most
83
111
  * 90), priced on Runtime and at the rival, with the saving. */
@@ -85,7 +113,7 @@ export declare function switching(t: Transport): {
85
113
  provider: CompareProvider;
86
114
  days?: number;
87
115
  }, options?: RequestOptions) => Promise<UsageComparison>;
88
- /** Whether a switch can still be recorded, and what it paid. */
116
+ /** Whether a switch can still be recorded, and what the welcome match paid. */
89
117
  get: (options?: RequestOptions) => Promise<SwitchingSummary>;
90
118
  /** Once per organization, before its first top-up. Recording the same
91
119
  * provider again answers the same summary; another fails with 409. */
@@ -1,6 +1,7 @@
1
1
  /** `runtime.switching`: compare your usage with a rival's published rates,
2
- * and record the rival you are leaving so your first top-up is matched, up to
3
- * $100, once the payment settles. */
2
+ * record the rival you are leaving, and read the welcome match: credit added
3
+ * within 30 days of signing up is matched, up to $1,000 in total, as each
4
+ * payment settles. */
4
5
  export function switching(t) {
5
6
  return {
6
7
  /** Your settled sandbox usage over the last `days` (default 30, at most
@@ -11,7 +12,7 @@ export function switching(t) {
11
12
  query: { provider: input.provider, days: input.days },
12
13
  ...options,
13
14
  }),
14
- /** Whether a switch can still be recorded, and what it paid. */
15
+ /** Whether a switch can still be recorded, and what the welcome match paid. */
15
16
  get: (options) => t.json({ method: "GET", path: "/v1/switching", ...options }),
16
17
  /** Once per organization, before its first top-up. Recording the same
17
18
  * provider again answers the same summary; another fails with 409. */
@@ -86,6 +86,9 @@ export type VolumeBackup = {
86
86
  storedBytes: number | null;
87
87
  meteredBytes: number | null;
88
88
  error: string | null;
89
+ /** Why it failed, when a code says it: `backup_stalled` when its copy off
90
+ * the host never began; back it up again. */
91
+ errorCode?: string | null;
89
92
  createdAt: string;
90
93
  readyAt: string | null;
91
94
  expiresAt: string;
@@ -0,0 +1,23 @@
1
+ import type { queues } from "./products/queues.js";
2
+ import type { streams } from "./products/streams.js";
3
+ /** Private until launch. CLOUD.md section 4. cli.ts does not call this module. */
4
+ export declare const RECORD_PRODUCTS: readonly ["queue", "stream"];
5
+ export type RecordProduct = (typeof RECORD_PRODUCTS)[number];
6
+ export type RecordClient = {
7
+ queues: ReturnType<typeof queues>;
8
+ streams: ReturnType<typeof streams>;
9
+ };
10
+ type Args = {
11
+ positional: string[];
12
+ flags: Map<string, string[]>;
13
+ rest?: string[];
14
+ };
15
+ type Out = {
16
+ json: boolean;
17
+ write(text: string): void;
18
+ error(text: string): void;
19
+ };
20
+ export declare const RECORD_HELP: Record<RecordProduct, string>;
21
+ /** Parsed like networkProductCommand; never obtains credentials for help or bad flags. */
22
+ export declare function recordCommand(product: RecordProduct, args: Args, out: Out, client: () => Promise<RecordClient>, signal?: AbortSignal): Promise<number>;
23
+ export {};
@@ -0,0 +1,308 @@
1
+ import { spawn } from "node:child_process";
2
+ import { RuntimeError } from "./errors.js";
3
+ import { named } from "./cli-name.js";
4
+ /** Private until launch. CLOUD.md section 4. cli.ts does not call this module. */
5
+ export const RECORD_PRODUCTS = ["queue", "stream"];
6
+ export const RECORD_HELP = {
7
+ queue: `runtime queue <command> (private until launch)
8
+ create --name work [--input '{"settings":{"fifo":false}}']
9
+ get <id> | list [--input '{"limit":10}']
10
+ update <id> --input '{"labels":{"team":"orders"}}'
11
+ delete <id> | purge <id>
12
+ send <id> --input '{"body":"hello"}'
13
+ receive <id> [--input '{"max":1,"waitSeconds":20}']
14
+ consume <id> --exec '<command>' [--max 1] [--wait-seconds 20]
15
+ [--visibility-seconds 30] Body on stdin; exit 0 acknowledges.
16
+ A failure releases the message immediately. max counts attempts, including
17
+ failures. Omit max to run until Ctrl-C. Cancellation releases known receipts.
18
+ --timeout-ms bounds each network call (default 30000); settlement can finish
19
+ after cancellation. Set visibility longer than processing; repeats are possible.
20
+ Consume makes a key per operation; --idempotency-key does not apply.
21
+ ack <id> --input '{"receiptHandles":["receipt"]}'
22
+ retry <id> --input '{"receiptHandle":"receipt","visibilitySeconds":0}'
23
+ wait <id> [--state ready|deleted] [--poll-ms 250]
24
+ Every call: --idempotency-key <key> --timeout-ms <ms>; use --json for JSON.
25
+ Retry a lost reply with the same key and input. Receives also need that key.
26
+ Settings: visibilityTimeoutSeconds, retentionSeconds, maxMessageBytes,
27
+ delaySeconds, fifo, deadLetter {queue,maxReceives}. At most 32 labels.
28
+ Send: body, attributes, delaySeconds, groupId, dedupId. Receive: max 1-10,
29
+ waitSeconds 0-20, visibilitySeconds. get returns the SQS URL.
30
+ `,
31
+ stream: `runtime stream <command> (private until launch)
32
+ create --name events [--input '{"partitions":1}']
33
+ get <id> | list [--input '{"limit":10}']
34
+ update <id> --input '{"retentionMs":86400000}' | delete <id>
35
+ publish <id> --input '{"records":[{"key":"order","value":"hello","headers":[]}]}'
36
+ read <id> --input '{"partition":0,"offset":"0","maxBytes":1048576,"waitMs":0}'
37
+ trim <id> --input '{"partition":0,"before":"100"}'
38
+ wait <id> [--state ready|deleted] [--poll-ms 250]
39
+ Every call: --idempotency-key <key> --timeout-ms <ms>; use --json for JSON.
40
+ Retry a lost reply with the same key and input. Offsets and retentionBytes
41
+ are decimal strings. Read takes offset OR time (Unix milliseconds).
42
+ get returns the Kafka bootstrap address and topic. At most 32 labels.
43
+ `,
44
+ };
45
+ function usage(product, message) {
46
+ throw new RuntimeError({
47
+ code: "usage",
48
+ status: 0,
49
+ message,
50
+ hint: `Run \`${named("runtime")} ${product} help\`.`,
51
+ });
52
+ }
53
+ /** Parsed like networkProductCommand; never obtains credentials for help or bad flags. */
54
+ export async function recordCommand(product, args, out, client, signal) {
55
+ if (args.rest?.length)
56
+ usage(product, "This command takes no arguments after --.");
57
+ const [given = "help", id, ...extra] = args.positional;
58
+ const verb = given === "ls" ? "list" : given === "rm" ? "delete" : given;
59
+ const actions = product === "queue"
60
+ ? ["send", "receive", "ack", "retry", "purge", "consume"]
61
+ : ["publish", "read", "trim"];
62
+ if (!["help", "create", "get", "list", "update", "delete", "wait", ...actions].includes(verb))
63
+ usage(product, `Unknown command ${given}.`);
64
+ const hasInput = [
65
+ "create",
66
+ "list",
67
+ "update",
68
+ "send",
69
+ "receive",
70
+ "ack",
71
+ "retry",
72
+ "publish",
73
+ "read",
74
+ "trim",
75
+ ].includes(verb);
76
+ const allowed = new Set([
77
+ ...(verb === "consume" ? [] : ["idempotency-key"]),
78
+ "timeout-ms",
79
+ ...(hasInput ? ["input"] : []),
80
+ ...(verb === "create" ? ["name"] : []),
81
+ ...(verb === "wait" ? ["state", "poll-ms"] : []),
82
+ ...(verb === "consume" ? ["exec", "max", "wait-seconds", "visibility-seconds"] : []),
83
+ ]);
84
+ for (const [flag, values] of args.flags) {
85
+ if (!allowed.has(flag))
86
+ usage(product, `Unknown option --${flag} for ${verb}.`);
87
+ if (values.length !== 1 || !values[0])
88
+ usage(product, `Give --${flag} exactly once with a value.`);
89
+ }
90
+ if (extra.length || (["help", "create", "list"].includes(verb) && id))
91
+ usage(product, "Unexpected positional argument.");
92
+ if (verb === "help") {
93
+ out.write(named(RECORD_HELP[product]));
94
+ return 0;
95
+ }
96
+ if (!["create", "list"].includes(verb) && !id)
97
+ usage(product, "Give the resource id.");
98
+ const flag = (key) => args.flags.get(key)?.[0];
99
+ const number = (key) => {
100
+ const text = flag(key);
101
+ if (text === undefined)
102
+ return undefined;
103
+ const value = Number(text);
104
+ if (!/^\d+$/.test(text) || !Number.isSafeInteger(value))
105
+ usage(product, `--${key} needs a nonnegative safe integer.`);
106
+ return value;
107
+ };
108
+ let input = {};
109
+ if (flag("input") !== undefined) {
110
+ try {
111
+ input = JSON.parse(flag("input"));
112
+ }
113
+ catch {
114
+ usage(product, "--input needs a JSON object.");
115
+ }
116
+ if (!input || Array.isArray(input) || typeof input !== "object")
117
+ usage(product, "--input needs a JSON object.");
118
+ }
119
+ if (flag("name")) {
120
+ if (Object.hasOwn(input, "name"))
121
+ usage(product, "Give name in --name or --input, not both.");
122
+ input.name = flag("name");
123
+ }
124
+ if (verb === "create" && (typeof input.name !== "string" || !input.name.trim()))
125
+ usage(product, "Give a name with --name or --input.");
126
+ if (["update", "send", "ack", "retry", "publish", "read", "trim"].includes(verb) &&
127
+ !flag("input"))
128
+ usage(product, `${verb} needs --input.`);
129
+ const state = flag("state") ?? "ready";
130
+ if (verb === "wait" && state !== "ready" && state !== "deleted")
131
+ usage(product, "--state must be ready or deleted.");
132
+ const timeoutMs = number("timeout-ms");
133
+ const pollMs = number("poll-ms");
134
+ const options = {
135
+ idempotencyKey: flag("idempotency-key") ?? crypto.randomUUID(),
136
+ ...(timeoutMs === undefined ? {} : { timeoutMs }),
137
+ };
138
+ const consumeOptions = verb === "consume"
139
+ ? {
140
+ ...(number("max") === undefined ? {} : { max: number("max") }),
141
+ ...(number("wait-seconds") === undefined ? {} : { waitSeconds: number("wait-seconds") }),
142
+ ...(number("visibility-seconds") === undefined
143
+ ? {}
144
+ : { visibilitySeconds: number("visibility-seconds") }),
145
+ ...(timeoutMs === undefined ? {} : { timeoutMs }),
146
+ }
147
+ : {};
148
+ if (verb === "consume") {
149
+ if (!flag("exec")?.trim())
150
+ usage(product, "consume needs --exec with a command.");
151
+ if ((consumeOptions.waitSeconds ?? 20) > 20)
152
+ usage(product, "--wait-seconds must be 0 to 20.");
153
+ if ((consumeOptions.visibilitySeconds ?? 30) > 43_200)
154
+ usage(product, "--visibility-seconds must be 0 to 43200.");
155
+ if (timeoutMs !== undefined && (timeoutMs < 1 || timeoutMs > 2_147_483_647))
156
+ usage(product, "consume --timeout-ms must be 1 to 2147483647.");
157
+ }
158
+ const api = await client();
159
+ const resource = product === "queue" ? api.queues : api.streams;
160
+ let result;
161
+ switch (verb) {
162
+ case "consume": {
163
+ const stopped = new AbortController();
164
+ const interrupt = () => stopped.abort();
165
+ const combined = signal ? AbortSignal.any([signal, stopped.signal]) : stopped.signal;
166
+ process.on("SIGINT", interrupt);
167
+ process.on("SIGTERM", interrupt);
168
+ try {
169
+ const consumed = await api.queues.consume(id, (message, running) => executeMessage(flag("exec"), message.body, running, out), { ...consumeOptions, signal: combined });
170
+ out.write(JSON.stringify(consumed, null, out.json ? undefined : 2));
171
+ return consumed.aborted ? 130 : consumed.retried ? 1 : 0;
172
+ }
173
+ finally {
174
+ process.removeListener("SIGINT", interrupt);
175
+ process.removeListener("SIGTERM", interrupt);
176
+ }
177
+ }
178
+ case "create":
179
+ result =
180
+ product === "queue"
181
+ ? await api.queues.create(input, options)
182
+ : await api.streams.create(input, options);
183
+ break;
184
+ case "update":
185
+ result =
186
+ product === "queue"
187
+ ? await api.queues.update(id, input, options)
188
+ : await api.streams.update(id, input, options);
189
+ break;
190
+ case "list":
191
+ result = await resource.list(input, options);
192
+ break;
193
+ case "get":
194
+ result = await resource.get(id, options);
195
+ break;
196
+ case "delete":
197
+ result = await resource.delete(id, options);
198
+ break;
199
+ case "wait":
200
+ result = await resource.wait(id, state, {
201
+ ...options,
202
+ ...(pollMs === undefined ? {} : { pollMs }),
203
+ });
204
+ break;
205
+ case "send":
206
+ result = await api.queues.send(id, input, options);
207
+ break;
208
+ case "receive":
209
+ result = await api.queues.receive(id, input, options);
210
+ break;
211
+ case "ack": {
212
+ const receipts = await api.queues.ack(id, input, options);
213
+ if (receipts.failed.length)
214
+ throw new RuntimeError({
215
+ code: receipts.failed[0].code,
216
+ status: 0,
217
+ message: receipts.failed[0].message,
218
+ hint: receipts.failed[0].hint,
219
+ details: { ...receipts },
220
+ idempotencyKey: options.idempotencyKey,
221
+ });
222
+ result = receipts;
223
+ break;
224
+ }
225
+ case "retry":
226
+ result = await api.queues.retry(id, input, options);
227
+ break;
228
+ case "purge":
229
+ result = await api.queues.purge(id, options);
230
+ break;
231
+ case "publish":
232
+ result = await api.streams.publish(id, input, options);
233
+ break;
234
+ case "read":
235
+ result = await api.streams.read(id, input, options);
236
+ break;
237
+ case "trim":
238
+ result = await api.streams.trim(id, input, options);
239
+ break;
240
+ }
241
+ // Include cursors, receipt failures and endpoint settings in either output mode.
242
+ out.write(JSON.stringify(result, null, out.json ? undefined : 2));
243
+ return 0;
244
+ }
245
+ /** Only the requested command is shell code. Message bytes go through stdin.
246
+ * Output goes to stderr so stdout keeps the CLI's JSON result parseable. */
247
+ function executeMessage(command, body, signal, out) {
248
+ return new Promise((resolve, reject) => {
249
+ const failed = (message) => new RuntimeError({
250
+ code: "command_failed",
251
+ status: 0,
252
+ message,
253
+ hint: "Fix the consumer command; the message will be made visible again.",
254
+ });
255
+ if (signal.aborted) {
256
+ reject(failed("Consumer command cancelled."));
257
+ return;
258
+ }
259
+ const grouped = process.platform !== "win32";
260
+ const child = spawn(command, {
261
+ shell: true,
262
+ detached: grouped,
263
+ stdio: ["pipe", "pipe", "pipe"],
264
+ });
265
+ const abort = () => {
266
+ if (grouped && child.pid) {
267
+ try {
268
+ process.kill(-child.pid, "SIGKILL");
269
+ }
270
+ catch (error) {
271
+ if (error.code !== "ESRCH")
272
+ child.kill("SIGKILL");
273
+ }
274
+ }
275
+ else
276
+ child.kill("SIGKILL");
277
+ };
278
+ signal.addEventListener("abort", abort, { once: true });
279
+ if (signal.aborted)
280
+ abort();
281
+ child.stdout.on("data", (bytes) => out.error(bytes.toString("utf8")));
282
+ child.stderr.on("data", (bytes) => out.error(bytes.toString("utf8")));
283
+ let inputError;
284
+ child.stdin.on("error", (error) => {
285
+ if (error.code !== "EPIPE") {
286
+ inputError = error;
287
+ abort();
288
+ }
289
+ });
290
+ child.once("error", (error) => {
291
+ signal.removeEventListener("abort", abort);
292
+ const failure = failed(`Consumer could not start: ${error.message}`);
293
+ out.error(`${failure.code}: ${failure.message} ${failure.hint}`);
294
+ reject(failure);
295
+ });
296
+ child.once("close", (code, killed) => {
297
+ signal.removeEventListener("abort", abort);
298
+ if (code === 0 && !signal.aborted && !inputError) {
299
+ resolve();
300
+ return;
301
+ }
302
+ const failure = failed(inputError?.message ?? `Consumer exited ${code ?? killed ?? "without a status"}.`);
303
+ out.error(`${failure.code}: ${failure.message} ${failure.hint}`);
304
+ reject(failure);
305
+ });
306
+ child.stdin.end(body);
307
+ });
308
+ }
@@ -0,0 +1,38 @@
1
+ import { type ProductName } from "./product-names.js";
2
+ import type { Sandboxes } from "./client.js";
3
+ import type { Snapshots } from "./snapshots.js";
4
+ import type { ClientExtensions } from "./products/index.js";
5
+ /** The client's properties under their old words, each the product it became. */
6
+ export type RenamedProducts = {
7
+ /** @deprecated Renamed `runtime.sandboxes`; works for 30 days after the rename, with a warning. */
8
+ readonly sandbox: Sandboxes;
9
+ /** @deprecated Renamed `runtime.snapshots`; works for 30 days after the rename, with a warning. */
10
+ readonly snapshot: Snapshots;
11
+ /** @deprecated Renamed `runtime.images`; works for 30 days after the rename, with a warning. */
12
+ readonly image: ClientExtensions["images"];
13
+ /** @deprecated Renamed `runtime.volumes`; works for 30 days after the rename, with a warning. */
14
+ readonly volume: ClientExtensions["volumes"];
15
+ /** @deprecated Renamed `runtime.jobs`; works for 30 days after the rename, with a warning. */
16
+ readonly job: ClientExtensions["jobs"];
17
+ /** @deprecated Renamed `runtime.domains`; works for 30 days after the rename, with a warning. */
18
+ readonly domain: ClientExtensions["domains"];
19
+ /** @deprecated Renamed `runtime.ports`; works for 30 days after the rename, with a warning. */
20
+ readonly port: ClientExtensions["ports"];
21
+ /** @deprecated Renamed `runtime.ips`; works for 30 days after the rename, with a warning. */
22
+ readonly address: ClientExtensions["ips"];
23
+ /** @deprecated Renamed `runtime.ips`; works for 30 days after the rename, with a warning. */
24
+ readonly addresses: ClientExtensions["ips"];
25
+ /** @deprecated Renamed `runtime.networks`; works for 30 days after the rename, with a warning. */
26
+ readonly network: ClientExtensions["networks"];
27
+ /** @deprecated Renamed `runtime.networks.wireguard`; works for 30 days after the rename, with a warning. */
28
+ readonly tunnel: ClientExtensions["networks"]["wireguard"];
29
+ };
30
+ /** Puts each old word on `client` as a property that answers the product it
31
+ * became and says so once per process, or, from the table's date, throws
32
+ * name_retired with a hint naming the new property. An old word the client
33
+ * already uses for something else is left alone. */
34
+ export declare function installRenamedProducts(client: object, options?: {
35
+ now?: () => Date;
36
+ table?: readonly ProductName[];
37
+ say?: (line: string) => void;
38
+ }): void;
@@ -0,0 +1,34 @@
1
+ import { RuntimeError } from "./errors.js";
2
+ import { PRODUCT_NAMES, wordOf } from "./product-names.js";
3
+ import { resolveWord, sdkPath } from "./product-renames.js";
4
+ const said = new Set();
5
+ /** Puts each old word on `client` as a property that answers the product it
6
+ * became and says so once per process, or, from the table's date, throws
7
+ * name_retired with a hint naming the new property. An old word the client
8
+ * already uses for something else is left alone. */
9
+ export function installRenamedProducts(client, options = {}) {
10
+ const table = options.table ?? PRODUCT_NAMES;
11
+ for (const product of table) {
12
+ for (const old of product.old) {
13
+ const [property] = sdkPath(wordOf(old.name));
14
+ if (property === undefined || property in client)
15
+ continue;
16
+ Object.defineProperty(client, property, {
17
+ configurable: true,
18
+ enumerable: false,
19
+ get() {
20
+ const use = resolveWord(old.name, "sdk", options.now?.() ?? new Date(), table);
21
+ if (use === undefined || use.kind === "current")
22
+ return undefined;
23
+ if (use.kind === "retired")
24
+ throw new RuntimeError({ ...use.error });
25
+ if (!said.has(use.warning)) {
26
+ said.add(use.warning);
27
+ (options.say ?? console.warn)(`Runtime: ${use.warning}`);
28
+ }
29
+ return sdkPath(use.to).reduce((at, key) => at[key], client);
30
+ },
31
+ });
32
+ }
33
+ }
34
+ }
@@ -1,4 +1,5 @@
1
1
  import { PagePromise, DevboxViewsCursorIDPage } from "./pagination.js";
2
+ export { RunloopSDK, Devbox, Execution, ExecutionResult, RunloopError } from "./sdk.js";
2
3
  import type { Runtime } from "../client.js";
3
4
  import { Sandbox } from "../sandbox.js";
4
5
  import { DiskSnapshots, type DevboxSnapshotDiskParams, type DevboxSnapshotView, type DiskSnapshotListParams } from "./snapshots.js";
@@ -101,6 +102,12 @@ export interface DevboxListParams {
101
102
  }
102
103
  export declare class Runloop {
103
104
  readonly devboxes: Devboxes;
105
+ get secrets(): never;
106
+ get objects(): never;
107
+ get axons(): never;
108
+ get gatewayConfigs(): never;
109
+ get mcpConfigs(): never;
110
+ get networkPolicies(): never;
104
111
  constructor(options?: ClientOptions & {
105
112
  bearerToken?: string;
106
113
  baseURL?: string;
@@ -302,10 +309,10 @@ export declare class Executions {
302
309
  kill(id: string, execution: string, body?: {
303
310
  kill_process_group?: boolean | null;
304
311
  } | RequestOptions, options?: RequestOptions): Promise<DevboxAsyncExecutionDetailView>;
305
- sendStdIn(id: string, execution: string, body?: {
312
+ sendStdIn(id: string, execution: string, body: {
306
313
  text?: string | null;
307
314
  signal?: "EOF" | "INTERRUPT" | null;
308
- } | RequestOptions, options?: RequestOptions): Promise<{
315
+ }, options?: RequestOptions): Promise<{
309
316
  devbox_id: string;
310
317
  execution_id: string;
311
318
  success: boolean;
@@ -1,5 +1,7 @@
1
1
  import { PagePromise, DevboxViewsCursorIDPage } from "./pagination.js";
2
+ export { RunloopSDK, Devbox, Execution, ExecutionResult, RunloopError } from "./sdk.js";
2
3
  import { Sandbox } from "../sandbox.js";
4
+ import { timeoutSignal } from "../transport.js";
3
5
  import { DiskSnapshots, requestOptions, snapshotOptions, snapshotView, nativeOptions, } from "./snapshots.js";
4
6
  export { DiskSnapshots, } from "./snapshots.js";
5
7
  export { PagePromise, DevboxSnapshotViewsDiskSnapshotsCursorIDPage, DevboxViewsCursorIDPage, } from "./pagination.js";
@@ -82,6 +84,24 @@ function view(sandbox) {
82
84
  }
83
85
  export class Runloop {
84
86
  devboxes;
87
+ get secrets() {
88
+ throw new CompatibilityError("Runloop", "duplicate-name secret rows and secret-ID handles; use the Runtime secrets API");
89
+ }
90
+ get objects() {
91
+ throw new CompatibilityError("Runloop", "signed storage-object uploads; use Runtime sandbox files");
92
+ }
93
+ get axons() {
94
+ throw new CompatibilityError("Runloop", "Axon registries and deleted event records; use the Runtime events API");
95
+ }
96
+ get gatewayConfigs() {
97
+ throw new CompatibilityError("Runloop", "named gateway bindings; use the Runtime secrets API with direct service requests");
98
+ }
99
+ get mcpConfigs() {
100
+ throw new CompatibilityError("Runloop", "named MCP grants; use the Runtime secrets API with your MCP client");
101
+ }
102
+ get networkPolicies() {
103
+ throw new CompatibilityError("Runloop", "reusable named network-policy bindings; use Runtime sandbox egress settings");
104
+ }
85
105
  constructor(options = {}) {
86
106
  const { bearerToken, baseURL, ...rest } = options;
87
107
  this.devboxes = new Devboxes(client({ ...rest, apiKey: rest.apiKey ?? bearerToken, baseUrl: rest.baseUrl ?? baseURL }));
@@ -217,7 +237,7 @@ export class Devboxes {
217
237
  throw new Error("timeoutMs must be positive");
218
238
  if (options.signal?.aborted)
219
239
  throw new LongPollAbortError("Long poll aborted", undefined);
220
- const deadline = timeoutMs === undefined ? undefined : AbortSignal.timeout(timeoutMs);
240
+ const deadline = timeoutMs === undefined ? undefined : timeoutSignal(timeoutMs);
221
241
  const signal = deadline && options.signal
222
242
  ? AbortSignal.any([deadline, options.signal])
223
243
  : (deadline ?? options.signal);
@@ -484,21 +504,22 @@ export class Executions {
484
504
  await (await (await lookup(this.runtime, id, nativeOptions(options))).processes.get(execution, nativeOptions(options))).kill("SIGKILL", nativeOptions(options));
485
505
  return this.retrieve(id, execution, {}, options);
486
506
  }
487
- async sendStdIn(id, execution, body = {}, options = {}) {
488
- if (requestOptions(body) &&
489
- (body.signal === undefined || (typeof body.signal === "object" && body.signal !== null)))
490
- return this.sendStdIn(id, execution, {}, body);
507
+ async sendStdIn(id, execution, body, options = {}) {
491
508
  options.signal?.throwIfAborted();
509
+ if (!body || typeof body !== "object" || Array.isArray(body))
510
+ throw new TypeError("Runloop stdin requires a body with nonempty text or a signal");
492
511
  only("Runloop stdin", body, ["text", "signal"]);
493
- const text = "text" in body ? body.text : undefined;
512
+ const text = body.text;
494
513
  const bodySignal = body.signal;
495
- if (text !== undefined && text !== null && typeof text !== "string")
496
- throw new TypeError("Runloop stdin text must be a string");
514
+ if (text !== undefined && text !== null && (typeof text !== "string" || text.length === 0))
515
+ throw new TypeError("Runloop stdin text must be a nonempty string");
497
516
  if (bodySignal !== undefined &&
498
517
  bodySignal !== null &&
499
518
  bodySignal !== "EOF" &&
500
519
  bodySignal !== "INTERRUPT")
501
520
  throw new TypeError("Runloop stdin signal must be EOF or INTERRUPT");
521
+ if ((text != null) === (bodySignal != null))
522
+ throw new TypeError("Runloop stdin requires exactly one of nonempty text or a signal");
502
523
  if (options.idempotencyKey !== undefined && (text || bodySignal === "EOF"))
503
524
  throw new CompatibilityError("Runloop", "caller idempotency keys for process input; native offsets protect transport retries");
504
525
  const p = await (await lookup(this.runtime, id, nativeOptions(options))).processes.get(execution, nativeOptions(options));