@cybernetyx1/atlasflow-runtime 0.1.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.
- package/LICENSE +18 -0
- package/README.md +56 -0
- package/dist/adapter/index.d.ts +1 -0
- package/dist/adapter/index.js +0 -0
- package/dist/channel-Dv3Hv1ee.d.ts +634 -0
- package/dist/chunk-4DU4GJ2X.js +347 -0
- package/dist/chunk-HO6QHSUS.js +85 -0
- package/dist/chunk-M4JW76IL.js +1161 -0
- package/dist/chunk-RF6W3TKJ.js +2762 -0
- package/dist/chunk-S7RZJMCF.js +47 -0
- package/dist/cloudflare/index.d.ts +109 -0
- package/dist/cloudflare/index.js +212 -0
- package/dist/command-kxrqWIH7.d.ts +204 -0
- package/dist/index-UFTgKRK4.d.ts +589 -0
- package/dist/index.d.ts +739 -0
- package/dist/index.js +965 -0
- package/dist/node/index.d.ts +65 -0
- package/dist/node/index.js +251 -0
- package/dist/providers.d.ts +40 -0
- package/dist/providers.js +26 -0
- package/dist/routing/index.d.ts +256 -0
- package/dist/routing/index.js +2184 -0
- package/package.json +68 -0
- package/schemas/persona-manifest.v1.schema.json +258 -0
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
// src/command.ts
|
|
2
|
+
function defineCommand(name, execute) {
|
|
3
|
+
return { name, execute: normalizeCommandExecutor(execute) };
|
|
4
|
+
}
|
|
5
|
+
function normalizeCommandExecutor(execute) {
|
|
6
|
+
return async (args, signal) => {
|
|
7
|
+
try {
|
|
8
|
+
const raw = await execute(args, signal);
|
|
9
|
+
if (raw == null) return { stdout: "", stderr: "", exitCode: 0 };
|
|
10
|
+
if (typeof raw === "string") return { stdout: raw, stderr: "", exitCode: 0 };
|
|
11
|
+
return {
|
|
12
|
+
stdout: raw.stdout ?? "",
|
|
13
|
+
stderr: raw.stderr ?? "",
|
|
14
|
+
exitCode: raw.exitCode ?? 0
|
|
15
|
+
};
|
|
16
|
+
} catch (err) {
|
|
17
|
+
const e = err;
|
|
18
|
+
return {
|
|
19
|
+
stdout: typeof e.stdout === "string" ? e.stdout : "",
|
|
20
|
+
stderr: typeof e.stderr === "string" ? e.stderr : err instanceof Error ? err.message : String(err),
|
|
21
|
+
exitCode: typeof e.code === "number" ? e.code : 1
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
function mergeCommands(defaults, perCall) {
|
|
27
|
+
if (!defaults?.length) return perCall ?? [];
|
|
28
|
+
if (!perCall?.length) return defaults;
|
|
29
|
+
const byName = /* @__PURE__ */ new Map();
|
|
30
|
+
for (const command of defaults) byName.set(command.name, command);
|
|
31
|
+
for (const command of perCall) byName.set(command.name, command);
|
|
32
|
+
return [...byName.values()];
|
|
33
|
+
}
|
|
34
|
+
async function createScopedSessionEnv(env, commands) {
|
|
35
|
+
if (!commands.length) return env;
|
|
36
|
+
if (env.scope) return env.scope({ commands });
|
|
37
|
+
throw new Error(
|
|
38
|
+
"Cannot use commands: this sandbox does not support scoped command execution. Use the default virtual sandbox or a connector that implements SessionEnv.scope()."
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export {
|
|
43
|
+
defineCommand,
|
|
44
|
+
normalizeCommandExecutor,
|
|
45
|
+
mergeCommands,
|
|
46
|
+
createScopedSessionEnv
|
|
47
|
+
};
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { DurableObject } from 'cloudflare:workers';
|
|
2
|
+
export { d as defineCommand } from '../command-kxrqWIH7.js';
|
|
3
|
+
import { S as SessionData, R as RunRecord, a as RunStatus, A as AtlasEvent, b as StreamCreateOptions, D as DurableStreamRecord, c as StreamAppendOptions, d as DurableStreamMessage, e as DurableStreamProducerTuple, f as StreamProducerAppendResult, g as StreamProducerCloseResult, h as DurableStreamSubscriptionCreateInput, i as DurableStreamSubscriptionResult, j as DurableStreamSubscriptionRecord, k as DurableStreamSubscriptionClaim, l as DurableStreamSubscriptionAckInput, m as DurableStreamSubscriptionStreamInfo, P as PersistenceAdapter } from '../index-UFTgKRK4.js';
|
|
4
|
+
|
|
5
|
+
interface CloudflareExecutionContextLike {
|
|
6
|
+
waitUntil?: (promise: Promise<unknown>) => void;
|
|
7
|
+
}
|
|
8
|
+
interface CloudflareFiberLike {
|
|
9
|
+
stash?: (value: unknown) => void | Promise<void>;
|
|
10
|
+
}
|
|
11
|
+
interface CloudflareAgentDurabilityLike {
|
|
12
|
+
runFiber?: <T>(name: string, run: (fiber?: CloudflareFiberLike) => T | Promise<T>) => T | Promise<T>;
|
|
13
|
+
keepAliveWhile?: <T>(run: () => T | Promise<T>) => T | Promise<T>;
|
|
14
|
+
}
|
|
15
|
+
interface CloudflareDurabilityOptions {
|
|
16
|
+
/**
|
|
17
|
+
* A Cloudflare Agents SDK Durable Object instance. When it exposes
|
|
18
|
+
* `runFiber`, AtlasFlow uses it for interruption-aware execution.
|
|
19
|
+
*/
|
|
20
|
+
agentInstance?: CloudflareAgentDurabilityLike | null;
|
|
21
|
+
/** The Worker execution context used by plain Worker routes. */
|
|
22
|
+
executionCtx?: CloudflareExecutionContextLike | null;
|
|
23
|
+
/** Stable name for the registered fiber. A generated request name is used when omitted. */
|
|
24
|
+
fiberName?: string;
|
|
25
|
+
/** Optional metadata written to the fiber snapshot before user code runs. */
|
|
26
|
+
stash?: unknown | ((fiberName: string) => unknown);
|
|
27
|
+
/** Throw instead of falling back when `runFiber` is unavailable. */
|
|
28
|
+
requireFiber?: boolean;
|
|
29
|
+
}
|
|
30
|
+
interface CloudflareDurabilityCapabilities {
|
|
31
|
+
runFiber: boolean;
|
|
32
|
+
keepAliveWhile: boolean;
|
|
33
|
+
waitUntil: boolean;
|
|
34
|
+
}
|
|
35
|
+
declare function cloudflareDurabilityCapabilities(options: CloudflareDurabilityOptions): CloudflareDurabilityCapabilities;
|
|
36
|
+
declare function hasCloudflareFiber(agentInstance: unknown): agentInstance is Required<Pick<CloudflareAgentDurabilityLike, "runFiber">>;
|
|
37
|
+
declare function runWithCloudflareDurability<T>(options: CloudflareDurabilityOptions, run: () => T | Promise<T>): Promise<T>;
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Cloudflare Durable Object persistence.
|
|
41
|
+
*
|
|
42
|
+
* `AtlasFlowStore` is a Durable Object whose transactional storage backs the
|
|
43
|
+
* same PersistenceAdapter the rest of the runtime uses (via `kvAdapter`). The
|
|
44
|
+
* Worker talks to it through `durableObjectAdapter(env.ATLAS_STORE)`, giving
|
|
45
|
+
* agents durable sessions and run records across requests and restarts.
|
|
46
|
+
*
|
|
47
|
+
* This module imports `cloudflare:workers`, so it only loads on the Workers
|
|
48
|
+
* runtime — Node consumers never import `@cybernetyx1/atlasflow-runtime/cloudflare`.
|
|
49
|
+
*/
|
|
50
|
+
|
|
51
|
+
type RunFilter = {
|
|
52
|
+
status?: RunStatus;
|
|
53
|
+
agent?: string;
|
|
54
|
+
limit?: number;
|
|
55
|
+
};
|
|
56
|
+
declare class AtlasFlowStore extends DurableObject {
|
|
57
|
+
#private;
|
|
58
|
+
sessionGet(key: string): Promise<SessionData | null>;
|
|
59
|
+
sessionPut(key: string, data: SessionData): Promise<void>;
|
|
60
|
+
sessionDelete(key: string): Promise<void>;
|
|
61
|
+
runCreate(record: RunRecord): Promise<void>;
|
|
62
|
+
runUpdate(runId: string, patch: Partial<RunRecord>): Promise<void>;
|
|
63
|
+
runGet(runId: string): Promise<RunRecord | null>;
|
|
64
|
+
runList(filter?: RunFilter): Promise<RunRecord[]>;
|
|
65
|
+
runClaimLease(runId: string, owner: string, now: number, ttlMs: number): Promise<boolean>;
|
|
66
|
+
runClaimQueued(runId: string, owner: string, now: number, ttlMs: number): Promise<boolean>;
|
|
67
|
+
runHeartbeatLease(runId: string, owner: string, now: number, ttlMs: number): Promise<boolean>;
|
|
68
|
+
runReleaseLease(runId: string, owner: string): Promise<void>;
|
|
69
|
+
runAppendEvent(runId: string, event: AtlasEvent): Promise<void>;
|
|
70
|
+
runEvents(runId: string): Promise<AtlasEvent[]>;
|
|
71
|
+
runEventCount(runId: string): Promise<number>;
|
|
72
|
+
streamCreate(path: string, opts?: StreamCreateOptions): Promise<{
|
|
73
|
+
record: DurableStreamRecord;
|
|
74
|
+
created: boolean;
|
|
75
|
+
}>;
|
|
76
|
+
streamGet(path: string): Promise<DurableStreamRecord | null>;
|
|
77
|
+
streamDelete(path: string): Promise<boolean>;
|
|
78
|
+
streamAppend(path: string, data: Uint8Array, opts: StreamAppendOptions): Promise<{
|
|
79
|
+
record: DurableStreamRecord;
|
|
80
|
+
message: DurableStreamMessage;
|
|
81
|
+
} | null>;
|
|
82
|
+
streamAppendWithProducer(path: string, data: Uint8Array, opts: StreamAppendOptions & {
|
|
83
|
+
producer: DurableStreamProducerTuple;
|
|
84
|
+
}): Promise<StreamProducerAppendResult | null>;
|
|
85
|
+
streamClose(path: string): Promise<DurableStreamRecord | null>;
|
|
86
|
+
streamCloseWithProducer(path: string, producer: DurableStreamProducerTuple): Promise<StreamProducerCloseResult | null>;
|
|
87
|
+
streamMessages(path: string): Promise<DurableStreamMessage[]>;
|
|
88
|
+
subscriptionCreateOrConfirm(id: string, input: DurableStreamSubscriptionCreateInput): Promise<DurableStreamSubscriptionResult<{
|
|
89
|
+
subscription: DurableStreamSubscriptionRecord;
|
|
90
|
+
created: boolean;
|
|
91
|
+
}>>;
|
|
92
|
+
subscriptionGet(id: string): Promise<DurableStreamSubscriptionRecord | null>;
|
|
93
|
+
subscriptionDelete(id: string): Promise<boolean>;
|
|
94
|
+
subscriptionAddExplicitStreams(id: string, streams: string[]): Promise<boolean>;
|
|
95
|
+
subscriptionRemoveExplicitStream(id: string, streamPath: string): Promise<boolean>;
|
|
96
|
+
subscriptionNotifyStreamAppend(streamPath: string, message?: DurableStreamMessage): Promise<void>;
|
|
97
|
+
subscriptionNotifyStreamDelete(streamPath: string): Promise<void>;
|
|
98
|
+
subscriptionClaim(id: string, worker: string): Promise<DurableStreamSubscriptionResult<DurableStreamSubscriptionClaim>>;
|
|
99
|
+
subscriptionAck(id: string, token: string, input: DurableStreamSubscriptionAckInput): Promise<DurableStreamSubscriptionResult<{
|
|
100
|
+
ok: true;
|
|
101
|
+
nextWake: boolean;
|
|
102
|
+
}>>;
|
|
103
|
+
subscriptionRelease(id: string, token: string, input: DurableStreamSubscriptionAckInput): Promise<DurableStreamSubscriptionResult<void>>;
|
|
104
|
+
subscriptionStreamInfos(subscription: DurableStreamSubscriptionRecord): Promise<DurableStreamSubscriptionStreamInfo[]>;
|
|
105
|
+
}
|
|
106
|
+
/** Build a PersistenceAdapter that proxies to the AtlasFlowStore Durable Object. */
|
|
107
|
+
declare function durableObjectAdapter(namespace: DurableObjectNamespace, name?: string): PersistenceAdapter;
|
|
108
|
+
|
|
109
|
+
export { AtlasFlowStore, type CloudflareAgentDurabilityLike, type CloudflareDurabilityCapabilities, type CloudflareDurabilityOptions, type CloudflareExecutionContextLike, type CloudflareFiberLike, cloudflareDurabilityCapabilities, durableObjectAdapter, hasCloudflareFiber, runWithCloudflareDurability };
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import {
|
|
2
|
+
kvAdapter
|
|
3
|
+
} from "../chunk-M4JW76IL.js";
|
|
4
|
+
import {
|
|
5
|
+
defineCommand
|
|
6
|
+
} from "../chunk-S7RZJMCF.js";
|
|
7
|
+
|
|
8
|
+
// src/cloudflare/index.ts
|
|
9
|
+
import { DurableObject } from "cloudflare:workers";
|
|
10
|
+
|
|
11
|
+
// src/cloudflare/durability.ts
|
|
12
|
+
function cloudflareDurabilityCapabilities(options) {
|
|
13
|
+
return {
|
|
14
|
+
runFiber: typeof options.agentInstance?.runFiber === "function",
|
|
15
|
+
keepAliveWhile: typeof options.agentInstance?.keepAliveWhile === "function",
|
|
16
|
+
waitUntil: typeof options.executionCtx?.waitUntil === "function"
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
function hasCloudflareFiber(agentInstance) {
|
|
20
|
+
return typeof agentInstance?.runFiber === "function";
|
|
21
|
+
}
|
|
22
|
+
async function runWithCloudflareDurability(options, run) {
|
|
23
|
+
const fiberName = options.fiberName ?? defaultFiberName();
|
|
24
|
+
const agentInstance = options.agentInstance;
|
|
25
|
+
if (typeof agentInstance?.runFiber === "function") {
|
|
26
|
+
return agentInstance.runFiber(fiberName, async (fiber) => {
|
|
27
|
+
if (options.stash !== void 0 && fiber?.stash) {
|
|
28
|
+
const value = typeof options.stash === "function" ? options.stash(fiberName) : options.stash;
|
|
29
|
+
await fiber.stash(value);
|
|
30
|
+
}
|
|
31
|
+
return run();
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
if (options.requireFiber) {
|
|
35
|
+
throw new Error(
|
|
36
|
+
"Cloudflare Agents SDK runFiber() is required for this operation. Pass an Agents SDK instance or disable requireFiber to allow keepAliveWhile()/waitUntil fallback."
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
if (typeof agentInstance?.keepAliveWhile === "function") {
|
|
40
|
+
return agentInstance.keepAliveWhile(run);
|
|
41
|
+
}
|
|
42
|
+
const promise = Promise.resolve().then(run);
|
|
43
|
+
try {
|
|
44
|
+
options.executionCtx?.waitUntil?.(promise);
|
|
45
|
+
} catch {
|
|
46
|
+
}
|
|
47
|
+
return promise;
|
|
48
|
+
}
|
|
49
|
+
function defaultFiberName() {
|
|
50
|
+
const cryptoLike = globalThis.crypto;
|
|
51
|
+
const randomUUID = cryptoLike?.randomUUID;
|
|
52
|
+
const id = typeof randomUUID === "function" ? randomUUID.call(cryptoLike) : `${Date.now()}:${Math.random().toString(16).slice(2)}`;
|
|
53
|
+
return `atlasflow:request:${id}`;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// src/cloudflare/index.ts
|
|
57
|
+
var AtlasFlowStore = class extends DurableObject {
|
|
58
|
+
#adapter = kvAdapter(this.ctx.storage);
|
|
59
|
+
sessionGet(key) {
|
|
60
|
+
return this.#adapter.sessions.get(key);
|
|
61
|
+
}
|
|
62
|
+
sessionPut(key, data) {
|
|
63
|
+
return this.#adapter.sessions.put(key, data);
|
|
64
|
+
}
|
|
65
|
+
sessionDelete(key) {
|
|
66
|
+
return this.#adapter.sessions.delete(key);
|
|
67
|
+
}
|
|
68
|
+
runCreate(record) {
|
|
69
|
+
return this.#adapter.runs.create(record);
|
|
70
|
+
}
|
|
71
|
+
runUpdate(runId, patch) {
|
|
72
|
+
return this.#adapter.runs.update(runId, patch);
|
|
73
|
+
}
|
|
74
|
+
runGet(runId) {
|
|
75
|
+
return this.#adapter.runs.get(runId);
|
|
76
|
+
}
|
|
77
|
+
runList(filter) {
|
|
78
|
+
return this.#adapter.runs.list(filter);
|
|
79
|
+
}
|
|
80
|
+
runClaimLease(runId, owner, now, ttlMs) {
|
|
81
|
+
return this.#adapter.runs.claimLease(runId, owner, now, ttlMs);
|
|
82
|
+
}
|
|
83
|
+
runClaimQueued(runId, owner, now, ttlMs) {
|
|
84
|
+
return this.#adapter.runs.claimQueued(runId, owner, now, ttlMs);
|
|
85
|
+
}
|
|
86
|
+
runHeartbeatLease(runId, owner, now, ttlMs) {
|
|
87
|
+
return this.#adapter.runs.heartbeatLease(runId, owner, now, ttlMs);
|
|
88
|
+
}
|
|
89
|
+
runReleaseLease(runId, owner) {
|
|
90
|
+
return this.#adapter.runs.releaseLease(runId, owner);
|
|
91
|
+
}
|
|
92
|
+
runAppendEvent(runId, event) {
|
|
93
|
+
return this.#adapter.runs.appendEvent(runId, event);
|
|
94
|
+
}
|
|
95
|
+
runEvents(runId) {
|
|
96
|
+
return this.#adapter.runs.events(runId);
|
|
97
|
+
}
|
|
98
|
+
runEventCount(runId) {
|
|
99
|
+
return this.#adapter.runs.eventCount?.(runId) ?? this.#adapter.runs.events(runId).then((e) => e.length);
|
|
100
|
+
}
|
|
101
|
+
streamCreate(path, opts) {
|
|
102
|
+
return this.#adapter.streams.create(path, opts);
|
|
103
|
+
}
|
|
104
|
+
streamGet(path) {
|
|
105
|
+
return this.#adapter.streams.get(path);
|
|
106
|
+
}
|
|
107
|
+
streamDelete(path) {
|
|
108
|
+
return this.#adapter.streams.delete(path);
|
|
109
|
+
}
|
|
110
|
+
streamAppend(path, data, opts) {
|
|
111
|
+
return this.#adapter.streams.append(path, data, opts);
|
|
112
|
+
}
|
|
113
|
+
streamAppendWithProducer(path, data, opts) {
|
|
114
|
+
return this.#adapter.streams.appendWithProducer(path, data, opts);
|
|
115
|
+
}
|
|
116
|
+
streamClose(path) {
|
|
117
|
+
return this.#adapter.streams.close(path);
|
|
118
|
+
}
|
|
119
|
+
streamCloseWithProducer(path, producer) {
|
|
120
|
+
return this.#adapter.streams.closeWithProducer(path, producer);
|
|
121
|
+
}
|
|
122
|
+
streamMessages(path) {
|
|
123
|
+
return this.#adapter.streams.messages(path);
|
|
124
|
+
}
|
|
125
|
+
subscriptionCreateOrConfirm(id, input) {
|
|
126
|
+
return this.#adapter.subscriptions.createOrConfirm(id, input);
|
|
127
|
+
}
|
|
128
|
+
subscriptionGet(id) {
|
|
129
|
+
return this.#adapter.subscriptions.get(id);
|
|
130
|
+
}
|
|
131
|
+
subscriptionDelete(id) {
|
|
132
|
+
return this.#adapter.subscriptions.delete(id);
|
|
133
|
+
}
|
|
134
|
+
subscriptionAddExplicitStreams(id, streams) {
|
|
135
|
+
return this.#adapter.subscriptions.addExplicitStreams(id, streams);
|
|
136
|
+
}
|
|
137
|
+
subscriptionRemoveExplicitStream(id, streamPath) {
|
|
138
|
+
return this.#adapter.subscriptions.removeExplicitStream(id, streamPath);
|
|
139
|
+
}
|
|
140
|
+
subscriptionNotifyStreamAppend(streamPath, message) {
|
|
141
|
+
return this.#adapter.subscriptions.notifyStreamAppend(streamPath, message);
|
|
142
|
+
}
|
|
143
|
+
subscriptionNotifyStreamDelete(streamPath) {
|
|
144
|
+
return this.#adapter.subscriptions.notifyStreamDelete(streamPath);
|
|
145
|
+
}
|
|
146
|
+
subscriptionClaim(id, worker) {
|
|
147
|
+
return this.#adapter.subscriptions.claim(id, worker);
|
|
148
|
+
}
|
|
149
|
+
subscriptionAck(id, token, input) {
|
|
150
|
+
return this.#adapter.subscriptions.ack(id, token, input);
|
|
151
|
+
}
|
|
152
|
+
subscriptionRelease(id, token, input) {
|
|
153
|
+
return this.#adapter.subscriptions.release(id, token, input);
|
|
154
|
+
}
|
|
155
|
+
subscriptionStreamInfos(subscription) {
|
|
156
|
+
return this.#adapter.subscriptions.streamInfos(subscription);
|
|
157
|
+
}
|
|
158
|
+
};
|
|
159
|
+
function durableObjectAdapter(namespace, name = "atlasflow") {
|
|
160
|
+
const stub = () => namespace.get(namespace.idFromName(name));
|
|
161
|
+
return {
|
|
162
|
+
sessions: {
|
|
163
|
+
get: (k) => stub().sessionGet(k),
|
|
164
|
+
put: (k, d) => stub().sessionPut(k, d),
|
|
165
|
+
delete: (k) => stub().sessionDelete(k)
|
|
166
|
+
},
|
|
167
|
+
runs: {
|
|
168
|
+
create: (r) => stub().runCreate(r),
|
|
169
|
+
update: (id, p) => stub().runUpdate(id, p),
|
|
170
|
+
get: (id) => stub().runGet(id),
|
|
171
|
+
list: (f) => stub().runList(f),
|
|
172
|
+
claimLease: (id, owner, now, ttlMs) => stub().runClaimLease(id, owner, now, ttlMs),
|
|
173
|
+
claimQueued: (id, owner, now, ttlMs) => stub().runClaimQueued(id, owner, now, ttlMs),
|
|
174
|
+
heartbeatLease: (id, owner, now, ttlMs) => stub().runHeartbeatLease(id, owner, now, ttlMs),
|
|
175
|
+
releaseLease: (id, owner) => stub().runReleaseLease(id, owner),
|
|
176
|
+
appendEvent: (id, e) => stub().runAppendEvent(id, e),
|
|
177
|
+
events: (id) => stub().runEvents(id),
|
|
178
|
+
eventCount: (id) => stub().runEventCount(id)
|
|
179
|
+
},
|
|
180
|
+
streams: {
|
|
181
|
+
create: (path, opts) => stub().streamCreate(path, opts),
|
|
182
|
+
get: (path) => stub().streamGet(path),
|
|
183
|
+
delete: (path) => stub().streamDelete(path),
|
|
184
|
+
append: (path, data, opts) => stub().streamAppend(path, data, opts),
|
|
185
|
+
appendWithProducer: (path, data, opts) => stub().streamAppendWithProducer(path, data, opts),
|
|
186
|
+
close: (path) => stub().streamClose(path),
|
|
187
|
+
closeWithProducer: (path, producer) => stub().streamCloseWithProducer(path, producer),
|
|
188
|
+
messages: (path) => stub().streamMessages(path)
|
|
189
|
+
},
|
|
190
|
+
subscriptions: {
|
|
191
|
+
createOrConfirm: (id, input) => stub().subscriptionCreateOrConfirm(id, input),
|
|
192
|
+
get: (id) => stub().subscriptionGet(id),
|
|
193
|
+
delete: (id) => stub().subscriptionDelete(id),
|
|
194
|
+
addExplicitStreams: (id, streams) => stub().subscriptionAddExplicitStreams(id, streams),
|
|
195
|
+
removeExplicitStream: (id, streamPath) => stub().subscriptionRemoveExplicitStream(id, streamPath),
|
|
196
|
+
notifyStreamAppend: (streamPath, message) => stub().subscriptionNotifyStreamAppend(streamPath, message),
|
|
197
|
+
notifyStreamDelete: (streamPath) => stub().subscriptionNotifyStreamDelete(streamPath),
|
|
198
|
+
claim: (id, worker) => stub().subscriptionClaim(id, worker),
|
|
199
|
+
ack: (id, token, input) => stub().subscriptionAck(id, token, input),
|
|
200
|
+
release: (id, token, input) => stub().subscriptionRelease(id, token, input),
|
|
201
|
+
streamInfos: (subscription) => stub().subscriptionStreamInfos(subscription)
|
|
202
|
+
}
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
export {
|
|
206
|
+
AtlasFlowStore,
|
|
207
|
+
cloudflareDurabilityCapabilities,
|
|
208
|
+
defineCommand,
|
|
209
|
+
durableObjectAdapter,
|
|
210
|
+
hasCloudflareFiber,
|
|
211
|
+
runWithCloudflareDurability
|
|
212
|
+
};
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sandbox interfaces. A SandboxFactory creates a SessionEnv — a filesystem +
|
|
3
|
+
* shell from some provider. The agent never names a vendor. AtlasFs is the
|
|
4
|
+
* ergonomic wrapper exposed on harness/session `.fs`.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
interface ShellResult {
|
|
8
|
+
stdout: string;
|
|
9
|
+
stderr: string;
|
|
10
|
+
exitCode: number;
|
|
11
|
+
}
|
|
12
|
+
interface ExecOptions {
|
|
13
|
+
cwd?: string;
|
|
14
|
+
env?: Record<string, string>;
|
|
15
|
+
timeoutMs?: number;
|
|
16
|
+
signal?: AbortSignal;
|
|
17
|
+
}
|
|
18
|
+
interface FileStat {
|
|
19
|
+
isFile: boolean;
|
|
20
|
+
isDirectory: boolean;
|
|
21
|
+
isSymbolicLink: boolean;
|
|
22
|
+
size: number;
|
|
23
|
+
mtimeMs: number;
|
|
24
|
+
}
|
|
25
|
+
interface SessionEnv {
|
|
26
|
+
exec(command: string, options?: ExecOptions): Promise<ShellResult>;
|
|
27
|
+
/**
|
|
28
|
+
* Create an operation-scoped environment with extra host-implemented
|
|
29
|
+
* commands registered only for that operation. Sandboxes that cannot
|
|
30
|
+
* isolate command grants should leave this undefined.
|
|
31
|
+
*/
|
|
32
|
+
scope?(options?: {
|
|
33
|
+
commands?: Command[];
|
|
34
|
+
}): Promise<SessionEnv>;
|
|
35
|
+
readFile(path: string): Promise<string>;
|
|
36
|
+
readFileBuffer(path: string): Promise<Uint8Array>;
|
|
37
|
+
writeFile(path: string, data: string | Uint8Array): Promise<void>;
|
|
38
|
+
stat(path: string): Promise<FileStat>;
|
|
39
|
+
readdir(path: string): Promise<string[]>;
|
|
40
|
+
exists(path: string): Promise<boolean>;
|
|
41
|
+
mkdir(path: string, options?: {
|
|
42
|
+
recursive?: boolean;
|
|
43
|
+
}): Promise<void>;
|
|
44
|
+
rm(path: string, options?: {
|
|
45
|
+
recursive?: boolean;
|
|
46
|
+
force?: boolean;
|
|
47
|
+
}): Promise<void>;
|
|
48
|
+
cwd: string;
|
|
49
|
+
resolvePath(path: string): string;
|
|
50
|
+
/**
|
|
51
|
+
* Release whatever backs this environment (container, VM, temp dir). The
|
|
52
|
+
* runtime calls this when the invocation ends — connectors that provision
|
|
53
|
+
* remote infrastructure MUST implement it or every run leaks a billed box.
|
|
54
|
+
*/
|
|
55
|
+
dispose?(): Promise<void>;
|
|
56
|
+
}
|
|
57
|
+
type SandboxHttpMethod = "GET" | "HEAD" | "POST" | "PUT" | "DELETE" | "PATCH" | "OPTIONS";
|
|
58
|
+
interface SandboxEnvHeaderRef {
|
|
59
|
+
env: string;
|
|
60
|
+
prefix?: string;
|
|
61
|
+
required?: boolean;
|
|
62
|
+
}
|
|
63
|
+
type SandboxHeaderValue = string | SandboxEnvHeaderRef;
|
|
64
|
+
interface SandboxAllowedUrl {
|
|
65
|
+
url: string;
|
|
66
|
+
/**
|
|
67
|
+
* Headers applied by the host-side fetch boundary. Use sandboxHeaderFromEnv()
|
|
68
|
+
* for credentials so secrets are never present in the sandbox process env.
|
|
69
|
+
*/
|
|
70
|
+
headers?: Record<string, SandboxHeaderValue>;
|
|
71
|
+
}
|
|
72
|
+
type SandboxAllowedUrlEntry = string | SandboxAllowedUrl;
|
|
73
|
+
interface SandboxNetworkPolicy {
|
|
74
|
+
allowedUrlPrefixes?: SandboxAllowedUrlEntry[];
|
|
75
|
+
allowedMethods?: SandboxHttpMethod[];
|
|
76
|
+
dangerouslyAllowFullInternetAccess?: boolean;
|
|
77
|
+
maxRedirects?: number;
|
|
78
|
+
timeoutMs?: number;
|
|
79
|
+
maxResponseSize?: number;
|
|
80
|
+
denyPrivateRanges?: boolean;
|
|
81
|
+
/** Test-only DNS resolver hook passed through to supported sandbox providers. */
|
|
82
|
+
_dnsResolve?: (hostname: string) => Promise<Array<{
|
|
83
|
+
address: string;
|
|
84
|
+
family: number;
|
|
85
|
+
}>>;
|
|
86
|
+
}
|
|
87
|
+
interface ResolvedSandboxAllowedUrl {
|
|
88
|
+
url: string;
|
|
89
|
+
transform?: Array<{
|
|
90
|
+
headers: Record<string, string>;
|
|
91
|
+
}>;
|
|
92
|
+
}
|
|
93
|
+
interface ResolvedSandboxNetworkPolicy extends Omit<SandboxNetworkPolicy, "allowedUrlPrefixes"> {
|
|
94
|
+
allowedUrlPrefixes?: Array<string | ResolvedSandboxAllowedUrl>;
|
|
95
|
+
}
|
|
96
|
+
declare function sandboxHeaderFromEnv(env: string, options?: {
|
|
97
|
+
prefix?: string;
|
|
98
|
+
required?: boolean;
|
|
99
|
+
}): SandboxEnvHeaderRef;
|
|
100
|
+
declare function resolveSandboxNetworkPolicy(policy: SandboxNetworkPolicy | undefined, env?: Record<string, unknown>): ResolvedSandboxNetworkPolicy | undefined;
|
|
101
|
+
interface SandboxFactory {
|
|
102
|
+
createSessionEnv(options: {
|
|
103
|
+
id: string;
|
|
104
|
+
cwd?: string;
|
|
105
|
+
env?: Record<string, unknown>;
|
|
106
|
+
}): Promise<SessionEnv>;
|
|
107
|
+
}
|
|
108
|
+
interface SandboxSessionContext {
|
|
109
|
+
id: string;
|
|
110
|
+
cwd?: string;
|
|
111
|
+
env?: Record<string, unknown>;
|
|
112
|
+
}
|
|
113
|
+
interface SandboxLifecycleDefinition {
|
|
114
|
+
/** Provider selected for this sandbox. Use a function for simple local/provider cascade logic. */
|
|
115
|
+
factory: SandboxFactory | ((ctx: SandboxSessionContext) => SandboxFactory);
|
|
116
|
+
/** Runs once for this factory instance before the first session is created. */
|
|
117
|
+
bootstrap?: (ctx: SandboxSessionContext) => void | Promise<void>;
|
|
118
|
+
/** Runs for every session after the provider creates its environment. */
|
|
119
|
+
onSession?: (env: SessionEnv, ctx: SandboxSessionContext) => void | Promise<void>;
|
|
120
|
+
/** Runs when each session is disposed, after the provider environment is disposed. */
|
|
121
|
+
cleanup?: (ctx: SandboxSessionContext) => void | Promise<void>;
|
|
122
|
+
}
|
|
123
|
+
interface SandboxCascadeProvider {
|
|
124
|
+
/** Human-readable provider name used in failure messages. */
|
|
125
|
+
name: string;
|
|
126
|
+
/**
|
|
127
|
+
* Provider factory, or a resolver that can return undefined to skip this
|
|
128
|
+
* provider for the current session (for example when an env var is absent).
|
|
129
|
+
*/
|
|
130
|
+
factory: SandboxFactory | ((ctx: SandboxSessionContext) => SandboxFactory | undefined | Promise<SandboxFactory | undefined>);
|
|
131
|
+
/** Optional predicate for provider availability. false means "skip", not failure. */
|
|
132
|
+
when?: (ctx: SandboxSessionContext) => boolean | Promise<boolean>;
|
|
133
|
+
}
|
|
134
|
+
type SandboxCascadeEntry = SandboxFactory | SandboxCascadeProvider;
|
|
135
|
+
declare function defineSandbox(input: SandboxFactory | SandboxLifecycleDefinition): SandboxFactory;
|
|
136
|
+
declare function sandboxCascade(entries: SandboxCascadeEntry[]): SandboxFactory;
|
|
137
|
+
declare function isSandboxFactory(value: unknown): value is SandboxFactory;
|
|
138
|
+
interface AtlasFs {
|
|
139
|
+
readFile(path: string): Promise<string>;
|
|
140
|
+
readFileBuffer(path: string): Promise<Uint8Array>;
|
|
141
|
+
writeFile(path: string, data: string | Uint8Array): Promise<void>;
|
|
142
|
+
stat(path: string): Promise<FileStat>;
|
|
143
|
+
readdir(path: string): Promise<string[]>;
|
|
144
|
+
exists(path: string): Promise<boolean>;
|
|
145
|
+
mkdir(path: string, options?: {
|
|
146
|
+
recursive?: boolean;
|
|
147
|
+
}): Promise<void>;
|
|
148
|
+
rm(path: string, options?: {
|
|
149
|
+
recursive?: boolean;
|
|
150
|
+
force?: boolean;
|
|
151
|
+
}): Promise<void>;
|
|
152
|
+
}
|
|
153
|
+
declare function makeFs(env: SessionEnv): AtlasFs;
|
|
154
|
+
/**
|
|
155
|
+
* Shared implementation of the AtlasFs.writeFile parent-creation guarantee.
|
|
156
|
+
* Adapters should route writes through this helper when their backing filesystem
|
|
157
|
+
* does not already create missing parent directories.
|
|
158
|
+
*/
|
|
159
|
+
declare function writeFileCreatingParents(write: () => Promise<void>, mkdirParent: () => Promise<unknown>): Promise<void>;
|
|
160
|
+
declare function createCwdSessionEnv(parentEnv: SessionEnv, cwd: string): SessionEnv;
|
|
161
|
+
/**
|
|
162
|
+
* Design note: a base class so connectors only implement what
|
|
163
|
+
* differs. Subclasses provide exec/read/write/stat/readdir/mkdir/rm; exists()
|
|
164
|
+
* and path resolution are handled here.
|
|
165
|
+
*/
|
|
166
|
+
declare abstract class BaseSandboxEnv implements SessionEnv {
|
|
167
|
+
abstract cwd: string;
|
|
168
|
+
abstract exec(command: string, options?: ExecOptions): Promise<ShellResult>;
|
|
169
|
+
abstract readFile(path: string): Promise<string>;
|
|
170
|
+
abstract readFileBuffer(path: string): Promise<Uint8Array>;
|
|
171
|
+
abstract writeFile(path: string, data: string | Uint8Array): Promise<void>;
|
|
172
|
+
abstract stat(path: string): Promise<FileStat>;
|
|
173
|
+
abstract readdir(path: string): Promise<string[]>;
|
|
174
|
+
abstract mkdir(path: string, options?: {
|
|
175
|
+
recursive?: boolean;
|
|
176
|
+
}): Promise<void>;
|
|
177
|
+
abstract rm(path: string, options?: {
|
|
178
|
+
recursive?: boolean;
|
|
179
|
+
force?: boolean;
|
|
180
|
+
}): Promise<void>;
|
|
181
|
+
exists(path: string): Promise<boolean>;
|
|
182
|
+
resolvePath(path: string): string;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
type CommandExecutorResult = ShellResult | {
|
|
186
|
+
stdout?: string;
|
|
187
|
+
stderr?: string;
|
|
188
|
+
exitCode?: number;
|
|
189
|
+
} | string | void;
|
|
190
|
+
type CommandExecutor = (args: string[], signal?: AbortSignal) => CommandExecutorResult | Promise<CommandExecutorResult>;
|
|
191
|
+
/**
|
|
192
|
+
* A host-implemented command that can be granted to a just-bash-backed
|
|
193
|
+
* operation without exposing its secrets to the sandbox environment.
|
|
194
|
+
*/
|
|
195
|
+
interface Command {
|
|
196
|
+
name: string;
|
|
197
|
+
execute(args: string[], signal?: AbortSignal): Promise<ShellResult>;
|
|
198
|
+
}
|
|
199
|
+
declare function defineCommand(name: string, execute: CommandExecutor): Command;
|
|
200
|
+
declare function normalizeCommandExecutor(execute: CommandExecutor): Command["execute"];
|
|
201
|
+
declare function mergeCommands(defaults: Command[] | undefined, perCall: Command[] | undefined): Command[];
|
|
202
|
+
declare function createScopedSessionEnv(env: SessionEnv, commands: Command[]): Promise<SessionEnv>;
|
|
203
|
+
|
|
204
|
+
export { type AtlasFs as A, BaseSandboxEnv as B, type Command as C, writeFileCreatingParents as D, type ExecOptions as E, type FileStat as F, type ResolvedSandboxAllowedUrl as R, type SandboxNetworkPolicy as S, type CommandExecutor as a, type SandboxFactory as b, type SessionEnv as c, defineCommand as d, type ShellResult as e, type CommandExecutorResult as f, type ResolvedSandboxNetworkPolicy as g, type SandboxAllowedUrl as h, type SandboxAllowedUrlEntry as i, type SandboxCascadeEntry as j, type SandboxCascadeProvider as k, type SandboxEnvHeaderRef as l, type SandboxHeaderValue as m, type SandboxHttpMethod as n, type SandboxLifecycleDefinition as o, type SandboxSessionContext as p, createCwdSessionEnv as q, createScopedSessionEnv as r, defineSandbox as s, isSandboxFactory as t, makeFs as u, mergeCommands as v, normalizeCommandExecutor as w, resolveSandboxNetworkPolicy as x, sandboxCascade as y, sandboxHeaderFromEnv as z };
|