@vymalo/opencode-oauth2 0.12.0 → 0.14.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 (57) hide show
  1. package/dist/cache.d.ts +6 -6
  2. package/dist/cache.js +100 -104
  3. package/dist/cache.js.map +1 -1
  4. package/dist/config.d.ts +107 -107
  5. package/dist/config.js +173 -182
  6. package/dist/config.js.map +1 -1
  7. package/dist/index.js +1 -0
  8. package/dist/index.js.map +1 -1
  9. package/dist/lib.js +1 -0
  10. package/dist/lib.js.map +1 -1
  11. package/dist/logging.d.ts +6 -6
  12. package/dist/logging.js +57 -56
  13. package/dist/logging.js.map +1 -1
  14. package/dist/model-discovery.d.ts +3 -3
  15. package/dist/model-discovery.js +61 -66
  16. package/dist/model-discovery.js.map +1 -1
  17. package/dist/model-normalization.js +84 -73
  18. package/dist/model-normalization.js.map +1 -1
  19. package/dist/oauth/browser.js +29 -25
  20. package/dist/oauth/browser.js.map +1 -1
  21. package/dist/oauth/client.d.ts +46 -46
  22. package/dist/oauth/client.js +411 -430
  23. package/dist/oauth/client.js.map +1 -1
  24. package/dist/oauth/device-code.d.ts +23 -23
  25. package/dist/oauth/device-code.js +225 -235
  26. package/dist/oauth/device-code.js.map +1 -1
  27. package/dist/oauth/discovery.d.ts +5 -5
  28. package/dist/oauth/discovery.js +34 -34
  29. package/dist/oauth/discovery.js.map +1 -1
  30. package/dist/oauth/http-utils.d.ts +27 -27
  31. package/dist/oauth/http-utils.js +96 -107
  32. package/dist/oauth/http-utils.js.map +1 -1
  33. package/dist/oauth/local-callback.d.ts +5 -5
  34. package/dist/oauth/local-callback.js +76 -74
  35. package/dist/oauth/local-callback.js.map +1 -1
  36. package/dist/oauth/pkce.d.ts +2 -2
  37. package/dist/oauth/pkce.js +9 -5
  38. package/dist/oauth/pkce.js.map +1 -1
  39. package/dist/oauth/subject-token.d.ts +15 -15
  40. package/dist/oauth/subject-token.js +68 -73
  41. package/dist/oauth/subject-token.js.map +1 -1
  42. package/dist/opencode.d.ts +15 -15
  43. package/dist/opencode.js +477 -497
  44. package/dist/opencode.js.map +1 -1
  45. package/dist/plugin.d.ts +39 -39
  46. package/dist/plugin.js +270 -277
  47. package/dist/plugin.js.map +1 -1
  48. package/dist/responses-repair.d.ts +12 -35
  49. package/dist/responses-repair.js +119 -125
  50. package/dist/responses-repair.js.map +1 -1
  51. package/dist/scheduler.d.ts +5 -5
  52. package/dist/scheduler.js +43 -45
  53. package/dist/scheduler.js.map +1 -1
  54. package/dist/types.d.ts +25 -25
  55. package/dist/types.js +1 -0
  56. package/dist/types.js.map +1 -1
  57. package/package.json +3 -3
@@ -1,41 +1,18 @@
1
1
  /**
2
- * Repair non-conformant OpenAI **Responses API** SSE streams.
3
- *
4
- * Some gateways (observed: Envoy AI Gateway fronting a local model server) emit
5
- * Responses streaming events **without** the `output_index` / `content_index`
6
- * fields that the canonical OpenAI Responses API always includes. The AI SDK's
7
- * `@ai-sdk/openai` responses parser (and, downstream, OpenCode) key each
8
- * message part by those indices, so when they are absent the text part is never
9
- * associated with its deltas and the host fails with
10
- * `text part <msg_id> not found` — even though the request, auth, routing, and
11
- * the gateway's final (non-streamed) object are all fine.
12
- *
13
- * This module injects the missing indices on the fly:
14
- * - `output_index` is assigned per item in the order their
15
- * `response.output_item.added` events arrive (reasoning → 0, message → 1, …).
16
- * - `content_index` is set to `0` on the single content / text / reasoning part
17
- * of each item (these gateways only ever emit one).
18
- *
19
- * Existing index fields are never overwritten, so the transform is a safe no-op
20
- * against a conformant gateway. Only the oauth2 plugin's `responseApi` path
21
- * installs it (as a wrapping `options.fetch`), and only for requests to the
22
- * `/responses` route with a `text/event-stream` body.
23
- */
24
- /**
25
- * Pure text form — repair a complete SSE document. Exposed for testing; the
26
- * runtime path uses {@link makeResponsesRepairStream}.
27
- */
2
+ * Pure text form repair a complete SSE document. Exposed for testing; the
3
+ * runtime path uses {@link makeResponsesRepairStream}.
4
+ */
28
5
  export declare function repairResponsesSseText(input: string): string;
