@37signals/basecamp 0.7.2 → 0.8.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 (96) hide show
  1. package/README.md +80 -1
  2. package/dist/client.d.ts +4 -4
  3. package/dist/client.d.ts.map +1 -1
  4. package/dist/client.js +30 -23
  5. package/dist/client.js.map +1 -1
  6. package/dist/download.d.ts.map +1 -1
  7. package/dist/errors.d.ts +10 -0
  8. package/dist/errors.d.ts.map +1 -1
  9. package/dist/errors.js +7 -1
  10. package/dist/errors.js.map +1 -1
  11. package/dist/generated/metadata.d.ts +32 -0
  12. package/dist/generated/metadata.d.ts.map +1 -0
  13. package/dist/generated/metadata.js +2670 -0
  14. package/dist/generated/metadata.js.map +1 -0
  15. package/dist/generated/{metadata.json → metadata.ts} +98 -45
  16. package/dist/generated/openapi-stripped.json +713 -440
  17. package/dist/generated/path-mapping.d.ts.map +1 -1
  18. package/dist/generated/path-mapping.js +6 -5
  19. package/dist/generated/path-mapping.js.map +1 -1
  20. package/dist/generated/path-mapping.ts +6 -5
  21. package/dist/generated/schema.d.ts +510 -297
  22. package/dist/generated/services/campfires.d.ts +22 -1
  23. package/dist/generated/services/campfires.d.ts.map +1 -1
  24. package/dist/generated/services/campfires.js +33 -1
  25. package/dist/generated/services/campfires.js.map +1 -1
  26. package/dist/generated/services/campfires.ts +46 -1
  27. package/dist/generated/services/card-columns.d.ts +31 -28
  28. package/dist/generated/services/card-columns.d.ts.map +1 -1
  29. package/dist/generated/services/card-columns.js +54 -51
  30. package/dist/generated/services/card-columns.js.map +1 -1
  31. package/dist/generated/services/card-columns.ts +62 -59
  32. package/dist/generated/services/index.d.ts +2 -2
  33. package/dist/generated/services/index.d.ts.map +1 -1
  34. package/dist/generated/services/index.js +2 -2
  35. package/dist/generated/services/index.js.map +1 -1
  36. package/dist/generated/services/index.ts +2 -2
  37. package/dist/generated/services/reports.d.ts +1 -1
  38. package/dist/generated/services/reports.js +1 -1
  39. package/dist/generated/services/reports.ts +1 -1
  40. package/dist/generated/services/todos.d.ts +8 -8
  41. package/dist/generated/services/todos.d.ts.map +1 -1
  42. package/dist/generated/services/todos.js +9 -6
  43. package/dist/generated/services/todos.js.map +1 -1
  44. package/dist/generated/services/todos.ts +12 -9
  45. package/dist/generated/services/tools.d.ts +11 -10
  46. package/dist/generated/services/tools.d.ts.map +1 -1
  47. package/dist/generated/services/tools.js +16 -8
  48. package/dist/generated/services/tools.js.map +1 -1
  49. package/dist/generated/services/tools.ts +21 -13
  50. package/dist/index.d.ts +6 -4
  51. package/dist/index.d.ts.map +1 -1
  52. package/dist/index.js +3 -3
  53. package/dist/index.js.map +1 -1
  54. package/dist/oauth/discovery.d.ts +105 -23
  55. package/dist/oauth/discovery.d.ts.map +1 -1
  56. package/dist/oauth/discovery.js +453 -61
  57. package/dist/oauth/discovery.js.map +1 -1
  58. package/dist/oauth/index.d.ts +2 -2
  59. package/dist/oauth/index.d.ts.map +1 -1
  60. package/dist/oauth/index.js +1 -1
  61. package/dist/oauth/index.js.map +1 -1
  62. package/dist/oauth/interactive-login.d.ts +20 -2
  63. package/dist/oauth/interactive-login.d.ts.map +1 -1
  64. package/dist/oauth/interactive-login.js +58 -4
  65. package/dist/oauth/interactive-login.js.map +1 -1
  66. package/dist/oauth/types.d.ts +54 -2
  67. package/dist/oauth/types.d.ts.map +1 -1
  68. package/dist/security.d.ts +22 -0
  69. package/dist/security.d.ts.map +1 -1
  70. package/dist/security.js +56 -1
  71. package/dist/security.js.map +1 -1
  72. package/dist/services/authorization.d.ts.map +1 -1
  73. package/dist/services/authorization.js +3 -0
  74. package/dist/services/authorization.js.map +1 -1
  75. package/dist/services/base.d.ts.map +1 -1
  76. package/dist/services/base.js +1 -3
  77. package/dist/services/base.js.map +1 -1
  78. package/dist/services/todos-extensions.d.ts +118 -0
  79. package/dist/services/todos-extensions.d.ts.map +1 -0
  80. package/dist/services/todos-extensions.js +113 -0
  81. package/dist/services/todos-extensions.js.map +1 -0
  82. package/dist/services/uploads-extensions.d.ts +33 -0
  83. package/dist/services/uploads-extensions.d.ts.map +1 -0
  84. package/dist/services/uploads-extensions.js +48 -0
  85. package/dist/services/uploads-extensions.js.map +1 -0
  86. package/package.json +7 -4
  87. package/src/generated/{metadata.json → metadata.ts} +98 -45
  88. package/src/generated/openapi-stripped.json +713 -440
  89. package/src/generated/path-mapping.ts +6 -5
  90. package/src/generated/schema.d.ts +510 -297
  91. package/src/generated/services/campfires.ts +46 -1
  92. package/src/generated/services/card-columns.ts +62 -59
  93. package/src/generated/services/index.ts +2 -2
  94. package/src/generated/services/reports.ts +1 -1
  95. package/src/generated/services/todos.ts +12 -9
  96. package/src/generated/services/tools.ts +21 -13
