@37signals/basecamp 0.10.0 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +146 -14
- package/dist/client.d.ts +4 -4
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +206 -133
- package/dist/client.js.map +1 -1
- package/dist/generated/metadata.d.ts.map +1 -1
- package/dist/generated/metadata.js +7 -17
- package/dist/generated/metadata.js.map +1 -1
- package/dist/generated/metadata.ts +7 -17
- package/dist/generated/openapi-stripped.json +7 -130
- package/dist/generated/path-mapping.d.ts.map +1 -1
- package/dist/generated/path-mapping.js +0 -1
- package/dist/generated/path-mapping.js.map +1 -1
- package/dist/generated/path-mapping.ts +0 -1
- package/dist/generated/schema.d.ts +0 -96
- package/dist/generated/services/everything.d.ts +0 -20
- package/dist/generated/services/everything.d.ts.map +1 -1
- package/dist/generated/services/everything.js +0 -22
- package/dist/generated/services/everything.js.map +1 -1
- package/dist/generated/services/everything.ts +0 -38
- package/dist/generated/services/index.d.ts +1 -1
- package/dist/generated/services/index.d.ts.map +1 -1
- package/dist/generated/services/index.js +1 -1
- package/dist/generated/services/index.js.map +1 -1
- package/dist/generated/services/index.ts +1 -1
- package/dist/hooks.d.ts.map +1 -1
- package/dist/hooks.js +4 -1
- package/dist/hooks.js.map +1 -1
- package/dist/index.d.ts +6 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -1
- package/dist/index.js.map +1 -1
- package/dist/oauth/device-errors.d.ts +29 -0
- package/dist/oauth/device-errors.d.ts.map +1 -0
- package/dist/oauth/device-errors.js +52 -0
- package/dist/oauth/device-errors.js.map +1 -0
- package/dist/oauth/device-login.d.ts +50 -0
- package/dist/oauth/device-login.d.ts.map +1 -0
- package/dist/oauth/device-login.js +118 -0
- package/dist/oauth/device-login.js.map +1 -0
- package/dist/oauth/device.d.ts +112 -0
- package/dist/oauth/device.d.ts.map +1 -0
- package/dist/oauth/device.js +746 -0
- package/dist/oauth/device.js.map +1 -0
- package/dist/oauth/exchange.d.ts.map +1 -1
- package/dist/oauth/exchange.js +75 -9
- package/dist/oauth/exchange.js.map +1 -1
- package/dist/oauth/index.d.ts +4 -1
- package/dist/oauth/index.d.ts.map +1 -1
- package/dist/oauth/index.js +4 -0
- package/dist/oauth/index.js.map +1 -1
- package/dist/oauth/limits.d.ts +15 -0
- package/dist/oauth/limits.d.ts.map +1 -0
- package/dist/oauth/limits.js +15 -0
- package/dist/oauth/limits.js.map +1 -0
- package/dist/oauth/token-manager.d.ts.map +1 -1
- package/dist/oauth/token-manager.js +15 -4
- package/dist/oauth/token-manager.js.map +1 -1
- package/dist/oauth/token-store.d.ts.map +1 -1
- package/dist/oauth/token-store.js +6 -0
- package/dist/oauth/token-store.js.map +1 -1
- package/dist/oauth/types.d.ts +35 -3
- package/dist/oauth/types.d.ts.map +1 -1
- package/dist/pagination.d.ts +5 -1
- package/dist/pagination.d.ts.map +1 -1
- package/dist/pagination.js.map +1 -1
- package/dist/services/base.d.ts +3 -1
- package/dist/services/base.d.ts.map +1 -1
- package/dist/services/base.js +16 -5
- package/dist/services/base.js.map +1 -1
- package/package.json +1 -1
- package/src/generated/metadata.ts +7 -17
- package/src/generated/openapi-stripped.json +7 -130
- package/src/generated/path-mapping.ts +0 -1
- package/src/generated/schema.d.ts +0 -96
- package/src/generated/services/everything.ts +0 -38
- package/src/generated/services/index.ts +1 -1
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RFC 8628 device login orchestration.
|
|
3
|
+
*
|
|
4
|
+
* `performDeviceLogin` accepts an ALREADY-SELECTED OAuthConfig (from discovery),
|
|
5
|
+
* guards the device capability, requests a device code, surfaces it through a
|
|
6
|
+
* display hook, and polls for the token.
|
|
7
|
+
*/
|
|
8
|
+
import { BasecampError } from "../errors.js";
|
|
9
|
+
import { DeviceFlowError } from "./device-errors.js";
|
|
10
|
+
import { requestDeviceAuthorization, pollDeviceToken, throwIfAborted, validatedClockSample, DEVICE_CODE_GRANT_TYPE, defaultClock, } from "./device.js";
|
|
11
|
+
/**
|
|
12
|
+
* Runs the full device authorization grant against a selected config.
|
|
13
|
+
*
|
|
14
|
+
* @throws DeviceFlowError("unavailable") when the config cannot do device flow;
|
|
15
|
+
* other DeviceFlowError reasons on denial/expiry/transport/cancellation.
|
|
16
|
+
*/
|
|
17
|
+
export async function performDeviceLogin(options) {
|
|
18
|
+
const { config, clientId, scope, display, signal, clock = defaultClock, fetch: customFetch, sleepFn } = options;
|
|
19
|
+
// Capability guard requires BOTH the endpoint and the advertised grant type.
|
|
20
|
+
// Require a genuine array: a manually-constructed config could supply
|
|
21
|
+
// grantTypesSupported as a string, and String.prototype.includes would
|
|
22
|
+
// substring-match and wrongly pass the guard (the other SDKs defend the same
|
|
23
|
+
// way — Python/Ruby check the collection type, Go/Kotlin are statically typed).
|
|
24
|
+
const supportsDeviceGrant = Array.isArray(config.grantTypesSupported) && config.grantTypesSupported.includes(DEVICE_CODE_GRANT_TYPE);
|
|
25
|
+
if (!config.deviceAuthorizationEndpoint || !supportsDeviceGrant) {
|
|
26
|
+
throw new DeviceFlowError("unavailable", "The selected authorization server does not support the device authorization grant");
|
|
27
|
+
}
|
|
28
|
+
// A non-function display is a usage error, not a late TypeError: it is the
|
|
29
|
+
// only mechanism surfacing the verification code, so dereferencing it AFTER
|
|
30
|
+
// the request would mint a code nobody can approve. Reject before any
|
|
31
|
+
// network activity (matching Go) — a JS caller can pass anything.
|
|
32
|
+
if (typeof display !== "function") {
|
|
33
|
+
throw new BasecampError("usage", "performDeviceLogin requires a display callback function");
|
|
34
|
+
}
|
|
35
|
+
// Honor a cancellation raised before any work: an already-aborted signal
|
|
36
|
+
// must not fire the authorization request or surface a code via display.
|
|
37
|
+
throwIfAborted(signal);
|
|
38
|
+
const auth = await requestDeviceAuthorization({
|
|
39
|
+
deviceAuthorizationEndpoint: config.deviceAuthorizationEndpoint,
|
|
40
|
+
clientId,
|
|
41
|
+
scope,
|
|
42
|
+
fetch: customFetch,
|
|
43
|
+
// Threaded so an abort DURING the request cancels it in flight and
|
|
44
|
+
// surfaces as the contractual cancelled — never a code shown post-cancel.
|
|
45
|
+
signal,
|
|
46
|
+
});
|
|
47
|
+
// Anchor the code's lifetime at ISSUANCE — the response's arrival, per
|
|
48
|
+
// SPEC §16 — before the display hook, so a slow display eats into the
|
|
49
|
+
// deadline instead of resetting it. Expiry past this point is arbitrated
|
|
50
|
+
// by the server (expired_token), so receipt-anchoring fails safe.
|
|
51
|
+
// Validated like the poller's samples — a malformed injected clock is the
|
|
52
|
+
// typed usage error before the code is surfaced.
|
|
53
|
+
const issuedAt = validatedClockSample(clock(), "performDeviceLogin");
|
|
54
|
+
// Re-check before surfacing the code: an abort racing the request's
|
|
55
|
+
// completion — or landing during the clock sample above (itself a callback
|
|
56
|
+
// seam) — must not reach the display hook.
|
|
57
|
+
throwIfAborted(signal);
|
|
58
|
+
// Race an async display hook against the abort signal: a hook awaiting user
|
|
59
|
+
// interaction must not hold a cancelled flow open until it settles. On
|
|
60
|
+
// abort the hook's promise is left to settle on its own (JS cannot cancel
|
|
61
|
+
// it) — the flow rejects promptly and never proceeds to polling.
|
|
62
|
+
await new Promise((resolve, reject) => {
|
|
63
|
+
const onAbort = () => reject(new DeviceFlowError("cancelled", "Device flow cancelled"));
|
|
64
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
65
|
+
if (signal?.aborted) {
|
|
66
|
+
// The abort won between the entry throwIfAborted and the registration
|
|
67
|
+
// above: the event is already spent, so the once-listener would never
|
|
68
|
+
// fire — and never auto-remove. Drop it before rejecting manually
|
|
69
|
+
// (same race handling as the sleep helper).
|
|
70
|
+
signal.removeEventListener("abort", onAbort);
|
|
71
|
+
onAbort();
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
Promise.resolve()
|
|
75
|
+
.then(() => {
|
|
76
|
+
// The abort can win between scheduling and this deferred callback —
|
|
77
|
+
// the outer promise has already rejected then, but this callback still
|
|
78
|
+
// runs. Re-check so a cancelled flow never surfaces the code.
|
|
79
|
+
if (signal?.aborted)
|
|
80
|
+
return undefined;
|
|
81
|
+
return display(auth);
|
|
82
|
+
})
|
|
83
|
+
.then(() => {
|
|
84
|
+
signal?.removeEventListener("abort", onAbort);
|
|
85
|
+
resolve();
|
|
86
|
+
}, (err) => {
|
|
87
|
+
signal?.removeEventListener("abort", onAbort);
|
|
88
|
+
reject(err);
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
// Deduct the elapsed display time from the issuance anchor so polling gets
|
|
92
|
+
// only the REMAINING lifetime. `expiresIn` is seconds; the clock is ms, so
|
|
93
|
+
// convert the elapsed span before subtracting.
|
|
94
|
+
const remainingSeconds = auth.expiresIn - (validatedClockSample(clock(), "performDeviceLogin") - issuedAt) / 1000;
|
|
95
|
+
// Re-check after the clock read: an abort landing after the display race
|
|
96
|
+
// settled (its listener is already removed) must still win over expiry —
|
|
97
|
+
// cancellation beats every other classification.
|
|
98
|
+
throwIfAborted(signal);
|
|
99
|
+
if (remainingSeconds <= 0) {
|
|
100
|
+
throw new DeviceFlowError("expired", "Device code expired before authorization completed");
|
|
101
|
+
}
|
|
102
|
+
return pollDeviceToken({
|
|
103
|
+
tokenEndpoint: config.tokenEndpoint,
|
|
104
|
+
clientId,
|
|
105
|
+
deviceCode: auth.deviceCode,
|
|
106
|
+
interval: auth.interval,
|
|
107
|
+
expiresIn: remainingSeconds,
|
|
108
|
+
// Absolute issuance-anchored deadline: clock time elapsing between the
|
|
109
|
+
// remainingSeconds computation above and pollDeviceToken's own clock()
|
|
110
|
+
// anchor would otherwise be handed BACK to the code's lifetime.
|
|
111
|
+
deadlineAtMs: issuedAt + auth.expiresIn * 1000,
|
|
112
|
+
signal,
|
|
113
|
+
clock,
|
|
114
|
+
fetch: customFetch,
|
|
115
|
+
sleepFn,
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
//# sourceMappingURL=device-login.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"device-login.js","sourceRoot":"","sources":["../../src/oauth/device-login.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RFC 8628 device authorization grant — request + poll.
|
|
3
|
+
*
|
|
4
|
+
* `requestDeviceAuthorization` obtains a device/user code pair;
|
|
5
|
+
* `pollDeviceToken` runs the §3.5 polling loop against the token endpoint. Both
|
|
6
|
+
* are TLS-guarded. The polling clock is monotonic and injectable for tests.
|
|
7
|
+
*/
|
|
8
|
+
import { MAX_TOKEN_LIFETIME_SECONDS } from "./limits.js";
|
|
9
|
+
export { MAX_TOKEN_LIFETIME_SECONDS };
|
|
10
|
+
import type { DeviceAuthorization, OAuthToken } from "./types.js";
|
|
11
|
+
/** URN grant type for the device authorization grant. */
|
|
12
|
+
export declare const DEVICE_CODE_GRANT_TYPE = "urn:ietf:params:oauth:grant-type:device_code";
|
|
13
|
+
/** Monotonic clock in milliseconds. Injectable so tests can advance time. */
|
|
14
|
+
export type MonotonicClock = () => number;
|
|
15
|
+
/**
|
|
16
|
+
* Default monotonic clock (ms): `performance.now()`, which every supported
|
|
17
|
+
* Node/browser runtime provides. The `Date.now()` branch is a last resort for
|
|
18
|
+
* exotic runtimes without `performance` — wall-clock, so not strictly monotonic;
|
|
19
|
+
* inject a real monotonic clock there if NTP steps matter.
|
|
20
|
+
*/
|
|
21
|
+
export declare const defaultClock: MonotonicClock;
|
|
22
|
+
/**
|
|
23
|
+
* Validate one sample from an injected clock seam. `Number.isFinite` performs
|
|
24
|
+
* no coercion, so a bigint, string, or Symbol sample fails exactly like a
|
|
25
|
+
* NaN/Infinity one — the typed usage error, never a raw TypeError out of later
|
|
26
|
+
* deadline arithmetic. Shared by the poller and the login orchestrator so both
|
|
27
|
+
* validate EVERY sample the same way.
|
|
28
|
+
*/
|
|
29
|
+
export declare function validatedClockSample(sample: unknown, entry: string): number;
|
|
30
|
+
/**
|
|
31
|
+
* Parameters for {@link requestDeviceAuthorization}.
|
|
32
|
+
*/
|
|
33
|
+
export interface RequestDeviceAuthorizationParams {
|
|
34
|
+
/** The device_authorization_endpoint from discovery. */
|
|
35
|
+
deviceAuthorizationEndpoint: string;
|
|
36
|
+
/** The public client id (e.g. "basecamp-cli"). */
|
|
37
|
+
clientId: string;
|
|
38
|
+
/** Requested scope. Omitted from the request entirely when unset → server default `read`. */
|
|
39
|
+
scope?: string;
|
|
40
|
+
/** Custom fetch (testing). */
|
|
41
|
+
fetch?: typeof globalThis.fetch;
|
|
42
|
+
/** Request timeout in milliseconds (default: 30000). */
|
|
43
|
+
timeoutMs?: number;
|
|
44
|
+
/** Cancellation signal — aborting rejects with DeviceFlowError("cancelled"). */
|
|
45
|
+
signal?: AbortSignal;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Requests a device/user code pair (RFC 8628 §3.1–3.2).
|
|
49
|
+
*
|
|
50
|
+
* @throws DeviceFlowError("cancelled") when the signal aborts;
|
|
51
|
+
* DeviceFlowError("transport") on a network failure; BasecampError on
|
|
52
|
+
* validation / non-2xx.
|
|
53
|
+
*/
|
|
54
|
+
export declare function requestDeviceAuthorization(params: RequestDeviceAuthorizationParams): Promise<DeviceAuthorization>;
|
|
55
|
+
/**
|
|
56
|
+
* Parameters for {@link pollDeviceToken}.
|
|
57
|
+
*/
|
|
58
|
+
export interface PollDeviceTokenParams {
|
|
59
|
+
/** The token_endpoint from discovery. */
|
|
60
|
+
tokenEndpoint: string;
|
|
61
|
+
/** The public client id. */
|
|
62
|
+
clientId: string;
|
|
63
|
+
/** The device_code from {@link requestDeviceAuthorization}. */
|
|
64
|
+
deviceCode: string;
|
|
65
|
+
/** Polling interval in seconds. */
|
|
66
|
+
interval: number;
|
|
67
|
+
/** Code lifetime in seconds (monotonic deadline). */
|
|
68
|
+
expiresIn: number;
|
|
69
|
+
/**
|
|
70
|
+
* Absolute monotonic deadline (ms, same clock as `clock`) anchoring the
|
|
71
|
+
* code's expiry at ISSUANCE. When set it overrides the `clock() + expiresIn`
|
|
72
|
+
* anchoring so time elapsed before this call is never handed back to the
|
|
73
|
+
* lifetime. Must be finite and no later than `expiresIn` seconds from now —
|
|
74
|
+
* a deadline can only shorten the validated lifetime, never extend it.
|
|
75
|
+
*/
|
|
76
|
+
deadlineAtMs?: number;
|
|
77
|
+
/** Cancellation signal — aborting rejects with DeviceFlowError("cancelled"). */
|
|
78
|
+
signal?: AbortSignal;
|
|
79
|
+
/** Injectable monotonic clock (ms). Default performance.now(). */
|
|
80
|
+
clock?: MonotonicClock;
|
|
81
|
+
/** Custom fetch (testing). */
|
|
82
|
+
fetch?: typeof globalThis.fetch;
|
|
83
|
+
/** Per-request timeout in milliseconds (default: 30000). */
|
|
84
|
+
timeoutMs?: number;
|
|
85
|
+
/**
|
|
86
|
+
* Injectable sleep (testing). Receives the wait in ms and the cancellation
|
|
87
|
+
* signal; defaults to a real, abortable timer. Lets tests assert the interval
|
|
88
|
+
* schedule (slow_down, backoff) without real delays.
|
|
89
|
+
*/
|
|
90
|
+
sleepFn?: (ms: number, signal?: AbortSignal) => Promise<void>;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Polls the token endpoint until the user approves, denies, or the codes expire
|
|
94
|
+
* (RFC 8628 §3.4–3.5). Handles authorization_pending, sustained slow_down (+5s),
|
|
95
|
+
* a monotonic expiry deadline, exponential backoff on connection timeouts, and
|
|
96
|
+
* cooperative cancellation.
|
|
97
|
+
*/
|
|
98
|
+
export declare function pollDeviceToken(params: PollDeviceTokenParams): Promise<OAuthToken>;
|
|
99
|
+
/**
|
|
100
|
+
* Validates a Retry-After delta for the 429 poll contract (SPEC §16): a
|
|
101
|
+
* positive integral number of seconds. A representable delta beyond
|
|
102
|
+
* MAX_DEVICE_SECONDS (the shared 32-bit-ms timer bound) CLAMPS to the
|
|
103
|
+
* ceiling — the wait rule clips to the remaining code lifetime, honoring the
|
|
104
|
+
* throttle. Anything else — missing, an HTTP-date, fractional, non-positive,
|
|
105
|
+
* or unrepresentable (beyond 2^53) — returns 0 so the caller falls back to
|
|
106
|
+
* the current interval. Trimming is ASCII SP/HTAB only (RFC 9110
|
|
107
|
+
* OWS) — NOT String.prototype.trim(), whose Unicode whitespace (NBSP above
|
|
108
|
+
* all) would trim a malformed value into validity.
|
|
109
|
+
*/
|
|
110
|
+
export declare function parseRetryAfterSeconds(header: string | null): number;
|
|
111
|
+
export declare function throwIfAborted(signal?: AbortSignal): void;
|
|
112
|
+
//# sourceMappingURL=device.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"device.d.ts","sourceRoot":"","sources":["../../src/oauth/device.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAMH,OAAO,EAAE,0BAA0B,EAAE,MAAM,aAAa,CAAC;AAIzD,OAAO,EAAE,0BAA0B,EAAE,CAAC;AACtC,OAAO,KAAK,EAAE,mBAAmB,EAAE,UAAU,EAAwC,MAAM,YAAY,CAAC;AAExG,yDAAyD;AACzD,eAAO,MAAM,sBAAsB,iDAAiD,CAAC;AAwDrF,6EAA6E;AAC7E,MAAM,MAAM,cAAc,GAAG,MAAM,MAAM,CAAC;AAE1C;;;;;GAKG;AACH,eAAO,MAAM,YAAY,EAAE,cAC0C,CAAC;AAEtE;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAK3E;AAcD;;GAEG;AACH,MAAM,WAAW,gCAAgC;IAC/C,wDAAwD;IACxD,2BAA2B,EAAE,MAAM,CAAC;IACpC,kDAAkD;IAClD,QAAQ,EAAE,MAAM,CAAC;IACjB,6FAA6F;IAC7F,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,8BAA8B;IAC9B,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;IAChC,wDAAwD;IACxD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gFAAgF;IAChF,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAED;;;;;;GAMG;AACH,wBAAsB,0BAA0B,CAC9C,MAAM,EAAE,gCAAgC,GACvC,OAAO,CAAC,mBAAmB,CAAC,CA+H9B;AA+ED;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,yCAAyC;IACzC,aAAa,EAAE,MAAM,CAAC;IACtB,4BAA4B;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,+DAA+D;IAC/D,UAAU,EAAE,MAAM,CAAC;IACnB,mCAAmC;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,qDAAqD;IACrD,SAAS,EAAE,MAAM,CAAC;IAClB;;;;;;OAMG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,gFAAgF;IAChF,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,kEAAkE;IAClE,KAAK,CAAC,EAAE,cAAc,CAAC;IACvB,8BAA8B;IAC9B,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;IAChC,4DAA4D;IAC5D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,OAAO,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAC/D;AAED;;;;;GAKG;AACH,wBAAsB,eAAe,CAAC,MAAM,EAAE,qBAAqB,GAAG,OAAO,CAAC,UAAU,CAAC,CA8MxF;AAMD;;;;;;;;;;GAUG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAoBpE;AAoQD,wBAAgB,cAAc,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,IAAI,CAIzD"}
|