29
6
  /**
30
- * Streaming form — a `TransformStream` that repairs SSE byte chunks, buffering
31
- * across chunk boundaries so a split mid-event is handled correctly.
32
- */
7
+ * Streaming form — a `TransformStream` that repairs SSE byte chunks, buffering
8
+ * across chunk boundaries so a split mid-event is handled correctly.
9
+ */
33
10
  export declare function makeResponsesRepairStream(): TransformStream<Uint8Array, Uint8Array>;
34
11
  /**
35
- * Wrap a `fetch` so Responses-API SSE responses are run through the index
36
- * repair before the AI SDK parses them. Non-`/responses` requests and
37
- * non-streaming responses pass through unchanged. Composes with a `delegate`
38
- * (a pre-existing `options.fetch`) so stacking with other fetch-wrapping
39
- * plugins works regardless of order.
40
- */
12
+ * Wrap a `fetch` so Responses-API SSE responses are run through the index
13
+ * repair before the AI SDK parses them. Non-`/responses` requests and
14
+ * non-streaming responses pass through unchanged. Composes with a `delegate`
15
+ * (a pre-existing `options.fetch`) so stacking with other fetch-wrapping
16
+ * plugins works regardless of order.
17
+ */
41
18
  export declare function createResponsesRepairFetch(delegate?: typeof fetch): typeof fetch;
@@ -1,26 +1,26 @@
1
1
  /**
2
- * Repair non-conformant OpenAI **Responses API** SSE streams.
3
- *
4
- * Some gateways (observed: Envoy AI Gateway fronting a local model server) emit
5
- * Responses streaming events **without** the `output_index` / `content_index`
6
- * fields that the canonical OpenAI Responses API always includes. The AI SDK's
7
- * `@ai-sdk/openai` responses parser (and, downstream, OpenCode) key each
8
- * message part by those indices, so when they are absent the text part is never
9
- * associated with its deltas and the host fails with
10
- * `text part <msg_id> not found` — even though the request, auth, routing, and
11
- * the gateway's final (non-streamed) object are all fine.
12
- *
13
- * This module injects the missing indices on the fly:
14
- * - `output_index` is assigned per item in the order their
15
- * `response.output_item.added` events arrive (reasoning → 0, message → 1, …).
16
- * - `content_index` is set to `0` on the single content / text / reasoning part
17
- * of each item (these gateways only ever emit one).
18
- *
19
- * Existing index fields are never overwritten, so the transform is a safe no-op
20
- * against a conformant gateway. Only the oauth2 plugin's `responseApi` path
21
- * installs it (as a wrapping `options.fetch`), and only for requests to the
22
- * `/responses` route with a `text/event-stream` body.
23
- */
2
+ * Repair non-conformant OpenAI **Responses API** SSE streams.
3
+ *
4
+ * Some gateways (observed: Envoy AI Gateway fronting a local model server) emit
5
+ * Responses streaming events **without** the `output_index` / `content_index`
6
+ * fields that the canonical OpenAI Responses API always includes. The AI SDK's
7
+ * `@ai-sdk/openai` responses parser (and, downstream, OpenCode) key each
8
+ * message part by those indices, so when they are absent the text part is never
9
+ * associated with its deltas and the host fails with
10
+ * `text part <msg_id> not found` — even though the request, auth, routing, and
11
+ * the gateway's final (non-streamed) object are all fine.
12
+ *
13
+ * This module injects the missing indices on the fly:
14
+ * - `output_index` is assigned per item in the order their
15
+ * `response.output_item.added` events arrive (reasoning → 0, message → 1, …).
16
+ * - `content_index` is set to `0` on the single content / text / reasoning part
17
+ * of each item (these gateways only ever emit one).
18
+ *
19
+ * Existing index fields are never overwritten, so the transform is a safe no-op
20
+ * against a conformant gateway. Only the oauth2 plugin's `responseApi` path
21
+ * installs it (as a wrapping `options.fetch`), and only for requests to the
22
+ * `/responses` route with a `text/event-stream` body.
23
+ */
24
24
  const CONTENT_EVENT = /content_part|output_text|reasoning_text/;
