@vymalo/opencode-oauth2 0.12.0 → 0.14.1

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,82 +1,84 @@
1
1
  import { createServer } from "node:http";
2
2
  function writeHtml(response, statusCode, body) {
3
- response.statusCode = statusCode;
4
- response.setHeader("Content-Type", "text/html; charset=utf-8");
5
- response.end(body);
3
+ response.statusCode = statusCode;
4
+ response.setHeader("Content-Type", "text/html; charset=utf-8");
5
+ response.end(body);
6
6
  }
7
7
  function parseCallback(request) {
8
- if (!request.url) {
9
- return undefined;
10
- }
11
- const url = new URL(request.url, "http://127.0.0.1");
12
- const code = url.searchParams.get("code");
13
- const state = url.searchParams.get("state");
14
- if (!code || !state) {
15
- return undefined;
16
- }
17
- return { code, state };
8
+ if (!request.url) {
9
+ return undefined;
10
+ }
11
+ const url = new URL(request.url, "http://127.0.0.1");
12
+ const code = url.searchParams.get("code");
13
+ const state = url.searchParams.get("state");
14
+ if (!code || !state) {
15
+ return undefined;
16
+ }
17
+ return {
18
+ code,
19
+ state
20
+ };
18
21
  }
19
22
  export async function startLocalCallbackServer(callbackPath = "/oauth2/callback", port) {
20
- let resolver;
21
- let rejecter;
22
- const promise = new Promise((resolve, reject) => {
23
- resolver = resolve;
24
- rejecter = reject;
25
- });
26
- const server = createServer((request, response) => {
27
- const requestUrl = request.url ?? "";
28
- const parsed = new URL(requestUrl, "http://127.0.0.1");
29
- if (parsed.pathname !== callbackPath) {
30
- writeHtml(response, 404, "<h1>Not Found</h1>");
31
- return;
32
- }
33
- const payload = parseCallback(request);
34
- if (!payload) {
35
- writeHtml(response, 400, "<h1>Invalid OAuth callback</h1>");
36
- rejecter?.(new Error("invalid oauth callback payload"));
37
- return;
38
- }
39
- writeHtml(response, 200, "<h1>Login complete</h1><p>You can close this tab.</p>");
40
- resolver?.(payload);
41
- });
42
- const listenPort = typeof port === "number" && port >= 0 ? port : 0;
43
- await new Promise((resolve, reject) => {
44
- server.once("error", reject);
45
- server.listen(listenPort, "127.0.0.1", () => resolve());
46
- });
47
- const address = server.address();
48
- if (!address || typeof address === "string") {
49
- throw new Error("failed to allocate local callback port");
50
- }
51
- return {
52
- redirectUri: `http://127.0.0.1:${address.port}${callbackPath}`,
53
- waitForCode(timeoutMs = 120_000) {
54
- return new Promise((resolve, reject) => {
55
- const timeout = setTimeout(() => {
56
- reject(new Error("timed out waiting for OAuth callback"));
57
- }, timeoutMs);
58
- promise
59
- .then((value) => {
60
- clearTimeout(timeout);
61
- resolve(value);
62
- })
63
- .catch((error) => {
64
- clearTimeout(timeout);
65
- reject(error);
66
- });
67
- });
68
- },
69
- close() {
70
- return new Promise((resolve, reject) => {
71
- server.close((error) => {
72
- if (error) {
73
- reject(error);
74
- return;
75
- }
76
- resolve();
77
- });
78
- });
79
- }
80
- };
23
+ let resolver;
24
+ let rejecter;
25
+ const promise = new Promise((resolve, reject) => {
26
+ resolver = resolve;
27
+ rejecter = reject;
28
+ });
29
+ const server = createServer((request, response) => {
30
+ const requestUrl = request.url ?? "";
31
+ const parsed = new URL(requestUrl, "http://127.0.0.1");
32
+ if (parsed.pathname !== callbackPath) {
33
+ writeHtml(response, 404, "<h1>Not Found</h1>");
34
+ return;
35
+ }
36
+ const payload = parseCallback(request);
37
+ if (!payload) {
38
+ writeHtml(response, 400, "<h1>Invalid OAuth callback</h1>");
39
+ rejecter?.(new Error("invalid oauth callback payload"));
40
+ return;
41
+ }
42
+ writeHtml(response, 200, "<h1>Login complete</h1><p>You can close this tab.</p>");
43
+ resolver?.(payload);
44
+ });
45
+ const listenPort = typeof port === "number" && port >= 0 ? port : 0;
46
+ await new Promise((resolve, reject) => {
47
+ server.once("error", reject);
48
+ server.listen(listenPort, "127.0.0.1", () => resolve());
49
+ });
50
+ const address = server.address();
51
+ if (!address || typeof address === "string") {
52
+ throw new Error("failed to allocate local callback port");
53
+ }
54
+ return {
55
+ redirectUri: `http://127.0.0.1:${address.port}${callbackPath}`,
56
+ waitForCode(timeoutMs = 12e4) {
57
+ return new Promise((resolve, reject) => {
58
+ const timeout = setTimeout(() => {
59
+ reject(new Error("timed out waiting for OAuth callback"));
60
+ }, timeoutMs);
61
+ promise.then((value) => {
62
+ clearTimeout(timeout);
63
+ resolve(value);
64
+ }).catch((error) => {
65
+ clearTimeout(timeout);
66
+ reject(error);
67
+ });
68
+ });
69
+ },
70
+ close() {
71
+ return new Promise((resolve, reject) => {
72
+ server.close((error) => {
73
+ if (error) {
74
+ reject(error);
75
+ return;
76
+ }
77
+ resolve();
78
+ });
79
+ });
80
+ }
81
+ };
81
82
  }