@@ -1,78 +1,261 @@
1
1
  /**
2
2
  * OAuth 2.0 discovery for Basecamp SDK.
3
3
  *
4
- * Fetches OAuth server configuration from the well-known discovery endpoint.
4
+ * Two composable operations plus an orchestrator (SPEC.md §16, communique §2/§3):
5
+ * - discover(issuerURL) — RFC 8414 AS metadata + issuer binding
6
+ * - discoverProtectedResource(origin) — RFC 9728 resource metadata
7
+ * - discoverFromResource(origin, opts) — resource-first selection + fallback
8
+ *
9
+ * All fetches are SSRF-hardened: HTTPS-only origins (localhost exempt), origin
10
+ * parsed/validated with the platform URL parser before any socket opens,
11
+ * redirects suppressed, timeouts bounded, and bodies read under a genuine
12
+ * bounded cap that aborts before the whole oversized body is buffered.
5
13
  */
6
- import { BasecampError } from "../errors.js";
14
+ import { BasecampError, truncateErrorMessage } from "../errors.js";
7
15
  import { isLocalhost } from "../security.js";
16
+ /** Default cap on a discovery response body (1 MiB) — discovery docs are tiny. */
17
+ const MAX_DISCOVERY_BODY_BYTES = 1 * 1024 * 1024;
18
+ /** True iff `value` is an array whose every element is a string. */
19
+ function isStringArray(value) {
20
+ return Array.isArray(value) && value.every((v) => typeof v === "string");
21
+ }
22
+ /**
23
+ * Resolves the caller-supplied body cap to a usable byte count. A finite,
24
+ * non-negative number is honored; anything else (Infinity, NaN, negative, a
25
+ * non-number) falls back to the default so the bounded read can never be
26
+ * silently disabled.
27
+ */
28
+ function resolveMaxBodyBytes(value) {
29
+ return typeof value === "number" && Number.isFinite(value) && value >= 0
30
+ ? value
31
+ : MAX_DISCOVERY_BODY_BYTES;
32
+ }
33
+ /**
34
+ * Hard resource-first selection/validation failure. Thrown — never returned as a
35
+ * fallback — so no consumer can convert it into a Launchpad request.
36
+ */
37
+ export class DiscoverySelectionError extends BasecampError {
38
+ reason;
39
+ constructor(reason, message, options) {
40
+ // Only capability_unavailable is consumer/usage-shaped (validation). Every
41
+ // other reason — including expected_issuer_unavailable — is an AS-metadata
42
+ // fault surfaced as api_error, matching the other four SDKs (an issuer the
43
+ // resource does not advertise is a metadata fault, not caller usage).
44
+ const code = reason === "capability_unavailable"
45
+ ? "validation"
46
+ : "api_error";
47
+ super(code, message, options);
48
+ this.name = "DiscoverySelectionError";
49
+ this.reason = reason;
50
+ }
51
+ }
52
+ /**
53
+ * Default Basecamp/Launchpad OAuth server URL.
54
+ */
55
+ export const LAUNCHPAD_BASE_URL = "https://launchpad.37signals.com";
8
56
  /**
9
- * Discovers OAuth server configuration from the well-known endpoint.
57
+ * Parses a caller- or metadata-supplied origin and enforces the origin-root
58
+ * profile: https (or http+localhost), host present, optional valid port, path
59
+ * empty or exactly "/", and no query/fragment/userinfo. Uses the platform URL
60
+ * parser (never a regex) so bracketed IPv6 and ports agree with the host the
61
+ * client actually dials.
10
62
  *
11
- * Fetches the OAuth 2.0 Authorization Server Metadata from:
12
- * `{baseUrl}/.well-known/oauth-authorization-server`
63
+ * Throws `BasecampError("usage")` on violation a bad *caller* origin is a
64
+ * usage error. Callers validating an *advertised* origin catch and reclassify.
13
65
  *
14
- * @param baseUrl - The OAuth server's base URL (e.g., "https://launchpad.37signals.com")
15
- * @param options - Optional configuration
16
- * @returns The OAuth server configuration
17
- * @throws BasecampError on network or parsing errors
66
+ * @returns the normalized origin (scheme://host[:port], no trailing slash)
67
+ */
68
+ export function requireOriginRoot(raw, label = "origin") {
69
+ // A non-string runtime input (e.g. a Symbol) would throw a native TypeError in
70
+ // RegExp.test/new URL below; surface the documented usage error instead.
71
+ if (typeof raw !== "string") {
72
+ throw new BasecampError("usage", `Invalid ${label}: not a valid absolute URL: ${String(raw)}`);
73
+ }
74
+ // Reject C0 controls, space, and backslash up front: WHATWG URL silently strips
75
+ // tabs/newlines/surrounding spaces and converts backslashes to forward slashes
76
+ // for special schemes, so a malformed spelling ("https:\\host", "https://host\n")
77
+ // would be cleaned and accepted. None is legitimate in an origin root.
78
+ if (/[\u0000-\u0020\\]/.test(raw)) {
79
+ throw new BasecampError("usage", `${label} contains invalid characters: ${raw}`);
80
+ }
81
+ // WHATWG recovers a missing or extra-slash authority ("https:host",
82
+ // "https:///host") into a clean origin. Require an explicit "://" followed by a
83
+ // non-empty authority (a non-slash character) so those spellings are rejected.
84
+ const authoritySep = raw.indexOf("://");
85
+ if (authoritySep < 0 || raw[authoritySep + 3] === undefined || raw[authoritySep + 3] === "/") {
86
+ throw new BasecampError("usage", `${label} must be an origin root: ${raw}`);
87
+ }
88
+ let url;
89
+ try {
90
+ url = new URL(raw);
91
+ }
92
+ catch {
93
+ throw new BasecampError("usage", `Invalid ${label}: not a valid absolute URL: ${raw}`);
94
+ }
95
+ const isLocalhostHttp = url.protocol === "http:" && isLocalhost(url.hostname);
96
+ if (url.protocol !== "https:" && !isLocalhostHttp) {
97
+ throw new BasecampError("usage", `${label} must use HTTPS (or http on localhost): ${raw}`);
98
+ }
99
+ if (!url.hostname) {
100
+ throw new BasecampError("usage", `${label} has no host: ${raw}`);
101
+ }
102
+ // The WHATWG URL parser normalizes delimiter-only userinfo ("https://@host",
103
+ // "https://:@host") to EMPTY username/password and drops it from href, so the
104
+ // parsed fields alone cannot catch it — also inspect the raw authority (the
105
+ // scheme check above guarantees raw starts with http(s)://).
106
+ const rawAuthority = raw.slice(raw.indexOf("//") + 2).split(/[/?#]/, 1)[0] ?? "";
107
+ if (url.username || url.password || rawAuthority.includes("@")) {
108
+ throw new BasecampError("usage", `${label} must not contain userinfo: ${raw}`);
109
+ }
110
+ // WHATWG `URL` exposes a bare trailing "?" or "#" (e.g. "https://host?") as an
111
+ // EMPTY search/hash and normalizes it away from `origin`, so the parsed fields
112
+ // alone miss the delimiter. Also scan the raw input: any "?"/"#" past the
113
+ // scheme is a query/fragment delimiter here (host/port carry neither, and the
114
+ // path is constrained to ""/"/" below).
115
+ if (url.search || url.hash || raw.includes("?") || raw.includes("#")) {
116
+ throw new BasecampError("usage", `${label} must not contain a query or fragment: ${raw}`);
117
+ }
118
+ if (url.pathname !== "" && url.pathname !== "/") {
119
+ throw new BasecampError("usage", `${label} must be an origin root (no path): ${raw}`);
120
+ }
121
+ // WHATWG resolves dot-segments ("/a/..", "/%2e%2e") to "/", so url.pathname above
122
+ // misses a path that was present in the raw input. Scan the raw path (everything
123
+ // from the first "/" after the authority — "?"/"#" are already rejected above).
124
+ const afterAuthority = raw.slice(raw.indexOf("://") + 3);
125
+ const rawPathStart = afterAuthority.indexOf("/");
126
+ if (rawPathStart >= 0 && afterAuthority.slice(rawPathStart) !== "/") {
127
+ throw new BasecampError("usage", `${label} must be an origin root (no path): ${raw}`);
128
+ }
129
+ // `new URL("https://h:notaport")` throws above and WHATWG rejects ports > 65535,
130
+ // but it ACCEPTS port 0 and keeps it in the origin. The origin-root profile (like
131
+ // the other SDKs) rejects any port outside 1–65535, so a caller/advertised issuer
132
+ // using `:0` fails as usage / invalid_issuer_origin rather than proceeding to a fetch.
133
+ if (url.port !== "" && (Number(url.port) < 1 || Number(url.port) > 65535)) {
134
+ throw new BasecampError("usage", `${label} has an invalid port: ${raw}`);
135
+ }
136
+ // WHATWG normalizes a dangling port ("https://host:") to url.port === "", so the
137
+ // check above misses it; scan the raw authority for a trailing ":" (an IPv6
138
+ // authority ends with "]", so only a trailing ":" is a dangling port).
139
+ if (rawAuthority.endsWith(":")) {
140
+ throw new BasecampError("usage", `${label} has an invalid port: ${raw}`);
141
+ }
142
+ // Note: a surviving url has a structurally valid (possibly default) port. url.origin
143
+ // drops a default port and any trailing slash — exactly the normalized origin we want.
144
+ return url.origin;
145
+ }
146
+ /**
147
+ * True when an issuer string is a valid origin root equal to Launchpad's.
18
148
  *
19
- * @example
20
- * ```ts
21
- * const config = await discover("https://launchpad.37signals.com");
22
- * console.log(config.tokenEndpoint);
23
- * // => "https://launchpad.37signals.com/authorization/token"
24
- * ```
149
+ * The comparison runs both sides through {@link requireOriginRoot}, so an
150
+ * advertised look-alike that is *not* a clean origin root — e.g.
151
+ * `https://launchpad.37signals.com/path` (path), userinfo, or a query — is not
152
+ * treated as Launchpad. It stays a non-Launchpad candidate and later fails hard
153
+ * (`ambiguous_issuers` / `invalid_issuer_origin`) rather than being silently
154
+ * excluded from selection. A trailing-slash-only origin root still matches
155
+ * because `requireOriginRoot` normalizes it away.
156
+ *
157
+ * Exported so the login orchestrator derives the legacy-token decision from the
158
+ * same predicate the selection heuristic uses.
25
159
  */
26
- export async function discover(baseUrl, options = {}) {
27
- const { fetch: customFetch = globalThis.fetch, timeoutMs = 10000 } = options;
28
- // Validate HTTPS before making any network request (allow localhost for testing)
160
+ export function isLaunchpadIssuer(issuer) {
29
161
  try {
30
- const parsed = new URL(baseUrl);
31
- if (parsed.protocol !== "https:" && !isLocalhost(parsed.hostname)) {
32
- throw new BasecampError("validation", `OAuth discovery base URL must use HTTPS: ${baseUrl}`);
162
+ return requireOriginRoot(issuer, "issuer") === requireOriginRoot(LAUNCHPAD_BASE_URL, "issuer");
163
+ }
164
+ catch {
165
+ return false;
166
+ }
167
+ }
168
+ /**
169
+ * Reads a Response body under a bounded, streaming cap. Aborts (cancels the
170
+ * stream) the moment the accumulated size exceeds `maxBytes`, so an oversized
171
+ * body is never fully buffered — real memory bounding, not a post-hoc check.
172
+ *
173
+ * Exported for reuse by the device-flow transport (same bounding, different
174
+ * `label` in the error message); not re-exported from the package index.
175
+ */
176
+ export async function readBodyBounded(response, maxBytes, label = "OAuth discovery") {
177
+ const body = response.body;
178
+ if (!body) {
179
+ // No readable stream available (some mock transports): guard the buffered
180
+ // length instead. Real runtimes always expose response.body.
181
+ const text = await response.text();
182
+ if (new TextEncoder().encode(text).length > maxBytes) {
183
+ throw new BasecampError("api_error", `${label} response exceeds size cap`);
33
184
  }
185
+ return text;
34
186
  }
35
- catch (err) {
36
- if (err instanceof BasecampError)
37
- throw err;
38
- throw new BasecampError("validation", `Invalid OAuth discovery base URL: ${baseUrl}`);
187
+ const reader = body.getReader();
188
+ const chunks = [];
189
+ let total = 0;
190
+ let exceeded = false;
191
+ for (;;) {
192
+ const { done, value } = await reader.read();
193
+ if (done)
194
+ break;
195
+ if (value) {
196
+ total += value.byteLength;
197
+ if (total > maxBytes) {
198
+ exceeded = true;
199
+ break;
200
+ }
201
+ chunks.push(value);
202
+ }
203
+ }
204
+ // Release the stream without blocking on cancellation (some transports hang on
205
+ // an awaited cancel()); the point is that we stopped reading past the cap.
206
+ void reader.cancel().catch(() => { });
207
+ if (exceeded) {
208
+ throw new BasecampError("api_error", `${label} response exceeds size cap`);
39
209
  }
40
- // Normalize base URL (remove trailing slash)
41
- const normalizedBase = baseUrl.replace(/\/$/, "");
42
- const discoveryUrl = `${normalizedBase}/.well-known/oauth-authorization-server`;
43
- // Create abort controller for timeout
210
+ const merged = new Uint8Array(total);
211
+ let offset = 0;
212
+ for (const c of chunks) {
213
+ merged.set(c, offset);
214
+ offset += c.byteLength;
215
+ }
216
+ return new TextDecoder().decode(merged);
217
+ }
218
+ /**
219
+ * SSRF-hardened GET of a discovery document. The origin must already be
220
+ * validated (via {@link requireOriginRoot}); this suppresses redirects, bounds
221
+ * the timeout, reads the body under a bounded cap, and maps non-2xx → api_error.
222
+ */
223
+ async function fetchDiscoveryDocument(url, options) {
224
+ const { fetch: customFetch = globalThis.fetch, timeoutMs = 10000 } = options;
225
+ const maxBodyBytes = resolveMaxBodyBytes(options.maxBodyBytes);
44
226
  const controller = new AbortController();
45
227
  const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
46
228
  try {
47
- const response = await customFetch(discoveryUrl, {
229
+ const response = await customFetch(url, {
48
230
  method: "GET",
49
- headers: {
50
- Accept: "application/json",
51
- },
231
+ headers: { Accept: "application/json" },
52
232
  signal: controller.signal,
233
+ // Suppress redirects: never chase an attacker-influenced Location. A 3xx
234
+ // surfaces below as a non-2xx api_error rather than a followed request.
235
+ redirect: "manual",
53
236
  });
54
- if (!response.ok) {
55
- const body = await response.text().catch(() => "");
56
- throw new BasecampError("network", `OAuth discovery failed with status ${response.status}: ${body}`, { httpStatus: response.status });
237
+ if (!response.ok || (response.status >= 300 && response.status < 400)) {
238
+ // Drain-and-cap defensively; body is unused on the error path. Truncate
239
+ // before embedding: the bounded read still permits up to maxBodyBytes (1 MiB
240
+ // default), and interpolating that whole body into the error string risks log
241
+ // spam / memory pressure and could echo sensitive server content. Cap it to
242
+ // 500 chars to match Go/Python/Ruby's truncated discovery error messages.
243
+ const body = await readBodyBounded(response, maxBodyBytes).catch(() => "");
244
+ throw new BasecampError("api_error", `OAuth discovery failed with status ${response.status}: ${truncateErrorMessage(body)}`, { httpStatus: response.status });
57
245
  }
58
- const data = (await response.json());
59
- // Validate required fields
60
- if (!data.issuer || !data.authorization_endpoint || !data.token_endpoint) {
61
- throw new BasecampError("api_error", "Invalid OAuth discovery response: missing required fields");
246
+ const text = await readBodyBounded(response, maxBodyBytes);
247
+ try {
248
+ return JSON.parse(text);
249
+ }
250
+ catch (err) {
251
+ throw new BasecampError("api_error", "Failed to parse OAuth discovery response", {
252
+ cause: err instanceof Error ? err : undefined,
253
+ });
62
254
  }
63
- return {
64
- issuer: data.issuer,
65
- authorizationEndpoint: data.authorization_endpoint,
66
- tokenEndpoint: data.token_endpoint,
67
- registrationEndpoint: data.registration_endpoint,
68
- scopesSupported: data.scopes_supported,
69
- codeChallengeMethodsSupported: data.code_challenge_methods_supported,
70
- };
71
255
  }
72
256
  catch (err) {
73
- if (err instanceof BasecampError) {
257
+ if (err instanceof BasecampError)
74
258
  throw err;
75
- }
76
259
  if (err instanceof Error) {
77
260
  if (err.name === "AbortError") {
78
261
  throw new BasecampError("network", "OAuth discovery request timed out", {
@@ -94,23 +277,232 @@ export async function discover(baseUrl, options = {}) {
94
277
  }
95
278
  }
96
279
  /**
97
- * Default Basecamp/Launchpad OAuth server URL.
98
- */
99
- export const LAUNCHPAD_BASE_URL = "https://launchpad.37signals.com";
100
- /**
101
- * Discovers OAuth configuration from Basecamp's Launchpad server.
102
- *
103
- * Convenience function that calls discover() with the Launchpad base URL.
280
+ * Discovers OAuth 2.0 Authorization Server Metadata (RFC 8414) from
281
+ * `{issuerURL}/.well-known/oauth-authorization-server`, and binds it: the
282
+ * returned `issuer` must equal the requested issuer by code-point (no
283
+ * normalization beyond origin-root parsing). `token_endpoint` is required;
284
+ * `authorization_endpoint` is optional (device-only servers omit it).
104
285
  *
105
- * @param options - Optional configuration
106
- * @returns The OAuth server configuration
286
+ * @param baseUrl - The OAuth server's issuer origin (e.g. "https://launchpad.37signals.com")
287
+ * @throws BasecampError("usage") on a malformed origin, api_error on invalid metadata
107
288
  *
108
289
  * @example
109
290
  * ```ts
110
- * const config = await discoverLaunchpad();
111
- * // Use config.authorizationEndpoint to start OAuth flow
291
+ * const config = await discover("https://launchpad.37signals.com");
292
+ * console.log(config.tokenEndpoint);
112
293
  * ```
113
294
  */
295
+ export async function discover(baseUrl, options = {}) {
296
+ const issuerOrigin = requireOriginRoot(baseUrl, "OAuth discovery base URL");
297
+ // Bind against the caller's raw baseUrl (RFC 8414 §3.3, SPEC.md §16 "NO
298
+ // normalization"); the normalized origin is only for the fetch URL.
299
+ return discoverAndBind(issuerOrigin, baseUrl, options);
300
+ }
301
+ /**
302
+ * Fetch AS metadata from `issuerOrigin`'s well-known URL but bind the returned
303
+ * `issuer` against `bindIssuer` by code-point. Routing and binding are distinct:
304
+ * fetch from the normalized origin, bind against the caller's raw identifier
305
+ * (which may spell a trailing slash or explicit default port). Public `discover`
306
+ * passes its raw `baseUrl` as `bindIssuer`; `discoverFromResource` passes the
307
+ * advertised issuer. Not exported — no public binding override.
308
+ */
309
+ async function discoverAndBind(issuerOrigin, bindIssuer, options) {
310
+ const discoveryUrl = `${issuerOrigin}/.well-known/oauth-authorization-server`;
311
+ const data = (await fetchDiscoveryDocument(discoveryUrl, options));
312
+ if (typeof data !== "object" || data === null) {
313
+ throw new BasecampError("api_error", "OAuth discovery response is not a JSON object");
314
+ }
315
+ return parseAndBindAsMetadata(data, bindIssuer);
316
+ }
317
+ /**
318
+ * Module-private structural marker for an RFC 8414 issuer-binding failure: the
319
+ * AS metadata's `issuer` did not equal the requested issuer by code-point.
320
+ *
321
+ * `discoverFromResource` branches on this via `instanceof` to classify
322
+ * `issuer_mismatch` vs `as_fetch_failed` — a structured tag, never a match on
323
+ * the message text. Kept private to this module and NOT re-exported from the
324
+ * package index: to any external caller of `discover`, this is an ordinary
325
+ * `api_error` `BasecampError`.
326
+ */
327
+ class IssuerBindingError extends BasecampError {
328
+ constructor(message) {
329
+ super("api_error", message);
330
+ this.name = "IssuerBindingError";
331
+ }
332
+ }
333
+ /**
334
+ * Validates AS metadata and binds `issuer` to `expectedIssuerOrigin` by
335
+ * code-point. Universal validation only: `issuer`+`token_endpoint` present and
336
+ * non-empty; any present endpoint field non-empty. Per-grant endpoint checks
337
+ * are the consumer's responsibility.
338
+ */
339
+ function parseAndBindAsMetadata(data, expectedIssuerOrigin) {
340
+ if (typeof data.issuer !== "string" || !data.issuer) {
341
+ throw new BasecampError("api_error", "Invalid OAuth discovery response: missing required fields (issuer)");
342
+ }
343
+ // RFC 8414 §3.3/§4: issuer identical by code-point. No normalization. Thrown
344
+ // as the structural IssuerBindingError so discoverFromResource can classify it
345
+ // without matching the message text.
346
+ if (data.issuer !== expectedIssuerOrigin) {
347
+ throw new IssuerBindingError(`OAuth issuer mismatch: metadata issuer "${data.issuer}" does not equal "${expectedIssuerOrigin}"`);
348
+ }
349
+ if (typeof data.token_endpoint !== "string" || !data.token_endpoint) {
350
+ throw new BasecampError("api_error", "Invalid OAuth discovery response: missing required fields (token_endpoint)");
351
+ }
352
+ // Every present endpoint field must be a non-empty string (reject "", arrays,
353
+ // numbers, etc. — a non-string endpoint is malformed, not merely empty).
354
+ for (const [key, value] of Object.entries(data)) {
355
+ if (key.endsWith("_endpoint") && value !== undefined && (typeof value !== "string" || value === "")) {
356
+ throw new BasecampError("api_error", `Invalid OAuth discovery response: invalid ${key}`);
357
+ }
358
+ }
359
+ // grant_types_supported, when present, must be an array of strings — never a
360
+ // bare string (substring-matching it would falsely enable a grant).
361
+ if (data.grant_types_supported !== undefined && !isStringArray(data.grant_types_supported)) {
362
+ throw new BasecampError("api_error", "Invalid OAuth discovery response: grant_types_supported must be an array of strings");
363
+ }
364
+ // code_challenge_methods_supported, when present, must likewise be an array of
365
+ // strings — a bare string would be substring-matched during PKCE negotiation
366
+ // and could falsely appear to advertise "S256".
367
+ if (data.code_challenge_methods_supported !== undefined &&
368
+ !isStringArray(data.code_challenge_methods_supported)) {
369
+ throw new BasecampError("api_error", "Invalid OAuth discovery response: code_challenge_methods_supported must be an array of strings");
370
+ }
371
+ // scopes_supported, when present, must be an array of strings — a bare string
372
+ // ("read write") or null would otherwise reach callers typed as an array and
373
+ // yield substring/null behavior instead of an api_error.
374
+ if (data.scopes_supported !== undefined && !isStringArray(data.scopes_supported)) {
375
+ throw new BasecampError("api_error", "Invalid OAuth discovery response: scopes_supported must be an array of strings");
376
+ }
377
+ return {
378
+ issuer: data.issuer,
379
+ authorizationEndpoint: data.authorization_endpoint,
380
+ tokenEndpoint: data.token_endpoint,
381
+ deviceAuthorizationEndpoint: data.device_authorization_endpoint,
382
+ registrationEndpoint: data.registration_endpoint,
383
+ scopesSupported: data.scopes_supported,
384
+ grantTypesSupported: data.grant_types_supported,
385
+ codeChallengeMethodsSupported: data.code_challenge_methods_supported,
386
+ };
387
+ }
388
+ /**
389
+ * Discovers RFC 9728 protected-resource metadata from
390
+ * `{resourceOrigin}/.well-known/oauth-protected-resource`. `resource` is
391
+ * required and must equal the requested origin by code-point.
392
+ * `authorization_servers` is preserved distinctly as absent vs `[]`.
393
+ *
394
+ * @throws BasecampError("usage") on a malformed caller origin, api_error on
395
+ * invalid metadata
396
+ */
397
+ export async function discoverProtectedResource(resourceOrigin, options = {}) {
398
+ const origin = requireOriginRoot(resourceOrigin, "resource origin");
399
+ const url = `${origin}/.well-known/oauth-protected-resource`;
400
+ const data = (await fetchDiscoveryDocument(url, options));
401
+ if (typeof data !== "object" || data === null) {
402
+ throw new BasecampError("api_error", "Resource metadata response is not a JSON object");
403
+ }
404
+ if (typeof data.resource !== "string" || !data.resource) {
405
+ throw new BasecampError("api_error", "Invalid resource metadata: missing required field (resource)");
406
+ }
407
+ // Bind the resource identifier to the requested identifier (the raw caller
408
+ // origin), code-point exact, NO normalization (RFC 9728 §3.3, SPEC.md §16): the
409
+ // well-known URL is built from the normalized origin, but doc.resource must be
410
+ // identical to what the caller supplied.
411
+ if (data.resource !== resourceOrigin) {
412
+ throw new BasecampError("api_error", `Resource identifier mismatch: metadata resource "${data.resource}" does not equal "${resourceOrigin}"`);
413
+ }
414
+ // authorization_servers, when present, MUST be an array of strings. A bare
415
+ // string slipped through and was iterated char-by-char during selection; a
416
+ // present JSON null is likewise malformed (an array is required when the key is
417
+ // present) — not a present-empty list. Reject every present non-array value so
418
+ // the orchestrator classifies it as resource_discovery_failed rather than
419
+ // silently taking no_as_advertised.
420
+ let authorizationServers;
421
+ if (Object.prototype.hasOwnProperty.call(data, "authorization_servers")) {
422
+ const raw = data.authorization_servers;
423
+ if (isStringArray(raw)) {
424
+ authorizationServers = raw;
425
+ }
426
+ else {
427
+ throw new BasecampError("api_error", "Invalid resource metadata: authorization_servers must be an array of strings when present");
428
+ }
429
+ }
430
+ return { resource: data.resource, authorizationServers };
431
+ }
432
+ /**
433
+ * Resource-first discovery orchestrator (SPEC.md §16). Composes RFC 9728 + RFC
434
+ * 8414 and applies the stage-sensitive fallback state machine.
435
+ *
436
+ * Returns `{ kind: "selected", config, issuer }` or `{ kind: "fallback", reason }`
437
+ * where `reason ∈ {resource_discovery_failed, no_as_advertised}`. Every hard
438
+ * failure throws {@link DiscoverySelectionError} — callers MUST NOT convert a
439
+ * throw into a Launchpad request.
440
+ */
441
+ export async function discoverFromResource(resourceOrigin, options = {}) {
442
+ const { expectedIssuer, ...discoverOptions } = options;
443
+ // --- Hop 1: resource metadata. Failure here is soft (before selection). ---
444
+ // Pass the RAW resourceOrigin so binding is code-point-exact against the caller's
445
+ // identifier (SPEC.md §16); discoverProtectedResource normalizes only its fetch
446
+ // URL. A malformed caller origin surfaces as usage (re-raised below), not a fallback.
447
+ let resource;
448
+ try {
449
+ resource = await discoverProtectedResource(resourceOrigin, discoverOptions);
450
+ }
451
+ catch (err) {
452
+ if (err instanceof BasecampError && err.code === "usage")
453
+ throw err;
454
+ return { kind: "fallback", reason: "resource_discovery_failed" };
455
+ }
456
+ const advertised = resource.authorizationServers ?? [];
457
+ // --- Selection ---
458
+ let selectedIssuer;
459
+ if (expectedIssuer !== undefined) {
460
+ const match = advertised.find((s) => s === expectedIssuer);
461
+ if (!match) {
462
+ throw new DiscoverySelectionError("expected_issuer_unavailable", `Expected issuer "${expectedIssuer}" is not advertised by the resource`);
463
+ }
464
+ selectedIssuer = match;
465
+ }
466
+ else {
467
+ // Deduplicate exact issuer strings first: a resource that advertises the same
468
+ // non-Launchpad issuer more than once denotes ONE issuer, not an ambiguous set.
469
+ const nonLaunchpad = [...new Set(advertised.filter((s) => !isLaunchpadIssuer(s)))];
470
+ if (nonLaunchpad.length >= 2) {
471
+ throw new DiscoverySelectionError("ambiguous_issuers", `Multiple non-Launchpad issuers advertised; pass expectedIssuer to disambiguate: ${nonLaunchpad.join(", ")}`);
472
+ }
473
+ if (nonLaunchpad.length === 0) {
474
+ // Valid resource metadata omits BC5 — soft fallback (before selection).
475
+ return { kind: "fallback", reason: "no_as_advertised" };
476
+ }
477
+ selectedIssuer = nonLaunchpad[0];
478
+ }
479
+ // --- BC5 is now committed: every subsequent failure is fatal (no Launchpad). ---
480
+ let issuerOrigin;
481
+ try {
482
+ issuerOrigin = requireOriginRoot(selectedIssuer, "advertised issuer");
483
+ }
484
+ catch (err) {
485
+ throw new DiscoverySelectionError("invalid_issuer_origin", `Advertised issuer "${selectedIssuer}" is not a valid origin root`, { cause: err instanceof Error ? err : undefined });
486
+ }
487
+ let config;
488
+ try {
489
+ // Fetch from the normalized origin, but bind against the exact advertised
490
+ // issuer string (selectedIssuer), not the normalized origin.
491
+ config = await discoverAndBind(issuerOrigin, selectedIssuer, discoverOptions);
492
+ }
493
+ catch (err) {
494
+ // Distinguish issuer-binding mismatch from a generic fetch failure via the
495
+ // structural marker (never the message text).
496
+ if (err instanceof IssuerBindingError) {
497
+ throw new DiscoverySelectionError("issuer_mismatch", err.message, { cause: err });
498
+ }
499
+ throw new DiscoverySelectionError("as_fetch_failed", `AS metadata fetch failed for committed issuer "${issuerOrigin}": ${err instanceof Error ? err.message : String(err)}`, { cause: err instanceof Error ? err : undefined });
500
+ }
501
+ return { kind: "selected", config, issuer: config.issuer };
502
+ }
503
+ /**
504
+ * Discovers OAuth configuration from Basecamp's Launchpad server.
505
+ */
114
506
  export async function discoverLaunchpad(options = {}) {
115
507
  return discover(LAUNCHPAD_BASE_URL, options);
116
508
  }
@@ -1 +1 @@
1
- {"version":3,"file":"discovery.js","sourceRoot":"","sources":["../../src/oauth/discovery.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAyB7C;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,CAAC,KAAK,UAAU,QAAQ,CAC5B,OAAe,EACf,UAA2B,EAAE;IAE7B,MAAM,EAAE,KAAK,EAAE,WAAW,GAAG,UAAU,CAAC,KAAK,EAAE,SAAS,GAAG,KAAK,EAAE,GAAG,OAAO,CAAC;IAE7E,iFAAiF;IACjF,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC;QAChC,IAAI,MAAM,CAAC,QAAQ,KAAK,QAAQ,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC;YAClE,MAAM,IAAI,aAAa,CAAC,YAAY,EAAE,4CAA4C,OAAO,EAAE,CAAC,CAAC;QAC/F,CAAC;IACH,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,GAAG,YAAY,aAAa;YAAE,MAAM,GAAG,CAAC;QAC5C,MAAM,IAAI,aAAa,CAAC,YAAY,EAAE,qCAAqC,OAAO,EAAE,CAAC,CAAC;IACxF,CAAC;IAED,6CAA6C;IAC7C,MAAM,cAAc,GAAG,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IAClD,MAAM,YAAY,GAAG,GAAG,cAAc,yCAAyC,CAAC;IAEhF,sCAAsC;IACtC,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;IACzC,MAAM,SAAS,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,SAAS,CAAC,CAAC;IAElE,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,WAAW,CAAC,YAAY,EAAE;YAC/C,MAAM,EAAE,KAAK;YACb,OAAO,EAAE;gBACP,MAAM,EAAE,kBAAkB;aAC3B;YACD,MAAM,EAAE,UAAU,CAAC,MAAM;SAC1B,CAAC,CAAC;QAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;YACnD,MAAM,IAAI,aAAa,CACrB,SAAS,EACT,sCAAsC,QAAQ,CAAC,MAAM,KAAK,IAAI,EAAE,EAChE,EAAE,UAAU,EAAE,QAAQ,CAAC,MAAM,EAAE,CAChC,CAAC;QACJ,CAAC;QAED,MAAM,IAAI,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAyB,CAAC;QAE7D,2BAA2B;QAC3B,IAAI,CAAC,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,sBAAsB,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,CAAC;YACzE,MAAM,IAAI,aAAa,CACrB,WAAW,EACX,2DAA2D,CAC5D,CAAC;QACJ,CAAC;QAED,OAAO;YACL,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,qBAAqB,EAAE,IAAI,CAAC,sBAAsB;YAClD,aAAa,EAAE,IAAI,CAAC,cAAc;YAClC,oBAAoB,EAAE,IAAI,CAAC,qBAAqB;YAChD,eAAe,EAAE,IAAI,CAAC,gBAAgB;YACtC,6BAA6B,EAAE,IAAI,CAAC,gCAAgC;SACrE,CAAC;IACJ,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,GAAG,YAAY,aAAa,EAAE,CAAC;YACjC,MAAM,GAAG,CAAC;QACZ,CAAC;QAED,IAAI,GAAG,YAAY,KAAK,EAAE,CAAC;YACzB,IAAI,GAAG,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;gBAC9B,MAAM,IAAI,aAAa,CAAC,SAAS,EAAE,mCAAmC,EAAE;oBACtE,KAAK,EAAE,GAAG;oBACV,SAAS,EAAE,IAAI;iBAChB,CAAC,CAAC;YACL,CAAC;YAED,MAAM,IAAI,aAAa,CAAC,SAAS,EAAE,2BAA2B,GAAG,CAAC,OAAO,EAAE,EAAE;gBAC3E,KAAK,EAAE,GAAG;gBACV,SAAS,EAAE,IAAI;aAChB,CAAC,CAAC;QACL,CAAC;QAED,MAAM,IAAI,aAAa,CAAC,SAAS,EAAE,2CAA2C,EAAE;YAC9E,SAAS,EAAE,IAAI;SAChB,CAAC,CAAC;IACL,CAAC;YAAS,CAAC;QACT,YAAY,CAAC,SAAS,CAAC,CAAC;IAC1B,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,iCAAiC,CAAC;AAEpE;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,UAA2B,EAAE;IAE7B,OAAO,QAAQ,CAAC,kBAAkB,EAAE,OAAO,CAAC,CAAC;AAC/C,CAAC"}
1
+ {"version":3,"file":"discovery.js","sourceRoot":"","sources":["../../src/oauth/discovery.ts"],"names":[],"mappings":"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"}
@@ -37,8 +37,8 @@
37
37
  * }
38
38
  * ```
39
39
  */
40
- export type { OAuthConfig, OAuthToken, ExchangeRequest, RefreshRequest, RawTokenResponse, OAuthErrorResponse, } from "./types.js";
41
- export { discover, discoverLaunchpad, LAUNCHPAD_BASE_URL, type DiscoverOptions, } from "./discovery.js";
40
+ export type { OAuthConfig, OAuthToken, ExchangeRequest, RefreshRequest, RawTokenResponse, OAuthErrorResponse, ProtectedResourceMetadata, FallbackReason, DiscoverySelectionErrorReason, DiscoverFromResourceResult, } from "./types.js";
41
+ export { discover, discoverProtectedResource, discoverFromResource, discoverLaunchpad, requireOriginRoot, DiscoverySelectionError, LAUNCHPAD_BASE_URL, type DiscoverOptions, type DiscoverFromResourceOptions, } from "./discovery.js";
42
42
  export { exchangeCode, refreshToken, isTokenExpired, type TokenOptions, } from "./exchange.js";
43
43
  export { generatePKCE, generateState, type PKCE, } from "./pkce.js";
44
44
  export { buildAuthorizationUrl, type AuthorizeParams, } from "./authorize.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/oauth/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AAGH,YAAY,EACV,WAAW,EACX,UAAU,EACV,eAAe,EACf,cAAc,EACd,gBAAgB,EAChB,kBAAkB,GACnB,MAAM,YAAY,CAAC;AAGpB,OAAO,EACL,QAAQ,EACR,iBAAiB,EACjB,kBAAkB,EAClB,KAAK,eAAe,GACrB,MAAM,gBAAgB,CAAC;AAGxB,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,cAAc,EACd,KAAK,YAAY,GAClB,MAAM,eAAe,CAAC;AAGvB,OAAO,EACL,YAAY,EACZ,aAAa,EACb,KAAK,IAAI,GACV,MAAM,WAAW,CAAC;AAGnB,OAAO,EACL,qBAAqB,EACrB,KAAK,eAAe,GACrB,MAAM,gBAAgB,CAAC;AAGxB,OAAO,EACL,cAAc,EACd,KAAK,UAAU,GAChB,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EACL,YAAY,EACZ,KAAK,mBAAmB,GACzB,MAAM,oBAAoB,CAAC;AAG5B,OAAO,EACL,mBAAmB,EACnB,KAAK,cAAc,EACnB,KAAK,qBAAqB,GAC3B,MAAM,sBAAsB,CAAC;AAG9B,OAAO,EACL,uBAAuB,EACvB,KAAK,uBAAuB,GAC7B,MAAM,wBAAwB,CAAC;AAGhC,OAAO,EACL,gBAAgB,GACjB,MAAM,eAAe,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/oauth/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AAGH,YAAY,EACV,WAAW,EACX,UAAU,EACV,eAAe,EACf,cAAc,EACd,gBAAgB,EAChB,kBAAkB,EAClB,yBAAyB,EACzB,cAAc,EACd,6BAA6B,EAC7B,0BAA0B,GAC3B,MAAM,YAAY,CAAC;AAGpB,OAAO,EACL,QAAQ,EACR,yBAAyB,EACzB,oBAAoB,EACpB,iBAAiB,EACjB,iBAAiB,EACjB,uBAAuB,EACvB,kBAAkB,EAClB,KAAK,eAAe,EACpB,KAAK,2BAA2B,GACjC,MAAM,gBAAgB,CAAC;AAGxB,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,cAAc,EACd,KAAK,YAAY,GAClB,MAAM,eAAe,CAAC;AAGvB,OAAO,EACL,YAAY,EACZ,aAAa,EACb,KAAK,IAAI,GACV,MAAM,WAAW,CAAC;AAGnB,OAAO,EACL,qBAAqB,EACrB,KAAK,eAAe,GACrB,MAAM,gBAAgB,CAAC;AAGxB,OAAO,EACL,cAAc,EACd,KAAK,UAAU,GAChB,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EACL,YAAY,EACZ,KAAK,mBAAmB,GACzB,MAAM,oBAAoB,CAAC;AAG5B,OAAO,EACL,mBAAmB,EACnB,KAAK,cAAc,EACnB,KAAK,qBAAqB,GAC3B,MAAM,sBAAsB,CAAC;AAG9B,OAAO,EACL,uBAAuB,EACvB,KAAK,uBAAuB,GAC7B,MAAM,wBAAwB,CAAC;AAGhC,OAAO,EACL,gBAAgB,GACjB,MAAM,eAAe,CAAC"}
@@ -38,7 +38,7 @@
38
38
  * ```
39
39
  */
40
40
  // Discovery
41
- export { discover, discoverLaunchpad, LAUNCHPAD_BASE_URL, } from "./discovery.js";
41
+ export { discover, discoverProtectedResource, discoverFromResource, discoverLaunchpad, requireOriginRoot, DiscoverySelectionError, LAUNCHPAD_BASE_URL, } from "./discovery.js";
42
42
  // Token exchange
43
43
  export { exchangeCode, refreshToken, isTokenExpired, } from "./exchange.js";
44
44
  // PKCE utilities
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/oauth/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AAYH,YAAY;AACZ,OAAO,EACL,QAAQ,EACR,iBAAiB,EACjB,kBAAkB,GAEnB,MAAM,gBAAgB,CAAC;AAExB,iBAAiB;AACjB,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,cAAc,GAEf,MAAM,eAAe,CAAC;AAEvB,iBAAiB;AACjB,OAAO,EACL,YAAY,EACZ,aAAa,GAEd,MAAM,WAAW,CAAC;AAEnB,oBAAoB;AACpB,OAAO,EACL,qBAAqB,GAEtB,MAAM,gBAAgB,CAAC;AAExB,cAAc;AACd,OAAO,EACL,cAAc,GAEf,MAAM,kBAAkB,CAAC;AAE1B,gBAAgB;AAChB,OAAO,EACL,YAAY,GAEb,MAAM,oBAAoB,CAAC;AAE5B,kBAAkB;AAClB,OAAO,EACL,mBAAmB,GAGpB,MAAM,sBAAsB,CAAC;AAE9B,oBAAoB;AACpB,OAAO,EACL,uBAAuB,GAExB,MAAM,wBAAwB,CAAC;AAEhC,WAAW;AACX,OAAO,EACL,gBAAgB,GACjB,MAAM,eAAe,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/oauth/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AAgBH,YAAY;AACZ,OAAO,EACL,QAAQ,EACR,yBAAyB,EACzB,oBAAoB,EACpB,iBAAiB,EACjB,iBAAiB,EACjB,uBAAuB,EACvB,kBAAkB,GAGnB,MAAM,gBAAgB,CAAC;AAExB,iBAAiB;AACjB,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,cAAc,GAEf,MAAM,eAAe,CAAC;AAEvB,iBAAiB;AACjB,OAAO,EACL,YAAY,EACZ,aAAa,GAEd,MAAM,WAAW,CAAC;AAEnB,oBAAoB;AACpB,OAAO,EACL,qBAAqB,GAEtB,MAAM,gBAAgB,CAAC;AAExB,cAAc;AACd,OAAO,EACL,cAAc,GAEf,MAAM,kBAAkB,CAAC;AAE1B,gBAAgB;AAChB,OAAO,EACL,YAAY,GAEb,MAAM,oBAAoB,CAAC;AAE5B,kBAAkB;AAClB,OAAO,EACL,mBAAmB,GAGpB,MAAM,sBAAsB,CAAC;AAE9B,oBAAoB;AACpB,OAAO,EACL,uBAAuB,GAExB,MAAM,wBAAwB,CAAC;AAEhC,WAAW;AACX,OAAO,EACL,gBAAgB,GACjB,MAAM,eAAe,CAAC"}