25
25
  // One SSE frame: an optional `event:` line then a `data:` line carrying JSON.
26
26
  // Tolerant of CRLF (`\r\n`) as well as LF line endings — both are valid SSE.
@@ -28,120 +28,114 @@ const BLOCK_RE = /^(?:event:\s*(\S+)[^\S\r\n]*[\r\n]+)?data:\s*(\{[\s\S]*\})\s*$
28
28
  // Frame boundary is a blank line: `\n\n` or `\r\n\r\n`.
29
29
  const FRAME_BOUNDARY = /\r\n\r\n|\n\n/;
30
30
  /**
31
- * Stateful per-stream renderer. Tracks the `item_id → output_index` mapping
32
- * across blocks (the map must persist for the whole stream, so each stream gets
33
- * its own injector instance).
34
- */
31
+ * Stateful per-stream renderer. Tracks the `item_id → output_index` mapping
32
+ * across blocks (the map must persist for the whole stream, so each stream gets
33
+ * its own injector instance).
34
+ */
35
35
  function createIndexInjector() {
36
- const outputIndex = new Map();
37
- let nextIndex = 0;
38
- return (block) => {
39
- const match = block.match(BLOCK_RE);
40
- if (!match) {
41
- // Comments, `data: [DONE]`, keep-alives — pass through untouched.
42
- return block;
43
- }
44
- let event;
45
- try {
46
- event = JSON.parse(match[2]);
47
- }
48
- catch {
49
- return block;
50
- }
51
- const type = typeof event.type === "string" ? event.type : "";
52
- const item = event.item;
53
- const itemId = (item && typeof item.id === "string" ? item.id : undefined) ??
54
- (typeof event.item_id === "string" ? event.item_id : undefined);
55
- if (type === "response.output_item.added" && itemId && !outputIndex.has(itemId)) {
56
- outputIndex.set(itemId, nextIndex++);
57
- }
58
- if (itemId && outputIndex.has(itemId) && event.output_index === undefined) {
59
- event.output_index = outputIndex.get(itemId);
60
- }
61
- if (CONTENT_EVENT.test(type) && event.content_index === undefined) {
62
- event.content_index = 0;
63
- }
64
- const eventLine = match[1] ? `event: ${match[1]}\n` : "";
65
- return `${eventLine}data: ${JSON.stringify(event)}\n\n`;
66
- };
36
+ const outputIndex = new Map();
37
+ let nextIndex = 0;
38
+ return (block) => {
39
+ const match = block.match(BLOCK_RE);
40
+ if (!match) {
41
+ // Comments, `data: [DONE]`, keep-alives — pass through untouched.
42
+ return block;
43
+ }
44
+ let event;
45
+ try {
46
+ event = JSON.parse(match[2]);
47
+ } catch {
48
+ return block;
49
+ }
50
+ const type = typeof event.type === "string" ? event.type : "";
51
+ const item = event.item;
52
+ const itemId = (item && typeof item.id === "string" ? item.id : undefined) ?? (typeof event.item_id === "string" ? event.item_id : undefined);
53
+ if (type === "response.output_item.added" && itemId && !outputIndex.has(itemId)) {
54
+ outputIndex.set(itemId, nextIndex++);
55
+ }
56
+ if (itemId && outputIndex.has(itemId) && event.output_index === undefined) {
57
+ event.output_index = outputIndex.get(itemId);
58
+ }
59
+ if (CONTENT_EVENT.test(type) && event.content_index === undefined) {
60
+ event.content_index = 0;
61
+ }
62
+ const eventLine = match[1] ? `event: ${match[1]}\n` : "";
63
+ return `${eventLine}data: ${JSON.stringify(event)}\n\n`;
64
+ };
67
65
  }