83
+
82
84
  //# sourceMappingURL=local-callback.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"local-callback.js","sourceRoot":"","sources":["../../src/oauth/local-callback.ts"],"names":[],"mappings":"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"}
1
+ {"mappings":"AAAA,SAAS,oBAA+D;AAaxE,SAAS,UAAU,UAA0B,YAAoB,MAAoB;CACnF,SAAS,aAAa;CACtB,SAAS,UAAU,gBAAgB,0BAA0B;CAC7D,SAAS,IAAI,IAAI;AACnB;AAEA,SAAS,cAAc,SAA2D;CAChF,IAAI,CAAC,QAAQ,KAAK;EAChB,OAAO;CACT;CAEA,MAAM,MAAM,IAAI,IAAI,QAAQ,KAAK,kBAAkB;CACnD,MAAM,OAAO,IAAI,aAAa,IAAI,MAAM;CACxC,MAAM,QAAQ,IAAI,aAAa,IAAI,OAAO;CAE1C,IAAI,CAAC,QAAQ,CAAC,OAAO;EACnB,OAAO;CACT;CAEA,OAAO;EAAE;EAAM;CAAM;AACvB;AAEA,OAAO,eAAe,yBACpB,eAAe,oBACf,MAC8B;CAC9B,IAAI;CACJ,IAAI;CAEJ,MAAM,UAAU,IAAI,SAA8B,SAAS,WAAW;EACpE,WAAW;EACX,WAAW;CACb,CAAC;CAED,MAAM,SAAS,cAAc,SAAS,aAAa;EACjD,MAAM,aAAa,QAAQ,OAAO;EAClC,MAAM,SAAS,IAAI,IAAI,YAAY,kBAAkB;EAErD,IAAI,OAAO,aAAa,cAAc;GACpC,UAAU,UAAU,KAAK,oBAAoB;GAC7C;EACF;EAEA,MAAM,UAAU,cAAc,OAAO;EACrC,IAAI,CAAC,SAAS;GACZ,UAAU,UAAU,KAAK,iCAAiC;GAC1D,WAAW,IAAI,MAAM,gCAAgC,CAAC;GACtD;EACF;EAEA,UAAU,UAAU,KAAK,uDAAuD;EAChF,WAAW,OAAO;CACpB,CAAC;CAED,MAAM,aAAa,OAAO,SAAS,YAAY,QAAQ,IAAI,OAAO;CAClE,MAAM,IAAI,SAAe,SAAS,WAAW;EAC3C,OAAO,KAAK,SAAS,MAAM;EAC3B,OAAO,OAAO,YAAY,mBAAmB,QAAQ,CAAC;CACxD,CAAC;CAED,MAAM,UAAU,OAAO,QAAQ;CAC/B,IAAI,CAAC,WAAW,OAAO,YAAY,UAAU;EAC3C,MAAM,IAAI,MAAM,wCAAwC;CAC1D;CAEA,OAAO;EACL,aAAa,oBAAoB,QAAQ,OAAO;EAChD,YAAY,YAAY,MAAS;GAC/B,OAAO,IAAI,SAA8B,SAAS,WAAW;IAC3D,MAAM,UAAU,iBAAiB;KAC/B,OAAO,IAAI,MAAM,sCAAsC,CAAC;IAC1D,GAAG,SAAS;IAEZ,QACG,MAAM,UAAU;KACf,aAAa,OAAO;KACpB,QAAQ,KAAK;IACf,CAAC,CAAC,CACD,OAAO,UAAU;KAChB,aAAa,OAAO;KACpB,OAAO,KAAK;IACd,CAAC;GACL,CAAC;EACH;EACA,QAAQ;GACN,OAAO,IAAI,SAAe,SAAS,WAAW;IAC5C,OAAO,OAAO,UAAU;KACtB,IAAI,OAAO;MACT,OAAO,KAAK;MACZ;KACF;KACA,QAAQ;IACV,CAAC;GACH,CAAC;EACH;CACF;AACF","names":[],"sources":["../../src/oauth/local-callback.ts"],"version":3,"file":"local-callback.js","sourceRoot":""}
@@ -1,5 +1,5 @@
1
1
  export declare function generatePkcePair(): {
2
- verifier: string;
3
- challenge: string;
2
+ verifier: string;
3
+ challenge: string;
4
4
  };
