@uncensoredcode/openbridge 0.1.0

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 (145) hide show
  1. package/README.md +117 -0
  2. package/bin/openbridge.js +10 -0
  3. package/package.json +85 -0
  4. package/packages/cli/dist/args.d.ts +30 -0
  5. package/packages/cli/dist/args.js +160 -0
  6. package/packages/cli/dist/cli.d.ts +2 -0
  7. package/packages/cli/dist/cli.js +9 -0
  8. package/packages/cli/dist/index.d.ts +26 -0
  9. package/packages/cli/dist/index.js +76 -0
  10. package/packages/runtime/dist/assistant-protocol.d.ts +34 -0
  11. package/packages/runtime/dist/assistant-protocol.js +121 -0
  12. package/packages/runtime/dist/execution/in-process.d.ts +14 -0
  13. package/packages/runtime/dist/execution/in-process.js +45 -0
  14. package/packages/runtime/dist/execution/types.d.ts +49 -0
  15. package/packages/runtime/dist/execution/types.js +20 -0
  16. package/packages/runtime/dist/index.d.ts +86 -0
  17. package/packages/runtime/dist/index.js +60 -0
  18. package/packages/runtime/dist/normalizers/index.d.ts +6 -0
  19. package/packages/runtime/dist/normalizers/index.js +12 -0
  20. package/packages/runtime/dist/normalizers/legacy-packet.d.ts +6 -0
  21. package/packages/runtime/dist/normalizers/legacy-packet.js +131 -0
  22. package/packages/runtime/dist/output-sanitizer.d.ts +23 -0
  23. package/packages/runtime/dist/output-sanitizer.js +78 -0
  24. package/packages/runtime/dist/packet-extractor.d.ts +17 -0
  25. package/packages/runtime/dist/packet-extractor.js +43 -0
  26. package/packages/runtime/dist/packet-normalizer.d.ts +21 -0
  27. package/packages/runtime/dist/packet-normalizer.js +47 -0
  28. package/packages/runtime/dist/prompt-compiler.d.ts +28 -0
  29. package/packages/runtime/dist/prompt-compiler.js +301 -0
  30. package/packages/runtime/dist/protocol.d.ts +44 -0
  31. package/packages/runtime/dist/protocol.js +165 -0
  32. package/packages/runtime/dist/provider-failure.d.ts +52 -0
  33. package/packages/runtime/dist/provider-failure.js +236 -0
  34. package/packages/runtime/dist/provider.d.ts +40 -0
  35. package/packages/runtime/dist/provider.js +1 -0
  36. package/packages/runtime/dist/runtime.d.ts +86 -0
  37. package/packages/runtime/dist/runtime.js +462 -0
  38. package/packages/runtime/dist/session-bound-provider.d.ts +52 -0
  39. package/packages/runtime/dist/session-bound-provider.js +366 -0
  40. package/packages/runtime/dist/tool-name-aliases.d.ts +5 -0
  41. package/packages/runtime/dist/tool-name-aliases.js +13 -0
  42. package/packages/runtime/dist/tools/bash.d.ts +9 -0
  43. package/packages/runtime/dist/tools/bash.js +157 -0
  44. package/packages/runtime/dist/tools/edit.d.ts +9 -0
  45. package/packages/runtime/dist/tools/edit.js +94 -0
  46. package/packages/runtime/dist/tools/index.d.ts +39 -0
  47. package/packages/runtime/dist/tools/index.js +27 -0
  48. package/packages/runtime/dist/tools/list-dir.d.ts +9 -0
  49. package/packages/runtime/dist/tools/list-dir.js +127 -0
  50. package/packages/runtime/dist/tools/read.d.ts +9 -0
  51. package/packages/runtime/dist/tools/read.js +56 -0
  52. package/packages/runtime/dist/tools/registry.d.ts +15 -0
  53. package/packages/runtime/dist/tools/registry.js +38 -0
  54. package/packages/runtime/dist/tools/runtime-path.d.ts +7 -0
  55. package/packages/runtime/dist/tools/runtime-path.js +22 -0
  56. package/packages/runtime/dist/tools/search-files.d.ts +9 -0
  57. package/packages/runtime/dist/tools/search-files.js +149 -0
  58. package/packages/runtime/dist/tools/text-file.d.ts +32 -0
  59. package/packages/runtime/dist/tools/text-file.js +101 -0
  60. package/packages/runtime/dist/tools/workspace-path.d.ts +17 -0
  61. package/packages/runtime/dist/tools/workspace-path.js +70 -0
  62. package/packages/runtime/dist/tools/write.d.ts +9 -0
  63. package/packages/runtime/dist/tools/write.js +59 -0
  64. package/packages/server/dist/bridge/bridge-model-catalog.d.ts +56 -0
  65. package/packages/server/dist/bridge/bridge-model-catalog.js +100 -0
  66. package/packages/server/dist/bridge/bridge-runtime-service.d.ts +61 -0
  67. package/packages/server/dist/bridge/bridge-runtime-service.js +1386 -0
  68. package/packages/server/dist/bridge/chat-completions/chat-completion-service.d.ts +127 -0
  69. package/packages/server/dist/bridge/chat-completions/chat-completion-service.js +1026 -0
  70. package/packages/server/dist/bridge/index.d.ts +335 -0
  71. package/packages/server/dist/bridge/index.js +45 -0
  72. package/packages/server/dist/bridge/live-provider-extraction-canary.d.ts +69 -0
  73. package/packages/server/dist/bridge/live-provider-extraction-canary.js +186 -0
  74. package/packages/server/dist/bridge/providers/generic-provider-transport.d.ts +53 -0
  75. package/packages/server/dist/bridge/providers/generic-provider-transport.js +973 -0
  76. package/packages/server/dist/bridge/providers/provider-session-resolver.d.ts +17 -0
  77. package/packages/server/dist/bridge/providers/provider-session-resolver.js +95 -0
  78. package/packages/server/dist/bridge/providers/provider-streams.d.ts +80 -0
  79. package/packages/server/dist/bridge/providers/provider-streams.js +844 -0
  80. package/packages/server/dist/bridge/providers/provider-transport-profile.d.ts +194 -0
  81. package/packages/server/dist/bridge/providers/provider-transport-profile.js +198 -0
  82. package/packages/server/dist/bridge/providers/web-provider-transport.d.ts +30 -0
  83. package/packages/server/dist/bridge/providers/web-provider-transport.js +151 -0
  84. package/packages/server/dist/bridge/state/file-bridge-state-store.d.ts +36 -0
  85. package/packages/server/dist/bridge/state/file-bridge-state-store.js +164 -0
  86. package/packages/server/dist/bridge/stores/local-session-package-store.d.ts +23 -0
  87. package/packages/server/dist/bridge/stores/local-session-package-store.js +548 -0
  88. package/packages/server/dist/bridge/stores/provider-store.d.ts +94 -0
  89. package/packages/server/dist/bridge/stores/provider-store.js +143 -0
  90. package/packages/server/dist/bridge/stores/session-backed-provider-store.d.ts +7 -0
  91. package/packages/server/dist/bridge/stores/session-backed-provider-store.js +26 -0
  92. package/packages/server/dist/bridge/stores/session-package-store.d.ts +286 -0
  93. package/packages/server/dist/bridge/stores/session-package-store.js +1527 -0
  94. package/packages/server/dist/bridge/stores/session-store.d.ts +120 -0
  95. package/packages/server/dist/bridge/stores/session-store.js +139 -0
  96. package/packages/server/dist/cli/index.d.ts +9 -0
  97. package/packages/server/dist/cli/index.js +6 -0
  98. package/packages/server/dist/cli/main.d.ts +2 -0
  99. package/packages/server/dist/cli/main.js +9 -0
  100. package/packages/server/dist/cli/run-bridge-server-cli.d.ts +54 -0
  101. package/packages/server/dist/cli/run-bridge-server-cli.js +371 -0
  102. package/packages/server/dist/client/bridge-api-client.d.ts +61 -0
  103. package/packages/server/dist/client/bridge-api-client.js +267 -0
  104. package/packages/server/dist/client/index.d.ts +11 -0
  105. package/packages/server/dist/client/index.js +11 -0
  106. package/packages/server/dist/config/bridge-server-config.d.ts +52 -0
  107. package/packages/server/dist/config/bridge-server-config.js +118 -0
  108. package/packages/server/dist/config/index.d.ts +20 -0
  109. package/packages/server/dist/config/index.js +8 -0
  110. package/packages/server/dist/http/bridge-api-route-context.d.ts +14 -0
  111. package/packages/server/dist/http/bridge-api-route-context.js +1 -0
  112. package/packages/server/dist/http/create-bridge-api-server.d.ts +72 -0
  113. package/packages/server/dist/http/create-bridge-api-server.js +225 -0
  114. package/packages/server/dist/http/index.d.ts +5 -0
  115. package/packages/server/dist/http/index.js +5 -0
  116. package/packages/server/dist/http/parse-request.d.ts +6 -0
  117. package/packages/server/dist/http/parse-request.js +27 -0
  118. package/packages/server/dist/http/register-bridge-api-routes.d.ts +7 -0
  119. package/packages/server/dist/http/register-bridge-api-routes.js +17 -0
  120. package/packages/server/dist/http/routes/admin-routes.d.ts +7 -0
  121. package/packages/server/dist/http/routes/admin-routes.js +135 -0
  122. package/packages/server/dist/http/routes/chat-completions-route.d.ts +7 -0
  123. package/packages/server/dist/http/routes/chat-completions-route.js +49 -0
  124. package/packages/server/dist/http/routes/health-routes.d.ts +6 -0
  125. package/packages/server/dist/http/routes/health-routes.js +7 -0
  126. package/packages/server/dist/http/routes/message-routes.d.ts +7 -0
  127. package/packages/server/dist/http/routes/message-routes.js +7 -0
  128. package/packages/server/dist/index.d.ts +85 -0
  129. package/packages/server/dist/index.js +28 -0
  130. package/packages/server/dist/security/bridge-auth.d.ts +9 -0
  131. package/packages/server/dist/security/bridge-auth.js +41 -0
  132. package/packages/server/dist/security/cors-policy.d.ts +5 -0
  133. package/packages/server/dist/security/cors-policy.js +34 -0
  134. package/packages/server/dist/security/index.d.ts +16 -0
  135. package/packages/server/dist/security/index.js +12 -0
  136. package/packages/server/dist/security/redact-sensitive-values.d.ts +19 -0
  137. package/packages/server/dist/security/redact-sensitive-values.js +67 -0
  138. package/packages/server/dist/shared/api-schema.d.ts +133 -0
  139. package/packages/server/dist/shared/api-schema.js +1 -0
  140. package/packages/server/dist/shared/bridge-api-error.d.ts +17 -0
  141. package/packages/server/dist/shared/bridge-api-error.js +19 -0
  142. package/packages/server/dist/shared/index.d.ts +7 -0
  143. package/packages/server/dist/shared/index.js +7 -0
  144. package/packages/server/dist/shared/output.d.ts +5 -0
  145. package/packages/server/dist/shared/output.js +14 -0