68
66
  /**
69
- * Pure text form — repair a complete SSE document. Exposed for testing; the
70
- * runtime path uses {@link makeResponsesRepairStream}.
71
- */
67
+ * Pure text form — repair a complete SSE document. Exposed for testing; the
68
+ * runtime path uses {@link makeResponsesRepairStream}.
69
+ */
72
70
  export function repairResponsesSseText(input) {
73
- const render = createIndexInjector();
74
- // Split after each blank-line boundary (LF or CRLF), keeping it attached to
75
- // its frame.
76
- return input
77
- .split(/(?<=\r\n\r\n|\n\n)/)
78
- .map(render)
79
- .join("");
71
+ const render = createIndexInjector();
72
+ // Split after each blank-line boundary (LF or CRLF), keeping it attached to
73
+ // its frame.
74
+ return input.split(/(?<=\r\n\r\n|\n\n)/).map(render).join("");
80
75
  }
81
76
  /**
82
- * Streaming form — a `TransformStream` that repairs SSE byte chunks, buffering
83
- * across chunk boundaries so a split mid-event is handled correctly.
84
- */
77
+ * Streaming form — a `TransformStream` that repairs SSE byte chunks, buffering
78
+ * across chunk boundaries so a split mid-event is handled correctly.
79
+ */
85
80
  export function makeResponsesRepairStream() {
86
- const render = createIndexInjector();
87
- const decoder = new TextDecoder();
88
- const encoder = new TextEncoder();
89
- let buffer = "";
90
- return new TransformStream({
91
- transform(chunk, controller) {
92
- buffer += decoder.decode(chunk, { stream: true });
93
- let out = "";
94
- let match;
95
- while ((match = FRAME_BOUNDARY.exec(buffer)) !== null) {
96
- const end = match.index + match[0].length;
97
- out += render(buffer.slice(0, end));
98
- buffer = buffer.slice(end);
99
- }
100
- if (out) {
101
- controller.enqueue(encoder.encode(out));
102
- }
103
- },
104
- flush(controller) {
105
- buffer += decoder.decode();
106
- if (buffer) {
107
- controller.enqueue(encoder.encode(render(buffer)));
108
- }
109
- }
110
- });
81
+ const render = createIndexInjector();
82
+ const decoder = new TextDecoder();
83
+ const encoder = new TextEncoder();
84
+ let buffer = "";
85
+ return new TransformStream({
86
+ transform(chunk, controller) {
87
+ buffer += decoder.decode(chunk, { stream: true });
88
+ let out = "";
89
+ let match;
90
+ while ((match = FRAME_BOUNDARY.exec(buffer)) !== null) {
91
+ const end = match.index + match[0].length;
92
+ out += render(buffer.slice(0, end));
93
+ buffer = buffer.slice(end);
94
+ }
95
+ if (out) {
96
+ controller.enqueue(encoder.encode(out));
97
+ }
98
+ },
99
+ flush(controller) {
100
+ buffer += decoder.decode();
101
+ if (buffer) {
102
+ controller.enqueue(encoder.encode(render(buffer)));
103
+ }
104
+ }
105
+ });
111
106
  }
112
107
  function urlOf(input) {
113
- if (typeof input === "string") {
114
- return input;
115
- }
116
- if (input instanceof URL) {
117
- return input.href;
118
- }
119
- return input.url;
108
+ if (typeof input === "string") {
109
+ return input;
110
+ }
111
+ if (input instanceof URL) {
112
+ return input.href;
113
+ }
114
+ return input.url;
120
115
  }