5
5
  export declare function generateStateToken(): string;
@@ -1,13 +1,17 @@
1
1
  import { createHash, randomBytes } from "node:crypto";
2
2
  function toBase64Url(buffer) {
3
- return buffer.toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/g, "");
3
+ return buffer.toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/g, "");
4
4
  }
5
5
  export function generatePkcePair() {
6
- const verifier = toBase64Url(randomBytes(32));
7
- const challenge = toBase64Url(createHash("sha256").update(verifier).digest());
8
- return { verifier, challenge };
6
+ const verifier = toBase64Url(randomBytes(32));
7
+ const challenge = toBase64Url(createHash("sha256").update(verifier).digest());
8
+ return {
9
+ verifier,
10
+ challenge
11
+ };
9
12
  }
10
13
  export function generateStateToken() {
11
- return toBase64Url(randomBytes(24));
14
+ return toBase64Url(randomBytes(24));
12
15
  }
16
+
13
17
  //# sourceMappingURL=pkce.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"pkce.js","sourceRoot":"","sources":["../../src/oauth/pkce.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAEtD,SAAS,WAAW,CAAC,MAAc;IACjC,OAAO,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;AAC/F,CAAC;AAED,MAAM,UAAU,gBAAgB;IAC9B,MAAM,QAAQ,GAAG,WAAW,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,CAAC;IAC9C,MAAM,SAAS,GAAG,WAAW,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC;IAE9E,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC;AACjC,CAAC;AAED,MAAM,UAAU,kBAAkB;IAChC,OAAO,WAAW,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,CAAC;AACtC,CAAC"}
1
+ {"mappings":"AAAA,SAAS,YAAY,mBAAmB;AAExC,SAAS,YAAY,QAAwB;CAC3C,OAAO,OAAO,SAAS,QAAQ,CAAC,CAAC,QAAQ,OAAO,GAAG,CAAC,CAAC,QAAQ,OAAO,GAAG,CAAC,CAAC,QAAQ,QAAQ,EAAE;AAC7F;AAEA,OAAO,SAAS,mBAA4D;CAC1E,MAAM,WAAW,YAAY,YAAY,EAAE,CAAC;CAC5C,MAAM,YAAY,YAAY,WAAW,QAAQ,CAAC,CAAC,OAAO,QAAQ,CAAC,CAAC,OAAO,CAAC;CAE5E,OAAO;EAAE;EAAU;CAAU;AAC/B;AAEA,OAAO,SAAS,qBAA6B;CAC3C,OAAO,YAAY,YAAY,EAAE,CAAC;AACpC","names":[],"sources":["../../src/oauth/pkce.ts"],"version":3,"file":"pkce.js","sourceRoot":""}
@@ -1,20 +1,20 @@
1
1
  import { type SubjectTokenSource } from "../config.js";
