@elaraai/e3-api-server 0.0.2-beta.12 → 0.0.2-beta.14

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 (111) hide show
  1. package/README.md +144 -29
  2. package/dist/src/async-operation-state.d.ts +63 -0
  3. package/dist/src/async-operation-state.d.ts.map +1 -0
  4. package/dist/src/async-operation-state.js +193 -0
  5. package/dist/src/async-operation-state.js.map +1 -0
  6. package/dist/src/auth/device.d.ts +26 -0
  7. package/dist/src/auth/device.d.ts.map +1 -0
  8. package/dist/src/auth/device.js +227 -0
  9. package/dist/src/auth/device.js.map +1 -0
  10. package/dist/src/auth/discovery.d.ts +23 -0
  11. package/dist/src/auth/discovery.d.ts.map +1 -0
  12. package/dist/src/auth/discovery.js +40 -0
  13. package/dist/src/auth/discovery.js.map +1 -0
  14. package/dist/src/auth/index.d.ts +56 -0
  15. package/dist/src/auth/index.d.ts.map +1 -0
  16. package/dist/src/auth/index.js +69 -0
  17. package/dist/src/auth/index.js.map +1 -0
  18. package/dist/src/auth/keys.d.ts +55 -0
  19. package/dist/src/auth/keys.d.ts.map +1 -0
  20. package/dist/src/auth/keys.js +78 -0
  21. package/dist/src/auth/keys.js.map +1 -0
  22. package/dist/src/beast2.d.ts +15 -3
  23. package/dist/src/beast2.d.ts.map +1 -1
  24. package/dist/src/beast2.js +30 -4
  25. package/dist/src/beast2.js.map +1 -1
  26. package/dist/src/cli.js +58 -6
  27. package/dist/src/cli.js.map +1 -1
  28. package/dist/src/errors.d.ts.map +1 -1
  29. package/dist/src/errors.js +5 -2
  30. package/dist/src/errors.js.map +1 -1
  31. package/dist/src/execution-state.d.ts +54 -0
  32. package/dist/src/execution-state.d.ts.map +1 -0
  33. package/dist/src/execution-state.js +150 -0
  34. package/dist/src/execution-state.js.map +1 -0
  35. package/dist/src/handlers/dataflow.d.ts +49 -0
  36. package/dist/src/handlers/dataflow.d.ts.map +1 -0
  37. package/dist/src/handlers/dataflow.js +371 -0
  38. package/dist/src/handlers/dataflow.js.map +1 -0
  39. package/dist/src/handlers/datasets.d.ts +23 -0
  40. package/dist/src/handlers/datasets.d.ts.map +1 -0
  41. package/dist/src/handlers/datasets.js +113 -0
  42. package/dist/src/handlers/datasets.js.map +1 -0
  43. package/dist/src/handlers/index.d.ts +12 -0
  44. package/dist/src/handlers/index.d.ts.map +1 -0
  45. package/dist/src/handlers/index.js +12 -0
  46. package/dist/src/handlers/index.js.map +1 -0
  47. package/dist/src/handlers/packages.d.ts +26 -0
  48. package/dist/src/handlers/packages.d.ts.map +1 -0
  49. package/dist/src/handlers/packages.js +101 -0
  50. package/dist/src/handlers/packages.js.map +1 -0
  51. package/dist/src/handlers/repos.d.ts +11 -0
  52. package/dist/src/handlers/repos.d.ts.map +1 -0
  53. package/dist/src/handlers/repos.js +52 -0
  54. package/dist/src/handlers/repos.js.map +1 -0
  55. package/dist/src/handlers/repository.d.ts +35 -0
  56. package/dist/src/handlers/repository.d.ts.map +1 -0
  57. package/dist/src/handlers/repository.js +142 -0
  58. package/dist/src/handlers/repository.js.map +1 -0
  59. package/dist/src/handlers/tasks.d.ts +18 -0
  60. package/dist/src/handlers/tasks.d.ts.map +1 -0
  61. package/dist/src/handlers/tasks.js +134 -0
  62. package/dist/src/handlers/tasks.js.map +1 -0
  63. package/dist/src/handlers/workspaces.d.ts +34 -0
  64. package/dist/src/handlers/workspaces.d.ts.map +1 -0
  65. package/dist/src/handlers/workspaces.js +225 -0
  66. package/dist/src/handlers/workspaces.js.map +1 -0
  67. package/dist/src/index.d.ts +3 -0
  68. package/dist/src/index.d.ts.map +1 -1
  69. package/dist/src/index.js +6 -0
  70. package/dist/src/index.js.map +1 -1
  71. package/dist/src/middleware/auth.d.ts +51 -0
  72. package/dist/src/middleware/auth.d.ts.map +1 -0
  73. package/dist/src/middleware/auth.js +158 -0
  74. package/dist/src/middleware/auth.js.map +1 -0
  75. package/dist/src/routes/datasets.d.ts +2 -1
  76. package/dist/src/routes/datasets.d.ts.map +1 -1
  77. package/dist/src/routes/datasets.js +50 -85
  78. package/dist/src/routes/datasets.js.map +1 -1
  79. package/dist/src/routes/executions.d.ts +2 -1
  80. package/dist/src/routes/executions.d.ts.map +1 -1
  81. package/dist/src/routes/executions.js +60 -286
  82. package/dist/src/routes/executions.js.map +1 -1
  83. package/dist/src/routes/index.d.ts +11 -0
  84. package/dist/src/routes/index.d.ts.map +1 -0
  85. package/dist/src/routes/index.js +11 -0
  86. package/dist/src/routes/index.js.map +1 -0
  87. package/dist/src/routes/packages.d.ts +2 -1
  88. package/dist/src/routes/packages.d.ts.map +1 -1
  89. package/dist/src/routes/packages.js +42 -105
  90. package/dist/src/routes/packages.js.map +1 -1
  91. package/dist/src/routes/repository.d.ts +2 -1
  92. package/dist/src/routes/repository.d.ts.map +1 -1
  93. package/dist/src/routes/repository.js +19 -54
  94. package/dist/src/routes/repository.js.map +1 -1
  95. package/dist/src/routes/tasks.d.ts +2 -1
  96. package/dist/src/routes/tasks.d.ts.map +1 -1
  97. package/dist/src/routes/tasks.js +22 -46
  98. package/dist/src/routes/tasks.js.map +1 -1
  99. package/dist/src/routes/workspaces.d.ts +2 -1
  100. package/dist/src/routes/workspaces.d.ts.map +1 -1
  101. package/dist/src/routes/workspaces.js +45 -116
  102. package/dist/src/routes/workspaces.js.map +1 -1
  103. package/dist/src/server.d.ts +24 -3
  104. package/dist/src/server.d.ts.map +1 -1
  105. package/dist/src/server.js +178 -19
  106. package/dist/src/server.js.map +1 -1
  107. package/dist/src/types.d.ts +486 -1
  108. package/dist/src/types.d.ts.map +1 -1
  109. package/dist/src/types.js +209 -2
  110. package/dist/src/types.js.map +1 -1
  111. package/package.json +15 -3
