@elaraai/e3-api-server 0.0.2-beta.9 → 1.0.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.md +4 -0
- package/README.md +194 -43
- package/dist/src/async-operation-state.d.ts +37 -0
- package/dist/src/async-operation-state.d.ts.map +1 -0
- package/dist/src/async-operation-state.js +118 -0
- package/dist/src/async-operation-state.js.map +1 -0
- package/dist/src/auth/device.d.ts +26 -0
- package/dist/src/auth/device.d.ts.map +1 -0
- package/dist/src/auth/device.js +227 -0
- package/dist/src/auth/device.js.map +1 -0
- package/dist/src/auth/discovery.d.ts +23 -0
- package/dist/src/auth/discovery.d.ts.map +1 -0
- package/dist/src/auth/discovery.js +40 -0
- package/dist/src/auth/discovery.js.map +1 -0
- package/dist/src/auth/index.d.ts +56 -0
- package/dist/src/auth/index.d.ts.map +1 -0
- package/dist/src/auth/index.js +69 -0
- package/dist/src/auth/index.js.map +1 -0
- package/dist/src/auth/keys.d.ts +55 -0
- package/dist/src/auth/keys.d.ts.map +1 -0
- package/dist/src/auth/keys.js +78 -0
- package/dist/src/auth/keys.js.map +1 -0
- package/dist/src/beast2.d.ts +15 -3
- package/dist/src/beast2.d.ts.map +1 -1
- package/dist/src/beast2.js +38 -8
- package/dist/src/beast2.js.map +1 -1
- package/dist/src/cli.js +58 -6
- package/dist/src/cli.js.map +1 -1
- package/dist/src/errors.d.ts +11 -0
- package/dist/src/errors.d.ts.map +1 -1
- package/dist/src/errors.js +95 -2
- package/dist/src/errors.js.map +1 -1
- package/dist/src/handlers/dataflow.d.ts +43 -0
- package/dist/src/handlers/dataflow.d.ts.map +1 -0
- package/dist/src/handlers/dataflow.js +363 -0
- package/dist/src/handlers/dataflow.js.map +1 -0
- package/dist/src/handlers/datasets.d.ts +39 -0
- package/dist/src/handlers/datasets.d.ts.map +1 -0
- package/dist/src/handlers/datasets.js +232 -0
- package/dist/src/handlers/datasets.js.map +1 -0
- package/dist/src/handlers/datasets.spec.d.ts +6 -0
- package/dist/src/handlers/datasets.spec.d.ts.map +1 -0
- package/dist/src/handlers/datasets.spec.js +151 -0
- package/dist/src/handlers/datasets.spec.js.map +1 -0
- package/dist/src/handlers/index.d.ts +11 -0
- package/dist/src/handlers/index.d.ts.map +1 -0
- package/dist/src/handlers/index.js +11 -0
- package/dist/src/handlers/index.js.map +1 -0
- package/dist/src/handlers/packages.d.ts +18 -0
- package/dist/src/handlers/packages.d.ts.map +1 -0
- package/dist/src/handlers/packages.js +51 -0
- package/dist/src/handlers/packages.js.map +1 -0
- package/dist/src/handlers/repository.d.ts +24 -0
- package/dist/src/handlers/repository.d.ts.map +1 -0
- package/dist/src/handlers/repository.js +79 -0
- package/dist/src/handlers/repository.js.map +1 -0
- package/dist/src/handlers/tasks.d.ts +18 -0
- package/dist/src/handlers/tasks.d.ts.map +1 -0
- package/dist/src/handlers/tasks.js +136 -0
- package/dist/src/handlers/tasks.js.map +1 -0
- package/dist/src/handlers/workspaces.d.ts +34 -0
- package/dist/src/handlers/workspaces.d.ts.map +1 -0
- package/dist/src/handlers/workspaces.js +225 -0
- package/dist/src/handlers/workspaces.js.map +1 -0
- package/dist/src/index.d.ts +3 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +6 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/middleware/auth.d.ts +51 -0
- package/dist/src/middleware/auth.d.ts.map +1 -0
- package/dist/src/middleware/auth.js +158 -0
- package/dist/src/middleware/auth.js.map +1 -0
- package/dist/src/orchestrator-manager.d.ts +45 -0
- package/dist/src/orchestrator-manager.d.ts.map +1 -0
- package/dist/src/orchestrator-manager.js +150 -0
- package/dist/src/orchestrator-manager.js.map +1 -0
- package/dist/src/routes/data.d.ts +21 -0
- package/dist/src/routes/data.d.ts.map +1 -0
- package/dist/src/routes/data.js +123 -0
- package/dist/src/routes/data.js.map +1 -0
- package/dist/src/routes/datasets.d.ts +2 -1
- package/dist/src/routes/datasets.d.ts.map +1 -1
- package/dist/src/routes/datasets.js +59 -83
- package/dist/src/routes/datasets.js.map +1 -1
- package/dist/src/routes/executions.d.ts +2 -1
- package/dist/src/routes/executions.d.ts.map +1 -1
- package/dist/src/routes/executions.js +54 -287
- package/dist/src/routes/executions.js.map +1 -1
- package/dist/src/routes/index.d.ts +15 -0
- package/dist/src/routes/index.d.ts.map +1 -0
- package/dist/src/routes/index.js +15 -0
- package/dist/src/routes/index.js.map +1 -0
- package/dist/src/routes/objects.d.ts +8 -0
- package/dist/src/routes/objects.d.ts.map +1 -0
- package/dist/src/routes/objects.js +37 -0
- package/dist/src/routes/objects.js.map +1 -0
- package/dist/src/routes/package-transfer.d.ts +23 -0
- package/dist/src/routes/package-transfer.d.ts.map +1 -0
- package/dist/src/routes/package-transfer.js +152 -0
- package/dist/src/routes/package-transfer.js.map +1 -0
- package/dist/src/routes/packages.d.ts +2 -1
- package/dist/src/routes/packages.d.ts.map +1 -1
- package/dist/src/routes/packages.js +18 -109
- package/dist/src/routes/packages.js.map +1 -1
- package/dist/src/routes/repository.d.ts +2 -1
- package/dist/src/routes/repository.d.ts.map +1 -1
- package/dist/src/routes/repository.js +19 -54
- package/dist/src/routes/repository.js.map +1 -1
- package/dist/src/routes/tasks.d.ts +2 -1
- package/dist/src/routes/tasks.d.ts.map +1 -1
- package/dist/src/routes/tasks.js +22 -46
- package/dist/src/routes/tasks.js.map +1 -1
- package/dist/src/routes/transfer.d.ts +19 -0
- package/dist/src/routes/transfer.d.ts.map +1 -0
- package/dist/src/routes/transfer.js +124 -0
- package/dist/src/routes/transfer.js.map +1 -0
- package/dist/src/routes/workspaces.d.ts +2 -1
- package/dist/src/routes/workspaces.d.ts.map +1 -1
- package/dist/src/routes/workspaces.js +83 -112
- package/dist/src/routes/workspaces.js.map +1 -1
- package/dist/src/server.d.ts +24 -3
- package/dist/src/server.d.ts.map +1 -1
- package/dist/src/server.js +270 -19
- package/dist/src/server.js.map +1 -1
- package/dist/src/types.d.ts +786 -1223
- package/dist/src/types.d.ts.map +1 -1
- package/dist/src/types.js +65 -407
- package/dist/src/types.js.map +1 -1
- package/package.json +28 -16
|
@@ -0,0 +1,363 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 Elara AI Pty Ltd
|
|
3
|
+
* Licensed under BSL 1.1. See LICENSE for details.
|
|
4
|
+
*/
|
|
5
|
+
import { NullType, some, none, variant } from '@elaraai/east';
|
|
6
|
+
import { dataflowGetGraph, workspaceStatus, executionFindCurrent, executionReadLog, WorkspaceLockError, ExecutionNotFoundError, coreEventToApiEvent, coreStatusToApiStatus, } from '@elaraai/e3-core';
|
|
7
|
+
import { sendSuccess, sendError, sendSuccessWithStatus } from '../beast2.js';
|
|
8
|
+
import { errorToVariant } from '../errors.js';
|
|
9
|
+
import { WorkspaceStatusResultType, DataflowGraphType, LogChunkType, DataflowExecutionStateType, } from '../types.js';
|
|
10
|
+
import { getOrchestrator, getStateStore, setActiveExecution, getActiveExecution, getLatestExecution, getExecutionStartTime, clearActiveExecution, } from '../orchestrator-manager.js';
|
|
11
|
+
/**
|
|
12
|
+
* Convert core DatasetStatusInfo to API type.
|
|
13
|
+
*/
|
|
14
|
+
function convertDatasetStatus(info) {
|
|
15
|
+
let status;
|
|
16
|
+
switch (info.status.type) {
|
|
17
|
+
case 'unset':
|
|
18
|
+
status = variant('unset', null);
|
|
19
|
+
break;
|
|
20
|
+
case 'stale':
|
|
21
|
+
status = variant('stale', null);
|
|
22
|
+
break;
|
|
23
|
+
case 'up-to-date':
|
|
24
|
+
status = variant('up-to-date', null);
|
|
25
|
+
break;
|
|
26
|
+
}
|
|
27
|
+
return {
|
|
28
|
+
path: info.path,
|
|
29
|
+
status,
|
|
30
|
+
hash: info.hash ? some(info.hash) : none,
|
|
31
|
+
isTaskOutput: info.isTaskOutput,
|
|
32
|
+
producedBy: info.producedBy ? some(info.producedBy) : none,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Convert core TaskStatusInfo to API type.
|
|
37
|
+
*/
|
|
38
|
+
function convertTaskStatus(info) {
|
|
39
|
+
let status;
|
|
40
|
+
switch (info.status.type) {
|
|
41
|
+
case 'up-to-date':
|
|
42
|
+
status = variant('up-to-date', { cached: info.status.cached });
|
|
43
|
+
break;
|
|
44
|
+
case 'ready':
|
|
45
|
+
status = variant('ready', null);
|
|
46
|
+
break;
|
|
47
|
+
case 'waiting':
|
|
48
|
+
status = variant('waiting', { reason: info.status.reason });
|
|
49
|
+
break;
|
|
50
|
+
case 'in-progress':
|
|
51
|
+
status = variant('in-progress', {
|
|
52
|
+
pid: info.status.pid != null ? some(BigInt(info.status.pid)) : none,
|
|
53
|
+
startedAt: info.status.startedAt ? some(info.status.startedAt) : none,
|
|
54
|
+
});
|
|
55
|
+
break;
|
|
56
|
+
case 'failed':
|
|
57
|
+
status = variant('failed', {
|
|
58
|
+
exitCode: BigInt(info.status.exitCode),
|
|
59
|
+
completedAt: info.status.completedAt ? some(info.status.completedAt) : none,
|
|
60
|
+
});
|
|
61
|
+
break;
|
|
62
|
+
case 'error':
|
|
63
|
+
status = variant('error', {
|
|
64
|
+
message: info.status.message,
|
|
65
|
+
completedAt: info.status.completedAt ? some(info.status.completedAt) : none,
|
|
66
|
+
});
|
|
67
|
+
break;
|
|
68
|
+
case 'stale-running':
|
|
69
|
+
status = variant('stale-running', {
|
|
70
|
+
pid: info.status.pid != null ? some(BigInt(info.status.pid)) : none,
|
|
71
|
+
startedAt: info.status.startedAt ? some(info.status.startedAt) : none,
|
|
72
|
+
});
|
|
73
|
+
break;
|
|
74
|
+
}
|
|
75
|
+
return {
|
|
76
|
+
name: info.name,
|
|
77
|
+
hash: info.hash,
|
|
78
|
+
status,
|
|
79
|
+
inputs: info.inputs,
|
|
80
|
+
output: info.output,
|
|
81
|
+
dependsOn: info.dependsOn,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Convert core WorkspaceStatusResult to API type.
|
|
86
|
+
*/
|
|
87
|
+
function convertWorkspaceStatus(result) {
|
|
88
|
+
return {
|
|
89
|
+
workspace: result.workspace,
|
|
90
|
+
lock: result.lock && result.lock.pid !== undefined
|
|
91
|
+
? some({
|
|
92
|
+
pid: BigInt(result.lock.pid),
|
|
93
|
+
acquiredAt: result.lock.acquiredAt,
|
|
94
|
+
bootId: result.lock.bootId ? some(result.lock.bootId) : none,
|
|
95
|
+
command: result.lock.command ? some(result.lock.command) : none,
|
|
96
|
+
})
|
|
97
|
+
: none,
|
|
98
|
+
datasets: result.datasets.map(convertDatasetStatus),
|
|
99
|
+
tasks: result.tasks.map(convertTaskStatus),
|
|
100
|
+
summary: {
|
|
101
|
+
datasets: {
|
|
102
|
+
total: BigInt(result.summary.datasets.total),
|
|
103
|
+
unset: BigInt(result.summary.datasets.unset),
|
|
104
|
+
stale: BigInt(result.summary.datasets.stale),
|
|
105
|
+
upToDate: BigInt(result.summary.datasets.upToDate),
|
|
106
|
+
},
|
|
107
|
+
tasks: {
|
|
108
|
+
total: BigInt(result.summary.tasks.total),
|
|
109
|
+
upToDate: BigInt(result.summary.tasks.upToDate),
|
|
110
|
+
ready: BigInt(result.summary.tasks.ready),
|
|
111
|
+
waiting: BigInt(result.summary.tasks.waiting),
|
|
112
|
+
inProgress: BigInt(result.summary.tasks.inProgress),
|
|
113
|
+
failed: BigInt(result.summary.tasks.failed),
|
|
114
|
+
error: BigInt(result.summary.tasks.error),
|
|
115
|
+
staleRunning: BigInt(result.summary.tasks.staleRunning),
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Start dataflow execution (non-blocking).
|
|
122
|
+
*
|
|
123
|
+
* Returns 202 Accepted immediately and runs execution in background.
|
|
124
|
+
* Creates execution state that can be polled via getDataflowExecution().
|
|
125
|
+
*/
|
|
126
|
+
export async function startDataflow(storage, repoPath, workspace, options) {
|
|
127
|
+
try {
|
|
128
|
+
const orchestrator = getOrchestrator(repoPath);
|
|
129
|
+
// Start execution via orchestrator (acquires lock internally)
|
|
130
|
+
const handle = await orchestrator.start(storage, repoPath, workspace, {
|
|
131
|
+
concurrency: options.concurrency,
|
|
132
|
+
force: options.force,
|
|
133
|
+
filter: options.filter,
|
|
134
|
+
});
|
|
135
|
+
// Track as active execution for this workspace
|
|
136
|
+
setActiveExecution(repoPath, workspace, handle);
|
|
137
|
+
// Set up completion handler to clear active execution
|
|
138
|
+
orchestrator.wait(handle).then(() => {
|
|
139
|
+
clearActiveExecution(repoPath, workspace);
|
|
140
|
+
}).catch(() => {
|
|
141
|
+
clearActiveExecution(repoPath, workspace);
|
|
142
|
+
});
|
|
143
|
+
// Return immediately with 202 Accepted
|
|
144
|
+
return sendSuccessWithStatus(NullType, null, 202);
|
|
145
|
+
}
|
|
146
|
+
catch (err) {
|
|
147
|
+
if (err instanceof WorkspaceLockError) {
|
|
148
|
+
return sendError(NullType, errorToVariant(err));
|
|
149
|
+
}
|
|
150
|
+
return sendError(NullType, errorToVariant(err));
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Get workspace status (for polling).
|
|
155
|
+
*/
|
|
156
|
+
export async function getDataflowStatus(storage, repoPath, workspace) {
|
|
157
|
+
try {
|
|
158
|
+
const result = await workspaceStatus(storage, repoPath, workspace);
|
|
159
|
+
return sendSuccess(WorkspaceStatusResultType, convertWorkspaceStatus(result));
|
|
160
|
+
}
|
|
161
|
+
catch (err) {
|
|
162
|
+
return sendError(WorkspaceStatusResultType, errorToVariant(err));
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Get dependency graph.
|
|
167
|
+
*/
|
|
168
|
+
export async function getDataflowGraph(storage, repoPath, workspace) {
|
|
169
|
+
try {
|
|
170
|
+
const graph = await dataflowGetGraph(storage, repoPath, workspace);
|
|
171
|
+
return sendSuccess(DataflowGraphType, {
|
|
172
|
+
tasks: graph.tasks.map((t) => ({
|
|
173
|
+
name: t.name,
|
|
174
|
+
hash: t.hash,
|
|
175
|
+
inputs: t.inputs,
|
|
176
|
+
output: t.output,
|
|
177
|
+
dependsOn: t.dependsOn,
|
|
178
|
+
})),
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
catch (err) {
|
|
182
|
+
return sendError(DataflowGraphType, errorToVariant(err));
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Get task logs.
|
|
187
|
+
*/
|
|
188
|
+
export async function getTaskLogs(storage, repoPath, workspace, taskName, stream, offset, limit) {
|
|
189
|
+
try {
|
|
190
|
+
// Find the current execution for this task
|
|
191
|
+
const execution = await executionFindCurrent(storage, repoPath, workspace, taskName);
|
|
192
|
+
if (!execution) {
|
|
193
|
+
throw new ExecutionNotFoundError(taskName);
|
|
194
|
+
}
|
|
195
|
+
// Read logs
|
|
196
|
+
const chunk = await executionReadLog(storage, repoPath, execution.taskHash, execution.inputsHash, execution.executionId, stream, { offset, limit });
|
|
197
|
+
return sendSuccess(LogChunkType, {
|
|
198
|
+
data: chunk.data,
|
|
199
|
+
offset: BigInt(chunk.offset),
|
|
200
|
+
size: BigInt(chunk.size),
|
|
201
|
+
totalSize: BigInt(chunk.totalSize),
|
|
202
|
+
complete: chunk.complete,
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
catch (err) {
|
|
206
|
+
return sendError(LogChunkType, errorToVariant(err));
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Get dataflow execution state (for polling).
|
|
211
|
+
*
|
|
212
|
+
* Returns the current execution state including events for progress tracking.
|
|
213
|
+
* Supports offset/limit for paginating events.
|
|
214
|
+
*/
|
|
215
|
+
export async function getDataflowExecution(repoPath, workspace, options = {}) {
|
|
216
|
+
const stateStore = getStateStore(repoPath);
|
|
217
|
+
// Find the latest execution for this workspace
|
|
218
|
+
const handle = await getLatestExecution(repoPath, workspace);
|
|
219
|
+
if (!handle) {
|
|
220
|
+
return sendError(DataflowExecutionStateType, variant('execution_not_found', {
|
|
221
|
+
task: workspace,
|
|
222
|
+
}));
|
|
223
|
+
}
|
|
224
|
+
// Read execution state
|
|
225
|
+
const coreState = await stateStore.read(repoPath, workspace, handle.id);
|
|
226
|
+
if (!coreState) {
|
|
227
|
+
return sendError(DataflowExecutionStateType, variant('execution_not_found', {
|
|
228
|
+
task: workspace,
|
|
229
|
+
}));
|
|
230
|
+
}
|
|
231
|
+
// Count total API-visible events, then slice for pagination
|
|
232
|
+
const offset = options.offset ?? 0;
|
|
233
|
+
const allEvents = coreState.events;
|
|
234
|
+
let totalApiEvents = 0;
|
|
235
|
+
for (const event of allEvents) {
|
|
236
|
+
if (coreEventToApiEvent(event) !== null) {
|
|
237
|
+
totalApiEvents++;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
// Apply offset and limit
|
|
241
|
+
let events = allEvents.slice(offset);
|
|
242
|
+
if (options.limit !== undefined) {
|
|
243
|
+
events = events.slice(0, options.limit);
|
|
244
|
+
}
|
|
245
|
+
// Convert page events to API format
|
|
246
|
+
const apiEvents = [];
|
|
247
|
+
for (const event of events) {
|
|
248
|
+
const apiEvent = coreEventToApiEvent(event);
|
|
249
|
+
if (apiEvent !== null) {
|
|
250
|
+
// Convert to East variant format
|
|
251
|
+
switch (apiEvent.type) {
|
|
252
|
+
case 'start':
|
|
253
|
+
apiEvents.push(variant('start', {
|
|
254
|
+
task: apiEvent.task,
|
|
255
|
+
timestamp: apiEvent.timestamp,
|
|
256
|
+
}));
|
|
257
|
+
break;
|
|
258
|
+
case 'complete':
|
|
259
|
+
apiEvents.push(variant('complete', {
|
|
260
|
+
task: apiEvent.task,
|
|
261
|
+
timestamp: apiEvent.timestamp,
|
|
262
|
+
duration: apiEvent.duration ?? 0,
|
|
263
|
+
}));
|
|
264
|
+
break;
|
|
265
|
+
case 'cached':
|
|
266
|
+
apiEvents.push(variant('cached', {
|
|
267
|
+
task: apiEvent.task,
|
|
268
|
+
timestamp: apiEvent.timestamp,
|
|
269
|
+
}));
|
|
270
|
+
break;
|
|
271
|
+
case 'failed':
|
|
272
|
+
apiEvents.push(variant('failed', {
|
|
273
|
+
task: apiEvent.task,
|
|
274
|
+
timestamp: apiEvent.timestamp,
|
|
275
|
+
duration: apiEvent.duration ?? 0,
|
|
276
|
+
exitCode: apiEvent.exitCode ?? BigInt(-1),
|
|
277
|
+
}));
|
|
278
|
+
break;
|
|
279
|
+
case 'error':
|
|
280
|
+
apiEvents.push(variant('error', {
|
|
281
|
+
task: apiEvent.task,
|
|
282
|
+
timestamp: apiEvent.timestamp,
|
|
283
|
+
message: apiEvent.message ?? 'Unknown error',
|
|
284
|
+
}));
|
|
285
|
+
break;
|
|
286
|
+
case 'input_unavailable':
|
|
287
|
+
apiEvents.push(variant('input_unavailable', {
|
|
288
|
+
task: apiEvent.task,
|
|
289
|
+
timestamp: apiEvent.timestamp,
|
|
290
|
+
reason: apiEvent.reason ?? 'Upstream task failed',
|
|
291
|
+
}));
|
|
292
|
+
break;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
// Convert status to API format
|
|
297
|
+
const apiStatus = coreStatusToApiStatus(coreState.status);
|
|
298
|
+
let status;
|
|
299
|
+
switch (apiStatus) {
|
|
300
|
+
case 'running':
|
|
301
|
+
status = variant('running', null);
|
|
302
|
+
break;
|
|
303
|
+
case 'completed':
|
|
304
|
+
status = variant('completed', null);
|
|
305
|
+
break;
|
|
306
|
+
case 'failed':
|
|
307
|
+
status = variant('failed', null);
|
|
308
|
+
break;
|
|
309
|
+
case 'aborted':
|
|
310
|
+
status = variant('aborted', null);
|
|
311
|
+
break;
|
|
312
|
+
}
|
|
313
|
+
// Calculate duration
|
|
314
|
+
const startTime = getExecutionStartTime(repoPath, workspace, handle.id);
|
|
315
|
+
const duration = startTime ? Date.now() - startTime : 0;
|
|
316
|
+
// Build summary if not running
|
|
317
|
+
let summary;
|
|
318
|
+
if (coreState.status !== 'running') {
|
|
319
|
+
summary = some({
|
|
320
|
+
executed: coreState.executed,
|
|
321
|
+
cached: coreState.cached,
|
|
322
|
+
failed: coreState.failed,
|
|
323
|
+
skipped: coreState.skipped,
|
|
324
|
+
duration,
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
else {
|
|
328
|
+
summary = none;
|
|
329
|
+
}
|
|
330
|
+
// Get completedAt value (handle Option type)
|
|
331
|
+
const completedAtValue = coreState.completedAt.type === 'some'
|
|
332
|
+
? some(coreState.completedAt.value.toISOString())
|
|
333
|
+
: none;
|
|
334
|
+
const state = {
|
|
335
|
+
status,
|
|
336
|
+
startedAt: coreState.startedAt.toISOString(),
|
|
337
|
+
completedAt: completedAtValue,
|
|
338
|
+
summary,
|
|
339
|
+
events: apiEvents,
|
|
340
|
+
totalEvents: BigInt(totalApiEvents),
|
|
341
|
+
};
|
|
342
|
+
return sendSuccess(DataflowExecutionStateType, state);
|
|
343
|
+
}
|
|
344
|
+
/**
|
|
345
|
+
* Cancel a running dataflow execution.
|
|
346
|
+
*/
|
|
347
|
+
export async function cancelDataflow(repoPath, workspace) {
|
|
348
|
+
try {
|
|
349
|
+
const orchestrator = getOrchestrator(repoPath);
|
|
350
|
+
const execution = getActiveExecution(repoPath, workspace);
|
|
351
|
+
if (!execution) {
|
|
352
|
+
return sendError(NullType, variant('internal', {
|
|
353
|
+
message: 'No active execution for this workspace',
|
|
354
|
+
}));
|
|
355
|
+
}
|
|
356
|
+
await orchestrator.cancel(execution);
|
|
357
|
+
return sendSuccess(NullType, null);
|
|
358
|
+
}
|
|
359
|
+
catch (err) {
|
|
360
|
+
return sendError(NullType, errorToVariant(err));
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
//# sourceMappingURL=dataflow.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dataflow.js","sourceRoot":"","sources":["../../../src/handlers/dataflow.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 Elara AI Pty Ltd
|
|
3
|
+
* Licensed under BSL 1.1. See LICENSE for details.
|
|
4
|
+
*/
|
|
5
|
+
import type { TreePath } from '@elaraai/e3-types';
|
|
6
|
+
import { type StorageBackend, type TransferBackend } from '@elaraai/e3-core';
|
|
7
|
+
/**
|
|
8
|
+
* List dataset fields at the given path.
|
|
9
|
+
*/
|
|
10
|
+
export declare function listDatasets(storage: StorageBackend, repoPath: string, workspace: string, treePath: TreePath): Promise<Response>;
|
|
11
|
+
/**
|
|
12
|
+
* Get dataset value as raw BEAST2 bytes.
|
|
13
|
+
*
|
|
14
|
+
* For objects > 1MB, returns a JSON response with a download URL
|
|
15
|
+
* that the client can fetch directly. This avoids browser issues
|
|
16
|
+
* with opaque redirect responses from `redirect: 'manual'`.
|
|
17
|
+
*/
|
|
18
|
+
export declare function getDataset(storage: StorageBackend, repoPath: string, workspace: string, treePath: TreePath, repo?: string, requestUrl?: string, transferBackend?: TransferBackend): Promise<Response>;
|
|
19
|
+
/**
|
|
20
|
+
* Set dataset value from raw BEAST2 bytes.
|
|
21
|
+
*/
|
|
22
|
+
export declare function setDataset(storage: StorageBackend, repoPath: string, workspace: string, treePath: TreePath, body: Uint8Array): Promise<Response>;
|
|
23
|
+
/**
|
|
24
|
+
* Get status detail for a single dataset.
|
|
25
|
+
*/
|
|
26
|
+
export declare function getDatasetStatus(storage: StorageBackend, repoPath: string, workspace: string, treePath: TreePath): Promise<Response>;
|
|
27
|
+
/**
|
|
28
|
+
* List datasets recursively (flat list with paths, types, and status).
|
|
29
|
+
*/
|
|
30
|
+
export declare function listDatasetsRecursive(storage: StorageBackend, repoPath: string, workspace: string, treePath: TreePath): Promise<Response>;
|
|
31
|
+
/**
|
|
32
|
+
* List all descendant dataset paths (string[]).
|
|
33
|
+
*/
|
|
34
|
+
export declare function listDatasetsRecursivePaths(storage: StorageBackend, repoPath: string, workspace: string, treePath: TreePath): Promise<Response>;
|
|
35
|
+
/**
|
|
36
|
+
* List immediate children with types and status (ListEntry[]).
|
|
37
|
+
*/
|
|
38
|
+
export declare function listDatasetsWithStatus(storage: StorageBackend, repoPath: string, workspace: string, treePath: TreePath): Promise<Response>;
|
|
39
|
+
//# sourceMappingURL=datasets.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"datasets.d.ts","sourceRoot":"","sources":["../../../src/handlers/datasets.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AASlD,OAAO,EAAuB,KAAK,cAAc,EAAE,KAAK,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAKlG;;GAEG;AACH,wBAAsB,YAAY,CAChC,OAAO,EAAE,cAAc,EACvB,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,QAAQ,GACjB,OAAO,CAAC,QAAQ,CAAC,CAOnB;AAID;;;;;;GAMG;AACH,wBAAsB,UAAU,CAC9B,OAAO,EAAE,cAAc,EACvB,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,QAAQ,EAClB,IAAI,CAAC,EAAE,MAAM,EACb,UAAU,CAAC,EAAE,MAAM,EACnB,eAAe,CAAC,EAAE,eAAe,GAChC,OAAO,CAAC,QAAQ,CAAC,CA2DnB;AAED;;GAEG;AACH,wBAAsB,UAAU,CAC9B,OAAO,EAAE,cAAc,EACvB,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,QAAQ,EAClB,IAAI,EAAE,UAAU,GACf,OAAO,CAAC,QAAQ,CAAC,CAcnB;AAqCD;;GAEG;AACH,wBAAsB,gBAAgB,CACpC,OAAO,EAAE,cAAc,EACvB,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,QAAQ,GACjB,OAAO,CAAC,QAAQ,CAAC,CA4BnB;AAED;;GAEG;AACH,wBAAsB,qBAAqB,CACzC,OAAO,EAAE,cAAc,EACvB,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,QAAQ,GACjB,OAAO,CAAC,QAAQ,CAAC,CAmBnB;AAoBD;;GAEG;AACH,wBAAsB,0BAA0B,CAC9C,OAAO,EAAE,cAAc,EACvB,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,QAAQ,GACjB,OAAO,CAAC,QAAQ,CAAC,CAenB;AAED;;GAEG;AACH,wBAAsB,sBAAsB,CAC1C,OAAO,EAAE,cAAc,EACvB,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,QAAQ,GACjB,OAAO,CAAC,QAAQ,CAAC,CAgBnB"}
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 Elara AI Pty Ltd
|
|
3
|
+
* Licensed under BSL 1.1. See LICENSE for details.
|
|
4
|
+
*/
|
|
5
|
+
import { NullType, ArrayType, StringType, decodeBeast2, some, none, variant, toEastTypeValue, isVariant } from '@elaraai/east';
|
|
6
|
+
import { workspaceListTree, workspaceGetDatasetHash, workspaceGetDatasetStatus, workspaceSetDataset, workspaceGetTree, } from '@elaraai/e3-core';
|
|
7
|
+
import { BEAST2_CONTENT_TYPE } from '@elaraai/e3-core';
|
|
8
|
+
import { sendSuccess, sendError } from '../beast2.js';
|
|
9
|
+
import { errorToVariant, sendJsonError } from '../errors.js';
|
|
10
|
+
import { DatasetStatusDetailType, ListEntryType } from '../types.js';
|
|
11
|
+
/**
|
|
12
|
+
* List dataset fields at the given path.
|
|
13
|
+
*/
|
|
14
|
+
export async function listDatasets(storage, repoPath, workspace, treePath) {
|
|
15
|
+
try {
|
|
16
|
+
const fields = await workspaceListTree(storage, repoPath, workspace, treePath);
|
|
17
|
+
return sendSuccess(ArrayType(StringType), fields);
|
|
18
|
+
}
|
|
19
|
+
catch (err) {
|
|
20
|
+
return sendError(ArrayType(StringType), errorToVariant(err));
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
const SIZE_THRESHOLD = 1 * 1024 * 1024; // 1 MB
|
|
24
|
+
/**
|
|
25
|
+
* Get dataset value as raw BEAST2 bytes.
|
|
26
|
+
*
|
|
27
|
+
* For objects > 1MB, returns a JSON response with a download URL
|
|
28
|
+
* that the client can fetch directly. This avoids browser issues
|
|
29
|
+
* with opaque redirect responses from `redirect: 'manual'`.
|
|
30
|
+
*/
|
|
31
|
+
export async function getDataset(storage, repoPath, workspace, treePath, repo, requestUrl, transferBackend) {
|
|
32
|
+
try {
|
|
33
|
+
if (treePath.length === 0) {
|
|
34
|
+
return new Response(JSON.stringify({ error: { type: 'bad_request', message: 'Path required for get' } }), {
|
|
35
|
+
status: 400,
|
|
36
|
+
headers: { 'Content-Type': 'application/json' },
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
const { refType, hash } = await workspaceGetDatasetHash(storage, repoPath, workspace, treePath);
|
|
40
|
+
if (refType === 'unassigned') {
|
|
41
|
+
return new Response(JSON.stringify({ error: { type: 'dataset_unassigned', message: 'Dataset is unassigned (pending task output)' } }), {
|
|
42
|
+
status: 404,
|
|
43
|
+
headers: { 'Content-Type': 'application/json' },
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
if (refType === 'null' || !hash) {
|
|
47
|
+
return new Response(JSON.stringify({ error: { type: 'dataset_null', message: 'Dataset is null' } }), {
|
|
48
|
+
status: 404,
|
|
49
|
+
headers: { 'Content-Type': 'application/json' },
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
// When serving via API with a transfer backend, check size to decide whether to redirect
|
|
53
|
+
if (transferBackend && repo && requestUrl) {
|
|
54
|
+
const { size } = await storage.objects.stat(repoPath, hash);
|
|
55
|
+
if (size > SIZE_THRESHOLD) {
|
|
56
|
+
let downloadUrl = await transferBackend.datasetDownload.getDownloadUrl(repo, hash);
|
|
57
|
+
// Resolve relative URL against the request origin
|
|
58
|
+
if (downloadUrl.startsWith('/')) {
|
|
59
|
+
const origin = new URL(requestUrl).origin;
|
|
60
|
+
downloadUrl = `${origin}${downloadUrl}`;
|
|
61
|
+
}
|
|
62
|
+
return new Response(JSON.stringify({ url: downloadUrl }), {
|
|
63
|
+
status: 200,
|
|
64
|
+
headers: {
|
|
65
|
+
'Content-Type': 'application/json',
|
|
66
|
+
'X-Content-Length': String(size),
|
|
67
|
+
'X-Content-SHA256': hash,
|
|
68
|
+
},
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
// Inline response
|
|
73
|
+
const data = await storage.objects.read(repoPath, hash);
|
|
74
|
+
return new Response(data, {
|
|
75
|
+
status: 200,
|
|
76
|
+
headers: {
|
|
77
|
+
'Content-Type': BEAST2_CONTENT_TYPE,
|
|
78
|
+
'Content-Length': String(data.byteLength),
|
|
79
|
+
'X-Content-SHA256': hash,
|
|
80
|
+
},
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
catch (err) {
|
|
84
|
+
return sendJsonError(err);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Set dataset value from raw BEAST2 bytes.
|
|
89
|
+
*/
|
|
90
|
+
export async function setDataset(storage, repoPath, workspace, treePath, body) {
|
|
91
|
+
try {
|
|
92
|
+
if (treePath.length === 0) {
|
|
93
|
+
return sendError(NullType, errorToVariant(new Error('Path required for set')));
|
|
94
|
+
}
|
|
95
|
+
// Body is raw BEAST2 - decode to get type and value
|
|
96
|
+
const { type, value } = decodeBeast2(body);
|
|
97
|
+
await workspaceSetDataset(storage, repoPath, workspace, treePath, value, type);
|
|
98
|
+
return sendSuccess(NullType, null);
|
|
99
|
+
}
|
|
100
|
+
catch (err) {
|
|
101
|
+
return sendError(NullType, errorToVariant(err));
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Flatten a tree of nodes into a list of ListEntry variants (dataset + tree entries).
|
|
106
|
+
*/
|
|
107
|
+
function flattenTreeEntries(nodes, pathPrefix, result, recursive) {
|
|
108
|
+
for (const node of nodes) {
|
|
109
|
+
const path = pathPrefix ? `${pathPrefix}.${node.name}` : `.${node.name}`;
|
|
110
|
+
if (node.kind === 'dataset') {
|
|
111
|
+
const datasetType = node.datasetType;
|
|
112
|
+
if (datasetType) {
|
|
113
|
+
const typeValue = isVariant(datasetType)
|
|
114
|
+
? datasetType
|
|
115
|
+
: toEastTypeValue(datasetType);
|
|
116
|
+
result.push(variant('dataset', {
|
|
117
|
+
path,
|
|
118
|
+
type: typeValue,
|
|
119
|
+
hash: node.hash ? some(node.hash) : none,
|
|
120
|
+
size: node.size !== undefined ? some(BigInt(node.size)) : none,
|
|
121
|
+
}));
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
else if (node.kind === 'tree') {
|
|
125
|
+
result.push(variant('tree', { path, kind: variant('struct', null) }));
|
|
126
|
+
if (recursive) {
|
|
127
|
+
flattenTreeEntries(node.children, path, result, recursive);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Get status detail for a single dataset.
|
|
134
|
+
*/
|
|
135
|
+
export async function getDatasetStatus(storage, repoPath, workspace, treePath) {
|
|
136
|
+
try {
|
|
137
|
+
if (treePath.length === 0) {
|
|
138
|
+
return sendError(DatasetStatusDetailType, errorToVariant(new Error('Path required for status')));
|
|
139
|
+
}
|
|
140
|
+
const result = await workspaceGetDatasetStatus(storage, repoPath, workspace, treePath);
|
|
141
|
+
// Build path string from treePath
|
|
142
|
+
const pathStr = '.' + treePath.map(s => s.value).join('.');
|
|
143
|
+
// Convert EastType to EastTypeValue if needed
|
|
144
|
+
const typeValue = isVariant(result.datasetType)
|
|
145
|
+
? result.datasetType
|
|
146
|
+
: toEastTypeValue(result.datasetType);
|
|
147
|
+
const detail = {
|
|
148
|
+
path: pathStr,
|
|
149
|
+
type: typeValue,
|
|
150
|
+
refType: result.refType,
|
|
151
|
+
hash: result.hash ? some(result.hash) : none,
|
|
152
|
+
size: result.size !== null ? some(BigInt(result.size)) : none,
|
|
153
|
+
};
|
|
154
|
+
return sendSuccess(DatasetStatusDetailType, detail);
|
|
155
|
+
}
|
|
156
|
+
catch (err) {
|
|
157
|
+
return sendError(DatasetStatusDetailType, errorToVariant(err));
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* List datasets recursively (flat list with paths, types, and status).
|
|
162
|
+
*/
|
|
163
|
+
export async function listDatasetsRecursive(storage, repoPath, workspace, treePath) {
|
|
164
|
+
try {
|
|
165
|
+
// Get tree with types and status included
|
|
166
|
+
const nodes = await workspaceGetTree(storage, repoPath, workspace, treePath, {
|
|
167
|
+
includeTypes: true,
|
|
168
|
+
includeStatus: true,
|
|
169
|
+
});
|
|
170
|
+
// Build path prefix from treePath
|
|
171
|
+
const pathPrefix = treePath.map(seg => seg.value).join('.');
|
|
172
|
+
// Flatten to list (includes tree entries)
|
|
173
|
+
const result = [];
|
|
174
|
+
flattenTreeEntries(nodes, pathPrefix ? `.${pathPrefix}` : '', result, true);
|
|
175
|
+
return sendSuccess(ArrayType(ListEntryType), result);
|
|
176
|
+
}
|
|
177
|
+
catch (err) {
|
|
178
|
+
return sendError(ArrayType(ListEntryType), errorToVariant(err));
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Flatten tree nodes into a list of dataset paths (no types/status).
|
|
183
|
+
*/
|
|
184
|
+
function flattenTreePaths(nodes, pathPrefix, result) {
|
|
185
|
+
for (const node of nodes) {
|
|
186
|
+
const path = pathPrefix ? `${pathPrefix}.${node.name}` : `.${node.name}`;
|
|
187
|
+
if (node.kind === 'dataset') {
|
|
188
|
+
result.push(path);
|
|
189
|
+
}
|
|
190
|
+
else if (node.kind === 'tree') {
|
|
191
|
+
flattenTreePaths(node.children, path, result);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* List all descendant dataset paths (string[]).
|
|
197
|
+
*/
|
|
198
|
+
export async function listDatasetsRecursivePaths(storage, repoPath, workspace, treePath) {
|
|
199
|
+
try {
|
|
200
|
+
const nodes = await workspaceGetTree(storage, repoPath, workspace, treePath, {
|
|
201
|
+
includeTypes: false,
|
|
202
|
+
includeStatus: false,
|
|
203
|
+
});
|
|
204
|
+
const pathPrefix = treePath.map(seg => seg.value).join('.');
|
|
205
|
+
const result = [];
|
|
206
|
+
flattenTreePaths(nodes, pathPrefix ? `.${pathPrefix}` : '', result);
|
|
207
|
+
return sendSuccess(ArrayType(StringType), result);
|
|
208
|
+
}
|
|
209
|
+
catch (err) {
|
|
210
|
+
return sendError(ArrayType(StringType), errorToVariant(err));
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* List immediate children with types and status (ListEntry[]).
|
|
215
|
+
*/
|
|
216
|
+
export async function listDatasetsWithStatus(storage, repoPath, workspace, treePath) {
|
|
217
|
+
try {
|
|
218
|
+
const nodes = await workspaceGetTree(storage, repoPath, workspace, treePath, {
|
|
219
|
+
maxDepth: 0,
|
|
220
|
+
includeTypes: true,
|
|
221
|
+
includeStatus: true,
|
|
222
|
+
});
|
|
223
|
+
const pathPrefix = treePath.map(seg => seg.value).join('.');
|
|
224
|
+
const result = [];
|
|
225
|
+
flattenTreeEntries(nodes, pathPrefix ? `.${pathPrefix}` : '', result, false);
|
|
226
|
+
return sendSuccess(ArrayType(ListEntryType), result);
|
|
227
|
+
}
|
|
228
|
+
catch (err) {
|
|
229
|
+
return sendError(ArrayType(ListEntryType), errorToVariant(err));
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
//# sourceMappingURL=datasets.js.map
|