2
2
  export interface ResolveSubjectTokenOptions {
3
- fetchImpl?: typeof fetch;
4
- timeoutMs?: number;
5
- /**
6
- * Override process.env. Lets tests inject GHA-style env vars without
7
- * mutating the real environment.
8
- */
9
- env?: Record<string, string | undefined>;
3
+ fetchImpl?: typeof fetch;
4
+ timeoutMs?: number;
5
+ /**
6
+ * Override process.env. Lets tests inject GHA-style env vars without
7
+ * mutating the real environment.
8
+ */
9
+ env?: Record<string, string | undefined>;
10
10
  }
11
11
  /**
12
- * Read the platform-supplied JWT that the plugin will present as the subject
13
- * token (or assertion) for the `jwt_bearer` and `token_exchange` flows.
14
- *
15
- * Each source resolves fresh on every call — we never cache the JWT itself,
16
- * only the OIDC access token it gets exchanged for. K8s projected SA tokens
17
- * rotate; GHA OIDC tokens are short-lived (~10 min); both are cheap to
18
- * re-fetch on demand.
19
- */
12
+ * Read the platform-supplied JWT that the plugin will present as the subject
13
+ * token (or assertion) for the `jwt_bearer` and `token_exchange` flows.
14
+ *
15
+ * Each source resolves fresh on every call — we never cache the JWT itself,
16
+ * only the OIDC access token it gets exchanged for. K8s projected SA tokens
17
+ * rotate; GHA OIDC tokens are short-lived (~10 min); both are cheap to
18
+ * re-fetch on demand.
19
+ */
20
20
  export declare function resolveSubjectToken(source: SubjectTokenSource, options?: ResolveSubjectTokenOptions): Promise<string>;
@@ -2,85 +2,80 @@ import { readFile } from "node:fs/promises";
2
2
  import { DEFAULT_K8S_SA_TOKEN_PATH } from "../config.js";
3
3
  import { readResponseBodyPreview, scrubSecrets } from "./http-utils.js";
4
4
  /**
5
- * Read the platform-supplied JWT that the plugin will present as the subject
6
- * token (or assertion) for the `jwt_bearer` and `token_exchange` flows.
7
- *
8
- * Each source resolves fresh on every call — we never cache the JWT itself,
9
- * only the OIDC access token it gets exchanged for. K8s projected SA tokens
10
- * rotate; GHA OIDC tokens are short-lived (~10 min); both are cheap to
11
- * re-fetch on demand.
12
- */
5
+ * Read the platform-supplied JWT that the plugin will present as the subject
6
+ * token (or assertion) for the `jwt_bearer` and `token_exchange` flows.
7
+ *
8
+ * Each source resolves fresh on every call — we never cache the JWT itself,
9
+ * only the OIDC access token it gets exchanged for. K8s projected SA tokens
10
+ * rotate; GHA OIDC tokens are short-lived (~10 min); both are cheap to
11
+ * re-fetch on demand.
12
+ */
13
13
  export async function resolveSubjectToken(source, options = {}) {
14
- switch (source.type) {
15
- case "github_actions":
16
- return resolveGithubActionsToken(source.audience, options);
17
- case "kubernetes_sa":
18
- return readJwtFile(source.tokenPath ?? DEFAULT_K8S_SA_TOKEN_PATH, "kubernetes_sa");
19
- case "file":
20
- return readJwtFile(source.path, "file");
21
- case "env":
22
- return resolveEnvToken(source.var, options.env ?? process.env);
23
- }
14
+ switch (source.type) {
15
+ case "github_actions": return resolveGithubActionsToken(source.audience, options);
16
+ case "kubernetes_sa": return readJwtFile(source.tokenPath ?? DEFAULT_K8S_SA_TOKEN_PATH, "kubernetes_sa");
17
+ case "file": return readJwtFile(source.path, "file");
18
+ case "env": return resolveEnvToken(source.var, options.env ?? process.env);
19
+ }
24
20
  }
