@clerk/shared
Version:
Internal package utils used by the Clerk SDKs
1 lines • 4.67 kB
Source Map (JSON)
{"version":3,"file":"protectCheckRunner.mjs","names":[],"sources":["../../../src/internal/clerk-js/protectCheckRunner.ts"],"sourcesContent":["import { ClerkRuntimeError, isClerkAPIResponseError } from '../../error';\nimport type { ProtectCheckResource } from '../../types';\nimport { ERROR_CODES } from './constants';\nimport { executeProtectCheck } from './protectCheck';\n\n// A GET reload does not re-mint an expired challenge today, so an uncapped reload loop would spin forever.\nexport const MAX_EXPIRED_PROTECT_CHECK_RELOADS = 2;\n\nexport interface ProtectCheckRunnerResource<TResource> {\n getProtectCheck: () => ProtectCheckResource | null | undefined;\n getResource: () => TResource;\n reload: () => Promise<unknown>;\n submitProtectCheck: (params: { proofToken: string }) => Promise<TResource>;\n}\n\nexport interface ProtectCheckRunOptions {\n container: HTMLDivElement;\n expiredReloads: { current: number };\n signal?: AbortSignal;\n setWidgetVisible?: (visible: boolean) => Promise<void>;\n loadTimeoutMs?: number;\n}\n\n/** `reissued` means the expired challenge was replaced by a fresh one on reload, so run again with it. */\nexport type ProtectCheckRunOutcome<TResource> = { status: 'resolved'; resource: TResource } | { status: 'reissued' };\n\nconst isExpired = (protectCheck: ProtectCheckResource) =>\n protectCheck.expiresAt !== undefined && protectCheck.expiresAt < Date.now();\n\nconst expiredError = () =>\n new ClerkRuntimeError('Protect verification expired', { code: ERROR_CODES.PROTECT_CHECK_TIMED_OUT });\n\nconst abortedError = () => new ClerkRuntimeError('Protect check aborted by caller', { code: 'protect_check_aborted' });\n\nconst reloadExpired = async <TResource>(\n resource: ProtectCheckRunnerResource<TResource>,\n expiredReloads: { current: number },\n): Promise<ProtectCheckRunOutcome<TResource>> => {\n if (expiredReloads.current >= MAX_EXPIRED_PROTECT_CHECK_RELOADS) {\n throw expiredError();\n }\n expiredReloads.current += 1;\n\n await resource.reload();\n\n const refreshed = resource.getProtectCheck();\n if (!refreshed) {\n return { status: 'resolved', resource: resource.getResource() };\n }\n if (isExpired(refreshed)) {\n throw expiredError();\n }\n return { status: 'reissued' };\n};\n\n/** Runs one Protect challenge against a sign-in or sign-up resource and submits the proof token. */\nexport async function runProtectCheck<TResource>(\n resource: ProtectCheckRunnerResource<TResource>,\n protectCheck: ProtectCheckResource,\n options: ProtectCheckRunOptions,\n): Promise<ProtectCheckRunOutcome<TResource>> {\n const { container, expiredReloads, signal, setWidgetVisible, loadTimeoutMs } = options;\n if (signal?.aborted) {\n throw abortedError();\n }\n if (isExpired(protectCheck)) {\n return reloadExpired(resource, expiredReloads);\n }\n\n // Deliberately unraced. Only the module load is bounded. The challenge itself may wait on a\n // person, and a timeout here used to abort valid challenges.\n const proofToken = await executeProtectCheck(protectCheck, container, { signal, setWidgetVisible, loadTimeoutMs });\n if (signal?.aborted) {\n throw abortedError();\n }\n\n try {\n const updated = await resource.submitProtectCheck({ proofToken });\n return { status: 'resolved', resource: updated };\n } catch (err) {\n if (signal?.aborted) {\n throw abortedError();\n }\n if (isClerkAPIResponseError(err) && err.errors?.[0]?.code === ERROR_CODES.PROTECT_CHECK_ALREADY_RESOLVED) {\n await resource.reload();\n return { status: 'resolved', resource: resource.getResource() };\n }\n throw err;\n }\n}\n"],"mappings":";;;;;;AAMA,MAAa,oCAAoC;AAoBjD,MAAM,aAAa,iBACjB,aAAa,cAAc,UAAa,aAAa,YAAY,KAAK,IAAI;AAE5E,MAAM,qBACJ,IAAI,kBAAkB,gCAAgC,EAAE,MAAM,YAAY,wBAAwB,CAAC;AAErG,MAAM,qBAAqB,IAAI,kBAAkB,mCAAmC,EAAE,MAAM,wBAAwB,CAAC;AAErH,MAAM,gBAAgB,OACpB,UACA,mBAC+C;CAC/C,IAAI,eAAe,cACjB,MAAM,aAAa;CAErB,eAAe,WAAW;CAE1B,MAAM,SAAS,OAAO;CAEtB,MAAM,YAAY,SAAS,gBAAgB;CAC3C,IAAI,CAAC,WACH,OAAO;EAAE,QAAQ;EAAY,UAAU,SAAS,YAAY;CAAE;CAEhE,IAAI,UAAU,SAAS,GACrB,MAAM,aAAa;CAErB,OAAO,EAAE,QAAQ,WAAW;AAC9B;;AAGA,eAAsB,gBACpB,UACA,cACA,SAC4C;CAC5C,MAAM,EAAE,WAAW,gBAAgB,QAAQ,kBAAkB,kBAAkB;CAC/E,IAAI,QAAQ,SACV,MAAM,aAAa;CAErB,IAAI,UAAU,YAAY,GACxB,OAAO,cAAc,UAAU,cAAc;CAK/C,MAAM,aAAa,MAAM,oBAAoB,cAAc,WAAW;EAAE;EAAQ;EAAkB;CAAc,CAAC;CACjH,IAAI,QAAQ,SACV,MAAM,aAAa;CAGrB,IAAI;EAEF,OAAO;GAAE,QAAQ;GAAY,UAAU,MADjB,SAAS,mBAAmB,EAAE,WAAW,CAAC;EACjB;CACjD,SAAS,KAAK;EACZ,IAAI,QAAQ,SACV,MAAM,aAAa;EAErB,IAAI,wBAAwB,GAAG,KAAK,IAAI,SAAS,EAAE,EAAE,SAAS,YAAY,gCAAgC;GACxG,MAAM,SAAS,OAAO;GACtB,OAAO;IAAE,QAAQ;IAAY,UAAU,SAAS,YAAY;GAAE;EAChE;EACA,MAAM;CACR;AACF"}