@elaraai/e3-api-server 0.0.2-beta.39 → 0.0.2-beta.40
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/dist/src/beast2.d.ts.map +1 -1
- package/dist/src/beast2.js +9 -5
- package/dist/src/beast2.js.map +1 -1
- package/dist/src/handlers/datasets.d.ts +5 -2
- package/dist/src/handlers/datasets.d.ts.map +1 -1
- package/dist/src/handlers/datasets.js +32 -3
- package/dist/src/handlers/datasets.js.map +1 -1
- package/dist/src/handlers/index.d.ts +1 -1
- package/dist/src/handlers/index.d.ts.map +1 -1
- package/dist/src/handlers/index.js +1 -1
- package/dist/src/handlers/index.js.map +1 -1
- package/dist/src/handlers/packages.d.ts +0 -8
- package/dist/src/handlers/packages.d.ts.map +1 -1
- package/dist/src/handlers/packages.js +3 -53
- package/dist/src/handlers/packages.js.map +1 -1
- 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 -2
- package/dist/src/routes/datasets.d.ts.map +1 -1
- package/dist/src/routes/datasets.js +6 -6
- package/dist/src/routes/datasets.js.map +1 -1
- package/dist/src/routes/index.d.ts +4 -0
- package/dist/src/routes/index.d.ts.map +1 -1
- package/dist/src/routes/index.js +4 -0
- package/dist/src/routes/index.js.map +1 -1
- 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.map +1 -1
- package/dist/src/routes/packages.js +1 -29
- package/dist/src/routes/packages.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/server.d.ts.map +1 -1
- package/dist/src/server.js +45 -24
- package/dist/src/server.js.map +1 -1
- package/dist/src/types.d.ts +52 -0
- package/dist/src/types.d.ts.map +1 -1
- package/dist/src/types.js +14 -0
- package/dist/src/types.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,8 @@
|
|
|
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
|
+
export declare function createObjectRoutes(storage: StorageBackend, getRepoPath: (repo: string) => string): Hono<import("hono/types").BlankEnv, import("hono/types").BlankSchema, "/">;
|
|
8
|
+
//# sourceMappingURL=objects.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"objects.d.ts","sourceRoot":"","sources":["../../../src/routes/objects.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAE5B,OAAO,EAA4C,KAAK,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAGjG,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,cAAc,EACvB,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,8EAgCtC"}
|
|
@@ -0,0 +1,38 @@
|
|
|
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 { NullType, variant } from '@elaraai/east';
|
|
7
|
+
import { BEAST2_CONTENT_TYPE, ObjectNotFoundError } from '@elaraai/e3-core';
|
|
8
|
+
import { sendError } from '../beast2.js';
|
|
9
|
+
export function createObjectRoutes(storage, getRepoPath) {
|
|
10
|
+
const app = new Hono();
|
|
11
|
+
// GET /api/repos/:repo/objects/:hash — Read object by hash
|
|
12
|
+
app.get('/:hash', async (c) => {
|
|
13
|
+
const repo = c.req.param('repo');
|
|
14
|
+
const repoPath = getRepoPath(repo);
|
|
15
|
+
const hash = c.req.param('hash');
|
|
16
|
+
if (!/^[a-f0-9]{64}$/.test(hash)) {
|
|
17
|
+
return sendError(NullType, variant('internal', { message: `invalid hash format: ${hash}` }));
|
|
18
|
+
}
|
|
19
|
+
try {
|
|
20
|
+
const data = await storage.objects.read(repoPath, hash);
|
|
21
|
+
return new Response(data, {
|
|
22
|
+
headers: {
|
|
23
|
+
'Content-Type': BEAST2_CONTENT_TYPE,
|
|
24
|
+
'Content-Length': String(data.byteLength),
|
|
25
|
+
'X-Content-SHA256': hash,
|
|
26
|
+
},
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
catch (err) {
|
|
30
|
+
if (err instanceof ObjectNotFoundError) {
|
|
31
|
+
return sendError(NullType, variant('object_not_found', { hash }));
|
|
32
|
+
}
|
|
33
|
+
throw err;
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
return app;
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=objects.js.map
|
|
@@ -0,0 +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,QAAQ,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,EAAE,mBAAmB,EAAE,mBAAmB,EAAuB,MAAM,kBAAkB,CAAC;AACjG,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEzC,MAAM,UAAU,kBAAkB,CAChC,OAAuB,EACvB,WAAqC;IAErC,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,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YACjC,OAAO,SAAS,CAAC,QAAQ,EAAE,OAAO,CAAC,UAAU,EAAE,EAAE,OAAO,EAAE,wBAAwB,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC;QAC/F,CAAC;QAED,IAAI,CAAC;YACH,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,IAAI,GAAG,YAAY,mBAAmB,EAAE,CAAC;gBACvC,OAAO,SAAS,CAAC,QAAQ,EAAE,OAAO,CAAC,kBAAkB,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;YACpE,CAAC;YACD,MAAM,GAAG,CAAC;QACZ,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,OAAO,GAAG,CAAC;AACb,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
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, TransferBackend } from '@elaraai/e3-core';
|
|
7
|
+
/**
|
|
8
|
+
* Create package transfer routes.
|
|
9
|
+
*
|
|
10
|
+
* Returns two Hono apps:
|
|
11
|
+
* - `repoApi`: Authenticated routes at repo level — mount at /api/repos/:repo
|
|
12
|
+
* (POST /import, POST /import/:id, GET /import/:id, GET /export/:id)
|
|
13
|
+
* - `pkgApi`: Authenticated routes at package level — mount at /api/repos/:repo/packages
|
|
14
|
+
* (POST /:name/:version/export)
|
|
15
|
+
*
|
|
16
|
+
* Unauthenticated data routes (upload/download bytes) are handled by the
|
|
17
|
+
* generic data endpoints in `data.ts`.
|
|
18
|
+
*/
|
|
19
|
+
export declare function createPackageTransferRoutes(storage: StorageBackend, getRepoPath: (repo: string) => string, transferBackend: TransferBackend): {
|
|
20
|
+
repoApi: Hono<import("hono/types").BlankEnv, import("hono/types").BlankSchema, "/">;
|
|
21
|
+
pkgApi: Hono<import("hono/types").BlankEnv, import("hono/types").BlankSchema, "/">;
|
|
22
|
+
};
|
|
23
|
+
//# sourceMappingURL=package-transfer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"package-transfer.d.ts","sourceRoot":"","sources":["../../../src/routes/package-transfer.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAW5B,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAaxE;;;;;;;;;;;GAWG;AACH,wBAAgB,2BAA2B,CACzC,OAAO,EAAE,cAAc,EACvB,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,EACrC,eAAe,EAAE,eAAe;;;EAwKjC"}
|
|
@@ -0,0 +1,168 @@
|
|
|
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, unlink, stat } 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 } from '@elaraai/east';
|
|
11
|
+
import { packageImport, packageExport, PackageNotFoundError, } from '@elaraai/e3-core';
|
|
12
|
+
import { PackageTransferInitRequestType, PackageTransferInitResponseType, PackageJobResponseType, PackageImportStatusType, PackageExportStatusType, } from '@elaraai/e3-types';
|
|
13
|
+
import { decodeBody, sendSuccess, sendError } from '../beast2.js';
|
|
14
|
+
import { errorToVariant } from '../errors.js';
|
|
15
|
+
const STAGING_DIR = join(tmpdir(), 'e3-transfers');
|
|
16
|
+
/**
|
|
17
|
+
* Create package transfer routes.
|
|
18
|
+
*
|
|
19
|
+
* Returns two Hono apps:
|
|
20
|
+
* - `repoApi`: Authenticated routes at repo level — mount at /api/repos/:repo
|
|
21
|
+
* (POST /import, POST /import/:id, GET /import/:id, GET /export/:id)
|
|
22
|
+
* - `pkgApi`: Authenticated routes at package level — mount at /api/repos/:repo/packages
|
|
23
|
+
* (POST /:name/:version/export)
|
|
24
|
+
*
|
|
25
|
+
* Unauthenticated data routes (upload/download bytes) are handled by the
|
|
26
|
+
* generic data endpoints in `data.ts`.
|
|
27
|
+
*/
|
|
28
|
+
export function createPackageTransferRoutes(storage, getRepoPath, transferBackend) {
|
|
29
|
+
const repoApi = new Hono();
|
|
30
|
+
const pkgApi = new Hono();
|
|
31
|
+
const MAX_PACKAGE_SIZE = 5n * 1024n * 1024n * 1024n; // 5 GB
|
|
32
|
+
// =========================================================================
|
|
33
|
+
// Repo-level routes (mounted at /api/repos/:repo)
|
|
34
|
+
// =========================================================================
|
|
35
|
+
// POST /api/repos/:repo/import — Init import
|
|
36
|
+
repoApi.post('/import', async (c) => {
|
|
37
|
+
const repo = c.req.param('repo');
|
|
38
|
+
const { size } = await decodeBody(c, PackageTransferInitRequestType);
|
|
39
|
+
if (size <= 0n || size > MAX_PACKAGE_SIZE) {
|
|
40
|
+
return sendError(PackageTransferInitResponseType, variant('internal', {
|
|
41
|
+
message: `Invalid size: must be between 1 and ${MAX_PACKAGE_SIZE} bytes`,
|
|
42
|
+
}));
|
|
43
|
+
}
|
|
44
|
+
const transferId = randomUUID();
|
|
45
|
+
await transferBackend.packageImport.create(transferId, {
|
|
46
|
+
repo,
|
|
47
|
+
size,
|
|
48
|
+
status: variant('created', null),
|
|
49
|
+
createdAt: new Date(),
|
|
50
|
+
});
|
|
51
|
+
await mkdir(STAGING_DIR, { recursive: true });
|
|
52
|
+
const uploadUrl = await transferBackend.packageImport.getUploadUrl(transferId, repo);
|
|
53
|
+
// Resolve relative URL against the request origin
|
|
54
|
+
const origin = new URL(c.req.url).origin;
|
|
55
|
+
const resolvedUrl = uploadUrl.startsWith('/') ? `${origin}${uploadUrl}` : uploadUrl;
|
|
56
|
+
return sendSuccess(PackageTransferInitResponseType, { id: transferId, uploadUrl: resolvedUrl });
|
|
57
|
+
});
|
|
58
|
+
// POST /api/repos/:repo/import/:id — Trigger import
|
|
59
|
+
repoApi.post('/import/:id', async (c) => {
|
|
60
|
+
const id = c.req.param('id');
|
|
61
|
+
const record = await transferBackend.packageImport.get(id);
|
|
62
|
+
if (!record) {
|
|
63
|
+
return sendError(PackageJobResponseType, variant('internal', { message: 'transfer not found' }));
|
|
64
|
+
}
|
|
65
|
+
const repoPath = getRepoPath(record.repo);
|
|
66
|
+
const stagingPath = join(STAGING_DIR, `${id}.zip.partial`);
|
|
67
|
+
try {
|
|
68
|
+
const result = await packageImport(storage, repoPath, stagingPath);
|
|
69
|
+
await transferBackend.packageImport.updateStatus(id, variant('completed', {
|
|
70
|
+
name: result.name,
|
|
71
|
+
version: result.version,
|
|
72
|
+
packageHash: result.packageHash,
|
|
73
|
+
objectCount: BigInt(result.objectCount),
|
|
74
|
+
}));
|
|
75
|
+
}
|
|
76
|
+
catch (err) {
|
|
77
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
78
|
+
await transferBackend.packageImport.updateStatus(id, variant('failed', { message }));
|
|
79
|
+
}
|
|
80
|
+
finally {
|
|
81
|
+
await unlink(stagingPath).catch(() => { });
|
|
82
|
+
}
|
|
83
|
+
return sendSuccess(PackageJobResponseType, { id });
|
|
84
|
+
});
|
|
85
|
+
// GET /api/repos/:repo/import/:id — Poll import status
|
|
86
|
+
repoApi.get('/import/:id', async (c) => {
|
|
87
|
+
const id = c.req.param('id');
|
|
88
|
+
const record = await transferBackend.packageImport.get(id);
|
|
89
|
+
if (!record) {
|
|
90
|
+
return sendError(PackageImportStatusType, variant('internal', { message: 'import job not found' }));
|
|
91
|
+
}
|
|
92
|
+
const { type, value } = record.status;
|
|
93
|
+
if (type === 'processing' || type === 'created' || type === 'uploaded') {
|
|
94
|
+
return sendSuccess(PackageImportStatusType, variant('processing', null));
|
|
95
|
+
}
|
|
96
|
+
if (type === 'failed') {
|
|
97
|
+
return sendSuccess(PackageImportStatusType, variant('failed', { message: value.message }));
|
|
98
|
+
}
|
|
99
|
+
if (type === 'completed') {
|
|
100
|
+
return sendSuccess(PackageImportStatusType, variant('completed', value));
|
|
101
|
+
}
|
|
102
|
+
return sendError(PackageImportStatusType, variant('internal', { message: 'unknown status' }));
|
|
103
|
+
});
|
|
104
|
+
// GET /api/repos/:repo/export/:id — Poll export status
|
|
105
|
+
repoApi.get('/export/:id', async (c) => {
|
|
106
|
+
const id = c.req.param('id');
|
|
107
|
+
const record = await transferBackend.packageExport.get(id);
|
|
108
|
+
if (!record) {
|
|
109
|
+
return sendError(PackageExportStatusType, variant('internal', { message: 'export job not found' }));
|
|
110
|
+
}
|
|
111
|
+
const { type, value } = record.status;
|
|
112
|
+
if (type === 'processing') {
|
|
113
|
+
return sendSuccess(PackageExportStatusType, variant('processing', null));
|
|
114
|
+
}
|
|
115
|
+
if (type === 'failed') {
|
|
116
|
+
return sendSuccess(PackageExportStatusType, variant('failed', { message: value.message }));
|
|
117
|
+
}
|
|
118
|
+
if (type === 'completed') {
|
|
119
|
+
const downloadUrl = await transferBackend.packageExport.getDownloadUrl(id, record.repo);
|
|
120
|
+
// Resolve relative URL against the request origin
|
|
121
|
+
const origin = new URL(c.req.url).origin;
|
|
122
|
+
const resolvedUrl = downloadUrl.startsWith('/') ? `${origin}${downloadUrl}` : downloadUrl;
|
|
123
|
+
return sendSuccess(PackageExportStatusType, variant('completed', {
|
|
124
|
+
downloadUrl: resolvedUrl,
|
|
125
|
+
size: value.size,
|
|
126
|
+
}));
|
|
127
|
+
}
|
|
128
|
+
return sendError(PackageExportStatusType, variant('internal', { message: 'unknown status' }));
|
|
129
|
+
});
|
|
130
|
+
// =========================================================================
|
|
131
|
+
// Package-level routes (mounted at /api/repos/:repo/packages)
|
|
132
|
+
// =========================================================================
|
|
133
|
+
// POST /api/repos/:repo/packages/:name/:version/export — Trigger export
|
|
134
|
+
pkgApi.post('/:name/:version/export', async (c) => {
|
|
135
|
+
const repo = c.req.param('repo');
|
|
136
|
+
const repoPath = getRepoPath(repo);
|
|
137
|
+
const name = c.req.param('name');
|
|
138
|
+
const version = c.req.param('version');
|
|
139
|
+
const id = randomUUID();
|
|
140
|
+
await transferBackend.packageExport.create(id, {
|
|
141
|
+
repo,
|
|
142
|
+
name,
|
|
143
|
+
version,
|
|
144
|
+
status: variant('processing', null),
|
|
145
|
+
createdAt: new Date(),
|
|
146
|
+
});
|
|
147
|
+
await mkdir(STAGING_DIR, { recursive: true });
|
|
148
|
+
const zipPath = join(STAGING_DIR, `${id}.zip`);
|
|
149
|
+
try {
|
|
150
|
+
await packageExport(storage, repoPath, name, version, zipPath);
|
|
151
|
+
const fileStat = await stat(zipPath);
|
|
152
|
+
await transferBackend.packageExport.updateStatus(id, variant('completed', {
|
|
153
|
+
size: BigInt(fileStat.size),
|
|
154
|
+
}));
|
|
155
|
+
}
|
|
156
|
+
catch (err) {
|
|
157
|
+
await unlink(zipPath).catch(() => { });
|
|
158
|
+
if (err instanceof PackageNotFoundError) {
|
|
159
|
+
return sendError(PackageJobResponseType, errorToVariant(err));
|
|
160
|
+
}
|
|
161
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
162
|
+
await transferBackend.packageExport.updateStatus(id, variant('failed', { message }));
|
|
163
|
+
}
|
|
164
|
+
return sendSuccess(PackageJobResponseType, { id });
|
|
165
|
+
});
|
|
166
|
+
return { repoApi, pkgApi };
|
|
167
|
+
}
|
|
168
|
+
//# sourceMappingURL=package-transfer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"package-transfer.js","sourceRoot":"","sources":["../../../src/routes/package-transfer.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"packages.d.ts","sourceRoot":"","sources":["../../../src/routes/packages.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"packages.d.ts","sourceRoot":"","sources":["../../../src/routes/packages.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAOvD,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,cAAc,EACvB,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,8EA8BtC"}
|
|
@@ -3,9 +3,7 @@
|
|
|
3
3
|
* Licensed under BSL 1.1. See LICENSE for details.
|
|
4
4
|
*/
|
|
5
5
|
import { Hono } from 'hono';
|
|
6
|
-
import {
|
|
7
|
-
import { listPackages, getPackage, importPackage, exportPackage, deletePackage, } from '../handlers/packages.js';
|
|
8
|
-
import { decodeBody } from '../beast2.js';
|
|
6
|
+
import { listPackages, getPackage, deletePackage, } from '../handlers/packages.js';
|
|
9
7
|
export function createPackageRoutes(storage, getRepoPath) {
|
|
10
8
|
const app = new Hono();
|
|
11
9
|
// GET /api/repos/:repo/packages - List all packages
|
|
@@ -22,32 +20,6 @@ export function createPackageRoutes(storage, getRepoPath) {
|
|
|
22
20
|
const version = c.req.param('version');
|
|
23
21
|
return getPackage(storage, repoPath, name, version);
|
|
24
22
|
});
|
|
25
|
-
// POST /api/repos/:repo/packages - Import a package from zip
|
|
26
|
-
app.post('/', async (c) => {
|
|
27
|
-
const repo = c.req.param('repo');
|
|
28
|
-
const repoPath = getRepoPath(repo);
|
|
29
|
-
// Read raw body as zip bytes
|
|
30
|
-
const contentType = c.req.header('content-type');
|
|
31
|
-
let archive;
|
|
32
|
-
if (contentType === 'application/beast2') {
|
|
33
|
-
// BEAST2 encoded blob
|
|
34
|
-
archive = await decodeBody(c, BlobType);
|
|
35
|
-
}
|
|
36
|
-
else {
|
|
37
|
-
// Raw zip bytes
|
|
38
|
-
const buffer = await c.req.arrayBuffer();
|
|
39
|
-
archive = new Uint8Array(buffer);
|
|
40
|
-
}
|
|
41
|
-
return importPackage(storage, repoPath, archive);
|
|
42
|
-
});
|
|
43
|
-
// GET /api/repos/:repo/packages/:name/:version/export - Export package as zip
|
|
44
|
-
app.get('/:name/:version/export', async (c) => {
|
|
45
|
-
const repo = c.req.param('repo');
|
|
46
|
-
const repoPath = getRepoPath(repo);
|
|
47
|
-
const name = c.req.param('name');
|
|
48
|
-
const version = c.req.param('version');
|
|
49
|
-
return exportPackage(storage, repoPath, name, version);
|
|
50
|
-
});
|
|
51
23
|
// DELETE /api/repos/:repo/packages/:name/:version - Remove a package
|
|
52
24
|
app.delete('/:name/:version', async (c) => {
|
|
53
25
|
const repo = c.req.param('repo');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"packages.js","sourceRoot":"","sources":["../../../src/routes/packages.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"packages.js","sourceRoot":"","sources":["../../../src/routes/packages.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAE5B,OAAO,EACL,YAAY,EACZ,UAAU,EACV,aAAa,GACd,MAAM,yBAAyB,CAAC;AAEjC,MAAM,UAAU,mBAAmB,CACjC,OAAuB,EACvB,WAAqC;IAErC,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;IAEvB,oDAAoD;IACpD,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;QACvB,MAAM,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAE,CAAC;QAClC,MAAM,QAAQ,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC;QACnC,OAAO,YAAY,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IACzC,CAAC,CAAC,CAAC;IAEH,qEAAqE;IACrE,GAAG,CAAC,GAAG,CAAC,iBAAiB,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;QACrC,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;QAClC,MAAM,OAAO,GAAG,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAE,CAAC;QACxC,OAAO,UAAU,CAAC,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;IACtD,CAAC,CAAC,CAAC;IAEH,qEAAqE;IACrE,GAAG,CAAC,MAAM,CAAC,iBAAiB,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;QACxC,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;QAClC,MAAM,OAAO,GAAG,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAE,CAAC;QACxC,OAAO,aAAa,CAAC,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;IACzD,CAAC,CAAC,CAAC;IAEH,OAAO,GAAG,CAAC;AACb,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
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, type TransferBackend } from '@elaraai/e3-core';
|
|
7
|
+
/**
|
|
8
|
+
* Create dataset transfer routes.
|
|
9
|
+
*
|
|
10
|
+
* Returns an `api` Hono app with authenticated routes (init upload, commit)
|
|
11
|
+
* mounted at /api/repos/:repo/workspaces/:ws/datasets.
|
|
12
|
+
*
|
|
13
|
+
* Unauthenticated data routes (upload/download bytes) are handled by the
|
|
14
|
+
* generic data endpoints in `data.ts`.
|
|
15
|
+
*/
|
|
16
|
+
export declare function createTransferRoutes(storage: StorageBackend, getRepoPath: (repo: string) => string, transferBackend: TransferBackend): {
|
|
17
|
+
api: Hono<import("hono/types").BlankEnv, import("hono/types").BlankSchema, "/">;
|
|
18
|
+
};
|
|
19
|
+
//# sourceMappingURL=transfer.d.ts.map
|
|
@@ -0,0 +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;AAQ5B,OAAO,EAGL,KAAK,cAAc,EACnB,KAAK,eAAe,EACrB,MAAM,kBAAkB,CAAC;AAM1B;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,cAAc,EACvB,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,EACrC,eAAe,EAAE,eAAe;;EAyHjC"}
|
|
@@ -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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"}
|
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;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;
|
|
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"}
|