@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.
Files changed (129) hide show
  1. package/README.md +83 -19
  2. package/dist/src/beast2.js +1 -1
  3. package/dist/src/beast2.js.map +1 -1
  4. package/dist/src/cli.js +13 -0
  5. package/dist/src/cli.js.map +1 -1
  6. package/dist/src/errors.d.ts.map +1 -1
  7. package/dist/src/errors.js +8 -1
  8. package/dist/src/errors.js.map +1 -1
  9. package/dist/src/handlers/dataflow.d.ts +58 -11
  10. package/dist/src/handlers/dataflow.d.ts.map +1 -1
  11. package/dist/src/handlers/dataflow.js +120 -48
  12. package/dist/src/handlers/dataflow.js.map +1 -1
  13. package/dist/src/handlers/dataflow.spec.d.ts +6 -0
  14. package/dist/src/handlers/dataflow.spec.d.ts.map +1 -0
  15. package/dist/src/handlers/dataflow.spec.js +106 -0
  16. package/dist/src/handlers/dataflow.spec.js.map +1 -0
  17. package/dist/src/handlers/datasets.d.ts +60 -34
  18. package/dist/src/handlers/datasets.d.ts.map +1 -1
  19. package/dist/src/handlers/datasets.js +452 -306
  20. package/dist/src/handlers/datasets.js.map +1 -1
  21. package/dist/src/handlers/datasets.spec.js +338 -119
  22. package/dist/src/handlers/datasets.spec.js.map +1 -1
  23. package/dist/src/handlers/functions.d.ts.map +1 -1
  24. package/dist/src/handlers/functions.js +10 -8
  25. package/dist/src/handlers/functions.js.map +1 -1
  26. package/dist/src/handlers/functions.spec.js +2 -2
  27. package/dist/src/handlers/functions.spec.js.map +1 -1
  28. package/dist/src/handlers/index.d.ts +2 -2
  29. package/dist/src/handlers/index.d.ts.map +1 -1
  30. package/dist/src/handlers/index.js +2 -2
  31. package/dist/src/handlers/index.js.map +1 -1
  32. package/dist/src/handlers/records.d.ts.map +1 -1
  33. package/dist/src/handlers/records.js +15 -12
  34. package/dist/src/handlers/records.js.map +1 -1
  35. package/dist/src/handlers/records.spec.js +9 -5
  36. package/dist/src/handlers/records.spec.js.map +1 -1
  37. package/dist/src/handlers/repository.d.ts +59 -10
  38. package/dist/src/handlers/repository.d.ts.map +1 -1
  39. package/dist/src/handlers/repository.js +147 -40
  40. package/dist/src/handlers/repository.js.map +1 -1
  41. package/dist/src/handlers/tasks.d.ts +2 -1
  42. package/dist/src/handlers/tasks.d.ts.map +1 -1
  43. package/dist/src/handlers/tasks.js +31 -8
  44. package/dist/src/handlers/tasks.js.map +1 -1
  45. package/dist/src/handlers/tasks.spec.d.ts +6 -0
  46. package/dist/src/handlers/tasks.spec.d.ts.map +1 -0
  47. package/dist/src/handlers/tasks.spec.js +64 -0
  48. package/dist/src/handlers/tasks.spec.js.map +1 -0
  49. package/dist/src/handlers/workspaces.d.ts +44 -6
  50. package/dist/src/handlers/workspaces.d.ts.map +1 -1
  51. package/dist/src/handlers/workspaces.js +74 -40
  52. package/dist/src/handlers/workspaces.js.map +1 -1
  53. package/dist/src/handlers/workspaces.spec.d.ts +6 -0
  54. package/dist/src/handlers/workspaces.spec.d.ts.map +1 -0
  55. package/dist/src/handlers/workspaces.spec.js +164 -0
  56. package/dist/src/handlers/workspaces.spec.js.map +1 -0
  57. package/dist/src/index.d.ts +3 -0
  58. package/dist/src/index.d.ts.map +1 -1
  59. package/dist/src/index.js +7 -0
  60. package/dist/src/index.js.map +1 -1
  61. package/dist/src/local-dataflow.d.ts +14 -0
  62. package/dist/src/local-dataflow.d.ts.map +1 -0
  63. package/dist/src/local-dataflow.js +41 -0
  64. package/dist/src/local-dataflow.js.map +1 -0
  65. package/dist/src/middleware/repository.d.ts +39 -0
  66. package/dist/src/middleware/repository.d.ts.map +1 -0
  67. package/dist/src/middleware/repository.js +77 -0
  68. package/dist/src/middleware/repository.js.map +1 -0
  69. package/dist/src/routes/data.d.ts +2 -2
  70. package/dist/src/routes/data.d.ts.map +1 -1
  71. package/dist/src/routes/data.js +22 -45
  72. package/dist/src/routes/data.js.map +1 -1
  73. package/dist/src/routes/datasets.d.ts +0 -3
  74. package/dist/src/routes/datasets.d.ts.map +1 -1
  75. package/dist/src/routes/datasets.js +40 -8
  76. package/dist/src/routes/datasets.js.map +1 -1
  77. package/dist/src/routes/executions.d.ts +37 -2
  78. package/dist/src/routes/executions.d.ts.map +1 -1
  79. package/dist/src/routes/executions.js +21 -12
  80. package/dist/src/routes/executions.js.map +1 -1
  81. package/dist/src/routes/index.d.ts +2 -1
  82. package/dist/src/routes/index.d.ts.map +1 -1
  83. package/dist/src/routes/index.js +1 -0
  84. package/dist/src/routes/index.js.map +1 -1
  85. package/dist/src/routes/objects.d.ts +16 -2
  86. package/dist/src/routes/objects.d.ts.map +1 -1
  87. package/dist/src/routes/objects.js +34 -3
  88. package/dist/src/routes/objects.js.map +1 -1
  89. package/dist/src/routes/repositories.d.ts +26 -0
  90. package/dist/src/routes/repositories.d.ts.map +1 -0
  91. package/dist/src/routes/repositories.js +58 -0
  92. package/dist/src/routes/repositories.js.map +1 -0
  93. package/dist/src/routes/repositories.spec.d.ts +6 -0
  94. package/dist/src/routes/repositories.spec.d.ts.map +1 -0
  95. package/dist/src/routes/repositories.spec.js +77 -0
  96. package/dist/src/routes/repositories.spec.js.map +1 -0
  97. package/dist/src/routes/repository.d.ts +12 -2
  98. package/dist/src/routes/repository.d.ts.map +1 -1
  99. package/dist/src/routes/repository.js +24 -9
  100. package/dist/src/routes/repository.js.map +1 -1
  101. package/dist/src/routes/transfer.d.ts +11 -9
  102. package/dist/src/routes/transfer.d.ts.map +1 -1
  103. package/dist/src/routes/transfer.js +90 -115
  104. package/dist/src/routes/transfer.js.map +1 -1
  105. package/dist/src/routes/workspaces.d.ts +14 -1
  106. package/dist/src/routes/workspaces.d.ts.map +1 -1
  107. package/dist/src/routes/workspaces.js +57 -46
  108. package/dist/src/routes/workspaces.js.map +1 -1
  109. package/dist/src/server.d.ts +18 -6
  110. package/dist/src/server.d.ts.map +1 -1
  111. package/dist/src/server.js +55 -182
  112. package/dist/src/server.js.map +1 -1
  113. package/dist/src/server.spec.d.ts +6 -0
  114. package/dist/src/server.spec.d.ts.map +1 -0
  115. package/dist/src/server.spec.js +59 -0
  116. package/dist/src/server.spec.js.map +1 -0
  117. package/dist/src/types.d.ts +200 -16
  118. package/dist/src/types.d.ts.map +1 -1
  119. package/dist/src/types.js +5 -2
  120. package/dist/src/types.js.map +1 -1
  121. package/package.json +5 -5
  122. package/dist/src/async-operation-state.d.ts +0 -37
  123. package/dist/src/async-operation-state.d.ts.map +0 -1
  124. package/dist/src/async-operation-state.js +0 -118
  125. package/dist/src/async-operation-state.js.map +0 -1
  126. package/dist/src/orchestrator-manager.d.ts +0 -45
  127. package/dist/src/orchestrator-manager.d.ts.map +0 -1
  128. package/dist/src/orchestrator-manager.js +0 -150
  129. 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 { BEAST2_CONTENT_TYPE } from '@elaraai/e3-core';
