@a5c-ai/adapters-gateway 5.1.1-staging.52898ebfc24f

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 (202) hide show
  1. package/README.md +20 -0
  2. package/dist/auth/bootstrap.d.ts +89 -0
  3. package/dist/auth/bootstrap.d.ts.map +1 -0
  4. package/dist/auth/bootstrap.js +222 -0
  5. package/dist/auth/bootstrap.js.map +1 -0
  6. package/dist/auth/hashing.d.ts +4 -0
  7. package/dist/auth/hashing.d.ts.map +1 -0
  8. package/dist/auth/hashing.js +27 -0
  9. package/dist/auth/hashing.js.map +1 -0
  10. package/dist/auth/middleware.d.ts +3 -0
  11. package/dist/auth/middleware.d.ts.map +1 -0
  12. package/dist/auth/middleware.js +17 -0
  13. package/dist/auth/middleware.js.map +1 -0
  14. package/dist/auth/tokens.d.ts +45 -0
  15. package/dist/auth/tokens.d.ts.map +1 -0
  16. package/dist/auth/tokens.js +186 -0
  17. package/dist/auth/tokens.js.map +1 -0
  18. package/dist/builtin-adapters.d.ts +17 -0
  19. package/dist/builtin-adapters.d.ts.map +1 -0
  20. package/dist/builtin-adapters.js +119 -0
  21. package/dist/builtin-adapters.js.map +1 -0
  22. package/dist/config.d.ts +37 -0
  23. package/dist/config.d.ts.map +1 -0
  24. package/dist/config.js +97 -0
  25. package/dist/config.js.map +1 -0
  26. package/dist/fanout/client-conn.d.ts +20 -0
  27. package/dist/fanout/client-conn.d.ts.map +1 -0
  28. package/dist/fanout/client-conn.js +53 -0
  29. package/dist/fanout/client-conn.js.map +1 -0
  30. package/dist/fanout/subscriber.d.ts +12 -0
  31. package/dist/fanout/subscriber.d.ts.map +1 -0
  32. package/dist/fanout/subscriber.js +40 -0
  33. package/dist/fanout/subscriber.js.map +1 -0
  34. package/dist/index.d.ts +30 -0
  35. package/dist/index.d.ts.map +1 -0
  36. package/dist/index.js +52 -0
  37. package/dist/index.js.map +1 -0
  38. package/dist/kanban/lib/config-loader.d.ts +29 -0
  39. package/dist/kanban/lib/config-loader.d.ts.map +1 -0
  40. package/dist/kanban/lib/config-loader.js +166 -0
  41. package/dist/kanban/lib/config-loader.js.map +1 -0
  42. package/dist/kanban/lib/config.d.ts +3 -0
  43. package/dist/kanban/lib/config.d.ts.map +1 -0
  44. package/dist/kanban/lib/config.js +6 -0
  45. package/dist/kanban/lib/config.js.map +1 -0
  46. package/dist/kanban/lib/create-global-registry.d.ts +28 -0
  47. package/dist/kanban/lib/create-global-registry.d.ts.map +1 -0
  48. package/dist/kanban/lib/create-global-registry.js +53 -0
  49. package/dist/kanban/lib/create-global-registry.js.map +1 -0
  50. package/dist/kanban/lib/dispatch-context-audit.d.ts +12 -0
  51. package/dist/kanban/lib/dispatch-context-audit.d.ts.map +1 -0
  52. package/dist/kanban/lib/dispatch-context-audit.js +44 -0
  53. package/dist/kanban/lib/dispatch-context-audit.js.map +1 -0
  54. package/dist/kanban/lib/error-handler.d.ts +28 -0
  55. package/dist/kanban/lib/error-handler.d.ts.map +1 -0
  56. package/dist/kanban/lib/error-handler.js +61 -0
  57. package/dist/kanban/lib/error-handler.js.map +1 -0
  58. package/dist/kanban/lib/global-registry.d.ts +49 -0
  59. package/dist/kanban/lib/global-registry.d.ts.map +1 -0
  60. package/dist/kanban/lib/global-registry.js +18 -0
  61. package/dist/kanban/lib/global-registry.js.map +1 -0
  62. package/dist/kanban/lib/parser.d.ts +36 -0
  63. package/dist/kanban/lib/parser.d.ts.map +1 -0
  64. package/dist/kanban/lib/parser.js +585 -0
  65. package/dist/kanban/lib/parser.js.map +1 -0
  66. package/dist/kanban/lib/path-resolver.d.ts +2 -0
  67. package/dist/kanban/lib/path-resolver.d.ts.map +1 -0
  68. package/dist/kanban/lib/path-resolver.js +16 -0
  69. package/dist/kanban/lib/path-resolver.js.map +1 -0
  70. package/dist/kanban/lib/review-service.d.ts +63 -0
  71. package/dist/kanban/lib/review-service.d.ts.map +1 -0
  72. package/dist/kanban/lib/review-service.js +571 -0
  73. package/dist/kanban/lib/review-service.js.map +1 -0
  74. package/dist/kanban/lib/run-cache.d.ts +36 -0
  75. package/dist/kanban/lib/run-cache.d.ts.map +1 -0
  76. package/dist/kanban/lib/run-cache.js +313 -0
  77. package/dist/kanban/lib/run-cache.js.map +1 -0
  78. package/dist/kanban/lib/server-init.d.ts +26 -0
  79. package/dist/kanban/lib/server-init.d.ts.map +1 -0
  80. package/dist/kanban/lib/server-init.js +179 -0
  81. package/dist/kanban/lib/server-init.js.map +1 -0
  82. package/dist/kanban/lib/services/automation-rule-service.d.ts +97 -0
  83. package/dist/kanban/lib/services/automation-rule-service.d.ts.map +1 -0
  84. package/dist/kanban/lib/services/automation-rule-service.js +806 -0
  85. package/dist/kanban/lib/services/automation-rule-service.js.map +1 -0
  86. package/dist/kanban/lib/services/automation-webhook-service.d.ts +44 -0
  87. package/dist/kanban/lib/services/automation-webhook-service.d.ts.map +1 -0
  88. package/dist/kanban/lib/services/automation-webhook-service.js +405 -0
  89. package/dist/kanban/lib/services/automation-webhook-service.js.map +1 -0
  90. package/dist/kanban/lib/services/backlog-query-service.d.ts +130 -0
  91. package/dist/kanban/lib/services/backlog-query-service.d.ts.map +1 -0
  92. package/dist/kanban/lib/services/backlog-query-service.js +1972 -0
  93. package/dist/kanban/lib/services/backlog-query-service.js.map +1 -0
  94. package/dist/kanban/lib/services/dispatch-context-label-service.d.ts +39 -0
  95. package/dist/kanban/lib/services/dispatch-context-label-service.d.ts.map +1 -0
  96. package/dist/kanban/lib/services/dispatch-context-label-service.js +160 -0
  97. package/dist/kanban/lib/services/dispatch-context-label-service.js.map +1 -0
  98. package/dist/kanban/lib/services/kanban-storage.d.ts +36 -0
  99. package/dist/kanban/lib/services/kanban-storage.d.ts.map +1 -0
  100. package/dist/kanban/lib/services/kanban-storage.js +26 -0
  101. package/dist/kanban/lib/services/kanban-storage.js.map +1 -0
  102. package/dist/kanban/lib/services/run-query-service.d.ts +79 -0
  103. package/dist/kanban/lib/services/run-query-service.d.ts.map +1 -0
  104. package/dist/kanban/lib/services/run-query-service.js +202 -0
  105. package/dist/kanban/lib/services/run-query-service.js.map +1 -0
  106. package/dist/kanban/lib/services/task-tag-service.d.ts +39 -0
  107. package/dist/kanban/lib/services/task-tag-service.d.ts.map +1 -0
  108. package/dist/kanban/lib/services/task-tag-service.js +145 -0
  109. package/dist/kanban/lib/services/task-tag-service.js.map +1 -0
  110. package/dist/kanban/lib/settings-section-storage.d.ts +13 -0
  111. package/dist/kanban/lib/settings-section-storage.d.ts.map +1 -0
  112. package/dist/kanban/lib/settings-section-storage.js +38 -0
  113. package/dist/kanban/lib/settings-section-storage.js.map +1 -0
  114. package/dist/kanban/lib/source-discovery.d.ts +10 -0
  115. package/dist/kanban/lib/source-discovery.d.ts.map +1 -0
  116. package/dist/kanban/lib/source-discovery.js +201 -0
  117. package/dist/kanban/lib/source-discovery.js.map +1 -0
  118. package/dist/kanban/lib/utils.d.ts +8 -0
  119. package/dist/kanban/lib/utils.d.ts.map +1 -0
  120. package/dist/kanban/lib/utils.js +116 -0
  121. package/dist/kanban/lib/utils.js.map +1 -0
  122. package/dist/kanban/lib/watcher.d.ts +14 -0
  123. package/dist/kanban/lib/watcher.d.ts.map +1 -0
  124. package/dist/kanban/lib/watcher.js +221 -0
  125. package/dist/kanban/lib/watcher.js.map +1 -0
  126. package/dist/kanban/lib/workspace-lifecycle.d.ts +68 -0
  127. package/dist/kanban/lib/workspace-lifecycle.d.ts.map +1 -0
  128. package/dist/kanban/lib/workspace-lifecycle.js +1085 -0
  129. package/dist/kanban/lib/workspace-lifecycle.js.map +1 -0
  130. package/dist/kanban/routes.d.ts +2 -0
  131. package/dist/kanban/routes.d.ts.map +1 -0
  132. package/dist/kanban/routes.js +1358 -0
  133. package/dist/kanban/routes.js.map +1 -0
  134. package/dist/kanban/types/breakpoint.d.ts +13 -0
  135. package/dist/kanban/types/breakpoint.d.ts.map +1 -0
  136. package/dist/kanban/types/breakpoint.js +3 -0
  137. package/dist/kanban/types/breakpoint.js.map +1 -0
  138. package/dist/kanban/types/index.d.ts +173 -0
  139. package/dist/kanban/types/index.d.ts.map +1 -0
  140. package/dist/kanban/types/index.js +3 -0
  141. package/dist/kanban/types/index.js.map +1 -0
  142. package/dist/logging.d.ts +7 -0
  143. package/dist/logging.d.ts.map +1 -0
  144. package/dist/logging.js +22 -0
  145. package/dist/logging.js.map +1 -0
  146. package/dist/notifications/types.d.ts +18 -0
  147. package/dist/notifications/types.d.ts.map +1 -0
  148. package/dist/notifications/types.js +2 -0
  149. package/dist/notifications/types.js.map +1 -0
  150. package/dist/notifications/webhook-out.d.ts +3 -0
  151. package/dist/notifications/webhook-out.d.ts.map +1 -0
  152. package/dist/notifications/webhook-out.js +55 -0
  153. package/dist/notifications/webhook-out.js.map +1 -0
  154. package/dist/pairing/short-code.d.ts +20 -0
  155. package/dist/pairing/short-code.d.ts.map +1 -0
  156. package/dist/pairing/short-code.js +50 -0
  157. package/dist/pairing/short-code.js.map +1 -0
  158. package/dist/protocol/errors.d.ts +10 -0
  159. package/dist/protocol/errors.d.ts.map +1 -0
  160. package/dist/protocol/errors.js +15 -0
  161. package/dist/protocol/errors.js.map +1 -0
  162. package/dist/protocol/frames.d.ts +107 -0
  163. package/dist/protocol/frames.d.ts.map +1 -0
  164. package/dist/protocol/frames.js +146 -0
  165. package/dist/protocol/frames.js.map +1 -0
  166. package/dist/protocol/v1.d.ts +111 -0
  167. package/dist/protocol/v1.d.ts.map +1 -0
  168. package/dist/protocol/v1.js +2 -0
  169. package/dist/protocol/v1.js.map +1 -0
  170. package/dist/runs/event-log-index.d.ts +29 -0
  171. package/dist/runs/event-log-index.d.ts.map +1 -0
  172. package/dist/runs/event-log-index.js +210 -0
  173. package/dist/runs/event-log-index.js.map +1 -0
  174. package/dist/runs/event-log.d.ts +25 -0
  175. package/dist/runs/event-log.d.ts.map +1 -0
  176. package/dist/runs/event-log.js +104 -0
  177. package/dist/runs/event-log.js.map +1 -0
  178. package/dist/runs/hook-broker.d.ts +18 -0
  179. package/dist/runs/hook-broker.d.ts.map +1 -0
  180. package/dist/runs/hook-broker.js +110 -0
  181. package/dist/runs/hook-broker.js.map +1 -0
  182. package/dist/runs/manager.d.ts +57 -0
  183. package/dist/runs/manager.d.ts.map +1 -0
  184. package/dist/runs/manager.js +757 -0
  185. package/dist/runs/manager.js.map +1 -0
  186. package/dist/runs/session-runtime.d.ts +8 -0
  187. package/dist/runs/session-runtime.d.ts.map +1 -0
  188. package/dist/runs/session-runtime.js +291 -0
  189. package/dist/runs/session-runtime.js.map +1 -0
  190. package/dist/runs/types.d.ts +55 -0
  191. package/dist/runs/types.d.ts.map +1 -0
  192. package/dist/runs/types.js +2 -0
  193. package/dist/runs/types.js.map +1 -0
  194. package/dist/server.d.ts +15 -0
  195. package/dist/server.d.ts.map +1 -0
  196. package/dist/server.js +702 -0
  197. package/dist/server.js.map +1 -0
  198. package/dist/static/webui-server.d.ts +2 -0
  199. package/dist/static/webui-server.d.ts.map +1 -0
  200. package/dist/static/webui-server.js +97 -0
  201. package/dist/static/webui-server.js.map +1 -0
  202. package/package.json +68 -0
