@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
@@ -0,0 +1,227 @@
1
+ /**
2
+ * Copyright (c) 2025 Elara AI Pty Ltd
3
+ * Licensed under BSL 1.1. See LICENSE for details.
4
+ */
5
+ /**
6
+ * OAuth2 Device Authorization Grant (RFC 8628) implementation.
7
+ */
8
+ import * as crypto from 'node:crypto';
9
+ import { Hono } from 'hono';
10
+ import { signJwt } from './keys.js';
11
+ // In-memory pending authorizations
12
+ const pendingAuths = new Map();
13
+ // Clean up expired authorizations periodically
14
+ // Use unref() so this timer doesn't prevent process exit
15
+ const cleanupInterval = setInterval(() => {
16
+ const now = Date.now();
17
+ for (const [deviceCode, auth] of pendingAuths) {
18
+ if (auth.expiresAt < now) {
19
+ pendingAuths.delete(deviceCode);
20
+ }
21
+ }
22
+ }, 60000); // Every minute
23
+ cleanupInterval.unref();
24
+ /**
25
+ * Generate a random device code.
26
+ */
27
+ function generateDeviceCode() {
28
+ return crypto.randomBytes(32).toString('hex');
29
+ }
30
+ /**
31
+ * Generate a user-friendly code (e.g., ABCD-1234).
32
+ */
33
+ function generateUserCode() {
34
+ const chars = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789'; // Exclude confusing chars
35
+ let code = '';
36
+ for (let i = 0; i < 8; i++) {
37
+ if (i === 4)
38
+ code += '-';
39
+ code += chars[crypto.randomInt(chars.length)];
40
+ }
41
+ return code;
42
+ }
43
+ /**
44
+ * Create device flow routes.
45
+ */
46
+ export function createDeviceRoutes(config) {
47
+ const app = new Hono();
48
+ // POST /oauth2/device_authorization - Start device flow
49
+ app.post('/oauth2/device_authorization', (c) => {
50
+ const deviceCode = generateDeviceCode();
51
+ const userCode = generateUserCode();
52
+ const expiresIn = 300; // 5 minutes
53
+ pendingAuths.set(deviceCode, {
54
+ userCode,
55
+ approved: config.autoApprove, // Auto-approve in CI mode
56
+ expiresAt: Date.now() + expiresIn * 1000,
57
+ });
58
+ return c.json({
59
+ device_code: deviceCode,
60
+ user_code: userCode,
61
+ verification_uri: `${config.baseUrl}/device`,
62
+ verification_uri_complete: `${config.baseUrl}/device?user_code=${userCode}`,
63
+ expires_in: expiresIn,
64
+ interval: 1, // Poll every 1 second (fast for dev)
65
+ });
66
+ });
67
+ // GET /device - HTML approval page
68
+ app.get('/device', (c) => {
69
+ const userCode = c.req.query('user_code') || '';
70
+ const autoApproveScript = config.autoApprove
71
+ ? `<script>setTimeout(() => document.forms[0].submit(), 500);</script>`
72
+ : '';
73
+ return c.html(`<!DOCTYPE html>
74
+ <html>
75
+ <head>
76
+ <title>e3 Device Login</title>
77
+ <style>
78
+ body { font-family: system-ui, sans-serif; max-width: 400px; margin: 50px auto; padding: 20px; }
79
+ h1 { color: #333; }
80
+ .code { font-size: 2em; font-family: monospace; letter-spacing: 0.1em; background: #f0f0f0; padding: 10px 20px; border-radius: 4px; }
81
+ button { background: #0066cc; color: white; border: none; padding: 12px 24px; font-size: 1em; border-radius: 4px; cursor: pointer; margin-top: 20px; }
82
+ button:hover { background: #0055aa; }
83
+ .auto { color: #666; font-style: italic; margin-top: 10px; }
84
+ </style>
85
+ </head>
86
+ <body>
87
+ <h1>e3 Device Login</h1>
88
+ <p>Confirm this code matches what's shown in your terminal:</p>
89
+ <div class="code">${userCode || '(no code)'}</div>
90
+ <form method="POST" action="/device/approve">
91
+ <input type="hidden" name="user_code" value="${userCode}">
92
+ <button type="submit">Approve</button>
93
+ </form>
94
+ ${config.autoApprove ? '<p class="auto">Auto-approving in CI mode...</p>' : ''}
95
+ ${autoApproveScript}
96
+ </body>
97
+ </html>`);
98
+ });
99
+ // POST /device/approve - Approve device code
100
+ app.post('/device/approve', async (c) => {
101
+ const body = await c.req.parseBody();
102
+ const userCode = String(body['user_code'] || '');
103
+ // Find the pending auth with this user code
104
+ for (const [_deviceCode, auth] of pendingAuths) {
105
+ if (auth.userCode === userCode && auth.expiresAt > Date.now()) {
106
+ auth.approved = true;
107
+ return c.html(`<!DOCTYPE html>
108
+ <html>
109
+ <head>
110
+ <title>e3 Device Login</title>
111
+ <style>
112
+ body { font-family: system-ui, sans-serif; max-width: 400px; margin: 50px auto; padding: 20px; }
113
+ h1 { color: #22aa22; }
114
+ </style>
115
+ </head>
116
+ <body>
117
+ <h1>✓ Approved</h1>
118
+ <p>You can close this window and return to your terminal.</p>
119
+ </body>
120
+ </html>`);
121
+ }
122
+ }
123
+ return c.html(`<!DOCTYPE html>
124
+ <html>
125
+ <head>
126
+ <title>e3 Device Login</title>
127
+ <style>
128
+ body { font-family: system-ui, sans-serif; max-width: 400px; margin: 50px auto; padding: 20px; }
129
+ h1 { color: #cc0000; }
130
+ </style>
131
+ </head>
132
+ <body>
133
+ <h1>✗ Invalid or Expired Code</h1>
134
+ <p>The code may have expired. Please try again.</p>
135
+ </body>
136
+ </html>`, 400);
137
+ });
138
+ // POST /oauth2/token - Exchange device code for tokens OR refresh tokens
139
+ app.post('/oauth2/token', async (c) => {
140
+ const body = await c.req.parseBody();
141
+ const grantType = String(body['grant_type'] || '');
142
+ // Device code grant
143
+ if (grantType === 'urn:ietf:params:oauth:grant-type:device_code') {
144
+ const deviceCode = String(body['device_code'] || '');
145
+ const auth = pendingAuths.get(deviceCode);
146
+ if (!auth || auth.expiresAt < Date.now()) {
147
+ return c.json({ error: 'expired_token' }, 400);
148
+ }
149
+ if (!auth.approved) {
150
+ return c.json({ error: 'authorization_pending' }, 400);
151
+ }
152
+ // Delete the pending auth
153
+ pendingAuths.delete(deviceCode);
154
+ // Generate tokens
155
+ const now = Math.floor(Date.now() / 1000);
156
+ const accessPayload = {
157
+ sub: 'dev-user',
158
+ iss: config.baseUrl,
159
+ aud: config.baseUrl,
160
+ iat: now,
161
+ nbf: now,
162
+ exp: now + config.accessTokenExpiry,
163
+ token_type: 'access',
164
+ };
165
+ const refreshPayload = {
166
+ sub: 'dev-user',
167
+ iss: config.baseUrl,
168
+ aud: config.baseUrl,
169
+ iat: now,
170
+ nbf: now,
171
+ exp: now + config.refreshTokenExpiry,
172
+ token_type: 'refresh',
173
+ };
174
+ return c.json({
175
+ access_token: signJwt(accessPayload, config.keys),
176
+ refresh_token: signJwt(refreshPayload, config.keys),
177
+ token_type: 'Bearer',
178
+ expires_in: config.accessTokenExpiry,
179
+ });
180
+ }
181
+ // Refresh token grant
182
+ if (grantType === 'refresh_token') {
183
+ const refreshToken = String(body['refresh_token'] || '');
184
+ try {
185
+ // Import verifyJwt dynamically to avoid circular dependency
186
+ const { verifyJwt } = await import('./keys.js');
187
+ const payload = verifyJwt(refreshToken, config.keys);
188
+ if (payload.token_type !== 'refresh') {
189
+ return c.json({ error: 'invalid_grant', error_description: 'Not a refresh token' }, 400);
190
+ }
191
+ // Generate new access token
192
+ const now = Math.floor(Date.now() / 1000);
193
+ const accessPayload = {
194
+ sub: payload.sub,
195
+ iss: config.baseUrl,
196
+ aud: config.baseUrl,
197
+ iat: now,
198
+ nbf: now,
199
+ exp: now + config.accessTokenExpiry,
200
+ token_type: 'access',
201
+ };
202
+ // Also issue a new refresh token (rotation)
203
+ const newRefreshPayload = {
204
+ sub: payload.sub,
205
+ iss: config.baseUrl,
206
+ aud: config.baseUrl,
207
+ iat: now,
208
+ nbf: now,
209
+ exp: now + config.refreshTokenExpiry,
210
+ token_type: 'refresh',
211
+ };
212
+ return c.json({
213
+ access_token: signJwt(accessPayload, config.keys),
214
+ refresh_token: signJwt(newRefreshPayload, config.keys),
215
+ token_type: 'Bearer',
216
+ expires_in: config.accessTokenExpiry,
217
+ });
218
+ }
219
+ catch {
220
+ return c.json({ error: 'invalid_grant', error_description: 'Invalid refresh token' }, 400);
221
+ }
222
+ }
223
+ return c.json({ error: 'unsupported_grant_type' }, 400);
224
+ });
225
+ return app;
226
+ }
227
+ //# sourceMappingURL=device.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"device.js","sourceRoot":"","sources":["../../../src/auth/device.ts"],"names":[],"mappings":"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"}
@@ -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
+ /**
6
+ * OIDC Discovery endpoint (/.well-known/openid-configuration).
7
+ */
8
+ import { Hono } from 'hono';
9
+ import type { KeyPair } from './keys.js';
10
+ /**
11
+ * Discovery configuration.
12
+ */
13
+ export interface DiscoveryConfig {
14
+ /** Server base URL (e.g., http://localhost:3000) */
15
+ baseUrl: string;
16
+ /** RSA keypair for JWKS */
17
+ keys: KeyPair;
18
+ }
19
+ /**
20
+ * Create discovery routes.
21
+ */
22
+ export declare function createDiscoveryRoutes(config: DiscoveryConfig): Hono;
23
+ //# sourceMappingURL=discovery.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discovery.d.ts","sourceRoot":"","sources":["../../../src/auth/discovery.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;GAEG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAGzC;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,oDAAoD;IACpD,OAAO,EAAE,MAAM,CAAC;IAChB,2BAA2B;IAC3B,IAAI,EAAE,OAAO,CAAC;CACf;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,eAAe,GAAG,IAAI,CA6BnE"}
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Copyright (c) 2025 Elara AI Pty Ltd
3
+ * Licensed under BSL 1.1. See LICENSE for details.
4
+ */
5
+ /**
6
+ * OIDC Discovery endpoint (/.well-known/openid-configuration).
7
+ */
8
+ import { Hono } from 'hono';
9
+ import { publicKeyToJwk } from './keys.js';
10
+ /**
11
+ * Create discovery routes.
12
+ */
13
+ export function createDiscoveryRoutes(config) {
14
+ const app = new Hono();
15
+ // GET /.well-known/openid-configuration - OIDC Discovery
16
+ app.get('/.well-known/openid-configuration', (c) => {
17
+ return c.json({
18
+ issuer: config.baseUrl,
19
+ device_authorization_endpoint: `${config.baseUrl}/oauth2/device_authorization`,
20
+ token_endpoint: `${config.baseUrl}/oauth2/token`,
21
+ jwks_uri: `${config.baseUrl}/.well-known/jwks.json`,
22
+ response_types_supported: ['token'],
23
+ grant_types_supported: [
24
+ 'urn:ietf:params:oauth:grant-type:device_code',
25
+ 'refresh_token',
26
+ ],
27
+ subject_types_supported: ['public'],
28
+ id_token_signing_alg_values_supported: ['RS256'],
29
+ token_endpoint_auth_methods_supported: ['none'],
30
+ });
31
+ });
32
+ // GET /.well-known/jwks.json - JSON Web Key Set
33
+ app.get('/.well-known/jwks.json', (c) => {
34
+ return c.json({
35
+ keys: [publicKeyToJwk(config.keys)],
36
+ });
37
+ });
38
+ return app;
39
+ }
40
+ //# sourceMappingURL=discovery.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discovery.js","sourceRoot":"","sources":["../../../src/auth/discovery.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;GAEG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAE5B,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAY3C;;GAEG;AACH,MAAM,UAAU,qBAAqB,CAAC,MAAuB;IAC3D,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;IAEvB,yDAAyD;IACzD,GAAG,CAAC,GAAG,CAAC,mCAAmC,EAAE,CAAC,CAAC,EAAE,EAAE;QACjD,OAAO,CAAC,CAAC,IAAI,CAAC;YACZ,MAAM,EAAE,MAAM,CAAC,OAAO;YACtB,6BAA6B,EAAE,GAAG,MAAM,CAAC,OAAO,8BAA8B;YAC9E,cAAc,EAAE,GAAG,MAAM,CAAC,OAAO,eAAe;YAChD,QAAQ,EAAE,GAAG,MAAM,CAAC,OAAO,wBAAwB;YACnD,wBAAwB,EAAE,CAAC,OAAO,CAAC;YACnC,qBAAqB,EAAE;gBACrB,8CAA8C;gBAC9C,eAAe;aAChB;YACD,uBAAuB,EAAE,CAAC,QAAQ,CAAC;YACnC,qCAAqC,EAAE,CAAC,OAAO,CAAC;YAChD,qCAAqC,EAAE,CAAC,MAAM,CAAC;SAChD,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,gDAAgD;IAChD,GAAG,CAAC,GAAG,CAAC,wBAAwB,EAAE,CAAC,CAAC,EAAE,EAAE;QACtC,OAAO,CAAC,CAAC,IAAI,CAAC;YACZ,IAAI,EAAE,CAAC,cAAc,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;SACpC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,OAAO,GAAG,CAAC;AACb,CAAC"}
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Copyright (c) 2025 Elara AI Pty Ltd
3
+ * Licensed under BSL 1.1. See LICENSE for details.
4
+ */
5
+ /**
6
+ * OIDC authentication provider for e3-api-server.
7
+ *
8
+ * Provides OAuth2 Device Flow (RFC 8628) with JWT tokens,
9
+ * compatible with AWS Cognito for cloud deployment.
10
+ */
11
+ import { Hono } from 'hono';
12
+ import { type KeyPair } from './keys.js';
13
+ export { generateKeyPair, verifyJwt, type KeyPair, type JwtPayload } from './keys.js';
14
+ /**
15
+ * Parse duration string to seconds.
16
+ * Supports: "5s", "15m", "1h", "24h", "90d"
17
+ */
18
+ export declare function parseDuration(duration: string): number;
19
+ /**
20
+ * OIDC provider configuration.
21
+ */
22
+ export interface OidcConfig {
23
+ /** Server base URL (e.g., http://localhost:3000) */
24
+ baseUrl: string;
25
+ /** Access token expiry duration (default: "1h") */
26
+ tokenExpiry?: string;
27
+ /** Refresh token expiry duration (default: "90d") */
28
+ refreshTokenExpiry?: string;
29
+ /** Auto-approve device codes (for CI testing) */
30
+ autoApprove?: boolean;
31
+ }
32
+ /**
33
+ * OIDC provider instance.
34
+ */
35
+ export interface OidcProvider {
36
+ /** Hono app with all auth routes */
37
+ routes: Hono;
38
+ /** RSA keypair (for validating tokens) */
39
+ keys: KeyPair;
40
+ /** Server base URL */
41
+ baseUrl: string;
42
+ /** Access token expiry in seconds */
43
+ accessTokenExpiry: number;
44
+ }
45
+ /**
46
+ * Create an OIDC provider for the e3-api-server.
47
+ *
48
+ * This provides:
49
+ * - /.well-known/openid-configuration (discovery)
50
+ * - /.well-known/jwks.json (public keys)
51
+ * - /oauth2/device_authorization (start device flow)
52
+ * - /device (approval page)
53
+ * - /oauth2/token (exchange codes and refresh tokens)
54
+ */
55
+ export declare function createOidcProvider(config: OidcConfig): OidcProvider;
56
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/auth/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;;;GAKG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAmB,KAAK,OAAO,EAAE,MAAM,WAAW,CAAC;AAI1D,OAAO,EAAE,eAAe,EAAE,SAAS,EAAE,KAAK,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,WAAW,CAAC;AAEtF;;;GAGG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAgBtD;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,oDAAoD;IACpD,OAAO,EAAE,MAAM,CAAC;IAChB,mDAAmD;IACnD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,qDAAqD;IACrD,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,iDAAiD;IACjD,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,oCAAoC;IACpC,MAAM,EAAE,IAAI,CAAC;IACb,0CAA0C;IAC1C,IAAI,EAAE,OAAO,CAAC;IACd,sBAAsB;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,qCAAqC;IACrC,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAED;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,UAAU,GAAG,YAAY,CA4BnE"}
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Copyright (c) 2025 Elara AI Pty Ltd
3
+ * Licensed under BSL 1.1. See LICENSE for details.
4
+ */
5
+ /**
6
+ * OIDC authentication provider for e3-api-server.
7
+ *
8
+ * Provides OAuth2 Device Flow (RFC 8628) with JWT tokens,
9
+ * compatible with AWS Cognito for cloud deployment.
10
+ */
11
+ import { Hono } from 'hono';
12
+ import { generateKeyPair } from './keys.js';
13
+ import { createDeviceRoutes } from './device.js';
14
+ import { createDiscoveryRoutes } from './discovery.js';
15
+ export { generateKeyPair, verifyJwt } from './keys.js';
16
+ /**
17
+ * Parse duration string to seconds.
18
+ * Supports: "5s", "15m", "1h", "24h", "90d"
19
+ */
20
+ export function parseDuration(duration) {
21
+ const match = duration.match(/^(\d+)(s|m|h|d)$/);
22
+ if (!match) {
23
+ throw new Error(`Invalid duration format: ${duration}. Use format like "5s", "15m", "1h", "90d"`);
24
+ }
25
+ const value = parseInt(match[1], 10);
26
+ const unit = match[2];
27
+ switch (unit) {
28
+ case 's': return value;
29
+ case 'm': return value * 60;
30
+ case 'h': return value * 60 * 60;
31
+ case 'd': return value * 60 * 60 * 24;
32
+ default: throw new Error(`Unknown duration unit: ${unit}`);
33
+ }
34
+ }
35
+ /**
36
+ * Create an OIDC provider for the e3-api-server.
37
+ *
38
+ * This provides:
39
+ * - /.well-known/openid-configuration (discovery)
40
+ * - /.well-known/jwks.json (public keys)
41
+ * - /oauth2/device_authorization (start device flow)
42
+ * - /device (approval page)
43
+ * - /oauth2/token (exchange codes and refresh tokens)
44
+ */
45
+ export function createOidcProvider(config) {
46
+ const keys = generateKeyPair();
47
+ const accessTokenExpiry = parseDuration(config.tokenExpiry ?? '1h');
48
+ const refreshTokenExpiry = parseDuration(config.refreshTokenExpiry ?? '90d');
49
+ const autoApprove = config.autoApprove ?? process.env.E3_AUTH_AUTO_APPROVE === '1';
50
+ const deviceConfig = {
51
+ baseUrl: config.baseUrl,
52
+ keys,
53
+ accessTokenExpiry,
54
+ refreshTokenExpiry,
55
+ autoApprove,
56
+ };
57
+ const app = new Hono();
58
+ // Mount discovery routes (/.well-known/*)
59
+ app.route('/', createDiscoveryRoutes({ baseUrl: config.baseUrl, keys }));
60
+ // Mount device flow routes (/oauth2/*, /device)
61
+ app.route('/', createDeviceRoutes(deviceConfig));
62
+ return {
63
+ routes: app,
64
+ keys,
65
+ baseUrl: config.baseUrl,
66
+ accessTokenExpiry,
67
+ };
68
+ }
69
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/auth/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;;;GAKG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,eAAe,EAAgB,MAAM,WAAW,CAAC;AAC1D,OAAO,EAAE,kBAAkB,EAAyB,MAAM,aAAa,CAAC;AACxE,OAAO,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AAEvD,OAAO,EAAE,eAAe,EAAE,SAAS,EAAiC,MAAM,WAAW,CAAC;AAEtF;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,QAAgB;IAC5C,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC;IACjD,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,IAAI,KAAK,CAAC,4BAA4B,QAAQ,4CAA4C,CAAC,CAAC;IACpG,CAAC;IAED,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IACrC,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;IAEtB,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,GAAG,CAAC,CAAC,OAAO,KAAK,CAAC;QACvB,KAAK,GAAG,CAAC,CAAC,OAAO,KAAK,GAAG,EAAE,CAAC;QAC5B,KAAK,GAAG,CAAC,CAAC,OAAO,KAAK,GAAG,EAAE,GAAG,EAAE,CAAC;QACjC,KAAK,GAAG,CAAC,CAAC,OAAO,KAAK,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC;QACtC,OAAO,CAAC,CAAC,MAAM,IAAI,KAAK,CAAC,0BAA0B,IAAI,EAAE,CAAC,CAAC;IAC7D,CAAC;AACH,CAAC;AA8BD;;;;;;;;;GASG;AACH,MAAM,UAAU,kBAAkB,CAAC,MAAkB;IACnD,MAAM,IAAI,GAAG,eAAe,EAAE,CAAC;IAC/B,MAAM,iBAAiB,GAAG,aAAa,CAAC,MAAM,CAAC,WAAW,IAAI,IAAI,CAAC,CAAC;IACpE,MAAM,kBAAkB,GAAG,aAAa,CAAC,MAAM,CAAC,kBAAkB,IAAI,KAAK,CAAC,CAAC;IAC7E,MAAM,WAAW,GAAG,MAAM,CAAC,WAAW,IAAI,OAAO,CAAC,GAAG,CAAC,oBAAoB,KAAK,GAAG,CAAC;IAEnF,MAAM,YAAY,GAAqB;QACrC,OAAO,EAAE,MAAM,CAAC,OAAO;QACvB,IAAI;QACJ,iBAAiB;QACjB,kBAAkB;QAClB,WAAW;KACZ,CAAC;IAEF,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;IAEvB,0CAA0C;IAC1C,GAAG,CAAC,KAAK,CAAC,GAAG,EAAE,qBAAqB,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IAEzE,gDAAgD;IAChD,GAAG,CAAC,KAAK,CAAC,GAAG,EAAE,kBAAkB,CAAC,YAAY,CAAC,CAAC,CAAC;IAEjD,OAAO;QACL,MAAM,EAAE,GAAG;QACX,IAAI;QACJ,OAAO,EAAE,MAAM,CAAC,OAAO;QACvB,iBAAiB;KAClB,CAAC;AACJ,CAAC"}
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Copyright (c) 2025 Elara AI Pty Ltd
3
+ * Licensed under BSL 1.1. See LICENSE for details.
4
+ */
5
+ /**
6
+ * RSA keypair generation and JWT signing for OIDC provider.
7
+ */
8
+ import * as crypto from 'node:crypto';
9
+ /**
10
+ * RSA keypair for JWT signing.
11
+ */
12
+ export interface KeyPair {
13
+ privateKey: crypto.KeyObject;
14
+ publicKey: crypto.KeyObject;
15
+ /** Key ID for JWKS */
16
+ kid: string;
17
+ }
18
+ /**
19
+ * JWT payload claims.
20
+ */
21
+ export interface JwtPayload {
22
+ /** Subject - user identifier */
23
+ sub: string;
24
+ /** Issuer */
25
+ iss: string;
26
+ /** Audience */
27
+ aud: string;
28
+ /** Expiration time (Unix timestamp) */
29
+ exp: number;
30
+ /** Issued at time (Unix timestamp) */
31
+ iat: number;
32
+ /** Not before time (Unix timestamp) */
33
+ nbf: number;
34
+ /** Token type (access or refresh) */
35
+ token_type?: 'access' | 'refresh';
36
+ }
37
+ /**
38
+ * Generate an RSA keypair for JWT signing.
39
+ * Keys are generated in-memory on server startup.
40
+ */
41
+ export declare function generateKeyPair(): KeyPair;
42
+ /**
43
+ * Sign a JWT payload with the private key.
44
+ */
45
+ export declare function signJwt(payload: JwtPayload, keys: KeyPair): string;
46
+ /**
47
+ * Verify a JWT and return the payload.
48
+ * @throws Error if verification fails
49
+ */
50
+ export declare function verifyJwt(token: string, keys: KeyPair): JwtPayload;
51
+ /**
52
+ * Export public key in JWK format for JWKS endpoint.
53
+ */
54
+ export declare function publicKeyToJwk(keys: KeyPair): object;
55
+ //# sourceMappingURL=keys.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"keys.d.ts","sourceRoot":"","sources":["../../../src/auth/keys.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;GAEG;AAEH,OAAO,KAAK,MAAM,MAAM,aAAa,CAAC;AAEtC;;GAEG;AACH,MAAM,WAAW,OAAO;IACtB,UAAU,EAAE,MAAM,CAAC,SAAS,CAAC;IAC7B,SAAS,EAAE,MAAM,CAAC,SAAS,CAAC;IAC5B,sBAAsB;IACtB,GAAG,EAAE,MAAM,CAAC;CACb;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,gCAAgC;IAChC,GAAG,EAAE,MAAM,CAAC;IACZ,aAAa;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,eAAe;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,uCAAuC;IACvC,GAAG,EAAE,MAAM,CAAC;IACZ,sCAAsC;IACtC,GAAG,EAAE,MAAM,CAAC;IACZ,uCAAuC;IACvC,GAAG,EAAE,MAAM,CAAC;IACZ,qCAAqC;IACrC,UAAU,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAC;CACnC;AAED;;;GAGG;AACH,wBAAgB,eAAe,IAAI,OAAO,CASzC;AAED;;GAEG;AACH,wBAAgB,OAAO,CAAC,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,OAAO,GAAG,MAAM,CAgBlE;AAED;;;GAGG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,UAAU,CA4BlE;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,CAQpD"}
@@ -0,0 +1,78 @@
1
+ /**
2
+ * Copyright (c) 2025 Elara AI Pty Ltd
3
+ * Licensed under BSL 1.1. See LICENSE for details.
4
+ */
5
+ /**
6
+ * RSA keypair generation and JWT signing for OIDC provider.
7
+ */
8
+ import * as crypto from 'node:crypto';
9
+ /**
10
+ * Generate an RSA keypair for JWT signing.
11
+ * Keys are generated in-memory on server startup.
12
+ */
13
+ export function generateKeyPair() {
14
+ const { privateKey, publicKey } = crypto.generateKeyPairSync('rsa', {
15
+ modulusLength: 2048,
16
+ });
17
+ // Generate a random key ID
18
+ const kid = crypto.randomBytes(8).toString('hex');
19
+ return { privateKey, publicKey, kid };
20
+ }
21
+ /**
22
+ * Sign a JWT payload with the private key.
23
+ */
24
+ export function signJwt(payload, keys) {
25
+ const header = {
26
+ alg: 'RS256',
27
+ typ: 'JWT',
28
+ kid: keys.kid,
29
+ };
30
+ const headerB64 = Buffer.from(JSON.stringify(header)).toString('base64url');
31
+ const payloadB64 = Buffer.from(JSON.stringify(payload)).toString('base64url');
32
+ const sign = crypto.createSign('RSA-SHA256');
33
+ sign.update(`${headerB64}.${payloadB64}`);
34
+ const signature = sign.sign(keys.privateKey);
35
+ const signatureB64 = signature.toString('base64url');
36
+ return `${headerB64}.${payloadB64}.${signatureB64}`;
37
+ }
38
+ /**
39
+ * Verify a JWT and return the payload.
40
+ * @throws Error if verification fails
41
+ */
42
+ export function verifyJwt(token, keys) {
43
+ const parts = token.split('.');
44
+ if (parts.length !== 3) {
45
+ throw new Error('Malformed JWT: expected 3 parts');
46
+ }
47
+ const [headerB64, payloadB64, signatureB64] = parts;
48
+ // Verify signature
49
+ const verify = crypto.createVerify('RSA-SHA256');
50
+ verify.update(`${headerB64}.${payloadB64}`);
51
+ const signature = Buffer.from(signatureB64, 'base64url');
52
+ if (!verify.verify(keys.publicKey, signature)) {
53
+ throw new Error('Invalid JWT signature');
54
+ }
55
+ // Decode and validate payload
56
+ const payload = JSON.parse(Buffer.from(payloadB64, 'base64url').toString());
57
+ const now = Math.floor(Date.now() / 1000);
58
+ if (payload.exp !== undefined && payload.exp < now) {
59
+ throw new Error('Token expired');
60
+ }
61
+ if (payload.nbf !== undefined && payload.nbf > now) {
62
+ throw new Error('Token not yet valid');
63
+ }
64
+ return payload;
65
+ }
66
+ /**
67
+ * Export public key in JWK format for JWKS endpoint.
68
+ */
69
+ export function publicKeyToJwk(keys) {
70
+ const publicKeyJwk = keys.publicKey.export({ format: 'jwk' });
71
+ return {
72
+ ...publicKeyJwk,
73
+ kid: keys.kid,
74
+ use: 'sig',
75
+ alg: 'RS256',
76
+ };
77
+ }
78
+ //# sourceMappingURL=keys.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"keys.js","sourceRoot":"","sources":["../../../src/auth/keys.ts"],"names":[],"mappings":"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"}
@@ -6,15 +6,27 @@ import type { EastType, ValueTypeOf } from '@elaraai/east';
6
6
  import type { Context } from 'hono';