6
+ import { isObjectHash } from '@elaraai/e3-core';
7
+ import { BEAST2_CONTENT_TYPE } from '@elaraai/e3-types';
7
8
  import { sendJsonError } from '../errors.js';
8
- export function createObjectRoutes(storage, getRepoPath) {
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 (!/^[a-f0-9]{64}$/.test(hash)) {
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,mBAAmB,EAAuB,MAAM,kBAAkB,CAAC;AAC5E,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAE7C,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,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,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"}
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,6 @@
1
+ /**
2
+ * Copyright (c) 2025 Elara AI Pty Ltd
3
+ * Licensed under BSL 1.1. See LICENSE for details.
4
+ */
5
+ export {};
6
+ //# sourceMappingURL=repositories.spec.d.ts.map
@@ -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
- export declare function createRepositoryRoutes(storage: StorageBackend, getRepoPath: (repo: string) => string): Hono<import("hono/types").BlankEnv, import("hono/types").BlankSchema, "/">;
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;AAKvD,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,cAAc,EACvB,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,8EA2BtC"}
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
- export function createRepositoryRoutes(storage, getRepoPath) {
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
- // POST /api/repos/:repo/gc - Start garbage collection (async)
18
- app.post('/gc', async (c) => {
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
- const options = await decodeBody(c, GcRequestType);
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
- // GET /api/repos/:repo/gc/:executionId - Get GC status
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;AAC5E,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,MAAM,UAAU,sBAAsB,CACpC,OAAuB,EACvB,WAAqC;IAErC,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,8DAA8D;IAC9D,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,QAAQ,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC;QACnC,MAAM,OAAO,GAAG,MAAM,UAAU,CAAC,CAAC,EAAE,aAAa,CAAC,CAAC;QACnD,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QAC1F,OAAO,OAAO,CAAC,OAAO,EAAE,QAAQ,EAAE,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IACxE,CAAC,CAAC,CAAC;IAEH,uDAAuD;IACvD,GAAG,CAAC,GAAG,CAAC,kBAAkB,EAAE,CAAC,CAAC,EAAE,EAAE;QAChC,MAAM,WAAW,GAAG,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,aAAa,CAAE,CAAC;QAChD,OAAO,WAAW,CAAC,WAAW,CAAC,CAAC;IAClC,CAAC,CAAC,CAAC;IAEH,OAAO,GAAG,CAAC;AACb,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 protocol-2 commit waits for the staged bytes to be verified
11
- * before it answers `processing` for the client to poll (default 5000 ms; 0
12
- * answers `processing` at once). A protocol-1 commit always waits.
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
- * A protocol-2 client (`?protocol=2` on the init and the commit) is sent its
27
- * bytes' plan as parts, and its commit runs in the background: the request
28
- * waits up to `commitWaitMs` for it and otherwise answers `processing`, which
29
- * the client polls — so verifying a delivery of many gigabytes never holds one
30
- * request open for as long as its SHA-256 takes. A protocol-1 client gets the
31
- * single upload URL and a commit that answers only when it is done.
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;AAM5B,OAAO,EAOL,KAAK,cAAc,EACnB,KAAK,eAAe,EACrB,MAAM,kBAAkB,CAAC;AAW1B,gDAAgD;AAChD,MAAM,WAAW,oBAAoB;IACnC;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAqDD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,cAAc,EACvB,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,EACrC,eAAe,EAAE,eAAe,EAChC,OAAO,GAAE,oBAAyB;;EA0OnC"}
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"}