25
21
  async function readJwtFile(path, sourceLabel) {
26
- let raw;
27
- try {
28
- raw = await readFile(path, "utf8");
29
- }
30
- catch (error) {
31
- const code = error.code;
32
- if (code === "ENOENT") {
33
- throw new Error(`subjectTokenSource (${sourceLabel}): no file at ${path} — check the mount/path`);
34
- }
35
- throw new Error(`subjectTokenSource (${sourceLabel}): failed to read ${path}: ${error instanceof Error ? error.message : String(error)}`);
36
- }
37
- const trimmed = raw.trim();
38
- if (trimmed.length === 0) {
39
- throw new Error(`subjectTokenSource (${sourceLabel}): file at ${path} is empty`);
40
- }
41
- return trimmed;
22
+ let raw;
23
+ try {
24
+ raw = await readFile(path, "utf8");
25
+ } catch (error) {
26
+ const code = error.code;
27
+ if (code === "ENOENT") {
28
+ throw new Error(`subjectTokenSource (${sourceLabel}): no file at ${path} — check the mount/path`);
29
+ }
30
+ throw new Error(`subjectTokenSource (${sourceLabel}): failed to read ${path}: ${error instanceof Error ? error.message : String(error)}`);
31
+ }
32
+ const trimmed = raw.trim();
33
+ if (trimmed.length === 0) {
34
+ throw new Error(`subjectTokenSource (${sourceLabel}): file at ${path} is empty`);
35
+ }
36
+ return trimmed;
42
37
  }
43
38
  function resolveEnvToken(name, env) {
44
- const value = env[name];
45
- if (typeof value !== "string" || value.trim().length === 0) {
46
- throw new Error(`subjectTokenSource (env): ${name} is not set or is empty`);
47
- }
48
- return value.trim();
39
+ const value = env[name];
40
+ if (typeof value !== "string" || value.trim().length === 0) {
41
+ throw new Error(`subjectTokenSource (env): ${name} is not set or is empty`);
42
+ }
43
+ return value.trim();
49
44
  }
50
45
  async function resolveGithubActionsToken(audience, options) {
51
- const env = options.env ?? process.env;
52
- const requestUrl = env.ACTIONS_ID_TOKEN_REQUEST_URL;
53
- const requestToken = env.ACTIONS_ID_TOKEN_REQUEST_TOKEN;
54
- if (!requestUrl || !requestToken) {
55
- throw new Error(`subjectTokenSource (github_actions): ACTIONS_ID_TOKEN_REQUEST_URL and ACTIONS_ID_TOKEN_REQUEST_TOKEN must be set — this only works inside a GitHub Actions job with \`permissions: { id-token: write }\``);
56
- }
57
- const url = new URL(requestUrl);
58
- url.searchParams.set("audience", audience);
59
- const fetchImpl = options.fetchImpl ?? fetch;
60
- const controller = new AbortController();
61
- const timer = setTimeout(() => controller.abort(), options.timeoutMs ?? 15_000);
62
- let response;
63
- try {
64
- response = await fetchImpl(url.toString(), {
65
- method: "GET",
66
- headers: {
67
- Authorization: `Bearer ${requestToken}`,
68
- Accept: "application/json"
69
- },
70
- signal: controller.signal
71
- });
72
- }
73
- finally {
74
- clearTimeout(timer);
75
- }
76
- if (!response.ok) {
77
- const preview = await readResponseBodyPreview(response, 500);
78
- throw new Error(`subjectTokenSource (github_actions): OIDC token request failed (${response.status})${preview ? `: ${scrubSecrets(preview)}` : ""}`);
79
- }
80
- const payload = (await response.json());
81
- if (typeof payload.value !== "string" || payload.value.length === 0) {
82
- throw new Error("subjectTokenSource (github_actions): response had no `value` field — GitHub may have changed the API shape");
83
- }
84
- return payload.value;
46
+ const env = options.env ?? process.env;
47
+ const requestUrl = env.ACTIONS_ID_TOKEN_REQUEST_URL;
48
+ const requestToken = env.ACTIONS_ID_TOKEN_REQUEST_TOKEN;
49
+ if (!requestUrl || !requestToken) {
50
+ throw new Error(`subjectTokenSource (github_actions): ACTIONS_ID_TOKEN_REQUEST_URL and ACTIONS_ID_TOKEN_REQUEST_TOKEN must be set — this only works inside a GitHub Actions job with \`permissions: { id-token: write }\``);
51
+ }
52
+ const url = new URL(requestUrl);
53
+ url.searchParams.set("audience", audience);
54
+ const fetchImpl = options.fetchImpl ?? fetch;
55
+ const controller = new AbortController();
56
+ const timer = setTimeout(() => controller.abort(), options.timeoutMs ?? 15e3);
57
+ let response;
58
+ try {
59
+ response = await fetchImpl(url.toString(), {
60
+ method: "GET",
61
+ headers: {
62
+ Authorization: `Bearer ${requestToken}`,
63
+ Accept: "application/json"
64
+ },
65
+ signal: controller.signal
66
+ });
67
+ } finally {
68
+ clearTimeout(timer);
69
+ }
70
+ if (!response.ok) {
71
+ const preview = await readResponseBodyPreview(response, 500);
72
+ throw new Error(`subjectTokenSource (github_actions): OIDC token request failed (${response.status})${preview ? `: ${scrubSecrets(preview)}` : ""}`);
73
+ }
74
+ const payload = await response.json();
75
+ if (typeof payload.value !== "string" || payload.value.length === 0) {
76
+ throw new Error("subjectTokenSource (github_actions): response had no `value` field — GitHub may have changed the API shape");
77
+ }
78
+ return payload.value;
85
79
  }