7
7
  import { type Error } from './types.js';
8
8
  /**
9
- * Decode BEAST2 request body.
9
+ * Decode BEAST2 request body from Hono context.
10
10
  */
11
11
  export declare function decodeBody<T extends EastType>(c: Context, type: T): Promise<ValueTypeOf<T>>;
12
+ /**
13
+ * Decode raw BEAST2 bytes (for handlers that receive body directly).
14
+ */
15
+ export declare function decodeBeast2<T extends EastType>(data: Uint8Array, type: T): ValueTypeOf<T>;
12
16
  /**
13
17
  * Send BEAST2 success response.
18
+ *
19
+ * Returns a web Response object that can be used by both Hono routes and Lambda handlers.
14
20
  */
15
- export declare function sendSuccess<T extends EastType>(c: Context, type: T, value: ValueTypeOf<T>): Response;
21
+ export declare function sendSuccess<T extends EastType>(type: T, value: ValueTypeOf<T>): Response;
16
22
  /**
17
23
  * Send BEAST2 error response.
24
+ *
25
+ * Returns a web Response object that can be used by both Hono routes and Lambda handlers.
26
+ */
27
+ export declare function sendError<T extends EastType>(type: T, error: Error): Response;
28
+ /**
29
+ * Send BEAST2 success response with custom HTTP status.
18
30
  */
