@crouter/sdk 0.3.377
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 +170 -0
- package/dist/client.d.ts +153 -0
- package/dist/client.js +491 -0
- package/dist/error-codes.d.ts +7 -0
- package/dist/error-codes.js +35 -0
- package/dist/errors.d.ts +43 -0
- package/dist/errors.js +76 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.js +13 -0
- package/dist/keygen-cli.d.ts +2 -0
- package/dist/keygen-cli.js +6 -0
- package/dist/keygen-command.d.ts +6 -0
- package/dist/keygen-command.js +157 -0
- package/dist/oauth/index.d.ts +147 -0
- package/dist/oauth/index.js +377 -0
- package/dist/oauth/keygen.d.ts +18 -0
- package/dist/oauth/keygen.js +46 -0
- package/dist/resources/activity.d.ts +22 -0
- package/dist/resources/activity.js +43 -0
- package/dist/resources/attachments.d.ts +15 -0
- package/dist/resources/attachments.js +13 -0
- package/dist/resources/bash.d.ts +9 -0
- package/dist/resources/bash.js +15 -0
- package/dist/resources/canvas/history.d.ts +11 -0
- package/dist/resources/canvas/history.js +20 -0
- package/dist/resources/canvas.d.ts +19 -0
- package/dist/resources/canvas.js +42 -0
- package/dist/resources/crons.d.ts +15 -0
- package/dist/resources/crons.js +33 -0
- package/dist/resources/custom-objects.d.ts +20 -0
- package/dist/resources/custom-objects.js +84 -0
- package/dist/resources/files.d.ts +34 -0
- package/dist/resources/files.js +34 -0
- package/dist/resources/forward.d.ts +7 -0
- package/dist/resources/forward.js +64 -0
- package/dist/resources/human/inbox.d.ts +14 -0
- package/dist/resources/human/inbox.js +30 -0
- package/dist/resources/human/requests.d.ts +13 -0
- package/dist/resources/human/requests.js +26 -0
- package/dist/resources/human.d.ts +8 -0
- package/dist/resources/human.js +10 -0
- package/dist/resources/identifiers.d.ts +8 -0
- package/dist/resources/identifiers.js +33 -0
- package/dist/resources/memory.d.ts +69 -0
- package/dist/resources/memory.js +30 -0
- package/dist/resources/models/config.d.ts +8 -0
- package/dist/resources/models/config.js +9 -0
- package/dist/resources/models/credentials.d.ts +10 -0
- package/dist/resources/models/credentials.js +17 -0
- package/dist/resources/models.d.ts +8 -0
- package/dist/resources/models.js +10 -0
- package/dist/resources/node-stream.d.ts +34 -0
- package/dist/resources/node-stream.js +176 -0
- package/dist/resources/nodes/jobs.d.ts +9 -0
- package/dist/resources/nodes/jobs.js +14 -0
- package/dist/resources/nodes/result.d.ts +8 -0
- package/dist/resources/nodes/result.js +11 -0
- package/dist/resources/nodes/worktree.d.ts +9 -0
- package/dist/resources/nodes/worktree.js +14 -0
- package/dist/resources/nodes.d.ts +23 -0
- package/dist/resources/nodes.js +47 -0
- package/dist/resources/providers.d.ts +51 -0
- package/dist/resources/providers.js +15 -0
- package/dist/resources/questions.d.ts +49 -0
- package/dist/resources/questions.js +21 -0
- package/dist/resources/request.d.ts +3 -0
- package/dist/resources/request.js +11 -0
- package/dist/resources/run-reply.d.ts +79 -0
- package/dist/resources/run-reply.js +84 -0
- package/dist/resources/run-stream.d.ts +40 -0
- package/dist/resources/run-stream.js +206 -0
- package/dist/resources/runs.d.ts +184 -0
- package/dist/resources/runs.js +197 -0
- package/dist/resources/shares.d.ts +40 -0
- package/dist/resources/shares.js +19 -0
- package/dist/resources/uploads.d.ts +27 -0
- package/dist/resources/uploads.js +11 -0
- package/dist/schema.d.ts +7 -0
- package/dist/schema.js +10 -0
- package/dist/stores/postgres.d.ts +29 -0
- package/dist/stores/postgres.js +86 -0
- package/dist/types.d.ts +80 -0
- package/dist/types.js +1 -0
- package/package.json +55 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export { Crouter as default, Crouter } from './client.js';
|
|
2
|
+
export type { CrouterOptions } from './client.js';
|
|
3
|
+
export { NodeStream } from './resources/node-stream.js';
|
|
4
|
+
export { RunStream } from './resources/run-stream.js';
|
|
5
|
+
export { CustomObjects } from './resources/custom-objects.js';
|
|
6
|
+
export type { CustomDeliveryStream, ReceiveOptions } from './resources/custom-objects.js';
|
|
7
|
+
export type { RunEvent, RunEventListener, RunEventOf, RunEventType, UnknownRunEvent } from './resources/run-stream.js';
|
|
8
|
+
export { RunReply } from './resources/run-reply.js';
|
|
9
|
+
export type { RunReplyCollectOptions, RunReplyEnding, RunReplyEvent, RunReplyResult, SentRunMessage } from './resources/run-reply.js';
|
|
10
|
+
export type { AppProfile, RunActivity, RunDeleteResult, RunObject, RunParsedOutcome, RunParseOptions, RunParseParams, RunStartParams, RunStartResult, RunStatus, RunTrace } from './resources/runs.js';
|
|
11
|
+
export type { FileDownloadOptions } from './resources/files.js';
|
|
12
|
+
export type { Upload, UploadCreateParams } from './resources/uploads.js';
|
|
13
|
+
export type { AttachmentLink } from './resources/attachments.js';
|
|
14
|
+
export type { Share, ShareCreated, ShareCreateParams } from './resources/shares.js';
|
|
15
|
+
export type { MemoryDocument, MemoryGetParams, MemoryListItem, MemoryListPage, MemoryListParams } from './resources/memory.js';
|
|
16
|
+
export type { Question, QuestionAnswered, QuestionFields, QuestionResponses, QuestionSlot, QuestionStatus } from './resources/questions.js';
|
|
17
|
+
export type { ProviderToolEntry } from './resources/providers.js';
|
|
18
|
+
export { OAuth2Client, MemoryConnectionStore, profileFromClaims } from './oauth/index.js';
|
|
19
|
+
export { refreshRefusal } from './oauth/index.js';
|
|
20
|
+
export type { RefreshFailure, RefreshRefusal } from './oauth/index.js';
|
|
21
|
+
export { generateKeyPair } from './oauth/keygen.js';
|
|
22
|
+
export { parsePrivateJwk, privateKeyFromFile } from './oauth/keygen.js';
|
|
23
|
+
export type { AuthorizeNonce, Connection, ConnectionStore, Identity, OAuth2Options } from './oauth/index.js';
|
|
24
|
+
export type { IdTokenClaims } from '@crouter/identity';
|
|
25
|
+
export { cursorFromRequest, forwardRunEvents } from './resources/forward.js';
|
|
26
|
+
export type { NodeStreamEvent, NodeStreamEventListener, NodeStreamEventType } from './resources/node-stream.js';
|
|
27
|
+
export { describeToolDefault, followActivity } from './resources/activity.js';
|
|
28
|
+
export type { ActivityStep, DescribeTool } from './resources/activity.js';
|
|
29
|
+
export { APIError, APIConnectionError, APIConnectionTimeoutError, APIUserAbortError, AuthenticationError, BadRequestError, ConflictError, CrouterError, InternalServerError, NotFoundError, PermissionDeniedError, RateLimitError, UnprocessableEntityError, mapError, } from './errors.js';
|
|
30
|
+
export { sdkErrorCodes } from './error-codes.js';
|
|
31
|
+
export type { SdkErrorCode } from './error-codes.js';
|
|
32
|
+
export type { AuthStatus, AuthStatusParams, CancelParams, EnsureProfileParams, JsonSchema, MessageParams, NodeCreateParams, NodeEventsOptions, NodeOutcomeOptions, OutputSchema, ParsedOutcome, RequestOptions, SchemaOutput, } from './types.js';
|
|
33
|
+
export type * from '@crouter/api';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export { Crouter as default, Crouter } from './client.js';
|
|
2
|
+
export { NodeStream } from './resources/node-stream.js';
|
|
3
|
+
export { RunStream } from './resources/run-stream.js';
|
|
4
|
+
export { CustomObjects } from './resources/custom-objects.js';
|
|
5
|
+
export { RunReply } from './resources/run-reply.js';
|
|
6
|
+
export { OAuth2Client, MemoryConnectionStore, profileFromClaims } from './oauth/index.js';
|
|
7
|
+
export { refreshRefusal } from './oauth/index.js';
|
|
8
|
+
export { generateKeyPair } from './oauth/keygen.js';
|
|
9
|
+
export { parsePrivateJwk, privateKeyFromFile } from './oauth/keygen.js';
|
|
10
|
+
export { cursorFromRequest, forwardRunEvents } from './resources/forward.js';
|
|
11
|
+
export { describeToolDefault, followActivity } from './resources/activity.js';
|
|
12
|
+
export { APIError, APIConnectionError, APIConnectionTimeoutError, APIUserAbortError, AuthenticationError, BadRequestError, ConflictError, CrouterError, InternalServerError, NotFoundError, PermissionDeniedError, RateLimitError, UnprocessableEntityError, mapError, } from './errors.js';
|
|
13
|
+
export { sdkErrorCodes } from './error-codes.js';
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export interface KeygenOptions {
|
|
2
|
+
/** How long `crtr cloud apps keys add` may run before keygen gives up. */
|
|
3
|
+
crtrTimeoutMs?: number;
|
|
4
|
+
}
|
|
5
|
+
/** The `crouter-sdk keygen` command. Returns the process exit code. */
|
|
6
|
+
export declare function runKeygen(argv: string[], options?: KeygenOptions): Promise<number>;
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { execFile } from 'node:child_process';
|
|
2
|
+
import { mkdir, open, unlink } from 'node:fs/promises';
|
|
3
|
+
import { dirname } from 'node:path';
|
|
4
|
+
import { createInterface } from 'node:readline';
|
|
5
|
+
import { generateKeyPair } from './oauth/keygen.js';
|
|
6
|
+
const USAGE = 'Usage: crouter-sdk keygen [--out <path>] [--app <client id>] [--yes]';
|
|
7
|
+
const CRTR_TIMEOUT_MS = 60_000;
|
|
8
|
+
function parseArgs(args) {
|
|
9
|
+
if (args[0] !== 'keygen')
|
|
10
|
+
throw new Error(USAGE);
|
|
11
|
+
const parsed = { path: 'local/app-key.json', yes: false };
|
|
12
|
+
const seen = new Set();
|
|
13
|
+
for (let i = 1; i < args.length; i++) {
|
|
14
|
+
const flag = args[i];
|
|
15
|
+
if (seen.has(flag))
|
|
16
|
+
throw new Error(USAGE);
|
|
17
|
+
seen.add(flag);
|
|
18
|
+
if (flag === '--yes') {
|
|
19
|
+
parsed.yes = true;
|
|
20
|
+
continue;
|
|
21
|
+
}
|
|
22
|
+
const value = args[++i];
|
|
23
|
+
if ((flag !== '--out' && flag !== '--app') || !value || value.startsWith('--'))
|
|
24
|
+
throw new Error(USAGE);
|
|
25
|
+
if (flag === '--out')
|
|
26
|
+
parsed.path = value;
|
|
27
|
+
else
|
|
28
|
+
parsed.app = value;
|
|
29
|
+
}
|
|
30
|
+
return parsed;
|
|
31
|
+
}
|
|
32
|
+
const manualSteps = (path) => [
|
|
33
|
+
'Next, in this order:',
|
|
34
|
+
" 1. Add the public JWK printed on stdout as a key: click Add key on your app's Sign-in tab in the console, or paste it under Register an app for a new app. Adding a key never replaces your current one.",
|
|
35
|
+
` 2. Then point your app's privateKey at ${path} and deploy.`,
|
|
36
|
+
' 3. Once a real sign-in works, retire the old key on the Sign-in tab.',
|
|
37
|
+
];
|
|
38
|
+
const addedSteps = (path, app) => [
|
|
39
|
+
'Next, in this order:',
|
|
40
|
+
` 1. Point your app's privateKey at ${path} and deploy.`,
|
|
41
|
+
' 2. Check that a real sign-in works.',
|
|
42
|
+
` 3. Retire the old key: on the app's Sign-in tab, or \`crtr cloud apps keys retire --app-id ${app} --kid <old kid>\` (\`crtr cloud apps keys list --app-id ${app}\` shows the kids).`,
|
|
43
|
+
];
|
|
44
|
+
const seconds = (ms) => {
|
|
45
|
+
const n = Math.max(1, Math.round(ms / 1000));
|
|
46
|
+
return `${n} second${n === 1 ? '' : 's'}`;
|
|
47
|
+
};
|
|
48
|
+
const say = (lines) => console.error(lines.join('\n'));
|
|
49
|
+
/** Asks on stderr; resolves true only for Enter or y/yes. End of input declines. */
|
|
50
|
+
function confirm(question) {
|
|
51
|
+
const rl = createInterface({ input: process.stdin, output: process.stderr });
|
|
52
|
+
return new Promise((resolve) => {
|
|
53
|
+
let answered = false;
|
|
54
|
+
rl.on('close', () => { if (!answered) {
|
|
55
|
+
process.stderr.write('\n');
|
|
56
|
+
resolve(false);
|
|
57
|
+
} });
|
|
58
|
+
rl.question(`${question} `, (answer) => {
|
|
59
|
+
answered = true;
|
|
60
|
+
rl.close();
|
|
61
|
+
resolve(/^(y|yes)?$/i.test(answer.trim()));
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
const parseJson = (text) => {
|
|
66
|
+
try {
|
|
67
|
+
return JSON.parse(text.trim());
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
return undefined;
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
const lastLine = (text) => text.split('\n').map((line) => line.trim()).filter(Boolean).at(-1);
|
|
74
|
+
/** The `message` of a JSON error that ends `text`, even when other lines (a warning, a notice) precede it. */
|
|
75
|
+
const errorMessage = (text) => {
|
|
76
|
+
const body = parseJson(text.slice(text.lastIndexOf('\n{') + 1));
|
|
77
|
+
return typeof body?.message === 'string' && body.message ? body.message : undefined;
|
|
78
|
+
};
|
|
79
|
+
/** Runs `crtr cloud apps keys add` once: execFile, no shell, the caller's environment. */
|
|
80
|
+
function addKey(app, publicJwk, timeoutMs) {
|
|
81
|
+
const argv = ['cloud', 'apps', 'keys', 'add', '--app-id', app, '--jwk', publicJwk, '--json'];
|
|
82
|
+
return new Promise((resolve) => {
|
|
83
|
+
execFile('crtr', argv, { timeout: timeoutMs, env: process.env, maxBuffer: 1024 * 1024 }, (error, stdout, stderr) => {
|
|
84
|
+
const err = error;
|
|
85
|
+
if (err?.code === 'ENOENT')
|
|
86
|
+
return resolve({ kind: 'missing' });
|
|
87
|
+
if (err) {
|
|
88
|
+
const message = err.killed
|
|
89
|
+
? `crtr did not answer within ${seconds(timeoutMs)}.`
|
|
90
|
+
: errorMessage(stdout) ?? errorMessage(stderr) ?? lastLine(stderr) ?? lastLine(stdout) ?? err.message;
|
|
91
|
+
return resolve({ kind: 'failed', message });
|
|
92
|
+
}
|
|
93
|
+
const answer = parseJson(stdout);
|
|
94
|
+
if (typeof answer?.kid !== 'string') {
|
|
95
|
+
return resolve({ kind: 'failed', message: `crtr answered without the added key: ${lastLine(stdout) ?? '(no output)'}` });
|
|
96
|
+
}
|
|
97
|
+
resolve({ kind: 'added', kid: answer.kid, created: answer.created !== false });
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
/** The `crouter-sdk keygen` command. Returns the process exit code. */
|
|
102
|
+
export async function runKeygen(argv, options = {}) {
|
|
103
|
+
const { path, app, yes } = parseArgs(argv);
|
|
104
|
+
await mkdir(dirname(path), { recursive: true });
|
|
105
|
+
// Reserve the destination before generating or printing the public key; never truncate an existing key.
|
|
106
|
+
const file = await open(path, 'wx', 0o600).catch((error) => {
|
|
107
|
+
if (error.code === 'EEXIST')
|
|
108
|
+
throw new Error(`${path} already exists. Delete it or pass --out to write somewhere else.`);
|
|
109
|
+
throw error;
|
|
110
|
+
});
|
|
111
|
+
let publicJwk;
|
|
112
|
+
let kid;
|
|
113
|
+
try {
|
|
114
|
+
const pair = await generateKeyPair();
|
|
115
|
+
await file.writeFile(`${JSON.stringify(pair.privateJwk)}\n`);
|
|
116
|
+
({ publicJwk, kid } = pair);
|
|
117
|
+
}
|
|
118
|
+
catch (error) {
|
|
119
|
+
await file.close();
|
|
120
|
+
await unlink(path);
|
|
121
|
+
throw error;
|
|
122
|
+
}
|
|
123
|
+
await file.close();
|
|
124
|
+
const publicLine = JSON.stringify(publicJwk);
|
|
125
|
+
console.error(`Saved the private key to ${path} (key id ${kid}). Keep it out of git.`);
|
|
126
|
+
console.log(publicLine);
|
|
127
|
+
if (!app) {
|
|
128
|
+
say([...manualSteps(path), 'Tip: pass --app <client id> to add the key with crtr.']);
|
|
129
|
+
return 0;
|
|
130
|
+
}
|
|
131
|
+
if (!yes) {
|
|
132
|
+
if (!process.stdin.isTTY || !process.stderr.isTTY) {
|
|
133
|
+
say(['Not adding the key: no terminal to confirm. Pass --yes to add it with crtr.', ...manualSteps(path)]);
|
|
134
|
+
return 0;
|
|
135
|
+
}
|
|
136
|
+
if (!(await confirm(`Add this key to ${app} as an additional key? Your current key keeps working. [Y/n]`))) {
|
|
137
|
+
say(manualSteps(path));
|
|
138
|
+
return 0;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
const outcome = await addKey(app, publicLine, options.crtrTimeoutMs ?? CRTR_TIMEOUT_MS);
|
|
142
|
+
if (outcome.kind === 'missing') {
|
|
143
|
+
say(["Couldn't find crtr, so the key was not added.", ...manualSteps(path)]);
|
|
144
|
+
return 0;
|
|
145
|
+
}
|
|
146
|
+
if (outcome.kind === 'failed') {
|
|
147
|
+
say([`Couldn't add the key: ${outcome.message}`, ...manualSteps(path)]);
|
|
148
|
+
return 2;
|
|
149
|
+
}
|
|
150
|
+
say([
|
|
151
|
+
outcome.created
|
|
152
|
+
? `Added key ${outcome.kid} to ${app} as an additional key. Your current key still works.`
|
|
153
|
+
: `Key ${outcome.kid} is already on ${app}.`,
|
|
154
|
+
...addedSteps(path, app),
|
|
155
|
+
]);
|
|
156
|
+
return 0;
|
|
157
|
+
}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { type JWK } from 'jose';
|
|
2
|
+
import { type IdTokenClaims } from '@crouter/identity';
|
|
3
|
+
import { Crouter } from '../client.js';
|
|
4
|
+
/**
|
|
5
|
+
* Why the directory refused a connection's refresh token, and what it means for the app's data:
|
|
6
|
+
* - `removed` (`grant_removed`): the person removed the app or deleted their account. The runtime has
|
|
7
|
+
* deleted the app's runs; delete what the app stores for them.
|
|
8
|
+
* - `paused` (`grant_suspended`): the grant is suspended or expired. Nothing was deleted; keep the
|
|
9
|
+
* person's data and show the app paused until they sign in again.
|
|
10
|
+
* - `reconnect` (`refresh_token_expired`, `refresh_token_reused`, or `grant_revoked` with no reason given):
|
|
11
|
+
* the grant still exists. Nothing was deleted; drop the dead connection and ask them to sign in again.
|
|
12
|
+
*/
|
|
13
|
+
export type RefreshRefusal = 'removed' | 'paused' | 'reconnect';
|
|
14
|
+
/** What a refused refresh means (`RefreshRefusal`), or `null` when `error` is not the directory refusing one.
|
|
15
|
+
* Takes any error a connected client or `refresh` threw; only `APIError` with `origin: 'directory'` counts. */
|
|
16
|
+
export declare function refreshRefusal(error: unknown): RefreshRefusal | null;
|
|
17
|
+
/** One connection `refreshIdleConnections` could not refresh. `reason` is `refreshRefusal(error)`. */
|
|
18
|
+
export interface RefreshFailure {
|
|
19
|
+
userId: string;
|
|
20
|
+
error: unknown;
|
|
21
|
+
reason: RefreshRefusal | null;
|
|
22
|
+
}
|
|
23
|
+
export interface Connection {
|
|
24
|
+
userId: string;
|
|
25
|
+
runtimeUrl: string;
|
|
26
|
+
refreshToken: string;
|
|
27
|
+
grantId: string;
|
|
28
|
+
accessToken: string;
|
|
29
|
+
accessTokenExpiresAt: number;
|
|
30
|
+
idToken?: string;
|
|
31
|
+
}
|
|
32
|
+
export interface ConnectionStore {
|
|
33
|
+
load(userId: string): Promise<Connection | null>;
|
|
34
|
+
save(connection: Connection): Promise<void>;
|
|
35
|
+
lock?<T>(userId: string, fn: () => Promise<T>): Promise<T>;
|
|
36
|
+
/** Connections last saved before this instant. A save must update the store's activity timestamp. */
|
|
37
|
+
listStale?(before: Date): Promise<Connection[]>;
|
|
38
|
+
}
|
|
39
|
+
export declare class MemoryConnectionStore implements ConnectionStore {
|
|
40
|
+
private readonly connections;
|
|
41
|
+
private readonly locks;
|
|
42
|
+
private readonly savedAt;
|
|
43
|
+
load(userId: string): Promise<Connection | null>;
|
|
44
|
+
save(connection: Connection): Promise<void>;
|
|
45
|
+
listStale(before: Date): Promise<Connection[]>;
|
|
46
|
+
lock<T>(userId: string, fn: () => Promise<T>): Promise<T>;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* A person's crouter cloud identity from a sign-in-only (`openid`, `openid email`, `openid profile`, or `openid email profile`) request, read from an
|
|
50
|
+
* ID token the SDK verified: ES256 signature against the directory's JWKS, `iss`, `aud` = the client id,
|
|
51
|
+
* `exp`, and the `nonce` from `authorizeUrl`. It is not a connection: it holds no runtime URL, refresh
|
|
52
|
+
* token, or grant, and nothing can be called on the person's runtime with it.
|
|
53
|
+
*/
|
|
54
|
+
export interface Identity {
|
|
55
|
+
/** The person's crouter cloud user id (`user:<id>`), the same `sub` a `Connection.userId` carries. */
|
|
56
|
+
sub: string;
|
|
57
|
+
/** Present only when `email` was requested and approved. */
|
|
58
|
+
email?: string;
|
|
59
|
+
emailVerified?: boolean;
|
|
60
|
+
/** Present only when `profile` was requested and approved and the person has a name (a phone-only account has none). The full name, e.g. `Sam Rivera`. */
|
|
61
|
+
name?: string;
|
|
62
|
+
givenName?: string;
|
|
63
|
+
familyName?: string;
|
|
64
|
+
/** Present only when `profile` was requested and approved and the ID token carries an https `picture` (the person's Google photo URL). An account with no photo has none; show initials then. */
|
|
65
|
+
picture?: string;
|
|
66
|
+
/** Every verified ID token claim. */
|
|
67
|
+
claims: IdTokenClaims;
|
|
68
|
+
}
|
|
69
|
+
/** `authorizeUrl`'s nonce: `string` when the scopes are known to include `openid`, `undefined` when known not to, else either. */
|
|
70
|
+
export type AuthorizeNonce<S extends readonly string[]> = string extends S[number] ? string | undefined : 'openid' extends S[number] ? string : undefined;
|
|
71
|
+
/** The `profile` claims a verified ID token carries, each only when present: use it on `Connection.idToken` after `verifyIdToken` for a sign-in that requested runtime scopes (`exchangeCode`), as `exchangeIdentity` does for a sign-in-only one. */
|
|
72
|
+
export declare function profileFromClaims(claims: IdTokenClaims): Pick<Identity, 'name' | 'givenName' | 'familyName' | 'picture'>;
|
|
73
|
+
export interface OAuth2Options {
|
|
74
|
+
clientId: string;
|
|
75
|
+
privateKey: string | JWK;
|
|
76
|
+
keyId?: string;
|
|
77
|
+
redirectUri: string;
|
|
78
|
+
issuer: string;
|
|
79
|
+
fetch?: typeof fetch;
|
|
80
|
+
}
|
|
81
|
+
export declare class OAuth2Client {
|
|
82
|
+
private readonly options;
|
|
83
|
+
private readonly issuer;
|
|
84
|
+
private readonly fetcher;
|
|
85
|
+
private jwks?;
|
|
86
|
+
private discoveryPromise?;
|
|
87
|
+
private readonly inFlight;
|
|
88
|
+
constructor(options: OAuth2Options);
|
|
89
|
+
private discovery;
|
|
90
|
+
/** Start a sign-in. When `scopes` includes `openid` the result carries the `nonce` to pass to the exchange; with literal scopes its type is `string`.
|
|
91
|
+
* `prompt: 'consent'` makes the directory show its consent screen even when the person already approved these scopes. */
|
|
92
|
+
authorizeUrl<const S extends readonly string[]>({ scopes, state, codeVerifier, prompt }: {
|
|
93
|
+
scopes: S;
|
|
94
|
+
state: string;
|
|
95
|
+
codeVerifier?: string;
|
|
96
|
+
prompt?: 'consent';
|
|
97
|
+
}): Promise<{
|
|
98
|
+
url: string;
|
|
99
|
+
codeVerifier: string;
|
|
100
|
+
state: string;
|
|
101
|
+
nonce: AuthorizeNonce<S>;
|
|
102
|
+
}>;
|
|
103
|
+
/**
|
|
104
|
+
* Finish a sign-in that asked for runtime scopes and return the person's `Connection`. A sign-in-only
|
|
105
|
+
* request (`openid`, `openid email`, `openid profile`, or `openid email profile`) gets no connection from the directory; finish it with
|
|
106
|
+
* `exchangeIdentity`, which this method names when it receives such a response.
|
|
107
|
+
*/
|
|
108
|
+
exchangeCode({ code, codeVerifier, state, expectedState, nonce }: {
|
|
109
|
+
code: string;
|
|
110
|
+
codeVerifier: string;
|
|
111
|
+
state: string;
|
|
112
|
+
expectedState: string;
|
|
113
|
+
nonce?: string;
|
|
114
|
+
}): Promise<Connection>;
|
|
115
|
+
/**
|
|
116
|
+
* Finish a sign-in-only request (`authorizeUrl` with scopes `openid` or `openid email`) and return the
|
|
117
|
+
* person's verified identity. There is no connection, refresh token, or runtime access on this path.
|
|
118
|
+
* `nonce` is the value `authorizeUrl` returned and is required. A response without an ID token, or with
|
|
119
|
+
* one that fails verification, throws `id_token_invalid`; a response carrying a runtime connection (the
|
|
120
|
+
* request asked for runtime scopes) throws `oauth_exchange_mismatch` and must be finished with `exchangeCode`.
|
|
121
|
+
*/
|
|
122
|
+
exchangeIdentity({ code, codeVerifier, state, expectedState, nonce }: {
|
|
123
|
+
code: string;
|
|
124
|
+
codeVerifier: string;
|
|
125
|
+
state: string;
|
|
126
|
+
expectedState: string;
|
|
127
|
+
nonce: string;
|
|
128
|
+
}): Promise<Identity>;
|
|
129
|
+
/** Refresh a store's idle connections once. The app owns scheduling; failures remain visible to its worker,
|
|
130
|
+
* each with `reason` set when the directory refused that connection's refresh (see `RefreshRefusal`). */
|
|
131
|
+
refreshIdleConnections(store: ConnectionStore, { olderThanMs }: {
|
|
132
|
+
olderThanMs: number;
|
|
133
|
+
}): Promise<{
|
|
134
|
+
refreshed: number;
|
|
135
|
+
failures: RefreshFailure[];
|
|
136
|
+
}>;
|
|
137
|
+
refresh(connection: Connection, store?: ConnectionStore): Promise<Connection>;
|
|
138
|
+
client(connection: Connection, store: ConnectionStore): Crouter;
|
|
139
|
+
/** Verify an ID token: ES256 signature against the discovered JWKS, `iss`, `aud` = client id, `exp`, and `nonce` when given. A token that fails any check throws `id_token_invalid`; a JWKS that can't be fetched or is malformed rethrows that error. */
|
|
140
|
+
verifyIdToken(idToken: string, { nonce }?: {
|
|
141
|
+
nonce?: string;
|
|
142
|
+
}): Promise<IdTokenClaims>;
|
|
143
|
+
revoke(connection: Connection): Promise<boolean>;
|
|
144
|
+
private tokenResponse;
|
|
145
|
+
private connectionFrom;
|
|
146
|
+
private post;
|
|
147
|
+
}
|