@@ -0,0 +1,548 @@
1
+ import crypto from "node:crypto";
2
+ import { chmodSync, closeSync, existsSync, mkdirSync, openSync, readFileSync, renameSync, rmSync, unlinkSync, writeFileSync } from "node:fs";
3
+ import path from "node:path";
4
+ import { z } from "zod";
5
+ import { bridgeApiErrorModule } from "../../shared/bridge-api-error.js";
6
+ import { providerStoreModule } from "./provider-store.js";
7
+ import { sessionPackageStoreModule } from "./session-package-store.js";
8
+ const { buildSessionPackageMetadata, cloneConfig, cloneInstalledProviderPackage, cloneProvider, cloneSessionPackage, cloneSessionPackageMetadata, inferProviderFromSessionPackage, installedProviderPackageSchema, sessionPackageDeleteResponseSchema, sessionPackageSchema, sessionPackageMetadataSchema } = sessionPackageStoreModule;
9
+ const { createProviderRequestSchema, providerDeleteResponseSchema, providerSchema } = providerStoreModule;
10
+ const { BridgeApiError } = bridgeApiErrorModule;
11
+ const SESSION_VAULT_VERSION = 1;
12
+ const SESSION_VAULT_ALGORITHM = "aes-256-gcm";
13
+ const SESSION_VAULT_KEY_BYTES = 32;
14
+ const vaultIndexSchema = z
15
+ .object({
16
+ version: z.literal(SESSION_VAULT_VERSION),
17
+ sessions: z.record(z.string(), sessionPackageMetadataSchema)
18
+ })
19
+ .strict();
20
+ const vaultEntrySchema = z
21
+ .object({
22
+ version: z.literal(SESSION_VAULT_VERSION),
23
+ algorithm: z.literal(SESSION_VAULT_ALGORITHM),
24
+ handle: z.string().trim().min(1),
25
+ providerId: z.string().trim().min(1),
26
+ metadata: sessionPackageMetadataSchema,
27
+ iv: z.string().trim().min(1),
28
+ authTag: z.string().trim().min(1),
29
+ ciphertext: z.string().trim().min(1)
30
+ })
31
+ .strict();
32
+ const legacySessionPackageMetadataSchema = z
33
+ .object({
34
+ handle: z.string().trim().min(1),
35
+ providerId: z.string().trim().min(1),
36
+ source: z.string().trim().min(1).optional(),
37
+ capturedAt: z.string().datetime({ offset: true }).optional(),
38
+ origin: z.string().url().optional(),
39
+ createdAt: z.string().datetime({ offset: true }),
40
+ lastUsedAt: z.string().datetime({ offset: true }).optional(),
41
+ lastVerifiedAt: z.string().datetime({ offset: true }).optional(),
42
+ idleExpiresAt: z.string().datetime({ offset: true }).optional(),
43
+ absoluteExpiresAt: z.string().datetime({ offset: true }).optional(),
44
+ status: sessionPackageMetadataSchema.shape.status,
45
+ version: z.number().int().min(1)
46
+ })
47
+ .strict();
48
+ const legacyVaultIndexSchema = z
49
+ .object({
50
+ version: z.literal(SESSION_VAULT_VERSION),
51
+ sessions: z.record(z.string(), legacySessionPackageMetadataSchema)
52
+ })
53
+ .strict();
54
+ const legacyVaultEntrySchema = z
55
+ .object({
56
+ version: z.literal(SESSION_VAULT_VERSION),
57
+ algorithm: z.literal(SESSION_VAULT_ALGORITHM),
58
+ handle: z.string().trim().min(1),
59
+ providerId: z.string().trim().min(1),
60
+ metadata: legacySessionPackageMetadataSchema,
61
+ iv: z.string().trim().min(1),
62
+ authTag: z.string().trim().min(1),
63
+ ciphertext: z.string().trim().min(1)
64
+ })
65
+ .strict();
66
+ class SessionPackageVaultError extends Error {
67
+ constructor(message) {
68
+ super(message);
69
+ this.name = "SessionPackageVaultError";
70
+ }
71
+ }
72
+ function clearLocalSessionVault(input) {
73
+ const vaultPath = path.resolve(input.vaultPath);
74
+ const entriesPath = path.join(vaultPath, "entries");
75
+ const indexPath = path.join(vaultPath, "index.json");
76
+ const archivedEntriesPath = existsSync(entriesPath)
77
+ ? `${entriesPath}.${crypto.randomUUID()}.clearing`
78
+ : null;
79
+ ensureSecureDir(vaultPath);
80
+ try {
81
+ if (archivedEntriesPath) {
82
+ renameSync(entriesPath, archivedEntriesPath);
83
+ }
84
+ ensureSecureDir(entriesPath);
85
+ writeAtomicJson(indexPath, vaultIndexSchema.parse({
86
+ version: SESSION_VAULT_VERSION,
87
+ sessions: {}
88
+ }));
89
+ }
90
+ catch (error) {
91
+ try {
92
+ if (archivedEntriesPath && existsSync(archivedEntriesPath)) {
93
+ rmSync(entriesPath, {
94
+ recursive: true,
95
+ force: true
96
+ });
97
+ renameSync(archivedEntriesPath, entriesPath);
98
+ }
99
+ }
100
+ catch { }
101
+ if (error instanceof SessionPackageVaultError) {
102
+ throw error;
103
+ }
104
+ throw new SessionPackageVaultError("Failed to clear session vault data.");
105
+ }
106
+ if (!archivedEntriesPath) {
107
+ return;
108
+ }
109
+ try {
110
+ rmSync(archivedEntriesPath, {
111
+ recursive: true,
112
+ force: true
113
+ });
114
+ }
115
+ catch {
116
+ throw new SessionPackageVaultError("Failed to remove previous session vault entries.");
117
+ }
118
+ }
119
+ function createLocalSessionPackageStore(options) {
120
+ const vaultPath = path.resolve(options.vaultPath);
121
+ const keyPath = path.resolve(options.keyPath);
122
+ const entriesPath = path.join(vaultPath, "entries");
123
+ const indexPath = path.join(vaultPath, "index.json");
124
+ const now = options.now ?? (() => new Date().toISOString());
125
+ const key = loadOrCreateVaultKey({
126
+ keyMaterial: options.keyMaterial ?? process.env.BRIDGE_SESSION_VAULT_KEY ?? null,
127
+ keyPath
128
+ });
129
+ ensureSecureDir(vaultPath);
130
+ ensureSecureDir(entriesPath);
131
+ const store = {
132
+ listProviders() {
133
+ return Object.keys(readVaultIndex().sessions)
134
+ .map((providerId) => readInstalledPackage(providerId)?.provider ?? null)
135
+ .filter((provider) => provider !== null)
136
+ .map(cloneProvider)
137
+ .sort((left, right) => left.id.localeCompare(right.id));
138
+ },
139
+ getProvider(providerId) {
140
+ const stored = readInstalledPackage(providerId);
141
+ return stored ? cloneProvider(stored.provider) : null;
142
+ },
143
+ createProvider(input) {
144
+ const normalized = createProviderRequestSchema.parse(input);
145
+ if (readVaultMetadata(normalized.id)) {
146
+ throw new BridgeApiError({
147
+ statusCode: 409,
148
+ code: "provider_exists",
149
+ message: `Provider '${normalized.id}' already exists.`
150
+ });
151
+ }
152
+ const timestamp = now();
153
+ const provider = providerSchema.parse({
154
+ ...normalized,
155
+ createdAt: timestamp,
156
+ updatedAt: timestamp
157
+ });
158
+ const installed = installedProviderPackageSchema.parse({
159
+ provider,
160
+ session: null
161
+ });
162
+ const metadata = buildSessionPackageMetadata(provider.id, null, {
163
+ existing: null,
164
+ now: timestamp,
165
+ handle: crypto.randomUUID()
166
+ });
167
+ writeInstalledPackage(metadata, installed);
168
+ return cloneProvider(provider);
169
+ },
170
+ updateProvider(providerId, patch) {
171
+ const existing = readInstalledPackage(providerId);
172
+ if (!existing) {
173
+ throw missingProviderError(providerId);
174
+ }
175
+ const nextProvider = providerSchema.parse({
176
+ ...existing.provider,
177
+ ...patch,
178
+ config: patch.config === undefined ? existing.provider.config : cloneConfig(patch.config),
179
+ updatedAt: createTimestamp(existing.provider.updatedAt, now())
180
+ });
181
+ const nextPackage = installedProviderPackageSchema.parse({
182
+ provider: nextProvider,
183
+ session: existing.session ? cloneSessionPackage(existing.session) : null
184
+ });
185
+ const nextMetadata = buildSessionPackageMetadata(providerId, nextPackage.session, {
186
+ existing: readVaultMetadata(providerId),
187
+ now: nextProvider.updatedAt,
188
+ handle: crypto.randomUUID()
189
+ });
190
+ writeInstalledPackage(nextMetadata, nextPackage);
191
+ return cloneProvider(nextProvider);
192
+ },
193
+ get(providerId) {
194
+ const metadata = readVaultMetadata(providerId);
195
+ if (!metadata || !metadata.hasSessionPackage || !isUsableMetadata(metadata, now())) {
196
+ return null;
197
+ }
198
+ const installed = readInstalledPackage(providerId);
199
+ if (!installed?.session) {
200
+ return null;
201
+ }
202
+ const lastUsedAt = now();
203
+ const nextMetadata = buildSessionPackageMetadata(providerId, installed.session, {
204
+ existing: {
205
+ ...metadata,
206
+ lastUsedAt
207
+ },
208
+ now: lastUsedAt,
209
+ handle: crypto.randomUUID()
210
+ });
211
+ writeInstalledPackage(nextMetadata, installed);
212
+ return cloneSessionPackage(installed.session);
213
+ },
214
+ getStatus(providerId) {
215
+ const metadata = readVaultMetadata(providerId);
216
+ return metadata ? cloneSessionPackageMetadata(metadata) : null;
217
+ },
218
+ put(providerId, value) {
219
+ const normalized = cloneSessionPackage(value);
220
+ const existing = readInstalledPackage(providerId);
221
+ const timestamp = createTimestamp(existing?.provider.updatedAt, now());
222
+ const provider = inferProviderFromSessionPackage({
223
+ providerId,
224
+ value: normalized,
225
+ existing: existing?.provider ?? null,
226
+ now: timestamp
227
+ });
228
+ const nextPackage = installedProviderPackageSchema.parse({
229
+ provider,
230
+ session: normalized
231
+ });
232
+ const nextMetadata = buildSessionPackageMetadata(providerId, normalized, {
233
+ existing: readVaultMetadata(providerId),
234
+ now: timestamp,
235
+ handle: crypto.randomUUID()
236
+ });
237
+ writeInstalledPackage(nextMetadata, nextPackage);
238
+ return cloneSessionPackageMetadata(nextMetadata);
239
+ },
240
+ delete(providerId) {
241
+ const metadata = readVaultMetadata(providerId);
242
+ if (!metadata) {
243
+ throw missingProviderError(providerId);
244
+ }
245
+ const nextIndex = {
246
+ ...readVaultIndex(),
247
+ sessions: {
248
+ ...readVaultIndex().sessions
249
+ }
250
+ };
251
+ delete nextIndex.sessions[providerId];
252
+ writeVaultIndex(nextIndex, options.testHooks);
253
+ try {
254
+ unlinkSync(getEntryPath(metadata.handle));
255
+ }
256
+ catch (error) {
257
+ if (error.code !== "ENOENT") {
258
+ throw new SessionPackageVaultError("Failed to remove session vault entry.");
259
+ }
260
+ }
261
+ const deleted = providerDeleteResponseSchema.parse({
262
+ ok: true,
263
+ id: providerId
264
+ });
265
+ return sessionPackageDeleteResponseSchema.parse({
266
+ ok: true,
267
+ providerId: deleted.id
268
+ });
269
+ },
270
+ deleteSession(providerId) {
271
+ const installed = readInstalledPackage(providerId);
272
+ if (!installed) {
273
+ throw missingProviderError(providerId);
274
+ }
275
+ const timestamp = createTimestamp(installed.provider.updatedAt, now());
276
+ const nextProvider = providerSchema.parse({
277
+ ...installed.provider,
278
+ updatedAt: timestamp
279
+ });
280
+ const nextPackage = installedProviderPackageSchema.parse({
281
+ provider: nextProvider,
282
+ session: null
283
+ });
284
+ const nextMetadata = buildSessionPackageMetadata(providerId, null, {
285
+ existing: readVaultMetadata(providerId),
286
+ now: timestamp,
287
+ handle: crypto.randomUUID()
288
+ });
289
+ writeInstalledPackage(nextMetadata, nextPackage);
290
+ return sessionPackageDeleteResponseSchema.parse({
291
+ ok: true,
292
+ providerId
293
+ });
294
+ },
295
+ listPackages() {
296
+ return Object.keys(readVaultIndex().sessions)
297
+ .map((providerId) => readInstalledPackage(providerId))
298
+ .filter((entry) => entry !== null)
299
+ .map(cloneInstalledProviderPackage)
300
+ .sort((left, right) => left.provider.id.localeCompare(right.provider.id));
301
+ },
302
+ getPackage(providerId) {
303
+ const installed = readInstalledPackage(providerId);
304
+ return installed ? cloneInstalledProviderPackage(installed) : null;
305
+ }
306
+ };
307
+ return store;
308
+ function readVaultMetadata(providerId) {
309
+ const metadata = readVaultIndex().sessions[providerId];
310
+ return metadata ? sessionPackageMetadataSchema.parse(metadata) : null;
311
+ }
312
+ function readInstalledPackage(providerId) {
313
+ const metadata = readVaultMetadata(providerId);
314
+ if (!metadata) {
315
+ return null;
316
+ }
317
+ const entry = readVaultEntry(metadata);
318
+ return decryptInstalledPackage(entry, key);
319
+ }
320
+ function readVaultIndex() {
321
+ if (!existsSync(indexPath)) {
322
+ return vaultIndexSchema.parse({
323
+ version: SESSION_VAULT_VERSION,
324
+ sessions: {}
325
+ });
326
+ }
327
+ const raw = parseJsonFile(indexPath, z.unknown(), "Session vault index is invalid.");
328
+ const parsed = vaultIndexSchema.safeParse(raw);
329
+ if (parsed.success) {
330
+ return parsed.data;
331
+ }
332
+ const legacy = legacyVaultIndexSchema.safeParse(raw);
333
+ if (legacy.success) {
334
+ return vaultIndexSchema.parse({
335
+ version: legacy.data.version,
336
+ sessions: Object.fromEntries(Object.entries(legacy.data.sessions).map(([providerId, metadata]) => [
337
+ providerId,
338
+ {
339
+ ...metadata,
340
+ hasSessionPackage: true
341
+ }
342
+ ]))
343
+ });
344
+ }
345
+ throw new SessionPackageVaultError("Session vault index is invalid.");
346
+ }
347
+ function writeVaultIndex(index, testHooks) {
348
+ writeAtomicJson(indexPath, vaultIndexSchema.parse(index), testHooks);
349
+ }
350
+ function readVaultEntry(metadata) {
351
+ const entryPath = getEntryPath(metadata.handle);
352
+ const raw = parseJsonFile(entryPath, z.unknown(), "Session vault entry is invalid.");
353
+ const parsed = vaultEntrySchema.safeParse(raw);
354
+ const entry = parsed.success ? parsed.data : normalizeLegacyVaultEntry(raw);
355
+ if (entry.providerId !== metadata.providerId || entry.handle !== metadata.handle) {
356
+ throw new SessionPackageVaultError("Session vault entry metadata does not match the provider mapping.");
357
+ }
358
+ return entry;
359
+ }
360
+ function writeInstalledPackage(metadata, value) {
361
+ const entry = encryptInstalledPackage(metadata, value, key);
362
+ writeAtomicJson(getEntryPath(metadata.handle), entry, options.testHooks);
363
+ writeVaultIndex(vaultIndexSchema.parse({
364
+ ...readVaultIndex(),
365
+ sessions: {
366
+ ...readVaultIndex().sessions,
367
+ [metadata.providerId]: metadata
368
+ }
369
+ }), options.testHooks);
370
+ }
371
+ function getEntryPath(handle) {
372
+ return path.join(entriesPath, `${handle}.json`);
373
+ }
374
+ }
375
+ function encryptInstalledPackage(metadata, value, key) {
376
+ const iv = crypto.randomBytes(12);
377
+ const cipher = crypto.createCipheriv("aes-256-gcm", key, iv);
378
+ const plaintext = Buffer.from(JSON.stringify(installedProviderPackageSchema.parse(value)), "utf8");
379
+ const ciphertext = Buffer.concat([cipher.update(plaintext), cipher.final()]);
380
+ const authTag = cipher.getAuthTag();
381
+ return vaultEntrySchema.parse({
382
+ version: SESSION_VAULT_VERSION,
383
+ algorithm: SESSION_VAULT_ALGORITHM,
384
+ handle: metadata.handle,
385
+ providerId: metadata.providerId,
386
+ metadata,
387
+ iv: iv.toString("base64"),
388
+ authTag: authTag.toString("base64"),
389
+ ciphertext: ciphertext.toString("base64")
390
+ });
391
+ }
392
+ function decryptInstalledPackage(entry, key) {
393
+ try {
394
+ const decipher = crypto.createDecipheriv(SESSION_VAULT_ALGORITHM, key, Buffer.from(entry.iv, "base64"));
395
+ decipher.setAuthTag(Buffer.from(entry.authTag, "base64"));
396
+ const plaintext = Buffer.concat([
397
+ decipher.update(Buffer.from(entry.ciphertext, "base64")),
398
+ decipher.final()
399
+ ]);
400
+ const decoded = JSON.parse(plaintext.toString("utf8"));
401
+ const installed = installedProviderPackageSchema.safeParse(decoded);
402
+ if (installed.success) {
403
+ return installed.data;
404
+ }
405
+ const legacySession = sessionPackageSchema.safeParse(decoded);
406
+ if (legacySession.success) {
407
+ return migrateLegacySessionPackage(entry, legacySession.data);
408
+ }
409
+ throw new Error("invalid installed package payload");
410
+ }
411
+ catch {
412
+ throw new SessionPackageVaultError("Session vault entry ciphertext is unreadable.");
413
+ }
414
+ }
415
+ function migrateLegacySessionPackage(entry, session) {
416
+ const provider = inferProviderFromSessionPackage({
417
+ providerId: entry.providerId,
418
+ value: session,
419
+ existing: null,
420
+ now: entry.metadata.lastUsedAt ?? entry.metadata.createdAt
421
+ });
422
+ return installedProviderPackageSchema.parse({
423
+ provider,
424
+ session
425
+ });
426
+ }
427
+ function normalizeLegacyVaultEntry(raw) {
428
+ const legacy = legacyVaultEntrySchema.safeParse(raw);
429
+ if (!legacy.success) {
430
+ throw new SessionPackageVaultError("Session vault entry is invalid.");
431
+ }
432
+ return vaultEntrySchema.parse({
433
+ ...legacy.data,
434
+ metadata: {
435
+ ...legacy.data.metadata,
436
+ hasSessionPackage: true
437
+ }
438
+ });
439
+ }
440
+ function loadOrCreateVaultKey(input) {
441
+ if (input.keyMaterial) {
442
+ return decodeVaultKeyMaterial(input.keyMaterial);
443
+ }
444
+ ensureSecureDir(path.dirname(input.keyPath));
445
+ try {
446
+ const fileValue = readFileSync(input.keyPath, "utf8").trim();
447
+ return decodeVaultKeyMaterial(fileValue);
448
+ }
449
+ catch (error) {
450
+ if (error.code !== "ENOENT") {
451
+ if (error instanceof SessionPackageVaultError) {
452
+ throw error;
453
+ }
454
+ throw new SessionPackageVaultError("Failed to load the session vault key.");
455
+ }
456
+ }
457
+ const createdKey = crypto.randomBytes(SESSION_VAULT_KEY_BYTES).toString("base64");
458
+ const fileDescriptor = openSync(input.keyPath, "wx", 0o600);
459
+ try {
460
+ writeFileSync(fileDescriptor, `${createdKey}\n`, "utf8");
461
+ }
462
+ finally {
463
+ closeSync(fileDescriptor);
464
+ }
465
+ chmodSync(input.keyPath, 0o600);
466
+ return decodeVaultKeyMaterial(createdKey);
467
+ }
468
+ function decodeVaultKeyMaterial(value) {
469
+ const key = Buffer.from(value.trim(), "base64");
470
+ if (key.byteLength !== SESSION_VAULT_KEY_BYTES) {
471
+ throw new SessionPackageVaultError("Session vault key must be base64-encoded 32-byte material.");
472
+ }
473
+ return key;
474
+ }
475
+ function parseJsonFile(targetPath, schema, message) {
476
+ try {
477
+ const raw = readFileSync(targetPath, "utf8");
478
+ return schema.parse(JSON.parse(raw));
479
+ }
480
+ catch (error) {
481
+ if (error.code === "ENOENT") {
482
+ throw new SessionPackageVaultError("Session vault entry is missing.");
483
+ }
484
+ if (error instanceof SessionPackageVaultError) {
485
+ throw error;
486
+ }
487
+ throw new SessionPackageVaultError(message);
488
+ }
489
+ }
490
+ function ensureSecureDir(targetPath) {
491
+ mkdirSync(targetPath, {
492
+ recursive: true,
493
+ mode: 0o700
494
+ });
495
+ }
496
+ function writeAtomicJson(targetPath, value, testHooks) {
497
+ ensureSecureDir(path.dirname(targetPath));
498
+ const tempPath = `${targetPath}.${crypto.randomUUID()}.tmp`;
499
+ try {
500
+ writeFileSync(tempPath, `${JSON.stringify(value, null, 2)}\n`, {
501
+ encoding: "utf8",
502
+ mode: 0o600
503
+ });
504
+ testHooks?.afterTempWrite?.(targetPath, tempPath);
505
+ renameSync(tempPath, targetPath);
506
+ chmodSync(targetPath, 0o600);
507
+ }
508
+ catch (error) {
509
+ try {
510
+ unlinkSync(tempPath);
511
+ }
512
+ catch { }
513
+ if (error instanceof SessionPackageVaultError) {
514
+ throw error;
515
+ }
516
+ throw new SessionPackageVaultError("Failed to commit session vault data.");
517
+ }
518
+ }
519
+ function isUsableMetadata(metadata, referenceTime) {
520
+ if (metadata.status !== "active" || !metadata.hasSessionPackage) {
521
+ return false;
522
+ }
523
+ if (metadata.absoluteExpiresAt && metadata.absoluteExpiresAt <= referenceTime) {
524
+ return false;
525
+ }
526
+ if (metadata.idleExpiresAt && metadata.idleExpiresAt <= referenceTime) {
527
+ return false;
528
+ }
529
+ return true;
530
+ }
531
+ function createTimestamp(previous, fallbackNow) {
532
+ const previousTime = previous ? Date.parse(previous) : 0;
533
+ const now = Date.parse(fallbackNow);
534
+ const nextTime = previousTime >= now ? previousTime + 1 : now;
535
+ return new Date(nextTime).toISOString();
536
+ }
537
+ function missingProviderError(id) {
538
+ return new BridgeApiError({
539
+ statusCode: 404,
540
+ code: "provider_not_found",
541
+ message: `Provider '${id}' was not found.`
542
+ });
543
+ }
544
+ export const localSessionPackageStoreModule = {
545
+ SessionPackageVaultError,
546
+ clearLocalSessionVault,
547
+ createLocalSessionPackageStore
548
+ };
@@ -0,0 +1,94 @@
1
+ import { z } from "zod";
2
+ declare const providerSchema: z.ZodObject<{
3
+ id: z.ZodString;
4
+ kind: z.ZodString;
5
+ label: z.ZodString;
6
+ enabled: z.ZodBoolean;
7
+ config: z.ZodObject<{}, z.core.$catchall<z.ZodUnknown>>;
8
+ createdAt: z.ZodString;
9
+ updatedAt: z.ZodString;
10
+ }, z.core.$strip>;
11
+ declare const createProviderRequestSchema: z.ZodObject<{
12
+ id: z.ZodString;
13
+ kind: z.ZodString;
14
+ label: z.ZodString;
15
+ enabled: z.ZodDefault<z.ZodBoolean>;
16
+ config: z.ZodDefault<z.ZodObject<{}, z.core.$catchall<z.ZodUnknown>>>;
17
+ }, z.core.$strict>;
18
+ declare const updateProviderRequestSchema: z.ZodObject<{
19
+ kind: z.ZodOptional<z.ZodString>;
20
+ label: z.ZodOptional<z.ZodString>;
21
+ enabled: z.ZodOptional<z.ZodBoolean>;
22
+ config: z.ZodOptional<z.ZodObject<{}, z.core.$catchall<z.ZodUnknown>>>;
23
+ }, z.core.$strict>;
24
+ declare const providerDeleteResponseSchema: z.ZodObject<{
25
+ ok: z.ZodLiteral<true>;
26
+ id: z.ZodString;
27
+ }, z.core.$strip>;
28
+ type ProviderRecord = z.infer<typeof providerSchema>;
29
+ type CreateProviderRequest = z.infer<typeof createProviderRequestSchema>;
30
+ type UpdateProviderRequest = z.infer<typeof updateProviderRequestSchema>;
31
+ type ProviderDeleteResponse = z.infer<typeof providerDeleteResponseSchema>;
32
+ type ProviderStore = {
33
+ list(): ProviderRecord[];
34
+ get(id: string): ProviderRecord | null;
35
+ create(input: CreateProviderRequest): ProviderRecord;
36
+ update(id: string, patch: UpdateProviderRequest): ProviderRecord;
37
+ delete(id: string): ProviderDeleteResponse;
38
+ };
39
+ declare function createInMemoryProviderStore(): ProviderStore;
40
+ export declare const providerStoreModule: {
41
+ providerSchema: z.ZodObject<{
42
+ id: z.ZodString;
43
+ kind: z.ZodString;
44
+ label: z.ZodString;
45
+ enabled: z.ZodBoolean;
46
+ config: z.ZodObject<{}, z.core.$catchall<z.ZodUnknown>>;
47
+ createdAt: z.ZodString;
48
+ updatedAt: z.ZodString;
49
+ }, z.core.$strip>;
50
+ createProviderRequestSchema: z.ZodObject<{
51
+ id: z.ZodString;
52
+ kind: z.ZodString;
53
+ label: z.ZodString;
54
+ enabled: z.ZodDefault<z.ZodBoolean>;
55
+ config: z.ZodDefault<z.ZodObject<{}, z.core.$catchall<z.ZodUnknown>>>;
56
+ }, z.core.$strict>;
57
+ updateProviderRequestSchema: z.ZodObject<{
58
+ kind: z.ZodOptional<z.ZodString>;
59
+ label: z.ZodOptional<z.ZodString>;
60
+ enabled: z.ZodOptional<z.ZodBoolean>;
61
+ config: z.ZodOptional<z.ZodObject<{}, z.core.$catchall<z.ZodUnknown>>>;
62
+ }, z.core.$strict>;
63
+ providerIdParamsSchema: z.ZodObject<{
64
+ id: z.ZodString;
65
+ }, z.core.$strict>;
66
+ providerResponseSchema: z.ZodObject<{
67
+ provider: z.ZodObject<{
68
+ id: z.ZodString;
69
+ kind: z.ZodString;
70
+ label: z.ZodString;
71
+ enabled: z.ZodBoolean;
72
+ config: z.ZodObject<{}, z.core.$catchall<z.ZodUnknown>>;
73
+ createdAt: z.ZodString;
74
+ updatedAt: z.ZodString;
75
+ }, z.core.$strip>;
76
+ }, z.core.$strip>;
77
+ providerListResponseSchema: z.ZodObject<{
78
+ providers: z.ZodArray<z.ZodObject<{
79
+ id: z.ZodString;
80
+ kind: z.ZodString;
81
+ label: z.ZodString;
82
+ enabled: z.ZodBoolean;
83
+ config: z.ZodObject<{}, z.core.$catchall<z.ZodUnknown>>;
84
+ createdAt: z.ZodString;
85
+ updatedAt: z.ZodString;
86
+ }, z.core.$strip>>;
87
+ }, z.core.$strip>;
88
+ providerDeleteResponseSchema: z.ZodObject<{
89
+ ok: z.ZodLiteral<true>;
90
+ id: z.ZodString;
91
+ }, z.core.$strip>;
92
+ createInMemoryProviderStore: typeof createInMemoryProviderStore;
93
+ };
94
+ export type { CreateProviderRequest, ProviderDeleteResponse, ProviderRecord, ProviderStore, UpdateProviderRequest };