@boxxy/auth-oauth 0.2.6 → 0.2.7
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 +12 -13
- package/dist/auth/create-auth-admin.d.ts +25 -12
- package/dist/auth/create-security-event-log.d.ts +1 -1
- package/dist/auth/format-security-event.d.ts +10 -2
- package/dist/auth/open-auth-database.d.ts +2 -2
- package/dist/http/create-public-door.d.ts +5 -1
- package/dist/http/{answer-mcp-request.d.ts → types.d.ts} +0 -2
- package/dist/index.d.ts +2 -5
- package/dist/migrations/grant-rows-migration.d.ts +2 -0
- package/dist/migrations/run-auth-migrations.d.ts +2 -0
- package/dist/test-utils/authorize-test-client.d.ts +1 -13
- package/dist/test-utils/pre-package-schema.d.ts +1 -0
- package/dist/test-utils/seed-pre-package-auth.d.ts +21 -0
- package/package.json +7 -13
- package/src/auth/create-auth-admin.ts +109 -41
- package/src/auth/create-security-event-log.ts +1 -3
- package/src/auth/format-security-event.ts +12 -11
- package/src/auth/normalize-client-name.ts +0 -2
- package/src/auth/open-auth-database.ts +8 -13
- package/src/http/create-public-door.ts +113 -29
- package/src/http/is-loopback-host.ts +0 -2
- package/src/http/normalize-public-url.ts +0 -2
- package/src/http/types.ts +11 -0
- package/src/index.ts +9 -5
- package/src/migrations/grant-rows-migration.ts +108 -0
- package/src/migrations/run-auth-migrations.ts +53 -0
- package/src/test-utils/authorize-test-client.ts +2 -194
- package/src/test-utils/build-stub-clock.ts +0 -2
- package/src/test-utils/pre-package-schema.ts +36 -0
- package/src/test-utils/register-test-cleanup.ts +0 -2
- package/src/test-utils/seed-pre-package-auth.ts +162 -0
- package/src/test-utils/setup-temp-dir.ts +0 -2
- package/src/utils/types.ts +0 -2
- package/dist/auth/answer-authorize-request.d.ts +0 -2
- package/dist/auth/answer-consent-request.d.ts +0 -10
- package/dist/auth/answer-enroll-request.d.ts +0 -9
- package/dist/auth/answer-login-request.d.ts +0 -9
- package/dist/auth/approval-window-seconds.d.ts +0 -1
- package/dist/auth/build-consent-binding.d.ts +0 -1
- package/dist/auth/create-approval-state.d.ts +0 -41
- package/dist/auth/create-enrollment-state.d.ts +0 -6
- package/dist/auth/create-enrollment-token.d.ts +0 -6
- package/dist/auth/create-owner-plugin.d.ts +0 -38
- package/dist/auth/create-passkey.d.ts +0 -11
- package/dist/auth/derive-token-hash.d.ts +0 -1
- package/dist/auth/is-allowed-redirect-uri.d.ts +0 -1
- package/dist/auth/load-web-authn.d.ts +0 -6
- package/dist/auth/mcp-auth-database.d.ts +0 -5
- package/dist/auth/mcp-auth-schema.d.ts +0 -54
- package/dist/auth/open-mcp-auth.d.ts +0 -80
- package/dist/auth/passkey-script.d.ts +0 -4
- package/dist/auth/read-client-name.d.ts +0 -3
- package/dist/auth/read-client-views.d.ts +0 -9
- package/dist/auth/read-enrollment-token.d.ts +0 -3
- package/dist/auth/read-grant-views.d.ts +0 -12
- package/dist/auth/read-owner-session-id.d.ts +0 -2
- package/dist/auth/record-refused-exchange.d.ts +0 -10
- package/dist/auth/remove-client.d.ts +0 -3
- package/dist/auth/remove-owner-session.d.ts +0 -3
- package/dist/auth/render-consent-page.d.ts +0 -9
- package/dist/auth/render-enroll-page.d.ts +0 -10
- package/dist/auth/render-login-page.d.ts +0 -9
- package/dist/auth/revoke-grant.d.ts +0 -3
- package/dist/auth/to-html-text.d.ts +0 -1
- package/dist/auth/to-script-json.d.ts +0 -1
- package/dist/auth/types.d.ts +0 -79
- package/dist/auth/update-passkey-use.d.ts +0 -10
- package/dist/auth/verify-oauth-query.d.ts +0 -1
- package/dist/auth/verify-passkey-assertion.d.ts +0 -11
- package/dist/auth/verify-passkey-registration.d.ts +0 -14
- package/dist/auth/verify-session-passkey.d.ts +0 -8
- package/dist/auth/write-grant-use.d.ts +0 -3
- package/dist/http/build-page-response.d.ts +0 -5
- package/dist/http/create-mcp-http-app.d.ts +0 -92
- package/dist/http/pick-error-message.d.ts +0 -1
- package/dist/http/public-door-paths.d.ts +0 -17
- package/dist/http/read-token-access.d.ts +0 -8
- package/dist/http/verify-access-token.d.ts +0 -2
- package/dist/test-utils/build-mock-new-passkey.d.ts +0 -2
- package/dist/test-utils/build-passkey-seeder.d.ts +0 -5
- package/dist/test-utils/build-seeder.d.ts +0 -5
- package/dist/test-utils/build-stub-authenticator.d.ts +0 -48
- package/dist/test-utils/load-web-authn-early.d.ts +0 -1
- package/dist/test-utils/seed-passkey.d.ts +0 -4
- package/dist/test-utils/start-stub-telemetry-collector.d.ts +0 -5
- package/dist/test-utils/types.d.ts +0 -7
- package/dist/utils/is-record.d.ts +0 -1
- package/dist/utils/parse-json-strings.d.ts +0 -1
- package/src/auth/answer-authorize-request.ts +0 -137
- package/src/auth/answer-consent-request.ts +0 -189
- package/src/auth/answer-enroll-request.ts +0 -190
- package/src/auth/answer-login-request.ts +0 -256
- package/src/auth/approval-window-seconds.ts +0 -5
- package/src/auth/build-consent-binding.ts +0 -13
- package/src/auth/create-approval-state.ts +0 -221
- package/src/auth/create-enrollment-state.ts +0 -56
- package/src/auth/create-enrollment-token.ts +0 -28
- package/src/auth/create-owner-plugin.ts +0 -113
- package/src/auth/create-passkey.ts +0 -48
- package/src/auth/derive-token-hash.ts +0 -7
- package/src/auth/is-allowed-redirect-uri.ts +0 -19
- package/src/auth/load-web-authn.ts +0 -19
- package/src/auth/mcp-auth-database.ts +0 -10
- package/src/auth/mcp-auth-schema.ts +0 -56
- package/src/auth/open-mcp-auth.ts +0 -138
- package/src/auth/passkey-script.ts +0 -50
- package/src/auth/read-client-name.ts +0 -17
- package/src/auth/read-client-views.ts +0 -27
- package/src/auth/read-enrollment-token.ts +0 -20
- package/src/auth/read-grant-views.ts +0 -53
- package/src/auth/read-owner-session-id.ts +0 -16
- package/src/auth/record-refused-exchange.ts +0 -74
- package/src/auth/remove-client.ts +0 -33
- package/src/auth/remove-owner-session.ts +0 -11
- package/src/auth/render-consent-page.ts +0 -61
- package/src/auth/render-enroll-page.ts +0 -59
- package/src/auth/render-login-page.ts +0 -58
- package/src/auth/revoke-grant.ts +0 -25
- package/src/auth/to-html-text.ts +0 -10
- package/src/auth/to-script-json.ts +0 -8
- package/src/auth/types.ts +0 -115
- package/src/auth/update-passkey-use.ts +0 -31
- package/src/auth/verify-oauth-query.ts +0 -41
- package/src/auth/verify-passkey-assertion.ts +0 -124
- package/src/auth/verify-passkey-registration.ts +0 -118
- package/src/auth/verify-session-passkey.ts +0 -47
- package/src/auth/write-grant-use.ts +0 -18
- package/src/http/answer-mcp-request.ts +0 -77
- package/src/http/build-page-response.ts +0 -26
- package/src/http/create-mcp-http-app.ts +0 -340
- package/src/http/pick-error-message.ts +0 -21
- package/src/http/public-door-paths.ts +0 -21
- package/src/http/read-token-access.ts +0 -44
- package/src/http/verify-access-token.ts +0 -46
- package/src/test-utils/build-mock-new-passkey.ts +0 -15
- package/src/test-utils/build-passkey-seeder.ts +0 -11
- package/src/test-utils/build-seeder.ts +0 -10
- package/src/test-utils/build-stub-authenticator.ts +0 -244
- package/src/test-utils/load-web-authn-early.ts +0 -8
- package/src/test-utils/seed-passkey.ts +0 -32
- package/src/test-utils/start-stub-telemetry-collector.ts +0 -27
- package/src/test-utils/types.ts +0 -11
- package/src/utils/is-record.ts +0 -5
- package/src/utils/parse-json-strings.ts +0 -15
|
@@ -1,244 +0,0 @@
|
|
|
1
|
-
// Copied from atc: packages/test-utils/src/build-stub-authenticator.ts at commit 4fe647cf.
|
|
2
|
-
|
|
3
|
-
import { createHash, randomBytes } from 'node:crypto';
|
|
4
|
-
|
|
5
|
-
// The parts of the creation and request options a browser passes to
|
|
6
|
-
// navigator.credentials that an authenticator reads.
|
|
7
|
-
interface CreationOptions {
|
|
8
|
-
readonly challenge: string;
|
|
9
|
-
readonly rp: { readonly id?: string };
|
|
10
|
-
readonly user: { readonly id: string };
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
interface RequestOptions {
|
|
14
|
-
readonly challenge: string;
|
|
15
|
-
readonly rpId?: string;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
// What a browser and its authenticator put in a response, each defaulting
|
|
19
|
-
// to the honest value: the page's origin as given, the RP ID the options
|
|
20
|
-
// hold, and a verified user.
|
|
21
|
-
interface Ceremony {
|
|
22
|
-
readonly origin: string;
|
|
23
|
-
readonly rpID?: string;
|
|
24
|
-
readonly userVerified?: boolean;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export interface StubRegistration {
|
|
28
|
-
readonly id: string;
|
|
29
|
-
readonly rawId: string;
|
|
30
|
-
readonly type: 'public-key';
|
|
31
|
-
readonly response: {
|
|
32
|
-
readonly clientDataJSON: string;
|
|
33
|
-
readonly attestationObject: string;
|
|
34
|
-
readonly transports: readonly string[];
|
|
35
|
-
};
|
|
36
|
-
readonly clientExtensionResults: Readonly<Record<string, never>>;
|
|
37
|
-
readonly authenticatorAttachment: 'platform';
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
export interface StubAssertion {
|
|
41
|
-
readonly id: string;
|
|
42
|
-
readonly rawId: string;
|
|
43
|
-
readonly type: 'public-key';
|
|
44
|
-
readonly response: {
|
|
45
|
-
readonly clientDataJSON: string;
|
|
46
|
-
readonly authenticatorData: string;
|
|
47
|
-
readonly signature: string;
|
|
48
|
-
readonly userHandle: string;
|
|
49
|
-
};
|
|
50
|
-
readonly clientExtensionResults: Readonly<Record<string, never>>;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
const FLAG_AT = 0x40;
|
|
54
|
-
|
|
55
|
-
type CBORValue = number | string | Buffer | ReadonlyMap<number | string, CBORValue>;
|
|
56
|
-
|
|
57
|
-
export function buildStubAuthenticator() {
|
|
58
|
-
const credentialID = randomBytes(16);
|
|
59
|
-
|
|
60
|
-
const keys = crypto.subtle.generateKey({ name: 'ECDSA', namedCurve: 'P-256' }, true, [
|
|
61
|
-
'sign',
|
|
62
|
-
'verify',
|
|
63
|
-
]);
|
|
64
|
-
|
|
65
|
-
let userHandle: string | null = null;
|
|
66
|
-
let counter = 0;
|
|
67
|
-
|
|
68
|
-
return {
|
|
69
|
-
credentialID: credentialID.toString('base64url'),
|
|
70
|
-
async create(options: CreationOptions, ceremony: Ceremony): Promise<StubRegistration> {
|
|
71
|
-
const pair = await keys;
|
|
72
|
-
const jwk = await crypto.subtle.exportKey('jwk', pair.publicKey);
|
|
73
|
-
|
|
74
|
-
userHandle = options.user.id;
|
|
75
|
-
|
|
76
|
-
// A COSE EC2 key: kty 2, alg -7 (ES256), crv 1 (P-256), x, y.
|
|
77
|
-
const coseKey = encodeCBOR(
|
|
78
|
-
new Map<number, CBORValue>([
|
|
79
|
-
[1, 2],
|
|
80
|
-
[3, -7],
|
|
81
|
-
[-1, 1],
|
|
82
|
-
[-2, Buffer.from(jwk.x ?? '', 'base64url')],
|
|
83
|
-
[-3, Buffer.from(jwk.y ?? '', 'base64url')],
|
|
84
|
-
]),
|
|
85
|
-
);
|
|
86
|
-
|
|
87
|
-
const length = Buffer.alloc(2);
|
|
88
|
-
|
|
89
|
-
length.writeUInt16BE(credentialID.length);
|
|
90
|
-
|
|
91
|
-
const authData = Buffer.concat([
|
|
92
|
-
buildAuthenticatorHeader(ceremony.rpID ?? options.rp.id ?? '', ceremony, 0, FLAG_AT),
|
|
93
|
-
Buffer.alloc(16),
|
|
94
|
-
length,
|
|
95
|
-
credentialID,
|
|
96
|
-
coseKey,
|
|
97
|
-
]);
|
|
98
|
-
|
|
99
|
-
const attestationObject = encodeCBOR(
|
|
100
|
-
new Map<string, CBORValue>([
|
|
101
|
-
['fmt', 'none'],
|
|
102
|
-
['attStmt', new Map()],
|
|
103
|
-
['authData', authData],
|
|
104
|
-
]),
|
|
105
|
-
);
|
|
106
|
-
|
|
107
|
-
return {
|
|
108
|
-
id: credentialID.toString('base64url'),
|
|
109
|
-
rawId: credentialID.toString('base64url'),
|
|
110
|
-
type: 'public-key',
|
|
111
|
-
response: {
|
|
112
|
-
clientDataJSON: buildClientData('webauthn.create', options.challenge, ceremony),
|
|
113
|
-
attestationObject: attestationObject.toString('base64url'),
|
|
114
|
-
transports: ['internal'],
|
|
115
|
-
},
|
|
116
|
-
clientExtensionResults: {},
|
|
117
|
-
authenticatorAttachment: 'platform',
|
|
118
|
-
};
|
|
119
|
-
},
|
|
120
|
-
async signAssertion(options: RequestOptions, ceremony: Ceremony): Promise<StubAssertion> {
|
|
121
|
-
if (userHandle === null) {
|
|
122
|
-
throw new Error('the stub authenticator holds no credential yet');
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
const pair = await keys;
|
|
126
|
-
|
|
127
|
-
counter += 1;
|
|
128
|
-
|
|
129
|
-
const authenticatorData = buildAuthenticatorHeader(
|
|
130
|
-
ceremony.rpID ?? options.rpId ?? '',
|
|
131
|
-
ceremony,
|
|
132
|
-
counter,
|
|
133
|
-
0,
|
|
134
|
-
);
|
|
135
|
-
|
|
136
|
-
const clientDataJSON = buildClientData('webauthn.get', options.challenge, ceremony);
|
|
137
|
-
|
|
138
|
-
const signed = Buffer.concat([
|
|
139
|
-
authenticatorData,
|
|
140
|
-
createHash('sha256').update(Buffer.from(clientDataJSON, 'base64url')).digest(),
|
|
141
|
-
]);
|
|
142
|
-
|
|
143
|
-
const raw = await crypto.subtle.sign(
|
|
144
|
-
{ name: 'ECDSA', hash: 'SHA-256' },
|
|
145
|
-
pair.privateKey,
|
|
146
|
-
signed,
|
|
147
|
-
);
|
|
148
|
-
|
|
149
|
-
return {
|
|
150
|
-
id: credentialID.toString('base64url'),
|
|
151
|
-
rawId: credentialID.toString('base64url'),
|
|
152
|
-
type: 'public-key',
|
|
153
|
-
response: {
|
|
154
|
-
clientDataJSON,
|
|
155
|
-
authenticatorData: authenticatorData.toString('base64url'),
|
|
156
|
-
signature: toDERSignature(Buffer.from(raw)).toString('base64url'),
|
|
157
|
-
userHandle,
|
|
158
|
-
},
|
|
159
|
-
clientExtensionResults: {},
|
|
160
|
-
};
|
|
161
|
-
},
|
|
162
|
-
};
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
// The CBOR subset a COSE key and a `none` attestation need: integers,
|
|
166
|
-
// byte strings, text strings, and maps.
|
|
167
|
-
function encodeCBOR(value: CBORValue): Buffer {
|
|
168
|
-
if (typeof value === 'number') {
|
|
169
|
-
return value >= 0 ? encodeCBORHead(0, value) : encodeCBORHead(1, -1 - value);
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
if (typeof value === 'string') {
|
|
173
|
-
const text = Buffer.from(value);
|
|
174
|
-
|
|
175
|
-
return Buffer.concat([encodeCBORHead(3, text.length), text]);
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
if (Buffer.isBuffer(value)) {
|
|
179
|
-
return Buffer.concat([encodeCBORHead(2, value.length), value]);
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
return Buffer.concat([
|
|
183
|
-
encodeCBORHead(5, value.size),
|
|
184
|
-
...[...value].flatMap(([key, item]) => [encodeCBOR(key), encodeCBOR(item)]),
|
|
185
|
-
]);
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
function encodeCBORHead(major: number, length: number): Buffer {
|
|
189
|
-
if (length < 24) {
|
|
190
|
-
return Buffer.from([(major << 5) | length]);
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
if (length < 256) {
|
|
194
|
-
return Buffer.from([(major << 5) | 24, length]);
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
const head = Buffer.alloc(3);
|
|
198
|
-
|
|
199
|
-
head.writeUInt8((major << 5) | 25);
|
|
200
|
-
head.writeUInt16BE(length, 1);
|
|
201
|
-
|
|
202
|
-
return head;
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
const FLAG_UP = 0x01;
|
|
206
|
-
const FLAG_UV = 0x04;
|
|
207
|
-
|
|
208
|
-
// The RP ID hash, the flags with user presence always set, and the
|
|
209
|
-
// big-endian signature counter.
|
|
210
|
-
function buildAuthenticatorHeader(
|
|
211
|
-
rpID: string,
|
|
212
|
-
ceremony: Ceremony,
|
|
213
|
-
signCount: number,
|
|
214
|
-
extraFlags: number,
|
|
215
|
-
): Buffer {
|
|
216
|
-
const flags = FLAG_UP | (ceremony.userVerified === false ? 0 : FLAG_UV) | extraFlags;
|
|
217
|
-
const count = Buffer.alloc(4);
|
|
218
|
-
|
|
219
|
-
count.writeUInt32BE(signCount);
|
|
220
|
-
|
|
221
|
-
return Buffer.concat([createHash('sha256').update(rpID).digest(), Buffer.from([flags]), count]);
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
function buildClientData(type: string, challenge: string, ceremony: Ceremony): string {
|
|
225
|
-
return Buffer.from(
|
|
226
|
-
JSON.stringify({ type, challenge, origin: ceremony.origin, crossOrigin: false }),
|
|
227
|
-
).toString('base64url');
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
// WebCrypto signs ECDSA as r and s side by side; WebAuthn carries the
|
|
231
|
-
// signature as an ASN.1 DER sequence of two integers.
|
|
232
|
-
function toDERSignature(raw: Buffer): Buffer {
|
|
233
|
-
const integers = [raw.subarray(0, 32), raw.subarray(32)].map((part) => {
|
|
234
|
-
const start = part.findIndex((byte) => byte !== 0);
|
|
235
|
-
const trimmed = start === -1 ? Buffer.from([0]) : part.subarray(start);
|
|
236
|
-
const value = (trimmed[0] ?? 0) >= 0x80 ? Buffer.concat([Buffer.from([0]), trimmed]) : trimmed;
|
|
237
|
-
|
|
238
|
-
return Buffer.concat([Buffer.from([0x02, value.length]), value]);
|
|
239
|
-
});
|
|
240
|
-
|
|
241
|
-
const body = Buffer.concat(integers);
|
|
242
|
-
|
|
243
|
-
return Buffer.concat([Buffer.from([0x30, body.length]), body]);
|
|
244
|
-
}
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
// Copied from atc: packages/mcp/src/testing/load-web-authn-early.ts at commit 4fe647cf.
|
|
2
|
-
|
|
3
|
-
import { loadWebAuthn } from '../auth/load-web-authn.ts';
|
|
4
|
-
|
|
5
|
-
// The first passkey ceremony in a test process loads the WebAuthn library,
|
|
6
|
-
// measured at about 0.26 s cold against 0.015 s warm. Loading it here keeps
|
|
7
|
-
// that one-time cost out of the first test's timeout.
|
|
8
|
-
await loadWebAuthn();
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
// Copied from atc: packages/mcp/src/test-utils/seed-passkey.ts at commit 4fe647cf.
|
|
2
|
-
|
|
3
|
-
import invariant from 'tiny-invariant';
|
|
4
|
-
import { createEnrollmentToken } from '../auth/create-enrollment-token.ts';
|
|
5
|
-
import { createPasskey } from '../auth/create-passkey.ts';
|
|
6
|
-
import type { NewPasskey } from '../auth/create-passkey.ts';
|
|
7
|
-
import { deriveTokenHash } from '../auth/derive-token-hash.ts';
|
|
8
|
-
import { buildMockNewPasskey } from './build-mock-new-passkey.ts';
|
|
9
|
-
import type { MCPAuthSeedDeps } from './types.ts';
|
|
10
|
-
|
|
11
|
-
export type PasskeyInput = Partial<Omit<NewPasskey, 'tokenHash'>>;
|
|
12
|
-
|
|
13
|
-
export async function seedPasskey(
|
|
14
|
-
deps: MCPAuthSeedDeps,
|
|
15
|
-
input: PasskeyInput = {},
|
|
16
|
-
): Promise<NewPasskey> {
|
|
17
|
-
const now = input.now ?? deps.clock.now();
|
|
18
|
-
|
|
19
|
-
const enrollment = await createEnrollmentToken(deps.db, now);
|
|
20
|
-
|
|
21
|
-
const passkey = buildMockNewPasskey({
|
|
22
|
-
...input,
|
|
23
|
-
now,
|
|
24
|
-
tokenHash: deriveTokenHash(enrollment.token),
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
const created = await createPasskey(deps.db, passkey);
|
|
28
|
-
|
|
29
|
-
invariant(created);
|
|
30
|
-
|
|
31
|
-
return passkey;
|
|
32
|
-
}
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
// Copied from atc: packages/test-utils/src/start-stub-telemetry-collector.ts at commit 4fe647cf.
|
|
2
|
-
|
|
3
|
-
import { registerTestCleanup } from './register-test-cleanup.ts';
|
|
4
|
-
|
|
5
|
-
export function startStubTelemetryCollector() {
|
|
6
|
-
const received: string[] = [];
|
|
7
|
-
|
|
8
|
-
const answerRequest = (request: Request) => {
|
|
9
|
-
received.push(request.url);
|
|
10
|
-
|
|
11
|
-
return new Response(null, { status: 204 });
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
const server = Bun.serve({
|
|
15
|
-
hostname: '127.0.0.1',
|
|
16
|
-
port: 0,
|
|
17
|
-
fetch: answerRequest,
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
const stop = registerTestCleanup(() => server.stop(true));
|
|
21
|
-
|
|
22
|
-
return {
|
|
23
|
-
url: `http://127.0.0.1:${String(server.port)}/`,
|
|
24
|
-
received,
|
|
25
|
-
stop,
|
|
26
|
-
};
|
|
27
|
-
}
|
package/src/test-utils/types.ts
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
// Copied from atc: packages/mcp/src/test-utils/types.ts at commit 4fe647cf.
|
|
2
|
-
|
|
3
|
-
import type { Kysely } from 'kysely';
|
|
4
|
-
import type { MCPAuthSchema } from '../auth/mcp-auth-schema.ts';
|
|
5
|
-
import type { AuthClock } from '../utils/types.ts';
|
|
6
|
-
|
|
7
|
-
// The handles the seeds of the authorization database take.
|
|
8
|
-
export interface MCPAuthSeedDeps {
|
|
9
|
-
readonly db: Kysely<MCPAuthSchema>;
|
|
10
|
-
readonly clock: Pick<AuthClock, 'now'>;
|
|
11
|
-
}
|
package/src/utils/is-record.ts
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
// Copied from atc: packages/core/src/parse-json-strings.ts at commit 4fe647cf.
|
|
2
|
-
|
|
3
|
-
export function parseJSONStrings(raw: string): string[] | null {
|
|
4
|
-
let parsed: unknown;
|
|
5
|
-
|
|
6
|
-
try {
|
|
7
|
-
parsed = JSON.parse(raw);
|
|
8
|
-
} catch {
|
|
9
|
-
return null;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
return Array.isArray(parsed)
|
|
13
|
-
? parsed.filter((item): item is string => typeof item === 'string')
|
|
14
|
-
: null;
|
|
15
|
-
}
|