@@ -2,131 +2,60 @@
2
2
  * Copyright (c) 2025 Elara AI Pty Ltd
3
3
  * Licensed under BSL 1.1. See LICENSE for details.
4
4
  */
5
- import * as fs from 'node:fs/promises';
6
- import * as os from 'node:os';
7
- import * as path from 'node:path';
8
5
  import { Hono } from 'hono';
9
- import { ArrayType, BlobType, NullType, some, none } from '@elaraai/east';
10
- import { WorkspaceStateType, parsePackageRef } from '@elaraai/e3-types';
11
- import { workspaceList, workspaceCreate, workspaceRemove, workspaceGetState, workspaceDeploy, workspaceExport, packageGetLatestVersion, } from '@elaraai/e3-core';
12
- import { decodeBody, sendSuccess, sendError } from '../beast2.js';
13
- import { errorToVariant } from '../errors.js';
14
- import { WorkspaceInfoType, CreateWorkspaceType, DeployRequestType } from '../types.js';
15
- export function createWorkspaceRoutes(repoPath) {
6
+ import { listWorkspaces, createWorkspace, getWorkspace, getWorkspaceStatus, deleteWorkspace, deployWorkspace, exportWorkspace, } from '../handlers/workspaces.js';
7
+ import { decodeBody } from '../beast2.js';
8
+ import { CreateWorkspaceType, DeployRequestType } from '../types.js';
9
+ export function createWorkspaceRoutes(storage, getRepoPath) {
16
10
  const app = new Hono();
17
- // GET /api/workspaces - List all workspaces
11
+ // GET /api/repos/:repo/workspaces - List all workspaces
18
12
  app.get('/', async (c) => {
19
- try {
20
- const workspaces = await workspaceList(repoPath);
21
- const result = await Promise.all(workspaces.map(async (name) => {
22
- const state = await workspaceGetState(repoPath, name);
23
- if (state) {
24
- return {
25
- name,
26
- deployed: true,
27
- packageName: some(state.packageName),
28
- packageVersion: some(state.packageVersion),
29
- };
30
- }
31
- else {
32
- return {
33
- name,
34
- deployed: false,
35
- packageName: none,
36
- packageVersion: none,
37
- };
38
- }
39
- }));
40
- return sendSuccess(c, ArrayType(WorkspaceInfoType), result);
41
- }
42
- catch (err) {
43
- return sendError(c, ArrayType(WorkspaceInfoType), errorToVariant(err));
44
- }
13
+ const repo = c.req.param('repo');
14
+ const repoPath = getRepoPath(repo);
15
+ return listWorkspaces(storage, repoPath);
45
16
  });
46
- // POST /api/workspaces - Create a new workspace
17
+ // POST /api/repos/:repo/workspaces - Create a new workspace
47
18
  app.post('/', async (c) => {
48
- try {
49
- const body = await decodeBody(c, CreateWorkspaceType);
50
- await workspaceCreate(repoPath, body.name);
51
- return sendSuccess(c, WorkspaceInfoType, {
52
- name: body.name,
53
- deployed: false,
54
- packageName: none,
55
- packageVersion: none,
56
- });
57
- }
58
- catch (err) {
59
- return sendError(c, WorkspaceInfoType, errorToVariant(err));
60
- }
19
+ const repo = c.req.param('repo');
20
+ const repoPath = getRepoPath(repo);
21
+ const body = await decodeBody(c, CreateWorkspaceType);
22
+ return createWorkspace(storage, repoPath, body.name);
61
23
  });
62
- // GET /api/workspaces/:name - Get workspace state
63
- app.get('/:name', async (c) => {
64
- try {
65
- const name = c.req.param('name');
66
- const state = await workspaceGetState(repoPath, name);
67
- if (!state) {
68
- // Workspace exists but not deployed - return error
69
- return sendError(c, WorkspaceStateType, errorToVariant(new Error(`Workspace '${name}' is not deployed`)));
70
- }
71
- return sendSuccess(c, WorkspaceStateType, state);
72
- }
73
- catch (err) {
74
- return sendError(c, WorkspaceStateType, errorToVariant(err));
75
- }
24
+ // GET /api/repos/:repo/workspaces/:ws - Get workspace state
25
+ app.get('/:ws', async (c) => {
26
+ const repo = c.req.param('repo');
27
+ const repoPath = getRepoPath(repo);
28
+ const ws = c.req.param('ws');
29
+ return getWorkspace(storage, repoPath, ws);
76
30
  });
77
- // DELETE /api/workspaces/:name - Remove a workspace
78
- app.delete('/:name', async (c) => {
79
- try {
80
- const name = c.req.param('name');
81
- await workspaceRemove(repoPath, name);
82
- return sendSuccess(c, NullType, null);
83
- }
84
- catch (err) {
85
- return sendError(c, NullType, errorToVariant(err));
86
- }
31
+ // GET /api/repos/:repo/workspaces/:ws/status - Get comprehensive workspace status
32
+ app.get('/:ws/status', (c) => {
33
+ const repo = c.req.param('repo');
34
+ const repoPath = getRepoPath(repo);
35
+ const ws = c.req.param('ws');
36
+ return getWorkspaceStatus(storage, repoPath, ws);
87
37
  });
88
- // POST /api/workspaces/:name/deploy - Deploy a package to a workspace
89
- app.post('/:name/deploy', async (c) => {
90
- try {
91
- const name = c.req.param('name');
92
- if (!name) {
93
- return sendError(c, NullType, errorToVariant(new Error('Missing workspace name parameter')));
94
- }
95
- const body = await decodeBody(c, DeployRequestType);
96
- const { name: pkgName, version: maybeVersion } = parsePackageRef(body.packageRef);
97
- const pkgVersion = maybeVersion ?? await packageGetLatestVersion(repoPath, pkgName);
98
- if (!pkgVersion) {
99
- return sendError(c, NullType, errorToVariant(new Error(`Package not found: ${pkgName}`)));
100
- }
101
- await workspaceDeploy(repoPath, name, pkgName, pkgVersion);
102
- return sendSuccess(c, NullType, null);
103
- }
104
- catch (err) {
105
- return sendError(c, NullType, errorToVariant(err));
106
- }
38
+ // DELETE /api/repos/:repo/workspaces/:ws - Remove a workspace
39
+ app.delete('/:ws', async (c) => {
40
+ const repo = c.req.param('repo');
41
+ const repoPath = getRepoPath(repo);
42
+ const ws = c.req.param('ws');
43
+ return deleteWorkspace(storage, repoPath, ws);
107
44
  });
108
- // GET /api/workspaces/:name/export - Export workspace as a package zip
109
- app.get('/:name/export', async (c) => {
110
- try {
111
- const name = c.req.param('name');
112
- if (!name) {
113
- return sendError(c, BlobType, errorToVariant(new Error('Missing workspace name parameter')));
114
- }
115
- // Export to temp file
116
- const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), 'e3-ws-export-'));
117
- const tempPath = path.join(tempDir, 'workspace.zip');
118
- try {
119
- await workspaceExport(repoPath, name, tempPath);
120
- const archive = await fs.readFile(tempPath);
121
- return sendSuccess(c, BlobType, new Uint8Array(archive));
122
- }
123
- finally {
124
- await fs.rm(tempDir, { recursive: true, force: true });
125
- }
126
- }
127
- catch (err) {
128
- return sendError(c, BlobType, errorToVariant(err));
129
- }
45
+ // POST /api/repos/:repo/workspaces/:ws/deploy - Deploy a package to a workspace
46
+ app.post('/:ws/deploy', async (c) => {
47
+ const repo = c.req.param('repo');
48
+ const repoPath = getRepoPath(repo);
49
+ const ws = c.req.param('ws');
50
+ const body = await decodeBody(c, DeployRequestType);
51
+ return deployWorkspace(storage, repoPath, ws, body.packageRef);
52
+ });
53
+ // GET /api/repos/:repo/workspaces/:ws/export - Export workspace as a package zip
54
+ app.get('/:ws/export', async (c) => {
55
+ const repo = c.req.param('repo');
56
+ const repoPath = getRepoPath(repo);
57
+ const ws = c.req.param('ws');
58
+ return exportWorkspace(storage, repoPath, ws);
130
59
  });
131
60
  return app;
132
61
  }
@@ -1 +1 @@
1
- {"version":3,"file":"workspaces.js","sourceRoot":"","sources":["../../../src/routes/workspaces.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"workspaces.js","sourceRoot":"","sources":["../../../src/routes/workspaces.ts"],"names":[],"mappings":"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"}
@@ -3,18 +3,32 @@
3
3
  * Licensed under BSL 1.1. See LICENSE for details.
4
4
  */
5
5
  import { type ServerType } from '@hono/node-server';
6
+ import { type AuthConfig } from './middleware/auth.js';
7
+ import { type OidcConfig } from './auth/index.js';
8
+ export type { AuthConfig } from './middleware/auth.js';
9
+ export type { OidcConfig } from './auth/index.js';
6
10
  /**
7
11
  * Server configuration options.
12
+ *
13
+ * Must specify exactly one of:
14
+ * - reposDir: Multi-repo mode - serves multiple repositories from subdirectories
15
+ * - singleRepoPath: Single-repo mode - serves a single repository at /repos/default
8
16
  */
9
17
  export interface ServerConfig {
10
- /** Path to e3 repository (required) */
11
- repo: string;
18
+ /** Directory containing repositories (multi-repo mode) */
19
+ reposDir?: string;
20
+ /** Path to a single repository (single-repo mode, access via /repos/default) */
21
+ singleRepoPath?: string;
12
22
  /** HTTP port (default: 3000) */
13
23
  port?: number;
14
24
  /** Bind address (default: "localhost") */
15
25
  host?: string;
16
26
  /** Enable CORS for cross-origin requests (default: false) */
17
27
  cors?: boolean;
28
+ /** Optional JWT authentication config (for external JWKS validation) */
29
+ auth?: AuthConfig;
30
+ /** Optional OIDC provider config (enables built-in auth server) */
31
+ oidc?: OidcConfig;
18
32
  }
19
33
  /**
20
34
  * Server instance handle.
@@ -32,8 +46,15 @@ export interface Server {
32
46
  /**
33
47
  * Create an e3 API server.
34
48
  *
49
+ * The server operates in multi-repo mode, serving multiple repositories
50
+ * from subdirectories of the configured reposDir.
51
+ *
52
+ * URL structure:
53
+ * - GET /api/repos - List available repositories
54
+ * - /api/repos/:repo/... - Repository-specific endpoints
55
+ *
35
56
  * @param config - Server configuration
36
57
  * @returns Server instance
37
58
  */
38
- export declare function createServer(config: ServerConfig): Server;
59
+ export declare function createServer(config: ServerConfig): Promise<Server>;
39
60
  //# sourceMappingURL=server.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/server.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,EAAS,KAAK,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAQ3D;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,uCAAuC;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,gCAAgC;IAChC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,0CAA0C;IAC1C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,6DAA6D;IAC7D,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;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;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,CAgFzD"}
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;AAYzF,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,CAoPxE"}
@@ -2,44 +2,203 @@
2
2
  * Copyright (c) 2025 Elara AI Pty Ltd
3
3
  * Licensed under BSL 1.1. See LICENSE for details.
4
4
  */
5
+ import * as path from 'node:path';
5
6
  import { Hono } from 'hono';
6
7
  import { cors } from 'hono/cors';
7
8
  import { serve } from '@hono/node-server';
8
- import { createRepositoryRoutes } from './routes/repository.js';
9
+ import { LocalStorage, repoInit, RepositoryNotFoundError } from '@elaraai/e3-core';
10
+ import { createAuthMiddleware } from './middleware/auth.js';
11
+ import { createOidcProvider } from './auth/index.js';
12
+ import { listRepos } from './handlers/repos.js';
13
+ import { startRepoDelete, getRepoDeleteStatus } from './handlers/repository.js';
14
+ import { sendError, sendSuccessWithStatus } from './beast2.js';
15
+ import { StringType, NullType, variant } from '@elaraai/east';
9
16
  import { createPackageRoutes } from './routes/packages.js';
10
17
  import { createWorkspaceRoutes } from './routes/workspaces.js';
11
18
  import { createDatasetRoutes } from './routes/datasets.js';
12
19
  import { createTaskRoutes } from './routes/tasks.js';
13
20
  import { createExecutionRoutes } from './routes/executions.js';
21
+ import { createRepositoryRoutes } from './routes/repository.js';
14
22
  /**
15
23
  * Create an e3 API server.
16
24
  *
25
+ * The server operates in multi-repo mode, serving multiple repositories
26
+ * from subdirectories of the configured reposDir.
27
+ *
28
+ * URL structure:
29
+ * - GET /api/repos - List available repositories
30
+ * - /api/repos/:repo/... - Repository-specific endpoints
31
+ *
17
32
  * @param config - Server configuration
18
33
  * @returns Server instance
19
34
  */
20
- export function createServer(config) {
21
- const { repo: repoPath, port = 3000, host = 'localhost', cors: enableCors = false } = config;
35
+ export async function createServer(config) {
36
+ const { reposDir, singleRepoPath, port = 3000, host = 'localhost', cors: enableCors = false, auth, oidc } = config;
37
+ // Validate config: exactly one of reposDir or singleRepoPath must be specified
38
+ if (reposDir && singleRepoPath) {
39
+ throw new Error('Cannot specify both reposDir and singleRepoPath');
40
+ }
41
+ if (!reposDir && !singleRepoPath) {
42
+ throw new Error('Must specify either reposDir or singleRepoPath');
43
+ }
44
+ const isSingleRepoMode = !!singleRepoPath;
45
+ // Single storage instance shared across all requests
46
+ const storage = new LocalStorage();
47
+ // Helper to compute repo path from repo name
48
+ // In single-repo mode, middleware validates 'default' before routes are called
49
+ const getRepoPath = (repoName) => {
50
+ if (isSingleRepoMode) {
51
+ // Middleware ensures repoName === 'default' before we get here
52
+ return singleRepoPath;
53
+ }
54
+ return path.join(reposDir, repoName);
55
+ };
22
56
  const app = new Hono();
23
57
  // Enable CORS if configured
24
58
  if (enableCors) {
25
59
  app.use('*', cors({ origin: '*' }));
26
60
  }
27
- // Repository routes: /api/status, /api/gc
28
- app.route('/api', createRepositoryRoutes(repoPath));
29
- // Package routes: /api/packages/*
30
- app.route('/api/packages', createPackageRoutes(repoPath));
31
- // Workspace routes: /api/workspaces/*
32
- const workspaceRoutes = createWorkspaceRoutes(repoPath);
33
- app.route('/api/workspaces', workspaceRoutes);
34
- // Dataset routes mounted under workspaces: /api/workspaces/:ws/list, /get, /set
35
- const datasetRoutes = createDatasetRoutes(repoPath);
36
- app.route('/api/workspaces/:ws', datasetRoutes);
37
- // Task routes: /api/workspaces/:ws/tasks/*
38
- const taskRoutes = createTaskRoutes(repoPath);
39
- app.route('/api/workspaces/:ws/tasks', taskRoutes);
40
- // Execution routes: /api/workspaces/:ws/start, /status, /graph, /logs/:task
41
- const executionRoutes = createExecutionRoutes(repoPath);
42
- app.route('/api/workspaces/:ws', executionRoutes);
61
+ // Create OIDC provider if configured (built-in auth server)
62
+ let oidcProvider;
63
+ if (oidc) {
64
+ oidcProvider = createOidcProvider(oidc);
65
+ // Mount OIDC routes at root (/.well-known/*, /oauth2/*, /device)
66
+ app.route('/', oidcProvider.routes);
67
+ }
68
+ // Apply auth middleware to all repo-specific routes if configured
69
+ // If OIDC is enabled but auth is not separately configured, use OIDC keys for validation
70
+ if (auth) {
71
+ const authMiddleware = await createAuthMiddleware(auth);
72
+ app.use('/api/repos/:repo/*', authMiddleware);
73
+ }
74
+ else if (oidcProvider) {
75
+ // Use the OIDC provider's keys for JWT validation
76
+ const authMiddleware = await createAuthMiddleware({
77
+ jwksUrl: `${oidc.baseUrl}/.well-known/jwks.json`,
78
+ issuer: oidc.baseUrl,
79
+ audience: oidc.baseUrl,
80
+ // Provide keys directly to avoid HTTP fetch to self
81
+ _internalKeys: oidcProvider.keys,
82
+ });
83
+ app.use('/api/repos/:repo/*', authMiddleware);
84
+ }
85
+ // Single-repo mode: validate repo name and handle disabled operations
86
+ // Runs AFTER auth middleware (so unauthorized users get 401, not 404/405)
87
+ if (isSingleRepoMode) {
88
+ app.use('/api/repos/:repo/*', async (c, next) => {
89
+ const method = c.req.method;
90
+ // PUT (create repo) is always disabled in single-repo mode
91
+ if (method === 'PUT') {
92
+ return c.json({
93
+ error: 'method_not_allowed',
94
+ message: 'Repository creation is disabled in single-repo mode'
95
+ }, 405);
96
+ }
97
+ // For DELETE (remove repo), check if it's the 'default' repo
98
+ if (method === 'DELETE') {
99
+ // DELETE on 'default' → 405 (deletion disabled)
100
+ // DELETE on other repos → 404 (repo doesn't exist)
101
+ const repo = c.req.param('repo');
102
+ if (repo === 'default') {
103
+ return c.json({
104
+ error: 'method_not_allowed',
105
+ message: 'Repository deletion is disabled in single-repo mode'
106
+ }, 405);
107
+ }
108
+ return c.json({ error: 'not_found', message: `Repository '${repo}' not found` }, 404);
109
+ }
110
+ // For other methods (GET, POST, etc.), validate repo name
111
+ const repo = c.req.param('repo');
112
+ if (repo !== 'default') {
113
+ return c.json({ error: 'not_found', message: `Repository '${repo}' not found` }, 404);
114
+ }
115
+ await next();
116
+ });
117
+ }
118
+ // Validate repository exists before processing requests (multi-repo mode only)
119
+ // In single-repo mode, this is handled by the middleware above
120
+ // Skip validation for PUT/DELETE on /api/repos/:repo (repo create/remove)
121
+ // Skip validation for /api/repos/:repo/delete/* (repo deletion status - repo may already be deleted)
122
+ if (!isSingleRepoMode) {
123
+ app.use('/api/repos/:repo/*', async (c, next) => {
124
+ // Skip validation for repo create/remove operations at the repo level
125
+ // These operate on repos that may not exist yet (PUT) or are being deleted (DELETE)
126
+ const method = c.req.method;
127
+ const path = c.req.path;
128
+ // Check if this is the base repo path (no subpath after repo name)
129
+ const repoPathMatch = path.match(/^\/api\/repos\/[^/]+$/);
130
+ if (repoPathMatch && (method === 'PUT' || method === 'DELETE')) {
131
+ await next();
132
+ return;
133
+ }
134
+ // Skip validation for delete status endpoint (repo may already be deleted)
135
+ const deleteStatusMatch = path.match(/^\/api\/repos\/[^/]+\/delete\/[^/]+$/);
136
+ if (deleteStatusMatch) {
137
+ await next();
138
+ return;
139
+ }
140
+ const repo = c.req.param('repo');
141
+ const repoPath = getRepoPath(repo);
142
+ try {
143
+ await storage.validateRepository(repoPath);
144
+ }
145
+ catch (err) {
146
+ if (err instanceof RepositoryNotFoundError) {
147
+ return sendError(NullType, variant('repository_not_found', { repo }));
148
+ }
149
+ throw err;
150
+ }
151
+ await next();
152
+ });
153
+ }
154
+ // GET /api/repos - List available repositories
155
+ app.get('/api/repos', async (c) => {
156
+ if (isSingleRepoMode) {
157
+ return c.json(['default']);
158
+ }
159
+ return listRepos(reposDir);
160
+ });
161
+ // PUT /api/repos/:repo - Create a new repository (multi-repo mode only)
162
+ // Note: Single-repo mode handler is registered earlier and takes precedence
163
+ if (!isSingleRepoMode) {
164
+ app.put('/api/repos/:repo', (c) => {
165
+ const repo = c.req.param('repo');
166
+ const repoPath = path.join(reposDir, repo);
167
+ const result = repoInit(repoPath);
168
+ if (!result.success) {
169
+ if (result.alreadyExists) {
170
+ return sendError(StringType, variant('internal', { message: `Repository '${repo}' already exists` }));
171
+ }
172
+ return sendError(StringType, variant('internal', { message: result.error?.message ?? 'Unknown error' }));
173
+ }
174
+ return sendSuccessWithStatus(StringType, repo, 201);
175
+ });
176
+ // DELETE /api/repos/:repo - Remove a repository (async, multi-repo mode only)
177
+ app.delete('/api/repos/:repo', (c) => {
178
+ const repo = c.req.param('repo');
179
+ const repoPath = path.join(reposDir, repo);
180
+ return startRepoDelete(repoPath);
181
+ });
182
+ // GET /api/repos/:repo/delete/:executionId - Get repo delete status
183
+ app.get('/api/repos/:repo/delete/:executionId', (c) => {
184
+ const executionId = c.req.param('executionId');
185
+ return getRepoDeleteStatus(executionId);
186
+ });
187
+ }
188
+ // Mount repository-specific routes
189
+ // Each route file creates a sub-app that uses getRepoPath to resolve the repo
190
+ // Repository status and GC: /api/repos/:repo/status, /api/repos/:repo/gc
191
+ app.route('/api/repos/:repo', createRepositoryRoutes(storage, getRepoPath));
192
+ // Package routes: /api/repos/:repo/packages/*
193
+ app.route('/api/repos/:repo/packages', createPackageRoutes(storage, getRepoPath));
194
+ // Workspace routes: /api/repos/:repo/workspaces/*
195
+ app.route('/api/repos/:repo/workspaces', createWorkspaceRoutes(storage, getRepoPath));
196
+ // Dataset routes: /api/repos/:repo/workspaces/:ws/datasets/*
197
+ app.route('/api/repos/:repo/workspaces/:ws/datasets', createDatasetRoutes(storage, getRepoPath));
198
+ // Task routes: /api/repos/:repo/workspaces/:ws/tasks/*
199
+ app.route('/api/repos/:repo/workspaces/:ws/tasks', createTaskRoutes(storage, getRepoPath));
200
+ // Execution/Dataflow routes: /api/repos/:repo/workspaces/:ws/dataflow/*
201
+ app.route('/api/repos/:repo/workspaces/:ws/dataflow', createExecutionRoutes(storage, getRepoPath));
43
202
  let httpServer = null;
44
203
  let actualPort = port;
45
204
  const server = {
@@ -1 +1 @@
1
- {"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/server.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/server.ts"],"names":[],"mappings":"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"}