@elaraai/e3-api-server 1.0.78 → 1.0.80
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 +83 -19
- package/dist/src/beast2.js +1 -1
- package/dist/src/beast2.js.map +1 -1
- package/dist/src/cli.js +13 -0
- package/dist/src/cli.js.map +1 -1
- package/dist/src/errors.d.ts.map +1 -1
- package/dist/src/errors.js +8 -1
- package/dist/src/errors.js.map +1 -1
- package/dist/src/handlers/dataflow.d.ts +58 -11
- package/dist/src/handlers/dataflow.d.ts.map +1 -1
- package/dist/src/handlers/dataflow.js +120 -48
- package/dist/src/handlers/dataflow.js.map +1 -1
- package/dist/src/handlers/dataflow.spec.d.ts +6 -0
- package/dist/src/handlers/dataflow.spec.d.ts.map +1 -0
- package/dist/src/handlers/dataflow.spec.js +106 -0
- package/dist/src/handlers/dataflow.spec.js.map +1 -0
- package/dist/src/handlers/datasets.d.ts +60 -34
- package/dist/src/handlers/datasets.d.ts.map +1 -1
- package/dist/src/handlers/datasets.js +452 -306
- package/dist/src/handlers/datasets.js.map +1 -1
- package/dist/src/handlers/datasets.spec.js +338 -119
- package/dist/src/handlers/datasets.spec.js.map +1 -1
- package/dist/src/handlers/functions.d.ts.map +1 -1
- package/dist/src/handlers/functions.js +10 -8
- package/dist/src/handlers/functions.js.map +1 -1
- package/dist/src/handlers/functions.spec.js +2 -2
- package/dist/src/handlers/functions.spec.js.map +1 -1
- package/dist/src/handlers/index.d.ts +2 -2
- package/dist/src/handlers/index.d.ts.map +1 -1
- package/dist/src/handlers/index.js +2 -2
- package/dist/src/handlers/index.js.map +1 -1
- package/dist/src/handlers/records.d.ts.map +1 -1
- package/dist/src/handlers/records.js +15 -12
- package/dist/src/handlers/records.js.map +1 -1
- package/dist/src/handlers/records.spec.js +9 -5
- package/dist/src/handlers/records.spec.js.map +1 -1
- package/dist/src/handlers/repository.d.ts +59 -10
- package/dist/src/handlers/repository.d.ts.map +1 -1
- package/dist/src/handlers/repository.js +147 -40
- package/dist/src/handlers/repository.js.map +1 -1
- package/dist/src/handlers/tasks.d.ts +2 -1
- package/dist/src/handlers/tasks.d.ts.map +1 -1
- package/dist/src/handlers/tasks.js +31 -8
- package/dist/src/handlers/tasks.js.map +1 -1
- package/dist/src/handlers/tasks.spec.d.ts +6 -0
- package/dist/src/handlers/tasks.spec.d.ts.map +1 -0
- package/dist/src/handlers/tasks.spec.js +64 -0
- package/dist/src/handlers/tasks.spec.js.map +1 -0
- package/dist/src/handlers/workspaces.d.ts +44 -6
- package/dist/src/handlers/workspaces.d.ts.map +1 -1
- package/dist/src/handlers/workspaces.js +74 -40
- package/dist/src/handlers/workspaces.js.map +1 -1
- package/dist/src/handlers/workspaces.spec.d.ts +6 -0
- package/dist/src/handlers/workspaces.spec.d.ts.map +1 -0
- package/dist/src/handlers/workspaces.spec.js +164 -0
- package/dist/src/handlers/workspaces.spec.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 +7 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/local-dataflow.d.ts +14 -0
- package/dist/src/local-dataflow.d.ts.map +1 -0
- package/dist/src/local-dataflow.js +41 -0
- package/dist/src/local-dataflow.js.map +1 -0
- package/dist/src/middleware/repository.d.ts +39 -0
- package/dist/src/middleware/repository.d.ts.map +1 -0
- package/dist/src/middleware/repository.js +77 -0
- package/dist/src/middleware/repository.js.map +1 -0
- package/dist/src/routes/data.d.ts +2 -2
- package/dist/src/routes/data.d.ts.map +1 -1
- package/dist/src/routes/data.js +22 -45
- package/dist/src/routes/data.js.map +1 -1
- package/dist/src/routes/datasets.d.ts +0 -3
- package/dist/src/routes/datasets.d.ts.map +1 -1
- package/dist/src/routes/datasets.js +40 -8
- package/dist/src/routes/datasets.js.map +1 -1
- package/dist/src/routes/executions.d.ts +37 -2
- package/dist/src/routes/executions.d.ts.map +1 -1
- package/dist/src/routes/executions.js +21 -12
- package/dist/src/routes/executions.js.map +1 -1
- package/dist/src/routes/index.d.ts +2 -1
- package/dist/src/routes/index.d.ts.map +1 -1
- package/dist/src/routes/index.js +1 -0
- package/dist/src/routes/index.js.map +1 -1
- package/dist/src/routes/objects.d.ts +16 -2
- package/dist/src/routes/objects.d.ts.map +1 -1
- package/dist/src/routes/objects.js +34 -3
- package/dist/src/routes/objects.js.map +1 -1
- package/dist/src/routes/repositories.d.ts +26 -0
- package/dist/src/routes/repositories.d.ts.map +1 -0
- package/dist/src/routes/repositories.js +58 -0
- package/dist/src/routes/repositories.js.map +1 -0
- package/dist/src/routes/repositories.spec.d.ts +6 -0
- package/dist/src/routes/repositories.spec.d.ts.map +1 -0
- package/dist/src/routes/repositories.spec.js +77 -0
- package/dist/src/routes/repositories.spec.js.map +1 -0
- package/dist/src/routes/repository.d.ts +12 -2
- package/dist/src/routes/repository.d.ts.map +1 -1
- package/dist/src/routes/repository.js +24 -9
- package/dist/src/routes/repository.js.map +1 -1
- package/dist/src/routes/transfer.d.ts +11 -9
- package/dist/src/routes/transfer.d.ts.map +1 -1
- package/dist/src/routes/transfer.js +90 -115
- package/dist/src/routes/transfer.js.map +1 -1
- package/dist/src/routes/workspaces.d.ts +14 -1
- package/dist/src/routes/workspaces.d.ts.map +1 -1
- package/dist/src/routes/workspaces.js +57 -46
- package/dist/src/routes/workspaces.js.map +1 -1
- package/dist/src/server.d.ts +18 -6
- package/dist/src/server.d.ts.map +1 -1
- package/dist/src/server.js +55 -182
- package/dist/src/server.js.map +1 -1
- package/dist/src/server.spec.d.ts +6 -0
- package/dist/src/server.spec.d.ts.map +1 -0
- package/dist/src/server.spec.js +59 -0
- package/dist/src/server.spec.js.map +1 -0
- package/dist/src/types.d.ts +200 -16
- package/dist/src/types.d.ts.map +1 -1
- package/dist/src/types.js +5 -2
- package/dist/src/types.js.map +1 -1
- package/package.json +5 -5
- package/dist/src/async-operation-state.d.ts +0 -37
- package/dist/src/async-operation-state.d.ts.map +0 -1
- package/dist/src/async-operation-state.js +0 -118
- package/dist/src/async-operation-state.js.map +0 -1
- package/dist/src/orchestrator-manager.d.ts +0 -45
- package/dist/src/orchestrator-manager.d.ts.map +0 -1
- package/dist/src/orchestrator-manager.js +0 -150
- package/dist/src/orchestrator-manager.js.map +0 -1
|
@@ -3,22 +3,53 @@
|
|
|
3
3
|
* Licensed under BSL 1.1. See LICENSE for details.
|
|
4
4
|
*/
|
|
5
5
|
import { Hono } from 'hono';
|
|
6
|
-
import {
|
|
6
|
+
import { isObjectHash } from '@elaraai/e3-core';
|
|
7
|
+
import { BEAST2_CONTENT_TYPE } from '@elaraai/e3-types';
|
|
7
8
|
import { sendJsonError } from '../errors.js';
|
|
8
|
-
|
|
9
|
+
import { DOWNLOAD_REDIRECT_BYTES } from '../handlers/datasets.js';
|
|
10
|
+
/**
|
|
11
|
+
* Creates the routes that read an object by its hash.
|
|
12
|
+
*
|
|
13
|
+
* @remarks
|
|
14
|
+
* A client downloading a collection by its segments reads each segment here.
|
|
15
|
+
* With a transfer backend, an object over {@link DOWNLOAD_REDIRECT_BYTES} is
|
|
16
|
+
* answered as a dataset download is: JSON `{ url }`, which the client fetches
|
|
17
|
+
* directly, so a host whose responses are capped never carries the bytes.
|
|
18
|
+
*
|
|
19
|
+
* @param storage - The storage backend the objects are read from
|
|
20
|
+
* @param getRepoPath - Maps a repository name to its path in the backend
|
|
21
|
+
* @param transferBackend - Serves large objects by URL; without it every object is answered inline
|
|
22
|
+
* @returns The Hono app, mounted at `/api/repos/:repo/objects`
|
|
23
|
+
*/
|
|
24
|
+
export function createObjectRoutes(storage, getRepoPath, transferBackend) {
|
|
9
25
|
const app = new Hono();
|
|
10
26
|
// GET /api/repos/:repo/objects/:hash — Read object by hash
|
|
11
27
|
app.get('/:hash', async (c) => {
|
|
12
28
|
const repo = c.req.param('repo');
|
|
13
29
|
const repoPath = getRepoPath(repo);
|
|
14
30
|
const hash = c.req.param('hash');
|
|
15
|
-
if (
|
|
31
|
+
if (!isObjectHash(hash)) {
|
|
16
32
|
return new Response(JSON.stringify({ error: { type: 'bad_request', message: `invalid hash format: ${hash}` } }), {
|
|
17
33
|
status: 400,
|
|
18
34
|
headers: { 'Content-Type': 'application/json' },
|
|
19
35
|
});
|
|
20
36
|
}
|
|
21
37
|
try {
|
|
38
|
+
if (transferBackend) {
|
|
39
|
+
const { size } = await storage.objects.stat(repoPath, hash);
|
|
40
|
+
if (size > DOWNLOAD_REDIRECT_BYTES) {
|
|
41
|
+
let url = await transferBackend.datasetDownload.getDownloadUrl(repo, hash);
|
|
42
|
+
if (url.startsWith('/'))
|
|
43
|
+
url = `${new URL(c.req.url).origin}${url}`;
|
|
44
|
+
return new Response(JSON.stringify({ url }), {
|
|
45
|
+
headers: {
|
|
46
|
+
'Content-Type': 'application/json',
|
|
47
|
+
'X-Content-Length': String(size),
|
|
48
|
+
'X-Content-SHA256': hash,
|
|
49
|
+
},
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
}
|
|
22
53
|
const data = await storage.objects.read(repoPath, hash);
|
|
23
54
|
return new Response(data, {
|
|
24
55
|
headers: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"objects.js","sourceRoot":"","sources":["../../../src/routes/objects.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"objects.js","sourceRoot":"","sources":["../../../src/routes/objects.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,YAAY,EAA6C,MAAM,kBAAkB,CAAC;AAC3F,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AAElE;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,kBAAkB,CAChC,OAAuB,EACvB,WAAqC,EACrC,eAAiC;IAEjC,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;IAEvB,2DAA2D;IAC3D,GAAG,CAAC,GAAG,CAAC,QAAQ,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;QAC5B,MAAM,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAE,CAAC;QAClC,MAAM,QAAQ,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC;QACnC,MAAM,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAE,CAAC;QAElC,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC;YACxB,OAAO,IAAI,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,aAAa,EAAE,OAAO,EAAE,wBAAwB,IAAI,EAAE,EAAE,EAAE,CAAC,EAAE;gBAC/G,MAAM,EAAE,GAAG;gBACX,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;aAChD,CAAC,CAAC;QACL,CAAC;QAED,IAAI,CAAC;YACH,IAAI,eAAe,EAAE,CAAC;gBACpB,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;gBAC5D,IAAI,IAAI,GAAG,uBAAuB,EAAE,CAAC;oBACnC,IAAI,GAAG,GAAG,MAAM,eAAe,CAAC,eAAe,CAAC,cAAc,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;oBAC3E,IAAI,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC;wBAAE,GAAG,GAAG,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,MAAM,GAAG,GAAG,EAAE,CAAC;oBACpE,OAAO,IAAI,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE;wBAC3C,OAAO,EAAE;4BACP,cAAc,EAAE,kBAAkB;4BAClC,kBAAkB,EAAE,MAAM,CAAC,IAAI,CAAC;4BAChC,kBAAkB,EAAE,IAAI;yBACzB;qBACF,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;YACD,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;YACxD,OAAO,IAAI,QAAQ,CAAC,IAAI,EAAE;gBACxB,OAAO,EAAE;oBACP,cAAc,EAAE,mBAAmB;oBACnC,gBAAgB,EAAE,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC;oBACzC,kBAAkB,EAAE,IAAI;iBACzB;aACF,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,aAAa,CAAC,GAAG,CAAC,CAAC;QAC5B,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,OAAO,GAAG,CAAC;AACb,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
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 type { StorageBackend } from '@elaraai/e3-core';
|
|
7
|
+
/**
|
|
8
|
+
* The routes of the repositories a host keeps, mounted at `/api/repos`: list
|
|
9
|
+
* them, create one and remove one. They go through the storage backend's
|
|
10
|
+
* `RepoStore`, so a host mounts them over its own — the local server over a
|
|
11
|
+
* directory of repositories, a cloud over its own stores — with the
|
|
12
|
+
* repository gate (`createRepositoryGate`) on `/api/repos/:repo/*`.
|
|
13
|
+
*
|
|
14
|
+
* @param storage - Storage backend, whose `RepoStore` keeps the repositories
|
|
15
|
+
* @returns The routes
|
|
16
|
+
*/
|
|
17
|
+
export declare function createRepositoriesRoutes(storage: StorageBackend): Hono<import("hono/types").BlankEnv, import("hono/types").BlankSchema, "/">;
|
|
18
|
+
/**
|
|
19
|
+
* The routes of a server of one repository, mounted at `/api/repos`: they
|
|
20
|
+
* list it, as `default`, and create and remove none. A refusal is JSON with
|
|
21
|
+
* its HTTP status, as the gate's are.
|
|
22
|
+
*
|
|
23
|
+
* @returns The routes
|
|
24
|
+
*/
|
|
25
|
+
export declare function createSingleRepositoryRoutes(): Hono<import("hono/types").BlankEnv, import("hono/types").BlankSchema, "/">;
|
|
26
|
+
//# sourceMappingURL=repositories.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repositories.d.ts","sourceRoot":"","sources":["../../../src/routes/repositories.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAE5B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAIvD;;;;;;;;;GASG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,cAAc,8EAa/D;AAED;;;;;;GAMG;AACH,wBAAgB,4BAA4B,+EAyB3C"}
|
|
@@ -0,0 +1,58 @@
|
|
|
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 { ArrayType, StringType } from '@elaraai/east';
|
|
7
|
+
import { createRepository, listRepositories, removeRepository } from '../handlers/repository.js';
|
|
8
|
+
import { sendSuccess } from '../beast2.js';
|
|
9
|
+
/**
|
|
10
|
+
* The routes of the repositories a host keeps, mounted at `/api/repos`: list
|
|
11
|
+
* them, create one and remove one. They go through the storage backend's
|
|
12
|
+
* `RepoStore`, so a host mounts them over its own — the local server over a
|
|
13
|
+
* directory of repositories, a cloud over its own stores — with the
|
|
14
|
+
* repository gate (`createRepositoryGate`) on `/api/repos/:repo/*`.
|
|
15
|
+
*
|
|
16
|
+
* @param storage - Storage backend, whose `RepoStore` keeps the repositories
|
|
17
|
+
* @returns The routes
|
|
18
|
+
*/
|
|
19
|
+
export function createRepositoriesRoutes(storage) {
|
|
20
|
+
const app = new Hono();
|
|
21
|
+
// GET /api/repos - The repositories, by name
|
|
22
|
+
app.get('/', () => listRepositories(storage));
|
|
23
|
+
// PUT /api/repos/:repo - Create a repository
|
|
24
|
+
app.put('/:repo', (c) => createRepository(storage, c.req.param('repo')));
|
|
25
|
+
// DELETE /api/repos/:repo - Remove a repository
|
|
26
|
+
app.delete('/:repo', (c) => removeRepository(storage, c.req.param('repo')));
|
|
27
|
+
return app;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* The routes of a server of one repository, mounted at `/api/repos`: they
|
|
31
|
+
* list it, as `default`, and create and remove none. A refusal is JSON with
|
|
32
|
+
* its HTTP status, as the gate's are.
|
|
33
|
+
*
|
|
34
|
+
* @returns The routes
|
|
35
|
+
*/
|
|
36
|
+
export function createSingleRepositoryRoutes() {
|
|
37
|
+
const app = new Hono();
|
|
38
|
+
// GET /api/repos - The one repository
|
|
39
|
+
app.get('/', () => sendSuccess(ArrayType(StringType), ['default']));
|
|
40
|
+
// PUT /api/repos/:repo - Refused: the server serves one repository
|
|
41
|
+
app.put('/:repo', (c) => c.json({
|
|
42
|
+
error: 'method_not_allowed',
|
|
43
|
+
message: 'Repository creation is disabled in single-repo mode',
|
|
44
|
+
}, 405));
|
|
45
|
+
// DELETE /api/repos/:repo - Refused for the one repository; any other is none
|
|
46
|
+
app.delete('/:repo', (c) => {
|
|
47
|
+
const repo = c.req.param('repo');
|
|
48
|
+
if (repo === 'default') {
|
|
49
|
+
return c.json({
|
|
50
|
+
error: 'method_not_allowed',
|
|
51
|
+
message: 'Repository deletion is disabled in single-repo mode',
|
|
52
|
+
}, 405);
|
|
53
|
+
}
|
|
54
|
+
return c.json({ error: 'not_found', message: `Repository '${repo}' not found` }, 404);
|
|
55
|
+
});
|
|
56
|
+
return app;
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=repositories.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repositories.js","sourceRoot":"","sources":["../../../src/routes/repositories.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAEtD,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AACjG,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAE3C;;;;;;;;;GASG;AACH,MAAM,UAAU,wBAAwB,CAAC,OAAuB;IAC9D,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;IAEvB,6CAA6C;IAC7C,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC,CAAC;IAE9C,6CAA6C;IAC7C,GAAG,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,gBAAgB,CAAC,OAAO,EAAE,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;IAEzE,gDAAgD;IAChD,GAAG,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,gBAAgB,CAAC,OAAO,EAAE,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;IAE5E,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,4BAA4B;IAC1C,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;IAEvB,sCAAsC;IACtC,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC,WAAW,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;IAEpE,mEAAmE;IACnE,GAAG,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;QAC9B,KAAK,EAAE,oBAAoB;QAC3B,OAAO,EAAE,qDAAqD;KAC/D,EAAE,GAAG,CAAC,CAAC,CAAC;IAET,8EAA8E;IAC9E,GAAG,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE;QACzB,MAAM,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QACjC,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;YACvB,OAAO,CAAC,CAAC,IAAI,CAAC;gBACZ,KAAK,EAAE,oBAAoB;gBAC3B,OAAO,EAAE,qDAAqD;aAC/D,EAAE,GAAG,CAAC,CAAC;QACV,CAAC;QACD,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,eAAe,IAAI,aAAa,EAAE,EAAE,GAAG,CAAC,CAAC;IACxF,CAAC,CAAC,CAAC;IAEH,OAAO,GAAG,CAAC;AACb,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repositories.spec.d.ts","sourceRoot":"","sources":["../../../src/routes/repositories.spec.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 Elara AI Pty Ltd
|
|
3
|
+
* Licensed under BSL 1.1. See LICENSE for details.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* The routes of a host's repositories, and the gate every request to one
|
|
7
|
+
* passes, mounted over a backend other than the local server's — the
|
|
8
|
+
* in-memory one, as a cloud mounts them over its own: a repository is listed,
|
|
9
|
+
* created, opened at each request and removed, and one being removed answers
|
|
10
|
+
* its status alone. And a server of one repository serves it as `default`,
|
|
11
|
+
* whichever order the gate and the routes are mounted in.
|
|
12
|
+
*/
|
|
13
|
+
import { describe, it } from 'node:test';
|
|
14
|
+
import assert from 'node:assert/strict';
|
|
15
|
+
import { Hono } from 'hono';
|
|
16
|
+
import { ArrayType, NullType, StringType, decodeBeast2For, variant } from '@elaraai/east';
|
|
17
|
+
import { InMemoryStorage } from '@elaraai/e3-core/test';
|
|
18
|
+
import { E3_RELEASE } from '@elaraai/e3-types';
|
|
19
|
+
import { createRepositoryGate, createSingleRepositoryGate } from '../middleware/repository.js';
|
|
20
|
+
import { ResponseType } from '../types.js';
|
|
21
|
+
import { createRepositoriesRoutes, createSingleRepositoryRoutes } from './repositories.js';
|
|
22
|
+
const decodeList = decodeBeast2For(ResponseType(ArrayType(StringType)));
|
|
23
|
+
const decodeName = decodeBeast2For(ResponseType(StringType));
|
|
24
|
+
const decodeNull = decodeBeast2For(ResponseType(NullType));
|
|
25
|
+
const bytes = async (response) => new Uint8Array(await (await response).arrayBuffer());
|
|
26
|
+
describe('the repositories routes and gate', () => {
|
|
27
|
+
it('list, create and remove a host\'s repositories, and open one at every request to it', async () => {
|
|
28
|
+
const storage = new InMemoryStorage();
|
|
29
|
+
const app = new Hono();
|
|
30
|
+
app.use('/api/repos/:repo/*', createRepositoryGate(storage, (repo) => repo));
|
|
31
|
+
app.route('/api/repos', createRepositoriesRoutes(storage));
|
|
32
|
+
app.get('/api/repos/:repo/probe', (c) => c.text('passed'));
|
|
33
|
+
app.get('/api/repos/:repo/status', (c) => c.text('its status'));
|
|
34
|
+
const notFound = (repo) => ({ error: 'not_found', message: `Repository '${repo}' not found` });
|
|
35
|
+
const created = await app.request('/api/repos/alpha', { method: 'PUT' });
|
|
36
|
+
assert.equal(created.status, 201);
|
|
37
|
+
assert.deepEqual(decodeName(await bytes(created)), variant('success', 'alpha'));
|
|
38
|
+
assert.deepEqual(decodeList(await bytes(app.request('/api/repos'))), variant('success', ['alpha']));
|
|
39
|
+
assert.equal((decodeName(await bytes(app.request('/api/repos/alpha', { method: 'PUT' })))).type, 'error', 'one that exists is not created again');
|
|
40
|
+
assert.equal(await (await app.request('/api/repos/alpha/probe')).text(), 'passed');
|
|
41
|
+
const missing = await app.request('/api/repos/beta/probe');
|
|
42
|
+
assert.equal(missing.status, 404);
|
|
43
|
+
assert.deepEqual(await missing.json(), notFound('beta'));
|
|
44
|
+
// One this e3 cannot open is refused, naming the release that upgraded it.
|
|
45
|
+
await app.request('/api/repos/gamma', { method: 'PUT' });
|
|
46
|
+
const record = await storage.refs.repositoryRead('gamma');
|
|
47
|
+
assert.ok(record !== null);
|
|
48
|
+
await storage.refs.repositoryWrite('gamma', { ...record, upgrades: [...record.upgrades, { name: 'from-a-newer-e3', release: '999.0.0' }] });
|
|
49
|
+
const refused = await app.request('/api/repos/gamma/probe');
|
|
50
|
+
assert.equal(refused.status, 500);
|
|
51
|
+
assert.deepEqual(await refused.json(), { error: { type: 'internal', message: `the repository at gamma has had the upgrade "from-a-newer-e3", which e3 999.0.0 applied and this e3, ${E3_RELEASE}, does not know — open it with e3 999.0.0 or a newer one` } });
|
|
52
|
+
// One being removed answers its status alone, and a removal asked again
|
|
53
|
+
// answers at once.
|
|
54
|
+
await storage.repos.setStatus('alpha', 'deleting', 'active');
|
|
55
|
+
assert.deepEqual(await (await app.request('/api/repos/alpha/probe')).json(), notFound('alpha'));
|
|
56
|
+
assert.equal(await (await app.request('/api/repos/alpha/status')).text(), 'its status');
|
|
57
|
+
assert.deepEqual(decodeNull(await bytes(app.request('/api/repos/alpha', { method: 'DELETE' }))), variant('success', null));
|
|
58
|
+
await storage.repos.setStatus('alpha', 'active', 'deleting');
|
|
59
|
+
assert.deepEqual(decodeNull(await bytes(app.request('/api/repos/alpha', { method: 'DELETE' }))), variant('success', null));
|
|
60
|
+
assert.deepEqual(decodeList(await bytes(app.request('/api/repos'))), variant('success', ['gamma']));
|
|
61
|
+
assert.deepEqual(await (await app.request('/api/repos/alpha/probe')).json(), notFound('alpha'));
|
|
62
|
+
assert.deepEqual(decodeNull(await bytes(app.request('/api/repos/alpha', { method: 'DELETE' }))), variant('error', variant('repository_not_found', { repo: 'alpha' })));
|
|
63
|
+
});
|
|
64
|
+
it('serve one repository as `default`, and create and remove none, the gate mounted ahead of the routes', async () => {
|
|
65
|
+
const app = new Hono();
|
|
66
|
+
app.use('/api/repos/:repo/*', createSingleRepositoryGate());
|
|
67
|
+
app.route('/api/repos', createSingleRepositoryRoutes());
|
|
68
|
+
app.get('/api/repos/:repo/probe', (c) => c.text('passed'));
|
|
69
|
+
assert.deepEqual(decodeList(await bytes(app.request('/api/repos'))), variant('success', ['default']));
|
|
70
|
+
assert.equal(await (await app.request('/api/repos/default/probe')).text(), 'passed');
|
|
71
|
+
assert.equal((await app.request('/api/repos/other/probe')).status, 404);
|
|
72
|
+
assert.equal((await app.request('/api/repos/new-repo', { method: 'PUT' })).status, 405);
|
|
73
|
+
assert.equal((await app.request('/api/repos/default', { method: 'DELETE' })).status, 405);
|
|
74
|
+
assert.equal((await app.request('/api/repos/other', { method: 'DELETE' })).status, 404);
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
//# sourceMappingURL=repositories.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repositories.spec.js","sourceRoot":"","sources":["../../../src/routes/repositories.spec.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,6 +3,16 @@
|
|
|
3
3
|
* Licensed under BSL 1.1. See LICENSE for details.
|
|
4
4
|
*/
|
|
5
5
|
import { Hono } from 'hono';
|
|
6
|
-
import type { StorageBackend } from '@elaraai/e3-core';
|
|
7
|
-
|
|
6
|
+
import type { StorageBackend, TransferBackend } from '@elaraai/e3-core';
|
|
7
|
+
/**
|
|
8
|
+
* Repository routes, mounted at `/api/repos/:repo`: its status, its record,
|
|
9
|
+
* and gc.
|
|
10
|
+
*
|
|
11
|
+
* @param storage - Storage backend
|
|
12
|
+
* @param getRepoPath - The repository identifier for a repo name
|
|
13
|
+
* @param transferBackend - Files and dispatches the job gc runs as, and holds
|
|
14
|
+
* the status a poll reads
|
|
15
|
+
* @returns The routes
|
|
16
|
+
*/
|
|
17
|
+
export declare function createRepositoryRoutes(storage: StorageBackend, getRepoPath: (repo: string) => string, transferBackend: TransferBackend): Hono<import("hono/types").BlankEnv, import("hono/types").BlankSchema, "/">;
|
|
8
18
|
//# sourceMappingURL=repository.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"repository.d.ts","sourceRoot":"","sources":["../../../src/routes/repository.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"repository.d.ts","sourceRoot":"","sources":["../../../src/routes/repository.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAKxE;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,cAAc,EACvB,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,EACrC,eAAe,EAAE,eAAe,8EAiCjC"}
|
|
@@ -3,10 +3,20 @@
|
|
|
3
3
|
* Licensed under BSL 1.1. See LICENSE for details.
|
|
4
4
|
*/
|
|
5
5
|
import { Hono } from 'hono';
|
|
6
|
-
import { getStatus, startGc, getGcStatus } from '../handlers/repository.js';
|
|
6
|
+
import { getStatus, getRecord, startGc, getGcStatus } from '../handlers/repository.js';
|
|
7
7
|
import { decodeBody } from '../beast2.js';
|
|
8
8
|
import { GcRequestType } from '../types.js';
|
|
9
|
-
|
|
9
|
+
/**
|
|
10
|
+
* Repository routes, mounted at `/api/repos/:repo`: its status, its record,
|
|
11
|
+
* and gc.
|
|
12
|
+
*
|
|
13
|
+
* @param storage - Storage backend
|
|
14
|
+
* @param getRepoPath - The repository identifier for a repo name
|
|
15
|
+
* @param transferBackend - Files and dispatches the job gc runs as, and holds
|
|
16
|
+
* the status a poll reads
|
|
17
|
+
* @returns The routes
|
|
18
|
+
*/
|
|
19
|
+
export function createRepositoryRoutes(storage, getRepoPath, transferBackend) {
|
|
10
20
|
const app = new Hono();
|
|
11
21
|
// GET /api/repos/:repo/status - Get repository status
|
|
12
22
|
app.get('/status', async (c) => {
|
|
@@ -14,18 +24,23 @@ export function createRepositoryRoutes(storage, getRepoPath) {
|
|
|
14
24
|
const repoPath = getRepoPath(repo);
|
|
15
25
|
return getStatus(storage, repoPath);
|
|
16
26
|
});
|
|
17
|
-
//
|
|
18
|
-
app.
|
|
27
|
+
// GET /api/repos/:repo/record - The repository's record: its release and upgrades
|
|
28
|
+
app.get('/record', async (c) => {
|
|
19
29
|
const repo = c.req.param('repo');
|
|
20
30
|
const repoPath = getRepoPath(repo);
|
|
21
|
-
|
|
22
|
-
const minAge = options.minAge?.type === 'some' ? Number(options.minAge.value) : undefined;
|
|
23
|
-
return startGc(storage, repoPath, { dryRun: options.dryRun, minAge });
|
|
31
|
+
return getRecord(storage, repoPath);
|
|
24
32
|
});
|
|
25
|
-
//
|
|
33
|
+
// POST /api/repos/:repo/gc - Start a gc job
|
|
34
|
+
app.post('/gc', async (c) => {
|
|
35
|
+
const repo = c.req.param('repo');
|
|
36
|
+
const request = await decodeBody(c, GcRequestType);
|
|
37
|
+
return startGc(repo, request, transferBackend.repoGc);
|
|
38
|
+
});
|
|
39
|
+
// GET /api/repos/:repo/gc/:executionId - Poll a gc job
|
|
26
40
|
app.get('/gc/:executionId', (c) => {
|
|
41
|
+
const repo = c.req.param('repo');
|
|
27
42
|
const executionId = c.req.param('executionId');
|
|
28
|
-
return getGcStatus(executionId);
|
|
43
|
+
return getGcStatus(transferBackend.repoGc, repo, executionId);
|
|
29
44
|
});
|
|
30
45
|
return app;
|
|
31
46
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"repository.js","sourceRoot":"","sources":["../../../src/routes/repository.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAE5B,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"repository.js","sourceRoot":"","sources":["../../../src/routes/repository.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAE5B,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AACvF,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C;;;;;;;;;GASG;AACH,MAAM,UAAU,sBAAsB,CACpC,OAAuB,EACvB,WAAqC,EACrC,eAAgC;IAEhC,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;IAEvB,sDAAsD;IACtD,GAAG,CAAC,GAAG,CAAC,SAAS,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;QAC7B,MAAM,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAE,CAAC;QAClC,MAAM,QAAQ,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC;QACnC,OAAO,SAAS,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IACtC,CAAC,CAAC,CAAC;IAEH,kFAAkF;IAClF,GAAG,CAAC,GAAG,CAAC,SAAS,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;QAC7B,MAAM,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAE,CAAC;QAClC,MAAM,QAAQ,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC;QACnC,OAAO,SAAS,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IACtC,CAAC,CAAC,CAAC;IAEH,4CAA4C;IAC5C,GAAG,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;QAC1B,MAAM,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAE,CAAC;QAClC,MAAM,OAAO,GAAG,MAAM,UAAU,CAAC,CAAC,EAAE,aAAa,CAAC,CAAC;QACnD,OAAO,OAAO,CAAC,IAAI,EAAE,OAAO,EAAE,eAAe,CAAC,MAAM,CAAC,CAAC;IACxD,CAAC,CAAC,CAAC;IAEH,uDAAuD;IACvD,GAAG,CAAC,GAAG,CAAC,kBAAkB,EAAE,CAAC,CAAC,EAAE,EAAE;QAChC,MAAM,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAE,CAAC;QAClC,MAAM,WAAW,GAAG,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,aAAa,CAAE,CAAC;QAChD,OAAO,WAAW,CAAC,eAAe,CAAC,MAAM,EAAE,IAAI,EAAE,WAAW,CAAC,CAAC;IAChE,CAAC,CAAC,CAAC;IAEH,OAAO,GAAG,CAAC;AACb,CAAC"}
|
|
@@ -7,9 +7,9 @@ import { type StorageBackend, type TransferBackend } from '@elaraai/e3-core';
|
|
|
7
7
|
/** Options for {@link createTransferRoutes}. */
|
|
8
8
|
export interface TransferRouteOptions {
|
|
9
9
|
/**
|
|
10
|
-
* How long a
|
|
11
|
-
*
|
|
12
|
-
*
|
|
10
|
+
* How long a commit waits for the staged bytes to be verified before it
|
|
11
|
+
* answers `processing` for the client to poll (default 5000 ms; 0 answers
|
|
12
|
+
* `processing` at once).
|
|
13
13
|
*/
|
|
14
14
|
commitWaitMs?: number;
|
|
15
15
|
}
|
|
@@ -23,12 +23,14 @@ export interface TransferRouteOptions {
|
|
|
23
23
|
* generic data endpoints in `data.ts`.
|
|
24
24
|
*
|
|
25
25
|
* @remarks
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
26
|
+
* The init and the commit name the protocol version they speak
|
|
27
|
+
* (`?protocol=N`) and the client's release (`&release=`), and one of another
|
|
28
|
+
* version, or none, is refused, naming both releases and the fix. A client is
|
|
29
|
+
* sent its bytes' plan as parts. The upload store commits the upload, where it
|
|
30
|
+
* runs its commits: the request waits up to `commitWaitMs` for it and
|
|
31
|
+
* otherwise answers `processing`, which the client polls from the store,
|
|
32
|
+
* whichever instance answers — so verifying a delivery of many gigabytes never
|
|
33
|
+
* holds one request open for as long as its SHA-256 takes.
|
|
32
34
|
*/
|
|
33
35
|
export declare function createTransferRoutes(storage: StorageBackend, getRepoPath: (repo: string) => string, transferBackend: TransferBackend, options?: TransferRouteOptions): {
|
|
34
36
|
api: Hono<import("hono/types").BlankEnv, import("hono/types").BlankSchema, "/">;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transfer.d.ts","sourceRoot":"","sources":["../../../src/routes/transfer.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"transfer.d.ts","sourceRoot":"","sources":["../../../src/routes/transfer.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAK5B,OAAO,EAKL,KAAK,cAAc,EACnB,KAAK,eAAe,EACrB,MAAM,kBAAkB,CAAC;AAU1B,gDAAgD;AAChD,MAAM,WAAW,oBAAoB;IACnC;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AA2DD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,cAAc,EACvB,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,EACrC,eAAe,EAAE,eAAe,EAChC,OAAO,GAAE,oBAAyB;;EAmLnC"}
|