@vymalo/opencode-lightbridge 0.16.1 → 0.18.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/dist/plugin.js CHANGED
@@ -1,13 +1,31 @@
1
1
  import { join } from "node:path";
2
2
  import { createJsonConsoleLogger, DEFAULT_TOKEN_EXPIRY_SKEW_MS, resolveCacheRoot, TokenRuntime } from "@vymalo/opencode-auth-core/lib";
3
+ import { FileCacheStore as SharedFileCacheStore } from "@vymalo/opencode-provider-sync/lib";
4
+ import { migrateRootTokenIfNeeded } from "./migration.js";
3
5
  /**
4
- * Identity for the umbrella's single `TokenRuntime` (ADR-0012). Constant
5
- * because v1 is single-IdP, same rationale as repo-auth's `HUMAN_IDENTITY`.
6
+ * Legacy identity for the exchanged project-token store (UNCHANGED by
7
+ * ADR-0017 — see `migration.ts`'s module doc for why only the ROOT token
8
+ * relocated). Kept as a constant, not `auth.id`, because the exchanged-token
9
+ * cache key has always been derived from this literal, independent of the
10
+ * configured IdP's `id`.
6
11
  */
7
12
  export const LIGHTBRIDGE_IDENTITY = "lightbridge";
8
- /** Own cache namespace — separate from oauth2/repo-auth/otel's stores. */
13
+ /** Own cache namespace for the exchanged-token store — separate from oauth2/repo-auth/otel's. */
9
14
  export const DEFAULT_CACHE_NAMESPACE = "opencode-lightbridge";
10
15
  /**
16
+ * ADR-0017: the human ROOT token now lives in the SAME cache file
17
+ * `@vymalo/opencode-oauth2` uses for a server of this id —
18
+ * `<cacheRoot>/opencode-oauth2/opencode-oauth2-model-sync/<id>.json`, a fused
19
+ * `CachedServerState` (token + discovered models). This is what lets a
20
+ * developer who configures the same IdP (`auth.id` == an oauth2 `servers[].id`,
21
+ * same issuer/clientId) log in ONCE and have both plugins read/write the same
22
+ * on-disk state. The literals are pinned here (not imported from
23
+ * `@vymalo/opencode-oauth2`, which lightbridge does not depend on) — see
24
+ * `docs/adr/0017-lightbridge-all-in-one.md` for the shared-contract rationale.
25
+ */
26
+ export const ROOT_CACHE_SEGMENT = "opencode-oauth2";
27
+ export const ROOT_CACHE_NAMESPACE = "opencode-oauth2-model-sync";
28
+ /**
11
29
  * Cache key for the default-project token — used when no `projectId` is
12
30
  * configured, so the exchange sends no `project_id` and the backend mints a
13
31
  * token for the caller's default project (ADR-0012). Distinct from any real
@@ -15,10 +33,9 @@ export const DEFAULT_CACHE_NAMESPACE = "opencode-lightbridge";
15
33
  */
16
34
  export const DEFAULT_PROJECT_KEY = "__default__";
17
35
  /**
18
- * Whether a cached project token is usable. Mirrors repo-auth's
19
- * `isProjectTokenUsable`: the project token carries no refresh token, so an
20
- * undefined `expiresAt` must be treated as expired (re-exchange), never as
21
- * non-expiring.
36
+ * Whether a cached project token is usable. The project token carries no
37
+ * refresh token, so an undefined `expiresAt` must be treated as expired
38
+ * (re-exchange), never as non-expiring.
22
39
  */
