@vymalo/opencode-lightbridge 0.18.1 → 0.20.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.
- package/README.md +3 -2
- package/dist/lib.d.ts +1 -2
- package/dist/lib.js +1 -2
- package/dist/lib.js.map +1 -1
- package/dist/opencode.d.ts +3 -1
- package/dist/opencode.js +167 -16
- package/dist/opencode.js.map +1 -1
- package/dist/plugin.d.ts +70 -48
- package/dist/plugin.js +84 -90
- package/dist/plugin.js.map +1 -1
- package/dist/sign-in.d.ts +70 -0
- package/dist/sign-in.js +152 -0
- package/dist/sign-in.js.map +1 -0
- package/package.json +4 -4
- package/dist/migration.d.ts +0 -31
- package/dist/migration.js +0 -91
- package/dist/migration.js.map +0 -1
package/README.md
CHANGED
|
@@ -83,8 +83,9 @@ Omitting `gateway`, `otel` and `register` is a valid, inert config — the plugi
|
|
|
83
83
|
|
|
84
84
|
**One login, shared with oauth2.** Configure the same `id`/`issuer`/`clientId` as an
|
|
85
85
|
`@vymalo/opencode-oauth2` server entry and logging in through either plugin makes the token
|
|
86
|
-
available to both — no second device-code/browser flow.
|
|
87
|
-
|
|
86
|
+
available to both — no second device-code/browser flow. The token lives in the durable OS **state**
|
|
87
|
+
directory, not the cache directory ([ADR-0022](https://github.com/ADORSYS-GIS/lightbridge-opencode-toolbeit/blob/main/docs/adr/0022-credentials-in-state-dir.md)).
|
|
88
|
+
**Upgrading to that release needs one re-login** (no migration, no fallback read). See
|
|
88
89
|
[`docs/lightbridge.md`](https://github.com/ADORSYS-GIS/lightbridge-opencode-toolbeit/blob/main/docs/lightbridge.md#one-login-shared-cache-with-oauth2-adr-0017).
|
|
89
90
|
|
|
90
91
|
## Scope: gateway + OTEL, not MCP
|
package/dist/lib.d.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
1
|
export { createLightbridgePlugin, LightbridgePlugin, PLUGIN_ID, type LightbridgePluginFactoryOptions, type LightbridgeRegisterHandle } from "./opencode.js";
|
|
2
|
-
export { LightbridgeRuntime, LIGHTBRIDGE_IDENTITY,
|
|
2
|
+
export { LightbridgeRuntime, LIGHTBRIDGE_IDENTITY, EXCHANGE_STATE_NAMESPACE, DEFAULT_PROJECT_KEY, ROOT_CACHE_NAMESPACE, ROOT_CACHE_SEGMENT, lightbridgeStateDir, rootCacheDir, rootStateDir, type LightbridgeRuntimeFactory, type LightbridgeRuntimeLike, type LightbridgeRuntimeOptions } from "./plugin.js";
|
|
3
3
|
export { hasOAuth2Conflict, needsProjectToken, parseLightbridgeOptions, type LightbridgeGatewayOptions, type LightbridgeOptions, type LightbridgeRegisterOptions, type ParsedLightbridgeOptions, type ProviderLookup } from "./config.js";
|
|
4
|
-
export { migrateRootTokenIfNeeded } from "./migration.js";
|
package/dist/lib.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
export { createLightbridgePlugin, LightbridgePlugin, PLUGIN_ID } from "./opencode.js";
|
|
2
|
-
export { LightbridgeRuntime, LIGHTBRIDGE_IDENTITY,
|
|
2
|
+
export { LightbridgeRuntime, LIGHTBRIDGE_IDENTITY, EXCHANGE_STATE_NAMESPACE, DEFAULT_PROJECT_KEY, ROOT_CACHE_NAMESPACE, ROOT_CACHE_SEGMENT, lightbridgeStateDir, rootCacheDir, rootStateDir } from "./plugin.js";
|
|
3
3
|
export { hasOAuth2Conflict, needsProjectToken, parseLightbridgeOptions } from "./config.js";
|
|
4
|
-
export { migrateRootTokenIfNeeded } from "./migration.js";
|
|
5
4
|
|
|
6
5
|
//# sourceMappingURL=lib.js.map
|
package/dist/lib.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"mappings":"AAAA,SACE,yBACA,mBACA,iBAGK;AAEP,SACE,oBACA,sBACA,
|
|
1
|
+
{"mappings":"AAAA,SACE,yBACA,mBACA,iBAGK;AAEP,SACE,oBACA,sBACA,0BACA,qBACA,sBACA,oBACA,qBACA,cACA,oBAIK;AAEP,SACE,mBACA,mBACA,+BAMK","names":[],"sources":["../src/lib.ts"],"version":3,"file":"lib.js","sourceRoot":""}
|
package/dist/opencode.d.ts
CHANGED
|
@@ -18,8 +18,10 @@ export interface LightbridgePluginFactoryOptions {
|
|
|
18
18
|
/** Shared-runtime HTTP client (auth-core `TokenRuntime`). Tests only. */
|
|
19
19
|
fetchImpl?: typeof fetch;
|
|
20
20
|
onAuthorizationUrl?: (url: string) => Promise<void> | void;
|
|
21
|
-
/** Override the
|
|
21
|
+
/** Override the CACHE root for the register module's disposable model list (defaults to the OS cache dir). */
|
|
22
22
|
cacheDir?: string;
|
|
23
|
+
/** Override the STATE root for credentials — tokens + refresh locks (defaults to the OS state dir, ADR-0022). */
|
|
24
|
+
stateDir?: string;
|
|
23
25
|
tokenExpirySkewMs?: number;
|
|
24
26
|
/**
|
|
25
27
|
* Build the shared `LightbridgeRuntimeLike` for `(auth, projectId)`.
|
package/dist/opencode.js
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
import { hostname } from "node:os";
|
|
2
|
-
import { join } from "node:path";
|
|
3
2
|
import { Plugin } from "@opencode/plugin/effect";
|
|
4
3
|
import { defaultTextMapSetter } from "@opentelemetry/api";
|
|
5
4
|
import { W3CTraceContextPropagator } from "@opentelemetry/core";
|
|
5
|
+
import { isInteractiveAuthRequiredError } from "@vymalo/opencode-auth-core/lib";
|
|
6
6
|
import { buildResource, createProviders, deferredAttribute, describeError, readVcsInfo, registerExitHandlers, resolveOtelConfig, TelemetryRecorder } from "@vymalo/opencode-core-otel";
|
|
7
7
|
import { applyResponsesApiSettings, mergeDiscoveredModels, propagateCachedBearer, ProviderModelSyncEngine, resolveCachedBearer, resolveProviderPackage, upsertManagedProvider } from "@vymalo/opencode-provider-sync/lib";
|
|
8
8
|
import { Effect, Stream } from "effect";
|
|
9
9
|
import { hasOAuth2Conflict, needsProjectToken, parseLightbridgeOptions } from "./config.js";
|
|
10
10
|
import { captureHostContext, createEffectLogger, DEFAULT_LOG_LEVEL, resolveLogLevel, runInHost } from "./logging.js";
|
|
11
11
|
import { adaptContext, adaptPermission, adaptPrompt, adaptToolAfter, adaptToolBefore, OtelEventAdapter } from "./otel-adapter.js";
|
|
12
|
-
import { LightbridgeRuntime, ROOT_CACHE_NAMESPACE, ROOT_CACHE_SEGMENT } from "./plugin.js";
|
|
12
|
+
import { LightbridgeRuntime, ROOT_CACHE_NAMESPACE, ROOT_CACHE_SEGMENT, rootCacheDir, rootStateDir } from "./plugin.js";
|
|
13
|
+
import { createSignInRegistration, createSignInRequiredNotifier, signInPath } from "./sign-in.js";
|
|
13
14
|
/** Stable plugin id. v2 requires one and keys storage/registrations by it. */
|
|
14
15
|
export const PLUGIN_ID = "vymalo.lightbridge";
|
|
15
16
|
function errorMessage(error) {
|
|
@@ -37,13 +38,16 @@ function safeHostname() {
|
|
|
37
38
|
* every export attempt, a later successful login resumes exporting on the
|
|
38
39
|
* next flush with nothing to restart.
|
|
39
40
|
*/
|
|
40
|
-
function createRuntimeTokenSource(runtime) {
|
|
41
|
+
function createRuntimeTokenSource(runtime, onSignInRequired) {
|
|
41
42
|
return {
|
|
42
43
|
headers: async () => {
|
|
43
44
|
try {
|
|
44
|
-
const token = await runtime.getProjectToken(
|
|
45
|
+
const token = await runtime.getProjectToken();
|
|
45
46
|
return { Authorization: `${token.tokenType || "Bearer"} ${token.accessToken}` };
|
|
46
|
-
} catch {
|
|
47
|
+
} catch (error) {
|
|
48
|
+
if (isInteractiveAuthRequiredError(error)) {
|
|
49
|
+
onSignInRequired("otel");
|
|
50
|
+
}
|
|
47
51
|
return undefined;
|
|
48
52
|
}
|
|
49
53
|
},
|
|
@@ -129,7 +133,7 @@ function warnIfTokenCommandConfigIgnored(otel, env, logger) {
|
|
|
129
133
|
* handlers. Mirrors `@vymalo/opencode-otel`'s orchestration verbatim, minus
|
|
130
134
|
* the standalone `tokenCommand` seam.
|
|
131
135
|
*/
|
|
132
|
-
async function buildOtelModule(location, otelConfig, logger, factoryOptions, runtime) {
|
|
136
|
+
async function buildOtelModule(location, otelConfig, logger, factoryOptions, runtime, onSignInRequired) {
|
|
133
137
|
const version = deferredAttribute(factoryOptions.deferredTimeoutMs);
|
|
134
138
|
const branch = deferredAttribute(factoryOptions.deferredTimeoutMs);
|
|
135
139
|
if (factoryOptions.hostInfo?.version) {
|
|
@@ -148,7 +152,7 @@ async function buildOtelModule(location, otelConfig, logger, factoryOptions, run
|
|
|
148
152
|
branch: branch.value,
|
|
149
153
|
vcs
|
|
150
154
|
});
|
|
151
|
-
const tokenSource = runtime ? createRuntimeTokenSource(runtime) : undefined;
|
|
155
|
+
const tokenSource = runtime ? createRuntimeTokenSource(runtime, onSignInRequired) : undefined;
|
|
152
156
|
const providers = createProviders(otelConfig, resource, logger, factoryOptions.exporters, tokenSource);
|
|
153
157
|
const recorder = new TelemetryRecorder({
|
|
154
158
|
providers,
|
|
@@ -249,15 +253,28 @@ export function createLightbridgePlugin(factoryOptions = {}) {
|
|
|
249
253
|
// and the OTEL token source below. `undefined` only for a register/auth-only
|
|
250
254
|
// config.
|
|
251
255
|
const buildRuntime = factoryOptions.runtimeFactory ?? ((auth, pid, options) => new LightbridgeRuntime(auth, pid, options));
|
|
252
|
-
|
|
256
|
+
// Built whenever a module needs a token OR the user must be able to sign in
|
|
257
|
+
// (device_code, ADR-0023): the sign-in method drives this same runtime.
|
|
258
|
+
const signInEnabled = parsed.auth.authFlow === "device_code";
|
|
259
|
+
const sharedRuntime = wantsProjectToken || signInEnabled ? buildRuntime(parsed.auth, parsed.projectId, {
|
|
253
260
|
logger,
|
|
254
261
|
fetchImpl: factoryOptions.fetchImpl,
|
|
255
262
|
onAuthorizationUrl: factoryOptions.onAuthorizationUrl,
|
|
256
|
-
|
|
263
|
+
stateDir: factoryOptions.stateDir,
|
|
257
264
|
tokenExpirySkewMs: factoryOptions.tokenExpirySkewMs,
|
|
258
265
|
exchange: parsed.gateway?.exchange ?? false
|
|
259
266
|
}) : undefined;
|
|
260
267
|
const reloadProviders = () => runInHost(hostContext, ctx.provider.reload());
|
|
268
|
+
const signInName = parsed.register?.name ?? parsed.auth.id;
|
|
269
|
+
const signInNotice = createSignInRequiredNotifier(logger, signInName);
|
|
270
|
+
// Only meaningful when the Connect dialog can actually be used to fix it.
|
|
271
|
+
const notifySignInRequired = (source) => {
|
|
272
|
+
if (signInEnabled) {
|
|
273
|
+
signInNotice.notify(source);
|
|
274
|
+
}
|
|
275
|
+
};
|
|
276
|
+
// Set below when sign-in is registered; the gateway hook calls it (cached).
|
|
277
|
+
let observeConnectionCached = async () => {};
|
|
261
278
|
// ---- register module (ADR-0017 requirement 1) ----
|
|
262
279
|
let engine;
|
|
263
280
|
let registerChain = Promise.resolve();
|
|
@@ -282,10 +299,14 @@ export function createLightbridgePlugin(factoryOptions = {}) {
|
|
|
282
299
|
servers: [buildRegisterServerConfig(parsed.auth, register)],
|
|
283
300
|
cacheNamespace: ROOT_CACHE_NAMESPACE
|
|
284
301
|
}, {
|
|
302
|
+
// Sign-in happens only in the host's Connect dialog (ADR-0023): the
|
|
303
|
+
// engine's warmup, scheduler and token reads are refresh-only.
|
|
304
|
+
neverInteractive: true,
|
|
285
305
|
logger,
|
|
286
306
|
fetchImpl: factoryOptions.fetchImpl,
|
|
287
307
|
onAuthorizationUrl: factoryOptions.onAuthorizationUrl,
|
|
288
|
-
cacheDir: factoryOptions.cacheDir ?
|
|
308
|
+
cacheDir: factoryOptions.cacheDir ? rootCacheDir(factoryOptions.cacheDir) : undefined,
|
|
309
|
+
stateDir: factoryOptions.stateDir ? rootStateDir(factoryOptions.stateDir) : undefined,
|
|
289
310
|
cacheNamespaceSegment: ROOT_CACHE_SEGMENT,
|
|
290
311
|
serviceLabel: "opencode-lightbridge"
|
|
291
312
|
});
|
|
@@ -301,6 +322,17 @@ export function createLightbridgePlugin(factoryOptions = {}) {
|
|
|
301
322
|
}
|
|
302
323
|
engine = next;
|
|
303
324
|
registerBearer = await resolveCachedBearer(parsed.auth.id, next, logger);
|
|
325
|
+
if (registerBearer === undefined && sharedRuntime) {
|
|
326
|
+
// resolveCachedBearer swallows why; ask the runtime so only a genuine
|
|
327
|
+
// "needs sign-in" (not a network/IdP outage) raises the notice.
|
|
328
|
+
try {
|
|
329
|
+
await sharedRuntime.ensureRootToken();
|
|
330
|
+
} catch (error) {
|
|
331
|
+
if (isInteractiveAuthRequiredError(error)) {
|
|
332
|
+
notifySignInRequired("register");
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
}
|
|
304
336
|
// Models and bearer are now known: ask the host to re-run transforms.
|
|
305
337
|
await reloadProviders();
|
|
306
338
|
};
|
|
@@ -355,6 +387,116 @@ export function createLightbridgePlugin(factoryOptions = {}) {
|
|
|
355
387
|
}
|
|
356
388
|
});
|
|
357
389
|
}
|
|
390
|
+
// ---- sign-in (ADR-0023): the ONLY place an interactive login can start ----
|
|
391
|
+
if (signInEnabled && sharedRuntime) {
|
|
392
|
+
const runtime = sharedRuntime;
|
|
393
|
+
const afterSignIn = async () => {
|
|
394
|
+
try {
|
|
395
|
+
// Pick up the new credential in the register module's engine and
|
|
396
|
+
// refresh the stamped bearer, then ask the host to re-run transforms.
|
|
397
|
+
if (engine) {
|
|
398
|
+
await engine.syncServer(parsed.auth.id);
|
|
399
|
+
registerBearer = await resolveCachedBearer(parsed.auth.id, engine, logger);
|
|
400
|
+
}
|
|
401
|
+
} catch (error) {
|
|
402
|
+
logger.warn("lightbridge_sign_in_sync_failed", { error: errorMessage(error) });
|
|
403
|
+
}
|
|
404
|
+
try {
|
|
405
|
+
await reloadProviders();
|
|
406
|
+
} catch (error) {
|
|
407
|
+
logger.warn("lightbridge_sign_in_reload_failed", { error: errorMessage(error) });
|
|
408
|
+
}
|
|
409
|
+
};
|
|
410
|
+
const registration = createSignInRegistration({
|
|
411
|
+
integrationID: parsed.auth.id,
|
|
412
|
+
runtime,
|
|
413
|
+
logger,
|
|
414
|
+
afterSignIn,
|
|
415
|
+
onSignedIn: () => signInNotice.reset(),
|
|
416
|
+
onSignInRequired: notifySignInRequired
|
|
417
|
+
});
|
|
418
|
+
// The integration id is `auth.id`, never the well-known URL's: the host
|
|
419
|
+
// loads the well-known manifest with `credentials.at(-1)` of ITS
|
|
420
|
+
// integration, and an oauth credential there would freeze it (ADR-0023).
|
|
421
|
+
yield* ctx.integration.transform((editor) => {
|
|
422
|
+
editor.update(parsed.auth.id, (integration) => {
|
|
423
|
+
integration.name = signInName;
|
|
424
|
+
});
|
|
425
|
+
editor.method.update(registration);
|
|
426
|
+
});
|
|
427
|
+
// ---- host disconnect => sign out (ADR-0023) ----
|
|
428
|
+
// TRANSITION-based: only a connection we saw present in THIS process and
|
|
429
|
+
// that is then gone signs us out. A host with no credential at startup is
|
|
430
|
+
// normal (users who signed in before sign-in moved into the dialog have a
|
|
431
|
+
// token and no host credential) and must keep working.
|
|
432
|
+
let connectionSeen = false;
|
|
433
|
+
let signingOut = false;
|
|
434
|
+
let lastObservedAt = 0;
|
|
435
|
+
const OBSERVE_CACHE_MS = 5e3;
|
|
436
|
+
const signOut = async () => {
|
|
437
|
+
logger.info("lightbridge_signed_out_by_host", { integrationID: parsed.auth.id });
|
|
438
|
+
try {
|
|
439
|
+
await runtime.reset();
|
|
440
|
+
} catch (error) {
|
|
441
|
+
logger.warn("lightbridge_sign_out_reset_failed", { error: errorMessage(error) });
|
|
442
|
+
}
|
|
443
|
+
// The engine keeps its token in memory even when the file is gone:
|
|
444
|
+
// drop it, and let the next transform build a fresh (signed-out) one.
|
|
445
|
+
stopEngine();
|
|
446
|
+
registerQueued = false;
|
|
447
|
+
signInNotice.reset();
|
|
448
|
+
notifySignInRequired("disconnect");
|
|
449
|
+
try {
|
|
450
|
+
await reloadProviders();
|
|
451
|
+
} catch (error) {
|
|
452
|
+
logger.warn("lightbridge_sign_out_reload_failed", { error: errorMessage(error) });
|
|
453
|
+
}
|
|
454
|
+
};
|
|
455
|
+
const onConnection = async (present) => {
|
|
456
|
+
if (present) {
|
|
457
|
+
connectionSeen = true;
|
|
458
|
+
return;
|
|
459
|
+
}
|
|
460
|
+
if (!connectionSeen || signingOut) {
|
|
461
|
+
return;
|
|
462
|
+
}
|
|
463
|
+
connectionSeen = false;
|
|
464
|
+
signingOut = true;
|
|
465
|
+
try {
|
|
466
|
+
await signOut();
|
|
467
|
+
} finally {
|
|
468
|
+
signingOut = false;
|
|
469
|
+
}
|
|
470
|
+
};
|
|
471
|
+
const observeConnection = (force) => {
|
|
472
|
+
if (!force && Date.now() - lastObservedAt < OBSERVE_CACHE_MS) {
|
|
473
|
+
return Promise.resolve();
|
|
474
|
+
}
|
|
475
|
+
lastObservedAt = Date.now();
|
|
476
|
+
return runInHost(hostContext, ctx.integration.connection.active(parsed.auth.id).pipe(Effect.flatMap((info) => Effect.promise(() => onConnection(info !== undefined))), Effect.ignore));
|
|
477
|
+
};
|
|
478
|
+
observeConnectionCached = () => observeConnection(false);
|
|
479
|
+
yield* Effect.forkScoped(Stream.runForEach(ctx.event.subscribe({ types: [
|
|
480
|
+
"credential.updated",
|
|
481
|
+
"credential.switched",
|
|
482
|
+
"integration.updated"
|
|
483
|
+
] }), () => Effect.promise(() => observeConnection(true))).pipe(Effect.tapError((error) => Effect.sync(() => logger.warn("lightbridge_connection_watch_failed", { error: errorMessage(error) }))), Effect.ignore));
|
|
484
|
+
void observeConnection(true);
|
|
485
|
+
// Report a missing sign-in once, up front, without any network on the
|
|
486
|
+
// signed-out path (a stored token may refresh, which is fine).
|
|
487
|
+
void runtime.ensureRootToken().catch((error) => {
|
|
488
|
+
if (isInteractiveAuthRequiredError(error)) {
|
|
489
|
+
notifySignInRequired("startup");
|
|
490
|
+
} else {
|
|
491
|
+
logger.debug("lightbridge_startup_token_check_failed", { error: errorMessage(error) });
|
|
492
|
+
}
|
|
493
|
+
});
|
|
494
|
+
} else if (parsed.auth.authFlow === "authorization_code") {
|
|
495
|
+
logger.warn("lightbridge_sign_in_unsupported_flow", {
|
|
496
|
+
authFlow: parsed.auth.authFlow,
|
|
497
|
+
message: `lightbridge signs in through the host's Connect dialog (${signInPath(signInName)}), which needs authFlow "device_code"`
|
|
498
|
+
});
|
|
499
|
+
}
|
|
358
500
|
// ---- gateway module ----
|
|
359
501
|
// `sharedRuntime` is always defined here: it is built whenever `gateway`
|
|
360
502
|
// or `otel` is configured (`wantsProjectToken`).
|
|
@@ -376,7 +518,8 @@ export function createLightbridgePlugin(factoryOptions = {}) {
|
|
|
376
518
|
}
|
|
377
519
|
return Effect.tryPromise({
|
|
378
520
|
try: async () => {
|
|
379
|
-
|
|
521
|
+
await observeConnectionCached();
|
|
522
|
+
const token = await runtime.getProjectToken();
|
|
380
523
|
// Header names are case-insensitive: drop any variant already set
|
|
381
524
|
// (a stamped record header, the placeholder key's, a lowercase copy).
|
|
382
525
|
for (const key of Object.keys(event.headers)) {
|
|
@@ -388,10 +531,18 @@ export function createLightbridgePlugin(factoryOptions = {}) {
|
|
|
388
531
|
logger.trace("lightbridge_gateway_bearer_injected", { providerId });
|
|
389
532
|
},
|
|
390
533
|
catch: (error) => error
|
|
391
|
-
}).pipe(Effect.tapError((error) => Effect.sync(() =>
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
534
|
+
}).pipe(Effect.tapError((error) => Effect.sync(() => {
|
|
535
|
+
const needsSignIn = isInteractiveAuthRequiredError(error);
|
|
536
|
+
// While signed out every request repeats this; the one-time
|
|
537
|
+
// lightbridge_sign_in_required warning already says what to do.
|
|
538
|
+
logger[needsSignIn && signInEnabled ? "debug" : "warn"]("lightbridge_gateway_no_bearer", {
|
|
539
|
+
providerId,
|
|
540
|
+
error: errorMessage(error)
|
|
541
|
+
});
|
|
542
|
+
if (needsSignIn) {
|
|
543
|
+
notifySignInRequired("gateway");
|
|
544
|
+
}
|
|
545
|
+
})), Effect.orDie);
|
|
395
546
|
});
|
|
396
547
|
}
|
|
397
548
|
// ---- otel module ----
|
|
@@ -404,7 +555,7 @@ export function createLightbridgePlugin(factoryOptions = {}) {
|
|
|
404
555
|
const built = yield* Effect.promise(() => buildOtelModule({
|
|
405
556
|
directory: ctx.location.directory,
|
|
406
557
|
projectId: ctx.location.project?.id
|
|
407
|
-
}, otelConfig, logger, factoryOptions, sharedRuntime));
|
|
558
|
+
}, otelConfig, logger, factoryOptions, sharedRuntime, notifySignInRequired));
|
|
408
559
|
otel = built;
|
|
409
560
|
const { recorder } = built;
|
|
410
561
|
const adapter = new OtelEventAdapter(recorder, factoryOptions.now);
|
package/dist/opencode.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"mappings":"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","names":[],"sources":["../src/opencode.ts"],"version":3,"file":"opencode.js","sourceRoot":""}
|
|
1
|
+
{"mappings":"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","names":[],"sources":["../src/opencode.ts"],"version":3,"file":"opencode.js","sourceRoot":""}
|
package/dist/plugin.d.ts
CHANGED
|
@@ -1,24 +1,28 @@
|
|
|
1
|
-
import { type AuthServerConfig, type Logger, type TokenSet } from "@vymalo/opencode-auth-core/lib";
|
|
1
|
+
import { type AuthServerConfig, type DeviceSignIn, type Logger, type TokenSet } from "@vymalo/opencode-auth-core/lib";
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* cache key has always been derived from this literal, independent of the
|
|
7
|
-
* configured IdP's `id`.
|
|
3
|
+
* Identity for the exchanged project-token store. Kept as a constant, not
|
|
4
|
+
* `auth.id`, because the exchanged-token key has always been derived from this
|
|
5
|
+
* literal, independent of the configured IdP's `id`.
|
|
8
6
|
*/
|
|
9
7
|
export declare const LIGHTBRIDGE_IDENTITY = "lightbridge";
|
|
10
|
-
/** Own cache namespace for the exchanged-token store — separate from oauth2/repo-auth/otel's. */
|
|
11
|
-
export declare const DEFAULT_CACHE_NAMESPACE = "opencode-lightbridge";
|
|
12
8
|
/**
|
|
13
|
-
*
|
|
9
|
+
* Own namespace for the exchanged-token store — separate from oauth2/repo-auth/
|
|
10
|
+
* otel's. It sits under the durable STATE root (ADR-0022): a project token is a
|
|
11
|
+
* credential, and is re-exchangeable only while the human root token survives.
|
|
12
|
+
*/
|
|
13
|
+
export declare const EXCHANGE_STATE_NAMESPACE = "opencode-lightbridge";
|
|
14
|
+
/**
|
|
15
|
+
* ADR-0017: the human ROOT token lives in the SAME credential file
|
|
14
16
|
* `@vymalo/opencode-oauth2` uses for a server of this id —
|
|
15
|
-
* `<
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
* same issuer/clientId) log in ONCE
|
|
19
|
-
* on-disk
|
|
20
|
-
* `@vymalo/opencode-oauth2`, which
|
|
21
|
-
* `docs/adr/0017-lightbridge-all-in-one.md`
|
|
17
|
+
* `<stateRoot>/opencode-oauth2/opencode-oauth2-model-sync/<id>.json`
|
|
18
|
+
* (ADR-0022 moved the root from the cache dir to the state dir; the relative
|
|
19
|
+
* path is unchanged). This is what lets a developer who configures the same
|
|
20
|
+
* IdP (`auth.id` == an oauth2 `servers[].id`, same issuer/clientId) log in ONCE
|
|
21
|
+
* and have both plugins read/write the same on-disk credential. The literals
|
|
22
|
+
* are pinned here (not imported from `@vymalo/opencode-oauth2`, which
|
|
23
|
+
* lightbridge does not depend on) — see `docs/adr/0017-lightbridge-all-in-one.md`
|
|
24
|
+
* for the shared-contract rationale. The discovered-model list for that server
|
|
25
|
+
* is a separate record in the CACHE root, owned by whichever engine syncs it.
|
|
22
26
|
*/
|
|
23
27
|
export declare const ROOT_CACHE_SEGMENT = "opencode-oauth2";
|
|
24
28
|
export declare const ROOT_CACHE_NAMESPACE = "opencode-oauth2-model-sync";
|
|
@@ -33,10 +37,10 @@ export interface LightbridgeRuntimeOptions {
|
|
|
33
37
|
logger?: Logger;
|
|
34
38
|
fetchImpl?: typeof fetch;
|
|
35
39
|
onAuthorizationUrl?: (url: string) => Promise<void> | void;
|
|
36
|
-
/** Override the
|
|
37
|
-
* the shared root-token store and the exchange-only store are joined
|
|
38
|
-
* this. Test seam; production callers omit it. */
|
|
39
|
-
|
|
40
|
+
/** Override the STATE root (defaults to the OS state dir convention, ADR-0022) —
|
|
41
|
+
* both the shared root-token store and the exchange-only store are joined
|
|
42
|
+
* from this. Test seam; production callers omit it. */
|
|
43
|
+
stateDir?: string;
|
|
40
44
|
tokenExpirySkewMs?: number;
|
|
41
45
|
/**
|
|
42
46
|
* Whether to perform the RFC 8693 exchange (ADR-0012) rather than use the
|
|
@@ -50,10 +54,28 @@ export interface LightbridgeRuntimeOptions {
|
|
|
50
54
|
* `TokenRuntime` (no network, no disk).
|
|
51
55
|
*/
|
|
52
56
|
export interface LightbridgeRuntimeLike {
|
|
53
|
-
|
|
54
|
-
|
|
57
|
+
/**
|
|
58
|
+
* A usable gateway/OTEL bearer. NEVER interactive (ADR-0023): when no usable
|
|
59
|
+
* token exists it rejects with `InteractiveAuthRequiredError` and the caller
|
|
60
|
+
* fails closed. The only way a human signs in is `beginDeviceSignIn`, driven
|
|
61
|
+
* from the host's Connect dialog.
|
|
62
|
+
*/
|
|
63
|
+
getProjectToken(): Promise<TokenSet>;
|
|
64
|
+
/**
|
|
65
|
+
* The shared human/IdP root token, refresh-only (never interactive).
|
|
66
|
+
* `minValidityMs` forces a real refresh when the cached token has less than
|
|
67
|
+
* that left (the host's 5-minute refresh window is wider than our skew).
|
|
68
|
+
*/
|
|
69
|
+
ensureRootToken(options?: {
|
|
70
|
+
minValidityMs?: number;
|
|
55
71
|
}): Promise<TokenSet>;
|
|
56
|
-
|
|
72
|
+
/**
|
|
73
|
+
* Request a device code for the Connect dialog; `complete` polls and stores.
|
|
74
|
+
* `signal` cancels the device-authorization request.
|
|
75
|
+
*/
|
|
76
|
+
beginDeviceSignIn(signal?: AbortSignal): Promise<DeviceSignIn>;
|
|
77
|
+
/** Drop every stored token for this identity (the host disconnected it). */
|
|
78
|
+
reset(): Promise<void>;
|
|
57
79
|
}
|
|
58
80
|
/**
|
|
59
81
|
* Builds a `LightbridgeRuntimeLike` for a given `(auth, projectId)` pair.
|
|
@@ -68,12 +90,11 @@ export type LightbridgeRuntimeFactory = (auth: AuthServerConfig, projectId: stri
|
|
|
68
90
|
* BOTH the gateway (`chat.headers`) and OTEL (`TokenSource.headers()`).
|
|
69
91
|
*
|
|
70
92
|
* The human root token itself is no longer lightbridge-exclusive storage: it
|
|
71
|
-
* lives in the SAME
|
|
72
|
-
* of this id (`ROOT_CACHE_SEGMENT`/`ROOT_CACHE_NAMESPACE
|
|
73
|
-
* both plugins against the same
|
|
74
|
-
* `servers[].id`, same issuer/clientId) means
|
|
75
|
-
*
|
|
76
|
-
* `migration.ts`.
|
|
93
|
+
* lives in the SAME credential file `@vymalo/opencode-oauth2` writes for a
|
|
94
|
+
* server of this id (`ROOT_CACHE_SEGMENT`/`ROOT_CACHE_NAMESPACE`, under the
|
|
95
|
+
* durable state root — ADR-0022), so configuring both plugins against the same
|
|
96
|
+
* IdP (`auth.id` matching an oauth2 `servers[].id`, same issuer/clientId) means
|
|
97
|
+
* logging in once.
|
|
77
98
|
*/
|
|
78
99
|
export declare class LightbridgeRuntime implements LightbridgeRuntimeLike {
|
|
79
100
|
private readonly projectId;
|
|
@@ -83,20 +104,12 @@ export declare class LightbridgeRuntime implements LightbridgeRuntimeLike {
|
|
|
83
104
|
private readonly logger;
|
|
84
105
|
private readonly tokenExpirySkewMs;
|
|
85
106
|
private readonly exchange;
|
|
86
|
-
private readonly
|
|
107
|
+
private readonly stateRoot;
|
|
87
108
|
private readonly serverId;
|
|
88
109
|
/** Token-cache key: the project id, or `DEFAULT_PROJECT_KEY` when unset. */
|
|
89
110
|
private readonly projectKey;
|
|
90
111
|
private inFlightExchange?;
|
|
91
|
-
private migration?;
|
|
92
112
|
constructor(auth: AuthServerConfig, projectId: string | undefined, options?: LightbridgeRuntimeOptions);
|
|
93
|
-
/**
|
|
94
|
-
* One-time (per instance) migration of a pre-ADR-0017 root token into the
|
|
95
|
-
* shared cache file — see `migration.ts`. Idempotent and cheap on every
|
|
96
|
-
* call after the first (the underlying function also short-circuits once
|
|
97
|
-
* the new location has ANY state).
|
|
98
|
-
*/
|
|
99
|
-
private ensureMigrated;
|
|
100
113
|
/** Non-network read of the cached project token, if any. */
|
|
101
114
|
getCachedProjectToken(): Promise<TokenSet | undefined>;
|
|
102
115
|
/**
|
|
@@ -122,20 +135,29 @@ export declare class LightbridgeRuntime implements LightbridgeRuntimeLike {
|
|
|
122
135
|
* invents a token: a failure propagates to the caller, which is expected to
|
|
123
136
|
* fail closed (no header / empty `headers()`).
|
|
124
137
|
*/
|
|
125
|
-
getProjectToken(
|
|
126
|
-
interactive?: boolean;
|
|
127
|
-
}): Promise<TokenSet>;
|
|
138
|
+
getProjectToken(): Promise<TokenSet>;
|
|
128
139
|
private performExchange;
|
|
140
|
+
/** See {@link LightbridgeRuntimeLike.ensureRootToken}. */
|
|
141
|
+
ensureRootToken(options?: {
|
|
142
|
+
minValidityMs?: number;
|
|
143
|
+
}): Promise<TokenSet>;
|
|
144
|
+
/**
|
|
145
|
+
* The ONLY interactive entry point (ADR-0023): the root runtime requests a
|
|
146
|
+
* device code and, on `complete`, stores the result through the shared
|
|
147
|
+
* credential file's single writer (`setCached` under the refresh lock).
|
|
148
|
+
*/
|
|
149
|
+
beginDeviceSignIn(signal?: AbortSignal): Promise<DeviceSignIn>;
|
|
129
150
|
/**
|
|
130
151
|
* Drop the cached tokens for this identity: the exchanged project token
|
|
131
|
-
* entirely (its own exclusive store), and the shared root
|
|
132
|
-
*
|
|
133
|
-
*
|
|
134
|
-
* survive a lightbridge-side logout.
|
|
152
|
+
* entirely (its own exclusive store), and the shared root credential. The
|
|
153
|
+
* discovered-model record is a separate file in the cache root and is not
|
|
154
|
+
* touched, so oauth2's models survive a lightbridge-side logout.
|
|
135
155
|
*/
|
|
136
156
|
reset(): Promise<void>;
|
|
137
157
|
}
|
|
138
|
-
/** Absolute path to the lightbridge-exclusive (exchanged-token)
|
|
139
|
-
export declare function
|
|
140
|
-
/** Absolute path to the SHARED root-
|
|
158
|
+
/** Absolute path to the lightbridge-exclusive (exchanged-token) STATE directory. */
|
|
159
|
+
export declare function lightbridgeStateDir(stateRoot: string): string;
|
|
160
|
+
/** Absolute path to the SHARED root-credential STATE directory (ADR-0017, ADR-0022). */
|
|
161
|
+
export declare function rootStateDir(stateRoot: string): string;
|
|
162
|
+
/** Absolute path to the SHARED discovered-model CACHE directory (disposable; ADR-0022). */
|
|
141
163
|
export declare function rootCacheDir(cacheRoot: string): string;
|
package/dist/plugin.js
CHANGED
|
@@ -1,27 +1,30 @@
|
|
|
1
1
|
import { join } from "node:path";
|
|
2
|
-
import { createJsonConsoleLogger, DEFAULT_TOKEN_EXPIRY_SKEW_MS,
|
|
3
|
-
import {
|
|
4
|
-
import { migrateRootTokenIfNeeded } from "./migration.js";
|
|
2
|
+
import { createJsonConsoleLogger, DEFAULT_TOKEN_EXPIRY_SKEW_MS, resolveStateRoot, TokenRuntime } from "@vymalo/opencode-auth-core/lib";
|
|
3
|
+
import { ServerCredentialStore } from "@vymalo/opencode-provider-sync/lib";
|
|
5
4
|
/**
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* cache key has always been derived from this literal, independent of the
|
|
10
|
-
* configured IdP's `id`.
|
|
5
|
+
* Identity for the exchanged project-token store. Kept as a constant, not
|
|
6
|
+
* `auth.id`, because the exchanged-token key has always been derived from this
|
|
7
|
+
* literal, independent of the configured IdP's `id`.
|
|
11
8
|
*/
|
|
12
9
|
export const LIGHTBRIDGE_IDENTITY = "lightbridge";
|
|
13
|
-
/** Own cache namespace for the exchanged-token store — separate from oauth2/repo-auth/otel's. */
|
|
14
|
-
export const DEFAULT_CACHE_NAMESPACE = "opencode-lightbridge";
|
|
15
10
|
/**
|
|
16
|
-
*
|
|
11
|
+
* Own namespace for the exchanged-token store — separate from oauth2/repo-auth/
|
|
12
|
+
* otel's. It sits under the durable STATE root (ADR-0022): a project token is a
|
|
13
|
+
* credential, and is re-exchangeable only while the human root token survives.
|
|
14
|
+
*/
|
|
15
|
+
export const EXCHANGE_STATE_NAMESPACE = "opencode-lightbridge";
|
|
16
|
+
/**
|
|
17
|
+
* ADR-0017: the human ROOT token lives in the SAME credential file
|
|
17
18
|
* `@vymalo/opencode-oauth2` uses for a server of this id —
|
|
18
|
-
* `<
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
* same issuer/clientId) log in ONCE
|
|
22
|
-
* on-disk
|
|
23
|
-
* `@vymalo/opencode-oauth2`, which
|
|
24
|
-
* `docs/adr/0017-lightbridge-all-in-one.md`
|
|
19
|
+
* `<stateRoot>/opencode-oauth2/opencode-oauth2-model-sync/<id>.json`
|
|
20
|
+
* (ADR-0022 moved the root from the cache dir to the state dir; the relative
|
|
21
|
+
* path is unchanged). This is what lets a developer who configures the same
|
|
22
|
+
* IdP (`auth.id` == an oauth2 `servers[].id`, same issuer/clientId) log in ONCE
|
|
23
|
+
* and have both plugins read/write the same on-disk credential. The literals
|
|
24
|
+
* are pinned here (not imported from `@vymalo/opencode-oauth2`, which
|
|
25
|
+
* lightbridge does not depend on) — see `docs/adr/0017-lightbridge-all-in-one.md`
|
|
26
|
+
* for the shared-contract rationale. The discovered-model list for that server
|
|
27
|
+
* is a separate record in the CACHE root, owned by whichever engine syncs it.
|
|
25
28
|
*/
|
|
26
29
|
export const ROOT_CACHE_SEGMENT = "opencode-oauth2";
|
|
27
30
|
export const ROOT_CACHE_NAMESPACE = "opencode-oauth2-model-sync";
|
|
@@ -48,14 +51,19 @@ function isProjectTokenUsable(token, skewMs) {
|
|
|
48
51
|
}
|
|
49
52
|
/**
|
|
50
53
|
* Build the ONE shared root `TokenRuntime` for `serverId`, persisting through
|
|
51
|
-
* the SAME
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
* `ProviderModelSyncEngine.buildTokenRuntime
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
54
|
+
* the SAME credential record `ProviderModelSyncEngine` uses (see
|
|
55
|
+
* `ROOT_CACHE_SEGMENT`/`ROOT_CACHE_NAMESPACE` above) — mirroring the override
|
|
56
|
+
* pattern in `@vymalo/opencode-provider-sync`'s
|
|
57
|
+
* `ProviderModelSyncEngine.buildTokenRuntime`, but WITHOUT running that
|
|
58
|
+
* engine's scheduler/model-discovery — this is a read/refresh-only participant
|
|
59
|
+
* in the shared credential file, not a second poller (see ADR-0017's
|
|
60
|
+
* double-scheduling guard, enforced inside the engine itself for the `register`
|
|
61
|
+
* path). It never touches the model-cache record, so a lightbridge-side write
|
|
62
|
+
* can no longer clobber oauth2's discovered models.
|
|
63
|
+
*
|
|
64
|
+
* `stateDir` is the credential store's directory, so the cross-process refresh
|
|
65
|
+
* lock (`<stateDir>/locks/<id>.lock`) sits beside the token it guards and is
|
|
66
|
+
* the very lock oauth2's engine takes for the same id.
|
|
59
67
|
*
|
|
60
68
|
* Unlike `ProviderModelSyncEngine`, this performs no cross-process
|
|
61
69
|
* "adopt-if-newer" reconciliation — every `getCached()` call here reads disk
|
|
@@ -65,28 +73,22 @@ function isProjectTokenUsable(token, skewMs) {
|
|
|
65
73
|
* fallback), and refreshes are still coordinated via `TokenRuntime`'s own
|
|
66
74
|
* cross-process file lock.
|
|
67
75
|
*/
|
|
68
|
-
function buildSharedRootTokenRuntime(serverId, auth,
|
|
76
|
+
function buildSharedRootTokenRuntime(serverId, auth, credentials, options) {
|
|
69
77
|
return new TokenRuntime(serverId, auth, {
|
|
70
78
|
logger: options.logger,
|
|
71
79
|
fetchImpl: options.fetchImpl,
|
|
72
80
|
onAuthorizationUrl: options.onAuthorizationUrl,
|
|
73
81
|
tokenExpirySkewMs: options.tokenExpirySkewMs,
|
|
74
82
|
serviceLabel: "opencode-lightbridge",
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
return state?.token;
|
|
78
|
-
},
|
|
83
|
+
stateDir: credentials.directory,
|
|
84
|
+
getCached: async () => (await credentials.load(serverId))?.token,
|
|
79
85
|
setCached: async (token) => {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
rawModels: existing?.rawModels ?? [],
|
|
87
|
-
token
|
|
88
|
-
};
|
|
89
|
-
await sharedStore.saveServerState(next);
|
|
86
|
+
await credentials.save(serverId, token, Date.now());
|
|
87
|
+
},
|
|
88
|
+
// Compare-and-clear of a refresh token the IdP rejected is done by
|
|
89
|
+
// TokenRuntime under the lock; this only performs the removal.
|
|
90
|
+
clearCached: async () => {
|
|
91
|
+
await credentials.remove(serverId);
|
|
90
92
|
}
|
|
91
93
|
});
|
|
92
94
|
}
|
|
@@ -98,12 +100,11 @@ function buildSharedRootTokenRuntime(serverId, auth, sharedStore, options) {
|
|
|
98
100
|
* BOTH the gateway (`chat.headers`) and OTEL (`TokenSource.headers()`).
|
|
99
101
|
*
|
|
100
102
|
* The human root token itself is no longer lightbridge-exclusive storage: it
|
|
101
|
-
* lives in the SAME
|
|
102
|
-
* of this id (`ROOT_CACHE_SEGMENT`/`ROOT_CACHE_NAMESPACE
|
|
103
|
-
* both plugins against the same
|
|
104
|
-
* `servers[].id`, same issuer/clientId) means
|
|
105
|
-
*
|
|
106
|
-
* `migration.ts`.
|
|
103
|
+
* lives in the SAME credential file `@vymalo/opencode-oauth2` writes for a
|
|
104
|
+
* server of this id (`ROOT_CACHE_SEGMENT`/`ROOT_CACHE_NAMESPACE`, under the
|
|
105
|
+
* durable state root — ADR-0022), so configuring both plugins against the same
|
|
106
|
+
* IdP (`auth.id` matching an oauth2 `servers[].id`, same issuer/clientId) means
|
|
107
|
+
* logging in once.
|
|
107
108
|
*/
|
|
108
109
|
export class LightbridgeRuntime {
|
|
109
110
|
projectId;
|
|
@@ -113,21 +114,20 @@ export class LightbridgeRuntime {
|
|
|
113
114
|
logger;
|
|
114
115
|
tokenExpirySkewMs;
|
|
115
116
|
exchange;
|
|
116
|
-
|
|
117
|
+
stateRoot;
|
|
117
118
|
serverId;
|
|
118
119
|
/** Token-cache key: the project id, or `DEFAULT_PROJECT_KEY` when unset. */
|
|
119
120
|
projectKey;
|
|
120
121
|
inFlightExchange;
|
|
121
|
-
migration;
|
|
122
122
|
constructor(auth, projectId, options = {}) {
|
|
123
123
|
this.projectId = projectId;
|
|
124
124
|
this.serverId = auth.id;
|
|
125
125
|
this.projectKey = projectId ?? DEFAULT_PROJECT_KEY;
|
|
126
126
|
this.logger = options.logger ?? createJsonConsoleLogger("info");
|
|
127
127
|
this.exchange = options.exchange ?? false;
|
|
128
|
-
this.
|
|
128
|
+
this.stateRoot = options.stateDir ?? resolveStateRoot();
|
|
129
129
|
this.tokenExpirySkewMs = typeof options.tokenExpirySkewMs === "number" && Number.isFinite(options.tokenExpirySkewMs) && options.tokenExpirySkewMs > 0 ? options.tokenExpirySkewMs : DEFAULT_TOKEN_EXPIRY_SKEW_MS;
|
|
130
|
-
this.sharedStore = new
|
|
130
|
+
this.sharedStore = new ServerCredentialStore(rootStateDir(this.stateRoot), this.logger);
|
|
131
131
|
this.rootRuntime = buildSharedRootTokenRuntime(this.serverId, auth, this.sharedStore, options);
|
|
132
132
|
// The exchange-only runtime keeps its OWN dedicated, lightbridge-exclusive
|
|
133
133
|
// store (unchanged location/shape) — there is no oauth2 equivalent for a
|
|
@@ -136,27 +136,11 @@ export class LightbridgeRuntime {
|
|
|
136
136
|
logger: this.logger,
|
|
137
137
|
fetchImpl: options.fetchImpl,
|
|
138
138
|
onAuthorizationUrl: options.onAuthorizationUrl,
|
|
139
|
-
|
|
139
|
+
stateDir: lightbridgeStateDir(this.stateRoot),
|
|
140
140
|
tokenExpirySkewMs: this.tokenExpirySkewMs,
|
|
141
141
|
serviceLabel: "opencode-lightbridge"
|
|
142
142
|
});
|
|
143
143
|
}
|
|
144
|
-
/**
|
|
145
|
-
* One-time (per instance) migration of a pre-ADR-0017 root token into the
|
|
146
|
-
* shared cache file — see `migration.ts`. Idempotent and cheap on every
|
|
147
|
-
* call after the first (the underlying function also short-circuits once
|
|
148
|
-
* the new location has ANY state).
|
|
149
|
-
*/
|
|
150
|
-
ensureMigrated() {
|
|
151
|
-
if (!this.migration) {
|
|
152
|
-
this.migration = migrateRootTokenIfNeeded(this.cacheRoot, ROOT_CACHE_SEGMENT, ROOT_CACHE_NAMESPACE, this.serverId, this.logger).catch((error) => {
|
|
153
|
-
// Never fatal: worst case is a fresh login, same as a first-ever
|
|
154
|
-
// install. Swallow so a migration hiccup can't break normal auth.
|
|
155
|
-
this.logger.debug("lightbridge_root_migration_error", { error: error instanceof Error ? error.message : String(error) });
|
|
156
|
-
});
|
|
157
|
-
}
|
|
158
|
-
return this.migration;
|
|
159
|
-
}
|
|
160
144
|
/** Non-network read of the cached project token, if any. */
|
|
161
145
|
async getCachedProjectToken() {
|
|
162
146
|
return this.exchangeRuntime.getExchangedByKey(this.projectKey);
|
|
@@ -184,10 +168,9 @@ export class LightbridgeRuntime {
|
|
|
184
168
|
* invents a token: a failure propagates to the caller, which is expected to
|
|
185
169
|
* fail closed (no header / empty `headers()`).
|
|
186
170
|
*/
|
|
187
|
-
async getProjectToken(
|
|
188
|
-
await this.ensureMigrated();
|
|
171
|
+
async getProjectToken() {
|
|
189
172
|
if (!this.exchange) {
|
|
190
|
-
return this.rootRuntime.ensure({ interactive:
|
|
173
|
+
return this.rootRuntime.ensure({ interactive: false });
|
|
191
174
|
}
|
|
192
175
|
const cached = await this.getCachedProjectToken();
|
|
193
176
|
if (isProjectTokenUsable(cached, this.tokenExpirySkewMs)) {
|
|
@@ -198,7 +181,7 @@ export class LightbridgeRuntime {
|
|
|
198
181
|
if (this.inFlightExchange) {
|
|
199
182
|
return this.inFlightExchange;
|
|
200
183
|
}
|
|
201
|
-
const exchange = this.performExchange(
|
|
184
|
+
const exchange = this.performExchange();
|
|
202
185
|
this.inFlightExchange = exchange;
|
|
203
186
|
try {
|
|
204
187
|
return await exchange;
|
|
@@ -208,8 +191,8 @@ export class LightbridgeRuntime {
|
|
|
208
191
|
}
|
|
209
192
|
}
|
|
210
193
|
}
|
|
211
|
-
async performExchange(
|
|
212
|
-
const human = await this.rootRuntime.ensure({ interactive:
|
|
194
|
+
async performExchange() {
|
|
195
|
+
const human = await this.rootRuntime.ensure({ interactive: false });
|
|
213
196
|
this.logger.info("lightbridge_exchange_started", { projectId: this.projectId ?? "(default)" });
|
|
214
197
|
try {
|
|
215
198
|
// No `projectId` → send no `project_id` param; the backend mints a token
|
|
@@ -225,30 +208,41 @@ export class LightbridgeRuntime {
|
|
|
225
208
|
throw error;
|
|
226
209
|
}
|
|
227
210
|
}
|
|
211
|
+
/** See {@link LightbridgeRuntimeLike.ensureRootToken}. */
|
|
212
|
+
async ensureRootToken(options = {}) {
|
|
213
|
+
return this.rootRuntime.ensure({
|
|
214
|
+
interactive: false,
|
|
215
|
+
minValidityMs: options.minValidityMs
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* The ONLY interactive entry point (ADR-0023): the root runtime requests a
|
|
220
|
+
* device code and, on `complete`, stores the result through the shared
|
|
221
|
+
* credential file's single writer (`setCached` under the refresh lock).
|
|
222
|
+
*/
|
|
223
|
+
async beginDeviceSignIn(signal) {
|
|
224
|
+
return this.rootRuntime.beginDeviceSignIn(signal);
|
|
225
|
+
}
|
|
228
226
|
/**
|
|
229
227
|
* Drop the cached tokens for this identity: the exchanged project token
|
|
230
|
-
* entirely (its own exclusive store), and the shared root
|
|
231
|
-
*
|
|
232
|
-
*
|
|
233
|
-
* survive a lightbridge-side logout.
|
|
228
|
+
* entirely (its own exclusive store), and the shared root credential. The
|
|
229
|
+
* discovered-model record is a separate file in the cache root and is not
|
|
230
|
+
* touched, so oauth2's models survive a lightbridge-side logout.
|
|
234
231
|
*/
|
|
235
232
|
async reset() {
|
|
236
233
|
await this.exchangeRuntime.reset();
|
|
237
|
-
|
|
238
|
-
if (existing?.token) {
|
|
239
|
-
await this.sharedStore.saveServerState({
|
|
240
|
-
...existing,
|
|
241
|
-
updatedAt: Date.now(),
|
|
242
|
-
token: undefined
|
|
243
|
-
});
|
|
244
|
-
}
|
|
234
|
+
await this.sharedStore.remove(this.serverId);
|
|
245
235
|
}
|
|
246
236
|
}
|
|
247
|
-
/** Absolute path to the lightbridge-exclusive (exchanged-token)
|
|
248
|
-
export function
|
|
249
|
-
return join(
|
|
237
|
+
/** Absolute path to the lightbridge-exclusive (exchanged-token) STATE directory. */
|
|
238
|
+
export function lightbridgeStateDir(stateRoot) {
|
|
239
|
+
return join(stateRoot, EXCHANGE_STATE_NAMESPACE);
|
|
240
|
+
}
|
|
241
|
+
/** Absolute path to the SHARED root-credential STATE directory (ADR-0017, ADR-0022). */
|
|
242
|
+
export function rootStateDir(stateRoot) {
|
|
243
|
+
return join(stateRoot, ROOT_CACHE_SEGMENT, ROOT_CACHE_NAMESPACE);
|
|
250
244
|
}
|
|
251
|
-
/** Absolute path to the SHARED
|
|
245
|
+
/** Absolute path to the SHARED discovered-model CACHE directory (disposable; ADR-0022). */
|
|
252
246
|
export function rootCacheDir(cacheRoot) {
|
|
253
247
|
return join(cacheRoot, ROOT_CACHE_SEGMENT, ROOT_CACHE_NAMESPACE);
|
|
254
248
|
}
|
package/dist/plugin.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"mappings":"AAAA,SAAS,YAAY;AAErB,SACE,yBACA,8BACA,kBACA,
|
|
1
|
+
{"mappings":"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","names":[],"sources":["../src/plugin.ts"],"version":3,"file":"plugin.js","sourceRoot":""}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import type { Credential, Plugin } from "@opencode/plugin/effect";
|
|
2
|
+
import { type TokenSet } from "@vymalo/opencode-auth-core/lib";
|
|
3
|
+
import type { Logger } from "./logging.js";
|
|
4
|
+
import type { LightbridgeRuntimeLike } from "./plugin.js";
|
|
5
|
+
type IntegrationEditor = Parameters<Parameters<Plugin.Context["integration"]["transform"]>[0]>[0];
|
|
6
|
+
/** The host's oauth-method registration shape (the package does not export it by name). */
|
|
7
|
+
export type IntegrationOAuthMethodRegistration = Extract<Parameters<IntegrationEditor["method"]["update"]>[0], {
|
|
8
|
+
method: {
|
|
9
|
+
type: "oauth";
|
|
10
|
+
};
|
|
11
|
+
}>;
|
|
12
|
+
/** Id of the one sign-in method lightbridge registers on its integration (ADR-0023). */
|
|
13
|
+
export declare const SIGN_IN_METHOD_ID = "device";
|
|
14
|
+
/** Label of the button the host renders for that method. */
|
|
15
|
+
export declare const SIGN_IN_METHOD_LABEL = "Sign in";
|
|
16
|
+
/** The host calls a method's `refresh` once the credential is within this of `expires`. */
|
|
17
|
+
export declare const HOST_REFRESH_WINDOW_MS: number;
|
|
18
|
+
/** The exact path a user follows to sign in, for the `lightbridge_sign_in_required` hint. */
|
|
19
|
+
export declare function signInPath(name: string): string;
|
|
20
|
+
/**
|
|
21
|
+
* Display-only account label (email / username) read from the access token's
|
|
22
|
+
* claims. Deliberately UNVERIFIED: nothing security-relevant ever reads it, it
|
|
23
|
+
* only decorates the host's connection row. Opaque (non-JWT) tokens and any
|
|
24
|
+
* decoding problem yield `undefined`.
|
|
25
|
+
*/
|
|
26
|
+
export declare function accountLabel(accessToken: string): string | undefined;
|
|
27
|
+
/**
|
|
28
|
+
* The host-side projection of our token: a "connected" marker plus the current
|
|
29
|
+
* access token. CUSTODY RULE (ADR-0023): `refresh` is ALWAYS `""` — the refresh
|
|
30
|
+
* token never leaves lightbridge's own state file, so a host credential-store
|
|
31
|
+
* leak or a host-driven refresh cannot replay (and thereby rotate away) it.
|
|
32
|
+
*/
|
|
33
|
+
export declare function projectCredential(token: TokenSet, now?: number): Credential.OAuth;
|
|
34
|
+
export interface SignInDependencies {
|
|
35
|
+
integrationID: string;
|
|
36
|
+
runtime: LightbridgeRuntimeLike;
|
|
37
|
+
logger: Logger;
|
|
38
|
+
/**
|
|
39
|
+
* Runs after the projection was handed back (kick the model sync, reload the
|
|
40
|
+
* host's providers). Detached: the dialog closes without waiting for it, and
|
|
41
|
+
* a failure or a late interrupt cannot undo the sign-in.
|
|
42
|
+
*/
|
|
43
|
+
afterSignIn: () => Promise<void>;
|
|
44
|
+
/** Called synchronously on a successful sign-in (re-arms the sign-in notice). */
|
|
45
|
+
onSignedIn?: () => void;
|
|
46
|
+
/** Called when a sign-in-related call finds no usable token (refresh-only failure). */
|
|
47
|
+
onSignInRequired?: (source: string) => void;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* The oauth method registration behind the host's "Connect" dialog (ADR-0023).
|
|
51
|
+
* `authorize` requests a device code and hands the host the URL + code to show;
|
|
52
|
+
* `callback` awaits the user's approval (interruptible: the host closing the
|
|
53
|
+
* dialog interrupts it, which aborts the polling) and returns the projection.
|
|
54
|
+
*/
|
|
55
|
+
export declare function createSignInRegistration(deps: SignInDependencies): IntegrationOAuthMethodRegistration;
|
|
56
|
+
export interface SignInNotice {
|
|
57
|
+
/** Warn (once until re-armed) that sign-in is needed; always records the source at debug. */
|
|
58
|
+
notify(source: string): void;
|
|
59
|
+
/** Re-arm: the next `notify` warns again (after a sign-in, or a host disconnect). */
|
|
60
|
+
reset(): void;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Emit `lightbridge_sign_in_required` at most once per arming, naming the exact
|
|
64
|
+
* path to sign in. Every non-interactive caller that finds no usable token
|
|
65
|
+
* (startup check, gateway header, OTEL token source, the register sync) reports
|
|
66
|
+
* through this one latch; each call is also recorded at `debug` as
|
|
67
|
+
* `lightbridge_sign_in_required_seen` so the sources stay observable.
|
|
68
|
+
*/
|
|
69
|
+
export declare function createSignInRequiredNotifier(logger: Logger, name: string): SignInNotice;
|
|
70
|
+
export {};
|
package/dist/sign-in.js
ADDED
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { isInteractiveAuthRequiredError } from "@vymalo/opencode-auth-core/lib";
|
|
2
|
+
import { Effect } from "effect";
|
|
3
|
+
/** Id of the one sign-in method lightbridge registers on its integration (ADR-0023). */
|
|
4
|
+
export const SIGN_IN_METHOD_ID = "device";
|
|
5
|
+
/** Label of the button the host renders for that method. */
|
|
6
|
+
export const SIGN_IN_METHOD_LABEL = "Sign in";
|
|
7
|
+
/** Fallback lifetime for a token the IdP gave no `expires_in` for. */
|
|
8
|
+
const FALLBACK_LIFETIME_MS = 60 * 60 * 1e3;
|
|
9
|
+
const MAX_LABEL_CHARS = 80;
|
|
10
|
+
/** The host calls a method's `refresh` once the credential is within this of `expires`. */
|
|
11
|
+
export const HOST_REFRESH_WINDOW_MS = 5 * 60 * 1e3;
|
|
12
|
+
/** The exact path a user follows to sign in, for the `lightbridge_sign_in_required` hint. */
|
|
13
|
+
export function signInPath(name) {
|
|
14
|
+
return `Settings → Providers → Show more providers → (Integrations dialog) search "${name}" → Sign in`;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Display-only account label (email / username) read from the access token's
|
|
18
|
+
* claims. Deliberately UNVERIFIED: nothing security-relevant ever reads it, it
|
|
19
|
+
* only decorates the host's connection row. Opaque (non-JWT) tokens and any
|
|
20
|
+
* decoding problem yield `undefined`.
|
|
21
|
+
*/
|
|
22
|
+
export function accountLabel(accessToken) {
|
|
23
|
+
const parts = accessToken.split(".");
|
|
24
|
+
if (parts.length !== 3 || !parts[1]) {
|
|
25
|
+
return undefined;
|
|
26
|
+
}
|
|
27
|
+
try {
|
|
28
|
+
const claims = JSON.parse(Buffer.from(parts[1], "base64url").toString("utf8"));
|
|
29
|
+
for (const key of ["email", "preferred_username"]) {
|
|
30
|
+
const value = claims[key];
|
|
31
|
+
if (typeof value === "string" && value.trim().length > 0) {
|
|
32
|
+
return value.trim().slice(0, MAX_LABEL_CHARS);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
} catch {}
|
|
36
|
+
return undefined;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* The host-side projection of our token: a "connected" marker plus the current
|
|
40
|
+
* access token. CUSTODY RULE (ADR-0023): `refresh` is ALWAYS `""` — the refresh
|
|
41
|
+
* token never leaves lightbridge's own state file, so a host credential-store
|
|
42
|
+
* leak or a host-driven refresh cannot replay (and thereby rotate away) it.
|
|
43
|
+
*/
|
|
44
|
+
export function projectCredential(token, now = Date.now()) {
|
|
45
|
+
const label = accountLabel(token.accessToken);
|
|
46
|
+
return {
|
|
47
|
+
type: "oauth",
|
|
48
|
+
methodID: SIGN_IN_METHOD_ID,
|
|
49
|
+
access: token.accessToken,
|
|
50
|
+
refresh: "",
|
|
51
|
+
expires: Math.floor(token.expiresAt ?? now + FALLBACK_LIFETIME_MS),
|
|
52
|
+
...label ? { metadata: { label } } : {}
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* The oauth method registration behind the host's "Connect" dialog (ADR-0023).
|
|
57
|
+
* `authorize` requests a device code and hands the host the URL + code to show;
|
|
58
|
+
* `callback` awaits the user's approval (interruptible: the host closing the
|
|
59
|
+
* dialog interrupts it, which aborts the polling) and returns the projection.
|
|
60
|
+
*/
|
|
61
|
+
export function createSignInRegistration(deps) {
|
|
62
|
+
const { integrationID, runtime, logger } = deps;
|
|
63
|
+
return {
|
|
64
|
+
integrationID,
|
|
65
|
+
method: {
|
|
66
|
+
id: SIGN_IN_METHOD_ID,
|
|
67
|
+
type: "oauth",
|
|
68
|
+
label: SIGN_IN_METHOD_LABEL
|
|
69
|
+
},
|
|
70
|
+
authorize: () => Effect.tryPromise({
|
|
71
|
+
// The effect's signal aborts when the host abandons the attempt, which
|
|
72
|
+
// also cancels the device-authorization request.
|
|
73
|
+
try: (signal) => runtime.beginDeviceSignIn(signal),
|
|
74
|
+
catch: (error) => error
|
|
75
|
+
}).pipe(Effect.tapError((error) => Effect.sync(() => logger.error("lightbridge_sign_in_begin_failed", errorFields(error)))), Effect.map((session) => ({
|
|
76
|
+
url: session.verificationUriComplete ?? session.verificationUri,
|
|
77
|
+
instructions: `Confirm the code ${session.userCode} on the page that opens, then approve the request.`,
|
|
78
|
+
expiresAt: session.expiresAt,
|
|
79
|
+
mode: "auto",
|
|
80
|
+
callback: Effect.tryPromise({
|
|
81
|
+
try: (signal) => session.complete(signal),
|
|
82
|
+
catch: (error) => error
|
|
83
|
+
}).pipe(Effect.tapError((error) => Effect.sync(() => logger.warn("lightbridge_sign_in_failed", errorFields(error)))), Effect.onInterrupt(() => Effect.sync(() => logger.info("lightbridge_sign_in_cancelled", { integrationID }))), Effect.map((token) => {
|
|
84
|
+
logger.info("lightbridge_sign_in_completed", { integrationID });
|
|
85
|
+
deps.onSignedIn?.();
|
|
86
|
+
// Detached on purpose (see `afterSignIn`).
|
|
87
|
+
void (async () => {
|
|
88
|
+
try {
|
|
89
|
+
await deps.afterSignIn();
|
|
90
|
+
} catch (error) {
|
|
91
|
+
logger.warn("lightbridge_sign_in_followup_failed", errorFields(error));
|
|
92
|
+
}
|
|
93
|
+
})();
|
|
94
|
+
return projectCredential(token);
|
|
95
|
+
}))
|
|
96
|
+
}))),
|
|
97
|
+
// The host calls this within HOST_REFRESH_WINDOW_MS of `expires`. Whatever it
|
|
98
|
+
// holds is ignored (it has no refresh token): the truth is our own runtime,
|
|
99
|
+
// forced to a real, non-interactive refresh through the single writer. A
|
|
100
|
+
// revoked/cleared root fails here - it never starts a flow.
|
|
101
|
+
refresh: () => Effect.tryPromise({
|
|
102
|
+
try: () => runtime.ensureRootToken({ minValidityMs: HOST_REFRESH_WINDOW_MS }),
|
|
103
|
+
catch: (error) => error
|
|
104
|
+
}).pipe(Effect.tapError((error) => Effect.sync(() => {
|
|
105
|
+
logger.warn("lightbridge_sign_in_refresh_failed", errorFields(error));
|
|
106
|
+
if (isInteractiveAuthRequiredError(error)) {
|
|
107
|
+
deps.onSignInRequired?.("refresh");
|
|
108
|
+
}
|
|
109
|
+
})), Effect.tap((token) => Effect.sync(() => {
|
|
110
|
+
// A refresh that "succeeds" with a token still inside the window means
|
|
111
|
+
// the refresh itself failed and we served what was left.
|
|
112
|
+
if (token.expiresAt !== undefined && token.expiresAt - Date.now() <= HOST_REFRESH_WINDOW_MS) {
|
|
113
|
+
logger.warn("lightbridge_sign_in_refresh_failed", { error: "refresh returned a token still inside the host refresh window" });
|
|
114
|
+
}
|
|
115
|
+
})), Effect.map((token) => projectCredential(token))),
|
|
116
|
+
label: (credential) => {
|
|
117
|
+
const label = credential.metadata?.label;
|
|
118
|
+
return typeof label === "string" ? label : undefined;
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
function errorFields(error) {
|
|
123
|
+
return { error: error instanceof Error ? error.message : String(error) };
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Emit `lightbridge_sign_in_required` at most once per arming, naming the exact
|
|
127
|
+
* path to sign in. Every non-interactive caller that finds no usable token
|
|
128
|
+
* (startup check, gateway header, OTEL token source, the register sync) reports
|
|
129
|
+
* through this one latch; each call is also recorded at `debug` as
|
|
130
|
+
* `lightbridge_sign_in_required_seen` so the sources stay observable.
|
|
131
|
+
*/
|
|
132
|
+
export function createSignInRequiredNotifier(logger, name) {
|
|
133
|
+
let notified = false;
|
|
134
|
+
return {
|
|
135
|
+
notify(source) {
|
|
136
|
+
logger.debug("lightbridge_sign_in_required_seen", { source });
|
|
137
|
+
if (notified) {
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
notified = true;
|
|
141
|
+
logger.warn("lightbridge_sign_in_required", {
|
|
142
|
+
source,
|
|
143
|
+
message: `lightbridge is not signed in: open ${signInPath(name)}`
|
|
144
|
+
});
|
|
145
|
+
},
|
|
146
|
+
reset() {
|
|
147
|
+
notified = false;
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
//# sourceMappingURL=sign-in.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"mappings":"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","names":[],"sources":["../src/sign-in.ts"],"version":3,"file":"sign-in.js","sourceRoot":""}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vymalo/opencode-lightbridge",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.20.0",
|
|
4
4
|
"description": "Umbrella OpenCode plugin for ADR-0012: one shared credential (TokenRuntime) drives both the LLM gateway bearer and OTEL export, so a developer authenticates once and every egress rides the same project-scoped token.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "vymalo contributors",
|
|
@@ -54,9 +54,9 @@
|
|
|
54
54
|
"@opentelemetry/api": "^1.9.1",
|
|
55
55
|
"@opentelemetry/api-logs": "^0.222.0",
|
|
56
56
|
"@opentelemetry/core": "^2.11.0",
|
|
57
|
-
"@vymalo/opencode-auth-core": "0.
|
|
58
|
-
"@vymalo/opencode-provider-sync": "0.
|
|
59
|
-
"@vymalo/opencode-core-otel": "0.
|
|
57
|
+
"@vymalo/opencode-auth-core": "0.20.0",
|
|
58
|
+
"@vymalo/opencode-provider-sync": "0.20.0",
|
|
59
|
+
"@vymalo/opencode-core-otel": "0.20.0"
|
|
60
60
|
},
|
|
61
61
|
"devDependencies": {
|
|
62
62
|
"@opentelemetry/sdk-logs": "^0.222.0",
|
package/dist/migration.d.ts
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { type Logger } from "@vymalo/opencode-auth-core/lib";
|
|
2
|
-
/**
|
|
3
|
-
* One-time migration read-path (ADR-0017, mandatory — not optional polish).
|
|
4
|
-
*
|
|
5
|
-
* v0.17 moves lightbridge's human root token from its own bespoke file
|
|
6
|
-
* (`<cacheRoot>/opencode-lightbridge/lightbridge.json`, a bare `TokenSet`) to
|
|
7
|
-
* the SAME fused `CachedServerState` file `@vymalo/opencode-oauth2` uses
|
|
8
|
-
* (`<cacheRoot>/<sharedSegment>/<sharedNamespace>/<serverId>.json`) so the two
|
|
9
|
-
* plugins can share one login (ADR-0017 §"one login, shared cache"). An
|
|
10
|
-
* install that already has a valid old-format token must NOT be forced
|
|
11
|
-
* through a fresh device-code/browser login just because the file moved.
|
|
12
|
-
*
|
|
13
|
-
* Behaviour:
|
|
14
|
-
* - If the NEW location already has a persisted state (with or without a
|
|
15
|
-
* token), this is a no-op — never clobbers a fresher state (e.g. one
|
|
16
|
-
* oauth2 has already been writing to, with real discovered models).
|
|
17
|
-
* - Else, read the OLD location. If it holds a structurally usable token
|
|
18
|
-
* (`accessToken` + `tokenType` present — possibly expired; an expired
|
|
19
|
-
* token with a refresh token is still worth adopting, since `TokenRuntime`
|
|
20
|
-
* will refresh it transparently), write it into the NEW location as a
|
|
21
|
-
* fresh `CachedServerState` (empty `models`/`rawModels` — nothing to carry
|
|
22
|
-
* over, since the old shape never tracked models).
|
|
23
|
-
* - Else (no old file, or it's empty/malformed) this is a no-op; the caller
|
|
24
|
-
* proceeds to a normal login.
|
|
25
|
-
*
|
|
26
|
-
* The old file is left in place (non-destructive) — this function only ever
|
|
27
|
-
* ADDS the new file, never deletes/mutates the old one. Safe to call more
|
|
28
|
-
* than once: the "new location already has a state" check makes every call
|
|
29
|
-
* after the first a cheap no-op.
|
|
30
|
-
*/
|
|
31
|
-
export declare function migrateRootTokenIfNeeded(cacheRoot: string, sharedSegment: string, sharedNamespace: string, serverId: string, logger: Logger): Promise<void>;
|
package/dist/migration.js
DELETED
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
import { join } from "node:path";
|
|
2
|
-
import { FileCacheStore as LegacyFileCacheStore } from "@vymalo/opencode-auth-core/lib";
|
|
3
|
-
import { FileCacheStore as SharedFileCacheStore } from "@vymalo/opencode-provider-sync/lib";
|
|
4
|
-
/**
|
|
5
|
-
* The pre-ADR-0017 on-disk location of lightbridge's human root token:
|
|
6
|
-
* `<cacheRoot>/opencode-lightbridge/lightbridge.json`, a bare `TokenSet`
|
|
7
|
-
* (see the OLD `LIGHTBRIDGE_IDENTITY`/`DEFAULT_CACHE_NAMESPACE` in `plugin.ts`,
|
|
8
|
-
* which are still used verbatim for the exchanged project-token store — only
|
|
9
|
-
* the ROOT token relocated).
|
|
10
|
-
*/
|
|
11
|
-
const OLD_ROOT_CACHE_NAMESPACE = "opencode-lightbridge";
|
|
12
|
-
const OLD_ROOT_KEY = "lightbridge";
|
|
13
|
-
function hasUsableTokenShape(value) {
|
|
14
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
15
|
-
return false;
|
|
16
|
-
}
|
|
17
|
-
const candidate = value;
|
|
18
|
-
return typeof candidate.accessToken === "string" && candidate.accessToken.length > 0 && typeof candidate.tokenType === "string" && candidate.tokenType.length > 0;
|
|
19
|
-
}
|
|
20
|
-
/**
|
|
21
|
-
* One-time migration read-path (ADR-0017, mandatory — not optional polish).
|
|
22
|
-
*
|
|
23
|
-
* v0.17 moves lightbridge's human root token from its own bespoke file
|
|
24
|
-
* (`<cacheRoot>/opencode-lightbridge/lightbridge.json`, a bare `TokenSet`) to
|
|
25
|
-
* the SAME fused `CachedServerState` file `@vymalo/opencode-oauth2` uses
|
|
26
|
-
* (`<cacheRoot>/<sharedSegment>/<sharedNamespace>/<serverId>.json`) so the two
|
|
27
|
-
* plugins can share one login (ADR-0017 §"one login, shared cache"). An
|
|
28
|
-
* install that already has a valid old-format token must NOT be forced
|
|
29
|
-
* through a fresh device-code/browser login just because the file moved.
|
|
30
|
-
*
|
|
31
|
-
* Behaviour:
|
|
32
|
-
* - If the NEW location already has a persisted state (with or without a
|
|
33
|
-
* token), this is a no-op — never clobbers a fresher state (e.g. one
|
|
34
|
-
* oauth2 has already been writing to, with real discovered models).
|
|
35
|
-
* - Else, read the OLD location. If it holds a structurally usable token
|
|
36
|
-
* (`accessToken` + `tokenType` present — possibly expired; an expired
|
|
37
|
-
* token with a refresh token is still worth adopting, since `TokenRuntime`
|
|
38
|
-
* will refresh it transparently), write it into the NEW location as a
|
|
39
|
-
* fresh `CachedServerState` (empty `models`/`rawModels` — nothing to carry
|
|
40
|
-
* over, since the old shape never tracked models).
|
|
41
|
-
* - Else (no old file, or it's empty/malformed) this is a no-op; the caller
|
|
42
|
-
* proceeds to a normal login.
|
|
43
|
-
*
|
|
44
|
-
* The old file is left in place (non-destructive) — this function only ever
|
|
45
|
-
* ADDS the new file, never deletes/mutates the old one. Safe to call more
|
|
46
|
-
* than once: the "new location already has a state" check makes every call
|
|
47
|
-
* after the first a cheap no-op.
|
|
48
|
-
*/
|
|
49
|
-
export async function migrateRootTokenIfNeeded(cacheRoot, sharedSegment, sharedNamespace, serverId, logger) {
|
|
50
|
-
const sharedStore = new SharedFileCacheStore(join(cacheRoot, sharedSegment, sharedNamespace), logger);
|
|
51
|
-
let alreadyMigrated;
|
|
52
|
-
try {
|
|
53
|
-
alreadyMigrated = await sharedStore.loadServerState(serverId);
|
|
54
|
-
} catch (error) {
|
|
55
|
-
logger.debug("lightbridge_root_migration_check_failed", { error: error instanceof Error ? error.message : String(error) });
|
|
56
|
-
return;
|
|
57
|
-
}
|
|
58
|
-
if (alreadyMigrated) {
|
|
59
|
-
// New location already has SOME state (with or without a token) — either
|
|
60
|
-
// a previous migration ran, or oauth2/register already populated it.
|
|
61
|
-
// Never overwrite it from the old file.
|
|
62
|
-
return;
|
|
63
|
-
}
|
|
64
|
-
const legacyStore = new LegacyFileCacheStore(join(cacheRoot, OLD_ROOT_CACHE_NAMESPACE), logger);
|
|
65
|
-
let legacyToken;
|
|
66
|
-
try {
|
|
67
|
-
legacyToken = await legacyStore.load(OLD_ROOT_KEY);
|
|
68
|
-
} catch (error) {
|
|
69
|
-
logger.debug("lightbridge_root_migration_legacy_read_failed", { error: error instanceof Error ? error.message : String(error) });
|
|
70
|
-
return;
|
|
71
|
-
}
|
|
72
|
-
if (!hasUsableTokenShape(legacyToken)) {
|
|
73
|
-
logger.trace("lightbridge_root_migration_nothing_to_adopt", { serverId });
|
|
74
|
-
return;
|
|
75
|
-
}
|
|
76
|
-
const migrated = {
|
|
77
|
-
serverId,
|
|
78
|
-
updatedAt: Date.now(),
|
|
79
|
-
models: [],
|
|
80
|
-
rawModels: [],
|
|
81
|
-
token: legacyToken
|
|
82
|
-
};
|
|
83
|
-
await sharedStore.ensureReady();
|
|
84
|
-
await sharedStore.saveServerState(migrated);
|
|
85
|
-
logger.info("lightbridge_root_migration_adopted", {
|
|
86
|
-
serverId,
|
|
87
|
-
hadRefreshToken: Boolean(legacyToken.refreshToken)
|
|
88
|
-
});
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
//# sourceMappingURL=migration.js.map
|
package/dist/migration.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"mappings":"AAAA,SAAS,YAAY;AAErB,SACE,kBAAkB,4BAGb;AACP,SACE,kBAAkB,4BAEb;;;;;;;;AASP,MAAM,2BAA2B;AACjC,MAAM,eAAe;AAErB,SAAS,oBAAoB,OAAmC;CAC9D,IAAI,CAAC,SAAS,OAAO,UAAU,YAAY,MAAM,QAAQ,KAAK,GAAG;EAC/D,OAAO;CACT;CACA,MAAM,YAAY;CAClB,OACE,OAAO,UAAU,gBAAgB,YACjC,UAAU,YAAY,SAAS,KAC/B,OAAO,UAAU,cAAc,YAC/B,UAAU,UAAU,SAAS;AAEjC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+BA,OAAO,eAAe,yBACpB,WACA,eACA,iBACA,UACA,QACe;CACf,MAAM,cAAc,IAAI,qBACtB,KAAK,WAAW,eAAe,eAAe,GAC9C,MACF;CAEA,IAAI;CACJ,IAAI;EACF,kBAAkB,MAAM,YAAY,gBAAgB,QAAQ;CAC9D,SAAS,OAAO;EACd,OAAO,MAAM,2CAA2C,EACtD,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,EAC9D,CAAC;EACD;CACF;CACA,IAAI,iBAAiB;;;;EAInB;CACF;CAEA,MAAM,cAAc,IAAI,qBAAqB,KAAK,WAAW,wBAAwB,GAAG,MAAM;CAC9F,IAAI;CACJ,IAAI;EACF,cAAc,MAAM,YAAY,KAAe,YAAY;CAC7D,SAAS,OAAO;EACd,OAAO,MAAM,iDAAiD,EAC5D,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,EAC9D,CAAC;EACD;CACF;CAEA,IAAI,CAAC,oBAAoB,WAAW,GAAG;EACrC,OAAO,MAAM,+CAA+C,EAAE,SAAS,CAAC;EACxE;CACF;CAEA,MAAM,WAA8B;EAClC;EACA,WAAW,KAAK,IAAI;EACpB,QAAQ,CAAC;EACT,WAAW,CAAC;EACZ,OAAO;CACT;CAEA,MAAM,YAAY,YAAY;CAC9B,MAAM,YAAY,gBAAgB,QAAQ;CAC1C,OAAO,KAAK,sCAAsC;EAChD;EACA,iBAAiB,QAAQ,YAAY,YAAY;CACnD,CAAC;AACH","names":[],"sources":["../src/migration.ts"],"version":3,"file":"migration.js","sourceRoot":""}
|