19
- export declare function sendError<T extends EastType>(c: Context, type: T, error: Error): Response;
31
+ export declare function sendSuccessWithStatus<T extends EastType>(type: T, value: ValueTypeOf<T>, status: number): Response;
20
32
  //# sourceMappingURL=beast2.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"beast2.d.ts","sourceRoot":"","sources":["../../src/beast2.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC3D,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AACpC,OAAO,EAAgB,KAAK,KAAK,EAAE,MAAM,YAAY,CAAC;AAEtD;;GAEG;AACH,wBAAsB,UAAU,CAAC,CAAC,SAAS,QAAQ,EACjD,CAAC,EAAE,OAAO,EACV,IAAI,EAAE,CAAC,GACN,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CASzB;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,CAAC,SAAS,QAAQ,EAC5C,CAAC,EAAE,OAAO,EACV,IAAI,EAAE,CAAC,EACP,KAAK,EAAE,WAAW,CAAC,CAAC,CAAC,GACpB,QAAQ,CAWV;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,CAAC,SAAS,QAAQ,EAC1C,CAAC,EAAE,OAAO,EACV,IAAI,EAAE,CAAC,EACP,KAAK,EAAE,KAAK,GACX,QAAQ,CAWV"}
1
+ {"version":3,"file":"beast2.d.ts","sourceRoot":"","sources":["../../src/beast2.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC3D,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AACpC,OAAO,EAAgB,KAAK,KAAK,EAAE,MAAM,YAAY,CAAC;AAEtD;;GAEG;AACH,wBAAsB,UAAU,CAAC,CAAC,SAAS,QAAQ,EACjD,CAAC,EAAE,OAAO,EACV,IAAI,EAAE,CAAC,GACN,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAUzB;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,CAAC,SAAS,QAAQ,EAC7C,IAAI,EAAE,UAAU,EAChB,IAAI,EAAE,CAAC,GACN,WAAW,CAAC,CAAC,CAAC,CAGhB;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,CAAC,SAAS,QAAQ,EAC5C,IAAI,EAAE,CAAC,EACP,KAAK,EAAE,WAAW,CAAC,CAAC,CAAC,GACpB,QAAQ,CAWV;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,CAAC,SAAS,QAAQ,EAC1C,IAAI,EAAE,CAAC,EACP,KAAK,EAAE,KAAK,GACX,QAAQ,CAWV;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,CAAC,SAAS,QAAQ,EACtD,IAAI,EAAE,CAAC,EACP,KAAK,EAAE,WAAW,CAAC,CAAC,CAAC,EACrB,MAAM,EAAE,MAAM,GACb,QAAQ,CAWV"}