121
116
  /**
122
- * Wrap a `fetch` so Responses-API SSE responses are run through the index
123
- * repair before the AI SDK parses them. Non-`/responses` requests and
124
- * non-streaming responses pass through unchanged. Composes with a `delegate`
125
- * (a pre-existing `options.fetch`) so stacking with other fetch-wrapping
126
- * plugins works regardless of order.
127
- */
117
+ * Wrap a `fetch` so Responses-API SSE responses are run through the index
118
+ * repair before the AI SDK parses them. Non-`/responses` requests and
119
+ * non-streaming responses pass through unchanged. Composes with a `delegate`
120
+ * (a pre-existing `options.fetch`) so stacking with other fetch-wrapping
121
+ * plugins works regardless of order.
122
+ */
128
123
  export function createResponsesRepairFetch(delegate) {
129
- const base = delegate ?? globalThis.fetch;
130
- const repaired = async (input, init) => {
131
- const response = await base(input, init);
132
- // HTTP media types are case-insensitive, so normalize before matching.
133
- const contentType = (response.headers.get("content-type") ?? "").toLowerCase();
134
- if (!response.body ||
135
- !urlOf(input).includes("/responses") ||
136
- !contentType.includes("text/event-stream")) {
137
- return response;
138
- }
139
- return new Response(response.body.pipeThrough(makeResponsesRepairStream()), {
140
- status: response.status,
141
- statusText: response.statusText,
142
- headers: response.headers
143
- });
144
- };
145
- return repaired;
124
+ const base = delegate ?? globalThis.fetch;
125
+ const repaired = async (input, init) => {
126
+ const response = await base(input, init);
127
+ // HTTP media types are case-insensitive, so normalize before matching.
128
+ const contentType = (response.headers.get("content-type") ?? "").toLowerCase();
129
+ if (!response.body || !urlOf(input).includes("/responses") || !contentType.includes("text/event-stream")) {
130
+ return response;
131
+ }
132
+ return new Response(response.body.pipeThrough(makeResponsesRepairStream()), {
133
+ status: response.status,
134
+ statusText: response.statusText,
135
+ headers: response.headers
136
+ });
137
+ };
138
+ return repaired;
146
139
  }
140
+
147
141
  //# sourceMappingURL=responses-repair.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"responses-repair.js","sourceRoot":"","sources":["../src/responses-repair.ts"],"names":[],"mappings":"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"}
1
+ {"mappings":"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","names":[],"sources":["../src/responses-repair.ts"],"version":3,"file":"responses-repair.js","sourceRoot":""}
@@ -1,11 +1,11 @@
1
1
  import type { Logger } from "./logging.js";
2
2
  export interface SchedulerHandle {
3
- stop(): void;
3
+ stop(): void;
4
4
  }
5
5
  export interface SchedulerOptions {
6
- intervalMs: number;
7
- logger: Logger;
8
- taskName: string;
9
- run: () => Promise<void>;
6
+ intervalMs: number;
7
+ logger: Logger;
8
+ taskName: string;
9
+ run: () => Promise<void>;
10
10
  }
11
11
  export declare function startScheduler(options: SchedulerOptions): SchedulerHandle;
package/dist/scheduler.js CHANGED
@@ -1,48 +1,46 @@
1
1
  export function startScheduler(options) {
2
- let failures = 0;
3
- let stopped = false;
4
- let timeout;
5
- const schedule = (delayMs) => {
6
- timeout = setTimeout(() => {
7
- void tick();
8
- }, delayMs);
9
- };
10
- const backoffDelay = () => {
11
- const retryWindow = 15_000 * 2 ** Math.max(0, failures - 1);
12
- return Math.min(options.intervalMs, retryWindow);
13
- };
14
- const tick = async () => {
15
- if (stopped) {
16
- return;
17
- }
18
- options.logger.trace("oauth2_scheduler_tick", {
19
- taskName: options.taskName,
20
- failures
21
- });
22
- try {
23
- await options.run();
24
- failures = 0;
25
- schedule(options.intervalMs);
26
- }
27
- catch (error) {
28
- failures += 1;
29
- options.logger.warn("sync_schedule_retry", {
30
- taskName: options.taskName,
31
- failures,
32
- delayMs: backoffDelay(),
33
- error: error instanceof Error ? error.message : String(error)
34
- });
35
- schedule(backoffDelay());
36
- }
37
- };
38
- schedule(options.intervalMs);
39
- return {
40
- stop() {
41
- stopped = true;
42
- if (timeout) {
43
- clearTimeout(timeout);
44
- }
45
- }
46
- };
2
+ let failures = 0;
3
+ let stopped = false;
4
+ let timeout;
5
+ const schedule = (delayMs) => {
6
+ timeout = setTimeout(() => {
7
+ void tick();
8
+ }, delayMs);
9
+ };
10
+ const backoffDelay = () => {
11
+ const retryWindow = 15e3 * 2 ** Math.max(0, failures - 1);
12
+ return Math.min(options.intervalMs, retryWindow);
13
+ };
14
+ const tick = async () => {
15
+ if (stopped) {
16
+ return;
17
+ }
18
+ options.logger.trace("oauth2_scheduler_tick", {
19
+ taskName: options.taskName,
20
+ failures
21
+ });
22
+ try {
23
+ await options.run();
24
+ failures = 0;
25
+ schedule(options.intervalMs);
26
+ } catch (error) {
27
+ failures += 1;
28
+ options.logger.warn("sync_schedule_retry", {
29
+ taskName: options.taskName,
30
+ failures,
31
+ delayMs: backoffDelay(),
32
+ error: error instanceof Error ? error.message : String(error)
33
+ });
34
+ schedule(backoffDelay());
35
+ }
36
+ };
37
+ schedule(options.intervalMs);
38
+ return { stop() {
39
+ stopped = true;
40
+ if (timeout) {
41
+ clearTimeout(timeout);
42
+ }
43
+ } };
47
44
  }