80
+
86
81
  //# sourceMappingURL=subject-token.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"subject-token.js","sourceRoot":"","sources":["../../src/oauth/subject-token.ts"],"names":[],"mappings":"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"}
1
+ {"mappings":"AAAA,SAAS,gBAAgB;AAEzB,SAAS,iCAA0D;AACnE,SAAS,yBAAyB,oBAAoB;;;;;;;;;;AAqBtD,OAAO,eAAe,oBACpB,QACA,UAAsC,CAAC,GACtB;CACjB,QAAQ,OAAO,MAAf;EACE,KAAK,kBACH,OAAO,0BAA0B,OAAO,UAAU,OAAO;EAC3D,KAAK,iBACH,OAAO,YAAY,OAAO,aAAa,2BAA2B,eAAe;EACnF,KAAK,QACH,OAAO,YAAY,OAAO,MAAM,MAAM;EACxC,KAAK,OACH,OAAO,gBAAgB,OAAO,KAAK,QAAQ,OAAO,QAAQ,GAAG;CACjE;AACF;AAEA,eAAe,YAAY,MAAc,aAAsC;CAC7E,IAAI;CACJ,IAAI;EACF,MAAM,MAAM,SAAS,MAAM,MAAM;CACnC,SAAS,OAAO;EACd,MAAM,OAAQ,MAAgC;EAC9C,IAAI,SAAS,UAAU;GACrB,MAAM,IAAI,MACR,uBAAuB,YAAY,gBAAgB,KAAK,wBAC1D;EACF;EACA,MAAM,IAAI,MACR,uBAAuB,YAAY,oBAAoB,KAAK,IAC1D,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,GAEzD;CACF;CACA,MAAM,UAAU,IAAI,KAAK;CACzB,IAAI,QAAQ,WAAW,GAAG;EACxB,MAAM,IAAI,MAAM,uBAAuB,YAAY,aAAa,KAAK,UAAU;CACjF;CACA,OAAO;AACT;AAEA,SAAS,gBAAgB,MAAc,KAAiD;CACtF,MAAM,QAAQ,IAAI;CAClB,IAAI,OAAO,UAAU,YAAY,MAAM,KAAK,CAAC,CAAC,WAAW,GAAG;EAC1D,MAAM,IAAI,MAAM,6BAA6B,KAAK,wBAAwB;CAC5E;CACA,OAAO,MAAM,KAAK;AACpB;AAEA,eAAe,0BACb,UACA,SACiB;CACjB,MAAM,MAAM,QAAQ,OAAO,QAAQ;CACnC,MAAM,aAAa,IAAI;CACvB,MAAM,eAAe,IAAI;CAEzB,IAAI,CAAC,cAAc,CAAC,cAAc;EAChC,MAAM,IAAI,MACR,0MACF;CACF;CAEA,MAAM,MAAM,IAAI,IAAI,UAAU;CAC9B,IAAI,aAAa,IAAI,YAAY,QAAQ;CAEzC,MAAM,YAAY,QAAQ,aAAa;CACvC,MAAM,aAAa,IAAI,gBAAgB;CACvC,MAAM,QAAQ,iBAAiB,WAAW,MAAM,GAAG,QAAQ,aAAa,IAAM;CAE9E,IAAI;CACJ,IAAI;EACF,WAAW,MAAM,UAAU,IAAI,SAAS,GAAG;GACzC,QAAQ;GACR,SAAS;IACP,eAAe,UAAU;IACzB,QAAQ;GACV;GACA,QAAQ,WAAW;EACrB,CAAC;CACH,UAAU;EACR,aAAa,KAAK;CACpB;CAEA,IAAI,CAAC,SAAS,IAAI;EAChB,MAAM,UAAU,MAAM,wBAAwB,UAAU,GAAG;EAC3D,MAAM,IAAI,MACR,mEAAmE,SAAS,OAAO,GACjF,UAAU,KAAK,aAAa,OAAO,MAAM,IAE7C;CACF;CAEA,MAAM,UAAW,MAAM,SAAS,KAAK;CACrC,IAAI,OAAO,QAAQ,UAAU,YAAY,QAAQ,MAAM,WAAW,GAAG;EACnE,MAAM,IAAI,MACR,4GACF;CACF;CACA,OAAO,QAAQ;AACjB","names":[],"sources":["../../src/oauth/subject-token.ts"],"version":3,"file":"subject-token.js","sourceRoot":""}
@@ -1,23 +1,23 @@
1
1
  import type { Plugin } from "@opencode-ai/plugin";
