@junobuild/core
Version:
JavaScript core client for Juno
4 lines • 465 kB
Source Map (JSON)
{
"version": 3,
"sources": ["../../src/index.ts", "../../../ic-client/src/webauthn/aaguid.ts", "../../../ic-client/src/webauthn/agent-js/cose-utils.ts", "../../../ic-client/src/webauthn/agent-js/cose-key.ts", "../../../ic-client/src/webauthn/credential.ts", "../../../ic-client/src/webauthn/errors.ts", "../../../ic-client/src/webauthn/identity.ts", "../../../ic-client/src/webauthn/_constants.ts", "../../../ic-client/src/webauthn/_options.ts", "../../../ic-client/src/webauthn/_progress.ts", "../../../ic-client/src/webauthn/types/progress.ts", "../../../ic-client/src/webauthn/utils.ts", "../../src/auth/services/auth-timout.services.ts", "../../src/core/stores/_store.ts", "../../src/auth/stores/auth.store.ts", "../../src/auth/utils/events.utils.ts", "../../src/core/stores/actor.store.ts", "../../src/core/stores/agent.store.ts", "../../src/core/stores/_agent.factory.ts", "../../src/core/constants/container.constants.ts", "../../src/auth/stores/auth-client.store.ts", "../../src/auth/services/sign-out.services.ts", "../../src/auth/services/_auth-client.services.ts", "../../src/auth/services/_user.services.ts", "../../../errors/src/utils.ts", "../../../errors/src/constants/cdn.constants.ts", "../../../errors/src/constants/collections.constants.ts", "../../../errors/src/constants/satellite.constants.ts", "../../../errors/src/constants/shared.constants.ts", "../../src/core/constants/call-options.constants.ts", "../../src/core/services/any-identity.services.ts", "../../src/auth/services/identity.services.ts", "../../src/datastore/api/doc.api.ts", "../../src/core/api/actor.api.ts", "../../../ic-client/src/actor/api/actor.api.ts", "../../../ic-client/src/declarations/mission_control/mission_control.factory.did.js", "../../../ic-client/src/declarations/orbiter/orbiter.factory.did.js", "../../../ic-client/src/declarations/orbiter/orbiter.factory.certified.did.js", "../../../ic-client/src/declarations/deprecated/satellite-deprecated-no-scope.factory.did.js", "../../../ic-client/src/declarations/deprecated/satellite-deprecated-version.factory.did.js", "../../../ic-client/src/declarations/deprecated/orbiter-deprecated-version.factory.did.js", "../../../ic-client/src/declarations/deprecated/mission_control-deprecated-version.factory.did.js", "../../../ic-client/src/declarations/deprecated/satellite-deprecated.factory.did.js", "../../../ic-client/src/declarations/satellite/satellite.factory.did.js", "../../../ic-client/src/declarations/satellite/satellite.factory.certified.did.js", "../../../ic-client/src/declarations/console/console.factory.did.js", "../../../ic-client/src/declarations/console/console.factory.certified.did.js", "../../../ic-client/src/declarations/sputnik/sputnik.factory.did.js", "../../../ic-client/src/actor/api/agent.api.ts", "../../../ic-client/src/actor/utils/agent.utils.ts", "../../src/core/utils/env.utils.ts", "../../src/core/stores/env.store.ts", "../../src/core/utils/list.utils.ts", "../../src/auth/types/errors.ts", "../../../utils/src/utils/did.utils.ts", "../../../utils/src/utils/env.utils.ts", "../../src/datastore/utils/data.utils.ts", "../../src/datastore/utils/doc.utils.ts", "../../src/datastore/services/doc.services.ts", "../../src/auth/services/load.services.ts", "../../src/core/utils/window.env.utils.ts", "../../src/auth/providers/internet-identity.providers.ts", "../../src/auth/constants/auth.constants.ts", "../../src/auth/utils/window.utils.ts", "../../src/auth/providers/_auth-client.providers.ts", "../../src/auth/helpers/progress.helpers.ts", "../../src/auth/types/auth-client.ts", "../../src/auth/services/redirect.services.ts", "../../../auth/src/errors.ts", "../../../auth/src/_session.ts", "../../../auth/src/api/_actor.api.ts", "../../../auth/src/api/auth.api.ts", "../../../auth/src/utils/session.utils.ts", "../../../auth/src/_constants.ts", "../../../auth/src/_context.ts", "../../../auth/src/utils/auth.utils.ts", "../../../auth/src/utils/url.utils.ts", "../../../auth/src/utils/session-storage.utils.ts", "../../../auth/src/utils/state.utils.ts", "../../../auth/src/authenticate.ts", "../../../auth/src/_openid.ts", "../../../auth/src/request.ts", "../../src/auth/helpers/window.helpers.ts", "../../src/auth/providers/google.providers.ts", "../../src/auth/providers/webauthn.providers.ts", "../../src/auth/services/user-webauthn.services.ts", "../../src/auth/types/webauthn.ts", "../../src/auth/services/sign-in.services.ts", "../../src/auth/services/sign-up.services.ts", "../../src/auth/utils/user.utils.ts", "../../src/functions/services/functions.services.ts", "../../src/storage/services/storage.services.ts", "../../src/storage/api/storage.api.ts", "../../../storage/src/services/upload.services.ts", "../../src/storage/utils/crypto.utils.ts"],
"sourcesContent": ["import {assertNonNullish} from '@dfinity/utils';\nimport {isWebAuthnAvailable} from '@junobuild/ic-client/webauthn';\nimport type {Asset, AssetEncoding, AssetKey, EncodingType, Storage} from '@junobuild/storage';\nimport {initAuthTimeoutWorker} from './auth/services/auth-timout.services';\nimport {loadAuth} from './auth/services/load.services';\nimport {AuthStore} from './auth/stores/auth.store';\nimport type {User} from './auth/types/user';\nimport {EnvStore} from './core/stores/env.store';\nimport type {Environment, UserEnvironment} from './core/types/env';\nimport type {Unsubscribe} from './core/types/subscription';\nimport {envContainer, envSatelliteId} from './core/utils/window.env.utils';\nexport * from './auth/providers/internet-identity.providers';\nexport {getIdentityOnce, unsafeIdentity} from './auth/services/identity.services';\nexport {handleRedirectCallback} from './auth/services/redirect.services';\nexport {signIn} from './auth/services/sign-in.services';\nexport {signOut} from './auth/services/sign-out.services';\nexport {signUp} from './auth/services/sign-up.services';\nexport type * from './auth/types/auth';\nexport * from './auth/types/auth-client';\nexport * from './auth/types/errors';\nexport type * from './auth/types/progress';\nexport type * from './auth/types/provider';\nexport type * from './auth/types/user';\nexport * from './auth/types/webauthn';\nexport * from './auth/utils/user.utils';\nexport type * from './core/types/env';\nexport {ListOrder, ListPaginate, ListParams, ListResults} from './core/types/list';\nexport type * from './core/types/satellite';\nexport type * from './core/types/subscription';\nexport type * from './core/types/utility';\nexport * from './datastore/services/doc.services';\nexport type * from './datastore/types/doc';\nexport * from './functions/services/functions.services';\nexport * from './storage/services/storage.services';\nexport type * from './storage/types/storage';\nexport {isWebAuthnAvailable};\nexport type {Asset, AssetEncoding, AssetKey, EncodingType, Storage};\n\nconst parseEnv = (userEnv?: UserEnvironment): Environment => {\n const satelliteId = userEnv?.satelliteId ?? envSatelliteId();\n\n assertNonNullish(satelliteId, 'Satellite ID is not configured. Juno cannot be initialized.');\n\n const container = userEnv?.container ?? envContainer();\n\n return {\n satelliteId,\n internetIdentityId: userEnv?.internetIdentityId,\n workers: userEnv?.workers,\n container\n };\n};\n\n/**\n * @deprecated Use {@link initSatellite} instead.\n */\nexport const initJuno = (userEnv?: UserEnvironment): Promise<Unsubscribe[]> =>\n initSatellite(userEnv);\n\n/**\n * Initializes a Satellite with the provided optional environment parameters.\n * If no environment is provided, the variables injected by the Vite or NextJS plugins will be used.\n * @param {UserEnvironment} [userEnv] - The optional user environment configuration.\n * @returns {Promise<Unsubscribe[]>} A promise that resolves to an array of unsubscribe functions.\n */\nexport const initSatellite = async (userEnv?: UserEnvironment): Promise<Unsubscribe[]> => {\n const env = parseEnv(userEnv);\n\n EnvStore.getInstance().set(env);\n\n await loadAuth();\n\n const authSubscribe =\n env.workers?.auth !== undefined ? initAuthTimeoutWorker(env.workers.auth) : undefined;\n\n return [...(authSubscribe ? [authSubscribe] : [])];\n};\n\n/**\n * Subscribes to authentication state changes. i.e. each time a user signs in or signs out, the callback will be triggered.\n * @param {function(User | null): void} callback - The callback function to execute when the authentication state changes.\n * @returns {Unsubscribe} A function to unsubscribe from the authentication state changes.\n */\nexport const onAuthStateChange = (callback: (authUser: User | null) => void): Unsubscribe =>\n AuthStore.getInstance().subscribe(callback);\n\n/**\n * @deprecated Use {@link onAuthStateChange} instead.\n */\nexport const authSubscribe = onAuthStateChange;\nexport {InternetIdentityConfig, InternetIdentityDomain} from './auth/types/internet-identity';\n", "import {uint8ArrayToArrayOfNumber} from '@dfinity/utils';\n\n/**\n * Extracts the AAGUID (Authenticator Attestation GUID) from a WebAuthn data buffer.\n *\n * The AAGUID is a 16-byte value located at offsets 37..53 within `authenticatorData`\n * when **attested credential data** is present (i.e., during registration/attestation).\n *\n * For assertion (sign-in) responses, `authenticatorData` is typically 37 bytes and\n * does not include an AAGUID.\n *\n * If the extracted value is all zeros (`00000000-0000-0000-0000-000000000000`),\n * this function returns `{ unknownProvider: null }` since some passkey providers\n * intentionally use a zero AAGUID.\n *\n * @param {Object} params\n * @param {Uint8Array} params.authData - The WebAuthn `authenticatorData` bytes.\n * @returns {{aaguid: string; bytes: Uint8Array} | {invalidAuthData: null} | {unknownProvider: null}}\n * - { aaguidText, aaguidBytes } for valid AAGUID\n * - { unknownProvider: null } for all-zero AAGUID\n * - { invalidAuthData: null } if `authData` is invalid (too short, too long, etc.)\n *\n * @see https://web.dev/articles/webauthn-aaguid\n */\nexport const extractAAGUID = ({\n authData\n}: {\n authData: Uint8Array;\n}):\n | {aaguidText: string; aaguidBytes: Uint8Array}\n | {invalidAuthData: null}\n | {unknownProvider: null} => {\n if (authData.byteLength < 37) {\n return {invalidAuthData: null};\n }\n\n if (authData.byteLength < 53) {\n return {invalidAuthData: null};\n }\n\n const bytes = authData.slice(37, 53);\n\n const result = bytesToAAGUID({bytes});\n\n if ('aaguid' in result) {\n return {aaguidBytes: bytes, aaguidText: result.aaguid};\n }\n\n return {unknownProvider: null};\n};\n\n/**\n * Convert 16 AAGUID bytes to canonical UUID string (lowercase, hyphenated).\n *\n * Returns:\n * - { aaguid } for non-zero AAGUIDs\n * - { unknownProvider: null } for all-zero AAGUID\n * - { invalidBytes: null } if length \u2260 16\n *\n * @param {{bytes: Uint8Array | number[]}} params\n * @returns {{aaguid: string} | {invalidBytes: null} | {unknownProvider: null}}\n */\nexport const bytesToAAGUID = ({\n bytes\n}: {\n bytes: Uint8Array | number[];\n}): {aaguid: string} | {invalidBytes: null} | {unknownProvider: null} => {\n if (bytes.length !== 16) {\n return {invalidBytes: null};\n }\n\n const hex = (bytes instanceof Uint8Array ? uint8ArrayToArrayOfNumber(bytes) : bytes)\n .map((byte) => byte.toString(16).padStart(2, '0'))\n .join('');\n\n const aaguid = hex.replace(/^(.{8})(.{4})(.{4})(.{4})(.{12})$/, '$1-$2-$3-$4-$5');\n\n // \"00000000-0000-0000-0000-0000000000000\" represents an unknown passkey provider. Some passkey providers use this AAGUID intentionally.\n // Source: https://web.dev/articles/webauthn-aaguid\n if (aaguid === '00000000-0000-0000-0000-000000000000') {\n return {unknownProvider: null};\n }\n\n return {aaguid};\n};\n", "import {DER_COSE_OID, wrapDER, type DerEncodedPublicKey} from '@icp-sdk/core/agent';\n\n/**\n * \u26A0\uFE0F !!!WARNING!!! \u26A0\uFE0F\n * This module is a copy/paste of the webauthn functions not exposed by Agent-js.\n * It is therefore not covered by any tests (\u203C\uFE0F) in this library.\n *\n * @see https://github.com/dfinity/agent-js/blob/main/packages/identity/src/identity/webauthn.ts\n */\n\n/**\n * From the documentation;\n * The authData is a byte array described in the spec. Parsing it will involve slicing bytes from\n * the array and converting them into usable objects.\n *\n * See https://webauthn.guide/#registration (subsection \"Example: Parsing the authenticator data\").\n * @param authData The authData field of the attestation response.\n * @returns The COSE key of the authData.\n */\nexport function _authDataToCose(authData: Uint8Array): Uint8Array {\n const dataView = new DataView(new ArrayBuffer(2));\n const idLenBytes = authData.slice(53, 55);\n [...new Uint8Array(idLenBytes)].forEach((v, i) => dataView.setUint8(i, v));\n const credentialIdLength = dataView.getUint16(0);\n\n // Get the public key object.\n return authData.slice(55 + credentialIdLength);\n}\n\nexport function _coseToDerEncodedBlob(cose: Uint8Array): DerEncodedPublicKey {\n return wrapDER(cose, DER_COSE_OID) as DerEncodedPublicKey;\n}\n", "import type {DerEncodedPublicKey} from '@icp-sdk/core/agent';\nimport type {PublicKeyWithToRaw} from '../types/identity';\nimport {_coseToDerEncodedBlob} from './cose-utils';\n\n/**\n * \u26A0\uFE0F !!!WARNING!!! \u26A0\uFE0F\n * This module is a copy/paste of the webauthn classes not exposed by Agent-js\n * extended with mandatory toRaw() and encodedKey made private.\n * It is therefore not covered by that many tests (\u203C\uFE0F) in this library.\n *\n * @see https://github.com/dfinity/agent-js/blob/main/packages/identity/src/identity/webauthn.ts\n */\n\n/**\n * COSE-encoded key (CBOR Object Signing and Encryption).\n * serialized as a Uint8Array.\n */\nexport type CoseEncodedKey = Uint8Array;\n\nexport class CosePublicKey implements PublicKeyWithToRaw {\n readonly #encodedKey: DerEncodedPublicKey;\n\n public constructor(protected _cose: CoseEncodedKey) {\n this.#encodedKey = _coseToDerEncodedBlob(_cose);\n }\n\n public toDer(): DerEncodedPublicKey {\n return this.#encodedKey;\n }\n\n public toRaw(): Uint8Array {\n return new Uint8Array(this.#encodedKey); // Strip __derEncodedPublicKey__\n }\n}\n", "import {uint8ArrayToBase64} from '@dfinity/utils';\nimport {extractAAGUID} from './aaguid';\nimport {type CoseEncodedKey, CosePublicKey} from './agent-js/cose-key';\nimport type {PublicKeyWithToRaw} from './types/identity';\n\n/**\n * Arguments to initialize a WebAuthn object.\n */\nexport interface InitWebAuthnCredentialArgs {\n /**\n * The credential ID (authenticator\u2019s `rawId`) as bytes.\n */\n rawId: Uint8Array;\n\n /**\n * COSE-encoded public key extracted from attestation/authData.\n */\n cose: CoseEncodedKey;\n}\n\nexport interface InitWebAuthnNewCredentialArgs extends InitWebAuthnCredentialArgs {\n /**\n * The authenticator data from the attestation.\n */\n authData: Uint8Array;\n}\n\n/**\n * A wrapper around a WebAuthn credential that provides various base information such as its ID or public key.\n */\nexport abstract class WebAuthnCredential {\n readonly #credentialId: Uint8Array;\n readonly #publicKey: CosePublicKey;\n\n /**\n * @param args - {@link InitWebAuthnCredentialArgs} used to initialize the credential.\n * @param args.rawId - Credential ID (`rawId`) as bytes.\n * @param args.cose - COSE-encoded public key.\n */\n constructor({rawId: credentialId, cose}: InitWebAuthnCredentialArgs) {\n this.#credentialId = credentialId;\n this.#publicKey = new CosePublicKey(cose);\n }\n\n /**\n * Returns the public key for this credential.\n */\n getPublicKey(): PublicKeyWithToRaw {\n return this.#publicKey;\n }\n\n /**\n * Returns the credential ID as bytes.\n */\n getCredentialId(): Uint8Array {\n return this.#credentialId;\n }\n\n /**\n * Returns the credential ID as textual representation (a base64 string).\n */\n getCredentialIdText(): string {\n return uint8ArrayToBase64(this.#credentialId);\n }\n}\n\n/**\n * A wrapper around a newly created WebAuthn credential.\n * It is created using `navigator.credentials.create` which provides an attestation.\n */\nexport class WebAuthnNewCredential extends WebAuthnCredential {\n readonly #aaguidText: string | undefined;\n readonly #aaguidBytes: Uint8Array | undefined;\n\n /**\n * @param args - {@link InitWebAuthnNewCredentialArgs} used to initialize the credential.\n * @param args.rawId - Credential ID (`rawId`) as bytes.\n * @param args.cose - COSE-encoded public key.\n * @params args.authData - Authenticator data from the attestation.\n */\n constructor({authData, ...rest}: InitWebAuthnNewCredentialArgs) {\n super(rest);\n\n const optionAaguid = extractAAGUID({authData});\n this.#aaguidText = 'aaguidText' in optionAaguid ? optionAaguid.aaguidText : undefined;\n this.#aaguidBytes = 'aaguidBytes' in optionAaguid ? optionAaguid.aaguidBytes : undefined;\n }\n\n /**\n * Returns AAGUID (Authenticator Attestation GUID).\n */\n getAAGUID(): Uint8Array | undefined {\n return this.#aaguidBytes;\n }\n\n /**\n * Returns the textual representation of the AAGUID (Authenticator Attestation GUID).\n */\n getAAGUIDText(): string | undefined {\n return this.#aaguidText;\n }\n}\n\n/**\n * A wrapper around a retrieval of existing WebAuthn credential.\n * It is created using `navigator.credentials.get` which provides an assertion.\n */\nexport class WebAuthnExistingCredential extends WebAuthnCredential {}\n", "export class WebAuthnIdentityHostnameError extends Error {}\nexport class WebAuthnIdentityCredentialNotInitializedError extends Error {}\nexport class WebAuthnIdentityCreateCredentialOnTheDeviceError extends Error {}\nexport class WebAuthnIdentityCredentialNotPublicKeyError extends Error {}\nexport class WebAuthnIdentityNoAttestationError extends Error {}\nexport class WebAuthnIdentityInvalidCredentialIdError extends Error {}\nexport class WebAuthnIdentityEncodeCborSignatureError extends Error {}\n// https://developer.mozilla.org/en-US/docs/Web/API/AuthenticatorAssertionResponse/authenticatorData\nexport class WebAuthnIdentityNoAuthenticatorDataError extends Error {}\n// https://developer.mozilla.org/en-US/docs/Web/API/AuthenticatorAssertionResponse/signature\nexport class WebAuthnIdentityNoSignatureError extends Error {}\n", "import {arrayBufferToUint8Array, isNullish, uint8ArraysEqual} from '@dfinity/utils';\nimport {Cbor, type Signature, SignIdentity} from '@icp-sdk/core/agent';\nimport {AUTHENTICATOR_ABORT_TIMEOUT} from './_constants';\nimport {createPasskeyOptions, retrievePasskeyOptions} from './_options';\nimport {execute} from './_progress';\nimport {_authDataToCose} from './agent-js/cose-utils';\nimport {\n type InitWebAuthnNewCredentialArgs,\n type WebAuthnCredential,\n WebAuthnExistingCredential,\n WebAuthnNewCredential\n} from './credential';\nimport {\n WebAuthnIdentityCreateCredentialOnTheDeviceError,\n WebAuthnIdentityCredentialNotInitializedError,\n WebAuthnIdentityCredentialNotPublicKeyError,\n WebAuthnIdentityEncodeCborSignatureError,\n WebAuthnIdentityInvalidCredentialIdError,\n WebAuthnIdentityNoAttestationError,\n WebAuthnIdentityNoAuthenticatorDataError\n} from './errors';\nimport type {\n AuthenticatorOptions,\n CreateWebAuthnIdentityWithExistingCredentialArgs,\n CreateWebAuthnIdentityWithNewCredentialArgs,\n PublicKeyWithToRaw,\n RetrievePublicKeyFn\n} from './types/identity';\nimport type {PasskeyOptions} from './types/passkey';\nimport {\n type WebAuthnSignProgressArgs,\n type WebAuthnSignProgressFn,\n WebAuthnSignProgressStep\n} from './types/progress';\n\ntype PublicKeyCredentialWithAttachment = Omit<PublicKeyCredential, 'response'> & {\n response: AuthenticatorAssertionResponse & {\n attestationObject?: ArrayBuffer;\n };\n};\n\nconst createAbortSignal = ({\n timeout\n}: Pick<AuthenticatorOptions<PasskeyOptions>, 'timeout'>): AbortSignal =>\n AbortSignal.timeout(timeout ?? AUTHENTICATOR_ABORT_TIMEOUT);\n\nconst retrieveCredentials = async ({\n challenge,\n credentialIds,\n passkeyOptions,\n timeout\n}: {\n challenge: Uint8Array;\n credentialIds?: Uint8Array[];\n} & AuthenticatorOptions<PasskeyOptions>): Promise<Credential | null> =>\n await navigator.credentials.get({\n publicKey: {\n ...retrievePasskeyOptions(passkeyOptions),\n challenge: challenge.buffer as BufferSource,\n allowCredentials: (credentialIds ?? []).map((id) => ({\n id: id.buffer as BufferSource,\n type: 'public-key'\n }))\n },\n signal: createAbortSignal({timeout})\n });\n\ntype WebAuthnState<T extends WebAuthnCredential> =\n | {status: 'pending'; retrievePublicKey: RetrievePublicKeyFn}\n | {status: 'initialized'; credential: T};\n\nconst assertWebAuthnStateInitialized: <T extends WebAuthnCredential>(\n state: WebAuthnState<T>\n) => asserts state is {\n status: 'initialized';\n credential: T;\n} = <T extends WebAuthnCredential>(state: WebAuthnState<T>): void => {\n if (state.status !== 'initialized') {\n throw new WebAuthnIdentityCredentialNotInitializedError();\n }\n};\n\nconst assertNonNullishCredential: (\n credential: Credential | null\n) => asserts credential is Credential = (credential: Credential | null): void => {\n if (isNullish(credential)) {\n throw new WebAuthnIdentityCreateCredentialOnTheDeviceError();\n }\n};\n\nconst assertCredentialPublicKey: (\n credential: Credential\n) => asserts credential is PublicKeyCredentialWithAttachment = ({type}: Credential): void => {\n if (type !== 'public-key') {\n throw new WebAuthnIdentityCredentialNotPublicKeyError();\n }\n};\n\n/**\n * A signing identity for the Internet Computer, backed by a WebAuthn credential.\n *\n * Use one of the factory methods to construct an instance:\n * - {@link WebAuthnIdentity.createWithNewCredential} to create a new passkey on the device.\n * - {@link WebAuthnIdentity.createWithExistingCredential} to use an existing passkey.\n *\n * @template T Concrete credential type for this identity\n * ({@link WebAuthnNewCredential} or {@link WebAuthnExistingCredential}).\n */\nexport class WebAuthnIdentity<T extends WebAuthnCredential> extends SignIdentity {\n readonly #onSignProgress: WebAuthnSignProgressFn | undefined;\n #state: WebAuthnState<T>;\n\n /**\n * @hidden Use the factory methods instead.\n *\n * Initializes the identity in either:\n * - **pending** state (existing-credential path; public key not yet known), or\n * - **initialized** state (new-credential path; public key known immediately).\n *\n * @private\n */\n private constructor({\n onProgress,\n ...args\n }: WebAuthnSignProgressArgs &\n (\n | InitWebAuthnNewCredentialArgs\n | Pick<CreateWebAuthnIdentityWithExistingCredentialArgs, 'retrievePublicKey'>\n )) {\n super();\n\n this.#onSignProgress = onProgress;\n\n if ('retrievePublicKey' in args) {\n const {retrievePublicKey} = args;\n\n this.#state = {\n status: 'pending',\n retrievePublicKey\n };\n\n return;\n }\n\n this.#state = WebAuthnIdentity.#createInitializedState({\n credential: new WebAuthnNewCredential(args)\n });\n }\n\n static #createInitializedState<T extends WebAuthnCredential>({\n credential\n }: {\n credential: WebAuthnNewCredential | WebAuthnExistingCredential;\n }): WebAuthnState<T> {\n return {\n status: 'initialized',\n credential: credential as T\n };\n }\n\n /**\n * Creates a new passkey on the device and returns an initialized identity.\n *\n * If you chain `create` and `sign`, the user will be prompted twice to authenticate\n * with their authenticator. You can track progress via the `onProgress` callback.\n *\n * @param args {@link CreateWebAuthnIdentityWithNewCredentialArgs} Options to create the passkey.\n * @returns A {@link WebAuthnIdentity} parameterized with {@link WebAuthnNewCredential}.\n */\n static async createWithNewCredential({\n passkeyOptions,\n timeout,\n ...restArgs\n }: CreateWebAuthnIdentityWithNewCredentialArgs = {}): Promise<\n WebAuthnIdentity<WebAuthnNewCredential>\n > {\n const credential = await navigator.credentials.create({\n publicKey: createPasskeyOptions(passkeyOptions),\n signal: createAbortSignal({timeout})\n });\n\n assertNonNullishCredential(credential);\n assertCredentialPublicKey(credential);\n\n const {\n response: {attestationObject},\n rawId\n } = credential;\n\n if (isNullish(attestationObject)) {\n throw new WebAuthnIdentityNoAttestationError();\n }\n\n // We have to parse the attestationObject as CBOR to ultimately retrieve the public key.\n // Similar as what's implemented in AgentJS.\n const {authData} = Cbor.decode<{authData: Uint8Array}>(\n arrayBufferToUint8Array(attestationObject)\n );\n\n const cose = _authDataToCose(authData);\n\n return new WebAuthnIdentity<WebAuthnNewCredential>({\n ...restArgs,\n rawId: arrayBufferToUint8Array(rawId),\n cose,\n authData\n });\n }\n\n /**\n * Creates an identity for an existing passkey.\n *\n * @param args {@link CreateWebAuthnIdentityWithExistingCredentialArgs} Options to retrieve the passkey.\n * @returns A {@link WebAuthnIdentity} parameterized with {@link WebAuthnExistingCredential}.\n */\n // We use async for consistency reason and because it might be future prone.\n // eslint-disable-next-line require-await\n static async createWithExistingCredential(\n args: CreateWebAuthnIdentityWithExistingCredentialArgs\n ): Promise<WebAuthnIdentity<WebAuthnExistingCredential>> {\n return new WebAuthnIdentity<WebAuthnExistingCredential>(args);\n }\n\n /**\n * Returns the credential\u2019s public key.\n *\n * @returns {PublicKey}\n * @throws WebAuthnIdentityCredentialNotInitializedError if the identity has not signed\n * any request yet.\n */\n override getPublicKey(): PublicKeyWithToRaw {\n assertWebAuthnStateInitialized(this.#state);\n\n const {credential} = this.#state;\n\n return credential.getPublicKey();\n }\n\n /**\n * Returns the concrete credential wrapper for this identity.\n *\n * For identities created with:\n * - `createWithNewCredential` \u2192 {@link WebAuthnNewCredential}\n * - `createWithExistingCredential` \u2192 {@link WebAuthnExistingCredential}\n *\n * @throws WebAuthnIdentityCredentialNotInitializedError if the identity has not signed\n * any request yet.\n */\n getCredential(): T {\n assertWebAuthnStateInitialized(this.#state);\n\n const {credential} = this.#state;\n\n return credential;\n }\n\n /**\n * Signs an arbitrary blob using the platform authenticator.\n *\n * @param blob Bytes to sign (used as the WebAuthn challenge).\n * @returns {Promise<Signature>} CBOR-encoded signature payload.\n */\n override async sign(blob: Uint8Array): Promise<Signature> {\n // 1. Request user credential (navigator.credentials.get)\n const requestCredential = async (): Promise<PublicKeyCredential> => {\n const credential = await retrieveCredentials({\n challenge: blob,\n ...(this.#state.status === 'initialized' && {\n credentialIds: [this.#state.credential.getCredentialId()]\n })\n });\n\n assertNonNullishCredential(credential);\n assertCredentialPublicKey(credential);\n\n return credential;\n };\n\n const credential = await execute({\n fn: requestCredential,\n step: WebAuthnSignProgressStep.RequestingUserCredential,\n onProgress: this.#onSignProgress\n });\n\n // 2. Assert credential ID if already initialized or load public key from backend and init state\n const finalizingCredential = async () => {\n const {rawId} = credential;\n\n // If the state was already initialized - credentials.create - then we \"only\"\n // assert that the rawId retrieved by credentials.get is equals to the one already known.\n if (this.#state.status === 'initialized') {\n if (\n !uint8ArraysEqual({\n a: this.#state.credential.getCredentialId(),\n b: arrayBufferToUint8Array(rawId)\n })\n ) {\n throw new WebAuthnIdentityInvalidCredentialIdError();\n }\n\n return;\n }\n\n // If the state was pending, we need to retrieve the public key for the credential\n // that was saved during a previous sign-up\n // because credentials.get does not provide an attestation.\n const {retrievePublicKey} = this.#state;\n\n const cose = await retrievePublicKey({\n credentialId: arrayBufferToUint8Array(rawId)\n });\n\n this.#state = WebAuthnIdentity.#createInitializedState({\n credential: new WebAuthnExistingCredential({\n rawId: arrayBufferToUint8Array(rawId),\n cose\n })\n });\n };\n\n await execute({\n fn: finalizingCredential,\n step: WebAuthnSignProgressStep.FinalizingCredential,\n onProgress: this.#onSignProgress\n });\n\n // 3. Sign the request\n // eslint-disable-next-line require-await\n const encodeSignature = async (): Promise<Signature> => {\n const {response} = credential;\n\n const {clientDataJSON} = response;\n\n // Only the response of type AuthenticatorAssertionResponse provides authenticatorData and signature\n // which is the type of response we are expecting.\n const {authenticatorData, signature} =\n 'authenticatorData' in response && 'signature' in response\n ? (response as AuthenticatorAssertionResponse)\n : {};\n\n if (isNullish(authenticatorData)) {\n throw new WebAuthnIdentityNoAuthenticatorDataError();\n }\n\n if (isNullish(signature)) {\n throw new WebAuthnIdentityNoAuthenticatorDataError();\n }\n\n const encoded = Cbor.encode({\n authenticator_data: authenticatorData,\n client_data_json: new TextDecoder().decode(clientDataJSON),\n signature: arrayBufferToUint8Array(signature)\n });\n\n if (isNullish(encoded)) {\n throw new WebAuthnIdentityEncodeCborSignatureError();\n }\n\n // Similar as AgentJS code.\n Object.assign(encoded, {\n __signature__: undefined\n });\n\n return encoded as Signature;\n };\n\n return await execute({\n fn: encodeSignature,\n step: WebAuthnSignProgressStep.Signing,\n onProgress: this.#onSignProgress\n });\n }\n}\n", "// See https://www.iana.org/assignments/cose/cose.xhtml#algorithms for a complete\n// list of these algorithms. We only list the ones we support here.\n//\n// According Google tutorial, https://web.dev/articles/passkey-registration, specifying\n// support for ECDSA with P-256 (-7) and RSA PKCS#1 (-257) gives complete coverage.\nexport const PUBLIC_KEY_COSE_ALGORITHMS = {\n ECDSA_WITH_SHA256: -7,\n RSA_WITH_SHA256: -257\n};\n\nexport const AUTHENTICATOR_ABORT_TIMEOUT = 60000;\n", "import {PUBLIC_KEY_COSE_ALGORITHMS} from './_constants';\nimport {WebAuthnIdentityHostnameError} from './errors';\nimport type {CreatePasskeyOptions, PasskeyOptions} from './types/passkey';\n\nconst randomValue = (): BufferSource => window.crypto.getRandomValues(new Uint8Array(16));\n\n/**\n * When creating a passkey, the challenge can simply be a random value.\n * Since the server doesn\u2019t need to verify the authenticity of the key,\n * it doesn\u2019t have to generate the challenge itself.\n *\n * In contrast, when signing a request with our credentials,\n * the request itself becomes the data (blob), the challenge, that must be signed.\n */\nconst createChallenge = (): BufferSource => randomValue();\n\n/**\n * The user ID is set to a random value, which holds little relevance\n * for the end user beyond being unique.\n *\n * Ultimately, once signed in, the user's actual identifier will be\n * the public key (principal) of the identity used to interact with the IC.\n */\nconst createUserId = (): BufferSource => randomValue();\n\nconst hostname = (): string => {\n const {\n location: {href}\n } = window;\n\n try {\n const {hostname} = new URL(href);\n return hostname;\n } catch {\n throw new WebAuthnIdentityHostnameError();\n }\n};\n\nconst relyingPartyId = ({appId}: Pick<PasskeyOptions, 'appId'>): string => appId?.id ?? hostname();\n\nexport const createPasskeyOptions = ({\n appId,\n user: userOptions\n}: CreatePasskeyOptions = {}): PublicKeyCredentialCreationOptions => {\n const {\n document: {title: name}\n } = window;\n\n const relyingParty = (): Pick<PublicKeyCredentialCreationOptions, 'rp'> => ({\n rp: {\n // Note: deprecated in WebAuthn L3\n name: appId?.name ?? name,\n id: relyingPartyId({appId})\n }\n });\n\n const user = (): Pick<PublicKeyCredentialCreationOptions, 'user'> => ({\n user: {\n id: createUserId(),\n name: userOptions?.name ?? userOptions?.displayName ?? name,\n displayName: userOptions?.displayName ?? name\n }\n });\n\n return {\n // We want to receive the attestation statement as generated by the authenticator\n attestation: 'direct',\n challenge: createChallenge(),\n ...relyingParty(),\n ...user(),\n pubKeyCredParams: Object.values(PUBLIC_KEY_COSE_ALGORITHMS).map((algorithm) => ({\n type: 'public-key',\n alg: algorithm\n })),\n excludeCredentials: [],\n authenticatorSelection: {\n // At least for now, we want a simplified flow and therefore indicates that we want a\n // platform authenticator ((an authenticator embedded to the platform device).\n authenticatorAttachment: 'platform',\n userVerification: 'preferred',\n // Along with requireResidentKey, make passkey discoverable,\n residentKey: 'required',\n requireResidentKey: true\n }\n };\n};\n\nexport const retrievePasskeyOptions = (\n options: PasskeyOptions = {}\n): Omit<PublicKeyCredentialRequestOptions, 'challenge'> => ({\n rpId: relyingPartyId(options),\n allowCredentials: [],\n userVerification: 'required'\n});\n", "import type {WebAuthnSignProgress, WebAuthnSignProgressArgs} from './types/progress';\n\nexport const execute = async <T>({\n fn,\n step,\n onProgress\n}: {\n fn: () => Promise<T>;\n} & Pick<WebAuthnSignProgress, 'step'> &\n WebAuthnSignProgressArgs): Promise<T> => {\n onProgress?.({\n step,\n state: 'in_progress'\n });\n\n try {\n const result = await fn();\n\n onProgress?.({\n step,\n state: 'success'\n });\n\n return result;\n } catch (err: unknown) {\n onProgress?.({\n step,\n state: 'error'\n });\n\n throw err;\n }\n};\n", "/**\n * Progress steps in the WebAuthn signing flow.\n */\nexport enum WebAuthnSignProgressStep {\n /** Calling `navigator.credentials.get` to obtain an assertion. */\n RequestingUserCredential,\n /** Verifying/initializing the credential (e.g., ID match, loading public key). */\n FinalizingCredential,\n /** Producing the signature and encoding the result. */\n Signing\n}\n\n/**\n * Status of the current step.\n */\nexport type WebAuthnSignProgressState = 'in_progress' | 'success' | 'error';\n\n/**\n * Payload emitted on progress updates.\n */\nexport interface WebAuthnSignProgress {\n /** The step being executed. */\n step: WebAuthnSignProgressStep;\n /** State of that step. */\n state: WebAuthnSignProgressState;\n}\n\n/**\n * Callback invoked on each progress update.\n */\nexport type WebAuthnSignProgressFn = (progress: WebAuthnSignProgress) => void;\n\n/**\n * Optional handler for progress updates.\n */\nexport interface WebAuthnSignProgressArgs {\n onProgress?: WebAuthnSignProgressFn;\n}\n", "import {nonNullish} from '@dfinity/utils';\n\n/**\n * Checks if a user-verifying platform authenticator (passkeys) is available on this device / browser.\n *\n * Returns `true` when:\n * 1) `window.PublicKeyCredential` exists, and\n * 2) the browser reports a user-verifying **platform** authenticator is available\n * (e.g., Touch ID, Windows Hello, Android biometrics/PIN).\n *\n * @returns {Promise<boolean>} `true` if an authenticator is available, otherwise `false`.\n */\nexport const isWebAuthnAvailable = async (): Promise<boolean> => {\n if (\n nonNullish(window.PublicKeyCredential) &&\n 'isUserVerifyingPlatformAuthenticatorAvailable' in PublicKeyCredential\n ) {\n return await PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable();\n }\n\n return false;\n};\n", "import {isNullish} from '@dfinity/utils';\nimport type {EnvironmentWorker} from '../../core/types/env';\nimport type {Unsubscribe} from '../../core/types/subscription';\nimport {AuthStore} from '../stores/auth.store';\nimport type {PostMessage, PostMessageDataResponseAuth} from '../types/post-message';\nimport type {User} from '../types/user';\nimport {emit} from '../utils/events.utils';\nimport {signOut} from './sign-out.services';\n\nexport const initAuthTimeoutWorker = (auth: EnvironmentWorker): Unsubscribe => {\n const workerUrl = auth === true ? './workers/auth.worker.js' : auth;\n const worker = new Worker(workerUrl);\n\n const timeoutSignOut = async () => {\n emit({message: 'junoSignOutAuthTimer'});\n await signOut();\n };\n\n worker.onmessage = async ({data}: MessageEvent<PostMessage<PostMessageDataResponseAuth>>) => {\n const {msg, data: value} = data;\n\n switch (msg) {\n case 'junoSignOutAuthTimer':\n await timeoutSignOut();\n return;\n case 'junoDelegationRemainingTime':\n emit({message: 'junoDelegationRemainingTime', detail: value?.authRemainingTime});\n return;\n }\n };\n\n return AuthStore.getInstance().subscribe((user: User | null) => {\n if (isNullish(user)) {\n worker.postMessage({msg: 'junoStopAuthTimer'});\n return;\n }\n\n worker.postMessage({msg: 'junoStartAuthTimer'});\n });\n};\n", "export abstract class Store<T> {\n private callbacks: {id: symbol; callback: (data: T | null) => void}[] = [];\n\n protected populate(data: T | null) {\n this.callbacks.forEach(({callback}: {id: symbol; callback: (data: T | null) => void}) =>\n callback(data)\n );\n }\n\n subscribe(callback: (data: T | null) => void): () => void {\n const callbackId = Symbol();\n this.callbacks.push({id: callbackId, callback});\n\n return () =>\n (this.callbacks = this.callbacks.filter(\n ({id}: {id: symbol; callback: (data: T | null) => void}) => id !== callbackId\n ));\n }\n}\n", "import {Store} from '../../core/stores/_store';\nimport type {Unsubscribe} from '../../core/types/subscription';\n\nimport type {User} from '../types/user';\n\nexport class AuthStore extends Store<User | null> {\n private static instance: AuthStore;\n\n private authUser: User | null = null;\n\n private constructor() {\n super();\n }\n\n static getInstance() {\n if (!AuthStore.instance) {\n AuthStore.instance = new AuthStore();\n }\n return AuthStore.instance;\n }\n\n set(authUser: User | null) {\n this.authUser = authUser;\n\n this.populate(authUser);\n }\n\n get(): User | null {\n return this.authUser;\n }\n\n override subscribe(callback: (data: User | null) => void): Unsubscribe {\n const unsubscribe: () => void = super.subscribe(callback);\n\n callback(this.authUser);\n\n return unsubscribe;\n }\n\n reset() {\n this.authUser = null;\n\n this.populate(this.authUser);\n }\n}\n", "export const emit = <T>({message, detail}: {message: string; detail?: T | undefined}) => {\n const $event: CustomEvent<T> = new CustomEvent<T>(message, {detail, bubbles: true});\n document.dispatchEvent($event);\n};\n", "import {isNullish} from '@dfinity/utils';\nimport {Actor, type ActorMethod, type ActorSubclass} from '@icp-sdk/core/agent';\nimport type {IDL} from '@icp-sdk/core/candid';\nimport type {ActorKey} from '../types/actor';\nimport type {SatelliteContext} from '../types/satellite';\nimport {AgentStore} from './agent.store';\n\ntype ActorParams = {\n idlFactory: IDL.InterfaceFactory;\n} & Required<Pick<SatelliteContext, 'satelliteId' | 'identity'>> &\n Pick<SatelliteContext, 'container'>;\n\ntype ActorRecord = Record<string, ActorMethod>;\n\nexport class ActorStore {\n private static instance: ActorStore;\n\n #actors: Record<string, ActorSubclass<ActorRecord>> | undefined | null = undefined;\n\n private constructor() {}\n\n static getInstance() {\n if (isNullish(ActorStore.instance)) {\n ActorStore.instance = new ActorStore();\n }\n return ActorStore.instance;\n }\n\n async getActor<T = ActorRecord>({\n satelliteId,\n identity,\n actorKey,\n ...rest\n }: ActorParams & {actorKey: ActorKey}): Promise<ActorSubclass<T>> {\n const key = `${actorKey}#${identity.getPrincipal().toText()}#${satelliteId};`;\n\n if (isNullish(this.#actors) || isNullish(this.#actors[key])) {\n const actor = await this.createActor({satelliteId, identity, ...rest});\n\n this.#actors = {\n ...(this.#actors ?? {}),\n [key]: actor\n };\n\n return actor as ActorSubclass<T>;\n }\n\n return this.#actors[key] as ActorSubclass<T>;\n }\n\n reset() {\n this.#actors = null;\n }\n\n private async createActor<T = ActorRecord>({\n idlFactory,\n satelliteId: canisterId,\n ...rest\n }: ActorParams): Promise<ActorSubclass<T>> {\n const agent = await AgentStore.getInstance().getAgent(rest);\n\n return Actor.createActor(idlFactory, {\n agent,\n canisterId\n });\n }\n}\n", "import {isNullish} from '@dfinity/utils';\nimport type {Agent, HttpAgent} from '@icp-sdk/core/agent';\nimport {type CreateAgentParams, createAgent} from './_agent.factory';\n\nexport class AgentStore {\n private static instance: AgentStore;\n\n #agents: Record<string, HttpAgent> | undefined | null = undefined;\n\n private constructor() {}\n\n static getInstance() {\n if (isNullish(AgentStore.instance)) {\n AgentStore.instance = new AgentStore();\n }\n return AgentStore.instance;\n }\n\n async getAgent({identity, ...rest}: CreateAgentParams): Promise<Agent> {\n const key = identity.getPrincipal().toText();\n\n if (isNullish(this.#agents) || isNullish(this.#agents[key])) {\n const agent = await createAgent({identity, ...rest});\n\n this.#agents = {\n ...(this.#agents ?? {}),\n [key]: agent\n };\n\n return agent;\n }\n\n return this.#agents[key];\n }\n\n reset() {\n this.#agents = null;\n }\n}\n", "import {nonNullish} from '@dfinity/utils';\nimport {HttpAgent} from '@icp-sdk/core/agent';\nimport {DOCKER_CONTAINER_URL} from '../constants/container.constants';\nimport type {SatelliteContext} from '../types/satellite';\n\nexport type CreateAgentParams = Required<Pick<SatelliteContext, 'identity'>> &\n Pick<SatelliteContext, 'container'>;\n\nexport const createAgent = async ({identity, container}: CreateAgentParams): Promise<HttpAgent> => {\n const localActor = nonNullish(container) && container !== false;\n\n const host = localActor\n ? container === true\n ? DOCKER_CONTAINER_URL\n : container\n : 'https://icp-api.io';\n\n const shouldFetchRootKey = nonNullish(container);\n\n return await HttpAgent.create({\n identity,\n shouldFetchRootKey,\n host\n });\n};\n", "export const DOCKER_CONTAINER_URL = 'http://127.0.0.1:5987';\nexport const DOCKER_INTERNET_IDENTITY_ID = 'rdmx6-jaaaa-aaaaa-aaadq-cai';\n", "import {isNullish} from '@dfinity/utils';\nimport {\n AuthClient,\n IdbStorage,\n KEY_STORAGE_DELEGATION,\n KEY_STORAGE_KEY\n} from '@icp-sdk/auth/client';\nimport type {DelegationChain, ECDSAKeyIdentity} from '@icp-sdk/core/identity';\n\nexport class AuthClientStore {\n static #instance: AuthClientStore | undefined;\n\n #authClient: AuthClient | undefined | null;\n\n private constructor() {}\n\n static getInstance(): AuthClientStore {\n if (isNullish(this.#instance)) {\n this.#instance = new AuthClientStore();\n }\n\n return this.#instance;\n }\n\n createAuthClient = async (): Promise<AuthClient> => {\n this.#authClient = await AuthClient.create({\n idleOptions: {\n disableIdle: true,\n disableDefaultIdleCallback: true\n }\n });\n\n return this.#authClient;\n };\n\n safeCreateAuthClient = async (): Promise<AuthClient> => {\n // Since AgentJS persists the identity key in IndexedDB by default,\n // it can be tampered with and affect the next login with Internet Identity or NFID.\n // To ensure each session starts clean and safe, we clear the stored keys before creating a new AuthClient\n // in case the user is not authenticated.\n const storage = new IdbStorage();\n await storage.remove(KEY_STORAGE_KEY);\n\n return await this.createAuthClient();\n };\n\n getAuthClient = (): AuthClient | undefined | null => this.#authClient;\n\n logout = async (): Promise<void> => {\n await this.#authClient?.logout();\n\n // Reset local object otherwise next sign in (sign in - sign out - sign in) might not work out - i.e. agent-js might not recreate the delegation or identity if not resetted\n // Technically we do not need this since we recreate the agent below. We just keep it to make the reset explicit.\n this.#authClient = null;\n };\n\n setAuthClientStorage = async ({\n delegationChain,\n sessionKey\n }: {\n delegationChain: DelegationChain;\n sessionKey: ECDSAKeyIdentity;\n }) => {\n const storage = new IdbStorage();\n\n await Promise.all([\n storage.set(KEY_STORAGE_KEY, sessionKey.getKeyPair()),\n storage.set(KEY_STORAGE_DELEGATION, JSON.stringify(delegationChain.toJSON()))\n ]);\n };\n}\n", "import {ActorStore} from '../../core/stores/actor.store';\nimport {AgentStore} from '../../core/stores/agent.store';\nimport {AuthClientStore} from '../stores/auth-client.store';\nimport {AuthStore} from '../stores/auth.store';\nimport type {SignOutOptions} from '../types/auth';\n\n/**\n * Signs out the current user.\n * @returns {Promise<void>} A promise that resolves when the sign-out process is complete.\n */\nexport const signOut = async (options?: SignOutOptions): Promise<void> => {\n await resetAuth();\n\n // Recreate an HttpClient immediately because next sign-in, if window is not reloaded, would fail if the agent is created within the process.\n // For example, Safari blocks the Internet Identity (II) window if the agent is created during the interaction.\n // Agent-js must be created either globally or at least before performing a sign-in.\n // We proceed with this reset regardless of the window reloading. This way we ensure it is reset not matter what.\n await AuthClientStore.getInstance().createAuthClient();\n\n if (options?.windowReload === false) {\n return;\n }\n\n window.location.reload();\n};\n\n/**\n * \u2139\uFE0F Exposed for testing purpose only. Should not be leaked to consumer or used by the library.\n */\nexport const resetAuth = async () => {\n await AuthClientStore.getInstance().logout();\n\n AuthStore.getInstance().reset();\n\n ActorStore.getInstance().reset();\n AgentStore.getInstance().reset();\n};\n", "import {AuthClientStore} from '../stores/auth-client.store';\n\n/**\n * Initializes a new `AuthClient`, checks authentication state,\n * and executes the provided function if already authenticated.\n *\n * - Always creates a fresh `AuthClient` using {@link createAuthClient}.\n * - If the client is **not authenticated**, it resets the client via {@link safeCreateAuthClient}\n * to ensure a clean session.\n * - If authenticated, it runs the given async function `fn`.\n *\n * @param {Object} params\n * @param {() => Promise<void>} params.fn - The asynchronous function to execute when authenticated.\n *\n * @returns {Promise<void>} Resolves when authentication is handled and the provided function is executed (if applicable).\n */\nexport const authenticateWithAuthClient = async ({fn}: {fn: () => Promise<void>}) => {\n const {createAuthClient, safeCreateAuthClient} = AuthClientStore.getInstance();\n\n const authClient = await createAuthClient();\n\n const isAuthenticated = await authClient.isAuthenticated();\n\n if (!isAuthenticated) {\n await safeCreateAuthClient();\n return;\n }\n\n await fn();\n};\n", "import {isNullish, nonNullish} from '@dfinity/utils';\nimport {isSatelliteError, JUNO_DATASTORE_ERROR_USER_CANNOT_UPDATE} from '@junobuild/errors';\nimport {getDoc, setDoc} from '../../datastore/services/doc.services';\nimport {InitError} from '../types/errors';\nimport type {ProviderWithoutData} from '../types/provider';\nimport type {User, UserData, UserDataWithoutProviderData} from '../types/user';\n\nimport {getIdentity} from './identity.services';\n\ntype UserId = string;\n\nexport const initUser = async ({provider}: {provider: ProviderWithoutData}): Promise<User> => {\n const {user, userId} = await loadUser();\n\n // For returning users we do not need to create a user entry.\n // Sign-in, sign-out, and sign-in again.\n if (nonNullish(user)) {\n return user;\n }\n\n try {\n return await createUser({userId, provider});\n } catch (error: unknown) {\n // It's unlikely, but since updating a user is restricted to the controller,\n // we want to guard against a rare race condition where a user attempts\n // to create a user entry that already exists. In such a case, instead of\n // throwing, we retry loading the user data. If that succeeds, it provides\n // a more graceful UX.\n //\n // With the new flow introduced in core library v2, this scenario should\n // never occur, but the handling remains given it was already implemented\n // with the earlier flow where user creation could happen during init.\n if (isSatelliteErr