23
40
  function isProjectTokenUsable(token, skewMs) {
24
41
  if (!token?.accessToken) {
@@ -30,59 +47,148 @@ function isProjectTokenUsable(token, skewMs) {
30
47
  return Date.now() + skewMs < token.expiresAt;
31
48
  }
32
49
  /**
33
- * The ONE shared `TokenRuntime` the umbrella plugin builds (ADR-0012): a
34
- * single human login, reused as the subject token for a project-scoped RFC
35
- * 8693 exchange whose result is consumed by BOTH the gateway (`chat.headers`)
36
- * and OTEL (`TokenSource.headers()`) — that sharing is the entire point of
37
- * the plugin. Lifecycle mirrors `@vymalo/opencode-repo-auth`'s "model b"
38
- * (`RepoAuthPlugin.resolveProjectToken`): auth-core has no higher-level
39
- * primitive for this yet, so the umbrella keeps its own thin copy rather than
40
- * reaching into a sibling package's internals.
50
+ * Build the ONE shared root `TokenRuntime` for `serverId`, persisting through
51
+ * the SAME fused `CachedServerState` shape+location `ProviderModelSyncEngine`
52
+ * uses (see `ROOT_CACHE_SEGMENT`/`ROOT_CACHE_NAMESPACE` above) — mirroring the
53
+ * override pattern in `@vymalo/opencode-provider-sync`'s
54
+ * `ProviderModelSyncEngine.buildTokenRuntime` (extract `.token`, preserve
55
+ * `.models`/`.rawModels` on write) but WITHOUT running that engine's
56
+ * scheduler/model-discovery — this is a read/refresh-only participant in the
57
+ * shared cache file, not a second poller (see ADR-0017's double-scheduling
58
+ * guard, enforced inside the engine itself for the `register` path).
59
+ *
60
+ * Unlike `ProviderModelSyncEngine`, this performs no cross-process
61
+ * "adopt-if-newer" reconciliation — every `getCached()` call here reads disk
62
+ * fresh and takes it as-is. That is deliberately simpler (no in-memory
63
+ * snapshot to reconcile against) and still safe: a momentarily unreadable/
64
+ * missing file degrades to "no cached token" (a safe, if suboptimal,
65
+ * fallback), and refreshes are still coordinated via `TokenRuntime`'s own
66
+ * cross-process file lock.
67
+ */
68
+ function buildSharedRootTokenRuntime(serverId, auth, sharedStore, options) {
69
+ return new TokenRuntime(serverId, auth, {
70
+ logger: options.logger,
71
+ fetchImpl: options.fetchImpl,
72
+ onAuthorizationUrl: options.onAuthorizationUrl,
73
+ tokenExpirySkewMs: options.tokenExpirySkewMs,
74
+ serviceLabel: "opencode-lightbridge",
75
+ getCached: async () => {
76
+ const state = await sharedStore.loadServerState(serverId);
77
+ return state?.token;
78
+ },
79
+ setCached: async (token) => {
80
+ const existing = await sharedStore.loadServerState(serverId);
81
+ const next = {
82
+ serverId,
83
+ updatedAt: Date.now(),
84
+ lastSyncAt: existing?.lastSyncAt,
85
+ models: existing?.models ?? [],
86
+ rawModels: existing?.rawModels ?? [],
87
+ token
88
+ };
89
+ await sharedStore.saveServerState(next);
90
+ }
91
+ });
92
+ }
93
+ /**
94
+ * The ONE shared runtime the umbrella plugin builds (ADR-0012, amended by
95
+ * ADR-0017): a single human login, reused as the subject token for a
96
+ * project-scoped RFC 8693 exchange (when `gateway.exchange` is `true`) or
97
+ * used directly as the gateway/OTEL bearer (the new default) — consumed by
98
+ * BOTH the gateway (`chat.headers`) and OTEL (`TokenSource.headers()`).
99
+ *
100
+ * The human root token itself is no longer lightbridge-exclusive storage: it
101
+ * lives in the SAME cache file `@vymalo/opencode-oauth2` writes for a server
102
+ * of this id (`ROOT_CACHE_SEGMENT`/`ROOT_CACHE_NAMESPACE`), so configuring
103
+ * both plugins against the same IdP (`auth.id` matching an oauth2
104
+ * `servers[].id`, same issuer/clientId) means logging in once. An upgrading
105
+ * install's pre-existing root token is migrated in automatically — see
106
+ * `migration.ts`.
41
107
  */
42
108
  export class LightbridgeRuntime {
43
109
  projectId;
44
- runtime;
110
+ rootRuntime;
111
+ sharedStore;
112
+ exchangeRuntime;
45
113
  logger;
46
114
  tokenExpirySkewMs;
115
+ exchange;
116
+ cacheRoot;
117
+ serverId;
47
118
  /** Token-cache key: the project id, or `DEFAULT_PROJECT_KEY` when unset. */
48
119
  projectKey;
49
120
  inFlightExchange;
121
+ migration;
50
122
  constructor(auth, projectId, options = {}) {
51
123
  this.projectId = projectId;
124
+ this.serverId = auth.id;
52
125
  this.projectKey = projectId ?? DEFAULT_PROJECT_KEY;
53
126
  this.logger = options.logger ?? createJsonConsoleLogger("info");
127
+ this.exchange = options.exchange ?? false;
128
+ this.cacheRoot = options.cacheDir ?? resolveCacheRoot();
54
129
  this.tokenExpirySkewMs = typeof options.tokenExpirySkewMs === "number" && Number.isFinite(options.tokenExpirySkewMs) && options.tokenExpirySkewMs > 0 ? options.tokenExpirySkewMs : DEFAULT_TOKEN_EXPIRY_SKEW_MS;
55
- this.runtime = new TokenRuntime(LIGHTBRIDGE_IDENTITY, auth, {
130
+ this.sharedStore = new SharedFileCacheStore(join(this.cacheRoot, ROOT_CACHE_SEGMENT, ROOT_CACHE_NAMESPACE), this.logger);
131
+ this.rootRuntime = buildSharedRootTokenRuntime(this.serverId, auth, this.sharedStore, options);
132
+ // The exchange-only runtime keeps its OWN dedicated, lightbridge-exclusive
133
+ // store (unchanged location/shape) — there is no oauth2 equivalent for a
134
+ // project-scoped exchanged token, so nothing to share here.
135
+ this.exchangeRuntime = new TokenRuntime(LIGHTBRIDGE_IDENTITY, auth, {
56
136
  logger: this.logger,
57
137
  fetchImpl: options.fetchImpl,
58
138
  onAuthorizationUrl: options.onAuthorizationUrl,
59
- cacheDir: options.cacheDir ?? join(resolveCacheRoot(), DEFAULT_CACHE_NAMESPACE),
60
- tokenExpirySkewMs: this.tokenExpirySkewMs
139
+ cacheDir: join(this.cacheRoot, DEFAULT_CACHE_NAMESPACE),
140
+ tokenExpirySkewMs: this.tokenExpirySkewMs,
141
+ serviceLabel: "opencode-lightbridge"
61
142
  });
62
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
+ }
63
160
  /** Non-network read of the cached project token, if any. */
64
161
  async getCachedProjectToken() {
65
- return this.runtime.getExchangedByKey(this.projectKey);
162
+ return this.exchangeRuntime.getExchangedByKey(this.projectKey);
66
163
  }
67
164
  /**
68
- * Resolve a usable project token, shared by every caller (gateway
69
- * `chat.headers`, OTEL `TokenSource.headers()`):
165
+ * Resolve a usable gateway/OTEL bearer, shared by every caller (gateway
166
+ * `chat.headers`, OTEL `TokenSource.headers()`).
167
+ *
168
+ * `gateway.exchange: false` (default, ADR-0017): the IdP access token IS
169
+ * the bearer — just `ensure()` the shared root token (refresh-only unless
170
+ * `interactive`).
171
+ *
172
+ * `gateway.exchange: true` (ADR-0012, unchanged):
70
173
  *
71
- * cached usable? ──yes──▶ return it
174
+ * cached exchanged token usable? ──yes──▶ return it
72
175
  * │ no
73
176
  * ▼
74
- * ensure human root (refresh-only unless `interactive`)
177
+ * ensure shared human root (refresh-only unless `interactive`)
75
178
  * ▼
76
179
  * exchangeTo(projectKey, humanToken, projectId ? { project_id } : {})
77
180
  * ▼ (no projectId → backend picks the default project)
78
181
  * cache + return
79
182
  *
80
- * Concurrent callers (a chat request racing an OTEL export) share the
81
- * in-flight exchange — at most one exchange POST per cache-miss window.
82
- * Never invents a token: an exchange failure propagates to the caller,
83
- * which is expected to fail closed (no header / empty `headers()`).
183
+ * Concurrent callers share the in-flight exchange in either mode. Never
184
+ * invents a token: a failure propagates to the caller, which is expected to
185
+ * fail closed (no header / empty `headers()`).
84
186
  */
85
187
  async getProjectToken(options = {}) {
188
+ await this.ensureMigrated();
189
+ if (!this.exchange) {
190
+ return this.rootRuntime.ensure({ interactive: options.interactive });
191
+ }
86
192
  const cached = await this.getCachedProjectToken();
87
193
  if (isProjectTokenUsable(cached, this.tokenExpirySkewMs)) {
88
194
  this.logger.trace("lightbridge_exchange_cache_hit", { projectId: this.projectId });
@@ -103,12 +209,12 @@ export class LightbridgeRuntime {
103
209
  }
104
210
  }
105
211
  async performExchange(options) {
106
- const human = await this.runtime.ensure({ interactive: options.interactive });
212
+ const human = await this.rootRuntime.ensure({ interactive: options.interactive });
107
213
  this.logger.info("lightbridge_exchange_started", { projectId: this.projectId ?? "(default)" });
108
214
  try {
109
215
  // No `projectId` → send no `project_id` param; the backend mints a token
110
216
  // for the caller's default project (ADR-0012).
111
- const exchanged = await this.runtime.exchangeTo(this.projectKey, human.accessToken, this.projectId ? { project_id: this.projectId } : {});
217
+ const exchanged = await this.exchangeRuntime.exchangeTo(this.projectKey, human.accessToken, this.projectId ? { project_id: this.projectId } : {});
112
218
  this.logger.info("lightbridge_exchange_success", { projectId: this.projectId ?? "(default)" });
113
219
  return exchanged;
114
220
  } catch (error) {
@@ -119,14 +225,32 @@ export class LightbridgeRuntime {
119
225
  throw error;
120
226
  }
121
227
  }
122
- /** Drop the on-disk human + project tokens for this identity. */
228
+ /**
229
+ * Drop the cached tokens for this identity: the exchanged project token
230
+ * entirely (its own exclusive store), and the shared root token's `token`
231
+ * field only — NOT the whole shared cache file, which may also hold
232
+ * `@vymalo/opencode-oauth2`'s discovered models for this server id and must
233
+ * survive a lightbridge-side logout.
234
+ */
123
235
  async reset() {
124
- await this.runtime.reset();
236
+ await this.exchangeRuntime.reset();
237
+ const existing = await this.sharedStore.loadServerState(this.serverId);
238
+ if (existing?.token) {
239
+ await this.sharedStore.saveServerState({
240
+ ...existing,
241
+ updatedAt: Date.now(),
242
+ token: undefined
243
+ });
244
+ }
125
245
  }
126
246
  }
127
- /** Absolute path to the lightbridge cache directory (for diagnostics / tests). */
247
+ /** Absolute path to the lightbridge-exclusive (exchanged-token) cache directory. */
128
248
  export function lightbridgeCacheDir(cacheRoot) {
129
249
  return join(cacheRoot, DEFAULT_CACHE_NAMESPACE);
130
250
  }
251
+ /** Absolute path to the SHARED root-token cache directory (ADR-0017). */
252
+ export function rootCacheDir(cacheRoot) {
253
+ return join(cacheRoot, ROOT_CACHE_SEGMENT, ROOT_CACHE_NAMESPACE);
254
+ }
131
255
 
132
256
  //# sourceMappingURL=plugin.js.map
@@ -1 +1 @@
1
- {"mappings":"AAAA,SAAS,YAAY;AAErB,SACE,yBACA,8BACA,kBACA,oBAIK;;;;;AAMP,OAAO,MAAM,uBAAuB;;AAGpC,OAAO,MAAM,0BAA0B;;;;;;;AAQvC,OAAO,MAAM,sBAAsB;;;;;;;AAqCnC,SAAS,qBAAqB,OAA6B,QAAmC;CAC5F,IAAI,CAAC,OAAO,aAAa;EACvB,OAAO;CACT;CACA,IAAI,MAAM,cAAc,WAAW;EACjC,OAAO;CACT;CACA,OAAO,KAAK,IAAI,IAAI,SAAS,MAAM;AACrC;;;;;;;;;;;AAYA,OAAO,MAAM,mBAAqD;CAU7C;CATnB,AAAiB;CACjB,AAAiB;CACjB,AAAiB;;CAEjB,AAAiB;CACjB,AAAQ;CAER,YACE,MACA,AAAiB,WACjB,UAAqC,CAAC,GACtC;EAFiB;EAGjB,KAAK,aAAa,aAAa;EAC/B,KAAK,SAAS,QAAQ,UAAU,wBAAwB,MAAM;EAC9D,KAAK,oBACH,OAAO,QAAQ,sBAAsB,YACrC,OAAO,SAAS,QAAQ,iBAAiB,KACzC,QAAQ,oBAAoB,IACxB,QAAQ,oBACR;EAEN,KAAK,UAAU,IAAI,aAAa,sBAAsB,MAAM;GAC1D,QAAQ,KAAK;GACb,WAAW,QAAQ;GACnB,oBAAoB,QAAQ;GAC5B,UAAU,QAAQ,YAAY,KAAK,iBAAiB,GAAG,uBAAuB;GAC9E,mBAAmB,KAAK;EAC1B,CAAC;CACH;;CAGA,MAAM,wBAAuD;EAC3D,OAAO,KAAK,QAAQ,kBAAkB,KAAK,UAAU;CACvD;;;;;;;;;;;;;;;;;;;CAoBA,MAAM,gBAAgB,UAAqC,CAAC,GAAsB;EAChF,MAAM,SAAS,MAAM,KAAK,sBAAsB;EAChD,IAAI,qBAAqB,QAAQ,KAAK,iBAAiB,GAAG;GACxD,KAAK,OAAO,MAAM,kCAAkC,EAAE,WAAW,KAAK,UAAU,CAAC;GACjF,OAAO;EACT;EACA,KAAK,OAAO,MAAM,mCAAmC,EAAE,WAAW,KAAK,UAAU,CAAC;EAElF,IAAI,KAAK,kBAAkB;GACzB,OAAO,KAAK;EACd;EAEA,MAAM,WAAW,KAAK,gBAAgB,OAAO;EAC7C,KAAK,mBAAmB;EACxB,IAAI;GACF,OAAO,MAAM;EACf,UAAU;GACR,IAAI,KAAK,qBAAqB,UAAU;IACtC,KAAK,mBAAmB;GAC1B;EACF;CACF;CAEA,MAAc,gBAAgB,SAAuD;EACnF,MAAM,QAAQ,MAAM,KAAK,QAAQ,OAAO,EAAE,aAAa,QAAQ,YAAY,CAAC;EAC5E,KAAK,OAAO,KAAK,gCAAgC,EAAE,WAAW,KAAK,aAAa,YAAY,CAAC;EAC7F,IAAI;;;GAGF,MAAM,YAAY,MAAM,KAAK,QAAQ,WACnC,KAAK,YACL,MAAM,aACN,KAAK,YAAY,EAAE,YAAY,KAAK,UAAU,IAAI,CAAC,CACrD;GACA,KAAK,OAAO,KAAK,gCAAgC,EAC/C,WAAW,KAAK,aAAa,YAC/B,CAAC;GACD,OAAO;EACT,SAAS,OAAO;GACd,KAAK,OAAO,MAAM,+BAA+B;IAC/C,WAAW,KAAK;IAChB,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;GAC9D,CAAC;GACD,MAAM;EACR;CACF;;CAGA,MAAM,QAAuB;EAC3B,MAAM,KAAK,QAAQ,MAAM;CAC3B;AACF;;AAGA,OAAO,SAAS,oBAAoB,WAA2B;CAC7D,OAAO,KAAK,WAAW,uBAAuB;AAChD","names":[],"sources":["../src/plugin.ts"],"version":3,"file":"plugin.js","sourceRoot":""}
1
+ {"mappings":"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","names":[],"sources":["../src/plugin.ts"],"version":3,"file":"plugin.js","sourceRoot":""}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vymalo/opencode-lightbridge",
3
- "version": "0.16.1",
3
+ "version": "0.18.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",
@@ -50,17 +50,23 @@
50
50
  "access": "public"
51
51
  },
52
52
  "dependencies": {
53
- "@opencode-ai/plugin": "1.15.10",
53
+ "@opencode/plugin": "2.2.6",
54
54
  "@opentelemetry/api": "^1.9.1",
55
- "@opentelemetry/api-logs": "^0.221.0",
56
- "@vymalo/opencode-auth-core": "0.16.1",
57
- "@vymalo/opencode-core-otel": "0.16.1"
55
+ "@opentelemetry/api-logs": "^0.222.0",
56
+ "@opentelemetry/core": "^2.11.0",
57
+ "@vymalo/opencode-auth-core": "0.18.0",
58
+ "@vymalo/opencode-core-otel": "0.18.0",
59
+ "@vymalo/opencode-provider-sync": "0.18.0"
58
60
  },
59
61
  "devDependencies": {
60
- "@opentelemetry/sdk-logs": "^0.221.0",
61
- "@opentelemetry/sdk-trace": "^2.10.0",
62
- "vite": "^8.2.1",
63
- "vitest": "^4.1.7"
62
+ "@opentelemetry/sdk-logs": "^0.222.0",
63
+ "@opentelemetry/sdk-trace": "^2.11.0",
64
+ "effect": "4.1.0",
65
+ "vite": "^8.3.0",
66
+ "vitest": "^5.0.1"
67
+ },
68
+ "peerDependencies": {
69
+ "effect": "^4.0.0"
64
70
  },
65
71
  "scripts": {
66
72
  "build": "node ../../scripts/build-package.mjs",