@elaraai/e3-api-server 0.0.2-beta.4 → 0.0.2-beta.41
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/README.md +145 -30
- 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.map +1 -1
- package/dist/src/errors.js +8 -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 +38 -0
- package/dist/src/handlers/datasets.d.ts.map +1 -0
- package/dist/src/handlers/datasets.js +222 -0
- package/dist/src/handlers/datasets.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 +134 -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 +125 -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 +38 -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 +168 -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 +45 -116
- 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 +266 -19
- package/dist/src/server.js.map +1 -1
- package/dist/src/types.d.ts +1385 -731
- package/dist/src/types.d.ts.map +1 -1
- package/dist/src/types.js +238 -2
- package/dist/src/types.js.map +1 -1
- package/package.json +16 -4
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 Elara AI Pty Ltd
|
|
3
|
+
* Licensed under BSL 1.1. See LICENSE for details.
|
|
4
|
+
*/
|
|
5
|
+
import { Hono } from 'hono';
|
|
6
|
+
import { mkdir, readFile, unlink } from 'node:fs/promises';
|
|
7
|
+
import { join } from 'node:path';
|
|
8
|
+
import { tmpdir } from 'node:os';
|
|
9
|
+
import { randomUUID } from 'node:crypto';
|
|
10
|
+
import { variant, NullType } from '@elaraai/east';
|
|
11
|
+
import { urlPathToTreePath } from '@elaraai/e3-types';
|
|
12
|
+
import { computeHash, workspaceSetDatasetByHash, } from '@elaraai/e3-core';
|
|
13
|
+
import { decodeBody, sendSuccess, sendError } from '../beast2.js';
|
|
14
|
+
import { TransferUploadRequestType, TransferUploadResponseType, TransferDoneResponseType } from '../types.js';
|
|
15
|
+
const STAGING_DIR = join(tmpdir(), 'e3-transfers');
|
|
16
|
+
/**
|
|
17
|
+
* Create dataset transfer routes.
|
|
18
|
+
*
|
|
19
|
+
* Returns an `api` Hono app with authenticated routes (init upload, commit)
|
|
20
|
+
* mounted at /api/repos/:repo/workspaces/:ws/datasets.
|
|
21
|
+
*
|
|
22
|
+
* Unauthenticated data routes (upload/download bytes) are handled by the
|
|
23
|
+
* generic data endpoints in `data.ts`.
|
|
24
|
+
*/
|
|
25
|
+
export function createTransferRoutes(storage, getRepoPath, transferBackend) {
|
|
26
|
+
const api = new Hono();
|
|
27
|
+
/**
|
|
28
|
+
* Extract dataset path from the request URL wildcard.
|
|
29
|
+
* The route is mounted at /api/repos/:repo/workspaces/:ws/datasets
|
|
30
|
+
* so a request to .../datasets/inputs/config/upload yields path "inputs/config".
|
|
31
|
+
*/
|
|
32
|
+
function extractDatasetPath(c, suffix) {
|
|
33
|
+
const fullPath = c.req.path;
|
|
34
|
+
const repo = c.req.param('repo');
|
|
35
|
+
const ws = c.req.param('ws');
|
|
36
|
+
const datasetsPrefix = `/api/repos/${encodeURIComponent(repo)}/workspaces/${encodeURIComponent(ws)}/datasets/`;
|
|
37
|
+
let pathStr = fullPath.startsWith(datasetsPrefix) ? fullPath.slice(datasetsPrefix.length) : '';
|
|
38
|
+
// Strip trailing suffix (e.g. "/upload" or "/upload/<id>")
|
|
39
|
+
if (pathStr.endsWith(suffix)) {
|
|
40
|
+
pathStr = pathStr.slice(0, -suffix.length);
|
|
41
|
+
}
|
|
42
|
+
// Remove trailing slash
|
|
43
|
+
if (pathStr.endsWith('/')) {
|
|
44
|
+
pathStr = pathStr.slice(0, -1);
|
|
45
|
+
}
|
|
46
|
+
return pathStr;
|
|
47
|
+
}
|
|
48
|
+
// =========================================================================
|
|
49
|
+
// Authenticated API routes (mounted at /api/repos/:repo/workspaces/:ws/datasets)
|
|
50
|
+
// =========================================================================
|
|
51
|
+
// POST routes use catch-all wildcard and dispatch based on URL suffix:
|
|
52
|
+
// - .../datasets/<path>/upload → init transfer
|
|
53
|
+
// - .../datasets/<path>/upload/<id> → commit transfer
|
|
54
|
+
api.post('/*', async (c) => {
|
|
55
|
+
const fullPath = c.req.path;
|
|
56
|
+
// Check for commit: .../upload/<uuid>
|
|
57
|
+
const commitMatch = fullPath.match(/\/upload\/([0-9a-f-]{36})$/);
|
|
58
|
+
if (commitMatch) {
|
|
59
|
+
return handleCommit(c, commitMatch[1]);
|
|
60
|
+
}
|
|
61
|
+
// Check for init: .../upload
|
|
62
|
+
if (fullPath.endsWith('/upload')) {
|
|
63
|
+
return handleInit(c);
|
|
64
|
+
}
|
|
65
|
+
// Not a transfer route — return 404
|
|
66
|
+
return new Response('Not found', { status: 404 });
|
|
67
|
+
});
|
|
68
|
+
async function handleInit(c) {
|
|
69
|
+
const repo = c.req.param('repo');
|
|
70
|
+
const ws = c.req.param('ws');
|
|
71
|
+
const repoPath = getRepoPath(repo);
|
|
72
|
+
const pathStr = extractDatasetPath(c, '/upload');
|
|
73
|
+
const { hash, size } = await decodeBody(c, TransferUploadRequestType);
|
|
74
|
+
// Dedup check — object already verified when originally stored
|
|
75
|
+
if (await storage.objects.exists(repoPath, hash)) {
|
|
76
|
+
const treePath = urlPathToTreePath(pathStr);
|
|
77
|
+
await workspaceSetDatasetByHash(storage, repoPath, ws, treePath, hash, new Map());
|
|
78
|
+
return sendSuccess(TransferUploadResponseType, variant('completed', null));
|
|
79
|
+
}
|
|
80
|
+
// Create transfer record in backend
|
|
81
|
+
const transferId = randomUUID();
|
|
82
|
+
await transferBackend.datasetUpload.create(transferId, { repo, workspace: ws, path: pathStr, hash, size });
|
|
83
|
+
// Create staging slot in OS temp dir
|
|
84
|
+
await mkdir(STAGING_DIR, { recursive: true });
|
|
85
|
+
const uploadUrl = await transferBackend.datasetUpload.getUploadUrl(transferId, repo, hash);
|
|
86
|
+
// Resolve relative URL against the request origin
|
|
87
|
+
const origin = new URL(c.req.url).origin;
|
|
88
|
+
const resolvedUrl = uploadUrl.startsWith('/') ? `${origin}${uploadUrl}` : uploadUrl;
|
|
89
|
+
return sendSuccess(TransferUploadResponseType, variant('upload', { id: transferId, uploadUrl: resolvedUrl }));
|
|
90
|
+
}
|
|
91
|
+
async function handleCommit(c, id) {
|
|
92
|
+
const transfer = await transferBackend.datasetUpload.get(id);
|
|
93
|
+
if (!transfer) {
|
|
94
|
+
return sendError(NullType, variant('internal', { message: 'transfer not found' }));
|
|
95
|
+
}
|
|
96
|
+
const repoPath = getRepoPath(transfer.repo);
|
|
97
|
+
const stagingPath = join(STAGING_DIR, `${id}.beast2.partial`);
|
|
98
|
+
try {
|
|
99
|
+
// Read from staging to verify size and hash
|
|
100
|
+
const data = await readFile(stagingPath);
|
|
101
|
+
if (BigInt(data.byteLength) !== transfer.size) {
|
|
102
|
+
await unlink(stagingPath).catch(() => { });
|
|
103
|
+
return sendSuccess(TransferDoneResponseType, variant('error', { message: `size mismatch: expected ${transfer.size}, got ${data.byteLength}` }));
|
|
104
|
+
}
|
|
105
|
+
const actualHash = computeHash(data);
|
|
106
|
+
if (actualHash !== transfer.hash) {
|
|
107
|
+
await unlink(stagingPath).catch(() => { });
|
|
108
|
+
return sendSuccess(TransferDoneResponseType, variant('error', { message: `hash mismatch: expected ${transfer.hash}, got ${actualHash}` }));
|
|
109
|
+
}
|
|
110
|
+
// Write through storage abstraction (re-hashes internally, that's fine)
|
|
111
|
+
await storage.objects.write(repoPath, data);
|
|
112
|
+
await unlink(stagingPath).catch(() => { });
|
|
113
|
+
// Update dataset ref
|
|
114
|
+
const treePath = urlPathToTreePath(transfer.path);
|
|
115
|
+
await workspaceSetDatasetByHash(storage, repoPath, transfer.workspace, treePath, actualHash, new Map());
|
|
116
|
+
return sendSuccess(TransferDoneResponseType, variant('completed', null));
|
|
117
|
+
}
|
|
118
|
+
finally {
|
|
119
|
+
await transferBackend.datasetUpload.delete(id);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return { api };
|
|
123
|
+
}
|
|
124
|
+
//# sourceMappingURL=transfer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transfer.js","sourceRoot":"","sources":["../../../src/routes/transfer.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,5 +3,6 @@
|
|
|
3
3
|
* Licensed under BSL 1.1. See LICENSE for details.
|
|
4
4
|
*/
|
|
5
5
|
import { Hono } from 'hono';
|
|
6
|
-
|
|
6
|
+
import type { StorageBackend } from '@elaraai/e3-core';
|
|
7
|
+
export declare function createWorkspaceRoutes(storage: StorageBackend, getRepoPath: (repo: string) => string): Hono<import("hono/types").BlankEnv, import("hono/types").BlankSchema, "/">;
|
|
7
8
|
//# sourceMappingURL=workspaces.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workspaces.d.ts","sourceRoot":"","sources":["../../../src/routes/workspaces.ts"],"names":[],"mappings":"AAAA;;;GAGG;
|
|
1
|
+
{"version":3,"file":"workspaces.d.ts","sourceRoot":"","sources":["../../../src/routes/workspaces.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAavD,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,cAAc,EACvB,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,8EA6DtC"}
|
|
@@ -2,131 +2,60 @@
|
|
|
2
2
|
* Copyright (c) 2025 Elara AI Pty Ltd
|
|
3
3
|
* Licensed under BSL 1.1. See LICENSE for details.
|
|
4
4
|
*/
|
|
5
|
-
import * as fs from 'node:fs/promises';
|
|
6
|
-
import * as os from 'node:os';
|
|
7
|
-
import * as path from 'node:path';
|
|
8
5
|
import { Hono } from 'hono';
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
|
|
13
|
-
import { errorToVariant } from '../errors.js';
|
|
14
|
-
import { WorkspaceInfoType, CreateWorkspaceType, DeployRequestType } from '../types.js';
|
|
15
|
-
export function createWorkspaceRoutes(repoPath) {
|
|
6
|
+
import { listWorkspaces, createWorkspace, getWorkspace, getWorkspaceStatus, deleteWorkspace, deployWorkspace, exportWorkspace, } from '../handlers/workspaces.js';
|
|
7
|
+
import { decodeBody } from '../beast2.js';
|
|
8
|
+
import { CreateWorkspaceType, DeployRequestType } from '../types.js';
|
|
9
|
+
export function createWorkspaceRoutes(storage, getRepoPath) {
|
|
16
10
|
const app = new Hono();
|
|
17
|
-
// GET /api/workspaces - List all workspaces
|
|
11
|
+
// GET /api/repos/:repo/workspaces - List all workspaces
|
|
18
12
|
app.get('/', async (c) => {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
const state = await workspaceGetState(repoPath, name);
|
|
23
|
-
if (state) {
|
|
24
|
-
return {
|
|
25
|
-
name,
|
|
26
|
-
deployed: true,
|
|
27
|
-
packageName: some(state.packageName),
|
|
28
|
-
packageVersion: some(state.packageVersion),
|
|
29
|
-
};
|
|
30
|
-
}
|
|
31
|
-
else {
|
|
32
|
-
return {
|
|
33
|
-
name,
|
|
34
|
-
deployed: false,
|
|
35
|
-
packageName: none,
|
|
36
|
-
packageVersion: none,
|
|
37
|
-
};
|
|
38
|
-
}
|
|
39
|
-
}));
|
|
40
|
-
return sendSuccess(c, ArrayType(WorkspaceInfoType), result);
|
|
41
|
-
}
|
|
42
|
-
catch (err) {
|
|
43
|
-
return sendError(c, ArrayType(WorkspaceInfoType), errorToVariant(err));
|
|
44
|
-
}
|
|
13
|
+
const repo = c.req.param('repo');
|
|
14
|
+
const repoPath = getRepoPath(repo);
|
|
15
|
+
return listWorkspaces(storage, repoPath);
|
|
45
16
|
});
|
|
46
|
-
// POST /api/workspaces - Create a new workspace
|
|
17
|
+
// POST /api/repos/:repo/workspaces - Create a new workspace
|
|
47
18
|
app.post('/', async (c) => {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
name: body.name,
|
|
53
|
-
deployed: false,
|
|
54
|
-
packageName: none,
|
|
55
|
-
packageVersion: none,
|
|
56
|
-
});
|
|
57
|
-
}
|
|
58
|
-
catch (err) {
|
|
59
|
-
return sendError(c, WorkspaceInfoType, errorToVariant(err));
|
|
60
|
-
}
|
|
19
|
+
const repo = c.req.param('repo');
|
|
20
|
+
const repoPath = getRepoPath(repo);
|
|
21
|
+
const body = await decodeBody(c, CreateWorkspaceType);
|
|
22
|
+
return createWorkspace(storage, repoPath, body.name);
|
|
61
23
|
});
|
|
62
|
-
// GET /api/workspaces/:
|
|
63
|
-
app.get('/:
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
// Workspace exists but not deployed - return error
|
|
69
|
-
return sendError(c, WorkspaceStateType, errorToVariant(new Error(`Workspace '${name}' is not deployed`)));
|
|
70
|
-
}
|
|
71
|
-
return sendSuccess(c, WorkspaceStateType, state);
|
|
72
|
-
}
|
|
73
|
-
catch (err) {
|
|
74
|
-
return sendError(c, WorkspaceStateType, errorToVariant(err));
|
|
75
|
-
}
|
|
24
|
+
// GET /api/repos/:repo/workspaces/:ws - Get workspace state
|
|
25
|
+
app.get('/:ws', async (c) => {
|
|
26
|
+
const repo = c.req.param('repo');
|
|
27
|
+
const repoPath = getRepoPath(repo);
|
|
28
|
+
const ws = c.req.param('ws');
|
|
29
|
+
return getWorkspace(storage, repoPath, ws);
|
|
76
30
|
});
|
|
77
|
-
//
|
|
78
|
-
app.
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
}
|
|
84
|
-
catch (err) {
|
|
85
|
-
return sendError(c, NullType, errorToVariant(err));
|
|
86
|
-
}
|
|
31
|
+
// GET /api/repos/:repo/workspaces/:ws/status - Get comprehensive workspace status
|
|
32
|
+
app.get('/:ws/status', (c) => {
|
|
33
|
+
const repo = c.req.param('repo');
|
|
34
|
+
const repoPath = getRepoPath(repo);
|
|
35
|
+
const ws = c.req.param('ws');
|
|
36
|
+
return getWorkspaceStatus(storage, repoPath, ws);
|
|
87
37
|
});
|
|
88
|
-
//
|
|
89
|
-
app.
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
}
|
|
95
|
-
const body = await decodeBody(c, DeployRequestType);
|
|
96
|
-
const { name: pkgName, version: maybeVersion } = parsePackageRef(body.packageRef);
|
|
97
|
-
const pkgVersion = maybeVersion ?? await packageGetLatestVersion(repoPath, pkgName);
|
|
98
|
-
if (!pkgVersion) {
|
|
99
|
-
return sendError(c, NullType, errorToVariant(new Error(`Package not found: ${pkgName}`)));
|
|
100
|
-
}
|
|
101
|
-
await workspaceDeploy(repoPath, name, pkgName, pkgVersion);
|
|
102
|
-
return sendSuccess(c, NullType, null);
|
|
103
|
-
}
|
|
104
|
-
catch (err) {
|
|
105
|
-
return sendError(c, NullType, errorToVariant(err));
|
|
106
|
-
}
|
|
38
|
+
// DELETE /api/repos/:repo/workspaces/:ws - Remove a workspace
|
|
39
|
+
app.delete('/:ws', async (c) => {
|
|
40
|
+
const repo = c.req.param('repo');
|
|
41
|
+
const repoPath = getRepoPath(repo);
|
|
42
|
+
const ws = c.req.param('ws');
|
|
43
|
+
return deleteWorkspace(storage, repoPath, ws);
|
|
107
44
|
});
|
|
108
|
-
//
|
|
109
|
-
app.
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
}
|
|
123
|
-
finally {
|
|
124
|
-
await fs.rm(tempDir, { recursive: true, force: true });
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
catch (err) {
|
|
128
|
-
return sendError(c, BlobType, errorToVariant(err));
|
|
129
|
-
}
|
|
45
|
+
// POST /api/repos/:repo/workspaces/:ws/deploy - Deploy a package to a workspace
|
|
46
|
+
app.post('/:ws/deploy', async (c) => {
|
|
47
|
+
const repo = c.req.param('repo');
|
|
48
|
+
const repoPath = getRepoPath(repo);
|
|
49
|
+
const ws = c.req.param('ws');
|
|
50
|
+
const body = await decodeBody(c, DeployRequestType);
|
|
51
|
+
return deployWorkspace(storage, repoPath, ws, body.packageRef);
|
|
52
|
+
});
|
|
53
|
+
// GET /api/repos/:repo/workspaces/:ws/export - Export workspace as a package zip
|
|
54
|
+
app.get('/:ws/export', async (c) => {
|
|
55
|
+
const repo = c.req.param('repo');
|
|
56
|
+
const repoPath = getRepoPath(repo);
|
|
57
|
+
const ws = c.req.param('ws');
|
|
58
|
+
return exportWorkspace(storage, repoPath, ws);
|
|
130
59
|
});
|
|
131
60
|
return app;
|
|
132
61
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workspaces.js","sourceRoot":"","sources":["../../../src/routes/workspaces.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,
|
|
1
|
+
{"version":3,"file":"workspaces.js","sourceRoot":"","sources":["../../../src/routes/workspaces.ts"],"names":[],"mappings":"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"}
|
package/dist/src/server.d.ts
CHANGED
|
@@ -3,18 +3,32 @@
|
|
|
3
3
|
* Licensed under BSL 1.1. See LICENSE for details.
|
|
4
4
|
*/
|
|
5
5
|
import { type ServerType } from '@hono/node-server';
|
|
6
|
+
import { type AuthConfig } from './middleware/auth.js';
|
|
7
|
+
import { type OidcConfig } from './auth/index.js';
|
|
8
|
+
export type { AuthConfig } from './middleware/auth.js';
|
|
9
|
+
export type { OidcConfig } from './auth/index.js';
|
|
6
10
|
/**
|
|
7
11
|
* Server configuration options.
|
|
12
|
+
*
|
|
13
|
+
* Must specify exactly one of:
|
|
14
|
+
* - reposDir: Multi-repo mode - serves multiple repositories from subdirectories
|
|
15
|
+
* - singleRepoPath: Single-repo mode - serves a single repository at /repos/default
|
|
8
16
|
*/
|
|
9
17
|
export interface ServerConfig {
|
|
10
|
-
/**
|
|
11
|
-
|
|
18
|
+
/** Directory containing repositories (multi-repo mode) */
|
|
19
|
+
reposDir?: string;
|
|
20
|
+
/** Path to a single repository (single-repo mode, access via /repos/default) */
|
|
21
|
+
singleRepoPath?: string;
|
|
12
22
|
/** HTTP port (default: 3000) */
|
|
13
23
|
port?: number;
|
|
14
24
|
/** Bind address (default: "localhost") */
|
|
15
25
|
host?: string;
|
|
16
26
|
/** Enable CORS for cross-origin requests (default: false) */
|
|
17
27
|
cors?: boolean;
|
|
28
|
+
/** Optional JWT authentication config (for external JWKS validation) */
|
|
29
|
+
auth?: AuthConfig;
|
|
30
|
+
/** Optional OIDC provider config (enables built-in auth server) */
|
|
31
|
+
oidc?: OidcConfig;
|
|
18
32
|
}
|
|
19
33
|
/**
|
|
20
34
|
* Server instance handle.
|
|
@@ -32,8 +46,15 @@ export interface Server {
|
|
|
32
46
|
/**
|
|
33
47
|
* Create an e3 API server.
|
|
34
48
|
*
|
|
49
|
+
* The server operates in multi-repo mode, serving multiple repositories
|
|
50
|
+
* from subdirectories of the configured reposDir.
|
|
51
|
+
*
|
|
52
|
+
* URL structure:
|
|
53
|
+
* - GET /api/repos - List available repositories
|
|
54
|
+
* - /api/repos/:repo/... - Repository-specific endpoints
|
|
55
|
+
*
|
|
35
56
|
* @param config - Server configuration
|
|
36
57
|
* @returns Server instance
|
|
37
58
|
*/
|
|
38
|
-
export declare function createServer(config: ServerConfig): Server
|
|
59
|
+
export declare function createServer(config: ServerConfig): Promise<Server>;
|
|
39
60
|
//# sourceMappingURL=server.d.ts.map
|
package/dist/src/server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/server.ts"],"names":[],"mappings":"AAAA;;;GAGG;
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/server.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,EAAS,KAAK,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAG3D,OAAO,EAAwB,KAAK,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAC7E,OAAO,EAAyC,KAAK,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAezF,YAAY,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AACvD,YAAY,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAElD;;;;;;GAMG;AACH,MAAM,WAAW,YAAY;IAC3B,0DAA0D;IAC1D,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gFAAgF;IAChF,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,gCAAgC;IAChC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,0CAA0C;IAC1C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,6DAA6D;IAC7D,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,wEAAwE;IACxE,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,mEAAmE;IACnE,IAAI,CAAC,EAAE,UAAU,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,MAAM;IACrB,uBAAuB;IACvB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,sBAAsB;IACtB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACtB,iCAAiC;IACjC,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC;IAChC,0CAA0C;IAC1C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,YAAY,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,CAmVxE"}
|