package/README.md ADDED
@@ -0,0 +1,20 @@
1
+ # @a5c-ai/adapters-gateway
2
+
3
+ `@a5c-ai/adapters-gateway` is the package scaffold for remote and browser-facing
4
+ adapters surfaces.
5
+
6
+ Current scope:
7
+
8
+ - `GatewayConfig` and default configuration helpers
9
+ - `createGateway(config)` returning a start/stop gateway handle
10
+ - token auth, HTTP/WS server, run manager, fanout replay, and runtime hook brokering
11
+ - optional static webui hosting from `@a5c-ai/genty-webui/dist`
12
+
13
+ Service templates:
14
+
15
+ - `examples/systemd/adapters-gateway.service`
16
+ - `examples/launchd/ai.a5c.adapters.gateway.plist`
17
+
18
+ If the web UI package is not installed, `/` returns a helpful 404. Install
19
+ `@a5c-ai/genty-webui` alongside this package or start the CLI with
20
+ `adapters gateway serve --webui /path/to/dist`.
@@ -0,0 +1,89 @@
1
+ import type { TokenIssueResult, TokenStore } from './tokens.js';
2
+ export type BootstrapAuthMode = 'manual' | 'local-dev' | 'bootstrap-admin';
3
+ export interface BootstrapAuthConfig {
4
+ mode: BootstrapAuthMode;
5
+ adminUsername: string | null;
6
+ adminPassword: string | null;
7
+ tokenSeed: string | null;
8
+ bootstrapTokenName: string;
9
+ }
10
+ export interface BootstrapAuthState {
11
+ mode: BootstrapAuthMode;
12
+ adminUsername: string;
13
+ passwordHash: string;
14
+ bootstrapTokenName: string;
15
+ bootstrapTokenId: string | null;
16
+ createdAt: number;
17
+ updatedAt: number;
18
+ lastLoginAt: number | null;
19
+ }
20
+ export interface BootstrapAuthStore {
21
+ get(): Promise<BootstrapAuthState | null>;
22
+ save(input: {
23
+ mode: BootstrapAuthMode;
24
+ adminUsername: string;
25
+ passwordHash: string;
26
+ bootstrapTokenName: string;
27
+ bootstrapTokenId?: string | null;
28
+ }): Promise<BootstrapAuthState>;
29
+ touchLogin(): Promise<void>;
30
+ updateBootstrapToken(tokenId: string | null): Promise<void>;
31
+ close?(): void;
32
+ }
33
+ export declare class MemoryBootstrapAuthStore implements BootstrapAuthStore {
34
+ private state;
35
+ get(): Promise<BootstrapAuthState | null>;
36
+ save(input: {
37
+ mode: BootstrapAuthMode;
38
+ adminUsername: string;
39
+ passwordHash: string;
40
+ bootstrapTokenName: string;
41
+ bootstrapTokenId?: string | null;
42
+ }): Promise<BootstrapAuthState>;
43
+ touchLogin(): Promise<void>;
44
+ updateBootstrapToken(tokenId: string | null): Promise<void>;
45
+ close(): void;
46
+ }
47
+ export declare class SqliteBootstrapAuthStore implements BootstrapAuthStore {
48
+ private readonly db;
49
+ constructor(dbPath: string);
50
+ get(): Promise<BootstrapAuthState | null>;
51
+ save(input: {
52
+ mode: BootstrapAuthMode;
53
+ adminUsername: string;
54
+ passwordHash: string;
55
+ bootstrapTokenName: string;
56
+ bootstrapTokenId?: string | null;
57
+ }): Promise<BootstrapAuthState>;
58
+ touchLogin(): Promise<void>;
59
+ updateBootstrapToken(tokenId: string | null): Promise<void>;
60
+ close(): void;
61
+ private rowToState;
62
+ }
63
+ export interface BootstrapAuthInitResult {
64
+ enabled: boolean;
65
+ mode: BootstrapAuthMode;
66
+ adminUsername: string | null;
67
+ bootstrapTokenIssued: boolean;
68
+ bootstrapTokenId: string | null;
69
+ }
70
+ export interface BootstrapLoginInput {
71
+ username: string;
72
+ password: string;
73
+ clientName?: string | null;
74
+ ttlMs?: number | null;
75
+ }
76
+ export declare class BootstrapAuthService {
77
+ private readonly config;
78
+ private readonly store;
79
+ private readonly tokenStore;
80
+ constructor(config: BootstrapAuthConfig, store: BootstrapAuthStore, tokenStore: TokenStore);
81
+ initialize(): Promise<BootstrapAuthInitResult>;
82
+ login(input: BootstrapLoginInput): Promise<TokenIssueResult | null>;
83
+ describe(): Promise<{
84
+ enabled: boolean;
85
+ mode: BootstrapAuthMode;
86
+ adminUsername: string | null;
87
+ bootstrapTokenId: string | null;
88
+ }>;
89
+ }
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bootstrap.d.ts","sourceRoot":"","sources":["../../src/auth/bootstrap.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,222 @@
1
+ import { createRequire } from 'node:module';
2
+ import { hashSecret, verifySecretHash } from './hashing.js';
3
+ const require = createRequire(import.meta.url);
4
+ const { DatabaseSync } = require('node:sqlite');
5
+ function now() {
6
+ return Date.now();
7
+ }
8
+ function normalizeString(value) {
9
+ if (typeof value !== 'string') {
10
+ return null;
11
+ }
12
+ const trimmed = value.trim();
13
+ return trimmed.length > 0 ? trimmed : null;
14
+ }
15
+ export class MemoryBootstrapAuthStore {
16
+ state = null;
17
+ async get() {
18
+ return this.state ? { ...this.state } : null;
19
+ }
20
+ async save(input) {
21
+ const timestamp = now();
22
+ const existing = this.state;
23
+ this.state = {
24
+ mode: input.mode,
25
+ adminUsername: input.adminUsername,
26
+ passwordHash: input.passwordHash,
27
+ bootstrapTokenName: input.bootstrapTokenName,
28
+ bootstrapTokenId: input.bootstrapTokenId ?? existing?.bootstrapTokenId ?? null,
29
+ createdAt: existing?.createdAt ?? timestamp,
30
+ updatedAt: timestamp,
31
+ lastLoginAt: existing?.lastLoginAt ?? null,
32
+ };
33
+ return { ...this.state };
34
+ }
35
+ async touchLogin() {
36
+ if (!this.state) {
37
+ return;
38
+ }
39
+ const timestamp = now();
40
+ this.state.lastLoginAt = timestamp;
41
+ this.state.updatedAt = timestamp;
42
+ }
43
+ async updateBootstrapToken(tokenId) {
44
+ if (!this.state) {
45
+ return;
46
+ }
47
+ this.state.bootstrapTokenId = tokenId;
48
+ this.state.updatedAt = now();
49
+ }
50
+ close() { }
51
+ }
52
+ export class SqliteBootstrapAuthStore {
53
+ db;
54
+ constructor(dbPath) {
55
+ this.db = new DatabaseSync(dbPath);
56
+ this.db.exec(`
57
+ CREATE TABLE IF NOT EXISTS gateway_bootstrap_auth (
58
+ singleton_key TEXT PRIMARY KEY,
59
+ mode TEXT NOT NULL,
60
+ admin_username TEXT NOT NULL,
61
+ password_hash TEXT NOT NULL,
62
+ bootstrap_token_name TEXT NOT NULL,
63
+ bootstrap_token_id TEXT,
64
+ created_at INTEGER NOT NULL,
65
+ updated_at INTEGER NOT NULL,
66
+ last_login_at INTEGER
67
+ );
68
+ `);
69
+ }
70
+ async get() {
71
+ const row = this.db.prepare(`
72
+ SELECT mode, admin_username, password_hash, bootstrap_token_name, bootstrap_token_id, created_at, updated_at, last_login_at
73
+ FROM gateway_bootstrap_auth
74
+ WHERE singleton_key = 'bootstrap'
75
+ `).get();
76
+ return row ? this.rowToState(row) : null;
77
+ }
78
+ async save(input) {
79
+ const existing = await this.get();
80
+ const timestamp = now();
81
+ this.db.prepare(`
82
+ INSERT INTO gateway_bootstrap_auth (
83
+ singleton_key,
84
+ mode,
85
+ admin_username,
86
+ password_hash,
87
+ bootstrap_token_name,
88
+ bootstrap_token_id,
89
+ created_at,
90
+ updated_at,
91
+ last_login_at
92
+ )
93
+ VALUES ('bootstrap', ?, ?, ?, ?, ?, ?, ?, ?)
94
+ ON CONFLICT(singleton_key) DO UPDATE SET
95
+ mode = excluded.mode,
96
+ admin_username = excluded.admin_username,
97
+ password_hash = excluded.password_hash,
98
+ bootstrap_token_name = excluded.bootstrap_token_name,
99
+ bootstrap_token_id = excluded.bootstrap_token_id,
100
+ updated_at = excluded.updated_at
101
+ `).run(input.mode, input.adminUsername, input.passwordHash, input.bootstrapTokenName, input.bootstrapTokenId ?? existing?.bootstrapTokenId ?? null, existing?.createdAt ?? timestamp, timestamp, existing?.lastLoginAt ?? null);
102
+ const state = await this.get();
103
+ if (!state) {
104
+ throw new Error('bootstrap_auth_state_missing');
105
+ }
106
+ return state;
107
+ }
108
+ async touchLogin() {
109
+ const timestamp = now();
110
+ this.db.prepare(`
111
+ UPDATE gateway_bootstrap_auth
112
+ SET last_login_at = ?, updated_at = ?
113
+ WHERE singleton_key = 'bootstrap'
114
+ `).run(timestamp, timestamp);
115
+ }
116
+ async updateBootstrapToken(tokenId) {
117
+ this.db.prepare(`
118
+ UPDATE gateway_bootstrap_auth
119
+ SET bootstrap_token_id = ?, updated_at = ?
120
+ WHERE singleton_key = 'bootstrap'
121
+ `).run(tokenId, now());
122
+ }
123
+ close() {
124
+ this.db.close();
125
+ }
126
+ rowToState(row) {
127
+ return {
128
+ mode: (row['mode'] === 'bootstrap-admin' || row['mode'] === 'local-dev') ? row['mode'] : 'manual',
129
+ adminUsername: String(row['admin_username']),
130
+ passwordHash: String(row['password_hash']),
131
+ bootstrapTokenName: String(row['bootstrap_token_name']),
132
+ bootstrapTokenId: row['bootstrap_token_id'] == null ? null : String(row['bootstrap_token_id']),
133
+ createdAt: Number(row['created_at']),
134
+ updatedAt: Number(row['updated_at']),
135
+ lastLoginAt: row['last_login_at'] == null ? null : Number(row['last_login_at']),
136
+ };
137
+ }
138
+ }
139
+ export class BootstrapAuthService {
140
+ config;
141
+ store;
142
+ tokenStore;
143
+ constructor(config, store, tokenStore) {
144
+ this.config = config;
145
+ this.store = store;
146
+ this.tokenStore = tokenStore;
147
+ }
148
+ async initialize() {
149
+ const mode = this.config.mode;
150
+ const adminUsername = normalizeString(this.config.adminUsername);
151
+ const adminPassword = normalizeString(this.config.adminPassword);
152
+ if (mode === 'manual' || !adminUsername || !adminPassword) {
153
+ return {
154
+ enabled: false,
155
+ mode,
156
+ adminUsername,
157
+ bootstrapTokenIssued: false,
158
+ bootstrapTokenId: null,
159
+ };
160
+ }
161
+ const passwordHash = await hashSecret(adminPassword);
162
+ let state = await this.store.save({
163
+ mode,
164
+ adminUsername,
165
+ passwordHash,
166
+ bootstrapTokenName: this.config.bootstrapTokenName,
167
+ });
168
+ let bootstrapTokenIssued = false;
169
+ const tokenSeed = normalizeString(this.config.tokenSeed);
170
+ if (tokenSeed) {
171
+ const existingToken = await this.tokenStore.verify(tokenSeed);
172
+ if (existingToken) {
173
+ await this.store.updateBootstrapToken(existingToken.id);
174
+ state = (await this.store.get()) ?? state;
175
+ }
176
+ else {
177
+ const issued = await this.tokenStore.create({
178
+ name: this.config.bootstrapTokenName,
179
+ plaintext: tokenSeed,
180
+ });
181
+ bootstrapTokenIssued = true;
182
+ await this.store.updateBootstrapToken(issued.id);
183
+ state = (await this.store.get()) ?? state;
184
+ }
185
+ }
186
+ return {
187
+ enabled: true,
188
+ mode: state.mode,
189
+ adminUsername: state.adminUsername,
190
+ bootstrapTokenIssued,
191
+ bootstrapTokenId: state.bootstrapTokenId,
192
+ };
193
+ }
194
+ async login(input) {
195
+ const state = await this.store.get();
196
+ if (!state) {
197
+ return null;
198
+ }
199
+ const username = normalizeString(input.username);
200
+ if (!username || username !== state.adminUsername) {
201
+ return null;
202
+ }
203
+ if (!(await verifySecretHash(state.passwordHash, input.password))) {
204
+ return null;
205
+ }
206
+ await this.store.touchLogin();
207
+ return await this.tokenStore.create({
208
+ name: normalizeString(input.clientName) ?? `${state.adminUsername}-session`,
209
+ ttlMs: typeof input.ttlMs === 'number' ? input.ttlMs : null,
210
+ });
211
+ }
212
+ async describe() {
213
+ const state = await this.store.get();
214
+ return {
215
+ enabled: state !== null,
216
+ mode: state?.mode ?? this.config.mode,
217
+ adminUsername: state?.adminUsername ?? normalizeString(this.config.adminUsername),
218
+ bootstrapTokenId: state?.bootstrapTokenId ?? null,
219
+ };
220
+ }
221
+ }
222
+ //# sourceMappingURL=bootstrap.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bootstrap.js","sourceRoot":"","sources":["../../src/auth/bootstrap.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export declare function hashToken(plaintext: string): Promise<string>;
2
+ export declare function verifyTokenHash(hash: string, plaintext: string): Promise<boolean>;
3
+ export declare const hashSecret: typeof hashToken;
4
+ export declare const verifySecretHash: typeof verifyTokenHash;
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hashing.d.ts","sourceRoot":"","sources":["../../src/auth/hashing.ts"],"names":[],"mappings":"AAaA,wBAAsB,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAKlE;AAED,wBAAsB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAMvF;AAED,eAAO,MAAM,UAAU,kBAAY,CAAC;AACpC,eAAO,MAAM,gBAAgB,wBAAkB,CAAC"}
@@ -0,0 +1,27 @@
1
+ import { randomBytes } from 'node:crypto';
2
+ import argon2 from 'argon2';
3
+ const ARGON2_OPTIONS = Object.freeze({
4
+ type: argon2.argon2id,
5
+ saltLength: 16,
6
+ hashLength: 32,
7
+ parallelism: 1,
8
+ memoryCost: 64 * 1024,
9
+ timeCost: 3,
10
+ });
11
+ export async function hashToken(plaintext) {
12
+ return await argon2.hash(plaintext, {
13
+ ...ARGON2_OPTIONS,
14
+ salt: randomBytes(ARGON2_OPTIONS.saltLength),
15
+ });
16
+ }
17
+ export async function verifyTokenHash(hash, plaintext) {
18
+ try {
19
+ return await argon2.verify(hash, plaintext);
20
+ }
21
+ catch {
22
+ return false;
23
+ }
24
+ }
25
+ export const hashSecret = hashToken;
26
+ export const verifySecretHash = verifyTokenHash;
27
+ //# sourceMappingURL=hashing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hashing.js","sourceRoot":"","sources":["../../src/auth/hashing.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE1C,OAAO,MAAM,MAAM,QAAQ,CAAC;AAE5B,MAAM,cAAc,GAAG,MAAM,CAAC,MAAM,CAAC;IACnC,IAAI,EAAE,MAAM,CAAC,QAAQ;IACrB,UAAU,EAAE,EAAE;IACd,UAAU,EAAE,EAAE;IACd,WAAW,EAAE,CAAC;IACd,UAAU,EAAE,EAAE,GAAG,IAAI;IACrB,QAAQ,EAAE,CAAC;CACZ,CAAC,CAAC;AAEH,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,SAAiB;IAC/C,OAAO,MAAM,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE;QAClC,GAAG,cAAc;QACjB,IAAI,EAAE,WAAW,CAAC,cAAc,CAAC,UAAU,CAAC;KAC7C,CAAC,CAAC;AACL,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,IAAY,EAAE,SAAiB;IACnE,IAAI,CAAC;QACH,OAAO,MAAM,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;IAC9C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,MAAM,CAAC,MAAM,UAAU,GAAG,SAAS,CAAC;AACpC,MAAM,CAAC,MAAM,gBAAgB,GAAG,eAAe,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { TokenStore, TokenRecord } from './tokens.js';
2
+ export declare function parseBearerToken(headerValue: string | null | undefined): string | null;
3
+ export declare function authenticateBearerToken(tokenStore: TokenStore, headerValue: string | null | undefined): Promise<TokenRecord | null>;
@@ -0,0 +1 @@
1
+ {"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../../src/auth/middleware.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE3D,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI,CAItF;AAED,wBAAsB,uBAAuB,CAC3C,UAAU,EAAE,UAAU,EACtB,WAAW,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GACrC,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAO7B"}
@@ -0,0 +1,17 @@
1
+ export function parseBearerToken(headerValue) {
2
+ if (!headerValue)
3
+ return null;
4
+ const match = headerValue.match(/^Bearer\s+(.+)$/i);
5
+ return match?.[1]?.trim() ?? null;
6
+ }
7
+ export async function authenticateBearerToken(tokenStore, headerValue) {
8
+ const token = parseBearerToken(headerValue);
9
+ if (!token)
10
+ return null;
11
+ const record = await tokenStore.verify(token);
12
+ if (!record)
13
+ return null;
14
+ await tokenStore.touch(record.id);
15
+ return record;
16
+ }
17
+ //# sourceMappingURL=middleware.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"middleware.js","sourceRoot":"","sources":["../../src/auth/middleware.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,gBAAgB,CAAC,WAAsC;IACrE,IAAI,CAAC,WAAW;QAAE,OAAO,IAAI,CAAC;IAC9B,MAAM,KAAK,GAAG,WAAW,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC;IACpD,OAAO,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,IAAI,CAAC;AACpC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAC3C,UAAsB,EACtB,WAAsC;IAEtC,MAAM,KAAK,GAAG,gBAAgB,CAAC,WAAW,CAAC,CAAC;IAC5C,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IACxB,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAC9C,IAAI,CAAC,MAAM;QAAE,OAAO,IAAI,CAAC;IACzB,MAAM,UAAU,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IAClC,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,45 @@
1
+ export interface TokenRecord {
2
+ id: string;
3
+ name: string;
4
+ createdAt: number;
5
+ updatedAt: number;
6
+ lastUsedAt: number | null;
7
+ expiresAt: number | null;
8
+ revokedAt: number | null;
9
+ }
10
+ export interface TokenIssueResult {
11
+ id: string;
12
+ plaintext: string;
13
+ record: TokenRecord;
14
+ }
15
+ export interface TokenCreateInput {
16
+ name: string;
17
+ ttlMs?: number | null;
18
+ plaintext?: string | null;
19
+ }
20
+ export interface TokenStore {
21
+ create(input: TokenCreateInput): Promise<TokenIssueResult>;
22
+ verify(plaintext: string): Promise<TokenRecord | null>;
23
+ revoke(id: string): Promise<boolean>;
24
+ list(): Promise<TokenRecord[]>;
25
+ touch(id: string): Promise<boolean>;
26
+ }
27
+ export declare class MemoryTokenStore implements TokenStore {
28
+ private readonly records;
29
+ create(input: TokenCreateInput): Promise<TokenIssueResult>;
30
+ verify(plaintext: string): Promise<TokenRecord | null>;
31
+ revoke(id: string): Promise<boolean>;
32
+ list(): Promise<TokenRecord[]>;
33
+ touch(id: string): Promise<boolean>;
34
+ }
35
+ export declare class SqliteTokenStore implements TokenStore {
36
+ private readonly db;
37
+ constructor(dbPath?: string);
38
+ create(input: TokenCreateInput): Promise<TokenIssueResult>;
39
+ verify(plaintext: string): Promise<TokenRecord | null>;
40
+ revoke(id: string): Promise<boolean>;
41
+ list(): Promise<TokenRecord[]>;
42
+ touch(id: string): Promise<boolean>;
43
+ close(): void;
44
+ private rowToRecord;
45
+ }
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tokens.d.ts","sourceRoot":"","sources":["../../src/auth/tokens.ts"],"names":[],"mappings":"AAWA,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,WAAW,CAAC;CACrB;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,MAAM,WAAW,UAAU;IACzB,MAAM,CAAC,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAAC;IAC3D,MAAM,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IACvD,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACrC,IAAI,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;IAC/B,KAAK,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CACrC;AA6BD,qBAAa,gBAAiB,YAAW,UAAU;IACjD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAwC;IAE1D,MAAM,CAAC,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAuB1D,MAAM,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IAWtD,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAQpC,IAAI,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;IAI9B,KAAK,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;CAO1C;AAED,qBAAa,gBAAiB,YAAW,UAAU;IACjD,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAM;gBAEb,MAAM,GAAE,MAA4B;IAiB1C,MAAM,CAAC,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAmC1D,MAAM,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IAiBtD,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAUpC,IAAI,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;IAS9B,KAAK,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAUzC,KAAK,IAAI,IAAI;IAIb,OAAO,CAAC,WAAW;CAYpB"}
@@ -0,0 +1,186 @@
1
+ import * as os from 'node:os';
2
+ import * as path from 'node:path';
3
+ import { randomBytes, randomUUID } from 'node:crypto';
4
+ import { mkdirSync } from 'node:fs';
5
+ import { createRequire } from 'node:module';
6
+ import { hashToken, verifyTokenHash } from './hashing.js';
7
+ const require = createRequire(import.meta.url);
8
+ const { DatabaseSync } = require('node:sqlite');
9
+ function defaultSqlitePath() {
10
+ return path.join(os.homedir(), '.adapters', 'gateway', 'tokens.db');
11
+ }
12
+ function now() {
13
+ return Date.now();
14
+ }
15
+ function issuePlaintextToken() {
16
+ return randomBytes(32).toString('base64url');
17
+ }
18
+ function toPublicRecord(record) {
19
+ const { hash: _hash, ...publicRecord } = record;
20
+ return publicRecord;
21
+ }
22
+ function isUsable(record, currentTime) {
23
+ if (record.revokedAt !== null)
24
+ return false;
25
+ if (record.expiresAt !== null && record.expiresAt <= currentTime)
26
+ return false;
27
+ return true;
28
+ }
29
+ export class MemoryTokenStore {
30
+ records = new Map();
31
+ async create(input) {
32
+ const plaintext = input.plaintext && input.plaintext.trim().length > 0
33
+ ? input.plaintext
34
+ : issuePlaintextToken();
35
+ const createdAt = now();
36
+ const record = {
37
+ id: randomUUID(),
38
+ name: input.name,
39
+ hash: await hashToken(plaintext),
40
+ createdAt,
41
+ updatedAt: createdAt,
42
+ lastUsedAt: null,
43
+ expiresAt: input.ttlMs ? createdAt + input.ttlMs : null,
44
+ revokedAt: null,
45
+ };
46
+ this.records.set(record.id, record);
47
+ return {
48
+ id: record.id,
49
+ plaintext,
50
+ record: toPublicRecord(record),
51
+ };
52
+ }
53
+ async verify(plaintext) {
54
+ const currentTime = now();
55
+ for (const record of this.records.values()) {
56
+ if (!isUsable(record, currentTime))
57
+ continue;
58
+ if (await verifyTokenHash(record.hash, plaintext)) {
59
+ return toPublicRecord(record);
60
+ }
61
+ }
62
+ return null;
63
+ }
64
+ async revoke(id) {
65
+ const record = this.records.get(id);
66
+ if (!record || record.revokedAt !== null)
67
+ return false;
68
+ record.revokedAt = now();
69
+ record.updatedAt = record.revokedAt;
70
+ return true;
71
+ }
72
+ async list() {
73
+ return Array.from(this.records.values()).map(toPublicRecord);
74
+ }
75
+ async touch(id) {
76
+ const record = this.records.get(id);
77
+ if (!record)
78
+ return false;
79
+ record.lastUsedAt = now();
80
+ record.updatedAt = record.lastUsedAt;
81
+ return true;
82
+ }
83
+ }
84
+ export class SqliteTokenStore {
85
+ db;
86
+ constructor(dbPath = defaultSqlitePath()) {
87
+ mkdirSync(path.dirname(dbPath), { recursive: true });
88
+ this.db = new DatabaseSync(dbPath);
89
+ this.db.exec(`
90
+ CREATE TABLE IF NOT EXISTS gateway_tokens (
91
+ id TEXT PRIMARY KEY,
92
+ name TEXT NOT NULL,
93
+ hash TEXT NOT NULL,
94
+ created_at INTEGER NOT NULL,
95
+ updated_at INTEGER NOT NULL,
96
+ last_used_at INTEGER,
97
+ expires_at INTEGER,
98
+ revoked_at INTEGER
99
+ );
100
+ `);
101
+ }
102
+ async create(input) {
103
+ const plaintext = input.plaintext && input.plaintext.trim().length > 0
104
+ ? input.plaintext
105
+ : issuePlaintextToken();
106
+ const createdAt = now();
107
+ const record = {
108
+ id: randomUUID(),
109
+ name: input.name,
110
+ hash: await hashToken(plaintext),
111
+ createdAt,
112
+ updatedAt: createdAt,
113
+ lastUsedAt: null,
114
+ expiresAt: input.ttlMs ? createdAt + input.ttlMs : null,
115
+ revokedAt: null,
116
+ };
117
+ this.db.prepare(`
118
+ INSERT INTO gateway_tokens (id, name, hash, created_at, updated_at, last_used_at, expires_at, revoked_at)
119
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)
120
+ `).run(record.id, record.name, record.hash, record.createdAt, record.updatedAt, record.lastUsedAt, record.expiresAt, record.revokedAt);
121
+ return {
122
+ id: record.id,
123
+ plaintext,
124
+ record: toPublicRecord(record),
125
+ };
126
+ }
127
+ async verify(plaintext) {
128
+ const rows = this.db.prepare(`
129
+ SELECT id, name, hash, created_at, updated_at, last_used_at, expires_at, revoked_at
130
+ FROM gateway_tokens
131
+ ORDER BY created_at DESC
132
+ `).all();
133
+ const currentTime = now();
134
+ for (const row of rows) {
135
+ const record = this.rowToRecord(row);
136
+ if (!isUsable(record, currentTime))
137
+ continue;
138
+ if (await verifyTokenHash(record.hash, plaintext)) {
139
+ return toPublicRecord(record);
140
+ }
141
+ }
142
+ return null;
143
+ }
144
+ async revoke(id) {
145
+ const updatedAt = now();
146
+ const result = this.db.prepare(`
147
+ UPDATE gateway_tokens
148
+ SET revoked_at = ?, updated_at = ?
149
+ WHERE id = ? AND revoked_at IS NULL
150
+ `).run(updatedAt, updatedAt, id);
151
+ return result.changes > 0;
152
+ }
153
+ async list() {
154
+ const rows = this.db.prepare(`
155
+ SELECT id, name, hash, created_at, updated_at, last_used_at, expires_at, revoked_at
156
+ FROM gateway_tokens
157
+ ORDER BY created_at DESC
158
+ `).all();
159
+ return rows.map((row) => toPublicRecord(this.rowToRecord(row)));
160
+ }
161
+ async touch(id) {
162
+ const updatedAt = now();
163
+ const result = this.db.prepare(`
164
+ UPDATE gateway_tokens
165
+ SET last_used_at = ?, updated_at = ?
166
+ WHERE id = ?
167
+ `).run(updatedAt, updatedAt, id);
168
+ return result.changes > 0;
169
+ }
170
+ close() {
171
+ this.db.close();
172
+ }
173
+ rowToRecord(row) {
174
+ return {
175
+ id: String(row['id']),
176
+ name: String(row['name']),
177
+ hash: String(row['hash']),
178
+ createdAt: Number(row['created_at']),
179
+ updatedAt: Number(row['updated_at']),
180
+ lastUsedAt: row['last_used_at'] == null ? null : Number(row['last_used_at']),
181
+ expiresAt: row['expires_at'] == null ? null : Number(row['expires_at']),
182
+ revokedAt: row['revoked_at'] == null ? null : Number(row['revoked_at']),
183
+ };
184
+ }
185
+ }
186
+ //# sourceMappingURL=tokens.js.map