45
+
48
46
  //# sourceMappingURL=scheduler.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"scheduler.js","sourceRoot":"","sources":["../src/scheduler.ts"],"names":[],"mappings":"AAaA,MAAM,UAAU,cAAc,CAAC,OAAyB;IACtD,IAAI,QAAQ,GAAG,CAAC,CAAC;IACjB,IAAI,OAAO,GAAG,KAAK,CAAC;IACpB,IAAI,OAAmC,CAAC;IAExC,MAAM,QAAQ,GAAG,CAAC,OAAe,EAAQ,EAAE;QACzC,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE;YACxB,KAAK,IAAI,EAAE,CAAC;QACd,CAAC,EAAE,OAAO,CAAC,CAAC;IACd,CAAC,CAAC;IAEF,MAAM,YAAY,GAAG,GAAW,EAAE;QAChC,MAAM,WAAW,GAAG,MAAM,GAAG,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,QAAQ,GAAG,CAAC,CAAC,CAAC;QAC5D,OAAO,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC;IACnD,CAAC,CAAC;IAEF,MAAM,IAAI,GAAG,KAAK,IAAmB,EAAE;QACrC,IAAI,OAAO,EAAE,CAAC;YACZ,OAAO;QACT,CAAC;QAED,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,uBAAuB,EAAE;YAC5C,QAAQ,EAAE,OAAO,CAAC,QAAQ;YAC1B,QAAQ;SACT,CAAC,CAAC;QAEH,IAAI,CAAC;YACH,MAAM,OAAO,CAAC,GAAG,EAAE,CAAC;YACpB,QAAQ,GAAG,CAAC,CAAC;YACb,QAAQ,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;QAC/B,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,QAAQ,IAAI,CAAC,CAAC;YACd,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,qBAAqB,EAAE;gBACzC,QAAQ,EAAE,OAAO,CAAC,QAAQ;gBAC1B,QAAQ;gBACR,OAAO,EAAE,YAAY,EAAE;gBACvB,KAAK,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;aAC9D,CAAC,CAAC;YACH,QAAQ,CAAC,YAAY,EAAE,CAAC,CAAC;QAC3B,CAAC;IACH,CAAC,CAAC;IAEF,QAAQ,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;IAE7B,OAAO;QACL,IAAI;YACF,OAAO,GAAG,IAAI,CAAC;YACf,IAAI,OAAO,EAAE,CAAC;gBACZ,YAAY,CAAC,OAAO,CAAC,CAAC;YACxB,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC"}