2
2
  import { type Logger, type LogLevel } from "./logging.js";
3
3
  /**
4
- * Map OpenCode's host-level `config.logLevel` (uppercase `"DEBUG" | "INFO" |
5
- * "WARN" | "ERROR"`) to this plugin's internal `LogLevel`. Unknown / missing
6
- * values fall through to `undefined` so the caller can apply its own default —
7
- * we never throw on the OpenCode-supplied value because the host owns
8
- * validation of its own field.
9
- *
10
- * Note: host `DEBUG` unlocks this plugin's most-verbose `"trace"` tier (there
11
- * is no separate host `TRACE` level), so running OpenCode with
12
- * `--log-level DEBUG` surfaces the `oauth2_*` trace events emitted across the
13
- * runtime hot paths.
14
- */
4
+ * Map OpenCode's host-level `config.logLevel` (uppercase `"DEBUG" | "INFO" |
5
+ * "WARN" | "ERROR"`) to this plugin's internal `LogLevel`. Unknown / missing
6
+ * values fall through to `undefined` so the caller can apply its own default —
7
+ * we never throw on the OpenCode-supplied value because the host owns
8
+ * validation of its own field.
9
+ *
10
+ * Note: host `DEBUG` unlocks this plugin's most-verbose `"trace"` tier (there
11
+ * is no separate host `TRACE` level), so running OpenCode with
12
+ * `--log-level DEBUG` surfaces the `oauth2_*` trace events emitted across the
13
+ * runtime hot paths.
14
+ */
15
15
  export declare function fromOpenCodeLogLevel(value: unknown): LogLevel | undefined;
16
16
  export interface OpenCodePluginFactoryOptions {
17
- logger?: Logger;
18
- fetchImpl?: typeof fetch;
19
- onAuthorizationUrl?: (url: string) => Promise<void> | void;
20
- cacheDir?: string;
17
+ logger?: Logger;
18
+ fetchImpl?: typeof fetch;
19
+ onAuthorizationUrl?: (url: string) => Promise<void> | void;
20
+ cacheDir?: string;
21
21
  }
22
22
  export declare function createOpencodeOauth2Plugin(factoryOptions?: OpenCodePluginFactoryOptions): Plugin;
23
23
  export declare const OpencodeOauth2Plugin: Plugin;