@ankhorage/auth-supabase 0.0.0-stage → 2.0.1
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/LICENSE +21 -0
- package/README.md +22 -2
- package/dist/authConfiguration.d.ts +15 -0
- package/dist/authConfiguration.d.ts.map +1 -0
- package/dist/authConfiguration.js +69 -0
- package/dist/authConfiguration.js.map +1 -0
- package/dist/authPasswordOperations.d.ts +10 -0
- package/dist/authPasswordOperations.d.ts.map +1 -0
- package/dist/authPasswordOperations.js +163 -0
- package/dist/authPasswordOperations.js.map +1 -0
- package/dist/authSessionContext.d.ts +19 -0
- package/dist/authSessionContext.d.ts.map +1 -0
- package/dist/authSessionContext.js +96 -0
- package/dist/authSessionContext.js.map +1 -0
- package/dist/authSessionOperations.d.ts +7 -0
- package/dist/authSessionOperations.d.ts.map +1 -0
- package/dist/authSessionOperations.js +79 -0
- package/dist/authSessionOperations.js.map +1 -0
- package/dist/createSupabaseAuthAdapter.d.ts +5 -0
- package/dist/createSupabaseAuthAdapter.d.ts.map +1 -0
- package/dist/createSupabaseAuthAdapter.js +76 -0
- package/dist/createSupabaseAuthAdapter.js.map +1 -0
- package/dist/errors.d.ts +7 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +89 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/oauth.d.ts +5 -0
- package/dist/oauth.d.ts.map +1 -0
- package/dist/oauth.js +34 -0
- package/dist/oauth.js.map +1 -0
- package/dist/oauthAttemptId.d.ts +9 -0
- package/dist/oauthAttemptId.d.ts.map +1 -0
- package/dist/oauthAttemptId.js +51 -0
- package/dist/oauthAttemptId.js.map +1 -0
- package/dist/oauthCallback.d.ts +23 -0
- package/dist/oauthCallback.d.ts.map +1 -0
- package/dist/oauthCallback.js +81 -0
- package/dist/oauthCallback.js.map +1 -0
- package/dist/oauthComplete.d.ts +5 -0
- package/dist/oauthComplete.d.ts.map +1 -0
- package/dist/oauthComplete.js +133 -0
- package/dist/oauthComplete.js.map +1 -0
- package/dist/oauthCompletionState.d.ts +13 -0
- package/dist/oauthCompletionState.d.ts.map +1 -0
- package/dist/oauthCompletionState.js +25 -0
- package/dist/oauthCompletionState.js.map +1 -0
- package/dist/oauthErrors.d.ts +9 -0
- package/dist/oauthErrors.d.ts.map +1 -0
- package/dist/oauthErrors.js +87 -0
- package/dist/oauthErrors.js.map +1 -0
- package/dist/oauthExchange.d.ts +14 -0
- package/dist/oauthExchange.d.ts.map +1 -0
- package/dist/oauthExchange.js +100 -0
- package/dist/oauthExchange.js.map +1 -0
- package/dist/oauthLifecycle.d.ts +8 -0
- package/dist/oauthLifecycle.d.ts.map +1 -0
- package/dist/oauthLifecycle.js +24 -0
- package/dist/oauthLifecycle.js.map +1 -0
- package/dist/oauthProviderDefinitions.d.ts +77 -0
- package/dist/oauthProviderDefinitions.d.ts.map +1 -0
- package/dist/oauthProviderDefinitions.js +114 -0
- package/dist/oauthProviderDefinitions.js.map +1 -0
- package/dist/oauthRuntime.d.ts +23 -0
- package/dist/oauthRuntime.d.ts.map +1 -0
- package/dist/oauthRuntime.js +22 -0
- package/dist/oauthRuntime.js.map +1 -0
- package/dist/oauthSetupRequirements.d.ts +12 -0
- package/dist/oauthSetupRequirements.d.ts.map +1 -0
- package/dist/oauthSetupRequirements.js +39 -0
- package/dist/oauthSetupRequirements.js.map +1 -0
- package/dist/oauthStart.d.ts +4 -0
- package/dist/oauthStart.d.ts.map +1 -0
- package/dist/oauthStart.js +108 -0
- package/dist/oauthStart.js.map +1 -0
- package/dist/oauthStartSupport.d.ts +52 -0
- package/dist/oauthStartSupport.d.ts.map +1 -0
- package/dist/oauthStartSupport.js +137 -0
- package/dist/oauthStartSupport.js.map +1 -0
- package/dist/oauthStorage.d.ts +25 -0
- package/dist/oauthStorage.d.ts.map +1 -0
- package/dist/oauthStorage.js +146 -0
- package/dist/oauthStorage.js.map +1 -0
- package/dist/oauthTypes.d.ts +49 -0
- package/dist/oauthTypes.d.ts.map +1 -0
- package/dist/oauthTypes.js +6 -0
- package/dist/oauthTypes.js.map +1 -0
- package/dist/profileVerification.d.ts +24 -0
- package/dist/profileVerification.d.ts.map +1 -0
- package/dist/profileVerification.js +178 -0
- package/dist/profileVerification.js.map +1 -0
- package/dist/session.d.ts +6 -0
- package/dist/session.d.ts.map +1 -0
- package/dist/session.js +124 -0
- package/dist/session.js.map +1 -0
- package/dist/types.d.ts +63 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +8 -0
- package/dist/types.js.map +1 -0
- package/package.json +70 -4
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { completeOAuthReplay, invalidCallback, parseCallback } from './oauthCallback.js';
|
|
2
|
+
import { clearOAuthAttempt, failOAuthAttempt, finalizeOAuthAttemptState, } from './oauthCompletionState.js';
|
|
3
|
+
import { oauthCompletionError } from './oauthErrors.js';
|
|
4
|
+
import { exchangeAndPersistOAuthSession } from './oauthExchange.js';
|
|
5
|
+
import { emitLifecycleEvent } from './oauthLifecycle.js';
|
|
6
|
+
import { constantTimeEqual, fingerprintConsumedOAuthCallback, fingerprintOAuthCallback, isAttemptExpired, readAttempt, readConsumedCallbacks, writeAttempt, writeConsumedCallbacks, } from './oauthStorage.js';
|
|
7
|
+
import { CONSUMED_CALLBACK_RETENTION_MS, } from './oauthTypes.js';
|
|
8
|
+
/*** Completes one Supabase OAuth authorization attempt. */
|
|
9
|
+
export async function completeSupabaseOAuthAuthorization(context, input) {
|
|
10
|
+
const loaded = await loadAttempt(context, input);
|
|
11
|
+
if (!loaded.ok)
|
|
12
|
+
return loaded.result;
|
|
13
|
+
const { attempt } = loaded;
|
|
14
|
+
if (attempt.status !== 'pending')
|
|
15
|
+
return completeOAuthReplay(input, attempt);
|
|
16
|
+
const parsed = await parseCompletion(context, attempt, input);
|
|
17
|
+
if (!parsed.ok)
|
|
18
|
+
return parsed.result;
|
|
19
|
+
const reserved = await reserveCallback(context, attempt, parsed.code);
|
|
20
|
+
if (!reserved.ok)
|
|
21
|
+
return reserved.result;
|
|
22
|
+
const session = await exchangeAndPersistOAuthSession(context, attempt, parsed.code);
|
|
23
|
+
if (!session.ok)
|
|
24
|
+
return session.result;
|
|
25
|
+
await finalizeOAuthAttemptState(context, attempt, reserved.callbackFingerprint);
|
|
26
|
+
return { ok: true, status: 'authenticated', provider: attempt.provider, session: session.data };
|
|
27
|
+
}
|
|
28
|
+
async function loadAttempt(context, input) {
|
|
29
|
+
let stored;
|
|
30
|
+
try {
|
|
31
|
+
stored = await readAttempt(context.storage, context.attemptStorageKey);
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
await clearOAuthAttempt(context);
|
|
35
|
+
return completionFailure('session_persistence_failed', 'Unable to read the OAuth attempt.');
|
|
36
|
+
}
|
|
37
|
+
if (stored.type !== 'valid') {
|
|
38
|
+
await clearOAuthAttempt(context);
|
|
39
|
+
return completionFailure('authorization_attempt_not_found', 'The OAuth attempt is invalid.');
|
|
40
|
+
}
|
|
41
|
+
const { attempt } = stored;
|
|
42
|
+
if (isAttemptExpired(attempt, context.now())) {
|
|
43
|
+
await clearOAuthAttempt(context);
|
|
44
|
+
return completionFailure('authorization_attempt_not_found', 'The OAuth attempt expired.', attempt);
|
|
45
|
+
}
|
|
46
|
+
return attempt.id === input.attemptId
|
|
47
|
+
? { ok: true, attempt }
|
|
48
|
+
: completionFailure('authorization_attempt_not_found', 'The OAuth attempt was not found.', attempt);
|
|
49
|
+
}
|
|
50
|
+
async function parseCompletion(context, attempt, input) {
|
|
51
|
+
if (input.response.type === 'cancelled') {
|
|
52
|
+
return completeCancellation(context, attempt, 'transport', input.response.reason);
|
|
53
|
+
}
|
|
54
|
+
if (input.response.type === 'error') {
|
|
55
|
+
return failOAuthAttempt(context, attempt, oauthCompletionError('authorization_failed', 'transport', 'The OAuth transport failed.', attempt.provider, true));
|
|
56
|
+
}
|
|
57
|
+
const callback = parseCallback(input.response.url, attempt);
|
|
58
|
+
if (callback.type === 'code')
|
|
59
|
+
return { ok: true, code: callback.code };
|
|
60
|
+
if (callback.type === 'error')
|
|
61
|
+
return failOAuthAttempt(context, attempt, callback.result);
|
|
62
|
+
return completeCancellation(context, attempt, 'callback', 'provider_denied');
|
|
63
|
+
}
|
|
64
|
+
async function completeCancellation(context, attempt, stage, reason) {
|
|
65
|
+
await finalizeOAuthAttemptState(context, attempt);
|
|
66
|
+
await emitLifecycleEvent(context.onLifecycleEvent, {
|
|
67
|
+
correlationId: attempt.id,
|
|
68
|
+
provider: attempt.provider,
|
|
69
|
+
stage,
|
|
70
|
+
status: 'cancelled',
|
|
71
|
+
});
|
|
72
|
+
return {
|
|
73
|
+
ok: false,
|
|
74
|
+
result: { ok: false, status: 'cancelled', provider: attempt.provider, reason },
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
async function reserveCallback(context, attempt, code) {
|
|
78
|
+
const callbackFingerprint = fingerprintOAuthCallback(attempt.id, code);
|
|
79
|
+
const consumedFingerprint = fingerprintConsumedOAuthCallback(attempt.redirectUri, code);
|
|
80
|
+
let callbacks;
|
|
81
|
+
try {
|
|
82
|
+
callbacks = await readConsumedCallbacks(context.storage, context.consumedCallbacksStorageKey, context.now());
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
return failOAuthAttempt(context, attempt, oauthCompletionError('session_persistence_failed', 'callback', 'Unable to read consumed OAuth callbacks.', attempt.provider, true));
|
|
86
|
+
}
|
|
87
|
+
if (callbacks.some((entry) => constantTimeEqual(entry.fingerprint, consumedFingerprint))) {
|
|
88
|
+
return failOAuthAttempt(context, attempt, invalidCallback(attempt.provider, 'The OAuth callback was already consumed.').result);
|
|
89
|
+
}
|
|
90
|
+
return writeCallbackReservation(context, attempt, callbacks, consumedFingerprint, callbackFingerprint);
|
|
91
|
+
}
|
|
92
|
+
async function writeCallbackReservation(context, attempt, callbacks, consumedFingerprint, callbackFingerprint) {
|
|
93
|
+
const ledgerWritten = await writeCallbackLedger(context, attempt, callbacks, consumedFingerprint);
|
|
94
|
+
if (!ledgerWritten.ok)
|
|
95
|
+
return ledgerWritten;
|
|
96
|
+
try {
|
|
97
|
+
await writeAttempt(context.storage, context.attemptStorageKey, {
|
|
98
|
+
...attempt,
|
|
99
|
+
status: 'completing',
|
|
100
|
+
callbackFingerprint,
|
|
101
|
+
});
|
|
102
|
+
return { ok: true, callbackFingerprint };
|
|
103
|
+
}
|
|
104
|
+
catch {
|
|
105
|
+
await clearOAuthAttempt(context);
|
|
106
|
+
return reservationFailure(attempt, 'Unable to reserve the OAuth callback.');
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
async function writeCallbackLedger(context, attempt, callbacks, fingerprint) {
|
|
110
|
+
try {
|
|
111
|
+
await writeConsumedCallbacks(context.storage, context.consumedCallbacksStorageKey, [
|
|
112
|
+
...callbacks,
|
|
113
|
+
{ fingerprint, expiresAt: context.now() + CONSUMED_CALLBACK_RETENTION_MS },
|
|
114
|
+
]);
|
|
115
|
+
return { ok: true };
|
|
116
|
+
}
|
|
117
|
+
catch {
|
|
118
|
+
return failOAuthAttempt(context, attempt, reservationFailure(attempt, 'Unable to reserve the OAuth callback.').result);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
function reservationFailure(attempt, message) {
|
|
122
|
+
return {
|
|
123
|
+
ok: false,
|
|
124
|
+
result: oauthCompletionError('session_persistence_failed', 'callback', message, attempt.provider, true),
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
function completionFailure(code, message, attempt) {
|
|
128
|
+
return {
|
|
129
|
+
ok: false,
|
|
130
|
+
result: oauthCompletionError(code, 'callback', message, attempt?.provider, true),
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
//# sourceMappingURL=oauthComplete.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oauthComplete.js","sourceRoot":"","sources":["../src/oauthComplete.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n AuthOAuthCancellationReason,\n AuthOAuthCompletionResult,\n CompleteOAuthAuthorizationInput,\n} from '@ankhorage/contracts/auth';\n\nimport { completeOAuthReplay, invalidCallback, parseCallback } from './oauthCallback.js';\nimport {\n clearOAuthAttempt,\n failOAuthAttempt,\n finalizeOAuthAttemptState,\n} from './oauthCompletionState.js';\nimport { oauthCompletionError } from './oauthErrors.js';\nimport { exchangeAndPersistOAuthSession } from './oauthExchange.js';\nimport { emitLifecycleEvent } from './oauthLifecycle.js';\nimport type { OAuthRuntimeContext } from './oauthRuntime.js';\nimport {\n constantTimeEqual,\n fingerprintConsumedOAuthCallback,\n fingerprintOAuthCallback,\n isAttemptExpired,\n readAttempt,\n readConsumedCallbacks,\n writeAttempt,\n writeConsumedCallbacks,\n} from './oauthStorage.js';\nimport {\n CONSUMED_CALLBACK_RETENTION_MS,\n type StoredConsumedOAuthCallback,\n type StoredOAuthAttempt,\n} from './oauthTypes.js';\n\ntype LoadedAttempt =\n | { readonly ok: true; readonly attempt: StoredOAuthAttempt }\n | { readonly ok: false; readonly result: AuthOAuthCompletionResult };\ntype ParsedCompletion =\n | { readonly ok: true; readonly code: string }\n | { readonly ok: false; readonly result: AuthOAuthCompletionResult };\ntype ReservedCallback =\n | { readonly ok: true; readonly callbackFingerprint: string }\n | { readonly ok: false; readonly result: AuthOAuthCompletionResult };\n\n/*** Completes one Supabase OAuth authorization attempt. */\nexport async function completeSupabaseOAuthAuthorization(\n context: OAuthRuntimeContext,\n input: CompleteOAuthAuthorizationInput,\n): Promise<AuthOAuthCompletionResult> {\n const loaded = await loadAttempt(context, input);\n if (!loaded.ok) return loaded.result;\n const { attempt } = loaded;\n if (attempt.status !== 'pending') return completeOAuthReplay(input, attempt);\n const parsed = await parseCompletion(context, attempt, input);\n if (!parsed.ok) return parsed.result;\n const reserved = await reserveCallback(context, attempt, parsed.code);\n if (!reserved.ok) return reserved.result;\n const session = await exchangeAndPersistOAuthSession(context, attempt, parsed.code);\n if (!session.ok) return session.result;\n await finalizeOAuthAttemptState(context, attempt, reserved.callbackFingerprint);\n return { ok: true, status: 'authenticated', provider: attempt.provider, session: session.data };\n}\n\nasync function loadAttempt(\n context: OAuthRuntimeContext,\n input: CompleteOAuthAuthorizationInput,\n): Promise<LoadedAttempt> {\n let stored;\n try {\n stored = await readAttempt(context.storage, context.attemptStorageKey);\n } catch {\n await clearOAuthAttempt(context);\n return completionFailure('session_persistence_failed', 'Unable to read the OAuth attempt.');\n }\n if (stored.type !== 'valid') {\n await clearOAuthAttempt(context);\n return completionFailure('authorization_attempt_not_found', 'The OAuth attempt is invalid.');\n }\n const { attempt } = stored;\n if (isAttemptExpired(attempt, context.now())) {\n await clearOAuthAttempt(context);\n return completionFailure(\n 'authorization_attempt_not_found',\n 'The OAuth attempt expired.',\n attempt,\n );\n }\n return attempt.id === input.attemptId\n ? { ok: true, attempt }\n : completionFailure(\n 'authorization_attempt_not_found',\n 'The OAuth attempt was not found.',\n attempt,\n );\n}\n\nasync function parseCompletion(\n context: OAuthRuntimeContext,\n attempt: StoredOAuthAttempt,\n input: CompleteOAuthAuthorizationInput,\n): Promise<ParsedCompletion> {\n if (input.response.type === 'cancelled') {\n return completeCancellation(context, attempt, 'transport', input.response.reason);\n }\n if (input.response.type === 'error') {\n return failOAuthAttempt(\n context,\n attempt,\n oauthCompletionError(\n 'authorization_failed',\n 'transport',\n 'The OAuth transport failed.',\n attempt.provider,\n true,\n ),\n );\n }\n const callback = parseCallback(input.response.url, attempt);\n if (callback.type === 'code') return { ok: true, code: callback.code };\n if (callback.type === 'error') return failOAuthAttempt(context, attempt, callback.result);\n return completeCancellation(context, attempt, 'callback', 'provider_denied');\n}\n\nasync function completeCancellation(\n context: OAuthRuntimeContext,\n attempt: StoredOAuthAttempt,\n stage: 'transport' | 'callback',\n reason: AuthOAuthCancellationReason,\n): Promise<ParsedCompletion> {\n await finalizeOAuthAttemptState(context, attempt);\n await emitLifecycleEvent(context.onLifecycleEvent, {\n correlationId: attempt.id,\n provider: attempt.provider,\n stage,\n status: 'cancelled',\n });\n return {\n ok: false,\n result: { ok: false, status: 'cancelled', provider: attempt.provider, reason },\n };\n}\n\nasync function reserveCallback(\n context: OAuthRuntimeContext,\n attempt: StoredOAuthAttempt,\n code: string,\n): Promise<ReservedCallback> {\n const callbackFingerprint = fingerprintOAuthCallback(attempt.id, code);\n const consumedFingerprint = fingerprintConsumedOAuthCallback(attempt.redirectUri, code);\n let callbacks: readonly StoredConsumedOAuthCallback[];\n try {\n callbacks = await readConsumedCallbacks(\n context.storage,\n context.consumedCallbacksStorageKey,\n context.now(),\n );\n } catch {\n return failOAuthAttempt(\n context,\n attempt,\n oauthCompletionError(\n 'session_persistence_failed',\n 'callback',\n 'Unable to read consumed OAuth callbacks.',\n attempt.provider,\n true,\n ),\n );\n }\n if (callbacks.some((entry) => constantTimeEqual(entry.fingerprint, consumedFingerprint))) {\n return failOAuthAttempt(\n context,\n attempt,\n invalidCallback(attempt.provider, 'The OAuth callback was already consumed.').result,\n );\n }\n return writeCallbackReservation(\n context,\n attempt,\n callbacks,\n consumedFingerprint,\n callbackFingerprint,\n );\n}\n\nasync function writeCallbackReservation(\n context: OAuthRuntimeContext,\n attempt: StoredOAuthAttempt,\n callbacks: readonly StoredConsumedOAuthCallback[],\n consumedFingerprint: string,\n callbackFingerprint: string,\n): Promise<ReservedCallback> {\n const ledgerWritten = await writeCallbackLedger(context, attempt, callbacks, consumedFingerprint);\n if (!ledgerWritten.ok) return ledgerWritten;\n try {\n await writeAttempt(context.storage, context.attemptStorageKey, {\n ...attempt,\n status: 'completing',\n callbackFingerprint,\n });\n return { ok: true, callbackFingerprint };\n } catch {\n await clearOAuthAttempt(context);\n return reservationFailure(attempt, 'Unable to reserve the OAuth callback.');\n }\n}\n\nasync function writeCallbackLedger(\n context: OAuthRuntimeContext,\n attempt: StoredOAuthAttempt,\n callbacks: readonly StoredConsumedOAuthCallback[],\n fingerprint: string,\n): Promise<{ ok: true } | { ok: false; result: AuthOAuthCompletionResult }> {\n try {\n await writeConsumedCallbacks(context.storage, context.consumedCallbacksStorageKey, [\n ...callbacks,\n { fingerprint, expiresAt: context.now() + CONSUMED_CALLBACK_RETENTION_MS },\n ]);\n return { ok: true };\n } catch {\n return failOAuthAttempt(\n context,\n attempt,\n reservationFailure(attempt, 'Unable to reserve the OAuth callback.').result,\n );\n }\n}\n\nfunction reservationFailure(\n attempt: StoredOAuthAttempt,\n message: string,\n): { ok: false; result: AuthOAuthCompletionResult } {\n return {\n ok: false,\n result: oauthCompletionError(\n 'session_persistence_failed',\n 'callback',\n message,\n attempt.provider,\n true,\n ),\n };\n}\n\nfunction completionFailure(\n code: 'authorization_attempt_not_found' | 'session_persistence_failed',\n message: string,\n attempt?: StoredOAuthAttempt,\n): LoadedAttempt {\n return {\n ok: false,\n result: oauthCompletionError(code, 'callback', message, attempt?.provider, true),\n };\n}\n"]}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { AuthOAuthCompletionResult } from '@ankhorage/contracts/auth';
|
|
2
|
+
import type { OAuthRuntimeContext } from './oauthRuntime.js';
|
|
3
|
+
import type { StoredOAuthAttempt } from './oauthTypes.js';
|
|
4
|
+
/*** Finalizes a failed OAuth attempt, emits safe lifecycle metadata, and returns its result. */
|
|
5
|
+
export declare function failOAuthAttempt(context: OAuthRuntimeContext, attempt: StoredOAuthAttempt, result: AuthOAuthCompletionResult): Promise<{
|
|
6
|
+
ok: false;
|
|
7
|
+
result: AuthOAuthCompletionResult;
|
|
8
|
+
}>;
|
|
9
|
+
/*** Marks an OAuth attempt completed and emits authentication success when applicable. */
|
|
10
|
+
export declare function finalizeOAuthAttemptState(context: OAuthRuntimeContext, attempt: StoredOAuthAttempt, callbackFingerprint?: string): Promise<void>;
|
|
11
|
+
/*** Clears the active attempt and its PKCE verifier. */
|
|
12
|
+
export declare function clearOAuthAttempt(context: OAuthRuntimeContext): Promise<void>;
|
|
13
|
+
//# sourceMappingURL=oauthCompletionState.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oauthCompletionState.d.ts","sourceRoot":"","sources":["../src/oauthCompletionState.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,2BAA2B,CAAC;AAG3E,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAE7D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAE1D,gGAAgG;AAChG,wBAAsB,gBAAgB,CACpC,OAAO,EAAE,mBAAmB,EAC5B,OAAO,EAAE,kBAAkB,EAC3B,MAAM,EAAE,yBAAyB,GAChC,OAAO,CAAC;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,yBAAyB,CAAA;CAAE,CAAC,CAI3D;AAED,0FAA0F;AAC1F,wBAAsB,yBAAyB,CAC7C,OAAO,EAAE,mBAAmB,EAC5B,OAAO,EAAE,kBAAkB,EAC3B,mBAAmB,CAAC,EAAE,MAAM,GAC3B,OAAO,CAAC,IAAI,CAAC,CAef;AAED,wDAAwD;AACxD,wBAAsB,iBAAiB,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CAMnF"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { emitLifecycleEvent, emitOAuthError } from './oauthLifecycle.js';
|
|
2
|
+
import { clearOAuthAttemptState, finalizeAttempt } from './oauthStorage.js';
|
|
3
|
+
/*** Finalizes a failed OAuth attempt, emits safe lifecycle metadata, and returns its result. */
|
|
4
|
+
export async function failOAuthAttempt(context, attempt, result) {
|
|
5
|
+
await finalizeOAuthAttemptState(context, attempt);
|
|
6
|
+
await emitOAuthError(context.onLifecycleEvent, attempt, result);
|
|
7
|
+
return { ok: false, result };
|
|
8
|
+
}
|
|
9
|
+
/*** Marks an OAuth attempt completed and emits authentication success when applicable. */
|
|
10
|
+
export async function finalizeOAuthAttemptState(context, attempt, callbackFingerprint) {
|
|
11
|
+
await finalizeAttempt(context.storage, context.attemptStorageKey, context.codeVerifierStorageKey, attempt, callbackFingerprint);
|
|
12
|
+
if (callbackFingerprint === undefined)
|
|
13
|
+
return;
|
|
14
|
+
await emitLifecycleEvent(context.onLifecycleEvent, {
|
|
15
|
+
correlationId: attempt.id,
|
|
16
|
+
provider: attempt.provider,
|
|
17
|
+
stage: 'session',
|
|
18
|
+
status: 'authenticated',
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
/*** Clears the active attempt and its PKCE verifier. */
|
|
22
|
+
export async function clearOAuthAttempt(context) {
|
|
23
|
+
await clearOAuthAttemptState(context.storage, context.attemptStorageKey, context.codeVerifierStorageKey);
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=oauthCompletionState.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oauthCompletionState.js","sourceRoot":"","sources":["../src/oauthCompletionState.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAEzE,OAAO,EAAE,sBAAsB,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAG5E,gGAAgG;AAChG,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,OAA4B,EAC5B,OAA2B,EAC3B,MAAiC;IAEjC,MAAM,yBAAyB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAClD,MAAM,cAAc,CAAC,OAAO,CAAC,gBAAgB,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;IAChE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC;AAC/B,CAAC;AAED,0FAA0F;AAC1F,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAC7C,OAA4B,EAC5B,OAA2B,EAC3B,mBAA4B;IAE5B,MAAM,eAAe,CACnB,OAAO,CAAC,OAAO,EACf,OAAO,CAAC,iBAAiB,EACzB,OAAO,CAAC,sBAAsB,EAC9B,OAAO,EACP,mBAAmB,CACpB,CAAC;IACF,IAAI,mBAAmB,KAAK,SAAS;QAAE,OAAO;IAC9C,MAAM,kBAAkB,CAAC,OAAO,CAAC,gBAAgB,EAAE;QACjD,aAAa,EAAE,OAAO,CAAC,EAAE;QACzB,QAAQ,EAAE,OAAO,CAAC,QAAQ;QAC1B,KAAK,EAAE,SAAS;QAChB,MAAM,EAAE,eAAe;KACxB,CAAC,CAAC;AACL,CAAC;AAED,wDAAwD;AACxD,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,OAA4B;IAClE,MAAM,sBAAsB,CAC1B,OAAO,CAAC,OAAO,EACf,OAAO,CAAC,iBAAiB,EACzB,OAAO,CAAC,sBAAsB,CAC/B,CAAC;AACJ,CAAC","sourcesContent":["import type { AuthOAuthCompletionResult } from '@ankhorage/contracts/auth';\n\nimport { emitLifecycleEvent, emitOAuthError } from './oauthLifecycle.js';\nimport type { OAuthRuntimeContext } from './oauthRuntime.js';\nimport { clearOAuthAttemptState, finalizeAttempt } from './oauthStorage.js';\nimport type { StoredOAuthAttempt } from './oauthTypes.js';\n\n/*** Finalizes a failed OAuth attempt, emits safe lifecycle metadata, and returns its result. */\nexport async function failOAuthAttempt(\n context: OAuthRuntimeContext,\n attempt: StoredOAuthAttempt,\n result: AuthOAuthCompletionResult,\n): Promise<{ ok: false; result: AuthOAuthCompletionResult }> {\n await finalizeOAuthAttemptState(context, attempt);\n await emitOAuthError(context.onLifecycleEvent, attempt, result);\n return { ok: false, result };\n}\n\n/*** Marks an OAuth attempt completed and emits authentication success when applicable. */\nexport async function finalizeOAuthAttemptState(\n context: OAuthRuntimeContext,\n attempt: StoredOAuthAttempt,\n callbackFingerprint?: string,\n): Promise<void> {\n await finalizeAttempt(\n context.storage,\n context.attemptStorageKey,\n context.codeVerifierStorageKey,\n attempt,\n callbackFingerprint,\n );\n if (callbackFingerprint === undefined) return;\n await emitLifecycleEvent(context.onLifecycleEvent, {\n correlationId: attempt.id,\n provider: attempt.provider,\n stage: 'session',\n status: 'authenticated',\n });\n}\n\n/*** Clears the active attempt and its PKCE verifier. */\nexport async function clearOAuthAttempt(context: OAuthRuntimeContext): Promise<void> {\n await clearOAuthAttemptState(\n context.storage,\n context.attemptStorageKey,\n context.codeVerifierStorageKey,\n );\n}\n"]}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { AuthOAuthCompletionResult, AuthOAuthError, AuthOAuthErrorCode, AuthOAuthErrorStage, AuthOAuthProviderId, AuthOAuthStartResult } from '@ankhorage/contracts/auth';
|
|
2
|
+
import type { SupabaseOAuthProviderId } from './oauthProviderDefinitions.js';
|
|
3
|
+
/*** Maps safe Supabase error metadata to the canonical OAuth error contract. */
|
|
4
|
+
export declare function mapSupabaseOAuthError(error: unknown, stage: AuthOAuthErrorStage, provider: SupabaseOAuthProviderId): AuthOAuthError;
|
|
5
|
+
/*** Creates a failed OAuth start result. */
|
|
6
|
+
export declare function oauthStartError(code: AuthOAuthErrorCode, message: string, provider: AuthOAuthProviderId | undefined, recoverable: boolean): AuthOAuthStartResult;
|
|
7
|
+
/*** Creates a failed OAuth completion result. */
|
|
8
|
+
export declare function oauthCompletionError(code: AuthOAuthErrorCode, stage: AuthOAuthErrorStage, message: string, provider: AuthOAuthProviderId | undefined, recoverable: boolean): AuthOAuthCompletionResult;
|
|
9
|
+
//# sourceMappingURL=oauthErrors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oauthErrors.d.ts","sourceRoot":"","sources":["../src/oauthErrors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,yBAAyB,EACzB,cAAc,EACd,kBAAkB,EAClB,mBAAmB,EACnB,mBAAmB,EACnB,oBAAoB,EACrB,MAAM,2BAA2B,CAAC;AAEnC,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,+BAA+B,CAAC;AAiD7E,gFAAgF;AAChF,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,OAAO,EACd,KAAK,EAAE,mBAAmB,EAC1B,QAAQ,EAAE,uBAAuB,GAChC,cAAc,CAehB;AAED,4CAA4C;AAC5C,wBAAgB,eAAe,CAC7B,IAAI,EAAE,kBAAkB,EACxB,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,mBAAmB,GAAG,SAAS,EACzC,WAAW,EAAE,OAAO,GACnB,oBAAoB,CAEtB;AAED,iDAAiD;AACjD,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,kBAAkB,EACxB,KAAK,EAAE,mBAAmB,EAC1B,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,mBAAmB,GAAG,SAAS,EACzC,WAAW,EAAE,OAAO,GACnB,yBAAyB,CAM3B"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
const OAUTH_ERROR_RULES = [
|
|
2
|
+
{
|
|
3
|
+
matches: includesAny('pkce_code_verifier_not_found', 'bad_code_verifier'),
|
|
4
|
+
code: 'pkce_mismatch',
|
|
5
|
+
stage: 'exchange',
|
|
6
|
+
message: 'The OAuth PKCE verifier is missing or invalid.',
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
matches: includesAny('bad_oauth_state', 'flow_state_not_found', 'flow_state_expired'),
|
|
10
|
+
code: 'state_mismatch',
|
|
11
|
+
message: 'The OAuth authorization state is missing, expired, or invalid.',
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
matches: includesAny('bad_oauth_callback'),
|
|
15
|
+
code: 'invalid_callback',
|
|
16
|
+
stage: 'callback',
|
|
17
|
+
message: 'Supabase Auth rejected the OAuth callback.',
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
matches: includesAny('provider_disabled'),
|
|
21
|
+
code: 'provider_disabled',
|
|
22
|
+
message: 'The OAuth provider is disabled in Supabase Auth.',
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
matches: includesAny('oauth_provider_not_supported'),
|
|
26
|
+
code: 'provider_misconfigured',
|
|
27
|
+
message: 'The OAuth provider is not configured in Supabase Auth.',
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
matches: includesAny('redirect'),
|
|
31
|
+
code: 'invalid_redirect_uri',
|
|
32
|
+
message: 'Supabase Auth rejected the OAuth redirect URI.',
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
matches: includesAny('authretryablefetcherror', 'fetch failed', 'network'),
|
|
36
|
+
code: 'network_error',
|
|
37
|
+
message: 'Unable to reach Supabase Auth during OAuth authorization.',
|
|
38
|
+
},
|
|
39
|
+
];
|
|
40
|
+
/*** Maps safe Supabase error metadata to the canonical OAuth error contract. */
|
|
41
|
+
export function mapSupabaseOAuthError(error, stage, provider) {
|
|
42
|
+
const normalized = normalizeOAuthErrorText(error);
|
|
43
|
+
const rule = OAUTH_ERROR_RULES.find((candidate) => candidate.matches(normalized));
|
|
44
|
+
if (rule !== undefined) {
|
|
45
|
+
return createOAuthError(rule.code, rule.stage ?? stage, rule.message, provider, true);
|
|
46
|
+
}
|
|
47
|
+
return createOAuthError(stage === 'start' ? 'authorization_failed' : 'code_exchange_failed', stage, stage === 'start'
|
|
48
|
+
? 'Supabase Auth could not start OAuth authorization.'
|
|
49
|
+
: 'Supabase Auth could not exchange the OAuth authorization code.', provider, true);
|
|
50
|
+
}
|
|
51
|
+
/*** Creates a failed OAuth start result. */
|
|
52
|
+
export function oauthStartError(code, message, provider, recoverable) {
|
|
53
|
+
return { ok: false, error: createOAuthError(code, 'start', message, provider, recoverable) };
|
|
54
|
+
}
|
|
55
|
+
/*** Creates a failed OAuth completion result. */
|
|
56
|
+
export function oauthCompletionError(code, stage, message, provider, recoverable) {
|
|
57
|
+
return {
|
|
58
|
+
ok: false,
|
|
59
|
+
status: 'error',
|
|
60
|
+
error: createOAuthError(code, stage, message, provider, recoverable),
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
/*** Creates a canonical OAuth error without exposing provider secrets. */
|
|
64
|
+
function createOAuthError(code, stage, message, provider, recoverable) {
|
|
65
|
+
return provider === undefined
|
|
66
|
+
? { code, stage, message, recoverable }
|
|
67
|
+
: { code, stage, message, provider, recoverable };
|
|
68
|
+
}
|
|
69
|
+
function normalizeOAuthErrorText(value) {
|
|
70
|
+
const code = readString(value, 'code');
|
|
71
|
+
const name = readString(value, 'name');
|
|
72
|
+
const message = readString(value, 'message') ?? 'Supabase Auth returned an OAuth error.';
|
|
73
|
+
return `${code ?? ''} ${name ?? ''} ${message}`.toLowerCase();
|
|
74
|
+
}
|
|
75
|
+
function includesAny(...needles) {
|
|
76
|
+
return (value) => needles.some((needle) => value.includes(needle));
|
|
77
|
+
}
|
|
78
|
+
function readString(value, key) {
|
|
79
|
+
if (!isRecord(value))
|
|
80
|
+
return undefined;
|
|
81
|
+
const candidate = Reflect.get(value, key);
|
|
82
|
+
return typeof candidate === 'string' ? candidate : undefined;
|
|
83
|
+
}
|
|
84
|
+
function isRecord(value) {
|
|
85
|
+
return typeof value === 'object' && value !== null;
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=oauthErrors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oauthErrors.js","sourceRoot":"","sources":["../src/oauthErrors.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n AuthOAuthCompletionResult,\n AuthOAuthError,\n AuthOAuthErrorCode,\n AuthOAuthErrorStage,\n AuthOAuthProviderId,\n AuthOAuthStartResult,\n} from '@ankhorage/contracts/auth';\n\nimport type { SupabaseOAuthProviderId } from './oauthProviderDefinitions.js';\n\ninterface OAuthErrorRule {\n readonly matches: (normalized: string) => boolean;\n readonly code: AuthOAuthErrorCode;\n readonly stage?: AuthOAuthErrorStage;\n readonly message: string;\n}\n\nconst OAUTH_ERROR_RULES: readonly OAuthErrorRule[] = [\n {\n matches: includesAny('pkce_code_verifier_not_found', 'bad_code_verifier'),\n code: 'pkce_mismatch',\n stage: 'exchange',\n message: 'The OAuth PKCE verifier is missing or invalid.',\n },\n {\n matches: includesAny('bad_oauth_state', 'flow_state_not_found', 'flow_state_expired'),\n code: 'state_mismatch',\n message: 'The OAuth authorization state is missing, expired, or invalid.',\n },\n {\n matches: includesAny('bad_oauth_callback'),\n code: 'invalid_callback',\n stage: 'callback',\n message: 'Supabase Auth rejected the OAuth callback.',\n },\n {\n matches: includesAny('provider_disabled'),\n code: 'provider_disabled',\n message: 'The OAuth provider is disabled in Supabase Auth.',\n },\n {\n matches: includesAny('oauth_provider_not_supported'),\n code: 'provider_misconfigured',\n message: 'The OAuth provider is not configured in Supabase Auth.',\n },\n {\n matches: includesAny('redirect'),\n code: 'invalid_redirect_uri',\n message: 'Supabase Auth rejected the OAuth redirect URI.',\n },\n {\n matches: includesAny('authretryablefetcherror', 'fetch failed', 'network'),\n code: 'network_error',\n message: 'Unable to reach Supabase Auth during OAuth authorization.',\n },\n];\n\n/*** Maps safe Supabase error metadata to the canonical OAuth error contract. */\nexport function mapSupabaseOAuthError(\n error: unknown,\n stage: AuthOAuthErrorStage,\n provider: SupabaseOAuthProviderId,\n): AuthOAuthError {\n const normalized = normalizeOAuthErrorText(error);\n const rule = OAUTH_ERROR_RULES.find((candidate) => candidate.matches(normalized));\n if (rule !== undefined) {\n return createOAuthError(rule.code, rule.stage ?? stage, rule.message, provider, true);\n }\n return createOAuthError(\n stage === 'start' ? 'authorization_failed' : 'code_exchange_failed',\n stage,\n stage === 'start'\n ? 'Supabase Auth could not start OAuth authorization.'\n : 'Supabase Auth could not exchange the OAuth authorization code.',\n provider,\n true,\n );\n}\n\n/*** Creates a failed OAuth start result. */\nexport function oauthStartError(\n code: AuthOAuthErrorCode,\n message: string,\n provider: AuthOAuthProviderId | undefined,\n recoverable: boolean,\n): AuthOAuthStartResult {\n return { ok: false, error: createOAuthError(code, 'start', message, provider, recoverable) };\n}\n\n/*** Creates a failed OAuth completion result. */\nexport function oauthCompletionError(\n code: AuthOAuthErrorCode,\n stage: AuthOAuthErrorStage,\n message: string,\n provider: AuthOAuthProviderId | undefined,\n recoverable: boolean,\n): AuthOAuthCompletionResult {\n return {\n ok: false,\n status: 'error',\n error: createOAuthError(code, stage, message, provider, recoverable),\n };\n}\n\n/*** Creates a canonical OAuth error without exposing provider secrets. */\nfunction createOAuthError(\n code: AuthOAuthErrorCode,\n stage: AuthOAuthErrorStage,\n message: string,\n provider: AuthOAuthProviderId | undefined,\n recoverable: boolean,\n): AuthOAuthError {\n return provider === undefined\n ? { code, stage, message, recoverable }\n : { code, stage, message, provider, recoverable };\n}\n\nfunction normalizeOAuthErrorText(value: unknown): string {\n const code = readString(value, 'code');\n const name = readString(value, 'name');\n const message = readString(value, 'message') ?? 'Supabase Auth returned an OAuth error.';\n return `${code ?? ''} ${name ?? ''} ${message}`.toLowerCase();\n}\n\nfunction includesAny(...needles: readonly string[]): (value: string) => boolean {\n return (value) => needles.some((needle) => value.includes(needle));\n}\n\nfunction readString(value: unknown, key: string): string | undefined {\n if (!isRecord(value)) return undefined;\n const candidate: unknown = Reflect.get(value, key);\n return typeof candidate === 'string' ? candidate : undefined;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null;\n}\n"]}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { AuthOAuthCompletionResult, AuthSession } from '@ankhorage/contracts/auth';
|
|
2
|
+
import type { OAuthRuntimeContext } from './oauthRuntime.js';
|
|
3
|
+
import type { StoredOAuthAttempt } from './oauthTypes.js';
|
|
4
|
+
type SessionResult = {
|
|
5
|
+
ok: true;
|
|
6
|
+
data: AuthSession;
|
|
7
|
+
} | {
|
|
8
|
+
ok: false;
|
|
9
|
+
result: AuthOAuthCompletionResult;
|
|
10
|
+
};
|
|
11
|
+
/*** Exchanges an OAuth code, persists its session, and verifies the generated profile. */
|
|
12
|
+
export declare function exchangeAndPersistOAuthSession(context: OAuthRuntimeContext, attempt: StoredOAuthAttempt, code: string): Promise<SessionResult>;
|
|
13
|
+
export {};
|
|
14
|
+
//# sourceMappingURL=oauthExchange.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oauthExchange.d.ts","sourceRoot":"","sources":["../src/oauthExchange.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,yBAAyB,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAMxF,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAE7D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAG1D,KAAK,aAAa,GAChB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,WAAW,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,yBAAyB,CAAA;CAAE,CAAC;AAErF,0FAA0F;AAC1F,wBAAsB,8BAA8B,CAClD,OAAO,EAAE,mBAAmB,EAC5B,OAAO,EAAE,kBAAkB,EAC3B,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,aAAa,CAAC,CASxB"}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { readResponseBody } from './errors.js';
|
|
2
|
+
import { failOAuthAttempt } from './oauthCompletionState.js';
|
|
3
|
+
import { mapSupabaseOAuthError, oauthCompletionError } from './oauthErrors.js';
|
|
4
|
+
import { emitLifecycleEvent } from './oauthLifecycle.js';
|
|
5
|
+
import { exchangeAuthorizationCode } from './oauthStartSupport.js';
|
|
6
|
+
import { normalizeSupabaseSession } from './session.js';
|
|
7
|
+
/*** Exchanges an OAuth code, persists its session, and verifies the generated profile. */
|
|
8
|
+
export async function exchangeAndPersistOAuthSession(context, attempt, code) {
|
|
9
|
+
const verifier = await readVerifier(context, attempt);
|
|
10
|
+
if (!verifier.ok)
|
|
11
|
+
return verifier;
|
|
12
|
+
const exchanged = await exchangeSession(context, attempt, code, verifier.data);
|
|
13
|
+
if (!exchanged.ok)
|
|
14
|
+
return exchanged;
|
|
15
|
+
const persisted = await persistSession(context, attempt, exchanged.data);
|
|
16
|
+
if (!persisted.ok)
|
|
17
|
+
return persisted;
|
|
18
|
+
const verified = await verifyProfile(context, attempt, exchanged.data);
|
|
19
|
+
return verified.ok ? exchanged : verified;
|
|
20
|
+
}
|
|
21
|
+
async function exchangeSession(context, attempt, code, verifier) {
|
|
22
|
+
let response;
|
|
23
|
+
try {
|
|
24
|
+
response = await exchangeAuthorizationCode({
|
|
25
|
+
anonKey: context.anonKey,
|
|
26
|
+
baseUrl: context.url,
|
|
27
|
+
code,
|
|
28
|
+
fetch: context.fetch,
|
|
29
|
+
verifier,
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
return failOAuthAttempt(context, attempt, oauthCompletionError('network_error', 'exchange', 'Unable to exchange the OAuth code.', attempt.provider, true));
|
|
34
|
+
}
|
|
35
|
+
return normalizeExchangeResponse(context, attempt, response);
|
|
36
|
+
}
|
|
37
|
+
async function normalizeExchangeResponse(context, attempt, response) {
|
|
38
|
+
const body = await readResponseBody(response);
|
|
39
|
+
if (!response.ok) {
|
|
40
|
+
return failOAuthAttempt(context, attempt, {
|
|
41
|
+
ok: false,
|
|
42
|
+
status: 'error',
|
|
43
|
+
error: mapSupabaseOAuthError(body, 'exchange', attempt.provider),
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
const session = normalizeSupabaseSession(body);
|
|
47
|
+
return session === null
|
|
48
|
+
? failOAuthAttempt(context, attempt, oauthCompletionError('provider_error', 'session', 'Supabase returned an invalid OAuth session.', attempt.provider, false))
|
|
49
|
+
: { ok: true, data: session };
|
|
50
|
+
}
|
|
51
|
+
async function readVerifier(context, attempt) {
|
|
52
|
+
let verifier;
|
|
53
|
+
try {
|
|
54
|
+
verifier = await context.storage.getItem(context.codeVerifierStorageKey);
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
return failOAuthAttempt(context, attempt, oauthCompletionError('session_persistence_failed', 'exchange', 'The OAuth verifier could not be read.', attempt.provider, true));
|
|
58
|
+
}
|
|
59
|
+
return verifier === null || verifier.length === 0
|
|
60
|
+
? failOAuthAttempt(context, attempt, oauthCompletionError('pkce_mismatch', 'exchange', 'The OAuth verifier is missing.', attempt.provider, true))
|
|
61
|
+
: { ok: true, data: verifier };
|
|
62
|
+
}
|
|
63
|
+
async function persistSession(context, attempt, session) {
|
|
64
|
+
try {
|
|
65
|
+
await context.persistSession(session);
|
|
66
|
+
return { ok: true };
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
return failOAuthAttempt(context, attempt, oauthCompletionError('session_persistence_failed', 'session', 'The OAuth session could not be persisted.', attempt.provider, true));
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
async function verifyProfile(context, attempt, session) {
|
|
73
|
+
if (context.verifyProfile === undefined)
|
|
74
|
+
return { ok: true };
|
|
75
|
+
let verification;
|
|
76
|
+
try {
|
|
77
|
+
verification = await context.verifyProfile({
|
|
78
|
+
correlationId: attempt.id,
|
|
79
|
+
provider: attempt.provider,
|
|
80
|
+
session,
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
catch {
|
|
84
|
+
verification = {
|
|
85
|
+
ok: false,
|
|
86
|
+
message: 'The generated public profile could not be verified.',
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
if (!verification.ok) {
|
|
90
|
+
return failOAuthAttempt(context, attempt, oauthCompletionError('profile_creation_failed', 'profile', verification.message, attempt.provider, true));
|
|
91
|
+
}
|
|
92
|
+
await emitLifecycleEvent(context.onLifecycleEvent, {
|
|
93
|
+
correlationId: attempt.id,
|
|
94
|
+
provider: attempt.provider,
|
|
95
|
+
stage: 'profile',
|
|
96
|
+
status: 'profile_verified',
|
|
97
|
+
});
|
|
98
|
+
return { ok: true };
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=oauthExchange.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oauthExchange.js","sourceRoot":"","sources":["../src/oauthExchange.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AuthOAuthCompletionResult, AuthSession } from '@ankhorage/contracts/auth';\n\nimport { readResponseBody } from './errors.js';\nimport { failOAuthAttempt } from './oauthCompletionState.js';\nimport { mapSupabaseOAuthError, oauthCompletionError } from './oauthErrors.js';\nimport { emitLifecycleEvent } from './oauthLifecycle.js';\nimport type { OAuthRuntimeContext } from './oauthRuntime.js';\nimport { exchangeAuthorizationCode } from './oauthStartSupport.js';\nimport type { StoredOAuthAttempt } from './oauthTypes.js';\nimport { normalizeSupabaseSession } from './session.js';\n\ntype SessionResult =\n { ok: true; data: AuthSession } | { ok: false; result: AuthOAuthCompletionResult };\n\n/*** Exchanges an OAuth code, persists its session, and verifies the generated profile. */\nexport async function exchangeAndPersistOAuthSession(\n context: OAuthRuntimeContext,\n attempt: StoredOAuthAttempt,\n code: string,\n): Promise<SessionResult> {\n const verifier = await readVerifier(context, attempt);\n if (!verifier.ok) return verifier;\n const exchanged = await exchangeSession(context, attempt, code, verifier.data);\n if (!exchanged.ok) return exchanged;\n const persisted = await persistSession(context, attempt, exchanged.data);\n if (!persisted.ok) return persisted;\n const verified = await verifyProfile(context, attempt, exchanged.data);\n return verified.ok ? exchanged : verified;\n}\n\nasync function exchangeSession(\n context: OAuthRuntimeContext,\n attempt: StoredOAuthAttempt,\n code: string,\n verifier: string,\n): Promise<SessionResult> {\n let response: Response;\n try {\n response = await exchangeAuthorizationCode({\n anonKey: context.anonKey,\n baseUrl: context.url,\n code,\n fetch: context.fetch,\n verifier,\n });\n } catch {\n return failOAuthAttempt(\n context,\n attempt,\n oauthCompletionError(\n 'network_error',\n 'exchange',\n 'Unable to exchange the OAuth code.',\n attempt.provider,\n true,\n ),\n );\n }\n return normalizeExchangeResponse(context, attempt, response);\n}\n\nasync function normalizeExchangeResponse(\n context: OAuthRuntimeContext,\n attempt: StoredOAuthAttempt,\n response: Response,\n): Promise<SessionResult> {\n const body = await readResponseBody(response);\n if (!response.ok) {\n return failOAuthAttempt(context, attempt, {\n ok: false,\n status: 'error',\n error: mapSupabaseOAuthError(body, 'exchange', attempt.provider),\n });\n }\n const session = normalizeSupabaseSession(body);\n return session === null\n ? failOAuthAttempt(\n context,\n attempt,\n oauthCompletionError(\n 'provider_error',\n 'session',\n 'Supabase returned an invalid OAuth session.',\n attempt.provider,\n false,\n ),\n )\n : { ok: true, data: session };\n}\n\nasync function readVerifier(\n context: OAuthRuntimeContext,\n attempt: StoredOAuthAttempt,\n): Promise<{ ok: true; data: string } | { ok: false; result: AuthOAuthCompletionResult }> {\n let verifier: string | null;\n try {\n verifier = await context.storage.getItem(context.codeVerifierStorageKey);\n } catch {\n return failOAuthAttempt(\n context,\n attempt,\n oauthCompletionError(\n 'session_persistence_failed',\n 'exchange',\n 'The OAuth verifier could not be read.',\n attempt.provider,\n true,\n ),\n );\n }\n return verifier === null || verifier.length === 0\n ? failOAuthAttempt(\n context,\n attempt,\n oauthCompletionError(\n 'pkce_mismatch',\n 'exchange',\n 'The OAuth verifier is missing.',\n attempt.provider,\n true,\n ),\n )\n : { ok: true, data: verifier };\n}\n\nasync function persistSession(\n context: OAuthRuntimeContext,\n attempt: StoredOAuthAttempt,\n session: AuthSession,\n): Promise<{ ok: true } | { ok: false; result: AuthOAuthCompletionResult }> {\n try {\n await context.persistSession(session);\n return { ok: true };\n } catch {\n return failOAuthAttempt(\n context,\n attempt,\n oauthCompletionError(\n 'session_persistence_failed',\n 'session',\n 'The OAuth session could not be persisted.',\n attempt.provider,\n true,\n ),\n );\n }\n}\n\nasync function verifyProfile(\n context: OAuthRuntimeContext,\n attempt: StoredOAuthAttempt,\n session: AuthSession,\n): Promise<{ ok: true } | { ok: false; result: AuthOAuthCompletionResult }> {\n if (context.verifyProfile === undefined) return { ok: true };\n let verification;\n try {\n verification = await context.verifyProfile({\n correlationId: attempt.id,\n provider: attempt.provider,\n session,\n });\n } catch {\n verification = {\n ok: false as const,\n message: 'The generated public profile could not be verified.',\n };\n }\n if (!verification.ok) {\n return failOAuthAttempt(\n context,\n attempt,\n oauthCompletionError(\n 'profile_creation_failed',\n 'profile',\n verification.message,\n attempt.provider,\n true,\n ),\n );\n }\n await emitLifecycleEvent(context.onLifecycleEvent, {\n correlationId: attempt.id,\n provider: attempt.provider,\n stage: 'profile',\n status: 'profile_verified',\n });\n return { ok: true };\n}\n"]}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { AuthOAuthCompletionResult } from '@ankhorage/contracts/auth';
|
|
2
|
+
import type { StoredOAuthAttempt } from './oauthTypes.js';
|
|
3
|
+
import type { SupabaseOAuthLifecycleEvent, SupabaseOAuthLifecycleObserver } from './types.js';
|
|
4
|
+
/*** Emits a redacted OAuth failure event for the supplied attempt. */
|
|
5
|
+
export declare function emitOAuthError(observer: SupabaseOAuthLifecycleObserver | undefined, attempt: StoredOAuthAttempt, result: AuthOAuthCompletionResult): Promise<void>;
|
|
6
|
+
/*** Notifies the optional lifecycle observer without changing authentication behavior. */
|
|
7
|
+
export declare function emitLifecycleEvent(observer: SupabaseOAuthLifecycleObserver | undefined, event: SupabaseOAuthLifecycleEvent): Promise<void>;
|
|
8
|
+
//# sourceMappingURL=oauthLifecycle.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oauthLifecycle.d.ts","sourceRoot":"","sources":["../src/oauthLifecycle.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,2BAA2B,CAAC;AAE3E,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAC1D,OAAO,KAAK,EAAE,2BAA2B,EAAE,8BAA8B,EAAE,MAAM,YAAY,CAAC;AAE9F,sEAAsE;AACtE,wBAAsB,cAAc,CAClC,QAAQ,EAAE,8BAA8B,GAAG,SAAS,EACpD,OAAO,EAAE,kBAAkB,EAC3B,MAAM,EAAE,yBAAyB,GAChC,OAAO,CAAC,IAAI,CAAC,CASf;AAED,0FAA0F;AAC1F,wBAAsB,kBAAkB,CACtC,QAAQ,EAAE,8BAA8B,GAAG,SAAS,EACpD,KAAK,EAAE,2BAA2B,GACjC,OAAO,CAAC,IAAI,CAAC,CAOf"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/*** Emits a redacted OAuth failure event for the supplied attempt. */
|
|
2
|
+
export async function emitOAuthError(observer, attempt, result) {
|
|
3
|
+
if (result.ok || result.status !== 'error')
|
|
4
|
+
return;
|
|
5
|
+
await emitLifecycleEvent(observer, {
|
|
6
|
+
correlationId: attempt.id,
|
|
7
|
+
provider: attempt.provider,
|
|
8
|
+
stage: result.error.stage,
|
|
9
|
+
status: 'error',
|
|
10
|
+
errorCode: result.error.code,
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
/*** Notifies the optional lifecycle observer without changing authentication behavior. */
|
|
14
|
+
export async function emitLifecycleEvent(observer, event) {
|
|
15
|
+
if (observer === undefined)
|
|
16
|
+
return;
|
|
17
|
+
try {
|
|
18
|
+
await observer(event);
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
// Observability must never change the authentication result.
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=oauthLifecycle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oauthLifecycle.js","sourceRoot":"","sources":["../src/oauthLifecycle.ts"],"names":[],"mappings":"AAKA,sEAAsE;AACtE,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,QAAoD,EACpD,OAA2B,EAC3B,MAAiC;IAEjC,IAAI,MAAM,CAAC,EAAE,IAAI,MAAM,CAAC,MAAM,KAAK,OAAO;QAAE,OAAO;IACnD,MAAM,kBAAkB,CAAC,QAAQ,EAAE;QACjC,aAAa,EAAE,OAAO,CAAC,EAAE;QACzB,QAAQ,EAAE,OAAO,CAAC,QAAQ;QAC1B,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,KAAK;QACzB,MAAM,EAAE,OAAO;QACf,SAAS,EAAE,MAAM,CAAC,KAAK,CAAC,IAAI;KAC7B,CAAC,CAAC;AACL,CAAC;AAED,0FAA0F;AAC1F,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,QAAoD,EACpD,KAAkC;IAElC,IAAI,QAAQ,KAAK,SAAS;QAAE,OAAO;IACnC,IAAI,CAAC;QACH,MAAM,QAAQ,CAAC,KAAK,CAAC,CAAC;IACxB,CAAC;IAAC,MAAM,CAAC;QACP,6DAA6D;IAC/D,CAAC;AACH,CAAC","sourcesContent":["import type { AuthOAuthCompletionResult } from '@ankhorage/contracts/auth';\n\nimport type { StoredOAuthAttempt } from './oauthTypes.js';\nimport type { SupabaseOAuthLifecycleEvent, SupabaseOAuthLifecycleObserver } from './types.js';\n\n/*** Emits a redacted OAuth failure event for the supplied attempt. */\nexport async function emitOAuthError(\n observer: SupabaseOAuthLifecycleObserver | undefined,\n attempt: StoredOAuthAttempt,\n result: AuthOAuthCompletionResult,\n): Promise<void> {\n if (result.ok || result.status !== 'error') return;\n await emitLifecycleEvent(observer, {\n correlationId: attempt.id,\n provider: attempt.provider,\n stage: result.error.stage,\n status: 'error',\n errorCode: result.error.code,\n });\n}\n\n/*** Notifies the optional lifecycle observer without changing authentication behavior. */\nexport async function emitLifecycleEvent(\n observer: SupabaseOAuthLifecycleObserver | undefined,\n event: SupabaseOAuthLifecycleEvent,\n): Promise<void> {\n if (observer === undefined) return;\n try {\n await observer(event);\n } catch {\n // Observability must never change the authentication result.\n }\n}\n"]}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import type { AuthOAuthProviderId } from '@ankhorage/contracts/auth';
|
|
2
|
+
import type { SecretPayload, SecretStoreResult } from '@ankhorage/contracts/secrets';
|
|
3
|
+
export declare const SUPABASE_OAUTH_PROVIDER_IDS: readonly ["google", "apple"];
|
|
4
|
+
export type SupabaseOAuthProviderId = (typeof SUPABASE_OAUTH_PROVIDER_IDS)[number];
|
|
5
|
+
export type SupabaseOAuthSecretPayload = SecretPayload & {
|
|
6
|
+
readonly clientId: string;
|
|
7
|
+
readonly clientSecret: string;
|
|
8
|
+
};
|
|
9
|
+
export interface SupabaseOAuthSecretFieldDefinition {
|
|
10
|
+
name: 'clientId' | 'clientSecret';
|
|
11
|
+
label: string;
|
|
12
|
+
secret: boolean;
|
|
13
|
+
}
|
|
14
|
+
export interface SupabaseOAuthRuntimeEnvironmentDefinition {
|
|
15
|
+
enabled: string;
|
|
16
|
+
clientId: string;
|
|
17
|
+
clientSecret: string;
|
|
18
|
+
redirectUri: string;
|
|
19
|
+
}
|
|
20
|
+
export interface SupabaseOAuthProviderDefinition {
|
|
21
|
+
id: SupabaseOAuthProviderId;
|
|
22
|
+
label: string;
|
|
23
|
+
defaultScopes: readonly string[];
|
|
24
|
+
secretFields: readonly SupabaseOAuthSecretFieldDefinition[];
|
|
25
|
+
runtimeEnvironment: SupabaseOAuthRuntimeEnvironmentDefinition;
|
|
26
|
+
}
|
|
27
|
+
export declare const SUPABASE_OAUTH_PROVIDER_DEFINITIONS: {
|
|
28
|
+
readonly google: {
|
|
29
|
+
readonly id: "google";
|
|
30
|
+
readonly label: "Google";
|
|
31
|
+
readonly defaultScopes: readonly ["openid", "email", "profile"];
|
|
32
|
+
readonly secretFields: readonly [{
|
|
33
|
+
readonly name: "clientId";
|
|
34
|
+
readonly label: "Client ID";
|
|
35
|
+
readonly secret: false;
|
|
36
|
+
}, {
|
|
37
|
+
readonly name: "clientSecret";
|
|
38
|
+
readonly label: "Client secret";
|
|
39
|
+
readonly secret: true;
|
|
40
|
+
}];
|
|
41
|
+
readonly runtimeEnvironment: {
|
|
42
|
+
readonly enabled: "GOTRUE_EXTERNAL_GOOGLE_ENABLED";
|
|
43
|
+
readonly clientId: "GOTRUE_EXTERNAL_GOOGLE_CLIENT_ID";
|
|
44
|
+
readonly clientSecret: "GOTRUE_EXTERNAL_GOOGLE_SECRET";
|
|
45
|
+
readonly redirectUri: "GOTRUE_EXTERNAL_GOOGLE_REDIRECT_URI";
|
|
46
|
+
};
|
|
47
|
+
};
|
|
48
|
+
readonly apple: {
|
|
49
|
+
readonly id: "apple";
|
|
50
|
+
readonly label: "Apple";
|
|
51
|
+
readonly defaultScopes: readonly ["name", "email"];
|
|
52
|
+
readonly secretFields: readonly [{
|
|
53
|
+
readonly name: "clientId";
|
|
54
|
+
readonly label: "Client ID";
|
|
55
|
+
readonly secret: false;
|
|
56
|
+
}, {
|
|
57
|
+
readonly name: "clientSecret";
|
|
58
|
+
readonly label: "Client secret";
|
|
59
|
+
readonly secret: true;
|
|
60
|
+
}];
|
|
61
|
+
readonly runtimeEnvironment: {
|
|
62
|
+
readonly enabled: "GOTRUE_EXTERNAL_APPLE_ENABLED";
|
|
63
|
+
readonly clientId: "GOTRUE_EXTERNAL_APPLE_CLIENT_ID";
|
|
64
|
+
readonly clientSecret: "GOTRUE_EXTERNAL_APPLE_SECRET";
|
|
65
|
+
readonly redirectUri: "GOTRUE_EXTERNAL_APPLE_REDIRECT_URI";
|
|
66
|
+
};
|
|
67
|
+
};
|
|
68
|
+
};
|
|
69
|
+
export declare function isSupabaseOAuthProviderId(provider: AuthOAuthProviderId): provider is SupabaseOAuthProviderId;
|
|
70
|
+
export declare function getSupabaseOAuthProviderDefinition(provider: AuthOAuthProviderId): SupabaseOAuthProviderDefinition | null;
|
|
71
|
+
export declare function validateSupabaseOAuthSecretPayload(provider: AuthOAuthProviderId, payload: SecretPayload): SecretStoreResult<SupabaseOAuthSecretPayload>;
|
|
72
|
+
export declare function materializeSupabaseOAuthEnvironment(input: {
|
|
73
|
+
provider: AuthOAuthProviderId;
|
|
74
|
+
payload: SecretPayload;
|
|
75
|
+
redirectUri: string;
|
|
76
|
+
}): SecretStoreResult<Readonly<Record<string, string>>>;
|
|
77
|
+
//# sourceMappingURL=oauthProviderDefinitions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oauthProviderDefinitions.d.ts","sourceRoot":"","sources":["../src/oauthProviderDefinitions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AACrE,OAAO,KAAK,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AAErF,eAAO,MAAM,2BAA2B,8BAA+B,CAAC;AACxE,MAAM,MAAM,uBAAuB,GAAG,CAAC,OAAO,2BAA2B,CAAC,CAAC,MAAM,CAAC,CAAC;AAEnF,MAAM,MAAM,0BAA0B,GAAG,aAAa,GAAG;IACvD,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;CAC/B,CAAC;AAEF,MAAM,WAAW,kCAAkC;IACjD,IAAI,EAAE,UAAU,GAAG,cAAc,CAAC;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,yCAAyC;IACxD,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,+BAA+B;IAC9C,EAAE,EAAE,uBAAuB,CAAC;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC,YAAY,EAAE,SAAS,kCAAkC,EAAE,CAAC;IAC5D,kBAAkB,EAAE,yCAAyC,CAAC;CAC/D;AAOD,eAAO,MAAM,mCAAmC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAyBqC,CAAC;AAYtF,wBAAgB,yBAAyB,CACvC,QAAQ,EAAE,mBAAmB,GAC5B,QAAQ,IAAI,uBAAuB,CAErC;AAED,wBAAgB,kCAAkC,CAChD,QAAQ,EAAE,mBAAmB,GAC5B,+BAA+B,GAAG,IAAI,CAIxC;AAED,wBAAgB,kCAAkC,CAChD,QAAQ,EAAE,mBAAmB,EAC7B,OAAO,EAAE,aAAa,GACrB,iBAAiB,CAAC,0BAA0B,CAAC,CA2C/C;AAED,wBAAgB,mCAAmC,CAAC,KAAK,EAAE;IACzD,QAAQ,EAAE,mBAAmB,CAAC;IAC9B,OAAO,EAAE,aAAa,CAAC;IACvB,WAAW,EAAE,MAAM,CAAC;CACrB,GAAG,iBAAiB,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,CAmCtD"}
|