1
+ {"mappings":"AAaA,OAAO,SAAS,eAAe,SAA4C;CACzE,IAAI,WAAW;CACf,IAAI,UAAU;CACd,IAAI;CAEJ,MAAM,YAAY,YAA0B;EAC1C,UAAU,iBAAiB;GACzB,KAAK,KAAK;EACZ,GAAG,OAAO;CACZ;CAEA,MAAM,qBAA6B;EACjC,MAAM,cAAc,OAAS,KAAK,KAAK,IAAI,GAAG,WAAW,CAAC;EAC1D,OAAO,KAAK,IAAI,QAAQ,YAAY,WAAW;CACjD;CAEA,MAAM,OAAO,YAA2B;EACtC,IAAI,SAAS;GACX;EACF;EAEA,QAAQ,OAAO,MAAM,yBAAyB;GAC5C,UAAU,QAAQ;GAClB;EACF,CAAC;EAED,IAAI;GACF,MAAM,QAAQ,IAAI;GAClB,WAAW;GACX,SAAS,QAAQ,UAAU;EAC7B,SAAS,OAAO;GACd,YAAY;GACZ,QAAQ,OAAO,KAAK,uBAAuB;IACzC,UAAU,QAAQ;IAClB;IACA,SAAS,aAAa;IACtB,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;GAC9D,CAAC;GACD,SAAS,aAAa,CAAC;EACzB;CACF;CAEA,SAAS,QAAQ,UAAU;CAE3B,OAAO,EACL,OAAO;EACL,UAAU;EACV,IAAI,SAAS;GACX,aAAa,OAAO;EACtB;CACF,EACF;AACF","names":[],"sources":["../src/scheduler.ts"],"version":3,"file":"scheduler.js","sourceRoot":""}
package/dist/types.d.ts CHANGED
@@ -1,37 +1,37 @@
1
1
  export interface RawModel {
2
- id: string;
3
- [key: string]: unknown;
2
+ id: string;
3
+ [key: string]: unknown;
4
4
  }
5
5
  export interface NormalizedModel {
6
- id: string;
7
- displayName: string;
6
+ id: string;
7
+ displayName: string;
8
8
  }
9
9
  export interface ModelDiff {
10
- added: string[];
11
- removed: string[];
12
- renamed: Array<{
13
- id: string;
14
- before: string;
15
- after: string;
16
- }>;
10
+ added: string[];
11
+ removed: string[];
12
+ renamed: Array<{
13
+ id: string;
14
+ before: string;
15
+ after: string;
16
+ }>;
17
17
  }
18
18
  export interface TokenSet {
19
- accessToken: string;
20
- tokenType: string;
21
- refreshToken?: string;
22
- scope?: string;
23
- expiresAt?: number;
19
+ accessToken: string;
20
+ tokenType: string;
21
+ refreshToken?: string;
22
+ scope?: string;
23
+ expiresAt?: number;
24
24
  }
25
25
  export interface CachedServerState {
26
- serverId: string;
27
- updatedAt: number;
28
- lastSyncAt?: number;
29
- models: NormalizedModel[];
30
- rawModels: RawModel[];
31
- token?: TokenSet;
26
+ serverId: string;
27
+ updatedAt: number;
28
+ lastSyncAt?: number;
29
+ models: NormalizedModel[];
30
+ rawModels: RawModel[];
31
+ token?: TokenSet;
32
32
  }
33
33
  export interface ServerSnapshot {
34
- serverId: string;
35
- models: NormalizedModel[];
36
- lastSyncAt?: number;
34
+ serverId: string;
35
+ models: NormalizedModel[];
36
+ lastSyncAt?: number;
37
37
  }
package/dist/types.js CHANGED
@@ -1,2 +1,3 @@
1
1
  export {};
2
+
2
3
  //# sourceMappingURL=types.js.map
package/dist/types.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
1
+ {"mappings":"","names":[],"sources":["../src/types.ts"],"version":3,"file":"types.js","sourceRoot":""}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vymalo/opencode-oauth2",
3
- "version": "0.12.0",
3
+ "version": "0.14.0",
4
4
  "description": "OpenCode plugin for OAuth2/OIDC-secured, OpenAI-compatible model providers with periodic model sync.",
5
5
  "license": "MIT",
6
6
  "author": "vymalo contributors",
@@ -52,11 +52,11 @@
52
52
  "devDependencies": {
53
53
  "@ai-sdk/openai": "^2.0.106",
54
54
  "ai": "^5.0.199",
55
- "vite": "^8.0.14",
55
+ "vite": "^8.2.1",
56
56
  "vitest": "^4.1.7"
57
57
  },
58
58
  "scripts": {
59
- "build": "tsc -p tsconfig.json",
59
+ "build": "node ../../scripts/build-package.mjs",
60
60
  "lint": "biome lint .",
61
61
  "typecheck": "tsc -p tsconfig.json --noEmit",
62
62
  "test": "vitest run",