@shelbyb/daywalker-sdk 0.6.0 → 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.
- package/README.md +168 -22
- package/dist/cli.js +102 -16
- package/dist/client.d.ts +81 -50
- package/dist/client.js +1015 -201
- package/dist/config.d.ts +12 -1
- package/dist/config.js +34 -2
- package/dist/crypto/digest.js +3 -2
- package/dist/crypto/dpop.d.ts +38 -1
- package/dist/crypto/dpop.js +124 -6
- package/dist/crypto/encoding.js +2 -0
- package/dist/crypto/index.d.ts +6 -4
- package/dist/crypto/index.js +4 -3
- package/dist/crypto/key-api.d.ts +69 -0
- package/dist/crypto/key-api.js +217 -0
- package/dist/crypto/keys.d.ts +5 -0
- package/dist/crypto/keys.js +25 -15
- package/dist/crypto/signatures.d.ts +13 -24
- package/dist/crypto/signatures.js +41 -84
- package/dist/crypto/webcrypto.d.ts +39 -0
- package/dist/crypto/webcrypto.js +26 -0
- package/dist/express.d.ts +2 -1
- package/dist/express.js +12 -32
- package/dist/index.d.ts +4 -4
- package/dist/index.js +2 -2
- package/dist/keystore/file.d.ts +14 -0
- package/dist/keystore/file.js +77 -0
- package/dist/keystore/index.d.ts +18 -0
- package/dist/keystore/index.js +71 -0
- package/dist/middleware.d.ts +27 -3
- package/dist/middleware.js +75 -22
- package/dist/next.d.ts +5 -3
- package/dist/next.js +38 -42
- package/dist/types.d.ts +129 -4
- package/package.json +11 -1
- package/dist/signing.d.ts +0 -3
- package/dist/signing.js +0 -2
package/dist/client.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type ResolvedConfig } from "./config.js";
|
|
2
|
-
import { type DaywalkerConfig, type TokenSet, type GetTokensOptions, type PublicJwk, type RetryOptions, type SelfCheckResult, type TokenPayload, type ValidateResult } from "./types.js";
|
|
2
|
+
import { type DaywalkerConfig, type ValidateTokenOptions, type TokenSet, type GetTokensOptions, type License, type LicenseOptions, type ConfigBundle, type PublicJwk, type RetryOptions, type SelfCheckResult, type TokenPayload, type ValidateResult } from "./types.js";
|
|
3
3
|
/** Validation results kept in memory; the least recently used are evicted past this. */
|
|
4
4
|
export declare const MAX_VALIDATION_CACHE_ENTRIES = 1000;
|
|
5
5
|
/** Longest 429 `Retry-After` waited out by default (`retry.maxRetryAfterMs`); longer ones return the 429. */
|
|
@@ -17,21 +17,45 @@ export type DaywalkerFetchInit = Omit<RequestInit, "body"> & {
|
|
|
17
17
|
/** Sent as `Idempotency-Key` (unless already set) and lets non-idempotent requests retry network errors. */
|
|
18
18
|
idempotencyKey?: string;
|
|
19
19
|
};
|
|
20
|
+
/**
|
|
21
|
+
* Longest a successful validation is cached (5 minutes), whatever `cacheTtlMs` says, so a revoked token
|
|
22
|
+
* can't stay accepted for long.
|
|
23
|
+
*/
|
|
24
|
+
export declare const MAX_CACHE_TTL_MS = 300000;
|
|
25
|
+
/** Longest incoming token accepted (characters); longer input is refused without calling Daywalker. */
|
|
26
|
+
export declare const MAX_TOKEN_LENGTH = 8192;
|
|
27
|
+
/** How long a fetched JWKS (`jwks: "auto"`) is used before it is refetched. */
|
|
28
|
+
export declare const JWKS_CACHE_TTL_MS = 600000;
|
|
29
|
+
/**
|
|
30
|
+
* Least time between two JWKS fetches, whatever triggers them (an unknown `kid`, an expired set, a failed
|
|
31
|
+
* fetch), so a flood of tokens naming made-up `kid`s costs at most one request to Daywalker per interval.
|
|
32
|
+
*/
|
|
33
|
+
export declare const JWKS_REFETCH_COOLDOWN_MS = 30000;
|
|
34
|
+
/** What signs this client's requests, and where it came from. */
|
|
35
|
+
type SignerSource = "signer" | "signingKey" | "ephemeral" | "keyStore";
|
|
20
36
|
export declare class Daywalker {
|
|
21
|
-
private
|
|
22
|
-
private readonly _rawConfig;
|
|
23
|
-
private _signingKeyPromise?;
|
|
24
|
-
private _previousSigningKeyPromise?;
|
|
25
|
-
private readonly _cache;
|
|
26
|
-
private readonly _inflight;
|
|
37
|
+
#private;
|
|
27
38
|
constructor(config?: DaywalkerConfig);
|
|
28
|
-
|
|
39
|
+
/** The resolved configuration, frozen, with the API key and private keys shown as "[configured]". */
|
|
40
|
+
get config(): Readonly<ResolvedConfig>;
|
|
29
41
|
toJSON(): Record<string, unknown>;
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
42
|
+
/**
|
|
43
|
+
* Shuts the client down: revokes its ephemeral signing key (which also ends the OAuth sessions it started)
|
|
44
|
+
* and forgets its tokens. Afterwards every call that needs Daywalker fails with CLIENT_CLOSED. Safe to call
|
|
45
|
+
* twice. Keys from `signingKey`, `keyStore` or `signer` are long-lived and are left alone.
|
|
46
|
+
*/
|
|
47
|
+
close(): Promise<{
|
|
48
|
+
revoked: string[];
|
|
49
|
+
failed: string[];
|
|
50
|
+
}>;
|
|
51
|
+
/**
|
|
52
|
+
* Resolves the signing key now instead of on the first request: loads it, or provisions and registers it
|
|
53
|
+
* (see `keyStore`). Call it at startup to fail fast. Returns where the key came from and its id.
|
|
54
|
+
*/
|
|
55
|
+
provisionSigningKey(): Promise<{
|
|
56
|
+
source: SignerSource;
|
|
57
|
+
keyId: string;
|
|
58
|
+
} | null>;
|
|
35
59
|
/**
|
|
36
60
|
* Signs and executes a request to Daywalker Auth (same origin as `authUrl` only).
|
|
37
61
|
* - Redirects are never followed: a 3xx throws a DaywalkerError (code UNEXPECTED_REDIRECT), so the API key,
|
|
@@ -41,58 +65,49 @@ export declare class Daywalker {
|
|
|
41
65
|
* - 429s are retried with exponential backoff, honoring `Retry-After` up to `retry.maxRetryAfterMs`. Network
|
|
42
66
|
* errors and timeouts are retried only for GET / HEAD / OPTIONS, with an `idempotencyKey`, or when
|
|
43
67
|
* `retry.retryNetworkErrors` is true. Options merge as defaults < `config.retry` < `init.retry`.
|
|
44
|
-
* - An explicit `Authorization` header is sent as given; otherwise `
|
|
45
|
-
*
|
|
68
|
+
* - An explicit `Authorization` header is sent as given; otherwise `DPoP <access token>` from the OAuth
|
|
69
|
+
* client credentials flow (`accessToken()`) is added, with a DPoP proof bound to it. The API key is never
|
|
70
|
+
* sent here: it only authenticates the client credentials grant. An answer of 401 ACCESS_TOKEN_EXPIRED
|
|
71
|
+
* refreshes the token and retries once. The signature covers method, path, query, authority and
|
|
72
|
+
* Content-Digest, never Authorization.
|
|
46
73
|
*/
|
|
47
74
|
fetch(path: string, init?: DaywalkerFetchInit): Promise<Response>;
|
|
48
|
-
private _cacheGet;
|
|
49
|
-
private _cacheSet;
|
|
50
75
|
/**
|
|
51
|
-
* Validates an incoming
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
76
|
+
* Validates an incoming token with memory caching and a discriminated union result.
|
|
77
|
+
* - Access tokens (JWTs) are verified offline when Daywalker's public key is configured. A DPoP-bound
|
|
78
|
+
* token (`cnf.jkt`) is only accepted with a valid DPoP proof (`options.dpop`; the adapters pass it).
|
|
79
|
+
* - Other tokens are validated online with `POST /api/v1/tokens/validate`, authenticated with this
|
|
80
|
+
* service's own DPoP-bound access token. The answer must name the expected service.
|
|
81
|
+
* - A missing, oversized or malformed token is rejected (401) without calling Daywalker. A token is never
|
|
82
|
+
* replaced by this service's own credentials: use `validateServiceCredentials()` for that.
|
|
83
|
+
* - Online validation fails closed: only a 2xx JSON answer with `valid: true` and a sane shape is accepted.
|
|
84
|
+
* Outages (network errors, timeouts, 5xx, malformed answers) return status 503 with error NETWORK_ERROR or
|
|
85
|
+
* SERVICE_UNAVAILABLE and are never cached. Each call gets its own copy of the (cached) result.
|
|
58
86
|
*/
|
|
59
|
-
validateToken(tokenOrOptions?: string | {
|
|
87
|
+
validateToken(tokenOrOptions?: string | (ValidateTokenOptions & {
|
|
60
88
|
token?: string;
|
|
61
|
-
|
|
62
|
-
forceRefresh?: boolean;
|
|
63
|
-
offlineOnly?: boolean;
|
|
64
|
-
}, options?: {
|
|
65
|
-
serviceSlug?: string;
|
|
66
|
-
forceRefresh?: boolean;
|
|
67
|
-
offlineOnly?: boolean;
|
|
68
|
-
}): Promise<ValidateResult>;
|
|
69
|
-
private _validateOnline;
|
|
89
|
+
}), options?: ValidateTokenOptions): Promise<ValidateResult>;
|
|
70
90
|
/**
|
|
71
|
-
* Service health check:
|
|
72
|
-
*
|
|
91
|
+
* Service health check: runs this service's OAuth client credentials flow (`accessToken()`) and checks
|
|
92
|
+
* that the granted services include `serviceSlug` (default: the configured one; with none configured, at
|
|
93
|
+
* least one service must be granted). Never use this to authenticate an incoming request. `forceRefresh`
|
|
94
|
+
* starts a new client credentials grant.
|
|
73
95
|
*/
|
|
74
|
-
|
|
96
|
+
validateServiceCredentials(options?: {
|
|
75
97
|
serviceSlug?: string;
|
|
76
98
|
forceRefresh?: boolean;
|
|
77
99
|
}): Promise<ValidateResult>;
|
|
78
100
|
/**
|
|
79
101
|
* Throws DaywalkerAuthError or DaywalkerRateLimitError if token is invalid or rate limited.
|
|
80
102
|
*/
|
|
81
|
-
requireValidToken(tokenOrOptions?: string | {
|
|
103
|
+
requireValidToken(tokenOrOptions?: string | (ValidateTokenOptions & {
|
|
82
104
|
token?: string;
|
|
83
|
-
|
|
84
|
-
offlineOnly?: boolean;
|
|
85
|
-
}, options?: {
|
|
86
|
-
serviceSlug?: string;
|
|
87
|
-
offlineOnly?: boolean;
|
|
88
|
-
}): Promise<TokenPayload>;
|
|
89
|
-
private _tokens;
|
|
90
|
-
private _tokenFlight;
|
|
91
|
-
private _tokenRequest;
|
|
105
|
+
}), options?: ValidateTokenOptions): Promise<TokenPayload>;
|
|
92
106
|
/**
|
|
93
107
|
* Client credentials grant (RFC 6749 §4.4): the signed request (API key + registered Ed25519 key) is
|
|
94
|
-
* exchanged for a short-lived access token JWT
|
|
95
|
-
*
|
|
108
|
+
* exchanged for a short-lived access token JWT and a rotating refresh token. By default the grant is
|
|
109
|
+
* narrowed to the configured service slug(s) (least privilege); with none configured it covers every
|
|
110
|
+
* service the credentials do. The tokens are remembered for `accessToken()`. The result is frozen.
|
|
96
111
|
*/
|
|
97
112
|
getTokens(options?: GetTokensOptions): Promise<TokenSet>;
|
|
98
113
|
/**
|
|
@@ -107,6 +122,20 @@ export declare class Daywalker {
|
|
|
107
122
|
* refresh token is never presented twice.
|
|
108
123
|
*/
|
|
109
124
|
accessToken(): Promise<string>;
|
|
125
|
+
/**
|
|
126
|
+
* The service's license key from Daywalker (issued with the client credentials grant, valid for one hour,
|
|
127
|
+
* cached in memory until a minute before it expires). A revoked or suspended service gets no license: this
|
|
128
|
+
* throws the DaywalkerAuthError Daywalker answered with (`SERVICE_REVOKED`, `SERVICE_SUSPENDED`,
|
|
129
|
+
* `DOMAIN_REVOKED`, ...). `LICENSE_UNAVAILABLE` (403) means Daywalker granted the service without a license.
|
|
130
|
+
* Never log the key.
|
|
131
|
+
*/
|
|
132
|
+
getLicense(options?: LicenseOptions): Promise<License>;
|
|
133
|
+
/**
|
|
134
|
+
* Fetches the config bundle (`POST /api/v1/services/:slug/bundle`) and opens it with the license key
|
|
135
|
+
* (AES-256-GCM). The bundle can only be read by a client that got the license from Daywalker. At a window
|
|
136
|
+
* rollover the key is refreshed once and the bundle opened again. Cached until shortly before it expires.
|
|
137
|
+
*/
|
|
138
|
+
fetchBundle(options?: LicenseOptions): Promise<ConfigBundle>;
|
|
110
139
|
/**
|
|
111
140
|
* Fetches Daywalker's public JWKS (GET /.well-known/jwks.json) for offline lease verification.
|
|
112
141
|
* Uses the configured `fetch`, sends no credentials, never follows redirects and times out after `timeoutMs`.
|
|
@@ -122,7 +151,8 @@ export declare class Daywalker {
|
|
|
122
151
|
keys: PublicJwk[];
|
|
123
152
|
}>;
|
|
124
153
|
/**
|
|
125
|
-
* Check configuration and verify signature readiness.
|
|
154
|
+
* Check configuration and verify signature readiness. Never provisions or registers a key: with a
|
|
155
|
+
* `keyStore` it only reads what is stored and reports what first use would need.
|
|
126
156
|
*/
|
|
127
157
|
selfCheck(): Promise<SelfCheckResult>;
|
|
128
158
|
}
|
|
@@ -131,3 +161,4 @@ export declare class Daywalker {
|
|
|
131
161
|
*/
|
|
132
162
|
export declare function createDaywalker(config?: DaywalkerConfig): Daywalker;
|
|
133
163
|
export declare const daywalker: Daywalker & (() => Daywalker);
|
|
164
|
+
export {};
|