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
@@ -0,0 +1,223 @@
1
+ import { CompatibilityError, only } from "../compat/core.js";
2
+ import { sseStream } from "./streams.js";
3
+ const FORMATS = {
4
+ text: "text/plain",
5
+ html: "text/html",
6
+ png: "image/png",
7
+ jpeg: "image/jpeg",
8
+ svg: "image/svg+xml",
9
+ latex: "text/latex",
10
+ markdown: "text/markdown",
11
+ javascript: "application/javascript",
12
+ json: "application/json",
13
+ };
14
+ /** One rich result, as Cloudflare's: each format by name, the MIME bundle in
15
+ * `data`. `chart` is never set on Runtime. */
16
+ export class Result {
17
+ text;
18
+ html;
19
+ png;
20
+ jpeg;
21
+ svg;
22
+ latex;
23
+ markdown;
24
+ javascript;
25
+ json;
26
+ chart;
27
+ data;
28
+ constructor(data) {
29
+ for (const [field, mime] of Object.entries(FORMATS))
30
+ if (data[mime] !== undefined)
31
+ this[field] = data[mime];
32
+ this.data = data;
33
+ }
34
+ formats() {
35
+ return Object.keys(FORMATS).filter((field) => this[field]);
36
+ }
37
+ }
38
+ export class Execution {
39
+ code;
40
+ context;
41
+ results = [];
42
+ logs = { stdout: [], stderr: [] };
43
+ error;
44
+ executionCount;
45
+ constructor(code, context) {
46
+ this.code = code;
47
+ this.context = context;
48
+ }
49
+ toJSON() {
50
+ return {
51
+ code: this.code,
52
+ logs: this.logs,
53
+ error: this.error,
54
+ executionCount: this.executionCount,
55
+ results: this.results.map((r) => ({
56
+ text: r.text,
57
+ html: r.html,
58
+ png: r.png,
59
+ jpeg: r.jpeg,
60
+ svg: r.svg,
61
+ latex: r.latex,
62
+ markdown: r.markdown,
63
+ javascript: r.javascript,
64
+ json: r.json,
65
+ chart: r.chart,
66
+ data: r.data,
67
+ })),
68
+ };
69
+ }
70
+ }
71
+ const context = (c) => ({
72
+ id: c.id,
73
+ language: c.language,
74
+ cwd: c.cwd,
75
+ createdAt: new Date(c.startedAt),
76
+ lastUsed: new Date(c.startedAt),
77
+ });
78
+ const failure = (e) => ({
79
+ name: e.name,
80
+ message: e.value,
81
+ traceback: e.traceback ? e.traceback.split("\n") : [],
82
+ });
83
+ /** A run that ended without the code's own error still tells the caller why. */
84
+ const ended = (run) => run.status === "timeout"
85
+ ? { name: "TimeoutError", message: "Execution timed out", traceback: [] }
86
+ : run.status === "interrupted" || run.status === "lost"
87
+ ? { name: "InterruptedError", message: `Execution ${run.status}`, traceback: [] }
88
+ : undefined;
89
+ const TEXT_MIME = /^text\/|json|javascript|svg|latex/;
90
+ export const RUN_ENV = "envVars on a run; set them when making the context with createCodeContext({ envVars })";
91
+ export const hasEnv = (env) => Object.values(env ?? {}).some((v) => v !== undefined);
92
+ function base64(bytes) {
93
+ let raw = "";
94
+ for (let i = 0; i < bytes.length; i += 32768)
95
+ raw += String.fromCharCode(...bytes.subarray(i, i + 32768));
96
+ return btoa(raw);
97
+ }
98
+ /** Cloudflare's code interpreter on Runtime's: Python, JavaScript and
99
+ * TypeScript contexts whose variables persist between runs. */
100
+ export class CodeInterpreter {
101
+ #native;
102
+ constructor(sandbox) {
103
+ this.#native = typeof sandbox === "function" ? sandbox : () => sandbox.native();
104
+ }
105
+ async createCodeContext(options = {}) {
106
+ only("Cloudflare createCodeContext", options, ["language", "cwd", "envVars", "timeout"]);
107
+ const language = this.#language(options.language);
108
+ const s = await this.#native();
109
+ return context(await s.interpreter.contexts.create({
110
+ language,
111
+ cwd: options.cwd ?? "/workspace",
112
+ env: Object.fromEntries(Object.entries(options.envVars ?? {}).filter((e) => e[1] !== undefined)),
113
+ }, options.timeout !== undefined ? { timeoutMs: options.timeout } : {}));
114
+ }
115
+ async runCode(code, options = {}) {
116
+ if (hasEnv(options.envVars))
117
+ throw new CompatibilityError("Cloudflare", RUN_ENV);
118
+ const { s, target } = await this.#prepare(options);
119
+ const execution = new Execution(code, target);
120
+ const run = await s.interpreter.run(code, {
121
+ context: target.id,
122
+ ...(options.timeout !== undefined ? { timeoutMs: options.timeout } : {}),
123
+ ...(options.signal ? { signal: options.signal } : {}),
124
+ onStdout: (text) => {
125
+ execution.logs.stdout.push(text);
126
+ return options.onStdout?.({ text, timestamp: Date.now() });
127
+ },
128
+ onStderr: (text) => {
129
+ execution.logs.stderr.push(text);
130
+ return options.onStderr?.({ text, timestamp: Date.now() });
131
+ },
132
+ onResult: async (raw) => {
133
+ const result = new Result(await this.#inline(s, raw));
134
+ execution.results.push(result);
135
+ return options.onResult?.(result);
136
+ },
137
+ onError: (raw) => {
138
+ execution.error = failure(raw);
139
+ return options.onError?.(execution.error);
140
+ },
141
+ });
142
+ execution.executionCount = run.executionCount ?? undefined;
143
+ if (!execution.error && ended(run)) {
144
+ execution.error = ended(run);
145
+ await options.onError?.(execution.error);
146
+ }
147
+ return execution;
148
+ }
149
+ /** The run as Cloudflare's container streams it: `data:` lines of stdout,
150
+ * stderr, result, error and execution_complete events. */
151
+ async runCodeStream(code, options = {}) {
152
+ if (hasEnv(options.envVars))
153
+ throw new CompatibilityError("Cloudflare", RUN_ENV);
154
+ const { s, target } = await this.#prepare(options);
155
+ return sseStream(async (send, cancelled) => {
156
+ const signal = options.signal ? AbortSignal.any([options.signal, cancelled]) : cancelled;
157
+ const run = await s.interpreter.run(code, {
158
+ context: target.id,
159
+ signal,
160
+ ...(options.timeout !== undefined ? { timeoutMs: options.timeout } : {}),
161
+ onStdout: (text) => send({ type: "stdout", text, timestamp: Date.now() }),
162
+ onStderr: (text) => send({ type: "stderr", text, timestamp: Date.now() }),
163
+ onResult: async (raw) => {
164
+ const { data: _data, ...fields } = new Result(await this.#inline(s, raw));
165
+ send({ type: "result", ...fields, data: raw.data, timestamp: Date.now() });
166
+ },
167
+ onError: (e) => send({ type: "error", ename: e.name, evalue: e.value, traceback: failure(e).traceback }),
168
+ });
169
+ const stop = ended(run);
170
+ if (run.error === null && stop)
171
+ send({ type: "error", ename: stop.name, evalue: stop.message, traceback: [] });
172
+ send({ type: "execution_complete", execution_count: run.executionCount });
173
+ });
174
+ }
175
+ async listCodeContexts() {
176
+ return (await (await this.#native()).interpreter.contexts.list()).map(context);
177
+ }
178
+ async deleteCodeContext(contextId) {
179
+ await (await this.#native()).interpreter.contexts.remove(contextId);
180
+ }
181
+ #language(language) {
182
+ if (language === undefined)
183
+ return "python";
184
+ if (!["python", "javascript", "typescript"].includes(language))
185
+ throw new Error(`Unsupported language: ${language}. Supported languages: python, javascript, typescript`);
186
+ return language;
187
+ }
188
+ async #prepare(options) {
189
+ only("Cloudflare runCode", options, [
190
+ "context",
191
+ "language",
192
+ "envVars",
193
+ "timeout",
194
+ "signal",
195
+ "onStdout",
196
+ "onStderr",
197
+ "onResult",
198
+ "onError",
199
+ ]);
200
+ const s = await this.#native();
201
+ // Each language's own name is Runtime's default context for it, started on first use.
202
+ const language = this.#language(options.context?.language ?? options.language);
203
+ const target = options.context ?? {
204
+ id: language,
205
+ language,
206
+ cwd: "/workspace",
207
+ createdAt: new Date(),
208
+ lastUsed: new Date(),
209
+ };
210
+ return { s, target };
211
+ }
212
+ /** Large results travel by reference; Cloudflare's arrive inline. */
213
+ async #inline(s, raw) {
214
+ const data = { ...raw.data };
215
+ for (const [mime, ref] of Object.entries(raw.refs ?? {})) {
216
+ if (data[mime] !== undefined)
217
+ continue;
218
+ const bytes = await s.interpreter.result(ref);
219
+ data[mime] = TEXT_MIME.test(mime) ? new TextDecoder().decode(bytes) : base64(bytes);
220
+ }
221
+ return data;
222
+ }
223
+ }
@@ -0,0 +1,38 @@
1
+ /** Cloudflare's stream helpers and type guards: the adapter's streams are
2
+ * server-sent events in Cloudflare's own shapes, so these read them as
3
+ * Cloudflare's do. */
4
+ export type FileMetadata = {
5
+ mimeType: string;
6
+ size: number;
7
+ isBinary: boolean;
8
+ encoding: "utf-8" | "base64";
9
+ };
10
+ export type FileChunk = string | Uint8Array;
11
+ export type FileStreamEvent = ({
12
+ type: "metadata";
13
+ } & FileMetadata) | {
14
+ type: "chunk";
15
+ data: string;
16
+ } | {
17
+ type: "complete";
18
+ bytesRead: number;
19
+ } | {
20
+ type: "error";
21
+ error: string;
22
+ };
23
+ /** One `data:` line per event, as Cloudflare's container sends them. */
24
+ export declare function sseStream<T>(events: (send: (event: T) => void, signal: AbortSignal) => Promise<void>): ReadableStream<Uint8Array>;
25
+ /** The events of a server-sent-events stream, each `data:` parsed as JSON;
26
+ * `[DONE]`, blank and unparsable data are skipped, as Cloudflare's do. */
27
+ export declare function parseSSEStream<T>(stream: ReadableStream<Uint8Array>, signal?: AbortSignal): AsyncIterable<T>;
28
+ /** A `readFileStream()` stream's chunks: strings for text, bytes for binary.
29
+ * Returns the file's metadata. */
30
+ export declare function streamFile(stream: ReadableStream<Uint8Array>): AsyncGenerator<FileChunk, FileMetadata>;
31
+ /** A whole `readFileStream()` file in memory, with its metadata. */
32
+ export declare function collectFile(stream: ReadableStream<Uint8Array>): Promise<{
33
+ content: string | Uint8Array;
34
+ metadata: FileMetadata;
35
+ }>;
36
+ export declare function isExecResult(value: unknown): boolean;
37
+ export declare function isProcess(value: unknown): boolean;
38
+ export declare function isProcessStatus(value: string): boolean;
@@ -0,0 +1,145 @@
1
+ /** Cloudflare's stream helpers and type guards: the adapter's streams are
2
+ * server-sent events in Cloudflare's own shapes, so these read them as
3
+ * Cloudflare's do. */
4
+ /** One `data:` line per event, as Cloudflare's container sends them. */
5
+ export function sseStream(events) {
6
+ const encode = new TextEncoder();
7
+ const cancelled = new AbortController();
8
+ return new ReadableStream({
9
+ async start(controller) {
10
+ try {
11
+ await events((event) => {
12
+ if (!cancelled.signal.aborted)
13
+ controller.enqueue(encode.encode(`data: ${JSON.stringify(event)}\n\n`));
14
+ }, cancelled.signal);
15
+ if (!cancelled.signal.aborted)
16
+ controller.close();
17
+ }
18
+ catch (error) {
19
+ if (!cancelled.signal.aborted)
20
+ controller.error(error);
21
+ }
22
+ },
23
+ cancel(reason) {
24
+ cancelled.abort(reason);
25
+ },
26
+ });
27
+ }
28
+ /** The events of a server-sent-events stream, each `data:` parsed as JSON;
29
+ * `[DONE]`, blank and unparsable data are skipped, as Cloudflare's do. */
30
+ export async function* parseSSEStream(stream, signal) {
31
+ const reader = stream.getReader();
32
+ const decoder = new TextDecoder();
33
+ let buffer = "";
34
+ let data = [];
35
+ const aborted = () => {
36
+ if (signal?.aborted)
37
+ throw new Error("Operation was aborted");
38
+ };
39
+ const onAbort = () => void reader.cancel().catch(() => undefined);
40
+ signal?.addEventListener("abort", onAbort);
41
+ const parse = function* (final) {
42
+ const lines = buffer.split(/\r?\n/);
43
+ buffer = final ? "" : lines.pop();
44
+ for (const line of lines) {
45
+ if (line === "") {
46
+ const text = data.join("\n");
47
+ data = [];
48
+ if (text.trim() === "" || text === "[DONE]")
49
+ continue;
50
+ try {
51
+ yield JSON.parse(text);
52
+ }
53
+ catch {
54
+ // Cloudflare skips data that is not JSON.
55
+ }
56
+ }
57
+ else if (line.startsWith("data:"))
58
+ data.push(line.slice(line[5] === " " ? 6 : 5));
59
+ }
60
+ };
61
+ try {
62
+ for (;;) {
63
+ aborted();
64
+ const { done, value } = await reader.read();
65
+ aborted();
66
+ if (done)
67
+ break;
68
+ buffer += decoder.decode(value, { stream: true });
69
+ yield* parse(false);
70
+ }
71
+ buffer += "\n\n";
72
+ yield* parse(true);
73
+ }
74
+ finally {
75
+ signal?.removeEventListener("abort", onAbort);
76
+ await reader.cancel().catch(() => undefined);
77
+ reader.releaseLock();
78
+ }
79
+ }
80
+ /** A `readFileStream()` stream's chunks: strings for text, bytes for binary.
81
+ * Returns the file's metadata. */
82
+ export async function* streamFile(stream) {
83
+ let metadata = null;
84
+ for await (const event of parseSSEStream(stream))
85
+ switch (event.type) {
86
+ case "metadata":
87
+ metadata = {
88
+ mimeType: event.mimeType,
89
+ size: event.size,
90
+ isBinary: event.isBinary,
91
+ encoding: event.encoding,
92
+ };
93
+ break;
94
+ case "chunk":
95
+ if (!metadata)
96
+ throw new Error("Received chunk before metadata");
97
+ yield metadata.isBinary && metadata.encoding === "base64"
98
+ ? Uint8Array.from(atob(event.data), (c) => c.charCodeAt(0))
99
+ : event.data;
100
+ break;
101
+ case "complete":
102
+ if (!metadata)
103
+ throw new Error("Stream completed without metadata");
104
+ return metadata;
105
+ case "error":
106
+ throw new Error(`File streaming error: ${event.error}`);
107
+ }
108
+ throw new Error("Stream ended unexpectedly");
109
+ }
110
+ /** A whole `readFileStream()` file in memory, with its metadata. */
111
+ export async function collectFile(stream) {
112
+ const chunks = [];
113
+ const reading = streamFile(stream);
114
+ let next = await reading.next();
115
+ while (!next.done) {
116
+ chunks.push(next.value);
117
+ next = await reading.next();
118
+ }
119
+ const metadata = next.value;
120
+ if (!metadata.isBinary)
121
+ return { content: chunks.filter((c) => typeof c === "string").join(""), metadata };
122
+ const bytes = chunks.filter((c) => c instanceof Uint8Array);
123
+ const content = new Uint8Array(bytes.reduce((sum, c) => sum + c.length, 0));
124
+ let offset = 0;
125
+ for (const chunk of bytes) {
126
+ content.set(chunk, offset);
127
+ offset += chunk.length;
128
+ }
129
+ return { content, metadata };
130
+ }
131
+ export function isExecResult(value) {
132
+ const v = value;
133
+ return (!!v &&
134
+ typeof v.success === "boolean" &&
135
+ typeof v.exitCode === "number" &&
136
+ typeof v.stdout === "string" &&
137
+ typeof v.stderr === "string");
138
+ }
139
+ export function isProcess(value) {
140
+ const v = value;
141
+ return (!!v && typeof v.id === "string" && typeof v.command === "string" && typeof v.status === "string");
142
+ }
143
+ export function isProcessStatus(value) {
144
+ return ["starting", "running", "completed", "failed", "killed", "error"].includes(value);
145
+ }
@@ -0,0 +1,9 @@
1
+ import type { WatchOptions } from "./index.js";
2
+ /** Cloudflare's watch filters: include or exclude, never both; by default
3
+ * .git, node_modules and .DS_Store are left out. */
4
+ export declare function watchFilters(options: WatchOptions): {
5
+ include?: string[];
6
+ exclude?: string[];
7
+ };
8
+ /** argv: path, recursive, include JSON, exclude JSON. Prints boot.digest. */
9
+ export declare const CHANGES = "import fnmatch,hashlib,json,os,sys\nroot,recursive,inc,exc=sys.argv[1],sys.argv[2]==\"1\",json.loads(sys.argv[3]),json.loads(sys.argv[4])\ndef hit(rel,pats): return any(fnmatch.fnmatch(rel,p) or fnmatch.fnmatch(os.path.basename(rel),p) or any(fnmatch.fnmatch(x,p) for x in rel.split(\"/\")) for p in pats)\nh=hashlib.sha256()\nfor d,dirs,files in os.walk(root):\n rel=os.path.relpath(d,root)\n dirs[:]=sorted(x for x in dirs if recursive and not hit(os.path.normpath(os.path.join(rel,x)),exc))\n for n in sorted(dirs+files):\n r=os.path.normpath(os.path.join(rel,n))\n if hit(r,exc) or (inc and n in files and not hit(r,inc)): continue\n try: st=os.lstat(os.path.join(d,n))\n except FileNotFoundError: continue\n h.update(f\"{r}\\0{st.st_size}\\0{st.st_mtime_ns}\\0{st.st_mode}\\n\".encode())\nprint(open(\"/proc/sys/kernel/random/boot_id\").read().strip().replace(\"-\",\"\")+\".\"+h.hexdigest())";
@@ -0,0 +1,24 @@
1
+ /** Cloudflare's watch filters: include or exclude, never both; by default
2
+ * .git, node_modules and .DS_Store are left out. */
3
+ export function watchFilters(options) {
4
+ if (options.include?.length && options.exclude?.length)
5
+ throw new Error("include and exclude cannot be used together");
6
+ if (options.include?.length)
7
+ return { include: options.include };
8
+ return { exclude: options.exclude ?? [".git", "node_modules", ".DS_Store"] };
9
+ }
10
+ /** argv: path, recursive, include JSON, exclude JSON. Prints boot.digest. */
11
+ export const CHANGES = `import fnmatch,hashlib,json,os,sys
12
+ root,recursive,inc,exc=sys.argv[1],sys.argv[2]=="1",json.loads(sys.argv[3]),json.loads(sys.argv[4])
13
+ def hit(rel,pats): return any(fnmatch.fnmatch(rel,p) or fnmatch.fnmatch(os.path.basename(rel),p) or any(fnmatch.fnmatch(x,p) for x in rel.split("/")) for p in pats)
14
+ h=hashlib.sha256()
15
+ for d,dirs,files in os.walk(root):
16
+ rel=os.path.relpath(d,root)
17
+ dirs[:]=sorted(x for x in dirs if recursive and not hit(os.path.normpath(os.path.join(rel,x)),exc))
18
+ for n in sorted(dirs+files):
19
+ r=os.path.normpath(os.path.join(rel,n))
20
+ if hit(r,exc) or (inc and n in files and not hit(r,inc)): continue
21
+ try: st=os.lstat(os.path.join(d,n))
22
+ except FileNotFoundError: continue
23
+ h.update(f"{r}\\0{st.st_size}\\0{st.st_mtime_ns}\\0{st.st_mode}\\n".encode())
24
+ print(open("/proc/sys/kernel/random/boot_id").read().strip().replace("-","")+"."+h.hexdigest())`;