@dloizides/auth-web 1.18.1 → 1.18.3

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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/components/useAuthScreenStyles.ts","../src/theme/AuthTheme.ts","../src/theme/AuthThemeProvider.tsx","../src/components/AuthScreen.tsx","../src/components/labels/loginLabels.ts","../src/components/labels/forgotPasswordLabels.ts","../src/components/labels/otpLabels.ts","../src/components/labels/pinLabels.ts","../src/components/labels/devicePinLabels.ts","../src/components/labels/passkeyLabels.ts","../src/components/labels/preferredMethodLabels.ts","../src/components/labels/demoLabels.ts","../src/components/labels/resetPasswordLabels.ts","../src/components/labels/accountSettingsLabels.ts","../src/components/labels/registerLabels.ts","../src/components/testIds.ts","../src/components/useAuthStyles.ts","../src/components/PrefillIntent.ts","../src/components/useLoginPrefill.ts","../src/components/useLoginSubmit.ts","../src/hooks/useBffAuth.ts","../src/components/LoginForm.tsx","../src/hooks/useBffPasswordHooks.ts","../src/components/ForgotPasswordForm.tsx","../src/hooks/useForgotPasswordSubmit.ts","../src/components/ForgotPasswordFields.tsx","../src/hooks/ResetPasswordError.ts","../src/password/PasswordPolicyError.ts","../src/password/passwordPolicy.ts","../src/hooks/useResetPasswordForm.ts","../src/components/ResetPasswordForm.tsx","../src/components/OtpFormSteps.tsx","../src/hooks/OtpLoginStep.ts","../src/hooks/useOtpLogin.ts","../src/components/OtpForm.tsx","../src/hooks/usePinLogin.ts","../src/components/PinForm.tsx","../src/components/DevicePinInput.tsx","../src/components/interpolate.ts","../src/devicePin/devicePinConstants.ts","../src/components/DevicePinLengthPicker.tsx","../src/devicePin/DevicePinErrorKey.ts","../src/devicePin/useDevicePinUnlock.ts","../src/components/DevicePinUnlockScreen.tsx","../src/devicePin/DevicePinEnrollErrorKey.ts","../src/devicePin/useDevicePinEnroll.ts","../src/components/DevicePinEnrollForm.tsx","../src/components/DevicePinOffer.tsx","../src/devicePin/useDevicePinDisable.ts","../src/components/DevicePinSettingsCard.tsx","../src/passkey/PasskeyCeremonyMode.ts","../src/passkey/browserLocation.ts","../src/passkey/passkeyNavigation.ts","../src/passkey/PasskeyCeremonyStatus.ts","../src/passkey/base64url.ts","../src/passkey/webAuthnCoercion.ts","../src/passkey/usePasskeyCeremony.ts","../src/components/PasskeyLoginButton.tsx","../src/components/PasskeySettingsCard.tsx","../src/preferences/preferredMethodCache.ts","../src/preferences/usePreferredMethodSetting.ts","../src/components/PreferredMethodSettingsCard.tsx","../src/password/ChangePasswordErrorKey.ts","../src/password/useChangePassword.ts","../src/components/ChangePasswordCard.tsx","../src/components/AccountSettingsScreen.tsx","../src/components/PreferredMethodHint.tsx","../src/components/DemoCredentialsBody.tsx","../src/components/DemoCredentialsHintVariant.ts","../src/components/useDemoCredentialsStyles.ts","../src/demo/resolveDemoCredentials.ts","../src/demo/resolveDemoAccounts.ts","../src/components/DemoCredentialsHint.tsx","../src/devicePin/useBffLoginConfig.ts","../src/preferences/preferencesClient.ts","../src/preferences/syncPreferredMethodCache.ts","../src/demo/useDemoCredentials.ts","../src/components/registerTestIds.ts","../src/components/RegisterFormFields.tsx","../src/hooks/RegisterErrorCode.ts","../src/hooks/routeRegisterOutcome.ts","../src/hooks/registerErrors.ts","../src/hooks/useRegisterForm.ts","../src/components/RegisterForm.tsx","../src/client/createBffAuthClient.ts","../src/router/resolvePostLoginRoute.ts","../src/router/resolveAccessibleRoutes.ts","../src/session/performBffLogout.ts","../src/password/changePasswordClient.ts"],"names":["useMemo","styles","jsx","FULL_WIDTH","StyleSheet","PrefillIntent","useState","BffAuthStatus","useCallback","jsxs","Text","View","Fragment","TextInput","TouchableOpacity","EMAIL_REGEX","useEffect","ActivityIndicator","ResetPasswordError","PasswordPolicyError","OtpLoginStep","toError","useRef","isValidEmail","transportErrorFor","Pressable","DevicePinErrorKey","DevicePinEnrollErrorKey","resolveErrorText","PasskeyCeremonyMode","PasskeyCeremonyStatus","ChangePasswordErrorKey","errorMessage","DemoCredentialsHintVariant","RegisterErrorCode","field","Button","isRecord","CSRF_HEADER","CSRF_HEADER_VALUE","JSON_CONTENT_TYPE","HTTP_BAD_REQUEST","lazyFetchHttpClient","createFetchHttpClient"],"mappings":";;;;;;;;;AA6BA,IAAM,UAAA,GAAa,MAAA;AACnB,IAAM,iBAAA,GAAoB,CAAA;AA+B1B,IAAM,eAAA,GAAkB,EAAA;AAGjB,SAAS,oBAAoB,KAAA,EAAoC;AACtE,EAAA,OAAO,QAAQ,MAAM;AACnB,IAAA,MAAM,EAAE,MAAA,EAAQ,KAAA,EAAO,OAAA,EAAS,YAAW,GAAI,KAAA;AAC/C,IAAA,OAAO,WAAW,MAAA,CAAyB;AAAA,MACzC,MAAA,EAAQ;AAAA,QACN,IAAA,EAAM,CAAA;AAAA;AAAA,QAEN,cAAA,EAAgB,YAAA;AAAA,QAChB,UAAA,EAAY,QAAA;AAAA,QACZ,SAAS,OAAA,CAAQ,EAAA;AAAA,QACjB,UAAA,EAAY,eAAA;AAAA,QACZ,iBAAiB,MAAA,CAAO;AAAA,OAC1B;AAAA,MACA,IAAA,EAAM;AAAA,QACJ,KAAA,EAAO,UAAA;AAAA,QACP,cAAc,KAAA,CAAM,IAAA;AAAA,QACpB,WAAA,EAAa,iBAAA;AAAA,QACb,aAAa,MAAA,CAAO,MAAA;AAAA,QACpB,SAAS,OAAA,CAAQ,EAAA;AAAA,QACjB,iBAAiB,MAAA,CAAO;AAAA,OAC1B;AAAA,MACA,KAAA,EAAO;AAAA,QACL,UAAU,UAAA,CAAW,KAAA;AAAA,QACrB,UAAA,EAAY,MAAA;AAAA,QACZ,cAAc,OAAA,CAAQ,EAAA;AAAA,QACtB,OAAO,MAAA,CAAO;AAAA,OAChB;AAAA,MACA,QAAA,EAAU;AAAA,QACR,UAAU,UAAA,CAAW,QAAA;AAAA,QACrB,cAAc,OAAA,CAAQ,EAAA;AAAA,QACtB,OAAO,MAAA,CAAO;AAAA,OAChB;AAAA,MACA,MAAA,EAAQ;AAAA,QACN,WAAW,OAAA,CAAQ,EAAA;AAAA,QACnB,KAAA,EAAO,UAAA;AAAA,QACP,UAAA,EAAY;AAAA;AACd,KACD,CAAA;AAAA,EACH,CAAA,EAAG,CAAC,KAAK,CAAC,CAAA;AACZ;;;ACLO,IAAM,gBAAA,GAA8B;AAAA,EACzC,MAAA,EAAQ;AAAA,IACN,UAAA,EAAY,SAAA;AAAA,IACZ,OAAA,EAAS,SAAA;AAAA,IACT,IAAA,EAAM,SAAA;AAAA,IACN,aAAA,EAAe,SAAA;AAAA,IACf,MAAA,EAAQ,SAAA;AAAA,IACR,OAAA,EAAS,SAAA;AAAA,IACT,SAAA,EAAW,SAAA;AAAA,IACX,MAAA,EAAQ,SAAA;AAAA,IACR,OAAA,EAAS;AAAA,GACX;AAAA,EACA,KAAA,EAAO;AAAA,IACL,KAAA,EAAO,CAAA;AAAA,IACP,IAAA,EAAM;AAAA,GACR;AAAA,EACA,OAAA,EAAS;AAAA,IACP,EAAA,EAAI,CAAA;AAAA,IACJ,EAAA,EAAI,EAAA;AAAA,IACJ,EAAA,EAAI,EAAA;AAAA,IACJ,EAAA,EAAI,EAAA;AAAA,IACJ,EAAA,EAAI;AAAA,GACN;AAAA,EACA,UAAA,EAAY;AAAA,IACV,KAAA,EAAO,EAAA;AAAA,IACP,QAAA,EAAU,EAAA;AAAA;AAAA,IAEV,KAAA,EAAO,EAAA;AAAA,IACP,IAAA,EAAM,EAAA;AAAA,IACN,OAAA,EAAS;AAAA;AAEb;AC/GA,IAAM,gBAAA,GAAmB,cAAyB,gBAAgB,CAAA;AAS3D,SAAS,iBAAA,CAAkB;AAAA,EAChC,KAAA;AAAA,EACA;AACF,CAAA,EAAmD;AACjD,EAAA,2BAAQ,gBAAA,CAAiB,QAAA,EAAjB,EAA0B,KAAA,EAAO,OAAQ,QAAA,EAAS,CAAA;AAC5D;AAQO,SAAS,aAAa,SAAA,EAAkC;AAC7D,EAAA,MAAM,YAAA,GAAe,WAAW,gBAAgB,CAAA;AAChD,EAAA,OAAOA,QAAQ,MAAM,SAAA,IAAa,cAAc,CAAC,SAAA,EAAW,YAAY,CAAC,CAAA;AAC3E;ACXO,IAAM,2BAAA,GAA8B;AAsBpC,SAAS,UAAA,CAAW;AAAA,EACzB,QAAA;AAAA,EACA,KAAA,EAAO,SAAA;AAAA,EACP,MAAA;AAAA,EACA,UAAA;AAAA,EACA,QAAA,GAAW,2BAAA;AAAA,EACX,KAAA;AAAA,EACA,QAAA;AAAA,EACA;AACF,CAAA,EAA4C;AAC1C,EAAA,MAAM,KAAA,GAAQ,aAAa,SAAS,CAAA;AACpC,EAAA,MAAMC,OAAAA,GAAS,oBAAoB,KAAK,CAAA;AAExC,EAAA,uBACE,IAAA,CAAC,IAAA,EAAA,EAAK,KAAA,EAAOA,OAAAA,CAAO,QAAQ,MAAA,EAC1B,QAAA,EAAA;AAAA,oBAAA,IAAA,CAAC,IAAA,EAAA,EAAK,KAAA,EAAO,CAACA,OAAAA,CAAO,IAAA,EAAM,EAAE,QAAA,EAAU,CAAA,EAAG,MAAA,EAAQ,UAAA,EAC/C,QAAA,EAAA;AAAA,MAAA,KAAA,KAAU,MAAA,mBAAYC,GAAAA,CAAC,IAAA,EAAA,EAAK,OAAOD,OAAAA,CAAO,KAAA,EAAQ,iBAAM,CAAA,GAAU,IAAA;AAAA,MAClE,QAAA,KAAa,yBAAYC,GAAAA,CAAC,QAAK,KAAA,EAAOD,OAAAA,CAAO,QAAA,EAAW,QAAA,EAAA,QAAA,EAAS,CAAA,GAAU,IAAA;AAAA,MAC3E;AAAA,KAAA,EACH,CAAA;AAAA,IACC,MAAA,KAAW,MAAA,mBAAYC,GAAAA,CAAC,QAAK,KAAA,EAAO,CAACD,OAAAA,CAAO,MAAA,EAAQ,EAAE,QAAA,EAAU,CAAA,EAAI,kBAAO,CAAA,GAAU;AAAA,GAAA,EACxF,CAAA;AAEJ;;;ACvDO,IAAM,oBAAA,GAAwC;AAAA,EACnD,KAAA,EAAO,SAAA;AAAA,EACP,QAAA,EAAU,cAAA;AAAA,EACV,aAAA,EAAe,UAAA;AAAA,EACf,mBAAA,EAAqB,qBAAA;AAAA,EACrB,aAAA,EAAe,UAAA;AAAA,EACf,mBAAA,EAAqB,qBAAA;AAAA,EACrB,MAAA,EAAQ,SAAA;AAAA,EACR,UAAA,EAAY,eAAA;AAAA,EACZ,cAAA,EAAgB,kBAAA;AAAA,EAChB,MAAA,EAAQ,mBAAA;AAAA,EACR,kBAAA,EAAoB,iCAAA;AAAA,EACpB,aAAA,EAAe;AACjB;;;ACNO,IAAM,8BAAA,GAA2D;AAAA,EACtE,KAAA,EAAO,iBAAA;AAAA,EACP,WAAA,EAAa,qDAAA;AAAA,EACb,UAAA,EAAY,OAAA;AAAA,EACZ,gBAAA,EAAkB,kBAAA;AAAA,EAClB,MAAA,EAAQ,iBAAA;AAAA,EACR,UAAA,EAAY,YAAA;AAAA,EACZ,cAAA,EAAgB,0DAAA;AAAA,EAChB,YAAA,EAAc,yCAAA;AAAA,EACd,YAAA,EAAc;AAChB;AAEO,IAAM,qCAAA,GAAoE;AAAA,EAC/E,GAAG,8BAAA;AAAA,EACH,MAAA,EAAQ,QAAA;AAAA,EACR,KAAA,EAAO;AACT;;;ACJO,IAAM,kBAAA,GAAoC;AAAA,EAC/C,YAAA,EAAc,qBAAA;AAAA,EACd,kBAAA,EAAoB,wDAAA;AAAA,EACpB,UAAA,EAAY,OAAA;AAAA,EACZ,gBAAA,EAAkB,kBAAA;AAAA,EAClB,aAAA,EAAe,WAAA;AAAA,EACf,UAAA,EAAY,YAAA;AAAA,EACZ,YAAA,EAAc,8BAAA;AAAA,EACd,WAAA,EAAa,iBAAA;AAAA,EACb,iBAAA,EAAmB,0CAAA;AAAA,EACnB,SAAA,EAAW,eAAA;AAAA,EACX,eAAA,EAAiB,gBAAA;AAAA,EACjB,YAAA,EAAc,QAAA;AAAA,EACd,SAAA,EAAW,cAAA;AAAA,EACX,WAAA,EAAa,gCAAA;AAAA,EACb,WAAA,EAAa,wCAAA;AAAA,EACb,MAAA,EAAQ,aAAA;AAAA,EACR,SAAA,EAAW,cAAA;AAAA,EACX,WAAA,EAAa;AACf;;;AC1CO,IAAM,kBAAA,GAAoC;AAAA,EAC/C,KAAA,EAAO,sBAAA;AAAA,EACP,WAAA,EAAa,0CAAA;AAAA,EACb,QAAA,EAAU,KAAA;AAAA,EACV,cAAA,EAAgB,gBAAA;AAAA,EAChB,MAAA,EAAQ,SAAA;AAAA,EACR,UAAA,EAAY,eAAA;AAAA,EACZ,UAAA,EAAY,uBAAA;AAAA,EACZ,UAAA,EAAY;AACd;;;AC0EO,IAAM,gCAAA,GAA0D;AAAA,EACrE,KAAA,EAAO,sBAAA;AAAA,EACP,WAAA,EAAa,cAAA;AAAA,EACb,WAAA,EAAa,yDAAA;AAAA,EACb,QAAA,EAAU,KAAA;AAAA,EACV,cAAA,EAAgB,gBAAA;AAAA,EAChB,MAAA,EAAQ,QAAA;AAAA,EACR,UAAA,EAAY,eAAA;AAAA,EACZ,kBAAA,EAAoB,+BAAA;AAAA,EACpB,eAAA,EAAiB,sDAAA;AAAA,EACjB,eAAA,EAAiB,uCAAA;AAAA,EACjB,YAAA,EAAc,mCAAA;AAAA,EACd,cAAA,EAAgB,qCAAA;AAAA,EAChB,mBAAA,EAAqB,kDAAA;AAAA,EACrB,gBAAA,EAAkB,qCAAA;AAAA,EAClB,qBAAA,EAAuB,kDAAA;AAAA,EACvB,YAAA,EAAc,iEAAA;AAAA,EACd,eAAA,EAAiB,mBAAA;AAAA,EACjB,cAAA,EAAgB;AAClB;AAEO,IAAM,gCAAA,GAA0D;AAAA,EACrE,UAAA,EAAY,+BAAA;AAAA,EACZ,gBAAA,EACE,mFAAA;AAAA,EACF,WAAA,EAAa,cAAA;AAAA,EACb,eAAA,EAAiB,6CAAA;AAAA,EACjB,SAAA,EAAW,SAAA;AAAA,EACX,aAAA,EAAe,6BAAA;AAAA,EACf,SAAA,EAAW,iBAAA;AAAA,EACX,eAAA,EACE,wFAAA;AAAA,EACF,WAAA,EAAa,YAAA;AAAA,EACb,gBAAA,EAAkB,yBAAA;AAAA,EAClB,QAAA,EAAU,SAAA;AAAA,EACV,cAAA,EAAgB,iBAAA;AAAA,EAChB,YAAA,EAAc,aAAA;AAAA,EACd,kBAAA,EAAoB,mBAAA;AAAA,EACpB,MAAA,EAAQ,UAAA;AAAA,EACR,UAAA,EAAY,WAAA;AAAA,EACZ,MAAA,EAAQ,QAAA;AAAA,EACR,UAAA,EAAY,yCAAA;AAAA,EACZ,aAAA,EAAe,oDAAA;AAAA,EACf,iBAAA,EAAmB,uDAAA;AAAA,EACnB,cAAA,EAAgB,wCAAA;AAAA,EAChB,eAAA,EAAiB,kDAAA;AAAA,EACjB,WAAA,EAAa;AACf;AAEO,IAAM,kCAAA,GAA8D;AAAA,EACzE,KAAA,EAAO,mBAAA;AAAA,EACP,WAAA,EAAa,wEAAA;AAAA,EACb,aAAA,EAAe,8CAAA;AAAA,EACf,cAAA,EAAgB,2BAAA;AAAA,EAChB,MAAA,EAAQ,0BAAA;AAAA,EACR,UAAA,EAAY,oDAAA;AAAA,EACZ,OAAA,EAAS,SAAA;AAAA,EACT,WAAA,EAAa,yCAAA;AAAA,EACb,SAAA,EAAW,cAAA;AAAA,EACX,aAAA,EAAe;AACjB;;;AClIO,IAAM,4BAAA,GAAmD;AAAA,EAC9D,YAAA,EAAc,wBAAA;AAAA,EACd,UAAA,EAAY,wDAAA;AAAA,EACZ,cAAA,EACE,0EAAA;AAAA,EACF,WAAA,EAAa,iEAAA;AAAA,EACb,aAAA,EAAe;AACjB;AAEO,IAAM,+BAAA,GAAyD;AAAA,EACpE,KAAA,EAAO,UAAA;AAAA,EACP,WAAA,EACE,gGAAA;AAAA,EACF,UAAA,EAAY,mEAAA;AAAA,EACZ,SAAA,EAAW,eAAA;AAAA,EACX,OAAA,EAAS,6CAAA;AAAA,EACT,iBAAA,EAAmB;AACrB;;;ACpBO,IAAM,wCAAA,GAA0E;AAAA,EACrF,KAAA,EAAO,0BAAA;AAAA,EACP,WAAA,EACE,+EAAA;AAAA,EACF,YAAA,EAAc,eAAA;AAAA,EACd,cAAA,EAAgB,UAAA;AAAA,EAChB,SAAA,EAAW,WAAA;AAAA,EACX,aAAA,EAAe,SAAA;AAAA,EACf,MAAA,EAAQ,WAAA;AAAA,EACR,UAAA,EAAY;AACd;AAEO,IAAM,oCAAA,GAAkE;AAAA,EAC7E,QAAA,EAAU,yCAAA;AAAA,EACV,GAAA,EAAK,0DAAA;AAAA,EACL,OAAA,EAAS;AACX;;;ACjBO,IAAM,oCAAA,GAAkE;AAAA,EAC7E,KAAA,EAAO,aAAA;AAAA,EACP,WAAA,EAAa,wDAAA;AAAA,EACb,aAAA,EAAe,UAAA;AAAA,EACf,aAAA,EAAe,UAAA;AAAA,EACf,cAAA,EAAgB,uBAAA;AAAA,EAChB,kBAAA,EAAoB,2DAAA;AAAA,EACpB,MAAA,EAAQ,cAAA;AAAA,EACR,UAAA,EAAY;AACd;;;ACdO,IAAM,6BAAA,GAAyD;AAAA,EACpE,KAAA,EAAO,gBAAA;AAAA,EACP,WAAA,EAAa,yCAAA;AAAA,EACb,gBAAA,EAAkB,cAAA;AAAA,EAClB,sBAAA,EAAwB,sBAAA;AAAA,EACxB,oBAAA,EAAsB,kBAAA;AAAA,EACtB,0BAAA,EAA4B,2BAAA;AAAA,EAC5B,MAAA,EAAQ,gBAAA;AAAA,EACR,UAAA,EAAY,cAAA;AAAA,EACZ,UAAA,EAAY,+BAAA;AAAA,EACZ,iBAAA,EACE,qFAAA;AAAA,EACF,aAAA,EAAe,6BAAA;AAAA,EACf,iBAAA,EAAmB,+DAAA;AAAA,EACnB,YAAA,EAAc;AAChB;;;ACWO,IAAM,+BAAA,GAAyD;AAAA,EACpE,OAAA,EAAS,kBAAA;AAAA,EAET,mBAAA,EAAqB,iBAAA;AAAA,EACrB,yBAAA,EAA2B,yCAAA;AAAA,EAC3B,oBAAA,EAAsB,kBAAA;AAAA,EACtB,0BAAA,EAA4B,6BAAA;AAAA,EAC5B,gBAAA,EAAkB,cAAA;AAAA,EAClB,sBAAA,EAAwB,sBAAA;AAAA,EACxB,oBAAA,EAAsB,sBAAA;AAAA,EACtB,0BAAA,EAA4B,4BAAA;AAAA,EAC5B,MAAA,EAAQ,iBAAA;AAAA,EACR,UAAA,EAAY,sBAAA;AAAA,EACZ,UAAA,EAAY,yCAAA;AAAA,EACZ,OAAA,EAAS,iCAAA;AAAA,EAET,oBAAA,EACE,mHAAA;AAAA,EACF,aAAA,EAAe,qDAAA;AAAA,EACf,oBAAA,EAAsB,8BAAA;AAAA,EACtB,mBAAA,EAAqB,mFAAA;AAAA,EACrB,iBAAA,EAAmB,kEAAA;AAAA,EACnB,WAAA,EAAa;AACf;;;AC9CA,SAAS,KAAA,CAAM,OAAe,WAAA,EAA0C;AACtE,EAAA,OAAO,EAAE,KAAA,EAAO,WAAA,EAAa,IAAA,EAAM,WAAA,EAAa,YAAY,KAAA,EAAM;AACpE;AAEO,IAAM,uBAAA,GAA8C;AAAA,EACzD,KAAA,EAAO,gBAAA;AAAA,EACP,QAAA,EAAU,wBAAA;AAAA,EACV,MAAA,EAAQ,gBAAA;AAAA,EACR,UAAA,EAAY,sBAAA;AAAA,EACZ,UAAA,EAAY,qBAAA;AAAA,EACZ,MAAA,EAAQ;AAAA,IACN,SAAA,EAAW,KAAA,CAAM,YAAA,EAAc,uBAAuB,CAAA;AAAA,IACtD,QAAA,EAAU,KAAA,CAAM,WAAA,EAAa,sBAAsB,CAAA;AAAA,IACnD,QAAA,EAAU,KAAA,CAAM,UAAA,EAAY,mBAAmB,CAAA;AAAA,IAC/C,KAAA,EAAO,KAAA,CAAM,OAAA,EAAS,kBAAkB,CAAA;AAAA,IACxC,QAAA,EAAU,KAAA,CAAM,UAAA,EAAY,mBAAmB,CAAA;AAAA,IAC/C,eAAA,EAAiB,KAAA,CAAM,kBAAA,EAAoB,sBAAsB,CAAA;AAAA,IACjE,UAAA,EAAY,KAAA,CAAM,mBAAA,EAAqB,8BAA8B;AAAA;AAEzE;;;AC/BO,IAAM,WAAA,GAAc;AAAA,EACzB,SAAA,EAAW,iBAAA;AAAA,EACX,kBAAA,EAAoB,qBAAA;AAAA,EACpB,kBAAA,EAAoB,qBAAA;AAAA,EACpB,iBAAA,EAAmB,mBAAA;AAAA,EACnB,eAAA,EAAiB,wBAAA;AAAA,EACjB,eAAA,EAAiB,wBAAA;AAAA,EACjB,UAAA,EAAY,kBAAA;AAAA,EAEZ,kBAAA,EAAoB,kBAAA;AAAA,EACpB,wBAAA,EAA0B,mBAAA;AAAA,EAC1B,0BAAA,EAA4B,oBAAA;AAAA,EAC5B,0BAAA,EAA4B,oBAAA;AAAA,EAC5B,yBAAA,EAA2B,mBAAA;AAAA,EAC3B,mBAAA,EAAqB,mBAAA;AAAA,EACrB,qBAAA,EAAuB,qBAAA;AAAA,EAEvB,iBAAA,EAAmB,iBAAA;AAAA,EACnB,qBAAA,EAAuB,gBAAA;AAAA,EACvB,yBAAA,EAA2B,oBAAA;AAAA,EAC3B,yBAAA,EAA2B,mBAAA;AAAA,EAC3B,kBAAA,EAAoB,kBAAA;AAAA,EAEpB,OAAA,EAAS,eAAA;AAAA,EACT,aAAA,EAAe,gBAAA;AAAA,EACf,gBAAA,EAAkB,kBAAA;AAAA,EAClB,YAAA,EAAc,eAAA;AAAA,EACd,eAAA,EAAiB,iBAAA;AAAA,EACjB,eAAA,EAAiB,iBAAA;AAAA,EACjB,oBAAA,EAAsB,uBAAA;AAAA,EACtB,QAAA,EAAU,gBAAA;AAAA,EAEV,OAAA,EAAS,eAAA;AAAA,EACT,QAAA,EAAU,gBAAA;AAAA,EACV,eAAA,EAAiB,iBAAA;AAAA,EACjB,QAAA,EAAU,gBAAA;AAAA;AAAA,EAGV,eAAA,EAAiB,wBAAA;AAAA,EACjB,oBAAA,EAAsB,8BAAA;AAAA,EACtB,qBAAA,EAAuB,+BAAA;AAAA,EACvB,0BAAA,EAA4B,qCAAA;AAAA,EAC5B,oBAAA,EAAsB,8BAAA;AAAA;AAAA,EAGtB,mBAAA,EAAqB,6BAAA;AAAA,EACrB,qBAAA,EAAuB,+BAAA;AAAA,EACvB,kBAAA,EAAoB,4BAAA;AAAA,EACpB,sBAAA,EAAwB,gCAAA;AAAA,EACxB,qBAAA,EAAuB,+BAAA;AAAA,EACvB,qBAAA,EAAuB,+BAAA;AAAA,EACvB,oBAAA,EAAsB,8BAAA;AAAA;AAAA,EAGtB,cAAA,EAAgB,uBAAA;AAAA,EAChB,oBAAA,EAAsB,8BAAA;AAAA,EACtB,kBAAA,EAAoB,4BAAA;AAAA;AAAA,EAGpB,iBAAA,EAAmB,0BAAA;AAAA,EACnB,uBAAA,EAAyB,iCAAA;AAAA,EACzB,uBAAA,EAAyB,iCAAA;AAAA,EACzB,wBAAA,EAA0B,kCAAA;AAAA,EAC1B,sBAAA,EAAwB,gCAAA;AAAA;AAAA,EAGxB,YAAA,EAAc,oBAAA;AAAA,EACd,kBAAA,EAAoB,2BAAA;AAAA,EACpB,iBAAA,EAAmB,0BAAA;AAAA,EACnB,oBAAA,EAAsB,6BAAA;AAAA;AAAA,EAGtB,eAAA,EAAiB,uBAAA;AAAA,EACjB,kBAAA,EAAoB,2BAAA;AAAA,EACpB,sBAAA,EAAwB,+BAAA;AAAA;AAAA;AAAA,EAIxB,uBAAA,EAAyB,gCAAA;AAAA,EACzB,6BAAA,EAA+B,uCAAA;AAAA,EAC/B,4BAAA,EAA8B,sCAAA;AAAA;AAAA,EAG9B,mBAAA,EAAqB,4BAAA;AAAA;AAAA,EAGrB,eAAA,EAAiB,uBAAA;AAAA,EACjB,6BAAA,EAA+B,uCAAA;AAAA,EAC/B,0BAAA,EAA4B,8BAAA;AAAA,EAC5B,sBAAA,EAAwB,0BAAA;AAAA,EACxB,0BAAA,EAA4B,8BAAA;AAAA,EAC5B,oBAAA,EAAsB,6BAAA;AAAA,EACtB,mBAAA,EAAqB,4BAAA;AAAA,EACrB,qBAAA,EAAuB,8BAAA;AAAA;AAAA,EAGvB,mBAAA,EAAqB,4BAAA;AAAA;AAAA,EAErB,2BAAA,EAA6B,qCAAA;AAAA,EAC7B,uBAAA,EAAyB,gCAAA;AAAA,EACzB,uBAAA,EAAyB,gCAAA;AAAA,EACzB,wBAAA,EAA0B,2BAAA;AAAA;AAAA,EAE1B,qBAAA,EAAuB;AACzB;AAGO,SAAS,gBAAA,CAAiB,QAAgB,MAAA,EAAyB;AACxE,EAAA,OAAO,MAAA,KAAW,UAAa,MAAA,KAAW,EAAA,GAAK,SAAS,CAAA,EAAG,MAAM,IAAI,MAAM,CAAA,CAAA;AAC7E;AChFA,IAAME,WAAAA,GAAa,MAAA;AACnB,IAAM,cAAA,GAAiB,GAAA;AACvB,IAAM,uBAAA,GAA0B,EAAA;AAEhC,IAAM,iBAAA,GAAoB,EAAA;AAGnB,SAAS,cAAc,KAAA,EAA8B;AAC1D,EAAA,OAAOH,QAAQ,MAAM;AACnB,IAAA,MAAM,EAAE,MAAA,EAAQ,KAAA,EAAO,OAAA,EAAS,YAAW,GAAI,KAAA;AAC/C,IAAA,OAAOI,WAAW,MAAA,CAAmB;AAAA,MACnC,MAAA,EAAQ;AAAA,QACN,IAAA,EAAM,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAKN,cAAA,EAAgB,YAAA;AAAA,QAChB,UAAA,EAAY,QAAA;AAAA,QACZ,SAAS,OAAA,CAAQ,EAAA;AAAA,QACjB,UAAA,EAAY,iBAAA;AAAA,QACZ,iBAAiB,MAAA,CAAO;AAAA,OAC1B;AAAA,MACA,IAAA,EAAM;AAAA,QACJ,KAAA,EAAOD,WAAAA;AAAA,QACP,QAAA,EAAU,cAAA;AAAA,QACV,cAAc,KAAA,CAAM,IAAA;AAAA,QACpB,SAAS,OAAA,CAAQ,EAAA;AAAA,QACjB,iBAAiB,MAAA,CAAO;AAAA,OAC1B;AAAA,MACA,KAAA,EAAO;AAAA,QACL,UAAU,UAAA,CAAW,KAAA;AAAA,QACrB,UAAA,EAAY,MAAA;AAAA,QACZ,SAAA,EAAW,QAAA;AAAA,QACX,cAAc,OAAA,CAAQ,EAAA;AAAA,QACtB,OAAO,MAAA,CAAO;AAAA,OAChB;AAAA,MACA,QAAA,EAAU;AAAA,QACR,UAAU,UAAA,CAAW,QAAA;AAAA,QACrB,SAAA,EAAW,QAAA;AAAA,QACX,cAAc,OAAA,CAAQ,EAAA;AAAA,QACtB,OAAO,MAAA,CAAO;AAAA,OAChB;AAAA,MACA,UAAA,EAAY;AAAA,QACV,cAAc,OAAA,CAAQ;AAAA,OACxB;AAAA,MACA,KAAA,EAAO;AAAA,QACL,UAAU,UAAA,CAAW,KAAA;AAAA,QACrB,UAAA,EAAY,KAAA;AAAA,QACZ,cAAc,OAAA,CAAQ,EAAA;AAAA,QACtB,OAAO,MAAA,CAAO;AAAA,OAChB;AAAA,MACA,KAAA,EAAO;AAAA,QACL,WAAA,EAAa,CAAA;AAAA,QACb,cAAc,KAAA,CAAM,KAAA;AAAA,QACpB,SAAS,OAAA,CAAQ,EAAA;AAAA,QACjB,UAAU,UAAA,CAAW,IAAA;AAAA,QACrB,aAAa,MAAA,CAAO,MAAA;AAAA,QACpB,iBAAiB,MAAA,CAAO,UAAA;AAAA,QACxB,OAAO,MAAA,CAAO;AAAA,OAChB;AAAA,MACA,UAAA,EAAY;AAAA,QACV,aAAa,MAAA,CAAO;AAAA,OACtB;AAAA,MACA,aAAA,EAAe;AAAA,QACb,cAAc,KAAA,CAAM,KAAA;AAAA,QACpB,eAAA,EAAiB,uBAAA;AAAA,QACjB,mBAAmB,OAAA,CAAQ,EAAA;AAAA;AAAA;AAAA;AAAA,QAI3B,UAAA,EAAY,CAAA;AAAA,QACZ,UAAA,EAAY,QAAA;AAAA,QACZ,cAAA,EAAgB,QAAA;AAAA,QAChB,WAAW,OAAA,CAAQ,EAAA;AAAA,QACnB,iBAAiB,MAAA,CAAO;AAAA,OAC1B;AAAA,MACA,qBAAA,EAAuB;AAAA,QACrB,iBAAiB,MAAA,CAAO;AAAA,OAC1B;AAAA,MACA,iBAAA,EAAmB;AAAA,QACjB,UAAU,UAAA,CAAW,IAAA;AAAA,QACrB,UAAA,EAAY,KAAA;AAAA,QACZ,OAAO,MAAA,CAAO;AAAA,OAChB;AAAA,MACA,QAAA,EAAU;AAAA,QACR,UAAU,UAAA,CAAW,OAAA;AAAA,QACrB,kBAAA,EAAoB,WAAA;AAAA,QACpB,OAAO,MAAA,CAAO;AAAA,OAChB;AAAA,MACA,SAAA,EAAW;AAAA,QACT,UAAU,UAAA,CAAW,OAAA;AAAA,QACrB,WAAW,OAAA,CAAQ,EAAA;AAAA,QACnB,OAAO,MAAA,CAAO;AAAA,OAChB;AAAA,MACA,WAAA,EAAa;AAAA,QACX,UAAU,UAAA,CAAW,IAAA;AAAA,QACrB,UAAA,EAAY,WAAW,IAAA,GAAO,GAAA;AAAA,QAC9B,OAAO,MAAA,CAAO;AAAA,OAChB;AAAA,MACA,UAAA,EAAY;AAAA,QACV,UAAU,UAAA,CAAW,OAAA;AAAA,QACrB,OAAO,MAAA,CAAO;AAAA,OAChB;AAAA,MACA,UAAA,EAAY;AAAA,QACV,SAAA,EAAW,QAAA;AAAA,QACX,WAAW,OAAA,CAAQ,EAAA;AAAA,QACnB,eAAA,EAAiB,QAAQ,EAAA,GAAK;AAAA,OAChC;AAAA,MACA,eAAA,EAAiB;AAAA,QACf,cAAc,KAAA,CAAM,KAAA;AAAA,QACpB,WAAA,EAAa,CAAA;AAAA,QACb,aAAa,MAAA,CAAO,OAAA;AAAA,QACpB,eAAA,EAAiB,uBAAA;AAAA,QACjB,mBAAmB,OAAA,CAAQ,EAAA;AAAA,QAC3B,UAAA,EAAY,CAAA;AAAA,QACZ,UAAA,EAAY,QAAA;AAAA,QACZ,cAAA,EAAgB,QAAA;AAAA,QAChB,WAAW,OAAA,CAAQ,EAAA;AAAA,QACnB,iBAAiB,MAAA,CAAO;AAAA,OAC1B;AAAA,MACA,mBAAA,EAAqB;AAAA,QACnB,UAAU,UAAA,CAAW,IAAA;AAAA,QACrB,UAAA,EAAY,KAAA;AAAA,QACZ,OAAO,MAAA,CAAO;AAAA,OAChB;AAAA,MACA,UAAA,EAAY;AAAA,QACV,UAAU,UAAA,CAAW,KAAA;AAAA,QACrB,UAAA,EAAY,KAAA;AAAA,QACZ,WAAW,OAAA,CAAQ,EAAA;AAAA,QACnB,OAAO,MAAA,CAAO;AAAA;AAChB,KACD,CAAA;AAAA,EACH,CAAA,EAAG,CAAC,KAAK,CAAC,CAAA;AACZ;;;AClKO,IAAW,aAAA,qBAAAE,cAAAA,KAAX;AAEL,EAAAA,eAAA,UAAA,CAAA,GAAW,UAAA;AAEX,EAAAA,eAAA,eAAA,CAAA,GAAgB,eAAA;AAJA,EAAA,OAAAA,cAAAA;AAAA,CAAA,EAAA,aAAA,IAAA,EAAA;;;ACqCX,SAAS,eAAA,CAAgB;AAAA,EAC9B,eAAA;AAAA,EACA,eAAA;AAAA,EACA,YAAA;AAAA,EACA;AACF,CAAA,EAAyD;AACvD,EAAA,MAAM,CAAC,QAAA,EAAU,WAAW,CAAA,GAAI,QAAA,CAAiB,mBAAmB,EAAE,CAAA;AACtE,EAAA,MAAM,CAAC,QAAA,EAAU,WAAW,CAAA,GAAI,QAAA,CAAiB,mBAAmB,EAAE,CAAA;AAGtE,EAAA,MAAM,CAAC,YAAA,EAAc,eAAe,CAAA,GAAI,SAA6B,YAAY,CAAA;AAEjF,EAAA,IAAI,iBAAiB,YAAA,EAAc;AAGjC,IAAA,eAAA,CAAgB,YAAY,CAAA;AAM5B,IAAA,MAAM,UAAA,GAAa,QAAA,CAAS,MAAA,KAAW,CAAA,IAAK,SAAS,MAAA,KAAW,CAAA;AAChE,IAAA,MAAM,WAAW,aAAA,KAAA,eAAA,wBAAiD,UAAA;AAElE,IAAA,IAAI,QAAA,EAAU;AACZ,MAAA,WAAA,CAAY,mBAAmB,EAAE,CAAA;AACjC,MAAA,WAAA,CAAY,mBAAmB,EAAE,CAAA;AAAA,IACnC;AAAA,EACF;AAEA,EAAA,OAAO,EAAE,QAAA,EAAU,QAAA,EAAU,WAAA,EAAa,WAAA,EAAY;AACxD;ACzCO,SAAS,cAAA,CAAe;AAAA,EAC7B,QAAA;AAAA,EACA,QAAA;AAAA,EACA,KAAA;AAAA,EACA,SAAA;AAAA,EACA,kBAAA;AAAA,EACA;AACF,CAAA,EAAuD;AACrD,EAAA,MAAM,CAAC,SAAA,EAAW,YAAY,CAAA,GAAIC,SAAwB,IAAI,CAAA;AAE9D,EAAA,MAAM,QAAA,GAAW,YAAY,YAA2B;AACtD,IAAA,YAAA,CAAa,IAAI,CAAA;AACjB,IAAA,MAAM,eAAA,GAAkB,SAAS,IAAA,EAAK;AACtC,IAAA,MAAM,eAAA,GAAkB,eAAA,CAAgB,MAAA,KAAW,CAAA,IAAK,SAAS,MAAA,KAAW,CAAA;AAC5E,IAAA,IAAI,eAAA,EAAiB;AACnB,MAAA,YAAA,CAAa,kBAAkB,CAAA;AAC/B,MAAA;AAAA,IACF;AACA,IAAA,IAAI;AACF,MAAA,MAAM,OAAO,MAAM,KAAA,CAAM,EAAE,QAAA,EAAU,eAAA,EAAiB,UAAU,CAAA;AAChE,MAAA,SAAA,CAAU,IAAI,CAAA;AAAA,IAChB,CAAA,CAAA,MAAQ;AAGN,MAAA,YAAA,CAAa,uBAAuB,CAAA;AAAA,IACtC;AAAA,EACF,CAAA,EAAG,CAAC,QAAA,EAAU,QAAA,EAAU,OAAO,SAAA,EAAW,kBAAA,EAAoB,uBAAuB,CAAC,CAAA;AAGtF,EAAA,MAAM,YAAA,GAAe,YAAY,MAAY;AAC3C,IAAA,KAAK,QAAA,EAAS;AAAA,EAChB,CAAA,EAAG,CAAC,QAAQ,CAAC,CAAA;AAEb,EAAA,OAAO,EAAE,WAAW,YAAA,EAAa;AACnC;ACvDO,IAAW,aAAA,qBAAAC,cAAAA,KAAX;AAEL,EAAAA,eAAA,SAAA,CAAA,GAAU,SAAA;AAEV,EAAAA,eAAA,eAAA,CAAA,GAAgB,eAAA;AAEhB,EAAAA,eAAA,iBAAA,CAAA,GAAkB,iBAAA;AANF,EAAA,OAAAA,cAAAA;AAAA,CAAA,EAAA,aAAA,IAAA,EAAA;AA0ClB,IAAM,eAAA,GAAgC,EAAE,IAAA,EAAM,IAAA,EAAM,QAAQ,SAAA,gBAAsB;AAClF,IAAM,YAAA,GAA6B,EAAE,IAAA,EAAM,IAAA,EAAM,QAAQ,iBAAA,wBAA8B;AAEvF,SAAS,QAAQ,KAAA,EAAuB;AACtC,EAAA,OAAO,iBAAiB,KAAA,GAAQ,KAAA,GAAQ,IAAI,KAAA,CAAM,MAAA,CAAO,KAAK,CAAC,CAAA;AACjE;AAOO,SAAS,WAAW,OAAA,EAA8C;AACvE,EAAA,MAAM,EAAE,MAAA,EAAQ,YAAA,GAAe,IAAA,EAAK,GAAI,OAAA;AAExC,EAAA,MAAM,CAAC,OAAA,EAAS,UAAU,CAAA,GAAID,QAAAA;AAAA,IAC5B,eAAe,eAAA,GAAkB;AAAA,GACnC;AACA,EAAA,MAAM,CAAC,YAAA,EAAc,eAAe,CAAA,GAAIA,SAAS,KAAK,CAAA;AACtD,EAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAIA,SAAuB,IAAI,CAAA;AAGrD,EAAA,MAAM,UAAA,GAAa,OAAO,IAAI,CAAA;AAC9B,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,UAAA,CAAW,OAAA,GAAU,IAAA;AACrB,IAAA,OAAO,MAAY;AACjB,MAAA,UAAA,CAAW,OAAA,GAAU,KAAA;AAAA,IACvB,CAAA;AAAA,EACF,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,MAAM,cAAA,GAAiBE,WAAAA,CAAY,CAAC,IAAA,KAAuB;AACzD,IAAA,IAAI,WAAW,OAAA,EAAS;AACtB,MAAA,UAAA,CAAW,IAAI,CAAA;AAAA,IACjB;AAAA,EACF,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,MAAM,OAAA,GAAUA,YAAY,YAA2B;AACrD,IAAA,IAAI;AACF,MAAA,MAAM,IAAA,GAAO,MAAM,MAAA,CAAO,cAAA,EAAe;AACzC,MAAA,cAAA;AAAA,QACE,SAAS,IAAA,GACL,YAAA,GACA,EAAE,IAAA,EAAM,QAAQ,eAAA;AAA4B,OAClD;AAAA,IACF,SAAS,MAAA,EAAQ;AACf,MAAA,cAAA,CAAe,YAAY,CAAA;AAC3B,MAAA,IAAI,WAAW,OAAA,EAAS;AACtB,QAAA,QAAA,CAAS,OAAA,CAAQ,MAAM,CAAC,CAAA;AAAA,MAC1B;AAAA,IACF;AAAA,EACF,CAAA,EAAG,CAAC,MAAA,EAAQ,cAAc,CAAC,CAAA;AAE3B,EAAA,MAAM,KAAA,GAAQA,WAAAA;AAAA,IACZ,OAAO,OAAA,KAA+C;AACpD,MAAA,IAAI,WAAW,OAAA,EAAS;AACtB,QAAA,eAAA,CAAgB,IAAI,CAAA;AACpB,QAAA,QAAA,CAAS,IAAI,CAAA;AAAA,MACf;AACA,MAAA,IAAI;AACF,QAAA,MAAM,IAAA,GAAO,MAAM,MAAA,CAAO,KAAA,CAAM,OAAO,CAAA;AACvC,QAAA,cAAA,CAAe,EAAE,IAAA,EAAM,MAAA,EAAQ,eAAA,sBAA6B,CAAA;AAC5D,QAAA,OAAO,IAAA;AAAA,MACT,SAAS,MAAA,EAAQ;AACf,QAAA,MAAM,GAAA,GAAM,QAAQ,MAAM,CAAA;AAC1B,QAAA,IAAI,WAAW,OAAA,EAAS;AACtB,UAAA,QAAA,CAAS,GAAG,CAAA;AAAA,QACd;AACA,QAAA,MAAM,GAAA;AAAA,MACR,CAAA,SAAE;AACA,QAAA,IAAI,WAAW,OAAA,EAAS;AACtB,UAAA,eAAA,CAAgB,KAAK,CAAA;AAAA,QACvB;AAAA,MACF;AAAA,IACF,CAAA;AAAA,IACA,CAAC,QAAQ,cAAc;AAAA,GACzB;AAEA,EAAA,MAAM,MAAA,GAASA,YAAY,YAA2B;AACpD,IAAA,IAAI,WAAW,OAAA,EAAS;AACtB,MAAA,eAAA,CAAgB,IAAI,CAAA;AACpB,MAAA,QAAA,CAAS,IAAI,CAAA;AAAA,IACf;AACA,IAAA,IAAI;AACF,MAAA,MAAM,OAAO,MAAA,EAAO;AAAA,IACtB,SAAS,MAAA,EAAQ;AAGf,MAAA,IAAI,WAAW,OAAA,EAAS;AACtB,QAAA,QAAA,CAAS,OAAA,CAAQ,MAAM,CAAC,CAAA;AAAA,MAC1B;AAAA,IACF,CAAA,SAAE;AACA,MAAA,cAAA,CAAe,YAAY,CAAA;AAC3B,MAAA,IAAI,WAAW,OAAA,EAAS;AACtB,QAAA,eAAA,CAAgB,KAAK,CAAA;AAAA,MACvB;AAAA,IACF;AAAA,EACF,CAAA,EAAG,CAAC,MAAA,EAAQ,cAAc,CAAC,CAAA;AAG3B,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,YAAA,EAAc;AAChB,MAAA,KAAK,OAAA,EAAQ;AAAA,IACf;AAAA,EAEF,CAAA,EAAG,CAAC,YAAA,EAAc,OAAO,CAAC,CAAA;AAE1B,EAAA,OAAOR,OAAAA;AAAA,IACL,OAAO;AAAA,MACL,MAAM,OAAA,CAAQ,IAAA;AAAA,MACd,QAAQ,OAAA,CAAQ,MAAA;AAAA,MAChB,YAAA;AAAA,MACA,KAAA;AAAA,MACA,KAAA;AAAA,MACA,MAAA;AAAA,MACA;AAAA,KACF,CAAA;AAAA,IACA,CAAC,QAAQ,IAAA,EAAM,OAAA,CAAQ,QAAQ,YAAA,EAAc,KAAA,EAAO,KAAA,EAAO,MAAA,EAAQ,OAAO;AAAA,GAC5E;AACF;ACnJO,SAAS,SAAA,CAAU;AAAA,EACxB,MAAA;AAAA,EACA,KAAA,EAAO,SAAA;AAAA,EACP,MAAA,EAAQ,UAAA;AAAA,EACR,SAAA;AAAA,EACA,gBAAA;AAAA,EACA,QAAA;AAAA,EACA,YAAA;AAAA,EACA,UAAA,GAAa,KAAA;AAAA,EACb,eAAA;AAAA,EACA,eAAA;AAAA,EACA,YAAA;AAAA,EACA;AACF,CAAA,EAA2C;AACzC,EAAA,MAAM,KAAA,GAAQ,aAAa,SAAS,CAAA;AACpC,EAAA,MAAMC,OAAAA,GAAS,cAAc,KAAK,CAAA;AAClC,EAAA,MAAM,MAAA,GAASD,OAAAA;AAAA,IACb,OAAO,EAAE,GAAG,oBAAA,EAAsB,GAAG,UAAA,EAAW,CAAA;AAAA,IAChD,CAAC,UAAU;AAAA,GACb;AAGA,EAAA,MAAM,EAAE,OAAO,YAAA,EAAa,GAAI,WAAW,EAAE,MAAA,EAAQ,YAAA,EAAc,KAAA,EAAO,CAAA;AAI1E,EAAA,MAAM,EAAE,QAAA,EAAU,QAAA,EAAU,WAAA,EAAa,WAAA,KAAgB,eAAA,CAAgB;AAAA,IACvE,eAAA;AAAA,IACA,eAAA;AAAA,IACA,YAAA;AAAA,IACA;AAAA,GACD,CAAA;AAED,EAAA,MAAM,EAAE,SAAA,EAAW,YAAA,EAAa,GAAI,cAAA,CAAe;AAAA,IACjD,QAAA;AAAA,IACA,QAAA;AAAA,IACA,KAAA;AAAA,IACA,SAAA;AAAA,IACA,oBAAoB,MAAA,CAAO,aAAA;AAAA,IAC3B,yBAAyB,MAAA,CAAO;AAAA,GACjC,CAAA;AAED,EAAA,MAAM,OAAA,mBACJS,IAAAA,CAAA,QAAA,EAAA,EACE,QAAA,EAAA;AAAA,oBAAAP,IAACQ,IAAAA,EAAA,EAAK,OAAOT,OAAAA,CAAO,KAAA,EAAQ,iBAAO,KAAA,EAAM,CAAA;AAAA,oBACvCC,IAACQ,IAAAA,EAAA,EAAK,OAAOT,OAAAA,CAAO,QAAA,EAAW,iBAAO,QAAA,EAAS,CAAA;AAAA,oBAE/CQ,IAAAA,CAACE,IAAAA,EAAA,EAAK,KAAA,EAAOV,QAAO,UAAA,EAClB,QAAA,EAAA;AAAA,sBAAAC,IAACQ,IAAAA,EAAA,EAAK,OAAOT,OAAAA,CAAO,KAAA,EAAQ,iBAAO,aAAA,EAAc,CAAA;AAAA,sBACjDC,GAAAA;AAAA,QAAC,SAAA;AAAA,QAAA;AAAA,UACC,mBAAmB,MAAA,CAAO,mBAAA;AAAA,UAC1B,oBAAoB,MAAA,CAAO,aAAA;AAAA,UAC3B,cAAA,EAAe,MAAA;AAAA,UACf,WAAA,EAAa,KAAA;AAAA,UACb,UAAU,CAAC,YAAA;AAAA,UACX,aAAa,MAAA,CAAO,mBAAA;AAAA,UACpB,oBAAA,EAAsB,MAAM,MAAA,CAAO,aAAA;AAAA,UACnC,OAAOD,OAAAA,CAAO,KAAA;AAAA,UACd,MAAA,EAAQ,gBAAA,CAAiB,WAAA,CAAY,kBAAA,EAAoB,YAAY,CAAA;AAAA,UACrE,KAAA,EAAO,QAAA;AAAA,UACP,YAAA,EAAc;AAAA;AAAA;AAChB,KAAA,EACF,CAAA;AAAA,oBAEAQ,IAAAA,CAACE,IAAAA,EAAA,EAAK,KAAA,EAAOV,QAAO,UAAA,EAClB,QAAA,EAAA;AAAA,sBAAAC,IAACQ,IAAAA,EAAA,EAAK,OAAOT,OAAAA,CAAO,KAAA,EAAQ,iBAAO,aAAA,EAAc,CAAA;AAAA,sBACjDC,GAAAA;AAAA,QAAC,SAAA;AAAA,QAAA;AAAA,UACC,eAAA,EAAe,IAAA;AAAA,UACf,mBAAmB,MAAA,CAAO,mBAAA;AAAA,UAC1B,oBAAoB,MAAA,CAAO,aAAA;AAAA,UAC3B,cAAA,EAAe,MAAA;AAAA,UACf,WAAA,EAAa,KAAA;AAAA,UACb,UAAU,CAAC,YAAA;AAAA,UACX,aAAa,MAAA,CAAO,mBAAA;AAAA,UACpB,oBAAA,EAAsB,MAAM,MAAA,CAAO,aAAA;AAAA,UACnC,OAAOD,OAAAA,CAAO,KAAA;AAAA,UACd,MAAA,EAAQ,gBAAA,CAAiB,WAAA,CAAY,kBAAA,EAAoB,YAAY,CAAA;AAAA,UACrE,KAAA,EAAO,QAAA;AAAA,UACP,YAAA,EAAc;AAAA;AAAA;AAChB,KAAA,EACF,CAAA;AAAA,IAEC,SAAA,KAAc,uBACbC,GAAAA;AAAA,MAACQ,IAAAA;AAAA,MAAA;AAAA,QACC,OAAOT,OAAAA,CAAO,SAAA;AAAA,QACd,MAAA,EAAQ,gBAAA,CAAiB,WAAA,CAAY,UAAA,EAAY,YAAY,CAAA;AAAA,QAE5D,QAAA,EAAA;AAAA;AAAA,KACH,GACE,IAAA;AAAA,IAEH,gBAAA,KAAqB,yBACpBC,GAAAA;AAAA,MAAC,gBAAA;AAAA,MAAA;AAAA,QACC,mBAAmB,MAAA,CAAO,cAAA;AAAA,QAC1B,oBAAoB,MAAA,CAAO,cAAA;AAAA,QAC3B,iBAAA,EAAkB,MAAA;AAAA,QAClB,QAAA,EAAU,YAAA;AAAA,QACV,OAAOD,OAAAA,CAAO,UAAA;AAAA,QACd,MAAA,EAAQ,gBAAA,CAAiB,WAAA,CAAY,eAAA,EAAiB,YAAY,CAAA;AAAA,QAClE,OAAA,EAAS,gBAAA;AAAA,QAET,QAAA,kBAAAC,IAACQ,IAAAA,EAAA,EAAK,OAAOT,OAAAA,CAAO,QAAA,EAAW,iBAAO,cAAA,EAAe;AAAA;AAAA,KACvD,GACE,IAAA;AAAA,oBAGJC,GAAAA,CAACS,IAAAA,EAAA,EAAK,KAAA,EAAOV,OAAAA,CAAO,YAClB,QAAA,kBAAAC,GAAAA;AAAA,MAAC,MAAA;AAAA,MAAA;AAAA,QACC,SAAA,EAAS,IAAA;AAAA,QACT,mBAAmB,MAAA,CAAO,MAAA;AAAA,QAC1B,kBAAA,EAAoB,YAAA,GAAe,MAAA,CAAO,UAAA,GAAa,MAAA,CAAO,MAAA;AAAA,QAC9D,OAAO,MAAA,CAAO,MAAA;AAAA,QACd,OAAA,EAAS,YAAA;AAAA,QACT,MAAA,EAAQ,gBAAA,CAAiB,WAAA,CAAY,iBAAA,EAAmB,YAAY,CAAA;AAAA,QACpE,OAAA,EAAS;AAAA;AAAA,KACX,EACF,CAAA;AAAA,IAEC,QAAA,KAAa,yBACZA,GAAAA;AAAA,MAAC,gBAAA;AAAA,MAAA;AAAA,QACC,mBAAmB,MAAA,CAAO,MAAA;AAAA,QAC1B,oBAAoB,MAAA,CAAO,MAAA;AAAA,QAC3B,iBAAA,EAAkB,MAAA;AAAA,QAClB,QAAA,EAAU,YAAA;AAAA,QACV,OAAOD,OAAAA,CAAO,UAAA;AAAA,QACd,MAAA,EAAQ,gBAAA,CAAiB,WAAA,CAAY,eAAA,EAAiB,YAAY,CAAA;AAAA,QAClE,OAAA,EAAS,QAAA;AAAA,QAET,QAAA,kBAAAC,IAACQ,IAAAA,EAAA,EAAK,OAAOT,OAAAA,CAAO,QAAA,EAAW,iBAAO,MAAA,EAAO;AAAA;AAAA,KAC/C,GACE;AAAA,GAAA,EACR,CAAA;AAGF,EAAA,MAAM,uBACJC,GAAAA;AAAA,IAACS,IAAAA;AAAA,IAAA;AAAA,MACC,KAAA,EAAO,UAAA,GAAa,MAAA,GAAYV,OAAAA,CAAO,IAAA;AAAA,MACvC,MAAA,EAAQ,gBAAA,CAAiB,WAAA,CAAY,SAAA,EAAW,YAAY,CAAA;AAAA,MAE3D,QAAA,EAAA;AAAA;AAAA,GACH;AAGF,EAAA,OAAO,UAAA,GAAa,uBAAOC,GAAAA,CAACS,MAAA,EAAK,KAAA,EAAOV,OAAAA,CAAO,MAAA,EAAS,QAAA,EAAA,IAAA,EAAK,CAAA;AAC/D;ACzIO,SAAS,qBACd,OAAA,EAC+D;AAC/D,EAAA,MAAM,EAAE,MAAA,EAAQ,GAAG,IAAA,EAAK,GAAI,OAAA;AAC5B,EAAA,OAAO,WAAA,CAAwD;AAAA,IAC7D,UAAA,EAAY,OAAO,OAAA,KAAY;AAC7B,MAAA,MAAM,MAAA,CAAO,eAAe,OAAO,CAAA;AACnC,MAAA,OAAO,MAAA;AAAA,IACT,CAAA;AAAA,IACA,GAAG;AAAA,GACJ,CAAA;AACH;AAcO,SAAS,oBACd,OAAA,EAC8D;AAC9D,EAAA,MAAM,EAAE,MAAA,EAAQ,GAAG,IAAA,EAAK,GAAI,OAAA;AAC5B,EAAA,OAAO,WAAA,CAAuD;AAAA,IAC5D,UAAA,EAAY,OAAO,OAAA,KAAY;AAC7B,MAAA,MAAM,MAAA,CAAO,cAAc,OAAO,CAAA;AAClC,MAAA,OAAO,MAAA;AAAA,IACT,CAAA;AAAA,IACA,GAAG;AAAA,GACJ,CAAA;AACH;AC/CA,IAAM,WAAA,GAAc,2BAAA;AAsBpB,SAAS,aAAa,KAAA,EAAwB;AAC5C,EAAA,OAAO,WAAA,CAAY,KAAK,KAAK,CAAA;AAC/B;AAGO,SAAS,kBAAA,CAAmB;AAAA,EACjC,MAAA;AAAA,EACA,KAAA,EAAO,SAAA;AAAA,EACP,MAAA,EAAQ,UAAA;AAAA,EACR,gBAAA;AAAA,EACA,SAAA;AAAA,EACA;AACF,CAAA,EAAoD;AAClD,EAAA,MAAM,KAAA,GAAQ,aAAa,SAAS,CAAA;AACpC,EAAA,MAAMA,OAAAA,GAAS,cAAc,KAAK,CAAA;AAClC,EAAA,MAAM,MAAA,GAASD,OAAAA;AAAA,IACb,OAAO,EAAE,GAAG,8BAAA,EAAgC,GAAG,UAAA,EAAW,CAAA;AAAA,IAC1D,CAAC,UAAU;AAAA,GACb;AAEA,EAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAIM,SAAS,EAAE,CAAA;AACrC,EAAA,MAAM,CAAC,SAAA,EAAW,YAAY,CAAA,GAAIA,SAAS,KAAK,CAAA;AAChD,EAAA,MAAM,CAAC,SAAA,EAAW,YAAY,CAAA,GAAIA,SAAwB,IAAI,CAAA;AAE9D,EAAA,MAAM,eAAA,GAAkBN,OAAAA;AAAA,IACtB,OAAO;AAAA,MACL,MAAA;AAAA,MACA,WAAW,MAAY;AACrB,QAAA,YAAA,CAAa,IAAI,CAAA;AACjB,QAAA,SAAA,IAAY;AAAA,MACd,CAAA;AAAA,MACA,SAAS,MAAY;AAGnB,QAAA,YAAA,CAAa,OAAO,YAAY,CAAA;AAAA,MAClC;AAAA,KACF,CAAA;AAAA,IACA,CAAC,MAAA,EAAQ,SAAA,EAAW,MAAA,CAAO,YAAY;AAAA,GACzC;AACA,EAAA,MAAM,QAAA,GAAW,qBAAqB,eAAe,CAAA;AAErD,EAAA,MAAM,SAAA,GAAY,SAAS,MAAA,KAAW,SAAA;AAEtC,EAAA,MAAM,YAAA,GAAeQ,YAAY,MAAY;AAC3C,IAAA,YAAA,CAAa,IAAI,CAAA;AACjB,IAAA,MAAM,YAAA,GAAe,MAAM,IAAA,EAAK;AAChC,IAAA,IAAI,CAAC,YAAA,CAAa,YAAY,CAAA,EAAG;AAC/B,MAAA,YAAA,CAAa,OAAO,YAAY,CAAA;AAChC,MAAA;AAAA,IACF;AACA,IAAA,QAAA,CAAS,MAAA,CAAO,EAAE,KAAA,EAAO,YAAA,EAAc,kBAAkB,CAAA;AAAA,EAC3D,GAAG,CAAC,KAAA,EAAO,UAAU,gBAAA,EAAkB,MAAA,CAAO,YAAY,CAAC,CAAA;AAE3D,EAAA,MAAM,iBAAA,GAAoB,YACtB,CAACP,OAAAA,CAAO,eAAeA,OAAAA,CAAO,qBAAqB,IACnDA,OAAAA,CAAO,aAAA;AAEX,EAAA,uBACEC,GAAAA,CAACS,IAAAA,EAAA,EAAK,KAAA,EAAOV,OAAAA,CAAO,QAClB,QAAA,kBAAAQ,IAAAA;AAAA,IAACE,IAAAA;AAAA,IAAA;AAAA,MACC,OAAOV,OAAAA,CAAO,IAAA;AAAA,MACd,MAAA,EAAQ,gBAAA,CAAiB,WAAA,CAAY,kBAAA,EAAoB,YAAY,CAAA;AAAA,MAErE,QAAA,EAAA;AAAA,wBAAAC,IAACQ,IAAAA,EAAA,EAAK,OAAOT,OAAAA,CAAO,KAAA,EAAQ,iBAAO,KAAA,EAAM,CAAA;AAAA,QAExC,4BACCC,GAAAA;AAAA,UAACQ,IAAAA;AAAA,UAAA;AAAA,YACC,OAAOT,OAAAA,CAAO,WAAA;AAAA,YACd,MAAA,EAAQ,gBAAA,CAAiB,WAAA,CAAY,qBAAA,EAAuB,YAAY,CAAA;AAAA,YAEvE,QAAA,EAAA,MAAA,CAAO;AAAA;AAAA,SACV,mBAEAQ,IAAAA,CAAAG,QAAAA,EAAA,EACE,QAAA,EAAA;AAAA,0BAAAV,IAACQ,IAAAA,EAAA,EAAK,OAAOT,OAAAA,CAAO,QAAA,EAAW,iBAAO,WAAA,EAAY,CAAA;AAAA,0BAElDQ,IAAAA,CAACE,IAAAA,EAAA,EAAK,KAAA,EAAOV,QAAO,UAAA,EAClB,QAAA,EAAA;AAAA,4BAAAC,IAACQ,IAAAA,EAAA,EAAK,OAAOT,OAAAA,CAAO,KAAA,EAAQ,iBAAO,UAAA,EAAW,CAAA;AAAA,4BAC9CC,GAAAA;AAAA,cAACW,SAAAA;AAAA,cAAA;AAAA,gBACC,mBAAmB,MAAA,CAAO,gBAAA;AAAA,gBAC1B,oBAAoB,MAAA,CAAO,UAAA;AAAA,gBAC3B,cAAA,EAAe,MAAA;AAAA,gBACf,WAAA,EAAa,KAAA;AAAA,gBACb,UAAU,CAAC,SAAA;AAAA,gBACX,YAAA,EAAa,eAAA;AAAA,gBACb,aAAa,MAAA,CAAO,gBAAA;AAAA,gBACpB,oBAAA,EAAsB,MAAM,MAAA,CAAO,aAAA;AAAA,gBACnC,OAAOZ,OAAAA,CAAO,KAAA;AAAA,gBACd,MAAA,EAAQ,gBAAA,CAAiB,WAAA,CAAY,wBAAA,EAA0B,YAAY,CAAA;AAAA,gBAC3E,KAAA,EAAO,KAAA;AAAA,gBACP,YAAA,EAAc;AAAA;AAAA;AAChB,WAAA,EACF,CAAA;AAAA,UAEC,SAAA,KAAc,uBACbC,GAAAA;AAAA,YAACQ,IAAAA;AAAA,YAAA;AAAA,cACC,OAAOT,OAAAA,CAAO,SAAA;AAAA,cACd,MAAA,EAAQ,gBAAA,CAAiB,WAAA,CAAY,mBAAA,EAAqB,YAAY,CAAA;AAAA,cAErE,QAAA,EAAA;AAAA;AAAA,WACH,GACE,IAAA;AAAA,0BAEJC,GAAAA;AAAA,YAACY,gBAAAA;AAAA,YAAA;AAAA,cACC,mBAAmB,MAAA,CAAO,MAAA;AAAA,cAC1B,kBAAA,EAAoB,SAAA,GAAY,MAAA,CAAO,UAAA,GAAa,MAAA,CAAO,MAAA;AAAA,cAC3D,iBAAA,EAAkB,QAAA;AAAA,cAClB,QAAA,EAAU,SAAA;AAAA,cACV,KAAA,EAAO,iBAAA;AAAA,cACP,MAAA,EAAQ,gBAAA,CAAiB,WAAA,CAAY,0BAAA,EAA4B,YAAY,CAAA;AAAA,cAC7E,OAAA,EAAS,YAAA;AAAA,cAER,sCACCZ,GAAAA,CAAC,qBAAkB,KAAA,EAAO,KAAA,CAAM,OAAO,SAAA,EAAW,IAAA,EAAK,SAAQ,CAAA,mBAE/DA,IAACQ,IAAAA,EAAA,EAAK,OAAOT,OAAAA,CAAO,iBAAA,EAAoB,iBAAO,MAAA,EAAO;AAAA;AAAA;AAE1D,SAAA,EACF;AAAA;AAAA;AAAA,GAEJ,EACF,CAAA;AAEJ;AChJA,IAAMc,YAAAA,GAAc,2BAAA;AAGb,SAAS,2BAA2B,KAAA,EAAwB;AACjE,EAAA,OAAOA,YAAAA,CAAY,IAAA,CAAK,KAAA,CAAM,IAAA,EAAM,CAAA;AACtC;AAgCO,SAAS,uBAAA,CAAwB;AAAA,EACtC,MAAA;AAAA,EACA,gBAAA;AAAA,EACA;AACF,CAAA,EAA+D;AAC7D,EAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAIT,SAAS,EAAE,CAAA;AACrC,EAAA,MAAM,CAAC,SAAA,EAAW,YAAY,CAAA,GAAIA,SAAS,KAAK,CAAA;AAChD,EAAA,MAAM,CAAC,YAAA,EAAc,eAAe,CAAA,GAAIA,SAAS,KAAK,CAAA;AACtD,EAAA,MAAM,CAAC,eAAA,EAAiB,kBAAkB,CAAA,GAAIA,SAAS,KAAK,CAAA;AAE5D,EAAA,MAAM,SAAA,GAAY,0BAAA,CAA2B,KAAK,CAAA,IAAK,CAAC,YAAA;AAExD,EAAA,MAAM,MAAA,GAASE,YAAY,MAAY;AACrC,IAAA,MAAM,MAAA,GAAS,MAAM,IAAA,EAAK;AAC1B,IAAA,IAAI,CAAC,0BAAA,CAA2B,MAAM,CAAA,IAAK,YAAA,EAAc;AACvD,MAAA;AAAA,IACF;AACA,IAAA,kBAAA,CAAmB,KAAK,CAAA;AACxB,IAAA,eAAA,CAAgB,IAAI,CAAA;AACpB,IAAA,MAAM,OAAA,GAAoC,EAAE,KAAA,EAAO,MAAA,EAAQ,gBAAA,EAAiB;AAC5E,IAAA,MAAA,CACG,cAAA,CAAe,OAAO,CAAA,CACtB,IAAA,CAAK,MAAM;AACV,MAAA,YAAA,CAAa,IAAI,CAAA;AACjB,MAAA,SAAA,IAAY;AAAA,IACd,CAAC,CAAA,CACA,KAAA,CAAM,MAAM,kBAAA,CAAmB,IAAI,CAAC,CAAA,CACpC,OAAA,CAAQ,MAAM,eAAA,CAAgB,KAAK,CAAC,CAAA;AAAA,EACzC,GAAG,CAAC,MAAA,EAAQ,OAAO,YAAA,EAAc,gBAAA,EAAkB,SAAS,CAAC,CAAA;AAE7D,EAAA,MAAM,KAAA,GAAQA,YAAY,MAAY;AACpC,IAAA,QAAA,CAAS,EAAE,CAAA;AACX,IAAA,YAAA,CAAa,KAAK,CAAA;AAClB,IAAA,eAAA,CAAgB,KAAK,CAAA;AACrB,IAAA,kBAAA,CAAmB,KAAK,CAAA;AAAA,EAC1B,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,OAAO;AAAA,IACL,KAAA;AAAA,IACA,QAAA;AAAA,IACA,SAAA;AAAA,IACA,YAAA;AAAA,IACA,eAAA;AAAA,IACA,SAAA;AAAA,IACA,MAAA;AAAA,IACA;AAAA,GACF;AACF;ACtEA,IAAM,sBAAA,GAAyB,CAAA;AAuC/B,SAAS,eAAe,KAAA,EAA+B;AACrD,EAAA,OAAOR,OAAAA;AAAA,IACL,MACEI,WAAW,MAAA,CAAoB;AAAA,MAC7B,IAAA,EAAM,EAAE,OAAA,EAAS,KAAA,CAAM,QAAQ,EAAA,EAAG;AAAA,MAClC,OAAA,EAAS;AAAA,QACP,aAAA,EAAe,KAAA;AAAA,QACf,cAAA,EAAgB,UAAA;AAAA,QAChB,UAAA,EAAY,QAAA;AAAA;AAAA;AAAA,QAGZ,QAAA,EAAU,MAAA;AAAA,QACV,SAAA,EAAW,MAAM,OAAA,CAAQ,EAAA;AAAA,QACzB,GAAA,EAAK,MAAM,OAAA,CAAQ;AAAA,OACrB;AAAA,MACA,eAAA,EAAiB;AAAA,QACf,YAAA,EAAc,MAAM,KAAA,CAAM,KAAA;AAAA,QAC1B,eAAA,EAAiB,MAAM,OAAA,CAAQ,EAAA;AAAA,QAC/B,iBAAA,EAAmB,MAAM,OAAA,CAAQ,EAAA;AAAA;AAAA,QAEjC,UAAA,EAAY,CAAA;AAAA,QACZ,WAAA,EAAa,sBAAA;AAAA,QACb,WAAA,EAAa,MAAM,MAAA,CAAO;AAAA,OAC5B;AAAA,MACA,mBAAA,EAAqB;AAAA,QACnB,QAAA,EAAU,MAAM,UAAA,CAAW,IAAA;AAAA,QAC3B,UAAA,EAAY,KAAA;AAAA,QACZ,KAAA,EAAO,MAAM,MAAA,CAAO;AAAA;AACtB,KACD,CAAA;AAAA,IACH,CAAC,KAAK;AAAA,GACR;AACF;AAGO,SAAS,oBAAA,CAAqB;AAAA,EACnC,MAAA;AAAA,EACA,KAAA,EAAO,SAAA;AAAA,EACP,MAAA,EAAQ,UAAA;AAAA,EACR,gBAAA;AAAA,EACA,OAAA,GAAU,IAAA;AAAA,EACV,SAAA;AAAA,EACA,QAAA;AAAA,EACA,OAAA;AAAA,EACA;AACF,CAAA,EAAsD;AACpD,EAAA,MAAM,KAAA,GAAQ,aAAa,SAAS,CAAA;AACpC,EAAA,MAAMH,OAAAA,GAAS,cAAc,KAAK,CAAA;AAClC,EAAA,MAAM,WAAA,GAAc,eAAe,KAAK,CAAA;AACxC,EAAA,MAAM,MAAA,GAASD,OAAAA;AAAA,IACb,OAAO,EAAE,GAAG,qCAAA,EAAuC,GAAG,UAAA,EAAW,CAAA;AAAA,IACjE,CAAC,UAAU;AAAA,GACb;AAEA,EAAA,MAAM,OAAO,uBAAA,CAAwB,EAAE,MAAA,EAAQ,gBAAA,EAAkB,WAAW,CAAA;AAG5E,EAAA,MAAM,EAAE,OAAM,GAAI,IAAA;AAClB,EAAAgB,UAAU,MAAM;AACd,IAAA,IAAI,CAAC,OAAA,EAAS;AACZ,MAAA,KAAA,EAAM;AAAA,IACR;AAAA,EACF,CAAA,EAAG,CAAC,OAAA,EAAS,KAAK,CAAC,CAAA;AAEnB,EAAA,MAAM,iBAAA,GAAoB,KAAK,SAAA,GAC3Bf,OAAAA,CAAO,gBACP,CAACA,OAAAA,CAAO,aAAA,EAAeA,OAAAA,CAAO,qBAAqB,CAAA;AAEvD,EAAA,MAAM,eAAe,MAAY;AAC/B,IAAA,IAAA,CAAK,KAAA,EAAM;AACX,IAAA,QAAA,IAAW;AAAA,EACb,CAAA;AAEA,EAAA,MAAM,cAAc,MAAY;AAC9B,IAAA,IAAA,CAAK,KAAA,EAAM;AACX,IAAA,OAAA,IAAU;AAAA,EACZ,CAAA;AAEA,EAAA,IAAI,KAAK,SAAA,EAAW;AAClB,IAAA,uBACEQ,IAAAA,CAACE,IAAAA,EAAA,EAAK,KAAA,EAAO,WAAA,CAAY,IAAA,EAAM,MAAA,EAAQ,gBAAA,CAAiB,WAAA,CAAY,kBAAA,EAAoB,YAAY,CAAA,EAClG,QAAA,EAAA;AAAA,sBAAAT,GAAAA,CAACQ,IAAAA,EAAA,EAAK,KAAA,EAAOT,OAAAA,CAAO,WAAA,EAAa,MAAA,EAAQ,gBAAA,CAAiB,WAAA,CAAY,qBAAA,EAAuB,YAAY,CAAA,EACtG,iBAAO,cAAA,EACV,CAAA;AAAA,MACC,OAAA,KAAY,yBACXC,GAAAA,CAACS,MAAA,EAAK,KAAA,EAAO,WAAA,CAAY,OAAA,EACvB,QAAA,kBAAAT,GAAAA;AAAA,QAACY,gBAAAA;AAAA,QAAA;AAAA,UACC,mBAAmB,MAAA,CAAO,KAAA;AAAA,UAC1B,oBAAoB,MAAA,CAAO,KAAA;AAAA,UAC3B,iBAAA,EAAkB,QAAA;AAAA,UAClB,OAAOb,OAAAA,CAAO,aAAA;AAAA,UACd,MAAA,EAAQ,gBAAA,CAAiB,WAAA,CAAY,yBAAA,EAA2B,YAAY,CAAA;AAAA,UAC5E,OAAA,EAAS,WAAA;AAAA,UAET,QAAA,kBAAAC,IAACQ,IAAAA,EAAA,EAAK,OAAOT,OAAAA,CAAO,iBAAA,EAAoB,iBAAO,KAAA,EAAM;AAAA;AAAA,SAEzD,CAAA,GACE;AAAA,KAAA,EACN,CAAA;AAAA,EAEJ;AAEA,EAAA,uBACEQ,IAAAA,CAACE,IAAAA,EAAA,EAAK,KAAA,EAAO,WAAA,CAAY,IAAA,EAAM,MAAA,EAAQ,gBAAA,CAAiB,WAAA,CAAY,kBAAA,EAAoB,YAAY,CAAA,EAClG,QAAA,EAAA;AAAA,oBAAAT,IAACQ,IAAAA,EAAA,EAAK,OAAOT,OAAAA,CAAO,QAAA,EAAW,iBAAO,WAAA,EAAY,CAAA;AAAA,oBAElDQ,IAAAA,CAACE,IAAAA,EAAA,EAAK,KAAA,EAAOV,QAAO,UAAA,EAClB,QAAA,EAAA;AAAA,sBAAAC,IAACQ,IAAAA,EAAA,EAAK,OAAOT,OAAAA,CAAO,KAAA,EAAQ,iBAAO,UAAA,EAAW,CAAA;AAAA,sBAC9CC,GAAAA;AAAA,QAACW,SAAAA;AAAA,QAAA;AAAA,UACC,mBAAmB,MAAA,CAAO,gBAAA;AAAA,UAC1B,oBAAoB,MAAA,CAAO,UAAA;AAAA,UAC3B,cAAA,EAAe,MAAA;AAAA,UACf,WAAA,EAAa,KAAA;AAAA,UACb,QAAA,EAAU,CAAC,IAAA,CAAK,YAAA;AAAA,UAChB,YAAA,EAAa,eAAA;AAAA,UACb,aAAa,MAAA,CAAO,gBAAA;AAAA,UACpB,oBAAA,EAAsB,MAAM,MAAA,CAAO,aAAA;AAAA,UACnC,OAAOZ,OAAAA,CAAO,KAAA;AAAA,UACd,MAAA,EAAQ,gBAAA,CAAiB,WAAA,CAAY,wBAAA,EAA0B,YAAY,CAAA;AAAA,UAC3E,OAAO,IAAA,CAAK,KAAA;AAAA,UACZ,cAAc,IAAA,CAAK;AAAA;AAAA;AACrB,KAAA,EACF,CAAA;AAAA,IAEC,KAAK,eAAA,mBACJC,GAAAA,CAACQ,IAAAA,EAAA,EAAK,KAAA,EAAOT,OAAAA,CAAO,SAAA,EAAW,MAAA,EAAQ,iBAAiB,WAAA,CAAY,mBAAA,EAAqB,YAAY,CAAA,EAClG,QAAA,EAAA,MAAA,CAAO,cACV,CAAA,GACE,IAAA;AAAA,oBAEJQ,IAAAA,CAACE,IAAAA,EAAA,EAAK,KAAA,EAAO,YAAY,OAAA,EACtB,QAAA,EAAA;AAAA,MAAA,QAAA,KAAa,yBACZT,GAAAA;AAAA,QAACY,gBAAAA;AAAA,QAAA;AAAA,UACC,mBAAmB,MAAA,CAAO,MAAA;AAAA,UAC1B,oBAAoB,MAAA,CAAO,MAAA;AAAA,UAC3B,iBAAA,EAAkB,QAAA;AAAA,UAClB,UAAU,IAAA,CAAK,YAAA;AAAA,UACf,OAAO,WAAA,CAAY,eAAA;AAAA,UACnB,MAAA,EAAQ,gBAAA,CAAiB,WAAA,CAAY,0BAAA,EAA4B,YAAY,CAAA;AAAA,UAC7E,OAAA,EAAS,YAAA;AAAA,UAET,QAAA,kBAAAZ,IAACQ,IAAAA,EAAA,EAAK,OAAO,WAAA,CAAY,mBAAA,EAAsB,iBAAO,MAAA,EAAO;AAAA;AAAA,OAC/D,GACE,IAAA;AAAA,sBAEJR,GAAAA;AAAA,QAACY,gBAAAA;AAAA,QAAA;AAAA,UACC,mBAAmB,MAAA,CAAO,MAAA;AAAA,UAC1B,kBAAA,EAAoB,IAAA,CAAK,YAAA,GAAe,MAAA,CAAO,aAAa,MAAA,CAAO,MAAA;AAAA,UACnE,iBAAA,EAAkB,QAAA;AAAA,UAClB,QAAA,EAAU,CAAC,IAAA,CAAK,SAAA;AAAA,UAChB,KAAA,EAAO,iBAAA;AAAA,UACP,MAAA,EAAQ,gBAAA,CAAiB,WAAA,CAAY,0BAAA,EAA4B,YAAY,CAAA;AAAA,UAC7E,SAAS,IAAA,CAAK,MAAA;AAAA,UAEb,QAAA,EAAA,IAAA,CAAK,+BACJZ,GAAAA,CAACe,mBAAA,EAAkB,KAAA,EAAO,MAAM,MAAA,CAAO,SAAA,EAAW,MAAK,OAAA,EAAQ,CAAA,mBAE/Df,GAAAA,CAACQ,IAAAA,EAAA,EAAK,KAAA,EAAOT,OAAAA,CAAO,iBAAA,EAAoB,QAAA,EAAA,MAAA,CAAO,MAAA,EAAO;AAAA;AAAA;AAE1D,KAAA,EACF;AAAA,GAAA,EACF,CAAA;AAEJ;;;AC/OO,IAAW,kBAAA,qBAAAiB,mBAAAA,KAAX;AAEL,EAAAA,oBAAA,OAAA,CAAA,GAAQ,OAAA;AAER,EAAAA,oBAAA,cAAA,CAAA,GAAe,cAAA;AAEf,EAAAA,oBAAA,UAAA,CAAA,GAAW,UAAA;AAEX,EAAAA,oBAAA,cAAA,CAAA,GAAe,cAAA;AAEf,EAAAA,oBAAA,SAAA,CAAA,GAAU,SAAA;AAVM,EAAA,OAAAA,mBAAAA;AAAA,CAAA,EAAA,kBAAA,IAAA,EAAA;;;ACDX,IAAW,mBAAA,qBAAAC,oBAAAA,KAAX;AAEL,EAAAA,qBAAA,UAAA,CAAA,GAAW,UAAA;AAEX,EAAAA,qBAAA,SAAA,CAAA,GAAU,SAAA;AAEV,EAAAA,qBAAA,kBAAA,CAAA,GAAmB,kBAAA;AAEnB,EAAAA,qBAAA,kBAAA,CAAA,GAAmB,kBAAA;AAEnB,EAAAA,qBAAA,cAAA,CAAA,GAAe,cAAA;AAVC,EAAA,OAAAA,oBAAAA;AAAA,CAAA,EAAA,mBAAA,IAAA,EAAA;;;ACSlB,IAAM,eAAA,GAAkB,OAAA;AACxB,IAAM,eAAA,GAAkB,OAAA;AACxB,IAAM,WAAA,GAAc,IAAA;AAGb,IAAM,mBAAA,GAAsB;AAE5B,IAAM,mBAAA,GAAsB;AAM5B,SAAS,uBAAuB,QAAA,EAAyC;AAC9E,EAAA,MAAM,SAAgC,EAAC;AACvC,EAAA,IAAI,QAAA,CAAS,SAAS,mBAAA,EAAqB;AACzC,IAAA,MAAA,CAAO,IAAA,CAAA,UAAA,gBAAiC;AAAA,EAC1C;AACA,EAAA,IAAI,QAAA,CAAS,SAAS,mBAAA,EAAqB;AACzC,IAAA,MAAA,CAAO,IAAA,CAAA,SAAA,eAAgC;AAAA,EACzC;AACA,EAAA,IAAI,CAAC,eAAA,CAAgB,IAAA,CAAK,QAAQ,CAAA,EAAG;AACnC,IAAA,MAAA,CAAO,IAAA,CAAA,kBAAA,wBAAyC;AAAA,EAClD;AACA,EAAA,IAAI,CAAC,eAAA,CAAgB,IAAA,CAAK,QAAQ,CAAA,EAAG;AACnC,IAAA,MAAA,CAAO,IAAA,CAAA,kBAAA,wBAAyC;AAAA,EAClD;AACA,EAAA,IAAI,CAAC,WAAA,CAAY,IAAA,CAAK,QAAQ,CAAA,EAAG;AAC/B,IAAA,MAAA,CAAO,IAAA,CAAA,cAAA,oBAAqC;AAAA,EAC9C;AACA,EAAA,OAAO,MAAA;AACT;AAGO,SAAS,gBAAgB,QAAA,EAA2B;AACzD,EAAA,OAAO,sBAAA,CAAuB,QAAQ,CAAA,CAAE,MAAA,KAAW,CAAA;AACrD;;;ACxBA,IAAM,gBAAA,GAAmB,GAAA;AA2BzB,SAAS,iBAAA,CAAkB,SAAiB,MAAA,EAAyB;AACnE,EAAA,OAAO,QAAQ,QAAA,CAAS,CAAA,QAAA,EAAW,MAAA,CAAO,MAAM,CAAC,CAAA,CAAE,CAAA;AACrD;AAGA,SAAS,UAAU,IAAA,EAIW;AAC5B,EAAA,IAAI,KAAK,WAAA,CAAY,MAAA,KAAW,KAAK,IAAA,CAAK,OAAA,CAAQ,WAAW,CAAA,EAAG;AAC9D,IAAA,OAAA,OAAA;AAAA,EACF;AACA,EAAA,IAAI,CAAC,eAAA,CAAgB,IAAA,CAAK,WAAW,CAAA,EAAG;AACtC,IAAA,OAAA,cAAA;AAAA,EACF;AACA,EAAA,IAAI,IAAA,CAAK,WAAA,KAAgB,IAAA,CAAK,OAAA,EAAS;AACrC,IAAA,OAAA,UAAA;AAAA,EACF;AACA,EAAA,IAAI,IAAA,CAAK,UAAU,EAAA,EAAI;AACrB,IAAA,OAAA,cAAA;AAAA,EACF;AACA,EAAA,OAAO,IAAA;AACT;AASA,SAAS,gBAAA,CACP,QACA,SAAA,EACwC;AACxC,EAAA,MAAM,eAAA,GAAkBnB,OAAAA;AAAA,IACtB,OAAO;AAAA,MACL,MAAA;AAAA,MACA,WAAW,SAAA,CAAU,SAAA;AAAA,MACrB,OAAA,EAAS,CAAC,GAAA,KAAqB;AAC7B,QAAA,IAAI,iBAAA,CAAkB,GAAA,CAAI,OAAA,EAAS,gBAAgB,CAAA,EAAG;AACpD,UAAA,SAAA,CAAU,mBAAmB,IAAI,CAAA;AACjC,UAAA,SAAA,CAAU,WAAA,CAAA,cAAA,oBAA2C;AACrD,UAAA;AAAA,QACF;AACA,QAAA,SAAA,CAAU,WAAA,CAAA,SAAA,eAAsC;AAAA,MAClD;AAAA,KACF,CAAA;AAAA,IACA,CAAC,QAAQ,SAAS;AAAA,GACpB;AACA,EAAA,OAAO,oBAAoB,eAAe,CAAA;AAC5C;AAYA,SAAS,UAAU,IAAA,EAAwB;AACzC,EAAA,IAAA,CAAK,YAAY,IAAI,CAAA;AACrB,EAAA,MAAM,UAAU,SAAA,CAAU;AAAA,IACxB,aAAa,IAAA,CAAK,WAAA;AAAA,IAClB,SAAS,IAAA,CAAK,eAAA;AAAA,IACd,OAAO,IAAA,CAAK;AAAA,GACb,CAAA;AACD,EAAA,IAAI,YAAY,IAAA,EAAM;AACpB,IAAA,IAAA,CAAK,MAAA,CAAO,EAAE,KAAA,EAAO,IAAA,CAAK,OAAO,WAAA,EAAa,IAAA,CAAK,aAAa,CAAA;AAChE,IAAA;AAAA,EACF;AACA,EAAA,IAAI,OAAA,KAAA,cAAA,qBAA6C;AAC/C,IAAA,IAAA,CAAK,mBAAmB,IAAI,CAAA;AAAA,EAC9B;AACA,EAAA,IAAA,CAAK,YAAY,OAAO,CAAA;AAC1B;AAiBA,SAAS,YAAA,GAA2D;AAClE,EAAA,MAAM,CAAC,WAAA,EAAa,cAAc,CAAA,GAAIM,SAAS,EAAE,CAAA;AACjD,EAAA,MAAM,CAAC,eAAA,EAAiB,kBAAkB,CAAA,GAAIA,SAAS,EAAE,CAAA;AACzD,EAAA,MAAM,CAAC,QAAA,EAAU,WAAW,CAAA,GAAIA,SAAoC,IAAI,CAAA;AACxE,EAAA,MAAM,CAAC,eAAA,EAAiB,kBAAkB,CAAA,GAAIA,SAAS,KAAK,CAAA;AAC5D,EAAA,OAAO;AAAA,IACL,KAAA,EAAO,EAAE,WAAA,EAAa,eAAA,EAAiB,UAAU,eAAA,EAAgB;AAAA,IACjE,OAAA,EAAS,EAAE,cAAA,EAAgB,kBAAA,EAAoB,aAAa,kBAAA;AAAmB,GACjF;AACF;AAMO,SAAS,oBAAA,CAAqB;AAAA,EACnC,MAAA;AAAA,EACA,KAAA;AAAA,EACA;AACF,CAAA,EAAyD;AACvD,EAAA,MAAM,EAAE,KAAA,EAAO,OAAA,EAAQ,GAAI,YAAA,EAAa;AACxC,EAAA,MAAM,SAAA,GAAYN,OAAAA;AAAA,IAChB,OAAO;AAAA,MACL,SAAA;AAAA,MACA,aAAa,OAAA,CAAQ,WAAA;AAAA,MACrB,oBAAoB,OAAA,CAAQ;AAAA,KAC9B,CAAA;AAAA,IACA,CAAC,SAAA,EAAW,OAAA,CAAQ,WAAA,EAAa,QAAQ,kBAAkB;AAAA,GAC7D;AACA,EAAA,MAAM,QAAA,GAAW,gBAAA,CAAiB,MAAA,EAAQ,SAAS,CAAA;AACnD,EAAA,MAAM,MAAA,GAAS,MACb,SAAA,CAAU;AAAA,IACR,aAAa,KAAA,CAAM,WAAA;AAAA,IACnB,iBAAiB,KAAA,CAAM,eAAA;AAAA,IACvB,KAAA;AAAA,IACA,aAAa,OAAA,CAAQ,WAAA;AAAA,IACrB,oBAAoB,OAAA,CAAQ,kBAAA;AAAA,IAC5B,QAAQ,QAAA,CAAS;AAAA,GAClB,CAAA;AACH,EAAA,OAAO;AAAA,IACL,aAAa,KAAA,CAAM,WAAA;AAAA,IACnB,iBAAiB,KAAA,CAAM,eAAA;AAAA,IACvB,gBAAgB,OAAA,CAAQ,cAAA;AAAA,IACxB,oBAAoB,OAAA,CAAQ,kBAAA;AAAA,IAC5B,YAAA,EAAc,SAAS,MAAA,KAAW,SAAA;AAAA,IAClC,UAAU,KAAA,CAAM,QAAA;AAAA,IAChB,iBAAiB,KAAA,CAAM,eAAA;AAAA,IACvB;AAAA,GACF;AACF;AC7JA,SAAS,YAAA,CACP,UACA,MAAA,EACe;AACf,EAAA,QAAQ,QAAA;AAAU,IAChB,KAAA,OAAA;AACE,MAAA,OAAO,MAAA,CAAO,UAAA;AAAA,IAChB,KAAA,cAAA;AACE,MAAA,OAAO,MAAA,CAAO,iBAAA;AAAA,IAChB,KAAA,UAAA;AACE,MAAA,OAAO,MAAA,CAAO,aAAA;AAAA,IAChB,KAAA,cAAA;AACE,MAAA,OAAO,MAAA,CAAO,iBAAA;AAAA,IAChB,KAAA,SAAA;AACE,MAAA,OAAO,MAAA,CAAO,YAAA;AAAA,IAChB;AACE,MAAA,OAAO,IAAA;AAAA;AAEb;AAGO,SAAS,iBAAA,CAAkB;AAAA,EAChC,MAAA;AAAA,EACA,KAAA;AAAA,EACA,KAAA,EAAO,SAAA;AAAA,EACP,MAAA,EAAQ,UAAA;AAAA,EACR,SAAA;AAAA,EACA;AACF,CAAA,EAAmD;AACjD,EAAA,MAAM,KAAA,GAAQ,aAAa,SAAS,CAAA;AACpC,EAAA,MAAMC,OAAAA,GAAS,cAAc,KAAK,CAAA;AAClC,EAAA,MAAM,MAAA,GAASD,OAAAA;AAAA,IACb,OAAO,EAAE,GAAG,6BAAA,EAA+B,GAAG,UAAA,EAAW,CAAA;AAAA,IACzD,CAAC,UAAU;AAAA,GACb;AAEA,EAAA,MAAM,OAAO,oBAAA,CAAqB,EAAE,MAAA,EAAQ,KAAA,EAAO,WAAW,CAAA;AAC9D,EAAA,MAAM,OAAA,GAAU,YAAA,CAAa,IAAA,CAAK,QAAA,EAAU,MAAM,CAAA;AAElD,EAAA,MAAM,iBAAA,GAAoB,KAAK,YAAA,GAC3B,CAACC,QAAO,aAAA,EAAeA,OAAAA,CAAO,qBAAqB,CAAA,GACnDA,OAAAA,CAAO,aAAA;AAEX,EAAA,uBACEC,GAAAA,CAACS,IAAAA,EAAA,EAAK,KAAA,EAAOV,OAAAA,CAAO,QAClB,QAAA,kBAAAQ,IAAAA;AAAA,IAACE,IAAAA;AAAA,IAAA;AAAA,MACC,OAAOV,OAAAA,CAAO,IAAA;AAAA,MACd,MAAA,EAAQ,gBAAA,CAAiB,WAAA,CAAY,iBAAA,EAAmB,YAAY,CAAA;AAAA,MAEpE,QAAA,EAAA;AAAA,wBAAAC,IAACQ,IAAAA,EAAA,EAAK,OAAOT,OAAAA,CAAO,KAAA,EAAQ,iBAAO,KAAA,EAAM,CAAA;AAAA,wBACzCC,IAACQ,IAAAA,EAAA,EAAK,OAAOT,OAAAA,CAAO,QAAA,EAAW,iBAAO,WAAA,EAAY,CAAA;AAAA,wBAElDQ,IAAAA,CAACE,IAAAA,EAAA,EAAK,KAAA,EAAOV,QAAO,UAAA,EAClB,QAAA,EAAA;AAAA,0BAAAC,IAACQ,IAAAA,EAAA,EAAK,OAAOT,OAAAA,CAAO,KAAA,EAAQ,iBAAO,gBAAA,EAAiB,CAAA;AAAA,0BACpDC,GAAAA;AAAA,YAACW,SAAAA;AAAA,YAAA;AAAA,cACC,eAAA,EAAe,IAAA;AAAA,cACf,mBAAmB,MAAA,CAAO,sBAAA;AAAA,cAC1B,oBAAoB,MAAA,CAAO,gBAAA;AAAA,cAC3B,cAAA,EAAe,MAAA;AAAA,cACf,WAAA,EAAa,KAAA;AAAA,cACb,QAAA,EAAU,CAAC,IAAA,CAAK,YAAA;AAAA,cAChB,aAAa,MAAA,CAAO,sBAAA;AAAA,cACpB,oBAAA,EAAsB,MAAM,MAAA,CAAO,aAAA;AAAA,cACnC,OAAOZ,OAAAA,CAAO,KAAA;AAAA,cACd,MAAA,EAAQ,gBAAA,CAAiB,WAAA,CAAY,qBAAA,EAAuB,YAAY,CAAA;AAAA,cACxE,OAAO,IAAA,CAAK,WAAA;AAAA,cACZ,cAAc,IAAA,CAAK;AAAA;AAAA;AACrB,SAAA,EACF,CAAA;AAAA,wBAEAQ,IAAAA,CAACE,IAAAA,EAAA,EAAK,KAAA,EAAOV,QAAO,UAAA,EAClB,QAAA,EAAA;AAAA,0BAAAC,IAACQ,IAAAA,EAAA,EAAK,OAAOT,OAAAA,CAAO,KAAA,EAAQ,iBAAO,oBAAA,EAAqB,CAAA;AAAA,0BACxDC,GAAAA;AAAA,YAACW,SAAAA;AAAA,YAAA;AAAA,cACC,eAAA,EAAe,IAAA;AAAA,cACf,mBAAmB,MAAA,CAAO,0BAAA;AAAA,cAC1B,oBAAoB,MAAA,CAAO,oBAAA;AAAA,cAC3B,cAAA,EAAe,MAAA;AAAA,cACf,WAAA,EAAa,KAAA;AAAA,cACb,QAAA,EAAU,CAAC,IAAA,CAAK,YAAA;AAAA,cAChB,aAAa,MAAA,CAAO,0BAAA;AAAA,cACpB,oBAAA,EAAsB,MAAM,MAAA,CAAO,aAAA;AAAA,cACnC,OAAOZ,OAAAA,CAAO,KAAA;AAAA,cACd,MAAA,EAAQ,gBAAA,CAAiB,WAAA,CAAY,yBAAA,EAA2B,YAAY,CAAA;AAAA,cAC5E,OAAO,IAAA,CAAK,eAAA;AAAA,cACZ,cAAc,IAAA,CAAK;AAAA;AAAA;AACrB,SAAA,EACF,CAAA;AAAA,QAEC,OAAA,KAAY,uBACXC,GAAAA;AAAA,UAACQ,IAAAA;AAAA,UAAA;AAAA,YACC,OAAOT,OAAAA,CAAO,SAAA;AAAA,YACd,MAAA,EAAQ,gBAAA,CAAiB,WAAA,CAAY,kBAAA,EAAoB,YAAY,CAAA;AAAA,YAEpE,QAAA,EAAA;AAAA;AAAA,SACH,GACE,IAAA;AAAA,wBAEJC,GAAAA;AAAA,UAACY,gBAAAA;AAAA,UAAA;AAAA,YACC,mBAAmB,MAAA,CAAO,MAAA;AAAA,YAC1B,kBAAA,EAAoB,IAAA,CAAK,YAAA,GAAe,MAAA,CAAO,aAAa,MAAA,CAAO,MAAA;AAAA,YACnE,iBAAA,EAAkB,QAAA;AAAA,YAClB,UAAU,IAAA,CAAK,YAAA;AAAA,YACf,KAAA,EAAO,iBAAA;AAAA,YACP,MAAA,EAAQ,gBAAA,CAAiB,WAAA,CAAY,yBAAA,EAA2B,YAAY,CAAA;AAAA,YAC5E,SAAS,IAAA,CAAK,MAAA;AAAA,YAEb,QAAA,EAAA,IAAA,CAAK,+BACJZ,GAAAA,CAACe,mBAAA,EAAkB,KAAA,EAAO,MAAM,MAAA,CAAO,SAAA,EAAW,MAAK,OAAA,EAAQ,CAAA,mBAE/Df,GAAAA,CAACQ,IAAAA,EAAA,EAAK,KAAA,EAAOT,OAAAA,CAAO,iBAAA,EAAoB,QAAA,EAAA,MAAA,CAAO,MAAA,EAAO;AAAA;AAAA;AAE1D;AAAA;AAAA,GACF,EACF,CAAA;AAEJ;AC9HO,SAAS,cAAA,CAAe;AAAA,EAC7B,MAAA,EAAAA,OAAAA;AAAA,EACA,KAAA;AAAA,EACA,MAAA;AAAA,EACA,YAAA;AAAA,EACA,YAAA;AAAA,EACA,SAAA;AAAA,EACA;AACF,CAAA,EAAgD;AAC9C,EAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAIK,SAAS,EAAE,CAAA;AACrC,EAAA,MAAM,WAAA,GAAc,eAChB,CAACL,OAAAA,CAAO,eAAeA,OAAAA,CAAO,qBAAqB,IACnDA,OAAAA,CAAO,aAAA;AAEX,EAAA,uBACEQ,IAAAA,CAAAG,QAAAA,EAAA,EACE,QAAA,EAAA;AAAA,oBAAAV,IAACQ,IAAAA,EAAA,EAAK,OAAOT,OAAAA,CAAO,KAAA,EAAQ,iBAAO,YAAA,EAAa,CAAA;AAAA,oBAChDC,IAACQ,IAAAA,EAAA,EAAK,OAAOT,OAAAA,CAAO,QAAA,EAAW,iBAAO,kBAAA,EAAmB,CAAA;AAAA,oBAEzDQ,IAAAA,CAACE,IAAAA,EAAA,EAAK,KAAA,EAAOV,QAAO,UAAA,EAClB,QAAA,EAAA;AAAA,sBAAAC,IAACQ,IAAAA,EAAA,EAAK,OAAOT,OAAAA,CAAO,KAAA,EAAQ,iBAAO,UAAA,EAAW,CAAA;AAAA,sBAC9CC,GAAAA;AAAA,QAACW,SAAAA;AAAA,QAAA;AAAA,UACC,mBAAmB,MAAA,CAAO,gBAAA;AAAA,UAC1B,oBAAoB,MAAA,CAAO,UAAA;AAAA,UAC3B,cAAA,EAAe,MAAA;AAAA,UACf,WAAA,EAAa,KAAA;AAAA,UACb,UAAU,CAAC,YAAA;AAAA,UACX,YAAA,EAAa,eAAA;AAAA,UACb,aAAa,MAAA,CAAO,gBAAA;AAAA,UACpB,oBAAA,EAAsB,MAAM,MAAA,CAAO,aAAA;AAAA,UACnC,OAAOZ,OAAAA,CAAO,KAAA;AAAA,UACd,MAAA,EAAQ,gBAAA,CAAiB,WAAA,CAAY,aAAA,EAAe,YAAY,CAAA;AAAA,UAChE,KAAA,EAAO,KAAA;AAAA,UACP,YAAA,EAAc;AAAA;AAAA;AAChB,KAAA,EACF,CAAA;AAAA,IAEC,cAAc,IAAA,mBACbC,GAAAA,CAACQ,IAAAA,EAAA,EAAK,KAAA,EAAOT,OAAAA,CAAO,SAAA,EAAW,MAAA,EAAQ,iBAAiB,WAAA,CAAY,QAAA,EAAU,YAAY,CAAA,EACvF,qBACH,CAAA,GACE,IAAA;AAAA,oBAEJC,GAAAA;AAAA,MAACY,gBAAAA;AAAA,MAAA;AAAA,QACC,mBAAmB,MAAA,CAAO,aAAA;AAAA,QAC1B,kBAAA,EAAoB,YAAA,GAAe,MAAA,CAAO,UAAA,GAAa,MAAA,CAAO,aAAA;AAAA,QAC9D,iBAAA,EAAkB,QAAA;AAAA,QAClB,QAAA,EAAU,YAAA;AAAA,QACV,KAAA,EAAO,WAAA;AAAA,QACP,MAAA,EAAQ,gBAAA,CAAiB,WAAA,CAAY,gBAAA,EAAkB,YAAY,CAAA;AAAA,QACnE,OAAA,EAAS,MAAY,QAAA,CAAS,KAAA,CAAM,MAAM,CAAA;AAAA,QAEzC,QAAA,EAAA,YAAA,mBACCZ,GAAAA,CAACe,iBAAAA,EAAA,EAAkB,KAAA,EAAO,KAAA,CAAM,OAAO,SAAA,EAAW,IAAA,EAAK,SAAQ,CAAA,mBAE/Df,IAACQ,IAAAA,EAAA,EAAK,OAAOT,OAAAA,CAAO,iBAAA,EAAoB,iBAAO,aAAA,EAAc;AAAA;AAAA;AAEjE,GAAA,EACF,CAAA;AAEJ;AAoBO,SAAS,aAAA,CAAc;AAAA,EAC5B,MAAA,EAAAA,OAAAA;AAAA,EACA,KAAA;AAAA,EACA,MAAA;AAAA,EACA,YAAA;AAAA,EACA,UAAA;AAAA,EACA,YAAA;AAAA,EACA,SAAA;AAAA,EACA,QAAA;AAAA,EACA,QAAA;AAAA,EACA;AACF,CAAA,EAA+C;AAC7C,EAAA,MAAM,CAAC,IAAA,EAAM,OAAO,CAAA,GAAIK,SAAS,EAAE,CAAA;AACnC,EAAA,MAAM,WAAA,GAAc,eAChB,CAACL,OAAAA,CAAO,eAAeA,OAAAA,CAAO,qBAAqB,IACnDA,OAAAA,CAAO,aAAA;AACX,EAAA,MAAM,WAAA,GAAc,MAAA,CAAO,iBAAA,CAAkB,OAAA,CAAQ,gBAAgB,UAAU,CAAA;AAE/E,EAAA,uBACEQ,IAAAA,CAAAG,QAAAA,EAAA,EACE,QAAA,EAAA;AAAA,oBAAAV,IAACQ,IAAAA,EAAA,EAAK,OAAOT,OAAAA,CAAO,KAAA,EAAQ,iBAAO,WAAA,EAAY,CAAA;AAAA,oBAC/CC,GAAAA,CAACQ,IAAAA,EAAA,EAAK,KAAA,EAAOT,OAAAA,CAAO,UAAW,QAAA,EAAA,WAAA,EAAY,CAAA;AAAA,oBAE3CQ,IAAAA,CAACE,IAAAA,EAAA,EAAK,KAAA,EAAOV,QAAO,UAAA,EAClB,QAAA,EAAA;AAAA,sBAAAC,IAACQ,IAAAA,EAAA,EAAK,OAAOT,OAAAA,CAAO,KAAA,EAAQ,iBAAO,SAAA,EAAU,CAAA;AAAA,sBAC7CC,GAAAA;AAAA,QAACW,SAAAA;AAAA,QAAA;AAAA,UACC,mBAAmB,MAAA,CAAO,eAAA;AAAA,UAC1B,oBAAoB,MAAA,CAAO,SAAA;AAAA,UAC3B,cAAA,EAAe,MAAA;AAAA,UACf,WAAA,EAAa,KAAA;AAAA,UACb,UAAU,CAAC,YAAA;AAAA,UACX,YAAA,EAAa,YAAA;AAAA,UACb,aAAa,MAAA,CAAO,eAAA;AAAA,UACpB,oBAAA,EAAsB,MAAM,MAAA,CAAO,aAAA;AAAA,UACnC,OAAOZ,OAAAA,CAAO,KAAA;AAAA,UACd,MAAA,EAAQ,gBAAA,CAAiB,WAAA,CAAY,YAAA,EAAc,YAAY,CAAA;AAAA,UAC/D,KAAA,EAAO,IAAA;AAAA,UACP,YAAA,EAAc;AAAA;AAAA;AAChB,KAAA,EACF,CAAA;AAAA,IAEC,cAAc,IAAA,mBACbC,GAAAA,CAACQ,IAAAA,EAAA,EAAK,KAAA,EAAOT,OAAAA,CAAO,SAAA,EAAW,MAAA,EAAQ,iBAAiB,WAAA,CAAY,QAAA,EAAU,YAAY,CAAA,EACvF,qBACH,CAAA,GACE,IAAA;AAAA,oBAEJC,GAAAA;AAAA,MAACY,gBAAAA;AAAA,MAAA;AAAA,QACC,mBAAmB,MAAA,CAAO,YAAA;AAAA,QAC1B,kBAAA,EAAoB,YAAA,GAAe,MAAA,CAAO,SAAA,GAAY,MAAA,CAAO,YAAA;AAAA,QAC7D,iBAAA,EAAkB,QAAA;AAAA,QAClB,QAAA,EAAU,YAAA;AAAA,QACV,KAAA,EAAO,WAAA;AAAA,QACP,MAAA,EAAQ,gBAAA,CAAiB,WAAA,CAAY,eAAA,EAAiB,YAAY,CAAA;AAAA,QAClE,OAAA,EAAS,MAAY,QAAA,CAAS,IAAA,CAAK,MAAM,CAAA;AAAA,QAExC,QAAA,EAAA,YAAA,mBACCZ,GAAAA,CAACe,iBAAAA,EAAA,EAAkB,KAAA,EAAO,KAAA,CAAM,OAAO,SAAA,EAAW,IAAA,EAAK,SAAQ,CAAA,mBAE/Df,IAACQ,IAAAA,EAAA,EAAK,OAAOT,OAAAA,CAAO,iBAAA,EAAoB,iBAAO,YAAA,EAAa;AAAA;AAAA,KAEhE;AAAA,oBAEAC,GAAAA;AAAA,MAACY,gBAAAA;AAAA,MAAA;AAAA,QACC,mBAAmB,MAAA,CAAO,MAAA;AAAA,QAC1B,kBAAA,EAAoB,YAAA,GAAe,MAAA,CAAO,SAAA,GAAY,MAAA,CAAO,MAAA;AAAA,QAC7D,iBAAA,EAAkB,MAAA;AAAA,QAClB,QAAA,EAAU,YAAA;AAAA,QACV,OAAOb,OAAAA,CAAO,UAAA;AAAA,QACd,MAAA,EAAQ,gBAAA,CAAiB,WAAA,CAAY,eAAA,EAAiB,YAAY,CAAA;AAAA,QAClE,OAAA,EAAS,QAAA;AAAA,QAET,QAAA,kBAAAC,GAAAA,CAACQ,IAAAA,EAAA,EAAK,KAAA,EAAOT,OAAAA,CAAO,QAAA,EAAW,QAAA,EAAA,YAAA,GAAe,MAAA,CAAO,SAAA,GAAY,MAAA,CAAO,MAAA,EAAO;AAAA;AAAA,KACjF;AAAA,oBAEAC,GAAAA;AAAA,MAACY,gBAAAA;AAAA,MAAA;AAAA,QACC,mBAAmB,MAAA,CAAO,WAAA;AAAA,QAC1B,oBAAoB,MAAA,CAAO,WAAA;AAAA,QAC3B,iBAAA,EAAkB,MAAA;AAAA,QAClB,QAAA,EAAU,YAAA;AAAA,QACV,MAAA,EAAQ,gBAAA,CAAiB,WAAA,CAAY,oBAAA,EAAsB,YAAY,CAAA;AAAA,QACvE,OAAA,EAAS,aAAA;AAAA,QAET,QAAA,kBAAAZ,IAACQ,IAAAA,EAAA,EAAK,OAAOT,OAAAA,CAAO,QAAA,EAAW,iBAAO,WAAA,EAAY;AAAA;AAAA;AACpD,GAAA,EACF,CAAA;AAEJ;;;AC9LO,IAAW,YAAA,qBAAAmB,aAAAA,KAAX;AAEL,EAAAA,cAAA,aAAA,CAAA,GAAc,aAAA;AAEd,EAAAA,cAAA,WAAA,CAAA,GAAY,WAAA;AAJI,EAAA,OAAAA,aAAAA;AAAA,CAAA,EAAA,YAAA,IAAA,EAAA;ACgElB,SAASC,SAAQ,KAAA,EAAuB;AACtC,EAAA,OAAO,iBAAiB,KAAA,GAAQ,KAAA,GAAQ,IAAI,KAAA,CAAM,MAAA,CAAO,KAAK,CAAC,CAAA;AACjE;AASA,IAAM,YAAA,GAA0B;AAAA,EAC9B,IAAA,EAAA,aAAA;AAAA,EACA,UAAA,EAAY,EAAA;AAAA,EACZ,WAAA,EAAa;AACf,CAAA;AAOO,SAAS,YAAY,OAAA,EAAgD;AAC1E,EAAA,MAAM,EAAE,QAAO,GAAI,OAAA;AAEnB,EAAA,MAAM,CAAC,IAAA,EAAM,OAAO,CAAA,GAAIf,SAAoB,YAAY,CAAA;AACxD,EAAA,MAAM,CAAC,YAAA,EAAc,eAAe,CAAA,GAAIA,SAAS,KAAK,CAAA;AACtD,EAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAIA,SAAuB,IAAI,CAAA;AAGrD,EAAA,MAAM,UAAA,GAAagB,OAAO,IAAI,CAAA;AAC9B,EAAAN,UAAU,MAAM;AACd,IAAA,UAAA,CAAW,OAAA,GAAU,IAAA;AACrB,IAAA,OAAO,MAAY;AACjB,MAAA,UAAA,CAAW,OAAA,GAAU,KAAA;AAAA,IACvB,CAAA;AAAA,EACF,CAAA,EAAG,EAAE,CAAA;AAIL,EAAA,MAAM,aAAA,GAAgBM,OAAO,EAAE,CAAA;AAE/B,EAAA,MAAM,YAAA,GAAed,YAAY,MAAY;AAC3C,IAAA,IAAI,WAAW,OAAA,EAAS;AACtB,MAAA,eAAA,CAAgB,IAAI,CAAA;AACpB,MAAA,QAAA,CAAS,IAAI,CAAA;AAAA,IACf;AAAA,EACF,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,MAAM,UAAA,GAAaA,YAAY,MAAY;AACzC,IAAA,IAAI,WAAW,OAAA,EAAS;AACtB,MAAA,eAAA,CAAgB,KAAK,CAAA;AAAA,IACvB;AAAA,EACF,CAAA,EAAG,EAAE,CAAA;AAGL,EAAA,MAAM,QAAA,GAAWA,WAAAA;AAAA,IACf,OAAO,UAAA,KAAqD;AAC1D,MAAA,YAAA,EAAa;AACb,MAAA,IAAI;AACF,QAAA,MAAM,SAAS,MAAM,MAAA,CAAO,UAAA,CAAW,EAAE,YAAY,CAAA;AACrD,QAAA,aAAA,CAAc,OAAA,GAAU,UAAA;AACxB,QAAA,IAAI,WAAW,OAAA,EAAS;AACtB,UAAA,OAAA,CAAQ,EAAE,IAAA,EAAA,WAAA,kBAA8B,UAAA,EAAY,WAAA,EAAa,QAAQ,CAAA;AAAA,QAC3E;AACA,QAAA,OAAO,MAAA;AAAA,MACT,SAAS,MAAA,EAAQ;AACf,QAAA,MAAM,GAAA,GAAMa,SAAQ,MAAM,CAAA;AAC1B,QAAA,IAAI,WAAW,OAAA,EAAS;AACtB,UAAA,QAAA,CAAS,GAAG,CAAA;AAAA,QACd;AACA,QAAA,MAAM,GAAA;AAAA,MACR,CAAA,SAAE;AACA,QAAA,UAAA,EAAW;AAAA,MACb;AAAA,IACF,CAAA;AAAA,IACA,CAAC,MAAA,EAAQ,YAAA,EAAc,UAAU;AAAA,GACnC;AAEA,EAAA,MAAM,WAAA,GAAcb,WAAAA;AAAA,IAClB,CAAC,UAAA,KAAqD,QAAA,CAAS,UAAU,CAAA;AAAA,IACzE,CAAC,QAAQ;AAAA,GACX;AAEA,EAAA,MAAM,MAAA,GAASA,WAAAA;AAAA,IACb,MAAoC,QAAA,CAAS,aAAA,CAAc,OAAO,CAAA;AAAA,IAClE,CAAC,QAAQ;AAAA,GACX;AAEA,EAAA,MAAM,UAAA,GAAaA,WAAAA;AAAA,IACjB,OAAO,GAAA,KAAkC;AACvC,MAAA,YAAA,EAAa;AACb,MAAA,IAAI;AACF,QAAA,OAAO,MAAM,OAAO,SAAA,CAAU,EAAE,UAAU,aAAA,CAAc,OAAA,EAAS,KAAK,CAAA;AAAA,MACxE,SAAS,MAAA,EAAQ;AACf,QAAA,MAAM,GAAA,GAAMa,SAAQ,MAAM,CAAA;AAC1B,QAAA,IAAI,WAAW,OAAA,EAAS;AACtB,UAAA,QAAA,CAAS,GAAG,CAAA;AAAA,QACd;AACA,QAAA,MAAM,GAAA;AAAA,MACR,CAAA,SAAE;AACA,QAAA,UAAA,EAAW;AAAA,MACb;AAAA,IACF,CAAA;AAAA,IACA,CAAC,MAAA,EAAQ,YAAA,EAAc,UAAU;AAAA,GACnC;AAEA,EAAA,MAAM,KAAA,GAAQb,YAAY,MAAY;AACpC,IAAA,aAAA,CAAc,OAAA,GAAU,EAAA;AACxB,IAAA,IAAI,WAAW,OAAA,EAAS;AACtB,MAAA,OAAA,CAAQ,YAAY,CAAA;AACpB,MAAA,QAAA,CAAS,IAAI,CAAA;AAAA,IACf;AAAA,EACF,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,OAAOR,OAAAA;AAAA,IACL,OAAO;AAAA,MACL,MAAM,IAAA,CAAK,IAAA;AAAA,MACX,YAAY,IAAA,CAAK,UAAA;AAAA,MACjB,aAAa,IAAA,CAAK,WAAA;AAAA,MAClB,YAAA;AAAA,MACA,KAAA;AAAA,MACA,WAAA;AAAA,MACA,UAAA;AAAA,MACA,MAAA;AAAA,MACA;AAAA,KACF,CAAA;AAAA,IACA;AAAA,MACE,IAAA,CAAK,IAAA;AAAA,MACL,IAAA,CAAK,UAAA;AAAA,MACL,IAAA,CAAK,WAAA;AAAA,MACL,YAAA;AAAA,MACA,KAAA;AAAA,MACA,WAAA;AAAA,MACA,UAAA;AAAA,MACA,MAAA;AAAA,MACA;AAAA;AACF,GACF;AACF;ACjLA,IAAMe,YAAAA,GAAc,2BAAA;AAsBpB,SAASQ,cAAa,KAAA,EAAwB;AAC5C,EAAA,OAAOR,YAAAA,CAAY,KAAK,KAAK,CAAA;AAC/B;AAGA,SAAS,iBAAA,CACP,IAAA,EACA,KAAA,EACA,MAAA,EACe;AACf,EAAA,IAAI,UAAU,IAAA,EAAM;AAClB,IAAA,OAAO,IAAA;AAAA,EACT;AAGA,EAAA,OAAO,IAAA,KAAA,aAAA,qBAAoC,MAAA,CAAO,YAAA,GAAe,MAAA,CAAO,WAAA;AAC1E;AAGA,SAAS,iBAAA,CACP,GAAA,EACA,MAAA,EACA,aAAA,EACyB;AACzB,EAAA,OAAOP,WAAAA;AAAA,IACL,CAAC,KAAA,KAAwB;AACvB,MAAA,aAAA,CAAc,IAAI,CAAA;AAClB,MAAA,IAAI,CAACe,aAAAA,CAAa,KAAK,CAAA,EAAG;AACxB,QAAA,aAAA,CAAc,OAAO,YAAY,CAAA;AACjC,QAAA;AAAA,MACF;AACA,MAAA,KAAK,IAAI,WAAA,CAAY,KAAK,CAAA,CAAE,KAAA,CAAM,MAAM,MAAS,CAAA;AAAA,IACnD,CAAA;AAAA,IACA,CAAC,GAAA,EAAK,MAAA,CAAO,YAAA,EAAc,aAAa;AAAA,GAC1C;AACF;AAGA,SAAS,gBAAA,CACP,GAAA,EACA,MAAA,EACA,aAAA,EACA,SAAA,EACwB;AACxB,EAAA,OAAOf,WAAAA;AAAA,IACL,CAAC,IAAA,KAAuB;AACtB,MAAA,aAAA,CAAc,IAAI,CAAA;AAClB,MAAA,IAAI,IAAA,CAAK,WAAW,CAAA,EAAG;AACrB,QAAA,aAAA,CAAc,OAAO,WAAW,CAAA;AAChC,QAAA;AAAA,MACF;AACA,MAAA,GAAA,CACG,UAAA,CAAW,IAAI,CAAA,CACf,IAAA,CAAK,CAAC,IAAA,KAAS;AACd,QAAA,SAAA,CAAU,IAAI,CAAA;AAAA,MAChB,CAAC,CAAA,CACA,KAAA,CAAM,MAAM,MAAS,CAAA;AAAA,IAC1B,CAAA;AAAA,IACA,CAAC,GAAA,EAAK,MAAA,CAAO,WAAA,EAAa,eAAe,SAAS;AAAA,GACpD;AACF;AAGO,SAAS,OAAA,CAAQ;AAAA,EACtB,MAAA;AAAA,EACA,KAAA,EAAO,SAAA;AAAA,EACP,MAAA,EAAQ,UAAA;AAAA,EACR,SAAA;AAAA,EACA,YAAA;AAAA,EACA,UAAA,GAAa;AACf,CAAA,EAAyC;AACvC,EAAA,MAAM,KAAA,GAAQ,aAAa,SAAS,CAAA;AACpC,EAAA,MAAMP,OAAAA,GAAS,cAAc,KAAK,CAAA;AAClC,EAAA,MAAM,MAAA,GAASD,OAAAA;AAAA,IACb,OAAO,EAAE,GAAG,kBAAA,EAAoB,GAAG,UAAA,EAAW,CAAA;AAAA,IAC9C,CAAC,UAAU;AAAA,GACb;AAEA,EAAA,MAAM,GAAA,GAAM,WAAA,CAAY,EAAE,MAAA,EAAQ,CAAA;AAGlC,EAAA,MAAM,CAAC,UAAA,EAAY,aAAa,CAAA,GAAIM,SAAwB,IAAI,CAAA;AAEhE,EAAA,MAAM,aAAA,GAAgB,iBAAA,CAAkB,GAAA,EAAK,MAAA,EAAQ,aAAa,CAAA;AAClE,EAAA,MAAM,YAAA,GAAe,gBAAA,CAAiB,GAAA,EAAK,MAAA,EAAQ,eAAe,SAAS,CAAA;AAC3E,EAAA,MAAM,YAAA,GAAeE,YAAY,MAAY;AAC3C,IAAA,aAAA,CAAc,IAAI,CAAA;AAClB,IAAA,KAAK,GAAA,CAAI,MAAA,EAAO,CAAE,KAAA,CAAM,MAAM,MAAS,CAAA;AAAA,EACzC,CAAA,EAAG,CAAC,GAAG,CAAC,CAAA;AACR,EAAA,MAAM,iBAAA,GAAoBA,YAAY,MAAY;AAChD,IAAA,aAAA,CAAc,IAAI,CAAA;AAClB,IAAA,GAAA,CAAI,KAAA,EAAM;AAAA,EACZ,CAAA,EAAG,CAAC,GAAG,CAAC,CAAA;AAER,EAAA,MAAM,YAAY,UAAA,IAAc,iBAAA,CAAkB,IAAI,IAAA,EAAM,GAAA,CAAI,OAAO,MAAM,CAAA;AAE7E,EAAA,MAAM,OAAA,GACJ,GAAA,CAAI,IAAA,KAAA,aAAA,qCACFN,GAAAA;AAAA,IAAC,cAAA;AAAA,IAAA;AAAA,MACC,SAAA;AAAA,MACA,cAAc,GAAA,CAAI,YAAA;AAAA,MAClB,MAAA;AAAA,MACA,MAAA,EAAQD,OAAAA;AAAA,MACR,YAAA;AAAA,MACA,KAAA;AAAA,MACA,QAAA,EAAU;AAAA;AAAA,sBAGZC,GAAAA;AAAA,IAAC,aAAA;AAAA,IAAA;AAAA,MACC,SAAA;AAAA,MACA,YAAY,GAAA,CAAI,UAAA;AAAA,MAChB,cAAc,GAAA,CAAI,YAAA;AAAA,MAClB,MAAA;AAAA,MACA,MAAA,EAAQD,OAAAA;AAAA,MACR,YAAA;AAAA,MACA,KAAA;AAAA,MACA,aAAA,EAAe,iBAAA;AAAA,MACf,QAAA,EAAU,YAAA;AAAA,MACV,QAAA,EAAU;AAAA;AAAA,GACZ;AAGJ,EAAA,MAAM,uBACJC,GAAAA;AAAA,IAACS,IAAAA;AAAA,IAAA;AAAA,MACC,KAAA,EAAO,UAAA,GAAa,MAAA,GAAYV,OAAAA,CAAO,IAAA;AAAA,MACvC,MAAA,EAAQ,gBAAA,CAAiB,WAAA,CAAY,OAAA,EAAS,YAAY,CAAA;AAAA,MAEzD,QAAA,EAAA;AAAA;AAAA,GACH;AAGF,EAAA,OAAO,UAAA,GAAa,uBAAOC,GAAAA,CAACS,MAAA,EAAK,KAAA,EAAOV,OAAAA,CAAO,MAAA,EAAS,QAAA,EAAA,IAAA,EAAK,CAAA;AAC/D;ACzIA,SAASoB,SAAQ,KAAA,EAAuB;AACtC,EAAA,OAAO,iBAAiB,KAAA,GAAQ,KAAA,GAAQ,IAAI,KAAA,CAAM,MAAA,CAAO,KAAK,CAAC,CAAA;AACjE;AAOO,SAAS,YAAY,OAAA,EAAgD;AAC1E,EAAA,MAAM,EAAE,MAAA,EAAQ,eAAA,EAAgB,GAAI,OAAA;AAEpC,EAAA,MAAM,CAAC,YAAA,EAAc,eAAe,CAAA,GAAIf,SAAS,KAAK,CAAA;AACtD,EAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAIA,SAAuB,IAAI,CAAA;AAGrD,EAAA,MAAM,UAAA,GAAagB,OAAO,IAAI,CAAA;AAC9B,EAAAN,UAAU,MAAM;AACd,IAAA,UAAA,CAAW,OAAA,GAAU,IAAA;AACrB,IAAA,OAAO,MAAY;AACjB,MAAA,UAAA,CAAW,OAAA,GAAU,KAAA;AAAA,IACvB,CAAA;AAAA,EACF,CAAA,EAAG,EAAE,CAAA;AAIL,EAAA,MAAM,UAAA,GAAaM,OAAO,eAAe,CAAA;AACzC,EAAAN,UAAU,MAAM;AACd,IAAA,UAAA,CAAW,OAAA,GAAU,eAAA;AAAA,EACvB,CAAA,EAAG,CAAC,eAAe,CAAC,CAAA;AAEpB,EAAA,MAAM,MAAA,GAASR,WAAAA;AAAA,IACb,OAAO,GAAA,KAAkC;AACvC,MAAA,IAAI,WAAW,OAAA,EAAS;AACtB,QAAA,eAAA,CAAgB,IAAI,CAAA;AACpB,QAAA,QAAA,CAAS,IAAI,CAAA;AAAA,MACf;AACA,MAAA,IAAI;AACF,QAAA,OAAO,MAAM,OAAO,QAAA,CAAS,EAAE,KAAK,eAAA,EAAiB,UAAA,CAAW,SAAS,CAAA;AAAA,MAC3E,SAAS,MAAA,EAAQ;AACf,QAAA,MAAM,GAAA,GAAMa,SAAQ,MAAM,CAAA;AAC1B,QAAA,IAAI,WAAW,OAAA,EAAS;AACtB,UAAA,QAAA,CAAS,GAAG,CAAA;AAAA,QACd;AACA,QAAA,MAAM,GAAA;AAAA,MACR,CAAA,SAAE;AACA,QAAA,IAAI,WAAW,OAAA,EAAS;AACtB,UAAA,eAAA,CAAgB,KAAK,CAAA;AAAA,QACvB;AAAA,MACF;AAAA,IACF,CAAA;AAAA,IACA,CAAC,MAAM;AAAA,GACT;AAEA,EAAA,MAAM,KAAA,GAAQb,YAAY,MAAY;AACpC,IAAA,IAAI,WAAW,OAAA,EAAS;AACtB,MAAA,QAAA,CAAS,IAAI,CAAA;AAAA,IACf;AAAA,EACF,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,OAAOR,OAAAA;AAAA,IACL,OAAO,EAAE,YAAA,EAAc,KAAA,EAAO,QAAQ,KAAA,EAAM,CAAA;AAAA,IAC5C,CAAC,YAAA,EAAc,KAAA,EAAO,MAAA,EAAQ,KAAK;AAAA,GACrC;AACF;AC5DA,SAASwB,kBAAAA,CAAkB,OAAqB,MAAA,EAAsC;AACpF,EAAA,IAAI,UAAU,IAAA,EAAM;AAClB,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,OAAO,MAAA,CAAO,UAAA;AAChB;AAGA,SAAS,gBAAA,CACP,GAAA,EACA,MAAA,EACA,aAAA,EACA,SAAA,EACyB;AACzB,EAAA,OAAOhB,WAAAA;AAAA,IACL,CAAC,KAAA,KAAwB;AACvB,MAAA,aAAA,CAAc,IAAI,CAAA;AAClB,MAAA,IAAI,KAAA,CAAM,WAAW,CAAA,EAAG;AACtB,QAAA,aAAA,CAAc,OAAO,UAAU,CAAA;AAC/B,QAAA;AAAA,MACF;AACA,MAAA,GAAA,CACG,MAAA,CAAO,KAAK,CAAA,CACZ,IAAA,CAAK,CAAC,IAAA,KAAS;AACd,QAAA,SAAA,CAAU,IAAI,CAAA;AAAA,MAChB,CAAC,CAAA,CACA,KAAA,CAAM,MAAM,MAAS,CAAA;AAAA,IAC1B,CAAA;AAAA,IACA,CAAC,GAAA,EAAK,MAAA,CAAO,UAAA,EAAY,eAAe,SAAS;AAAA,GACnD;AACF;AAGO,SAAS,OAAA,CAAQ;AAAA,EACtB,MAAA;AAAA,EACA,eAAA;AAAA,EACA,KAAA,EAAO,SAAA;AAAA,EACP,MAAA,EAAQ,UAAA;AAAA,EACR,SAAA;AAAA,EACA,YAAA;AAAA,EACA,UAAA,GAAa;AACf,CAAA,EAAyC;AACvC,EAAA,MAAM,KAAA,GAAQ,aAAa,SAAS,CAAA;AACpC,EAAA,MAAMP,OAAAA,GAAS,cAAc,KAAK,CAAA;AAClC,EAAA,MAAM,MAAA,GAASD,OAAAA;AAAA,IACb,OAAO,EAAE,GAAG,kBAAA,EAAoB,GAAG,UAAA,EAAW,CAAA;AAAA,IAC9C,CAAC,UAAU;AAAA,GACb;AAEA,EAAA,MAAM,GAAA,GAAM,WAAA,CAAY,EAAE,MAAA,EAAQ,iBAAiB,CAAA;AAGnD,EAAA,MAAM,CAAC,UAAA,EAAY,aAAa,CAAA,GAAIM,SAAwB,IAAI,CAAA;AAChE,EAAA,MAAM,CAAC,QAAA,EAAU,WAAW,CAAA,GAAIA,SAAS,EAAE,CAAA;AAE3C,EAAA,MAAM,YAAA,GAAe,gBAAA,CAAiB,GAAA,EAAK,MAAA,EAAQ,eAAe,SAAS,CAAA;AAE3E,EAAA,MAAM,SAAA,GAAY,UAAA,IAAckB,kBAAAA,CAAkB,GAAA,CAAI,OAAO,MAAM,CAAA;AACnE,EAAA,MAAM,WAAA,GAAc,IAAI,YAAA,GACpB,CAACvB,QAAO,aAAA,EAAeA,OAAAA,CAAO,qBAAqB,CAAA,GACnDA,OAAAA,CAAO,aAAA;AAEX,EAAA,MAAM,OAAA,mBACJQ,IAAAA,CAAAG,QAAAA,EAAA,EACE,QAAA,EAAA;AAAA,oBAAAV,IAACQ,IAAAA,EAAA,EAAK,OAAOT,OAAAA,CAAO,KAAA,EAAQ,iBAAO,KAAA,EAAM,CAAA;AAAA,oBACvCC,IAACQ,IAAAA,EAAA,EAAK,OAAOT,OAAAA,CAAO,QAAA,EAAW,iBAAO,WAAA,EAAY,CAAA;AAAA,oBAElDQ,IAAAA,CAACE,IAAAA,EAAA,EAAK,KAAA,EAAOV,QAAO,UAAA,EAClB,QAAA,EAAA;AAAA,sBAAAC,IAACQ,IAAAA,EAAA,EAAK,OAAOT,OAAAA,CAAO,KAAA,EAAQ,iBAAO,QAAA,EAAS,CAAA;AAAA,sBAC5CC,GAAAA;AAAA,QAACW,SAAAA;AAAA,QAAA;AAAA,UACC,mBAAmB,MAAA,CAAO,cAAA;AAAA,UAC1B,oBAAoB,MAAA,CAAO,QAAA;AAAA,UAC3B,cAAA,EAAe,MAAA;AAAA,UACf,WAAA,EAAa,KAAA;AAAA,UACb,QAAA,EAAU,CAAC,GAAA,CAAI,YAAA;AAAA,UACf,YAAA,EAAa,YAAA;AAAA,UACb,aAAa,MAAA,CAAO,cAAA;AAAA,UACpB,oBAAA,EAAsB,MAAM,MAAA,CAAO,aAAA;AAAA,UACnC,eAAA,EAAe,IAAA;AAAA,UACf,OAAOZ,OAAAA,CAAO,KAAA;AAAA,UACd,MAAA,EAAQ,gBAAA,CAAiB,WAAA,CAAY,QAAA,EAAU,YAAY,CAAA;AAAA,UAC3D,KAAA,EAAO,QAAA;AAAA,UACP,YAAA,EAAc;AAAA;AAAA;AAChB,KAAA,EACF,CAAA;AAAA,IAEC,SAAA,KAAc,uBACbC,GAAAA;AAAA,MAACQ,IAAAA;AAAA,MAAA;AAAA,QACC,OAAOT,OAAAA,CAAO,SAAA;AAAA,QACd,MAAA,EAAQ,gBAAA,CAAiB,WAAA,CAAY,QAAA,EAAU,YAAY,CAAA;AAAA,QAE1D,QAAA,EAAA;AAAA;AAAA,KACH,GACE,IAAA;AAAA,oBAEJC,GAAAA;AAAA,MAACY,gBAAAA;AAAA,MAAA;AAAA,QACC,mBAAmB,MAAA,CAAO,MAAA;AAAA,QAC1B,kBAAA,EAAoB,GAAA,CAAI,YAAA,GAAe,MAAA,CAAO,aAAa,MAAA,CAAO,MAAA;AAAA,QAClE,iBAAA,EAAkB,QAAA;AAAA,QAClB,UAAU,GAAA,CAAI,YAAA;AAAA,QACd,KAAA,EAAO,WAAA;AAAA,QACP,MAAA,EAAQ,gBAAA,CAAiB,WAAA,CAAY,eAAA,EAAiB,YAAY,CAAA;AAAA,QAClE,OAAA,EAAS,MAAY,YAAA,CAAa,QAAA,CAAS,MAAM,CAAA;AAAA,QAEhD,QAAA,EAAA,GAAA,CAAI,+BACHZ,GAAAA,CAACe,mBAAA,EAAkB,KAAA,EAAO,MAAM,MAAA,CAAO,SAAA,EAAW,MAAK,OAAA,EAAQ,CAAA,mBAE/Df,GAAAA,CAACQ,IAAAA,EAAA,EAAK,KAAA,EAAOT,OAAAA,CAAO,iBAAA,EAAoB,QAAA,EAAA,MAAA,CAAO,MAAA,EAAO;AAAA;AAAA;AAE1D,GAAA,EACJ,CAAA;AAGF,EAAA,MAAM,uBACJC,GAAAA;AAAA,IAACS,IAAAA;AAAA,IAAA;AAAA,MACC,KAAA,EAAO,UAAA,GAAa,MAAA,GAAYV,OAAAA,CAAO,IAAA;AAAA,MACvC,MAAA,EAAQ,gBAAA,CAAiB,WAAA,CAAY,OAAA,EAAS,YAAY,CAAA;AAAA,MAEzD,QAAA,EAAA;AAAA;AAAA,GACH;AAGF,EAAA,OAAO,UAAA,GAAa,uBAAOC,GAAAA,CAACS,MAAA,EAAK,KAAA,EAAOV,OAAAA,CAAO,MAAA,EAAS,QAAA,EAAA,IAAA,EAAK,CAAA;AAC/D;ACjIA,IAAM,QAAA,GAAW,EAAA;AACjB,IAAM,gBAAA,GAAmB,CAAA;AACzB,IAAM,UAAA,GAAa,CAAA;AACnB,IAAM,OAAA,GAAU,EAAA;AAChB,IAAM,cAAA,GAAiB,EAAA;AACvB,IAAM,mBAAA,GAAsB,EAAA;AAC5B,IAAM,WAAA,GAAc,CAAA;AAGpB,SAAS,QAAA,CAAS,KAAa,MAAA,EAAwB;AACrD,EAAA,OAAO,IAAI,OAAA,CAAQ,KAAA,EAAO,EAAE,CAAA,CAAE,KAAA,CAAM,GAAG,MAAM,CAAA;AAC/C;AAGA,SAAS,aAAa,KAAA,EAA2D;AAC/E,EAAA,OAAOD,OAAAA;AAAA,IACL,OAAO;AAAA,MACL,MAAA,EAAQ,EAAE,eAAA,EAAiB,KAAA,CAAM,OAAO,OAAA,EAAS,WAAA,EAAa,KAAA,CAAM,MAAA,CAAO,OAAA,EAAQ;AAAA,MACnF,KAAA,EAAO,EAAE,eAAA,EAAiB,KAAA,CAAM,OAAO,UAAA,EAAY,WAAA,EAAa,KAAA,CAAM,MAAA,CAAO,MAAA;AAAO,KACtF,CAAA;AAAA,IACA,CAAC,KAAK;AAAA,GACR;AACF;AAGO,SAAS,cAAA,CAAe;AAAA,EAC7B,KAAA;AAAA,EACA,MAAA;AAAA,EACA,QAAA;AAAA,EACA,MAAA;AAAA,EACA,YAAA;AAAA,EACA,kBAAA;AAAA,EACA,iBAAA;AAAA,EACA,UAAA;AAAA,EACA,SAAA;AAAA,EACA,KAAA,EAAO,SAAA;AAAA,EACP;AACF,CAAA,EAAgD;AAC9C,EAAA,MAAM,KAAA,GAAQ,aAAa,SAAS,CAAA;AACpC,EAAA,MAAM,QAAA,GAAWsB,OAA2B,IAAI,CAAA;AAChD,EAAA,MAAM,SAAA,GAAY,aAAa,KAAK,CAAA;AACpC,EAAA,MAAM,KAAA,GAAQ,MAAM,IAAA,CAAK,EAAE,QAAO,EAAG,CAAC,OAAA,EAAS,KAAA,KAAU,KAAK,CAAA;AAC9D,EAAA,MAAM,MAAA,GAAS,gBAAA,CAAiB,MAAA,EAAQ,YAAY,CAAA;AAEpD,EAAA,uBACEb,IAAAA;AAAA,IAAC,SAAA;AAAA,IAAA;AAAA,MACC,iBAAA;AAAA,MACA,kBAAA;AAAA,MACA,iBAAA,EAAkB,QAAA;AAAA,MAClB,QAAA;AAAA,MACA,OAAO,MAAA,CAAO,GAAA;AAAA,MACd,MAAA,EAAQ,GAAG,MAAM,CAAA,IAAA,CAAA;AAAA,MACjB,OAAA,EAAS,MAAY,QAAA,CAAS,OAAA,EAAS,KAAA,EAAM;AAAA,MAE5C,QAAA,EAAA;AAAA,QAAA,KAAA,CAAM,GAAA,CAAI,CAAC,KAAA,KAAU;AACpB,UAAA,MAAM,MAAA,GAAS,QAAQ,KAAA,CAAM,MAAA;AAC7B,UAAA,uBACEP,GAAAA;AAAA,YAACS,IAAAA;AAAA,YAAA;AAAA,cAEC,kBAAA,EAAoB,SAAS,UAAA,GAAa,SAAA;AAAA,cAC1C,KAAA,EAAO,CAAC,MAAA,CAAO,GAAA,EAAK,SAAS,SAAA,CAAU,MAAA,GAAS,UAAU,KAAK,CAAA;AAAA,cAC/D,QAAQ,CAAA,EAAG,MAAM,CAAA,KAAA,EAAQ,MAAA,CAAO,KAAK,CAAC,CAAA;AAAA,aAAA;AAAA,YAHjC;AAAA,WAIP;AAAA,QAEJ,CAAC,CAAA;AAAA,wBACDT,GAAAA;AAAA,UAACW,SAAAA;AAAA,UAAA;AAAA,YACC,GAAA,EAAK,QAAA;AAAA,YACL,iBAAA;AAAA,YACA,kBAAA;AAAA,YACA,SAAA,EAAS,IAAA;AAAA,YACT,WAAA,EAAW,IAAA;AAAA,YACX,UAAU,CAAC,QAAA;AAAA,YACX,YAAA,EAAa,YAAA;AAAA,YACb,SAAA,EAAW,MAAA;AAAA,YACX,eAAA,EAAe,IAAA;AAAA,YACf,OAAO,MAAA,CAAO,WAAA;AAAA,YACd,MAAA,EAAQ,MAAA;AAAA,YACR,KAAA;AAAA,YACA,cAAc,CAAC,GAAA,KAAsB,SAAS,QAAA,CAAS,GAAA,EAAK,MAAM,CAAC;AAAA;AAAA;AACrE;AAAA;AAAA,GACF;AAEJ;AAEA,IAAM,MAAA,GAAST,WAAW,MAAA,CAAO;AAAA,EAC/B,GAAA,EAAK;AAAA,IACH,YAAA,EAAc,UAAA;AAAA,IACd,WAAA,EAAa,gBAAA;AAAA,IACb,MAAA,EAAQ,QAAA;AAAA,IACR,KAAA,EAAO;AAAA,GACT;AAAA,EACA,WAAA,EAAa;AAAA,IACX,MAAA,EAAQ,WAAA;AAAA,IACR,OAAA,EAAS,CAAA;AAAA,IACT,QAAA,EAAU,UAAA;AAAA,IACV,KAAA,EAAO;AAAA,GACT;AAAA,EACA,GAAA,EAAK;AAAA,IACH,UAAA,EAAY,QAAA;AAAA,IACZ,aAAA,EAAe,KAAA;AAAA,IACf,GAAA,EAAK,OAAA;AAAA,IACL,cAAA,EAAgB,QAAA;AAAA,IAChB,cAAA,EAAgB,mBAAA;AAAA,IAChB,SAAA,EAAW;AAAA;AAEf,CAAC,CAAA;;;ACjJM,SAAS,WAAA,CACd,UACA,MAAA,EACQ;AACR,EAAA,OAAO,QAAA,CAAS,OAAA,CAAQ,YAAA,EAAc,CAAC,OAAO,GAAA,KAAgB;AAC5D,IAAA,MAAM,KAAA,GAAQ,OAAO,GAAG,CAAA;AACxB,IAAA,OAAO,KAAA,KAAU,MAAA,GAAY,KAAA,GAAQ,MAAA,CAAO,KAAK,CAAA;AAAA,EACnD,CAAC,CAAA;AACH;;;ACTO,IAAM,yBAAA,GAA+C,CAAC,CAAA,EAAG,CAAA,EAAG,CAAC;AAG7D,IAAM,yBAAA,GAA4B;AAGlC,SAAS,mBAAmB,KAAA,EAAwB;AACzD,EAAA,OAAO,yBAAA,CAA0B,SAAS,KAAK,CAAA;AACjD;ACuBA,IAAM,qBAAA,GAAwB,EAAA;AAC9B,IAAM,cAAA,GAAiB,EAAA;AAGvB,SAAS,gBAAgB,KAAA,EAKvB;AACA,EAAA,OAAOJ,OAAAA;AAAA,IACL,OAAO;AAAA,MACL,IAAA,EAAM,EAAE,WAAA,EAAa,KAAA,CAAM,OAAO,MAAA,EAAO;AAAA,MACzC,MAAA,EAAQ,EAAE,eAAA,EAAiB,KAAA,CAAM,OAAO,OAAA,EAAS,WAAA,EAAa,KAAA,CAAM,MAAA,CAAO,OAAA,EAAQ;AAAA,MACnF,IAAA,EAAM,EAAE,KAAA,EAAO,KAAA,CAAM,OAAO,IAAA,EAAK;AAAA,MACjC,UAAA,EAAY,EAAE,KAAA,EAAO,KAAA,CAAM,OAAO,SAAA;AAAU,KAC9C,CAAA;AAAA,IACA,CAAC,KAAK;AAAA,GACR;AACF;AAGO,SAAS,qBAAA,CAAsB;AAAA,EACpC,QAAA;AAAA,EACA,QAAA;AAAA,EACA,UAAA;AAAA,EACA,YAAA;AAAA,EACA,KAAA,EAAO,SAAA;AAAA,EACP;AACF,CAAA,EAAuD;AACrD,EAAA,MAAM,KAAA,GAAQ,aAAa,SAAS,CAAA;AACpC,EAAA,MAAM,OAAA,GAAU,gBAAgB,KAAK,CAAA;AACrC,EAAA,MAAM,MAAA,GAAS,gBAAA,CAAiB,WAAA,CAAY,qBAAA,EAAuB,YAAY,CAAA;AAE/E,EAAA,uBACEE,GAAAA,CAACS,IAAAA,EAAA,EAAK,mBAAkB,YAAA,EAAa,IAAA,EAAK,YAAA,EAAa,KAAA,EAAOV,OAAAA,CAAO,GAAA,EAClE,QAAA,EAAA,yBAAA,CAA0B,GAAA,CAAI,CAAC,MAAA,KAAW;AACzC,IAAA,MAAM,SAAS,MAAA,KAAW,QAAA;AAC1B,IAAA,uBACEC,GAAAA;AAAA,MAACuB,SAAAA;AAAA,MAAA;AAAA,QAMC,cAAA,EAAc,MAAA;AAAA,QACd,mBAAmB,WAAA,CAAY,UAAA,EAAY,EAAE,KAAA,EAAO,QAAQ,CAAA;AAAA,QAC5D,kBAAA,EAAoB,OAAO,MAAM,CAAA;AAAA,QAGjC,iBAAA,EAAkB,OAAA;AAAA,QAClB,kBAAA,EAAoB,EAAE,QAAA,EAAU,MAAA,EAAO;AAAA,QACvC,QAAA;AAAA,QACA,KAAA,EAAO,CAACxB,OAAAA,CAAO,IAAA,EAAM,QAAQ,IAAA,EAAM,MAAA,GAAS,OAAA,CAAQ,MAAA,GAAS,IAAI,CAAA;AAAA,QACjE,QAAQ,CAAA,EAAG,MAAM,CAAA,CAAA,EAAI,MAAA,CAAO,MAAM,CAAC,CAAA,CAAA;AAAA,QACnC,OAAA,EAAS,MAAY,QAAA,CAAS,MAAM,CAAA;AAAA,QAEpC,0BAAAC,GAAAA,CAACQ,IAAAA,EAAA,EAAK,KAAA,EAAO,CAACT,OAAAA,CAAO,IAAA,EAAM,OAAA,CAAQ,IAAA,EAAM,SAAS,OAAA,CAAQ,UAAA,GAAa,IAAI,CAAA,EACxE,QAAA,EAAA,MAAA,CAAO,MAAM,CAAA,EAChB;AAAA,OAAA;AAAA,MAnBK;AAAA,KAoBP;AAAA,EAEJ,CAAC,CAAA,EACH,CAAA;AAEJ;AAEA,IAAMA,OAAAA,GAASG,WAAW,MAAA,CAAO;AAAA,EAC/B,IAAA,EAAM;AAAA,IACJ,UAAA,EAAY,QAAA;AAAA,IACZ,YAAA,EAAc,CAAA;AAAA,IACd,WAAA,EAAa,CAAA;AAAA,IACb,IAAA,EAAM,CAAA;AAAA,IACN,eAAA,EAAiB;AAAA,GACnB;AAAA,EACA,GAAA,EAAK;AAAA,IACH,aAAA,EAAe,KAAA;AAAA,IACf,GAAA,EAAK,CAAA;AAAA,IACL,YAAA,EAAc;AAAA,GAChB;AAAA,EACA,IAAA,EAAM;AAAA,IACJ,QAAA,EAAU,cAAA;AAAA,IACV,UAAA,EAAY;AAAA;AAEhB,CAAC,CAAA;;;ACpHM,IAAW,iBAAA,qBAAAsB,kBAAAA,KAAX;AAEL,EAAAA,mBAAA,YAAA,CAAA,GAAa,YAAA;AAEb,EAAAA,mBAAA,SAAA,CAAA,GAAU,SAAA;AAEV,EAAAA,mBAAA,WAAA,CAAA,GAAY,YAAA;AAEZ,EAAAA,mBAAA,aAAA,CAAA,GAAc,cAAA;AAEd,EAAAA,mBAAA,SAAA,CAAA,GAAU,SAAA;AAVM,EAAA,OAAAA,kBAAAA;AAAA,CAAA,EAAA,iBAAA,IAAA,EAAA;AC4CX,SAAS,kBAAA,CAAmB;AAAA,EACjC,MAAA;AAAA,EACA,MAAA;AAAA,EACA;AACF,CAAA,EAAqD;AACnD,EAAA,MAAM,CAAC,GAAA,EAAK,WAAW,CAAA,GAAIpB,SAAiB,EAAE,CAAA;AAC9C,EAAA,MAAM,CAAC,UAAA,EAAY,aAAa,CAAA,GAAIA,SAAkB,KAAK,CAAA;AAC3D,EAAA,MAAM,CAAC,QAAA,EAAU,WAAW,CAAA,GAAIA,SAAmC,IAAI,CAAA;AACvE,EAAA,MAAM,CAAC,iBAAA,EAAmB,oBAAoB,CAAA,GAAIA,SAAwB,IAAI,CAAA;AAE9E,EAAA,MAAM,MAAA,GAASE,WAAAA,CAAY,CAAC,IAAA,KAAuB;AACjD,IAAA,WAAA,CAAY,IAAI,CAAA;AAChB,IAAA,WAAA,CAAY,IAAI,CAAA;AAChB,IAAA,oBAAA,CAAqB,IAAI,CAAA;AAAA,EAC3B,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,MAAM,MAAA,GAASA,YAAY,MAAY;AACrC,IAAA,WAAA,CAAY,IAAI,CAAA;AAChB,IAAA,oBAAA,CAAqB,IAAI,CAAA;AACzB,IAAA,IAAI,GAAA,CAAI,SAAS,MAAA,EAAQ;AACvB,MAAA,WAAA,CAAA,YAAA,kBAAwC;AACxC,MAAA;AAAA,IACF;AACA,IAAA,aAAA,CAAc,IAAI,CAAA;AAClB,IAAA,MAAA,CACG,oBAAoB,EAAE,GAAA,EAAK,CAAA,CAC3B,IAAA,CAAK,CAAC,MAAA,KAAW;AAChB,MAAA,IAAI,MAAA,CAAO,WAAW,SAAA,EAAW;AAC/B,QAAA,UAAA,CAAW,OAAO,IAAI,CAAA;AACtB,QAAA;AAAA,MACF;AACA,MAAA,IAAI,MAAA,CAAO,WAAW,SAAA,EAAW;AAC/B,QAAA,WAAA,CAAA,SAAA,eAAqC;AACrC,QAAA;AAAA,MACF;AACA,MAAA,IAAI,MAAA,CAAO,WAAW,QAAA,EAAU;AAC9B,QAAA,oBAAA,CAAqB,OAAO,iBAAiB,CAAA;AAC7C,QAAA,WAAA,CAAA,YAAA,iBAAuC;AACvC,QAAA;AAAA,MACF;AACA,MAAA,IAAI,MAAA,CAAO,WAAW,aAAA,EAAe;AACnC,QAAA,oBAAA,CAAqB,OAAO,iBAAiB,CAAA;AAC7C,QAAA,WAAA,CAAA,cAAA,mBAAyC;AACzC,QAAA;AAAA,MACF;AACA,MAAA,WAAA,CAAA,SAAA,eAAqC;AAAA,IACvC,CAAC,CAAA,CACA,KAAA,CAAM,MAAM;AACX,MAAA,WAAA,CAAA,SAAA,eAAqC;AAAA,IACvC,CAAC,CAAA,CACA,OAAA,CAAQ,MAAM;AACb,MAAA,aAAA,CAAc,KAAK,CAAA;AAAA,IACrB,CAAC,CAAA;AAAA,EACL,GAAG,CAAC,MAAA,EAAQ,GAAA,EAAK,MAAA,EAAQ,UAAU,CAAC,CAAA;AAEpC,EAAA,OAAO,EAAE,GAAA,EAAK,UAAA,EAAY,QAAA,EAAU,iBAAA,EAAmB,QAAQ,MAAA,EAAO;AACxE;ACtDA,SAAS,gBAAA,CACP,QAAA,EACA,MAAA,EACA,UAAA,EACA,MAAA,EACe;AACf,EAAA,IAAI,aAAa,IAAA,EAAM;AACrB,IAAA,OAAO,IAAA;AAAA,EACT;AACA,EAAA,IAAI,QAAA,KAAA,YAAA,mBAA2C;AAC7C,IAAA,OAAO,YAAY,MAAA,CAAO,eAAA,EAAiB,EAAE,KAAA,EAAO,QAAQ,CAAA;AAAA,EAC9D;AACA,EAAA,IAAI,QAAA,KAAA,SAAA,gBAAwC;AAC1C,IAAA,OAAO,MAAA,CAAO,YAAA;AAAA,EAChB;AACA,EAAA,IAAI,QAAA,KAAA,YAAA,kBAA0C;AAC5C,IAAA,OAAO,UAAA,KAAe,IAAA,GAClB,WAAA,CAAY,MAAA,CAAO,mBAAA,EAAqB,EAAE,KAAA,EAAO,UAAA,EAAY,CAAA,GAC7D,MAAA,CAAO,cAAA;AAAA,EACb;AACA,EAAA,IAAI,QAAA,KAAA,cAAA,oBAA4C;AAC9C,IAAA,OAAO,UAAA,KAAe,IAAA,GAClB,WAAA,CAAY,MAAA,CAAO,qBAAA,EAAuB,EAAE,KAAA,EAAO,UAAA,EAAY,CAAA,GAC/D,MAAA,CAAO,gBAAA;AAAA,EACb;AACA,EAAA,OAAO,MAAA,CAAO,YAAA;AAChB;AAGO,SAAS,qBAAA,CAAsB;AAAA,EACpC,MAAA;AAAA,EACA,MAAA;AAAA,EACA,kBAAA;AAAA,EACA,KAAA,EAAO,SAAA;AAAA,EACP,MAAA,EAAQ,UAAA;AAAA,EACR,YAAA;AAAA,EACA,UAAA;AAAA,EACA;AACF,CAAA,EAAuD;AACrD,EAAA,MAAM,KAAA,GAAQ,aAAa,SAAS,CAAA;AACpC,EAAA,MAAMP,OAAAA,GAAS,cAAc,KAAK,CAAA;AAClC,EAAA,MAAM,MAAA,GAASD,OAAAA;AAAA,IACb,OAAO,EAAE,GAAG,gCAAA,EAAkC,GAAG,UAAA,EAAW,CAAA;AAAA,IAC5D,CAAC,UAAU;AAAA,GACb;AAEA,EAAA,MAAM,EAAE,KAAK,UAAA,EAAY,QAAA,EAAU,mBAAmB,MAAA,EAAQ,MAAA,KAAW,kBAAA,CAAmB;AAAA,IAC1F,MAAA;AAAA,IACA,MAAA;AAAA,IACA;AAAA,GACD,CAAA;AAED,EAAA,MAAM,UAAU,kBAAA,KAAuB,EAAA;AACvC,EAAA,MAAM,KAAA,GAAQ,OAAA,GAAU,WAAA,CAAY,MAAA,CAAO,KAAA,EAAO,EAAE,IAAA,EAAM,kBAAA,EAAoB,CAAA,GAAI,MAAA,CAAO,WAAA;AACzF,EAAA,MAAM,KAAA,GAAQ,gBAAA,CAAiB,QAAA,EAAU,MAAA,EAAQ,mBAAmB,MAAM,CAAA;AAC1E,EAAA,MAAM,WAAA,GAAc,aAChB,CAACC,OAAAA,CAAO,eAAeA,OAAAA,CAAO,qBAAqB,IACnDA,OAAAA,CAAO,aAAA;AAEX,EAAA,uBACEC,GAAAA,CAACS,IAAAA,EAAA,EAAK,KAAA,EAAOV,OAAAA,CAAO,QAClB,QAAA,kBAAAQ,IAAAA;AAAA,IAACE,IAAAA;AAAA,IAAA;AAAA,MACC,OAAOV,OAAAA,CAAO,IAAA;AAAA,MACd,MAAA,EAAQ,gBAAA,CAAiB,WAAA,CAAY,eAAA,EAAiB,YAAY,CAAA;AAAA,MAElE,QAAA,EAAA;AAAA,wBAAAC,IAACQ,IAAAA,EAAA,EAAK,KAAA,EAAOT,OAAAA,CAAO,OAAQ,QAAA,EAAA,KAAA,EAAM,CAAA;AAAA,wBAClCC,GAAAA,CAACQ,IAAAA,EAAA,EAAK,OAAOT,OAAAA,CAAO,QAAA,EAAW,QAAA,EAAA,WAAA,CAAY,MAAA,CAAO,WAAA,EAAa,EAAE,KAAA,EAAO,MAAA,EAAQ,CAAA,EAAE,CAAA;AAAA,wBAElFC,GAAAA;AAAA,UAAC,cAAA;AAAA,UAAA;AAAA,YACC,mBAAmB,MAAA,CAAO,cAAA;AAAA,YAC1B,oBAAoB,MAAA,CAAO,QAAA;AAAA,YAC3B,QAAA,EAAU,UAAA;AAAA,YACV,WAAW,MAAA,CAAO,cAAA;AAAA,YAClB,YAAY,MAAA,CAAO,eAAA;AAAA,YACnB,MAAA,EAAQ,MAAA;AAAA,YACR,QAAQ,WAAA,CAAY,oBAAA;AAAA,YACpB,YAAA;AAAA,YACA,KAAA;AAAA,YACA,KAAA,EAAO,GAAA;AAAA,YACP,QAAA,EAAU;AAAA;AAAA,SACZ;AAAA,QAEC,KAAA,KAAU,uBACTA,GAAAA;AAAA,UAACQ,IAAAA;AAAA,UAAA;AAAA,YACC,OAAOT,OAAAA,CAAO,SAAA;AAAA,YACd,MAAA,EAAQ,gBAAA,CAAiB,WAAA,CAAY,oBAAA,EAAsB,YAAY,CAAA;AAAA,YAEtE,QAAA,EAAA;AAAA;AAAA,SACH,GACE,IAAA;AAAA,wBAEJC,GAAAA;AAAA,UAACY,gBAAAA;AAAA,UAAA;AAAA,YACC,mBAAmB,MAAA,CAAO,MAAA;AAAA,YAC1B,kBAAA,EAAoB,UAAA,GAAa,MAAA,CAAO,UAAA,GAAa,MAAA,CAAO,MAAA;AAAA,YAC5D,iBAAA,EAAkB,QAAA;AAAA,YAClB,QAAA,EAAU,UAAA;AAAA,YACV,KAAA,EAAO,WAAA;AAAA,YACP,MAAA,EAAQ,gBAAA,CAAiB,WAAA,CAAY,qBAAA,EAAuB,YAAY,CAAA;AAAA,YACxE,OAAA,EAAS,MAAA;AAAA,YAER,QAAA,EAAA,UAAA,mBACCZ,GAAAA,CAACe,iBAAAA,EAAA,EAAkB,KAAA,EAAO,KAAA,CAAM,OAAO,SAAA,EAAW,IAAA,EAAK,SAAQ,CAAA,mBAE/Df,IAACQ,IAAAA,EAAA,EAAK,OAAOT,OAAAA,CAAO,iBAAA,EAAoB,iBAAO,MAAA,EAAO;AAAA;AAAA,SAE1D;AAAA,wBAEAC,GAAAA;AAAA,UAACY,gBAAAA;AAAA,UAAA;AAAA,YACC,mBAAmB,MAAA,CAAO,eAAA;AAAA,YAC1B,oBAAoB,MAAA,CAAO,kBAAA;AAAA,YAC3B,iBAAA,EAAkB,QAAA;AAAA,YAClB,QAAA,EAAU,UAAA;AAAA,YACV,OAAOb,OAAAA,CAAO,UAAA;AAAA,YACd,MAAA,EAAQ,gBAAA,CAAiB,WAAA,CAAY,0BAAA,EAA4B,YAAY,CAAA;AAAA,YAC7E,OAAA,EAAS,aAAA;AAAA,YAET,QAAA,kBAAAC,IAACQ,IAAAA,EAAA,EAAK,OAAOT,OAAAA,CAAO,QAAA,EAAW,iBAAO,kBAAA,EAAmB;AAAA;AAAA;AAC3D;AAAA;AAAA,GACF,EACF,CAAA;AAEJ;;;AC3KO,IAAW,uBAAA,qBAAA0B,wBAAAA,KAAX;AAEL,EAAAA,yBAAA,UAAA,CAAA,GAAW,UAAA;AAEX,EAAAA,yBAAA,cAAA,CAAA,GAAe,cAAA;AAEf,EAAAA,yBAAA,WAAA,CAAA,GAAY,WAAA;AAEZ,EAAAA,yBAAA,YAAA,CAAA,GAAa,aAAA;AAEb,EAAAA,yBAAA,QAAA,CAAA,GAAS,QAAA;AAVO,EAAA,OAAAA,wBAAAA;AAAA,CAAA,EAAA,uBAAA,IAAA,EAAA;ACwClB,SAAS,YAAY,MAAA,EAAwD;AAC3E,EAAA,IAAI,MAAA,CAAO,WAAW,cAAA,EAAgB;AACpC,IAAA,OAAA,cAAA;AAAA,EACF;AACA,EAAA,IAAI,MAAA,CAAO,WAAW,WAAA,EAAa;AACjC,IAAA,OAAA,WAAA;AAAA,EACF;AACA,EAAA,IAAI,MAAA,CAAO,WAAW,YAAA,EAAc;AAClC,IAAA,OAAA,aAAA;AAAA,EACF;AACA,EAAA,OAAA,QAAA;AACF;AAEO,SAAS,kBAAA,CAAmB;AAAA,EACjC,MAAA;AAAA,EACA,MAAA;AAAA,EACA;AACF,CAAA,EAAqD;AACnD,EAAA,MAAM,CAAC,GAAA,EAAK,WAAW,CAAA,GAAIrB,SAAiB,EAAE,CAAA;AAC9C,EAAA,MAAM,CAAC,UAAA,EAAY,eAAe,CAAA,GAAIA,SAAiB,EAAE,CAAA;AACzD,EAAA,MAAM,CAAC,UAAA,EAAY,aAAa,CAAA,GAAIA,SAAkB,KAAK,CAAA;AAC3D,EAAA,MAAM,CAAC,QAAA,EAAU,WAAW,CAAA,GAAIA,SAAyC,IAAI,CAAA;AAE7E,EAAA,MAAM,MAAA,GAASE,WAAAA,CAAY,CAAC,IAAA,KAAuB;AACjD,IAAA,WAAA,CAAY,IAAI,CAAA;AAChB,IAAA,WAAA,CAAY,IAAI,CAAA;AAAA,EAClB,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,MAAM,aAAA,GAAgBA,WAAAA,CAAY,CAAC,IAAA,KAAuB;AACxD,IAAA,eAAA,CAAgB,IAAI,CAAA;AACpB,IAAA,WAAA,CAAY,IAAI,CAAA;AAAA,EAClB,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,MAAM,MAAA,GAASA,YAAY,MAAY;AACrC,IAAA,WAAA,CAAY,IAAI,CAAA;AAChB,IAAA,MAAM,WAAA,GAAc,IAAI,MAAA,KAAW,MAAA;AACnC,IAAA,MAAM,aAAa,GAAA,KAAQ,UAAA;AAC3B,IAAA,IAAI,eAAe,UAAA,EAAY;AAC7B,MAAA,WAAA,CAAA,UAAA,gBAA4C;AAC5C,MAAA;AAAA,IACF;AACA,IAAA,aAAA,CAAc,IAAI,CAAA;AAClB,IAAA,MAAA,CACG,eAAA,CAAgB,EAAE,GAAA,EAAK,MAAA,EAAQ,CAAA,CAC/B,IAAA,CAAK,CAAC,MAAA,KAAW;AAChB,MAAA,IAAI,MAAA,CAAO,WAAW,SAAA,EAAW;AAC/B,QAAA,UAAA,EAAW;AACX,QAAA;AAAA,MACF;AACA,MAAA,WAAA,CAAY,WAAA,CAAY,MAAM,CAAC,CAAA;AAAA,IACjC,CAAC,CAAA,CACA,KAAA,CAAM,MAAM;AACX,MAAA,WAAA,CAAA,QAAA,cAA0C;AAAA,IAC5C,CAAC,CAAA,CACA,OAAA,CAAQ,MAAM;AACb,MAAA,aAAA,CAAc,KAAK,CAAA;AAAA,IACrB,CAAC,CAAA;AAAA,EACL,GAAG,CAAC,MAAA,EAAQ,KAAK,UAAA,EAAY,MAAA,EAAQ,UAAU,CAAC,CAAA;AAEhD,EAAA,OAAO,EAAE,GAAA,EAAK,UAAA,EAAY,YAAY,QAAA,EAAU,MAAA,EAAQ,eAAe,MAAA,EAAO;AAChF;AC1DA,SAASoB,iBAAAA,CACP,QAAA,EACA,MAAA,EACA,MAAA,EACe;AACf,EAAA,IAAI,aAAa,IAAA,EAAM;AACrB,IAAA,OAAO,IAAA;AAAA,EACT;AACA,EAAA,IAAI,QAAA,KAAA,UAAA,iBAA+C;AACjD,IAAA,OAAO,YAAY,MAAA,CAAO,aAAA,EAAe,EAAE,KAAA,EAAO,QAAQ,CAAA;AAAA,EAC5D;AACA,EAAA,IAAI,QAAA,KAAA,cAAA,qBAAmD;AACrD,IAAA,OAAO,MAAA,CAAO,iBAAA;AAAA,EAChB;AACA,EAAA,IAAI,QAAA,KAAA,WAAA,kBAAgD;AAClD,IAAA,OAAO,MAAA,CAAO,cAAA;AAAA,EAChB;AACA,EAAA,IAAI,QAAA,KAAA,aAAA,mBAAiD;AACnD,IAAA,OAAO,MAAA,CAAO,eAAA;AAAA,EAChB;AACA,EAAA,OAAO,MAAA,CAAO,WAAA;AAChB;AAGO,SAAS,mBAAA,CAAoB;AAAA,EAClC,MAAA;AAAA,EACA,aAAA,GAAgB,yBAAA;AAAA,EAChB,KAAA,EAAO,SAAA;AAAA,EACP,MAAA,EAAQ,UAAA;AAAA,EACR,YAAA;AAAA,EACA,UAAA;AAAA,EACA;AACF,CAAA,EAAqD;AACnD,EAAA,MAAM,KAAA,GAAQ,aAAa,SAAS,CAAA;AACpC,EAAA,MAAM3B,OAAAA,GAAS,cAAc,KAAK,CAAA;AAClC,EAAA,MAAM,MAAA,GAASD,OAAAA;AAAA,IACb,OAAO,EAAE,GAAG,gCAAA,EAAkC,GAAG,UAAA,EAAW,CAAA;AAAA,IAC5D,CAAC,UAAU;AAAA,GACb;AAEA,EAAA,MAAM,CAAC,MAAA,EAAQ,SAAS,CAAA,GAAIM,SAAiB,aAAa,CAAA;AAC1D,EAAA,MAAM,EAAE,GAAA,EAAK,UAAA,EAAY,UAAA,EAAY,UAAU,MAAA,EAAQ,aAAA,EAAe,MAAA,EAAO,GAC3E,kBAAA,CAAmB,EAAE,MAAA,EAAQ,MAAA,EAAQ,YAAY,CAAA;AACnD,EAAA,MAAM,KAAA,GAAQsB,iBAAAA,CAAiB,QAAA,EAAU,MAAA,EAAQ,MAAM,CAAA;AACvD,EAAA,MAAM,WAAA,GAAc,aAChB,CAAC3B,OAAAA,CAAO,eAAeA,OAAAA,CAAO,qBAAqB,IACnDA,OAAAA,CAAO,aAAA;AAEX,EAAA,uBACEQ,IAAAA;AAAA,IAACE,IAAAA;AAAA,IAAA;AAAA,MACC,OAAOV,OAAAA,CAAO,IAAA;AAAA,MACd,MAAA,EAAQ,gBAAA,CAAiB,WAAA,CAAY,mBAAA,EAAqB,YAAY,CAAA;AAAA,MAEtE,QAAA,EAAA;AAAA,wBAAAC,IAACQ,IAAAA,EAAA,EAAK,OAAOT,OAAAA,CAAO,KAAA,EAAQ,iBAAO,SAAA,EAAU,CAAA;AAAA,wBAC7CC,GAAAA,CAACQ,IAAAA,EAAA,EAAK,OAAOT,OAAAA,CAAO,QAAA,EAAW,QAAA,EAAA,WAAA,CAAY,MAAA,CAAO,eAAA,EAAiB,EAAE,KAAA,EAAO,MAAA,EAAQ,CAAA,EAAE,CAAA;AAAA,wBAEtFC,IAACQ,IAAAA,EAAA,EAAK,OAAOT,OAAAA,CAAO,KAAA,EAAQ,iBAAO,WAAA,EAAY,CAAA;AAAA,wBAC/CC,GAAAA;AAAA,UAAC,qBAAA;AAAA,UAAA;AAAA,YACC,QAAA,EAAU,UAAA;AAAA,YACV,YAAY,MAAA,CAAO,gBAAA;AAAA,YACnB,QAAA,EAAU,MAAA;AAAA,YACV,YAAA;AAAA,YACA,KAAA;AAAA,YACA,QAAA,EAAU,CAAC,MAAA,KAAiB;AAC1B,cAAA,SAAA,CAAU,MAAM,CAAA;AAChB,cAAA,MAAA,CAAO,EAAE,CAAA;AACT,cAAA,aAAA,CAAc,EAAE,CAAA;AAAA,YAClB;AAAA;AAAA,SACF;AAAA,wBAEAA,IAACQ,IAAAA,EAAA,EAAK,OAAOT,OAAAA,CAAO,KAAA,EAAQ,iBAAO,QAAA,EAAS,CAAA;AAAA,wBAC5CC,GAAAA;AAAA,UAAC,cAAA;AAAA,UAAA;AAAA,YACC,mBAAmB,MAAA,CAAO,cAAA;AAAA,YAC1B,oBAAoB,MAAA,CAAO,QAAA;AAAA,YAC3B,QAAA,EAAU,UAAA;AAAA,YACV,WAAW,MAAA,CAAO,cAAA;AAAA,YAClB,YAAY,MAAA,CAAO,QAAA;AAAA,YACnB,MAAA,EAAQ,MAAA;AAAA,YACR,QAAQ,WAAA,CAAY,kBAAA;AAAA,YACpB,YAAA;AAAA,YACA,KAAA;AAAA,YACA,KAAA,EAAO,GAAA;AAAA,YACP,QAAA,EAAU;AAAA;AAAA,SACZ;AAAA,wBAEAA,IAACQ,IAAAA,EAAA,EAAK,OAAOT,OAAAA,CAAO,KAAA,EAAQ,iBAAO,YAAA,EAAa,CAAA;AAAA,wBAChDC,GAAAA;AAAA,UAAC,cAAA;AAAA,UAAA;AAAA,YACC,mBAAmB,MAAA,CAAO,kBAAA;AAAA,YAC1B,oBAAoB,MAAA,CAAO,YAAA;AAAA,YAC3B,QAAA,EAAU,UAAA;AAAA,YACV,WAAW,MAAA,CAAO,kBAAA;AAAA,YAClB,YAAY,MAAA,CAAO,YAAA;AAAA,YACnB,MAAA,EAAQ,MAAA;AAAA,YACR,QAAQ,WAAA,CAAY,sBAAA;AAAA,YACpB,YAAA;AAAA,YACA,KAAA;AAAA,YACA,KAAA,EAAO,UAAA;AAAA,YACP,QAAA,EAAU;AAAA;AAAA,SACZ;AAAA,QAEC,KAAA,KAAU,uBACTA,GAAAA;AAAA,UAACQ,IAAAA;AAAA,UAAA;AAAA,YACC,OAAOT,OAAAA,CAAO,SAAA;AAAA,YACd,MAAA,EAAQ,gBAAA,CAAiB,WAAA,CAAY,oBAAA,EAAsB,YAAY,CAAA;AAAA,YAEtE,QAAA,EAAA;AAAA;AAAA,SACH,GACE,IAAA;AAAA,wBAEJC,GAAAA;AAAA,UAACY,gBAAAA;AAAA,UAAA;AAAA,YACC,mBAAmB,MAAA,CAAO,MAAA;AAAA,YAC1B,kBAAA,EAAoB,UAAA,GAAa,MAAA,CAAO,UAAA,GAAa,MAAA,CAAO,MAAA;AAAA,YAC5D,iBAAA,EAAkB,QAAA;AAAA,YAClB,QAAA,EAAU,UAAA;AAAA,YACV,KAAA,EAAO,WAAA;AAAA,YACP,MAAA,EAAQ,gBAAA,CAAiB,WAAA,CAAY,qBAAA,EAAuB,YAAY,CAAA;AAAA,YACxE,OAAA,EAAS,MAAA;AAAA,YAER,QAAA,EAAA,UAAA,mBACCZ,GAAAA,CAACe,iBAAAA,EAAA,EAAkB,KAAA,EAAO,KAAA,CAAM,OAAO,SAAA,EAAW,IAAA,EAAK,SAAQ,CAAA,mBAE/Df,IAACQ,IAAAA,EAAA,EAAK,OAAOT,OAAAA,CAAO,iBAAA,EAAoB,iBAAO,MAAA,EAAO;AAAA;AAAA,SAE1D;AAAA,wBAEAC,GAAAA;AAAA,UAACY,gBAAAA;AAAA,UAAA;AAAA,YACC,mBAAmB,MAAA,CAAO,UAAA;AAAA,YAC1B,oBAAoB,MAAA,CAAO,MAAA;AAAA,YAC3B,iBAAA,EAAkB,QAAA;AAAA,YAClB,QAAA,EAAU,UAAA;AAAA,YACV,OAAOb,OAAAA,CAAO,UAAA;AAAA,YACd,MAAA,EAAQ,gBAAA,CAAiB,WAAA,CAAY,qBAAA,EAAuB,YAAY,CAAA;AAAA,YACxE,OAAA,EAAS,QAAA;AAAA,YAET,QAAA,kBAAAC,IAACQ,IAAAA,EAAA,EAAK,OAAOT,OAAAA,CAAO,QAAA,EAAW,iBAAO,MAAA,EAAO;AAAA;AAAA;AAC/C;AAAA;AAAA,GACF;AAEJ;AC/IO,SAAS,cAAA,CAAe;AAAA,EAC7B,MAAA;AAAA,EACA,aAAA;AAAA,EACA,KAAA,EAAO,SAAA;AAAA,EACP,MAAA,EAAQ,UAAA;AAAA,EACR,YAAA;AAAA,EACA;AACF,CAAA,EAAgD;AAC9C,EAAA,MAAM,KAAA,GAAQ,aAAa,SAAS,CAAA;AACpC,EAAA,MAAMA,OAAAA,GAAS,cAAc,KAAK,CAAA;AAClC,EAAA,MAAM,MAAA,GAASD,OAAAA;AAAA,IACb,OAAO,EAAE,GAAG,gCAAA,EAAkC,GAAG,UAAA,EAAW,CAAA;AAAA,IAC5D,CAAC,UAAU;AAAA,GACb;AACA,EAAA,MAAM,CAAC,QAAA,EAAU,WAAW,CAAA,GAAIM,SAAkB,KAAK,CAAA;AACvD,EAAA,MAAM,UAAA,GAAa,gBAAA,CAAiB,WAAA,CAAY,cAAA,EAAgB,YAAY,CAAA;AAE5E,EAAA,IAAI,QAAA,EAAU;AACZ,IAAA,uBACEJ,IAACS,IAAAA,EAAA,EAAK,OAAOV,OAAAA,CAAO,IAAA,EAAM,MAAA,EAAQ,UAAA,EAChC,QAAA,kBAAAC,GAAAA;AAAA,MAAC,mBAAA;AAAA,MAAA;AAAA,QACC,MAAA;AAAA,QACA,aAAA;AAAA,QACA,MAAA,EAAQ,UAAA;AAAA,QACR,YAAA;AAAA,QACA,KAAA;AAAA,QACA,QAAA,EAAU,SAAA;AAAA,QACV,UAAA,EAAY;AAAA;AAAA,KACd,EACF,CAAA;AAAA,EAEJ;AAEA,EAAA,uBACEO,KAACE,IAAAA,EAAA,EAAK,OAAOV,OAAAA,CAAO,IAAA,EAAM,QAAQ,UAAA,EAChC,QAAA,EAAA;AAAA,oBAAAC,IAACQ,IAAAA,EAAA,EAAK,OAAOT,OAAAA,CAAO,KAAA,EAAQ,iBAAO,UAAA,EAAW,CAAA;AAAA,oBAC9CC,IAACQ,IAAAA,EAAA,EAAK,OAAOT,OAAAA,CAAO,QAAA,EAAW,iBAAO,gBAAA,EAAiB,CAAA;AAAA,oBAEvDC,GAAAA;AAAA,MAACY,gBAAAA;AAAA,MAAA;AAAA,QACC,mBAAmB,MAAA,CAAO,eAAA;AAAA,QAC1B,oBAAoB,MAAA,CAAO,WAAA;AAAA,QAC3B,iBAAA,EAAkB,QAAA;AAAA,QAClB,OAAOb,OAAAA,CAAO,aAAA;AAAA,QACd,MAAA,EAAQ,gBAAA,CAAiB,WAAA,CAAY,oBAAA,EAAsB,YAAY,CAAA;AAAA,QACvE,OAAA,EAAS,MAAY,WAAA,CAAY,IAAI,CAAA;AAAA,QAErC,QAAA,kBAAAC,IAACQ,IAAAA,EAAA,EAAK,OAAOT,OAAAA,CAAO,iBAAA,EAAoB,iBAAO,WAAA,EAAY;AAAA;AAAA,KAC7D;AAAA,oBAEAC,GAAAA;AAAA,MAACY,gBAAAA;AAAA,MAAA;AAAA,QACC,mBAAmB,MAAA,CAAO,aAAA;AAAA,QAC1B,oBAAoB,MAAA,CAAO,SAAA;AAAA,QAC3B,iBAAA,EAAkB,QAAA;AAAA,QAClB,OAAOb,OAAAA,CAAO,eAAA;AAAA,QACd,MAAA,EAAQ,gBAAA,CAAiB,WAAA,CAAY,kBAAA,EAAoB,YAAY,CAAA;AAAA,QACrE,OAAA,EAAS,SAAA;AAAA,QAET,QAAA,kBAAAC,IAACQ,IAAAA,EAAA,EAAK,OAAOT,OAAAA,CAAO,mBAAA,EAAsB,iBAAO,SAAA,EAAU;AAAA;AAAA;AAC7D,GAAA,EACF,CAAA;AAEJ;AC/DO,SAAS,mBAAA,CAAoB;AAAA,EAClC,MAAA;AAAA,EACA,aAAA;AAAA,EACA;AACF,CAAA,EAAuD;AACrD,EAAA,MAAM,CAAC,MAAA,EAAQ,SAAS,CAAA,GAAIK,SAAkB,aAAa,CAAA;AAC3D,EAAA,MAAM,CAAC,SAAA,EAAW,YAAY,CAAA,GAAIA,SAAkB,KAAK,CAAA;AACzD,EAAA,MAAM,CAAC,MAAA,EAAQ,SAAS,CAAA,GAAIA,SAAkB,KAAK,CAAA;AAEnD,EAAA,MAAM,OAAA,GAAUE,YAAY,MAAY;AACtC,IAAA,SAAA,CAAU,KAAK,CAAA;AACf,IAAA,YAAA,CAAa,IAAI,CAAA;AACjB,IAAA,MAAA,CACG,gBAAA,EAAiB,CACjB,IAAA,CAAK,CAAC,EAAA,KAAO;AACZ,MAAA,IAAI,EAAA,EAAI;AACN,QAAA,SAAA,CAAU,KAAK,CAAA;AACf,QAAA,SAAA,GAAY,KAAK,CAAA;AACjB,QAAA;AAAA,MACF;AACA,MAAA,SAAA,CAAU,IAAI,CAAA;AAAA,IAChB,CAAC,CAAA,CACA,KAAA,CAAM,MAAM;AACX,MAAA,SAAA,CAAU,IAAI,CAAA;AAAA,IAChB,CAAC,CAAA,CACA,OAAA,CAAQ,MAAM;AACb,MAAA,YAAA,CAAa,KAAK,CAAA;AAAA,IACpB,CAAC,CAAA;AAAA,EACL,CAAA,EAAG,CAAC,MAAA,EAAQ,SAAS,CAAC,CAAA;AAEtB,EAAA,MAAM,WAAA,GAAcA,YAAY,MAAY;AAC1C,IAAA,SAAA,CAAU,IAAI,CAAA;AACd,IAAA,SAAA,GAAY,IAAI,CAAA;AAAA,EAClB,CAAA,EAAG,CAAC,SAAS,CAAC,CAAA;AAEd,EAAA,OAAO,EAAE,MAAA,EAAQ,SAAA,EAAW,MAAA,EAAQ,SAAS,WAAA,EAAY;AAC3D;ACrBO,SAAS,qBAAA,CAAsB;AAAA,EACpC,MAAA;AAAA,EACA,aAAA;AAAA,EACA,KAAA,EAAO,SAAA;AAAA,EACP,MAAA,EAAQ,UAAA;AAAA,EACR,YAAA;AAAA,EACA,YAAA;AAAA,EACA;AACF,CAAA,EAAuD;AACrD,EAAA,MAAM,KAAA,GAAQ,aAAa,SAAS,CAAA;AACpC,EAAA,MAAMP,OAAAA,GAAS,cAAc,KAAK,CAAA;AAClC,EAAA,MAAM,MAAA,GAASD,OAAAA;AAAA,IACb,OAAO,EAAE,GAAG,kCAAA,EAAoC,GAAG,UAAA,EAAW,CAAA;AAAA,IAC9D,CAAC,UAAU;AAAA,GACb;AACA,EAAA,MAAM,oBAAA,GAAuBA,OAAAA;AAAA,IAC3B,OAAO,EAAE,GAAG,gCAAA,EAAkC,GAAG,YAAA,EAAa,CAAA;AAAA,IAC9D,CAAC,YAAY;AAAA,GACf;AAEA,EAAA,MAAM,CAAC,SAAA,EAAW,YAAY,CAAA,GAAIM,SAAkB,KAAK,CAAA;AACzD,EAAA,MAAM,EAAE,MAAA,EAAQ,SAAA,EAAW,QAAQ,OAAA,EAAS,WAAA,KAAgB,mBAAA,CAAoB;AAAA,IAC9E,MAAA;AAAA,IACA,aAAA;AAAA,IACA;AAAA,GACD,CAAA;AAED,EAAA,MAAM,iBAAiB,MAAY;AACjC,IAAA,YAAA,CAAa,KAAK,CAAA;AAClB,IAAA,WAAA,EAAY;AAAA,EACd,CAAA;AAEA,EAAA,MAAM,kBAAA,GAAqB,YACvB,CAACL,OAAAA,CAAO,iBAAiBA,OAAAA,CAAO,qBAAqB,IACrDA,OAAAA,CAAO,eAAA;AAEX,EAAA,uBACEQ,IAAAA;AAAA,IAACE,IAAAA;AAAA,IAAA;AAAA,MACC,OAAOV,OAAAA,CAAO,IAAA;AAAA,MACd,MAAA,EAAQ,gBAAA,CAAiB,WAAA,CAAY,iBAAA,EAAmB,YAAY,CAAA;AAAA,MAEpE,QAAA,EAAA;AAAA,wBAAAC,IAACQ,IAAAA,EAAA,EAAK,OAAOT,OAAAA,CAAO,KAAA,EAAQ,iBAAO,KAAA,EAAM,CAAA;AAAA,wBACzCC,IAACQ,IAAAA,EAAA,EAAK,OAAOT,OAAAA,CAAO,QAAA,EAAW,iBAAO,WAAA,EAAY,CAAA;AAAA,wBAClDC,GAAAA;AAAA,UAACQ,IAAAA;AAAA,UAAA;AAAA,YACC,OAAOT,OAAAA,CAAO,UAAA;AAAA,YACd,MAAA,EAAQ,gBAAA,CAAiB,WAAA,CAAY,uBAAA,EAAyB,YAAY,CAAA;AAAA,YAEzE,QAAA,EAAA,MAAA,GAAS,MAAA,CAAO,aAAA,GAAgB,MAAA,CAAO;AAAA;AAAA,SAC1C;AAAA,QAEC,yBACCC,GAAAA;AAAA,UAACQ,IAAAA;AAAA,UAAA;AAAA,YACC,OAAOT,OAAAA,CAAO,SAAA;AAAA,YACd,MAAA,EAAQ,gBAAA,CAAiB,WAAA,CAAY,sBAAA,EAAwB,YAAY,CAAA;AAAA,YAExE,QAAA,EAAA,MAAA,CAAO;AAAA;AAAA,SACV,GACE,IAAA;AAAA,QAEH,YAAA;AAAa;AAAA;AAAA,GAChB;AAGF,EAAA,SAAS,YAAA,GAA6B;AACpC,IAAA,IAAI,SAAA,EAAW;AACb,MAAA,uBACEC,GAAAA;AAAA,QAAC,mBAAA;AAAA,QAAA;AAAA,UACC,MAAA;AAAA,UACA,MAAA,EAAQ,oBAAA;AAAA,UACR,YAAA;AAAA,UACA,KAAA;AAAA,UACA,QAAA,EAAU,MAAY,YAAA,CAAa,KAAK,CAAA;AAAA,UACxC,UAAA,EAAY;AAAA;AAAA,OACd;AAAA,IAEJ;AACA,IAAA,IAAI,MAAA,EAAQ;AACV,MAAA,uBACEA,GAAAA;AAAA,QAACY,gBAAAA;AAAA,QAAA;AAAA,UACC,mBAAmB,MAAA,CAAO,WAAA;AAAA,UAC1B,kBAAA,EAAoB,SAAA,GAAY,MAAA,CAAO,SAAA,GAAY,MAAA,CAAO,OAAA;AAAA,UAC1D,iBAAA,EAAkB,QAAA;AAAA,UAClB,QAAA,EAAU,SAAA;AAAA,UACV,KAAA,EAAO,kBAAA;AAAA,UACP,MAAA,EAAQ,gBAAA,CAAiB,WAAA,CAAY,wBAAA,EAA0B,YAAY,CAAA;AAAA,UAC3E,OAAA,EAAS,OAAA;AAAA,UAER,QAAA,EAAA,SAAA,mBACCZ,GAAAA,CAACe,iBAAAA,EAAA,EAAkB,KAAA,EAAO,KAAA,CAAM,OAAO,OAAA,EAAS,IAAA,EAAK,SAAQ,CAAA,mBAE7Df,IAACQ,IAAAA,EAAA,EAAK,OAAOT,OAAAA,CAAO,mBAAA,EAAsB,iBAAO,OAAA,EAAQ;AAAA;AAAA,OAE7D;AAAA,IAEJ;AACA,IAAA,uBACEC,GAAAA;AAAA,MAACY,gBAAAA;AAAA,MAAA;AAAA,QACC,mBAAmB,MAAA,CAAO,UAAA;AAAA,QAC1B,oBAAoB,MAAA,CAAO,MAAA;AAAA,QAC3B,iBAAA,EAAkB,QAAA;AAAA,QAClB,OAAOb,OAAAA,CAAO,aAAA;AAAA,QACd,MAAA,EAAQ,gBAAA,CAAiB,WAAA,CAAY,uBAAA,EAAyB,YAAY,CAAA;AAAA,QAC1E,OAAA,EAAS,MAAY,YAAA,CAAa,IAAI,CAAA;AAAA,QAEtC,QAAA,kBAAAC,IAACQ,IAAAA,EAAA,EAAK,OAAOT,OAAAA,CAAO,iBAAA,EAAoB,iBAAO,MAAA,EAAO;AAAA;AAAA,KACxD;AAAA,EAEJ;AACF;;;ACzJO,IAAW,mBAAA,qBAAA4B,oBAAAA,KAAX;AAEL,EAAAA,qBAAA,OAAA,CAAA,GAAQ,OAAA;AAER,EAAAA,qBAAA,UAAA,CAAA,GAAW,UAAA;AAJK,EAAA,OAAAA,oBAAAA;AAAA,CAAA,EAAA,mBAAA,IAAA,EAAA;;;ACMX,SAAS,kBAAA,GAAsC;AACpD,EAAA,IAAI,OAAO,WAAW,WAAA,EAAa;AACjC,IAAA,OAAO,IAAA;AAAA,EACT;AAGA,EAAA,MAAM,kBAAyC,MAAA,CAA2B,QAAA;AAC1E,EAAA,IAAI,oBAAoB,MAAA,EAAW;AACjC,IAAA,OAAO,IAAA;AAAA,EACT;AACA,EAAA,OAAO,eAAA;AACT;;;ACKA,IAAM,sBAAA,GAAyB,oBAAA;AAC/B,IAAM,yBAAA,GAA4B,uBAAA;AAClC,IAAM,gBAAA,GAAmB,WAAA;AACzB,IAAM,mBAAA,GAAsB,cAAA;AAC5B,IAAM,aAAA,GAAgB,SAAA;AACtB,IAAM,wBAAA,GAA2B,YAAA;AACjC,IAAM,uBAAA,GAA4C,WAAA;AAClD,IAAM,oBAAA,GAAyC,QAAA;AAG/C,SAAS,kBAAA,CAAmB,UAAkB,SAAA,EAA2B;AACvE,EAAA,OAAO,GAAG,QAAQ,CAAA,CAAA,EAAI,gBAAgB,CAAA,CAAA,EAAI,kBAAA,CAAmB,SAAS,CAAC,CAAA,CAAA;AACzE;AAGA,SAAS,gBAAA,GAA2C;AAClD,EAAA,MAAM,kBAAkB,kBAAA,EAAmB;AAC3C,EAAA,IAAI,oBAAoB,IAAA,EAAM;AAC5B,IAAA,OAAO,IAAA;AAAA,EACT;AACA,EAAA,OAAO,IAAI,eAAA,CAAgB,eAAA,CAAgB,MAAM,CAAA;AACnD;AASO,SAAS,kBAAkB,SAAA,EAAyB;AACzD,EAAA,MAAM,kBAAkB,kBAAA,EAAmB;AAC3C,EAAA,IAAI,oBAAoB,IAAA,EAAM;AAC5B,IAAA;AAAA,EACF;AACA,EAAA,eAAA,CAAgB,MAAA,CAAO,kBAAA,CAAmB,sBAAA,EAAwB,SAAS,CAAC,CAAA;AAC9E;AAUO,SAAS,yBAAyB,SAAA,EAAyB;AAChE,EAAA,MAAM,kBAAkB,kBAAA,EAAmB;AAC3C,EAAA,IAAI,oBAAoB,IAAA,EAAM;AAC5B,IAAA;AAAA,EACF;AACA,EAAA,eAAA,CAAgB,MAAA,CAAO,kBAAA,CAAmB,yBAAA,EAA2B,SAAS,CAAC,CAAA;AACjF;AAOO,SAAS,gBAAA,GAA4C;AAC1D,EAAA,MAAM,SAAS,gBAAA,EAAiB;AAChC,EAAA,IAAI,WAAW,IAAA,EAAM;AACnB,IAAA,OAAO,IAAA;AAAA,EACT;AACA,EAAA,MAAM,KAAA,GAAQ,MAAA,CAAO,GAAA,CAAI,mBAAmB,CAAA;AAC5C,EAAA,IAAI,UAAU,uBAAA,EAAyB;AACrC,IAAA,OAAO,uBAAA;AAAA,EACT;AACA,EAAA,IAAI,UAAU,oBAAA,EAAsB;AAClC,IAAA,OAAO,oBAAA;AAAA,EACT;AACA,EAAA,OAAO,IAAA;AACT;AAOO,SAAS,qBAAA,GAAiC;AAC/C,EAAA,MAAM,SAAS,gBAAA,EAAiB;AAChC,EAAA,IAAI,WAAW,IAAA,EAAM;AACnB,IAAA,OAAO,KAAA;AAAA,EACT;AACA,EAAA,OAAO,MAAA,CAAO,GAAA,CAAI,aAAa,CAAA,KAAM,wBAAA;AACvC;;;ACzGO,IAAW,qBAAA,qBAAAC,sBAAAA,KAAX;AAEL,EAAAA,uBAAA,MAAA,CAAA,GAAO,MAAA;AAEP,EAAAA,uBAAA,SAAA,CAAA,GAAU,SAAA;AAEV,EAAAA,uBAAA,SAAA,CAAA,GAAU,SAAA;AAEV,EAAAA,uBAAA,OAAA,CAAA,GAAQ,OAAA;AARQ,EAAA,OAAAA,sBAAAA;AAAA,CAAA,EAAA,qBAAA,IAAA,EAAA;;;ACaX,SAAS,iBAAiB,KAAA,EAAwC;AACvE,EAAA,MAAM,MAAA,GAAS,MAAM,OAAA,CAAQ,IAAA,EAAM,GAAG,CAAA,CAAE,OAAA,CAAQ,MAAM,GAAG,CAAA;AACzD,EAAA,MAAM,MAAA,GAAS,MAAA,CAAO,MAAA,CAAO,IAAA,CAAK,IAAA,CAAK,OAAO,MAAA,GAAS,CAAC,CAAA,GAAI,CAAA,EAAG,GAAG,CAAA;AAClE,EAAA,MAAM,MAAA,GAAS,KAAK,MAAM,CAAA;AAC1B,EAAA,MAAM,QAAQ,IAAI,UAAA,CAAW,IAAI,WAAA,CAAY,MAAA,CAAO,MAAM,CAAC,CAAA;AAC3D,EAAA,KAAA,IAAS,IAAI,CAAA,EAAG,CAAA,GAAI,MAAA,CAAO,MAAA,EAAQ,KAAK,CAAA,EAAG;AACzC,IAAA,KAAA,CAAM,CAAC,CAAA,GAAI,MAAA,CAAO,UAAA,CAAW,CAAC,CAAA;AAAA,EAChC;AACA,EAAA,OAAO,KAAA;AACT;AAGO,SAAS,iBAAiB,MAAA,EAA0C;AACzE,EAAA,MAAM,QAAQ,MAAA,YAAkB,UAAA,GAAa,MAAA,GAAS,IAAI,WAAW,MAAM,CAAA;AAC3E,EAAA,IAAI,MAAA,GAAS,EAAA;AACb,EAAA,KAAA,IAAS,IAAI,CAAA,EAAG,CAAA,GAAI,KAAA,CAAM,MAAA,EAAQ,KAAK,CAAA,EAAG;AACxC,IAAA,MAAA,IAAU,MAAA,CAAO,YAAA,CAAa,KAAA,CAAM,CAAC,CAAW,CAAA;AAAA,EAClD;AAGA,EAAA,OAAO,IAAA,CAAK,MAAM,CAAA,CAAE,OAAA,CAAQ,KAAA,EAAO,GAAG,CAAA,CAAE,OAAA,CAAQ,KAAA,EAAO,GAAG,CAAA,CAAE,OAAA,CAAQ,MAAM,EAAE,CAAA;AAC9E;;;ACZA,IAAM,eAAA,GAAkB,YAAA;AAGxB,SAAS,cAAc,KAAA,EAA6D;AAClF,EAAA,IAAI,CAAC,KAAA,CAAM,OAAA,CAAQ,KAAK,CAAA,EAAG;AACzB,IAAA,OAAO,MAAA;AAAA,EACT;AACA,EAAA,OAAO,KAAA,CAAM,GAAA,CAAI,CAAC,KAAA,KAAyC;AACzD,IAAA,MAAM,UAAA,GAAa,KAAA;AACnB,IAAA,OAAO;AAAA,MACL,IAAA,EAAM,eAAA;AAAA,MACN,EAAA,EAAI,gBAAA,CAAiB,UAAA,CAAW,EAAE,CAAA;AAAA,MAClC,YAAY,UAAA,CAAW;AAAA,KACzB;AAAA,EACF,CAAC,CAAA;AACH;AAGO,SAAS,kBACd,OAAA,EACoC;AACpC,EAAA,MAAM,OAAO,OAAA,CAAQ,IAAA;AACrB,EAAA,OAAO;AAAA,IACL,GAAI,OAAA;AAAA,IACJ,SAAA,EAAW,gBAAA,CAAiB,OAAA,CAAQ,SAAmB,CAAA;AAAA,IACvD,IAAA,EAAM,EAAE,GAAG,IAAA,EAAM,IAAI,gBAAA,CAAiB,IAAA,CAAK,EAAE,CAAA,EAAE;AAAA,IAC/C,kBAAA,EAAoB,aAAA,CAAc,OAAA,CAAQ,kBAAkB;AAAA,GAC9D;AACF;AAGO,SAAS,iBACd,OAAA,EACmC;AACnC,EAAA,OAAO;AAAA,IACL,GAAI,OAAA;AAAA,IACJ,SAAA,EAAW,gBAAA,CAAiB,OAAA,CAAQ,SAAmB,CAAA;AAAA,IACvD,gBAAA,EAAkB,aAAA,CAAc,OAAA,CAAQ,gBAAgB;AAAA,GAC1D;AACF;AAGA,SAAS,eAAe,QAAA,EAAsD;AAC5E,EAAA,OAAO,OAAO,QAAA,CAAS,aAAA,KAAkB,aAAa,QAAA,CAAS,aAAA,KAAkB,EAAC;AACpF;AAGO,SAAS,kBACd,UAAA,EACyB;AACzB,EAAA,MAAM,WAAW,UAAA,CAAW,QAAA;AAC5B,EAAA,OAAO;AAAA,IACL,IAAI,UAAA,CAAW,EAAA;AAAA,IACf,KAAA,EAAO,gBAAA,CAAiB,UAAA,CAAW,KAAK,CAAA;AAAA,IACxC,MAAM,UAAA,CAAW,IAAA;AAAA,IACjB,QAAA,EAAU;AAAA,MACR,iBAAA,EAAmB,gBAAA,CAAiB,QAAA,CAAS,iBAAiB,CAAA;AAAA,MAC9D,cAAA,EAAgB,gBAAA,CAAiB,QAAA,CAAS,cAAc,CAAA;AAAA,MACxD,UAAA,EAAY,eAAe,QAAQ;AAAA,KACrC;AAAA,IACA,sBAAA,EAAwB,WAAW,yBAAA;AAA0B,GAC/D;AACF;AAGO,SAAS,gBACd,UAAA,EACyB;AACzB,EAAA,MAAM,WAAW,UAAA,CAAW,QAAA;AAC5B,EAAA,MAAM,aACJ,QAAA,CAAS,UAAA,KAAe,OAAO,gBAAA,CAAiB,QAAA,CAAS,UAAU,CAAA,GAAI,IAAA;AACzE,EAAA,OAAO;AAAA,IACL,IAAI,UAAA,CAAW,EAAA;AAAA,IACf,KAAA,EAAO,gBAAA,CAAiB,UAAA,CAAW,KAAK,CAAA;AAAA,IACxC,MAAM,UAAA,CAAW,IAAA;AAAA,IACjB,QAAA,EAAU;AAAA,MACR,iBAAA,EAAmB,gBAAA,CAAiB,QAAA,CAAS,iBAAiB,CAAA;AAAA,MAC9D,cAAA,EAAgB,gBAAA,CAAiB,QAAA,CAAS,cAAc,CAAA;AAAA,MACxD,SAAA,EAAW,gBAAA,CAAiB,QAAA,CAAS,SAAS,CAAA;AAAA,MAC9C;AAAA,KACF;AAAA,IACA,sBAAA,EAAwB,WAAW,yBAAA;AAA0B,GAC/D;AACF;;;AChCA,IAAM,eAAA,GAAoC,WAAA;AAC1C,IAAM,YAAA,GAAiC,QAAA;AACvC,IAAM,kBAAA,GAAqB,CAAC,iBAAA,EAAmB,YAAY,CAAA;AAE3D,IAAM,SAAA,GAAY;AAAA,EAChB,uBAA6B;AAAA,IAC3B,OAAA,EAAS,4BAAA;AAAA,IACT,MAAA,EAAQ;AAAA,GACV;AAAA,EACA,6BAAgC;AAAA,IAC9B,OAAA,EAAS,+BAAA;AAAA,IACT,MAAA,EAAQ;AAAA;AAEZ,CAAA;AAGA,SAAS,aAAA,GAAyB;AAChC,EAAA,OACE,OAAO,MAAA,KAAW,WAAA,IAClB,OAAO,SAAA,KAAc,WAAA,IACrB,OAAO,SAAA,CAAU,WAAA,KAAgB,WAAA,IACjC,OAAO,MAAA,CAAO,mBAAA,KAAwB,WAAA;AAE1C;AAGA,SAAS,QAAA,CAAS,KAAa,IAAA,EAAkC;AAC/D,EAAA,OAAO,MAAM,GAAA,EAAK;AAAA,IAChB,MAAA,EAAQ,MAAA;AAAA,IACR,WAAA,EAAa,aAAA;AAAA,IACb,OAAA,EAAS,EAAE,cAAA,EAAgB,kBAAA,EAAmB;AAAA,IAC9C,IAAA,EAAM,IAAA,CAAK,SAAA,CAAU,IAAA,IAAQ,EAAE;AAAA,GAChC,CAAA;AACH;AAGA,eAAe,WAAA,CACb,MACA,QAAA,EACqC;AACrC,EAAA,MAAM,UAAA,GACJ,IAAA,KAAA,UAAA,kBACI,MAAM,SAAA,CAAU,YAAY,MAAA,CAAO;AAAA,IACjC,SAAA,EAAW,iBAAA,CAAkB,QAAA,CAAS,OAAO;AAAA,GAC9C,CAAA,GACD,MAAM,SAAA,CAAU,YAAY,GAAA,CAAI;AAAA,IAC9B,SAAA,EAAW,gBAAA,CAAiB,QAAA,CAAS,OAAO;AAAA,GAC7C,CAAA;AACP,EAAA,OAAO,UAAA;AACT;AAGA,SAAS,eAAA,CACP,IAAA,EACA,WAAA,EACA,UAAA,EACyB;AACzB,EAAA,OAAO,IAAA,KAAA,UAAA,kBACH,EAAE,WAAA,EAAa,mBAAA,EAAqB,iBAAA,CAAkB,UAAU,CAAA,EAAE,GAClE,EAAE,WAAA,EAAa,iBAAA,EAAmB,eAAA,CAAgB,UAAU,CAAA,EAAE;AACpE;AAGA,SAAS,gBAAA,CAAiB,MAA2B,SAAA,EAAyB;AAC5E,EAAA,IAAI,IAAA,KAAA,UAAA,iBAAuC;AACzC,IAAA,wBAAA,CAAyB,SAAS,CAAA;AAClC,IAAA;AAAA,EACF;AACA,EAAA,iBAAA,CAAkB,SAAS,CAAA;AAC7B;AAGA,SAAS,cAAc,MAAA,EAAmC;AACxD,EAAA,MAAM,IAAA,GAAO,MAAA,YAAkB,KAAA,GAAQ,MAAA,CAAO,IAAA,GAAO,EAAA;AACrD,EAAA,OAAO,kBAAA,CAAmB,QAAA,CAAS,IAAI,CAAA,GAAI,eAAA,GAAkB,YAAA;AAC/D;AAEO,SAAS,mBACd,UAAA,EAC0B;AAC1B,EAAA,MAAM,EAAE,IAAA,EAAM,SAAA,EAAW,SAAA,EAAU,GAAI,UAAA;AACvC,EAAA,MAAM,CAAC,MAAA,EAAQ,SAAS,CAAA,GAAIxB,QAAAA,CAAAA,MAAAA,YAA0D;AACtF,EAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAIA,SAAkC,IAAI,CAAA;AAChE,EAAA,MAAM,WAAA,GAAcN,OAAAA,CAAQ,aAAA,EAAe,EAAE,CAAA;AAE7C,EAAA,MAAM,OAAA,GAAUQ,WAAAA;AAAA,IACd,CAAC,IAAA,KAAoC;AACnC,MAAA,SAAA,CAAA,SAAA,eAAuC;AACvC,MAAA,IAAI,cAAc,MAAA,EAAW;AAC3B,QAAA,SAAA,CAAU,IAAI,CAAA;AACd,QAAA;AAAA,MACF;AACA,MAAA,MAAM,kBAAkB,kBAAA,EAAmB;AAC3C,MAAA,IAAI,IAAA,KAAA,OAAA,gBAAsC,oBAAoB,IAAA,EAAM;AAClE,QAAA,eAAA,CAAgB,OAAO,SAAS,CAAA;AAAA,MAClC;AAAA,IACF,CAAA;AAAA,IACA,CAAC,IAAA,EAAM,SAAA,EAAW,SAAS;AAAA,GAC7B;AAEA,EAAA,MAAM,KAAA,GAAQA,YAAY,MAAY;AACpC,IAAA,IAAI,CAAC,WAAA,EAAa;AAChB,MAAA,gBAAA,CAAiB,MAAM,SAAS,CAAA;AAChC,MAAA;AAAA,IACF;AACA,IAAA,SAAA,CAAA,SAAA,eAAuC;AACvC,IAAA,QAAA,CAAS,IAAI,CAAA;AAEb,IAAA,KAAA,CAAM,YAA2B;AAC/B,MAAA,IAAI;AACF,QAAA,MAAM,eAAA,GAAkB,MAAM,QAAA,CAAS,SAAA,CAAU,IAAI,CAAA,CAAE,OAAA,EAAS,EAAE,CAAA;AAElE,QAAA,IAAI,CAAC,gBAAgB,EAAA,EAAI;AACvB,UAAA,gBAAA,CAAiB,MAAM,SAAS,CAAA;AAChC,UAAA;AAAA,QACF;AACA,QAAA,MAAM,QAAA,GAAY,MAAM,eAAA,CAAgB,IAAA,EAAK;AAC7C,QAAA,MAAM,UAAA,GAAa,MAAM,WAAA,CAAY,IAAA,EAAM,QAAQ,CAAA;AACnD,QAAA,IAAI,eAAe,IAAA,EAAM;AAOvB,UAAA,IAAI,IAAA,KAAA,OAAA,cAAoC;AACtC,YAAA,gBAAA,CAAiB,MAAM,SAAS,CAAA;AAChC,YAAA;AAAA,UACF;AACA,UAAA,SAAA,CAAA,OAAA,aAAqC;AACrC,UAAA,QAAA,CAAS,YAAY,CAAA;AACrB,UAAA;AAAA,QACF;AACA,QAAA,MAAM,iBAAiB,MAAM,QAAA;AAAA,UAC3B,SAAA,CAAU,IAAI,CAAA,CAAE,MAAA;AAAA,UAChB,eAAA,CAAgB,IAAA,EAAM,QAAA,CAAS,WAAA,EAAa,UAAU;AAAA,SACxD;AACA,QAAA,IAAI,CAAC,eAAe,EAAA,EAAI;AACtB,UAAA,SAAA,CAAA,OAAA,aAAqC;AACrC,UAAA,QAAA,CAAS,YAAY,CAAA;AACrB,UAAA;AAAA,QACF;AAIA,QAAA,IAAI,IAAA,KAAA,UAAA,iBAAuC;AACzC,UAAA,MAAM,EAAE,OAAA,EAAQ,GAAK,MAAM,eAAe,IAAA,EAAK;AAC/C,UAAA,IAAI,CAAC,OAAA,EAAS;AACZ,YAAA,SAAA,CAAA,OAAA,aAAqC;AACrC,YAAA,QAAA,CAAS,YAAY,CAAA;AACrB,YAAA;AAAA,UACF;AACA,UAAA,OAAA,CAAQ,KAAA,CAAS,CAAA;AACjB,UAAA;AAAA,QACF;AACA,QAAA,MAAM,EAAE,IAAA,EAAK,GAAK,MAAM,eAAe,IAAA,EAAK;AAC5C,QAAA,OAAA,CAAQ,IAAI,CAAA;AAAA,MACd,SAAS,MAAA,EAAQ;AACf,QAAA,SAAA,CAAA,OAAA,aAAqC;AACrC,QAAA,QAAA,CAAS,aAAA,CAAc,MAAM,CAAC,CAAA;AAAA,MAChC;AAAA,IACF,CAAA,GAAG;AAAA,EACL,GAAG,CAAC,WAAA,EAAa,IAAA,EAAM,SAAA,EAAW,OAAO,CAAC,CAAA;AAE1C,EAAA,MAAM,kBAAA,GAAqBA,YAAY,MAAY;AACjD,IAAA,gBAAA,CAAiB,MAAM,SAAS,CAAA;AAAA,EAClC,CAAA,EAAG,CAAC,IAAA,EAAM,SAAS,CAAC,CAAA;AAEpB,EAAA,MAAM,KAAA,GAAQA,YAAY,MAAY;AACpC,IAAA,SAAA,CAAA,MAAA,YAAoC;AACpC,IAAA,QAAA,CAAS,IAAI,CAAA;AAAA,EACf,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,OAAOR,OAAAA;AAAA,IACL,OAAO,EAAE,MAAA,EAAQ,OAAO,WAAA,EAAa,KAAA,EAAO,oBAAoB,KAAA,EAAM,CAAA;AAAA,IACtE,CAAC,MAAA,EAAQ,KAAA,EAAO,WAAA,EAAa,KAAA,EAAO,oBAAoB,KAAK;AAAA,GAC/D;AACF;AC1NA,IAAM,kBAAA,GAAqB,GAAA;AAGpB,SAAS,kBAAA,CAAmB;AAAA,EACjC,SAAA,GAAY,kBAAA;AAAA,EACZ,KAAA,EAAO,SAAA;AAAA,EACP,MAAA,EAAQ,UAAA;AAAA,EACR;AACF,CAAA,EAAoD;AAClD,EAAA,MAAM,KAAA,GAAQ,aAAa,SAAS,CAAA;AACpC,EAAA,MAAMC,OAAAA,GAAS,cAAc,KAAK,CAAA;AAClC,EAAA,MAAM,MAAA,GAASD,OAAAA;AAAA,IACb,OAAO,EAAE,GAAG,4BAAA,EAA8B,GAAG,UAAA,EAAW,CAAA;AAAA,IACxD,CAAC,UAAU;AAAA,GACb;AACA,EAAA,MAAM,QAAA,GAAW,kBAAA,CAAmB,EAAE,IAAA,EAAA,OAAA,cAAiC,WAAW,CAAA;AAGlF,EAAA,MAAM,KAAA,GAAQ,QAAA,CAAS,KAAA,IAAS,gBAAA,EAAiB;AAEjD,EAAA,uBACES,KAACE,IAAAA,EAAA,EAAK,QAAQ,gBAAA,CAAiB,WAAA,CAAY,YAAA,EAAc,YAAY,CAAA,EAClE,QAAA,EAAA;AAAA,IAAA,KAAA,KAAU,IAAA,mBACTF,IAAAA,CAAAG,QAAAA,EAAA,EACE,QAAA,EAAA;AAAA,sBAAAV,GAAAA;AAAA,QAACQ,IAAAA;AAAA,QAAA;AAAA,UACC,OAAOT,OAAAA,CAAO,SAAA;AAAA,UACd,MAAA,EAAQ,gBAAA,CAAiB,WAAA,CAAY,iBAAA,EAAmB,YAAY,CAAA;AAAA,UAEnE,QAAA,EAAA,KAAA,KAAU,WAAA,GAAc,MAAA,CAAO,cAAA,GAAiB,MAAA,CAAO;AAAA;AAAA,OAC1D;AAAA,sBAGAC,GAAAA;AAAA,QAACY,gBAAAA;AAAA,QAAA;AAAA,UACC,mBAAmB,MAAA,CAAO,aAAA;AAAA,UAC1B,oBAAoB,MAAA,CAAO,aAAA;AAAA,UAC3B,iBAAA,EAAkB,QAAA;AAAA,UAClB,MAAA,EAAQ,gBAAA,CAAiB,WAAA,CAAY,oBAAA,EAAsB,YAAY,CAAA;AAAA,UACvE,OAAA,EAAS,MAAY,QAAA,CAAS,kBAAA,EAAmB;AAAA,UAEjD,QAAA,kBAAAZ,IAACQ,IAAAA,EAAA,EAAK,OAAOT,OAAAA,CAAO,QAAA,EAAW,iBAAO,aAAA,EAAc;AAAA;AAAA;AACtD,KAAA,EACF,CAAA,GACE,IAAA;AAAA,oBAEJC,GAAAA;AAAA,MAACY,gBAAAA;AAAA,MAAA;AAAA,QACC,mBAAmB,MAAA,CAAO,UAAA;AAAA,QAC1B,oBAAoB,MAAA,CAAO,YAAA;AAAA,QAC3B,iBAAA,EAAkB,QAAA;AAAA,QAClB,OAAOb,OAAAA,CAAO,eAAA;AAAA,QACd,MAAA,EAAQ,gBAAA,CAAiB,WAAA,CAAY,kBAAA,EAAoB,YAAY,CAAA;AAAA,QACrE,OAAA,EAAS,MAAY,QAAA,CAAS,KAAA,EAAM;AAAA,QAEpC,QAAA,kBAAAC,IAACQ,IAAAA,EAAA,EAAK,OAAOT,OAAAA,CAAO,mBAAA,EAAsB,iBAAO,YAAA,EAAa;AAAA;AAAA;AAChE,GAAA,EACF,CAAA;AAEJ;ACrDA,IAAM,mBAAA,GAAsB,GAAA;AAS5B,SAAS,eAAA,GAA0B;AACjC,EAAA,MAAM,kBAAkB,kBAAA,EAAmB;AAC3C,EAAA,IAAI,oBAAoB,IAAA,EAAM;AAC5B,IAAA,OAAO,mBAAA;AAAA,EACT;AACA,EAAA,OAAO,eAAA,CAAgB,QAAA;AACzB;AAGO,SAAS,mBAAA,CAAoB;AAAA,EAClC,SAAA;AAAA,EACA,KAAA,EAAO,SAAA;AAAA,EACP,MAAA,EAAQ,UAAA;AAAA,EACR;AACF,CAAA,EAAqD;AACnD,EAAA,MAAM,KAAA,GAAQ,aAAa,SAAS,CAAA;AACpC,EAAA,MAAMA,OAAAA,GAAS,cAAc,KAAK,CAAA;AAClC,EAAA,MAAM,MAAA,GAASD,OAAAA;AAAA,IACb,OAAO,EAAE,GAAG,+BAAA,EAAiC,GAAG,UAAA,EAAW,CAAA;AAAA,IAC3D,CAAC,UAAU;AAAA,GACb;AACA,EAAA,MAAM,MAAA,GAAS,aAAa,eAAA,EAAgB;AAC5C,EAAA,MAAM,WAAW,kBAAA,CAAmB;AAAA,IAClC,IAAA,EAAA,UAAA;AAAA,IACA,SAAA,EAAW;AAAA,GACZ,CAAA;AAGD,EAAA,MAAM,cAAA,GACJ,QAAA,CAAS,MAAA,KAAA,SAAA,kBAA4C,qBAAA,EAAsB;AAE7E,EAAA,uBACES,IAAAA;AAAA,IAACE,IAAAA;AAAA,IAAA;AAAA,MACC,OAAOV,OAAAA,CAAO,IAAA;AAAA,MACd,MAAA,EAAQ,gBAAA,CAAiB,WAAA,CAAY,eAAA,EAAiB,YAAY,CAAA;AAAA,MAElE,QAAA,EAAA;AAAA,wBAAAC,IAACQ,IAAAA,EAAA,EAAK,OAAOT,OAAAA,CAAO,KAAA,EAAQ,iBAAO,KAAA,EAAM,CAAA;AAAA,wBACzCC,IAACQ,IAAAA,EAAA,EAAK,OAAOT,OAAAA,CAAO,QAAA,EAAW,iBAAO,WAAA,EAAY,CAAA;AAAA,wBAClDC,IAACQ,IAAAA,EAAA,EAAK,OAAOT,OAAAA,CAAO,UAAA,EAAa,iBAAO,UAAA,EAAW,CAAA;AAAA,QAElD,iCACCC,GAAAA;AAAA,UAACQ,IAAAA;AAAA,UAAA;AAAA,YACC,OAAOT,OAAAA,CAAO,WAAA;AAAA,YACd,MAAA,EAAQ,gBAAA,CAAiB,WAAA,CAAY,sBAAA,EAAwB,YAAY,CAAA;AAAA,YAExE,QAAA,EAAA,MAAA,CAAO;AAAA;AAAA,SACV,GACE,IAAA;AAAA,wBAEJC,GAAAA;AAAA,UAACY,gBAAAA;AAAA,UAAA;AAAA,YACC,mBAAmB,MAAA,CAAO,OAAA;AAAA,YAC1B,oBAAoB,MAAA,CAAO,SAAA;AAAA,YAC3B,iBAAA,EAAkB,QAAA;AAAA,YAClB,OAAOb,OAAAA,CAAO,aAAA;AAAA,YACd,MAAA,EAAQ,gBAAA,CAAiB,WAAA,CAAY,kBAAA,EAAoB,YAAY,CAAA;AAAA,YACrE,OAAA,EAAS,MAAY,QAAA,CAAS,KAAA,EAAM;AAAA,YAEpC,QAAA,kBAAAC,IAACQ,IAAAA,EAAA,EAAK,OAAOT,OAAAA,CAAO,iBAAA,EAAoB,iBAAO,SAAA,EAAU;AAAA;AAAA;AAC3D;AAAA;AAAA,GACF;AAEJ;;;ACrGA,IAAM,SAAA,GAAY,qCAAA;AAGlB,SAAS,WAAA,GAA8B;AACrC,EAAA,IAAI;AACF,IAAA,IAAI,OAAO,iBAAiB,WAAA,EAAa;AACvC,MAAA,OAAO,IAAA;AAAA,IACT;AACA,IAAA,OAAO,YAAA;AAAA,EACT,CAAA,CAAA,MAAQ;AAEN,IAAA,OAAO,IAAA;AAAA,EACT;AACF;AAOO,SAAS,yBAAA,GAA2C;AACzD,EAAA,MAAM,QAAQ,WAAA,EAAY;AAC1B,EAAA,IAAI,UAAU,IAAA,EAAM;AAClB,IAAA,OAAO,IAAA;AAAA,EACT;AACA,EAAA,IAAI;AACF,IAAA,MAAM,KAAA,GAAQ,KAAA,CAAM,OAAA,CAAQ,SAAS,CAAA;AACrC,IAAA,OAAO,KAAA,KAAU,IAAA,IAAQ,KAAA,KAAU,EAAA,GAAK,IAAA,GAAO,KAAA;AAAA,EACjD,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,IAAA;AAAA,EACT;AACF;AAMO,SAAS,qBAAqB,MAAA,EAA6B;AAChE,EAAA,MAAM,QAAQ,WAAA,EAAY;AAC1B,EAAA,IAAI,UAAU,IAAA,EAAM;AAClB,IAAA;AAAA,EACF;AACA,EAAA,IAAI;AACF,IAAA,IAAI,MAAA,KAAW,IAAA,IAAQ,MAAA,KAAW,EAAA,EAAI;AACpC,MAAA,KAAA,CAAM,WAAW,SAAS,CAAA;AAC1B,MAAA;AAAA,IACF;AACA,IAAA,KAAA,CAAM,OAAA,CAAQ,WAAW,MAAM,CAAA;AAAA,EACjC,CAAA,CAAA,MAAQ;AAAA,EAER;AACF;AAGO,SAAS,0BAAA,GAAmC;AACjD,EAAA,oBAAA,CAAqB,IAAI,CAAA;AAC3B;;;ACnCO,SAAS,yBAAA,CAA0B;AAAA,EACxC,MAAA;AAAA,EACA;AACF,CAAA,EAAmE;AACjE,EAAA,MAAM,CAAC,OAAA,EAAS,UAAU,CAAA,GAAIK,SAAkB,IAAI,CAAA;AACpD,EAAA,MAAM,CAAC,MAAA,EAAQ,SAAS,CAAA,GAAIA,SAAkB,KAAK,CAAA;AACnD,EAAA,MAAM,CAAC,MAAA,EAAQ,SAAS,CAAA,GAAIA,SAAkB,KAAK,CAAA;AACnD,EAAA,MAAM,CAAC,QAAA,EAAU,WAAW,CAAA,GAAIA,SAAwB,IAAI,CAAA;AAE5D,EAAAU,UAAU,MAAM;AACd,IAAA,IAAI,MAAA,GAAS,IAAA;AACb,IAAA,MAAA,CACG,uBAAA,EAAwB,CACxB,IAAA,CAAK,CAAC,MAAA,KAAW;AAChB,MAAA,IAAI,MAAA,EAAQ;AACV,QAAA,WAAA,CAAY,MAAM,CAAA;AAAA,MACpB;AAAA,IACF,CAAC,CAAA,CACA,KAAA,CAAM,MAAM;AAAA,IAEb,CAAC,CAAA,CACA,OAAA,CAAQ,MAAM;AACb,MAAA,IAAI,MAAA,EAAQ;AACV,QAAA,UAAA,CAAW,KAAK,CAAA;AAAA,MAClB;AAAA,IACF,CAAC,CAAA;AACH,IAAA,OAAO,MAAY;AACjB,MAAA,MAAA,GAAS,KAAA;AAAA,IACX,CAAA;AAAA,EACF,CAAA,EAAG,CAAC,MAAM,CAAC,CAAA;AAEX,EAAA,MAAM,MAAA,GAASR,WAAAA;AAAA,IACb,CAAC,MAAA,KAAgC;AAC/B,MAAA,MAAM,QAAA,GAAW,QAAA;AACjB,MAAA,IAAI,WAAW,QAAA,EAAU;AACvB,QAAA;AAAA,MACF;AACA,MAAA,SAAA,CAAU,KAAK,CAAA;AACf,MAAA,SAAA,CAAU,IAAI,CAAA;AACd,MAAA,WAAA,CAAY,MAAM,CAAA;AAClB,MAAA,MAAA,CACG,uBAAA,CAAwB,MAAM,CAAA,CAC9B,IAAA,CAAK,CAAC,EAAA,KAAO;AACZ,QAAA,IAAI,EAAA,EAAI;AACN,UAAA,oBAAA,CAAqB,MAAM,CAAA;AAC3B,UAAA,SAAA,GAAY,MAAM,CAAA;AAClB,UAAA;AAAA,QACF;AACA,QAAA,WAAA,CAAY,QAAQ,CAAA;AACpB,QAAA,SAAA,CAAU,IAAI,CAAA;AAAA,MAChB,CAAC,CAAA,CACA,KAAA,CAAM,MAAM;AACX,QAAA,WAAA,CAAY,QAAQ,CAAA;AACpB,QAAA,SAAA,CAAU,IAAI,CAAA;AAAA,MAChB,CAAC,CAAA,CACA,OAAA,CAAQ,MAAM;AACb,QAAA,SAAA,CAAU,KAAK,CAAA;AAAA,MACjB,CAAC,CAAA;AAAA,IACL,CAAA;AAAA,IACA,CAAC,MAAA,EAAQ,QAAA,EAAU,SAAS;AAAA,GAC9B;AAEA,EAAA,OAAO,EAAE,OAAA,EAAS,MAAA,EAAQ,MAAA,EAAQ,UAAU,MAAA,EAAO;AACrD;ACpEA,IAAM,aAAA,GAAgB,UAAA;AAsBtB,SAAS,iBAAA,CAAkB,QAAgB,MAAA,EAA+C;AACxF,EAAA,IAAI,WAAW,UAAA,EAAY;AACzB,IAAA,OAAO,MAAA,CAAO,cAAA;AAAA,EAChB;AACA,EAAA,IAAI,WAAW,KAAA,EAAO;AACpB,IAAA,OAAO,MAAA,CAAO,SAAA;AAAA,EAChB;AACA,EAAA,IAAI,WAAW,SAAA,EAAW;AACxB,IAAA,OAAO,MAAA,CAAO,aAAA;AAAA,EAChB;AACA,EAAA,OAAO,MAAA;AACT;AAGO,SAAS,2BAAA,CAA4B;AAAA,EAC1C,MAAA;AAAA,EACA,gBAAA;AAAA,EACA,KAAA,EAAO,SAAA;AAAA,EACP,MAAA,EAAQ,UAAA;AAAA,EACR,YAAA;AAAA,EACA;AACF,CAAA,EAA6D;AAC3D,EAAA,MAAM,KAAA,GAAQ,aAAa,SAAS,CAAA;AACpC,EAAA,MAAMP,OAAAA,GAAS,cAAc,KAAK,CAAA;AAClC,EAAA,MAAM,MAAA,GAASD,OAAAA;AAAA,IACb,OAAO,EAAE,GAAG,wCAAA,EAA0C,GAAG,UAAA,EAAW,CAAA;AAAA,IACpE,CAAC,UAAU;AAAA,GACb;AAEA,EAAA,MAAM,EAAE,OAAA,EAAS,MAAA,EAAQ,QAAQ,QAAA,EAAU,MAAA,KAAW,yBAAA,CAA0B;AAAA,IAC9E,MAAA;AAAA,IACA;AAAA,GACD,CAAA;AAGD,EAAA,MAAM,OAAA,GAAUA,OAAAA;AAAA,IACd,MAAM;AAAA,MACJ,EAAE,KAAA,EAAO,IAAA,EAAM,KAAK,aAAA,EAAe,KAAA,EAAO,OAAO,YAAA,EAAa;AAAA,MAC9D,GAAG,gBAAA,CAAiB,GAAA,CAAI,CAAC,MAAA,MAAY;AAAA,QACnC,KAAA,EAAO,MAAA;AAAA,QACP,GAAA,EAAK,MAAA;AAAA,QACL,KAAA,EAAO,iBAAA,CAAkB,MAAA,EAAQ,MAAM;AAAA,OACzC,CAAE;AAAA,KACJ;AAAA,IACA,CAAC,kBAAkB,MAAM;AAAA,GAC3B;AAEA,EAAA,uBACES,IAAAA;AAAA,IAACE,IAAAA;AAAA,IAAA;AAAA,MACC,OAAOV,OAAAA,CAAO,IAAA;AAAA,MACd,MAAA,EAAQ,gBAAA,CAAiB,WAAA,CAAY,uBAAA,EAAyB,YAAY,CAAA;AAAA,MAE1E,QAAA,EAAA;AAAA,wBAAAC,IAACQ,IAAAA,EAAA,EAAK,OAAOT,OAAAA,CAAO,KAAA,EAAQ,iBAAO,KAAA,EAAM,CAAA;AAAA,wBACzCC,IAACQ,IAAAA,EAAA,EAAK,OAAOT,OAAAA,CAAO,QAAA,EAAW,iBAAO,WAAA,EAAY,CAAA;AAAA,QAEjD,OAAA,mBACCC,GAAAA,CAACe,iBAAAA,EAAA,EAAkB,KAAA,EAAO,KAAA,CAAM,MAAA,CAAO,OAAA,EAAS,MAAK,OAAA,EAAQ,CAAA,GAE7D,OAAA,CAAQ,GAAA,CAAI,CAAC,MAAA,KAAW;AACtB,UAAA,MAAM,UAAA,GAAa,OAAO,KAAA,KAAU,QAAA;AACpC,UAAA,MAAM,eAAe,CAAA,EAAG,gBAAA;AAAA,YACtB,WAAA,CAAY,6BAAA;AAAA,YACZ;AAAA,WACD,CAAA,CAAA,EAAI,MAAA,CAAO,GAAG,CAAA,CAAA;AACf,UAAA,uBACEf,GAAAA;AAAA,YAACY,gBAAAA;AAAA,YAAA;AAAA,cAMC,cAAA,EAAc,UAAA;AAAA,cACd,mBAAmB,MAAA,CAAO,WAAA;AAAA,cAC1B,oBAAoB,MAAA,CAAO,KAAA;AAAA,cAC3B,iBAAA,EAAkB,OAAA;AAAA,cAClB,kBAAA,EAAoB,EAAE,QAAA,EAAU,UAAA,EAAW;AAAA,cAC3C,QAAA,EAAU,MAAA;AAAA,cACV,KAAA,EAAO,UAAA,GAAab,OAAAA,CAAO,eAAA,GAAkBA,OAAAA,CAAO,UAAA;AAAA,cACpD,MAAA,EAAQ,YAAA;AAAA,cACR,OAAA,EAAS,MAAY,MAAA,CAAO,MAAA,CAAO,KAAK,CAAA;AAAA,cAExC,0BAAAC,GAAAA,CAACQ,IAAAA,EAAA,EAAK,KAAA,EAAO,aAAaT,OAAAA,CAAO,mBAAA,GAAsBA,OAAAA,CAAO,QAAA,EAC3D,uBAAa,CAAA,OAAA,EAAK,MAAA,CAAO,KAAK,CAAA,CAAA,GAAK,OAAO,KAAA,EAC7C;AAAA,aAAA;AAAA,YAjBK,MAAA,CAAO;AAAA,WAkBd;AAAA,QAEJ,CAAC,CAAA;AAAA,QAGF,MAAA,mBAASC,GAAAA,CAACQ,IAAAA,EAAA,EAAK,OAAOT,OAAAA,CAAO,UAAA,EAAa,QAAA,EAAA,MAAA,CAAO,MAAA,EAAO,CAAA,GAAU,IAAA;AAAA,QAElE,yBACCC,GAAAA;AAAA,UAACQ,IAAAA;AAAA,UAAA;AAAA,YACC,OAAOT,OAAAA,CAAO,SAAA;AAAA,YACd,MAAA,EAAQ,gBAAA,CAAiB,WAAA,CAAY,4BAAA,EAA8B,YAAY,CAAA;AAAA,YAE9E,QAAA,EAAA,MAAA,CAAO;AAAA;AAAA,SACV,GACE;AAAA;AAAA;AAAA,GACN;AAEJ;;;ACrJO,IAAW,sBAAA,qBAAA8B,uBAAAA,KAAX;AAEL,EAAAA,wBAAA,iBAAA,CAAA,GAAkB,mBAAA;AAElB,EAAAA,wBAAA,UAAA,CAAA,GAAW,UAAA;AAEX,EAAAA,wBAAA,iBAAA,CAAA,GAAkB,kBAAA;AAElB,EAAAA,wBAAA,gBAAA,CAAA,GAAiB,iBAAA;AAEjB,EAAAA,wBAAA,cAAA,CAAA,GAAe,cAAA;AAEf,EAAAA,wBAAA,QAAA,CAAA,GAAS,QAAA;AAZO,EAAA,OAAAA,uBAAAA;AAAA,CAAA,EAAA,sBAAA,IAAA,EAAA;ACwClB,SAAS,kBAAkB,MAAA,EAA6E;AACtG,EAAA,IAAI,WAAW,gBAAA,EAAkB;AAC/B,IAAA,OAAA,iBAAA;AAAA,EACF;AACA,EAAA,IAAI,WAAW,cAAA,EAAgB;AAC7B,IAAA,OAAA,cAAA;AAAA,EACF;AACA,EAAA,OAAA,QAAA;AACF;AAEO,SAAS,iBAAA,CAAkB;AAAA,EAChC,MAAA;AAAA,EACA;AACF,CAAA,EAAmD;AACjD,EAAA,MAAM,CAAC,eAAA,EAAiB,eAAe,CAAA,GAAIzB,SAAiB,EAAE,CAAA;AAC9D,EAAA,MAAM,CAAC,WAAA,EAAa,WAAW,CAAA,GAAIA,SAAiB,EAAE,CAAA;AACtD,EAAA,MAAM,CAAC,eAAA,EAAiB,eAAe,CAAA,GAAIA,SAAiB,EAAE,CAAA;AAC9D,EAAA,MAAM,CAAC,UAAA,EAAY,aAAa,CAAA,GAAIA,SAAkB,KAAK,CAAA;AAC3D,EAAA,MAAM,CAAC,SAAA,EAAW,YAAY,CAAA,GAAIA,SAAkB,KAAK,CAAA;AACzD,EAAA,MAAM,CAAC,QAAA,EAAU,WAAW,CAAA,GAAIA,SAAwC,IAAI,CAAA;AAG5E,EAAA,MAAM,WAAA,GAAcE,YAAY,MAAY;AAC1C,IAAA,WAAA,CAAY,IAAI,CAAA;AAChB,IAAA,YAAA,CAAa,KAAK,CAAA;AAAA,EACpB,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,MAAM,kBAAA,GAAqBA,WAAAA,CAAY,CAAC,KAAA,KAAwB;AAC9D,IAAA,eAAA,CAAgB,KAAK,CAAA;AACrB,IAAA,WAAA,EAAY;AAAA,EACd,CAAA,EAAG,CAAC,WAAW,CAAC,CAAA;AAChB,EAAA,MAAM,cAAA,GAAiBA,WAAAA,CAAY,CAAC,KAAA,KAAwB;AAC1D,IAAA,WAAA,CAAY,KAAK,CAAA;AACjB,IAAA,WAAA,EAAY;AAAA,EACd,CAAA,EAAG,CAAC,WAAW,CAAC,CAAA;AAChB,EAAA,MAAM,kBAAA,GAAqBA,WAAAA,CAAY,CAAC,KAAA,KAAwB;AAC9D,IAAA,eAAA,CAAgB,KAAK,CAAA;AACrB,IAAA,WAAA,EAAY;AAAA,EACd,CAAA,EAAG,CAAC,WAAW,CAAC,CAAA;AAEhB,EAAA,MAAM,KAAA,GAAQA,YAAY,MAAY;AACpC,IAAA,eAAA,CAAgB,EAAE,CAAA;AAClB,IAAA,WAAA,CAAY,EAAE,CAAA;AACd,IAAA,eAAA,CAAgB,EAAE,CAAA;AAClB,IAAA,aAAA,CAAc,KAAK,CAAA;AACnB,IAAA,YAAA,CAAa,KAAK,CAAA;AAClB,IAAA,WAAA,CAAY,IAAI,CAAA;AAAA,EAClB,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,MAAM,MAAA,GAASA,YAAY,MAAY;AACrC,IAAA,IAAI,oBAAoB,EAAA,EAAI;AAC1B,MAAA,WAAA,CAAA,kBAAA,uBAAkD;AAClD,MAAA;AAAA,IACF;AACA,IAAA,IAAI,gBAAgB,eAAA,EAAiB;AACnC,MAAA,WAAA,CAAA,UAAA,gBAA2C;AAC3C,MAAA;AAAA,IACF;AACA,IAAA,IAAI,CAAC,eAAA,CAAgB,WAAW,CAAA,EAAG;AACjC,MAAA,WAAA,CAAA,mBAAA,uBAAkD;AAClD,MAAA;AAAA,IACF;AAEA,IAAA,WAAA,CAAY,IAAI,CAAA;AAChB,IAAA,YAAA,CAAa,KAAK,CAAA;AAClB,IAAA,aAAA,CAAc,IAAI,CAAA;AAClB,IAAA,MAAA,CACG,cAAA,CAAe,EAAE,eAAA,EAAiB,WAAA,EAAa,CAAA,CAC/C,IAAA,CAAK,CAAC,MAAA,KAAW;AAChB,MAAA,IAAI,MAAA,CAAO,WAAW,SAAA,EAAW;AAC/B,QAAA,eAAA,CAAgB,EAAE,CAAA;AAClB,QAAA,WAAA,CAAY,EAAE,CAAA;AACd,QAAA,eAAA,CAAgB,EAAE,CAAA;AAClB,QAAA,YAAA,CAAa,IAAI,CAAA;AACjB,QAAA,SAAA,IAAY;AACZ,QAAA;AAAA,MACF;AACA,MAAA,WAAA,CAAY,iBAAA,CAAkB,MAAA,CAAO,MAAM,CAAC,CAAA;AAAA,IAC9C,CAAC,CAAA,CACA,KAAA,CAAM,MAAM;AACX,MAAA,WAAA,CAAA,QAAA,cAAyC;AAAA,IAC3C,CAAC,CAAA,CACA,OAAA,CAAQ,MAAM;AACb,MAAA,aAAA,CAAc,KAAK,CAAA;AAAA,IACrB,CAAC,CAAA;AAAA,EACL,GAAG,CAAC,MAAA,EAAQ,iBAAiB,WAAA,EAAa,eAAA,EAAiB,SAAS,CAAC,CAAA;AAErE,EAAA,OAAO;AAAA,IACL,eAAA;AAAA,IACA,WAAA;AAAA,IACA,eAAA;AAAA,IACA,kBAAA;AAAA,IACA,cAAA;AAAA,IACA,kBAAA;AAAA,IACA,UAAA;AAAA,IACA,SAAA;AAAA,IACA,QAAA;AAAA,IACA,MAAA;AAAA,IACA;AAAA,GACF;AACF;ACvGA,SAASwB,aAAAA,CAAa,UAAyC,MAAA,EAA8C;AAC3G,EAAA,QAAQ,QAAA;AAAU,IAChB,KAAA,mBAAA;AACE,MAAA,OAAO,MAAA,CAAO,oBAAA;AAAA,IAChB,KAAA,UAAA;AACE,MAAA,OAAO,MAAA,CAAO,aAAA;AAAA,IAChB,KAAA,kBAAA;AACE,MAAA,OAAO,MAAA,CAAO,oBAAA;AAAA,IAChB,KAAA,iBAAA;AACE,MAAA,OAAO,MAAA,CAAO,mBAAA;AAAA,IAChB,KAAA,cAAA;AACE,MAAA,OAAO,MAAA,CAAO,iBAAA;AAAA,IAChB,KAAA,QAAA;AACE,MAAA,OAAO,MAAA,CAAO,WAAA;AAAA,IAChB;AACE,MAAA,OAAO,IAAA;AAAA;AAEb;AAGO,SAAS,kBAAA,CAAmB;AAAA,EACjC,MAAA;AAAA,EACA,KAAA,EAAO,SAAA;AAAA,EACP,MAAA,EAAQ,UAAA;AAAA,EACR,YAAA;AAAA,EACA;AACF,CAAA,EAAoD;AAClD,EAAA,MAAM,KAAA,GAAQ,aAAa,SAAS,CAAA;AACpC,EAAA,MAAM/B,OAAAA,GAAS,cAAc,KAAK,CAAA;AAClC,EAAA,MAAM,MAAA,GAASD,OAAAA;AAAA,IACb,OAAO,EAAE,GAAG,+BAAA,EAAiC,GAAG,UAAA,EAAW,CAAA;AAAA,IAC3D,CAAC,UAAU;AAAA,GACb;AACA,EAAA,MAAM,IAAA,GAAO,iBAAA,CAAkB,EAAE,MAAA,EAAQ,WAAW,CAAA;AACpD,EAAA,MAAM,OAAA,GAAUgC,aAAAA,CAAa,IAAA,CAAK,QAAA,EAAU,MAAM,CAAA;AAElD,EAAA,uBACEvB,IAAAA;AAAA,IAACE,IAAAA;AAAA,IAAA;AAAA,MACC,OAAOV,OAAAA,CAAO,IAAA;AAAA,MACd,MAAA,EAAQ,gBAAA,CAAiB,WAAA,CAAY,6BAAA,EAA+B,YAAY,CAAA;AAAA,MAEhF,QAAA,EAAA;AAAA,wBAAAC,IAACQ,IAAAA,EAAA,EAAK,OAAOT,OAAAA,CAAO,KAAA,EAAQ,iBAAO,mBAAA,EAAoB,CAAA;AAAA,wBACvDC,IAACQ,IAAAA,EAAA,EAAK,OAAOT,OAAAA,CAAO,QAAA,EAAW,iBAAO,yBAAA,EAA0B,CAAA;AAAA,wBAEhEQ,IAAAA,CAACE,IAAAA,EAAA,EAAK,KAAA,EAAOV,QAAO,UAAA,EAClB,QAAA,EAAA;AAAA,0BAAAC,IAACQ,IAAAA,EAAA,EAAK,OAAOT,OAAAA,CAAO,KAAA,EAAQ,iBAAO,oBAAA,EAAqB,CAAA;AAAA,0BACxDC,GAAAA;AAAA,YAACW,SAAAA;AAAA,YAAA;AAAA,cACC,oBAAoB,MAAA,CAAO,oBAAA;AAAA,cAC3B,YAAA,EAAa,kBAAA;AAAA,cACb,aAAa,MAAA,CAAO,0BAAA;AAAA,cACpB,oBAAA,EAAsB,MAAM,MAAA,CAAO,aAAA;AAAA,cACnC,eAAA,EAAe,IAAA;AAAA,cACf,OAAOZ,OAAAA,CAAO,KAAA;AAAA,cACd,MAAA,EAAQ,gBAAA,CAAiB,WAAA,CAAY,0BAAA,EAA4B,YAAY,CAAA;AAAA,cAC7E,OAAO,IAAA,CAAK,eAAA;AAAA,cACZ,cAAc,IAAA,CAAK;AAAA;AAAA;AACrB,SAAA,EACF,CAAA;AAAA,wBAEAQ,IAAAA,CAACE,IAAAA,EAAA,EAAK,KAAA,EAAOV,QAAO,UAAA,EAClB,QAAA,EAAA;AAAA,0BAAAC,IAACQ,IAAAA,EAAA,EAAK,OAAOT,OAAAA,CAAO,KAAA,EAAQ,iBAAO,gBAAA,EAAiB,CAAA;AAAA,0BACpDC,GAAAA;AAAA,YAACW,SAAAA;AAAA,YAAA;AAAA,cACC,oBAAoB,MAAA,CAAO,gBAAA;AAAA,cAC3B,YAAA,EAAa,cAAA;AAAA,cACb,aAAa,MAAA,CAAO,sBAAA;AAAA,cACpB,oBAAA,EAAsB,MAAM,MAAA,CAAO,aAAA;AAAA,cACnC,eAAA,EAAe,IAAA;AAAA,cACf,OAAOZ,OAAAA,CAAO,KAAA;AAAA,cACd,MAAA,EAAQ,gBAAA,CAAiB,WAAA,CAAY,sBAAA,EAAwB,YAAY,CAAA;AAAA,cACzE,OAAO,IAAA,CAAK,WAAA;AAAA,cACZ,cAAc,IAAA,CAAK;AAAA;AAAA;AACrB,SAAA,EACF,CAAA;AAAA,wBAEAQ,IAAAA,CAACE,IAAAA,EAAA,EAAK,KAAA,EAAOV,QAAO,UAAA,EAClB,QAAA,EAAA;AAAA,0BAAAC,IAACQ,IAAAA,EAAA,EAAK,OAAOT,OAAAA,CAAO,KAAA,EAAQ,iBAAO,oBAAA,EAAqB,CAAA;AAAA,0BACxDC,GAAAA;AAAA,YAACW,SAAAA;AAAA,YAAA;AAAA,cACC,oBAAoB,MAAA,CAAO,oBAAA;AAAA,cAC3B,YAAA,EAAa,cAAA;AAAA,cACb,aAAa,MAAA,CAAO,0BAAA;AAAA,cACpB,oBAAA,EAAsB,MAAM,MAAA,CAAO,aAAA;AAAA,cACnC,eAAA,EAAe,IAAA;AAAA,cACf,OAAOZ,OAAAA,CAAO,KAAA;AAAA,cACd,MAAA,EAAQ,gBAAA,CAAiB,WAAA,CAAY,0BAAA,EAA4B,YAAY,CAAA;AAAA,cAC7E,OAAO,IAAA,CAAK,eAAA;AAAA,cACZ,cAAc,IAAA,CAAK;AAAA;AAAA;AACrB,SAAA,EACF,CAAA;AAAA,QAEC,OAAA,KAAY,uBACXC,GAAAA;AAAA,UAACQ,IAAAA;AAAA,UAAA;AAAA,YACC,OAAOT,OAAAA,CAAO,SAAA;AAAA,YACd,MAAA,EAAQ,gBAAA,CAAiB,WAAA,CAAY,mBAAA,EAAqB,YAAY,CAAA;AAAA,YAErE,QAAA,EAAA;AAAA;AAAA,SACH,GACE,IAAA;AAAA,QAEH,IAAA,CAAK,4BACJC,GAAAA;AAAA,UAACQ,IAAAA;AAAA,UAAA;AAAA,YACC,OAAOT,OAAAA,CAAO,WAAA;AAAA,YACd,MAAA,EAAQ,gBAAA,CAAiB,WAAA,CAAY,qBAAA,EAAuB,YAAY,CAAA;AAAA,YAEvE,QAAA,EAAA,MAAA,CAAO;AAAA;AAAA,SACV,GACE,IAAA;AAAA,wBAEJC,GAAAA;AAAA,UAACY,gBAAAA;AAAA,UAAA;AAAA,YACC,mBAAmB,MAAA,CAAO,UAAA;AAAA,YAC1B,kBAAA,EAAoB,IAAA,CAAK,UAAA,GAAa,MAAA,CAAO,aAAa,MAAA,CAAO,MAAA;AAAA,YACjE,iBAAA,EAAkB,QAAA;AAAA,YAClB,UAAU,IAAA,CAAK,UAAA;AAAA,YACf,KAAA,EAAO,KAAK,UAAA,GAAa,CAACb,QAAO,aAAA,EAAeA,OAAAA,CAAO,qBAAqB,CAAA,GAAIA,OAAAA,CAAO,aAAA;AAAA,YACvF,MAAA,EAAQ,gBAAA,CAAiB,WAAA,CAAY,oBAAA,EAAsB,YAAY,CAAA;AAAA,YACvE,SAAS,IAAA,CAAK,MAAA;AAAA,YAEb,QAAA,EAAA,IAAA,CAAK,6BACJC,GAAAA,CAACe,mBAAA,EAAkB,KAAA,EAAO,MAAM,MAAA,CAAO,SAAA,EAAW,MAAK,OAAA,EAAQ,CAAA,mBAE/Df,GAAAA,CAACQ,IAAAA,EAAA,EAAK,KAAA,EAAOT,OAAAA,CAAO,iBAAA,EAAoB,QAAA,EAAA,MAAA,CAAO,MAAA,EAAO;AAAA;AAAA;AAE1D;AAAA;AAAA,GACF;AAEJ;AC1EA,IAAM,GAAA,GAAM,EAAA;AAEZ,IAAM,MAAA,GAASG,WAAW,MAAA,CAAO;AAAA,EAC/B,OAAA,EAAS;AAAA,IACP,KAAA,EAAO,MAAA;AAAA,IACP,UAAA,EAAY,QAAA;AAAA,IACZ,MAAA,EAAQ;AAAA;AAEZ,CAAC,CAAA;AAGM,SAAS,qBAAA,CAAsB;AAAA,EACpC,cAAA;AAAA,EACA,SAAA;AAAA,EACA,QAAA;AAAA,EACA,eAAA;AAAA,EACA,KAAA,EAAO,SAAA;AAAA,EACP,MAAA,EAAQ,UAAA;AAAA,EACR;AACF,CAAA,EAAuD;AACrD,EAAA,MAAM,KAAA,GAAQ,aAAa,SAAS,CAAA;AACpC,EAAA,MAAMH,OAAAA,GAAS,cAAc,KAAK,CAAA;AAClC,EAAA,MAAM,MAAA,GAASD,OAAAA;AAAA,IACb,OAAO,EAAE,GAAG,+BAAA,EAAiC,GAAG,UAAA,EAAW,CAAA;AAAA,IAC3D,CAAC,UAAU;AAAA,GACb;AAEA,EAAA,uBACEE,GAAAA;AAAA,IAAC,UAAA;AAAA,IAAA;AAAA,MACC,uBAAuBD,OAAAA,CAAO,MAAA;AAAA,MAC9B,MAAA,EAAQ,gBAAA,CAAiB,WAAA,CAAY,eAAA,EAAiB,YAAY,CAAA;AAAA,MAElE,0BAAAQ,IAAAA,CAACE,IAAAA,EAAA,EAAK,KAAA,EAAO,OAAO,OAAA,EAClB,QAAA,EAAA;AAAA,wBAAAT,IAACQ,IAAAA,EAAA,EAAK,OAAOT,OAAAA,CAAO,KAAA,EAAQ,iBAAO,OAAA,EAAQ,CAAA;AAAA,wBAE3CC,GAAAA;AAAA,UAAC,kBAAA;AAAA,UAAA;AAAA,YACC,QAAQ,cAAA,CAAe,MAAA;AAAA,YACvB,MAAA,EAAQ,UAAA;AAAA,YACR,YAAA;AAAA,YACA,KAAA;AAAA,YACA,WAAW,cAAA,CAAe;AAAA;AAAA,SAC5B;AAAA,QAEC,SAAA,KAAc,yBACbA,GAAAA;AAAA,UAAC,qBAAA;AAAA,UAAA;AAAA,YACC,QAAQ,SAAA,CAAU,MAAA;AAAA,YAClB,cAAc,SAAA,CAAU,YAAA;AAAA,YACxB,eAAe,SAAA,CAAU,aAAA;AAAA,YACzB,QAAQ,SAAA,CAAU,MAAA;AAAA,YAClB,YAAA;AAAA,YACA,KAAA;AAAA,YACA,WAAW,SAAA,CAAU;AAAA;AAAA,SACvB,GACE,IAAA;AAAA,QAEH,QAAA,KAAa,yBACZA,GAAAA;AAAA,UAAC,mBAAA;AAAA,UAAA;AAAA,YACC,QAAQ,QAAA,CAAS,MAAA;AAAA,YACjB,WAAW,QAAA,CAAS,SAAA;AAAA,YACpB,YAAA;AAAA,YACA;AAAA;AAAA,SACF,GACE,IAAA;AAAA,QAEH,eAAA,KAAoB,yBACnBA,GAAAA;AAAA,UAAC,2BAAA;AAAA,UAAA;AAAA,YACC,kBAAkB,eAAA,CAAgB,gBAAA;AAAA,YAClC,QAAQ,eAAA,CAAgB,MAAA;AAAA,YACxB,QAAQ,eAAA,CAAgB,MAAA;AAAA,YACxB,YAAA;AAAA,YACA,KAAA;AAAA,YACA,WAAW,eAAA,CAAgB;AAAA;AAAA,SAC7B,GACE;AAAA,OAAA,EACN;AAAA;AAAA,GACF;AAEJ;AChIA,SAAS,OAAA,CAAQ,QAAuB,MAAA,EAAkD;AACxF,EAAA,IAAI,WAAW,UAAA,EAAY;AACzB,IAAA,OAAO,MAAA,CAAO,QAAA;AAAA,EAChB;AACA,EAAA,IAAI,WAAW,KAAA,EAAO;AACpB,IAAA,OAAO,MAAA,CAAO,GAAA;AAAA,EAChB;AACA,EAAA,IAAI,WAAW,SAAA,EAAW;AACxB,IAAA,OAAO,MAAA,CAAO,OAAA;AAAA,EAChB;AACA,EAAA,OAAO,IAAA;AACT;AAGO,SAAS,mBAAA,CAAoB;AAAA,EAClC,MAAA;AAAA,EACA,KAAA,EAAO,SAAA;AAAA,EACP,MAAA,EAAQ,UAAA;AAAA,EACR;AACF,CAAA,EAA4D;AAC1D,EAAA,MAAM,KAAA,GAAQ,aAAa,SAAS,CAAA;AACpC,EAAA,MAAMD,OAAAA,GAAS,cAAc,KAAK,CAAA;AAClC,EAAA,MAAM,MAAA,GAASD,OAAAA;AAAA,IACb,OAAO,EAAE,GAAG,oCAAA,EAAsC,GAAG,UAAA,EAAW,CAAA;AAAA,IAChE,CAAC,UAAU;AAAA,GACb;AAEA,EAAA,MAAM,IAAA,GAAO,OAAA,CAAQ,MAAA,EAAQ,MAAM,CAAA;AACnC,EAAA,IAAI,SAAS,IAAA,EAAM;AACjB,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,uBACEE,GAAAA,CAACS,IAAAA,EAAA,EAAK,MAAA,EAAQ,gBAAA,CAAiB,YAAY,mBAAA,EAAqB,YAAY,CAAA,EAC1E,QAAA,kBAAAT,IAACQ,IAAAA,EAAA,EAAK,OAAOT,OAAAA,CAAO,UAAA,EAAa,gBAAK,CAAA,EACxC,CAAA;AAEJ;ACzBO,SAAS,mBAAA,CAAoB;AAAA,EAClC,WAAA;AAAA,EACA,MAAA;AAAA,EACA,MAAA,EAAAA,OAAAA;AAAA,EACA,UAAA;AAAA,EACA,YAAA;AAAA,EACA,YAAA;AAAA,EACA,WAAA;AAAA,EACA;AACF,CAAA,EAAqD;AAInD,EAAA,MAAM,MAAA,GAAS,CAAC,IAAA,KACd,gBAAA,CAAiB,WAAA,KAAgB,MAAA,GAAY,IAAA,GAAO,CAAA,EAAG,IAAI,CAAA,CAAA,EAAI,WAAW,CAAA,CAAA,EAAI,YAAY,CAAA;AAE5F,EAAA,MAAM,QAAA,GAAW,OAAO,YAAA,KAAiB,QAAA,IAAY,aAAa,MAAA,GAAS,CAAA;AAE3E,EAAA,uBACEQ,IAAAA,CAACE,IAAAA,EAAA,EACE,QAAA,EAAA;AAAA,IAAA,QAAA,mBACCT,GAAAA;AAAA,MAACQ,IAAAA;AAAA,MAAA;AAAA,QACC,OAAOT,OAAAA,CAAO,YAAA;AAAA,QACd,MAAA,EAAQ,MAAA,CAAO,WAAA,CAAY,2BAA2B,CAAA;AAAA,QAErD,QAAA,EAAA;AAAA;AAAA,KACH,GACE,IAAA;AAAA,oBAEJQ,IAAAA,CAACE,IAAAA,EAAA,EAAK,KAAA,EAAOV,QAAO,GAAA,EAClB,QAAA,EAAA;AAAA,sBAAAC,IAACQ,IAAAA,EAAA,EAAK,OAAOT,OAAAA,CAAO,QAAA,EAAW,iBAAO,aAAA,EAAc,CAAA;AAAA,sBACpDC,GAAAA;AAAA,QAACQ,IAAAA;AAAA,QAAA;AAAA,UACC,UAAA,EAAU,IAAA;AAAA,UACV,OAAOT,OAAAA,CAAO,QAAA;AAAA,UACd,MAAA,EAAQ,MAAA,CAAO,WAAA,CAAY,uBAAuB,CAAA;AAAA,UAEjD,QAAA,EAAA,WAAA,CAAY;AAAA;AAAA;AACf,KAAA,EACF,CAAA;AAAA,oBAEAQ,IAAAA,CAACE,IAAAA,EAAA,EAAK,KAAA,EAAOV,QAAO,GAAA,EAClB,QAAA,EAAA;AAAA,sBAAAC,IAACQ,IAAAA,EAAA,EAAK,OAAOT,OAAAA,CAAO,QAAA,EAAW,iBAAO,aAAA,EAAc,CAAA;AAAA,sBACpDC,GAAAA;AAAA,QAACQ,IAAAA;AAAA,QAAA;AAAA,UACC,UAAA,EAAU,IAAA;AAAA,UACV,OAAOT,OAAAA,CAAO,QAAA;AAAA,UACd,MAAA,EAAQ,MAAA,CAAO,WAAA,CAAY,uBAAuB,CAAA;AAAA,UAEjD,QAAA,EAAA,WAAA,CAAY;AAAA;AAAA;AACf,KAAA,EACF,CAAA;AAAA,IAEC,KAAA,KAAU,yBACTC,GAAAA;AAAA,MAACY,gBAAAA;AAAA,MAAA;AAAA,QACC,mBAAmB,MAAA,CAAO,kBAAA;AAAA,QAC1B,oBAAoB,MAAA,CAAO,cAAA;AAAA,QAC3B,iBAAA,EAAkB,QAAA;AAAA,QAClB,KAAA,EAAO,CAAC,UAAA,CAAW,eAAA,EAAiBb,QAAO,SAAS,CAAA;AAAA,QACpD,MAAA,EAAQ,MAAA,CAAO,WAAA,CAAY,wBAAwB,CAAA;AAAA,QACnD,OAAA,EAAS,KAAA;AAAA,QAET,QAAA,kBAAAC,IAACQ,IAAAA,EAAA,EAAK,OAAO,UAAA,CAAW,mBAAA,EAAsB,iBAAO,cAAA,EAAe;AAAA;AAAA,KACtE,GACE;AAAA,GAAA,EACN,CAAA;AAEJ;;;ACjGO,IAAW,0BAAA,qBAAAuB,2BAAAA,KAAX;AAEL,EAAAA,4BAAA,OAAA,CAAA,GAAQ,OAAA;AAER,EAAAA,4BAAA,YAAA,CAAA,GAAa,YAAA;AAJG,EAAA,OAAAA,2BAAAA;AAAA,CAAA,EAAA,0BAAA,IAAA,EAAA;ACsClB,IAAM,kBAAA,GAAqB,CAAA;AAS3B,IAAM,kBAAA,GAAqB,EAAA;AAE3B,IAAM,iBAAA,GAAoB,CAAA;AAE1B,IAAM,oBAAA,GAAuB,GAAA;AAE7B,IAAM,6BAAA,GAAgC,IAAA;AAEtC,IAAM,IAAA,GAAO,CAAA;AAOb,IAAM,cAAA,GAAiB,SAAS,MAAA,CAAO;AAAA,EACrC,GAAA,EAAK,OAAA;AAAA,EACL,OAAA,EAAS,WAAA;AAAA,EACT,OAAA,EAAS;AACX,CAAC,CAAA;AAGM,SAAS,yBAAyB,KAAA,EAAyC;AAChF,EAAA,OAAOjC,QAAQ,MAAM;AACnB,IAAA,MAAM,EAAE,MAAA,EAAQ,KAAA,EAAO,OAAA,EAAS,YAAW,GAAI,KAAA;AAC/C,IAAA,OAAOI,WAAW,MAAA,CAA8B;AAAA,MAC9C,KAAA,EAAO;AAAA,QACL,WAAA,EAAa,kBAAA;AAAA,QACb,eAAA,EAAiB,iBAAA;AAAA,QACjB,cAAc,KAAA,CAAM,IAAA;AAAA,QACpB,aAAa,MAAA,CAAO,MAAA;AAAA,QACpB,iBAAiB,MAAA,CAAO,OAAA;AAAA,QACxB,SAAS,OAAA,CAAQ,EAAA;AAAA,QACjB,cAAc,OAAA,CAAQ,EAAA;AAAA,QACtB,iBAAiB,MAAA,CAAO;AAAA,OAC1B;AAAA,MACA,KAAA,EAAO;AAAA,QACL,UAAU,UAAA,CAAW,OAAA;AAAA,QACrB,UAAA,EAAY,KAAA;AAAA,QACZ,aAAA,EAAe,oBAAA;AAAA,QACf,aAAA,EAAe,WAAA;AAAA,QACf,OAAO,MAAA,CAAO;AAAA,OAChB;AAAA,MACA,WAAA,EAAa;AAAA,QACX,UAAU,UAAA,CAAW,OAAA;AAAA,QACrB,UAAA,EAAY,WAAW,OAAA,GAAU,6BAAA;AAAA,QACjC,SAAA,EAAW,QAAQ,EAAA,GAAK,IAAA;AAAA,QACxB,cAAc,OAAA,CAAQ,EAAA;AAAA,QACtB,OAAO,MAAA,CAAO;AAAA,OAChB;AAAA,MACA,YAAA,EAAc;AAAA,QACZ,UAAU,UAAA,CAAW,OAAA;AAAA,QACrB,UAAA,EAAY,KAAA;AAAA,QACZ,OAAO,MAAA,CAAO,IAAA;AAAA;AAAA;AAAA,QAGd,WAAW,OAAA,CAAQ,EAAA;AAAA,QACnB,YAAA,EAAc,QAAQ,EAAA,GAAK;AAAA,OAC7B;AAAA,MACA,GAAA,EAAK;AAAA,QACH,aAAA,EAAe,KAAA;AAAA,QACf,UAAA,EAAY,QAAA;AAAA,QACZ,cAAA,EAAgB,eAAA;AAAA,QAChB,SAAA,EAAW,QAAQ,EAAA,GAAK;AAAA,OAC1B;AAAA,MACA,QAAA,EAAU;AAAA,QACR,UAAU,UAAA,CAAW,OAAA;AAAA,QACrB,OAAO,MAAA,CAAO;AAAA,OAChB;AAAA,MACA,QAAA,EAAU;AAAA,QACR,UAAA,EAAY,cAAA;AAAA,QACZ,UAAU,UAAA,CAAW,OAAA;AAAA,QACrB,UAAA,EAAY,KAAA;AAAA,QACZ,WAAA,EAAa,kBAAA;AAAA,QACb,cAAc,KAAA,CAAM,KAAA;AAAA,QACpB,aAAa,MAAA,CAAO,MAAA;AAAA,QACpB,eAAA,EAAiB,QAAQ,EAAA,GAAK,IAAA;AAAA,QAC9B,mBAAmB,OAAA,CAAQ,EAAA;AAAA;AAAA,QAE3B,UAAA,EAAY,CAAA;AAAA,QACZ,iBAAiB,MAAA,CAAO,OAAA;AAAA,QACxB,OAAO,MAAA,CAAO;AAAA,OAChB;AAAA;AAAA;AAAA;AAAA;AAAA,MAMA,UAAA,EAAY;AAAA,QACV,WAAW,OAAA,CAAQ,EAAA;AAAA,QACnB,SAAA,EAAW;AAAA,OACb;AAAA,MACA,iBAAA,EAAmB;AAAA,QACjB,SAAA,EAAW,QAAA;AAAA,QACX,cAAA,EAAgB,QAAA;AAAA,QAChB,SAAA,EAAW,kBAAA;AAAA,QACX,mBAAmB,OAAA,CAAQ;AAAA,OAC7B;AAAA,MACA,qBAAA,EAAuB;AAAA,QACrB,UAAU,UAAA,CAAW,OAAA;AAAA,QACrB,kBAAA,EAAoB,WAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAOpB,OAAO,MAAA,CAAO;AAAA,OAChB;AAAA,MACA,cAAA,EAAgB;AAAA,QACd,WAAW,OAAA,CAAQ,EAAA;AAAA,QACnB,YAAY,OAAA,CAAQ,EAAA;AAAA,QACpB,cAAA,EAAgB,kBAAA;AAAA,QAChB,gBAAgB,MAAA,CAAO;AAAA,OACzB;AAAA,MACA,SAAA,EAAW;AAAA,QACT,SAAA,EAAW;AAAA;AACb,KACD,CAAA;AAAA,EACH,CAAA,EAAG,CAAC,KAAK,CAAC,CAAA;AACZ;;;AC/JO,SAAS,uBACd,WAAA,EACwB;AACxB,EAAA,IAAI,WAAA,KAAgB,MAAA,IAAa,WAAA,KAAgB,IAAA,EAAM;AACrD,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,MAAM,QAAA,GACJ,OAAO,WAAA,CAAY,QAAA,KAAa,WAAW,WAAA,CAAY,QAAA,CAAS,MAAK,GAAI,EAAA;AAC3E,EAAA,MAAM,WAAW,OAAO,WAAA,CAAY,QAAA,KAAa,QAAA,GAAW,YAAY,QAAA,GAAW,EAAA;AAEnF,EAAA,MAAM,UAAA,GAAa,QAAA,CAAS,MAAA,KAAW,CAAA,IAAK,SAAS,MAAA,KAAW,CAAA;AAChE,EAAA,IAAI,UAAA,EAAY;AACd,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,OAAO,EAAE,UAAU,QAAA,EAAS;AAC9B;;;ACjBA,SAAS,eAAe,OAAA,EAAkD;AACxE,EAAA,IAAI,OAAA,KAAY,MAAA,IAAa,OAAA,KAAY,IAAA,EAAM;AAC7C,IAAA,OAAO,IAAA;AAAA,EACT;AACA,EAAA,MAAM,IAAA,GAAO,uBAAuB,OAAO,CAAA;AAC3C,EAAA,IAAI,SAAS,IAAA,EAAM;AACjB,IAAA,OAAO,IAAA;AAAA,EACT;AACA,EAAA,MAAM,QAAQ,OAAO,OAAA,CAAQ,KAAA,KAAU,QAAA,GAAW,QAAQ,KAAA,GAAQ,EAAA;AAClE,EAAA,OAAO,EAAE,KAAA,EAAO,QAAA,EAAU,KAAK,QAAA,EAAU,QAAA,EAAU,KAAK,QAAA,EAAS;AACnE;AAOO,SAAS,mBAAmB,QAAA,EAAyD;AAC1F,EAAA,IAAI,CAAC,KAAA,CAAM,OAAA,CAAQ,QAAQ,CAAA,EAAG;AAC5B,IAAA,OAAO,EAAC;AAAA,EACV;AACA,EAAA,OAAO,QAAA,CACJ,IAAI,cAAc,CAAA,CAClB,OAAO,CAAC,OAAA,KAAoC,YAAY,IAAI,CAAA;AACjE;AAOO,SAAS,oBACd,WAAA,EACe;AACf,EAAA,IAAI,WAAA,KAAgB,MAAA,IAAa,WAAA,KAAgB,IAAA,EAAM;AACrD,IAAA,OAAO,EAAC;AAAA,EACV;AAEA,EAAA,MAAM,QAAA,GAAW,kBAAA,CAAmB,WAAA,CAAY,iBAAiB,CAAA;AACjE,EAAA,IAAI,QAAA,CAAS,SAAS,CAAA,EAAG;AACvB,IAAA,OAAO,QAAA;AAAA,EACT;AAEA,EAAA,MAAM,MAAA,GAAS,uBAAuB,WAAW,CAAA;AACjD,EAAA,OAAO,MAAA,KAAW,IAAA,GACd,EAAC,GACD,CAAC,EAAE,KAAA,EAAO,EAAA,EAAI,QAAA,EAAU,MAAA,CAAO,QAAA,EAAU,QAAA,EAAU,MAAA,CAAO,UAAU,CAAA;AAC1E;ACgCO,SAAS,mBAAA,CAAoB;AAAA,EAClC,WAAA;AAAA,EACA,QAAA;AAAA,EACA,OAAA,GAAA,YAAA;AAAA,EACA,KAAA,EAAO,SAAA;AAAA,EACP,MAAA,EAAQ,UAAA;AAAA,EACR,YAAA;AAAA,EACA;AACF,CAAA,EAA4D;AAC1D,EAAA,MAAM,KAAA,GAAQ,aAAa,SAAS,CAAA;AACpC,EAAA,MAAM,UAAA,GAAa,cAAc,KAAK,CAAA;AACtC,EAAA,MAAMH,OAAAA,GAAS,yBAAyB,KAAK,CAAA;AAC7C,EAAA,MAAM,CAAC,QAAA,EAAU,WAAW,CAAA,GAAIK,SAAkB,KAAK,CAAA;AACvD,EAAA,MAAM,MAAA,GAASN,OAAAA;AAAA,IACb,OAAO,EAAE,GAAG,oCAAA,EAAsC,GAAG,UAAA,EAAW,CAAA;AAAA,IAChE,CAAC,UAAU;AAAA,GACb;AAIA,EAAA,MAAM,gBAAA,GAAmBA,OAAAA;AAAA,IACvB,MACE,QAAA,KAAa,MAAA,IAAa,QAAA,CAAS,MAAA,GAAS,IACxC,kBAAA,CAAmB,QAAQ,CAAA,GAC3B,mBAAA,CAAoB,WAAW,CAAA;AAAA,IACrC,CAAC,UAAU,WAAW;AAAA,GACxB;AAIA,EAAA,MAAM,OAAA,GAAUQ,WAAAA;AAAA,IACd,CAAC,OAAA,KACC,KAAA,KAAU,MAAA,GACN,SACA,MAAY,KAAA,CAAM,EAAE,QAAA,EAAU,OAAA,CAAQ,QAAA,EAAU,QAAA,EAAU,OAAA,CAAQ,UAAU,CAAA;AAAA,IAClF,CAAC,KAAK;AAAA,GACR;AAEA,EAAA,MAAM,YAAA,GAAeA,YAAY,MAAY;AAC3C,IAAA,WAAA,CAAY,CAAC,OAAA,KAAY,CAAC,OAAO,CAAA;AAAA,EACnC,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,IAAI,gBAAA,CAAiB,WAAW,CAAA,EAAG;AACjC,IAAA,OAAO,IAAA;AAAA,EACT;AAKA,EAAA,MAAM,QAAA,GAAW,iBAAiB,MAAA,KAAW,CAAA;AAC7C,EAAA,MAAM,OAAO,gBAAA,CAAiB,GAAA,CAAI,CAAC,OAAA,EAAS,0BAC1CN,GAAAA;AAAA,IAAC,mBAAA;AAAA,IAAA;AAAA,MAEC,YAAA,EAAc,QAAA,GAAW,MAAA,GAAY,OAAA,CAAQ,KAAA;AAAA,MAC7C,UAAA;AAAA,MACA,aAAa,EAAE,QAAA,EAAU,QAAQ,QAAA,EAAU,QAAA,EAAU,QAAQ,QAAA,EAAS;AAAA,MACtE,MAAA;AAAA,MACA,MAAA,EAAQD,OAAAA;AAAA,MACR,WAAA,EAAa,WAAW,MAAA,GAAY,KAAA;AAAA,MACpC,YAAA;AAAA,MACA,KAAA,EAAO,QAAQ,OAAO;AAAA,KAAA;AAAA,IARjB,GAAG,OAAA,CAAQ,QAAQ,CAAA,CAAA,EAAI,MAAA,CAAO,KAAK,CAAC,CAAA;AAAA,GAU5C,CAAA;AAED,EAAA,IAAI,OAAA,KAAA,OAAA,cAA8C;AAChD,IAAA,uBACEQ,IAAAA;AAAA,MAACE,IAAAA;AAAA,MAAA;AAAA,QACC,OAAOV,OAAAA,CAAO,KAAA;AAAA,QACd,MAAA,EAAQ,gBAAA,CAAiB,WAAA,CAAY,mBAAA,EAAqB,YAAY,CAAA;AAAA,QAEtE,QAAA,EAAA;AAAA,0BAAAC,IAACQ,IAAAA,EAAA,EAAK,OAAOT,OAAAA,CAAO,KAAA,EAAQ,iBAAO,KAAA,EAAM,CAAA;AAAA,0BACzCC,IAACQ,IAAAA,EAAA,EAAK,OAAOT,OAAAA,CAAO,WAAA,EAAc,iBAAO,WAAA,EAAY,CAAA;AAAA,UACpD;AAAA;AAAA;AAAA,KACH;AAAA,EAEJ;AAEA,EAAA,uBACEQ,IAAAA;AAAA,IAACE,IAAAA;AAAA,IAAA;AAAA,MACC,OAAOV,OAAAA,CAAO,UAAA;AAAA,MACd,MAAA,EAAQ,gBAAA,CAAiB,WAAA,CAAY,mBAAA,EAAqB,YAAY,CAAA;AAAA,MAEtE,QAAA,EAAA;AAAA,wBAAAC,GAAAA;AAAA,UAACY,gBAAAA;AAAA,UAAA;AAAA,YAMC,eAAA,EAAe,QAAA;AAAA,YACf,mBAAmB,MAAA,CAAO,UAAA;AAAA,YAC1B,oBAAoB,MAAA,CAAO,MAAA;AAAA,YAC3B,iBAAA,EAAkB,QAAA;AAAA,YAClB,kBAAA,EAAoB,EAAE,QAAA,EAAS;AAAA,YAC/B,OAAOb,OAAAA,CAAO,iBAAA;AAAA,YACd,MAAA,EAAQ,gBAAA,CAAiB,WAAA,CAAY,qBAAA,EAAuB,YAAY,CAAA;AAAA,YACxE,OAAA,EAAS,YAAA;AAAA,YAET,QAAA,kBAAAC,IAACQ,IAAAA,EAAA,EAAK,OAAOT,OAAAA,CAAO,qBAAA,EAAwB,iBAAO,MAAA,EAAO;AAAA;AAAA,SAC5D;AAAA,QAEC,QAAA,mBAAWC,GAAAA,CAACS,IAAAA,EAAA,EAAK,KAAA,EAAOV,OAAAA,CAAO,cAAA,EAAiB,QAAA,EAAA,IAAA,EAAK,CAAA,GAAU;AAAA;AAAA;AAAA,GAClE;AAEJ;AC5LA,IAAM,YAAA,GAA+B;AAAA,EACnC,SAAS,EAAC;AAAA,EACV,mBAAA,EAAqB,KAAA;AAAA,EACrB,WAAA,EAAa;AAAA,IACX,kBAAA,EAAoB,IAAA;AAAA,IACpB,MAAA,EAAQ,KAAA;AAAA,IACR,SAAA,EAAW,IAAA;AAAA,IACX,eAAA,EAAiB;AAAA,GACnB;AAAA,EACA,IAAA,EAAM;AACR,CAAA;AAeO,SAAS,kBACd,MAAA,EACyB;AACzB,EAAA,MAAM,CAAC,MAAA,EAAQ,SAAS,CAAA,GAAIK,SAAyB,YAAY,CAAA;AACjE,EAAA,MAAM,CAAC,OAAA,EAAS,UAAU,CAAA,GAAIA,SAAkB,IAAI,CAAA;AAEpD,EAAAU,UAAU,MAAM;AACd,IAAA,IAAI,MAAA,GAAS,IAAA;AACb,IAAA,MAAA,CACG,cAAA,EAAe,CACf,IAAA,CAAK,CAAC,IAAA,KAAS;AACd,MAAA,IAAI,MAAA,EAAQ;AACV,QAAA,SAAA,CAAU,IAAI,CAAA;AAAA,MAChB;AAAA,IACF,CAAC,CAAA,CACA,KAAA,CAAM,MAAM;AACX,MAAA,IAAI,MAAA,EAAQ;AACV,QAAA,SAAA,CAAU,YAAY,CAAA;AAAA,MACxB;AAAA,IACF,CAAC,CAAA,CACA,OAAA,CAAQ,MAAM;AACb,MAAA,IAAI,MAAA,EAAQ;AACV,QAAA,UAAA,CAAW,KAAK,CAAA;AAAA,MAClB;AAAA,IACF,CAAC,CAAA;AACH,IAAA,OAAO,MAAY;AACjB,MAAA,MAAA,GAAS,KAAA;AAAA,IACX,CAAA;AAAA,EACF,CAAA,EAAG,CAAC,MAAM,CAAC,CAAA;AAEX,EAAA,OAAO,EAAE,QAAQ,OAAA,EAAQ;AAC3B;;;AC1DA,IAAM,WAAA,GAAc,YAAA;AACpB,IAAM,iBAAA,GAAoB,GAAA;AAC1B,IAAM,iBAAA,GAAoB,kBAAA;AAG1B,IAAM,uBAAA,GAA0B,SAAA;AAGhC,IAAM,gBAAA,GAAmB,uBAAA;AACzB,IAAM,4BAAA,GAA+B,mCAAA;AAoCrC,SAAS,SAAS,KAAA,EAAkD;AAClE,EAAA,OAAO,OAAO,KAAA,KAAU,QAAA,IAAY,KAAA,KAAU,IAAA;AAChD;AAGA,SAAS,kBAAA,CAAmB,QAAiC,GAAA,EAA4B;AACvF,EAAA,MAAM,KAAA,GAAQ,OAAO,GAAG,CAAA;AACxB,EAAA,IAAI,OAAO,KAAA,KAAU,QAAA,IAAY,KAAA,KAAU,EAAA,EAAI;AAC7C,IAAA,OAAO,IAAA;AAAA,EACT;AACA,EAAA,OAAO,KAAA;AACT;AAMO,SAAS,wBAAwB,OAAA,EAA0D;AAChG,EAAA,MAAM,OAAO,OAAA,CAAQ,IAAA;AACrB,EAAA,MAAM,WAAW,OAAA,CAAQ,OAAA,IAAW,EAAA,EAAI,OAAA,CAAQ,OAAO,EAAE,CAAA;AACzD,EAAA,MAAM,OAAA,GAAU,QAAQ,cAAA,IAAkB,uBAAA;AAC1C,EAAA,MAAM,SAAA,GAAY,CAAA,EAAG,OAAO,CAAA,SAAA,EAAY,OAAO,CAAA,CAAA;AAE/C,EAAA,OAAO;AAAA,IACL,MAAM,uBAAA,GAAkD;AACtD,MAAA,IAAI;AACF,QAAA,MAAM,QAAA,GAAW,MAAM,IAAA,CAAK;AAAA,UAC1B,GAAA,EAAK,CAAA,EAAG,SAAS,CAAA,CAAA,EAAI,gBAAgB,CAAA,CAAA;AAAA,UACrC,MAAA,EAAQ,KAAA;AAAA,UACR,OAAA,EAAS,EAAE,MAAA,EAAQ,iBAAA,EAAkB;AAAA,UACrC,WAAA,EAAa;AAAA,SACd,CAAA;AACD,QAAA,IAAI,CAAC,QAAA,CAAS,EAAA,IAAM,CAAC,QAAA,CAAS,QAAA,CAAS,IAAI,CAAA,EAAG;AAC5C,UAAA,OAAO,IAAA;AAAA,QACT;AACA,QAAA,OAAO,kBAAA,CAAmB,QAAA,CAAS,IAAA,EAAM,sBAAsB,CAAA;AAAA,MACjE,CAAA,CAAA,MAAQ;AACN,QAAA,OAAO,IAAA;AAAA,MACT;AAAA,IACF,CAAA;AAAA,IAEA,MAAM,wBAAwB,MAAA,EAAyC;AACrE,MAAA,IAAI;AACF,QAAA,MAAM,QAAA,GAAW,MAAM,IAAA,CAAK;AAAA,UAC1B,GAAA,EAAK,CAAA,EAAG,SAAS,CAAA,CAAA,EAAI,4BAA4B,CAAA,CAAA;AAAA,UACjD,MAAA,EAAQ,KAAA;AAAA,UACR,OAAA,EAAS;AAAA,YACP,cAAA,EAAgB,iBAAA;AAAA,YAChB,MAAA,EAAQ,iBAAA;AAAA,YACR,CAAC,WAAW,GAAG;AAAA,WACjB;AAAA,UACA,IAAA,EAAM,IAAA,CAAK,SAAA,CAAU,EAAE,QAAQ,CAAA;AAAA,UAC/B,WAAA,EAAa;AAAA,SACd,CAAA;AACD,QAAA,OAAO,QAAA,CAAS,EAAA;AAAA,MAClB,CAAA,CAAA,MAAQ;AACN,QAAA,OAAO,KAAA;AAAA,MACT;AAAA,IACF;AAAA,GACF;AACF;;;ACzGA,eAAsB,8BACpB,MAAA,EACwB;AACxB,EAAA,IAAI;AACF,IAAA,MAAM,MAAA,GAAS,MAAM,MAAA,CAAO,uBAAA,EAAwB;AACpD,IAAA,oBAAA,CAAqB,MAAM,CAAA;AAC3B,IAAA,OAAO,MAAA;AAAA,EACT,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,IAAA;AAAA,EACT;AACF;ACUA,SAAS,UAAA,CAAW,GAA2B,CAAA,EAAoC;AACjF,EAAA,IAAI,CAAA,KAAM,IAAA,IAAQ,CAAA,KAAM,IAAA,EAAM;AAC5B,IAAA,OAAO,CAAA,KAAM,CAAA;AAAA,EACf;AACA,EAAA,OAAO,EAAE,QAAA,KAAa,CAAA,CAAE,QAAA,IAAY,CAAA,CAAE,aAAa,CAAA,CAAE,QAAA;AACvD;AAqDO,SAAS,kBAAA,CAAmB;AAAA,EACjC,WAAA;AAAA,EACA,cAAA,GAAiB;AACnB,CAAA,GAAyC,EAAC,EAA6B;AAErE,EAAA,MAAM,QAAA,GAAWhB,QAAQ,MAAM,mBAAA,CAAoB,WAAW,CAAA,EAAG,CAAC,WAAW,CAAC,CAAA;AAI9E,EAAA,MAAM,QAAA,GAAWA,QAAgC,MAAM;AACrD,IAAA,MAAM,KAAA,GAAQ,SAAS,CAAC,CAAA;AACxB,IAAA,OAAO,KAAA,KAAU,SACb,IAAA,GACA,EAAE,UAAU,KAAA,CAAM,QAAA,EAAU,QAAA,EAAU,KAAA,CAAM,QAAA,EAAS;AAAA,EAC3D,CAAA,EAAG,CAAC,QAAQ,CAAC,CAAA;AAGb,EAAA,MAAM,CAAC,MAAA,EAAQ,SAAS,CAAA,GAAIM,QAAAA;AAAA,IAC1B,iBAAiB,QAAA,GAAW;AAAA,GAC9B;AAGA,EAAA,MAAM,CAAC,YAAA,EAAc,eAAe,CAAA,GAAIA,SAAiB,CAAC,CAAA;AAC1D,EAAA,MAAM,CAAC,aAAA,EAAe,gBAAgB,CAAA,GAAIA,QAAAA;AAAA,IAAA,eAAA;AAAA,GAE1C;AAIA,EAAA,MAAM,CAAC,UAAA,EAAY,aAAa,CAAA,GAAIA,QAAAA;AAAA,IAClC,iBAAiB,QAAA,GAAW;AAAA,GAC9B;AAYA,EAAA,MAAM,iBAAiB,cAAA,IAAkB,QAAA,KAAa,QAAQ,CAAC,UAAA,CAAW,UAAU,UAAU,CAAA;AAC9F,EAAA,IAAI,cAAA,EAAgB;AAClB,IAAA,aAAA,CAAc,QAAQ,CAAA;AACtB,IAAA,SAAA,CAAU,QAAQ,CAAA;AAClB,IAAA,eAAA,CAAgB,CAAC,OAAA,KAAY,OAAA,GAAU,CAAC,CAAA;AAExC,IAAA,gBAAA,CAAA,eAAA,qBAA4C;AAAA,EAC9C;AAEA,EAAA,MAAM,SAAA,GAAYE,WAAAA,CAAY,CAAC,IAAA,KAAgC;AAC7D,IAAA,SAAA,CAAU,IAAI,CAAA;AACd,IAAA,eAAA,CAAgB,CAAC,OAAA,KAAY,OAAA,GAAU,CAAC,CAAA;AAExC,IAAA,gBAAA,CAAA,UAAA,gBAAuC;AAAA,EACzC,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,OAAOR,OAAAA;AAAA,IACL,OAAO;AAAA,MACL,cAAA,EAAgB;AAAA,QACd,iBAAiB,MAAA,EAAQ,QAAA;AAAA,QACzB,iBAAiB,MAAA,EAAQ,QAAA;AAAA,QACzB,YAAA;AAAA,QACA;AAAA,OACF;AAAA;AAAA;AAAA;AAAA;AAAA,MAKA,SAAA,EAAW,EAAE,WAAA,EAAa,QAAA,EAAU,OAAO,SAAA;AAAU,KACvD,CAAA;AAAA,IACA,CAAC,MAAA,EAAQ,YAAA,EAAc,aAAA,EAAe,WAAA,EAAa,UAAU,SAAS;AAAA,GACxE;AACF;;;ACjKO,IAAM,eAAA,GAAkB;AAAA,EAC7B,IAAA,EAAM,eAAA;AAAA,EACN,cAAA,EAAgB,2BAAA;AAAA,EAChB,aAAA,EAAe,0BAAA;AAAA,EACf,aAAA,EAAe,yBAAA;AAAA,EACf,UAAA,EAAY,sBAAA;AAAA,EACZ,aAAA,EAAe,yBAAA;AAAA,EACf,oBAAA,EAAsB,iCAAA;AAAA,EACtB,eAAA,EAAiB,4BAAA;AAAA,EACjB,YAAA,EAAc,wBAAA;AAAA,EACd,YAAA,EAAc;AAChB;ACEA,IAAM,MAAA,GAAiC;AAAA,EACrC,EAAE,GAAA,EAAK,WAAA,EAAa,QAAQ,eAAA,CAAgB,cAAA,EAAgB,cAAc,MAAA,EAAO;AAAA,EACjF,EAAE,GAAA,EAAK,UAAA,EAAY,QAAQ,eAAA,CAAgB,aAAA,EAAe,cAAc,MAAA,EAAO;AAAA,EAC/E,EAAE,GAAA,EAAK,UAAA,EAAY,QAAQ,eAAA,CAAgB,aAAA,EAAe,cAAc,UAAA,EAAW;AAAA,EACnF,EAAE,KAAK,OAAA,EAAS,MAAA,EAAQ,gBAAgB,UAAA,EAAY,YAAA,EAAc,OAAA,EAAS,YAAA,EAAc,eAAA,EAAgB;AAAA,EACzG,EAAE,GAAA,EAAK,UAAA,EAAY,QAAQ,eAAA,CAAgB,aAAA,EAAe,QAAQ,IAAA,EAAK;AAAA,EACvE,EAAE,GAAA,EAAK,iBAAA,EAAmB,QAAQ,eAAA,CAAgB,oBAAA,EAAsB,QAAQ,IAAA,EAAK;AAAA,EACrF,EAAE,GAAA,EAAK,YAAA,EAAc,MAAA,EAAQ,gBAAgB,eAAA;AAC/C,CAAA;AAEA,IAAM,UAAA,GAAa,KAAA;AACnB,IAAM,aAAA,GAAgB,CAAA;AAEtB,IAAM,oBAAA,GAAuB,SAAA;AAE7B,IAAM,cAAA,GAAiBI,WAAW,MAAA,CAAO;AAAA,EACvC,QAAA,EAAU;AAAA,IACR,QAAA,EAAU,UAAA;AAAA,IACV,IAAA,EAAM,UAAA;AAAA,IACN,GAAA,EAAK,UAAA;AAAA,IACL,KAAA,EAAO,aAAA;AAAA,IACP,MAAA,EAAQ,aAAA;AAAA,IACR,OAAA,EAAS;AAAA;AAEb,CAAC,CAAA;AAYM,SAAS,kBAAA,CAAmB;AAAA,EACjC,MAAA;AAAA,EACA,MAAA;AAAA,EACA,QAAA;AAAA,EACA,KAAA;AAAA,EACA,MAAA,EAAAH,OAAAA;AAAA,EACA,QAAA;AAAA,EACA;AACF,CAAA,EAAoD;AAClD,EAAA,uBACEQ,IAAAA,CAAAG,QAAAA,EAAA,EACG,QAAA,EAAA;AAAA,IAAA,MAAA,CAAO,GAAA,CAAI,CAAC,MAAA,KAAW;AACtB,MAAA,MAAM,IAAA,GAAO,MAAA,CAAO,MAAA,CAAO,MAAA,CAAO,GAAG,CAAA;AACrC,MAAA,uBACEH,IAAAA,CAACE,IAAAA,EAAA,EAAsB,KAAA,EAAOV,QAAO,UAAA,EACnC,QAAA,EAAA;AAAA,wBAAAC,IAACQ,IAAAA,EAAA,EAAK,OAAOT,OAAAA,CAAO,KAAA,EAAQ,eAAK,KAAA,EAAM,CAAA;AAAA,wBACvCC,GAAAA;AAAA,UAACW,SAAAA;AAAA,UAAA;AAAA,YACC,mBAAmB,IAAA,CAAK,IAAA;AAAA,YACxB,oBAAoB,IAAA,CAAK,UAAA;AAAA,YACzB,cAAA,EAAe,MAAA;AAAA,YACf,cAAc,MAAA,CAAO,YAAA;AAAA,YACrB,WAAA,EAAa,KAAA;AAAA,YACb,UAAU,CAAC,QAAA;AAAA,YACX,YAAA,EAAc,OAAO,YAAA,IAAgB,SAAA;AAAA,YACrC,aAAa,IAAA,CAAK,WAAA;AAAA,YAClB,oBAAA,EAAsB,MAAM,MAAA,CAAO,aAAA;AAAA,YACnC,eAAA,EAAiB,OAAO,MAAA,KAAW,IAAA;AAAA,YACnC,OAAOZ,OAAAA,CAAO,KAAA;AAAA,YACd,MAAA,EAAQ,gBAAA,CAAiB,MAAA,CAAO,MAAA,EAAQ,YAAY,CAAA;AAAA,YACpD,KAAA,EAAO,MAAA,CAAO,MAAA,CAAO,GAAG,CAAA;AAAA,YACxB,cAAc,CAAC,IAAA,KAAS,QAAA,CAAS,MAAA,CAAO,KAAK,IAAI;AAAA;AAAA;AACnD,OAAA,EAAA,EAjBS,OAAO,GAkBlB,CAAA;AAAA,IAEJ,CAAC,CAAA;AAAA,oBACDC,GAAAA;AAAA,MAACW,SAAAA;AAAA,MAAA;AAAA,QACC,2BAAA,EAA2B,IAAA;AAAA,QAC3B,iBAAA,EAAkB,MAAA;AAAA,QAClB,YAAA,EAAa,KAAA;AAAA,QACb,SAAA,EAAW,KAAA;AAAA,QACX,yBAAA,EAA0B,qBAAA;AAAA,QAC1B,WAAA,EAAa,oBAAA;AAAA,QACb,OAAO,cAAA,CAAe,QAAA;AAAA,QACtB,MAAA,EAAQ,gBAAA,CAAiB,eAAA,CAAgB,YAAA,EAAc,YAAY,CAAA;AAAA,QACnE,OAAO,MAAA,CAAO,OAAA;AAAA,QACd,YAAA,EAAc,CAAC,IAAA,KAAS,QAAA,CAAS,WAAW,IAAI;AAAA;AAAA;AAClD,GAAA,EACF,CAAA;AAEJ;;;ACxGO,IAAW,iBAAA,qBAAAqB,kBAAAA,KAAX;AAEL,EAAAA,mBAAA,eAAA,CAAA,GAAgB,eAAA;AAEhB,EAAAA,mBAAA,cAAA,CAAA,GAAe,cAAA;AAEf,EAAAA,mBAAA,cAAA,CAAA,GAAe,cAAA;AAEf,EAAAA,mBAAA,kBAAA,CAAA,GAAmB,kBAAA;AAEnB,EAAAA,mBAAA,eAAA,CAAA,GAAgB,eAAA;AAEhB,EAAAA,mBAAA,YAAA,CAAA,GAAa,YAAA;AAEb,EAAAA,mBAAA,cAAA,CAAA,GAAe,cAAA;AAEf,EAAAA,mBAAA,kBAAA,CAAA,GAAmB,kBAAA;AAEnB,EAAAA,mBAAA,QAAA,CAAA,GAAS,QAAA;AAET,EAAAA,mBAAA,UAAA,CAAA,GAAW,UAAA;AApBK,EAAA,OAAAA,kBAAAA;AAAA,CAAA,EAAA,iBAAA,IAAA,EAAA;;;ACUX,SAAS,oBAAA,CACd,SACA,QAAA,EACM;AACN,EAAA,IAAI,QAAQ,EAAA,EAAI;AACd,IAAA,QAAA,CAAS,SAAA,CAAU,QAAQ,MAAM,CAAA;AACjC,IAAA;AAAA,EACF;AACA,EAAA,IAAI,QAAQ,KAAA,KAAA,UAAA,iBAAsC;AAAC,IAAA,QAAA,CAAS,OAAA,GAAU,QAAQ,KAAK,CAAA;AAAA,EAAE;AACvF;;;ACdA,IAAM,mBAAA,GAAsB,CAAA;AAC5B,IAAM,gBAAA,GAAmB,IAAA;AACzB,IAAM,gBAAA,GAAmB,CAAA;AACzB,IAAM,qBAAA,GAAwB,UAAA;AAC9B,IAAM,oBAAA,GAAuB,IAAA;AAC7B,IAAM,sBAAA,GAAyB,cAAA;AAG/B,IAAM,kBAAA,GAA0E;AAAA,EAC9E,CAAC,gBAAA,EAAA,eAAA,qBAAiD;AAAA,EAClD,CAAC,aAAA,EAAA,YAAA,kBAA2C;AAAA,EAC5C,CAAC,gBAAA,EAAA,cAAA,oBAAgD;AAAA,EACjD,CAAC,eAAA,EAAA,cAAA;AACH,CAAA;AAGO,SAAS,yBAAyB,QAAA,EAA2B;AAClE,EAAA,IAAI,QAAA,CAAS,SAAS,mBAAA,EAAqB;AAAC,IAAA,OAAO,KAAA;AAAA,EAAM;AACzD,EAAA,IAAI,CAAC,qBAAA,CAAsB,IAAA,CAAK,QAAQ,CAAA,EAAG;AAAC,IAAA,OAAO,KAAA;AAAA,EAAM;AACzD,EAAA,IAAI,CAAC,oBAAA,CAAqB,IAAA,CAAK,QAAQ,CAAA,EAAG;AAAC,IAAA,OAAO,KAAA;AAAA,EAAM;AACxD,EAAA,OAAO,sBAAA,CAAuB,KAAK,QAAQ,CAAA;AAC7C;AAQA,SAAS,cAAc,KAAA,EAAwB;AAC7C,EAAA,IAAI,gBAAA,CAAiB,IAAA,CAAK,KAAK,CAAA,EAAG;AAAC,IAAA,OAAO,KAAA;AAAA,EAAM;AAChD,EAAA,MAAM,KAAA,GAAQ,KAAA,CAAM,KAAA,CAAM,GAAG,CAAA;AAC7B,EAAA,IAAI,KAAA,CAAM,WAAW,gBAAA,EAAkB;AAAC,IAAA,OAAO,KAAA;AAAA,EAAM;AACrD,EAAA,MAAM,CAAC,KAAA,GAAQ,EAAA,EAAI,MAAA,GAAS,EAAE,CAAA,GAAI,KAAA;AAClC,EAAA,OAAO,KAAA,KAAU,MAAM,MAAA,CAAO,KAAA,CAAM,GAAG,EAAE,CAAA,CAAE,SAAS,GAAG,CAAA;AACzD;AAGO,SAAS,mBAAmB,MAAA,EAAgD;AACjF,EAAA,OAAO;AAAA,IACL,SAAA,EAAW,MAAA,CAAO,SAAA,CAAU,IAAA,EAAK;AAAA,IACjC,QAAA,EAAU,MAAA,CAAO,QAAA,CAAS,IAAA,EAAK;AAAA,IAC/B,QAAA,EAAU,MAAA,CAAO,QAAA,CAAS,IAAA,EAAK;AAAA,IAC/B,KAAA,EAAO,MAAA,CAAO,KAAA,CAAM,IAAA,EAAK;AAAA,IACzB,UAAU,MAAA,CAAO,QAAA;AAAA,IACjB,iBAAiB,MAAA,CAAO,eAAA;AAAA,IACxB,UAAA,EAAY,MAAA,CAAO,UAAA,CAAW,IAAA,EAAK;AAAA,IACnC,OAAA,EAAS,MAAA,CAAO,OAAA,CAAQ,IAAA;AAAK,GAC/B;AACF;AAEA,SAAS,wBAAwB,MAAA,EAAqC;AACpE,EAAA,MAAM,QAAA,GAAW;AAAA,IACf,MAAA,CAAO,SAAA;AAAA,IACP,MAAA,CAAO,QAAA;AAAA,IACP,MAAA,CAAO,QAAA;AAAA,IACP,MAAA,CAAO,KAAA;AAAA,IACP,MAAA,CAAO,QAAA;AAAA,IACP,MAAA,CAAO;AAAA,GACT;AACA,EAAA,OAAO,QAAA,CAAS,IAAA,CAAK,CAAC,KAAA,KAAU,UAAU,EAAE,CAAA;AAC9C;AAGO,SAAS,sBAAA,CACd,QACA,cAAA,EAC0B;AAC1B,EAAA,IAAI,uBAAA,CAAwB,MAAM,CAAA,EAAG;AAAC,IAAA,OAAA,eAAA;AAAA,EAAuC;AAC7E,EAAA,IAAI,CAAC,aAAA,CAAc,MAAA,CAAO,KAAK,CAAA,EAAG;AAAC,IAAA,OAAA,cAAA;AAAA,EAAsC;AACzE,EAAA,IAAI,CAAC,cAAA,CAAe,MAAA,CAAO,QAAQ,CAAA,EAAG;AAAC,IAAA,OAAA,cAAA;AAAA,EAAsC;AAC7E,EAAA,IAAI,MAAA,CAAO,QAAA,KAAa,MAAA,CAAO,eAAA,EAAiB;AAAC,IAAA,OAAA,kBAAA;AAAA,EAA0C;AAC3F,EAAA,OAAO,IAAA;AACT;AAEA,SAAS,UAAU,KAAA,EAAwB;AACzC,EAAA,IAAI,iBAAiB,KAAA,EAAO;AAAC,IAAA,OAAO,KAAA,CAAM,OAAA;AAAA,EAAQ;AAClD,EAAA,OAAO,OAAO,KAAA,KAAU,QAAA,GAAW,KAAA,GAAQ,EAAA;AAC7C;AAGO,SAAS,qBAAqB,KAAA,EAAmC;AACtE,EAAA,MAAM,OAAA,GAAU,UAAU,KAAK,CAAA;AAC/B,EAAA,IAAI,YAAY,EAAA,EAAI;AAAC,IAAA,OAAA,QAAA;AAAA,EAAgC;AACrD,EAAA,MAAM,KAAA,GAAQ,kBAAA,CAAmB,IAAA,CAAK,CAAC,CAAC,IAAI,CAAA,KAAM,OAAA,CAAQ,QAAA,CAAS,IAAI,CAAC,CAAA;AACxE,EAAA,OAAO,KAAA,KAAU,MAAA,GAAA,kBAAA,0BAAiD,KAAA,CAAM,CAAC,CAAA;AAC3E;;;ACvDA,IAAM,YAAA,GAAmC;AAAA,EACvC,SAAA,EAAW,EAAA;AAAA,EACX,QAAA,EAAU,EAAA;AAAA,EACV,QAAA,EAAU,EAAA;AAAA,EACV,KAAA,EAAO,EAAA;AAAA,EACP,QAAA,EAAU,EAAA;AAAA,EACV,eAAA,EAAiB,EAAA;AAAA,EACjB,UAAA,EAAY,EAAA;AAAA,EACZ,OAAA,EAAS;AACX,CAAA;AAEA,SAAS,eAAe,MAAA,EAAkD;AACxE,EAAA,OAAO;AAAA,IACL,WAAW,MAAA,CAAO,SAAA;AAAA,IAClB,UAAU,MAAA,CAAO,QAAA;AAAA,IACjB,UAAU,MAAA,CAAO,QAAA;AAAA,IACjB,OAAO,MAAA,CAAO,KAAA;AAAA,IACd,UAAU,MAAA,CAAO,QAAA;AAAA,IACjB,YAAY,MAAA,CAAO,UAAA;AAAA,IACnB,SAAS,MAAA,CAAO;AAAA,GAClB;AACF;AAGO,SAAS,eAAA,CAAyB;AAAA,EACvC,QAAA;AAAA,EACA,cAAA,GAAiB,wBAAA;AAAA,EACjB;AACF,CAAA,EAAiE;AAC/D,EAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAI5B,SAA6B,YAAY,CAAA;AACnE,EAAA,MAAM,CAAC,YAAA,EAAc,eAAe,CAAA,GAAIA,SAAS,KAAK,CAAA;AACtD,EAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAIA,SAAmC,IAAI,CAAA;AAEjE,EAAA,MAAM,QAAA,GAAWgB,OAAO,KAAK,CAAA;AAE7B,EAAA,MAAM,QAAA,GAAWd,WAAAA,CAAY,CAAC2B,MAAAA,EAAsB,KAAA,KAAwB;AAC1E,IAAA,QAAA,CAAS,CAAC,UAAU,EAAE,GAAG,MAAM,CAACA,MAAK,GAAG,KAAA,EAAM,CAAE,CAAA;AAAA,EAClD,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,MAAM,MAAA,GAAS3B,YAAY,YAAqD;AAC9E,IAAA,IAAI,SAAS,OAAA,EAAS;AAAC,MAAA,OAAO,EAAE,EAAA,EAAI,KAAA,EAAO,KAAA,EAAA,UAAA,iBAAkC;AAAA,IAAE;AAC/E,IAAA,eAAA,IAAkB;AAClB,IAAA,MAAM,OAAA,GAAU,mBAAmB,KAAK,CAAA;AAExC,IAAA,MAAM,UACJ,OAAA,CAAQ,OAAA,KAAY,EAAA,GAAK,sBAAA,CAAuB,SAAS,cAAc,CAAA,GAAA,QAAA;AACzE,IAAA,IAAI,YAAY,IAAA,EAAM;AACpB,MAAA,QAAA,CAAS,OAAO,CAAA;AAChB,MAAA,OAAO,EAAE,EAAA,EAAI,KAAA,EAAO,KAAA,EAAO,OAAA,EAAQ;AAAA,IACrC;AAEA,IAAA,QAAA,CAAS,OAAA,GAAU,IAAA;AACnB,IAAA,QAAA,CAAS,IAAI,CAAA;AACb,IAAA,eAAA,CAAgB,IAAI,CAAA;AACpB,IAAA,IAAI;AACF,MAAA,MAAM,MAAA,GAAS,MAAM,QAAA,CAAS,cAAA,CAAe,OAAO,CAAC,CAAA;AACrD,MAAA,OAAO,EAAE,EAAA,EAAI,IAAA,EAAM,MAAA,EAAO;AAAA,IAC5B,SAAS,MAAA,EAAQ;AACf,MAAA,MAAM,IAAA,GAAO,qBAAqB,MAAM,CAAA;AACxC,MAAA,QAAA,CAAS,IAAI,CAAA;AACb,MAAA,OAAO,EAAE,EAAA,EAAI,KAAA,EAAO,KAAA,EAAO,IAAA,EAAK;AAAA,IAClC,CAAA,SAAE;AACA,MAAA,QAAA,CAAS,OAAA,GAAU,KAAA;AACnB,MAAA,eAAA,CAAgB,KAAK,CAAA;AAAA,IACvB;AAAA,EACF,GAAG,CAAC,QAAA,EAAU,eAAA,EAAiB,cAAA,EAAgB,KAAK,CAAC,CAAA;AAErD,EAAA,OAAO,EAAE,KAAA,EAAO,QAAA,EAAU,MAAA,EAAQ,cAAc,KAAA,EAAM;AACxD;AC7DO,SAAS,YAAA,CAAsB;AAAA,EACpC,QAAA;AAAA,EACA,SAAA;AAAA,EACA,OAAA;AAAA,EACA,eAAA;AAAA,EACA,cAAA;AAAA,EACA,MAAA,EAAQ,UAAA;AAAA,EACR,KAAA,EAAO,SAAA;AAAA,EACP,MAAA;AAAA,EACA;AACF,CAAA,EAAuD;AACrD,EAAA,MAAM,KAAA,GAAQ,aAAa,SAAS,CAAA;AACpC,EAAA,MAAMP,OAAAA,GAAS,cAAc,KAAK,CAAA;AAClC,EAAA,MAAM,MAAA,GAASD,OAAAA;AAAA,IACb,OAAO,EAAE,GAAG,uBAAA,EAAyB,GAAG,UAAA,EAAW,CAAA;AAAA,IACnD,CAAC,UAAU;AAAA,GACb;AACA,EAAA,MAAM,EAAE,KAAA,EAAO,QAAA,EAAU,MAAA,EAAQ,YAAA,KAAiB,eAAA,CAAyB;AAAA,IACzE,QAAA;AAAA,IACA,eAAA;AAAA,IACA;AAAA,GACD,CAAA;AAGD,EAAA,MAAM,WAAA,GAAcQ,YAAY,YAA2B;AACzD,IAAA,oBAAA,CAAqB,MAAM,MAAA,EAAO,EAAG,EAAE,SAAA,EAAW,SAAS,CAAA;AAAA,EAC7D,CAAA,EAAG,CAAC,OAAA,EAAS,SAAA,EAAW,MAAM,CAAC,CAAA;AAE/B,EAAA,uBACEN,GAAAA,CAACS,IAAAA,EAAA,EAAK,KAAA,EAAOV,OAAAA,CAAO,QAClB,QAAA,kBAAAQ,IAAAA,CAACE,MAAA,EAAK,KAAA,EAAOV,QAAO,IAAA,EAAM,MAAA,EAAQ,iBAAiB,eAAA,CAAgB,IAAA,EAAM,YAAY,CAAA,EACnF,QAAA,EAAA;AAAA,oBAAAC,IAACQ,IAAAA,EAAA,EAAK,OAAOT,OAAAA,CAAO,KAAA,EAAQ,iBAAO,KAAA,EAAM,CAAA;AAAA,oBACzCC,IAACQ,IAAAA,EAAA,EAAK,OAAOT,OAAAA,CAAO,QAAA,EAAW,iBAAO,QAAA,EAAS,CAAA;AAAA,oBAE/CC,GAAAA;AAAA,MAAC,kBAAA;AAAA,MAAA;AAAA,QACC,QAAA,EAAU,YAAA;AAAA,QACV,MAAA;AAAA,QACA,MAAA,EAAQD,OAAAA;AAAA,QACR,YAAA;AAAA,QACA,KAAA;AAAA,QACA,MAAA,EAAQ,KAAA;AAAA,QACR,QAAA,EAAU;AAAA;AAAA,KACZ;AAAA,oBAEAC,GAAAA,CAACS,IAAAA,EAAA,EAAK,KAAA,EAAOV,OAAAA,CAAO,YAClB,QAAA,kBAAAC,GAAAA;AAAA,MAACkC,MAAAA;AAAA,MAAA;AAAA,QACC,SAAA,EAAS,IAAA;AAAA,QACT,mBAAmB,MAAA,CAAO,UAAA;AAAA,QAC1B,kBAAA,EAAoB,YAAA,GAAe,MAAA,CAAO,UAAA,GAAa,MAAA,CAAO,MAAA;AAAA,QAC9D,OAAO,MAAA,CAAO,MAAA;AAAA,QACd,OAAA,EAAS,YAAA;AAAA,QACT,MAAA,EAAQ,gBAAA,CAAiB,eAAA,CAAgB,YAAA,EAAc,YAAY,CAAA;AAAA,QACnE,OAAA,EAAS;AAAA;AAAA,KACX,EACF,CAAA;AAAA,IAEC;AAAA,GAAA,EACH,CAAA,EACF,CAAA;AAEJ;AChEA,eAAe,oBAAoB,OAAA,EAA6C;AAC9E,EAAA,MAAM,YACJ,OAAO,KAAA,KAAU,aAAa,KAAA,CAAM,IAAA,CAAK,UAAU,CAAA,GAAI,MAAA;AACzD,EAAA,IAAI,cAAc,MAAA,EAAW;AAC3B,IAAA,MAAM,IAAI,MAAM,iEAAiE,CAAA;AAAA,EACnF;AACA,EAAA,OAAO,qBAAA,CAAsB,SAAS,CAAA,CAAE,OAAO,CAAA;AACjD;AAMO,SAAS,mBAAA,CAAoB,OAAA,GAAsC,EAAC,EAAkB;AAC3F,EAAA,OAAO,IAAI,aAAA,CAAc;AAAA,IACvB,IAAA,EAAM,QAAQ,IAAA,IAAQ,mBAAA;AAAA,IACtB,SAAS,OAAA,CAAQ;AAAA,GAClB,CAAA;AACH;;;ACdA,SAASC,UAAS,KAAA,EAAkD;AAClE,EAAA,OAAO,OAAO,KAAA,KAAU,QAAA,IAAY,KAAA,KAAU,IAAA;AAChD;AAGA,SAAS,qBAAqB,WAAA,EAAgC;AAC5D,EAAA,IAAI,CAACA,SAAAA,CAAS,WAAW,CAAA,EAAG;AAC1B,IAAA,OAAO,EAAC;AAAA,EACV;AACA,EAAA,MAAM,QAAQ,WAAA,CAAY,KAAA;AAC1B,EAAA,IAAI,CAAC,KAAA,CAAM,OAAA,CAAQ,KAAK,CAAA,EAAG;AACzB,IAAA,OAAO,EAAC;AAAA,EACV;AACA,EAAA,OAAO,MAAM,MAAA,CAAO,CAAC,IAAA,KAAyB,OAAO,SAAS,QAAQ,CAAA;AACxE;AAOO,SAAS,iBAAiB,IAAA,EAAyB;AACxD,EAAA,MAAM,IAAA,GAAO,KAAA,CAAM,OAAA,CAAQ,IAAA,CAAK,KAAK,CAAA,GACjC,IAAA,CAAK,KAAA,CAAM,MAAA,CAAO,CAAC,IAAA,KAAyB,OAAO,IAAA,KAAS,QAAQ,IACpE,EAAC;AACL,EAAA,MAAM,KAAA,GAAQ,oBAAA,CAAqB,IAAA,CAAK,YAAY,CAAA;AACpD,EAAA,OAAO,KAAA,CAAM,IAAA,iBAAK,IAAI,GAAA,CAAI,CAAC,GAAG,IAAA,EAAM,GAAG,KAAK,CAAC,CAAC,CAAA;AAChD;AAQO,SAAS,qBAAA,CAAsB,MAAe,KAAA,EAAsC;AACzF,EAAA,MAAM,SAAA,GAAY,IAAI,GAAA,CAAI,gBAAA,CAAiB,IAAI,CAAC,CAAA;AAChD,EAAA,KAAA,MAAW,KAAA,IAAS,MAAM,MAAA,EAAQ;AAChC,IAAA,IAAI,SAAA,CAAU,GAAA,CAAI,KAAA,CAAM,IAAI,CAAA,EAAG;AAC7B,MAAA,OAAO,KAAA,CAAM,KAAA;AAAA,IACf;AAAA,EACF;AACA,EAAA,OAAO,MAAM,QAAA,IAAY,IAAA;AAC3B;;;AC/DO,SAAS,uBAAA,CAAwB,MAAe,KAAA,EAAoC;AACzF,EAAA,MAAM,SAAA,GAAY,IAAI,GAAA,CAAI,gBAAA,CAAiB,IAAI,CAAC,CAAA;AAChD,EAAA,OAAO,KAAA,CAAM,OAAO,MAAA,CAAO,CAAC,UAAU,SAAA,CAAU,GAAA,CAAI,KAAA,CAAM,IAAI,CAAC,CAAA;AACjE;;;ACqDA,SAAShB,SAAQ,MAAA,EAAwB;AACvC,EAAA,OAAO,kBAAkB,KAAA,GAAQ,MAAA,GAAS,IAAI,KAAA,CAAM,MAAA,CAAO,MAAM,CAAC,CAAA;AACpE;AAGA,SAAS,UAAA,CAAW,UAAoC,OAAA,EAAwC;AAC9F,EAAA,IAAI,aAAa,MAAA,EAAW;AAC1B,IAAA;AAAA,EACF;AACA,EAAA,IAAI;AACF,IAAA,QAAA,EAAS;AAAA,EACX,SAAS,MAAA,EAAQ;AACf,IAAA,OAAA,GAAUA,QAAAA,CAAQ,MAAM,CAAC,CAAA;AAAA,EAC3B;AACF;AAGA,SAAS,eAAe,GAAA,EAAmB;AACzC,EAAA,IAAI,OAAO,WAAW,WAAA,EAAa;AACjC,IAAA;AAAA,EACF;AACA,EAAA,MAAA,CAAO,QAAA,CAAS,OAAO,GAAG,CAAA;AAC5B;AAOA,eAAsB,iBAAiB,OAAA,EAA2D;AAChG,EAAA,MAAM,EAAE,MAAA,EAAQ,cAAA,EAAgB,YAAY,OAAA,EAAS,aAAA,GAAgB,gBAAe,GAAI,OAAA;AAGxF,EAAA,UAAA,CAAW,gBAAgB,OAAO,CAAA;AAIlC,EAAA,IAAI,YAAA,GAA8B,IAAA;AAClC,EAAA,IAAI;AACF,IAAA,YAAA,GAAe,MAAM,MAAA,CAAO,MAAA,CAAO,EAAE,QAAA,EAAU,OAAO,CAAA;AAAA,EACxD,SAAS,MAAA,EAAQ;AACf,IAAA,OAAA,GAAUA,QAAAA,CAAQ,MAAM,CAAC,CAAA;AAAA,EAC3B;AAKA,EAAA,IAAI,iBAAiB,IAAA,EAAM;AACzB,IAAA,MAAM,GAAA,GAAM,YAAA;AACZ,IAAA,UAAA,CAAW,MAAM,aAAA,CAAc,GAAG,CAAA,EAAG,OAAO,CAAA;AAC5C,IAAA;AAAA,EACF;AAEA,EAAA,UAAA,CAAW,YAAY,OAAO,CAAA;AAChC;ACvFO,IAAM,wBAAA,GAA2B;AAGxC,IAAMiB,YAAAA,GAAc,YAAA;AACpB,IAAMC,kBAAAA,GAAoB,GAAA;AAC1B,IAAMC,kBAAAA,GAAoB,kBAAA;AAE1B,IAAM,eAAA,GAAkB,GAAA;AACxB,IAAM,OAAA,GAAU,GAAA;AAChB,IAAMC,iBAAAA,GAAmB,GAAA;AACzB,IAAM,iBAAA,GAAoB,GAAA;AAG1B,eAAeC,qBAAoB,OAAA,EAA6C;AAC9E,EAAA,MAAM,YACJ,OAAO,KAAA,KAAU,aAAa,KAAA,CAAM,IAAA,CAAK,UAAU,CAAA,GAAI,MAAA;AACzD,EAAA,IAAI,cAAc,MAAA,EAAW;AAC3B,IAAA,MAAM,IAAI,MAAM,2EAA2E,CAAA;AAAA,EAC7F;AACA,EAAA,OAAOC,qBAAAA,CAAsB,SAAS,CAAA,CAAE,OAAO,CAAA;AACjD;AAGA,SAAS,iBAAiB,MAAA,EAAsC;AAC9D,EAAA,IAAI,MAAA,KAAW,eAAA,IAAmB,MAAA,KAAW,OAAA,EAAS;AACpD,IAAA,OAAO,EAAE,QAAQ,SAAA,EAAU;AAAA,EAC7B;AACA,EAAA,IAAI,WAAWF,iBAAAA,EAAkB;AAC/B,IAAA,OAAO,EAAE,QAAQ,gBAAA,EAAiB;AAAA,EACpC;AACA,EAAA,IAAI,WAAW,iBAAA,EAAmB;AAChC,IAAA,OAAO,EAAE,QAAQ,cAAA,EAAe;AAAA,EAClC;AACA,EAAA,OAAO,EAAE,QAAQ,OAAA,EAAQ;AAC3B;AAQO,SAAS,6BAAA,CACd,OAAA,GAAgD,EAAC,EACpB;AAC7B,EAAA,MAAM,IAAA,GAAO,QAAQ,IAAA,IAAQC,oBAAAA;AAC7B,EAAA,MAAM,OAAA,GAAU,QAAQ,OAAA,IAAW,EAAA;AACnC,EAAA,MAAM,GAAA,GAAM,CAAA,EAAG,OAAO,CAAA,EAAG,wBAAwB,CAAA,CAAA;AAEjD,EAAA,OAAO;AAAA,IACL,cAAA,EAAgB,OAAO,OAAA,KAAkE;AACvF,MAAA,IAAI;AACF,QAAA,MAAM,QAAA,GAAW,MAAM,IAAA,CAAK;AAAA,UAC1B,GAAA;AAAA,UACA,MAAA,EAAQ,MAAA;AAAA,UACR,SAAS,EAAE,cAAA,EAAgBF,oBAAmB,CAACF,YAAW,GAAGC,kBAAAA,EAAkB;AAAA,UAC/E,IAAA,EAAM,KAAK,SAAA,CAAU;AAAA,YACnB,iBAAiB,OAAA,CAAQ,eAAA;AAAA,YACzB,aAAa,OAAA,CAAQ;AAAA,WACtB;AAAA,SACF,CAAA;AACD,QAAA,OAAO,gBAAA,CAAiB,SAAS,MAAM,CAAA;AAAA,MACzC,CAAA,CAAA,MAAQ;AACN,QAAA,OAAO,EAAE,QAAQ,OAAA,EAAQ;AAAA,MAC3B;AAAA,IACF;AAAA,GACF;AACF","file":"index.mjs","sourcesContent":["/**\n * `useAuthScreenStyles` — the StyleSheet for the `<AuthScreen>` whole-composition.\n *\n * Kept separate from `useAuthStyles` (which styles the form *fields*) so the\n * screen-level card chrome — the single surface every auth control shares — is\n * defined in exactly one place. This is the composition that fixes the P1-04\n * \"loose wrapper\" class of bug: apps drop controls INTO this card rather than\n * hand-rolling their own.\n */\nimport { useMemo } from 'react';\n\nimport { StyleSheet, type TextStyle, type ViewStyle } from 'react-native';\n\nimport type { AuthTheme } from '../theme/AuthTheme';\n\n/** The named styles `<AuthScreen>` draws from. */\nexport interface AuthScreenStyles {\n /** Full-bleed, centered background layer. */\n screen: ViewStyle;\n /** The single card surface every auth control shares. */\n card: ViewStyle;\n /** Optional heading at the top of the card. */\n title: TextStyle;\n /** Optional sub-heading under the title. */\n subtitle: TextStyle;\n /** Optional content rendered below/outside the card (e.g. a sign-up footer). */\n footer: ViewStyle;\n}\n\nconst FULL_WIDTH = '100%';\nconst CARD_BORDER_WIDTH = 1;\n\n/**\n * Gap between the top of the viewport and the card, in dp.\n *\n * This replaces `justifyContent: 'center'` — and the replacement is the whole\n * point, so it is worth stating why.\n *\n * A vertically CENTRED card re-centres itself whenever its content grows. The\n * growth is drawn downward, but the card's top edge moves UP by half of it, so\n * every control already on screen shifts under the visitor's cursor. Measured on\n * `app.zygos.dloizides.com/login`: expanding the demo disclosure grew the card\n * 445.6 → 589.6px and pulled the username input from y=275.2 to y=203.2 and the\n * password input from y=368.8 to y=296.8 — 72px UP each, mid-interaction.\n *\n * `<DemoCredentialsHint>` was deliberately mounted BELOW the form to avoid\n * exactly this, and centring defeated that placement. Note the defect is NOT\n * specific to the disclosure: ANY growth shifts the fields — a validation error\n * appearing under an input, a passkey button arriving after the config fetch, an\n * OTP tab swap. Top-anchoring fixes the whole class at once, which is why it is\n * preferred over reserving the disclosure's height (which would leave ~144px of\n * permanent dead space on every login) or absolutely positioning the expanded\n * panel (which removes it from the scrollable area, so on a short viewport the\n * credentials would be unreachable).\n *\n * Small-viewport safety: with a top anchor, content that exceeds the viewport\n * overflows downward ONLY. Under the previous centring it overflowed BOTH ways\n * and the top of the card was clipped past the top edge, unreachable by any\n * scroll. This is therefore strictly better at every viewport size, and needs no\n * `overflow` override to be so.\n */\nconst CARD_TOP_OFFSET = 64;\n\n/** Build the `<AuthScreen>` `StyleSheet` from the resolved theme. */\nexport function useAuthScreenStyles(theme: AuthTheme): AuthScreenStyles {\n return useMemo(() => {\n const { colors, radii, spacing, typography } = theme;\n return StyleSheet.create<AuthScreenStyles>({\n screen: {\n flex: 1,\n // Deliberately NOT `justifyContent: 'center'` — see CARD_TOP_OFFSET.\n justifyContent: 'flex-start',\n alignItems: 'center',\n padding: spacing.md,\n paddingTop: CARD_TOP_OFFSET,\n backgroundColor: colors.background,\n },\n card: {\n width: FULL_WIDTH,\n borderRadius: radii.card,\n borderWidth: CARD_BORDER_WIDTH,\n borderColor: colors.border,\n padding: spacing.xl,\n backgroundColor: colors.surface,\n },\n title: {\n fontSize: typography.title,\n fontWeight: 'bold',\n marginBottom: spacing.xs,\n color: colors.text,\n },\n subtitle: {\n fontSize: typography.subtitle,\n marginBottom: spacing.lg,\n color: colors.textSecondary,\n },\n footer: {\n marginTop: spacing.lg,\n width: FULL_WIDTH,\n alignItems: 'center',\n },\n });\n }, [theme]);\n}\n","/**\n * `AuthTheme` — the design-token contract every `@dloizides/auth-web` component\n * is styled against.\n *\n * The package owns **no** brand. Katalogos, Erevna and Kefi each look different;\n * each one maps its own theme system onto this flat token bag and passes it in\n * (via the `theme` prop or `<AuthThemeProvider>`). The component code only ever\n * reads these tokens — never an app-specific theme object — so the same\n * `<LoginForm>` renders on-brand in three visually distinct apps.\n *\n * Keep this shape minimal and stable: it is a public API surface.\n */\n\n/** Colour tokens — the only colours the auth components reference. */\nexport interface AuthThemeColors {\n /** Page / screen background behind the form card. */\n background: string;\n /** The form card surface colour. */\n surface: string;\n /** Primary text (titles, labels, input text). */\n text: string;\n /** Muted / secondary text (subtitles, helper copy). */\n textSecondary: string;\n /** Input + card border colour; also the disabled-button fill. */\n border: string;\n /** Brand primary — the submit button fill and link colour. */\n primary: string;\n /** Text drawn on top of `primary` (e.g. the submit button label). */\n onPrimary: string;\n /** Error text and error-state borders. */\n danger: string;\n /** Success text (e.g. the forgot-password confirmation). */\n success: string;\n}\n\n/** Corner-radius tokens. */\nexport interface AuthThemeRadii {\n /** Inputs and buttons. */\n input: number;\n /** The form card. */\n card: number;\n}\n\n/** Spacing scale (in density-independent pixels). */\nexport interface AuthThemeSpacing {\n /** Tight gap — e.g. label-to-input. */\n xs: number;\n /** Small gap. */\n sm: number;\n /** Default gap — between stacked fields. */\n md: number;\n /** Large gap — section separation. */\n lg: number;\n /** Card inner padding. */\n xl: number;\n}\n\n/** Font-size tokens. */\nexport interface AuthThemeTypography {\n /** Form title. */\n title: number;\n /** Form subtitle. */\n subtitle: number;\n /**\n * Field labels.\n *\n * The shared forms contract (\"The TWO legitimate label voices\", mirrored in\n * `@dloizides/ui-forms`' `labelVariants.ts`) defines exactly two: `field` —\n * 13 / 600 / sentence case, a label that is READ — and `control` — 11 / 700 /\n * uppercase, a label that is SCANNED. Auth field labels are prose addressed to\n * the person signing in, so they are the `field` voice: **13**.\n *\n * Through 1.13.0 this default was 14, which is neither voice — drift. Every\n * portal that renders `<LoginForm>` inherits this token (all of them reuse\n * `defaultAuthTheme.typography` verbatim), so the drift was uniform across\n * zygos, agora, erevna, katalogos and ichnos, and it read against the 13px\n * `Field` labels those same apps use on every non-auth form.\n */\n label: number;\n /** Input text and button text. */\n body: number;\n /** Helper / error / footer copy. */\n caption: number;\n}\n\n/** The full token bag a consuming app supplies. */\nexport interface AuthTheme {\n colors: AuthThemeColors;\n radii: AuthThemeRadii;\n spacing: AuthThemeSpacing;\n typography: AuthThemeTypography;\n}\n\n/**\n * A neutral, accessible light-mode theme. Apps are expected to override this —\n * it exists so a component renders sensibly with zero configuration and so\n * `<AuthThemeProvider>` has a default value.\n */\nexport const defaultAuthTheme: AuthTheme = {\n colors: {\n background: '#f5f5f7',\n surface: '#ffffff',\n text: '#1a1a1a',\n textSecondary: '#6b6b6b',\n border: '#d0d0d5',\n primary: '#2563eb',\n onPrimary: '#ffffff',\n danger: '#d33333',\n success: '#1f7a3d',\n },\n radii: {\n input: 8,\n card: 12,\n },\n spacing: {\n xs: 8,\n sm: 12,\n md: 20,\n lg: 32,\n xl: 24,\n },\n typography: {\n title: 28,\n subtitle: 16,\n // 13, not 14 — the shared contract's `field` voice. See AuthThemeTypography.label.\n label: 13,\n body: 16,\n caption: 12,\n },\n};\n","/**\n * React context for the `AuthTheme`.\n *\n * Two ways to theme `@dloizides/auth-web` components:\n *\n * 1. Wrap the auth screens in `<AuthThemeProvider theme={appAuthTheme}>` —\n * every component below reads the theme from context.\n * 2. Pass `theme` directly as a prop to an individual component — the prop\n * always wins over context.\n *\n * With neither, components fall back to `defaultAuthTheme`. `useAuthTheme()`\n * implements that precedence (prop → context → default) so each component does\n * not re-derive it.\n */\nimport { createContext, useContext, useMemo, type ReactElement, type ReactNode } from 'react';\n\nimport { defaultAuthTheme, type AuthTheme } from './AuthTheme';\n\nconst AuthThemeContext = createContext<AuthTheme>(defaultAuthTheme);\n\nexport interface AuthThemeProviderProps {\n /** The token bag every descendant auth component is styled against. */\n theme: AuthTheme;\n children: ReactNode;\n}\n\n/** Provides an `AuthTheme` to every `@dloizides/auth-web` component below it. */\nexport function AuthThemeProvider({\n theme,\n children,\n}: Readonly<AuthThemeProviderProps>): ReactElement {\n return <AuthThemeContext.Provider value={theme}>{children}</AuthThemeContext.Provider>;\n}\n\n/**\n * Resolve the effective theme for a component.\n *\n * Precedence: an explicit `themeProp` (if given) wins over the context value,\n * which itself defaults to `defaultAuthTheme` when no provider is mounted.\n */\nexport function useAuthTheme(themeProp?: AuthTheme): AuthTheme {\n const contextTheme = useContext(AuthThemeContext);\n return useMemo(() => themeProp ?? contextTheme, [themeProp, contextTheme]);\n}\n","/**\n * `<AuthScreen>` — the screen-level auth composition, extracted from Kefi's\n * login card (the design reference) so every app gets ONE tidy card instead of\n * hand-rolling its own wrapper.\n *\n * The package's forms (`<LoginForm>`, `<OtpForm>`, `<PinForm>`) each render their\n * own `screen` + `card` chrome by default (drop-one-in-on-a-blank-route mode).\n * When an app needs to compose several controls (method tabs + a form + a passkey\n * button + a hint) onto ONE surface, it renders them as `chromeless` children of\n * an `<AuthScreen>`: the AuthScreen owns the single card, the forms contribute\n * fields only. This makes the P1-04 \"loose wrapper\" bug impossible by\n * construction — the app can no longer assemble a card with the wrong (or no)\n * surface, border, padding or width.\n *\n * Slots mirror Kefi's login composition exactly: an optional `title`/`subtitle`\n * at the top of the card, the `children` (the auth controls), and an optional\n * `footer` rendered OUTSIDE the card (Kefi's sign-up footer sits below it).\n */\nimport { type ReactElement, type ReactNode } from 'react';\n\nimport { Text, View } from 'react-native';\n\nimport { useAuthScreenStyles } from './useAuthScreenStyles';\nimport { useAuthTheme } from '../theme/AuthThemeProvider';\n\nimport type { AuthTheme } from '../theme/AuthTheme';\n\n/**\n * Default auth-card max width, in dp. Matches the package's standalone form card\n * so a single `<LoginForm>` and an `<AuthScreen>`-composed login read the same\n * width unless the app overrides it.\n */\nexport const DEFAULT_AUTH_CARD_MAX_WIDTH = 420;\n\nexport interface AuthScreenProps {\n /** The auth controls placed on the shared card (forms should be `chromeless`). */\n children: ReactNode;\n /** Explicit theme; overrides any `<AuthThemeProvider>`. Falls back to the default theme. */\n theme?: AuthTheme;\n /** testID on the outer full-screen centering container. */\n testID?: string;\n /** testID on the inner card surface. */\n cardTestID?: string;\n /** Max card width in dp. Defaults to {@link DEFAULT_AUTH_CARD_MAX_WIDTH}. */\n maxWidth?: number;\n /** Optional heading rendered at the top of the card. */\n title?: string;\n /** Optional sub-heading rendered under the title. */\n subtitle?: string;\n /** Optional content rendered below/outside the card (e.g. a sign-up footer). */\n footer?: ReactNode;\n}\n\n/** The screen-level auth composition: one centered card the controls share. */\nexport function AuthScreen({\n children,\n theme: themeProp,\n testID,\n cardTestID,\n maxWidth = DEFAULT_AUTH_CARD_MAX_WIDTH,\n title,\n subtitle,\n footer,\n}: Readonly<AuthScreenProps>): ReactElement {\n const theme = useAuthTheme(themeProp);\n const styles = useAuthScreenStyles(theme);\n\n return (\n <View style={styles.screen} testID={testID}>\n <View style={[styles.card, { maxWidth }]} testID={cardTestID}>\n {title !== undefined ? <Text style={styles.title}>{title}</Text> : null}\n {subtitle !== undefined ? <Text style={styles.subtitle}>{subtitle}</Text> : null}\n {children}\n </View>\n {footer !== undefined ? <View style={[styles.footer, { maxWidth }]}>{footer}</View> : null}\n </View>\n );\n}\n","/** Strings rendered by `<LoginForm>`. */\nexport interface LoginFormLabels {\n title: string;\n subtitle: string;\n usernameLabel: string;\n usernamePlaceholder: string;\n passwordLabel: string;\n passwordPlaceholder: string;\n submit: string;\n /** Shown while the login request is in flight. */\n submitting: string;\n /** The \"Forgot password?\" link text. */\n forgotPassword: string;\n /** The \"Create account\" link shown below the submit button when an\n * `onSignUp` handler is supplied. Omit the handler to hide the link. */\n signUp: string;\n /** Generic credentials-rejected message. */\n invalidCredentials: string;\n /** Shown when one or both fields are empty on submit. */\n missingFields: string;\n}\n\nexport const DEFAULT_LOGIN_LABELS: LoginFormLabels = {\n title: 'Sign in',\n subtitle: 'Welcome back',\n usernameLabel: 'Username',\n usernamePlaceholder: 'Enter your username',\n passwordLabel: 'Password',\n passwordPlaceholder: 'Enter your password',\n submit: 'Sign in',\n submitting: 'Signing in...',\n forgotPassword: 'Forgot password?',\n signUp: 'Create an account',\n invalidCredentials: 'Incorrect username or password.',\n missingFields: 'Enter both your username and password.',\n};\n","/** Strings rendered by `<ForgotPasswordForm>`. */\nexport interface ForgotPasswordFormLabels {\n title: string;\n /** Copy above the email field. */\n description: string;\n emailLabel: string;\n emailPlaceholder: string;\n submit: string;\n submitting: string;\n /** Generic confirmation, shown regardless of whether the email is registered. */\n successMessage: string;\n /** Shown on a network / 5xx failure. */\n networkError: string;\n /** Shown when the entered value is not a valid email. */\n invalidEmail: string;\n}\n\n/**\n * Strings rendered by `<ForgotPasswordFields>` — the embedded modal body. It is\n * the forgot-password form plus the two modal affordances (`cancel` alongside\n * submit, `close` on the success state) that a screen-shaped form has no need of.\n */\nexport interface ForgotPasswordFieldsLabels extends ForgotPasswordFormLabels {\n /** The \"cancel\" button shown alongside submit. */\n cancel: string;\n /** The \"close\" button shown on the success state. */\n close: string;\n}\n\nexport const DEFAULT_FORGOT_PASSWORD_LABELS: ForgotPasswordFormLabels = {\n title: 'Forgot password',\n description: 'Enter your email and we will send you a reset link.',\n emailLabel: 'Email',\n emailPlaceholder: 'Enter your email',\n submit: 'Send reset link',\n submitting: 'Sending...',\n successMessage: 'If that email is registered, a reset link is on its way.',\n networkError: 'Something went wrong. Please try again.',\n invalidEmail: 'Enter a valid email address.',\n};\n\nexport const DEFAULT_FORGOT_PASSWORD_FIELDS_LABELS: ForgotPasswordFieldsLabels = {\n ...DEFAULT_FORGOT_PASSWORD_LABELS,\n cancel: 'Cancel',\n close: 'Close',\n};\n","/** Strings rendered by `<OtpForm>` — the two-step email-OTP login form. */\nexport interface OtpFormLabels {\n // ── Step 1: request a code ────────────────────────────────────────────────\n /** Title shown on the request-a-code step. */\n requestTitle: string;\n /** Copy above the email field. */\n requestDescription: string;\n emailLabel: string;\n emailPlaceholder: string;\n /** The \"send code\" button. */\n requestSubmit: string;\n /** Shown while the request is in flight. */\n requesting: string;\n /** Shown when the entered value is not a valid email. */\n invalidEmail: string;\n\n // ── Step 2: enter the code ────────────────────────────────────────────────\n /** Title shown on the enter-the-code step. */\n verifyTitle: string;\n /** Copy above the code field; `{identifier}` is replaced with the email. */\n verifyDescription: string;\n codeLabel: string;\n codePlaceholder: string;\n /** The \"verify\" button. */\n verifySubmit: string;\n /** Shown while verification is in flight. */\n verifying: string;\n /** Shown when the code field is empty on submit. */\n missingCode: string;\n /** Generic \"that code was wrong / expired\" message. */\n invalidCode: string;\n\n // ── Step 2 affordances ────────────────────────────────────────────────────\n /** The \"resend code\" link text. */\n resend: string;\n /** Shown while a resend is in flight. */\n resending: string;\n /** The \"use a different email\" link text — returns to step 1. */\n changeEmail: string;\n}\n\nexport const DEFAULT_OTP_LABELS: OtpFormLabels = {\n requestTitle: 'Sign in with a code',\n requestDescription: 'Enter your email and we will send you a one-time code.',\n emailLabel: 'Email',\n emailPlaceholder: 'Enter your email',\n requestSubmit: 'Send code',\n requesting: 'Sending...',\n invalidEmail: 'Enter a valid email address.',\n verifyTitle: 'Enter your code',\n verifyDescription: 'We sent a one-time code to {identifier}.',\n codeLabel: 'One-time code',\n codePlaceholder: 'Enter the code',\n verifySubmit: 'Verify',\n verifying: 'Verifying...',\n missingCode: 'Enter the code we emailed you.',\n invalidCode: 'That code is incorrect or has expired.',\n resend: 'Resend code',\n resending: 'Resending...',\n changeEmail: 'Use a different email',\n};\n","/** Strings rendered by `<PinForm>` — the single-step event-PIN login form. */\nexport interface PinFormLabels {\n /** Title shown above the PIN field. */\n title: string;\n /** Copy above the PIN field. */\n description: string;\n pinLabel: string;\n pinPlaceholder: string;\n /** The \"sign in\" button. */\n submit: string;\n /** Shown while the PIN exchange is in flight. */\n submitting: string;\n /** Shown when the PIN field is empty on submit. */\n missingPin: string;\n /** Generic \"that PIN was wrong / expired / locked out\" message. */\n invalidPin: string;\n}\n\nexport const DEFAULT_PIN_LABELS: PinFormLabels = {\n title: 'Enter your event PIN',\n description: 'Enter the PIN for this event to sign in.',\n pinLabel: 'PIN',\n pinPlaceholder: 'Enter your PIN',\n submit: 'Sign in',\n submitting: 'Signing in...',\n missingPin: 'Enter your event PIN.',\n invalidPin: 'That PIN is incorrect, has expired, or is locked out.',\n};\n","/**\n * Strings rendered by `<DevicePinUnlockScreen>` — the returning-device unlock\n * gate. `{name}` / `{count}` placeholders are substituted by the component.\n */\nexport interface DevicePinUnlockLabels {\n /** Greeting with the remembered username; `{name}` is substituted. */\n title: string;\n /** Greeting when no username is remembered. */\n titleNoName: string;\n /** Copy above the PIN pad; `{count}` is substituted with the PIN length. */\n description: string;\n pinLabel: string;\n pinPlaceholder: string;\n /** The \"unlock\" submit button. */\n submit: string;\n /** Shown while the unlock is in flight. */\n submitting: string;\n /** The \"sign in with password instead\" escape link. */\n usePasswordInstead: string;\n /** Accessibility hint for the escape link. */\n usePasswordHint: string;\n /** Error: not enough digits entered; `{count}` is substituted. */\n errorIncomplete: string;\n /** Error: wrong PIN / unknown device (generic). */\n errorInvalid: string;\n /** Error: locked out, no retry hint. */\n errorLockedOut: string;\n /** Error: locked out with a retry hint; `{count}` is the seconds. */\n errorLockedOutRetry: string;\n /** Error: rate-limited, no retry hint. */\n errorRateLimited: string;\n /** Error: rate-limited with a retry hint; `{count}` is the seconds. */\n errorRateLimitedRetry: string;\n /** Error: anything else (network / unexpected). */\n errorGeneric: string;\n /** Accessibility label for a filled PIN dot. */\n digitFilledHint: string;\n /** Accessibility label for an empty PIN dot. */\n digitEmptyHint: string;\n}\n\n/**\n * Strings rendered by `<DevicePinEnrollForm>` (and the length picker it hosts)\n * plus the `<DevicePinOffer>` wrapper. `{count}` placeholders are substituted.\n */\nexport interface DevicePinEnrollLabels {\n // ── Offer (post-login skippable card) ─────────────────────────────────────\n offerTitle: string;\n offerDescription: string;\n offerAccept: string;\n offerAcceptHint: string;\n offerSkip: string;\n offerSkipHint: string;\n\n // ── Enrol form ────────────────────────────────────────────────────────────\n formTitle: string;\n /** Copy above the form; `{count}` is substituted with the chosen length. */\n formDescription: string;\n lengthLabel: string;\n /** Accessibility hint for a length pill; `{count}` is substituted. */\n lengthOptionHint: string;\n pinLabel: string;\n pinPlaceholder: string;\n confirmLabel: string;\n confirmPlaceholder: string;\n submit: string;\n submitting: string;\n cancel: string;\n cancelHint: string;\n /** Error: PINs do not match / wrong length; `{count}` is substituted. */\n errorMismatch: string;\n /** Error: the current session is not authenticated. */\n errorUnauthorized: string;\n /** Error: the session already has a PIN / is forbidden. */\n errorForbidden: string;\n /** Error: the PIN failed server-side validation. */\n errorInvalidPin: string;\n /** Error: any other failure. */\n errorFailed: string;\n}\n\n/** Strings rendered by `<DevicePinSettingsCard>` — the account toggle. */\nexport interface DevicePinSettingsLabels {\n title: string;\n description: string;\n /** Status line when a device PIN is enabled. */\n statusEnabled: string;\n /** Status line when no device PIN is set. */\n statusDisabled: string;\n /** The \"enable\" button. */\n enable: string;\n enableHint: string;\n /** The \"disable\" button. */\n disable: string;\n disableHint: string;\n /** Shown while disabling is in flight. */\n disabling: string;\n /** Error shown when disabling fails. */\n disableFailed: string;\n}\n\nexport const DEFAULT_DEVICE_PIN_UNLOCK_LABELS: DevicePinUnlockLabels = {\n title: 'Welcome back, {name}',\n titleNoName: 'Welcome back',\n description: 'Enter your {count}-digit PIN to sign in on this device.',\n pinLabel: 'PIN',\n pinPlaceholder: 'Enter your PIN',\n submit: 'Unlock',\n submitting: 'Signing in...',\n usePasswordInstead: 'Sign in with password instead',\n usePasswordHint: 'Switch to signing in with your username and password',\n errorIncomplete: 'Enter all {count} digits of your PIN.',\n errorInvalid: 'That PIN is incorrect. Try again.',\n errorLockedOut: 'Too many attempts. Try again later.',\n errorLockedOutRetry: 'Too many attempts. Try again in {count} seconds.',\n errorRateLimited: 'Too many requests. Try again later.',\n errorRateLimitedRetry: 'Too many requests. Try again in {count} seconds.',\n errorGeneric: 'Something went wrong. Try again, or sign in with your password.',\n digitFilledHint: 'PIN digit entered',\n digitEmptyHint: 'PIN digit not yet entered',\n};\n\nexport const DEFAULT_DEVICE_PIN_ENROLL_LABELS: DevicePinEnrollLabels = {\n offerTitle: 'Set a PIN for faster sign-in?',\n offerDescription:\n 'Next time, sign in on this device with a short PIN instead of your full password.',\n offerAccept: 'Set up a PIN',\n offerAcceptHint: 'Open the form to choose a quick sign-in PIN',\n offerSkip: 'Not now',\n offerSkipHint: 'Dismiss the PIN setup offer',\n formTitle: 'Choose your PIN',\n formDescription:\n 'Pick a {count}-digit PIN you will remember. You will use it to sign in on this device.',\n lengthLabel: 'PIN length',\n lengthOptionHint: 'Use a {count}-digit PIN',\n pinLabel: 'New PIN',\n pinPlaceholder: 'Enter a new PIN',\n confirmLabel: 'Confirm PIN',\n confirmPlaceholder: 'Re-enter your PIN',\n submit: 'Save PIN',\n submitting: 'Saving...',\n cancel: 'Cancel',\n cancelHint: 'Close the PIN setup form without saving',\n errorMismatch: 'The PINs must match and be exactly {count} digits.',\n errorUnauthorized: 'Your session has expired. Sign in again to set a PIN.',\n errorForbidden: 'A PIN is already set for this session.',\n errorInvalidPin: 'That PIN is not allowed. Choose a different one.',\n errorFailed: 'Could not set your PIN. Try again later.',\n};\n\nexport const DEFAULT_DEVICE_PIN_SETTINGS_LABELS: DevicePinSettingsLabels = {\n title: 'Quick PIN sign-in',\n description: 'Sign in on this device with a short PIN instead of your full password.',\n statusEnabled: 'Quick PIN sign-in is enabled on this device.',\n statusDisabled: 'Quick PIN sign-in is off.',\n enable: 'Enable quick PIN sign-in',\n enableHint: 'Set a PIN so you can sign in faster on this device',\n disable: 'Disable',\n disableHint: 'Remove the PIN sign-in from this device',\n disabling: 'Disabling...',\n disableFailed: 'Could not disable PIN sign-in. Try again later.',\n};\n","/** Strings rendered by `<PasskeyLoginButton>` — the login-surface passkey CTA. */\nexport interface PasskeyLoginLabels {\n /** The \"sign in with a passkey\" button. */\n signInButton: string;\n signInHint: string;\n /** Error banner when the ceremony was cancelled. */\n errorCancelled: string;\n /** Error banner when the ceremony failed. */\n errorFailed: string;\n /**\n * The \"try another way\" affordance shown after an in-page ceremony error — it\n * hands off to the Keycloak-hosted passkey/password flow. This is the seam that\n * rescues a user whose credential is only enrolled in Keycloak (not the in-page\n * RP store): the in-page ceremony can't see it, so they fall back to KC.\n */\n tryAnotherWay: string;\n}\n\n/** Strings rendered by `<PasskeySettingsCard>` — the account passkey card. */\nexport interface PasskeySettingsLabels {\n title: string;\n description: string;\n /** Italic hint about the re-auth step. */\n reauthHint: string;\n /** The \"add a passkey\" button. */\n addButton: string;\n addHint: string;\n /** Success line shown after returning from a registration. */\n registeredSuccess: string;\n}\n\nexport const DEFAULT_PASSKEY_LOGIN_LABELS: PasskeyLoginLabels = {\n signInButton: 'Sign in with a passkey',\n signInHint: 'Use your fingerprint, face, or security key to sign in',\n errorCancelled:\n 'Passkey sign-in was cancelled. You can try again or sign in another way.',\n errorFailed: \"Passkey sign-in didn't work. Try again, or sign in another way.\",\n tryAnotherWay: 'Sign in another way',\n};\n\nexport const DEFAULT_PASSKEY_SETTINGS_LABELS: PasskeySettingsLabels = {\n title: 'Passkeys',\n description:\n 'Add a passkey to sign in with your fingerprint, face, or a security key instead of a password.',\n reauthHint: \"You'll be asked to confirm your password before adding a passkey.\",\n addButton: 'Add a passkey',\n addHint: 'Start setting up a passkey for this account',\n registeredSuccess: 'Your passkey was added. You can now use it to sign in.',\n};\n","/** Strings rendered by `<PreferredMethodSettingsCard>` — the cross-device default-method picker. */\nexport interface PreferredMethodSettingsLabels {\n title: string;\n description: string;\n /** The \"no preference / ask me each time\" option. */\n noPreference: string;\n /** Display name for the password method option. */\n methodPassword: string;\n /** Display name for the device-PIN method option. */\n methodPin: string;\n /** Display name for the passkey method option. */\n methodPasskey: string;\n /** Shown while a selection is being saved. */\n saving: string;\n /** Error shown when saving the preference fails. */\n saveFailed: string;\n}\n\n/** Strings rendered by `<PreferredMethodHint>` — the login-screen \"you usually sign in with…\" line. */\nexport interface PreferredMethodHintLabels {\n /** Full sentence shown when the cached preference is password. */\n password: string;\n /** Full sentence shown when the cached preference is device-PIN. */\n pin: string;\n /** Full sentence shown when the cached preference is passkey. */\n passkey: string;\n}\n\nexport const DEFAULT_PREFERRED_METHOD_SETTINGS_LABELS: PreferredMethodSettingsLabels = {\n title: 'Preferred sign-in method',\n description:\n 'Pick how you usually sign in. We will show this method first on your devices.',\n noPreference: 'No preference',\n methodPassword: 'Password',\n methodPin: 'Quick PIN',\n methodPasskey: 'Passkey',\n saving: 'Saving...',\n saveFailed: 'Could not save your preference. Try again later.',\n};\n\nexport const DEFAULT_PREFERRED_METHOD_HINT_LABELS: PreferredMethodHintLabels = {\n password: 'You usually sign in with your password.',\n pin: 'You usually sign in with your quick PIN on this account.',\n passkey: 'You usually sign in with a passkey.',\n};\n","/** Strings rendered by `<DemoCredentialsHint>` — the public-demo credentials panel. */\nexport interface DemoCredentialsHintLabels {\n /** Panel heading (e.g. \"Demo access\"). */\n title: string;\n /** Copy under the heading explaining what the demo account is. */\n description: string;\n /** Row label for the demo username. */\n usernameLabel: string;\n /** Row label for the demo password. */\n passwordLabel: string;\n /** The \"use these credentials\" button that fills the login form. */\n useCredentials: string;\n /** Accessibility hint for that button. */\n useCredentialsHint: string;\n /**\n * The collapsed disclosure trigger (e.g. \"Try the demo\").\n *\n * Keep the word \"demo\" in it. This one line is the ONLY thing an evaluator\n * scanning the page has to find, so it must be searchable by the word they\n * are looking for — a coy label like \"Just looking?\" is discreet at the cost\n * of being undiscoverable, which defeats the point of shipping a demo.\n */\n toggle: string;\n /** Accessibility hint for the disclosure trigger. */\n toggleHint: string;\n}\n\nexport const DEFAULT_DEMO_CREDENTIALS_HINT_LABELS: DemoCredentialsHintLabels = {\n title: 'Demo access',\n description: 'Explore the full product with our shared demo account.',\n usernameLabel: 'Username',\n passwordLabel: 'Password',\n useCredentials: 'Use these credentials',\n useCredentialsHint: 'Fill the sign-in form with the demo username and password',\n toggle: 'Try the demo',\n toggleHint: 'Show the demo account username and password',\n};\n","/** Strings rendered by `<ResetPasswordForm>`. */\nexport interface ResetPasswordFormLabels {\n title: string;\n description: string;\n newPasswordLabel: string;\n newPasswordPlaceholder: string;\n confirmPasswordLabel: string;\n confirmPasswordPlaceholder: string;\n submit: string;\n submitting: string;\n /** Error: one or both fields empty. */\n errorEmpty: string;\n /** Error: the new password fails the policy. */\n errorWeakPassword: string;\n /** Error: confirm does not match. */\n errorMismatch: string;\n /** Error: the reset token is missing / expired / consumed. */\n errorTokenInvalid: string;\n /** Error: a network / 5xx failure. */\n errorNetwork: string;\n}\n\nexport const DEFAULT_RESET_PASSWORD_LABELS: ResetPasswordFormLabels = {\n title: 'Reset password',\n description: 'Choose a new password for your account.',\n newPasswordLabel: 'New password',\n newPasswordPlaceholder: 'Enter a new password',\n confirmPasswordLabel: 'Confirm password',\n confirmPasswordPlaceholder: 'Re-enter the new password',\n submit: 'Reset password',\n submitting: 'Resetting...',\n errorEmpty: 'Fill in both password fields.',\n errorWeakPassword:\n 'Use at least 8 characters with an uppercase letter, a lowercase letter and a digit.',\n errorMismatch: 'The passwords do not match.',\n errorTokenInvalid: 'This reset link is invalid or has expired. Request a new one.',\n errorNetwork: 'Something went wrong. Please try again.',\n};\n","/**\n * Strings rendered by `<AccountSettingsScreen>` and its `ChangePasswordCard`.\n *\n * As with every auth label bag, the consuming app supplies already-localised\n * strings; the `DEFAULT_*` English constant lets the screen render with no\n * `labels` prop and lets an app spread-override only the keys it cares about.\n */\n\n/** Strings for the account-settings screen shell + the in-app change-password form. */\nexport interface AccountSettingsLabels {\n /** The screen heading above the stacked settings cards. */\n heading: string;\n\n // ── Change-password card ────────────────────────────────────────────────────\n /** Card title. */\n changePasswordTitle: string;\n /** Card body copy above the fields. */\n changePasswordDescription: string;\n currentPasswordLabel: string;\n currentPasswordPlaceholder: string;\n newPasswordLabel: string;\n newPasswordPlaceholder: string;\n confirmPasswordLabel: string;\n confirmPasswordPlaceholder: string;\n /** Submit button. */\n submit: string;\n /** Shown while the submit is in flight. */\n submitting: string;\n /** Accessibility hint for the submit button. */\n submitHint: string;\n /** Shown after a successful change. */\n success: string;\n\n // ── Error messages (one per ChangePasswordErrorKey) ─────────────────────────\n /** New password fails the shared policy. */\n errorWeakNewPassword: string;\n /** New password and confirmation do not match. */\n errorMismatch: string;\n /** Current password field left blank. */\n errorCurrentRequired: string;\n /** BFF 400 — current password wrong or new one rejected server-side. */\n errorInvalidCurrent: string;\n /** BFF 401 — session not authenticated. */\n errorUnauthorized: string;\n /** Any other failure. */\n errorFailed: string;\n}\n\nexport const DEFAULT_ACCOUNT_SETTINGS_LABELS: AccountSettingsLabels = {\n heading: 'Account settings',\n\n changePasswordTitle: 'Change password',\n changePasswordDescription: 'Update the password you use to sign in.',\n currentPasswordLabel: 'Current password',\n currentPasswordPlaceholder: 'Enter your current password',\n newPasswordLabel: 'New password',\n newPasswordPlaceholder: 'Enter a new password',\n confirmPasswordLabel: 'Confirm new password',\n confirmPasswordPlaceholder: 'Re-enter your new password',\n submit: 'Change password',\n submitting: 'Changing password...',\n submitHint: 'Submit the form to change your password',\n success: 'Your password has been changed.',\n\n errorWeakNewPassword:\n 'Your new password must be at least 8 characters and include an uppercase letter, a lowercase letter and a number.',\n errorMismatch: 'The new password and its confirmation do not match.',\n errorCurrentRequired: 'Enter your current password.',\n errorInvalidCurrent: 'Your current password is incorrect, or the new password does not meet the policy.',\n errorUnauthorized: 'Your session has expired. Sign in again to change your password.',\n errorFailed: 'Could not change your password. Try again later.',\n};\n","import type { RegisterInputField } from '../../hooks/registerTypes';\n\n/** Copy for one visible registration input. */\nexport interface RegisterFieldLabels {\n /** Visible label above the input. */\n label: string;\n placeholder: string;\n /** `accessibilityHint` for the input. */\n hint: string;\n /** `accessibilityLabel` for the input. */\n inputLabel: string;\n}\n\n/** Strings rendered by `<RegisterForm>`. Error copy is not here: the app maps `RegisterErrorCode`. */\nexport interface RegisterFormLabels {\n title: string;\n subtitle: string;\n submit: string;\n /** `accessibilityHint` for the submit button. */\n submitHint: string;\n /** `accessibilityLabel` for the submit button while the request runs. */\n submitting: string;\n fields: Record<RegisterInputField, RegisterFieldLabels>;\n}\n\nfunction field(label: string, placeholder: string): RegisterFieldLabels {\n return { label, placeholder, hint: placeholder, inputLabel: label };\n}\n\nexport const DEFAULT_REGISTER_LABELS: RegisterFormLabels = {\n title: 'Create account',\n subtitle: 'Sign up to get started',\n submit: 'Create account',\n submitHint: 'Creates your account',\n submitting: 'Creating account...',\n fields: {\n firstName: field('First name', 'Enter your first name'),\n lastName: field('Last name', 'Enter your last name'),\n username: field('Username', 'Choose a username'),\n email: field('Email', 'Enter your email'),\n password: field('Password', 'Choose a password'),\n confirmPassword: field('Confirm password', 'Repeat your password'),\n tenantName: field('Organisation name', 'Enter your organisation name'),\n },\n};\n","/**\n * Stable `testID` values for every interactive element the auth components\n * render. Exported so E2E suites and unit tests reference one source of truth\n * rather than hard-coding string literals.\n *\n * Each component also accepts a `testIdPrefix` prop; when set, these base IDs\n * are prefixed so two forms can coexist on one screen without ID collisions.\n *\n * `sonarjs/no-hardcoded-passwords` is disabled for this file: it flags keys\n * such as `loginPasswordInput`, but every value here is a UI test ID, not a\n * credential. There are no secrets in this module.\n */\n/* eslint-disable sonarjs/no-hardcoded-passwords */\nexport const AuthTestIds = {\n loginForm: 'auth-login-form',\n loginUsernameInput: 'auth-login-username',\n loginPasswordInput: 'auth-login-password',\n loginSubmitButton: 'auth-login-submit',\n loginForgotLink: 'auth-login-forgot-link',\n loginSignUpLink: 'auth-login-signup-link',\n loginError: 'auth-login-error',\n\n forgotPasswordForm: 'auth-forgot-form',\n forgotPasswordEmailInput: 'auth-forgot-email',\n forgotPasswordSubmitButton: 'auth-forgot-submit',\n forgotPasswordCancelButton: 'auth-forgot-cancel',\n forgotPasswordCloseButton: 'auth-forgot-close',\n forgotPasswordError: 'auth-forgot-error',\n forgotPasswordSuccess: 'auth-forgot-success',\n\n resetPasswordForm: 'auth-reset-form',\n resetPasswordNewInput: 'auth-reset-new',\n resetPasswordConfirmInput: 'auth-reset-confirm',\n resetPasswordSubmitButton: 'auth-reset-submit',\n resetPasswordError: 'auth-reset-error',\n\n otpForm: 'auth-otp-form',\n otpEmailInput: 'auth-otp-email',\n otpRequestButton: 'auth-otp-request',\n otpCodeInput: 'auth-otp-code',\n otpVerifyButton: 'auth-otp-verify',\n otpResendButton: 'auth-otp-resend',\n otpChangeEmailButton: 'auth-otp-change-email',\n otpError: 'auth-otp-error',\n\n pinForm: 'auth-pin-form',\n pinInput: 'auth-pin-input',\n pinSubmitButton: 'auth-pin-submit',\n pinError: 'auth-pin-error',\n\n // Device-PIN unlock gate\n devicePinUnlock: 'auth-device-pin-unlock',\n devicePinUnlockInput: 'auth-device-pin-unlock-input',\n devicePinUnlockSubmit: 'auth-device-pin-unlock-submit',\n devicePinUnlockUsePassword: 'auth-device-pin-unlock-use-password',\n devicePinUnlockError: 'auth-device-pin-unlock-error',\n\n // Device-PIN enrol form + length picker\n devicePinEnrollForm: 'auth-device-pin-enroll-form',\n devicePinEnrollLength: 'auth-device-pin-enroll-length',\n devicePinEnrollPin: 'auth-device-pin-enroll-pin',\n devicePinEnrollConfirm: 'auth-device-pin-enroll-confirm',\n devicePinEnrollSubmit: 'auth-device-pin-enroll-submit',\n devicePinEnrollCancel: 'auth-device-pin-enroll-cancel',\n devicePinEnrollError: 'auth-device-pin-enroll-error',\n\n // Device-PIN offer (post-login)\n devicePinOffer: 'auth-device-pin-offer',\n devicePinOfferAccept: 'auth-device-pin-offer-accept',\n devicePinOfferSkip: 'auth-device-pin-offer-skip',\n\n // Device-PIN settings card\n devicePinSettings: 'auth-device-pin-settings',\n devicePinSettingsStatus: 'auth-device-pin-settings-status',\n devicePinSettingsEnable: 'auth-device-pin-settings-enable',\n devicePinSettingsDisable: 'auth-device-pin-settings-disable',\n devicePinSettingsError: 'auth-device-pin-settings-error',\n\n // Passkey login button\n passkeyLogin: 'auth-passkey-login',\n passkeyLoginButton: 'auth-passkey-login-button',\n passkeyLoginError: 'auth-passkey-login-error',\n passkeyLoginFallback: 'auth-passkey-login-fallback',\n\n // Passkey settings card\n passkeySettings: 'auth-passkey-settings',\n passkeySettingsAdd: 'auth-passkey-settings-add',\n passkeySettingsSuccess: 'auth-passkey-settings-success',\n\n // Preferred-method settings card (cross-device default-method picker).\n // Each option row appends `-${method}` to `preferredMethodSettingsOption`.\n preferredMethodSettings: 'auth-preferred-method-settings',\n preferredMethodSettingsOption: 'auth-preferred-method-settings-option',\n preferredMethodSettingsError: 'auth-preferred-method-settings-error',\n\n // Preferred-method login-screen hint\n preferredMethodHint: 'auth-preferred-method-hint',\n\n // Account-settings screen shell + in-app change-password form\n accountSettings: 'auth-account-settings',\n accountSettingsChangePassword: 'auth-account-settings-change-password',\n changePasswordCurrentInput: 'auth-change-password-current',\n changePasswordNewInput: 'auth-change-password-new',\n changePasswordConfirmInput: 'auth-change-password-confirm',\n changePasswordSubmit: 'auth-change-password-submit',\n changePasswordError: 'auth-change-password-error',\n changePasswordSuccess: 'auth-change-password-success',\n\n // Public-demo credentials panel\n demoCredentialsHint: 'auth-demo-credentials-hint',\n // Per-account heading, present only when >1 account is published (multi-account).\n demoCredentialsAccountLabel: 'auth-demo-credentials-account-label',\n demoCredentialsUsername: 'auth-demo-credentials-username',\n demoCredentialsPassword: 'auth-demo-credentials-password',\n demoCredentialsUseButton: 'auth-demo-credentials-use',\n // The collapsed disclosure trigger (`disclosure` variant only).\n demoCredentialsToggle: 'auth-demo-credentials-toggle',\n} as const;\n\n/** Apply an optional prefix to a base test ID. */\nexport function withTestIdPrefix(baseId: string, prefix?: string): string {\n return prefix === undefined || prefix === '' ? baseId : `${prefix}-${baseId}`;\n}\n","/**\n * `useAuthStyles` — turns an `AuthTheme` token bag into a React Native\n * `StyleSheet` shared by all three auth forms.\n *\n * Building the stylesheet here (once, memoised per theme) keeps each form\n * component focused on layout + behaviour, and guarantees the three forms are\n * visually consistent. Token → style mapping lives in exactly one place, so an\n * app re-theming `<LoginForm>` automatically re-themes the others.\n */\nimport { useMemo } from 'react';\n\nimport { StyleSheet, type TextStyle, type ViewStyle } from 'react-native';\n\nimport type { AuthTheme } from '../theme/AuthTheme';\n\n/** The named styles every auth form draws from. */\nexport interface AuthStyles {\n screen: ViewStyle;\n card: ViewStyle;\n title: TextStyle;\n subtitle: TextStyle;\n fieldGroup: ViewStyle;\n label: TextStyle;\n input: TextStyle;\n inputError: TextStyle;\n primaryButton: ViewStyle;\n primaryButtonDisabled: ViewStyle;\n primaryButtonText: TextStyle;\n linkText: TextStyle;\n errorText: TextStyle;\n successText: TextStyle;\n helperText: TextStyle;\n /** Centered, tappable secondary link row (e.g. \"use password instead\"). */\n escapeLink: ViewStyle;\n /** Outlined secondary button (e.g. disable / cancel actions). */\n secondaryButton: ViewStyle;\n /** Label drawn inside `secondaryButton`. */\n secondaryButtonText: TextStyle;\n /** Status line (e.g. the device-PIN settings enabled/disabled state). */\n statusText: TextStyle;\n}\n\nconst FULL_WIDTH = '100%';\nconst CARD_MAX_WIDTH = 420;\nconst BUTTON_VERTICAL_PADDING = 14;\n/** Gap above the card. Mirrors `useAuthScreenStyles`' CARD_TOP_OFFSET — see the note there. */\nconst SCREEN_TOP_OFFSET = 64;\n\n/** Build the auth `StyleSheet` from the resolved theme. */\nexport function useAuthStyles(theme: AuthTheme): AuthStyles {\n return useMemo(() => {\n const { colors, radii, spacing, typography } = theme;\n return StyleSheet.create<AuthStyles>({\n screen: {\n flex: 1,\n // Top-anchored, NOT centred — a centred card re-centres as it grows and\n // drags the inputs up under the cursor. Same reasoning (and the same\n // measurement) as `useAuthScreenStyles`' CARD_TOP_OFFSET; kept in step so\n // a standalone `<LoginForm>` and an `<AuthScreen>`-composed one agree.\n justifyContent: 'flex-start',\n alignItems: 'center',\n padding: spacing.md,\n paddingTop: SCREEN_TOP_OFFSET,\n backgroundColor: colors.background,\n },\n card: {\n width: FULL_WIDTH,\n maxWidth: CARD_MAX_WIDTH,\n borderRadius: radii.card,\n padding: spacing.xl,\n backgroundColor: colors.surface,\n },\n title: {\n fontSize: typography.title,\n fontWeight: 'bold',\n textAlign: 'center',\n marginBottom: spacing.xs,\n color: colors.text,\n },\n subtitle: {\n fontSize: typography.subtitle,\n textAlign: 'center',\n marginBottom: spacing.lg,\n color: colors.textSecondary,\n },\n fieldGroup: {\n marginBottom: spacing.md,\n },\n label: {\n fontSize: typography.label,\n fontWeight: '600',\n marginBottom: spacing.xs,\n color: colors.text,\n },\n input: {\n borderWidth: 1,\n borderRadius: radii.input,\n padding: spacing.sm,\n fontSize: typography.body,\n borderColor: colors.border,\n backgroundColor: colors.background,\n color: colors.text,\n },\n inputError: {\n borderColor: colors.danger,\n },\n primaryButton: {\n borderRadius: radii.input,\n paddingVertical: BUTTON_VERTICAL_PADDING,\n paddingHorizontal: spacing.md,\n // Never shrink below the label width: in a row of actions (e.g. the\n // forgot-password modal's Cancel + submit), shrinking would clip a long\n // label like \"Send reset link\" past the button's rounded edge.\n flexShrink: 0,\n alignItems: 'center',\n justifyContent: 'center',\n marginTop: spacing.xs,\n backgroundColor: colors.primary,\n },\n primaryButtonDisabled: {\n backgroundColor: colors.border,\n },\n primaryButtonText: {\n fontSize: typography.body,\n fontWeight: '600',\n color: colors.onPrimary,\n },\n linkText: {\n fontSize: typography.caption,\n textDecorationLine: 'underline',\n color: colors.primary,\n },\n errorText: {\n fontSize: typography.caption,\n marginTop: spacing.xs,\n color: colors.danger,\n },\n successText: {\n fontSize: typography.body,\n lineHeight: typography.body * 1.4,\n color: colors.success,\n },\n helperText: {\n fontSize: typography.caption,\n color: colors.textSecondary,\n },\n escapeLink: {\n alignSelf: 'center',\n marginTop: spacing.md,\n paddingVertical: spacing.xs / 2,\n },\n secondaryButton: {\n borderRadius: radii.input,\n borderWidth: 1,\n borderColor: colors.primary,\n paddingVertical: BUTTON_VERTICAL_PADDING,\n paddingHorizontal: spacing.md,\n flexShrink: 0,\n alignItems: 'center',\n justifyContent: 'center',\n marginTop: spacing.sm,\n backgroundColor: colors.surface,\n },\n secondaryButtonText: {\n fontSize: typography.body,\n fontWeight: '600',\n color: colors.primary,\n },\n statusText: {\n fontSize: typography.label,\n fontWeight: '600',\n marginTop: spacing.sm,\n color: colors.text,\n },\n });\n }, [theme]);\n}\n","/**\n * Who asked for a prefill — the difference between \"the user requested this\" and\n * \"the app offered it\".\n *\n * A seed that the USER asked for (tapping \"use these credentials\") must always\n * apply: they can see the fields, they know what is in them, and they asked\n * anyway. A seed the APP offers (a demo pair arriving from `GET /bff/config`\n * mid-typing) must not: it is an unrequested, racing write against a field the\n * user may already be filling in.\n *\n * Collapsing the two into a bare nonce bump is what makes a late-arriving config\n * fetch overwrite the username a real account holder is halfway through typing.\n * `<LoginForm>` switches on this, never on a string literal.\n */\nexport const enum PrefillIntent {\n /** The user asked for it. Always applies, over whatever is in the fields. */\n Explicit = 'explicit',\n /** The app offered it. Applies only to untouched, empty fields. */\n Opportunistic = 'opportunistic',\n}\n","/**\n * `useLoginPrefill` — `<LoginForm>`'s credential field state, with re-seeding.\n *\n * Extracted from `<LoginForm>` because it is the one piece of that component\n * with real logic (the rest is JSX assembly), and because the contract it\n * encodes is easy to get subtly wrong:\n *\n * - `initialUsername` / `initialPassword` **seed** the fields; they do not own\n * them. Once mounted the user is in charge — every value stays editable and\n * clearable. A prefill the user cannot clear would lock a real account holder\n * out of a page that advertises a demo login.\n * - `prefillNonce` is the *re-seed signal*. `useState` ignores its initial\n * argument after mount, so a \"fill the form for me\" button that merely\n * changed `initialUsername` would do nothing at all. Bumping the nonce is\n * what re-applies the seed values.\n *\n * The nonce comparison re-seeds **during render** rather than in an effect —\n * React's documented \"adjusting state when a prop changes\" pattern. React\n * re-runs the component immediately with the new state and never commits the\n * stale render, so there is no flash of the previous values and no extra paint.\n */\nimport { useState } from 'react';\n\nimport { PrefillIntent } from './PrefillIntent';\n\n/** Inputs that seed (and re-seed) the login fields. */\nexport interface UseLoginPrefillArgs {\n /** Seeds the username field. */\n initialUsername?: string;\n /** Seeds the password field. */\n initialPassword?: string;\n /** Change this to re-apply the seed values to the (possibly edited) fields. */\n prefillNonce?: number;\n /**\n * Whether the pending re-seed was requested by the user or offered by the app.\n * An {@link PrefillIntent.Opportunistic} bump is DROPPED unless both fields are\n * still empty, so a late-arriving config fetch cannot overwrite what someone is\n * typing. Omit for the historical behaviour: every bump applies unconditionally.\n */\n prefillIntent?: PrefillIntent;\n}\n\n/** The live field values plus their setters. */\nexport interface UseLoginPrefillResult {\n username: string;\n password: string;\n setUsername: (value: string) => void;\n setPassword: (value: string) => void;\n}\n\n/** Own the login credential fields: seeded from props, then owned by the user. */\nexport function useLoginPrefill({\n initialUsername,\n initialPassword,\n prefillNonce,\n prefillIntent,\n}: Readonly<UseLoginPrefillArgs>): UseLoginPrefillResult {\n const [username, setUsername] = useState<string>(initialUsername ?? '');\n const [password, setPassword] = useState<string>(initialPassword ?? '');\n // Which prefill signal the fields currently reflect. Seeded with the incoming\n // nonce so a first render never counts as a re-seed.\n const [appliedNonce, setAppliedNonce] = useState<number | undefined>(prefillNonce);\n\n if (prefillNonce !== appliedNonce) {\n // Consume the signal even if the seed is declined below, so a dropped\n // opportunistic bump is never retried on a later render.\n setAppliedNonce(prefillNonce);\n\n // \"Has the user interacted?\" is answered with the only evidence this hook\n // has: what is in the fields. Both empty means an offered seed cannot\n // destroy anything — there is nothing there to lose. Anything else means\n // someone typed, so an unrequested write stays out of their way.\n const isPristine = username.length === 0 && password.length === 0;\n const mayApply = prefillIntent !== PrefillIntent.Opportunistic || isPristine;\n\n if (mayApply) {\n setUsername(initialUsername ?? '');\n setPassword(initialPassword ?? '');\n }\n }\n\n return { username, password, setUsername, setPassword };\n}\n","/**\n * `useLoginSubmit` — `<LoginForm>`'s submit logic, extracted from the component.\n *\n * The component's remaining body is JSX assembly; this hook owns the only branch\n * logic it had: the required-fields guard, the trimmed-username BFF call, and the\n * two error branches. Keeping it here makes that logic unit-testable and keeps\n * the render body under the component size limit.\n *\n * The error copy is deliberately generic: a wrong credential comes back from the\n * BFF as a non-2xx, and the message must never echo the raw error (it can leak\n * whether the username exists).\n */\nimport { useCallback, useState } from 'react';\n\nimport type { BffLoginRequest, BffUser } from '@dloizides/auth-client';\n\n/** Inputs the submit logic needs from `<LoginForm>`. */\nexport interface UseLoginSubmitArgs {\n /** The current username field value (trimmed before submit). */\n username: string;\n /** The current password field value. */\n password: string;\n /** The BFF password-login callback from `useBffAuth`. */\n login: (request: BffLoginRequest) => Promise<BffUser>;\n /** Called with the signed-in user after a successful login. */\n onSuccess: (user: BffUser) => void;\n /** Message shown when one or both fields are empty on submit. */\n missingFieldsLabel: string;\n /** Generic credentials-rejected message. */\n invalidCredentialsLabel: string;\n}\n\n/** The current error text (if any) plus the void-returning press handler. */\nexport interface UseLoginSubmitResult {\n /** The message to show, or `null` when there is nothing to report. */\n errorText: string | null;\n /** `onPress`-ready handler that runs the login. */\n handleSubmit: () => void;\n}\n\n/** Own `<LoginForm>`'s submit branch logic and its error state. */\nexport function useLoginSubmit({\n username,\n password,\n login,\n onSuccess,\n missingFieldsLabel,\n invalidCredentialsLabel,\n}: Readonly<UseLoginSubmitArgs>): UseLoginSubmitResult {\n const [errorText, setErrorText] = useState<string | null>(null);\n\n const runLogin = useCallback(async (): Promise<void> => {\n setErrorText(null);\n const trimmedUsername = username.trim();\n const hasMissingField = trimmedUsername.length === 0 || password.length === 0;\n if (hasMissingField) {\n setErrorText(missingFieldsLabel);\n return;\n }\n try {\n const user = await login({ username: trimmedUsername, password });\n onSuccess(user);\n } catch {\n // The BFF answers a wrong credential with a non-2xx; show a generic\n // message — never echo the raw error (it can leak whether the user exists).\n setErrorText(invalidCredentialsLabel);\n }\n }, [username, password, login, onSuccess, missingFieldsLabel, invalidCredentialsLabel]);\n\n // `onPress` expects a void-returning handler; `runLogin` is async, so wrap it.\n const handleSubmit = useCallback((): void => {\n void runLogin();\n }, [runLogin]);\n\n return { errorText, handleSubmit };\n}\n","/**\n * `useBffAuth` — the headless login/logout/session hook.\n *\n * This is the \"escape hatch\" half of the package's design: apps that want a\n * fully custom layout skip `<LoginForm>` and drive auth themselves with this\n * hook. `<LoginForm>` itself is built on top of it, so the ready-made and the\n * custom paths share one code path.\n *\n * It owns nothing the BFF owns: no tokens, no refresh, no realm awareness. It\n * holds only the *current user* (the sanitised claims from `/bff/me`) plus the\n * in-flight status of `login` / `logout`. The httpOnly session cookie is the\n * single source of truth — `refresh()` re-reads `/bff/me` to resync.\n *\n * `BffUser` and `BffAuthClient` come from `@dloizides/auth-client`.\n */\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react';\n\nimport type { BffAuthClient, BffLoginRequest, BffUser } from '@dloizides/auth-client';\n\n/** Lifecycle status of the auth session. */\nexport const enum BffAuthStatus {\n /** The initial `/bff/me` probe has not finished yet. */\n Loading = 'loading',\n /** A live session exists; `user` is populated. */\n Authenticated = 'authenticated',\n /** No session; `user` is `null`. */\n Unauthenticated = 'unauthenticated',\n}\n\nexport interface UseBffAuthOptions {\n /** The same-origin BFF client (build it with `createBffAuthClient`). */\n client: BffAuthClient;\n /**\n * When `true` (default), the hook probes `GET /bff/me` on mount to bootstrap\n * `status`/`user`. Set `false` to skip the probe (e.g. on a public page).\n */\n probeOnMount?: boolean;\n}\n\nexport interface UseBffAuthResult {\n /** The signed-in user, or `null` when there is no session. */\n user: BffUser | null;\n /** Session lifecycle status. */\n status: BffAuthStatus;\n /** `true` while a `login` or `logout` call is in flight. */\n isSubmitting: boolean;\n /** The last `login`/`logout`/`refresh` error, cleared on the next attempt. */\n error: Error | null;\n /** ROPC password login via `POST /bff/login`. Resolves to the user; rejects on failure. */\n login: (request: BffLoginRequest) => Promise<BffUser>;\n /** End the session via `POST /bff/logout`. Always resolves; never throws to the caller. */\n logout: () => Promise<void>;\n /** Re-read `GET /bff/me` and resync `user`/`status`. */\n refresh: () => Promise<void>;\n}\n\n/** Internal: the mutable session state the hook tracks. */\ninterface SessionState {\n user: BffUser | null;\n status: BffAuthStatus;\n}\n\nconst INITIAL_LOADING: SessionState = { user: null, status: BffAuthStatus.Loading };\nconst INITIAL_IDLE: SessionState = { user: null, status: BffAuthStatus.Unauthenticated };\n\nfunction toError(value: unknown): Error {\n return value instanceof Error ? value : new Error(String(value));\n}\n\n/**\n * Headless BFF auth. Returns the current user, the session status, and\n * `login` / `logout` / `refresh` callbacks. No rendering — the consumer (or\n * `<LoginForm>`) wires it to UI.\n */\nexport function useBffAuth(options: UseBffAuthOptions): UseBffAuthResult {\n const { client, probeOnMount = true } = options;\n\n const [session, setSession] = useState<SessionState>(\n probeOnMount ? INITIAL_LOADING : INITIAL_IDLE,\n );\n const [isSubmitting, setIsSubmitting] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n\n // Guard against a `setState` after the consumer unmounts mid-request.\n const mountedRef = useRef(true);\n useEffect(() => {\n mountedRef.current = true;\n return (): void => {\n mountedRef.current = false;\n };\n }, []);\n\n const safeSetSession = useCallback((next: SessionState) => {\n if (mountedRef.current) {\n setSession(next);\n }\n }, []);\n\n const refresh = useCallback(async (): Promise<void> => {\n try {\n const user = await client.getCurrentUser();\n safeSetSession(\n user === null\n ? INITIAL_IDLE\n : { user, status: BffAuthStatus.Authenticated },\n );\n } catch (caught) {\n safeSetSession(INITIAL_IDLE);\n if (mountedRef.current) {\n setError(toError(caught));\n }\n }\n }, [client, safeSetSession]);\n\n const login = useCallback(\n async (request: BffLoginRequest): Promise<BffUser> => {\n if (mountedRef.current) {\n setIsSubmitting(true);\n setError(null);\n }\n try {\n const user = await client.login(request);\n safeSetSession({ user, status: BffAuthStatus.Authenticated });\n return user;\n } catch (caught) {\n const err = toError(caught);\n if (mountedRef.current) {\n setError(err);\n }\n throw err;\n } finally {\n if (mountedRef.current) {\n setIsSubmitting(false);\n }\n }\n },\n [client, safeSetSession],\n );\n\n const logout = useCallback(async (): Promise<void> => {\n if (mountedRef.current) {\n setIsSubmitting(true);\n setError(null);\n }\n try {\n await client.logout();\n } catch (caught) {\n // A failed logout still leaves the SPA logged out client-side — surface\n // the error but do not reject; the caller's UI should not get stuck.\n if (mountedRef.current) {\n setError(toError(caught));\n }\n } finally {\n safeSetSession(INITIAL_IDLE);\n if (mountedRef.current) {\n setIsSubmitting(false);\n }\n }\n }, [client, safeSetSession]);\n\n // Bootstrap the session once on mount when probing is enabled.\n useEffect(() => {\n if (probeOnMount) {\n void refresh();\n }\n // `refresh` is stable for a stable `client`; `probeOnMount` is read once.\n }, [probeOnMount, refresh]);\n\n return useMemo(\n () => ({\n user: session.user,\n status: session.status,\n isSubmitting,\n error,\n login,\n logout,\n refresh,\n }),\n [session.user, session.status, isSubmitting, error, login, logout, refresh],\n );\n}\n","/**\n * `<LoginForm>` — the ready-made, themeable password-login form.\n *\n * The \"themeable component\" half of the package design: drop it in, pass a\n * `client`, a `theme` (or wrap in `<AuthThemeProvider>`) and a localised\n * `labels` bag, and you have a branded login surface. It is built on the\n * headless `useBffAuth` hook, so the ready-made and custom-layout paths share\n * one code path.\n *\n * The package ships no router and no i18n. `onSuccess` hands the signed-in\n * `BffUser` back to the app, which decides where to navigate (typically via\n * `resolvePostLoginRoute`). All copy comes from `labels`.\n */\nimport { useMemo, type ReactElement } from 'react';\n\nimport { Text, TextInput, TouchableOpacity, View } from 'react-native';\n\nimport { Button } from '@dloizides/ui-buttons';\n\nimport { DEFAULT_LOGIN_LABELS, type LoginFormLabels } from './labels';\nimport { AuthTestIds, withTestIdPrefix } from './testIds';\nimport { useAuthStyles } from './useAuthStyles';\nimport { useLoginPrefill } from './useLoginPrefill';\nimport { useLoginSubmit } from './useLoginSubmit';\nimport { useBffAuth } from '../hooks/useBffAuth';\n\nimport { useAuthTheme } from '../theme/AuthThemeProvider';\n\nimport type { LoginFormProps } from './LoginForm.types';\n\nexport type { LoginFormProps } from './LoginForm.types';\n\n/** Themeable password-login form built on `useBffAuth`. */\nexport function LoginForm({\n client,\n theme: themeProp,\n labels: labelsProp,\n onSuccess,\n onForgotPassword,\n onSignUp,\n testIdPrefix,\n chromeless = false,\n initialUsername,\n initialPassword,\n prefillNonce,\n prefillIntent,\n}: Readonly<LoginFormProps>): ReactElement {\n const theme = useAuthTheme(themeProp);\n const styles = useAuthStyles(theme);\n const labels = useMemo<LoginFormLabels>(\n () => ({ ...DEFAULT_LOGIN_LABELS, ...labelsProp }),\n [labelsProp],\n );\n\n // probeOnMount is off: the login screen does not need a /bff/me round-trip.\n const { login, isSubmitting } = useBffAuth({ client, probeOnMount: false });\n\n // The credential fields: seeded from the `initial*` props, then owned by the\n // user. See `useLoginPrefill` for why the nonce exists.\n const { username, password, setUsername, setPassword } = useLoginPrefill({\n initialUsername,\n initialPassword,\n prefillNonce,\n prefillIntent,\n });\n\n const { errorText, handleSubmit } = useLoginSubmit({\n username,\n password,\n login,\n onSuccess,\n missingFieldsLabel: labels.missingFields,\n invalidCredentialsLabel: labels.invalidCredentials,\n });\n\n const content = (\n <>\n <Text style={styles.title}>{labels.title}</Text>\n <Text style={styles.subtitle}>{labels.subtitle}</Text>\n\n <View style={styles.fieldGroup}>\n <Text style={styles.label}>{labels.usernameLabel}</Text>\n <TextInput\n accessibilityHint={labels.usernamePlaceholder}\n accessibilityLabel={labels.usernameLabel}\n autoCapitalize=\"none\"\n autoCorrect={false}\n editable={!isSubmitting}\n placeholder={labels.usernamePlaceholder}\n placeholderTextColor={theme.colors.textSecondary}\n style={styles.input}\n testID={withTestIdPrefix(AuthTestIds.loginUsernameInput, testIdPrefix)}\n value={username}\n onChangeText={setUsername}\n />\n </View>\n\n <View style={styles.fieldGroup}>\n <Text style={styles.label}>{labels.passwordLabel}</Text>\n <TextInput\n secureTextEntry\n accessibilityHint={labels.passwordPlaceholder}\n accessibilityLabel={labels.passwordLabel}\n autoCapitalize=\"none\"\n autoCorrect={false}\n editable={!isSubmitting}\n placeholder={labels.passwordPlaceholder}\n placeholderTextColor={theme.colors.textSecondary}\n style={styles.input}\n testID={withTestIdPrefix(AuthTestIds.loginPasswordInput, testIdPrefix)}\n value={password}\n onChangeText={setPassword}\n />\n </View>\n\n {errorText !== null ? (\n <Text\n style={styles.errorText}\n testID={withTestIdPrefix(AuthTestIds.loginError, testIdPrefix)}\n >\n {errorText}\n </Text>\n ) : null}\n\n {onForgotPassword !== undefined ? (\n <TouchableOpacity\n accessibilityHint={labels.forgotPassword}\n accessibilityLabel={labels.forgotPassword}\n accessibilityRole=\"link\"\n disabled={isSubmitting}\n style={styles.fieldGroup}\n testID={withTestIdPrefix(AuthTestIds.loginForgotLink, testIdPrefix)}\n onPress={onForgotPassword}\n >\n <Text style={styles.linkText}>{labels.forgotPassword}</Text>\n </TouchableOpacity>\n ) : null}\n\n {/* The shared Button owns keyboard parity: a held Enter is one login, not one per key-repeat. */}\n <View style={styles.fieldGroup}>\n <Button\n fullWidth\n accessibilityHint={labels.submit}\n accessibilityLabel={isSubmitting ? labels.submitting : labels.submit}\n label={labels.submit}\n loading={isSubmitting}\n testID={withTestIdPrefix(AuthTestIds.loginSubmitButton, testIdPrefix)}\n onPress={handleSubmit}\n />\n </View>\n\n {onSignUp !== undefined ? (\n <TouchableOpacity\n accessibilityHint={labels.signUp}\n accessibilityLabel={labels.signUp}\n accessibilityRole=\"link\"\n disabled={isSubmitting}\n style={styles.fieldGroup}\n testID={withTestIdPrefix(AuthTestIds.loginSignUpLink, testIdPrefix)}\n onPress={onSignUp}\n >\n <Text style={styles.linkText}>{labels.signUp}</Text>\n </TouchableOpacity>\n ) : null}\n </>\n );\n\n const card = (\n <View\n style={chromeless ? undefined : styles.card}\n testID={withTestIdPrefix(AuthTestIds.loginForm, testIdPrefix)}\n >\n {content}\n </View>\n );\n\n return chromeless ? card : <View style={styles.screen}>{card}</View>;\n}\n","/**\n * React Query mutation hooks for the BFF password-reset flow.\n *\n * Headless counterparts to `<ForgotPasswordForm>` / `<ResetPasswordForm>` —\n * apps with a custom layout use these directly. They POST to the same-origin\n * `/bff/forgot-password` and `/bff/reset-password`, which the BFF proxies to\n * TenantService.\n *\n * Extracted + generalised from `apps/katalogos-web/src/auth/bffPasswordHooks.ts`.\n * Difference: the katalogos version closed over a module-level singleton\n * `bffAuthClient`; the package version takes the `client` in the options so it\n * carries no global state.\n *\n * The mutation result type is `undefined` (not `void`): the BFF endpoints\n * return no body, and `undefined` is a valid generic argument where the lint\n * config rejects `void`.\n */\nimport { useMutation, type UseMutationOptions, type UseMutationResult } from '@tanstack/react-query';\n\nimport type {\n BffAuthClient,\n BffForgotPasswordRequest,\n BffResetPasswordRequest,\n} from '@dloizides/auth-client';\n\nexport type UseBffForgotPasswordOptions = Omit<\n UseMutationOptions<undefined, Error, BffForgotPasswordRequest>,\n 'mutationFn'\n> & {\n /** The same-origin BFF client. */\n client: BffAuthClient;\n};\n\n/**\n * Mutation that POSTs to `/bff/forgot-password`.\n *\n * The backend returns 200 unconditionally (no email enumeration); the UI\n * should show the same \"if that email exists, we sent a link\" message whether\n * `onSuccess` or `onError` fires.\n */\nexport function useBffForgotPassword(\n options: UseBffForgotPasswordOptions,\n): UseMutationResult<undefined, Error, BffForgotPasswordRequest> {\n const { client, ...rest } = options;\n return useMutation<undefined, Error, BffForgotPasswordRequest>({\n mutationFn: async (request) => {\n await client.forgotPassword(request);\n return undefined;\n },\n ...rest,\n });\n}\n\nexport type UseBffResetPasswordOptions = Omit<\n UseMutationOptions<undefined, Error, BffResetPasswordRequest>,\n 'mutationFn'\n> & {\n /** The same-origin BFF client. */\n client: BffAuthClient;\n};\n\n/**\n * Mutation that POSTs to `/bff/reset-password`. A `400` (invalid / expired\n * token) surfaces as a rejected mutation with the status in the error message.\n */\nexport function useBffResetPassword(\n options: UseBffResetPasswordOptions,\n): UseMutationResult<undefined, Error, BffResetPasswordRequest> {\n const { client, ...rest } = options;\n return useMutation<undefined, Error, BffResetPasswordRequest>({\n mutationFn: async (request) => {\n await client.resetPassword(request);\n return undefined;\n },\n ...rest,\n });\n}\n","/**\n * `<ForgotPasswordForm>` — the ready-made, themeable \"request a reset link\"\n * form.\n *\n * Captures an email and POSTs to `/bff/forgot-password` via the headless\n * `useBffForgotPassword` hook. The backend answers 200 unconditionally (no\n * email enumeration), so on success the form swaps to a generic confirmation\n * message — it never reveals whether the address is registered.\n *\n * Extracted + generalised from `apps/katalogos-web/src/components/Auth/\n * ForgotPasswordModal.tsx` — minus the modal shell (apps own the surface) and\n * the app-specific `FM()` calls (copy now comes from `labels`).\n */\nimport { useCallback, useMemo, useState, type ReactElement } from 'react';\n\nimport { ActivityIndicator, Text, TextInput, TouchableOpacity, View } from 'react-native';\n\nimport { DEFAULT_FORGOT_PASSWORD_LABELS, type ForgotPasswordFormLabels } from './labels';\nimport { AuthTestIds, withTestIdPrefix } from './testIds';\nimport { useAuthStyles } from './useAuthStyles';\nimport { useBffForgotPassword } from '../hooks/useBffPasswordHooks';\nimport { useAuthTheme } from '../theme/AuthThemeProvider';\n\nimport type { AuthTheme } from '../theme/AuthTheme';\nimport type { BffAuthClient } from '@dloizides/auth-client';\n\n// A deliberately loose, linear-time email shape check — `[^@\\s]` and `[^.\\s]`\n// character classes have no overlapping alternation, so there is no\n// super-linear backtracking. Strict validation is the backend's job.\nconst EMAIL_REGEX = /^[^@\\s]+@[^.\\s]+\\.[^\\s]+$/;\n\nexport interface ForgotPasswordFormProps {\n /** The same-origin BFF client (build it with `createBffAuthClient`). */\n client: BffAuthClient;\n /** Explicit theme; overrides any `<AuthThemeProvider>`. */\n theme?: AuthTheme;\n /** Localised copy. Partial — unspecified keys fall back to English defaults. */\n labels?: Partial<ForgotPasswordFormLabels>;\n /**\n * Full URL with a `{token}` placeholder; forwarded to the backend so it can\n * build the reset-email link without hardcoding any frontend host. Optional —\n * apps that configure the template server-side can omit it.\n */\n resetUrlTemplate?: string;\n /** Called once the request succeeds (the generic-confirmation state). */\n onSuccess?: () => void;\n /** Prefix applied to every `testID`. */\n testIdPrefix?: string;\n}\n\n/** `true` when `value` looks like an email address. */\nfunction isValidEmail(value: string): boolean {\n return EMAIL_REGEX.test(value);\n}\n\n/** Themeable \"request a reset link\" form built on `useBffForgotPassword`. */\nexport function ForgotPasswordForm({\n client,\n theme: themeProp,\n labels: labelsProp,\n resetUrlTemplate,\n onSuccess,\n testIdPrefix,\n}: Readonly<ForgotPasswordFormProps>): ReactElement {\n const theme = useAuthTheme(themeProp);\n const styles = useAuthStyles(theme);\n const labels = useMemo<ForgotPasswordFormLabels>(\n () => ({ ...DEFAULT_FORGOT_PASSWORD_LABELS, ...labelsProp }),\n [labelsProp],\n );\n\n const [email, setEmail] = useState('');\n const [submitted, setSubmitted] = useState(false);\n const [errorText, setErrorText] = useState<string | null>(null);\n\n const mutationOptions = useMemo(\n () => ({\n client,\n onSuccess: (): void => {\n setSubmitted(true);\n onSuccess?.();\n },\n onError: (): void => {\n // Only a network / 5xx failure reaches here — a 200 (the no-enumeration\n // branch) is success. Show a friendly retry message.\n setErrorText(labels.networkError);\n },\n }),\n [client, onSuccess, labels.networkError],\n );\n const mutation = useBffForgotPassword(mutationOptions);\n\n const isPending = mutation.status === 'pending';\n\n const handleSubmit = useCallback((): void => {\n setErrorText(null);\n const trimmedEmail = email.trim();\n if (!isValidEmail(trimmedEmail)) {\n setErrorText(labels.invalidEmail);\n return;\n }\n mutation.mutate({ email: trimmedEmail, resetUrlTemplate });\n }, [email, mutation, resetUrlTemplate, labels.invalidEmail]);\n\n const submitButtonStyle = isPending\n ? [styles.primaryButton, styles.primaryButtonDisabled]\n : styles.primaryButton;\n\n return (\n <View style={styles.screen}>\n <View\n style={styles.card}\n testID={withTestIdPrefix(AuthTestIds.forgotPasswordForm, testIdPrefix)}\n >\n <Text style={styles.title}>{labels.title}</Text>\n\n {submitted ? (\n <Text\n style={styles.successText}\n testID={withTestIdPrefix(AuthTestIds.forgotPasswordSuccess, testIdPrefix)}\n >\n {labels.successMessage}\n </Text>\n ) : (\n <>\n <Text style={styles.subtitle}>{labels.description}</Text>\n\n <View style={styles.fieldGroup}>\n <Text style={styles.label}>{labels.emailLabel}</Text>\n <TextInput\n accessibilityHint={labels.emailPlaceholder}\n accessibilityLabel={labels.emailLabel}\n autoCapitalize=\"none\"\n autoCorrect={false}\n editable={!isPending}\n keyboardType=\"email-address\"\n placeholder={labels.emailPlaceholder}\n placeholderTextColor={theme.colors.textSecondary}\n style={styles.input}\n testID={withTestIdPrefix(AuthTestIds.forgotPasswordEmailInput, testIdPrefix)}\n value={email}\n onChangeText={setEmail}\n />\n </View>\n\n {errorText !== null ? (\n <Text\n style={styles.errorText}\n testID={withTestIdPrefix(AuthTestIds.forgotPasswordError, testIdPrefix)}\n >\n {errorText}\n </Text>\n ) : null}\n\n <TouchableOpacity\n accessibilityHint={labels.submit}\n accessibilityLabel={isPending ? labels.submitting : labels.submit}\n accessibilityRole=\"button\"\n disabled={isPending}\n style={submitButtonStyle}\n testID={withTestIdPrefix(AuthTestIds.forgotPasswordSubmitButton, testIdPrefix)}\n onPress={handleSubmit}\n >\n {isPending ? (\n <ActivityIndicator color={theme.colors.onPrimary} size=\"small\" />\n ) : (\n <Text style={styles.primaryButtonText}>{labels.submit}</Text>\n )}\n </TouchableOpacity>\n </>\n )}\n </View>\n </View>\n );\n}\n","/**\n * `useForgotPasswordSubmit` — react-query-FREE form-state + submit logic for a\n * \"request a reset link\" surface.\n *\n * Why a second forgot-password hook when `useBffForgotPassword` already exists?\n * That one wraps `useMutation`, so it can only run under a `QueryClientProvider`.\n * The product login routes (katalogos / erevna / kefi) deliberately keep\n * react-query OUT of their bundle — there is no provider there, and mounting a\n * `useMutation` crashes with \"No QueryClient set\". Every app therefore\n * hand-rolled the same direct-`client.forgotPassword` call. This hook is that\n * shared logic, promoted into the package: a plain `useState` + promise chain,\n * safe on a provider-less route.\n *\n * Behaviour mirrors the apps' modal exactly:\n * - `canSubmit` is true only when the trimmed email looks valid and no request\n * is in flight (the submit button gates on this).\n * - `submit()` no-ops when the email is invalid or a request is already running.\n * - The backend is anti-enumeration (always 200 for the \"found an account?\"\n * branch), so the only failure that surfaces is a network / 5xx one, via\n * `hasNetworkError`.\n * - `reset()` clears everything — call it when the modal closes so reopening\n * shows a fresh form.\n */\nimport { useCallback, useState } from 'react';\n\nimport type { BffAuthClient, BffForgotPasswordRequest } from '@dloizides/auth-client';\n\n// A deliberately loose, linear-time email shape check — the `[^@\\s]` / `[^.\\s]`\n// character classes share no alternation, so there is no super-linear\n// backtracking. Strict validation is the backend's job.\nconst EMAIL_REGEX = /^[^@\\s]+@[^.\\s]+\\.[^\\s]+$/;\n\n/** `true` when `value` (after trimming) looks like an email address. */\nexport function isValidForgotPasswordEmail(value: string): boolean {\n return EMAIL_REGEX.test(value.trim());\n}\n\nexport interface UseForgotPasswordSubmitArgs {\n /** The same-origin BFF client (build it with `createBffAuthClient`). */\n client: BffAuthClient;\n /**\n * Full URL with a `{token}` placeholder, forwarded to the backend so it can\n * build the reset-email link without hardcoding a frontend host.\n */\n resetUrlTemplate?: string;\n /** Invoked once the request succeeds (the generic-confirmation state). */\n onSuccess?: () => void;\n}\n\nexport interface UseForgotPasswordSubmitResult {\n email: string;\n setEmail: (value: string) => void;\n /** `true` once the request has succeeded (show the generic confirmation). */\n submitted: boolean;\n /** `true` while the request is in flight. */\n isSubmitting: boolean;\n /** `true` when the last submit hit a network / 5xx failure. */\n hasNetworkError: boolean;\n /** `true` when the email is valid and no request is in flight. */\n canSubmit: boolean;\n /** Validate, then fire the request (no-op when `canSubmit` is false). */\n submit: () => void;\n /** Clear all state — call when the modal closes. */\n reset: () => void;\n}\n\n/** Headless, react-query-free \"request a reset link\" logic. */\nexport function useForgotPasswordSubmit({\n client,\n resetUrlTemplate,\n onSuccess,\n}: UseForgotPasswordSubmitArgs): UseForgotPasswordSubmitResult {\n const [email, setEmail] = useState('');\n const [submitted, setSubmitted] = useState(false);\n const [isSubmitting, setIsSubmitting] = useState(false);\n const [hasNetworkError, setHasNetworkError] = useState(false);\n\n const canSubmit = isValidForgotPasswordEmail(email) && !isSubmitting;\n\n const submit = useCallback((): void => {\n const target = email.trim();\n if (!isValidForgotPasswordEmail(target) || isSubmitting) {\n return;\n }\n setHasNetworkError(false);\n setIsSubmitting(true);\n const request: BffForgotPasswordRequest = { email: target, resetUrlTemplate };\n client\n .forgotPassword(request)\n .then(() => {\n setSubmitted(true);\n onSuccess?.();\n })\n .catch(() => setHasNetworkError(true))\n .finally(() => setIsSubmitting(false));\n }, [client, email, isSubmitting, resetUrlTemplate, onSuccess]);\n\n const reset = useCallback((): void => {\n setEmail('');\n setSubmitted(false);\n setIsSubmitting(false);\n setHasNetworkError(false);\n }, []);\n\n return {\n email,\n setEmail,\n submitted,\n isSubmitting,\n hasNetworkError,\n canSubmit,\n submit,\n reset,\n };\n}\n","/**\n * `<ForgotPasswordFields>` — the embedded, themeable \"request a reset link\"\n * body, sized to live INSIDE an app-owned modal shell (not a full screen).\n *\n * The product apps each show \"Forgot password?\" as a modal launched from their\n * login route, wrapping their own modal chrome (title bar + close affordance)\n * around an identical email field + submit/cancel body. This is that body,\n * promoted into the package so the three apps stop hand-rolling it.\n *\n * Built on the react-query-free `useForgotPasswordSubmit` hook, so it renders +\n * submits on a provider-less login route (where `useMutation` would crash). The\n * backend is anti-enumeration, so a successful request swaps to a generic\n * confirmation that never reveals whether the address is registered.\n *\n * Differs from the screen-shaped `<ForgotPasswordForm>`: no outer screen/card\n * wrapper and no title (the host modal owns those), plus two modal affordances —\n * a `Cancel` button beside submit and a `Close` button on the success state —\n * each rendered only when its handler is supplied.\n */\nimport { useEffect, useMemo, type ReactElement } from 'react';\n\nimport {\n ActivityIndicator,\n StyleSheet,\n Text,\n TextInput,\n TouchableOpacity,\n View,\n type TextStyle,\n type ViewStyle,\n} from 'react-native';\n\nimport {\n DEFAULT_FORGOT_PASSWORD_FIELDS_LABELS,\n type ForgotPasswordFieldsLabels,\n} from './labels';\nimport { AuthTestIds, withTestIdPrefix } from './testIds';\nimport { useAuthStyles } from './useAuthStyles';\nimport { useForgotPasswordSubmit } from '../hooks/useForgotPasswordSubmit';\nimport { useAuthTheme } from '../theme/AuthThemeProvider';\n\nimport type { AuthTheme } from '../theme/AuthTheme';\nimport type { BffAuthClient } from '@dloizides/auth-client';\n\nconst SECONDARY_BORDER_WIDTH = 1;\n\nexport interface ForgotPasswordFieldsProps {\n /** The same-origin BFF client (build it with `createBffAuthClient`). */\n client: BffAuthClient;\n /** Explicit theme; overrides any `<AuthThemeProvider>`. */\n theme?: AuthTheme;\n /** Localised copy. Partial — unspecified keys fall back to English defaults. */\n labels?: Partial<ForgotPasswordFieldsLabels>;\n /**\n * Full URL with a `{token}` placeholder, forwarded to the backend so it can\n * build the reset-email link without hardcoding a frontend host.\n */\n resetUrlTemplate?: string;\n /**\n * The host modal's open state. When it flips to `false` the body clears\n * itself, so reopening shows a fresh form regardless of which affordance\n * closed it. Defaults to `true` for non-modal embedding.\n */\n visible?: boolean;\n /** Called once the request succeeds (the generic-confirmation state). */\n onSuccess?: () => void;\n /** When supplied, renders a Cancel button beside submit. */\n onCancel?: () => void;\n /** When supplied, renders a Close button on the success state. */\n onClose?: () => void;\n /** Prefix applied to every `testID`. */\n testIdPrefix?: string;\n}\n\n/** The modal-specific styles `useAuthStyles` does not carry. */\ninterface ModalStyles {\n body: ViewStyle;\n actions: ViewStyle;\n secondaryButton: ViewStyle;\n secondaryButtonText: TextStyle;\n}\n\n/** Build the modal-only styles from the resolved theme. */\nfunction useModalStyles(theme: AuthTheme): ModalStyles {\n return useMemo(\n () =>\n StyleSheet.create<ModalStyles>({\n body: { padding: theme.spacing.md },\n actions: {\n flexDirection: 'row',\n justifyContent: 'flex-end',\n alignItems: 'center',\n // Wrap (rather than clip) when a long submit label + Cancel can't\n // fit a narrow modal on one line.\n flexWrap: 'wrap',\n marginTop: theme.spacing.md,\n gap: theme.spacing.sm,\n },\n secondaryButton: {\n borderRadius: theme.radii.input,\n paddingVertical: theme.spacing.sm,\n paddingHorizontal: theme.spacing.md,\n // Match the submit button: never shrink below the label width.\n flexShrink: 0,\n borderWidth: SECONDARY_BORDER_WIDTH,\n borderColor: theme.colors.border,\n },\n secondaryButtonText: {\n fontSize: theme.typography.body,\n fontWeight: '600',\n color: theme.colors.text,\n },\n }),\n [theme],\n );\n}\n\n/** Embedded \"request a reset link\" body for an app-owned modal. */\nexport function ForgotPasswordFields({\n client,\n theme: themeProp,\n labels: labelsProp,\n resetUrlTemplate,\n visible = true,\n onSuccess,\n onCancel,\n onClose,\n testIdPrefix,\n}: Readonly<ForgotPasswordFieldsProps>): ReactElement {\n const theme = useAuthTheme(themeProp);\n const styles = useAuthStyles(theme);\n const modalStyles = useModalStyles(theme);\n const labels = useMemo<ForgotPasswordFieldsLabels>(\n () => ({ ...DEFAULT_FORGOT_PASSWORD_FIELDS_LABELS, ...labelsProp }),\n [labelsProp],\n );\n\n const form = useForgotPasswordSubmit({ client, resetUrlTemplate, onSuccess });\n\n // Clear the body when the host modal closes, so reopening starts fresh.\n const { reset } = form;\n useEffect(() => {\n if (!visible) {\n reset();\n }\n }, [visible, reset]);\n\n const submitButtonStyle = form.canSubmit\n ? styles.primaryButton\n : [styles.primaryButton, styles.primaryButtonDisabled];\n\n const handleCancel = (): void => {\n form.reset();\n onCancel?.();\n };\n\n const handleClose = (): void => {\n form.reset();\n onClose?.();\n };\n\n if (form.submitted) {\n return (\n <View style={modalStyles.body} testID={withTestIdPrefix(AuthTestIds.forgotPasswordForm, testIdPrefix)}>\n <Text style={styles.successText} testID={withTestIdPrefix(AuthTestIds.forgotPasswordSuccess, testIdPrefix)}>\n {labels.successMessage}\n </Text>\n {onClose !== undefined ? (\n <View style={modalStyles.actions}>\n <TouchableOpacity\n accessibilityHint={labels.close}\n accessibilityLabel={labels.close}\n accessibilityRole=\"button\"\n style={styles.primaryButton}\n testID={withTestIdPrefix(AuthTestIds.forgotPasswordCloseButton, testIdPrefix)}\n onPress={handleClose}\n >\n <Text style={styles.primaryButtonText}>{labels.close}</Text>\n </TouchableOpacity>\n </View>\n ) : null}\n </View>\n );\n }\n\n return (\n <View style={modalStyles.body} testID={withTestIdPrefix(AuthTestIds.forgotPasswordForm, testIdPrefix)}>\n <Text style={styles.subtitle}>{labels.description}</Text>\n\n <View style={styles.fieldGroup}>\n <Text style={styles.label}>{labels.emailLabel}</Text>\n <TextInput\n accessibilityHint={labels.emailPlaceholder}\n accessibilityLabel={labels.emailLabel}\n autoCapitalize=\"none\"\n autoCorrect={false}\n editable={!form.isSubmitting}\n keyboardType=\"email-address\"\n placeholder={labels.emailPlaceholder}\n placeholderTextColor={theme.colors.textSecondary}\n style={styles.input}\n testID={withTestIdPrefix(AuthTestIds.forgotPasswordEmailInput, testIdPrefix)}\n value={form.email}\n onChangeText={form.setEmail}\n />\n </View>\n\n {form.hasNetworkError ? (\n <Text style={styles.errorText} testID={withTestIdPrefix(AuthTestIds.forgotPasswordError, testIdPrefix)}>\n {labels.networkError}\n </Text>\n ) : null}\n\n <View style={modalStyles.actions}>\n {onCancel !== undefined ? (\n <TouchableOpacity\n accessibilityHint={labels.cancel}\n accessibilityLabel={labels.cancel}\n accessibilityRole=\"button\"\n disabled={form.isSubmitting}\n style={modalStyles.secondaryButton}\n testID={withTestIdPrefix(AuthTestIds.forgotPasswordCancelButton, testIdPrefix)}\n onPress={handleCancel}\n >\n <Text style={modalStyles.secondaryButtonText}>{labels.cancel}</Text>\n </TouchableOpacity>\n ) : null}\n\n <TouchableOpacity\n accessibilityHint={labels.submit}\n accessibilityLabel={form.isSubmitting ? labels.submitting : labels.submit}\n accessibilityRole=\"button\"\n disabled={!form.canSubmit}\n style={submitButtonStyle}\n testID={withTestIdPrefix(AuthTestIds.forgotPasswordSubmitButton, testIdPrefix)}\n onPress={form.submit}\n >\n {form.isSubmitting ? (\n <ActivityIndicator color={theme.colors.onPrimary} size=\"small\" />\n ) : (\n <Text style={styles.primaryButtonText}>{labels.submit}</Text>\n )}\n </TouchableOpacity>\n </View>\n </View>\n );\n}\n","/**\n * The discrete failure states the reset-password flow can surface.\n *\n * Each member is the stable key a consuming app maps onto a localised message.\n * `useResetPasswordForm` reports exactly one of these at a time, preferring the\n * earliest-fixable issue so the user resolves one thing at a time.\n */\nexport const enum ResetPasswordError {\n /** One or both password fields are empty. */\n Empty = 'empty',\n /** The new password fails the shared password policy. */\n WeakPassword = 'weakPassword',\n /** The confirm field does not match the new password. */\n Mismatch = 'mismatch',\n /** The reset token is missing, expired, or already consumed. */\n TokenInvalid = 'tokenInvalid',\n /** A network or 5xx failure prevented the reset from completing. */\n Network = 'network',\n}\n","/**\n * The discrete ways a password can fail the shared client-side policy.\n *\n * Each member is the stable key a consuming app maps onto a localised message —\n * the package never ships translated copy.\n */\nexport const enum PasswordPolicyError {\n /** Shorter than `PASSWORD_MIN_LENGTH`. */\n TooShort = 'tooShort',\n /** Longer than `PASSWORD_MAX_LENGTH`. */\n TooLong = 'tooLong',\n /** Contains no `A-Z` character. */\n MissingUppercase = 'missingUppercase',\n /** Contains no `a-z` character. */\n MissingLowercase = 'missingLowercase',\n /** Contains no `0-9` character. */\n MissingDigit = 'missingDigit',\n}\n","/**\n * Client-side password policy that mirrors the backend\n * (TenantService `ResetPasswordRequestValidator`):\n *\n * - 8 ≤ length ≤ 128\n * - at least one uppercase letter\n * - at least one lowercase letter\n * - at least one digit\n *\n * Shared so every app's `<ResetPasswordForm>` (and any future password input)\n * rejects ~99% of bad passwords before a network round-trip. Extracted from\n * `apps/katalogos-web/src/auth/passwordPolicy.ts`.\n */\nimport { PasswordPolicyError } from './PasswordPolicyError';\n\nconst UPPERCASE_REGEX = /[A-Z]/;\nconst LOWERCASE_REGEX = /[a-z]/;\nconst DIGIT_REGEX = /\\d/;\n\n/** Minimum acceptable password length. */\nexport const PASSWORD_MIN_LENGTH = 8;\n/** Maximum acceptable password length. */\nexport const PASSWORD_MAX_LENGTH = 128;\n\n/**\n * Return every policy rule the given password violates. An empty array means\n * the password is acceptable.\n */\nexport function validatePasswordPolicy(password: string): PasswordPolicyError[] {\n const errors: PasswordPolicyError[] = [];\n if (password.length < PASSWORD_MIN_LENGTH) {\n errors.push(PasswordPolicyError.TooShort);\n }\n if (password.length > PASSWORD_MAX_LENGTH) {\n errors.push(PasswordPolicyError.TooLong);\n }\n if (!UPPERCASE_REGEX.test(password)) {\n errors.push(PasswordPolicyError.MissingUppercase);\n }\n if (!LOWERCASE_REGEX.test(password)) {\n errors.push(PasswordPolicyError.MissingLowercase);\n }\n if (!DIGIT_REGEX.test(password)) {\n errors.push(PasswordPolicyError.MissingDigit);\n }\n return errors;\n}\n\n/** `true` when the password satisfies every policy rule. */\nexport function isPasswordValid(password: string): boolean {\n return validatePasswordPolicy(password).length === 0;\n}\n","/**\n * `useResetPasswordForm` — form-state + submit logic for the reset-password\n * screen.\n *\n * The (testable) logic — policy validation, confirm-match, error mapping — is\n * kept out of the rendered component so `<ResetPasswordForm>` stays thin and\n * the rules are unit-tested directly. The hook returns plain values + callbacks\n * the component (or a custom layout) wires to JSX.\n *\n * Behaviour:\n * - Validates the new password against the shared `passwordPolicy`.\n * - Validates confirmPassword matches.\n * - Surfaces a single `ResetPasswordError` at submit time, preferring the\n * earliest-fixable issue (empty → weak → mismatch → token).\n * - Calls `useBffResetPassword` (`POST /bff/reset-password`). On success,\n * invokes the supplied `onSuccess`.\n *\n * Extracted + generalised from `apps/katalogos-web/src/auth/useResetPasswordForm.ts`.\n */\nimport { useMemo, useState } from 'react';\n\nimport { ResetPasswordError } from './ResetPasswordError';\nimport { useBffResetPassword } from './useBffPasswordHooks';\nimport { isPasswordValid } from '../password/passwordPolicy';\n\nimport type { BffAuthClient } from '@dloizides/auth-client';\n\nconst HTTP_BAD_REQUEST = 400;\n\nexport interface UseResetPasswordFormArgs {\n /** The same-origin BFF client. */\n client: BffAuthClient;\n /** The reset token, typically read from the deep-link URL. */\n token: string;\n /** Invoked once the password has been reset successfully. */\n onSuccess: () => void;\n}\n\nexport interface UseResetPasswordFormResult {\n newPassword: string;\n confirmPassword: string;\n setNewPassword: (value: string) => void;\n setConfirmPassword: (value: string) => void;\n /** `true` while the reset request is in flight. */\n isSubmitting: boolean;\n /** The single active error, or `null` when the form is clean. */\n errorKey: ResetPasswordError | null;\n /** `true` once a token-related failure is detected (drives a \"request a new link\" UI). */\n hasInvalidToken: boolean;\n /** Validate, then submit. */\n submit: () => void;\n}\n\n/** `true` when the BFF error message carries the given HTTP status. */\nfunction isHttpStatusError(message: string, status: number): boolean {\n return message.includes(` status ${String(status)}`);\n}\n\n/** Run the synchronous pre-flight checks; the earliest-fixable failure wins. */\nfunction preflight(args: {\n newPassword: string;\n confirm: string;\n token: string;\n}): ResetPasswordError | null {\n if (args.newPassword.length === 0 || args.confirm.length === 0) {\n return ResetPasswordError.Empty;\n }\n if (!isPasswordValid(args.newPassword)) {\n return ResetPasswordError.WeakPassword;\n }\n if (args.newPassword !== args.confirm) {\n return ResetPasswordError.Mismatch;\n }\n if (args.token === '') {\n return ResetPasswordError.TokenInvalid;\n }\n return null;\n}\n\ninterface MutationCallbacks {\n onSuccess: () => void;\n setErrorKey: (error: ResetPasswordError) => void;\n setHasInvalidToken: (value: boolean) => void;\n}\n\n/** Wire the reset mutation, mapping a backend 400 onto a token-invalid error. */\nfunction useResetMutation(\n client: BffAuthClient,\n callbacks: MutationCallbacks,\n): ReturnType<typeof useBffResetPassword> {\n const mutationOptions = useMemo(\n () => ({\n client,\n onSuccess: callbacks.onSuccess,\n onError: (err: Error): void => {\n if (isHttpStatusError(err.message, HTTP_BAD_REQUEST)) {\n callbacks.setHasInvalidToken(true);\n callbacks.setErrorKey(ResetPasswordError.TokenInvalid);\n return;\n }\n callbacks.setErrorKey(ResetPasswordError.Network);\n },\n }),\n [client, callbacks],\n );\n return useBffResetPassword(mutationOptions);\n}\n\ninterface SubmitArgs {\n newPassword: string;\n confirmPassword: string;\n token: string;\n setErrorKey: (error: ResetPasswordError | null) => void;\n setHasInvalidToken: (value: boolean) => void;\n mutate: (request: { token: string; newPassword: string }) => void;\n}\n\n/** Validate, then either fire the mutation or surface the pre-flight failure. */\nfunction runSubmit(args: SubmitArgs): void {\n args.setErrorKey(null);\n const failure = preflight({\n newPassword: args.newPassword,\n confirm: args.confirmPassword,\n token: args.token,\n });\n if (failure === null) {\n args.mutate({ token: args.token, newPassword: args.newPassword });\n return;\n }\n if (failure === ResetPasswordError.TokenInvalid) {\n args.setHasInvalidToken(true);\n }\n args.setErrorKey(failure);\n}\n\ninterface FormState {\n newPassword: string;\n confirmPassword: string;\n errorKey: ResetPasswordError | null;\n hasInvalidToken: boolean;\n}\n\ninterface FormSetters {\n setNewPassword: (value: string) => void;\n setConfirmPassword: (value: string) => void;\n setErrorKey: (error: ResetPasswordError | null) => void;\n setHasInvalidToken: (value: boolean) => void;\n}\n\n/** Bundle the four `useState` cells the form needs. */\nfunction useFormState(): { state: FormState; setters: FormSetters } {\n const [newPassword, setNewPassword] = useState('');\n const [confirmPassword, setConfirmPassword] = useState('');\n const [errorKey, setErrorKey] = useState<ResetPasswordError | null>(null);\n const [hasInvalidToken, setHasInvalidToken] = useState(false);\n return {\n state: { newPassword, confirmPassword, errorKey, hasInvalidToken },\n setters: { setNewPassword, setConfirmPassword, setErrorKey, setHasInvalidToken },\n };\n}\n\n/**\n * Headless reset-password form logic. Returns the field values, setters, the\n * single active error, and a `submit` callback.\n */\nexport function useResetPasswordForm({\n client,\n token,\n onSuccess,\n}: UseResetPasswordFormArgs): UseResetPasswordFormResult {\n const { state, setters } = useFormState();\n const callbacks = useMemo<MutationCallbacks>(\n () => ({\n onSuccess,\n setErrorKey: setters.setErrorKey,\n setHasInvalidToken: setters.setHasInvalidToken,\n }),\n [onSuccess, setters.setErrorKey, setters.setHasInvalidToken],\n );\n const mutation = useResetMutation(client, callbacks);\n const submit = (): void =>\n runSubmit({\n newPassword: state.newPassword,\n confirmPassword: state.confirmPassword,\n token,\n setErrorKey: setters.setErrorKey,\n setHasInvalidToken: setters.setHasInvalidToken,\n mutate: mutation.mutate,\n });\n return {\n newPassword: state.newPassword,\n confirmPassword: state.confirmPassword,\n setNewPassword: setters.setNewPassword,\n setConfirmPassword: setters.setConfirmPassword,\n isSubmitting: mutation.status === 'pending',\n errorKey: state.errorKey,\n hasInvalidToken: state.hasInvalidToken,\n submit,\n };\n}\n","/**\n * `<ResetPasswordForm>` — the ready-made, themeable \"choose a new password\"\n * form.\n *\n * Built on the headless `useResetPasswordForm` hook, which owns all the logic\n * (shared password policy, confirm-match, backend-error mapping). The component\n * is a thin render layer: two fields, one button, one error line.\n *\n * Extracted + generalised from `apps/katalogos-web/src/auth/useResetPasswordForm.ts`\n * + the katalogos reset-password route — minus the app-specific `FM()` and\n * router calls (copy is in `labels`, navigation is the app's `onSuccess`).\n */\nimport { useMemo, type ReactElement } from 'react';\n\nimport { ActivityIndicator, Text, TextInput, TouchableOpacity, View } from 'react-native';\n\nimport { DEFAULT_RESET_PASSWORD_LABELS, type ResetPasswordFormLabels } from './labels';\nimport { AuthTestIds, withTestIdPrefix } from './testIds';\nimport { useAuthStyles } from './useAuthStyles';\nimport { ResetPasswordError } from '../hooks/ResetPasswordError';\nimport { useResetPasswordForm } from '../hooks/useResetPasswordForm';\nimport { useAuthTheme } from '../theme/AuthThemeProvider';\n\nimport type { AuthTheme } from '../theme/AuthTheme';\nimport type { BffAuthClient } from '@dloizides/auth-client';\n\nexport interface ResetPasswordFormProps {\n /** The same-origin BFF client (build it with `createBffAuthClient`). */\n client: BffAuthClient;\n /** The reset token, typically read from the deep-link URL by the app. */\n token: string;\n /** Explicit theme; overrides any `<AuthThemeProvider>`. */\n theme?: AuthTheme;\n /** Localised copy. Partial — unspecified keys fall back to English defaults. */\n labels?: Partial<ResetPasswordFormLabels>;\n /** Called once the password has been reset successfully. */\n onSuccess: () => void;\n /** Prefix applied to every `testID`. */\n testIdPrefix?: string;\n}\n\n/** Resolve the active `ResetPasswordError` onto its localised message. */\nfunction errorMessage(\n errorKey: ResetPasswordError | null,\n labels: ResetPasswordFormLabels,\n): string | null {\n switch (errorKey) {\n case ResetPasswordError.Empty:\n return labels.errorEmpty;\n case ResetPasswordError.WeakPassword:\n return labels.errorWeakPassword;\n case ResetPasswordError.Mismatch:\n return labels.errorMismatch;\n case ResetPasswordError.TokenInvalid:\n return labels.errorTokenInvalid;\n case ResetPasswordError.Network:\n return labels.errorNetwork;\n default:\n return null;\n }\n}\n\n/** Themeable \"choose a new password\" form built on `useResetPasswordForm`. */\nexport function ResetPasswordForm({\n client,\n token,\n theme: themeProp,\n labels: labelsProp,\n onSuccess,\n testIdPrefix,\n}: Readonly<ResetPasswordFormProps>): ReactElement {\n const theme = useAuthTheme(themeProp);\n const styles = useAuthStyles(theme);\n const labels = useMemo<ResetPasswordFormLabels>(\n () => ({ ...DEFAULT_RESET_PASSWORD_LABELS, ...labelsProp }),\n [labelsProp],\n );\n\n const form = useResetPasswordForm({ client, token, onSuccess });\n const message = errorMessage(form.errorKey, labels);\n\n const submitButtonStyle = form.isSubmitting\n ? [styles.primaryButton, styles.primaryButtonDisabled]\n : styles.primaryButton;\n\n return (\n <View style={styles.screen}>\n <View\n style={styles.card}\n testID={withTestIdPrefix(AuthTestIds.resetPasswordForm, testIdPrefix)}\n >\n <Text style={styles.title}>{labels.title}</Text>\n <Text style={styles.subtitle}>{labels.description}</Text>\n\n <View style={styles.fieldGroup}>\n <Text style={styles.label}>{labels.newPasswordLabel}</Text>\n <TextInput\n secureTextEntry\n accessibilityHint={labels.newPasswordPlaceholder}\n accessibilityLabel={labels.newPasswordLabel}\n autoCapitalize=\"none\"\n autoCorrect={false}\n editable={!form.isSubmitting}\n placeholder={labels.newPasswordPlaceholder}\n placeholderTextColor={theme.colors.textSecondary}\n style={styles.input}\n testID={withTestIdPrefix(AuthTestIds.resetPasswordNewInput, testIdPrefix)}\n value={form.newPassword}\n onChangeText={form.setNewPassword}\n />\n </View>\n\n <View style={styles.fieldGroup}>\n <Text style={styles.label}>{labels.confirmPasswordLabel}</Text>\n <TextInput\n secureTextEntry\n accessibilityHint={labels.confirmPasswordPlaceholder}\n accessibilityLabel={labels.confirmPasswordLabel}\n autoCapitalize=\"none\"\n autoCorrect={false}\n editable={!form.isSubmitting}\n placeholder={labels.confirmPasswordPlaceholder}\n placeholderTextColor={theme.colors.textSecondary}\n style={styles.input}\n testID={withTestIdPrefix(AuthTestIds.resetPasswordConfirmInput, testIdPrefix)}\n value={form.confirmPassword}\n onChangeText={form.setConfirmPassword}\n />\n </View>\n\n {message !== null ? (\n <Text\n style={styles.errorText}\n testID={withTestIdPrefix(AuthTestIds.resetPasswordError, testIdPrefix)}\n >\n {message}\n </Text>\n ) : null}\n\n <TouchableOpacity\n accessibilityHint={labels.submit}\n accessibilityLabel={form.isSubmitting ? labels.submitting : labels.submit}\n accessibilityRole=\"button\"\n disabled={form.isSubmitting}\n style={submitButtonStyle}\n testID={withTestIdPrefix(AuthTestIds.resetPasswordSubmitButton, testIdPrefix)}\n onPress={form.submit}\n >\n {form.isSubmitting ? (\n <ActivityIndicator color={theme.colors.onPrimary} size=\"small\" />\n ) : (\n <Text style={styles.primaryButtonText}>{labels.submit}</Text>\n )}\n </TouchableOpacity>\n </View>\n </View>\n );\n}\n","/**\n * The two step sub-components of `<OtpForm>` — `<OtpRequestStep>` (collect the\n * email, ask the BFF to send a code) and `<OtpVerifyStep>` (collect the code,\n * verify it, offer resend / change-email).\n *\n * Split out of `OtpForm.tsx` to keep that file focused on the flow wiring; each\n * step is a thin, self-contained render layer. Both are styled by the shared\n * `AuthStyles` token-derived stylesheet so they match the other auth forms.\n */\nimport { useState, type ReactElement } from 'react';\n\nimport { ActivityIndicator, Text, TextInput, TouchableOpacity, View } from 'react-native';\n\nimport { AuthTestIds, withTestIdPrefix } from './testIds';\nimport { type AuthStyles } from './useAuthStyles';\n\nimport type { OtpFormLabels } from './labels';\nimport type { AuthTheme } from '../theme/AuthTheme';\n\nexport interface OtpRequestStepProps {\n styles: AuthStyles;\n theme: AuthTheme;\n labels: OtpFormLabels;\n testIdPrefix?: string;\n isSubmitting: boolean;\n errorText: string | null;\n /** Called with the trimmed email when the user taps \"send code\". */\n onSubmit: (email: string) => void;\n}\n\n/** Step 1 — collect the email and trigger `POST /bff/otp/request`. */\nexport function OtpRequestStep({\n styles,\n theme,\n labels,\n testIdPrefix,\n isSubmitting,\n errorText,\n onSubmit,\n}: Readonly<OtpRequestStepProps>): ReactElement {\n const [email, setEmail] = useState('');\n const buttonStyle = isSubmitting\n ? [styles.primaryButton, styles.primaryButtonDisabled]\n : styles.primaryButton;\n\n return (\n <>\n <Text style={styles.title}>{labels.requestTitle}</Text>\n <Text style={styles.subtitle}>{labels.requestDescription}</Text>\n\n <View style={styles.fieldGroup}>\n <Text style={styles.label}>{labels.emailLabel}</Text>\n <TextInput\n accessibilityHint={labels.emailPlaceholder}\n accessibilityLabel={labels.emailLabel}\n autoCapitalize=\"none\"\n autoCorrect={false}\n editable={!isSubmitting}\n keyboardType=\"email-address\"\n placeholder={labels.emailPlaceholder}\n placeholderTextColor={theme.colors.textSecondary}\n style={styles.input}\n testID={withTestIdPrefix(AuthTestIds.otpEmailInput, testIdPrefix)}\n value={email}\n onChangeText={setEmail}\n />\n </View>\n\n {errorText !== null ? (\n <Text style={styles.errorText} testID={withTestIdPrefix(AuthTestIds.otpError, testIdPrefix)}>\n {errorText}\n </Text>\n ) : null}\n\n <TouchableOpacity\n accessibilityHint={labels.requestSubmit}\n accessibilityLabel={isSubmitting ? labels.requesting : labels.requestSubmit}\n accessibilityRole=\"button\"\n disabled={isSubmitting}\n style={buttonStyle}\n testID={withTestIdPrefix(AuthTestIds.otpRequestButton, testIdPrefix)}\n onPress={(): void => onSubmit(email.trim())}\n >\n {isSubmitting ? (\n <ActivityIndicator color={theme.colors.onPrimary} size=\"small\" />\n ) : (\n <Text style={styles.primaryButtonText}>{labels.requestSubmit}</Text>\n )}\n </TouchableOpacity>\n </>\n );\n}\n\nexport interface OtpVerifyStepProps {\n styles: AuthStyles;\n theme: AuthTheme;\n labels: OtpFormLabels;\n testIdPrefix?: string;\n /** The email the code was sent to — interpolated into the description copy. */\n identifier: string;\n isSubmitting: boolean;\n errorText: string | null;\n /** Called with the trimmed code when the user taps \"verify\". */\n onSubmit: (code: string) => void;\n /** Called when the user taps \"resend code\". */\n onResend: () => void;\n /** Called when the user taps \"use a different email\". */\n onChangeEmail: () => void;\n}\n\n/** Step 2 — collect the code, verify it, and offer resend / change-email. */\nexport function OtpVerifyStep({\n styles,\n theme,\n labels,\n testIdPrefix,\n identifier,\n isSubmitting,\n errorText,\n onSubmit,\n onResend,\n onChangeEmail,\n}: Readonly<OtpVerifyStepProps>): ReactElement {\n const [code, setCode] = useState('');\n const buttonStyle = isSubmitting\n ? [styles.primaryButton, styles.primaryButtonDisabled]\n : styles.primaryButton;\n const description = labels.verifyDescription.replace('{identifier}', identifier);\n\n return (\n <>\n <Text style={styles.title}>{labels.verifyTitle}</Text>\n <Text style={styles.subtitle}>{description}</Text>\n\n <View style={styles.fieldGroup}>\n <Text style={styles.label}>{labels.codeLabel}</Text>\n <TextInput\n accessibilityHint={labels.codePlaceholder}\n accessibilityLabel={labels.codeLabel}\n autoCapitalize=\"none\"\n autoCorrect={false}\n editable={!isSubmitting}\n keyboardType=\"number-pad\"\n placeholder={labels.codePlaceholder}\n placeholderTextColor={theme.colors.textSecondary}\n style={styles.input}\n testID={withTestIdPrefix(AuthTestIds.otpCodeInput, testIdPrefix)}\n value={code}\n onChangeText={setCode}\n />\n </View>\n\n {errorText !== null ? (\n <Text style={styles.errorText} testID={withTestIdPrefix(AuthTestIds.otpError, testIdPrefix)}>\n {errorText}\n </Text>\n ) : null}\n\n <TouchableOpacity\n accessibilityHint={labels.verifySubmit}\n accessibilityLabel={isSubmitting ? labels.verifying : labels.verifySubmit}\n accessibilityRole=\"button\"\n disabled={isSubmitting}\n style={buttonStyle}\n testID={withTestIdPrefix(AuthTestIds.otpVerifyButton, testIdPrefix)}\n onPress={(): void => onSubmit(code.trim())}\n >\n {isSubmitting ? (\n <ActivityIndicator color={theme.colors.onPrimary} size=\"small\" />\n ) : (\n <Text style={styles.primaryButtonText}>{labels.verifySubmit}</Text>\n )}\n </TouchableOpacity>\n\n <TouchableOpacity\n accessibilityHint={labels.resend}\n accessibilityLabel={isSubmitting ? labels.resending : labels.resend}\n accessibilityRole=\"link\"\n disabled={isSubmitting}\n style={styles.fieldGroup}\n testID={withTestIdPrefix(AuthTestIds.otpResendButton, testIdPrefix)}\n onPress={onResend}\n >\n <Text style={styles.linkText}>{isSubmitting ? labels.resending : labels.resend}</Text>\n </TouchableOpacity>\n\n <TouchableOpacity\n accessibilityHint={labels.changeEmail}\n accessibilityLabel={labels.changeEmail}\n accessibilityRole=\"link\"\n disabled={isSubmitting}\n testID={withTestIdPrefix(AuthTestIds.otpChangeEmailButton, testIdPrefix)}\n onPress={onChangeEmail}\n >\n <Text style={styles.linkText}>{labels.changeEmail}</Text>\n </TouchableOpacity>\n </>\n );\n}\n","/**\n * The two discrete steps of the email-OTP login flow.\n *\n * `useOtpLogin` is at exactly one of these at a time, and `<OtpForm>` renders a\n * different surface per step. The flow is strictly forward: a request moves\n * `RequestCode` → `EnterCode`; a resend stays on `EnterCode`. Each member is a\n * stable key — `<OtpForm>` switches on it, never on a string literal.\n */\nexport const enum OtpLoginStep {\n /** Step 1: collect the email and ask the BFF to send a code. */\n RequestCode = 'requestCode',\n /** Step 2: the code is on its way — collect and verify it. */\n EnterCode = 'enterCode',\n}\n","/**\n * `useOtpLogin` — the headless email-OTP login hook.\n *\n * The \"escape hatch\" half of the OTP design: apps that want a fully custom\n * layout skip `<OtpForm>` and drive the two-step flow themselves with this\n * hook. `<OtpForm>` itself is built on top of it, so the ready-made and the\n * custom paths share one code path — the same lesson as `useBffAuth`.\n *\n * The flow is a small forward state machine:\n *\n * step 1 `RequestCode` → `requestCode(identifier)` → `POST /bff/otp/request`\n * step 2 `EnterCode` → `verifyCode(otp)` → `POST /bff/otp/verify`\n * → `resend()` → `POST /bff/otp/request`\n *\n * It owns nothing the BFF owns — no tokens, no refresh, no realm awareness. It\n * holds only the current step, the identifier the code was sent to, the latest\n * `requestOtp` result (so the UI can show the expiry), and the in-flight status\n * + error. A successful `verifyCode` resolves to the `BffUser` exactly like\n * `useBffAuth.login`; the consumer routes from there.\n *\n * `BffAuthClient` / `BffUser` / `BffOtpRequestResult` come from\n * `@dloizides/auth-client`.\n */\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react';\n\nimport { OtpLoginStep } from './OtpLoginStep';\n\nimport type {\n BffAuthClient,\n BffOtpRequestResult,\n BffUser,\n} from '@dloizides/auth-client';\n\nexport interface UseOtpLoginOptions {\n /** The same-origin BFF client (build it with `createBffAuthClient`). */\n client: BffAuthClient;\n}\n\nexport interface UseOtpLoginResult {\n /** Which of the two steps the flow is currently on. */\n step: OtpLoginStep;\n /** The identifier (email) the code was last requested for; `''` before step 1. */\n identifier: string;\n /**\n * The latest `POST /bff/otp/request` result, or `null` before any request.\n * Carries `expiresIn` for a countdown — never depend on `code` being present.\n */\n lastRequest: BffOtpRequestResult | null;\n /** `true` while a `requestCode` / `verifyCode` / `resend` call is in flight. */\n isSubmitting: boolean;\n /** The last error, cleared at the start of the next attempt. */\n error: Error | null;\n /**\n * Step 1 — ask the BFF to email a code to `identifier`. On success the flow\n * advances to `EnterCode`. Rejects (and stays on `RequestCode`) on failure.\n */\n requestCode: (identifier: string) => Promise<BffOtpRequestResult>;\n /**\n * Step 2 — verify the entered `otp` for the stored identifier. Resolves to the\n * signed-in `BffUser`; rejects on a bad / expired code (the flow stays on\n * `EnterCode` so the user can retry or resend).\n */\n verifyCode: (otp: string) => Promise<BffUser>;\n /**\n * Re-send a code to the stored identifier without leaving `EnterCode`. A\n * convenience wrapper over `requestOtp` for the step-2 \"resend\" affordance.\n */\n resend: () => Promise<BffOtpRequestResult>;\n /** Return to step 1 (e.g. the user mistyped their email). Clears the error. */\n reset: () => void;\n}\n\nfunction toError(value: unknown): Error {\n return value instanceof Error ? value : new Error(String(value));\n}\n\n/** Internal: the step + identifier + last-request triple the hook tracks. */\ninterface FlowState {\n step: OtpLoginStep;\n identifier: string;\n lastRequest: BffOtpRequestResult | null;\n}\n\nconst INITIAL_FLOW: FlowState = {\n step: OtpLoginStep.RequestCode,\n identifier: '',\n lastRequest: null,\n};\n\n/**\n * Headless email-OTP login. Returns the current step, the in-flight status, and\n * `requestCode` / `verifyCode` / `resend` / `reset` callbacks. No rendering —\n * the consumer (or `<OtpForm>`) wires it to UI.\n */\nexport function useOtpLogin(options: UseOtpLoginOptions): UseOtpLoginResult {\n const { client } = options;\n\n const [flow, setFlow] = useState<FlowState>(INITIAL_FLOW);\n const [isSubmitting, setIsSubmitting] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n\n // Guard against a `setState` after the consumer unmounts mid-request.\n const mountedRef = useRef(true);\n useEffect(() => {\n mountedRef.current = true;\n return (): void => {\n mountedRef.current = false;\n };\n }, []);\n\n // The identifier is also held in a ref so `verifyCode` / `resend` read the\n // latest value without being re-created every time `flow` changes.\n const identifierRef = useRef('');\n\n const beginAttempt = useCallback((): void => {\n if (mountedRef.current) {\n setIsSubmitting(true);\n setError(null);\n }\n }, []);\n\n const endAttempt = useCallback((): void => {\n if (mountedRef.current) {\n setIsSubmitting(false);\n }\n }, []);\n\n /** Shared `requestOtp` call used by both `requestCode` and `resend`. */\n const sendCode = useCallback(\n async (identifier: string): Promise<BffOtpRequestResult> => {\n beginAttempt();\n try {\n const result = await client.requestOtp({ identifier });\n identifierRef.current = identifier;\n if (mountedRef.current) {\n setFlow({ step: OtpLoginStep.EnterCode, identifier, lastRequest: result });\n }\n return result;\n } catch (caught) {\n const err = toError(caught);\n if (mountedRef.current) {\n setError(err);\n }\n throw err;\n } finally {\n endAttempt();\n }\n },\n [client, beginAttempt, endAttempt],\n );\n\n const requestCode = useCallback(\n (identifier: string): Promise<BffOtpRequestResult> => sendCode(identifier),\n [sendCode],\n );\n\n const resend = useCallback(\n (): Promise<BffOtpRequestResult> => sendCode(identifierRef.current),\n [sendCode],\n );\n\n const verifyCode = useCallback(\n async (otp: string): Promise<BffUser> => {\n beginAttempt();\n try {\n return await client.verifyOtp({ username: identifierRef.current, otp });\n } catch (caught) {\n const err = toError(caught);\n if (mountedRef.current) {\n setError(err);\n }\n throw err;\n } finally {\n endAttempt();\n }\n },\n [client, beginAttempt, endAttempt],\n );\n\n const reset = useCallback((): void => {\n identifierRef.current = '';\n if (mountedRef.current) {\n setFlow(INITIAL_FLOW);\n setError(null);\n }\n }, []);\n\n return useMemo(\n () => ({\n step: flow.step,\n identifier: flow.identifier,\n lastRequest: flow.lastRequest,\n isSubmitting,\n error,\n requestCode,\n verifyCode,\n resend,\n reset,\n }),\n [\n flow.step,\n flow.identifier,\n flow.lastRequest,\n isSubmitting,\n error,\n requestCode,\n verifyCode,\n resend,\n reset,\n ],\n );\n}\n","/**\n * `<OtpForm>` — the ready-made, themeable two-step email-OTP login form.\n *\n * The \"themeable component\" half of the OTP design: drop it in, pass a\n * `client`, a `theme` (or wrap in `<AuthThemeProvider>`) and a localised\n * `labels` bag, and you have a branded email-OTP surface. It is built on the\n * headless `useOtpLogin` hook, so the ready-made and custom-layout paths share\n * one code path — the same pattern as `<LoginForm>`.\n *\n * Two steps, switched on `OtpLoginStep`:\n * 1. `RequestCode` — `<OtpRequestStep>`: an email field + a \"send code\" button.\n * 2. `EnterCode` — `<OtpVerifyStep>`: a code field + a \"verify\" button, plus\n * \"resend code\" and \"use a different email\" affordances.\n *\n * The package ships no router and no i18n. `onSuccess` hands the signed-in\n * `BffUser` back to the app; all copy comes from `labels`.\n */\nimport { useCallback, useMemo, useState, type ReactElement } from 'react';\n\nimport { View } from 'react-native';\n\nimport { DEFAULT_OTP_LABELS, type OtpFormLabels } from './labels';\nimport { OtpRequestStep, OtpVerifyStep } from './OtpFormSteps';\nimport { AuthTestIds, withTestIdPrefix } from './testIds';\nimport { useAuthStyles } from './useAuthStyles';\nimport { OtpLoginStep } from '../hooks/OtpLoginStep';\nimport { useOtpLogin, type UseOtpLoginResult } from '../hooks/useOtpLogin';\nimport { useAuthTheme } from '../theme/AuthThemeProvider';\n\nimport type { AuthTheme } from '../theme/AuthTheme';\nimport type { BffAuthClient, BffUser } from '@dloizides/auth-client';\n\n// A deliberately loose, linear-time email shape check — identical to the one\n// `<ForgotPasswordForm>` uses. Strict validation is the backend's job.\nconst EMAIL_REGEX = /^[^@\\s]+@[^.\\s]+\\.[^\\s]+$/;\n\nexport interface OtpFormProps {\n /** The same-origin BFF client (build it with `createBffAuthClient`). */\n client: BffAuthClient;\n /** Explicit theme; overrides any `<AuthThemeProvider>`. Falls back to the default theme. */\n theme?: AuthTheme;\n /** Localised copy. Partial — unspecified keys fall back to English defaults. */\n labels?: Partial<OtpFormLabels>;\n /** Called with the signed-in user after a successful code verification. */\n onSuccess: (user: BffUser) => void;\n /** Prefix applied to every `testID` so multiple forms can share a screen. */\n testIdPrefix?: string;\n /**\n * When `true`, render WITHOUT the built-in `screen` + `card` chrome so the\n * form can be composed as a child of `<AuthScreen>`. Defaults to `false` —\n * standalone drop-in behaviour is byte-identical to before.\n */\n chromeless?: boolean;\n}\n\n/** `true` when `value` looks like an email address. */\nfunction isValidEmail(value: string): boolean {\n return EMAIL_REGEX.test(value);\n}\n\n/** Resolve the in-flight transport error onto a localised, non-leaking message. */\nfunction transportErrorFor(\n step: OtpLoginStep,\n error: Error | null,\n labels: OtpFormLabels,\n): string | null {\n if (error === null) {\n return null;\n }\n // Never echo the raw error — it can leak whether the identifier exists. Show\n // a generic, step-appropriate message instead.\n return step === OtpLoginStep.RequestCode ? labels.invalidEmail : labels.invalidCode;\n}\n\n/** Drive step 1: validate the email locally, then call `requestCode`. */\nfunction useRequestHandler(\n otp: UseOtpLoginResult,\n labels: OtpFormLabels,\n setLocalError: (value: string | null) => void,\n): (email: string) => void {\n return useCallback(\n (email: string): void => {\n setLocalError(null);\n if (!isValidEmail(email)) {\n setLocalError(labels.invalidEmail);\n return;\n }\n void otp.requestCode(email).catch(() => undefined);\n },\n [otp, labels.invalidEmail, setLocalError],\n );\n}\n\n/** Drive step 2: validate the code is present, then call `verifyCode`. */\nfunction useVerifyHandler(\n otp: UseOtpLoginResult,\n labels: OtpFormLabels,\n setLocalError: (value: string | null) => void,\n onSuccess: (user: BffUser) => void,\n): (code: string) => void {\n return useCallback(\n (code: string): void => {\n setLocalError(null);\n if (code.length === 0) {\n setLocalError(labels.missingCode);\n return;\n }\n otp\n .verifyCode(code)\n .then((user) => {\n onSuccess(user);\n })\n .catch(() => undefined);\n },\n [otp, labels.missingCode, setLocalError, onSuccess],\n );\n}\n\n/** Themeable two-step email-OTP login form built on `useOtpLogin`. */\nexport function OtpForm({\n client,\n theme: themeProp,\n labels: labelsProp,\n onSuccess,\n testIdPrefix,\n chromeless = false,\n}: Readonly<OtpFormProps>): ReactElement {\n const theme = useAuthTheme(themeProp);\n const styles = useAuthStyles(theme);\n const labels = useMemo<OtpFormLabels>(\n () => ({ ...DEFAULT_OTP_LABELS, ...labelsProp }),\n [labelsProp],\n );\n\n const otp = useOtpLogin({ client });\n // A local validation error (bad email / empty code) lives separately from the\n // hook's transport error so a client-side failure does not need a round-trip.\n const [localError, setLocalError] = useState<string | null>(null);\n\n const handleRequest = useRequestHandler(otp, labels, setLocalError);\n const handleVerify = useVerifyHandler(otp, labels, setLocalError, onSuccess);\n const handleResend = useCallback((): void => {\n setLocalError(null);\n void otp.resend().catch(() => undefined);\n }, [otp]);\n const handleChangeEmail = useCallback((): void => {\n setLocalError(null);\n otp.reset();\n }, [otp]);\n\n const errorText = localError ?? transportErrorFor(otp.step, otp.error, labels);\n\n const content =\n otp.step === OtpLoginStep.RequestCode ? (\n <OtpRequestStep\n errorText={errorText}\n isSubmitting={otp.isSubmitting}\n labels={labels}\n styles={styles}\n testIdPrefix={testIdPrefix}\n theme={theme}\n onSubmit={handleRequest}\n />\n ) : (\n <OtpVerifyStep\n errorText={errorText}\n identifier={otp.identifier}\n isSubmitting={otp.isSubmitting}\n labels={labels}\n styles={styles}\n testIdPrefix={testIdPrefix}\n theme={theme}\n onChangeEmail={handleChangeEmail}\n onResend={handleResend}\n onSubmit={handleVerify}\n />\n );\n\n const card = (\n <View\n style={chromeless ? undefined : styles.card}\n testID={withTestIdPrefix(AuthTestIds.otpForm, testIdPrefix)}\n >\n {content}\n </View>\n );\n\n return chromeless ? card : <View style={styles.screen}>{card}</View>;\n}\n","/**\n * `usePinLogin` — the headless event-scoped PIN login hook.\n *\n * The \"escape hatch\" half of the PIN design: apps that want a fully custom\n * layout skip `<PinForm>` and drive the flow themselves with this hook.\n * `<PinForm>` itself is built on top of it, so the ready-made and the custom\n * paths share one code path — the same lesson as `useOtpLogin` / `useBffAuth`.\n *\n * Unlike `useOtpLogin` the PIN flow is a **single step** — there is no\n * request/verify split, the staff member just enters the PIN:\n *\n * `submit(pin)` → `POST /bff/pin/login` → `BffUser`\n *\n * The `(event, pin)` pair alone identifies the staff member (unified-auth plan\n * §4.4) — the `eventExternalId` is supplied to the hook by the page/route, the\n * PIN by the user. It owns nothing the BFF owns — no tokens, no refresh, no\n * realm awareness. It holds only the in-flight status + error. A successful\n * `submit` resolves to the `BffUser` exactly like `useBffAuth.login`; the\n * consumer routes from there.\n *\n * `BffAuthClient` / `BffUser` come from `@dloizides/auth-client`.\n */\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react';\n\nimport type { BffAuthClient, BffUser } from '@dloizides/auth-client';\n\nexport interface UsePinLoginOptions {\n /** The same-origin BFF client (build it with `createBffAuthClient`). */\n client: BffAuthClient;\n /**\n * External id of the event the PIN is scoped to. Supplied by the page/route\n * — the event context is never typed by the user.\n */\n eventExternalId: string;\n}\n\nexport interface UsePinLoginResult {\n /** `true` while a `submit` call is in flight. */\n isSubmitting: boolean;\n /** The last error, cleared at the start of the next attempt. */\n error: Error | null;\n /**\n * Exchange the entered `pin` (for the hook's `eventExternalId`) for a\n * session. Resolves to the signed-in `BffUser`; rejects on a bad / expired /\n * locked-out PIN (the consumer can let the user retry).\n */\n submit: (pin: string) => Promise<BffUser>;\n /** Clear the current error so the form can be retried cleanly. */\n reset: () => void;\n}\n\nfunction toError(value: unknown): Error {\n return value instanceof Error ? value : new Error(String(value));\n}\n\n/**\n * Headless event-scoped PIN login. Returns the in-flight status, the last\n * error, and `submit` / `reset` callbacks. No rendering — the consumer (or\n * `<PinForm>`) wires it to UI.\n */\nexport function usePinLogin(options: UsePinLoginOptions): UsePinLoginResult {\n const { client, eventExternalId } = options;\n\n const [isSubmitting, setIsSubmitting] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n\n // Guard against a `setState` after the consumer unmounts mid-request.\n const mountedRef = useRef(true);\n useEffect(() => {\n mountedRef.current = true;\n return (): void => {\n mountedRef.current = false;\n };\n }, []);\n\n // The event id is also held in a ref so `submit` reads the latest value\n // without being re-created every time the prop changes.\n const eventIdRef = useRef(eventExternalId);\n useEffect(() => {\n eventIdRef.current = eventExternalId;\n }, [eventExternalId]);\n\n const submit = useCallback(\n async (pin: string): Promise<BffUser> => {\n if (mountedRef.current) {\n setIsSubmitting(true);\n setError(null);\n }\n try {\n return await client.pinLogin({ pin, eventExternalId: eventIdRef.current });\n } catch (caught) {\n const err = toError(caught);\n if (mountedRef.current) {\n setError(err);\n }\n throw err;\n } finally {\n if (mountedRef.current) {\n setIsSubmitting(false);\n }\n }\n },\n [client],\n );\n\n const reset = useCallback((): void => {\n if (mountedRef.current) {\n setError(null);\n }\n }, []);\n\n return useMemo(\n () => ({ isSubmitting, error, submit, reset }),\n [isSubmitting, error, submit, reset],\n );\n}\n","/**\n * `<PinForm>` — the ready-made, themeable single-step event-PIN login form.\n *\n * The \"themeable component\" half of the PIN design: drop it in, pass a\n * `client`, the `eventExternalId` of the event the staff member is signing in\n * to, a `theme` (or wrap in `<AuthThemeProvider>`) and a localised `labels`\n * bag, and you have a branded event-PIN surface. It is built on the headless\n * `usePinLogin` hook, so the ready-made and custom-layout paths share one code\n * path — the same pattern as `<OtpForm>` / `<LoginForm>`.\n *\n * Unlike `<OtpForm>` the PIN flow is a single step: a PIN field + a \"sign in\"\n * button. The `eventExternalId` is a prop, never typed by the user — the event\n * context comes from the route/page the form is rendered on.\n *\n * The package ships no router and no i18n. `onSuccess` hands the signed-in\n * `BffUser` back to the app; all copy comes from `labels`.\n */\nimport { useCallback, useMemo, useState, type ReactElement } from 'react';\n\nimport { ActivityIndicator, Text, TextInput, TouchableOpacity, View } from 'react-native';\n\nimport { DEFAULT_PIN_LABELS, type PinFormLabels } from './labels';\nimport { AuthTestIds, withTestIdPrefix } from './testIds';\nimport { useAuthStyles } from './useAuthStyles';\nimport { usePinLogin, type UsePinLoginResult } from '../hooks/usePinLogin';\nimport { useAuthTheme } from '../theme/AuthThemeProvider';\n\nimport type { AuthTheme } from '../theme/AuthTheme';\nimport type { BffAuthClient, BffUser } from '@dloizides/auth-client';\n\nexport interface PinFormProps {\n /** The same-origin BFF client (build it with `createBffAuthClient`). */\n client: BffAuthClient;\n /**\n * External id of the event the PIN is scoped to. Supplied by the route/page\n * — the event context is never typed by the user.\n */\n eventExternalId: string;\n /** Explicit theme; overrides any `<AuthThemeProvider>`. Falls back to the default theme. */\n theme?: AuthTheme;\n /** Localised copy. Partial — unspecified keys fall back to English defaults. */\n labels?: Partial<PinFormLabels>;\n /** Called with the signed-in user after a successful PIN exchange. */\n onSuccess: (user: BffUser) => void;\n /** Prefix applied to every `testID` so multiple forms can share a screen. */\n testIdPrefix?: string;\n /**\n * When `true`, render WITHOUT the built-in `screen` + `card` chrome so the\n * form can be composed as a child of `<AuthScreen>`. Defaults to `false` —\n * standalone drop-in behaviour is byte-identical to before.\n */\n chromeless?: boolean;\n}\n\n/** Resolve the in-flight transport error onto a localised, non-leaking message. */\nfunction transportErrorFor(error: Error | null, labels: PinFormLabels): string | null {\n if (error === null) {\n return null;\n }\n // Never echo the raw error — show a generic message instead.\n return labels.invalidPin;\n}\n\n/** Drive the single submit step: validate the PIN is present, then call `submit`. */\nfunction useSubmitHandler(\n pin: UsePinLoginResult,\n labels: PinFormLabels,\n setLocalError: (value: string | null) => void,\n onSuccess: (user: BffUser) => void,\n): (value: string) => void {\n return useCallback(\n (value: string): void => {\n setLocalError(null);\n if (value.length === 0) {\n setLocalError(labels.missingPin);\n return;\n }\n pin\n .submit(value)\n .then((user) => {\n onSuccess(user);\n })\n .catch(() => undefined);\n },\n [pin, labels.missingPin, setLocalError, onSuccess],\n );\n}\n\n/** Themeable single-step event-PIN login form built on `usePinLogin`. */\nexport function PinForm({\n client,\n eventExternalId,\n theme: themeProp,\n labels: labelsProp,\n onSuccess,\n testIdPrefix,\n chromeless = false,\n}: Readonly<PinFormProps>): ReactElement {\n const theme = useAuthTheme(themeProp);\n const styles = useAuthStyles(theme);\n const labels = useMemo<PinFormLabels>(\n () => ({ ...DEFAULT_PIN_LABELS, ...labelsProp }),\n [labelsProp],\n );\n\n const pin = usePinLogin({ client, eventExternalId });\n // A local validation error (empty PIN) lives separately from the hook's\n // transport error so a client-side failure does not need a round-trip.\n const [localError, setLocalError] = useState<string | null>(null);\n const [pinValue, setPinValue] = useState('');\n\n const handleSubmit = useSubmitHandler(pin, labels, setLocalError, onSuccess);\n\n const errorText = localError ?? transportErrorFor(pin.error, labels);\n const buttonStyle = pin.isSubmitting\n ? [styles.primaryButton, styles.primaryButtonDisabled]\n : styles.primaryButton;\n\n const content = (\n <>\n <Text style={styles.title}>{labels.title}</Text>\n <Text style={styles.subtitle}>{labels.description}</Text>\n\n <View style={styles.fieldGroup}>\n <Text style={styles.label}>{labels.pinLabel}</Text>\n <TextInput\n accessibilityHint={labels.pinPlaceholder}\n accessibilityLabel={labels.pinLabel}\n autoCapitalize=\"none\"\n autoCorrect={false}\n editable={!pin.isSubmitting}\n keyboardType=\"number-pad\"\n placeholder={labels.pinPlaceholder}\n placeholderTextColor={theme.colors.textSecondary}\n secureTextEntry\n style={styles.input}\n testID={withTestIdPrefix(AuthTestIds.pinInput, testIdPrefix)}\n value={pinValue}\n onChangeText={setPinValue}\n />\n </View>\n\n {errorText !== null ? (\n <Text\n style={styles.errorText}\n testID={withTestIdPrefix(AuthTestIds.pinError, testIdPrefix)}\n >\n {errorText}\n </Text>\n ) : null}\n\n <TouchableOpacity\n accessibilityHint={labels.submit}\n accessibilityLabel={pin.isSubmitting ? labels.submitting : labels.submit}\n accessibilityRole=\"button\"\n disabled={pin.isSubmitting}\n style={buttonStyle}\n testID={withTestIdPrefix(AuthTestIds.pinSubmitButton, testIdPrefix)}\n onPress={(): void => handleSubmit(pinValue.trim())}\n >\n {pin.isSubmitting ? (\n <ActivityIndicator color={theme.colors.onPrimary} size=\"small\" />\n ) : (\n <Text style={styles.primaryButtonText}>{labels.submit}</Text>\n )}\n </TouchableOpacity>\n </>\n );\n\n const card = (\n <View\n style={chromeless ? undefined : styles.card}\n testID={withTestIdPrefix(AuthTestIds.pinForm, testIdPrefix)}\n >\n {content}\n </View>\n );\n\n return chromeless ? card : <View style={styles.screen}>{card}</View>;\n}\n","/**\n * A masked numeric PIN input for the device-PIN unlock + enrol surfaces.\n *\n * A single hidden secure `TextInput` captures the digits (numeric keyboard,\n * length-capped, digits-only); a row of dot cells visualises how many have been\n * entered. Tapping anywhere on the row focuses the field. Purely presentational\n * — all submit / error logic lives in the unlock / enrol hooks. Styled from the\n * `AuthTheme` token bag (no hardcoded brand colours).\n */\nimport { useMemo, useRef, type ReactElement } from 'react';\n\nimport {\n Pressable,\n StyleSheet,\n TextInput,\n View,\n type TextInput as RNTextInput,\n type ViewStyle,\n} from 'react-native';\n\nimport { withTestIdPrefix } from './testIds';\nimport { useAuthTheme } from '../theme/AuthThemeProvider';\n\nimport type { AuthTheme } from '../theme/AuthTheme';\n\nexport interface DevicePinInputProps {\n /** The current PIN value (digits only). */\n value: string;\n /** Number of dot cells to render — the enrolled / chosen PIN length. */\n length: number;\n /** Disable input while a request is in flight. */\n disabled: boolean;\n /** Base testID for the underlying field (a11y + E2E targeting). */\n testID: string;\n /** Optional prefix applied to the testID. */\n testIdPrefix?: string;\n /** Accessibility label for the field. */\n accessibilityLabel: string;\n /** Accessibility hint for the field. */\n accessibilityHint: string;\n /** Accessibility label for a filled dot. */\n filledHint: string;\n /** Accessibility label for an empty dot. */\n emptyHint: string;\n /** Explicit theme; overrides any `<AuthThemeProvider>`. */\n theme?: AuthTheme;\n /** Emit the next digits-only value (already length-capped). */\n onChange: (next: string) => void;\n}\n\nconst DOT_SIZE = 18;\nconst DOT_BORDER_WIDTH = 2;\nconst DOT_RADIUS = 9;\nconst ROW_GAP = 12;\nconst ROW_MIN_HEIGHT = 44;\nconst ROW_VERTICAL_MARGIN = 16;\nconst HIDDEN_SIZE = 1;\n\n/** Strip everything but digits and cap to `length`. */\nfunction sanitise(raw: string, length: number): string {\n return raw.replace(/\\D/g, '').slice(0, length);\n}\n\n/** Build the dot fill/border styles from the theme. */\nfunction useDotStyles(theme: AuthTheme): { filled: ViewStyle; empty: ViewStyle } {\n return useMemo(\n () => ({\n filled: { backgroundColor: theme.colors.primary, borderColor: theme.colors.primary },\n empty: { backgroundColor: theme.colors.background, borderColor: theme.colors.border },\n }),\n [theme],\n );\n}\n\n/** Themeable masked PIN pad — dots reflect entered digits; a hidden field captures them. */\nexport function DevicePinInput({\n value,\n length,\n disabled,\n testID,\n testIdPrefix,\n accessibilityLabel,\n accessibilityHint,\n filledHint,\n emptyHint,\n theme: themeProp,\n onChange,\n}: Readonly<DevicePinInputProps>): ReactElement {\n const theme = useAuthTheme(themeProp);\n const inputRef = useRef<RNTextInput | null>(null);\n const dotStyles = useDotStyles(theme);\n const cells = Array.from({ length }, (_unused, index) => index);\n const baseId = withTestIdPrefix(testID, testIdPrefix);\n\n return (\n <Pressable\n accessibilityHint={accessibilityHint}\n accessibilityLabel={accessibilityLabel}\n accessibilityRole=\"button\"\n disabled={disabled}\n style={styles.row}\n testID={`${baseId}-row`}\n onPress={(): void => inputRef.current?.focus()}\n >\n {cells.map((index) => {\n const filled = index < value.length;\n return (\n <View\n key={index}\n accessibilityLabel={filled ? filledHint : emptyHint}\n style={[styles.dot, filled ? dotStyles.filled : dotStyles.empty]}\n testID={`${baseId}-dot-${String(index)}`}\n />\n );\n })}\n <TextInput\n ref={inputRef}\n accessibilityHint={accessibilityHint}\n accessibilityLabel={accessibilityLabel}\n autoFocus\n caretHidden\n editable={!disabled}\n keyboardType=\"number-pad\"\n maxLength={length}\n secureTextEntry\n style={styles.hiddenInput}\n testID={baseId}\n value={value}\n onChangeText={(raw: string): void => onChange(sanitise(raw, length))}\n />\n </Pressable>\n );\n}\n\nconst styles = StyleSheet.create({\n dot: {\n borderRadius: DOT_RADIUS,\n borderWidth: DOT_BORDER_WIDTH,\n height: DOT_SIZE,\n width: DOT_SIZE,\n },\n hiddenInput: {\n height: HIDDEN_SIZE,\n opacity: 0,\n position: 'absolute',\n width: HIDDEN_SIZE,\n },\n row: {\n alignItems: 'center',\n flexDirection: 'row',\n gap: ROW_GAP,\n justifyContent: 'center',\n marginVertical: ROW_VERTICAL_MARGIN,\n minHeight: ROW_MIN_HEIGHT,\n },\n});\n","/**\n * Minimal label placeholder interpolation.\n *\n * The device-PIN / passkey label bags carry `{name}` and `{count}` placeholders\n * (e.g. `'Enter your {count}-digit PIN.'`). The package ships no i18n framework,\n * so this tiny helper substitutes named placeholders without pulling one in.\n * Unknown placeholders are left untouched; absent keys substitute nothing.\n */\n\n/** Replace every `{key}` in `template` with the matching value (String-coerced). */\nexport function interpolate(\n template: string,\n values: Readonly<Record<string, string | number>>,\n): string {\n return template.replace(/\\{(\\w+)\\}/g, (match, key: string) => {\n const value = values[key];\n return value === undefined ? match : String(value);\n });\n}\n","/**\n * Shared device-PIN constants for the unlock + enrol surfaces.\n *\n * The allowed PIN lengths (4 / 6 / 8) mirror the BFF's accepted `digits` values\n * (`POST /bff/pin/enroll`). Centralised here so neither the enrol form nor the\n * unlock screen carries magic numbers, and so the default length is defined once.\n */\n\n/** The PIN lengths the BFF accepts on enrol (`digits` ∈ {4, 6, 8}). */\nexport const DEVICE_PIN_ALLOWED_DIGITS: readonly number[] = [4, 6, 8];\n\n/** Default PIN length offered when the BFF reports no stored `pinDigits`. */\nexport const DEVICE_PIN_DEFAULT_DIGITS = 4;\n\n/** Guard: is `value` one of the BFF-accepted PIN lengths? */\nexport function isAllowedPinDigits(value: number): boolean {\n return DEVICE_PIN_ALLOWED_DIGITS.includes(value);\n}\n","/**\n * The PIN-length (4/6/8) picker row for `<DevicePinEnrollForm>`.\n *\n * Presentational: renders one pill per allowed length and reports the chosen\n * one. Styled from the `AuthTheme` token bag. Extracted from the enrol form to\n * keep that component focused.\n */\nimport { useMemo, type ReactElement } from 'react';\n\nimport {\n Pressable,\n StyleSheet,\n Text,\n View,\n type TextStyle,\n type ViewStyle,\n} from 'react-native';\n\nimport { interpolate } from './interpolate';\nimport { AuthTestIds, withTestIdPrefix } from './testIds';\nimport { DEVICE_PIN_ALLOWED_DIGITS } from '../devicePin/devicePinConstants';\nimport { useAuthTheme } from '../theme/AuthThemeProvider';\n\nimport type { AuthTheme } from '../theme/AuthTheme';\n\nexport interface DevicePinLengthPickerProps {\n /** The currently-selected PIN length. */\n selected: number;\n /** Disable while a request is in flight. */\n disabled: boolean;\n /** Accessibility hint template for a pill; `{count}` is substituted. */\n optionHint: string;\n /** Optional prefix applied to each pill's testID. */\n testIdPrefix?: string;\n /** Explicit theme; overrides any `<AuthThemeProvider>`. */\n theme?: AuthTheme;\n /** Report the newly-chosen length. */\n onSelect: (digits: number) => void;\n}\n\nconst PILL_VERTICAL_PADDING = 10;\nconst PILL_FONT_SIZE = 15;\n\n/** Build the theme-derived pill styles. */\nfunction usePickerStyles(theme: AuthTheme): {\n active: ViewStyle;\n text: TextStyle;\n textActive: TextStyle;\n pill: ViewStyle;\n} {\n return useMemo(\n () => ({\n pill: { borderColor: theme.colors.border },\n active: { backgroundColor: theme.colors.primary, borderColor: theme.colors.primary },\n text: { color: theme.colors.text },\n textActive: { color: theme.colors.onPrimary },\n }),\n [theme],\n );\n}\n\n/** Themeable 4/6/8 length chooser. */\nexport function DevicePinLengthPicker({\n selected,\n disabled,\n optionHint,\n testIdPrefix,\n theme: themeProp,\n onSelect,\n}: Readonly<DevicePinLengthPickerProps>): ReactElement {\n const theme = useAuthTheme(themeProp);\n const dynamic = usePickerStyles(theme);\n const baseId = withTestIdPrefix(AuthTestIds.devicePinEnrollLength, testIdPrefix);\n\n return (\n <View accessibilityRole=\"radiogroup\" role=\"radiogroup\" style={styles.row}>\n {DEVICE_PIN_ALLOWED_DIGITS.map((option) => {\n const active = option === selected;\n return (\n <Pressable\n key={option}\n // Explicit `aria-checked`: react-native-web 0.21.2 ignores\n // `accessibilityState` entirely, so without this the ONLY thing\n // distinguishing the chosen PIN length is the pill's fill colour —\n // WCAG 1.4.1 (colour alone). `accessibilityState` is kept for native.\n aria-checked={active}\n accessibilityHint={interpolate(optionHint, { count: option })}\n accessibilityLabel={String(option)}\n // `radio`, not `button`: these are a mutually-exclusive set, and\n // `aria-checked` is only meaningful on a checkable role.\n accessibilityRole=\"radio\"\n accessibilityState={{ selected: active }}\n disabled={disabled}\n style={[styles.pill, dynamic.pill, active ? dynamic.active : null]}\n testID={`${baseId}-${String(option)}`}\n onPress={(): void => onSelect(option)}\n >\n <Text style={[styles.text, dynamic.text, active ? dynamic.textActive : null]}>\n {String(option)}\n </Text>\n </Pressable>\n );\n })}\n </View>\n );\n}\n\nconst styles = StyleSheet.create({\n pill: {\n alignItems: 'center',\n borderRadius: 8,\n borderWidth: 1,\n flex: 1,\n paddingVertical: PILL_VERTICAL_PADDING,\n },\n row: {\n flexDirection: 'row',\n gap: 8,\n marginBottom: 8,\n },\n text: {\n fontSize: PILL_FONT_SIZE,\n fontWeight: '700',\n },\n});\n","/**\n * The localizable error states the device-PIN UNLOCK surface can show.\n *\n * Kept deliberately coarse so the UI never reveals whether a failed unlock was a\n * wrong PIN or an unknown / revoked device (both map to `Invalid`). `LockedOut`\n * and `RateLimited` carry no count — the human-readable \"try again later\" copy\n * is built from the `retryAfterSeconds` hint at the call site, not encoded here.\n */\nexport const enum DevicePinErrorKey {\n /** The PIN entered was too short for the enrolled length. */\n Incomplete = 'incomplete',\n /** Wrong PIN, or unknown / revoked device. Generic on purpose. */\n Invalid = 'invalid',\n /** Locked out after too many wrong attempts. */\n LockedOut = 'locked_out',\n /** Rate-limited by the BFF (too many requests). */\n RateLimited = 'rate_limited',\n /** Anything else (network / unexpected). */\n Generic = 'generic',\n}\n","/**\n * The react-query-FREE state machine behind {@link DevicePinUnlockScreen}.\n *\n * Lives on the login route group, which has NO QueryClient provider — so this\n * hook uses plain `useState` + `.then()/.catch()/.finally()` over the supplied\n * client's `unlockWithDevicePin`, never `useMutation`/`useQuery`. Pulling the\n * logic into a hook keeps the screen presentational and lets the submit / error\n * / lockout transitions be unit-tested without rendering.\n *\n * Submit flow:\n * - client-side preflight: a PIN shorter than the enrolled `digits` short-circuits\n * to {@link DevicePinErrorKey.Incomplete} with no network call;\n * - `success` → clear error, call `onSignedIn(user)`;\n * - `invalid` → {@link DevicePinErrorKey.Invalid} (generic — never reveal\n * wrong-pin vs unknown-device);\n * - `locked` → {@link DevicePinErrorKey.LockedOut} + the optional retry seconds;\n * - `rateLimited` → {@link DevicePinErrorKey.RateLimited} + the optional seconds;\n * - `error` / a thrown rejection → {@link DevicePinErrorKey.Generic}.\n */\nimport { useCallback, useState } from 'react';\n\nimport { DevicePinErrorKey } from './DevicePinErrorKey';\n\nimport type { DevicePinUnlockCapableClient } from './types';\n\n/** The signed-in user shape the success path hands back (claim bag). */\nexport type DevicePinUnlockedUser = { [claim: string]: unknown };\n\nexport interface UseDevicePinUnlockArgs {\n /** The client exposing `unlockWithDevicePin`. */\n client: DevicePinUnlockCapableClient;\n /** Enrolled PIN length (4/6/8) — a shorter entry is rejected before any call. */\n digits: number;\n /** Called with the fresh user after a successful unlock. */\n onSignedIn: (user: DevicePinUnlockedUser) => void;\n}\n\nexport interface UseDevicePinUnlockResult {\n /** The PIN currently entered. */\n pin: string;\n /** `true` while an unlock call is in flight. */\n submitting: boolean;\n /** The current error key, or `null` when there is none. */\n errorKey: DevicePinErrorKey | null;\n /** Seconds until retry, set with a `LockedOut`/`RateLimited` error; else `null`. */\n retryAfterSeconds: number | null;\n /** Replace the entered PIN. Clears a stale error. */\n setPin: (next: string) => void;\n /** Run the unlock attempt for the current PIN. */\n submit: () => void;\n}\n\nexport function useDevicePinUnlock({\n client,\n digits,\n onSignedIn,\n}: UseDevicePinUnlockArgs): UseDevicePinUnlockResult {\n const [pin, setPinState] = useState<string>('');\n const [submitting, setSubmitting] = useState<boolean>(false);\n const [errorKey, setErrorKey] = useState<DevicePinErrorKey | null>(null);\n const [retryAfterSeconds, setRetryAfterSeconds] = useState<number | null>(null);\n\n const setPin = useCallback((next: string): void => {\n setPinState(next);\n setErrorKey(null);\n setRetryAfterSeconds(null);\n }, []);\n\n const submit = useCallback((): void => {\n setErrorKey(null);\n setRetryAfterSeconds(null);\n if (pin.length < digits) {\n setErrorKey(DevicePinErrorKey.Incomplete);\n return;\n }\n setSubmitting(true);\n client\n .unlockWithDevicePin({ pin })\n .then((result) => {\n if (result.status === 'success') {\n onSignedIn(result.user);\n return;\n }\n if (result.status === 'invalid') {\n setErrorKey(DevicePinErrorKey.Invalid);\n return;\n }\n if (result.status === 'locked') {\n setRetryAfterSeconds(result.retryAfterSeconds);\n setErrorKey(DevicePinErrorKey.LockedOut);\n return;\n }\n if (result.status === 'rateLimited') {\n setRetryAfterSeconds(result.retryAfterSeconds);\n setErrorKey(DevicePinErrorKey.RateLimited);\n return;\n }\n setErrorKey(DevicePinErrorKey.Generic);\n })\n .catch(() => {\n setErrorKey(DevicePinErrorKey.Generic);\n })\n .finally(() => {\n setSubmitting(false);\n });\n }, [client, pin, digits, onSignedIn]);\n\n return { pin, submitting, errorKey, retryAfterSeconds, setPin, submit };\n}\n","/**\n * The device-PIN UNLOCK gate — shown on the login route for a returning,\n * logged-OUT user whose device is remembered (`hasPin && rememberedUsername`).\n *\n * Renders a masked PIN pad of the enrolled length; on submit it calls\n * `client.unlockWithDevicePin` (via {@link useDevicePinUnlock}) and, on success,\n * routes through the SAME `onSignedIn` path as the password tab. A\n * \"Sign in with password instead\" escape calls `onUsePassword` (the caller swaps\n * this screen out). All five result statuses are handled, including the lockout /\n * rate-limit retry countdown surfaced from `retryAfterSeconds`.\n *\n * react-query-FREE: all logic lives in `useDevicePinUnlock`, which uses plain\n * `useState` + `.then()` over the client — never `useMutation`. Presentational\n * only here. Distinct from the event-staff PIN (`PinForm`); this is `devicePin`.\n */\nimport { useMemo, type ReactElement } from 'react';\n\nimport { ActivityIndicator, Text, TouchableOpacity, View } from 'react-native';\n\nimport { DevicePinInput } from './DevicePinInput';\nimport { interpolate } from './interpolate';\nimport { DEFAULT_DEVICE_PIN_UNLOCK_LABELS, type DevicePinUnlockLabels } from './labels';\nimport { AuthTestIds, withTestIdPrefix } from './testIds';\nimport { useAuthStyles } from './useAuthStyles';\nimport { DevicePinErrorKey } from '../devicePin/DevicePinErrorKey';\nimport {\n useDevicePinUnlock,\n type DevicePinUnlockedUser,\n} from '../devicePin/useDevicePinUnlock';\nimport { useAuthTheme } from '../theme/AuthThemeProvider';\n\nimport type { DevicePinUnlockCapableClient } from '../devicePin/types';\nimport type { AuthTheme } from '../theme/AuthTheme';\n\nexport interface DevicePinUnlockScreenProps {\n /** The client exposing `unlockWithDevicePin`. */\n client: DevicePinUnlockCapableClient;\n /** Enrolled PIN length (4/6/8). */\n digits: number;\n /** Remembered username, shown in the greeting (may be empty). */\n rememberedUsername: string;\n /** Explicit theme; overrides any `<AuthThemeProvider>`. */\n theme?: AuthTheme;\n /** Localised copy. Partial — unspecified keys fall back to English defaults. */\n labels?: Partial<DevicePinUnlockLabels>;\n /** Prefix applied to every `testID`. */\n testIdPrefix?: string;\n /** Called with the fresh user after a successful unlock. */\n onSignedIn: (user: DevicePinUnlockedUser) => void;\n /** Escape hatch → render the normal password/OTP/event-PIN tabs. */\n onUsePassword: () => void;\n}\n\n/** Resolve the localized error copy for the current unlock error state. */\nfunction resolveErrorText(\n errorKey: DevicePinErrorKey | null,\n digits: number,\n retryAfter: number | null,\n labels: DevicePinUnlockLabels,\n): string | null {\n if (errorKey === null) {\n return null;\n }\n if (errorKey === DevicePinErrorKey.Incomplete) {\n return interpolate(labels.errorIncomplete, { count: digits });\n }\n if (errorKey === DevicePinErrorKey.Invalid) {\n return labels.errorInvalid;\n }\n if (errorKey === DevicePinErrorKey.LockedOut) {\n return retryAfter !== null\n ? interpolate(labels.errorLockedOutRetry, { count: retryAfter })\n : labels.errorLockedOut;\n }\n if (errorKey === DevicePinErrorKey.RateLimited) {\n return retryAfter !== null\n ? interpolate(labels.errorRateLimitedRetry, { count: retryAfter })\n : labels.errorRateLimited;\n }\n return labels.errorGeneric;\n}\n\n/** Themeable device-PIN unlock gate built on `useDevicePinUnlock`. */\nexport function DevicePinUnlockScreen({\n client,\n digits,\n rememberedUsername,\n theme: themeProp,\n labels: labelsProp,\n testIdPrefix,\n onSignedIn,\n onUsePassword,\n}: Readonly<DevicePinUnlockScreenProps>): ReactElement {\n const theme = useAuthTheme(themeProp);\n const styles = useAuthStyles(theme);\n const labels = useMemo<DevicePinUnlockLabels>(\n () => ({ ...DEFAULT_DEVICE_PIN_UNLOCK_LABELS, ...labelsProp }),\n [labelsProp],\n );\n\n const { pin, submitting, errorKey, retryAfterSeconds, setPin, submit } = useDevicePinUnlock({\n client,\n digits,\n onSignedIn,\n });\n\n const hasName = rememberedUsername !== '';\n const title = hasName ? interpolate(labels.title, { name: rememberedUsername }) : labels.titleNoName;\n const error = resolveErrorText(errorKey, digits, retryAfterSeconds, labels);\n const buttonStyle = submitting\n ? [styles.primaryButton, styles.primaryButtonDisabled]\n : styles.primaryButton;\n\n return (\n <View style={styles.screen}>\n <View\n style={styles.card}\n testID={withTestIdPrefix(AuthTestIds.devicePinUnlock, testIdPrefix)}\n >\n <Text style={styles.title}>{title}</Text>\n <Text style={styles.subtitle}>{interpolate(labels.description, { count: digits })}</Text>\n\n <DevicePinInput\n accessibilityHint={labels.pinPlaceholder}\n accessibilityLabel={labels.pinLabel}\n disabled={submitting}\n emptyHint={labels.digitEmptyHint}\n filledHint={labels.digitFilledHint}\n length={digits}\n testID={AuthTestIds.devicePinUnlockInput}\n testIdPrefix={testIdPrefix}\n theme={theme}\n value={pin}\n onChange={setPin}\n />\n\n {error !== null ? (\n <Text\n style={styles.errorText}\n testID={withTestIdPrefix(AuthTestIds.devicePinUnlockError, testIdPrefix)}\n >\n {error}\n </Text>\n ) : null}\n\n <TouchableOpacity\n accessibilityHint={labels.submit}\n accessibilityLabel={submitting ? labels.submitting : labels.submit}\n accessibilityRole=\"button\"\n disabled={submitting}\n style={buttonStyle}\n testID={withTestIdPrefix(AuthTestIds.devicePinUnlockSubmit, testIdPrefix)}\n onPress={submit}\n >\n {submitting ? (\n <ActivityIndicator color={theme.colors.onPrimary} size=\"small\" />\n ) : (\n <Text style={styles.primaryButtonText}>{labels.submit}</Text>\n )}\n </TouchableOpacity>\n\n <TouchableOpacity\n accessibilityHint={labels.usePasswordHint}\n accessibilityLabel={labels.usePasswordInstead}\n accessibilityRole=\"button\"\n disabled={submitting}\n style={styles.escapeLink}\n testID={withTestIdPrefix(AuthTestIds.devicePinUnlockUsePassword, testIdPrefix)}\n onPress={onUsePassword}\n >\n <Text style={styles.linkText}>{labels.usePasswordInstead}</Text>\n </TouchableOpacity>\n </View>\n </View>\n );\n}\n","/**\n * The localizable failure states the device-PIN ENROL form can show — shared by\n * the post-login offer and the settings toggle.\n */\nexport const enum DevicePinEnrollErrorKey {\n /** PIN length wrong or the confirmation didn't match (no network call). */\n Mismatch = 'mismatch',\n /** The current session is not authenticated (401). */\n Unauthorized = 'unauthorized',\n /** The session already has a PIN, or is otherwise forbidden (403). */\n Forbidden = 'forbidden',\n /** The PIN failed server-side validation (400). */\n InvalidPin = 'invalid_pin',\n /** Any other failure (grant / network / unexpected). */\n Failed = 'failed',\n}\n","/**\n * The react-query-FREE state machine behind {@link DevicePinEnrollForm}, shared\n * by the post-login offer and the settings toggle.\n *\n * Enrol requires an authenticated session (the session cookie travels on the\n * client's `enrollDevicePin` call) — but the post-login offer can render adjacent\n * to the login route group, so this stays react-query-free (`useState` +\n * `.then()/.catch()/.finally()`), never `useMutation`. Pulling the logic into a\n * hook lets the confirm / mismatch / status transitions be unit-tested without\n * rendering, and keeps the form component presentational.\n *\n * Submit flow (a single PIN entry confirmed against itself):\n * - preflight: PIN must be exactly `digits` long and equal its confirmation,\n * else {@link DevicePinEnrollErrorKey.Mismatch} (no network call);\n * - `success` → call `onEnrolled`;\n * - `unauthorized` / `forbidden` / `invalidPin` → the matching error key;\n * - `error` / a thrown rejection → {@link DevicePinEnrollErrorKey.Failed}.\n */\nimport { useCallback, useState } from 'react';\n\nimport { DevicePinEnrollErrorKey } from './DevicePinEnrollErrorKey';\n\nimport type { DevicePinEnrollCapableClient, DevicePinEnrollResult } from './types';\n\nexport interface UseDevicePinEnrollArgs {\n /** The client exposing `enrollDevicePin`. */\n client: DevicePinEnrollCapableClient;\n /** Chosen PIN length (4/6/8). */\n digits: number;\n /** Called after a successful enrol so the surface can dismiss / flip state. */\n onEnrolled: () => void;\n}\n\nexport interface UseDevicePinEnrollResult {\n pin: string;\n confirmPin: string;\n submitting: boolean;\n errorKey: DevicePinEnrollErrorKey | null;\n setPin: (next: string) => void;\n setConfirmPin: (next: string) => void;\n submit: () => void;\n}\n\n/** Map a non-success enrol result onto its localizable error key. */\nfunction errorKeyFor(result: DevicePinEnrollResult): DevicePinEnrollErrorKey {\n if (result.status === 'unauthorized') {\n return DevicePinEnrollErrorKey.Unauthorized;\n }\n if (result.status === 'forbidden') {\n return DevicePinEnrollErrorKey.Forbidden;\n }\n if (result.status === 'invalidPin') {\n return DevicePinEnrollErrorKey.InvalidPin;\n }\n return DevicePinEnrollErrorKey.Failed;\n}\n\nexport function useDevicePinEnroll({\n client,\n digits,\n onEnrolled,\n}: UseDevicePinEnrollArgs): UseDevicePinEnrollResult {\n const [pin, setPinState] = useState<string>('');\n const [confirmPin, setConfirmState] = useState<string>('');\n const [submitting, setSubmitting] = useState<boolean>(false);\n const [errorKey, setErrorKey] = useState<DevicePinEnrollErrorKey | null>(null);\n\n const setPin = useCallback((next: string): void => {\n setPinState(next);\n setErrorKey(null);\n }, []);\n\n const setConfirmPin = useCallback((next: string): void => {\n setConfirmState(next);\n setErrorKey(null);\n }, []);\n\n const submit = useCallback((): void => {\n setErrorKey(null);\n const wrongLength = pin.length !== digits;\n const mismatched = pin !== confirmPin;\n if (wrongLength || mismatched) {\n setErrorKey(DevicePinEnrollErrorKey.Mismatch);\n return;\n }\n setSubmitting(true);\n client\n .enrollDevicePin({ pin, digits })\n .then((result) => {\n if (result.status === 'success') {\n onEnrolled();\n return;\n }\n setErrorKey(errorKeyFor(result));\n })\n .catch(() => {\n setErrorKey(DevicePinEnrollErrorKey.Failed);\n })\n .finally(() => {\n setSubmitting(false);\n });\n }, [client, pin, confirmPin, digits, onEnrolled]);\n\n return { pin, confirmPin, submitting, errorKey, setPin, setConfirmPin, submit };\n}\n","/**\n * The shared device-PIN ENROL form — reused by the post-login offer\n * ({@link DevicePinOffer}) and the settings toggle ({@link DevicePinSettingsCard}).\n *\n * Lets the user pick a PIN length (4/6/8), enter + confirm a PIN, and submit via\n * `client.enrollDevicePin` (through {@link useDevicePinEnroll}). On success it\n * calls `onEnrolled`; `onCancel` dismisses without saving. Presentational only —\n * all submit / mismatch / status logic lives in the hook (react-query-free).\n * Styled from the `AuthTheme` token bag.\n */\nimport { useMemo, useState, type ReactElement } from 'react';\n\nimport { ActivityIndicator, Text, TouchableOpacity, View } from 'react-native';\n\nimport { DevicePinInput } from './DevicePinInput';\nimport { DevicePinLengthPicker } from './DevicePinLengthPicker';\nimport { interpolate } from './interpolate';\nimport { DEFAULT_DEVICE_PIN_ENROLL_LABELS, type DevicePinEnrollLabels } from './labels';\nimport { AuthTestIds, withTestIdPrefix } from './testIds';\nimport { useAuthStyles } from './useAuthStyles';\nimport { DevicePinEnrollErrorKey } from '../devicePin/DevicePinEnrollErrorKey';\nimport { DEVICE_PIN_DEFAULT_DIGITS } from '../devicePin/devicePinConstants';\nimport { useDevicePinEnroll } from '../devicePin/useDevicePinEnroll';\nimport { useAuthTheme } from '../theme/AuthThemeProvider';\n\nimport type { DevicePinEnrollCapableClient } from '../devicePin/types';\nimport type { AuthTheme } from '../theme/AuthTheme';\n\nexport interface DevicePinEnrollFormProps {\n /** The client exposing `enrollDevicePin`. */\n client: DevicePinEnrollCapableClient;\n /** Initial PIN length (defaults to {@link DEVICE_PIN_DEFAULT_DIGITS}). */\n initialDigits?: number;\n /** Explicit theme; overrides any `<AuthThemeProvider>`. */\n theme?: AuthTheme;\n /** Localised copy. Partial — unspecified keys fall back to English defaults. */\n labels?: Partial<DevicePinEnrollLabels>;\n /** Prefix applied to every `testID`. */\n testIdPrefix?: string;\n /** Called after a successful enrol. */\n onEnrolled: () => void;\n /** Called when the user cancels without saving. */\n onCancel: () => void;\n}\n\n/** Resolve the localized error copy for the current enrol error state. */\nfunction resolveErrorText(\n errorKey: DevicePinEnrollErrorKey | null,\n digits: number,\n labels: DevicePinEnrollLabels,\n): string | null {\n if (errorKey === null) {\n return null;\n }\n if (errorKey === DevicePinEnrollErrorKey.Mismatch) {\n return interpolate(labels.errorMismatch, { count: digits });\n }\n if (errorKey === DevicePinEnrollErrorKey.Unauthorized) {\n return labels.errorUnauthorized;\n }\n if (errorKey === DevicePinEnrollErrorKey.Forbidden) {\n return labels.errorForbidden;\n }\n if (errorKey === DevicePinEnrollErrorKey.InvalidPin) {\n return labels.errorInvalidPin;\n }\n return labels.errorFailed;\n}\n\n/** Themeable device-PIN enrol form built on `useDevicePinEnroll`. */\nexport function DevicePinEnrollForm({\n client,\n initialDigits = DEVICE_PIN_DEFAULT_DIGITS,\n theme: themeProp,\n labels: labelsProp,\n testIdPrefix,\n onEnrolled,\n onCancel,\n}: Readonly<DevicePinEnrollFormProps>): ReactElement {\n const theme = useAuthTheme(themeProp);\n const styles = useAuthStyles(theme);\n const labels = useMemo<DevicePinEnrollLabels>(\n () => ({ ...DEFAULT_DEVICE_PIN_ENROLL_LABELS, ...labelsProp }),\n [labelsProp],\n );\n\n const [digits, setDigits] = useState<number>(initialDigits);\n const { pin, confirmPin, submitting, errorKey, setPin, setConfirmPin, submit } =\n useDevicePinEnroll({ client, digits, onEnrolled });\n const error = resolveErrorText(errorKey, digits, labels);\n const buttonStyle = submitting\n ? [styles.primaryButton, styles.primaryButtonDisabled]\n : styles.primaryButton;\n\n return (\n <View\n style={styles.card}\n testID={withTestIdPrefix(AuthTestIds.devicePinEnrollForm, testIdPrefix)}\n >\n <Text style={styles.title}>{labels.formTitle}</Text>\n <Text style={styles.subtitle}>{interpolate(labels.formDescription, { count: digits })}</Text>\n\n <Text style={styles.label}>{labels.lengthLabel}</Text>\n <DevicePinLengthPicker\n disabled={submitting}\n optionHint={labels.lengthOptionHint}\n selected={digits}\n testIdPrefix={testIdPrefix}\n theme={theme}\n onSelect={(option): void => {\n setDigits(option);\n setPin('');\n setConfirmPin('');\n }}\n />\n\n <Text style={styles.label}>{labels.pinLabel}</Text>\n <DevicePinInput\n accessibilityHint={labels.pinPlaceholder}\n accessibilityLabel={labels.pinLabel}\n disabled={submitting}\n emptyHint={labels.pinPlaceholder}\n filledHint={labels.pinLabel}\n length={digits}\n testID={AuthTestIds.devicePinEnrollPin}\n testIdPrefix={testIdPrefix}\n theme={theme}\n value={pin}\n onChange={setPin}\n />\n\n <Text style={styles.label}>{labels.confirmLabel}</Text>\n <DevicePinInput\n accessibilityHint={labels.confirmPlaceholder}\n accessibilityLabel={labels.confirmLabel}\n disabled={submitting}\n emptyHint={labels.confirmPlaceholder}\n filledHint={labels.confirmLabel}\n length={digits}\n testID={AuthTestIds.devicePinEnrollConfirm}\n testIdPrefix={testIdPrefix}\n theme={theme}\n value={confirmPin}\n onChange={setConfirmPin}\n />\n\n {error !== null ? (\n <Text\n style={styles.errorText}\n testID={withTestIdPrefix(AuthTestIds.devicePinEnrollError, testIdPrefix)}\n >\n {error}\n </Text>\n ) : null}\n\n <TouchableOpacity\n accessibilityHint={labels.submit}\n accessibilityLabel={submitting ? labels.submitting : labels.submit}\n accessibilityRole=\"button\"\n disabled={submitting}\n style={buttonStyle}\n testID={withTestIdPrefix(AuthTestIds.devicePinEnrollSubmit, testIdPrefix)}\n onPress={submit}\n >\n {submitting ? (\n <ActivityIndicator color={theme.colors.onPrimary} size=\"small\" />\n ) : (\n <Text style={styles.primaryButtonText}>{labels.submit}</Text>\n )}\n </TouchableOpacity>\n\n <TouchableOpacity\n accessibilityHint={labels.cancelHint}\n accessibilityLabel={labels.cancel}\n accessibilityRole=\"button\"\n disabled={submitting}\n style={styles.escapeLink}\n testID={withTestIdPrefix(AuthTestIds.devicePinEnrollCancel, testIdPrefix)}\n onPress={onCancel}\n >\n <Text style={styles.linkText}>{labels.cancel}</Text>\n </TouchableOpacity>\n </View>\n );\n}\n","/**\n * The skippable post-login \"Set a PIN for faster sign-in?\" offer.\n *\n * Mount on the post-login landing for an authenticated user who does NOT already\n * have a device PIN. It is dismissible and non-blocking: an initial prompt with\n * \"Set up a PIN\" / \"Not now\"; tapping accept reveals the shared\n * {@link DevicePinEnrollForm}; on success or skip it calls `onDismiss` so the\n * host can hide it (and remember the dismissal). Self-contained, react-query-free.\n */\nimport { useMemo, useState, type ReactElement } from 'react';\n\nimport { Text, TouchableOpacity, View } from 'react-native';\n\nimport { DevicePinEnrollForm } from './DevicePinEnrollForm';\nimport {\n DEFAULT_DEVICE_PIN_ENROLL_LABELS,\n type DevicePinEnrollLabels,\n} from './labels';\nimport { AuthTestIds, withTestIdPrefix } from './testIds';\nimport { useAuthStyles } from './useAuthStyles';\nimport { useAuthTheme } from '../theme/AuthThemeProvider';\n\nimport type { DevicePinEnrollCapableClient } from '../devicePin/types';\nimport type { AuthTheme } from '../theme/AuthTheme';\n\nexport interface DevicePinOfferProps {\n /** The client exposing `enrollDevicePin`. */\n client: DevicePinEnrollCapableClient;\n /** Initial PIN length offered in the enrol form. */\n initialDigits?: number;\n /** Explicit theme; overrides any `<AuthThemeProvider>`. */\n theme?: AuthTheme;\n /** Localised copy. Partial — unspecified keys fall back to English defaults. */\n labels?: Partial<DevicePinEnrollLabels>;\n /** Prefix applied to every `testID`. */\n testIdPrefix?: string;\n /** Called when the offer is finished — accepted+enrolled, or skipped. */\n onDismiss: () => void;\n}\n\n/** Themeable, skippable post-login device-PIN setup offer. */\nexport function DevicePinOffer({\n client,\n initialDigits,\n theme: themeProp,\n labels: labelsProp,\n testIdPrefix,\n onDismiss,\n}: Readonly<DevicePinOfferProps>): ReactElement {\n const theme = useAuthTheme(themeProp);\n const styles = useAuthStyles(theme);\n const labels = useMemo<DevicePinEnrollLabels>(\n () => ({ ...DEFAULT_DEVICE_PIN_ENROLL_LABELS, ...labelsProp }),\n [labelsProp],\n );\n const [expanded, setExpanded] = useState<boolean>(false);\n const cardTestId = withTestIdPrefix(AuthTestIds.devicePinOffer, testIdPrefix);\n\n if (expanded) {\n return (\n <View style={styles.card} testID={cardTestId}>\n <DevicePinEnrollForm\n client={client}\n initialDigits={initialDigits}\n labels={labelsProp}\n testIdPrefix={testIdPrefix}\n theme={theme}\n onCancel={onDismiss}\n onEnrolled={onDismiss}\n />\n </View>\n );\n }\n\n return (\n <View style={styles.card} testID={cardTestId}>\n <Text style={styles.title}>{labels.offerTitle}</Text>\n <Text style={styles.subtitle}>{labels.offerDescription}</Text>\n\n <TouchableOpacity\n accessibilityHint={labels.offerAcceptHint}\n accessibilityLabel={labels.offerAccept}\n accessibilityRole=\"button\"\n style={styles.primaryButton}\n testID={withTestIdPrefix(AuthTestIds.devicePinOfferAccept, testIdPrefix)}\n onPress={(): void => setExpanded(true)}\n >\n <Text style={styles.primaryButtonText}>{labels.offerAccept}</Text>\n </TouchableOpacity>\n\n <TouchableOpacity\n accessibilityHint={labels.offerSkipHint}\n accessibilityLabel={labels.offerSkip}\n accessibilityRole=\"button\"\n style={styles.secondaryButton}\n testID={withTestIdPrefix(AuthTestIds.devicePinOfferSkip, testIdPrefix)}\n onPress={onDismiss}\n >\n <Text style={styles.secondaryButtonText}>{labels.offerSkip}</Text>\n </TouchableOpacity>\n </View>\n );\n}\n","/**\n * The react-query-FREE state machine behind the device-PIN settings card's\n * DISABLE action.\n *\n * Extracted from {@link DevicePinSettingsCard} so the disable transitions\n * (success flips `hasPin` off; a `false` result or a thrown rejection raises the\n * `failed` flag) can be unit-tested without rendering. Plain `useState` +\n * `.then()/.catch()/.finally()` over the client — never `useMutation`.\n *\n * Seeded with `initialHasPin` (from `GET /bff/config`); it tracks its own\n * enabled/disabled state thereafter. `markEnabled` is called by the host after a\n * successful enrol (the enrol form owns that call) to flip the card back on.\n */\nimport { useCallback, useState } from 'react';\n\nimport type { DevicePinDisableCapableClient } from './types';\n\nexport interface UseDevicePinDisableArgs {\n /** The client exposing `disableDevicePin`. */\n client: DevicePinDisableCapableClient;\n /** Whether this device already has an enrolled PIN (seeded from config). */\n initialHasPin: boolean;\n /** Called whenever the enabled state changes (enabled / disabled). */\n onChanged?: (hasPin: boolean) => void;\n}\n\nexport interface UseDevicePinDisableResult {\n /** `true` when the device currently has an enrolled PIN. */\n hasPin: boolean;\n /** `true` while a disable call is in flight. */\n disabling: boolean;\n /** `true` when the last disable attempt failed. */\n failed: boolean;\n /** Run the disable call for the current session. */\n disable: () => void;\n /** Flip the card to enabled (called by the host after a successful enrol). */\n markEnabled: () => void;\n}\n\nexport function useDevicePinDisable({\n client,\n initialHasPin,\n onChanged,\n}: UseDevicePinDisableArgs): UseDevicePinDisableResult {\n const [hasPin, setHasPin] = useState<boolean>(initialHasPin);\n const [disabling, setDisabling] = useState<boolean>(false);\n const [failed, setFailed] = useState<boolean>(false);\n\n const disable = useCallback((): void => {\n setFailed(false);\n setDisabling(true);\n client\n .disableDevicePin()\n .then((ok) => {\n if (ok) {\n setHasPin(false);\n onChanged?.(false);\n return;\n }\n setFailed(true);\n })\n .catch(() => {\n setFailed(true);\n })\n .finally(() => {\n setDisabling(false);\n });\n }, [client, onChanged]);\n\n const markEnabled = useCallback((): void => {\n setHasPin(true);\n onChanged?.(true);\n }, [onChanged]);\n\n return { hasPin, disabling, failed, disable, markEnabled };\n}\n","/**\n * The authenticated \"Quick PIN sign-in\" settings control.\n *\n * Mount on an authenticated settings/account surface. Seeded with `initialHasPin`\n * (from `GET /bff/config`); it tracks its own enabled/disabled state thereafter\n * and offers either:\n * - Enable → reveals the shared {@link DevicePinEnrollForm} → `client.enrollDevicePin`;\n * - Disable → `client.disableDevicePin` (revokes the offline token + clears the\n * device record server-side).\n *\n * `onChanged(hasPin)` fires whenever the enabled state flips, so the host can\n * persist / re-fetch. react-query-free: the disable logic lives in\n * {@link useDevicePinDisable}; the enrol logic in the shared form's hook.\n */\nimport { useMemo, useState, type ReactElement } from 'react';\n\nimport { ActivityIndicator, Text, TouchableOpacity, View } from 'react-native';\n\nimport { DevicePinEnrollForm } from './DevicePinEnrollForm';\nimport {\n DEFAULT_DEVICE_PIN_ENROLL_LABELS,\n DEFAULT_DEVICE_PIN_SETTINGS_LABELS,\n type DevicePinEnrollLabels,\n type DevicePinSettingsLabels,\n} from './labels';\nimport { AuthTestIds, withTestIdPrefix } from './testIds';\nimport { useAuthStyles } from './useAuthStyles';\nimport { useDevicePinDisable } from '../devicePin/useDevicePinDisable';\nimport { useAuthTheme } from '../theme/AuthThemeProvider';\n\nimport type {\n DevicePinDisableCapableClient,\n DevicePinEnrollCapableClient,\n} from '../devicePin/types';\nimport type { AuthTheme } from '../theme/AuthTheme';\n\nexport interface DevicePinSettingsCardProps {\n /** The client exposing both `enrollDevicePin` and `disableDevicePin`. */\n client: DevicePinEnrollCapableClient & DevicePinDisableCapableClient;\n /** Whether this device already has an enrolled PIN (seeded from config). */\n initialHasPin: boolean;\n /** Explicit theme; overrides any `<AuthThemeProvider>`. */\n theme?: AuthTheme;\n /** Settings-card copy. Partial — unspecified keys fall back to English. */\n labels?: Partial<DevicePinSettingsLabels>;\n /** Enrol-form copy passed through to the embedded form. */\n enrollLabels?: Partial<DevicePinEnrollLabels>;\n /** Prefix applied to every `testID`. */\n testIdPrefix?: string;\n /** Called whenever the enabled state flips (enabled / disabled). */\n onChanged?: (hasPin: boolean) => void;\n}\n\n/** Themeable authenticated device-PIN enable/disable card. */\nexport function DevicePinSettingsCard({\n client,\n initialHasPin,\n theme: themeProp,\n labels: labelsProp,\n enrollLabels,\n testIdPrefix,\n onChanged,\n}: Readonly<DevicePinSettingsCardProps>): ReactElement {\n const theme = useAuthTheme(themeProp);\n const styles = useAuthStyles(theme);\n const labels = useMemo<DevicePinSettingsLabels>(\n () => ({ ...DEFAULT_DEVICE_PIN_SETTINGS_LABELS, ...labelsProp }),\n [labelsProp],\n );\n const resolvedEnrollLabels = useMemo<DevicePinEnrollLabels>(\n () => ({ ...DEFAULT_DEVICE_PIN_ENROLL_LABELS, ...enrollLabels }),\n [enrollLabels],\n );\n\n const [enrolling, setEnrolling] = useState<boolean>(false);\n const { hasPin, disabling, failed, disable, markEnabled } = useDevicePinDisable({\n client,\n initialHasPin,\n onChanged,\n });\n\n const handleEnrolled = (): void => {\n setEnrolling(false);\n markEnabled();\n };\n\n const disableButtonStyle = disabling\n ? [styles.secondaryButton, styles.primaryButtonDisabled]\n : styles.secondaryButton;\n\n return (\n <View\n style={styles.card}\n testID={withTestIdPrefix(AuthTestIds.devicePinSettings, testIdPrefix)}\n >\n <Text style={styles.title}>{labels.title}</Text>\n <Text style={styles.subtitle}>{labels.description}</Text>\n <Text\n style={styles.statusText}\n testID={withTestIdPrefix(AuthTestIds.devicePinSettingsStatus, testIdPrefix)}\n >\n {hasPin ? labels.statusEnabled : labels.statusDisabled}\n </Text>\n\n {failed ? (\n <Text\n style={styles.errorText}\n testID={withTestIdPrefix(AuthTestIds.devicePinSettingsError, testIdPrefix)}\n >\n {labels.disableFailed}\n </Text>\n ) : null}\n\n {renderAction()}\n </View>\n );\n\n function renderAction(): ReactElement {\n if (enrolling) {\n return (\n <DevicePinEnrollForm\n client={client}\n labels={resolvedEnrollLabels}\n testIdPrefix={testIdPrefix}\n theme={theme}\n onCancel={(): void => setEnrolling(false)}\n onEnrolled={handleEnrolled}\n />\n );\n }\n if (hasPin) {\n return (\n <TouchableOpacity\n accessibilityHint={labels.disableHint}\n accessibilityLabel={disabling ? labels.disabling : labels.disable}\n accessibilityRole=\"button\"\n disabled={disabling}\n style={disableButtonStyle}\n testID={withTestIdPrefix(AuthTestIds.devicePinSettingsDisable, testIdPrefix)}\n onPress={disable}\n >\n {disabling ? (\n <ActivityIndicator color={theme.colors.primary} size=\"small\" />\n ) : (\n <Text style={styles.secondaryButtonText}>{labels.disable}</Text>\n )}\n </TouchableOpacity>\n );\n }\n return (\n <TouchableOpacity\n accessibilityHint={labels.enableHint}\n accessibilityLabel={labels.enable}\n accessibilityRole=\"button\"\n style={styles.primaryButton}\n testID={withTestIdPrefix(AuthTestIds.devicePinSettingsEnable, testIdPrefix)}\n onPress={(): void => setEnrolling(true)}\n >\n <Text style={styles.primaryButtonText}>{labels.enable}</Text>\n </TouchableOpacity>\n );\n }\n}\n","/**\n * Which WebAuthn ceremony {@link usePasskeyCeremony} drives.\n *\n * `Login` runs a usernameless/discoverable assertion\n * (`navigator.credentials.get`) from the login surface; `Register` runs an\n * attestation (`navigator.credentials.create`) from an authenticated settings\n * surface. The mode selects the `/bff/passkey/{login,register}/*` endpoint pair\n * and the matching redirect fallback.\n */\nexport const enum PasskeyCeremonyMode {\n /** Assertion ceremony — sign in with an existing passkey. */\n Login = 'login',\n /** Attestation ceremony — add a passkey to the signed-in account. */\n Register = 'register',\n}\n","/**\n * Capability-first access to the browser `Location`.\n *\n * WHY THIS EXISTS — `typeof window === 'undefined'` is NOT a native guard.\n * React Native's `setUpGlobals` does `global.window = global`, so on a real\n * device `window` EXISTS while `window.location` does NOT. Every `typeof window`\n * guard in the passkey helpers therefore fell straight through on native and\n * `window.location.search` / `window.location.pathname` threw a TypeError\n * DURING RENDER — `PasskeyLoginButton` calls `readPasskeyError()` and\n * `PasskeySettingsCard` calls `readPasskeyRegistered()` on every render — i.e.\n * a hard crash on any native screen that mounts them.\n *\n * On the web this is exactly equivalent to the old `typeof window` check (a\n * browser always has `window.location`), so web behaviour is unchanged.\n */\nexport function getBrowserLocation(): Location | null {\n if (typeof window === 'undefined') {\n return null;\n }\n // `Partial<Window>` is the honest type off-web: the DOM lib types `location` as\n // always-present, which is precisely the assumption that breaks on native.\n const browserLocation: Location | undefined = (window as Partial<Window>).location;\n if (browserLocation === undefined) {\n return null;\n }\n return browserLocation;\n}\n","/**\n * Navigation helpers for the passkey (WebAuthn) BFF endpoints.\n *\n * Unlike the device-PIN client (which is plain `fetch`), the passkey login and\n * registration ceremonies are NOT fetches — they are full-page BROWSER\n * NAVIGATIONS. The BFF (`Bff.AspNetCore` 1.3.x) drives the WebAuthn ceremony\n * through Keycloak's hosted pages, then redirects the browser back:\n * - login: `/bff/passkey/login?returnUrl=<rel>` → on success the browser\n * lands on `returnUrl` with the session cookie already set;\n * - registration: `/bff/passkey/register?returnUrl=<rel>` → Keycloak re-auths\n * the user (password) then runs the credential-creation ceremony, returning\n * the browser to `returnUrl?passkey=registered`;\n * - failure / cancel: the BFF redirects to `<login>?passkeyError=cancelled` or\n * `<login>?passkeyError=failed`.\n *\n * react-query-FREE by construction: there is NO fetch here at all — every\n * function is a pure `window.location` read or `window.location.assign`. The\n * login route group has no QueryClient provider, so the passkey login button\n * (which lives there) MUST avoid any react-query primitive; navigation satisfies\n * that trivially.\n *\n * All reads are SSR- AND NATIVE-safe: they resolve the browser `Location` through\n * {@link getBrowserLocation} (a capability probe — `typeof window` alone is not a\n * native guard, since React Native defines `global.window = global`) and return a\n * benign default rather than throwing when there is no `location`.\n */\nimport { getBrowserLocation } from './browserLocation';\n\n/** The recognised passkey error codes the BFF sends back via `?passkeyError=`. */\nexport type PasskeyErrorCode = 'cancelled' | 'failed';\n\nconst PASSKEY_LOGIN_ENDPOINT = '/bff/passkey/login';\nconst PASSKEY_REGISTER_ENDPOINT = '/bff/passkey/register';\nconst RETURN_URL_PARAM = 'returnUrl';\nconst PASSKEY_ERROR_PARAM = 'passkeyError';\nconst PASSKEY_PARAM = 'passkey';\nconst PASSKEY_REGISTERED_VALUE = 'registered';\nconst PASSKEY_ERROR_CANCELLED: PasskeyErrorCode = 'cancelled';\nconst PASSKEY_ERROR_FAILED: PasskeyErrorCode = 'failed';\n\n/** Build the `<endpoint>?returnUrl=<encoded>` URL the browser navigates to. */\nfunction buildNavigationUrl(endpoint: string, returnUrl: string): string {\n return `${endpoint}?${RETURN_URL_PARAM}=${encodeURIComponent(returnUrl)}`;\n}\n\n/** Read the current query string SSR-/native-safely, or `null` off-web. */\nfunction readSearchParams(): URLSearchParams | null {\n const browserLocation = getBrowserLocation();\n if (browserLocation === null) {\n return null;\n }\n return new URLSearchParams(browserLocation.search);\n}\n\n/**\n * Start the passkey LOGIN ceremony by navigating the browser to the BFF's\n * `/bff/passkey/login` endpoint. The BFF redirects through Keycloak's WebAuthn\n * ceremony and, on success, returns the browser to `returnUrl` with a session\n * cookie set. No-op off-web (no `window`). `returnUrl` should be a relative\n * app path (e.g. `'/'`).\n */\nexport function startPasskeyLogin(returnUrl: string): void {\n const browserLocation = getBrowserLocation();\n if (browserLocation === null) {\n return;\n }\n browserLocation.assign(buildNavigationUrl(PASSKEY_LOGIN_ENDPOINT, returnUrl));\n}\n\n/**\n * Start the passkey REGISTRATION ceremony by navigating the browser to the BFF's\n * `/bff/passkey/register` endpoint. Requires an authenticated session; Keycloak\n * re-authenticates the user (password) then runs the credential-creation\n * ceremony, returning the browser to `returnUrl?passkey=registered`. No-op\n * off-web. `returnUrl` should be a relative app path so the user lands back on\n * the same settings surface.\n */\nexport function startPasskeyRegistration(returnUrl: string): void {\n const browserLocation = getBrowserLocation();\n if (browserLocation === null) {\n return;\n }\n browserLocation.assign(buildNavigationUrl(PASSKEY_REGISTER_ENDPOINT, returnUrl));\n}\n\n/**\n * Read the `?passkeyError=` query param the BFF appends on a failed / cancelled\n * ceremony. Returns `'cancelled'` or `'failed'` for the two known values, or\n * `null` for an absent / unknown value. SSR-safe (returns `null` off-web).\n */\nexport function readPasskeyError(): PasskeyErrorCode | null {\n const params = readSearchParams();\n if (params === null) {\n return null;\n }\n const value = params.get(PASSKEY_ERROR_PARAM);\n if (value === PASSKEY_ERROR_CANCELLED) {\n return PASSKEY_ERROR_CANCELLED;\n }\n if (value === PASSKEY_ERROR_FAILED) {\n return PASSKEY_ERROR_FAILED;\n }\n return null;\n}\n\n/**\n * `true` when the browser has just returned from a successful passkey\n * registration, i.e. the `?passkey=registered` query param is present. SSR-safe\n * (returns `false` off-web).\n */\nexport function readPasskeyRegistered(): boolean {\n const params = readSearchParams();\n if (params === null) {\n return false;\n }\n return params.get(PASSKEY_PARAM) === PASSKEY_REGISTERED_VALUE;\n}\n","/**\n * The lifecycle state of an in-page passkey ceremony.\n *\n * `Idle` before the user acts; `Running` while options are fetched, the\n * authenticator prompts, and the assertion/attestation is verified; `Success`\n * once the BFF confirms (a login has a session cookie set, a registration has a\n * stored credential); `Error` on a genuine in-page failure (see\n * {@link PasskeyErrorCode}). A redirect fallback (RP not configured / unsupported\n * browser) navigates the page away, so the hook never lands in a terminal state\n * for that path.\n */\nexport const enum PasskeyCeremonyStatus {\n /** No ceremony has started. */\n Idle = 'idle',\n /** A ceremony is in flight (fetch → authenticator → verify). */\n Running = 'running',\n /** The ceremony completed and the BFF confirmed it. */\n Success = 'success',\n /** The ceremony failed in-page (cancelled or failed). */\n Error = 'error',\n}\n","/**\n * base64url <-> bytes conversion for the in-page WebAuthn ceremony.\n *\n * The BFF speaks Fido2NetLib's wire format, where every binary field\n * (`challenge`, `user.id`, credential ids, `attestationObject`,\n * `clientDataJSON`, `authenticatorData`, `signature`, `userHandle`) is a\n * **base64url** string. The browser WebAuthn API, by contrast, wants/returns\n * `ArrayBuffer`s. `usePasskeyCeremony` uses these two helpers to bridge the two:\n * decode options coming from the BFF into buffers before\n * `navigator.credentials.*`, and encode the resulting credential back into\n * base64url before posting it to the verify endpoint.\n *\n * base64url = standard base64 with `+`/`/` replaced by `-`/`_` and no `=`\n * padding. Both `atob`/`btoa` exist in every supported browser and in Node ≥ 18\n * (this package's engine floor), so no `Buffer` dependency is pulled in.\n */\n\n/**\n * Decode a base64url string to a `Uint8Array`. Tolerates missing padding.\n *\n * Backed by an explicit `ArrayBuffer` (not a `SharedArrayBuffer`) so the result\n * satisfies the DOM `BufferSource` the WebAuthn API expects for\n * `challenge` / credential ids under the TS 5.7+ typed-array generics.\n */\nexport function base64UrlToBytes(value: string): Uint8Array<ArrayBuffer> {\n const base64 = value.replace(/-/g, '+').replace(/_/g, '/');\n const padded = base64.padEnd(Math.ceil(base64.length / 4) * 4, '=');\n const binary = atob(padded);\n const bytes = new Uint8Array(new ArrayBuffer(binary.length));\n for (let i = 0; i < binary.length; i += 1) {\n bytes[i] = binary.charCodeAt(i);\n }\n return bytes;\n}\n\n/** Encode an `ArrayBuffer` / typed-array to an unpadded base64url string. */\nexport function bytesToBase64Url(buffer: ArrayBuffer | Uint8Array): string {\n const bytes = buffer instanceof Uint8Array ? buffer : new Uint8Array(buffer);\n let binary = '';\n for (let i = 0; i < bytes.length; i += 1) {\n binary += String.fromCharCode(bytes[i] as number);\n }\n // btoa only ever emits `=` as trailing padding, so a plain global strip is\n // equivalent to `/=+$/` without the super-linear-backtracking risk.\n return btoa(binary).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=/g, '');\n}\n","/**\n * Coercion between the BFF's Fido2NetLib JSON and the browser WebAuthn API.\n *\n * The passkey RP fetch endpoints (`/bff/passkey/*`) return a\n * `{ challengeId, options }` envelope where `options` is Fido2NetLib's\n * `CredentialCreateOptions` / `AssertionOptions` serialized verbatim — binary\n * fields as base64url strings, plus harmless extras (`status`, `errorMessage`)\n * the WebAuthn API ignores. `navigator.credentials.create/get` needs the binary\n * fields as `BufferSource`s, so {@link toCreationOptions} / {@link toRequestOptions}\n * decode `challenge`, `user.id` and the credential-descriptor ids in place.\n *\n * After the ceremony, {@link encodeAttestation} / {@link encodeAssertion} turn the\n * returned `PublicKeyCredential` back into the exact shape Fido2NetLib\n * deserializes (`AuthenticatorAttestationRawResponse` /\n * `AuthenticatorAssertionRawResponse`): `id`/`rawId`/`type` + a `response` object\n * whose binary members are base64url. These bodies are posted to the matching\n * verify endpoint.\n */\nimport { base64UrlToBytes, bytesToBase64Url } from './base64url';\n\n/** The `{ challengeId, options }` body returned by each options endpoint. */\nexport interface PasskeyOptionsEnvelope {\n challengeId: string;\n options: Record<string, unknown>;\n}\n\n/** A Fido2 credential descriptor as it arrives on the wire (id = base64url). */\ninterface RawCredentialDescriptor {\n type?: string;\n id: string;\n transports?: string[];\n}\n\nconst PUBLIC_KEY_TYPE = 'public-key';\n\n/** Map the wire allow/exclude list (base64url ids) to WebAuthn descriptors. */\nfunction toDescriptors(value: unknown): PublicKeyCredentialDescriptor[] | undefined {\n if (!Array.isArray(value)) {\n return undefined;\n }\n return value.map((entry): PublicKeyCredentialDescriptor => {\n const descriptor = entry as RawCredentialDescriptor;\n return {\n type: PUBLIC_KEY_TYPE,\n id: base64UrlToBytes(descriptor.id),\n transports: descriptor.transports as AuthenticatorTransport[] | undefined,\n };\n });\n}\n\n/** Decode registration options (`challenge`, `user.id`, `excludeCredentials`). */\nexport function toCreationOptions(\n options: Record<string, unknown>,\n): PublicKeyCredentialCreationOptions {\n const user = options.user as { id: string; name: string; displayName: string };\n return {\n ...(options as unknown as PublicKeyCredentialCreationOptions),\n challenge: base64UrlToBytes(options.challenge as string),\n user: { ...user, id: base64UrlToBytes(user.id) },\n excludeCredentials: toDescriptors(options.excludeCredentials),\n };\n}\n\n/** Decode assertion options (`challenge`, `allowCredentials`). */\nexport function toRequestOptions(\n options: Record<string, unknown>,\n): PublicKeyCredentialRequestOptions {\n return {\n ...(options as unknown as PublicKeyCredentialRequestOptions),\n challenge: base64UrlToBytes(options.challenge as string),\n allowCredentials: toDescriptors(options.allowCredentials),\n };\n}\n\n/** Read the optional `getTransports()` an attestation response may expose. */\nfunction readTransports(response: AuthenticatorAttestationResponse): string[] {\n return typeof response.getTransports === 'function' ? response.getTransports() : [];\n}\n\n/** Encode a registration credential to `AuthenticatorAttestationRawResponse` JSON. */\nexport function encodeAttestation(\n credential: PublicKeyCredential,\n): Record<string, unknown> {\n const response = credential.response as AuthenticatorAttestationResponse;\n return {\n id: credential.id,\n rawId: bytesToBase64Url(credential.rawId),\n type: credential.type,\n response: {\n attestationObject: bytesToBase64Url(response.attestationObject),\n clientDataJSON: bytesToBase64Url(response.clientDataJSON),\n transports: readTransports(response),\n },\n clientExtensionResults: credential.getClientExtensionResults(),\n };\n}\n\n/** Encode a login credential to `AuthenticatorAssertionRawResponse` JSON. */\nexport function encodeAssertion(\n credential: PublicKeyCredential,\n): Record<string, unknown> {\n const response = credential.response as AuthenticatorAssertionResponse;\n const userHandle =\n response.userHandle !== null ? bytesToBase64Url(response.userHandle) : null;\n return {\n id: credential.id,\n rawId: bytesToBase64Url(credential.rawId),\n type: credential.type,\n response: {\n authenticatorData: bytesToBase64Url(response.authenticatorData),\n clientDataJSON: bytesToBase64Url(response.clientDataJSON),\n signature: bytesToBase64Url(response.signature),\n userHandle,\n },\n clientExtensionResults: credential.getClientExtensionResults(),\n };\n}\n","/**\n * `usePasskeyCeremony` — the react-query-FREE, in-page WebAuthn ceremony hook.\n *\n * Replaces the full-page Keycloak redirect with a same-origin ceremony driven\n * entirely in the browser (Move 2b passkey rebuild):\n *\n * options fetch → `navigator.credentials.create/get` → verify fetch\n *\n * against the BFF's `/bff/passkey/{login,register}/{options,verify}` endpoints.\n * It lives on the login route group (no QueryClient provider), so — like the\n * device-PIN hooks — it uses plain `fetch` + `useState`, never react-query.\n *\n * INERT-BY-DEFAULT / never-regress contract: the in-page path activates ONLY\n * when the BFF's WebAuthn RP is configured. Until then the options endpoint\n * returns **501**, and the hook transparently falls back to the legacy redirect\n * ({@link startPasskeyLogin} / {@link startPasskeyRegistration}). The same\n * fallback covers a non-2xx options response and an unsupported browser (native,\n * or a browser without `PublicKeyCredential`). So with the flag off the observed\n * behaviour is byte-for-byte the old redirect; nothing ships until the owner\n * flips `Bff:Passkey`.\n *\n * Once the ceremony has actually started (the authenticator prompt is up), a\n * failure is surfaced in-page rather than redirected: a user cancel / timeout\n * (`NotAllowedError` / `AbortError`) → {@link PasskeyErrorCode} `'cancelled'`,\n * anything else → `'failed'`.\n */\nimport { useCallback, useMemo, useState } from 'react';\n\nimport { getBrowserLocation } from './browserLocation';\nimport { PasskeyCeremonyMode } from './PasskeyCeremonyMode';\nimport { PasskeyCeremonyStatus } from './PasskeyCeremonyStatus';\nimport {\n startPasskeyLogin,\n startPasskeyRegistration,\n type PasskeyErrorCode,\n} from './passkeyNavigation';\nimport {\n encodeAssertion,\n encodeAttestation,\n toCreationOptions,\n toRequestOptions,\n type PasskeyOptionsEnvelope,\n} from './webAuthnCoercion';\n\nimport type { BffUser } from '@dloizides/auth-client';\n\n/** Options for {@link usePasskeyCeremony}. */\nexport interface UsePasskeyCeremonyOptions {\n /** Which ceremony to run — login (assertion) or register (attestation). */\n mode: PasskeyCeremonyMode;\n /**\n * Relative app path used two ways: the redirect fallback returns here, and (for\n * login) a successful in-page ceremony navigates here unless `onSuccess` is set.\n */\n returnUrl: string;\n /**\n * Called on a successful in-page ceremony. For login it receives the signed-in\n * `BffUser`; for register it receives `undefined`. When omitted, a login\n * navigates to `returnUrl` and a register just resolves to `Success`.\n */\n onSuccess?: (user: BffUser | undefined) => void;\n}\n\n/** The state + controls {@link usePasskeyCeremony} returns. */\nexport interface UsePasskeyCeremonyResult {\n /** Current lifecycle state. */\n status: PasskeyCeremonyStatus;\n /** The in-page error code, or `null`. */\n error: PasskeyErrorCode | null;\n /** `true` when the browser can run the in-page ceremony (else it redirects). */\n isSupported: boolean;\n /** Start the ceremony (or redirect-fallback when the RP is off / unsupported). */\n start: () => void;\n /**\n * Hand off to the legacy Keycloak redirect explicitly. Wired to the \"try\n * another way\" affordance a surface shows after an in-page error — the escape\n * hatch for a credential enrolled only in Keycloak (invisible to the in-page\n * RP store), which the in-page ceremony cannot use.\n */\n fallbackToRedirect: () => void;\n /** Clear a terminal state so the affordance can be retried. */\n reset: () => void;\n}\n\nconst ERROR_CANCELLED: PasskeyErrorCode = 'cancelled';\nconst ERROR_FAILED: PasskeyErrorCode = 'failed';\nconst CANCEL_ERROR_NAMES = ['NotAllowedError', 'AbortError'];\n\nconst ENDPOINTS = {\n [PasskeyCeremonyMode.Login]: {\n options: '/bff/passkey/login/options',\n verify: '/bff/passkey/login/verify',\n },\n [PasskeyCeremonyMode.Register]: {\n options: '/bff/passkey/register/options',\n verify: '/bff/passkey/register/verify',\n },\n} as const;\n\n/** `true` when this runtime exposes the WebAuthn API needed for the in-page path. */\nfunction detectSupport(): boolean {\n return (\n typeof window !== 'undefined' &&\n typeof navigator !== 'undefined' &&\n typeof navigator.credentials !== 'undefined' &&\n typeof window.PublicKeyCredential !== 'undefined'\n );\n}\n\n/** POST a same-origin JSON body (cookies included), tolerating an empty body. */\nfunction postJson(url: string, body: unknown): Promise<Response> {\n return fetch(url, {\n method: 'POST',\n credentials: 'same-origin',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(body ?? {}),\n });\n}\n\n/** Run the browser ceremony for the decoded options; `null` if none returned. */\nasync function runCeremony(\n mode: PasskeyCeremonyMode,\n envelope: PasskeyOptionsEnvelope,\n): Promise<PublicKeyCredential | null> {\n const credential =\n mode === PasskeyCeremonyMode.Register\n ? await navigator.credentials.create({\n publicKey: toCreationOptions(envelope.options),\n })\n : await navigator.credentials.get({\n publicKey: toRequestOptions(envelope.options),\n });\n return credential as PublicKeyCredential | null;\n}\n\n/** Build the verify body for the ceremony's credential. */\nfunction buildVerifyBody(\n mode: PasskeyCeremonyMode,\n challengeId: string,\n credential: PublicKeyCredential,\n): Record<string, unknown> {\n return mode === PasskeyCeremonyMode.Register\n ? { challengeId, attestationResponse: encodeAttestation(credential) }\n : { challengeId, assertionResponse: encodeAssertion(credential) };\n}\n\n/** Fire the legacy redirect for the current mode (the never-regress fallback). */\nfunction redirectFallback(mode: PasskeyCeremonyMode, returnUrl: string): void {\n if (mode === PasskeyCeremonyMode.Register) {\n startPasskeyRegistration(returnUrl);\n return;\n }\n startPasskeyLogin(returnUrl);\n}\n\n/** Classify a thrown ceremony error into a user-facing code. */\nfunction classifyError(caught: unknown): PasskeyErrorCode {\n const name = caught instanceof Error ? caught.name : '';\n return CANCEL_ERROR_NAMES.includes(name) ? ERROR_CANCELLED : ERROR_FAILED;\n}\n\nexport function usePasskeyCeremony(\n optionsArg: UsePasskeyCeremonyOptions,\n): UsePasskeyCeremonyResult {\n const { mode, returnUrl, onSuccess } = optionsArg;\n const [status, setStatus] = useState<PasskeyCeremonyStatus>(PasskeyCeremonyStatus.Idle);\n const [error, setError] = useState<PasskeyErrorCode | null>(null);\n const isSupported = useMemo(detectSupport, []);\n\n const succeed = useCallback(\n (user: BffUser | undefined): void => {\n setStatus(PasskeyCeremonyStatus.Success);\n if (onSuccess !== undefined) {\n onSuccess(user);\n return;\n }\n const browserLocation = getBrowserLocation();\n if (mode === PasskeyCeremonyMode.Login && browserLocation !== null) {\n browserLocation.assign(returnUrl);\n }\n },\n [mode, onSuccess, returnUrl],\n );\n\n const start = useCallback((): void => {\n if (!isSupported) {\n redirectFallback(mode, returnUrl);\n return;\n }\n setStatus(PasskeyCeremonyStatus.Running);\n setError(null);\n\n void (async (): Promise<void> => {\n try {\n const optionsResponse = await postJson(ENDPOINTS[mode].options, {});\n // 501 (RP not configured) or any non-2xx → transparently use the old path.\n if (!optionsResponse.ok) {\n redirectFallback(mode, returnUrl);\n return;\n }\n const envelope = (await optionsResponse.json()) as PasskeyOptionsEnvelope;\n const credential = await runCeremony(mode, envelope);\n if (credential === null) {\n // No credential produced WITHOUT a throw. For LOGIN this is the\n // unambiguous \"this device has nothing to sign in-page with\" signal (a\n // real user cancel throws NotAllowedError, handled in catch) — hand off\n // to the Keycloak redirect so a user whose passkey is enrolled only in\n // KC can still sign in. REGISTER is always a fresh in-page enrolment, so\n // surface its failure in-page instead.\n if (mode === PasskeyCeremonyMode.Login) {\n redirectFallback(mode, returnUrl);\n return;\n }\n setStatus(PasskeyCeremonyStatus.Error);\n setError(ERROR_FAILED);\n return;\n }\n const verifyResponse = await postJson(\n ENDPOINTS[mode].verify,\n buildVerifyBody(mode, envelope.challengeId, credential),\n );\n if (!verifyResponse.ok) {\n setStatus(PasskeyCeremonyStatus.Error);\n setError(ERROR_FAILED);\n return;\n }\n // Login/verify returns 401 on a bad assertion (handled above) and\n // `{ user }` on success. Register/verify always returns 200 with a\n // generic `{ success }` boolean — a false there is still a failure.\n if (mode === PasskeyCeremonyMode.Register) {\n const { success } = (await verifyResponse.json()) as { success: boolean };\n if (!success) {\n setStatus(PasskeyCeremonyStatus.Error);\n setError(ERROR_FAILED);\n return;\n }\n succeed(undefined);\n return;\n }\n const { user } = (await verifyResponse.json()) as { user: BffUser };\n succeed(user);\n } catch (caught) {\n setStatus(PasskeyCeremonyStatus.Error);\n setError(classifyError(caught));\n }\n })();\n }, [isSupported, mode, returnUrl, succeed]);\n\n const fallbackToRedirect = useCallback((): void => {\n redirectFallback(mode, returnUrl);\n }, [mode, returnUrl]);\n\n const reset = useCallback((): void => {\n setStatus(PasskeyCeremonyStatus.Idle);\n setError(null);\n }, []);\n\n return useMemo(\n () => ({ status, error, isSupported, start, fallbackToRedirect, reset }),\n [status, error, isSupported, start, fallbackToRedirect, reset],\n );\n}\n","/**\n * The \"Sign in with a passkey\" button rendered on the unified login surface when\n * the BFF advertises the `passkey` method.\n *\n * The passkey login runs IN-PAGE via `usePasskeyCeremony`\n * (`navigator.credentials.get` against the same-origin `/bff/passkey/login/*`\n * fetch endpoints), landing the authenticated user on `returnUrl` (default `'/'`)\n * with a session cookie set. When the BFF's WebAuthn RP is not configured the\n * options endpoint returns 501 and the hook transparently falls back to the\n * legacy Keycloak redirect — so nothing regresses until the flag flips. A\n * cancelled / failed in-page ceremony surfaces as an inline error banner; a prior\n * redirect round-trip's `?passkeyError=…` is still honoured too.\n *\n * react-query-free: the hook uses plain `fetch` + `useState` (see\n * `usePasskeyCeremony`), so it is safe to mount inside the login route group\n * which has no QueryClient provider.\n */\nimport { useMemo, type ReactElement } from 'react';\n\nimport { Text, TouchableOpacity, View } from 'react-native';\n\nimport { DEFAULT_PASSKEY_LOGIN_LABELS, type PasskeyLoginLabels } from './labels';\nimport { AuthTestIds, withTestIdPrefix } from './testIds';\nimport { useAuthStyles } from './useAuthStyles';\nimport { PasskeyCeremonyMode } from '../passkey/PasskeyCeremonyMode';\nimport { readPasskeyError } from '../passkey/passkeyNavigation';\nimport { usePasskeyCeremony } from '../passkey/usePasskeyCeremony';\nimport { useAuthTheme } from '../theme/AuthThemeProvider';\n\nimport type { AuthTheme } from '../theme/AuthTheme';\n\nexport interface PasskeyLoginButtonProps {\n /** Relative app path the BFF returns to on success. Defaults to `'/'`. */\n returnUrl?: string;\n /** Explicit theme; overrides any `<AuthThemeProvider>`. */\n theme?: AuthTheme;\n /** Localised copy. Partial — unspecified keys fall back to English defaults. */\n labels?: Partial<PasskeyLoginLabels>;\n /** Prefix applied to every `testID`. */\n testIdPrefix?: string;\n}\n\n/** The app root — an authenticated user is routed onward to their dashboard. */\nconst DEFAULT_RETURN_URL = '/';\n\n/** Themeable passkey login CTA + error banner. */\nexport function PasskeyLoginButton({\n returnUrl = DEFAULT_RETURN_URL,\n theme: themeProp,\n labels: labelsProp,\n testIdPrefix,\n}: Readonly<PasskeyLoginButtonProps>): ReactElement {\n const theme = useAuthTheme(themeProp);\n const styles = useAuthStyles(theme);\n const labels = useMemo<PasskeyLoginLabels>(\n () => ({ ...DEFAULT_PASSKEY_LOGIN_LABELS, ...labelsProp }),\n [labelsProp],\n );\n const ceremony = usePasskeyCeremony({ mode: PasskeyCeremonyMode.Login, returnUrl });\n // The in-page ceremony error takes precedence; a `?passkeyError=…` left by a\n // prior redirect fallback is still surfaced on first mount.\n const error = ceremony.error ?? readPasskeyError();\n\n return (\n <View testID={withTestIdPrefix(AuthTestIds.passkeyLogin, testIdPrefix)}>\n {error !== null ? (\n <>\n <Text\n style={styles.errorText}\n testID={withTestIdPrefix(AuthTestIds.passkeyLoginError, testIdPrefix)}\n >\n {error === 'cancelled' ? labels.errorCancelled : labels.errorFailed}\n </Text>\n {/* Escape hatch to the Keycloak-hosted flow — rescues a credential\n enrolled only in KC, which the in-page ceremony cannot see. */}\n <TouchableOpacity\n accessibilityHint={labels.tryAnotherWay}\n accessibilityLabel={labels.tryAnotherWay}\n accessibilityRole=\"button\"\n testID={withTestIdPrefix(AuthTestIds.passkeyLoginFallback, testIdPrefix)}\n onPress={(): void => ceremony.fallbackToRedirect()}\n >\n <Text style={styles.linkText}>{labels.tryAnotherWay}</Text>\n </TouchableOpacity>\n </>\n ) : null}\n\n <TouchableOpacity\n accessibilityHint={labels.signInHint}\n accessibilityLabel={labels.signInButton}\n accessibilityRole=\"button\"\n style={styles.secondaryButton}\n testID={withTestIdPrefix(AuthTestIds.passkeyLoginButton, testIdPrefix)}\n onPress={(): void => ceremony.start()}\n >\n <Text style={styles.secondaryButtonText}>{labels.signInButton}</Text>\n </TouchableOpacity>\n </View>\n );\n}\n","/**\n * The authenticated \"Passkeys\" settings card.\n *\n * Mount on an authenticated settings / account surface (alongside the device-PIN\n * card). Adding a passkey runs IN-PAGE via `usePasskeyCeremony`\n * (`navigator.credentials.create` against the same-origin\n * `/bff/passkey/register/*` fetch endpoints, session-cookie authenticated); on\n * success we show an inline success line — no navigation. When the BFF's WebAuthn\n * RP is not configured the options endpoint returns 501 and the hook falls back\n * to the legacy Keycloak redirect, which returns here with `?passkey=registered`;\n * that param is still honoured on mount, so nothing regresses until the flag flips.\n *\n * react-query-free: the hook uses plain `fetch` + `useState` (see\n * `usePasskeyCeremony`). Mirrors `DevicePinSettingsCard`.\n */\nimport { useMemo, type ReactElement } from 'react';\n\nimport { Text, TouchableOpacity, View } from 'react-native';\n\nimport { DEFAULT_PASSKEY_SETTINGS_LABELS, type PasskeySettingsLabels } from './labels';\nimport { AuthTestIds, withTestIdPrefix } from './testIds';\nimport { useAuthStyles } from './useAuthStyles';\nimport { PasskeyCeremonyMode } from '../passkey/PasskeyCeremonyMode';\nimport { PasskeyCeremonyStatus } from '../passkey/PasskeyCeremonyStatus';\nimport { getBrowserLocation } from '../passkey/browserLocation';\nimport { readPasskeyRegistered } from '../passkey/passkeyNavigation';\nimport { usePasskeyCeremony } from '../passkey/usePasskeyCeremony';\nimport { useAuthTheme } from '../theme/AuthThemeProvider';\n\nimport type { AuthTheme } from '../theme/AuthTheme';\n\nexport interface PasskeySettingsCardProps {\n /**\n * Relative app path the BFF returns to after registration. Defaults to the\n * current `window.location.pathname` so the user lands back on this page.\n */\n returnUrl?: string;\n /** Explicit theme; overrides any `<AuthThemeProvider>`. */\n theme?: AuthTheme;\n /** Localised copy. Partial — unspecified keys fall back to English defaults. */\n labels?: Partial<PasskeySettingsLabels>;\n /** Prefix applied to every `testID`. */\n testIdPrefix?: string;\n}\n\n/** Fallback return path when there is no browser `location` to read the pathname from. */\nconst DEFAULT_RETURN_PATH = '/';\n\n/**\n * Read the current pathname SSR-/native-safely so registration returns to this page.\n *\n * Runs on EVERY render, so it must never throw: React Native defines\n * `global.window = global` but no `window.location`, which made the previous\n * `typeof window` guard fall through and crash the screen.\n */\nfunction readCurrentPath(): string {\n const browserLocation = getBrowserLocation();\n if (browserLocation === null) {\n return DEFAULT_RETURN_PATH;\n }\n return browserLocation.pathname;\n}\n\n/** Themeable authenticated passkey add card. */\nexport function PasskeySettingsCard({\n returnUrl,\n theme: themeProp,\n labels: labelsProp,\n testIdPrefix,\n}: Readonly<PasskeySettingsCardProps>): ReactElement {\n const theme = useAuthTheme(themeProp);\n const styles = useAuthStyles(theme);\n const labels = useMemo<PasskeySettingsLabels>(\n () => ({ ...DEFAULT_PASSKEY_SETTINGS_LABELS, ...labelsProp }),\n [labelsProp],\n );\n const target = returnUrl ?? readCurrentPath();\n const ceremony = usePasskeyCeremony({\n mode: PasskeyCeremonyMode.Register,\n returnUrl: target,\n });\n // Success comes either from the in-page ceremony completing, or from a prior\n // redirect fallback returning here with `?passkey=registered`.\n const justRegistered =\n ceremony.status === PasskeyCeremonyStatus.Success || readPasskeyRegistered();\n\n return (\n <View\n style={styles.card}\n testID={withTestIdPrefix(AuthTestIds.passkeySettings, testIdPrefix)}\n >\n <Text style={styles.title}>{labels.title}</Text>\n <Text style={styles.subtitle}>{labels.description}</Text>\n <Text style={styles.helperText}>{labels.reauthHint}</Text>\n\n {justRegistered ? (\n <Text\n style={styles.successText}\n testID={withTestIdPrefix(AuthTestIds.passkeySettingsSuccess, testIdPrefix)}\n >\n {labels.registeredSuccess}\n </Text>\n ) : null}\n\n <TouchableOpacity\n accessibilityHint={labels.addHint}\n accessibilityLabel={labels.addButton}\n accessibilityRole=\"button\"\n style={styles.primaryButton}\n testID={withTestIdPrefix(AuthTestIds.passkeySettingsAdd, testIdPrefix)}\n onPress={(): void => ceremony.start()}\n >\n <Text style={styles.primaryButtonText}>{labels.addButton}</Text>\n </TouchableOpacity>\n </View>\n );\n}\n","/**\n * Device-local cache of the user's preferred login method (unified-login D5).\n *\n * The preference is owned server-side (TenantService UserPreference), but the\n * LOGIN screen needs it BEFORE the user is authenticated — when no server call\n * is possible. So we cache it in `localStorage`, seeded after every successful\n * login (see {@link syncPreferredMethodFromServer}). A user who sets \"passkey\"\n * on device A will, after their first login on device B, see device B's login\n * screen prefer passkey too — cross-device sync with one-login lag.\n *\n * SSR-safe: every function no-ops / returns `null` when `localStorage` is\n * unavailable (server render, native, privacy modes that throw on access).\n */\n\n/** The `localStorage` key the preferred method is cached under. */\nconst CACHE_KEY = 'dloizides.auth.preferredLoginMethod';\n\n/** Resolve `localStorage` SSR-safely; `null` when unavailable. */\nfunction safeStorage(): Storage | null {\n try {\n if (typeof localStorage === 'undefined') {\n return null;\n }\n return localStorage;\n } catch {\n // Accessing localStorage can throw (e.g. sandboxed iframes, privacy modes).\n return null;\n }\n}\n\n/**\n * Read the cached preferred login method, or `null` when none is cached / the\n * store is unavailable. Cheap + synchronous so the login screen can call it on\n * render.\n */\nexport function readCachedPreferredMethod(): string | null {\n const store = safeStorage();\n if (store === null) {\n return null;\n }\n try {\n const value = store.getItem(CACHE_KEY);\n return value === null || value === '' ? null : value;\n } catch {\n return null;\n }\n}\n\n/**\n * Write (or, with `null`, clear) the cached preferred login method. No-op when\n * the store is unavailable. Never throws.\n */\nexport function cachePreferredMethod(method: string | null): void {\n const store = safeStorage();\n if (store === null) {\n return;\n }\n try {\n if (method === null || method === '') {\n store.removeItem(CACHE_KEY);\n return;\n }\n store.setItem(CACHE_KEY, method);\n } catch {\n // Quota / privacy-mode write failures are non-fatal — the hint is optional.\n }\n}\n\n/** Clear the cached preferred login method (e.g. on logout). Never throws. */\nexport function clearCachedPreferredMethod(): void {\n cachePreferredMethod(null);\n}\n","/**\n * Headless logic for the preferred-login-method settings control\n * (unified-login D5). react-query-FREE: plain `useState`/`useEffect`/\n * `useCallback` + the discriminated `PreferredMethodClient`. Mirrors the\n * device-PIN hooks so the settings card stays a thin renderer.\n *\n * On mount it loads the server-stored preference. `select` writes optimistically\n * (the radio flips immediately), persists via the client, mirrors the value into\n * the device-local cache on success, and reverts on failure.\n */\nimport { useCallback, useEffect, useState } from 'react';\n\nimport { cachePreferredMethod } from './preferredMethodCache';\n\nimport type { PreferredMethodClient } from './preferencesClient';\n\nexport interface UsePreferredMethodSettingArgs {\n /** The client exposing `getPreferredLoginMethod` + `setPreferredLoginMethod`. */\n client: PreferredMethodClient;\n /** Called whenever a save succeeds (the new value, `null` = no preference). */\n onChanged?: (method: string | null) => void;\n}\n\nexport interface UsePreferredMethodSettingResult {\n /** `true` until the initial server load resolves. */\n loading: boolean;\n /** `true` while a selection is being persisted. */\n saving: boolean;\n /** `true` when the last save failed (cleared on the next `select`). */\n failed: boolean;\n /** The currently-selected method, or `null` for \"no preference\". */\n selected: string | null;\n /** Optimistically select a method (`null` clears the preference) and persist it. */\n select: (method: string | null) => void;\n}\n\nexport function usePreferredMethodSetting({\n client,\n onChanged,\n}: UsePreferredMethodSettingArgs): UsePreferredMethodSettingResult {\n const [loading, setLoading] = useState<boolean>(true);\n const [saving, setSaving] = useState<boolean>(false);\n const [failed, setFailed] = useState<boolean>(false);\n const [selected, setSelected] = useState<string | null>(null);\n\n useEffect(() => {\n let active = true;\n client\n .getPreferredLoginMethod()\n .then((method) => {\n if (active) {\n setSelected(method);\n }\n })\n .catch(() => {\n // Leave the default (null) — the load is best-effort.\n })\n .finally(() => {\n if (active) {\n setLoading(false);\n }\n });\n return (): void => {\n active = false;\n };\n }, [client]);\n\n const select = useCallback(\n (method: string | null): void => {\n const previous = selected;\n if (method === previous) {\n return;\n }\n setFailed(false);\n setSaving(true);\n setSelected(method);\n client\n .setPreferredLoginMethod(method)\n .then((ok) => {\n if (ok) {\n cachePreferredMethod(method);\n onChanged?.(method);\n return;\n }\n setSelected(previous);\n setFailed(true);\n })\n .catch(() => {\n setSelected(previous);\n setFailed(true);\n })\n .finally(() => {\n setSaving(false);\n });\n },\n [client, selected, onChanged],\n );\n\n return { loading, saving, failed, selected, select };\n}\n","/**\n * The authenticated \"Preferred sign-in method\" settings card (unified-login D5).\n *\n * Mount on an authenticated settings/account surface alongside the device-PIN\n * and passkey cards. It lets the user pick which of their enabled login methods\n * they want emphasised on the login screen — stored SERVER-SIDE so the choice\n * follows them across devices. The login screen reads the device-local mirror\n * of this value (see `readCachedPreferredMethod` / `<PreferredMethodHint>`).\n *\n * `availableMethods` should be the BFF's advertised methods (from\n * `GET /bff/config` → `useBffLoginConfig().methods`) so the card only offers\n * methods this product actually supports. A \"No preference\" option always\n * appears. react-query-free: the persistence lives in `usePreferredMethodSetting`.\n */\nimport { useMemo, type ReactElement } from 'react';\n\nimport { ActivityIndicator, Text, TouchableOpacity, View } from 'react-native';\n\nimport {\n DEFAULT_PREFERRED_METHOD_SETTINGS_LABELS,\n type PreferredMethodSettingsLabels,\n} from './labels';\nimport { AuthTestIds, withTestIdPrefix } from './testIds';\nimport { useAuthStyles } from './useAuthStyles';\nimport { usePreferredMethodSetting } from '../preferences/usePreferredMethodSetting';\nimport { useAuthTheme } from '../theme/AuthThemeProvider';\n\nimport type { PreferredMethodClient } from '../preferences/preferencesClient';\nimport type { AuthTheme } from '../theme/AuthTheme';\n\n/** The sentinel option value representing \"no preference\". */\nconst NO_PREFERENCE = '__none__';\n\nexport interface PreferredMethodSettingsCardProps {\n /** The client exposing `getPreferredLoginMethod` + `setPreferredLoginMethod`. */\n client: PreferredMethodClient;\n /**\n * The login methods this BFF advertises (lowercase, e.g.\n * `['password', 'pin', 'passkey']`). Only these are offered, plus the\n * always-present \"No preference\" option.\n */\n availableMethods: readonly string[];\n /** Explicit theme; overrides any `<AuthThemeProvider>`. */\n theme?: AuthTheme;\n /** Localised copy. Partial — unspecified keys fall back to English defaults. */\n labels?: Partial<PreferredMethodSettingsLabels>;\n /** Prefix applied to every `testID`. */\n testIdPrefix?: string;\n /** Called whenever a save succeeds (`null` = no preference). */\n onChanged?: (method: string | null) => void;\n}\n\n/** Map a known lowercase method id to its localised display name; raw id otherwise. */\nfunction methodDisplayName(method: string, labels: PreferredMethodSettingsLabels): string {\n if (method === 'password') {\n return labels.methodPassword;\n }\n if (method === 'pin') {\n return labels.methodPin;\n }\n if (method === 'passkey') {\n return labels.methodPasskey;\n }\n return method;\n}\n\n/** Themeable authenticated preferred-method picker. */\nexport function PreferredMethodSettingsCard({\n client,\n availableMethods,\n theme: themeProp,\n labels: labelsProp,\n testIdPrefix,\n onChanged,\n}: Readonly<PreferredMethodSettingsCardProps>): ReactElement {\n const theme = useAuthTheme(themeProp);\n const styles = useAuthStyles(theme);\n const labels = useMemo<PreferredMethodSettingsLabels>(\n () => ({ ...DEFAULT_PREFERRED_METHOD_SETTINGS_LABELS, ...labelsProp }),\n [labelsProp],\n );\n\n const { loading, saving, failed, selected, select } = usePreferredMethodSetting({\n client,\n onChanged,\n });\n\n // The \"No preference\" option (sentinel) plus one row per advertised method.\n const options = useMemo<ReadonlyArray<{ value: string | null; key: string; label: string }>>(\n () => [\n { value: null, key: NO_PREFERENCE, label: labels.noPreference },\n ...availableMethods.map((method) => ({\n value: method,\n key: method,\n label: methodDisplayName(method, labels),\n })),\n ],\n [availableMethods, labels],\n );\n\n return (\n <View\n style={styles.card}\n testID={withTestIdPrefix(AuthTestIds.preferredMethodSettings, testIdPrefix)}\n >\n <Text style={styles.title}>{labels.title}</Text>\n <Text style={styles.subtitle}>{labels.description}</Text>\n\n {loading ? (\n <ActivityIndicator color={theme.colors.primary} size=\"small\" />\n ) : (\n options.map((option) => {\n const isSelected = option.value === selected;\n const optionTestId = `${withTestIdPrefix(\n AuthTestIds.preferredMethodSettingsOption,\n testIdPrefix,\n )}-${option.key}`;\n return (\n <TouchableOpacity\n key={option.key}\n // Explicit `aria-checked`: react-native-web 0.21.2 ignores\n // `accessibilityState`, so a screen reader on the web build could\n // not tell which preferred method was chosen — the distinction was\n // carried by button styling alone. Kept alongside for native.\n aria-checked={isSelected}\n accessibilityHint={labels.description}\n accessibilityLabel={option.label}\n accessibilityRole=\"radio\"\n accessibilityState={{ selected: isSelected }}\n disabled={saving}\n style={isSelected ? styles.secondaryButton : styles.escapeLink}\n testID={optionTestId}\n onPress={(): void => select(option.value)}\n >\n <Text style={isSelected ? styles.secondaryButtonText : styles.linkText}>\n {isSelected ? `✓ ${option.label}` : option.label}\n </Text>\n </TouchableOpacity>\n );\n })\n )}\n\n {saving ? <Text style={styles.helperText}>{labels.saving}</Text> : null}\n\n {failed ? (\n <Text\n style={styles.errorText}\n testID={withTestIdPrefix(AuthTestIds.preferredMethodSettingsError, testIdPrefix)}\n >\n {labels.saveFailed}\n </Text>\n ) : null}\n </View>\n );\n}\n","/**\n * The localizable failure states the authenticated \"Change password\" form can\n * show. Client-side validation states never hit the network; the rest map from\n * the BFF's `POST /bff/account/change-password` response.\n */\nexport const enum ChangePasswordErrorKey {\n /** New password is empty / fails the shared password policy (no network call). */\n WeakNewPassword = 'weak_new_password',\n /** New password and its confirmation do not match (no network call). */\n Mismatch = 'mismatch',\n /** Current password field was left blank (no network call). */\n CurrentRequired = 'current_required',\n /** BFF 400 — the current password is wrong, or the new one was rejected server-side. */\n InvalidCurrent = 'invalid_current',\n /** BFF 401 — the session is not (or no longer) authenticated. */\n Unauthorized = 'unauthorized',\n /** Any other failure (network / unexpected). */\n Failed = 'failed',\n}\n","/**\n * The react-query-FREE state machine behind the authenticated \"Change password\"\n * form. Owns the three field values, runs client-side validation, submits to the\n * BFF via a {@link ChangePasswordCapableClient}, and exposes a discriminated\n * error key so the form shows the precise cause — all without rendering, so the\n * logic is unit-tested directly (plain `useState` + `.then()/.catch()/.finally()`,\n * never `useMutation`; mirrors `useDevicePinDisable`).\n *\n * Client-side gates (no network round-trip): current password non-empty, new ===\n * confirm, and the new password satisfies the shared {@link isPasswordValid}\n * policy (mirrors the backend). Only after those pass does it call the BFF.\n */\nimport { useCallback, useState } from 'react';\n\nimport { ChangePasswordErrorKey } from './ChangePasswordErrorKey';\nimport type { ChangePasswordCapableClient } from './changePasswordClient';\nimport { isPasswordValid } from './passwordPolicy';\n\nexport interface UseChangePasswordArgs {\n /** The client exposing `changePassword`. */\n client: ChangePasswordCapableClient;\n /** Called once after a successful change (the form has been cleared by then). */\n onChanged?: () => void;\n}\n\nexport interface UseChangePasswordResult {\n currentPassword: string;\n newPassword: string;\n confirmPassword: string;\n setCurrentPassword: (value: string) => void;\n setNewPassword: (value: string) => void;\n setConfirmPassword: (value: string) => void;\n /** `true` while a BFF submit is in flight. */\n submitting: boolean;\n /** `true` after a successful change (until `reset` / a field edit). */\n succeeded: boolean;\n /** The current failure cause, or `null` when there is none. */\n errorKey: ChangePasswordErrorKey | null;\n /** Validate then submit. A validation failure sets `errorKey` and skips the network call. */\n submit: () => void;\n /** Clear every field + status back to a blank form. */\n reset: () => void;\n}\n\n/** Map a resolved {@link ChangePasswordResult} status to its form error key. */\nfunction errorKeyForStatus(status: 'invalidCurrent' | 'unauthorized' | 'error'): ChangePasswordErrorKey {\n if (status === 'invalidCurrent') {\n return ChangePasswordErrorKey.InvalidCurrent;\n }\n if (status === 'unauthorized') {\n return ChangePasswordErrorKey.Unauthorized;\n }\n return ChangePasswordErrorKey.Failed;\n}\n\nexport function useChangePassword({\n client,\n onChanged,\n}: UseChangePasswordArgs): UseChangePasswordResult {\n const [currentPassword, setCurrentValue] = useState<string>('');\n const [newPassword, setNewValue] = useState<string>('');\n const [confirmPassword, setConfirmValue] = useState<string>('');\n const [submitting, setSubmitting] = useState<boolean>(false);\n const [succeeded, setSucceeded] = useState<boolean>(false);\n const [errorKey, setErrorKey] = useState<ChangePasswordErrorKey | null>(null);\n\n // Editing any field clears a stale error / success banner.\n const clearStatus = useCallback((): void => {\n setErrorKey(null);\n setSucceeded(false);\n }, []);\n\n const setCurrentPassword = useCallback((value: string): void => {\n setCurrentValue(value);\n clearStatus();\n }, [clearStatus]);\n const setNewPassword = useCallback((value: string): void => {\n setNewValue(value);\n clearStatus();\n }, [clearStatus]);\n const setConfirmPassword = useCallback((value: string): void => {\n setConfirmValue(value);\n clearStatus();\n }, [clearStatus]);\n\n const reset = useCallback((): void => {\n setCurrentValue('');\n setNewValue('');\n setConfirmValue('');\n setSubmitting(false);\n setSucceeded(false);\n setErrorKey(null);\n }, []);\n\n const submit = useCallback((): void => {\n if (currentPassword === '') {\n setErrorKey(ChangePasswordErrorKey.CurrentRequired);\n return;\n }\n if (newPassword !== confirmPassword) {\n setErrorKey(ChangePasswordErrorKey.Mismatch);\n return;\n }\n if (!isPasswordValid(newPassword)) {\n setErrorKey(ChangePasswordErrorKey.WeakNewPassword);\n return;\n }\n\n setErrorKey(null);\n setSucceeded(false);\n setSubmitting(true);\n client\n .changePassword({ currentPassword, newPassword })\n .then((result) => {\n if (result.status === 'success') {\n setCurrentValue('');\n setNewValue('');\n setConfirmValue('');\n setSucceeded(true);\n onChanged?.();\n return;\n }\n setErrorKey(errorKeyForStatus(result.status));\n })\n .catch(() => {\n setErrorKey(ChangePasswordErrorKey.Failed);\n })\n .finally(() => {\n setSubmitting(false);\n });\n }, [client, currentPassword, newPassword, confirmPassword, onChanged]);\n\n return {\n currentPassword,\n newPassword,\n confirmPassword,\n setCurrentPassword,\n setNewPassword,\n setConfirmPassword,\n submitting,\n succeeded,\n errorKey,\n submit,\n reset,\n };\n}\n","/**\n * ChangePasswordCard — an authenticated, in-app \"Change password\" form.\n *\n * The signed-in user types their OWN current + new password in their OWN app;\n * that is a legitimate first-class feature (no Keycloak-console detour). The card\n * is purely presentational: all state, validation and submission live in\n * {@link useChangePassword}, which posts to `POST /bff/account/change-password`\n * through a {@link ChangePasswordCapableClient}. This package never stores, logs\n * or inspects the password values — it forwards them to the app's own BFF over\n * the session cookie and reads back only a status.\n *\n * Theme-driven and react-query-free, mirroring `DevicePinSettingsCard` /\n * `ResetPasswordForm`.\n */\nimport { useMemo, type ReactElement } from 'react';\n\nimport { ActivityIndicator, Text, TextInput, TouchableOpacity, View } from 'react-native';\n\nimport { DEFAULT_ACCOUNT_SETTINGS_LABELS, type AccountSettingsLabels } from './labels';\nimport { AuthTestIds, withTestIdPrefix } from './testIds';\nimport { useAuthStyles } from './useAuthStyles';\nimport { ChangePasswordErrorKey } from '../password/ChangePasswordErrorKey';\nimport type { ChangePasswordCapableClient } from '../password/changePasswordClient';\nimport { useChangePassword } from '../password/useChangePassword';\nimport { useAuthTheme } from '../theme/AuthThemeProvider';\n\nimport type { AuthTheme } from '../theme/AuthTheme';\n\nexport interface ChangePasswordCardProps {\n /** The client exposing `changePassword` (see `createBffChangePasswordClient`). */\n client: ChangePasswordCapableClient;\n /** Explicit theme; overrides any `<AuthThemeProvider>`. */\n theme?: AuthTheme;\n /** Localised copy. Partial — unspecified keys fall back to English defaults. */\n labels?: Partial<AccountSettingsLabels>;\n /** Prefix applied to every `testID`. */\n testIdPrefix?: string;\n /** Called once after a successful password change. */\n onChanged?: () => void;\n}\n\n/** Resolve the localized message for the current error key (`null` → no banner). */\nfunction errorMessage(errorKey: ChangePasswordErrorKey | null, labels: AccountSettingsLabels): string | null {\n switch (errorKey) {\n case ChangePasswordErrorKey.WeakNewPassword:\n return labels.errorWeakNewPassword;\n case ChangePasswordErrorKey.Mismatch:\n return labels.errorMismatch;\n case ChangePasswordErrorKey.CurrentRequired:\n return labels.errorCurrentRequired;\n case ChangePasswordErrorKey.InvalidCurrent:\n return labels.errorInvalidCurrent;\n case ChangePasswordErrorKey.Unauthorized:\n return labels.errorUnauthorized;\n case ChangePasswordErrorKey.Failed:\n return labels.errorFailed;\n default:\n return null;\n }\n}\n\n/** Themeable authenticated change-password form. */\nexport function ChangePasswordCard({\n client,\n theme: themeProp,\n labels: labelsProp,\n testIdPrefix,\n onChanged,\n}: Readonly<ChangePasswordCardProps>): ReactElement {\n const theme = useAuthTheme(themeProp);\n const styles = useAuthStyles(theme);\n const labels = useMemo<AccountSettingsLabels>(\n () => ({ ...DEFAULT_ACCOUNT_SETTINGS_LABELS, ...labelsProp }),\n [labelsProp],\n );\n const form = useChangePassword({ client, onChanged });\n const message = errorMessage(form.errorKey, labels);\n\n return (\n <View\n style={styles.card}\n testID={withTestIdPrefix(AuthTestIds.accountSettingsChangePassword, testIdPrefix)}\n >\n <Text style={styles.title}>{labels.changePasswordTitle}</Text>\n <Text style={styles.subtitle}>{labels.changePasswordDescription}</Text>\n\n <View style={styles.fieldGroup}>\n <Text style={styles.label}>{labels.currentPasswordLabel}</Text>\n <TextInput\n accessibilityLabel={labels.currentPasswordLabel}\n autoComplete=\"current-password\"\n placeholder={labels.currentPasswordPlaceholder}\n placeholderTextColor={theme.colors.textSecondary}\n secureTextEntry\n style={styles.input}\n testID={withTestIdPrefix(AuthTestIds.changePasswordCurrentInput, testIdPrefix)}\n value={form.currentPassword}\n onChangeText={form.setCurrentPassword}\n />\n </View>\n\n <View style={styles.fieldGroup}>\n <Text style={styles.label}>{labels.newPasswordLabel}</Text>\n <TextInput\n accessibilityLabel={labels.newPasswordLabel}\n autoComplete=\"new-password\"\n placeholder={labels.newPasswordPlaceholder}\n placeholderTextColor={theme.colors.textSecondary}\n secureTextEntry\n style={styles.input}\n testID={withTestIdPrefix(AuthTestIds.changePasswordNewInput, testIdPrefix)}\n value={form.newPassword}\n onChangeText={form.setNewPassword}\n />\n </View>\n\n <View style={styles.fieldGroup}>\n <Text style={styles.label}>{labels.confirmPasswordLabel}</Text>\n <TextInput\n accessibilityLabel={labels.confirmPasswordLabel}\n autoComplete=\"new-password\"\n placeholder={labels.confirmPasswordPlaceholder}\n placeholderTextColor={theme.colors.textSecondary}\n secureTextEntry\n style={styles.input}\n testID={withTestIdPrefix(AuthTestIds.changePasswordConfirmInput, testIdPrefix)}\n value={form.confirmPassword}\n onChangeText={form.setConfirmPassword}\n />\n </View>\n\n {message !== null ? (\n <Text\n style={styles.errorText}\n testID={withTestIdPrefix(AuthTestIds.changePasswordError, testIdPrefix)}\n >\n {message}\n </Text>\n ) : null}\n\n {form.succeeded ? (\n <Text\n style={styles.successText}\n testID={withTestIdPrefix(AuthTestIds.changePasswordSuccess, testIdPrefix)}\n >\n {labels.success}\n </Text>\n ) : null}\n\n <TouchableOpacity\n accessibilityHint={labels.submitHint}\n accessibilityLabel={form.submitting ? labels.submitting : labels.submit}\n accessibilityRole=\"button\"\n disabled={form.submitting}\n style={form.submitting ? [styles.primaryButton, styles.primaryButtonDisabled] : styles.primaryButton}\n testID={withTestIdPrefix(AuthTestIds.changePasswordSubmit, testIdPrefix)}\n onPress={form.submit}\n >\n {form.submitting ? (\n <ActivityIndicator color={theme.colors.onPrimary} size=\"small\" />\n ) : (\n <Text style={styles.primaryButtonText}>{labels.submit}</Text>\n )}\n </TouchableOpacity>\n </View>\n );\n}\n","/**\n * AccountSettingsScreen — the shared, composable authenticated account surface\n * every dloizides portal can mount to give a signed-in user one place to manage\n * their account. Self-contained and theme-driven: it stacks a set of independent,\n * individually-themed cards, each rendered only when its config is supplied.\n *\n * - **Change password** (always) — the in-app `<ChangePasswordCard>` form\n * (`POST /bff/account/change-password`). No password value is handled by this\n * package beyond forwarding it to the app's own BFF.\n * - **Device PIN** (optional) — the existing `<DevicePinSettingsCard>`, so every\n * portal gets quick-PIN enable/disable for free.\n * - **Passkeys** (optional) — the existing `<PasskeySettingsCard>`.\n * - **Preferred sign-in method** (optional) — the existing\n * `<PreferredMethodSettingsCard>`.\n *\n * Purely presentational assembly: each card owns its own behaviour + hooks (all\n * react-query-free). The screen only threads the shared `theme` / `testIdPrefix`\n * down and lays the cards out in a scrollable, centered column.\n */\nimport { useMemo, type ReactElement } from 'react';\n\nimport { ScrollView, StyleSheet, Text, View } from 'react-native';\n\nimport { ChangePasswordCard } from './ChangePasswordCard';\nimport { DevicePinSettingsCard } from './DevicePinSettingsCard';\nimport { DEFAULT_ACCOUNT_SETTINGS_LABELS, type AccountSettingsLabels } from './labels';\nimport type {\n DevicePinEnrollLabels,\n DevicePinSettingsLabels,\n PasskeySettingsLabels,\n PreferredMethodSettingsLabels,\n} from './labels';\nimport { PasskeySettingsCard } from './PasskeySettingsCard';\nimport { PreferredMethodSettingsCard } from './PreferredMethodSettingsCard';\nimport { AuthTestIds, withTestIdPrefix } from './testIds';\nimport { useAuthStyles } from './useAuthStyles';\nimport type { ChangePasswordCapableClient } from '../password/changePasswordClient';\nimport type { PreferredMethodClient } from '../preferences/preferencesClient';\nimport { useAuthTheme } from '../theme/AuthThemeProvider';\n\nimport type {\n DevicePinDisableCapableClient,\n DevicePinEnrollCapableClient,\n} from '../devicePin/types';\nimport type { AuthTheme } from '../theme/AuthTheme';\n\n/** Device-PIN section config — mirrors `DevicePinSettingsCard` (theme/testIdPrefix threaded by the screen). */\nexport interface AccountSettingsDevicePinConfig {\n client: DevicePinEnrollCapableClient & DevicePinDisableCapableClient;\n initialHasPin: boolean;\n labels?: Partial<DevicePinSettingsLabels>;\n enrollLabels?: Partial<DevicePinEnrollLabels>;\n onChanged?: (hasPin: boolean) => void;\n}\n\n/** Passkeys section config — mirrors `PasskeySettingsCard`. */\nexport interface AccountSettingsPasskeysConfig {\n returnUrl?: string;\n labels?: Partial<PasskeySettingsLabels>;\n}\n\n/** Preferred-method section config — mirrors `PreferredMethodSettingsCard`. */\nexport interface AccountSettingsPreferredMethodConfig {\n client: PreferredMethodClient;\n availableMethods: readonly string[];\n labels?: Partial<PreferredMethodSettingsLabels>;\n onChanged?: (method: string | null) => void;\n}\n\n/** Change-password section config. */\nexport interface AccountSettingsChangePasswordConfig {\n client: ChangePasswordCapableClient;\n onChanged?: () => void;\n}\n\nexport interface AccountSettingsScreenProps {\n /** Change-password form config (always rendered). */\n changePassword: AccountSettingsChangePasswordConfig;\n /** Device-PIN card config. Omit to hide the section. */\n devicePin?: AccountSettingsDevicePinConfig;\n /** Passkeys card config. Omit to hide the section. */\n passkeys?: AccountSettingsPasskeysConfig;\n /** Preferred-method card config. Omit to hide the section. */\n preferredMethod?: AccountSettingsPreferredMethodConfig;\n /** Explicit theme; overrides any `<AuthThemeProvider>`. Threaded to every card. */\n theme?: AuthTheme;\n /** Screen + change-password copy (partial; unspecified keys fall back to English). */\n labels?: Partial<AccountSettingsLabels>;\n /** Prefix applied to every `testID`, on the screen and every card. */\n testIdPrefix?: string;\n}\n\nconst GAP = 16;\n\nconst layout = StyleSheet.create({\n content: {\n width: '100%',\n alignItems: 'center',\n rowGap: GAP,\n },\n});\n\n/** The shared authenticated account-management surface. */\nexport function AccountSettingsScreen({\n changePassword,\n devicePin,\n passkeys,\n preferredMethod,\n theme: themeProp,\n labels: labelsProp,\n testIdPrefix,\n}: Readonly<AccountSettingsScreenProps>): ReactElement {\n const theme = useAuthTheme(themeProp);\n const styles = useAuthStyles(theme);\n const labels = useMemo<AccountSettingsLabels>(\n () => ({ ...DEFAULT_ACCOUNT_SETTINGS_LABELS, ...labelsProp }),\n [labelsProp],\n );\n\n return (\n <ScrollView\n contentContainerStyle={styles.screen}\n testID={withTestIdPrefix(AuthTestIds.accountSettings, testIdPrefix)}\n >\n <View style={layout.content}>\n <Text style={styles.title}>{labels.heading}</Text>\n\n <ChangePasswordCard\n client={changePassword.client}\n labels={labelsProp}\n testIdPrefix={testIdPrefix}\n theme={theme}\n onChanged={changePassword.onChanged}\n />\n\n {devicePin !== undefined ? (\n <DevicePinSettingsCard\n client={devicePin.client}\n enrollLabels={devicePin.enrollLabels}\n initialHasPin={devicePin.initialHasPin}\n labels={devicePin.labels}\n testIdPrefix={testIdPrefix}\n theme={theme}\n onChanged={devicePin.onChanged}\n />\n ) : null}\n\n {passkeys !== undefined ? (\n <PasskeySettingsCard\n labels={passkeys.labels}\n returnUrl={passkeys.returnUrl}\n testIdPrefix={testIdPrefix}\n theme={theme}\n />\n ) : null}\n\n {preferredMethod !== undefined ? (\n <PreferredMethodSettingsCard\n availableMethods={preferredMethod.availableMethods}\n client={preferredMethod.client}\n labels={preferredMethod.labels}\n testIdPrefix={testIdPrefix}\n theme={theme}\n onChanged={preferredMethod.onChanged}\n />\n ) : null}\n </View>\n </ScrollView>\n );\n}\n","/**\n * The login-screen \"you usually sign in with…\" hint (unified-login D5).\n *\n * Mount at the top of the login surface. Given the device-local cached\n * preferred method (`readCachedPreferredMethod()`), it renders a single\n * reassurance line naming that method. Renders NOTHING for an unknown / absent\n * method so the login screen stays clean for first-time visitors.\n *\n * No network, no state — pure presentation driven by the cached value the host\n * passes in. (The cache is seeded post-login by `syncPreferredMethodFromServer`.)\n */\nimport { useMemo, type ReactElement } from 'react';\n\nimport { Text, View } from 'react-native';\n\nimport {\n DEFAULT_PREFERRED_METHOD_HINT_LABELS,\n type PreferredMethodHintLabels,\n} from './labels';\nimport { AuthTestIds, withTestIdPrefix } from './testIds';\nimport { useAuthStyles } from './useAuthStyles';\nimport { useAuthTheme } from '../theme/AuthThemeProvider';\n\nimport type { AuthTheme } from '../theme/AuthTheme';\n\nexport interface PreferredMethodHintProps {\n /**\n * The cached preferred method (`'password'` | `'pin'` | `'passkey'`), or\n * `null`. Typically `readCachedPreferredMethod()`. An unknown / `null` value\n * renders nothing.\n */\n method: string | null;\n /** Explicit theme; overrides any `<AuthThemeProvider>`. */\n theme?: AuthTheme;\n /** Localised copy. Partial — unspecified keys fall back to English defaults. */\n labels?: Partial<PreferredMethodHintLabels>;\n /** Prefix applied to the `testID`. */\n testIdPrefix?: string;\n}\n\n/** Pick the full hint sentence for a known method, else `null`. */\nfunction hintFor(method: string | null, labels: PreferredMethodHintLabels): string | null {\n if (method === 'password') {\n return labels.password;\n }\n if (method === 'pin') {\n return labels.pin;\n }\n if (method === 'passkey') {\n return labels.passkey;\n }\n return null;\n}\n\n/** Themeable login-screen preferred-method hint. Renders `null` when there is nothing to say. */\nexport function PreferredMethodHint({\n method,\n theme: themeProp,\n labels: labelsProp,\n testIdPrefix,\n}: Readonly<PreferredMethodHintProps>): ReactElement | null {\n const theme = useAuthTheme(themeProp);\n const styles = useAuthStyles(theme);\n const labels = useMemo<PreferredMethodHintLabels>(\n () => ({ ...DEFAULT_PREFERRED_METHOD_HINT_LABELS, ...labelsProp }),\n [labelsProp],\n );\n\n const text = hintFor(method, labels);\n if (text === null) {\n return null;\n }\n\n return (\n <View testID={withTestIdPrefix(AuthTestIds.preferredMethodHint, testIdPrefix)}>\n <Text style={styles.helperText}>{text}</Text>\n </View>\n );\n}\n","/**\n * `<DemoCredentialsBody>` — the credential rows plus the optional fill button.\n *\n * Extracted from `<DemoCredentialsHint>` so the two variants (`Panel`,\n * `Disclosure`) share ONE rendering of the credentials themselves and differ\n * only in the chrome wrapped around them. Without this split the disclosure\n * variant would have grown a second copy of the rows, and the next change to a\n * `testID` or an accessibility hint would have had to be made twice — with\n * nothing failing if it was only made once.\n *\n * Not exported from the package: it is an implementation detail of the hint.\n */\nimport { type ReactElement } from 'react';\n\nimport { Text, TouchableOpacity, View } from 'react-native';\n\nimport { AuthTestIds, withTestIdPrefix } from './testIds';\n\nimport type { DemoCredentialsHintLabels } from './labels';\nimport type { DemoCredentialsStyles } from './useDemoCredentialsStyles';\nimport type { AuthStyles } from './useAuthStyles';\nimport type { DemoCredentials } from '../demo/types';\n\n/** Props for {@link DemoCredentialsBody}. */\nexport interface DemoCredentialsBodyProps {\n /** The already-resolved (trimmed, validated) demo pair. */\n credentials: DemoCredentials;\n /** Resolved copy — fully populated by the caller, never partial. */\n labels: DemoCredentialsHintLabels;\n /** The demo panel's styles, built from the resolved theme. */\n styles: DemoCredentialsStyles;\n /** Shared auth styles, for the secondary-button treatment. */\n authStyles: AuthStyles;\n /** `testID` prefix, applied to every element. */\n testIdPrefix?: string;\n /**\n * A per-account heading (e.g. \"Master\"). Rendered ONLY when it is a non-empty\n * string — the single-account case passes nothing, so the rows are byte-for-byte\n * what they were before multi-account existed. Multiple accounts each pass their\n * own label so a visitor can tell them apart.\n */\n accountLabel?: string;\n /**\n * A per-account index suffixed onto every `testID` (e.g. `-username-0`) so N\n * accounts each get unique selectors. Omit for the single-account case to keep\n * the original, unsuffixed testIDs — no test or E2E regression.\n */\n testIdIndex?: number;\n /** Omit to render read-only — the values stay selectable for manual copying. */\n onUse?: () => void;\n}\n\n/** The username/password rows and the \"use these credentials\" action. */\nexport function DemoCredentialsBody({\n credentials,\n labels,\n styles,\n authStyles,\n testIdPrefix,\n accountLabel,\n testIdIndex,\n onUse,\n}: Readonly<DemoCredentialsBodyProps>): ReactElement {\n // Suffix the base testID with the account index only when one is given, then\n // apply the prefix — so `zygos` + `username` + index 1 → `zygos-...-username-1`,\n // and a single account (no index) stays `zygos-...-username`.\n const testId = (base: string): string =>\n withTestIdPrefix(testIdIndex === undefined ? base : `${base}-${testIdIndex}`, testIdPrefix);\n\n const hasLabel = typeof accountLabel === 'string' && accountLabel.length > 0;\n\n return (\n <View>\n {hasLabel ? (\n <Text\n style={styles.accountLabel}\n testID={testId(AuthTestIds.demoCredentialsAccountLabel)}\n >\n {accountLabel}\n </Text>\n ) : null}\n\n <View style={styles.row}>\n <Text style={styles.rowLabel}>{labels.usernameLabel}</Text>\n <Text\n selectable\n style={styles.rowValue}\n testID={testId(AuthTestIds.demoCredentialsUsername)}\n >\n {credentials.username}\n </Text>\n </View>\n\n <View style={styles.row}>\n <Text style={styles.rowLabel}>{labels.passwordLabel}</Text>\n <Text\n selectable\n style={styles.rowValue}\n testID={testId(AuthTestIds.demoCredentialsPassword)}\n >\n {credentials.password}\n </Text>\n </View>\n\n {onUse !== undefined ? (\n <TouchableOpacity\n accessibilityHint={labels.useCredentialsHint}\n accessibilityLabel={labels.useCredentials}\n accessibilityRole=\"button\"\n style={[authStyles.secondaryButton, styles.useButton]}\n testID={testId(AuthTestIds.demoCredentialsUseButton)}\n onPress={onUse}\n >\n <Text style={authStyles.secondaryButtonText}>{labels.useCredentials}</Text>\n </TouchableOpacity>\n ) : null}\n </View>\n );\n}\n","/**\n * How `<DemoCredentialsHint>` presents itself on the login surface.\n *\n * The two variants answer opposite questions, and the choice is a product\n * decision rather than a styling one:\n *\n * - `Panel` assumes the page exists FOR the demo — a sales/marketing console\n * where every visitor is an evaluator. It advertises loudly.\n * - `Disclosure` assumes the page is a real customer's front door that ALSO\n * happens to offer a demo. Real account holders outnumber evaluators, so the\n * demo collapses behind one quiet line of text and costs them nothing.\n *\n * `Disclosure` is the default because the second case is the common one across\n * the estate: every product login screen is a page paying customers use daily.\n *\n * ⚠️ \"Discreet\" is achieved with SIZE, WEIGHT and POSITION — never by lowering\n * contrast. Both variants draw their text from `colors.textSecondary`, a token\n * every app already holds to the WCAG AA 4.5:1 floor. Dimming this further with\n * opacity would trade an accessibility guarantee for a visual preference; if a\n * consuming app's `textSecondary` fails AA, that is the app's token to fix.\n */\nexport const enum DemoCredentialsHintVariant {\n /** Always-open inset panel with a brand rail. The original presentation. */\n Panel = 'panel',\n /** One quiet \"try the demo\" line that expands the credentials on tap. */\n Disclosure = 'disclosure',\n}\n","/**\n * `useDemoCredentialsStyles` — the StyleSheet for `<DemoCredentialsHint>`.\n *\n * Kept out of `useAuthStyles` (which styles the form *fields*) because the demo\n * panel is its own surface, exactly as `<AuthScreen>`'s card chrome is.\n *\n * The visual idea, in tokens only — this panel is the first thing a prospective\n * client sees, so it has to read as a deliberate part of the product rather than\n * a debug notice:\n *\n * - **Inset, not alarming.** The panel fills with `colors.background` while\n * sitting on the card's `colors.surface`, so it reads as a recess in the card.\n * That is the same figure/ground relationship the inputs already use\n * (`useAuthStyles.input` is a `background` fill on the same card) — the panel\n * belongs to the form rather than interrupting it. No warning yellow, no\n * dedicated \"notice\" colour: the palette stays the app's own.\n * - **One brand accent.** A hairline rail in `colors.primary` down the leading\n * edge, plus the eyebrow heading in the same token, ties the panel to the\n * brand and gives it a deliberate reading order — and it is the ONLY saturated\n * element, so the panel never competes with the real \"Sign in\" button.\n * - **Credentials as chips.** Each value returns to `colors.surface` inside the\n * recess, so it lifts off the panel and reads as a discrete, copyable token.\n * Monospace, because the audience for a published demo password includes\n * people who will retype it and must not confuse `l`/`1` or `O`/`0`.\n */\nimport { useMemo } from 'react';\n\nimport { Platform, StyleSheet, type TextStyle, type ViewStyle } from 'react-native';\n\nimport type { AuthTheme } from '../theme/AuthTheme';\n\n/** The named styles `<DemoCredentialsHint>` draws from. */\nexport interface DemoCredentialsStyles {\n /** The inset panel surface. */\n panel: ViewStyle;\n /** Small brand-coloured eyebrow heading. */\n title: TextStyle;\n /** Explanatory copy under the heading. */\n description: TextStyle;\n /** A per-account heading (multi-account only), e.g. \"Master\". */\n accountLabel: TextStyle;\n /** A label/value credential row. */\n row: ViewStyle;\n /** The leading label in a credential row. */\n rowLabel: TextStyle;\n /** The trailing monospace value chip in a credential row. */\n rowValue: TextStyle;\n /** Outer wrapper for the `Disclosure` variant. */\n disclosure: ViewStyle;\n /** The collapsed \"try the demo\" trigger's touch target. */\n disclosureTrigger: ViewStyle;\n /** The trigger's label. */\n disclosureTriggerText: TextStyle;\n /** The expanded credentials, indented under the trigger. */\n disclosureBody: ViewStyle;\n /** Spacing correction for the fill button inside the body. */\n useButton: ViewStyle;\n}\n\nconst PANEL_BORDER_WIDTH = 1;\n/**\n * Minimum touch-target height for the disclosure trigger, in dp.\n *\n * The trigger is deliberately small *type* — that is what makes it discreet —\n * but a small hit area is a usability defect, not a design choice. WCAG 2.2\n * 2.5.8 sets 24×24 as the floor; this pads the one-line label out to a\n * comfortable target so \"quiet\" never becomes \"hard to tap\".\n */\nconst TRIGGER_MIN_HEIGHT = 32;\n/** Width of the brand rail down the panel's leading edge. */\nconst ACCENT_RAIL_WIDTH = 3;\n/** Tracking on the small uppercase eyebrow heading — it needs air to stay legible. */\nconst TITLE_LETTER_SPACING = 0.8;\n/** Comfortable reading leading for the description copy. */\nconst DESCRIPTION_LINE_HEIGHT_RATIO = 1.45;\n/** Halves a spacing token for the tight insets inside a value chip. */\nconst HALF = 2;\n\n/**\n * The platform's monospace face. RN has no cross-platform monospace token:\n * `'monospace'` resolves on Android and web, but on iOS it silently falls back\n * to the system face, so iOS names Menlo explicitly.\n */\nconst MONOSPACE_FONT = Platform.select({\n ios: 'Menlo',\n android: 'monospace',\n default: 'monospace',\n});\n\n/** Build the demo-panel `StyleSheet` from the resolved theme. */\nexport function useDemoCredentialsStyles(theme: AuthTheme): DemoCredentialsStyles {\n return useMemo(() => {\n const { colors, radii, spacing, typography } = theme;\n return StyleSheet.create<DemoCredentialsStyles>({\n panel: {\n borderWidth: PANEL_BORDER_WIDTH,\n borderLeftWidth: ACCENT_RAIL_WIDTH,\n borderRadius: radii.card,\n borderColor: colors.border,\n borderLeftColor: colors.primary,\n padding: spacing.md,\n marginBottom: spacing.md,\n backgroundColor: colors.background,\n },\n title: {\n fontSize: typography.caption,\n fontWeight: '700',\n letterSpacing: TITLE_LETTER_SPACING,\n textTransform: 'uppercase',\n color: colors.primary,\n },\n description: {\n fontSize: typography.caption,\n lineHeight: typography.caption * DESCRIPTION_LINE_HEIGHT_RATIO,\n marginTop: spacing.xs / HALF,\n marginBottom: spacing.sm,\n color: colors.textSecondary,\n },\n accountLabel: {\n fontSize: typography.caption,\n fontWeight: '700',\n color: colors.text,\n // Separates one account block from the previous one; the first block sits\n // under the panel description / disclosure divider, which already spaces it.\n marginTop: spacing.sm,\n marginBottom: spacing.xs / HALF,\n },\n row: {\n flexDirection: 'row',\n alignItems: 'center',\n justifyContent: 'space-between',\n marginTop: spacing.xs / HALF,\n },\n rowLabel: {\n fontSize: typography.caption,\n color: colors.textSecondary,\n },\n rowValue: {\n fontFamily: MONOSPACE_FONT,\n fontSize: typography.caption,\n fontWeight: '600',\n borderWidth: PANEL_BORDER_WIDTH,\n borderRadius: radii.input,\n borderColor: colors.border,\n paddingVertical: spacing.xs / HALF,\n paddingHorizontal: spacing.xs,\n // Never let a long password squeeze the label off the row.\n flexShrink: 1,\n backgroundColor: colors.surface,\n color: colors.text,\n },\n\n // ── Disclosure variant ──────────────────────────────────────────────\n // No panel fill, no border, no brand rail: the collapsed state is one\n // line of text and nothing else, so on a page a real customer uses it\n // reads as a footnote rather than as a second call to action.\n disclosure: {\n marginTop: spacing.md,\n alignSelf: 'stretch',\n },\n disclosureTrigger: {\n alignSelf: 'center',\n justifyContent: 'center',\n minHeight: TRIGGER_MIN_HEIGHT,\n paddingHorizontal: spacing.xs,\n },\n disclosureTriggerText: {\n fontSize: typography.caption,\n textDecorationLine: 'underline',\n // `textSecondary`, NOT a dimmed `text`. This is the same token the rest\n // of the helper copy uses, so it inherits whatever AA contrast the\n // consuming app already guarantees. Discretion here is carried by the\n // caption size, the centred placement below the form, and the absence\n // of any fill or border — never by fading the text toward the\n // background, which is how \"discreet\" quietly becomes a contrast bug.\n color: colors.textSecondary,\n },\n disclosureBody: {\n marginTop: spacing.sm,\n paddingTop: spacing.sm,\n borderTopWidth: PANEL_BORDER_WIDTH,\n borderTopColor: colors.border,\n },\n useButton: {\n alignSelf: 'stretch',\n },\n });\n }, [theme]);\n}\n","/**\n * `resolveDemoCredentials` — the single fail-closed gate for the demo surface.\n *\n * Every demo affordance in the package (the `<DemoCredentialsHint>` panel and\n * the `useDemoCredentials` wiring hook) routes its input through this function,\n * so \"should we advertise a demo account at all?\" is decided in exactly ONE\n * place and always the same way.\n *\n * Fail closed, deliberately. The realistic source of these values is an env var\n * (`process.env.EXPO_PUBLIC_DEMO_USERNAME`), which is `string | undefined` at\n * runtime no matter what the type says — a consumer writing `username: env.X!`\n * hands us `undefined` and TypeScript never notices. A half-configured demo must\n * render NOTHING rather than an empty panel inviting a client to sign in with\n * blank credentials, so anything that is not a genuinely non-empty string pair\n * resolves to `null`.\n */\nimport type { DemoCredentials } from './types';\n\n/**\n * Narrow an unvalidated demo-credential pair to a usable one, or `null`.\n *\n * Returns `null` for: `undefined` / `null`, a non-string field (runtime junk\n * from an unset env var), a blank/whitespace-only username, and an empty\n * password. Otherwise returns a NEW pair with the username trimmed.\n *\n * The password is deliberately NOT trimmed: leading/trailing whitespace can be\n * a legitimate part of a password, and silently altering it would turn a\n * working credential into a mystery login failure.\n */\nexport function resolveDemoCredentials(\n credentials?: DemoCredentials | null,\n): DemoCredentials | null {\n if (credentials === undefined || credentials === null) {\n return null;\n }\n\n const username =\n typeof credentials.username === 'string' ? credentials.username.trim() : '';\n const password = typeof credentials.password === 'string' ? credentials.password : '';\n\n const isUnusable = username.length === 0 || password.length === 0;\n if (isUnusable) {\n return null;\n }\n\n return { username, password };\n}\n","/**\n * `resolveDemoAccounts` — the fail-closed gate for the MULTI-account demo surface.\n *\n * The list counterpart of {@link resolveDemoCredentials}. Where that answers\n * \"is there a demo account?\" with one pair or `null`, this answers \"which demo\n * accounts should we advertise?\" with a (possibly empty) ARRAY. An empty array\n * means render nothing — exactly the `null` contract, expressed as a list.\n *\n * Two inputs collapse to the same output shape:\n *\n * - a `credentials.publishedAccounts` list (Bff.AspNetCore 1.17.0+) → each valid\n * entry, in order, labels preserved;\n * - a legacy single pair (`{ username, password }`, no `publishedAccounts`) →\n * wrapped into a ONE-item list with an empty label, so a single-account\n * deployment renders exactly as it did before this list existed.\n *\n * Every entry is validated through the same trim/non-empty discipline as the\n * single resolver, so a half-configured entry (blank username, `undefined` from\n * an unset value) is dropped rather than rendered as an empty row.\n */\nimport { resolveDemoCredentials } from './resolveDemoCredentials';\n\nimport type { DemoAccount, DemoCredentials } from './types';\n\n/**\n * Narrow one unvalidated account to a usable one, or `null`. Trims the username\n * and validates the pair exactly like {@link resolveDemoCredentials}; carries the\n * label through, defaulting a missing / non-string label to `''`.\n */\nfunction resolveAccount(account?: DemoAccount | null): DemoAccount | null {\n if (account === undefined || account === null) {\n return null;\n }\n const pair = resolveDemoCredentials(account);\n if (pair === null) {\n return null;\n }\n const label = typeof account.label === 'string' ? account.label : '';\n return { label, username: pair.username, password: pair.password };\n}\n\n/**\n * Validate a raw list of accounts, dropping any unusable entry. Used by the hint\n * when a consumer passes an `accounts` prop directly (the hook already routes its\n * list through here too, so validation happens in exactly one place).\n */\nexport function resolveAccountList(accounts?: readonly DemoAccount[] | null): DemoAccount[] {\n if (!Array.isArray(accounts)) {\n return [];\n }\n return accounts\n .map(resolveAccount)\n .filter((account): account is DemoAccount => account !== null);\n}\n\n/**\n * Resolve the ordered list of demo accounts to advertise, from either the new\n * `publishedAccounts` list or the legacy single pair. Returns `[]` when nothing\n * is usable — the \"render nothing\" contract, as a list.\n */\nexport function resolveDemoAccounts(\n credentials?: DemoCredentials | null,\n): DemoAccount[] {\n if (credentials === undefined || credentials === null) {\n return [];\n }\n\n const fromList = resolveAccountList(credentials.publishedAccounts);\n if (fromList.length > 0) {\n return fromList;\n }\n\n const single = resolveDemoCredentials(credentials);\n return single === null\n ? []\n : [{ label: '', username: single.username, password: single.password }];\n}\n","/**\n * `<DemoCredentialsHint>` — the public-demo credentials surface.\n *\n * Mount on the login surface of a product with an OPEN demo account whose\n * credentials are already published (typically on the marketing site). It shows\n * the username and password and offers a one-tap \"use these credentials\" action\n * that fills the form, so a non-technical evaluator never has to copy-paste a\n * password between two tabs to see the product.\n *\n * It authenticates nothing. It fills fields; `<LoginForm>` then submits them\n * down the ordinary path — same BFF, same Keycloak, same session, same roles.\n * There is no bypass here and no credential in this package: the host supplies\n * the pair, and the demo account's blast radius is whatever the IdP grants it.\n *\n * Fails closed: no credentials (or a half-configured pair) renders `null` — zero\n * DOM — so a misconfigured env var can never publish an empty demo panel.\n *\n * ## Two variants, and why the default changed in 1.13.0\n *\n * Originally this only rendered an always-open panel above the form. That is\n * right for a page whose whole purpose IS the demo, and wrong for the far more\n * common case: a login screen paying customers use every day, where an\n * unmissable \"here are some credentials\" block is noise at best and a trust\n * problem at worst.\n *\n * `DemoCredentialsHintVariant.Disclosure` — now the default — collapses the\n * whole thing to one quiet line (\"Try the demo\") that expands on tap. Pass\n * `variant={DemoCredentialsHintVariant.Panel}` to keep the original block.\n *\n * ⚠️ Two things this deliberately does NOT do to achieve discretion:\n *\n * - **It does not lower contrast.** The trigger uses `colors.textSecondary`,\n * the same AA-held token as every other piece of helper copy. Discretion is\n * carried by size, placement and the absence of chrome.\n * - **It does not hide from assistive tech.** The trigger is a real focusable\n * button carrying an explicit `aria-expanded` (plus `accessibilityState` for\n * native), so a screen reader announces both that it exists and whether it is\n * open. Visually quiet must not mean absent — a demo nobody can find is a demo\n * nobody uses.\n *\n * ⚠️ Through 1.13.0 this carried ONLY `accessibilityState={{ expanded }}` and\n * therefore announced nothing on web: react-native-web 0.21.2 does not read\n * `accessibilityState`, so the rendered button had no `aria-expanded` at all.\n * The old unit test asserted the React *prop*, so it passed against the bug.\n *\n * ## Layout stability\n *\n * The expanded body renders BELOW the trigger, and the component is designed to\n * sit BELOW `<LoginForm>` (see the zygos login route). Expanding therefore grows\n * the card downward and never displaces the username or password inputs the\n * visitor may already be interacting with. Mounting it ABOVE the form would make\n * every expansion shove the fields down the page — precisely the jarring\n * behaviour a disclosure exists to avoid.\n */\nimport { useCallback, useMemo, useState, type ReactElement } from 'react';\n\nimport { Text, TouchableOpacity, View } from 'react-native';\n\nimport { DemoCredentialsBody } from './DemoCredentialsBody';\nimport { DemoCredentialsHintVariant } from './DemoCredentialsHintVariant';\nimport {\n DEFAULT_DEMO_CREDENTIALS_HINT_LABELS,\n type DemoCredentialsHintLabels,\n} from './labels';\nimport { AuthTestIds, withTestIdPrefix } from './testIds';\nimport { useAuthStyles } from './useAuthStyles';\nimport { useDemoCredentialsStyles } from './useDemoCredentialsStyles';\nimport { resolveAccountList, resolveDemoAccounts } from '../demo/resolveDemoAccounts';\nimport { useAuthTheme } from '../theme/AuthThemeProvider';\n\nimport type { DemoAccount, DemoCredentials } from '../demo/types';\nimport type { AuthTheme } from '../theme/AuthTheme';\n\nexport interface DemoCredentialsHintProps {\n /**\n * The demo credentials to advertise. `undefined` — or a pair with a blank\n * username or password — renders nothing at all. When {@link accounts} is given\n * and non-empty it takes precedence; otherwise this single pair is resolved\n * (and, if it carries a `publishedAccounts` list, expanded) into the rows.\n */\n credentials?: DemoCredentials;\n /**\n * The resolved list of demo accounts to advertise, one labelled row per entry.\n * Preferred over {@link credentials} when present and non-empty. A single entry\n * renders exactly like the legacy single-pair panel (no per-account heading).\n * This is what `useDemoCredentials().hintProps` supplies.\n */\n accounts?: DemoAccount[];\n /**\n * Presentation. Defaults to `Disclosure` (one quiet expandable line); pass\n * `Panel` for the original always-open block.\n */\n variant?: DemoCredentialsHintVariant;\n /** Explicit theme; overrides any `<AuthThemeProvider>`. */\n theme?: AuthTheme;\n /** Localised copy. Partial — unspecified keys fall back to English defaults. */\n labels?: Partial<DemoCredentialsHintLabels>;\n /** Prefix applied to every `testID`. */\n testIdPrefix?: string;\n /**\n * Called with the resolved credentials when the user taps \"use these\n * credentials\". Omit to render read-only (no button) — the values are still\n * selectable, so a visitor can copy them by hand.\n */\n onUse?: (credentials: DemoCredentials) => void;\n}\n\n/** Themeable public-demo credentials surface. Renders `null` when there is no demo. */\nexport function DemoCredentialsHint({\n credentials,\n accounts,\n variant = DemoCredentialsHintVariant.Disclosure,\n theme: themeProp,\n labels: labelsProp,\n testIdPrefix,\n onUse,\n}: Readonly<DemoCredentialsHintProps>): ReactElement | null {\n const theme = useAuthTheme(themeProp);\n const authStyles = useAuthStyles(theme);\n const styles = useDemoCredentialsStyles(theme);\n const [expanded, setExpanded] = useState<boolean>(false);\n const labels = useMemo<DemoCredentialsHintLabels>(\n () => ({ ...DEFAULT_DEMO_CREDENTIALS_HINT_LABELS, ...labelsProp }),\n [labelsProp],\n );\n // Resolve to the ordered account list. An `accounts` prop (from the hook) wins;\n // otherwise resolve the single pair — which also fails closed standalone.\n // Memoised so the body / handlers are stable across renders.\n const resolvedAccounts = useMemo<DemoAccount[]>(\n () =>\n accounts !== undefined && accounts.length > 0\n ? resolveAccountList(accounts)\n : resolveDemoAccounts(credentials),\n [accounts, credentials],\n );\n\n // A factory of no-arg fill handlers, one per account, each closing over its own\n // pair. `undefined` when the caller wants read-only (no fill button).\n const makeUse = useCallback(\n (account: DemoAccount): (() => void) | undefined =>\n onUse === undefined\n ? undefined\n : (): void => onUse({ username: account.username, password: account.password }),\n [onUse],\n );\n\n const handleToggle = useCallback((): void => {\n setExpanded((current) => !current);\n }, []);\n\n if (resolvedAccounts.length === 0) {\n return null;\n }\n\n // One account renders exactly as before: no per-account heading, unsuffixed\n // testIDs. Multiple accounts each get their label as a heading and an index\n // suffixed onto every testID so N rows have unique selectors.\n const isSingle = resolvedAccounts.length === 1;\n const body = resolvedAccounts.map((account, index) => (\n <DemoCredentialsBody\n key={`${account.username}-${String(index)}`}\n accountLabel={isSingle ? undefined : account.label}\n authStyles={authStyles}\n credentials={{ username: account.username, password: account.password }}\n labels={labels}\n styles={styles}\n testIdIndex={isSingle ? undefined : index}\n testIdPrefix={testIdPrefix}\n onUse={makeUse(account)}\n />\n ));\n\n if (variant === DemoCredentialsHintVariant.Panel) {\n return (\n <View\n style={styles.panel}\n testID={withTestIdPrefix(AuthTestIds.demoCredentialsHint, testIdPrefix)}\n >\n <Text style={styles.title}>{labels.title}</Text>\n <Text style={styles.description}>{labels.description}</Text>\n {body}\n </View>\n );\n }\n\n return (\n <View\n style={styles.disclosure}\n testID={withTestIdPrefix(AuthTestIds.demoCredentialsHint, testIdPrefix)}\n >\n <TouchableOpacity\n // `aria-expanded` is passed EXPLICITLY and is the only reason a browser\n // announces the open/closed state. `accessibilityState` below is kept for\n // native, where it is the prop that works — but react-native-web 0.21.2\n // does not read it at all (measured: it emits `aria-label` and `role`, and\n // no `aria-expanded`). Guarded by DemoCredentialsHint.dom.test.tsx.\n aria-expanded={expanded}\n accessibilityHint={labels.toggleHint}\n accessibilityLabel={labels.toggle}\n accessibilityRole=\"button\"\n accessibilityState={{ expanded }}\n style={styles.disclosureTrigger}\n testID={withTestIdPrefix(AuthTestIds.demoCredentialsToggle, testIdPrefix)}\n onPress={handleToggle}\n >\n <Text style={styles.disclosureTriggerText}>{labels.toggle}</Text>\n </TouchableOpacity>\n\n {expanded ? <View style={styles.disclosureBody}>{body}</View> : null}\n </View>\n );\n}\n","/**\n * `useBffLoginConfig` — fetch the BFF login config once and expose it.\n *\n * The login surface only renders the methods the BFF actually has enabled, and\n * the device-PIN unlock gate only triggers when the per-device state says so.\n * Both come from `GET /bff/config`, which the supplied client reads and parses\n * (this hook is transport-agnostic — it delegates the fetch + parsing to the\n * client's `getLoginConfig`, mirroring kefi-web's `useBffConfig` shape).\n *\n * react-query-FREE by construction: plain `useState` + `useEffect`, never\n * `useQuery`. The login route group has no QueryClient provider, so this hook —\n * and every component built on it — must avoid react-query primitives.\n *\n * On a rejected `getLoginConfig` the hook falls back to a safe empty config\n * (no methods, registration off, empty device-state) so the surface stays\n * usable even when `/bff/config` is unreachable in dev. `loading` flips to\n * `false` as soon as the call settles.\n */\nimport { useEffect, useState } from 'react';\n\nimport type { BffLoginConfig, LoginConfigCapableClient } from './types';\n\n/** A safe, inert config used before the first fetch resolves / on failure. */\nconst EMPTY_CONFIG: BffLoginConfig = {\n methods: [],\n registrationEnabled: false,\n deviceState: {\n rememberedUsername: null,\n hasPin: false,\n pinDigits: null,\n preferredMethod: null,\n },\n demo: null,\n};\n\n/** What {@link useBffLoginConfig} returns. */\nexport interface UseBffLoginConfigResult {\n /** The parsed login config; the empty fallback until the fetch resolves. */\n config: BffLoginConfig;\n /** `true` until the initial `getLoginConfig` call settles. */\n loading: boolean;\n}\n\n/**\n * Fetch `getLoginConfig()` once on mount and expose `{ config, loading }`. The\n * empty fallback config is used until the call resolves and on any failure. The\n * effect guards against a `setState` after the consumer unmounts mid-request.\n */\nexport function useBffLoginConfig(\n client: LoginConfigCapableClient,\n): UseBffLoginConfigResult {\n const [config, setConfig] = useState<BffLoginConfig>(EMPTY_CONFIG);\n const [loading, setLoading] = useState<boolean>(true);\n\n useEffect(() => {\n let active = true;\n client\n .getLoginConfig()\n .then((next) => {\n if (active) {\n setConfig(next);\n }\n })\n .catch(() => {\n if (active) {\n setConfig(EMPTY_CONFIG);\n }\n })\n .finally(() => {\n if (active) {\n setLoading(false);\n }\n });\n return (): void => {\n active = false;\n };\n }, [client]);\n\n return { config, loading };\n}\n","/**\n * Same-origin client for the user's cross-device login-method preference\n * (unified-login D5). Unlike the device-PIN client (which targets the BFF's\n * own `/bff/*` auth endpoints), the preference lives in TenantService and is\n * reached THROUGH the BFF's YARP proxy:\n *\n * - GET `${baseUrl}/bff/api/{tenantsSegment}/api/v1/me/preferences`\n * → `{ ..., preferredLoginMethod }`\n * - PUT `${baseUrl}/bff/api/{tenantsSegment}/api/v1/me/login-method-preference`\n * body `{ method }`\n *\n * The BFF attaches the session's Bearer token to the proxied request, so both\n * calls require an authenticated session (the cookie travels via\n * `credentials: 'include'`). The PUT carries the `X-BFF-Csrf` header the BFF\n * anti-forgery middleware requires.\n *\n * react-query-FREE: plain `HttpClient` calls with `.then/.catch`. Portable\n * across every consumer (Expo RN-web apps AND the kefi/poueni surfaces).\n */\nimport type { HttpClient } from '@dloizides/auth-client';\n\nconst CSRF_HEADER = 'X-BFF-Csrf';\nconst CSRF_HEADER_VALUE = '1';\nconst JSON_CONTENT_TYPE = 'application/json';\n\n/** The default BFF YARP downstream segment that routes to TenantService. */\nconst DEFAULT_TENANTS_SEGMENT = 'tenants';\n\n/** The TenantService routes, relative to the BFF tenants proxy base. */\nconst PREFERENCES_PATH = 'api/v1/me/preferences';\nconst LOGIN_METHOD_PREFERENCE_PATH = 'api/v1/me/login-method-preference';\n\nexport interface PreferencesClientOptions {\n /** Runtime-agnostic HTTP transport (wrap native `fetch` with `createFetchHttpClient`). */\n http: HttpClient;\n /**\n * BFF origin. Defaults to `''` (same-origin) — the production wiring. An\n * explicit origin is only useful for tests or a non-same-origin BFF.\n */\n baseUrl?: string;\n /**\n * The BFF YARP downstream segment that routes to TenantService. Defaults to\n * `'tenants'` — the segment every product BFF (katalogos / erevna / kefi)\n * uses for `tenant-api`.\n */\n tenantsSegment?: string;\n}\n\n/**\n * The narrow client the preferred-method UI depends on. Both methods NEVER\n * reject — they resolve a benign value on any failure so the settings card and\n * the post-login cache sync degrade gracefully rather than throwing.\n */\nexport interface PreferredMethodClient {\n /**\n * `GET /me/preferences` → the stored preferred login method, or `null` when\n * the user never picked one (or on any failure).\n */\n getPreferredLoginMethod(): Promise<string | null>;\n /**\n * `PUT /me/login-method-preference` — set (or clear, with `null`) the stored\n * preference. Resolves `true` on a 2xx, `false` on anything else.\n */\n setPreferredLoginMethod(method: string | null): Promise<boolean>;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null;\n}\n\n/** Read an optional non-empty string field off a record, else `null`. */\nfunction readOptionalString(record: Record<string, unknown>, key: string): string | null {\n const value = record[key];\n if (typeof value !== 'string' || value === '') {\n return null;\n }\n return value;\n}\n\n/**\n * Build a same-origin {@link PreferredMethodClient}. With no `baseUrl` this is\n * the production wiring: same-origin, the session cookie travels automatically.\n */\nexport function createPreferencesClient(options: PreferencesClientOptions): PreferredMethodClient {\n const http = options.http;\n const baseUrl = (options.baseUrl ?? '').replace(/\\/$/, '');\n const segment = options.tenantsSegment ?? DEFAULT_TENANTS_SEGMENT;\n const proxyBase = `${baseUrl}/bff/api/${segment}`;\n\n return {\n async getPreferredLoginMethod(): Promise<string | null> {\n try {\n const response = await http({\n url: `${proxyBase}/${PREFERENCES_PATH}`,\n method: 'GET',\n headers: { Accept: JSON_CONTENT_TYPE },\n credentials: 'include',\n });\n if (!response.ok || !isRecord(response.data)) {\n return null;\n }\n return readOptionalString(response.data, 'preferredLoginMethod');\n } catch {\n return null;\n }\n },\n\n async setPreferredLoginMethod(method: string | null): Promise<boolean> {\n try {\n const response = await http({\n url: `${proxyBase}/${LOGIN_METHOD_PREFERENCE_PATH}`,\n method: 'PUT',\n headers: {\n 'Content-Type': JSON_CONTENT_TYPE,\n Accept: JSON_CONTENT_TYPE,\n [CSRF_HEADER]: CSRF_HEADER_VALUE,\n },\n body: JSON.stringify({ method }),\n credentials: 'include',\n });\n return response.ok;\n } catch {\n return false;\n }\n },\n };\n}\n","/**\n * Seed the device-local preferred-method cache from the server.\n *\n * Call this right AFTER a successful login (any method), while a session\n * exists: it reads the server-owned preference and writes it into\n * `localStorage` so the NEXT visit's login screen can emphasise it before the\n * user authenticates. This is the bridge that makes the preference cross-device\n * (the cache on a new device gets seeded on that device's first login).\n *\n * Fire-and-forget + never throws — a failed sync just leaves the cache as-is;\n * the login hint is an optional nicety, never a blocker.\n */\nimport { cachePreferredMethod } from './preferredMethodCache';\n\nimport type { PreferredMethodClient } from './preferencesClient';\n\n/**\n * Fetch the server-stored preferred login method and mirror it into the\n * device-local cache. Resolves to the value written (or `null`). Safe to\n * `void` — it swallows all errors.\n */\nexport async function syncPreferredMethodFromServer(\n client: PreferredMethodClient,\n): Promise<string | null> {\n try {\n const method = await client.getPreferredLoginMethod();\n cachePreferredMethod(method);\n return method;\n } catch {\n return null;\n }\n}\n","/**\n * `useDemoCredentials` — the wiring between `<DemoCredentialsHint>` and\n * `<LoginForm>`, so a consuming app does not hand-roll it.\n *\n * Without this hook every app would rediscover the same trap: `<LoginForm>`'s\n * `initialUsername` / `initialPassword` seed `useState`, and `useState` ignores\n * its initial argument on re-render — so wiring the hint's button to a plain\n * `setState` would render a form that stubbornly stays empty. The fix (a nonce\n * that re-applies the seed) is package plumbing, not app code.\n *\n * The hook owns that state and hands back two ready-to-spread prop bags:\n *\n * ```tsx\n * const demo = useDemoCredentials({ credentials: DEMO, prefillOnMount: true });\n *\n * <AuthScreen theme={authTheme}>\n * <DemoCredentialsHint {...demo.hintProps} theme={authTheme} />\n * <LoginForm {...demo.loginFormProps} chromeless client={client} theme={authTheme}\n * onSuccess={handleSignedIn} />\n * </AuthScreen>\n * ```\n *\n * Pass a *stable* `credentials` reference (a module-level const, or memoised).\n * An object literal re-created every render re-creates `hintProps` every render.\n */\nimport { useCallback, useMemo, useState } from 'react';\n\nimport { resolveDemoAccounts } from './resolveDemoAccounts';\nimport { PrefillIntent } from '../components/PrefillIntent';\n\nimport type { DemoAccount, DemoCredentials } from './types';\n\n/**\n * Compare two resolved pairs by VALUE.\n *\n * Identity is not usable here: `resolveDemoCredentials` builds a new object\n * whenever the caller's `credentials` reference changes, and a react-query\n * refetch hands back a fresh object carrying identical values on every poll.\n * Comparing by identity would re-seed the form on every refetch — stomping the\n * user's typing on a timer.\n */\nfunction isSamePair(a: DemoCredentials | null, b: DemoCredentials | null): boolean {\n if (a === null || b === null) {\n return a === b;\n }\n return a.username === b.username && a.password === b.password;\n}\n\n/** Options for {@link useDemoCredentials}. */\nexport interface UseDemoCredentialsOptions {\n /**\n * The demo credentials to advertise. Omit (or pass a half-configured pair) and\n * the whole surface disappears: the hint renders nothing and the form is never\n * seeded. See `resolveDemoCredentials`.\n */\n credentials?: DemoCredentials;\n /**\n * When `true` the form arrives ALREADY filled, so signing in as the demo user\n * is a single tap on \"Sign in\" — the hint panel then explains why the fields\n * are populated and re-fills them if the visitor clears them.\n *\n * Defaults to `false`: the fields start empty and the visitor opts in by\n * tapping \"Use these credentials\". Prefer the default unless the page is a\n * genuinely public demo — a login form that arrives pre-filled with someone\n * else's credentials is confusing on a page real account holders also use.\n */\n prefillOnMount?: boolean;\n}\n\n/** The `<LoginForm>` props that carry the demo prefill. Spread onto the form. */\nexport interface DemoCredentialsLoginFormProps {\n initialUsername?: string;\n initialPassword?: string;\n prefillNonce: number;\n prefillIntent: PrefillIntent;\n}\n\n/** The `<DemoCredentialsHint>` props that carry the credentials + fill action. */\nexport interface DemoCredentialsHintWiring {\n credentials?: DemoCredentials;\n /**\n * The resolved list of demo accounts (from `publishedAccounts`, else the legacy\n * single pair wrapped into one). The hint renders one labelled row per entry and\n * prefers this over {@link credentials} when present. Additive — a hint given only\n * `credentials` still resolves the same list itself.\n */\n accounts: DemoAccount[];\n onUse: (credentials: DemoCredentials) => void;\n}\n\n/** What {@link useDemoCredentials} hands back. */\nexport interface UseDemoCredentialsResult {\n /** Spread onto `<LoginForm>`. */\n loginFormProps: DemoCredentialsLoginFormProps;\n /** Spread onto `<DemoCredentialsHint>`. */\n hintProps: DemoCredentialsHintWiring;\n}\n\n/** Wire a demo-credentials hint to a login form. Returns two prop bags to spread. */\nexport function useDemoCredentials({\n credentials,\n prefillOnMount = false,\n}: Readonly<UseDemoCredentialsOptions> = {}): UseDemoCredentialsResult {\n // The full resolved list (multi-account or a single legacy pair wrapped into one).\n const accounts = useMemo(() => resolveDemoAccounts(credentials), [credentials]);\n // The form seeds from the FIRST account — the one the legacy fields mirror, and\n // the natural default when a page arrives pre-filled. As a bare pair (no label)\n // so the value-gated auto-seed below compares it cleanly.\n const resolved = useMemo<DemoCredentials | null>(() => {\n const first = accounts[0];\n return first === undefined\n ? null\n : { username: first.username, password: first.password };\n }, [accounts]);\n\n // The values currently seeded into the form (`null` = nothing seeded).\n const [filled, setFilled] = useState<DemoCredentials | null>(\n prefillOnMount ? resolved : null,\n );\n // Bumped on every fill so `<LoginForm>` re-applies the seed to fields the user\n // may already have edited or cleared.\n const [prefillNonce, setPrefillNonce] = useState<number>(0);\n const [prefillIntent, setPrefillIntent] = useState<PrefillIntent>(\n PrefillIntent.Opportunistic,\n );\n // The pair the auto-seed has already consumed. Initialised to what a\n // synchronous `credentials` already seeded via `useState` above, so the\n // module-const path never double-seeds and its nonce stays at 0.\n const [autoSeeded, setAutoSeeded] = useState<DemoCredentials | null>(\n prefillOnMount ? resolved : null,\n );\n\n // Credentials fetched from `GET /bff/config` land AFTER mount, and `useState`\n // honours its initial argument on the first render only — so without this the\n // `prefillOnMount` seed above silently never happens for any BFF-fronted app,\n // and the panel renders next to a stubbornly empty form. Adjusting state during\n // render (React's documented \"derive state from props\" pattern) rather than in\n // an effect avoids a committed render showing the un-seeded form first.\n //\n // Gated on the pair's VALUE, so this runs at most once per distinct credential\n // pair: re-renders and refetches that carry the same values do nothing, which\n // is what stops it looping.\n const shouldAutoSeed = prefillOnMount && resolved !== null && !isSamePair(resolved, autoSeeded);\n if (shouldAutoSeed) {\n setAutoSeeded(resolved);\n setFilled(resolved);\n setPrefillNonce((current) => current + 1);\n // Offered, not requested: `<LoginForm>` drops this if the user is typing.\n setPrefillIntent(PrefillIntent.Opportunistic);\n }\n\n const handleUse = useCallback((next: DemoCredentials): void => {\n setFilled(next);\n setPrefillNonce((current) => current + 1);\n // The user tapped the button — this one always applies.\n setPrefillIntent(PrefillIntent.Explicit);\n }, []);\n\n return useMemo(\n () => ({\n loginFormProps: {\n initialUsername: filled?.username,\n initialPassword: filled?.password,\n prefillNonce,\n prefillIntent,\n },\n // `credentials` is passed through unresolved on purpose: the hint applies\n // `resolveDemoAccounts` itself, so it fails closed even when it is used\n // standalone, without this hook. `accounts` is the already-resolved list the\n // hint prefers — one labelled row per entry.\n hintProps: { credentials, accounts, onUse: handleUse },\n }),\n [filled, prefillNonce, prefillIntent, credentials, accounts, handleUse],\n );\n}\n","/**\n * `testID` values for `<RegisterForm>`.\n *\n * Kept apart from `AuthTestIds` on purpose: these are the unprefixed\n * `register-*` IDs katalogos-web and erevna-web rendered before the extraction,\n * and the E2E suites (`E2ETests/shared/testIds.ts`,\n * `E2ETests/helpers/katalogos-signup-helpers.ts`) already select on them.\n * Changing a value here breaks those suites.\n *\n * `sonarjs/no-hardcoded-passwords` is disabled for this file: it flags the\n * `passwordInput` keys, but every value here is a UI test ID, not a credential.\n */\n/* eslint-disable sonarjs/no-hardcoded-passwords */\nexport const RegisterTestIds = {\n form: 'register-form',\n firstNameInput: 'register-first-name-input',\n lastNameInput: 'register-last-name-input',\n usernameInput: 'register-username-input',\n emailInput: 'register-email-input',\n passwordInput: 'register-password-input',\n confirmPasswordInput: 'register-confirm-password-input',\n tenantNameInput: 'register-tenant-name-input',\n submitButton: 'register-submit-button',\n websiteInput: 'register-website',\n} as const;\n","/**\n * The inputs of `<RegisterForm>`: the seven visible fields plus the off-screen\n * honeypot. Presentational only; state lives in `useRegisterForm`.\n */\nimport { type ComponentProps, type ReactElement } from 'react';\n\nimport { StyleSheet, Text, TextInput, View } from 'react-native';\n\nimport { RegisterTestIds } from './registerTestIds';\nimport { withTestIdPrefix } from './testIds';\n\nimport type { RegisterFormLabels } from './labels/registerLabels';\nimport type { useAuthStyles } from './useAuthStyles';\nimport type { RegisterField, RegisterFormValues, RegisterInputField } from '../hooks/registerTypes';\nimport type { AuthTheme } from '../theme/AuthTheme';\n\ntype InputProps = ComponentProps<typeof TextInput>;\n\ninterface FieldConfig {\n key: RegisterInputField;\n testId: string;\n secure?: boolean;\n autoComplete?: InputProps['autoComplete'];\n keyboardType?: InputProps['keyboardType'];\n}\n\nconst FIELDS: readonly FieldConfig[] = [\n { key: 'firstName', testId: RegisterTestIds.firstNameInput, autoComplete: 'name' },\n { key: 'lastName', testId: RegisterTestIds.lastNameInput, autoComplete: 'name' },\n { key: 'username', testId: RegisterTestIds.usernameInput, autoComplete: 'username' },\n { key: 'email', testId: RegisterTestIds.emailInput, autoComplete: 'email', keyboardType: 'email-address' },\n { key: 'password', testId: RegisterTestIds.passwordInput, secure: true },\n { key: 'confirmPassword', testId: RegisterTestIds.confirmPasswordInput, secure: true },\n { key: 'tenantName', testId: RegisterTestIds.tenantNameInput },\n];\n\nconst OFF_SCREEN = -9999;\nconst HONEYPOT_SIZE = 1;\n// Never shown to a human; a bot reads it to decide what to type.\nconst HONEYPOT_PLACEHOLDER = 'Website';\n\nconst honeypotStyles = StyleSheet.create({\n honeypot: {\n position: 'absolute',\n left: OFF_SCREEN,\n top: OFF_SCREEN,\n width: HONEYPOT_SIZE,\n height: HONEYPOT_SIZE,\n opacity: 0,\n },\n});\n\nexport interface RegisterFormFieldsProps {\n values: RegisterFormValues;\n labels: RegisterFormLabels;\n disabled: boolean;\n theme: AuthTheme;\n styles: ReturnType<typeof useAuthStyles>;\n onChange: (field: RegisterField, value: string) => void;\n testIdPrefix?: string;\n}\n\nexport function RegisterFormFields({\n values,\n labels,\n disabled,\n theme,\n styles,\n onChange,\n testIdPrefix,\n}: Readonly<RegisterFormFieldsProps>): ReactElement {\n return (\n <>\n {FIELDS.map((config) => {\n const copy = labels.fields[config.key];\n return (\n <View key={config.key} style={styles.fieldGroup}>\n <Text style={styles.label}>{copy.label}</Text>\n <TextInput\n accessibilityHint={copy.hint}\n accessibilityLabel={copy.inputLabel}\n autoCapitalize=\"none\"\n autoComplete={config.autoComplete}\n autoCorrect={false}\n editable={!disabled}\n keyboardType={config.keyboardType ?? 'default'}\n placeholder={copy.placeholder}\n placeholderTextColor={theme.colors.textSecondary}\n secureTextEntry={config.secure === true}\n style={styles.input}\n testID={withTestIdPrefix(config.testId, testIdPrefix)}\n value={values[config.key]}\n onChangeText={(text) => onChange(config.key, text)}\n />\n </View>\n );\n })}\n <TextInput\n accessibilityElementsHidden\n accessibilityRole=\"none\"\n autoComplete=\"off\"\n focusable={false}\n importantForAccessibility=\"no-hide-descendants\"\n placeholder={HONEYPOT_PLACEHOLDER}\n style={honeypotStyles.honeypot}\n testID={withTestIdPrefix(RegisterTestIds.websiteInput, testIdPrefix)}\n value={values.website}\n onChangeText={(text) => onChange('website', text)}\n />\n </>\n );\n}\n","/**\n * The discrete failure states the registration flow can report.\n *\n * Each member is a stable key the consuming app maps onto a localised message\n * (`FM('register.usernameTaken')`, …). The package never renders copy for these\n * itself — it ships no translations.\n */\nexport const enum RegisterErrorCode {\n /** A required field (anything but the honeypot) is empty. */\n MissingFields = 'missingFields',\n /** The email does not look like an address. */\n InvalidEmail = 'invalidEmail',\n /** The password fails the active password policy. */\n WeakPassword = 'weakPassword',\n /** The confirm field does not match the password. */\n PasswordMismatch = 'passwordMismatch',\n /** The server reported `USERNAME_TAKEN`. */\n UsernameTaken = 'usernameTaken',\n /** The server reported `EMAIL_TAKEN`. */\n EmailTaken = 'emailTaken',\n /** The server reported `REALM_REQUIRED` or `REALM_INVALID`. */\n RealmInvalid = 'realmInvalid',\n /** The server rejected the request with an unrecognised message. */\n ValidationFailed = 'validationFailed',\n /** Generic failure: network error, empty message, or a filled honeypot (never revealed). */\n Failed = 'failed',\n /** A submit is already running; the second press was ignored. Do not surface it. */\n InFlight = 'inFlight',\n}\n","/**\n * Route a finished registration submit to the app's callbacks.\n *\n * Kept out of `<RegisterForm>` so the only branching the component had is unit\n * tested: success goes to `onSuccess`; every failure goes to `onError` except\n * `InFlight`, which marks a press the hook ignored and is never surfaced.\n */\nimport { RegisterErrorCode } from './RegisterErrorCode';\n\nimport type { RegisterSubmitOutcome } from './registerTypes';\n\nexport interface RegisterOutcomeHandlers<TResult> {\n onSuccess: (result: TResult) => void;\n onError?: (error: RegisterErrorCode) => void;\n}\n\n/** Deliver `outcome` to the matching handler. */\nexport function routeRegisterOutcome<TResult>(\n outcome: RegisterSubmitOutcome<TResult>,\n handlers: RegisterOutcomeHandlers<TResult>,\n): void {\n if (outcome.ok) {\n handlers.onSuccess(outcome.result);\n return;\n }\n if (outcome.error !== RegisterErrorCode.InFlight) {handlers.onError?.(outcome.error);}\n}\n","/**\n * Pure registration helpers: trimming, client-side validation and decoding of a\n * TenantService failure (surfaced by the BFF as a plain error whose message\n * carries an error-code substring).\n *\n * Merged from the katalogos-web and erevna-web `useRegisterForm` copies, which\n * were identical apart from katalogos' honeypot.\n */\nimport { RegisterErrorCode } from './RegisterErrorCode';\n\nimport type { RegisterFormValues, RegisterPasswordPolicy } from './registerTypes';\n\nconst MIN_PASSWORD_LENGTH = 8;\nconst WHITESPACE_REGEX = /\\s/;\nconst EMAIL_PART_COUNT = 2;\nconst PASSWORD_LETTER_REGEX = /[a-zA-Z]/;\nconst PASSWORD_DIGIT_REGEX = /\\d/;\nconst PASSWORD_SPECIAL_REGEX = /[^a-zA-Z0-9]/;\n\n/** Server error-code substring → code. First match wins. */\nconst SERVER_ERROR_CODES: ReadonlyArray<readonly [string, RegisterErrorCode]> = [\n ['USERNAME_TAKEN', RegisterErrorCode.UsernameTaken],\n ['EMAIL_TAKEN', RegisterErrorCode.EmailTaken],\n ['REALM_REQUIRED', RegisterErrorCode.RealmInvalid],\n ['REALM_INVALID', RegisterErrorCode.RealmInvalid],\n];\n\n/** The default password rule: 8+ characters with a letter, a digit and a special character. */\nexport function isRegisterPasswordStrong(password: string): boolean {\n if (password.length < MIN_PASSWORD_LENGTH) {return false;}\n if (!PASSWORD_LETTER_REGEX.test(password)) {return false;}\n if (!PASSWORD_DIGIT_REGEX.test(password)) {return false;}\n return PASSWORD_SPECIAL_REGEX.test(password);\n}\n\n/**\n * The pre-extraction app rule `^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$`, written without the\n * regex's super-linear backtracking: no whitespace, exactly one `@`, a non-empty\n * local part, and a dot strictly inside the domain. Rejects `a@b.c@d`. Strict\n * validation is the backend's job.\n */\nfunction isEmailShaped(email: string): boolean {\n if (WHITESPACE_REGEX.test(email)) {return false;}\n const parts = email.split('@');\n if (parts.length !== EMAIL_PART_COUNT) {return false;}\n const [local = '', domain = ''] = parts;\n return local !== '' && domain.slice(1, -1).includes('.');\n}\n\n/** Trim every text field; passwords are left exactly as typed. */\nexport function trimRegisterValues(values: RegisterFormValues): RegisterFormValues {\n return {\n firstName: values.firstName.trim(),\n lastName: values.lastName.trim(),\n username: values.username.trim(),\n email: values.email.trim(),\n password: values.password,\n confirmPassword: values.confirmPassword,\n tenantName: values.tenantName.trim(),\n website: values.website.trim(),\n };\n}\n\nfunction hasMissingRequiredField(values: RegisterFormValues): boolean {\n const required = [\n values.firstName,\n values.lastName,\n values.username,\n values.email,\n values.password,\n values.tenantName,\n ];\n return required.some((value) => value === '');\n}\n\n/** The first client-side problem with already-trimmed values, or `null`. */\nexport function validateRegisterValues(\n values: RegisterFormValues,\n passwordPolicy: RegisterPasswordPolicy,\n): RegisterErrorCode | null {\n if (hasMissingRequiredField(values)) {return RegisterErrorCode.MissingFields;}\n if (!isEmailShaped(values.email)) {return RegisterErrorCode.InvalidEmail;}\n if (!passwordPolicy(values.password)) {return RegisterErrorCode.WeakPassword;}\n if (values.password !== values.confirmPassword) {return RegisterErrorCode.PasswordMismatch;}\n return null;\n}\n\nfunction messageOf(error: unknown): string {\n if (error instanceof Error) {return error.message;}\n return typeof error === 'string' ? error : '';\n}\n\n/** Decode a thrown registration failure into a {@link RegisterErrorCode}. */\nexport function mapRegisterErrorCode(error: unknown): RegisterErrorCode {\n const message = messageOf(error);\n if (message === '') {return RegisterErrorCode.Failed;}\n const match = SERVER_ERROR_CODES.find(([code]) => message.includes(code));\n return match === undefined ? RegisterErrorCode.ValidationFailed : match[1];\n}\n","/**\n * `useRegisterForm` — headless registration state, client validation, honeypot\n * refusal and submit flow.\n *\n * The hook does not know how registration is sent: the app passes `onSubmit`,\n * which builds its own request (realm, verify-URL template) and calls its BFF.\n * Failures come back as a {@link RegisterErrorCode}; the app maps it to copy.\n * No react-query, so it runs on provider-less auth routes.\n */\nimport { useCallback, useRef, useState } from 'react';\n\nimport { isRegisterPasswordStrong, mapRegisterErrorCode, trimRegisterValues, validateRegisterValues } from './registerErrors';\nimport { RegisterErrorCode } from './RegisterErrorCode';\n\nimport type {\n RegisterField,\n RegisterFormValues,\n RegisterPasswordPolicy,\n RegisterSubmitOutcome,\n RegisterSubmitValues,\n} from './registerTypes';\n\nexport interface UseRegisterFormArgs<TResult> {\n /** Send the registration. Throw on failure; the message is decoded to a code. */\n onSubmit: (values: RegisterSubmitValues) => Promise<TResult>;\n /** Password rule. Defaults to {@link isRegisterPasswordStrong}. */\n passwordPolicy?: RegisterPasswordPolicy;\n /**\n * Called once per ACCEPTED submit, before validation (e.g. a \"signup started\"\n * event). A press ignored because a submit is already in flight does not call it.\n */\n onSubmitAttempt?: () => void;\n}\n\nexport interface UseRegisterFormResult<TResult> {\n state: RegisterFormValues;\n setField: (field: RegisterField, value: string) => void;\n submit: () => Promise<RegisterSubmitOutcome<TResult>>;\n isSubmitting: boolean;\n /** The last failure, cleared when a submit starts. */\n error: RegisterErrorCode | null;\n}\n\nconst EMPTY_VALUES: RegisterFormValues = {\n firstName: '',\n lastName: '',\n username: '',\n email: '',\n password: '',\n confirmPassword: '',\n tenantName: '',\n website: '',\n};\n\nfunction toSubmitValues(values: RegisterFormValues): RegisterSubmitValues {\n return {\n firstName: values.firstName,\n lastName: values.lastName,\n username: values.username,\n email: values.email,\n password: values.password,\n tenantName: values.tenantName,\n website: values.website,\n };\n}\n\n/** Headless registration form logic. */\nexport function useRegisterForm<TResult>({\n onSubmit,\n passwordPolicy = isRegisterPasswordStrong,\n onSubmitAttempt,\n}: UseRegisterFormArgs<TResult>): UseRegisterFormResult<TResult> {\n const [state, setState] = useState<RegisterFormValues>(EMPTY_VALUES);\n const [isSubmitting, setIsSubmitting] = useState(false);\n const [error, setError] = useState<RegisterErrorCode | null>(null);\n // A ref, not state: a double press inside one frame must see the flag at once.\n const inFlight = useRef(false);\n\n const setField = useCallback((field: RegisterField, value: string): void => {\n setState((prev) => ({ ...prev, [field]: value }));\n }, []);\n\n const submit = useCallback(async (): Promise<RegisterSubmitOutcome<TResult>> => {\n if (inFlight.current) {return { ok: false, error: RegisterErrorCode.InFlight };}\n onSubmitAttempt?.();\n const trimmed = trimRegisterValues(state);\n // A filled honeypot gets the generic code, so the trap is never revealed.\n const refusal =\n trimmed.website === '' ? validateRegisterValues(trimmed, passwordPolicy) : RegisterErrorCode.Failed;\n if (refusal !== null) {\n setError(refusal);\n return { ok: false, error: refusal };\n }\n\n inFlight.current = true;\n setError(null);\n setIsSubmitting(true);\n try {\n const result = await onSubmit(toSubmitValues(trimmed));\n return { ok: true, result };\n } catch (caught) {\n const code = mapRegisterErrorCode(caught);\n setError(code);\n return { ok: false, error: code };\n } finally {\n inFlight.current = false;\n setIsSubmitting(false);\n }\n }, [onSubmit, onSubmitAttempt, passwordPolicy, state]);\n\n return { state, setField, submit, isSubmitting, error };\n}\n","/**\n * `<RegisterForm>` — the ready-made, themeable sign-up form.\n *\n * Extracted from the identical katalogos-web and erevna-web register screens.\n * The app keeps what differs per product: the request it sends (`onSubmit`, which\n * carries the realm and verify-URL template), where to go afterwards\n * (`onSuccess`), and the localised copy (`labels`, plus mapping a\n * `RegisterErrorCode` to a message in `onError`).\n */\nimport { useCallback, useMemo, type ReactElement, type ReactNode } from 'react';\n\nimport { Text, View } from 'react-native';\n\nimport { Button } from '@dloizides/ui-buttons';\n\nimport { DEFAULT_REGISTER_LABELS, type RegisterFormLabels } from './labels/registerLabels';\nimport { RegisterFormFields } from './RegisterFormFields';\nimport { RegisterTestIds } from './registerTestIds';\nimport { withTestIdPrefix } from './testIds';\nimport { useAuthStyles } from './useAuthStyles';\nimport { routeRegisterOutcome } from '../hooks/routeRegisterOutcome';\nimport { useRegisterForm } from '../hooks/useRegisterForm';\nimport { useAuthTheme } from '../theme/AuthThemeProvider';\n\nimport type { RegisterErrorCode } from '../hooks/RegisterErrorCode';\nimport type { RegisterPasswordPolicy, RegisterSubmitValues } from '../hooks/registerTypes';\nimport type { AuthTheme } from '../theme/AuthTheme';\n\nexport interface RegisterFormProps<TResult> {\n /** Send the registration (build the request, call the BFF). Throw on failure. */\n onSubmit: (values: RegisterSubmitValues) => Promise<TResult>;\n /** Called with whatever `onSubmit` resolved to. */\n onSuccess: (result: TResult) => void;\n /** Called with the failure code; map it to localised copy. */\n onError?: (error: RegisterErrorCode) => void;\n /** Called once per accepted submit, before validation (e.g. a \"signup started\" event); never for a press ignored in flight. */\n onSubmitAttempt?: () => void;\n /** Password rule. Defaults to `isRegisterPasswordStrong`. */\n passwordPolicy?: RegisterPasswordPolicy;\n /** Localised copy. Partial: unspecified top-level keys fall back to English defaults. */\n labels?: Partial<RegisterFormLabels>;\n /** Explicit theme; overrides any `<AuthThemeProvider>`. */\n theme?: AuthTheme;\n /** Rendered under the submit button (e.g. \"Already have an account?\"). */\n footer?: ReactNode;\n /** Prefix applied to every `testID`. */\n testIdPrefix?: string;\n}\n\n/** Themeable registration form built on `useRegisterForm`. */\nexport function RegisterForm<TResult>({\n onSubmit,\n onSuccess,\n onError,\n onSubmitAttempt,\n passwordPolicy,\n labels: labelsProp,\n theme: themeProp,\n footer,\n testIdPrefix,\n}: Readonly<RegisterFormProps<TResult>>): ReactElement {\n const theme = useAuthTheme(themeProp);\n const styles = useAuthStyles(theme);\n const labels = useMemo<RegisterFormLabels>(\n () => ({ ...DEFAULT_REGISTER_LABELS, ...labelsProp }),\n [labelsProp],\n );\n const { state, setField, submit, isSubmitting } = useRegisterForm<TResult>({\n onSubmit,\n onSubmitAttempt,\n passwordPolicy,\n });\n\n // The shared Button owns keyboard parity: a held Enter is one press, not one per key-repeat.\n const handlePress = useCallback(async (): Promise<void> => {\n routeRegisterOutcome(await submit(), { onSuccess, onError });\n }, [onError, onSuccess, submit]);\n\n return (\n <View style={styles.screen}>\n <View style={styles.card} testID={withTestIdPrefix(RegisterTestIds.form, testIdPrefix)}>\n <Text style={styles.title}>{labels.title}</Text>\n <Text style={styles.subtitle}>{labels.subtitle}</Text>\n\n <RegisterFormFields\n disabled={isSubmitting}\n labels={labels}\n styles={styles}\n testIdPrefix={testIdPrefix}\n theme={theme}\n values={state}\n onChange={setField}\n />\n\n <View style={styles.fieldGroup}>\n <Button\n fullWidth\n accessibilityHint={labels.submitHint}\n accessibilityLabel={isSubmitting ? labels.submitting : labels.submit}\n label={labels.submit}\n loading={isSubmitting}\n testID={withTestIdPrefix(RegisterTestIds.submitButton, testIdPrefix)}\n onPress={handlePress}\n />\n </View>\n\n {footer}\n </View>\n </View>\n );\n}\n","/**\n * `createBffAuthClient` — the one-line wiring of a same-origin `BffAuthClient`.\n *\n * `BffAuthClient` (from `@dloizides/auth-client`) needs an `HttpClient`. Every\n * app wired it the same way — `createFetchHttpClient(fetch)` — and every app\n * hit the same trap: binding `fetch` at module load throws in a non-browser\n * runtime (the Jest/jsdom test environment has no `fetch` global). The lesson\n * of Phase 1 was \"copy-pasted auth adapters ship the same bug N times\", so the\n * correct wiring lives here once.\n *\n * `fetch` is resolved **lazily, per request** — module load stays\n * side-effect-free. `baseUrl` is omitted by default → same-origin: every\n * `/bff/*` call goes to the SPA's own host, which is fronted by the per-app\n * BFF (`bff-katalogos`, `bff-erevna`, ...).\n *\n * Extracted + generalised from `apps/katalogos-web/src/auth/bffAuthClient.ts`.\n */\nimport {\n BffAuthClient,\n createFetchHttpClient,\n type HttpClient,\n type HttpRequest,\n type HttpResponse,\n} from '@dloizides/auth-client';\n\nexport interface CreateBffAuthClientOptions {\n /**\n * BFF origin. Omit (the production default) for same-origin — the SPA's own\n * host is the BFF. An explicit origin is only useful for a non-same-origin\n * BFF or for tests.\n */\n baseUrl?: string;\n /**\n * Override the HTTP transport. Defaults to a lazily-resolved native `fetch`.\n * Tests pass a fake `HttpClient` here; production never needs to.\n */\n http?: HttpClient;\n}\n\n/**\n * Resolve the platform `fetch` lazily, per request.\n *\n * Resolving inside the request — never at module load — keeps importing this\n * module side-effect-free, so a test runtime without a `fetch` global does not\n * blow up the moment any file transitively imports `@dloizides/auth-web`.\n */\nasync function lazyFetchHttpClient(request: HttpRequest): Promise<HttpResponse> {\n const fetchImpl: typeof fetch | undefined =\n typeof fetch === 'function' ? fetch.bind(globalThis) : undefined;\n if (fetchImpl === undefined) {\n throw new Error('createBffAuthClient: fetch is not available in this environment');\n }\n return createFetchHttpClient(fetchImpl)(request);\n}\n\n/**\n * Build a same-origin `BffAuthClient`. With no arguments this is the exact\n * production wiring: same-origin, lazy `fetch`, no token handling.\n */\nexport function createBffAuthClient(options: CreateBffAuthClientOptions = {}): BffAuthClient {\n return new BffAuthClient({\n http: options.http ?? lazyFetchHttpClient,\n baseUrl: options.baseUrl,\n });\n}\n","/**\n * `resolvePostLoginRoute` — the role-based post-login router helper.\n *\n * The unified-auth plan's secondary goal is to kill the \"too many login links\"\n * problem (KUCY V2 has seven, one per role). One login surface; after a\n * successful login the app reads the user's role from the token claims and\n * routes to the right dashboard.\n *\n * This helper is intentionally pure and app-agnostic. The package does NOT\n * know any app's routes — the consuming app supplies a `RoleRouteTable`\n * mapping role → path. The helper picks the highest-priority matching role.\n *\n * Role priority: a user can hold several roles (`superUser` + `admin` + ...).\n * The table is consulted in the order its entries are listed — the FIRST\n * entry whose role the user holds wins. So an app lists the most privileged\n * role first. A `fallback` covers a user whose roles match no entry.\n */\nimport type { BffUser } from '@dloizides/auth-client';\n\n/** One role → route mapping. */\nexport interface RoleRoute {\n /** The Keycloak role name to match against the user's claims. */\n role: string;\n /** The route/path to send a user holding that role to. */\n route: string;\n /**\n * Optional translation key for a human label of this route — consumed by the\n * multi-role dashboard nav (`resolveAccessibleRoutes`) so an app can render a\n * localized link per accessible dashboard. Ignored by `resolvePostLoginRoute`\n * (landing only cares about the path). The package stays i18n-agnostic: it\n * carries the key, the app resolves it.\n */\n labelKey?: string;\n}\n\n/** An app-supplied, ordered role-routing table. */\nexport interface RoleRouteTable {\n /**\n * Ordered list of role → route entries. Order is priority: the first entry\n * whose `role` the user holds is chosen. List the most privileged role first.\n */\n routes: RoleRoute[];\n /**\n * Route used when the user holds none of the listed roles. When omitted and\n * nothing matches, `resolvePostLoginRoute` returns `null` and the caller\n * decides what to do (e.g. show an \"no access\" screen).\n */\n fallback?: string;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null;\n}\n\n/** Read a string array of roles from a `realm_access`-shaped value. */\nfunction readRealmAccessRoles(realmAccess: unknown): string[] {\n if (!isRecord(realmAccess)) {\n return [];\n }\n const roles = realmAccess.roles;\n if (!Array.isArray(roles)) {\n return [];\n }\n return roles.filter((role): role is string => typeof role === 'string');\n}\n\n/**\n * Collect every role on a `BffUser` — both the flat `roles` array and the\n * nested `realm_access.roles` — into a de-duplicated set. The BFF may surface\n * roles in either shape; this normalises both.\n */\nexport function collectUserRoles(user: BffUser): string[] {\n const flat = Array.isArray(user.roles)\n ? user.roles.filter((role): role is string => typeof role === 'string')\n : [];\n const realm = readRealmAccessRoles(user.realm_access);\n return Array.from(new Set([...flat, ...realm]));\n}\n\n/**\n * Resolve the post-login route for a user against an app-supplied table.\n *\n * Returns the route of the first table entry whose role the user holds; if no\n * entry matches, returns the table's `fallback`, or `null` when there is none.\n */\nexport function resolvePostLoginRoute(user: BffUser, table: RoleRouteTable): string | null {\n const userRoles = new Set(collectUserRoles(user));\n for (const entry of table.routes) {\n if (userRoles.has(entry.role)) {\n return entry.route;\n }\n }\n return table.fallback ?? null;\n}\n","/**\n * `resolveAccessibleRoutes` — the multi-role companion to\n * `resolvePostLoginRoute`.\n *\n * Where `resolvePostLoginRoute` answers \"where does this user LAND after login\"\n * (the single highest-priority route), this answers \"which dashboards can this\n * user REACH\" — the full, ordered set of role→route entries the user's role-set\n * unlocks. An app renders that set as a cross-dashboard nav so a user holding\n * several roles (e.g. a tenant owner who also organizes) can move between every\n * surface their roles grant, instead of being trapped on the one they landed on.\n *\n * Pure and app-agnostic, exactly like `resolvePostLoginRoute`: it reuses the\n * same `collectUserRoles` reader (flat `roles` + nested `realm_access.roles`)\n * and the same app-supplied `RoleRouteTable`. Table order is preserved, so the\n * nav lists the most privileged dashboard first. The table `fallback` is NOT\n * included — a fallback is a landing safety net, not a dashboard the user's\n * roles unlock. A user who holds none of the listed roles gets an empty list.\n */\nimport { collectUserRoles } from './resolvePostLoginRoute';\n\nimport type { RoleRoute, RoleRouteTable } from './resolvePostLoginRoute';\nimport type { BffUser } from '@dloizides/auth-client';\n\n/**\n * Resolve every route in `table` whose role the user holds, in table\n * (priority) order.\n *\n * @returns the matching `RoleRoute` entries (each carrying its optional\n * `labelKey`), or an empty array when the user holds none of the roles.\n */\nexport function resolveAccessibleRoutes(user: BffUser, table: RoleRouteTable): RoleRoute[] {\n const userRoles = new Set(collectUserRoles(user));\n return table.routes.filter((entry) => userRoles.has(entry.role));\n}\n","/**\n * `performBffLogout` — the shared logout sequencer.\n *\n * Every app hand-rolled its own logout ordering inside its `AuthProvider`, and\n * the orderings disagreed. Two of them (zygos-web, agora-web) navigated FIRST\n * and called the BFF second:\n *\n * ```ts\n * redirectTo('/(auth)/login'); // window.location.replace() → document unload\n * await bffAuthClient.logout(); // races the unload — may never be sent\n * ```\n *\n * That is wrong twice over:\n *\n * 1. **The BFF call can be cancelled.** A document navigation kills in-flight\n * fetches, so `POST /bff/logout` may never reach the server: the SPA looks\n * logged out while the httpOnly session cookie stays ALIVE. The `catch`\n * logged it \"non-fatal\", so the defect was silent.\n * 2. **The IdP session survives.** `BffAuthClient.logout()` ends the *identity\n * provider's* browser session by doing a top-level navigation to the IdP's\n * RP-initiated logout URL (only a real navigation carries the IdP's own\n * cookie — a back-channel POST cannot clear it). An app that navigates to\n * its own login route first pre-empts that navigation, so the IdP still\n * considers the user signed in and the next authorize round-trip silently\n * re-authenticates them. That is the \"sign-out that signs you back in\" bug\n * the client's own docs warn about.\n *\n * This helper owns the whole sequence so neither can be reintroduced per-app:\n *\n * 1. `onClearSession()` — drop local state immediately so the UI reflects the\n * sign-out right away (perceived performance; no spinner needed).\n * 2. `await client.logout({ redirect: false })` — let the network call SETTLE,\n * and take the IdP logout URL rather than letting the client navigate mid-\n * sequence. Errors are captured, never rethrown.\n * 3. Navigate LAST, exactly once, when nothing is in flight to cancel:\n * - an IdP logout URL → a top-level navigation to the IdP, which ends that\n * session and bounces the user back. `onRedirect` is deliberately NOT\n * called: two competing navigations would race, and the IdP round-trip\n * already returns the user to the app.\n * - otherwise (ROPC / OTP / device-PIN logins never had an IdP cookie, so\n * the URL is `null`) → `onRedirect()`, the app's own login route.\n *\n * Step 3 runs even when step 2 rejects: a BFF that is down must not trap the\n * user on a page they asked to leave. The local session is already gone, so the\n * client-side sign-out holds regardless.\n *\n * Headless and framework-free: it takes callbacks, so an app can pair it with\n * Redux, a context, expo-router, or `window.location` without this package\n * knowing about any of them.\n */\n\n/**\n * The only part of a `BffAuthClient` this helper needs. Structural, so it is\n * trivially fakeable in tests and does not couple to the full client surface.\n */\nexport interface BffLogoutClient {\n /**\n * `POST /bff/logout` — ends the server-side session. With `redirect: false`\n * it returns the IdP's RP-initiated logout URL (or `null` when the session\n * never involved an IdP browser cookie) instead of navigating there itself.\n */\n logout: (options?: { redirect?: boolean }) => Promise<string | null>;\n}\n\n/** Callbacks + client for {@link performBffLogout}. */\nexport interface PerformBffLogoutOptions {\n /** The BFF auth client whose `logout()` ends the server-side session. */\n client: BffLogoutClient;\n /** Drop local session state. Runs BEFORE the network call. Optional. */\n onClearSession?: () => void;\n /**\n * Navigate to the app's logged-out route. Runs only AFTER the network call\n * settles, and only when there is no IdP logout URL to honour. Optional.\n */\n onRedirect?: () => void;\n /** Observe a failed logout step (e.g. to log it). Never rethrown. Optional. */\n onError?: (error: Error) => void;\n /**\n * Test seam: perform the top-level navigation to the IdP logout URL. Defaults\n * to `window.location.assign`. Must be a real navigation — a `fetch` here\n * would not carry the IdP cookie and would silently fail to end the session.\n */\n navigateToIdp?: (url: string) => void;\n}\n\n/** Coerce an unknown thrown value into an `Error`. */\nfunction toError(caught: unknown): Error {\n return caught instanceof Error ? caught : new Error(String(caught));\n}\n\n/** Run a caller callback without letting it break the logout sequence. */\nfunction runGuarded(callback: (() => void) | undefined, onError?: (error: Error) => void): void {\n if (callback === undefined) {\n return;\n }\n try {\n callback();\n } catch (caught) {\n onError?.(toError(caught));\n }\n}\n\n/** Default top-level navigation to the IdP logout URL; SSR-safe. */\nfunction assignLocation(url: string): void {\n if (typeof window === 'undefined') {\n return;\n }\n window.location.assign(url);\n}\n\n/**\n * End the session: clear locally, await the BFF, then navigate exactly once.\n *\n * Never rejects — callers may `void` it safely.\n */\nexport async function performBffLogout(options: Readonly<PerformBffLogoutOptions>): Promise<void> {\n const { client, onClearSession, onRedirect, onError, navigateToIdp = assignLocation } = options;\n\n // 1. Local state first: the UI reflects the sign-out immediately.\n runGuarded(onClearSession, onError);\n\n // 2. Let the server-side logout SETTLE before anything can cancel it. Take\n // the IdP URL instead of letting the client navigate mid-sequence.\n let idpLogoutUrl: string | null = null;\n try {\n idpLogoutUrl = await client.logout({ redirect: false });\n } catch (caught) {\n onError?.(toError(caught));\n }\n\n // 3. Navigate last, exactly once — and always, even if step 2 failed.\n // Honouring the IdP URL is not optional: dropping it leaves the IdP\n // session alive and the next authorize call signs the user straight back in.\n if (idpLogoutUrl !== null) {\n const url = idpLogoutUrl;\n runGuarded(() => navigateToIdp(url), onError);\n return;\n }\n\n runGuarded(onRedirect, onError);\n}\n","/**\n * The client capability the authenticated change-password form depends on, plus\n * a ready-made same-origin BFF implementation.\n *\n * As with the device-PIN surfaces, the UI depends on a **structural** shape\n * ({@link ChangePasswordCapableClient}) — exactly one method — so a consuming app\n * may pass the ready-made client below or a thin hand-rolled object. The ready\n * client POSTs to the same-origin BFF and maps the response to a\n * {@link ChangePasswordResult}; it never rejects for an expected outcome.\n *\n * SECURITY: the password values live only in the request the end user's OWN\n * browser sends to their OWN app's BFF over the session cookie. This package\n * neither stores, logs, nor inspects them — it forwards `currentPassword` /\n * `newPassword` to the BFF and reads back only a status code.\n */\nimport {\n createFetchHttpClient,\n type HttpClient,\n type HttpRequest,\n type HttpResponse,\n} from '@dloizides/auth-client';\n\nimport type { ChangePasswordResult } from './ChangePasswordResult';\n\n/** The request body posted to `POST /bff/account/change-password`. */\nexport interface ChangePasswordRequest {\n currentPassword: string;\n newPassword: string;\n}\n\n/** The single-method capability the change-password form needs. */\nexport interface ChangePasswordCapableClient {\n /** Change the signed-in user's password. Resolves a result; never rejects on an expected outcome. */\n changePassword(request: ChangePasswordRequest): Promise<ChangePasswordResult>;\n}\n\n/** Options for {@link createBffChangePasswordClient}. */\nexport interface CreateBffChangePasswordClientOptions {\n /**\n * BFF origin. Omit (the production default) for same-origin — the SPA's own\n * host is the BFF. An explicit origin is useful only for a non-same-origin BFF\n * or for tests.\n */\n baseUrl?: string;\n /**\n * Override the HTTP transport. Defaults to a lazily-resolved native `fetch`\n * (module load stays side-effect-free, so a `fetch`-less test runtime does not\n * blow up on import). Tests pass a fake `HttpClient`.\n */\n http?: HttpClient;\n}\n\n/** The BFF endpoint the ready client posts to. */\nexport const CHANGE_PASSWORD_ENDPOINT = '/bff/account/change-password';\n\n/** BFF double-submit marker header — mirrors `@dloizides/auth-client`'s `BffAuthClient`. */\nconst CSRF_HEADER = 'X-BFF-Csrf';\nconst CSRF_HEADER_VALUE = '1';\nconst JSON_CONTENT_TYPE = 'application/json';\n\nconst HTTP_NO_CONTENT = 204;\nconst HTTP_OK = 200;\nconst HTTP_BAD_REQUEST = 400;\nconst HTTP_UNAUTHORIZED = 401;\n\n/** Lazy same-origin `fetch` transport — resolved per request, never at module load. */\nasync function lazyFetchHttpClient(request: HttpRequest): Promise<HttpResponse> {\n const fetchImpl: typeof fetch | undefined =\n typeof fetch === 'function' ? fetch.bind(globalThis) : undefined;\n if (fetchImpl === undefined) {\n throw new Error('createBffChangePasswordClient: fetch is not available in this environment');\n }\n return createFetchHttpClient(fetchImpl)(request);\n}\n\n/** Map a BFF status code to the discriminated result the form routes on. */\nfunction resultFromStatus(status: number): ChangePasswordResult {\n if (status === HTTP_NO_CONTENT || status === HTTP_OK) {\n return { status: 'success' };\n }\n if (status === HTTP_BAD_REQUEST) {\n return { status: 'invalidCurrent' };\n }\n if (status === HTTP_UNAUTHORIZED) {\n return { status: 'unauthorized' };\n }\n return { status: 'error' };\n}\n\n/**\n * Build a same-origin change-password client. With no arguments this is the exact\n * production wiring: same-origin, lazy `fetch`, session-cookie auth, the BFF CSRF\n * marker header attached. A thrown transport error resolves to `{ status: 'error' }`\n * so the caller never has to catch.\n */\nexport function createBffChangePasswordClient(\n options: CreateBffChangePasswordClientOptions = {},\n): ChangePasswordCapableClient {\n const http = options.http ?? lazyFetchHttpClient;\n const baseUrl = options.baseUrl ?? '';\n const url = `${baseUrl}${CHANGE_PASSWORD_ENDPOINT}`;\n\n return {\n changePassword: async (request: ChangePasswordRequest): Promise<ChangePasswordResult> => {\n try {\n const response = await http({\n url,\n method: 'POST',\n headers: { 'Content-Type': JSON_CONTENT_TYPE, [CSRF_HEADER]: CSRF_HEADER_VALUE },\n body: JSON.stringify({\n currentPassword: request.currentPassword,\n newPassword: request.newPassword,\n }),\n });\n return resultFromStatus(response.status);\n } catch {\n return { status: 'error' };\n }\n },\n };\n}\n"]}
1
+ {"version":3,"sources":["../src/components/useAuthScreenStyles.ts","../src/theme/AuthTheme.ts","../src/theme/AuthThemeProvider.tsx","../src/components/AuthScreen.tsx","../src/components/labels/loginLabels.ts","../src/components/labels/forgotPasswordLabels.ts","../src/components/labels/otpLabels.ts","../src/components/labels/pinLabels.ts","../src/components/labels/devicePinLabels.ts","../src/components/labels/passkeyLabels.ts","../src/components/labels/preferredMethodLabels.ts","../src/components/labels/demoLabels.ts","../src/components/labels/resetPasswordLabels.ts","../src/components/labels/accountSettingsLabels.ts","../src/components/labels/registerLabels.ts","../src/components/testIds.ts","../src/components/useAuthStyles.ts","../src/components/PrefillIntent.ts","../src/components/useLoginPrefill.ts","../src/components/useLoginSubmit.ts","../src/components/useSubmitOnEnter.ts","../src/hooks/useBffAuth.ts","../src/components/LoginForm.tsx","../src/hooks/useBffPasswordHooks.ts","../src/components/ForgotPasswordForm.tsx","../src/hooks/useForgotPasswordSubmit.ts","../src/components/ForgotPasswordFields.tsx","../src/hooks/ResetPasswordError.ts","../src/password/PasswordPolicyError.ts","../src/password/passwordPolicy.ts","../src/hooks/useResetPasswordForm.ts","../src/components/ResetPasswordForm.tsx","../src/components/OtpFormSteps.tsx","../src/hooks/OtpLoginStep.ts","../src/hooks/useOtpLogin.ts","../src/components/OtpForm.tsx","../src/hooks/usePinLogin.ts","../src/components/PinForm.tsx","../src/components/DevicePinInput.tsx","../src/components/interpolate.ts","../src/devicePin/devicePinConstants.ts","../src/components/DevicePinLengthPicker.tsx","../src/devicePin/DevicePinErrorKey.ts","../src/devicePin/useDevicePinUnlock.ts","../src/components/DevicePinUnlockScreen.tsx","../src/devicePin/DevicePinEnrollErrorKey.ts","../src/devicePin/useDevicePinEnroll.ts","../src/components/DevicePinEnrollForm.tsx","../src/components/DevicePinOffer.tsx","../src/devicePin/useDevicePinDisable.ts","../src/components/DevicePinSettingsCard.tsx","../src/passkey/PasskeyCeremonyMode.ts","../src/passkey/browserLocation.ts","../src/passkey/passkeyNavigation.ts","../src/passkey/PasskeyCeremonyStatus.ts","../src/passkey/base64url.ts","../src/passkey/webAuthnCoercion.ts","../src/passkey/usePasskeyCeremony.ts","../src/components/PasskeyLoginButton.tsx","../src/components/PasskeySettingsCard.tsx","../src/preferences/preferredMethodCache.ts","../src/preferences/usePreferredMethodSetting.ts","../src/components/PreferredMethodSettingsCard.tsx","../src/password/ChangePasswordErrorKey.ts","../src/password/useChangePassword.ts","../src/components/ChangePasswordCard.tsx","../src/components/AccountSettingsScreen.tsx","../src/components/PreferredMethodHint.tsx","../src/components/DemoCredentialsBody.tsx","../src/components/DemoCredentialsHintVariant.ts","../src/components/useDemoCredentialsStyles.ts","../src/demo/resolveDemoCredentials.ts","../src/demo/resolveDemoAccounts.ts","../src/components/DemoCredentialsHint.tsx","../src/devicePin/useBffLoginConfig.ts","../src/preferences/preferencesClient.ts","../src/preferences/syncPreferredMethodCache.ts","../src/demo/useDemoCredentials.ts","../src/components/registerTestIds.ts","../src/components/RegisterFormFields.tsx","../src/hooks/RegisterErrorCode.ts","../src/hooks/routeRegisterOutcome.ts","../src/hooks/registerErrors.ts","../src/hooks/useRegisterForm.ts","../src/components/RegisterForm.tsx","../src/client/createBffAuthClient.ts","../src/router/resolvePostLoginRoute.ts","../src/router/resolveAccessibleRoutes.ts","../src/session/performBffLogout.ts","../src/password/changePasswordClient.ts"],"names":["useMemo","styles","jsx","FULL_WIDTH","StyleSheet","PrefillIntent","useState","useCallback","BffAuthStatus","useRef","jsxs","Text","View","Fragment","TextInput","TouchableOpacity","EMAIL_REGEX","useEffect","ActivityIndicator","ResetPasswordError","PasswordPolicyError","OtpLoginStep","toError","isValidEmail","transportErrorFor","Pressable","DevicePinErrorKey","DevicePinEnrollErrorKey","resolveErrorText","PasskeyCeremonyMode","PasskeyCeremonyStatus","ChangePasswordErrorKey","errorMessage","DemoCredentialsHintVariant","RegisterErrorCode","field","Button","isRecord","CSRF_HEADER","CSRF_HEADER_VALUE","JSON_CONTENT_TYPE","HTTP_BAD_REQUEST","lazyFetchHttpClient","createFetchHttpClient"],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * `useAuthScreenStyles` — the StyleSheet for the `<AuthScreen>` whole-composition.\n *\n * Kept separate from `useAuthStyles` (which styles the form *fields*) so the\n * screen-level card chrome — the single surface every auth control shares — is\n * defined in exactly one place. This is the composition that fixes the P1-04\n * \"loose wrapper\" class of bug: apps drop controls INTO this card rather than\n * hand-rolling their own.\n */\nimport { useMemo } from 'react';\n\nimport { StyleSheet, type TextStyle, type ViewStyle } from 'react-native';\n\nimport type { AuthTheme } from '../theme/AuthTheme';\n\n/** The named styles `<AuthScreen>` draws from. */\nexport interface AuthScreenStyles {\n /** Full-bleed, centered background layer. */\n screen: ViewStyle;\n /** The single card surface every auth control shares. */\n card: ViewStyle;\n /** Optional heading at the top of the card. */\n title: TextStyle;\n /** Optional sub-heading under the title. */\n subtitle: TextStyle;\n /** Optional content rendered below/outside the card (e.g. a sign-up footer). */\n footer: ViewStyle;\n}\n\nconst FULL_WIDTH = '100%';\nconst CARD_BORDER_WIDTH = 1;\n\n/**\n * Gap between the top of the viewport and the card, in dp.\n *\n * This replaces `justifyContent: 'center'` — and the replacement is the whole\n * point, so it is worth stating why.\n *\n * A vertically CENTRED card re-centres itself whenever its content grows. The\n * growth is drawn downward, but the card's top edge moves UP by half of it, so\n * every control already on screen shifts under the visitor's cursor. Measured on\n * `app.zygos.dloizides.com/login`: expanding the demo disclosure grew the card\n * 445.6 → 589.6px and pulled the username input from y=275.2 to y=203.2 and the\n * password input from y=368.8 to y=296.8 — 72px UP each, mid-interaction.\n *\n * `<DemoCredentialsHint>` was deliberately mounted BELOW the form to avoid\n * exactly this, and centring defeated that placement. Note the defect is NOT\n * specific to the disclosure: ANY growth shifts the fields — a validation error\n * appearing under an input, a passkey button arriving after the config fetch, an\n * OTP tab swap. Top-anchoring fixes the whole class at once, which is why it is\n * preferred over reserving the disclosure's height (which would leave ~144px of\n * permanent dead space on every login) or absolutely positioning the expanded\n * panel (which removes it from the scrollable area, so on a short viewport the\n * credentials would be unreachable).\n *\n * Small-viewport safety: with a top anchor, content that exceeds the viewport\n * overflows downward ONLY. Under the previous centring it overflowed BOTH ways\n * and the top of the card was clipped past the top edge, unreachable by any\n * scroll. This is therefore strictly better at every viewport size, and needs no\n * `overflow` override to be so.\n */\nconst CARD_TOP_OFFSET = 64;\n\n/** Build the `<AuthScreen>` `StyleSheet` from the resolved theme. */\nexport function useAuthScreenStyles(theme: AuthTheme): AuthScreenStyles {\n return useMemo(() => {\n const { colors, radii, spacing, typography } = theme;\n return StyleSheet.create<AuthScreenStyles>({\n screen: {\n flex: 1,\n // Deliberately NOT `justifyContent: 'center'` — see CARD_TOP_OFFSET.\n justifyContent: 'flex-start',\n alignItems: 'center',\n padding: spacing.md,\n paddingTop: CARD_TOP_OFFSET,\n backgroundColor: colors.background,\n },\n card: {\n width: FULL_WIDTH,\n borderRadius: radii.card,\n borderWidth: CARD_BORDER_WIDTH,\n borderColor: colors.border,\n padding: spacing.xl,\n backgroundColor: colors.surface,\n },\n title: {\n fontSize: typography.title,\n fontWeight: 'bold',\n marginBottom: spacing.xs,\n color: colors.text,\n },\n subtitle: {\n fontSize: typography.subtitle,\n marginBottom: spacing.lg,\n color: colors.textSecondary,\n },\n footer: {\n marginTop: spacing.lg,\n width: FULL_WIDTH,\n alignItems: 'center',\n },\n });\n }, [theme]);\n}\n","/**\n * `AuthTheme` — the design-token contract every `@dloizides/auth-web` component\n * is styled against.\n *\n * The package owns **no** brand. Katalogos, Erevna and Kefi each look different;\n * each one maps its own theme system onto this flat token bag and passes it in\n * (via the `theme` prop or `<AuthThemeProvider>`). The component code only ever\n * reads these tokens — never an app-specific theme object — so the same\n * `<LoginForm>` renders on-brand in three visually distinct apps.\n *\n * Keep this shape minimal and stable: it is a public API surface.\n */\n\n/** Colour tokens — the only colours the auth components reference. */\nexport interface AuthThemeColors {\n /** Page / screen background behind the form card. */\n background: string;\n /** The form card surface colour. */\n surface: string;\n /** Primary text (titles, labels, input text). */\n text: string;\n /** Muted / secondary text (subtitles, helper copy). */\n textSecondary: string;\n /** Input + card border colour; also the disabled-button fill. */\n border: string;\n /** Brand primary — the submit button fill and link colour. */\n primary: string;\n /** Text drawn on top of `primary` (e.g. the submit button label). */\n onPrimary: string;\n /** Error text and error-state borders. */\n danger: string;\n /** Success text (e.g. the forgot-password confirmation). */\n success: string;\n}\n\n/** Corner-radius tokens. */\nexport interface AuthThemeRadii {\n /** Inputs and buttons. */\n input: number;\n /** The form card. */\n card: number;\n}\n\n/** Spacing scale (in density-independent pixels). */\nexport interface AuthThemeSpacing {\n /** Tight gap — e.g. label-to-input. */\n xs: number;\n /** Small gap. */\n sm: number;\n /** Default gap — between stacked fields. */\n md: number;\n /** Large gap — section separation. */\n lg: number;\n /** Card inner padding. */\n xl: number;\n}\n\n/** Font-size tokens. */\nexport interface AuthThemeTypography {\n /** Form title. */\n title: number;\n /** Form subtitle. */\n subtitle: number;\n /**\n * Field labels.\n *\n * The shared forms contract (\"The TWO legitimate label voices\", mirrored in\n * `@dloizides/ui-forms`' `labelVariants.ts`) defines exactly two: `field` —\n * 13 / 600 / sentence case, a label that is READ — and `control` — 11 / 700 /\n * uppercase, a label that is SCANNED. Auth field labels are prose addressed to\n * the person signing in, so they are the `field` voice: **13**.\n *\n * Through 1.13.0 this default was 14, which is neither voice — drift. Every\n * portal that renders `<LoginForm>` inherits this token (all of them reuse\n * `defaultAuthTheme.typography` verbatim), so the drift was uniform across\n * zygos, agora, erevna, katalogos and ichnos, and it read against the 13px\n * `Field` labels those same apps use on every non-auth form.\n */\n label: number;\n /** Input text and button text. */\n body: number;\n /** Helper / error / footer copy. */\n caption: number;\n}\n\n/** The full token bag a consuming app supplies. */\nexport interface AuthTheme {\n colors: AuthThemeColors;\n radii: AuthThemeRadii;\n spacing: AuthThemeSpacing;\n typography: AuthThemeTypography;\n}\n\n/**\n * A neutral, accessible light-mode theme. Apps are expected to override this —\n * it exists so a component renders sensibly with zero configuration and so\n * `<AuthThemeProvider>` has a default value.\n */\nexport const defaultAuthTheme: AuthTheme = {\n colors: {\n background: '#f5f5f7',\n surface: '#ffffff',\n text: '#1a1a1a',\n textSecondary: '#6b6b6b',\n border: '#d0d0d5',\n primary: '#2563eb',\n onPrimary: '#ffffff',\n danger: '#d33333',\n success: '#1f7a3d',\n },\n radii: {\n input: 8,\n card: 12,\n },\n spacing: {\n xs: 8,\n sm: 12,\n md: 20,\n lg: 32,\n xl: 24,\n },\n typography: {\n title: 28,\n subtitle: 16,\n // 13, not 14 — the shared contract's `field` voice. See AuthThemeTypography.label.\n label: 13,\n body: 16,\n caption: 12,\n },\n};\n","/**\n * React context for the `AuthTheme`.\n *\n * Two ways to theme `@dloizides/auth-web` components:\n *\n * 1. Wrap the auth screens in `<AuthThemeProvider theme={appAuthTheme}>` —\n * every component below reads the theme from context.\n * 2. Pass `theme` directly as a prop to an individual component — the prop\n * always wins over context.\n *\n * With neither, components fall back to `defaultAuthTheme`. `useAuthTheme()`\n * implements that precedence (prop → context → default) so each component does\n * not re-derive it.\n */\nimport { createContext, useContext, useMemo, type ReactElement, type ReactNode } from 'react';\n\nimport { defaultAuthTheme, type AuthTheme } from './AuthTheme';\n\nconst AuthThemeContext = createContext<AuthTheme>(defaultAuthTheme);\n\nexport interface AuthThemeProviderProps {\n /** The token bag every descendant auth component is styled against. */\n theme: AuthTheme;\n children: ReactNode;\n}\n\n/** Provides an `AuthTheme` to every `@dloizides/auth-web` component below it. */\nexport function AuthThemeProvider({\n theme,\n children,\n}: Readonly<AuthThemeProviderProps>): ReactElement {\n return <AuthThemeContext.Provider value={theme}>{children}</AuthThemeContext.Provider>;\n}\n\n/**\n * Resolve the effective theme for a component.\n *\n * Precedence: an explicit `themeProp` (if given) wins over the context value,\n * which itself defaults to `defaultAuthTheme` when no provider is mounted.\n */\nexport function useAuthTheme(themeProp?: AuthTheme): AuthTheme {\n const contextTheme = useContext(AuthThemeContext);\n return useMemo(() => themeProp ?? contextTheme, [themeProp, contextTheme]);\n}\n","/**\n * `<AuthScreen>` — the screen-level auth composition, extracted from Kefi's\n * login card (the design reference) so every app gets ONE tidy card instead of\n * hand-rolling its own wrapper.\n *\n * The package's forms (`<LoginForm>`, `<OtpForm>`, `<PinForm>`) each render their\n * own `screen` + `card` chrome by default (drop-one-in-on-a-blank-route mode).\n * When an app needs to compose several controls (method tabs + a form + a passkey\n * button + a hint) onto ONE surface, it renders them as `chromeless` children of\n * an `<AuthScreen>`: the AuthScreen owns the single card, the forms contribute\n * fields only. This makes the P1-04 \"loose wrapper\" bug impossible by\n * construction — the app can no longer assemble a card with the wrong (or no)\n * surface, border, padding or width.\n *\n * Slots mirror Kefi's login composition exactly: an optional `title`/`subtitle`\n * at the top of the card, the `children` (the auth controls), and an optional\n * `footer` rendered OUTSIDE the card (Kefi's sign-up footer sits below it).\n */\nimport { type ReactElement, type ReactNode } from 'react';\n\nimport { Text, View } from 'react-native';\n\nimport { useAuthScreenStyles } from './useAuthScreenStyles';\nimport { useAuthTheme } from '../theme/AuthThemeProvider';\n\nimport type { AuthTheme } from '../theme/AuthTheme';\n\n/**\n * Default auth-card max width, in dp. Matches the package's standalone form card\n * so a single `<LoginForm>` and an `<AuthScreen>`-composed login read the same\n * width unless the app overrides it.\n */\nexport const DEFAULT_AUTH_CARD_MAX_WIDTH = 420;\n\nexport interface AuthScreenProps {\n /** The auth controls placed on the shared card (forms should be `chromeless`). */\n children: ReactNode;\n /** Explicit theme; overrides any `<AuthThemeProvider>`. Falls back to the default theme. */\n theme?: AuthTheme;\n /** testID on the outer full-screen centering container. */\n testID?: string;\n /** testID on the inner card surface. */\n cardTestID?: string;\n /** Max card width in dp. Defaults to {@link DEFAULT_AUTH_CARD_MAX_WIDTH}. */\n maxWidth?: number;\n /** Optional heading rendered at the top of the card. */\n title?: string;\n /** Optional sub-heading rendered under the title. */\n subtitle?: string;\n /** Optional content rendered below/outside the card (e.g. a sign-up footer). */\n footer?: ReactNode;\n}\n\n/** The screen-level auth composition: one centered card the controls share. */\nexport function AuthScreen({\n children,\n theme: themeProp,\n testID,\n cardTestID,\n maxWidth = DEFAULT_AUTH_CARD_MAX_WIDTH,\n title,\n subtitle,\n footer,\n}: Readonly<AuthScreenProps>): ReactElement {\n const theme = useAuthTheme(themeProp);\n const styles = useAuthScreenStyles(theme);\n\n return (\n <View style={styles.screen} testID={testID}>\n <View style={[styles.card, { maxWidth }]} testID={cardTestID}>\n {title !== undefined ? <Text style={styles.title}>{title}</Text> : null}\n {subtitle !== undefined ? <Text style={styles.subtitle}>{subtitle}</Text> : null}\n {children}\n </View>\n {footer !== undefined ? <View style={[styles.footer, { maxWidth }]}>{footer}</View> : null}\n </View>\n );\n}\n","/** Strings rendered by `<LoginForm>`. */\nexport interface LoginFormLabels {\n title: string;\n subtitle: string;\n usernameLabel: string;\n usernamePlaceholder: string;\n passwordLabel: string;\n passwordPlaceholder: string;\n submit: string;\n /** Shown while the login request is in flight. */\n submitting: string;\n /** The \"Forgot password?\" link text. */\n forgotPassword: string;\n /** The \"Create account\" link shown below the submit button when an\n * `onSignUp` handler is supplied. Omit the handler to hide the link. */\n signUp: string;\n /** Generic credentials-rejected message. */\n invalidCredentials: string;\n /** Shown when one or both fields are empty on submit. */\n missingFields: string;\n}\n\nexport const DEFAULT_LOGIN_LABELS: LoginFormLabels = {\n title: 'Sign in',\n subtitle: 'Welcome back',\n usernameLabel: 'Username',\n usernamePlaceholder: 'Enter your username',\n passwordLabel: 'Password',\n passwordPlaceholder: 'Enter your password',\n submit: 'Sign in',\n submitting: 'Signing in...',\n forgotPassword: 'Forgot password?',\n signUp: 'Create an account',\n invalidCredentials: 'Incorrect username or password.',\n missingFields: 'Enter both your username and password.',\n};\n","/** Strings rendered by `<ForgotPasswordForm>`. */\nexport interface ForgotPasswordFormLabels {\n title: string;\n /** Copy above the email field. */\n description: string;\n emailLabel: string;\n emailPlaceholder: string;\n submit: string;\n submitting: string;\n /** Generic confirmation, shown regardless of whether the email is registered. */\n successMessage: string;\n /** Shown on a network / 5xx failure. */\n networkError: string;\n /** Shown when the entered value is not a valid email. */\n invalidEmail: string;\n}\n\n/**\n * Strings rendered by `<ForgotPasswordFields>` — the embedded modal body. It is\n * the forgot-password form plus the two modal affordances (`cancel` alongside\n * submit, `close` on the success state) that a screen-shaped form has no need of.\n */\nexport interface ForgotPasswordFieldsLabels extends ForgotPasswordFormLabels {\n /** The \"cancel\" button shown alongside submit. */\n cancel: string;\n /** The \"close\" button shown on the success state. */\n close: string;\n}\n\nexport const DEFAULT_FORGOT_PASSWORD_LABELS: ForgotPasswordFormLabels = {\n title: 'Forgot password',\n description: 'Enter your email and we will send you a reset link.',\n emailLabel: 'Email',\n emailPlaceholder: 'Enter your email',\n submit: 'Send reset link',\n submitting: 'Sending...',\n successMessage: 'If that email is registered, a reset link is on its way.',\n networkError: 'Something went wrong. Please try again.',\n invalidEmail: 'Enter a valid email address.',\n};\n\nexport const DEFAULT_FORGOT_PASSWORD_FIELDS_LABELS: ForgotPasswordFieldsLabels = {\n ...DEFAULT_FORGOT_PASSWORD_LABELS,\n cancel: 'Cancel',\n close: 'Close',\n};\n","/** Strings rendered by `<OtpForm>` — the two-step email-OTP login form. */\nexport interface OtpFormLabels {\n // ── Step 1: request a code ────────────────────────────────────────────────\n /** Title shown on the request-a-code step. */\n requestTitle: string;\n /** Copy above the email field. */\n requestDescription: string;\n emailLabel: string;\n emailPlaceholder: string;\n /** The \"send code\" button. */\n requestSubmit: string;\n /** Shown while the request is in flight. */\n requesting: string;\n /** Shown when the entered value is not a valid email. */\n invalidEmail: string;\n\n // ── Step 2: enter the code ────────────────────────────────────────────────\n /** Title shown on the enter-the-code step. */\n verifyTitle: string;\n /** Copy above the code field; `{identifier}` is replaced with the email. */\n verifyDescription: string;\n codeLabel: string;\n codePlaceholder: string;\n /** The \"verify\" button. */\n verifySubmit: string;\n /** Shown while verification is in flight. */\n verifying: string;\n /** Shown when the code field is empty on submit. */\n missingCode: string;\n /** Generic \"that code was wrong / expired\" message. */\n invalidCode: string;\n\n // ── Step 2 affordances ────────────────────────────────────────────────────\n /** The \"resend code\" link text. */\n resend: string;\n /** Shown while a resend is in flight. */\n resending: string;\n /** The \"use a different email\" link text — returns to step 1. */\n changeEmail: string;\n}\n\nexport const DEFAULT_OTP_LABELS: OtpFormLabels = {\n requestTitle: 'Sign in with a code',\n requestDescription: 'Enter your email and we will send you a one-time code.',\n emailLabel: 'Email',\n emailPlaceholder: 'Enter your email',\n requestSubmit: 'Send code',\n requesting: 'Sending...',\n invalidEmail: 'Enter a valid email address.',\n verifyTitle: 'Enter your code',\n verifyDescription: 'We sent a one-time code to {identifier}.',\n codeLabel: 'One-time code',\n codePlaceholder: 'Enter the code',\n verifySubmit: 'Verify',\n verifying: 'Verifying...',\n missingCode: 'Enter the code we emailed you.',\n invalidCode: 'That code is incorrect or has expired.',\n resend: 'Resend code',\n resending: 'Resending...',\n changeEmail: 'Use a different email',\n};\n","/** Strings rendered by `<PinForm>` — the single-step event-PIN login form. */\nexport interface PinFormLabels {\n /** Title shown above the PIN field. */\n title: string;\n /** Copy above the PIN field. */\n description: string;\n pinLabel: string;\n pinPlaceholder: string;\n /** The \"sign in\" button. */\n submit: string;\n /** Shown while the PIN exchange is in flight. */\n submitting: string;\n /** Shown when the PIN field is empty on submit. */\n missingPin: string;\n /** Generic \"that PIN was wrong / expired / locked out\" message. */\n invalidPin: string;\n}\n\nexport const DEFAULT_PIN_LABELS: PinFormLabels = {\n title: 'Enter your event PIN',\n description: 'Enter the PIN for this event to sign in.',\n pinLabel: 'PIN',\n pinPlaceholder: 'Enter your PIN',\n submit: 'Sign in',\n submitting: 'Signing in...',\n missingPin: 'Enter your event PIN.',\n invalidPin: 'That PIN is incorrect, has expired, or is locked out.',\n};\n","/**\n * Strings rendered by `<DevicePinUnlockScreen>` — the returning-device unlock\n * gate. `{name}` / `{count}` placeholders are substituted by the component.\n */\nexport interface DevicePinUnlockLabels {\n /** Greeting with the remembered username; `{name}` is substituted. */\n title: string;\n /** Greeting when no username is remembered. */\n titleNoName: string;\n /** Copy above the PIN pad; `{count}` is substituted with the PIN length. */\n description: string;\n pinLabel: string;\n pinPlaceholder: string;\n /** The \"unlock\" submit button. */\n submit: string;\n /** Shown while the unlock is in flight. */\n submitting: string;\n /** The \"sign in with password instead\" escape link. */\n usePasswordInstead: string;\n /** Accessibility hint for the escape link. */\n usePasswordHint: string;\n /** Error: not enough digits entered; `{count}` is substituted. */\n errorIncomplete: string;\n /** Error: wrong PIN / unknown device (generic). */\n errorInvalid: string;\n /** Error: locked out, no retry hint. */\n errorLockedOut: string;\n /** Error: locked out with a retry hint; `{count}` is the seconds. */\n errorLockedOutRetry: string;\n /** Error: rate-limited, no retry hint. */\n errorRateLimited: string;\n /** Error: rate-limited with a retry hint; `{count}` is the seconds. */\n errorRateLimitedRetry: string;\n /** Error: anything else (network / unexpected). */\n errorGeneric: string;\n /** Accessibility label for a filled PIN dot. */\n digitFilledHint: string;\n /** Accessibility label for an empty PIN dot. */\n digitEmptyHint: string;\n}\n\n/**\n * Strings rendered by `<DevicePinEnrollForm>` (and the length picker it hosts)\n * plus the `<DevicePinOffer>` wrapper. `{count}` placeholders are substituted.\n */\nexport interface DevicePinEnrollLabels {\n // ── Offer (post-login skippable card) ─────────────────────────────────────\n offerTitle: string;\n offerDescription: string;\n offerAccept: string;\n offerAcceptHint: string;\n offerSkip: string;\n offerSkipHint: string;\n\n // ── Enrol form ────────────────────────────────────────────────────────────\n formTitle: string;\n /** Copy above the form; `{count}` is substituted with the chosen length. */\n formDescription: string;\n lengthLabel: string;\n /** Accessibility hint for a length pill; `{count}` is substituted. */\n lengthOptionHint: string;\n pinLabel: string;\n pinPlaceholder: string;\n confirmLabel: string;\n confirmPlaceholder: string;\n submit: string;\n submitting: string;\n cancel: string;\n cancelHint: string;\n /** Error: PINs do not match / wrong length; `{count}` is substituted. */\n errorMismatch: string;\n /** Error: the current session is not authenticated. */\n errorUnauthorized: string;\n /** Error: the session already has a PIN / is forbidden. */\n errorForbidden: string;\n /** Error: the PIN failed server-side validation. */\n errorInvalidPin: string;\n /** Error: any other failure. */\n errorFailed: string;\n}\n\n/** Strings rendered by `<DevicePinSettingsCard>` — the account toggle. */\nexport interface DevicePinSettingsLabels {\n title: string;\n description: string;\n /** Status line when a device PIN is enabled. */\n statusEnabled: string;\n /** Status line when no device PIN is set. */\n statusDisabled: string;\n /** The \"enable\" button. */\n enable: string;\n enableHint: string;\n /** The \"disable\" button. */\n disable: string;\n disableHint: string;\n /** Shown while disabling is in flight. */\n disabling: string;\n /** Error shown when disabling fails. */\n disableFailed: string;\n}\n\nexport const DEFAULT_DEVICE_PIN_UNLOCK_LABELS: DevicePinUnlockLabels = {\n title: 'Welcome back, {name}',\n titleNoName: 'Welcome back',\n description: 'Enter your {count}-digit PIN to sign in on this device.',\n pinLabel: 'PIN',\n pinPlaceholder: 'Enter your PIN',\n submit: 'Unlock',\n submitting: 'Signing in...',\n usePasswordInstead: 'Sign in with password instead',\n usePasswordHint: 'Switch to signing in with your username and password',\n errorIncomplete: 'Enter all {count} digits of your PIN.',\n errorInvalid: 'That PIN is incorrect. Try again.',\n errorLockedOut: 'Too many attempts. Try again later.',\n errorLockedOutRetry: 'Too many attempts. Try again in {count} seconds.',\n errorRateLimited: 'Too many requests. Try again later.',\n errorRateLimitedRetry: 'Too many requests. Try again in {count} seconds.',\n errorGeneric: 'Something went wrong. Try again, or sign in with your password.',\n digitFilledHint: 'PIN digit entered',\n digitEmptyHint: 'PIN digit not yet entered',\n};\n\nexport const DEFAULT_DEVICE_PIN_ENROLL_LABELS: DevicePinEnrollLabels = {\n offerTitle: 'Set a PIN for faster sign-in?',\n offerDescription:\n 'Next time, sign in on this device with a short PIN instead of your full password.',\n offerAccept: 'Set up a PIN',\n offerAcceptHint: 'Open the form to choose a quick sign-in PIN',\n offerSkip: 'Not now',\n offerSkipHint: 'Dismiss the PIN setup offer',\n formTitle: 'Choose your PIN',\n formDescription:\n 'Pick a {count}-digit PIN you will remember. You will use it to sign in on this device.',\n lengthLabel: 'PIN length',\n lengthOptionHint: 'Use a {count}-digit PIN',\n pinLabel: 'New PIN',\n pinPlaceholder: 'Enter a new PIN',\n confirmLabel: 'Confirm PIN',\n confirmPlaceholder: 'Re-enter your PIN',\n submit: 'Save PIN',\n submitting: 'Saving...',\n cancel: 'Cancel',\n cancelHint: 'Close the PIN setup form without saving',\n errorMismatch: 'The PINs must match and be exactly {count} digits.',\n errorUnauthorized: 'Your session has expired. Sign in again to set a PIN.',\n errorForbidden: 'A PIN is already set for this session.',\n errorInvalidPin: 'That PIN is not allowed. Choose a different one.',\n errorFailed: 'Could not set your PIN. Try again later.',\n};\n\nexport const DEFAULT_DEVICE_PIN_SETTINGS_LABELS: DevicePinSettingsLabels = {\n title: 'Quick PIN sign-in',\n description: 'Sign in on this device with a short PIN instead of your full password.',\n statusEnabled: 'Quick PIN sign-in is enabled on this device.',\n statusDisabled: 'Quick PIN sign-in is off.',\n enable: 'Enable quick PIN sign-in',\n enableHint: 'Set a PIN so you can sign in faster on this device',\n disable: 'Disable',\n disableHint: 'Remove the PIN sign-in from this device',\n disabling: 'Disabling...',\n disableFailed: 'Could not disable PIN sign-in. Try again later.',\n};\n","/** Strings rendered by `<PasskeyLoginButton>` — the login-surface passkey CTA. */\nexport interface PasskeyLoginLabels {\n /** The \"sign in with a passkey\" button. */\n signInButton: string;\n signInHint: string;\n /** Error banner when the ceremony was cancelled. */\n errorCancelled: string;\n /** Error banner when the ceremony failed. */\n errorFailed: string;\n /**\n * The \"try another way\" affordance shown after an in-page ceremony error — it\n * hands off to the Keycloak-hosted passkey/password flow. This is the seam that\n * rescues a user whose credential is only enrolled in Keycloak (not the in-page\n * RP store): the in-page ceremony can't see it, so they fall back to KC.\n */\n tryAnotherWay: string;\n}\n\n/** Strings rendered by `<PasskeySettingsCard>` — the account passkey card. */\nexport interface PasskeySettingsLabels {\n title: string;\n description: string;\n /** Italic hint about the re-auth step. */\n reauthHint: string;\n /** The \"add a passkey\" button. */\n addButton: string;\n addHint: string;\n /** Success line shown after returning from a registration. */\n registeredSuccess: string;\n}\n\nexport const DEFAULT_PASSKEY_LOGIN_LABELS: PasskeyLoginLabels = {\n signInButton: 'Sign in with a passkey',\n signInHint: 'Use your fingerprint, face, or security key to sign in',\n errorCancelled:\n 'Passkey sign-in was cancelled. You can try again or sign in another way.',\n errorFailed: \"Passkey sign-in didn't work. Try again, or sign in another way.\",\n tryAnotherWay: 'Sign in another way',\n};\n\nexport const DEFAULT_PASSKEY_SETTINGS_LABELS: PasskeySettingsLabels = {\n title: 'Passkeys',\n description:\n 'Add a passkey to sign in with your fingerprint, face, or a security key instead of a password.',\n reauthHint: \"You'll be asked to confirm your password before adding a passkey.\",\n addButton: 'Add a passkey',\n addHint: 'Start setting up a passkey for this account',\n registeredSuccess: 'Your passkey was added. You can now use it to sign in.',\n};\n","/** Strings rendered by `<PreferredMethodSettingsCard>` — the cross-device default-method picker. */\nexport interface PreferredMethodSettingsLabels {\n title: string;\n description: string;\n /** The \"no preference / ask me each time\" option. */\n noPreference: string;\n /** Display name for the password method option. */\n methodPassword: string;\n /** Display name for the device-PIN method option. */\n methodPin: string;\n /** Display name for the passkey method option. */\n methodPasskey: string;\n /** Shown while a selection is being saved. */\n saving: string;\n /** Error shown when saving the preference fails. */\n saveFailed: string;\n}\n\n/** Strings rendered by `<PreferredMethodHint>` — the login-screen \"you usually sign in with…\" line. */\nexport interface PreferredMethodHintLabels {\n /** Full sentence shown when the cached preference is password. */\n password: string;\n /** Full sentence shown when the cached preference is device-PIN. */\n pin: string;\n /** Full sentence shown when the cached preference is passkey. */\n passkey: string;\n}\n\nexport const DEFAULT_PREFERRED_METHOD_SETTINGS_LABELS: PreferredMethodSettingsLabels = {\n title: 'Preferred sign-in method',\n description:\n 'Pick how you usually sign in. We will show this method first on your devices.',\n noPreference: 'No preference',\n methodPassword: 'Password',\n methodPin: 'Quick PIN',\n methodPasskey: 'Passkey',\n saving: 'Saving...',\n saveFailed: 'Could not save your preference. Try again later.',\n};\n\nexport const DEFAULT_PREFERRED_METHOD_HINT_LABELS: PreferredMethodHintLabels = {\n password: 'You usually sign in with your password.',\n pin: 'You usually sign in with your quick PIN on this account.',\n passkey: 'You usually sign in with a passkey.',\n};\n","/** Strings rendered by `<DemoCredentialsHint>` — the public-demo credentials panel. */\nexport interface DemoCredentialsHintLabels {\n /** Panel heading (e.g. \"Demo access\"). */\n title: string;\n /** Copy under the heading explaining what the demo account is. */\n description: string;\n /** Row label for the demo username. */\n usernameLabel: string;\n /** Row label for the demo password. */\n passwordLabel: string;\n /** The \"use these credentials\" button that fills the login form. */\n useCredentials: string;\n /** Accessibility hint for that button. */\n useCredentialsHint: string;\n /**\n * The collapsed disclosure trigger (e.g. \"Try the demo\").\n *\n * Keep the word \"demo\" in it. This one line is the ONLY thing an evaluator\n * scanning the page has to find, so it must be searchable by the word they\n * are looking for — a coy label like \"Just looking?\" is discreet at the cost\n * of being undiscoverable, which defeats the point of shipping a demo.\n */\n toggle: string;\n /** Accessibility hint for the disclosure trigger. */\n toggleHint: string;\n}\n\nexport const DEFAULT_DEMO_CREDENTIALS_HINT_LABELS: DemoCredentialsHintLabels = {\n title: 'Demo access',\n description: 'Explore the full product with our shared demo account.',\n usernameLabel: 'Username',\n passwordLabel: 'Password',\n useCredentials: 'Use these credentials',\n useCredentialsHint: 'Fill the sign-in form with the demo username and password',\n toggle: 'Try the demo',\n toggleHint: 'Show the demo account username and password',\n};\n","/** Strings rendered by `<ResetPasswordForm>`. */\nexport interface ResetPasswordFormLabels {\n title: string;\n description: string;\n newPasswordLabel: string;\n newPasswordPlaceholder: string;\n confirmPasswordLabel: string;\n confirmPasswordPlaceholder: string;\n submit: string;\n submitting: string;\n /** Error: one or both fields empty. */\n errorEmpty: string;\n /** Error: the new password fails the policy. */\n errorWeakPassword: string;\n /** Error: confirm does not match. */\n errorMismatch: string;\n /** Error: the reset token is missing / expired / consumed. */\n errorTokenInvalid: string;\n /** Error: a network / 5xx failure. */\n errorNetwork: string;\n}\n\nexport const DEFAULT_RESET_PASSWORD_LABELS: ResetPasswordFormLabels = {\n title: 'Reset password',\n description: 'Choose a new password for your account.',\n newPasswordLabel: 'New password',\n newPasswordPlaceholder: 'Enter a new password',\n confirmPasswordLabel: 'Confirm password',\n confirmPasswordPlaceholder: 'Re-enter the new password',\n submit: 'Reset password',\n submitting: 'Resetting...',\n errorEmpty: 'Fill in both password fields.',\n errorWeakPassword:\n 'Use at least 8 characters with an uppercase letter, a lowercase letter and a digit.',\n errorMismatch: 'The passwords do not match.',\n errorTokenInvalid: 'This reset link is invalid or has expired. Request a new one.',\n errorNetwork: 'Something went wrong. Please try again.',\n};\n","/**\n * Strings rendered by `<AccountSettingsScreen>` and its `ChangePasswordCard`.\n *\n * As with every auth label bag, the consuming app supplies already-localised\n * strings; the `DEFAULT_*` English constant lets the screen render with no\n * `labels` prop and lets an app spread-override only the keys it cares about.\n */\n\n/** Strings for the account-settings screen shell + the in-app change-password form. */\nexport interface AccountSettingsLabels {\n /** The screen heading above the stacked settings cards. */\n heading: string;\n\n // ── Change-password card ────────────────────────────────────────────────────\n /** Card title. */\n changePasswordTitle: string;\n /** Card body copy above the fields. */\n changePasswordDescription: string;\n currentPasswordLabel: string;\n currentPasswordPlaceholder: string;\n newPasswordLabel: string;\n newPasswordPlaceholder: string;\n confirmPasswordLabel: string;\n confirmPasswordPlaceholder: string;\n /** Submit button. */\n submit: string;\n /** Shown while the submit is in flight. */\n submitting: string;\n /** Accessibility hint for the submit button. */\n submitHint: string;\n /** Shown after a successful change. */\n success: string;\n\n // ── Error messages (one per ChangePasswordErrorKey) ─────────────────────────\n /** New password fails the shared policy. */\n errorWeakNewPassword: string;\n /** New password and confirmation do not match. */\n errorMismatch: string;\n /** Current password field left blank. */\n errorCurrentRequired: string;\n /** BFF 400 — current password wrong or new one rejected server-side. */\n errorInvalidCurrent: string;\n /** BFF 401 — session not authenticated. */\n errorUnauthorized: string;\n /** Any other failure. */\n errorFailed: string;\n}\n\nexport const DEFAULT_ACCOUNT_SETTINGS_LABELS: AccountSettingsLabels = {\n heading: 'Account settings',\n\n changePasswordTitle: 'Change password',\n changePasswordDescription: 'Update the password you use to sign in.',\n currentPasswordLabel: 'Current password',\n currentPasswordPlaceholder: 'Enter your current password',\n newPasswordLabel: 'New password',\n newPasswordPlaceholder: 'Enter a new password',\n confirmPasswordLabel: 'Confirm new password',\n confirmPasswordPlaceholder: 'Re-enter your new password',\n submit: 'Change password',\n submitting: 'Changing password...',\n submitHint: 'Submit the form to change your password',\n success: 'Your password has been changed.',\n\n errorWeakNewPassword:\n 'Your new password must be at least 8 characters and include an uppercase letter, a lowercase letter and a number.',\n errorMismatch: 'The new password and its confirmation do not match.',\n errorCurrentRequired: 'Enter your current password.',\n errorInvalidCurrent: 'Your current password is incorrect, or the new password does not meet the policy.',\n errorUnauthorized: 'Your session has expired. Sign in again to change your password.',\n errorFailed: 'Could not change your password. Try again later.',\n};\n","import type { RegisterInputField } from '../../hooks/registerTypes';\n\n/** Copy for one visible registration input. */\nexport interface RegisterFieldLabels {\n /** Visible label above the input. */\n label: string;\n placeholder: string;\n /** `accessibilityHint` for the input. */\n hint: string;\n /** `accessibilityLabel` for the input. */\n inputLabel: string;\n}\n\n/** Strings rendered by `<RegisterForm>`. Error copy is not here: the app maps `RegisterErrorCode`. */\nexport interface RegisterFormLabels {\n title: string;\n subtitle: string;\n submit: string;\n /** `accessibilityHint` for the submit button. */\n submitHint: string;\n /** `accessibilityLabel` for the submit button while the request runs. */\n submitting: string;\n fields: Record<RegisterInputField, RegisterFieldLabels>;\n}\n\nfunction field(label: string, placeholder: string): RegisterFieldLabels {\n return { label, placeholder, hint: placeholder, inputLabel: label };\n}\n\nexport const DEFAULT_REGISTER_LABELS: RegisterFormLabels = {\n title: 'Create account',\n subtitle: 'Sign up to get started',\n submit: 'Create account',\n submitHint: 'Creates your account',\n submitting: 'Creating account...',\n fields: {\n firstName: field('First name', 'Enter your first name'),\n lastName: field('Last name', 'Enter your last name'),\n username: field('Username', 'Choose a username'),\n email: field('Email', 'Enter your email'),\n password: field('Password', 'Choose a password'),\n confirmPassword: field('Confirm password', 'Repeat your password'),\n tenantName: field('Organisation name', 'Enter your organisation name'),\n },\n};\n","/**\n * Stable `testID` values for every interactive element the auth components\n * render. Exported so E2E suites and unit tests reference one source of truth\n * rather than hard-coding string literals.\n *\n * Each component also accepts a `testIdPrefix` prop; when set, these base IDs\n * are prefixed so two forms can coexist on one screen without ID collisions.\n *\n * `sonarjs/no-hardcoded-passwords` is disabled for this file: it flags keys\n * such as `loginPasswordInput`, but every value here is a UI test ID, not a\n * credential. There are no secrets in this module.\n */\n/* eslint-disable sonarjs/no-hardcoded-passwords */\nexport const AuthTestIds = {\n loginForm: 'auth-login-form',\n loginUsernameInput: 'auth-login-username',\n loginPasswordInput: 'auth-login-password',\n loginSubmitButton: 'auth-login-submit',\n loginForgotLink: 'auth-login-forgot-link',\n loginSignUpLink: 'auth-login-signup-link',\n loginError: 'auth-login-error',\n\n forgotPasswordForm: 'auth-forgot-form',\n forgotPasswordEmailInput: 'auth-forgot-email',\n forgotPasswordSubmitButton: 'auth-forgot-submit',\n forgotPasswordCancelButton: 'auth-forgot-cancel',\n forgotPasswordCloseButton: 'auth-forgot-close',\n forgotPasswordError: 'auth-forgot-error',\n forgotPasswordSuccess: 'auth-forgot-success',\n\n resetPasswordForm: 'auth-reset-form',\n resetPasswordNewInput: 'auth-reset-new',\n resetPasswordConfirmInput: 'auth-reset-confirm',\n resetPasswordSubmitButton: 'auth-reset-submit',\n resetPasswordError: 'auth-reset-error',\n\n otpForm: 'auth-otp-form',\n otpEmailInput: 'auth-otp-email',\n otpRequestButton: 'auth-otp-request',\n otpCodeInput: 'auth-otp-code',\n otpVerifyButton: 'auth-otp-verify',\n otpResendButton: 'auth-otp-resend',\n otpChangeEmailButton: 'auth-otp-change-email',\n otpError: 'auth-otp-error',\n\n pinForm: 'auth-pin-form',\n pinInput: 'auth-pin-input',\n pinSubmitButton: 'auth-pin-submit',\n pinError: 'auth-pin-error',\n\n // Device-PIN unlock gate\n devicePinUnlock: 'auth-device-pin-unlock',\n devicePinUnlockInput: 'auth-device-pin-unlock-input',\n devicePinUnlockSubmit: 'auth-device-pin-unlock-submit',\n devicePinUnlockUsePassword: 'auth-device-pin-unlock-use-password',\n devicePinUnlockError: 'auth-device-pin-unlock-error',\n\n // Device-PIN enrol form + length picker\n devicePinEnrollForm: 'auth-device-pin-enroll-form',\n devicePinEnrollLength: 'auth-device-pin-enroll-length',\n devicePinEnrollPin: 'auth-device-pin-enroll-pin',\n devicePinEnrollConfirm: 'auth-device-pin-enroll-confirm',\n devicePinEnrollSubmit: 'auth-device-pin-enroll-submit',\n devicePinEnrollCancel: 'auth-device-pin-enroll-cancel',\n devicePinEnrollError: 'auth-device-pin-enroll-error',\n\n // Device-PIN offer (post-login)\n devicePinOffer: 'auth-device-pin-offer',\n devicePinOfferAccept: 'auth-device-pin-offer-accept',\n devicePinOfferSkip: 'auth-device-pin-offer-skip',\n\n // Device-PIN settings card\n devicePinSettings: 'auth-device-pin-settings',\n devicePinSettingsStatus: 'auth-device-pin-settings-status',\n devicePinSettingsEnable: 'auth-device-pin-settings-enable',\n devicePinSettingsDisable: 'auth-device-pin-settings-disable',\n devicePinSettingsError: 'auth-device-pin-settings-error',\n\n // Passkey login button\n passkeyLogin: 'auth-passkey-login',\n passkeyLoginButton: 'auth-passkey-login-button',\n passkeyLoginError: 'auth-passkey-login-error',\n passkeyLoginFallback: 'auth-passkey-login-fallback',\n\n // Passkey settings card\n passkeySettings: 'auth-passkey-settings',\n passkeySettingsAdd: 'auth-passkey-settings-add',\n passkeySettingsSuccess: 'auth-passkey-settings-success',\n\n // Preferred-method settings card (cross-device default-method picker).\n // Each option row appends `-${method}` to `preferredMethodSettingsOption`.\n preferredMethodSettings: 'auth-preferred-method-settings',\n preferredMethodSettingsOption: 'auth-preferred-method-settings-option',\n preferredMethodSettingsError: 'auth-preferred-method-settings-error',\n\n // Preferred-method login-screen hint\n preferredMethodHint: 'auth-preferred-method-hint',\n\n // Account-settings screen shell + in-app change-password form\n accountSettings: 'auth-account-settings',\n accountSettingsChangePassword: 'auth-account-settings-change-password',\n changePasswordCurrentInput: 'auth-change-password-current',\n changePasswordNewInput: 'auth-change-password-new',\n changePasswordConfirmInput: 'auth-change-password-confirm',\n changePasswordSubmit: 'auth-change-password-submit',\n changePasswordError: 'auth-change-password-error',\n changePasswordSuccess: 'auth-change-password-success',\n\n // Public-demo credentials panel\n demoCredentialsHint: 'auth-demo-credentials-hint',\n // Per-account heading, present only when >1 account is published (multi-account).\n demoCredentialsAccountLabel: 'auth-demo-credentials-account-label',\n demoCredentialsUsername: 'auth-demo-credentials-username',\n demoCredentialsPassword: 'auth-demo-credentials-password',\n demoCredentialsUseButton: 'auth-demo-credentials-use',\n // The collapsed disclosure trigger (`disclosure` variant only).\n demoCredentialsToggle: 'auth-demo-credentials-toggle',\n} as const;\n\n/** Apply an optional prefix to a base test ID. */\nexport function withTestIdPrefix(baseId: string, prefix?: string): string {\n return prefix === undefined || prefix === '' ? baseId : `${prefix}-${baseId}`;\n}\n","/**\n * `useAuthStyles` — turns an `AuthTheme` token bag into a React Native\n * `StyleSheet` shared by all three auth forms.\n *\n * Building the stylesheet here (once, memoised per theme) keeps each form\n * component focused on layout + behaviour, and guarantees the three forms are\n * visually consistent. Token → style mapping lives in exactly one place, so an\n * app re-theming `<LoginForm>` automatically re-themes the others.\n */\nimport { useMemo } from 'react';\n\nimport { StyleSheet, type TextStyle, type ViewStyle } from 'react-native';\n\nimport type { AuthTheme } from '../theme/AuthTheme';\n\n/** The named styles every auth form draws from. */\nexport interface AuthStyles {\n screen: ViewStyle;\n card: ViewStyle;\n title: TextStyle;\n subtitle: TextStyle;\n fieldGroup: ViewStyle;\n label: TextStyle;\n input: TextStyle;\n inputError: TextStyle;\n primaryButton: ViewStyle;\n primaryButtonDisabled: ViewStyle;\n primaryButtonText: TextStyle;\n linkText: TextStyle;\n errorText: TextStyle;\n successText: TextStyle;\n helperText: TextStyle;\n /** Centered, tappable secondary link row (e.g. \"use password instead\"). */\n escapeLink: ViewStyle;\n /** Outlined secondary button (e.g. disable / cancel actions). */\n secondaryButton: ViewStyle;\n /** Label drawn inside `secondaryButton`. */\n secondaryButtonText: TextStyle;\n /** Status line (e.g. the device-PIN settings enabled/disabled state). */\n statusText: TextStyle;\n}\n\nconst FULL_WIDTH = '100%';\nconst CARD_MAX_WIDTH = 420;\nconst BUTTON_VERTICAL_PADDING = 14;\n/** Gap above the card. Mirrors `useAuthScreenStyles`' CARD_TOP_OFFSET — see the note there. */\nconst SCREEN_TOP_OFFSET = 64;\n\n/** Build the auth `StyleSheet` from the resolved theme. */\nexport function useAuthStyles(theme: AuthTheme): AuthStyles {\n return useMemo(() => {\n const { colors, radii, spacing, typography } = theme;\n return StyleSheet.create<AuthStyles>({\n screen: {\n flex: 1,\n // Top-anchored, NOT centred — a centred card re-centres as it grows and\n // drags the inputs up under the cursor. Same reasoning (and the same\n // measurement) as `useAuthScreenStyles`' CARD_TOP_OFFSET; kept in step so\n // a standalone `<LoginForm>` and an `<AuthScreen>`-composed one agree.\n justifyContent: 'flex-start',\n alignItems: 'center',\n padding: spacing.md,\n paddingTop: SCREEN_TOP_OFFSET,\n backgroundColor: colors.background,\n },\n card: {\n width: FULL_WIDTH,\n maxWidth: CARD_MAX_WIDTH,\n borderRadius: radii.card,\n padding: spacing.xl,\n backgroundColor: colors.surface,\n },\n title: {\n fontSize: typography.title,\n fontWeight: 'bold',\n textAlign: 'center',\n marginBottom: spacing.xs,\n color: colors.text,\n },\n subtitle: {\n fontSize: typography.subtitle,\n textAlign: 'center',\n marginBottom: spacing.lg,\n color: colors.textSecondary,\n },\n fieldGroup: {\n marginBottom: spacing.md,\n },\n label: {\n fontSize: typography.label,\n fontWeight: '600',\n marginBottom: spacing.xs,\n color: colors.text,\n },\n input: {\n borderWidth: 1,\n borderRadius: radii.input,\n padding: spacing.sm,\n fontSize: typography.body,\n borderColor: colors.border,\n backgroundColor: colors.background,\n color: colors.text,\n },\n inputError: {\n borderColor: colors.danger,\n },\n primaryButton: {\n borderRadius: radii.input,\n paddingVertical: BUTTON_VERTICAL_PADDING,\n paddingHorizontal: spacing.md,\n // Never shrink below the label width: in a row of actions (e.g. the\n // forgot-password modal's Cancel + submit), shrinking would clip a long\n // label like \"Send reset link\" past the button's rounded edge.\n flexShrink: 0,\n alignItems: 'center',\n justifyContent: 'center',\n marginTop: spacing.xs,\n backgroundColor: colors.primary,\n },\n primaryButtonDisabled: {\n backgroundColor: colors.border,\n },\n primaryButtonText: {\n fontSize: typography.body,\n fontWeight: '600',\n color: colors.onPrimary,\n },\n linkText: {\n fontSize: typography.caption,\n textDecorationLine: 'underline',\n color: colors.primary,\n },\n errorText: {\n fontSize: typography.caption,\n marginTop: spacing.xs,\n color: colors.danger,\n },\n successText: {\n fontSize: typography.body,\n lineHeight: typography.body * 1.4,\n color: colors.success,\n },\n helperText: {\n fontSize: typography.caption,\n color: colors.textSecondary,\n },\n escapeLink: {\n alignSelf: 'center',\n marginTop: spacing.md,\n paddingVertical: spacing.xs / 2,\n },\n secondaryButton: {\n borderRadius: radii.input,\n borderWidth: 1,\n borderColor: colors.primary,\n paddingVertical: BUTTON_VERTICAL_PADDING,\n paddingHorizontal: spacing.md,\n flexShrink: 0,\n alignItems: 'center',\n justifyContent: 'center',\n marginTop: spacing.sm,\n backgroundColor: colors.surface,\n },\n secondaryButtonText: {\n fontSize: typography.body,\n fontWeight: '600',\n color: colors.primary,\n },\n statusText: {\n fontSize: typography.label,\n fontWeight: '600',\n marginTop: spacing.sm,\n color: colors.text,\n },\n });\n }, [theme]);\n}\n","/**\n * Who asked for a prefill — the difference between \"the user requested this\" and\n * \"the app offered it\".\n *\n * A seed that the USER asked for (tapping \"use these credentials\") must always\n * apply: they can see the fields, they know what is in them, and they asked\n * anyway. A seed the APP offers (a demo pair arriving from `GET /bff/config`\n * mid-typing) must not: it is an unrequested, racing write against a field the\n * user may already be filling in.\n *\n * Collapsing the two into a bare nonce bump is what makes a late-arriving config\n * fetch overwrite the username a real account holder is halfway through typing.\n * `<LoginForm>` switches on this, never on a string literal.\n */\nexport const enum PrefillIntent {\n /** The user asked for it. Always applies, over whatever is in the fields. */\n Explicit = 'explicit',\n /** The app offered it. Applies only to untouched, empty fields. */\n Opportunistic = 'opportunistic',\n}\n","/**\n * `useLoginPrefill` — `<LoginForm>`'s credential field state, with re-seeding.\n *\n * Extracted from `<LoginForm>` because it is the one piece of that component\n * with real logic (the rest is JSX assembly), and because the contract it\n * encodes is easy to get subtly wrong:\n *\n * - `initialUsername` / `initialPassword` **seed** the fields; they do not own\n * them. Once mounted the user is in charge — every value stays editable and\n * clearable. A prefill the user cannot clear would lock a real account holder\n * out of a page that advertises a demo login.\n * - `prefillNonce` is the *re-seed signal*. `useState` ignores its initial\n * argument after mount, so a \"fill the form for me\" button that merely\n * changed `initialUsername` would do nothing at all. Bumping the nonce is\n * what re-applies the seed values.\n *\n * The nonce comparison re-seeds **during render** rather than in an effect —\n * React's documented \"adjusting state when a prop changes\" pattern. React\n * re-runs the component immediately with the new state and never commits the\n * stale render, so there is no flash of the previous values and no extra paint.\n */\nimport { useState } from 'react';\n\nimport { PrefillIntent } from './PrefillIntent';\n\n/** Inputs that seed (and re-seed) the login fields. */\nexport interface UseLoginPrefillArgs {\n /** Seeds the username field. */\n initialUsername?: string;\n /** Seeds the password field. */\n initialPassword?: string;\n /** Change this to re-apply the seed values to the (possibly edited) fields. */\n prefillNonce?: number;\n /**\n * Whether the pending re-seed was requested by the user or offered by the app.\n * An {@link PrefillIntent.Opportunistic} bump is DROPPED unless both fields are\n * still empty, so a late-arriving config fetch cannot overwrite what someone is\n * typing. Omit for the historical behaviour: every bump applies unconditionally.\n */\n prefillIntent?: PrefillIntent;\n}\n\n/** The live field values plus their setters. */\nexport interface UseLoginPrefillResult {\n username: string;\n password: string;\n setUsername: (value: string) => void;\n setPassword: (value: string) => void;\n}\n\n/** Own the login credential fields: seeded from props, then owned by the user. */\nexport function useLoginPrefill({\n initialUsername,\n initialPassword,\n prefillNonce,\n prefillIntent,\n}: Readonly<UseLoginPrefillArgs>): UseLoginPrefillResult {\n const [username, setUsername] = useState<string>(initialUsername ?? '');\n const [password, setPassword] = useState<string>(initialPassword ?? '');\n // Which prefill signal the fields currently reflect. Seeded with the incoming\n // nonce so a first render never counts as a re-seed.\n const [appliedNonce, setAppliedNonce] = useState<number | undefined>(prefillNonce);\n\n if (prefillNonce !== appliedNonce) {\n // Consume the signal even if the seed is declined below, so a dropped\n // opportunistic bump is never retried on a later render.\n setAppliedNonce(prefillNonce);\n\n // \"Has the user interacted?\" is answered with the only evidence this hook\n // has: what is in the fields. Both empty means an offered seed cannot\n // destroy anything — there is nothing there to lose. Anything else means\n // someone typed, so an unrequested write stays out of their way.\n const isPristine = username.length === 0 && password.length === 0;\n const mayApply = prefillIntent !== PrefillIntent.Opportunistic || isPristine;\n\n if (mayApply) {\n setUsername(initialUsername ?? '');\n setPassword(initialPassword ?? '');\n }\n }\n\n return { username, password, setUsername, setPassword };\n}\n","/**\n * `useLoginSubmit` — `<LoginForm>`'s submit logic, extracted from the component.\n *\n * The component's remaining body is JSX assembly; this hook owns the only branch\n * logic it had: the required-fields guard, the trimmed-username BFF call, and the\n * two error branches. Keeping it here makes that logic unit-testable and keeps\n * the render body under the component size limit.\n *\n * The error copy is deliberately generic: a wrong credential comes back from the\n * BFF as a non-2xx, and the message must never echo the raw error (it can leak\n * whether the username exists).\n */\nimport { useCallback, useRef, useState } from 'react';\n\nimport type { BffLoginRequest, BffUser } from '@dloizides/auth-client';\n\n/** Inputs the submit logic needs from `<LoginForm>`. */\nexport interface UseLoginSubmitArgs {\n /** The current username field value (trimmed before submit). */\n username: string;\n /** The current password field value. */\n password: string;\n /** The BFF password-login callback from `useBffAuth`. */\n login: (request: BffLoginRequest) => Promise<BffUser>;\n /** Called with the signed-in user after a successful login. */\n onSuccess: (user: BffUser) => void;\n /** Message shown when one or both fields are empty on submit. */\n missingFieldsLabel: string;\n /** Generic credentials-rejected message. */\n invalidCredentialsLabel: string;\n}\n\n/** The current error text (if any) plus the void-returning press handler. */\nexport interface UseLoginSubmitResult {\n /** The message to show, or `null` when there is nothing to report. */\n errorText: string | null;\n /** `onPress`-ready handler that runs the login. */\n handleSubmit: () => void;\n}\n\n/** Own `<LoginForm>`'s submit branch logic and its error state. */\nexport function useLoginSubmit({\n username,\n password,\n login,\n onSuccess,\n missingFieldsLabel,\n invalidCredentialsLabel,\n}: Readonly<UseLoginSubmitArgs>): UseLoginSubmitResult {\n const [errorText, setErrorText] = useState<string | null>(null);\n // A ref, not state: an Enter in a (read-only, still focusable) field during a pending\n // login must see the flag at once. The button is covered by `loading`; a field is not.\n const inFlight = useRef(false);\n\n const runLogin = useCallback(async (): Promise<void> => {\n if (inFlight.current) {return;}\n setErrorText(null);\n const trimmedUsername = username.trim();\n const hasMissingField = trimmedUsername.length === 0 || password.length === 0;\n if (hasMissingField) {\n setErrorText(missingFieldsLabel);\n return;\n }\n inFlight.current = true;\n try {\n const user = await login({ username: trimmedUsername, password });\n onSuccess(user);\n } catch {\n // The BFF answers a wrong credential with a non-2xx; show a generic\n // message — never echo the raw error (it can leak whether the user exists).\n setErrorText(invalidCredentialsLabel);\n } finally {\n inFlight.current = false;\n }\n }, [username, password, login, onSuccess, missingFieldsLabel, invalidCredentialsLabel]);\n\n // `onPress` expects a void-returning handler; `runLogin` is async, so wrap it.\n const handleSubmit = useCallback((): void => {\n void runLogin();\n }, [runLogin]);\n\n return { errorText, handleSubmit };\n}\n","/**\n * Enter in a text field submits the form. RN-web renders no `<form>`, so without\n * `onSubmitEditing` a keyboard user can only submit by tabbing to the button.\n *\n * An OS key-repeat of a held Enter is ignored, matching the shared Button's rule\n * (one held key is one press); a submit already in flight is refused by the\n * form's own guard.\n */\nimport { useCallback } from 'react';\n\nimport type { NativeSyntheticEvent, TextInputSubmitEditingEventData } from 'react-native';\n\ntype SubmitEditingEvent = NativeSyntheticEvent<TextInputSubmitEditingEventData>;\n\nfunction isKeyRepeat(event: SubmitEditingEvent | undefined): boolean {\n const native = event?.nativeEvent as { repeat?: unknown } | undefined;\n return native?.repeat === true;\n}\n\n/** An `onSubmitEditing` handler that runs `submit` once per Enter press. */\nexport function useSubmitOnEnter(submit: () => unknown): (event?: SubmitEditingEvent) => void {\n return useCallback(\n (event?: SubmitEditingEvent) => {\n if (isKeyRepeat(event)) {return;}\n submit();\n },\n [submit],\n );\n}\n","/**\n * `useBffAuth` — the headless login/logout/session hook.\n *\n * This is the \"escape hatch\" half of the package's design: apps that want a\n * fully custom layout skip `<LoginForm>` and drive auth themselves with this\n * hook. `<LoginForm>` itself is built on top of it, so the ready-made and the\n * custom paths share one code path.\n *\n * It owns nothing the BFF owns: no tokens, no refresh, no realm awareness. It\n * holds only the *current user* (the sanitised claims from `/bff/me`) plus the\n * in-flight status of `login` / `logout`. The httpOnly session cookie is the\n * single source of truth — `refresh()` re-reads `/bff/me` to resync.\n *\n * `BffUser` and `BffAuthClient` come from `@dloizides/auth-client`.\n */\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react';\n\nimport type { BffAuthClient, BffLoginRequest, BffUser } from '@dloizides/auth-client';\n\n/** Lifecycle status of the auth session. */\nexport const enum BffAuthStatus {\n /** The initial `/bff/me` probe has not finished yet. */\n Loading = 'loading',\n /** A live session exists; `user` is populated. */\n Authenticated = 'authenticated',\n /** No session; `user` is `null`. */\n Unauthenticated = 'unauthenticated',\n}\n\nexport interface UseBffAuthOptions {\n /** The same-origin BFF client (build it with `createBffAuthClient`). */\n client: BffAuthClient;\n /**\n * When `true` (default), the hook probes `GET /bff/me` on mount to bootstrap\n * `status`/`user`. Set `false` to skip the probe (e.g. on a public page).\n */\n probeOnMount?: boolean;\n}\n\nexport interface UseBffAuthResult {\n /** The signed-in user, or `null` when there is no session. */\n user: BffUser | null;\n /** Session lifecycle status. */\n status: BffAuthStatus;\n /** `true` while a `login` or `logout` call is in flight. */\n isSubmitting: boolean;\n /** The last `login`/`logout`/`refresh` error, cleared on the next attempt. */\n error: Error | null;\n /** ROPC password login via `POST /bff/login`. Resolves to the user; rejects on failure. */\n login: (request: BffLoginRequest) => Promise<BffUser>;\n /** End the session via `POST /bff/logout`. Always resolves; never throws to the caller. */\n logout: () => Promise<void>;\n /** Re-read `GET /bff/me` and resync `user`/`status`. */\n refresh: () => Promise<void>;\n}\n\n/** Internal: the mutable session state the hook tracks. */\ninterface SessionState {\n user: BffUser | null;\n status: BffAuthStatus;\n}\n\nconst INITIAL_LOADING: SessionState = { user: null, status: BffAuthStatus.Loading };\nconst INITIAL_IDLE: SessionState = { user: null, status: BffAuthStatus.Unauthenticated };\n\nfunction toError(value: unknown): Error {\n return value instanceof Error ? value : new Error(String(value));\n}\n\n/**\n * Headless BFF auth. Returns the current user, the session status, and\n * `login` / `logout` / `refresh` callbacks. No rendering — the consumer (or\n * `<LoginForm>`) wires it to UI.\n */\nexport function useBffAuth(options: UseBffAuthOptions): UseBffAuthResult {\n const { client, probeOnMount = true } = options;\n\n const [session, setSession] = useState<SessionState>(\n probeOnMount ? INITIAL_LOADING : INITIAL_IDLE,\n );\n const [isSubmitting, setIsSubmitting] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n\n // Guard against a `setState` after the consumer unmounts mid-request.\n const mountedRef = useRef(true);\n useEffect(() => {\n mountedRef.current = true;\n return (): void => {\n mountedRef.current = false;\n };\n }, []);\n\n const safeSetSession = useCallback((next: SessionState) => {\n if (mountedRef.current) {\n setSession(next);\n }\n }, []);\n\n const refresh = useCallback(async (): Promise<void> => {\n try {\n const user = await client.getCurrentUser();\n safeSetSession(\n user === null\n ? INITIAL_IDLE\n : { user, status: BffAuthStatus.Authenticated },\n );\n } catch (caught) {\n safeSetSession(INITIAL_IDLE);\n if (mountedRef.current) {\n setError(toError(caught));\n }\n }\n }, [client, safeSetSession]);\n\n const login = useCallback(\n async (request: BffLoginRequest): Promise<BffUser> => {\n if (mountedRef.current) {\n setIsSubmitting(true);\n setError(null);\n }\n try {\n const user = await client.login(request);\n safeSetSession({ user, status: BffAuthStatus.Authenticated });\n return user;\n } catch (caught) {\n const err = toError(caught);\n if (mountedRef.current) {\n setError(err);\n }\n throw err;\n } finally {\n if (mountedRef.current) {\n setIsSubmitting(false);\n }\n }\n },\n [client, safeSetSession],\n );\n\n const logout = useCallback(async (): Promise<void> => {\n if (mountedRef.current) {\n setIsSubmitting(true);\n setError(null);\n }\n try {\n await client.logout();\n } catch (caught) {\n // A failed logout still leaves the SPA logged out client-side — surface\n // the error but do not reject; the caller's UI should not get stuck.\n if (mountedRef.current) {\n setError(toError(caught));\n }\n } finally {\n safeSetSession(INITIAL_IDLE);\n if (mountedRef.current) {\n setIsSubmitting(false);\n }\n }\n }, [client, safeSetSession]);\n\n // Bootstrap the session once on mount when probing is enabled.\n useEffect(() => {\n if (probeOnMount) {\n void refresh();\n }\n // `refresh` is stable for a stable `client`; `probeOnMount` is read once.\n }, [probeOnMount, refresh]);\n\n return useMemo(\n () => ({\n user: session.user,\n status: session.status,\n isSubmitting,\n error,\n login,\n logout,\n refresh,\n }),\n [session.user, session.status, isSubmitting, error, login, logout, refresh],\n );\n}\n","/**\n * `<LoginForm>` — the ready-made, themeable password-login form.\n *\n * The \"themeable component\" half of the package design: drop it in, pass a\n * `client`, a `theme` (or wrap in `<AuthThemeProvider>`) and a localised\n * `labels` bag, and you have a branded login surface. It is built on the\n * headless `useBffAuth` hook, so the ready-made and custom-layout paths share\n * one code path.\n *\n * The package ships no router and no i18n. `onSuccess` hands the signed-in\n * `BffUser` back to the app, which decides where to navigate (typically via\n * `resolvePostLoginRoute`). All copy comes from `labels`.\n */\nimport { useMemo, type ReactElement } from 'react';\n\nimport { Text, TextInput, TouchableOpacity, View } from 'react-native';\n\nimport { Button } from '@dloizides/ui-buttons';\n\nimport { DEFAULT_LOGIN_LABELS, type LoginFormLabels } from './labels';\nimport { AuthTestIds, withTestIdPrefix } from './testIds';\nimport { useAuthStyles } from './useAuthStyles';\nimport { useLoginPrefill } from './useLoginPrefill';\nimport { useLoginSubmit } from './useLoginSubmit';\nimport { useSubmitOnEnter } from './useSubmitOnEnter';\nimport { useBffAuth } from '../hooks/useBffAuth';\n\nimport { useAuthTheme } from '../theme/AuthThemeProvider';\n\nimport type { LoginFormProps } from './LoginForm.types';\n\nexport type { LoginFormProps } from './LoginForm.types';\n\n/** Themeable password-login form built on `useBffAuth`. */\nexport function LoginForm({\n client,\n theme: themeProp,\n labels: labelsProp,\n onSuccess,\n onForgotPassword,\n onSignUp,\n testIdPrefix,\n chromeless = false,\n initialUsername,\n initialPassword,\n prefillNonce,\n prefillIntent,\n}: Readonly<LoginFormProps>): ReactElement {\n const theme = useAuthTheme(themeProp);\n const styles = useAuthStyles(theme);\n const labels = useMemo<LoginFormLabels>(\n () => ({ ...DEFAULT_LOGIN_LABELS, ...labelsProp }),\n [labelsProp],\n );\n\n // probeOnMount is off: the login screen does not need a /bff/me round-trip.\n const { login, isSubmitting } = useBffAuth({ client, probeOnMount: false });\n\n // The credential fields: seeded from the `initial*` props, then owned by the\n // user. See `useLoginPrefill` for why the nonce exists.\n const { username, password, setUsername, setPassword } = useLoginPrefill({\n initialUsername,\n initialPassword,\n prefillNonce,\n prefillIntent,\n });\n\n const { errorText, handleSubmit } = useLoginSubmit({\n username,\n password,\n login,\n onSuccess,\n missingFieldsLabel: labels.missingFields,\n invalidCredentialsLabel: labels.invalidCredentials,\n });\n const handleSubmitEditing = useSubmitOnEnter(handleSubmit);\n\n const content = (\n <>\n <Text style={styles.title}>{labels.title}</Text>\n <Text style={styles.subtitle}>{labels.subtitle}</Text>\n\n <View style={styles.fieldGroup}>\n <Text style={styles.label}>{labels.usernameLabel}</Text>\n <TextInput\n accessibilityHint={labels.usernamePlaceholder}\n accessibilityLabel={labels.usernameLabel}\n autoCapitalize=\"none\"\n autoCorrect={false}\n editable={!isSubmitting}\n placeholder={labels.usernamePlaceholder}\n placeholderTextColor={theme.colors.textSecondary}\n returnKeyType=\"go\"\n style={styles.input}\n testID={withTestIdPrefix(AuthTestIds.loginUsernameInput, testIdPrefix)}\n value={username}\n onChangeText={setUsername}\n onSubmitEditing={handleSubmitEditing}\n />\n </View>\n\n <View style={styles.fieldGroup}>\n <Text style={styles.label}>{labels.passwordLabel}</Text>\n <TextInput\n secureTextEntry\n accessibilityHint={labels.passwordPlaceholder}\n accessibilityLabel={labels.passwordLabel}\n autoCapitalize=\"none\"\n autoCorrect={false}\n editable={!isSubmitting}\n placeholder={labels.passwordPlaceholder}\n placeholderTextColor={theme.colors.textSecondary}\n returnKeyType=\"go\"\n style={styles.input}\n testID={withTestIdPrefix(AuthTestIds.loginPasswordInput, testIdPrefix)}\n value={password}\n onChangeText={setPassword}\n onSubmitEditing={handleSubmitEditing}\n />\n </View>\n\n {errorText !== null ? (\n <Text\n style={styles.errorText}\n testID={withTestIdPrefix(AuthTestIds.loginError, testIdPrefix)}\n >\n {errorText}\n </Text>\n ) : null}\n\n {onForgotPassword !== undefined ? (\n <TouchableOpacity\n accessibilityHint={labels.forgotPassword}\n accessibilityLabel={labels.forgotPassword}\n accessibilityRole=\"link\"\n disabled={isSubmitting}\n style={styles.fieldGroup}\n testID={withTestIdPrefix(AuthTestIds.loginForgotLink, testIdPrefix)}\n onPress={onForgotPassword}\n >\n <Text style={styles.linkText}>{labels.forgotPassword}</Text>\n </TouchableOpacity>\n ) : null}\n\n {/* The shared Button owns keyboard parity: a held Enter is one login, not one per key-repeat. */}\n <View style={styles.fieldGroup}>\n <Button\n fullWidth\n accessibilityHint={labels.submit}\n accessibilityLabel={isSubmitting ? labels.submitting : labels.submit}\n label={labels.submit}\n loading={isSubmitting}\n testID={withTestIdPrefix(AuthTestIds.loginSubmitButton, testIdPrefix)}\n onPress={handleSubmit}\n />\n </View>\n\n {onSignUp !== undefined ? (\n <TouchableOpacity\n accessibilityHint={labels.signUp}\n accessibilityLabel={labels.signUp}\n accessibilityRole=\"link\"\n disabled={isSubmitting}\n style={styles.fieldGroup}\n testID={withTestIdPrefix(AuthTestIds.loginSignUpLink, testIdPrefix)}\n onPress={onSignUp}\n >\n <Text style={styles.linkText}>{labels.signUp}</Text>\n </TouchableOpacity>\n ) : null}\n </>\n );\n\n const card = (\n <View\n style={chromeless ? undefined : styles.card}\n testID={withTestIdPrefix(AuthTestIds.loginForm, testIdPrefix)}\n >\n {content}\n </View>\n );\n\n return chromeless ? card : <View style={styles.screen}>{card}</View>;\n}\n","/**\n * React Query mutation hooks for the BFF password-reset flow.\n *\n * Headless counterparts to `<ForgotPasswordForm>` / `<ResetPasswordForm>` —\n * apps with a custom layout use these directly. They POST to the same-origin\n * `/bff/forgot-password` and `/bff/reset-password`, which the BFF proxies to\n * TenantService.\n *\n * Extracted + generalised from `apps/katalogos-web/src/auth/bffPasswordHooks.ts`.\n * Difference: the katalogos version closed over a module-level singleton\n * `bffAuthClient`; the package version takes the `client` in the options so it\n * carries no global state.\n *\n * The mutation result type is `undefined` (not `void`): the BFF endpoints\n * return no body, and `undefined` is a valid generic argument where the lint\n * config rejects `void`.\n */\nimport { useMutation, type UseMutationOptions, type UseMutationResult } from '@tanstack/react-query';\n\nimport type {\n BffAuthClient,\n BffForgotPasswordRequest,\n BffResetPasswordRequest,\n} from '@dloizides/auth-client';\n\nexport type UseBffForgotPasswordOptions = Omit<\n UseMutationOptions<undefined, Error, BffForgotPasswordRequest>,\n 'mutationFn'\n> & {\n /** The same-origin BFF client. */\n client: BffAuthClient;\n};\n\n/**\n * Mutation that POSTs to `/bff/forgot-password`.\n *\n * The backend returns 200 unconditionally (no email enumeration); the UI\n * should show the same \"if that email exists, we sent a link\" message whether\n * `onSuccess` or `onError` fires.\n */\nexport function useBffForgotPassword(\n options: UseBffForgotPasswordOptions,\n): UseMutationResult<undefined, Error, BffForgotPasswordRequest> {\n const { client, ...rest } = options;\n return useMutation<undefined, Error, BffForgotPasswordRequest>({\n mutationFn: async (request) => {\n await client.forgotPassword(request);\n return undefined;\n },\n ...rest,\n });\n}\n\nexport type UseBffResetPasswordOptions = Omit<\n UseMutationOptions<undefined, Error, BffResetPasswordRequest>,\n 'mutationFn'\n> & {\n /** The same-origin BFF client. */\n client: BffAuthClient;\n};\n\n/**\n * Mutation that POSTs to `/bff/reset-password`. A `400` (invalid / expired\n * token) surfaces as a rejected mutation with the status in the error message.\n */\nexport function useBffResetPassword(\n options: UseBffResetPasswordOptions,\n): UseMutationResult<undefined, Error, BffResetPasswordRequest> {\n const { client, ...rest } = options;\n return useMutation<undefined, Error, BffResetPasswordRequest>({\n mutationFn: async (request) => {\n await client.resetPassword(request);\n return undefined;\n },\n ...rest,\n });\n}\n","/**\n * `<ForgotPasswordForm>` — the ready-made, themeable \"request a reset link\"\n * form.\n *\n * Captures an email and POSTs to `/bff/forgot-password` via the headless\n * `useBffForgotPassword` hook. The backend answers 200 unconditionally (no\n * email enumeration), so on success the form swaps to a generic confirmation\n * message — it never reveals whether the address is registered.\n *\n * Extracted + generalised from `apps/katalogos-web/src/components/Auth/\n * ForgotPasswordModal.tsx` — minus the modal shell (apps own the surface) and\n * the app-specific `FM()` calls (copy now comes from `labels`).\n */\nimport { useCallback, useMemo, useState, type ReactElement } from 'react';\n\nimport { ActivityIndicator, Text, TextInput, TouchableOpacity, View } from 'react-native';\n\nimport { DEFAULT_FORGOT_PASSWORD_LABELS, type ForgotPasswordFormLabels } from './labels';\nimport { AuthTestIds, withTestIdPrefix } from './testIds';\nimport { useAuthStyles } from './useAuthStyles';\nimport { useBffForgotPassword } from '../hooks/useBffPasswordHooks';\nimport { useAuthTheme } from '../theme/AuthThemeProvider';\n\nimport type { AuthTheme } from '../theme/AuthTheme';\nimport type { BffAuthClient } from '@dloizides/auth-client';\n\n// A deliberately loose, linear-time email shape check — `[^@\\s]` and `[^.\\s]`\n// character classes have no overlapping alternation, so there is no\n// super-linear backtracking. Strict validation is the backend's job.\nconst EMAIL_REGEX = /^[^@\\s]+@[^.\\s]+\\.[^\\s]+$/;\n\nexport interface ForgotPasswordFormProps {\n /** The same-origin BFF client (build it with `createBffAuthClient`). */\n client: BffAuthClient;\n /** Explicit theme; overrides any `<AuthThemeProvider>`. */\n theme?: AuthTheme;\n /** Localised copy. Partial — unspecified keys fall back to English defaults. */\n labels?: Partial<ForgotPasswordFormLabels>;\n /**\n * Full URL with a `{token}` placeholder; forwarded to the backend so it can\n * build the reset-email link without hardcoding any frontend host. Optional —\n * apps that configure the template server-side can omit it.\n */\n resetUrlTemplate?: string;\n /** Called once the request succeeds (the generic-confirmation state). */\n onSuccess?: () => void;\n /** Prefix applied to every `testID`. */\n testIdPrefix?: string;\n}\n\n/** `true` when `value` looks like an email address. */\nfunction isValidEmail(value: string): boolean {\n return EMAIL_REGEX.test(value);\n}\n\n/** Themeable \"request a reset link\" form built on `useBffForgotPassword`. */\nexport function ForgotPasswordForm({\n client,\n theme: themeProp,\n labels: labelsProp,\n resetUrlTemplate,\n onSuccess,\n testIdPrefix,\n}: Readonly<ForgotPasswordFormProps>): ReactElement {\n const theme = useAuthTheme(themeProp);\n const styles = useAuthStyles(theme);\n const labels = useMemo<ForgotPasswordFormLabels>(\n () => ({ ...DEFAULT_FORGOT_PASSWORD_LABELS, ...labelsProp }),\n [labelsProp],\n );\n\n const [email, setEmail] = useState('');\n const [submitted, setSubmitted] = useState(false);\n const [errorText, setErrorText] = useState<string | null>(null);\n\n const mutationOptions = useMemo(\n () => ({\n client,\n onSuccess: (): void => {\n setSubmitted(true);\n onSuccess?.();\n },\n onError: (): void => {\n // Only a network / 5xx failure reaches here — a 200 (the no-enumeration\n // branch) is success. Show a friendly retry message.\n setErrorText(labels.networkError);\n },\n }),\n [client, onSuccess, labels.networkError],\n );\n const mutation = useBffForgotPassword(mutationOptions);\n\n const isPending = mutation.status === 'pending';\n\n const handleSubmit = useCallback((): void => {\n setErrorText(null);\n const trimmedEmail = email.trim();\n if (!isValidEmail(trimmedEmail)) {\n setErrorText(labels.invalidEmail);\n return;\n }\n mutation.mutate({ email: trimmedEmail, resetUrlTemplate });\n }, [email, mutation, resetUrlTemplate, labels.invalidEmail]);\n\n const submitButtonStyle = isPending\n ? [styles.primaryButton, styles.primaryButtonDisabled]\n : styles.primaryButton;\n\n return (\n <View style={styles.screen}>\n <View\n style={styles.card}\n testID={withTestIdPrefix(AuthTestIds.forgotPasswordForm, testIdPrefix)}\n >\n <Text style={styles.title}>{labels.title}</Text>\n\n {submitted ? (\n <Text\n style={styles.successText}\n testID={withTestIdPrefix(AuthTestIds.forgotPasswordSuccess, testIdPrefix)}\n >\n {labels.successMessage}\n </Text>\n ) : (\n <>\n <Text style={styles.subtitle}>{labels.description}</Text>\n\n <View style={styles.fieldGroup}>\n <Text style={styles.label}>{labels.emailLabel}</Text>\n <TextInput\n accessibilityHint={labels.emailPlaceholder}\n accessibilityLabel={labels.emailLabel}\n autoCapitalize=\"none\"\n autoCorrect={false}\n editable={!isPending}\n keyboardType=\"email-address\"\n placeholder={labels.emailPlaceholder}\n placeholderTextColor={theme.colors.textSecondary}\n style={styles.input}\n testID={withTestIdPrefix(AuthTestIds.forgotPasswordEmailInput, testIdPrefix)}\n value={email}\n onChangeText={setEmail}\n />\n </View>\n\n {errorText !== null ? (\n <Text\n style={styles.errorText}\n testID={withTestIdPrefix(AuthTestIds.forgotPasswordError, testIdPrefix)}\n >\n {errorText}\n </Text>\n ) : null}\n\n <TouchableOpacity\n accessibilityHint={labels.submit}\n accessibilityLabel={isPending ? labels.submitting : labels.submit}\n accessibilityRole=\"button\"\n disabled={isPending}\n style={submitButtonStyle}\n testID={withTestIdPrefix(AuthTestIds.forgotPasswordSubmitButton, testIdPrefix)}\n onPress={handleSubmit}\n >\n {isPending ? (\n <ActivityIndicator color={theme.colors.onPrimary} size=\"small\" />\n ) : (\n <Text style={styles.primaryButtonText}>{labels.submit}</Text>\n )}\n </TouchableOpacity>\n </>\n )}\n </View>\n </View>\n );\n}\n","/**\n * `useForgotPasswordSubmit` — react-query-FREE form-state + submit logic for a\n * \"request a reset link\" surface.\n *\n * Why a second forgot-password hook when `useBffForgotPassword` already exists?\n * That one wraps `useMutation`, so it can only run under a `QueryClientProvider`.\n * The product login routes (katalogos / erevna / kefi) deliberately keep\n * react-query OUT of their bundle — there is no provider there, and mounting a\n * `useMutation` crashes with \"No QueryClient set\". Every app therefore\n * hand-rolled the same direct-`client.forgotPassword` call. This hook is that\n * shared logic, promoted into the package: a plain `useState` + promise chain,\n * safe on a provider-less route.\n *\n * Behaviour mirrors the apps' modal exactly:\n * - `canSubmit` is true only when the trimmed email looks valid and no request\n * is in flight (the submit button gates on this).\n * - `submit()` no-ops when the email is invalid or a request is already running.\n * - The backend is anti-enumeration (always 200 for the \"found an account?\"\n * branch), so the only failure that surfaces is a network / 5xx one, via\n * `hasNetworkError`.\n * - `reset()` clears everything — call it when the modal closes so reopening\n * shows a fresh form.\n */\nimport { useCallback, useState } from 'react';\n\nimport type { BffAuthClient, BffForgotPasswordRequest } from '@dloizides/auth-client';\n\n// A deliberately loose, linear-time email shape check — the `[^@\\s]` / `[^.\\s]`\n// character classes share no alternation, so there is no super-linear\n// backtracking. Strict validation is the backend's job.\nconst EMAIL_REGEX = /^[^@\\s]+@[^.\\s]+\\.[^\\s]+$/;\n\n/** `true` when `value` (after trimming) looks like an email address. */\nexport function isValidForgotPasswordEmail(value: string): boolean {\n return EMAIL_REGEX.test(value.trim());\n}\n\nexport interface UseForgotPasswordSubmitArgs {\n /** The same-origin BFF client (build it with `createBffAuthClient`). */\n client: BffAuthClient;\n /**\n * Full URL with a `{token}` placeholder, forwarded to the backend so it can\n * build the reset-email link without hardcoding a frontend host.\n */\n resetUrlTemplate?: string;\n /** Invoked once the request succeeds (the generic-confirmation state). */\n onSuccess?: () => void;\n}\n\nexport interface UseForgotPasswordSubmitResult {\n email: string;\n setEmail: (value: string) => void;\n /** `true` once the request has succeeded (show the generic confirmation). */\n submitted: boolean;\n /** `true` while the request is in flight. */\n isSubmitting: boolean;\n /** `true` when the last submit hit a network / 5xx failure. */\n hasNetworkError: boolean;\n /** `true` when the email is valid and no request is in flight. */\n canSubmit: boolean;\n /** Validate, then fire the request (no-op when `canSubmit` is false). */\n submit: () => void;\n /** Clear all state — call when the modal closes. */\n reset: () => void;\n}\n\n/** Headless, react-query-free \"request a reset link\" logic. */\nexport function useForgotPasswordSubmit({\n client,\n resetUrlTemplate,\n onSuccess,\n}: UseForgotPasswordSubmitArgs): UseForgotPasswordSubmitResult {\n const [email, setEmail] = useState('');\n const [submitted, setSubmitted] = useState(false);\n const [isSubmitting, setIsSubmitting] = useState(false);\n const [hasNetworkError, setHasNetworkError] = useState(false);\n\n const canSubmit = isValidForgotPasswordEmail(email) && !isSubmitting;\n\n const submit = useCallback((): void => {\n const target = email.trim();\n if (!isValidForgotPasswordEmail(target) || isSubmitting) {\n return;\n }\n setHasNetworkError(false);\n setIsSubmitting(true);\n const request: BffForgotPasswordRequest = { email: target, resetUrlTemplate };\n client\n .forgotPassword(request)\n .then(() => {\n setSubmitted(true);\n onSuccess?.();\n })\n .catch(() => setHasNetworkError(true))\n .finally(() => setIsSubmitting(false));\n }, [client, email, isSubmitting, resetUrlTemplate, onSuccess]);\n\n const reset = useCallback((): void => {\n setEmail('');\n setSubmitted(false);\n setIsSubmitting(false);\n setHasNetworkError(false);\n }, []);\n\n return {\n email,\n setEmail,\n submitted,\n isSubmitting,\n hasNetworkError,\n canSubmit,\n submit,\n reset,\n };\n}\n","/**\n * `<ForgotPasswordFields>` — the embedded, themeable \"request a reset link\"\n * body, sized to live INSIDE an app-owned modal shell (not a full screen).\n *\n * The product apps each show \"Forgot password?\" as a modal launched from their\n * login route, wrapping their own modal chrome (title bar + close affordance)\n * around an identical email field + submit/cancel body. This is that body,\n * promoted into the package so the three apps stop hand-rolling it.\n *\n * Built on the react-query-free `useForgotPasswordSubmit` hook, so it renders +\n * submits on a provider-less login route (where `useMutation` would crash). The\n * backend is anti-enumeration, so a successful request swaps to a generic\n * confirmation that never reveals whether the address is registered.\n *\n * Differs from the screen-shaped `<ForgotPasswordForm>`: no outer screen/card\n * wrapper and no title (the host modal owns those), plus two modal affordances —\n * a `Cancel` button beside submit and a `Close` button on the success state —\n * each rendered only when its handler is supplied.\n */\nimport { useEffect, useMemo, type ReactElement } from 'react';\n\nimport {\n ActivityIndicator,\n StyleSheet,\n Text,\n TextInput,\n TouchableOpacity,\n View,\n type TextStyle,\n type ViewStyle,\n} from 'react-native';\n\nimport {\n DEFAULT_FORGOT_PASSWORD_FIELDS_LABELS,\n type ForgotPasswordFieldsLabels,\n} from './labels';\nimport { AuthTestIds, withTestIdPrefix } from './testIds';\nimport { useAuthStyles } from './useAuthStyles';\nimport { useForgotPasswordSubmit } from '../hooks/useForgotPasswordSubmit';\nimport { useAuthTheme } from '../theme/AuthThemeProvider';\n\nimport type { AuthTheme } from '../theme/AuthTheme';\nimport type { BffAuthClient } from '@dloizides/auth-client';\n\nconst SECONDARY_BORDER_WIDTH = 1;\n\nexport interface ForgotPasswordFieldsProps {\n /** The same-origin BFF client (build it with `createBffAuthClient`). */\n client: BffAuthClient;\n /** Explicit theme; overrides any `<AuthThemeProvider>`. */\n theme?: AuthTheme;\n /** Localised copy. Partial — unspecified keys fall back to English defaults. */\n labels?: Partial<ForgotPasswordFieldsLabels>;\n /**\n * Full URL with a `{token}` placeholder, forwarded to the backend so it can\n * build the reset-email link without hardcoding a frontend host.\n */\n resetUrlTemplate?: string;\n /**\n * The host modal's open state. When it flips to `false` the body clears\n * itself, so reopening shows a fresh form regardless of which affordance\n * closed it. Defaults to `true` for non-modal embedding.\n */\n visible?: boolean;\n /** Called once the request succeeds (the generic-confirmation state). */\n onSuccess?: () => void;\n /** When supplied, renders a Cancel button beside submit. */\n onCancel?: () => void;\n /** When supplied, renders a Close button on the success state. */\n onClose?: () => void;\n /** Prefix applied to every `testID`. */\n testIdPrefix?: string;\n}\n\n/** The modal-specific styles `useAuthStyles` does not carry. */\ninterface ModalStyles {\n body: ViewStyle;\n actions: ViewStyle;\n secondaryButton: ViewStyle;\n secondaryButtonText: TextStyle;\n}\n\n/** Build the modal-only styles from the resolved theme. */\nfunction useModalStyles(theme: AuthTheme): ModalStyles {\n return useMemo(\n () =>\n StyleSheet.create<ModalStyles>({\n body: { padding: theme.spacing.md },\n actions: {\n flexDirection: 'row',\n justifyContent: 'flex-end',\n alignItems: 'center',\n // Wrap (rather than clip) when a long submit label + Cancel can't\n // fit a narrow modal on one line.\n flexWrap: 'wrap',\n marginTop: theme.spacing.md,\n gap: theme.spacing.sm,\n },\n secondaryButton: {\n borderRadius: theme.radii.input,\n paddingVertical: theme.spacing.sm,\n paddingHorizontal: theme.spacing.md,\n // Match the submit button: never shrink below the label width.\n flexShrink: 0,\n borderWidth: SECONDARY_BORDER_WIDTH,\n borderColor: theme.colors.border,\n },\n secondaryButtonText: {\n fontSize: theme.typography.body,\n fontWeight: '600',\n color: theme.colors.text,\n },\n }),\n [theme],\n );\n}\n\n/** Embedded \"request a reset link\" body for an app-owned modal. */\nexport function ForgotPasswordFields({\n client,\n theme: themeProp,\n labels: labelsProp,\n resetUrlTemplate,\n visible = true,\n onSuccess,\n onCancel,\n onClose,\n testIdPrefix,\n}: Readonly<ForgotPasswordFieldsProps>): ReactElement {\n const theme = useAuthTheme(themeProp);\n const styles = useAuthStyles(theme);\n const modalStyles = useModalStyles(theme);\n const labels = useMemo<ForgotPasswordFieldsLabels>(\n () => ({ ...DEFAULT_FORGOT_PASSWORD_FIELDS_LABELS, ...labelsProp }),\n [labelsProp],\n );\n\n const form = useForgotPasswordSubmit({ client, resetUrlTemplate, onSuccess });\n\n // Clear the body when the host modal closes, so reopening starts fresh.\n const { reset } = form;\n useEffect(() => {\n if (!visible) {\n reset();\n }\n }, [visible, reset]);\n\n const submitButtonStyle = form.canSubmit\n ? styles.primaryButton\n : [styles.primaryButton, styles.primaryButtonDisabled];\n\n const handleCancel = (): void => {\n form.reset();\n onCancel?.();\n };\n\n const handleClose = (): void => {\n form.reset();\n onClose?.();\n };\n\n if (form.submitted) {\n return (\n <View style={modalStyles.body} testID={withTestIdPrefix(AuthTestIds.forgotPasswordForm, testIdPrefix)}>\n <Text style={styles.successText} testID={withTestIdPrefix(AuthTestIds.forgotPasswordSuccess, testIdPrefix)}>\n {labels.successMessage}\n </Text>\n {onClose !== undefined ? (\n <View style={modalStyles.actions}>\n <TouchableOpacity\n accessibilityHint={labels.close}\n accessibilityLabel={labels.close}\n accessibilityRole=\"button\"\n style={styles.primaryButton}\n testID={withTestIdPrefix(AuthTestIds.forgotPasswordCloseButton, testIdPrefix)}\n onPress={handleClose}\n >\n <Text style={styles.primaryButtonText}>{labels.close}</Text>\n </TouchableOpacity>\n </View>\n ) : null}\n </View>\n );\n }\n\n return (\n <View style={modalStyles.body} testID={withTestIdPrefix(AuthTestIds.forgotPasswordForm, testIdPrefix)}>\n <Text style={styles.subtitle}>{labels.description}</Text>\n\n <View style={styles.fieldGroup}>\n <Text style={styles.label}>{labels.emailLabel}</Text>\n <TextInput\n accessibilityHint={labels.emailPlaceholder}\n accessibilityLabel={labels.emailLabel}\n autoCapitalize=\"none\"\n autoCorrect={false}\n editable={!form.isSubmitting}\n keyboardType=\"email-address\"\n placeholder={labels.emailPlaceholder}\n placeholderTextColor={theme.colors.textSecondary}\n style={styles.input}\n testID={withTestIdPrefix(AuthTestIds.forgotPasswordEmailInput, testIdPrefix)}\n value={form.email}\n onChangeText={form.setEmail}\n />\n </View>\n\n {form.hasNetworkError ? (\n <Text style={styles.errorText} testID={withTestIdPrefix(AuthTestIds.forgotPasswordError, testIdPrefix)}>\n {labels.networkError}\n </Text>\n ) : null}\n\n <View style={modalStyles.actions}>\n {onCancel !== undefined ? (\n <TouchableOpacity\n accessibilityHint={labels.cancel}\n accessibilityLabel={labels.cancel}\n accessibilityRole=\"button\"\n disabled={form.isSubmitting}\n style={modalStyles.secondaryButton}\n testID={withTestIdPrefix(AuthTestIds.forgotPasswordCancelButton, testIdPrefix)}\n onPress={handleCancel}\n >\n <Text style={modalStyles.secondaryButtonText}>{labels.cancel}</Text>\n </TouchableOpacity>\n ) : null}\n\n <TouchableOpacity\n accessibilityHint={labels.submit}\n accessibilityLabel={form.isSubmitting ? labels.submitting : labels.submit}\n accessibilityRole=\"button\"\n disabled={!form.canSubmit}\n style={submitButtonStyle}\n testID={withTestIdPrefix(AuthTestIds.forgotPasswordSubmitButton, testIdPrefix)}\n onPress={form.submit}\n >\n {form.isSubmitting ? (\n <ActivityIndicator color={theme.colors.onPrimary} size=\"small\" />\n ) : (\n <Text style={styles.primaryButtonText}>{labels.submit}</Text>\n )}\n </TouchableOpacity>\n </View>\n </View>\n );\n}\n","/**\n * The discrete failure states the reset-password flow can surface.\n *\n * Each member is the stable key a consuming app maps onto a localised message.\n * `useResetPasswordForm` reports exactly one of these at a time, preferring the\n * earliest-fixable issue so the user resolves one thing at a time.\n */\nexport const enum ResetPasswordError {\n /** One or both password fields are empty. */\n Empty = 'empty',\n /** The new password fails the shared password policy. */\n WeakPassword = 'weakPassword',\n /** The confirm field does not match the new password. */\n Mismatch = 'mismatch',\n /** The reset token is missing, expired, or already consumed. */\n TokenInvalid = 'tokenInvalid',\n /** A network or 5xx failure prevented the reset from completing. */\n Network = 'network',\n}\n","/**\n * The discrete ways a password can fail the shared client-side policy.\n *\n * Each member is the stable key a consuming app maps onto a localised message —\n * the package never ships translated copy.\n */\nexport const enum PasswordPolicyError {\n /** Shorter than `PASSWORD_MIN_LENGTH`. */\n TooShort = 'tooShort',\n /** Longer than `PASSWORD_MAX_LENGTH`. */\n TooLong = 'tooLong',\n /** Contains no `A-Z` character. */\n MissingUppercase = 'missingUppercase',\n /** Contains no `a-z` character. */\n MissingLowercase = 'missingLowercase',\n /** Contains no `0-9` character. */\n MissingDigit = 'missingDigit',\n}\n","/**\n * Client-side password policy that mirrors the backend\n * (TenantService `ResetPasswordRequestValidator`):\n *\n * - 8 ≤ length ≤ 128\n * - at least one uppercase letter\n * - at least one lowercase letter\n * - at least one digit\n *\n * Shared so every app's `<ResetPasswordForm>` (and any future password input)\n * rejects ~99% of bad passwords before a network round-trip. Extracted from\n * `apps/katalogos-web/src/auth/passwordPolicy.ts`.\n */\nimport { PasswordPolicyError } from './PasswordPolicyError';\n\nconst UPPERCASE_REGEX = /[A-Z]/;\nconst LOWERCASE_REGEX = /[a-z]/;\nconst DIGIT_REGEX = /\\d/;\n\n/** Minimum acceptable password length. */\nexport const PASSWORD_MIN_LENGTH = 8;\n/** Maximum acceptable password length. */\nexport const PASSWORD_MAX_LENGTH = 128;\n\n/**\n * Return every policy rule the given password violates. An empty array means\n * the password is acceptable.\n */\nexport function validatePasswordPolicy(password: string): PasswordPolicyError[] {\n const errors: PasswordPolicyError[] = [];\n if (password.length < PASSWORD_MIN_LENGTH) {\n errors.push(PasswordPolicyError.TooShort);\n }\n if (password.length > PASSWORD_MAX_LENGTH) {\n errors.push(PasswordPolicyError.TooLong);\n }\n if (!UPPERCASE_REGEX.test(password)) {\n errors.push(PasswordPolicyError.MissingUppercase);\n }\n if (!LOWERCASE_REGEX.test(password)) {\n errors.push(PasswordPolicyError.MissingLowercase);\n }\n if (!DIGIT_REGEX.test(password)) {\n errors.push(PasswordPolicyError.MissingDigit);\n }\n return errors;\n}\n\n/** `true` when the password satisfies every policy rule. */\nexport function isPasswordValid(password: string): boolean {\n return validatePasswordPolicy(password).length === 0;\n}\n","/**\n * `useResetPasswordForm` — form-state + submit logic for the reset-password\n * screen.\n *\n * The (testable) logic — policy validation, confirm-match, error mapping — is\n * kept out of the rendered component so `<ResetPasswordForm>` stays thin and\n * the rules are unit-tested directly. The hook returns plain values + callbacks\n * the component (or a custom layout) wires to JSX.\n *\n * Behaviour:\n * - Validates the new password against the shared `passwordPolicy`.\n * - Validates confirmPassword matches.\n * - Surfaces a single `ResetPasswordError` at submit time, preferring the\n * earliest-fixable issue (empty → weak → mismatch → token).\n * - Calls `useBffResetPassword` (`POST /bff/reset-password`). On success,\n * invokes the supplied `onSuccess`.\n *\n * Extracted + generalised from `apps/katalogos-web/src/auth/useResetPasswordForm.ts`.\n */\nimport { useMemo, useState } from 'react';\n\nimport { ResetPasswordError } from './ResetPasswordError';\nimport { useBffResetPassword } from './useBffPasswordHooks';\nimport { isPasswordValid } from '../password/passwordPolicy';\n\nimport type { BffAuthClient } from '@dloizides/auth-client';\n\nconst HTTP_BAD_REQUEST = 400;\n\nexport interface UseResetPasswordFormArgs {\n /** The same-origin BFF client. */\n client: BffAuthClient;\n /** The reset token, typically read from the deep-link URL. */\n token: string;\n /** Invoked once the password has been reset successfully. */\n onSuccess: () => void;\n}\n\nexport interface UseResetPasswordFormResult {\n newPassword: string;\n confirmPassword: string;\n setNewPassword: (value: string) => void;\n setConfirmPassword: (value: string) => void;\n /** `true` while the reset request is in flight. */\n isSubmitting: boolean;\n /** The single active error, or `null` when the form is clean. */\n errorKey: ResetPasswordError | null;\n /** `true` once a token-related failure is detected (drives a \"request a new link\" UI). */\n hasInvalidToken: boolean;\n /** Validate, then submit. */\n submit: () => void;\n}\n\n/** `true` when the BFF error message carries the given HTTP status. */\nfunction isHttpStatusError(message: string, status: number): boolean {\n return message.includes(` status ${String(status)}`);\n}\n\n/** Run the synchronous pre-flight checks; the earliest-fixable failure wins. */\nfunction preflight(args: {\n newPassword: string;\n confirm: string;\n token: string;\n}): ResetPasswordError | null {\n if (args.newPassword.length === 0 || args.confirm.length === 0) {\n return ResetPasswordError.Empty;\n }\n if (!isPasswordValid(args.newPassword)) {\n return ResetPasswordError.WeakPassword;\n }\n if (args.newPassword !== args.confirm) {\n return ResetPasswordError.Mismatch;\n }\n if (args.token === '') {\n return ResetPasswordError.TokenInvalid;\n }\n return null;\n}\n\ninterface MutationCallbacks {\n onSuccess: () => void;\n setErrorKey: (error: ResetPasswordError) => void;\n setHasInvalidToken: (value: boolean) => void;\n}\n\n/** Wire the reset mutation, mapping a backend 400 onto a token-invalid error. */\nfunction useResetMutation(\n client: BffAuthClient,\n callbacks: MutationCallbacks,\n): ReturnType<typeof useBffResetPassword> {\n const mutationOptions = useMemo(\n () => ({\n client,\n onSuccess: callbacks.onSuccess,\n onError: (err: Error): void => {\n if (isHttpStatusError(err.message, HTTP_BAD_REQUEST)) {\n callbacks.setHasInvalidToken(true);\n callbacks.setErrorKey(ResetPasswordError.TokenInvalid);\n return;\n }\n callbacks.setErrorKey(ResetPasswordError.Network);\n },\n }),\n [client, callbacks],\n );\n return useBffResetPassword(mutationOptions);\n}\n\ninterface SubmitArgs {\n newPassword: string;\n confirmPassword: string;\n token: string;\n setErrorKey: (error: ResetPasswordError | null) => void;\n setHasInvalidToken: (value: boolean) => void;\n mutate: (request: { token: string; newPassword: string }) => void;\n}\n\n/** Validate, then either fire the mutation or surface the pre-flight failure. */\nfunction runSubmit(args: SubmitArgs): void {\n args.setErrorKey(null);\n const failure = preflight({\n newPassword: args.newPassword,\n confirm: args.confirmPassword,\n token: args.token,\n });\n if (failure === null) {\n args.mutate({ token: args.token, newPassword: args.newPassword });\n return;\n }\n if (failure === ResetPasswordError.TokenInvalid) {\n args.setHasInvalidToken(true);\n }\n args.setErrorKey(failure);\n}\n\ninterface FormState {\n newPassword: string;\n confirmPassword: string;\n errorKey: ResetPasswordError | null;\n hasInvalidToken: boolean;\n}\n\ninterface FormSetters {\n setNewPassword: (value: string) => void;\n setConfirmPassword: (value: string) => void;\n setErrorKey: (error: ResetPasswordError | null) => void;\n setHasInvalidToken: (value: boolean) => void;\n}\n\n/** Bundle the four `useState` cells the form needs. */\nfunction useFormState(): { state: FormState; setters: FormSetters } {\n const [newPassword, setNewPassword] = useState('');\n const [confirmPassword, setConfirmPassword] = useState('');\n const [errorKey, setErrorKey] = useState<ResetPasswordError | null>(null);\n const [hasInvalidToken, setHasInvalidToken] = useState(false);\n return {\n state: { newPassword, confirmPassword, errorKey, hasInvalidToken },\n setters: { setNewPassword, setConfirmPassword, setErrorKey, setHasInvalidToken },\n };\n}\n\n/**\n * Headless reset-password form logic. Returns the field values, setters, the\n * single active error, and a `submit` callback.\n */\nexport function useResetPasswordForm({\n client,\n token,\n onSuccess,\n}: UseResetPasswordFormArgs): UseResetPasswordFormResult {\n const { state, setters } = useFormState();\n const callbacks = useMemo<MutationCallbacks>(\n () => ({\n onSuccess,\n setErrorKey: setters.setErrorKey,\n setHasInvalidToken: setters.setHasInvalidToken,\n }),\n [onSuccess, setters.setErrorKey, setters.setHasInvalidToken],\n );\n const mutation = useResetMutation(client, callbacks);\n const submit = (): void =>\n runSubmit({\n newPassword: state.newPassword,\n confirmPassword: state.confirmPassword,\n token,\n setErrorKey: setters.setErrorKey,\n setHasInvalidToken: setters.setHasInvalidToken,\n mutate: mutation.mutate,\n });\n return {\n newPassword: state.newPassword,\n confirmPassword: state.confirmPassword,\n setNewPassword: setters.setNewPassword,\n setConfirmPassword: setters.setConfirmPassword,\n isSubmitting: mutation.status === 'pending',\n errorKey: state.errorKey,\n hasInvalidToken: state.hasInvalidToken,\n submit,\n };\n}\n","/**\n * `<ResetPasswordForm>` — the ready-made, themeable \"choose a new password\"\n * form.\n *\n * Built on the headless `useResetPasswordForm` hook, which owns all the logic\n * (shared password policy, confirm-match, backend-error mapping). The component\n * is a thin render layer: two fields, one button, one error line.\n *\n * Extracted + generalised from `apps/katalogos-web/src/auth/useResetPasswordForm.ts`\n * + the katalogos reset-password route — minus the app-specific `FM()` and\n * router calls (copy is in `labels`, navigation is the app's `onSuccess`).\n */\nimport { useMemo, type ReactElement } from 'react';\n\nimport { ActivityIndicator, Text, TextInput, TouchableOpacity, View } from 'react-native';\n\nimport { DEFAULT_RESET_PASSWORD_LABELS, type ResetPasswordFormLabels } from './labels';\nimport { AuthTestIds, withTestIdPrefix } from './testIds';\nimport { useAuthStyles } from './useAuthStyles';\nimport { ResetPasswordError } from '../hooks/ResetPasswordError';\nimport { useResetPasswordForm } from '../hooks/useResetPasswordForm';\nimport { useAuthTheme } from '../theme/AuthThemeProvider';\n\nimport type { AuthTheme } from '../theme/AuthTheme';\nimport type { BffAuthClient } from '@dloizides/auth-client';\n\nexport interface ResetPasswordFormProps {\n /** The same-origin BFF client (build it with `createBffAuthClient`). */\n client: BffAuthClient;\n /** The reset token, typically read from the deep-link URL by the app. */\n token: string;\n /** Explicit theme; overrides any `<AuthThemeProvider>`. */\n theme?: AuthTheme;\n /** Localised copy. Partial — unspecified keys fall back to English defaults. */\n labels?: Partial<ResetPasswordFormLabels>;\n /** Called once the password has been reset successfully. */\n onSuccess: () => void;\n /** Prefix applied to every `testID`. */\n testIdPrefix?: string;\n}\n\n/** Resolve the active `ResetPasswordError` onto its localised message. */\nfunction errorMessage(\n errorKey: ResetPasswordError | null,\n labels: ResetPasswordFormLabels,\n): string | null {\n switch (errorKey) {\n case ResetPasswordError.Empty:\n return labels.errorEmpty;\n case ResetPasswordError.WeakPassword:\n return labels.errorWeakPassword;\n case ResetPasswordError.Mismatch:\n return labels.errorMismatch;\n case ResetPasswordError.TokenInvalid:\n return labels.errorTokenInvalid;\n case ResetPasswordError.Network:\n return labels.errorNetwork;\n default:\n return null;\n }\n}\n\n/** Themeable \"choose a new password\" form built on `useResetPasswordForm`. */\nexport function ResetPasswordForm({\n client,\n token,\n theme: themeProp,\n labels: labelsProp,\n onSuccess,\n testIdPrefix,\n}: Readonly<ResetPasswordFormProps>): ReactElement {\n const theme = useAuthTheme(themeProp);\n const styles = useAuthStyles(theme);\n const labels = useMemo<ResetPasswordFormLabels>(\n () => ({ ...DEFAULT_RESET_PASSWORD_LABELS, ...labelsProp }),\n [labelsProp],\n );\n\n const form = useResetPasswordForm({ client, token, onSuccess });\n const message = errorMessage(form.errorKey, labels);\n\n const submitButtonStyle = form.isSubmitting\n ? [styles.primaryButton, styles.primaryButtonDisabled]\n : styles.primaryButton;\n\n return (\n <View style={styles.screen}>\n <View\n style={styles.card}\n testID={withTestIdPrefix(AuthTestIds.resetPasswordForm, testIdPrefix)}\n >\n <Text style={styles.title}>{labels.title}</Text>\n <Text style={styles.subtitle}>{labels.description}</Text>\n\n <View style={styles.fieldGroup}>\n <Text style={styles.label}>{labels.newPasswordLabel}</Text>\n <TextInput\n secureTextEntry\n accessibilityHint={labels.newPasswordPlaceholder}\n accessibilityLabel={labels.newPasswordLabel}\n autoCapitalize=\"none\"\n autoCorrect={false}\n editable={!form.isSubmitting}\n placeholder={labels.newPasswordPlaceholder}\n placeholderTextColor={theme.colors.textSecondary}\n style={styles.input}\n testID={withTestIdPrefix(AuthTestIds.resetPasswordNewInput, testIdPrefix)}\n value={form.newPassword}\n onChangeText={form.setNewPassword}\n />\n </View>\n\n <View style={styles.fieldGroup}>\n <Text style={styles.label}>{labels.confirmPasswordLabel}</Text>\n <TextInput\n secureTextEntry\n accessibilityHint={labels.confirmPasswordPlaceholder}\n accessibilityLabel={labels.confirmPasswordLabel}\n autoCapitalize=\"none\"\n autoCorrect={false}\n editable={!form.isSubmitting}\n placeholder={labels.confirmPasswordPlaceholder}\n placeholderTextColor={theme.colors.textSecondary}\n style={styles.input}\n testID={withTestIdPrefix(AuthTestIds.resetPasswordConfirmInput, testIdPrefix)}\n value={form.confirmPassword}\n onChangeText={form.setConfirmPassword}\n />\n </View>\n\n {message !== null ? (\n <Text\n style={styles.errorText}\n testID={withTestIdPrefix(AuthTestIds.resetPasswordError, testIdPrefix)}\n >\n {message}\n </Text>\n ) : null}\n\n <TouchableOpacity\n accessibilityHint={labels.submit}\n accessibilityLabel={form.isSubmitting ? labels.submitting : labels.submit}\n accessibilityRole=\"button\"\n disabled={form.isSubmitting}\n style={submitButtonStyle}\n testID={withTestIdPrefix(AuthTestIds.resetPasswordSubmitButton, testIdPrefix)}\n onPress={form.submit}\n >\n {form.isSubmitting ? (\n <ActivityIndicator color={theme.colors.onPrimary} size=\"small\" />\n ) : (\n <Text style={styles.primaryButtonText}>{labels.submit}</Text>\n )}\n </TouchableOpacity>\n </View>\n </View>\n );\n}\n","/**\n * The two step sub-components of `<OtpForm>` — `<OtpRequestStep>` (collect the\n * email, ask the BFF to send a code) and `<OtpVerifyStep>` (collect the code,\n * verify it, offer resend / change-email).\n *\n * Split out of `OtpForm.tsx` to keep that file focused on the flow wiring; each\n * step is a thin, self-contained render layer. Both are styled by the shared\n * `AuthStyles` token-derived stylesheet so they match the other auth forms.\n */\nimport { useState, type ReactElement } from 'react';\n\nimport { ActivityIndicator, Text, TextInput, TouchableOpacity, View } from 'react-native';\n\nimport { AuthTestIds, withTestIdPrefix } from './testIds';\nimport { type AuthStyles } from './useAuthStyles';\n\nimport type { OtpFormLabels } from './labels';\nimport type { AuthTheme } from '../theme/AuthTheme';\n\nexport interface OtpRequestStepProps {\n styles: AuthStyles;\n theme: AuthTheme;\n labels: OtpFormLabels;\n testIdPrefix?: string;\n isSubmitting: boolean;\n errorText: string | null;\n /** Called with the trimmed email when the user taps \"send code\". */\n onSubmit: (email: string) => void;\n}\n\n/** Step 1 — collect the email and trigger `POST /bff/otp/request`. */\nexport function OtpRequestStep({\n styles,\n theme,\n labels,\n testIdPrefix,\n isSubmitting,\n errorText,\n onSubmit,\n}: Readonly<OtpRequestStepProps>): ReactElement {\n const [email, setEmail] = useState('');\n const buttonStyle = isSubmitting\n ? [styles.primaryButton, styles.primaryButtonDisabled]\n : styles.primaryButton;\n\n return (\n <>\n <Text style={styles.title}>{labels.requestTitle}</Text>\n <Text style={styles.subtitle}>{labels.requestDescription}</Text>\n\n <View style={styles.fieldGroup}>\n <Text style={styles.label}>{labels.emailLabel}</Text>\n <TextInput\n accessibilityHint={labels.emailPlaceholder}\n accessibilityLabel={labels.emailLabel}\n autoCapitalize=\"none\"\n autoCorrect={false}\n editable={!isSubmitting}\n keyboardType=\"email-address\"\n placeholder={labels.emailPlaceholder}\n placeholderTextColor={theme.colors.textSecondary}\n style={styles.input}\n testID={withTestIdPrefix(AuthTestIds.otpEmailInput, testIdPrefix)}\n value={email}\n onChangeText={setEmail}\n />\n </View>\n\n {errorText !== null ? (\n <Text style={styles.errorText} testID={withTestIdPrefix(AuthTestIds.otpError, testIdPrefix)}>\n {errorText}\n </Text>\n ) : null}\n\n <TouchableOpacity\n accessibilityHint={labels.requestSubmit}\n accessibilityLabel={isSubmitting ? labels.requesting : labels.requestSubmit}\n accessibilityRole=\"button\"\n disabled={isSubmitting}\n style={buttonStyle}\n testID={withTestIdPrefix(AuthTestIds.otpRequestButton, testIdPrefix)}\n onPress={(): void => onSubmit(email.trim())}\n >\n {isSubmitting ? (\n <ActivityIndicator color={theme.colors.onPrimary} size=\"small\" />\n ) : (\n <Text style={styles.primaryButtonText}>{labels.requestSubmit}</Text>\n )}\n </TouchableOpacity>\n </>\n );\n}\n\nexport interface OtpVerifyStepProps {\n styles: AuthStyles;\n theme: AuthTheme;\n labels: OtpFormLabels;\n testIdPrefix?: string;\n /** The email the code was sent to — interpolated into the description copy. */\n identifier: string;\n isSubmitting: boolean;\n errorText: string | null;\n /** Called with the trimmed code when the user taps \"verify\". */\n onSubmit: (code: string) => void;\n /** Called when the user taps \"resend code\". */\n onResend: () => void;\n /** Called when the user taps \"use a different email\". */\n onChangeEmail: () => void;\n}\n\n/** Step 2 — collect the code, verify it, and offer resend / change-email. */\nexport function OtpVerifyStep({\n styles,\n theme,\n labels,\n testIdPrefix,\n identifier,\n isSubmitting,\n errorText,\n onSubmit,\n onResend,\n onChangeEmail,\n}: Readonly<OtpVerifyStepProps>): ReactElement {\n const [code, setCode] = useState('');\n const buttonStyle = isSubmitting\n ? [styles.primaryButton, styles.primaryButtonDisabled]\n : styles.primaryButton;\n const description = labels.verifyDescription.replace('{identifier}', identifier);\n\n return (\n <>\n <Text style={styles.title}>{labels.verifyTitle}</Text>\n <Text style={styles.subtitle}>{description}</Text>\n\n <View style={styles.fieldGroup}>\n <Text style={styles.label}>{labels.codeLabel}</Text>\n <TextInput\n accessibilityHint={labels.codePlaceholder}\n accessibilityLabel={labels.codeLabel}\n autoCapitalize=\"none\"\n autoCorrect={false}\n editable={!isSubmitting}\n keyboardType=\"number-pad\"\n placeholder={labels.codePlaceholder}\n placeholderTextColor={theme.colors.textSecondary}\n style={styles.input}\n testID={withTestIdPrefix(AuthTestIds.otpCodeInput, testIdPrefix)}\n value={code}\n onChangeText={setCode}\n />\n </View>\n\n {errorText !== null ? (\n <Text style={styles.errorText} testID={withTestIdPrefix(AuthTestIds.otpError, testIdPrefix)}>\n {errorText}\n </Text>\n ) : null}\n\n <TouchableOpacity\n accessibilityHint={labels.verifySubmit}\n accessibilityLabel={isSubmitting ? labels.verifying : labels.verifySubmit}\n accessibilityRole=\"button\"\n disabled={isSubmitting}\n style={buttonStyle}\n testID={withTestIdPrefix(AuthTestIds.otpVerifyButton, testIdPrefix)}\n onPress={(): void => onSubmit(code.trim())}\n >\n {isSubmitting ? (\n <ActivityIndicator color={theme.colors.onPrimary} size=\"small\" />\n ) : (\n <Text style={styles.primaryButtonText}>{labels.verifySubmit}</Text>\n )}\n </TouchableOpacity>\n\n <TouchableOpacity\n accessibilityHint={labels.resend}\n accessibilityLabel={isSubmitting ? labels.resending : labels.resend}\n accessibilityRole=\"link\"\n disabled={isSubmitting}\n style={styles.fieldGroup}\n testID={withTestIdPrefix(AuthTestIds.otpResendButton, testIdPrefix)}\n onPress={onResend}\n >\n <Text style={styles.linkText}>{isSubmitting ? labels.resending : labels.resend}</Text>\n </TouchableOpacity>\n\n <TouchableOpacity\n accessibilityHint={labels.changeEmail}\n accessibilityLabel={labels.changeEmail}\n accessibilityRole=\"link\"\n disabled={isSubmitting}\n testID={withTestIdPrefix(AuthTestIds.otpChangeEmailButton, testIdPrefix)}\n onPress={onChangeEmail}\n >\n <Text style={styles.linkText}>{labels.changeEmail}</Text>\n </TouchableOpacity>\n </>\n );\n}\n","/**\n * The two discrete steps of the email-OTP login flow.\n *\n * `useOtpLogin` is at exactly one of these at a time, and `<OtpForm>` renders a\n * different surface per step. The flow is strictly forward: a request moves\n * `RequestCode` → `EnterCode`; a resend stays on `EnterCode`. Each member is a\n * stable key — `<OtpForm>` switches on it, never on a string literal.\n */\nexport const enum OtpLoginStep {\n /** Step 1: collect the email and ask the BFF to send a code. */\n RequestCode = 'requestCode',\n /** Step 2: the code is on its way — collect and verify it. */\n EnterCode = 'enterCode',\n}\n","/**\n * `useOtpLogin` — the headless email-OTP login hook.\n *\n * The \"escape hatch\" half of the OTP design: apps that want a fully custom\n * layout skip `<OtpForm>` and drive the two-step flow themselves with this\n * hook. `<OtpForm>` itself is built on top of it, so the ready-made and the\n * custom paths share one code path — the same lesson as `useBffAuth`.\n *\n * The flow is a small forward state machine:\n *\n * step 1 `RequestCode` → `requestCode(identifier)` → `POST /bff/otp/request`\n * step 2 `EnterCode` → `verifyCode(otp)` → `POST /bff/otp/verify`\n * → `resend()` → `POST /bff/otp/request`\n *\n * It owns nothing the BFF owns — no tokens, no refresh, no realm awareness. It\n * holds only the current step, the identifier the code was sent to, the latest\n * `requestOtp` result (so the UI can show the expiry), and the in-flight status\n * + error. A successful `verifyCode` resolves to the `BffUser` exactly like\n * `useBffAuth.login`; the consumer routes from there.\n *\n * `BffAuthClient` / `BffUser` / `BffOtpRequestResult` come from\n * `@dloizides/auth-client`.\n */\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react';\n\nimport { OtpLoginStep } from './OtpLoginStep';\n\nimport type {\n BffAuthClient,\n BffOtpRequestResult,\n BffUser,\n} from '@dloizides/auth-client';\n\nexport interface UseOtpLoginOptions {\n /** The same-origin BFF client (build it with `createBffAuthClient`). */\n client: BffAuthClient;\n}\n\nexport interface UseOtpLoginResult {\n /** Which of the two steps the flow is currently on. */\n step: OtpLoginStep;\n /** The identifier (email) the code was last requested for; `''` before step 1. */\n identifier: string;\n /**\n * The latest `POST /bff/otp/request` result, or `null` before any request.\n * Carries `expiresIn` for a countdown — never depend on `code` being present.\n */\n lastRequest: BffOtpRequestResult | null;\n /** `true` while a `requestCode` / `verifyCode` / `resend` call is in flight. */\n isSubmitting: boolean;\n /** The last error, cleared at the start of the next attempt. */\n error: Error | null;\n /**\n * Step 1 — ask the BFF to email a code to `identifier`. On success the flow\n * advances to `EnterCode`. Rejects (and stays on `RequestCode`) on failure.\n */\n requestCode: (identifier: string) => Promise<BffOtpRequestResult>;\n /**\n * Step 2 — verify the entered `otp` for the stored identifier. Resolves to the\n * signed-in `BffUser`; rejects on a bad / expired code (the flow stays on\n * `EnterCode` so the user can retry or resend).\n */\n verifyCode: (otp: string) => Promise<BffUser>;\n /**\n * Re-send a code to the stored identifier without leaving `EnterCode`. A\n * convenience wrapper over `requestOtp` for the step-2 \"resend\" affordance.\n */\n resend: () => Promise<BffOtpRequestResult>;\n /** Return to step 1 (e.g. the user mistyped their email). Clears the error. */\n reset: () => void;\n}\n\nfunction toError(value: unknown): Error {\n return value instanceof Error ? value : new Error(String(value));\n}\n\n/** Internal: the step + identifier + last-request triple the hook tracks. */\ninterface FlowState {\n step: OtpLoginStep;\n identifier: string;\n lastRequest: BffOtpRequestResult | null;\n}\n\nconst INITIAL_FLOW: FlowState = {\n step: OtpLoginStep.RequestCode,\n identifier: '',\n lastRequest: null,\n};\n\n/**\n * Headless email-OTP login. Returns the current step, the in-flight status, and\n * `requestCode` / `verifyCode` / `resend` / `reset` callbacks. No rendering —\n * the consumer (or `<OtpForm>`) wires it to UI.\n */\nexport function useOtpLogin(options: UseOtpLoginOptions): UseOtpLoginResult {\n const { client } = options;\n\n const [flow, setFlow] = useState<FlowState>(INITIAL_FLOW);\n const [isSubmitting, setIsSubmitting] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n\n // Guard against a `setState` after the consumer unmounts mid-request.\n const mountedRef = useRef(true);\n useEffect(() => {\n mountedRef.current = true;\n return (): void => {\n mountedRef.current = false;\n };\n }, []);\n\n // The identifier is also held in a ref so `verifyCode` / `resend` read the\n // latest value without being re-created every time `flow` changes.\n const identifierRef = useRef('');\n\n const beginAttempt = useCallback((): void => {\n if (mountedRef.current) {\n setIsSubmitting(true);\n setError(null);\n }\n }, []);\n\n const endAttempt = useCallback((): void => {\n if (mountedRef.current) {\n setIsSubmitting(false);\n }\n }, []);\n\n /** Shared `requestOtp` call used by both `requestCode` and `resend`. */\n const sendCode = useCallback(\n async (identifier: string): Promise<BffOtpRequestResult> => {\n beginAttempt();\n try {\n const result = await client.requestOtp({ identifier });\n identifierRef.current = identifier;\n if (mountedRef.current) {\n setFlow({ step: OtpLoginStep.EnterCode, identifier, lastRequest: result });\n }\n return result;\n } catch (caught) {\n const err = toError(caught);\n if (mountedRef.current) {\n setError(err);\n }\n throw err;\n } finally {\n endAttempt();\n }\n },\n [client, beginAttempt, endAttempt],\n );\n\n const requestCode = useCallback(\n (identifier: string): Promise<BffOtpRequestResult> => sendCode(identifier),\n [sendCode],\n );\n\n const resend = useCallback(\n (): Promise<BffOtpRequestResult> => sendCode(identifierRef.current),\n [sendCode],\n );\n\n const verifyCode = useCallback(\n async (otp: string): Promise<BffUser> => {\n beginAttempt();\n try {\n return await client.verifyOtp({ username: identifierRef.current, otp });\n } catch (caught) {\n const err = toError(caught);\n if (mountedRef.current) {\n setError(err);\n }\n throw err;\n } finally {\n endAttempt();\n }\n },\n [client, beginAttempt, endAttempt],\n );\n\n const reset = useCallback((): void => {\n identifierRef.current = '';\n if (mountedRef.current) {\n setFlow(INITIAL_FLOW);\n setError(null);\n }\n }, []);\n\n return useMemo(\n () => ({\n step: flow.step,\n identifier: flow.identifier,\n lastRequest: flow.lastRequest,\n isSubmitting,\n error,\n requestCode,\n verifyCode,\n resend,\n reset,\n }),\n [\n flow.step,\n flow.identifier,\n flow.lastRequest,\n isSubmitting,\n error,\n requestCode,\n verifyCode,\n resend,\n reset,\n ],\n );\n}\n","/**\n * `<OtpForm>` — the ready-made, themeable two-step email-OTP login form.\n *\n * The \"themeable component\" half of the OTP design: drop it in, pass a\n * `client`, a `theme` (or wrap in `<AuthThemeProvider>`) and a localised\n * `labels` bag, and you have a branded email-OTP surface. It is built on the\n * headless `useOtpLogin` hook, so the ready-made and custom-layout paths share\n * one code path — the same pattern as `<LoginForm>`.\n *\n * Two steps, switched on `OtpLoginStep`:\n * 1. `RequestCode` — `<OtpRequestStep>`: an email field + a \"send code\" button.\n * 2. `EnterCode` — `<OtpVerifyStep>`: a code field + a \"verify\" button, plus\n * \"resend code\" and \"use a different email\" affordances.\n *\n * The package ships no router and no i18n. `onSuccess` hands the signed-in\n * `BffUser` back to the app; all copy comes from `labels`.\n */\nimport { useCallback, useMemo, useState, type ReactElement } from 'react';\n\nimport { View } from 'react-native';\n\nimport { DEFAULT_OTP_LABELS, type OtpFormLabels } from './labels';\nimport { OtpRequestStep, OtpVerifyStep } from './OtpFormSteps';\nimport { AuthTestIds, withTestIdPrefix } from './testIds';\nimport { useAuthStyles } from './useAuthStyles';\nimport { OtpLoginStep } from '../hooks/OtpLoginStep';\nimport { useOtpLogin, type UseOtpLoginResult } from '../hooks/useOtpLogin';\nimport { useAuthTheme } from '../theme/AuthThemeProvider';\n\nimport type { AuthTheme } from '../theme/AuthTheme';\nimport type { BffAuthClient, BffUser } from '@dloizides/auth-client';\n\n// A deliberately loose, linear-time email shape check — identical to the one\n// `<ForgotPasswordForm>` uses. Strict validation is the backend's job.\nconst EMAIL_REGEX = /^[^@\\s]+@[^.\\s]+\\.[^\\s]+$/;\n\nexport interface OtpFormProps {\n /** The same-origin BFF client (build it with `createBffAuthClient`). */\n client: BffAuthClient;\n /** Explicit theme; overrides any `<AuthThemeProvider>`. Falls back to the default theme. */\n theme?: AuthTheme;\n /** Localised copy. Partial — unspecified keys fall back to English defaults. */\n labels?: Partial<OtpFormLabels>;\n /** Called with the signed-in user after a successful code verification. */\n onSuccess: (user: BffUser) => void;\n /** Prefix applied to every `testID` so multiple forms can share a screen. */\n testIdPrefix?: string;\n /**\n * When `true`, render WITHOUT the built-in `screen` + `card` chrome so the\n * form can be composed as a child of `<AuthScreen>`. Defaults to `false` —\n * standalone drop-in behaviour is byte-identical to before.\n */\n chromeless?: boolean;\n}\n\n/** `true` when `value` looks like an email address. */\nfunction isValidEmail(value: string): boolean {\n return EMAIL_REGEX.test(value);\n}\n\n/** Resolve the in-flight transport error onto a localised, non-leaking message. */\nfunction transportErrorFor(\n step: OtpLoginStep,\n error: Error | null,\n labels: OtpFormLabels,\n): string | null {\n if (error === null) {\n return null;\n }\n // Never echo the raw error — it can leak whether the identifier exists. Show\n // a generic, step-appropriate message instead.\n return step === OtpLoginStep.RequestCode ? labels.invalidEmail : labels.invalidCode;\n}\n\n/** Drive step 1: validate the email locally, then call `requestCode`. */\nfunction useRequestHandler(\n otp: UseOtpLoginResult,\n labels: OtpFormLabels,\n setLocalError: (value: string | null) => void,\n): (email: string) => void {\n return useCallback(\n (email: string): void => {\n setLocalError(null);\n if (!isValidEmail(email)) {\n setLocalError(labels.invalidEmail);\n return;\n }\n void otp.requestCode(email).catch(() => undefined);\n },\n [otp, labels.invalidEmail, setLocalError],\n );\n}\n\n/** Drive step 2: validate the code is present, then call `verifyCode`. */\nfunction useVerifyHandler(\n otp: UseOtpLoginResult,\n labels: OtpFormLabels,\n setLocalError: (value: string | null) => void,\n onSuccess: (user: BffUser) => void,\n): (code: string) => void {\n return useCallback(\n (code: string): void => {\n setLocalError(null);\n if (code.length === 0) {\n setLocalError(labels.missingCode);\n return;\n }\n otp\n .verifyCode(code)\n .then((user) => {\n onSuccess(user);\n })\n .catch(() => undefined);\n },\n [otp, labels.missingCode, setLocalError, onSuccess],\n );\n}\n\n/** Themeable two-step email-OTP login form built on `useOtpLogin`. */\nexport function OtpForm({\n client,\n theme: themeProp,\n labels: labelsProp,\n onSuccess,\n testIdPrefix,\n chromeless = false,\n}: Readonly<OtpFormProps>): ReactElement {\n const theme = useAuthTheme(themeProp);\n const styles = useAuthStyles(theme);\n const labels = useMemo<OtpFormLabels>(\n () => ({ ...DEFAULT_OTP_LABELS, ...labelsProp }),\n [labelsProp],\n );\n\n const otp = useOtpLogin({ client });\n // A local validation error (bad email / empty code) lives separately from the\n // hook's transport error so a client-side failure does not need a round-trip.\n const [localError, setLocalError] = useState<string | null>(null);\n\n const handleRequest = useRequestHandler(otp, labels, setLocalError);\n const handleVerify = useVerifyHandler(otp, labels, setLocalError, onSuccess);\n const handleResend = useCallback((): void => {\n setLocalError(null);\n void otp.resend().catch(() => undefined);\n }, [otp]);\n const handleChangeEmail = useCallback((): void => {\n setLocalError(null);\n otp.reset();\n }, [otp]);\n\n const errorText = localError ?? transportErrorFor(otp.step, otp.error, labels);\n\n const content =\n otp.step === OtpLoginStep.RequestCode ? (\n <OtpRequestStep\n errorText={errorText}\n isSubmitting={otp.isSubmitting}\n labels={labels}\n styles={styles}\n testIdPrefix={testIdPrefix}\n theme={theme}\n onSubmit={handleRequest}\n />\n ) : (\n <OtpVerifyStep\n errorText={errorText}\n identifier={otp.identifier}\n isSubmitting={otp.isSubmitting}\n labels={labels}\n styles={styles}\n testIdPrefix={testIdPrefix}\n theme={theme}\n onChangeEmail={handleChangeEmail}\n onResend={handleResend}\n onSubmit={handleVerify}\n />\n );\n\n const card = (\n <View\n style={chromeless ? undefined : styles.card}\n testID={withTestIdPrefix(AuthTestIds.otpForm, testIdPrefix)}\n >\n {content}\n </View>\n );\n\n return chromeless ? card : <View style={styles.screen}>{card}</View>;\n}\n","/**\n * `usePinLogin` — the headless event-scoped PIN login hook.\n *\n * The \"escape hatch\" half of the PIN design: apps that want a fully custom\n * layout skip `<PinForm>` and drive the flow themselves with this hook.\n * `<PinForm>` itself is built on top of it, so the ready-made and the custom\n * paths share one code path — the same lesson as `useOtpLogin` / `useBffAuth`.\n *\n * Unlike `useOtpLogin` the PIN flow is a **single step** — there is no\n * request/verify split, the staff member just enters the PIN:\n *\n * `submit(pin)` → `POST /bff/pin/login` → `BffUser`\n *\n * The `(event, pin)` pair alone identifies the staff member (unified-auth plan\n * §4.4) — the `eventExternalId` is supplied to the hook by the page/route, the\n * PIN by the user. It owns nothing the BFF owns — no tokens, no refresh, no\n * realm awareness. It holds only the in-flight status + error. A successful\n * `submit` resolves to the `BffUser` exactly like `useBffAuth.login`; the\n * consumer routes from there.\n *\n * `BffAuthClient` / `BffUser` come from `@dloizides/auth-client`.\n */\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react';\n\nimport type { BffAuthClient, BffUser } from '@dloizides/auth-client';\n\nexport interface UsePinLoginOptions {\n /** The same-origin BFF client (build it with `createBffAuthClient`). */\n client: BffAuthClient;\n /**\n * External id of the event the PIN is scoped to. Supplied by the page/route\n * — the event context is never typed by the user.\n */\n eventExternalId: string;\n}\n\nexport interface UsePinLoginResult {\n /** `true` while a `submit` call is in flight. */\n isSubmitting: boolean;\n /** The last error, cleared at the start of the next attempt. */\n error: Error | null;\n /**\n * Exchange the entered `pin` (for the hook's `eventExternalId`) for a\n * session. Resolves to the signed-in `BffUser`; rejects on a bad / expired /\n * locked-out PIN (the consumer can let the user retry).\n */\n submit: (pin: string) => Promise<BffUser>;\n /** Clear the current error so the form can be retried cleanly. */\n reset: () => void;\n}\n\nfunction toError(value: unknown): Error {\n return value instanceof Error ? value : new Error(String(value));\n}\n\n/**\n * Headless event-scoped PIN login. Returns the in-flight status, the last\n * error, and `submit` / `reset` callbacks. No rendering — the consumer (or\n * `<PinForm>`) wires it to UI.\n */\nexport function usePinLogin(options: UsePinLoginOptions): UsePinLoginResult {\n const { client, eventExternalId } = options;\n\n const [isSubmitting, setIsSubmitting] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n\n // Guard against a `setState` after the consumer unmounts mid-request.\n const mountedRef = useRef(true);\n useEffect(() => {\n mountedRef.current = true;\n return (): void => {\n mountedRef.current = false;\n };\n }, []);\n\n // The event id is also held in a ref so `submit` reads the latest value\n // without being re-created every time the prop changes.\n const eventIdRef = useRef(eventExternalId);\n useEffect(() => {\n eventIdRef.current = eventExternalId;\n }, [eventExternalId]);\n\n const submit = useCallback(\n async (pin: string): Promise<BffUser> => {\n if (mountedRef.current) {\n setIsSubmitting(true);\n setError(null);\n }\n try {\n return await client.pinLogin({ pin, eventExternalId: eventIdRef.current });\n } catch (caught) {\n const err = toError(caught);\n if (mountedRef.current) {\n setError(err);\n }\n throw err;\n } finally {\n if (mountedRef.current) {\n setIsSubmitting(false);\n }\n }\n },\n [client],\n );\n\n const reset = useCallback((): void => {\n if (mountedRef.current) {\n setError(null);\n }\n }, []);\n\n return useMemo(\n () => ({ isSubmitting, error, submit, reset }),\n [isSubmitting, error, submit, reset],\n );\n}\n","/**\n * `<PinForm>` — the ready-made, themeable single-step event-PIN login form.\n *\n * The \"themeable component\" half of the PIN design: drop it in, pass a\n * `client`, the `eventExternalId` of the event the staff member is signing in\n * to, a `theme` (or wrap in `<AuthThemeProvider>`) and a localised `labels`\n * bag, and you have a branded event-PIN surface. It is built on the headless\n * `usePinLogin` hook, so the ready-made and custom-layout paths share one code\n * path — the same pattern as `<OtpForm>` / `<LoginForm>`.\n *\n * Unlike `<OtpForm>` the PIN flow is a single step: a PIN field + a \"sign in\"\n * button. The `eventExternalId` is a prop, never typed by the user — the event\n * context comes from the route/page the form is rendered on.\n *\n * The package ships no router and no i18n. `onSuccess` hands the signed-in\n * `BffUser` back to the app; all copy comes from `labels`.\n */\nimport { useCallback, useMemo, useState, type ReactElement } from 'react';\n\nimport { ActivityIndicator, Text, TextInput, TouchableOpacity, View } from 'react-native';\n\nimport { DEFAULT_PIN_LABELS, type PinFormLabels } from './labels';\nimport { AuthTestIds, withTestIdPrefix } from './testIds';\nimport { useAuthStyles } from './useAuthStyles';\nimport { usePinLogin, type UsePinLoginResult } from '../hooks/usePinLogin';\nimport { useAuthTheme } from '../theme/AuthThemeProvider';\n\nimport type { AuthTheme } from '../theme/AuthTheme';\nimport type { BffAuthClient, BffUser } from '@dloizides/auth-client';\n\nexport interface PinFormProps {\n /** The same-origin BFF client (build it with `createBffAuthClient`). */\n client: BffAuthClient;\n /**\n * External id of the event the PIN is scoped to. Supplied by the route/page\n * — the event context is never typed by the user.\n */\n eventExternalId: string;\n /** Explicit theme; overrides any `<AuthThemeProvider>`. Falls back to the default theme. */\n theme?: AuthTheme;\n /** Localised copy. Partial — unspecified keys fall back to English defaults. */\n labels?: Partial<PinFormLabels>;\n /** Called with the signed-in user after a successful PIN exchange. */\n onSuccess: (user: BffUser) => void;\n /** Prefix applied to every `testID` so multiple forms can share a screen. */\n testIdPrefix?: string;\n /**\n * When `true`, render WITHOUT the built-in `screen` + `card` chrome so the\n * form can be composed as a child of `<AuthScreen>`. Defaults to `false` —\n * standalone drop-in behaviour is byte-identical to before.\n */\n chromeless?: boolean;\n}\n\n/** Resolve the in-flight transport error onto a localised, non-leaking message. */\nfunction transportErrorFor(error: Error | null, labels: PinFormLabels): string | null {\n if (error === null) {\n return null;\n }\n // Never echo the raw error — show a generic message instead.\n return labels.invalidPin;\n}\n\n/** Drive the single submit step: validate the PIN is present, then call `submit`. */\nfunction useSubmitHandler(\n pin: UsePinLoginResult,\n labels: PinFormLabels,\n setLocalError: (value: string | null) => void,\n onSuccess: (user: BffUser) => void,\n): (value: string) => void {\n return useCallback(\n (value: string): void => {\n setLocalError(null);\n if (value.length === 0) {\n setLocalError(labels.missingPin);\n return;\n }\n pin\n .submit(value)\n .then((user) => {\n onSuccess(user);\n })\n .catch(() => undefined);\n },\n [pin, labels.missingPin, setLocalError, onSuccess],\n );\n}\n\n/** Themeable single-step event-PIN login form built on `usePinLogin`. */\nexport function PinForm({\n client,\n eventExternalId,\n theme: themeProp,\n labels: labelsProp,\n onSuccess,\n testIdPrefix,\n chromeless = false,\n}: Readonly<PinFormProps>): ReactElement {\n const theme = useAuthTheme(themeProp);\n const styles = useAuthStyles(theme);\n const labels = useMemo<PinFormLabels>(\n () => ({ ...DEFAULT_PIN_LABELS, ...labelsProp }),\n [labelsProp],\n );\n\n const pin = usePinLogin({ client, eventExternalId });\n // A local validation error (empty PIN) lives separately from the hook's\n // transport error so a client-side failure does not need a round-trip.\n const [localError, setLocalError] = useState<string | null>(null);\n const [pinValue, setPinValue] = useState('');\n\n const handleSubmit = useSubmitHandler(pin, labels, setLocalError, onSuccess);\n\n const errorText = localError ?? transportErrorFor(pin.error, labels);\n const buttonStyle = pin.isSubmitting\n ? [styles.primaryButton, styles.primaryButtonDisabled]\n : styles.primaryButton;\n\n const content = (\n <>\n <Text style={styles.title}>{labels.title}</Text>\n <Text style={styles.subtitle}>{labels.description}</Text>\n\n <View style={styles.fieldGroup}>\n <Text style={styles.label}>{labels.pinLabel}</Text>\n <TextInput\n accessibilityHint={labels.pinPlaceholder}\n accessibilityLabel={labels.pinLabel}\n autoCapitalize=\"none\"\n autoCorrect={false}\n editable={!pin.isSubmitting}\n keyboardType=\"number-pad\"\n placeholder={labels.pinPlaceholder}\n placeholderTextColor={theme.colors.textSecondary}\n secureTextEntry\n style={styles.input}\n testID={withTestIdPrefix(AuthTestIds.pinInput, testIdPrefix)}\n value={pinValue}\n onChangeText={setPinValue}\n />\n </View>\n\n {errorText !== null ? (\n <Text\n style={styles.errorText}\n testID={withTestIdPrefix(AuthTestIds.pinError, testIdPrefix)}\n >\n {errorText}\n </Text>\n ) : null}\n\n <TouchableOpacity\n accessibilityHint={labels.submit}\n accessibilityLabel={pin.isSubmitting ? labels.submitting : labels.submit}\n accessibilityRole=\"button\"\n disabled={pin.isSubmitting}\n style={buttonStyle}\n testID={withTestIdPrefix(AuthTestIds.pinSubmitButton, testIdPrefix)}\n onPress={(): void => handleSubmit(pinValue.trim())}\n >\n {pin.isSubmitting ? (\n <ActivityIndicator color={theme.colors.onPrimary} size=\"small\" />\n ) : (\n <Text style={styles.primaryButtonText}>{labels.submit}</Text>\n )}\n </TouchableOpacity>\n </>\n );\n\n const card = (\n <View\n style={chromeless ? undefined : styles.card}\n testID={withTestIdPrefix(AuthTestIds.pinForm, testIdPrefix)}\n >\n {content}\n </View>\n );\n\n return chromeless ? card : <View style={styles.screen}>{card}</View>;\n}\n","/**\n * A masked numeric PIN input for the device-PIN unlock + enrol surfaces.\n *\n * A single hidden secure `TextInput` captures the digits (numeric keyboard,\n * length-capped, digits-only); a row of dot cells visualises how many have been\n * entered. Tapping anywhere on the row focuses the field. Purely presentational\n * — all submit / error logic lives in the unlock / enrol hooks. Styled from the\n * `AuthTheme` token bag (no hardcoded brand colours).\n */\nimport { useMemo, useRef, type ReactElement } from 'react';\n\nimport {\n Pressable,\n StyleSheet,\n TextInput,\n View,\n type TextInput as RNTextInput,\n type ViewStyle,\n} from 'react-native';\n\nimport { withTestIdPrefix } from './testIds';\nimport { useAuthTheme } from '../theme/AuthThemeProvider';\n\nimport type { AuthTheme } from '../theme/AuthTheme';\n\nexport interface DevicePinInputProps {\n /** The current PIN value (digits only). */\n value: string;\n /** Number of dot cells to render — the enrolled / chosen PIN length. */\n length: number;\n /** Disable input while a request is in flight. */\n disabled: boolean;\n /** Base testID for the underlying field (a11y + E2E targeting). */\n testID: string;\n /** Optional prefix applied to the testID. */\n testIdPrefix?: string;\n /** Accessibility label for the field. */\n accessibilityLabel: string;\n /** Accessibility hint for the field. */\n accessibilityHint: string;\n /** Accessibility label for a filled dot. */\n filledHint: string;\n /** Accessibility label for an empty dot. */\n emptyHint: string;\n /** Explicit theme; overrides any `<AuthThemeProvider>`. */\n theme?: AuthTheme;\n /** Emit the next digits-only value (already length-capped). */\n onChange: (next: string) => void;\n}\n\nconst DOT_SIZE = 18;\nconst DOT_BORDER_WIDTH = 2;\nconst DOT_RADIUS = 9;\nconst ROW_GAP = 12;\nconst ROW_MIN_HEIGHT = 44;\nconst ROW_VERTICAL_MARGIN = 16;\nconst HIDDEN_SIZE = 1;\n\n/** Strip everything but digits and cap to `length`. */\nfunction sanitise(raw: string, length: number): string {\n return raw.replace(/\\D/g, '').slice(0, length);\n}\n\n/** Build the dot fill/border styles from the theme. */\nfunction useDotStyles(theme: AuthTheme): { filled: ViewStyle; empty: ViewStyle } {\n return useMemo(\n () => ({\n filled: { backgroundColor: theme.colors.primary, borderColor: theme.colors.primary },\n empty: { backgroundColor: theme.colors.background, borderColor: theme.colors.border },\n }),\n [theme],\n );\n}\n\n/** Themeable masked PIN pad — dots reflect entered digits; a hidden field captures them. */\nexport function DevicePinInput({\n value,\n length,\n disabled,\n testID,\n testIdPrefix,\n accessibilityLabel,\n accessibilityHint,\n filledHint,\n emptyHint,\n theme: themeProp,\n onChange,\n}: Readonly<DevicePinInputProps>): ReactElement {\n const theme = useAuthTheme(themeProp);\n const inputRef = useRef<RNTextInput | null>(null);\n const dotStyles = useDotStyles(theme);\n const cells = Array.from({ length }, (_unused, index) => index);\n const baseId = withTestIdPrefix(testID, testIdPrefix);\n\n return (\n <Pressable\n accessibilityHint={accessibilityHint}\n accessibilityLabel={accessibilityLabel}\n accessibilityRole=\"button\"\n disabled={disabled}\n style={styles.row}\n testID={`${baseId}-row`}\n onPress={(): void => inputRef.current?.focus()}\n >\n {cells.map((index) => {\n const filled = index < value.length;\n return (\n <View\n key={index}\n accessibilityLabel={filled ? filledHint : emptyHint}\n style={[styles.dot, filled ? dotStyles.filled : dotStyles.empty]}\n testID={`${baseId}-dot-${String(index)}`}\n />\n );\n })}\n <TextInput\n ref={inputRef}\n accessibilityHint={accessibilityHint}\n accessibilityLabel={accessibilityLabel}\n autoFocus\n caretHidden\n editable={!disabled}\n keyboardType=\"number-pad\"\n maxLength={length}\n secureTextEntry\n style={styles.hiddenInput}\n testID={baseId}\n value={value}\n onChangeText={(raw: string): void => onChange(sanitise(raw, length))}\n />\n </Pressable>\n );\n}\n\nconst styles = StyleSheet.create({\n dot: {\n borderRadius: DOT_RADIUS,\n borderWidth: DOT_BORDER_WIDTH,\n height: DOT_SIZE,\n width: DOT_SIZE,\n },\n hiddenInput: {\n height: HIDDEN_SIZE,\n opacity: 0,\n position: 'absolute',\n width: HIDDEN_SIZE,\n },\n row: {\n alignItems: 'center',\n flexDirection: 'row',\n gap: ROW_GAP,\n justifyContent: 'center',\n marginVertical: ROW_VERTICAL_MARGIN,\n minHeight: ROW_MIN_HEIGHT,\n },\n});\n","/**\n * Minimal label placeholder interpolation.\n *\n * The device-PIN / passkey label bags carry `{name}` and `{count}` placeholders\n * (e.g. `'Enter your {count}-digit PIN.'`). The package ships no i18n framework,\n * so this tiny helper substitutes named placeholders without pulling one in.\n * Unknown placeholders are left untouched; absent keys substitute nothing.\n */\n\n/** Replace every `{key}` in `template` with the matching value (String-coerced). */\nexport function interpolate(\n template: string,\n values: Readonly<Record<string, string | number>>,\n): string {\n return template.replace(/\\{(\\w+)\\}/g, (match, key: string) => {\n const value = values[key];\n return value === undefined ? match : String(value);\n });\n}\n","/**\n * Shared device-PIN constants for the unlock + enrol surfaces.\n *\n * The allowed PIN lengths (4 / 6 / 8) mirror the BFF's accepted `digits` values\n * (`POST /bff/pin/enroll`). Centralised here so neither the enrol form nor the\n * unlock screen carries magic numbers, and so the default length is defined once.\n */\n\n/** The PIN lengths the BFF accepts on enrol (`digits` ∈ {4, 6, 8}). */\nexport const DEVICE_PIN_ALLOWED_DIGITS: readonly number[] = [4, 6, 8];\n\n/** Default PIN length offered when the BFF reports no stored `pinDigits`. */\nexport const DEVICE_PIN_DEFAULT_DIGITS = 4;\n\n/** Guard: is `value` one of the BFF-accepted PIN lengths? */\nexport function isAllowedPinDigits(value: number): boolean {\n return DEVICE_PIN_ALLOWED_DIGITS.includes(value);\n}\n","/**\n * The PIN-length (4/6/8) picker row for `<DevicePinEnrollForm>`.\n *\n * Presentational: renders one pill per allowed length and reports the chosen\n * one. Styled from the `AuthTheme` token bag. Extracted from the enrol form to\n * keep that component focused.\n */\nimport { useMemo, type ReactElement } from 'react';\n\nimport {\n Pressable,\n StyleSheet,\n Text,\n View,\n type TextStyle,\n type ViewStyle,\n} from 'react-native';\n\nimport { interpolate } from './interpolate';\nimport { AuthTestIds, withTestIdPrefix } from './testIds';\nimport { DEVICE_PIN_ALLOWED_DIGITS } from '../devicePin/devicePinConstants';\nimport { useAuthTheme } from '../theme/AuthThemeProvider';\n\nimport type { AuthTheme } from '../theme/AuthTheme';\n\nexport interface DevicePinLengthPickerProps {\n /** The currently-selected PIN length. */\n selected: number;\n /** Disable while a request is in flight. */\n disabled: boolean;\n /** Accessibility hint template for a pill; `{count}` is substituted. */\n optionHint: string;\n /** Optional prefix applied to each pill's testID. */\n testIdPrefix?: string;\n /** Explicit theme; overrides any `<AuthThemeProvider>`. */\n theme?: AuthTheme;\n /** Report the newly-chosen length. */\n onSelect: (digits: number) => void;\n}\n\nconst PILL_VERTICAL_PADDING = 10;\nconst PILL_FONT_SIZE = 15;\n\n/** Build the theme-derived pill styles. */\nfunction usePickerStyles(theme: AuthTheme): {\n active: ViewStyle;\n text: TextStyle;\n textActive: TextStyle;\n pill: ViewStyle;\n} {\n return useMemo(\n () => ({\n pill: { borderColor: theme.colors.border },\n active: { backgroundColor: theme.colors.primary, borderColor: theme.colors.primary },\n text: { color: theme.colors.text },\n textActive: { color: theme.colors.onPrimary },\n }),\n [theme],\n );\n}\n\n/** Themeable 4/6/8 length chooser. */\nexport function DevicePinLengthPicker({\n selected,\n disabled,\n optionHint,\n testIdPrefix,\n theme: themeProp,\n onSelect,\n}: Readonly<DevicePinLengthPickerProps>): ReactElement {\n const theme = useAuthTheme(themeProp);\n const dynamic = usePickerStyles(theme);\n const baseId = withTestIdPrefix(AuthTestIds.devicePinEnrollLength, testIdPrefix);\n\n return (\n <View accessibilityRole=\"radiogroup\" role=\"radiogroup\" style={styles.row}>\n {DEVICE_PIN_ALLOWED_DIGITS.map((option) => {\n const active = option === selected;\n return (\n <Pressable\n key={option}\n // Explicit `aria-checked`: react-native-web 0.21.2 ignores\n // `accessibilityState` entirely, so without this the ONLY thing\n // distinguishing the chosen PIN length is the pill's fill colour —\n // WCAG 1.4.1 (colour alone). `accessibilityState` is kept for native.\n aria-checked={active}\n accessibilityHint={interpolate(optionHint, { count: option })}\n accessibilityLabel={String(option)}\n // `radio`, not `button`: these are a mutually-exclusive set, and\n // `aria-checked` is only meaningful on a checkable role.\n accessibilityRole=\"radio\"\n accessibilityState={{ selected: active }}\n disabled={disabled}\n style={[styles.pill, dynamic.pill, active ? dynamic.active : null]}\n testID={`${baseId}-${String(option)}`}\n onPress={(): void => onSelect(option)}\n >\n <Text style={[styles.text, dynamic.text, active ? dynamic.textActive : null]}>\n {String(option)}\n </Text>\n </Pressable>\n );\n })}\n </View>\n );\n}\n\nconst styles = StyleSheet.create({\n pill: {\n alignItems: 'center',\n borderRadius: 8,\n borderWidth: 1,\n flex: 1,\n paddingVertical: PILL_VERTICAL_PADDING,\n },\n row: {\n flexDirection: 'row',\n gap: 8,\n marginBottom: 8,\n },\n text: {\n fontSize: PILL_FONT_SIZE,\n fontWeight: '700',\n },\n});\n","/**\n * The localizable error states the device-PIN UNLOCK surface can show.\n *\n * Kept deliberately coarse so the UI never reveals whether a failed unlock was a\n * wrong PIN or an unknown / revoked device (both map to `Invalid`). `LockedOut`\n * and `RateLimited` carry no count — the human-readable \"try again later\" copy\n * is built from the `retryAfterSeconds` hint at the call site, not encoded here.\n */\nexport const enum DevicePinErrorKey {\n /** The PIN entered was too short for the enrolled length. */\n Incomplete = 'incomplete',\n /** Wrong PIN, or unknown / revoked device. Generic on purpose. */\n Invalid = 'invalid',\n /** Locked out after too many wrong attempts. */\n LockedOut = 'locked_out',\n /** Rate-limited by the BFF (too many requests). */\n RateLimited = 'rate_limited',\n /** Anything else (network / unexpected). */\n Generic = 'generic',\n}\n","/**\n * The react-query-FREE state machine behind {@link DevicePinUnlockScreen}.\n *\n * Lives on the login route group, which has NO QueryClient provider — so this\n * hook uses plain `useState` + `.then()/.catch()/.finally()` over the supplied\n * client's `unlockWithDevicePin`, never `useMutation`/`useQuery`. Pulling the\n * logic into a hook keeps the screen presentational and lets the submit / error\n * / lockout transitions be unit-tested without rendering.\n *\n * Submit flow:\n * - client-side preflight: a PIN shorter than the enrolled `digits` short-circuits\n * to {@link DevicePinErrorKey.Incomplete} with no network call;\n * - `success` → clear error, call `onSignedIn(user)`;\n * - `invalid` → {@link DevicePinErrorKey.Invalid} (generic — never reveal\n * wrong-pin vs unknown-device);\n * - `locked` → {@link DevicePinErrorKey.LockedOut} + the optional retry seconds;\n * - `rateLimited` → {@link DevicePinErrorKey.RateLimited} + the optional seconds;\n * - `error` / a thrown rejection → {@link DevicePinErrorKey.Generic}.\n */\nimport { useCallback, useState } from 'react';\n\nimport { DevicePinErrorKey } from './DevicePinErrorKey';\n\nimport type { DevicePinUnlockCapableClient } from './types';\n\n/** The signed-in user shape the success path hands back (claim bag). */\nexport type DevicePinUnlockedUser = { [claim: string]: unknown };\n\nexport interface UseDevicePinUnlockArgs {\n /** The client exposing `unlockWithDevicePin`. */\n client: DevicePinUnlockCapableClient;\n /** Enrolled PIN length (4/6/8) — a shorter entry is rejected before any call. */\n digits: number;\n /** Called with the fresh user after a successful unlock. */\n onSignedIn: (user: DevicePinUnlockedUser) => void;\n}\n\nexport interface UseDevicePinUnlockResult {\n /** The PIN currently entered. */\n pin: string;\n /** `true` while an unlock call is in flight. */\n submitting: boolean;\n /** The current error key, or `null` when there is none. */\n errorKey: DevicePinErrorKey | null;\n /** Seconds until retry, set with a `LockedOut`/`RateLimited` error; else `null`. */\n retryAfterSeconds: number | null;\n /** Replace the entered PIN. Clears a stale error. */\n setPin: (next: string) => void;\n /** Run the unlock attempt for the current PIN. */\n submit: () => void;\n}\n\nexport function useDevicePinUnlock({\n client,\n digits,\n onSignedIn,\n}: UseDevicePinUnlockArgs): UseDevicePinUnlockResult {\n const [pin, setPinState] = useState<string>('');\n const [submitting, setSubmitting] = useState<boolean>(false);\n const [errorKey, setErrorKey] = useState<DevicePinErrorKey | null>(null);\n const [retryAfterSeconds, setRetryAfterSeconds] = useState<number | null>(null);\n\n const setPin = useCallback((next: string): void => {\n setPinState(next);\n setErrorKey(null);\n setRetryAfterSeconds(null);\n }, []);\n\n const submit = useCallback((): void => {\n setErrorKey(null);\n setRetryAfterSeconds(null);\n if (pin.length < digits) {\n setErrorKey(DevicePinErrorKey.Incomplete);\n return;\n }\n setSubmitting(true);\n client\n .unlockWithDevicePin({ pin })\n .then((result) => {\n if (result.status === 'success') {\n onSignedIn(result.user);\n return;\n }\n if (result.status === 'invalid') {\n setErrorKey(DevicePinErrorKey.Invalid);\n return;\n }\n if (result.status === 'locked') {\n setRetryAfterSeconds(result.retryAfterSeconds);\n setErrorKey(DevicePinErrorKey.LockedOut);\n return;\n }\n if (result.status === 'rateLimited') {\n setRetryAfterSeconds(result.retryAfterSeconds);\n setErrorKey(DevicePinErrorKey.RateLimited);\n return;\n }\n setErrorKey(DevicePinErrorKey.Generic);\n })\n .catch(() => {\n setErrorKey(DevicePinErrorKey.Generic);\n })\n .finally(() => {\n setSubmitting(false);\n });\n }, [client, pin, digits, onSignedIn]);\n\n return { pin, submitting, errorKey, retryAfterSeconds, setPin, submit };\n}\n","/**\n * The device-PIN UNLOCK gate — shown on the login route for a returning,\n * logged-OUT user whose device is remembered (`hasPin && rememberedUsername`).\n *\n * Renders a masked PIN pad of the enrolled length; on submit it calls\n * `client.unlockWithDevicePin` (via {@link useDevicePinUnlock}) and, on success,\n * routes through the SAME `onSignedIn` path as the password tab. A\n * \"Sign in with password instead\" escape calls `onUsePassword` (the caller swaps\n * this screen out). All five result statuses are handled, including the lockout /\n * rate-limit retry countdown surfaced from `retryAfterSeconds`.\n *\n * react-query-FREE: all logic lives in `useDevicePinUnlock`, which uses plain\n * `useState` + `.then()` over the client — never `useMutation`. Presentational\n * only here. Distinct from the event-staff PIN (`PinForm`); this is `devicePin`.\n */\nimport { useMemo, type ReactElement } from 'react';\n\nimport { ActivityIndicator, Text, TouchableOpacity, View } from 'react-native';\n\nimport { DevicePinInput } from './DevicePinInput';\nimport { interpolate } from './interpolate';\nimport { DEFAULT_DEVICE_PIN_UNLOCK_LABELS, type DevicePinUnlockLabels } from './labels';\nimport { AuthTestIds, withTestIdPrefix } from './testIds';\nimport { useAuthStyles } from './useAuthStyles';\nimport { DevicePinErrorKey } from '../devicePin/DevicePinErrorKey';\nimport {\n useDevicePinUnlock,\n type DevicePinUnlockedUser,\n} from '../devicePin/useDevicePinUnlock';\nimport { useAuthTheme } from '../theme/AuthThemeProvider';\n\nimport type { DevicePinUnlockCapableClient } from '../devicePin/types';\nimport type { AuthTheme } from '../theme/AuthTheme';\n\nexport interface DevicePinUnlockScreenProps {\n /** The client exposing `unlockWithDevicePin`. */\n client: DevicePinUnlockCapableClient;\n /** Enrolled PIN length (4/6/8). */\n digits: number;\n /** Remembered username, shown in the greeting (may be empty). */\n rememberedUsername: string;\n /** Explicit theme; overrides any `<AuthThemeProvider>`. */\n theme?: AuthTheme;\n /** Localised copy. Partial — unspecified keys fall back to English defaults. */\n labels?: Partial<DevicePinUnlockLabels>;\n /** Prefix applied to every `testID`. */\n testIdPrefix?: string;\n /** Called with the fresh user after a successful unlock. */\n onSignedIn: (user: DevicePinUnlockedUser) => void;\n /** Escape hatch → render the normal password/OTP/event-PIN tabs. */\n onUsePassword: () => void;\n}\n\n/** Resolve the localized error copy for the current unlock error state. */\nfunction resolveErrorText(\n errorKey: DevicePinErrorKey | null,\n digits: number,\n retryAfter: number | null,\n labels: DevicePinUnlockLabels,\n): string | null {\n if (errorKey === null) {\n return null;\n }\n if (errorKey === DevicePinErrorKey.Incomplete) {\n return interpolate(labels.errorIncomplete, { count: digits });\n }\n if (errorKey === DevicePinErrorKey.Invalid) {\n return labels.errorInvalid;\n }\n if (errorKey === DevicePinErrorKey.LockedOut) {\n return retryAfter !== null\n ? interpolate(labels.errorLockedOutRetry, { count: retryAfter })\n : labels.errorLockedOut;\n }\n if (errorKey === DevicePinErrorKey.RateLimited) {\n return retryAfter !== null\n ? interpolate(labels.errorRateLimitedRetry, { count: retryAfter })\n : labels.errorRateLimited;\n }\n return labels.errorGeneric;\n}\n\n/** Themeable device-PIN unlock gate built on `useDevicePinUnlock`. */\nexport function DevicePinUnlockScreen({\n client,\n digits,\n rememberedUsername,\n theme: themeProp,\n labels: labelsProp,\n testIdPrefix,\n onSignedIn,\n onUsePassword,\n}: Readonly<DevicePinUnlockScreenProps>): ReactElement {\n const theme = useAuthTheme(themeProp);\n const styles = useAuthStyles(theme);\n const labels = useMemo<DevicePinUnlockLabels>(\n () => ({ ...DEFAULT_DEVICE_PIN_UNLOCK_LABELS, ...labelsProp }),\n [labelsProp],\n );\n\n const { pin, submitting, errorKey, retryAfterSeconds, setPin, submit } = useDevicePinUnlock({\n client,\n digits,\n onSignedIn,\n });\n\n const hasName = rememberedUsername !== '';\n const title = hasName ? interpolate(labels.title, { name: rememberedUsername }) : labels.titleNoName;\n const error = resolveErrorText(errorKey, digits, retryAfterSeconds, labels);\n const buttonStyle = submitting\n ? [styles.primaryButton, styles.primaryButtonDisabled]\n : styles.primaryButton;\n\n return (\n <View style={styles.screen}>\n <View\n style={styles.card}\n testID={withTestIdPrefix(AuthTestIds.devicePinUnlock, testIdPrefix)}\n >\n <Text style={styles.title}>{title}</Text>\n <Text style={styles.subtitle}>{interpolate(labels.description, { count: digits })}</Text>\n\n <DevicePinInput\n accessibilityHint={labels.pinPlaceholder}\n accessibilityLabel={labels.pinLabel}\n disabled={submitting}\n emptyHint={labels.digitEmptyHint}\n filledHint={labels.digitFilledHint}\n length={digits}\n testID={AuthTestIds.devicePinUnlockInput}\n testIdPrefix={testIdPrefix}\n theme={theme}\n value={pin}\n onChange={setPin}\n />\n\n {error !== null ? (\n <Text\n style={styles.errorText}\n testID={withTestIdPrefix(AuthTestIds.devicePinUnlockError, testIdPrefix)}\n >\n {error}\n </Text>\n ) : null}\n\n <TouchableOpacity\n accessibilityHint={labels.submit}\n accessibilityLabel={submitting ? labels.submitting : labels.submit}\n accessibilityRole=\"button\"\n disabled={submitting}\n style={buttonStyle}\n testID={withTestIdPrefix(AuthTestIds.devicePinUnlockSubmit, testIdPrefix)}\n onPress={submit}\n >\n {submitting ? (\n <ActivityIndicator color={theme.colors.onPrimary} size=\"small\" />\n ) : (\n <Text style={styles.primaryButtonText}>{labels.submit}</Text>\n )}\n </TouchableOpacity>\n\n <TouchableOpacity\n accessibilityHint={labels.usePasswordHint}\n accessibilityLabel={labels.usePasswordInstead}\n accessibilityRole=\"button\"\n disabled={submitting}\n style={styles.escapeLink}\n testID={withTestIdPrefix(AuthTestIds.devicePinUnlockUsePassword, testIdPrefix)}\n onPress={onUsePassword}\n >\n <Text style={styles.linkText}>{labels.usePasswordInstead}</Text>\n </TouchableOpacity>\n </View>\n </View>\n );\n}\n","/**\n * The localizable failure states the device-PIN ENROL form can show — shared by\n * the post-login offer and the settings toggle.\n */\nexport const enum DevicePinEnrollErrorKey {\n /** PIN length wrong or the confirmation didn't match (no network call). */\n Mismatch = 'mismatch',\n /** The current session is not authenticated (401). */\n Unauthorized = 'unauthorized',\n /** The session already has a PIN, or is otherwise forbidden (403). */\n Forbidden = 'forbidden',\n /** The PIN failed server-side validation (400). */\n InvalidPin = 'invalid_pin',\n /** Any other failure (grant / network / unexpected). */\n Failed = 'failed',\n}\n","/**\n * The react-query-FREE state machine behind {@link DevicePinEnrollForm}, shared\n * by the post-login offer and the settings toggle.\n *\n * Enrol requires an authenticated session (the session cookie travels on the\n * client's `enrollDevicePin` call) — but the post-login offer can render adjacent\n * to the login route group, so this stays react-query-free (`useState` +\n * `.then()/.catch()/.finally()`), never `useMutation`. Pulling the logic into a\n * hook lets the confirm / mismatch / status transitions be unit-tested without\n * rendering, and keeps the form component presentational.\n *\n * Submit flow (a single PIN entry confirmed against itself):\n * - preflight: PIN must be exactly `digits` long and equal its confirmation,\n * else {@link DevicePinEnrollErrorKey.Mismatch} (no network call);\n * - `success` → call `onEnrolled`;\n * - `unauthorized` / `forbidden` / `invalidPin` → the matching error key;\n * - `error` / a thrown rejection → {@link DevicePinEnrollErrorKey.Failed}.\n */\nimport { useCallback, useState } from 'react';\n\nimport { DevicePinEnrollErrorKey } from './DevicePinEnrollErrorKey';\n\nimport type { DevicePinEnrollCapableClient, DevicePinEnrollResult } from './types';\n\nexport interface UseDevicePinEnrollArgs {\n /** The client exposing `enrollDevicePin`. */\n client: DevicePinEnrollCapableClient;\n /** Chosen PIN length (4/6/8). */\n digits: number;\n /** Called after a successful enrol so the surface can dismiss / flip state. */\n onEnrolled: () => void;\n}\n\nexport interface UseDevicePinEnrollResult {\n pin: string;\n confirmPin: string;\n submitting: boolean;\n errorKey: DevicePinEnrollErrorKey | null;\n setPin: (next: string) => void;\n setConfirmPin: (next: string) => void;\n submit: () => void;\n}\n\n/** Map a non-success enrol result onto its localizable error key. */\nfunction errorKeyFor(result: DevicePinEnrollResult): DevicePinEnrollErrorKey {\n if (result.status === 'unauthorized') {\n return DevicePinEnrollErrorKey.Unauthorized;\n }\n if (result.status === 'forbidden') {\n return DevicePinEnrollErrorKey.Forbidden;\n }\n if (result.status === 'invalidPin') {\n return DevicePinEnrollErrorKey.InvalidPin;\n }\n return DevicePinEnrollErrorKey.Failed;\n}\n\nexport function useDevicePinEnroll({\n client,\n digits,\n onEnrolled,\n}: UseDevicePinEnrollArgs): UseDevicePinEnrollResult {\n const [pin, setPinState] = useState<string>('');\n const [confirmPin, setConfirmState] = useState<string>('');\n const [submitting, setSubmitting] = useState<boolean>(false);\n const [errorKey, setErrorKey] = useState<DevicePinEnrollErrorKey | null>(null);\n\n const setPin = useCallback((next: string): void => {\n setPinState(next);\n setErrorKey(null);\n }, []);\n\n const setConfirmPin = useCallback((next: string): void => {\n setConfirmState(next);\n setErrorKey(null);\n }, []);\n\n const submit = useCallback((): void => {\n setErrorKey(null);\n const wrongLength = pin.length !== digits;\n const mismatched = pin !== confirmPin;\n if (wrongLength || mismatched) {\n setErrorKey(DevicePinEnrollErrorKey.Mismatch);\n return;\n }\n setSubmitting(true);\n client\n .enrollDevicePin({ pin, digits })\n .then((result) => {\n if (result.status === 'success') {\n onEnrolled();\n return;\n }\n setErrorKey(errorKeyFor(result));\n })\n .catch(() => {\n setErrorKey(DevicePinEnrollErrorKey.Failed);\n })\n .finally(() => {\n setSubmitting(false);\n });\n }, [client, pin, confirmPin, digits, onEnrolled]);\n\n return { pin, confirmPin, submitting, errorKey, setPin, setConfirmPin, submit };\n}\n","/**\n * The shared device-PIN ENROL form — reused by the post-login offer\n * ({@link DevicePinOffer}) and the settings toggle ({@link DevicePinSettingsCard}).\n *\n * Lets the user pick a PIN length (4/6/8), enter + confirm a PIN, and submit via\n * `client.enrollDevicePin` (through {@link useDevicePinEnroll}). On success it\n * calls `onEnrolled`; `onCancel` dismisses without saving. Presentational only —\n * all submit / mismatch / status logic lives in the hook (react-query-free).\n * Styled from the `AuthTheme` token bag.\n */\nimport { useMemo, useState, type ReactElement } from 'react';\n\nimport { ActivityIndicator, Text, TouchableOpacity, View } from 'react-native';\n\nimport { DevicePinInput } from './DevicePinInput';\nimport { DevicePinLengthPicker } from './DevicePinLengthPicker';\nimport { interpolate } from './interpolate';\nimport { DEFAULT_DEVICE_PIN_ENROLL_LABELS, type DevicePinEnrollLabels } from './labels';\nimport { AuthTestIds, withTestIdPrefix } from './testIds';\nimport { useAuthStyles } from './useAuthStyles';\nimport { DevicePinEnrollErrorKey } from '../devicePin/DevicePinEnrollErrorKey';\nimport { DEVICE_PIN_DEFAULT_DIGITS } from '../devicePin/devicePinConstants';\nimport { useDevicePinEnroll } from '../devicePin/useDevicePinEnroll';\nimport { useAuthTheme } from '../theme/AuthThemeProvider';\n\nimport type { DevicePinEnrollCapableClient } from '../devicePin/types';\nimport type { AuthTheme } from '../theme/AuthTheme';\n\nexport interface DevicePinEnrollFormProps {\n /** The client exposing `enrollDevicePin`. */\n client: DevicePinEnrollCapableClient;\n /** Initial PIN length (defaults to {@link DEVICE_PIN_DEFAULT_DIGITS}). */\n initialDigits?: number;\n /** Explicit theme; overrides any `<AuthThemeProvider>`. */\n theme?: AuthTheme;\n /** Localised copy. Partial — unspecified keys fall back to English defaults. */\n labels?: Partial<DevicePinEnrollLabels>;\n /** Prefix applied to every `testID`. */\n testIdPrefix?: string;\n /** Called after a successful enrol. */\n onEnrolled: () => void;\n /** Called when the user cancels without saving. */\n onCancel: () => void;\n}\n\n/** Resolve the localized error copy for the current enrol error state. */\nfunction resolveErrorText(\n errorKey: DevicePinEnrollErrorKey | null,\n digits: number,\n labels: DevicePinEnrollLabels,\n): string | null {\n if (errorKey === null) {\n return null;\n }\n if (errorKey === DevicePinEnrollErrorKey.Mismatch) {\n return interpolate(labels.errorMismatch, { count: digits });\n }\n if (errorKey === DevicePinEnrollErrorKey.Unauthorized) {\n return labels.errorUnauthorized;\n }\n if (errorKey === DevicePinEnrollErrorKey.Forbidden) {\n return labels.errorForbidden;\n }\n if (errorKey === DevicePinEnrollErrorKey.InvalidPin) {\n return labels.errorInvalidPin;\n }\n return labels.errorFailed;\n}\n\n/** Themeable device-PIN enrol form built on `useDevicePinEnroll`. */\nexport function DevicePinEnrollForm({\n client,\n initialDigits = DEVICE_PIN_DEFAULT_DIGITS,\n theme: themeProp,\n labels: labelsProp,\n testIdPrefix,\n onEnrolled,\n onCancel,\n}: Readonly<DevicePinEnrollFormProps>): ReactElement {\n const theme = useAuthTheme(themeProp);\n const styles = useAuthStyles(theme);\n const labels = useMemo<DevicePinEnrollLabels>(\n () => ({ ...DEFAULT_DEVICE_PIN_ENROLL_LABELS, ...labelsProp }),\n [labelsProp],\n );\n\n const [digits, setDigits] = useState<number>(initialDigits);\n const { pin, confirmPin, submitting, errorKey, setPin, setConfirmPin, submit } =\n useDevicePinEnroll({ client, digits, onEnrolled });\n const error = resolveErrorText(errorKey, digits, labels);\n const buttonStyle = submitting\n ? [styles.primaryButton, styles.primaryButtonDisabled]\n : styles.primaryButton;\n\n return (\n <View\n style={styles.card}\n testID={withTestIdPrefix(AuthTestIds.devicePinEnrollForm, testIdPrefix)}\n >\n <Text style={styles.title}>{labels.formTitle}</Text>\n <Text style={styles.subtitle}>{interpolate(labels.formDescription, { count: digits })}</Text>\n\n <Text style={styles.label}>{labels.lengthLabel}</Text>\n <DevicePinLengthPicker\n disabled={submitting}\n optionHint={labels.lengthOptionHint}\n selected={digits}\n testIdPrefix={testIdPrefix}\n theme={theme}\n onSelect={(option): void => {\n setDigits(option);\n setPin('');\n setConfirmPin('');\n }}\n />\n\n <Text style={styles.label}>{labels.pinLabel}</Text>\n <DevicePinInput\n accessibilityHint={labels.pinPlaceholder}\n accessibilityLabel={labels.pinLabel}\n disabled={submitting}\n emptyHint={labels.pinPlaceholder}\n filledHint={labels.pinLabel}\n length={digits}\n testID={AuthTestIds.devicePinEnrollPin}\n testIdPrefix={testIdPrefix}\n theme={theme}\n value={pin}\n onChange={setPin}\n />\n\n <Text style={styles.label}>{labels.confirmLabel}</Text>\n <DevicePinInput\n accessibilityHint={labels.confirmPlaceholder}\n accessibilityLabel={labels.confirmLabel}\n disabled={submitting}\n emptyHint={labels.confirmPlaceholder}\n filledHint={labels.confirmLabel}\n length={digits}\n testID={AuthTestIds.devicePinEnrollConfirm}\n testIdPrefix={testIdPrefix}\n theme={theme}\n value={confirmPin}\n onChange={setConfirmPin}\n />\n\n {error !== null ? (\n <Text\n style={styles.errorText}\n testID={withTestIdPrefix(AuthTestIds.devicePinEnrollError, testIdPrefix)}\n >\n {error}\n </Text>\n ) : null}\n\n <TouchableOpacity\n accessibilityHint={labels.submit}\n accessibilityLabel={submitting ? labels.submitting : labels.submit}\n accessibilityRole=\"button\"\n disabled={submitting}\n style={buttonStyle}\n testID={withTestIdPrefix(AuthTestIds.devicePinEnrollSubmit, testIdPrefix)}\n onPress={submit}\n >\n {submitting ? (\n <ActivityIndicator color={theme.colors.onPrimary} size=\"small\" />\n ) : (\n <Text style={styles.primaryButtonText}>{labels.submit}</Text>\n )}\n </TouchableOpacity>\n\n <TouchableOpacity\n accessibilityHint={labels.cancelHint}\n accessibilityLabel={labels.cancel}\n accessibilityRole=\"button\"\n disabled={submitting}\n style={styles.escapeLink}\n testID={withTestIdPrefix(AuthTestIds.devicePinEnrollCancel, testIdPrefix)}\n onPress={onCancel}\n >\n <Text style={styles.linkText}>{labels.cancel}</Text>\n </TouchableOpacity>\n </View>\n );\n}\n","/**\n * The skippable post-login \"Set a PIN for faster sign-in?\" offer.\n *\n * Mount on the post-login landing for an authenticated user who does NOT already\n * have a device PIN. It is dismissible and non-blocking: an initial prompt with\n * \"Set up a PIN\" / \"Not now\"; tapping accept reveals the shared\n * {@link DevicePinEnrollForm}; on success or skip it calls `onDismiss` so the\n * host can hide it (and remember the dismissal). Self-contained, react-query-free.\n */\nimport { useMemo, useState, type ReactElement } from 'react';\n\nimport { Text, TouchableOpacity, View } from 'react-native';\n\nimport { DevicePinEnrollForm } from './DevicePinEnrollForm';\nimport {\n DEFAULT_DEVICE_PIN_ENROLL_LABELS,\n type DevicePinEnrollLabels,\n} from './labels';\nimport { AuthTestIds, withTestIdPrefix } from './testIds';\nimport { useAuthStyles } from './useAuthStyles';\nimport { useAuthTheme } from '../theme/AuthThemeProvider';\n\nimport type { DevicePinEnrollCapableClient } from '../devicePin/types';\nimport type { AuthTheme } from '../theme/AuthTheme';\n\nexport interface DevicePinOfferProps {\n /** The client exposing `enrollDevicePin`. */\n client: DevicePinEnrollCapableClient;\n /** Initial PIN length offered in the enrol form. */\n initialDigits?: number;\n /** Explicit theme; overrides any `<AuthThemeProvider>`. */\n theme?: AuthTheme;\n /** Localised copy. Partial — unspecified keys fall back to English defaults. */\n labels?: Partial<DevicePinEnrollLabels>;\n /** Prefix applied to every `testID`. */\n testIdPrefix?: string;\n /** Called when the offer is finished — accepted+enrolled, or skipped. */\n onDismiss: () => void;\n}\n\n/** Themeable, skippable post-login device-PIN setup offer. */\nexport function DevicePinOffer({\n client,\n initialDigits,\n theme: themeProp,\n labels: labelsProp,\n testIdPrefix,\n onDismiss,\n}: Readonly<DevicePinOfferProps>): ReactElement {\n const theme = useAuthTheme(themeProp);\n const styles = useAuthStyles(theme);\n const labels = useMemo<DevicePinEnrollLabels>(\n () => ({ ...DEFAULT_DEVICE_PIN_ENROLL_LABELS, ...labelsProp }),\n [labelsProp],\n );\n const [expanded, setExpanded] = useState<boolean>(false);\n const cardTestId = withTestIdPrefix(AuthTestIds.devicePinOffer, testIdPrefix);\n\n if (expanded) {\n return (\n <View style={styles.card} testID={cardTestId}>\n <DevicePinEnrollForm\n client={client}\n initialDigits={initialDigits}\n labels={labelsProp}\n testIdPrefix={testIdPrefix}\n theme={theme}\n onCancel={onDismiss}\n onEnrolled={onDismiss}\n />\n </View>\n );\n }\n\n return (\n <View style={styles.card} testID={cardTestId}>\n <Text style={styles.title}>{labels.offerTitle}</Text>\n <Text style={styles.subtitle}>{labels.offerDescription}</Text>\n\n <TouchableOpacity\n accessibilityHint={labels.offerAcceptHint}\n accessibilityLabel={labels.offerAccept}\n accessibilityRole=\"button\"\n style={styles.primaryButton}\n testID={withTestIdPrefix(AuthTestIds.devicePinOfferAccept, testIdPrefix)}\n onPress={(): void => setExpanded(true)}\n >\n <Text style={styles.primaryButtonText}>{labels.offerAccept}</Text>\n </TouchableOpacity>\n\n <TouchableOpacity\n accessibilityHint={labels.offerSkipHint}\n accessibilityLabel={labels.offerSkip}\n accessibilityRole=\"button\"\n style={styles.secondaryButton}\n testID={withTestIdPrefix(AuthTestIds.devicePinOfferSkip, testIdPrefix)}\n onPress={onDismiss}\n >\n <Text style={styles.secondaryButtonText}>{labels.offerSkip}</Text>\n </TouchableOpacity>\n </View>\n );\n}\n","/**\n * The react-query-FREE state machine behind the device-PIN settings card's\n * DISABLE action.\n *\n * Extracted from {@link DevicePinSettingsCard} so the disable transitions\n * (success flips `hasPin` off; a `false` result or a thrown rejection raises the\n * `failed` flag) can be unit-tested without rendering. Plain `useState` +\n * `.then()/.catch()/.finally()` over the client — never `useMutation`.\n *\n * Seeded with `initialHasPin` (from `GET /bff/config`); it tracks its own\n * enabled/disabled state thereafter. `markEnabled` is called by the host after a\n * successful enrol (the enrol form owns that call) to flip the card back on.\n */\nimport { useCallback, useState } from 'react';\n\nimport type { DevicePinDisableCapableClient } from './types';\n\nexport interface UseDevicePinDisableArgs {\n /** The client exposing `disableDevicePin`. */\n client: DevicePinDisableCapableClient;\n /** Whether this device already has an enrolled PIN (seeded from config). */\n initialHasPin: boolean;\n /** Called whenever the enabled state changes (enabled / disabled). */\n onChanged?: (hasPin: boolean) => void;\n}\n\nexport interface UseDevicePinDisableResult {\n /** `true` when the device currently has an enrolled PIN. */\n hasPin: boolean;\n /** `true` while a disable call is in flight. */\n disabling: boolean;\n /** `true` when the last disable attempt failed. */\n failed: boolean;\n /** Run the disable call for the current session. */\n disable: () => void;\n /** Flip the card to enabled (called by the host after a successful enrol). */\n markEnabled: () => void;\n}\n\nexport function useDevicePinDisable({\n client,\n initialHasPin,\n onChanged,\n}: UseDevicePinDisableArgs): UseDevicePinDisableResult {\n const [hasPin, setHasPin] = useState<boolean>(initialHasPin);\n const [disabling, setDisabling] = useState<boolean>(false);\n const [failed, setFailed] = useState<boolean>(false);\n\n const disable = useCallback((): void => {\n setFailed(false);\n setDisabling(true);\n client\n .disableDevicePin()\n .then((ok) => {\n if (ok) {\n setHasPin(false);\n onChanged?.(false);\n return;\n }\n setFailed(true);\n })\n .catch(() => {\n setFailed(true);\n })\n .finally(() => {\n setDisabling(false);\n });\n }, [client, onChanged]);\n\n const markEnabled = useCallback((): void => {\n setHasPin(true);\n onChanged?.(true);\n }, [onChanged]);\n\n return { hasPin, disabling, failed, disable, markEnabled };\n}\n","/**\n * The authenticated \"Quick PIN sign-in\" settings control.\n *\n * Mount on an authenticated settings/account surface. Seeded with `initialHasPin`\n * (from `GET /bff/config`); it tracks its own enabled/disabled state thereafter\n * and offers either:\n * - Enable → reveals the shared {@link DevicePinEnrollForm} → `client.enrollDevicePin`;\n * - Disable → `client.disableDevicePin` (revokes the offline token + clears the\n * device record server-side).\n *\n * `onChanged(hasPin)` fires whenever the enabled state flips, so the host can\n * persist / re-fetch. react-query-free: the disable logic lives in\n * {@link useDevicePinDisable}; the enrol logic in the shared form's hook.\n */\nimport { useMemo, useState, type ReactElement } from 'react';\n\nimport { ActivityIndicator, Text, TouchableOpacity, View } from 'react-native';\n\nimport { DevicePinEnrollForm } from './DevicePinEnrollForm';\nimport {\n DEFAULT_DEVICE_PIN_ENROLL_LABELS,\n DEFAULT_DEVICE_PIN_SETTINGS_LABELS,\n type DevicePinEnrollLabels,\n type DevicePinSettingsLabels,\n} from './labels';\nimport { AuthTestIds, withTestIdPrefix } from './testIds';\nimport { useAuthStyles } from './useAuthStyles';\nimport { useDevicePinDisable } from '../devicePin/useDevicePinDisable';\nimport { useAuthTheme } from '../theme/AuthThemeProvider';\n\nimport type {\n DevicePinDisableCapableClient,\n DevicePinEnrollCapableClient,\n} from '../devicePin/types';\nimport type { AuthTheme } from '../theme/AuthTheme';\n\nexport interface DevicePinSettingsCardProps {\n /** The client exposing both `enrollDevicePin` and `disableDevicePin`. */\n client: DevicePinEnrollCapableClient & DevicePinDisableCapableClient;\n /** Whether this device already has an enrolled PIN (seeded from config). */\n initialHasPin: boolean;\n /** Explicit theme; overrides any `<AuthThemeProvider>`. */\n theme?: AuthTheme;\n /** Settings-card copy. Partial — unspecified keys fall back to English. */\n labels?: Partial<DevicePinSettingsLabels>;\n /** Enrol-form copy passed through to the embedded form. */\n enrollLabels?: Partial<DevicePinEnrollLabels>;\n /** Prefix applied to every `testID`. */\n testIdPrefix?: string;\n /** Called whenever the enabled state flips (enabled / disabled). */\n onChanged?: (hasPin: boolean) => void;\n}\n\n/** Themeable authenticated device-PIN enable/disable card. */\nexport function DevicePinSettingsCard({\n client,\n initialHasPin,\n theme: themeProp,\n labels: labelsProp,\n enrollLabels,\n testIdPrefix,\n onChanged,\n}: Readonly<DevicePinSettingsCardProps>): ReactElement {\n const theme = useAuthTheme(themeProp);\n const styles = useAuthStyles(theme);\n const labels = useMemo<DevicePinSettingsLabels>(\n () => ({ ...DEFAULT_DEVICE_PIN_SETTINGS_LABELS, ...labelsProp }),\n [labelsProp],\n );\n const resolvedEnrollLabels = useMemo<DevicePinEnrollLabels>(\n () => ({ ...DEFAULT_DEVICE_PIN_ENROLL_LABELS, ...enrollLabels }),\n [enrollLabels],\n );\n\n const [enrolling, setEnrolling] = useState<boolean>(false);\n const { hasPin, disabling, failed, disable, markEnabled } = useDevicePinDisable({\n client,\n initialHasPin,\n onChanged,\n });\n\n const handleEnrolled = (): void => {\n setEnrolling(false);\n markEnabled();\n };\n\n const disableButtonStyle = disabling\n ? [styles.secondaryButton, styles.primaryButtonDisabled]\n : styles.secondaryButton;\n\n return (\n <View\n style={styles.card}\n testID={withTestIdPrefix(AuthTestIds.devicePinSettings, testIdPrefix)}\n >\n <Text style={styles.title}>{labels.title}</Text>\n <Text style={styles.subtitle}>{labels.description}</Text>\n <Text\n style={styles.statusText}\n testID={withTestIdPrefix(AuthTestIds.devicePinSettingsStatus, testIdPrefix)}\n >\n {hasPin ? labels.statusEnabled : labels.statusDisabled}\n </Text>\n\n {failed ? (\n <Text\n style={styles.errorText}\n testID={withTestIdPrefix(AuthTestIds.devicePinSettingsError, testIdPrefix)}\n >\n {labels.disableFailed}\n </Text>\n ) : null}\n\n {renderAction()}\n </View>\n );\n\n function renderAction(): ReactElement {\n if (enrolling) {\n return (\n <DevicePinEnrollForm\n client={client}\n labels={resolvedEnrollLabels}\n testIdPrefix={testIdPrefix}\n theme={theme}\n onCancel={(): void => setEnrolling(false)}\n onEnrolled={handleEnrolled}\n />\n );\n }\n if (hasPin) {\n return (\n <TouchableOpacity\n accessibilityHint={labels.disableHint}\n accessibilityLabel={disabling ? labels.disabling : labels.disable}\n accessibilityRole=\"button\"\n disabled={disabling}\n style={disableButtonStyle}\n testID={withTestIdPrefix(AuthTestIds.devicePinSettingsDisable, testIdPrefix)}\n onPress={disable}\n >\n {disabling ? (\n <ActivityIndicator color={theme.colors.primary} size=\"small\" />\n ) : (\n <Text style={styles.secondaryButtonText}>{labels.disable}</Text>\n )}\n </TouchableOpacity>\n );\n }\n return (\n <TouchableOpacity\n accessibilityHint={labels.enableHint}\n accessibilityLabel={labels.enable}\n accessibilityRole=\"button\"\n style={styles.primaryButton}\n testID={withTestIdPrefix(AuthTestIds.devicePinSettingsEnable, testIdPrefix)}\n onPress={(): void => setEnrolling(true)}\n >\n <Text style={styles.primaryButtonText}>{labels.enable}</Text>\n </TouchableOpacity>\n );\n }\n}\n","/**\n * Which WebAuthn ceremony {@link usePasskeyCeremony} drives.\n *\n * `Login` runs a usernameless/discoverable assertion\n * (`navigator.credentials.get`) from the login surface; `Register` runs an\n * attestation (`navigator.credentials.create`) from an authenticated settings\n * surface. The mode selects the `/bff/passkey/{login,register}/*` endpoint pair\n * and the matching redirect fallback.\n */\nexport const enum PasskeyCeremonyMode {\n /** Assertion ceremony — sign in with an existing passkey. */\n Login = 'login',\n /** Attestation ceremony — add a passkey to the signed-in account. */\n Register = 'register',\n}\n","/**\n * Capability-first access to the browser `Location`.\n *\n * WHY THIS EXISTS — `typeof window === 'undefined'` is NOT a native guard.\n * React Native's `setUpGlobals` does `global.window = global`, so on a real\n * device `window` EXISTS while `window.location` does NOT. Every `typeof window`\n * guard in the passkey helpers therefore fell straight through on native and\n * `window.location.search` / `window.location.pathname` threw a TypeError\n * DURING RENDER — `PasskeyLoginButton` calls `readPasskeyError()` and\n * `PasskeySettingsCard` calls `readPasskeyRegistered()` on every render — i.e.\n * a hard crash on any native screen that mounts them.\n *\n * On the web this is exactly equivalent to the old `typeof window` check (a\n * browser always has `window.location`), so web behaviour is unchanged.\n */\nexport function getBrowserLocation(): Location | null {\n if (typeof window === 'undefined') {\n return null;\n }\n // `Partial<Window>` is the honest type off-web: the DOM lib types `location` as\n // always-present, which is precisely the assumption that breaks on native.\n const browserLocation: Location | undefined = (window as Partial<Window>).location;\n if (browserLocation === undefined) {\n return null;\n }\n return browserLocation;\n}\n","/**\n * Navigation helpers for the passkey (WebAuthn) BFF endpoints.\n *\n * Unlike the device-PIN client (which is plain `fetch`), the passkey login and\n * registration ceremonies are NOT fetches — they are full-page BROWSER\n * NAVIGATIONS. The BFF (`Bff.AspNetCore` 1.3.x) drives the WebAuthn ceremony\n * through Keycloak's hosted pages, then redirects the browser back:\n * - login: `/bff/passkey/login?returnUrl=<rel>` → on success the browser\n * lands on `returnUrl` with the session cookie already set;\n * - registration: `/bff/passkey/register?returnUrl=<rel>` → Keycloak re-auths\n * the user (password) then runs the credential-creation ceremony, returning\n * the browser to `returnUrl?passkey=registered`;\n * - failure / cancel: the BFF redirects to `<login>?passkeyError=cancelled` or\n * `<login>?passkeyError=failed`.\n *\n * react-query-FREE by construction: there is NO fetch here at all — every\n * function is a pure `window.location` read or `window.location.assign`. The\n * login route group has no QueryClient provider, so the passkey login button\n * (which lives there) MUST avoid any react-query primitive; navigation satisfies\n * that trivially.\n *\n * All reads are SSR- AND NATIVE-safe: they resolve the browser `Location` through\n * {@link getBrowserLocation} (a capability probe — `typeof window` alone is not a\n * native guard, since React Native defines `global.window = global`) and return a\n * benign default rather than throwing when there is no `location`.\n */\nimport { getBrowserLocation } from './browserLocation';\n\n/** The recognised passkey error codes the BFF sends back via `?passkeyError=`. */\nexport type PasskeyErrorCode = 'cancelled' | 'failed';\n\nconst PASSKEY_LOGIN_ENDPOINT = '/bff/passkey/login';\nconst PASSKEY_REGISTER_ENDPOINT = '/bff/passkey/register';\nconst RETURN_URL_PARAM = 'returnUrl';\nconst PASSKEY_ERROR_PARAM = 'passkeyError';\nconst PASSKEY_PARAM = 'passkey';\nconst PASSKEY_REGISTERED_VALUE = 'registered';\nconst PASSKEY_ERROR_CANCELLED: PasskeyErrorCode = 'cancelled';\nconst PASSKEY_ERROR_FAILED: PasskeyErrorCode = 'failed';\n\n/** Build the `<endpoint>?returnUrl=<encoded>` URL the browser navigates to. */\nfunction buildNavigationUrl(endpoint: string, returnUrl: string): string {\n return `${endpoint}?${RETURN_URL_PARAM}=${encodeURIComponent(returnUrl)}`;\n}\n\n/** Read the current query string SSR-/native-safely, or `null` off-web. */\nfunction readSearchParams(): URLSearchParams | null {\n const browserLocation = getBrowserLocation();\n if (browserLocation === null) {\n return null;\n }\n return new URLSearchParams(browserLocation.search);\n}\n\n/**\n * Start the passkey LOGIN ceremony by navigating the browser to the BFF's\n * `/bff/passkey/login` endpoint. The BFF redirects through Keycloak's WebAuthn\n * ceremony and, on success, returns the browser to `returnUrl` with a session\n * cookie set. No-op off-web (no `window`). `returnUrl` should be a relative\n * app path (e.g. `'/'`).\n */\nexport function startPasskeyLogin(returnUrl: string): void {\n const browserLocation = getBrowserLocation();\n if (browserLocation === null) {\n return;\n }\n browserLocation.assign(buildNavigationUrl(PASSKEY_LOGIN_ENDPOINT, returnUrl));\n}\n\n/**\n * Start the passkey REGISTRATION ceremony by navigating the browser to the BFF's\n * `/bff/passkey/register` endpoint. Requires an authenticated session; Keycloak\n * re-authenticates the user (password) then runs the credential-creation\n * ceremony, returning the browser to `returnUrl?passkey=registered`. No-op\n * off-web. `returnUrl` should be a relative app path so the user lands back on\n * the same settings surface.\n */\nexport function startPasskeyRegistration(returnUrl: string): void {\n const browserLocation = getBrowserLocation();\n if (browserLocation === null) {\n return;\n }\n browserLocation.assign(buildNavigationUrl(PASSKEY_REGISTER_ENDPOINT, returnUrl));\n}\n\n/**\n * Read the `?passkeyError=` query param the BFF appends on a failed / cancelled\n * ceremony. Returns `'cancelled'` or `'failed'` for the two known values, or\n * `null` for an absent / unknown value. SSR-safe (returns `null` off-web).\n */\nexport function readPasskeyError(): PasskeyErrorCode | null {\n const params = readSearchParams();\n if (params === null) {\n return null;\n }\n const value = params.get(PASSKEY_ERROR_PARAM);\n if (value === PASSKEY_ERROR_CANCELLED) {\n return PASSKEY_ERROR_CANCELLED;\n }\n if (value === PASSKEY_ERROR_FAILED) {\n return PASSKEY_ERROR_FAILED;\n }\n return null;\n}\n\n/**\n * `true` when the browser has just returned from a successful passkey\n * registration, i.e. the `?passkey=registered` query param is present. SSR-safe\n * (returns `false` off-web).\n */\nexport function readPasskeyRegistered(): boolean {\n const params = readSearchParams();\n if (params === null) {\n return false;\n }\n return params.get(PASSKEY_PARAM) === PASSKEY_REGISTERED_VALUE;\n}\n","/**\n * The lifecycle state of an in-page passkey ceremony.\n *\n * `Idle` before the user acts; `Running` while options are fetched, the\n * authenticator prompts, and the assertion/attestation is verified; `Success`\n * once the BFF confirms (a login has a session cookie set, a registration has a\n * stored credential); `Error` on a genuine in-page failure (see\n * {@link PasskeyErrorCode}). A redirect fallback (RP not configured / unsupported\n * browser) navigates the page away, so the hook never lands in a terminal state\n * for that path.\n */\nexport const enum PasskeyCeremonyStatus {\n /** No ceremony has started. */\n Idle = 'idle',\n /** A ceremony is in flight (fetch → authenticator → verify). */\n Running = 'running',\n /** The ceremony completed and the BFF confirmed it. */\n Success = 'success',\n /** The ceremony failed in-page (cancelled or failed). */\n Error = 'error',\n}\n","/**\n * base64url <-> bytes conversion for the in-page WebAuthn ceremony.\n *\n * The BFF speaks Fido2NetLib's wire format, where every binary field\n * (`challenge`, `user.id`, credential ids, `attestationObject`,\n * `clientDataJSON`, `authenticatorData`, `signature`, `userHandle`) is a\n * **base64url** string. The browser WebAuthn API, by contrast, wants/returns\n * `ArrayBuffer`s. `usePasskeyCeremony` uses these two helpers to bridge the two:\n * decode options coming from the BFF into buffers before\n * `navigator.credentials.*`, and encode the resulting credential back into\n * base64url before posting it to the verify endpoint.\n *\n * base64url = standard base64 with `+`/`/` replaced by `-`/`_` and no `=`\n * padding. Both `atob`/`btoa` exist in every supported browser and in Node ≥ 18\n * (this package's engine floor), so no `Buffer` dependency is pulled in.\n */\n\n/**\n * Decode a base64url string to a `Uint8Array`. Tolerates missing padding.\n *\n * Backed by an explicit `ArrayBuffer` (not a `SharedArrayBuffer`) so the result\n * satisfies the DOM `BufferSource` the WebAuthn API expects for\n * `challenge` / credential ids under the TS 5.7+ typed-array generics.\n */\nexport function base64UrlToBytes(value: string): Uint8Array<ArrayBuffer> {\n const base64 = value.replace(/-/g, '+').replace(/_/g, '/');\n const padded = base64.padEnd(Math.ceil(base64.length / 4) * 4, '=');\n const binary = atob(padded);\n const bytes = new Uint8Array(new ArrayBuffer(binary.length));\n for (let i = 0; i < binary.length; i += 1) {\n bytes[i] = binary.charCodeAt(i);\n }\n return bytes;\n}\n\n/** Encode an `ArrayBuffer` / typed-array to an unpadded base64url string. */\nexport function bytesToBase64Url(buffer: ArrayBuffer | Uint8Array): string {\n const bytes = buffer instanceof Uint8Array ? buffer : new Uint8Array(buffer);\n let binary = '';\n for (let i = 0; i < bytes.length; i += 1) {\n binary += String.fromCharCode(bytes[i] as number);\n }\n // btoa only ever emits `=` as trailing padding, so a plain global strip is\n // equivalent to `/=+$/` without the super-linear-backtracking risk.\n return btoa(binary).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=/g, '');\n}\n","/**\n * Coercion between the BFF's Fido2NetLib JSON and the browser WebAuthn API.\n *\n * The passkey RP fetch endpoints (`/bff/passkey/*`) return a\n * `{ challengeId, options }` envelope where `options` is Fido2NetLib's\n * `CredentialCreateOptions` / `AssertionOptions` serialized verbatim — binary\n * fields as base64url strings, plus harmless extras (`status`, `errorMessage`)\n * the WebAuthn API ignores. `navigator.credentials.create/get` needs the binary\n * fields as `BufferSource`s, so {@link toCreationOptions} / {@link toRequestOptions}\n * decode `challenge`, `user.id` and the credential-descriptor ids in place.\n *\n * After the ceremony, {@link encodeAttestation} / {@link encodeAssertion} turn the\n * returned `PublicKeyCredential` back into the exact shape Fido2NetLib\n * deserializes (`AuthenticatorAttestationRawResponse` /\n * `AuthenticatorAssertionRawResponse`): `id`/`rawId`/`type` + a `response` object\n * whose binary members are base64url. These bodies are posted to the matching\n * verify endpoint.\n */\nimport { base64UrlToBytes, bytesToBase64Url } from './base64url';\n\n/** The `{ challengeId, options }` body returned by each options endpoint. */\nexport interface PasskeyOptionsEnvelope {\n challengeId: string;\n options: Record<string, unknown>;\n}\n\n/** A Fido2 credential descriptor as it arrives on the wire (id = base64url). */\ninterface RawCredentialDescriptor {\n type?: string;\n id: string;\n transports?: string[];\n}\n\nconst PUBLIC_KEY_TYPE = 'public-key';\n\n/** Map the wire allow/exclude list (base64url ids) to WebAuthn descriptors. */\nfunction toDescriptors(value: unknown): PublicKeyCredentialDescriptor[] | undefined {\n if (!Array.isArray(value)) {\n return undefined;\n }\n return value.map((entry): PublicKeyCredentialDescriptor => {\n const descriptor = entry as RawCredentialDescriptor;\n return {\n type: PUBLIC_KEY_TYPE,\n id: base64UrlToBytes(descriptor.id),\n transports: descriptor.transports as AuthenticatorTransport[] | undefined,\n };\n });\n}\n\n/** Decode registration options (`challenge`, `user.id`, `excludeCredentials`). */\nexport function toCreationOptions(\n options: Record<string, unknown>,\n): PublicKeyCredentialCreationOptions {\n const user = options.user as { id: string; name: string; displayName: string };\n return {\n ...(options as unknown as PublicKeyCredentialCreationOptions),\n challenge: base64UrlToBytes(options.challenge as string),\n user: { ...user, id: base64UrlToBytes(user.id) },\n excludeCredentials: toDescriptors(options.excludeCredentials),\n };\n}\n\n/** Decode assertion options (`challenge`, `allowCredentials`). */\nexport function toRequestOptions(\n options: Record<string, unknown>,\n): PublicKeyCredentialRequestOptions {\n return {\n ...(options as unknown as PublicKeyCredentialRequestOptions),\n challenge: base64UrlToBytes(options.challenge as string),\n allowCredentials: toDescriptors(options.allowCredentials),\n };\n}\n\n/** Read the optional `getTransports()` an attestation response may expose. */\nfunction readTransports(response: AuthenticatorAttestationResponse): string[] {\n return typeof response.getTransports === 'function' ? response.getTransports() : [];\n}\n\n/** Encode a registration credential to `AuthenticatorAttestationRawResponse` JSON. */\nexport function encodeAttestation(\n credential: PublicKeyCredential,\n): Record<string, unknown> {\n const response = credential.response as AuthenticatorAttestationResponse;\n return {\n id: credential.id,\n rawId: bytesToBase64Url(credential.rawId),\n type: credential.type,\n response: {\n attestationObject: bytesToBase64Url(response.attestationObject),\n clientDataJSON: bytesToBase64Url(response.clientDataJSON),\n transports: readTransports(response),\n },\n clientExtensionResults: credential.getClientExtensionResults(),\n };\n}\n\n/** Encode a login credential to `AuthenticatorAssertionRawResponse` JSON. */\nexport function encodeAssertion(\n credential: PublicKeyCredential,\n): Record<string, unknown> {\n const response = credential.response as AuthenticatorAssertionResponse;\n const userHandle =\n response.userHandle !== null ? bytesToBase64Url(response.userHandle) : null;\n return {\n id: credential.id,\n rawId: bytesToBase64Url(credential.rawId),\n type: credential.type,\n response: {\n authenticatorData: bytesToBase64Url(response.authenticatorData),\n clientDataJSON: bytesToBase64Url(response.clientDataJSON),\n signature: bytesToBase64Url(response.signature),\n userHandle,\n },\n clientExtensionResults: credential.getClientExtensionResults(),\n };\n}\n","/**\n * `usePasskeyCeremony` — the react-query-FREE, in-page WebAuthn ceremony hook.\n *\n * Replaces the full-page Keycloak redirect with a same-origin ceremony driven\n * entirely in the browser (Move 2b passkey rebuild):\n *\n * options fetch → `navigator.credentials.create/get` → verify fetch\n *\n * against the BFF's `/bff/passkey/{login,register}/{options,verify}` endpoints.\n * It lives on the login route group (no QueryClient provider), so — like the\n * device-PIN hooks — it uses plain `fetch` + `useState`, never react-query.\n *\n * INERT-BY-DEFAULT / never-regress contract: the in-page path activates ONLY\n * when the BFF's WebAuthn RP is configured. Until then the options endpoint\n * returns **501**, and the hook transparently falls back to the legacy redirect\n * ({@link startPasskeyLogin} / {@link startPasskeyRegistration}). The same\n * fallback covers a non-2xx options response and an unsupported browser (native,\n * or a browser without `PublicKeyCredential`). So with the flag off the observed\n * behaviour is byte-for-byte the old redirect; nothing ships until the owner\n * flips `Bff:Passkey`.\n *\n * Once the ceremony has actually started (the authenticator prompt is up), a\n * failure is surfaced in-page rather than redirected: a user cancel / timeout\n * (`NotAllowedError` / `AbortError`) → {@link PasskeyErrorCode} `'cancelled'`,\n * anything else → `'failed'`.\n */\nimport { useCallback, useMemo, useState } from 'react';\n\nimport { getBrowserLocation } from './browserLocation';\nimport { PasskeyCeremonyMode } from './PasskeyCeremonyMode';\nimport { PasskeyCeremonyStatus } from './PasskeyCeremonyStatus';\nimport {\n startPasskeyLogin,\n startPasskeyRegistration,\n type PasskeyErrorCode,\n} from './passkeyNavigation';\nimport {\n encodeAssertion,\n encodeAttestation,\n toCreationOptions,\n toRequestOptions,\n type PasskeyOptionsEnvelope,\n} from './webAuthnCoercion';\n\nimport type { BffUser } from '@dloizides/auth-client';\n\n/** Options for {@link usePasskeyCeremony}. */\nexport interface UsePasskeyCeremonyOptions {\n /** Which ceremony to run — login (assertion) or register (attestation). */\n mode: PasskeyCeremonyMode;\n /**\n * Relative app path used two ways: the redirect fallback returns here, and (for\n * login) a successful in-page ceremony navigates here unless `onSuccess` is set.\n */\n returnUrl: string;\n /**\n * Called on a successful in-page ceremony. For login it receives the signed-in\n * `BffUser`; for register it receives `undefined`. When omitted, a login\n * navigates to `returnUrl` and a register just resolves to `Success`.\n */\n onSuccess?: (user: BffUser | undefined) => void;\n}\n\n/** The state + controls {@link usePasskeyCeremony} returns. */\nexport interface UsePasskeyCeremonyResult {\n /** Current lifecycle state. */\n status: PasskeyCeremonyStatus;\n /** The in-page error code, or `null`. */\n error: PasskeyErrorCode | null;\n /** `true` when the browser can run the in-page ceremony (else it redirects). */\n isSupported: boolean;\n /** Start the ceremony (or redirect-fallback when the RP is off / unsupported). */\n start: () => void;\n /**\n * Hand off to the legacy Keycloak redirect explicitly. Wired to the \"try\n * another way\" affordance a surface shows after an in-page error — the escape\n * hatch for a credential enrolled only in Keycloak (invisible to the in-page\n * RP store), which the in-page ceremony cannot use.\n */\n fallbackToRedirect: () => void;\n /** Clear a terminal state so the affordance can be retried. */\n reset: () => void;\n}\n\nconst ERROR_CANCELLED: PasskeyErrorCode = 'cancelled';\nconst ERROR_FAILED: PasskeyErrorCode = 'failed';\nconst CANCEL_ERROR_NAMES = ['NotAllowedError', 'AbortError'];\n\nconst ENDPOINTS = {\n [PasskeyCeremonyMode.Login]: {\n options: '/bff/passkey/login/options',\n verify: '/bff/passkey/login/verify',\n },\n [PasskeyCeremonyMode.Register]: {\n options: '/bff/passkey/register/options',\n verify: '/bff/passkey/register/verify',\n },\n} as const;\n\n/** `true` when this runtime exposes the WebAuthn API needed for the in-page path. */\nfunction detectSupport(): boolean {\n return (\n typeof window !== 'undefined' &&\n typeof navigator !== 'undefined' &&\n typeof navigator.credentials !== 'undefined' &&\n typeof window.PublicKeyCredential !== 'undefined'\n );\n}\n\n/** POST a same-origin JSON body (cookies included), tolerating an empty body. */\nfunction postJson(url: string, body: unknown): Promise<Response> {\n return fetch(url, {\n method: 'POST',\n credentials: 'same-origin',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(body ?? {}),\n });\n}\n\n/** Run the browser ceremony for the decoded options; `null` if none returned. */\nasync function runCeremony(\n mode: PasskeyCeremonyMode,\n envelope: PasskeyOptionsEnvelope,\n): Promise<PublicKeyCredential | null> {\n const credential =\n mode === PasskeyCeremonyMode.Register\n ? await navigator.credentials.create({\n publicKey: toCreationOptions(envelope.options),\n })\n : await navigator.credentials.get({\n publicKey: toRequestOptions(envelope.options),\n });\n return credential as PublicKeyCredential | null;\n}\n\n/** Build the verify body for the ceremony's credential. */\nfunction buildVerifyBody(\n mode: PasskeyCeremonyMode,\n challengeId: string,\n credential: PublicKeyCredential,\n): Record<string, unknown> {\n return mode === PasskeyCeremonyMode.Register\n ? { challengeId, attestationResponse: encodeAttestation(credential) }\n : { challengeId, assertionResponse: encodeAssertion(credential) };\n}\n\n/** Fire the legacy redirect for the current mode (the never-regress fallback). */\nfunction redirectFallback(mode: PasskeyCeremonyMode, returnUrl: string): void {\n if (mode === PasskeyCeremonyMode.Register) {\n startPasskeyRegistration(returnUrl);\n return;\n }\n startPasskeyLogin(returnUrl);\n}\n\n/** Classify a thrown ceremony error into a user-facing code. */\nfunction classifyError(caught: unknown): PasskeyErrorCode {\n const name = caught instanceof Error ? caught.name : '';\n return CANCEL_ERROR_NAMES.includes(name) ? ERROR_CANCELLED : ERROR_FAILED;\n}\n\nexport function usePasskeyCeremony(\n optionsArg: UsePasskeyCeremonyOptions,\n): UsePasskeyCeremonyResult {\n const { mode, returnUrl, onSuccess } = optionsArg;\n const [status, setStatus] = useState<PasskeyCeremonyStatus>(PasskeyCeremonyStatus.Idle);\n const [error, setError] = useState<PasskeyErrorCode | null>(null);\n const isSupported = useMemo(detectSupport, []);\n\n const succeed = useCallback(\n (user: BffUser | undefined): void => {\n setStatus(PasskeyCeremonyStatus.Success);\n if (onSuccess !== undefined) {\n onSuccess(user);\n return;\n }\n const browserLocation = getBrowserLocation();\n if (mode === PasskeyCeremonyMode.Login && browserLocation !== null) {\n browserLocation.assign(returnUrl);\n }\n },\n [mode, onSuccess, returnUrl],\n );\n\n const start = useCallback((): void => {\n if (!isSupported) {\n redirectFallback(mode, returnUrl);\n return;\n }\n setStatus(PasskeyCeremonyStatus.Running);\n setError(null);\n\n void (async (): Promise<void> => {\n try {\n const optionsResponse = await postJson(ENDPOINTS[mode].options, {});\n // 501 (RP not configured) or any non-2xx → transparently use the old path.\n if (!optionsResponse.ok) {\n redirectFallback(mode, returnUrl);\n return;\n }\n const envelope = (await optionsResponse.json()) as PasskeyOptionsEnvelope;\n const credential = await runCeremony(mode, envelope);\n if (credential === null) {\n // No credential produced WITHOUT a throw. For LOGIN this is the\n // unambiguous \"this device has nothing to sign in-page with\" signal (a\n // real user cancel throws NotAllowedError, handled in catch) — hand off\n // to the Keycloak redirect so a user whose passkey is enrolled only in\n // KC can still sign in. REGISTER is always a fresh in-page enrolment, so\n // surface its failure in-page instead.\n if (mode === PasskeyCeremonyMode.Login) {\n redirectFallback(mode, returnUrl);\n return;\n }\n setStatus(PasskeyCeremonyStatus.Error);\n setError(ERROR_FAILED);\n return;\n }\n const verifyResponse = await postJson(\n ENDPOINTS[mode].verify,\n buildVerifyBody(mode, envelope.challengeId, credential),\n );\n if (!verifyResponse.ok) {\n setStatus(PasskeyCeremonyStatus.Error);\n setError(ERROR_FAILED);\n return;\n }\n // Login/verify returns 401 on a bad assertion (handled above) and\n // `{ user }` on success. Register/verify always returns 200 with a\n // generic `{ success }` boolean — a false there is still a failure.\n if (mode === PasskeyCeremonyMode.Register) {\n const { success } = (await verifyResponse.json()) as { success: boolean };\n if (!success) {\n setStatus(PasskeyCeremonyStatus.Error);\n setError(ERROR_FAILED);\n return;\n }\n succeed(undefined);\n return;\n }\n const { user } = (await verifyResponse.json()) as { user: BffUser };\n succeed(user);\n } catch (caught) {\n setStatus(PasskeyCeremonyStatus.Error);\n setError(classifyError(caught));\n }\n })();\n }, [isSupported, mode, returnUrl, succeed]);\n\n const fallbackToRedirect = useCallback((): void => {\n redirectFallback(mode, returnUrl);\n }, [mode, returnUrl]);\n\n const reset = useCallback((): void => {\n setStatus(PasskeyCeremonyStatus.Idle);\n setError(null);\n }, []);\n\n return useMemo(\n () => ({ status, error, isSupported, start, fallbackToRedirect, reset }),\n [status, error, isSupported, start, fallbackToRedirect, reset],\n );\n}\n","/**\n * The \"Sign in with a passkey\" button rendered on the unified login surface when\n * the BFF advertises the `passkey` method.\n *\n * The passkey login runs IN-PAGE via `usePasskeyCeremony`\n * (`navigator.credentials.get` against the same-origin `/bff/passkey/login/*`\n * fetch endpoints), landing the authenticated user on `returnUrl` (default `'/'`)\n * with a session cookie set. When the BFF's WebAuthn RP is not configured the\n * options endpoint returns 501 and the hook transparently falls back to the\n * legacy Keycloak redirect — so nothing regresses until the flag flips. A\n * cancelled / failed in-page ceremony surfaces as an inline error banner; a prior\n * redirect round-trip's `?passkeyError=…` is still honoured too.\n *\n * react-query-free: the hook uses plain `fetch` + `useState` (see\n * `usePasskeyCeremony`), so it is safe to mount inside the login route group\n * which has no QueryClient provider.\n */\nimport { useMemo, type ReactElement } from 'react';\n\nimport { Text, TouchableOpacity, View } from 'react-native';\n\nimport { DEFAULT_PASSKEY_LOGIN_LABELS, type PasskeyLoginLabels } from './labels';\nimport { AuthTestIds, withTestIdPrefix } from './testIds';\nimport { useAuthStyles } from './useAuthStyles';\nimport { PasskeyCeremonyMode } from '../passkey/PasskeyCeremonyMode';\nimport { readPasskeyError } from '../passkey/passkeyNavigation';\nimport { usePasskeyCeremony } from '../passkey/usePasskeyCeremony';\nimport { useAuthTheme } from '../theme/AuthThemeProvider';\n\nimport type { AuthTheme } from '../theme/AuthTheme';\n\nexport interface PasskeyLoginButtonProps {\n /** Relative app path the BFF returns to on success. Defaults to `'/'`. */\n returnUrl?: string;\n /** Explicit theme; overrides any `<AuthThemeProvider>`. */\n theme?: AuthTheme;\n /** Localised copy. Partial — unspecified keys fall back to English defaults. */\n labels?: Partial<PasskeyLoginLabels>;\n /** Prefix applied to every `testID`. */\n testIdPrefix?: string;\n}\n\n/** The app root — an authenticated user is routed onward to their dashboard. */\nconst DEFAULT_RETURN_URL = '/';\n\n/** Themeable passkey login CTA + error banner. */\nexport function PasskeyLoginButton({\n returnUrl = DEFAULT_RETURN_URL,\n theme: themeProp,\n labels: labelsProp,\n testIdPrefix,\n}: Readonly<PasskeyLoginButtonProps>): ReactElement {\n const theme = useAuthTheme(themeProp);\n const styles = useAuthStyles(theme);\n const labels = useMemo<PasskeyLoginLabels>(\n () => ({ ...DEFAULT_PASSKEY_LOGIN_LABELS, ...labelsProp }),\n [labelsProp],\n );\n const ceremony = usePasskeyCeremony({ mode: PasskeyCeremonyMode.Login, returnUrl });\n // The in-page ceremony error takes precedence; a `?passkeyError=…` left by a\n // prior redirect fallback is still surfaced on first mount.\n const error = ceremony.error ?? readPasskeyError();\n\n return (\n <View testID={withTestIdPrefix(AuthTestIds.passkeyLogin, testIdPrefix)}>\n {error !== null ? (\n <>\n <Text\n style={styles.errorText}\n testID={withTestIdPrefix(AuthTestIds.passkeyLoginError, testIdPrefix)}\n >\n {error === 'cancelled' ? labels.errorCancelled : labels.errorFailed}\n </Text>\n {/* Escape hatch to the Keycloak-hosted flow — rescues a credential\n enrolled only in KC, which the in-page ceremony cannot see. */}\n <TouchableOpacity\n accessibilityHint={labels.tryAnotherWay}\n accessibilityLabel={labels.tryAnotherWay}\n accessibilityRole=\"button\"\n testID={withTestIdPrefix(AuthTestIds.passkeyLoginFallback, testIdPrefix)}\n onPress={(): void => ceremony.fallbackToRedirect()}\n >\n <Text style={styles.linkText}>{labels.tryAnotherWay}</Text>\n </TouchableOpacity>\n </>\n ) : null}\n\n <TouchableOpacity\n accessibilityHint={labels.signInHint}\n accessibilityLabel={labels.signInButton}\n accessibilityRole=\"button\"\n style={styles.secondaryButton}\n testID={withTestIdPrefix(AuthTestIds.passkeyLoginButton, testIdPrefix)}\n onPress={(): void => ceremony.start()}\n >\n <Text style={styles.secondaryButtonText}>{labels.signInButton}</Text>\n </TouchableOpacity>\n </View>\n );\n}\n","/**\n * The authenticated \"Passkeys\" settings card.\n *\n * Mount on an authenticated settings / account surface (alongside the device-PIN\n * card). Adding a passkey runs IN-PAGE via `usePasskeyCeremony`\n * (`navigator.credentials.create` against the same-origin\n * `/bff/passkey/register/*` fetch endpoints, session-cookie authenticated); on\n * success we show an inline success line — no navigation. When the BFF's WebAuthn\n * RP is not configured the options endpoint returns 501 and the hook falls back\n * to the legacy Keycloak redirect, which returns here with `?passkey=registered`;\n * that param is still honoured on mount, so nothing regresses until the flag flips.\n *\n * react-query-free: the hook uses plain `fetch` + `useState` (see\n * `usePasskeyCeremony`). Mirrors `DevicePinSettingsCard`.\n */\nimport { useMemo, type ReactElement } from 'react';\n\nimport { Text, TouchableOpacity, View } from 'react-native';\n\nimport { DEFAULT_PASSKEY_SETTINGS_LABELS, type PasskeySettingsLabels } from './labels';\nimport { AuthTestIds, withTestIdPrefix } from './testIds';\nimport { useAuthStyles } from './useAuthStyles';\nimport { PasskeyCeremonyMode } from '../passkey/PasskeyCeremonyMode';\nimport { PasskeyCeremonyStatus } from '../passkey/PasskeyCeremonyStatus';\nimport { getBrowserLocation } from '../passkey/browserLocation';\nimport { readPasskeyRegistered } from '../passkey/passkeyNavigation';\nimport { usePasskeyCeremony } from '../passkey/usePasskeyCeremony';\nimport { useAuthTheme } from '../theme/AuthThemeProvider';\n\nimport type { AuthTheme } from '../theme/AuthTheme';\n\nexport interface PasskeySettingsCardProps {\n /**\n * Relative app path the BFF returns to after registration. Defaults to the\n * current `window.location.pathname` so the user lands back on this page.\n */\n returnUrl?: string;\n /** Explicit theme; overrides any `<AuthThemeProvider>`. */\n theme?: AuthTheme;\n /** Localised copy. Partial — unspecified keys fall back to English defaults. */\n labels?: Partial<PasskeySettingsLabels>;\n /** Prefix applied to every `testID`. */\n testIdPrefix?: string;\n}\n\n/** Fallback return path when there is no browser `location` to read the pathname from. */\nconst DEFAULT_RETURN_PATH = '/';\n\n/**\n * Read the current pathname SSR-/native-safely so registration returns to this page.\n *\n * Runs on EVERY render, so it must never throw: React Native defines\n * `global.window = global` but no `window.location`, which made the previous\n * `typeof window` guard fall through and crash the screen.\n */\nfunction readCurrentPath(): string {\n const browserLocation = getBrowserLocation();\n if (browserLocation === null) {\n return DEFAULT_RETURN_PATH;\n }\n return browserLocation.pathname;\n}\n\n/** Themeable authenticated passkey add card. */\nexport function PasskeySettingsCard({\n returnUrl,\n theme: themeProp,\n labels: labelsProp,\n testIdPrefix,\n}: Readonly<PasskeySettingsCardProps>): ReactElement {\n const theme = useAuthTheme(themeProp);\n const styles = useAuthStyles(theme);\n const labels = useMemo<PasskeySettingsLabels>(\n () => ({ ...DEFAULT_PASSKEY_SETTINGS_LABELS, ...labelsProp }),\n [labelsProp],\n );\n const target = returnUrl ?? readCurrentPath();\n const ceremony = usePasskeyCeremony({\n mode: PasskeyCeremonyMode.Register,\n returnUrl: target,\n });\n // Success comes either from the in-page ceremony completing, or from a prior\n // redirect fallback returning here with `?passkey=registered`.\n const justRegistered =\n ceremony.status === PasskeyCeremonyStatus.Success || readPasskeyRegistered();\n\n return (\n <View\n style={styles.card}\n testID={withTestIdPrefix(AuthTestIds.passkeySettings, testIdPrefix)}\n >\n <Text style={styles.title}>{labels.title}</Text>\n <Text style={styles.subtitle}>{labels.description}</Text>\n <Text style={styles.helperText}>{labels.reauthHint}</Text>\n\n {justRegistered ? (\n <Text\n style={styles.successText}\n testID={withTestIdPrefix(AuthTestIds.passkeySettingsSuccess, testIdPrefix)}\n >\n {labels.registeredSuccess}\n </Text>\n ) : null}\n\n <TouchableOpacity\n accessibilityHint={labels.addHint}\n accessibilityLabel={labels.addButton}\n accessibilityRole=\"button\"\n style={styles.primaryButton}\n testID={withTestIdPrefix(AuthTestIds.passkeySettingsAdd, testIdPrefix)}\n onPress={(): void => ceremony.start()}\n >\n <Text style={styles.primaryButtonText}>{labels.addButton}</Text>\n </TouchableOpacity>\n </View>\n );\n}\n","/**\n * Device-local cache of the user's preferred login method (unified-login D5).\n *\n * The preference is owned server-side (TenantService UserPreference), but the\n * LOGIN screen needs it BEFORE the user is authenticated — when no server call\n * is possible. So we cache it in `localStorage`, seeded after every successful\n * login (see {@link syncPreferredMethodFromServer}). A user who sets \"passkey\"\n * on device A will, after their first login on device B, see device B's login\n * screen prefer passkey too — cross-device sync with one-login lag.\n *\n * SSR-safe: every function no-ops / returns `null` when `localStorage` is\n * unavailable (server render, native, privacy modes that throw on access).\n */\n\n/** The `localStorage` key the preferred method is cached under. */\nconst CACHE_KEY = 'dloizides.auth.preferredLoginMethod';\n\n/** Resolve `localStorage` SSR-safely; `null` when unavailable. */\nfunction safeStorage(): Storage | null {\n try {\n if (typeof localStorage === 'undefined') {\n return null;\n }\n return localStorage;\n } catch {\n // Accessing localStorage can throw (e.g. sandboxed iframes, privacy modes).\n return null;\n }\n}\n\n/**\n * Read the cached preferred login method, or `null` when none is cached / the\n * store is unavailable. Cheap + synchronous so the login screen can call it on\n * render.\n */\nexport function readCachedPreferredMethod(): string | null {\n const store = safeStorage();\n if (store === null) {\n return null;\n }\n try {\n const value = store.getItem(CACHE_KEY);\n return value === null || value === '' ? null : value;\n } catch {\n return null;\n }\n}\n\n/**\n * Write (or, with `null`, clear) the cached preferred login method. No-op when\n * the store is unavailable. Never throws.\n */\nexport function cachePreferredMethod(method: string | null): void {\n const store = safeStorage();\n if (store === null) {\n return;\n }\n try {\n if (method === null || method === '') {\n store.removeItem(CACHE_KEY);\n return;\n }\n store.setItem(CACHE_KEY, method);\n } catch {\n // Quota / privacy-mode write failures are non-fatal — the hint is optional.\n }\n}\n\n/** Clear the cached preferred login method (e.g. on logout). Never throws. */\nexport function clearCachedPreferredMethod(): void {\n cachePreferredMethod(null);\n}\n","/**\n * Headless logic for the preferred-login-method settings control\n * (unified-login D5). react-query-FREE: plain `useState`/`useEffect`/\n * `useCallback` + the discriminated `PreferredMethodClient`. Mirrors the\n * device-PIN hooks so the settings card stays a thin renderer.\n *\n * On mount it loads the server-stored preference. `select` writes optimistically\n * (the radio flips immediately), persists via the client, mirrors the value into\n * the device-local cache on success, and reverts on failure.\n */\nimport { useCallback, useEffect, useState } from 'react';\n\nimport { cachePreferredMethod } from './preferredMethodCache';\n\nimport type { PreferredMethodClient } from './preferencesClient';\n\nexport interface UsePreferredMethodSettingArgs {\n /** The client exposing `getPreferredLoginMethod` + `setPreferredLoginMethod`. */\n client: PreferredMethodClient;\n /** Called whenever a save succeeds (the new value, `null` = no preference). */\n onChanged?: (method: string | null) => void;\n}\n\nexport interface UsePreferredMethodSettingResult {\n /** `true` until the initial server load resolves. */\n loading: boolean;\n /** `true` while a selection is being persisted. */\n saving: boolean;\n /** `true` when the last save failed (cleared on the next `select`). */\n failed: boolean;\n /** The currently-selected method, or `null` for \"no preference\". */\n selected: string | null;\n /** Optimistically select a method (`null` clears the preference) and persist it. */\n select: (method: string | null) => void;\n}\n\nexport function usePreferredMethodSetting({\n client,\n onChanged,\n}: UsePreferredMethodSettingArgs): UsePreferredMethodSettingResult {\n const [loading, setLoading] = useState<boolean>(true);\n const [saving, setSaving] = useState<boolean>(false);\n const [failed, setFailed] = useState<boolean>(false);\n const [selected, setSelected] = useState<string | null>(null);\n\n useEffect(() => {\n let active = true;\n client\n .getPreferredLoginMethod()\n .then((method) => {\n if (active) {\n setSelected(method);\n }\n })\n .catch(() => {\n // Leave the default (null) — the load is best-effort.\n })\n .finally(() => {\n if (active) {\n setLoading(false);\n }\n });\n return (): void => {\n active = false;\n };\n }, [client]);\n\n const select = useCallback(\n (method: string | null): void => {\n const previous = selected;\n if (method === previous) {\n return;\n }\n setFailed(false);\n setSaving(true);\n setSelected(method);\n client\n .setPreferredLoginMethod(method)\n .then((ok) => {\n if (ok) {\n cachePreferredMethod(method);\n onChanged?.(method);\n return;\n }\n setSelected(previous);\n setFailed(true);\n })\n .catch(() => {\n setSelected(previous);\n setFailed(true);\n })\n .finally(() => {\n setSaving(false);\n });\n },\n [client, selected, onChanged],\n );\n\n return { loading, saving, failed, selected, select };\n}\n","/**\n * The authenticated \"Preferred sign-in method\" settings card (unified-login D5).\n *\n * Mount on an authenticated settings/account surface alongside the device-PIN\n * and passkey cards. It lets the user pick which of their enabled login methods\n * they want emphasised on the login screen — stored SERVER-SIDE so the choice\n * follows them across devices. The login screen reads the device-local mirror\n * of this value (see `readCachedPreferredMethod` / `<PreferredMethodHint>`).\n *\n * `availableMethods` should be the BFF's advertised methods (from\n * `GET /bff/config` → `useBffLoginConfig().methods`) so the card only offers\n * methods this product actually supports. A \"No preference\" option always\n * appears. react-query-free: the persistence lives in `usePreferredMethodSetting`.\n */\nimport { useMemo, type ReactElement } from 'react';\n\nimport { ActivityIndicator, Text, TouchableOpacity, View } from 'react-native';\n\nimport {\n DEFAULT_PREFERRED_METHOD_SETTINGS_LABELS,\n type PreferredMethodSettingsLabels,\n} from './labels';\nimport { AuthTestIds, withTestIdPrefix } from './testIds';\nimport { useAuthStyles } from './useAuthStyles';\nimport { usePreferredMethodSetting } from '../preferences/usePreferredMethodSetting';\nimport { useAuthTheme } from '../theme/AuthThemeProvider';\n\nimport type { PreferredMethodClient } from '../preferences/preferencesClient';\nimport type { AuthTheme } from '../theme/AuthTheme';\n\n/** The sentinel option value representing \"no preference\". */\nconst NO_PREFERENCE = '__none__';\n\nexport interface PreferredMethodSettingsCardProps {\n /** The client exposing `getPreferredLoginMethod` + `setPreferredLoginMethod`. */\n client: PreferredMethodClient;\n /**\n * The login methods this BFF advertises (lowercase, e.g.\n * `['password', 'pin', 'passkey']`). Only these are offered, plus the\n * always-present \"No preference\" option.\n */\n availableMethods: readonly string[];\n /** Explicit theme; overrides any `<AuthThemeProvider>`. */\n theme?: AuthTheme;\n /** Localised copy. Partial — unspecified keys fall back to English defaults. */\n labels?: Partial<PreferredMethodSettingsLabels>;\n /** Prefix applied to every `testID`. */\n testIdPrefix?: string;\n /** Called whenever a save succeeds (`null` = no preference). */\n onChanged?: (method: string | null) => void;\n}\n\n/** Map a known lowercase method id to its localised display name; raw id otherwise. */\nfunction methodDisplayName(method: string, labels: PreferredMethodSettingsLabels): string {\n if (method === 'password') {\n return labels.methodPassword;\n }\n if (method === 'pin') {\n return labels.methodPin;\n }\n if (method === 'passkey') {\n return labels.methodPasskey;\n }\n return method;\n}\n\n/** Themeable authenticated preferred-method picker. */\nexport function PreferredMethodSettingsCard({\n client,\n availableMethods,\n theme: themeProp,\n labels: labelsProp,\n testIdPrefix,\n onChanged,\n}: Readonly<PreferredMethodSettingsCardProps>): ReactElement {\n const theme = useAuthTheme(themeProp);\n const styles = useAuthStyles(theme);\n const labels = useMemo<PreferredMethodSettingsLabels>(\n () => ({ ...DEFAULT_PREFERRED_METHOD_SETTINGS_LABELS, ...labelsProp }),\n [labelsProp],\n );\n\n const { loading, saving, failed, selected, select } = usePreferredMethodSetting({\n client,\n onChanged,\n });\n\n // The \"No preference\" option (sentinel) plus one row per advertised method.\n const options = useMemo<ReadonlyArray<{ value: string | null; key: string; label: string }>>(\n () => [\n { value: null, key: NO_PREFERENCE, label: labels.noPreference },\n ...availableMethods.map((method) => ({\n value: method,\n key: method,\n label: methodDisplayName(method, labels),\n })),\n ],\n [availableMethods, labels],\n );\n\n return (\n <View\n style={styles.card}\n testID={withTestIdPrefix(AuthTestIds.preferredMethodSettings, testIdPrefix)}\n >\n <Text style={styles.title}>{labels.title}</Text>\n <Text style={styles.subtitle}>{labels.description}</Text>\n\n {loading ? (\n <ActivityIndicator color={theme.colors.primary} size=\"small\" />\n ) : (\n options.map((option) => {\n const isSelected = option.value === selected;\n const optionTestId = `${withTestIdPrefix(\n AuthTestIds.preferredMethodSettingsOption,\n testIdPrefix,\n )}-${option.key}`;\n return (\n <TouchableOpacity\n key={option.key}\n // Explicit `aria-checked`: react-native-web 0.21.2 ignores\n // `accessibilityState`, so a screen reader on the web build could\n // not tell which preferred method was chosen — the distinction was\n // carried by button styling alone. Kept alongside for native.\n aria-checked={isSelected}\n accessibilityHint={labels.description}\n accessibilityLabel={option.label}\n accessibilityRole=\"radio\"\n accessibilityState={{ selected: isSelected }}\n disabled={saving}\n style={isSelected ? styles.secondaryButton : styles.escapeLink}\n testID={optionTestId}\n onPress={(): void => select(option.value)}\n >\n <Text style={isSelected ? styles.secondaryButtonText : styles.linkText}>\n {isSelected ? `✓ ${option.label}` : option.label}\n </Text>\n </TouchableOpacity>\n );\n })\n )}\n\n {saving ? <Text style={styles.helperText}>{labels.saving}</Text> : null}\n\n {failed ? (\n <Text\n style={styles.errorText}\n testID={withTestIdPrefix(AuthTestIds.preferredMethodSettingsError, testIdPrefix)}\n >\n {labels.saveFailed}\n </Text>\n ) : null}\n </View>\n );\n}\n","/**\n * The localizable failure states the authenticated \"Change password\" form can\n * show. Client-side validation states never hit the network; the rest map from\n * the BFF's `POST /bff/account/change-password` response.\n */\nexport const enum ChangePasswordErrorKey {\n /** New password is empty / fails the shared password policy (no network call). */\n WeakNewPassword = 'weak_new_password',\n /** New password and its confirmation do not match (no network call). */\n Mismatch = 'mismatch',\n /** Current password field was left blank (no network call). */\n CurrentRequired = 'current_required',\n /** BFF 400 — the current password is wrong, or the new one was rejected server-side. */\n InvalidCurrent = 'invalid_current',\n /** BFF 401 — the session is not (or no longer) authenticated. */\n Unauthorized = 'unauthorized',\n /** Any other failure (network / unexpected). */\n Failed = 'failed',\n}\n","/**\n * The react-query-FREE state machine behind the authenticated \"Change password\"\n * form. Owns the three field values, runs client-side validation, submits to the\n * BFF via a {@link ChangePasswordCapableClient}, and exposes a discriminated\n * error key so the form shows the precise cause — all without rendering, so the\n * logic is unit-tested directly (plain `useState` + `.then()/.catch()/.finally()`,\n * never `useMutation`; mirrors `useDevicePinDisable`).\n *\n * Client-side gates (no network round-trip): current password non-empty, new ===\n * confirm, and the new password satisfies the shared {@link isPasswordValid}\n * policy (mirrors the backend). Only after those pass does it call the BFF.\n */\nimport { useCallback, useState } from 'react';\n\nimport { ChangePasswordErrorKey } from './ChangePasswordErrorKey';\nimport type { ChangePasswordCapableClient } from './changePasswordClient';\nimport { isPasswordValid } from './passwordPolicy';\n\nexport interface UseChangePasswordArgs {\n /** The client exposing `changePassword`. */\n client: ChangePasswordCapableClient;\n /** Called once after a successful change (the form has been cleared by then). */\n onChanged?: () => void;\n}\n\nexport interface UseChangePasswordResult {\n currentPassword: string;\n newPassword: string;\n confirmPassword: string;\n setCurrentPassword: (value: string) => void;\n setNewPassword: (value: string) => void;\n setConfirmPassword: (value: string) => void;\n /** `true` while a BFF submit is in flight. */\n submitting: boolean;\n /** `true` after a successful change (until `reset` / a field edit). */\n succeeded: boolean;\n /** The current failure cause, or `null` when there is none. */\n errorKey: ChangePasswordErrorKey | null;\n /** Validate then submit. A validation failure sets `errorKey` and skips the network call. */\n submit: () => void;\n /** Clear every field + status back to a blank form. */\n reset: () => void;\n}\n\n/** Map a resolved {@link ChangePasswordResult} status to its form error key. */\nfunction errorKeyForStatus(status: 'invalidCurrent' | 'unauthorized' | 'error'): ChangePasswordErrorKey {\n if (status === 'invalidCurrent') {\n return ChangePasswordErrorKey.InvalidCurrent;\n }\n if (status === 'unauthorized') {\n return ChangePasswordErrorKey.Unauthorized;\n }\n return ChangePasswordErrorKey.Failed;\n}\n\nexport function useChangePassword({\n client,\n onChanged,\n}: UseChangePasswordArgs): UseChangePasswordResult {\n const [currentPassword, setCurrentValue] = useState<string>('');\n const [newPassword, setNewValue] = useState<string>('');\n const [confirmPassword, setConfirmValue] = useState<string>('');\n const [submitting, setSubmitting] = useState<boolean>(false);\n const [succeeded, setSucceeded] = useState<boolean>(false);\n const [errorKey, setErrorKey] = useState<ChangePasswordErrorKey | null>(null);\n\n // Editing any field clears a stale error / success banner.\n const clearStatus = useCallback((): void => {\n setErrorKey(null);\n setSucceeded(false);\n }, []);\n\n const setCurrentPassword = useCallback((value: string): void => {\n setCurrentValue(value);\n clearStatus();\n }, [clearStatus]);\n const setNewPassword = useCallback((value: string): void => {\n setNewValue(value);\n clearStatus();\n }, [clearStatus]);\n const setConfirmPassword = useCallback((value: string): void => {\n setConfirmValue(value);\n clearStatus();\n }, [clearStatus]);\n\n const reset = useCallback((): void => {\n setCurrentValue('');\n setNewValue('');\n setConfirmValue('');\n setSubmitting(false);\n setSucceeded(false);\n setErrorKey(null);\n }, []);\n\n const submit = useCallback((): void => {\n if (currentPassword === '') {\n setErrorKey(ChangePasswordErrorKey.CurrentRequired);\n return;\n }\n if (newPassword !== confirmPassword) {\n setErrorKey(ChangePasswordErrorKey.Mismatch);\n return;\n }\n if (!isPasswordValid(newPassword)) {\n setErrorKey(ChangePasswordErrorKey.WeakNewPassword);\n return;\n }\n\n setErrorKey(null);\n setSucceeded(false);\n setSubmitting(true);\n client\n .changePassword({ currentPassword, newPassword })\n .then((result) => {\n if (result.status === 'success') {\n setCurrentValue('');\n setNewValue('');\n setConfirmValue('');\n setSucceeded(true);\n onChanged?.();\n return;\n }\n setErrorKey(errorKeyForStatus(result.status));\n })\n .catch(() => {\n setErrorKey(ChangePasswordErrorKey.Failed);\n })\n .finally(() => {\n setSubmitting(false);\n });\n }, [client, currentPassword, newPassword, confirmPassword, onChanged]);\n\n return {\n currentPassword,\n newPassword,\n confirmPassword,\n setCurrentPassword,\n setNewPassword,\n setConfirmPassword,\n submitting,\n succeeded,\n errorKey,\n submit,\n reset,\n };\n}\n","/**\n * ChangePasswordCard — an authenticated, in-app \"Change password\" form.\n *\n * The signed-in user types their OWN current + new password in their OWN app;\n * that is a legitimate first-class feature (no Keycloak-console detour). The card\n * is purely presentational: all state, validation and submission live in\n * {@link useChangePassword}, which posts to `POST /bff/account/change-password`\n * through a {@link ChangePasswordCapableClient}. This package never stores, logs\n * or inspects the password values — it forwards them to the app's own BFF over\n * the session cookie and reads back only a status.\n *\n * Theme-driven and react-query-free, mirroring `DevicePinSettingsCard` /\n * `ResetPasswordForm`.\n */\nimport { useMemo, type ReactElement } from 'react';\n\nimport { ActivityIndicator, Text, TextInput, TouchableOpacity, View } from 'react-native';\n\nimport { DEFAULT_ACCOUNT_SETTINGS_LABELS, type AccountSettingsLabels } from './labels';\nimport { AuthTestIds, withTestIdPrefix } from './testIds';\nimport { useAuthStyles } from './useAuthStyles';\nimport { ChangePasswordErrorKey } from '../password/ChangePasswordErrorKey';\nimport type { ChangePasswordCapableClient } from '../password/changePasswordClient';\nimport { useChangePassword } from '../password/useChangePassword';\nimport { useAuthTheme } from '../theme/AuthThemeProvider';\n\nimport type { AuthTheme } from '../theme/AuthTheme';\n\nexport interface ChangePasswordCardProps {\n /** The client exposing `changePassword` (see `createBffChangePasswordClient`). */\n client: ChangePasswordCapableClient;\n /** Explicit theme; overrides any `<AuthThemeProvider>`. */\n theme?: AuthTheme;\n /** Localised copy. Partial — unspecified keys fall back to English defaults. */\n labels?: Partial<AccountSettingsLabels>;\n /** Prefix applied to every `testID`. */\n testIdPrefix?: string;\n /** Called once after a successful password change. */\n onChanged?: () => void;\n}\n\n/** Resolve the localized message for the current error key (`null` → no banner). */\nfunction errorMessage(errorKey: ChangePasswordErrorKey | null, labels: AccountSettingsLabels): string | null {\n switch (errorKey) {\n case ChangePasswordErrorKey.WeakNewPassword:\n return labels.errorWeakNewPassword;\n case ChangePasswordErrorKey.Mismatch:\n return labels.errorMismatch;\n case ChangePasswordErrorKey.CurrentRequired:\n return labels.errorCurrentRequired;\n case ChangePasswordErrorKey.InvalidCurrent:\n return labels.errorInvalidCurrent;\n case ChangePasswordErrorKey.Unauthorized:\n return labels.errorUnauthorized;\n case ChangePasswordErrorKey.Failed:\n return labels.errorFailed;\n default:\n return null;\n }\n}\n\n/** Themeable authenticated change-password form. */\nexport function ChangePasswordCard({\n client,\n theme: themeProp,\n labels: labelsProp,\n testIdPrefix,\n onChanged,\n}: Readonly<ChangePasswordCardProps>): ReactElement {\n const theme = useAuthTheme(themeProp);\n const styles = useAuthStyles(theme);\n const labels = useMemo<AccountSettingsLabels>(\n () => ({ ...DEFAULT_ACCOUNT_SETTINGS_LABELS, ...labelsProp }),\n [labelsProp],\n );\n const form = useChangePassword({ client, onChanged });\n const message = errorMessage(form.errorKey, labels);\n\n return (\n <View\n style={styles.card}\n testID={withTestIdPrefix(AuthTestIds.accountSettingsChangePassword, testIdPrefix)}\n >\n <Text style={styles.title}>{labels.changePasswordTitle}</Text>\n <Text style={styles.subtitle}>{labels.changePasswordDescription}</Text>\n\n <View style={styles.fieldGroup}>\n <Text style={styles.label}>{labels.currentPasswordLabel}</Text>\n <TextInput\n accessibilityLabel={labels.currentPasswordLabel}\n autoComplete=\"current-password\"\n placeholder={labels.currentPasswordPlaceholder}\n placeholderTextColor={theme.colors.textSecondary}\n secureTextEntry\n style={styles.input}\n testID={withTestIdPrefix(AuthTestIds.changePasswordCurrentInput, testIdPrefix)}\n value={form.currentPassword}\n onChangeText={form.setCurrentPassword}\n />\n </View>\n\n <View style={styles.fieldGroup}>\n <Text style={styles.label}>{labels.newPasswordLabel}</Text>\n <TextInput\n accessibilityLabel={labels.newPasswordLabel}\n autoComplete=\"new-password\"\n placeholder={labels.newPasswordPlaceholder}\n placeholderTextColor={theme.colors.textSecondary}\n secureTextEntry\n style={styles.input}\n testID={withTestIdPrefix(AuthTestIds.changePasswordNewInput, testIdPrefix)}\n value={form.newPassword}\n onChangeText={form.setNewPassword}\n />\n </View>\n\n <View style={styles.fieldGroup}>\n <Text style={styles.label}>{labels.confirmPasswordLabel}</Text>\n <TextInput\n accessibilityLabel={labels.confirmPasswordLabel}\n autoComplete=\"new-password\"\n placeholder={labels.confirmPasswordPlaceholder}\n placeholderTextColor={theme.colors.textSecondary}\n secureTextEntry\n style={styles.input}\n testID={withTestIdPrefix(AuthTestIds.changePasswordConfirmInput, testIdPrefix)}\n value={form.confirmPassword}\n onChangeText={form.setConfirmPassword}\n />\n </View>\n\n {message !== null ? (\n <Text\n style={styles.errorText}\n testID={withTestIdPrefix(AuthTestIds.changePasswordError, testIdPrefix)}\n >\n {message}\n </Text>\n ) : null}\n\n {form.succeeded ? (\n <Text\n style={styles.successText}\n testID={withTestIdPrefix(AuthTestIds.changePasswordSuccess, testIdPrefix)}\n >\n {labels.success}\n </Text>\n ) : null}\n\n <TouchableOpacity\n accessibilityHint={labels.submitHint}\n accessibilityLabel={form.submitting ? labels.submitting : labels.submit}\n accessibilityRole=\"button\"\n disabled={form.submitting}\n style={form.submitting ? [styles.primaryButton, styles.primaryButtonDisabled] : styles.primaryButton}\n testID={withTestIdPrefix(AuthTestIds.changePasswordSubmit, testIdPrefix)}\n onPress={form.submit}\n >\n {form.submitting ? (\n <ActivityIndicator color={theme.colors.onPrimary} size=\"small\" />\n ) : (\n <Text style={styles.primaryButtonText}>{labels.submit}</Text>\n )}\n </TouchableOpacity>\n </View>\n );\n}\n","/**\n * AccountSettingsScreen — the shared, composable authenticated account surface\n * every dloizides portal can mount to give a signed-in user one place to manage\n * their account. Self-contained and theme-driven: it stacks a set of independent,\n * individually-themed cards, each rendered only when its config is supplied.\n *\n * - **Change password** (always) — the in-app `<ChangePasswordCard>` form\n * (`POST /bff/account/change-password`). No password value is handled by this\n * package beyond forwarding it to the app's own BFF.\n * - **Device PIN** (optional) — the existing `<DevicePinSettingsCard>`, so every\n * portal gets quick-PIN enable/disable for free.\n * - **Passkeys** (optional) — the existing `<PasskeySettingsCard>`.\n * - **Preferred sign-in method** (optional) — the existing\n * `<PreferredMethodSettingsCard>`.\n *\n * Purely presentational assembly: each card owns its own behaviour + hooks (all\n * react-query-free). The screen only threads the shared `theme` / `testIdPrefix`\n * down and lays the cards out in a scrollable, centered column.\n */\nimport { useMemo, type ReactElement } from 'react';\n\nimport { ScrollView, StyleSheet, Text, View } from 'react-native';\n\nimport { ChangePasswordCard } from './ChangePasswordCard';\nimport { DevicePinSettingsCard } from './DevicePinSettingsCard';\nimport { DEFAULT_ACCOUNT_SETTINGS_LABELS, type AccountSettingsLabels } from './labels';\nimport type {\n DevicePinEnrollLabels,\n DevicePinSettingsLabels,\n PasskeySettingsLabels,\n PreferredMethodSettingsLabels,\n} from './labels';\nimport { PasskeySettingsCard } from './PasskeySettingsCard';\nimport { PreferredMethodSettingsCard } from './PreferredMethodSettingsCard';\nimport { AuthTestIds, withTestIdPrefix } from './testIds';\nimport { useAuthStyles } from './useAuthStyles';\nimport type { ChangePasswordCapableClient } from '../password/changePasswordClient';\nimport type { PreferredMethodClient } from '../preferences/preferencesClient';\nimport { useAuthTheme } from '../theme/AuthThemeProvider';\n\nimport type {\n DevicePinDisableCapableClient,\n DevicePinEnrollCapableClient,\n} from '../devicePin/types';\nimport type { AuthTheme } from '../theme/AuthTheme';\n\n/** Device-PIN section config — mirrors `DevicePinSettingsCard` (theme/testIdPrefix threaded by the screen). */\nexport interface AccountSettingsDevicePinConfig {\n client: DevicePinEnrollCapableClient & DevicePinDisableCapableClient;\n initialHasPin: boolean;\n labels?: Partial<DevicePinSettingsLabels>;\n enrollLabels?: Partial<DevicePinEnrollLabels>;\n onChanged?: (hasPin: boolean) => void;\n}\n\n/** Passkeys section config — mirrors `PasskeySettingsCard`. */\nexport interface AccountSettingsPasskeysConfig {\n returnUrl?: string;\n labels?: Partial<PasskeySettingsLabels>;\n}\n\n/** Preferred-method section config — mirrors `PreferredMethodSettingsCard`. */\nexport interface AccountSettingsPreferredMethodConfig {\n client: PreferredMethodClient;\n availableMethods: readonly string[];\n labels?: Partial<PreferredMethodSettingsLabels>;\n onChanged?: (method: string | null) => void;\n}\n\n/** Change-password section config. */\nexport interface AccountSettingsChangePasswordConfig {\n client: ChangePasswordCapableClient;\n onChanged?: () => void;\n}\n\nexport interface AccountSettingsScreenProps {\n /** Change-password form config (always rendered). */\n changePassword: AccountSettingsChangePasswordConfig;\n /** Device-PIN card config. Omit to hide the section. */\n devicePin?: AccountSettingsDevicePinConfig;\n /** Passkeys card config. Omit to hide the section. */\n passkeys?: AccountSettingsPasskeysConfig;\n /** Preferred-method card config. Omit to hide the section. */\n preferredMethod?: AccountSettingsPreferredMethodConfig;\n /** Explicit theme; overrides any `<AuthThemeProvider>`. Threaded to every card. */\n theme?: AuthTheme;\n /** Screen + change-password copy (partial; unspecified keys fall back to English). */\n labels?: Partial<AccountSettingsLabels>;\n /** Prefix applied to every `testID`, on the screen and every card. */\n testIdPrefix?: string;\n}\n\nconst GAP = 16;\n\nconst layout = StyleSheet.create({\n content: {\n width: '100%',\n alignItems: 'center',\n rowGap: GAP,\n },\n});\n\n/** The shared authenticated account-management surface. */\nexport function AccountSettingsScreen({\n changePassword,\n devicePin,\n passkeys,\n preferredMethod,\n theme: themeProp,\n labels: labelsProp,\n testIdPrefix,\n}: Readonly<AccountSettingsScreenProps>): ReactElement {\n const theme = useAuthTheme(themeProp);\n const styles = useAuthStyles(theme);\n const labels = useMemo<AccountSettingsLabels>(\n () => ({ ...DEFAULT_ACCOUNT_SETTINGS_LABELS, ...labelsProp }),\n [labelsProp],\n );\n\n return (\n <ScrollView\n contentContainerStyle={styles.screen}\n testID={withTestIdPrefix(AuthTestIds.accountSettings, testIdPrefix)}\n >\n <View style={layout.content}>\n <Text style={styles.title}>{labels.heading}</Text>\n\n <ChangePasswordCard\n client={changePassword.client}\n labels={labelsProp}\n testIdPrefix={testIdPrefix}\n theme={theme}\n onChanged={changePassword.onChanged}\n />\n\n {devicePin !== undefined ? (\n <DevicePinSettingsCard\n client={devicePin.client}\n enrollLabels={devicePin.enrollLabels}\n initialHasPin={devicePin.initialHasPin}\n labels={devicePin.labels}\n testIdPrefix={testIdPrefix}\n theme={theme}\n onChanged={devicePin.onChanged}\n />\n ) : null}\n\n {passkeys !== undefined ? (\n <PasskeySettingsCard\n labels={passkeys.labels}\n returnUrl={passkeys.returnUrl}\n testIdPrefix={testIdPrefix}\n theme={theme}\n />\n ) : null}\n\n {preferredMethod !== undefined ? (\n <PreferredMethodSettingsCard\n availableMethods={preferredMethod.availableMethods}\n client={preferredMethod.client}\n labels={preferredMethod.labels}\n testIdPrefix={testIdPrefix}\n theme={theme}\n onChanged={preferredMethod.onChanged}\n />\n ) : null}\n </View>\n </ScrollView>\n );\n}\n","/**\n * The login-screen \"you usually sign in with…\" hint (unified-login D5).\n *\n * Mount at the top of the login surface. Given the device-local cached\n * preferred method (`readCachedPreferredMethod()`), it renders a single\n * reassurance line naming that method. Renders NOTHING for an unknown / absent\n * method so the login screen stays clean for first-time visitors.\n *\n * No network, no state — pure presentation driven by the cached value the host\n * passes in. (The cache is seeded post-login by `syncPreferredMethodFromServer`.)\n */\nimport { useMemo, type ReactElement } from 'react';\n\nimport { Text, View } from 'react-native';\n\nimport {\n DEFAULT_PREFERRED_METHOD_HINT_LABELS,\n type PreferredMethodHintLabels,\n} from './labels';\nimport { AuthTestIds, withTestIdPrefix } from './testIds';\nimport { useAuthStyles } from './useAuthStyles';\nimport { useAuthTheme } from '../theme/AuthThemeProvider';\n\nimport type { AuthTheme } from '../theme/AuthTheme';\n\nexport interface PreferredMethodHintProps {\n /**\n * The cached preferred method (`'password'` | `'pin'` | `'passkey'`), or\n * `null`. Typically `readCachedPreferredMethod()`. An unknown / `null` value\n * renders nothing.\n */\n method: string | null;\n /** Explicit theme; overrides any `<AuthThemeProvider>`. */\n theme?: AuthTheme;\n /** Localised copy. Partial — unspecified keys fall back to English defaults. */\n labels?: Partial<PreferredMethodHintLabels>;\n /** Prefix applied to the `testID`. */\n testIdPrefix?: string;\n}\n\n/** Pick the full hint sentence for a known method, else `null`. */\nfunction hintFor(method: string | null, labels: PreferredMethodHintLabels): string | null {\n if (method === 'password') {\n return labels.password;\n }\n if (method === 'pin') {\n return labels.pin;\n }\n if (method === 'passkey') {\n return labels.passkey;\n }\n return null;\n}\n\n/** Themeable login-screen preferred-method hint. Renders `null` when there is nothing to say. */\nexport function PreferredMethodHint({\n method,\n theme: themeProp,\n labels: labelsProp,\n testIdPrefix,\n}: Readonly<PreferredMethodHintProps>): ReactElement | null {\n const theme = useAuthTheme(themeProp);\n const styles = useAuthStyles(theme);\n const labels = useMemo<PreferredMethodHintLabels>(\n () => ({ ...DEFAULT_PREFERRED_METHOD_HINT_LABELS, ...labelsProp }),\n [labelsProp],\n );\n\n const text = hintFor(method, labels);\n if (text === null) {\n return null;\n }\n\n return (\n <View testID={withTestIdPrefix(AuthTestIds.preferredMethodHint, testIdPrefix)}>\n <Text style={styles.helperText}>{text}</Text>\n </View>\n );\n}\n","/**\n * `<DemoCredentialsBody>` — the credential rows plus the optional fill button.\n *\n * Extracted from `<DemoCredentialsHint>` so the two variants (`Panel`,\n * `Disclosure`) share ONE rendering of the credentials themselves and differ\n * only in the chrome wrapped around them. Without this split the disclosure\n * variant would have grown a second copy of the rows, and the next change to a\n * `testID` or an accessibility hint would have had to be made twice — with\n * nothing failing if it was only made once.\n *\n * Not exported from the package: it is an implementation detail of the hint.\n */\nimport { type ReactElement } from 'react';\n\nimport { Text, TouchableOpacity, View } from 'react-native';\n\nimport { AuthTestIds, withTestIdPrefix } from './testIds';\n\nimport type { DemoCredentialsHintLabels } from './labels';\nimport type { DemoCredentialsStyles } from './useDemoCredentialsStyles';\nimport type { AuthStyles } from './useAuthStyles';\nimport type { DemoCredentials } from '../demo/types';\n\n/** Props for {@link DemoCredentialsBody}. */\nexport interface DemoCredentialsBodyProps {\n /** The already-resolved (trimmed, validated) demo pair. */\n credentials: DemoCredentials;\n /** Resolved copy — fully populated by the caller, never partial. */\n labels: DemoCredentialsHintLabels;\n /** The demo panel's styles, built from the resolved theme. */\n styles: DemoCredentialsStyles;\n /** Shared auth styles, for the secondary-button treatment. */\n authStyles: AuthStyles;\n /** `testID` prefix, applied to every element. */\n testIdPrefix?: string;\n /**\n * A per-account heading (e.g. \"Master\"). Rendered ONLY when it is a non-empty\n * string — the single-account case passes nothing, so the rows are byte-for-byte\n * what they were before multi-account existed. Multiple accounts each pass their\n * own label so a visitor can tell them apart.\n */\n accountLabel?: string;\n /**\n * A per-account index suffixed onto every `testID` (e.g. `-username-0`) so N\n * accounts each get unique selectors. Omit for the single-account case to keep\n * the original, unsuffixed testIDs — no test or E2E regression.\n */\n testIdIndex?: number;\n /** Omit to render read-only — the values stay selectable for manual copying. */\n onUse?: () => void;\n}\n\n/** The username/password rows and the \"use these credentials\" action. */\nexport function DemoCredentialsBody({\n credentials,\n labels,\n styles,\n authStyles,\n testIdPrefix,\n accountLabel,\n testIdIndex,\n onUse,\n}: Readonly<DemoCredentialsBodyProps>): ReactElement {\n // Suffix the base testID with the account index only when one is given, then\n // apply the prefix — so `zygos` + `username` + index 1 → `zygos-...-username-1`,\n // and a single account (no index) stays `zygos-...-username`.\n const testId = (base: string): string =>\n withTestIdPrefix(testIdIndex === undefined ? base : `${base}-${testIdIndex}`, testIdPrefix);\n\n const hasLabel = typeof accountLabel === 'string' && accountLabel.length > 0;\n\n return (\n <View>\n {hasLabel ? (\n <Text\n style={styles.accountLabel}\n testID={testId(AuthTestIds.demoCredentialsAccountLabel)}\n >\n {accountLabel}\n </Text>\n ) : null}\n\n <View style={styles.row}>\n <Text style={styles.rowLabel}>{labels.usernameLabel}</Text>\n <Text\n selectable\n style={styles.rowValue}\n testID={testId(AuthTestIds.demoCredentialsUsername)}\n >\n {credentials.username}\n </Text>\n </View>\n\n <View style={styles.row}>\n <Text style={styles.rowLabel}>{labels.passwordLabel}</Text>\n <Text\n selectable\n style={styles.rowValue}\n testID={testId(AuthTestIds.demoCredentialsPassword)}\n >\n {credentials.password}\n </Text>\n </View>\n\n {onUse !== undefined ? (\n <TouchableOpacity\n accessibilityHint={labels.useCredentialsHint}\n accessibilityLabel={labels.useCredentials}\n accessibilityRole=\"button\"\n style={[authStyles.secondaryButton, styles.useButton]}\n testID={testId(AuthTestIds.demoCredentialsUseButton)}\n onPress={onUse}\n >\n <Text style={authStyles.secondaryButtonText}>{labels.useCredentials}</Text>\n </TouchableOpacity>\n ) : null}\n </View>\n );\n}\n","/**\n * How `<DemoCredentialsHint>` presents itself on the login surface.\n *\n * The two variants answer opposite questions, and the choice is a product\n * decision rather than a styling one:\n *\n * - `Panel` assumes the page exists FOR the demo — a sales/marketing console\n * where every visitor is an evaluator. It advertises loudly.\n * - `Disclosure` assumes the page is a real customer's front door that ALSO\n * happens to offer a demo. Real account holders outnumber evaluators, so the\n * demo collapses behind one quiet line of text and costs them nothing.\n *\n * `Disclosure` is the default because the second case is the common one across\n * the estate: every product login screen is a page paying customers use daily.\n *\n * ⚠️ \"Discreet\" is achieved with SIZE, WEIGHT and POSITION — never by lowering\n * contrast. Both variants draw their text from `colors.textSecondary`, a token\n * every app already holds to the WCAG AA 4.5:1 floor. Dimming this further with\n * opacity would trade an accessibility guarantee for a visual preference; if a\n * consuming app's `textSecondary` fails AA, that is the app's token to fix.\n */\nexport const enum DemoCredentialsHintVariant {\n /** Always-open inset panel with a brand rail. The original presentation. */\n Panel = 'panel',\n /** One quiet \"try the demo\" line that expands the credentials on tap. */\n Disclosure = 'disclosure',\n}\n","/**\n * `useDemoCredentialsStyles` — the StyleSheet for `<DemoCredentialsHint>`.\n *\n * Kept out of `useAuthStyles` (which styles the form *fields*) because the demo\n * panel is its own surface, exactly as `<AuthScreen>`'s card chrome is.\n *\n * The visual idea, in tokens only — this panel is the first thing a prospective\n * client sees, so it has to read as a deliberate part of the product rather than\n * a debug notice:\n *\n * - **Inset, not alarming.** The panel fills with `colors.background` while\n * sitting on the card's `colors.surface`, so it reads as a recess in the card.\n * That is the same figure/ground relationship the inputs already use\n * (`useAuthStyles.input` is a `background` fill on the same card) — the panel\n * belongs to the form rather than interrupting it. No warning yellow, no\n * dedicated \"notice\" colour: the palette stays the app's own.\n * - **One brand accent.** A hairline rail in `colors.primary` down the leading\n * edge, plus the eyebrow heading in the same token, ties the panel to the\n * brand and gives it a deliberate reading order — and it is the ONLY saturated\n * element, so the panel never competes with the real \"Sign in\" button.\n * - **Credentials as chips.** Each value returns to `colors.surface` inside the\n * recess, so it lifts off the panel and reads as a discrete, copyable token.\n * Monospace, because the audience for a published demo password includes\n * people who will retype it and must not confuse `l`/`1` or `O`/`0`.\n */\nimport { useMemo } from 'react';\n\nimport { Platform, StyleSheet, type TextStyle, type ViewStyle } from 'react-native';\n\nimport type { AuthTheme } from '../theme/AuthTheme';\n\n/** The named styles `<DemoCredentialsHint>` draws from. */\nexport interface DemoCredentialsStyles {\n /** The inset panel surface. */\n panel: ViewStyle;\n /** Small brand-coloured eyebrow heading. */\n title: TextStyle;\n /** Explanatory copy under the heading. */\n description: TextStyle;\n /** A per-account heading (multi-account only), e.g. \"Master\". */\n accountLabel: TextStyle;\n /** A label/value credential row. */\n row: ViewStyle;\n /** The leading label in a credential row. */\n rowLabel: TextStyle;\n /** The trailing monospace value chip in a credential row. */\n rowValue: TextStyle;\n /** Outer wrapper for the `Disclosure` variant. */\n disclosure: ViewStyle;\n /** The collapsed \"try the demo\" trigger's touch target. */\n disclosureTrigger: ViewStyle;\n /** The trigger's label. */\n disclosureTriggerText: TextStyle;\n /** The expanded credentials, indented under the trigger. */\n disclosureBody: ViewStyle;\n /** Spacing correction for the fill button inside the body. */\n useButton: ViewStyle;\n}\n\nconst PANEL_BORDER_WIDTH = 1;\n/**\n * Minimum touch-target height for the disclosure trigger, in dp.\n *\n * The trigger is deliberately small *type* — that is what makes it discreet —\n * but a small hit area is a usability defect, not a design choice. WCAG 2.2\n * 2.5.8 sets 24×24 as the floor; this pads the one-line label out to a\n * comfortable target so \"quiet\" never becomes \"hard to tap\".\n */\nconst TRIGGER_MIN_HEIGHT = 32;\n/** Width of the brand rail down the panel's leading edge. */\nconst ACCENT_RAIL_WIDTH = 3;\n/** Tracking on the small uppercase eyebrow heading — it needs air to stay legible. */\nconst TITLE_LETTER_SPACING = 0.8;\n/** Comfortable reading leading for the description copy. */\nconst DESCRIPTION_LINE_HEIGHT_RATIO = 1.45;\n/** Halves a spacing token for the tight insets inside a value chip. */\nconst HALF = 2;\n\n/**\n * The platform's monospace face. RN has no cross-platform monospace token:\n * `'monospace'` resolves on Android and web, but on iOS it silently falls back\n * to the system face, so iOS names Menlo explicitly.\n */\nconst MONOSPACE_FONT = Platform.select({\n ios: 'Menlo',\n android: 'monospace',\n default: 'monospace',\n});\n\n/** Build the demo-panel `StyleSheet` from the resolved theme. */\nexport function useDemoCredentialsStyles(theme: AuthTheme): DemoCredentialsStyles {\n return useMemo(() => {\n const { colors, radii, spacing, typography } = theme;\n return StyleSheet.create<DemoCredentialsStyles>({\n panel: {\n borderWidth: PANEL_BORDER_WIDTH,\n borderLeftWidth: ACCENT_RAIL_WIDTH,\n borderRadius: radii.card,\n borderColor: colors.border,\n borderLeftColor: colors.primary,\n padding: spacing.md,\n marginBottom: spacing.md,\n backgroundColor: colors.background,\n },\n title: {\n fontSize: typography.caption,\n fontWeight: '700',\n letterSpacing: TITLE_LETTER_SPACING,\n textTransform: 'uppercase',\n color: colors.primary,\n },\n description: {\n fontSize: typography.caption,\n lineHeight: typography.caption * DESCRIPTION_LINE_HEIGHT_RATIO,\n marginTop: spacing.xs / HALF,\n marginBottom: spacing.sm,\n color: colors.textSecondary,\n },\n accountLabel: {\n fontSize: typography.caption,\n fontWeight: '700',\n color: colors.text,\n // Separates one account block from the previous one; the first block sits\n // under the panel description / disclosure divider, which already spaces it.\n marginTop: spacing.sm,\n marginBottom: spacing.xs / HALF,\n },\n row: {\n flexDirection: 'row',\n alignItems: 'center',\n justifyContent: 'space-between',\n marginTop: spacing.xs / HALF,\n },\n rowLabel: {\n fontSize: typography.caption,\n color: colors.textSecondary,\n },\n rowValue: {\n fontFamily: MONOSPACE_FONT,\n fontSize: typography.caption,\n fontWeight: '600',\n borderWidth: PANEL_BORDER_WIDTH,\n borderRadius: radii.input,\n borderColor: colors.border,\n paddingVertical: spacing.xs / HALF,\n paddingHorizontal: spacing.xs,\n // Never let a long password squeeze the label off the row.\n flexShrink: 1,\n backgroundColor: colors.surface,\n color: colors.text,\n },\n\n // ── Disclosure variant ──────────────────────────────────────────────\n // No panel fill, no border, no brand rail: the collapsed state is one\n // line of text and nothing else, so on a page a real customer uses it\n // reads as a footnote rather than as a second call to action.\n disclosure: {\n marginTop: spacing.md,\n alignSelf: 'stretch',\n },\n disclosureTrigger: {\n alignSelf: 'center',\n justifyContent: 'center',\n minHeight: TRIGGER_MIN_HEIGHT,\n paddingHorizontal: spacing.xs,\n },\n disclosureTriggerText: {\n fontSize: typography.caption,\n textDecorationLine: 'underline',\n // `textSecondary`, NOT a dimmed `text`. This is the same token the rest\n // of the helper copy uses, so it inherits whatever AA contrast the\n // consuming app already guarantees. Discretion here is carried by the\n // caption size, the centred placement below the form, and the absence\n // of any fill or border — never by fading the text toward the\n // background, which is how \"discreet\" quietly becomes a contrast bug.\n color: colors.textSecondary,\n },\n disclosureBody: {\n marginTop: spacing.sm,\n paddingTop: spacing.sm,\n borderTopWidth: PANEL_BORDER_WIDTH,\n borderTopColor: colors.border,\n },\n useButton: {\n alignSelf: 'stretch',\n },\n });\n }, [theme]);\n}\n","/**\n * `resolveDemoCredentials` — the single fail-closed gate for the demo surface.\n *\n * Every demo affordance in the package (the `<DemoCredentialsHint>` panel and\n * the `useDemoCredentials` wiring hook) routes its input through this function,\n * so \"should we advertise a demo account at all?\" is decided in exactly ONE\n * place and always the same way.\n *\n * Fail closed, deliberately. The realistic source of these values is an env var\n * (`process.env.EXPO_PUBLIC_DEMO_USERNAME`), which is `string | undefined` at\n * runtime no matter what the type says — a consumer writing `username: env.X!`\n * hands us `undefined` and TypeScript never notices. A half-configured demo must\n * render NOTHING rather than an empty panel inviting a client to sign in with\n * blank credentials, so anything that is not a genuinely non-empty string pair\n * resolves to `null`.\n */\nimport type { DemoCredentials } from './types';\n\n/**\n * Narrow an unvalidated demo-credential pair to a usable one, or `null`.\n *\n * Returns `null` for: `undefined` / `null`, a non-string field (runtime junk\n * from an unset env var), a blank/whitespace-only username, and an empty\n * password. Otherwise returns a NEW pair with the username trimmed.\n *\n * The password is deliberately NOT trimmed: leading/trailing whitespace can be\n * a legitimate part of a password, and silently altering it would turn a\n * working credential into a mystery login failure.\n */\nexport function resolveDemoCredentials(\n credentials?: DemoCredentials | null,\n): DemoCredentials | null {\n if (credentials === undefined || credentials === null) {\n return null;\n }\n\n const username =\n typeof credentials.username === 'string' ? credentials.username.trim() : '';\n const password = typeof credentials.password === 'string' ? credentials.password : '';\n\n const isUnusable = username.length === 0 || password.length === 0;\n if (isUnusable) {\n return null;\n }\n\n return { username, password };\n}\n","/**\n * `resolveDemoAccounts` — the fail-closed gate for the MULTI-account demo surface.\n *\n * The list counterpart of {@link resolveDemoCredentials}. Where that answers\n * \"is there a demo account?\" with one pair or `null`, this answers \"which demo\n * accounts should we advertise?\" with a (possibly empty) ARRAY. An empty array\n * means render nothing — exactly the `null` contract, expressed as a list.\n *\n * Two inputs collapse to the same output shape:\n *\n * - a `credentials.publishedAccounts` list (Bff.AspNetCore 1.17.0+) → each valid\n * entry, in order, labels preserved;\n * - a legacy single pair (`{ username, password }`, no `publishedAccounts`) →\n * wrapped into a ONE-item list with an empty label, so a single-account\n * deployment renders exactly as it did before this list existed.\n *\n * Every entry is validated through the same trim/non-empty discipline as the\n * single resolver, so a half-configured entry (blank username, `undefined` from\n * an unset value) is dropped rather than rendered as an empty row.\n */\nimport { resolveDemoCredentials } from './resolveDemoCredentials';\n\nimport type { DemoAccount, DemoCredentials } from './types';\n\n/**\n * Narrow one unvalidated account to a usable one, or `null`. Trims the username\n * and validates the pair exactly like {@link resolveDemoCredentials}; carries the\n * label through, defaulting a missing / non-string label to `''`.\n */\nfunction resolveAccount(account?: DemoAccount | null): DemoAccount | null {\n if (account === undefined || account === null) {\n return null;\n }\n const pair = resolveDemoCredentials(account);\n if (pair === null) {\n return null;\n }\n const label = typeof account.label === 'string' ? account.label : '';\n return { label, username: pair.username, password: pair.password };\n}\n\n/**\n * Validate a raw list of accounts, dropping any unusable entry. Used by the hint\n * when a consumer passes an `accounts` prop directly (the hook already routes its\n * list through here too, so validation happens in exactly one place).\n */\nexport function resolveAccountList(accounts?: readonly DemoAccount[] | null): DemoAccount[] {\n if (!Array.isArray(accounts)) {\n return [];\n }\n return accounts\n .map(resolveAccount)\n .filter((account): account is DemoAccount => account !== null);\n}\n\n/**\n * Resolve the ordered list of demo accounts to advertise, from either the new\n * `publishedAccounts` list or the legacy single pair. Returns `[]` when nothing\n * is usable — the \"render nothing\" contract, as a list.\n */\nexport function resolveDemoAccounts(\n credentials?: DemoCredentials | null,\n): DemoAccount[] {\n if (credentials === undefined || credentials === null) {\n return [];\n }\n\n const fromList = resolveAccountList(credentials.publishedAccounts);\n if (fromList.length > 0) {\n return fromList;\n }\n\n const single = resolveDemoCredentials(credentials);\n return single === null\n ? []\n : [{ label: '', username: single.username, password: single.password }];\n}\n","/**\n * `<DemoCredentialsHint>` — the public-demo credentials surface.\n *\n * Mount on the login surface of a product with an OPEN demo account whose\n * credentials are already published (typically on the marketing site). It shows\n * the username and password and offers a one-tap \"use these credentials\" action\n * that fills the form, so a non-technical evaluator never has to copy-paste a\n * password between two tabs to see the product.\n *\n * It authenticates nothing. It fills fields; `<LoginForm>` then submits them\n * down the ordinary path — same BFF, same Keycloak, same session, same roles.\n * There is no bypass here and no credential in this package: the host supplies\n * the pair, and the demo account's blast radius is whatever the IdP grants it.\n *\n * Fails closed: no credentials (or a half-configured pair) renders `null` — zero\n * DOM — so a misconfigured env var can never publish an empty demo panel.\n *\n * ## Two variants, and why the default changed in 1.13.0\n *\n * Originally this only rendered an always-open panel above the form. That is\n * right for a page whose whole purpose IS the demo, and wrong for the far more\n * common case: a login screen paying customers use every day, where an\n * unmissable \"here are some credentials\" block is noise at best and a trust\n * problem at worst.\n *\n * `DemoCredentialsHintVariant.Disclosure` — now the default — collapses the\n * whole thing to one quiet line (\"Try the demo\") that expands on tap. Pass\n * `variant={DemoCredentialsHintVariant.Panel}` to keep the original block.\n *\n * ⚠️ Two things this deliberately does NOT do to achieve discretion:\n *\n * - **It does not lower contrast.** The trigger uses `colors.textSecondary`,\n * the same AA-held token as every other piece of helper copy. Discretion is\n * carried by size, placement and the absence of chrome.\n * - **It does not hide from assistive tech.** The trigger is a real focusable\n * button carrying an explicit `aria-expanded` (plus `accessibilityState` for\n * native), so a screen reader announces both that it exists and whether it is\n * open. Visually quiet must not mean absent — a demo nobody can find is a demo\n * nobody uses.\n *\n * ⚠️ Through 1.13.0 this carried ONLY `accessibilityState={{ expanded }}` and\n * therefore announced nothing on web: react-native-web 0.21.2 does not read\n * `accessibilityState`, so the rendered button had no `aria-expanded` at all.\n * The old unit test asserted the React *prop*, so it passed against the bug.\n *\n * ## Layout stability\n *\n * The expanded body renders BELOW the trigger, and the component is designed to\n * sit BELOW `<LoginForm>` (see the zygos login route). Expanding therefore grows\n * the card downward and never displaces the username or password inputs the\n * visitor may already be interacting with. Mounting it ABOVE the form would make\n * every expansion shove the fields down the page — precisely the jarring\n * behaviour a disclosure exists to avoid.\n */\nimport { useCallback, useMemo, useState, type ReactElement } from 'react';\n\nimport { Text, TouchableOpacity, View } from 'react-native';\n\nimport { DemoCredentialsBody } from './DemoCredentialsBody';\nimport { DemoCredentialsHintVariant } from './DemoCredentialsHintVariant';\nimport {\n DEFAULT_DEMO_CREDENTIALS_HINT_LABELS,\n type DemoCredentialsHintLabels,\n} from './labels';\nimport { AuthTestIds, withTestIdPrefix } from './testIds';\nimport { useAuthStyles } from './useAuthStyles';\nimport { useDemoCredentialsStyles } from './useDemoCredentialsStyles';\nimport { resolveAccountList, resolveDemoAccounts } from '../demo/resolveDemoAccounts';\nimport { useAuthTheme } from '../theme/AuthThemeProvider';\n\nimport type { DemoAccount, DemoCredentials } from '../demo/types';\nimport type { AuthTheme } from '../theme/AuthTheme';\n\nexport interface DemoCredentialsHintProps {\n /**\n * The demo credentials to advertise. `undefined` — or a pair with a blank\n * username or password — renders nothing at all. When {@link accounts} is given\n * and non-empty it takes precedence; otherwise this single pair is resolved\n * (and, if it carries a `publishedAccounts` list, expanded) into the rows.\n */\n credentials?: DemoCredentials;\n /**\n * The resolved list of demo accounts to advertise, one labelled row per entry.\n * Preferred over {@link credentials} when present and non-empty. A single entry\n * renders exactly like the legacy single-pair panel (no per-account heading).\n * This is what `useDemoCredentials().hintProps` supplies.\n */\n accounts?: DemoAccount[];\n /**\n * Presentation. Defaults to `Disclosure` (one quiet expandable line); pass\n * `Panel` for the original always-open block.\n */\n variant?: DemoCredentialsHintVariant;\n /** Explicit theme; overrides any `<AuthThemeProvider>`. */\n theme?: AuthTheme;\n /** Localised copy. Partial — unspecified keys fall back to English defaults. */\n labels?: Partial<DemoCredentialsHintLabels>;\n /** Prefix applied to every `testID`. */\n testIdPrefix?: string;\n /**\n * Called with the resolved credentials when the user taps \"use these\n * credentials\". Omit to render read-only (no button) — the values are still\n * selectable, so a visitor can copy them by hand.\n */\n onUse?: (credentials: DemoCredentials) => void;\n}\n\n/** Themeable public-demo credentials surface. Renders `null` when there is no demo. */\nexport function DemoCredentialsHint({\n credentials,\n accounts,\n variant = DemoCredentialsHintVariant.Disclosure,\n theme: themeProp,\n labels: labelsProp,\n testIdPrefix,\n onUse,\n}: Readonly<DemoCredentialsHintProps>): ReactElement | null {\n const theme = useAuthTheme(themeProp);\n const authStyles = useAuthStyles(theme);\n const styles = useDemoCredentialsStyles(theme);\n const [expanded, setExpanded] = useState<boolean>(false);\n const labels = useMemo<DemoCredentialsHintLabels>(\n () => ({ ...DEFAULT_DEMO_CREDENTIALS_HINT_LABELS, ...labelsProp }),\n [labelsProp],\n );\n // Resolve to the ordered account list. An `accounts` prop (from the hook) wins;\n // otherwise resolve the single pair — which also fails closed standalone.\n // Memoised so the body / handlers are stable across renders.\n const resolvedAccounts = useMemo<DemoAccount[]>(\n () =>\n accounts !== undefined && accounts.length > 0\n ? resolveAccountList(accounts)\n : resolveDemoAccounts(credentials),\n [accounts, credentials],\n );\n\n // A factory of no-arg fill handlers, one per account, each closing over its own\n // pair. `undefined` when the caller wants read-only (no fill button).\n const makeUse = useCallback(\n (account: DemoAccount): (() => void) | undefined =>\n onUse === undefined\n ? undefined\n : (): void => onUse({ username: account.username, password: account.password }),\n [onUse],\n );\n\n const handleToggle = useCallback((): void => {\n setExpanded((current) => !current);\n }, []);\n\n if (resolvedAccounts.length === 0) {\n return null;\n }\n\n // One account renders exactly as before: no per-account heading, unsuffixed\n // testIDs. Multiple accounts each get their label as a heading and an index\n // suffixed onto every testID so N rows have unique selectors.\n const isSingle = resolvedAccounts.length === 1;\n const body = resolvedAccounts.map((account, index) => (\n <DemoCredentialsBody\n key={`${account.username}-${String(index)}`}\n accountLabel={isSingle ? undefined : account.label}\n authStyles={authStyles}\n credentials={{ username: account.username, password: account.password }}\n labels={labels}\n styles={styles}\n testIdIndex={isSingle ? undefined : index}\n testIdPrefix={testIdPrefix}\n onUse={makeUse(account)}\n />\n ));\n\n if (variant === DemoCredentialsHintVariant.Panel) {\n return (\n <View\n style={styles.panel}\n testID={withTestIdPrefix(AuthTestIds.demoCredentialsHint, testIdPrefix)}\n >\n <Text style={styles.title}>{labels.title}</Text>\n <Text style={styles.description}>{labels.description}</Text>\n {body}\n </View>\n );\n }\n\n return (\n <View\n style={styles.disclosure}\n testID={withTestIdPrefix(AuthTestIds.demoCredentialsHint, testIdPrefix)}\n >\n <TouchableOpacity\n // `aria-expanded` is passed EXPLICITLY and is the only reason a browser\n // announces the open/closed state. `accessibilityState` below is kept for\n // native, where it is the prop that works — but react-native-web 0.21.2\n // does not read it at all (measured: it emits `aria-label` and `role`, and\n // no `aria-expanded`). Guarded by DemoCredentialsHint.dom.test.tsx.\n aria-expanded={expanded}\n accessibilityHint={labels.toggleHint}\n accessibilityLabel={labels.toggle}\n accessibilityRole=\"button\"\n accessibilityState={{ expanded }}\n style={styles.disclosureTrigger}\n testID={withTestIdPrefix(AuthTestIds.demoCredentialsToggle, testIdPrefix)}\n onPress={handleToggle}\n >\n <Text style={styles.disclosureTriggerText}>{labels.toggle}</Text>\n </TouchableOpacity>\n\n {expanded ? <View style={styles.disclosureBody}>{body}</View> : null}\n </View>\n );\n}\n","/**\n * `useBffLoginConfig` — fetch the BFF login config once and expose it.\n *\n * The login surface only renders the methods the BFF actually has enabled, and\n * the device-PIN unlock gate only triggers when the per-device state says so.\n * Both come from `GET /bff/config`, which the supplied client reads and parses\n * (this hook is transport-agnostic — it delegates the fetch + parsing to the\n * client's `getLoginConfig`, mirroring kefi-web's `useBffConfig` shape).\n *\n * react-query-FREE by construction: plain `useState` + `useEffect`, never\n * `useQuery`. The login route group has no QueryClient provider, so this hook —\n * and every component built on it — must avoid react-query primitives.\n *\n * On a rejected `getLoginConfig` the hook falls back to a safe empty config\n * (no methods, registration off, empty device-state) so the surface stays\n * usable even when `/bff/config` is unreachable in dev. `loading` flips to\n * `false` as soon as the call settles.\n */\nimport { useEffect, useState } from 'react';\n\nimport type { BffLoginConfig, LoginConfigCapableClient } from './types';\n\n/** A safe, inert config used before the first fetch resolves / on failure. */\nconst EMPTY_CONFIG: BffLoginConfig = {\n methods: [],\n registrationEnabled: false,\n deviceState: {\n rememberedUsername: null,\n hasPin: false,\n pinDigits: null,\n preferredMethod: null,\n },\n demo: null,\n};\n\n/** What {@link useBffLoginConfig} returns. */\nexport interface UseBffLoginConfigResult {\n /** The parsed login config; the empty fallback until the fetch resolves. */\n config: BffLoginConfig;\n /** `true` until the initial `getLoginConfig` call settles. */\n loading: boolean;\n}\n\n/**\n * Fetch `getLoginConfig()` once on mount and expose `{ config, loading }`. The\n * empty fallback config is used until the call resolves and on any failure. The\n * effect guards against a `setState` after the consumer unmounts mid-request.\n */\nexport function useBffLoginConfig(\n client: LoginConfigCapableClient,\n): UseBffLoginConfigResult {\n const [config, setConfig] = useState<BffLoginConfig>(EMPTY_CONFIG);\n const [loading, setLoading] = useState<boolean>(true);\n\n useEffect(() => {\n let active = true;\n client\n .getLoginConfig()\n .then((next) => {\n if (active) {\n setConfig(next);\n }\n })\n .catch(() => {\n if (active) {\n setConfig(EMPTY_CONFIG);\n }\n })\n .finally(() => {\n if (active) {\n setLoading(false);\n }\n });\n return (): void => {\n active = false;\n };\n }, [client]);\n\n return { config, loading };\n}\n","/**\n * Same-origin client for the user's cross-device login-method preference\n * (unified-login D5). Unlike the device-PIN client (which targets the BFF's\n * own `/bff/*` auth endpoints), the preference lives in TenantService and is\n * reached THROUGH the BFF's YARP proxy:\n *\n * - GET `${baseUrl}/bff/api/{tenantsSegment}/api/v1/me/preferences`\n * → `{ ..., preferredLoginMethod }`\n * - PUT `${baseUrl}/bff/api/{tenantsSegment}/api/v1/me/login-method-preference`\n * body `{ method }`\n *\n * The BFF attaches the session's Bearer token to the proxied request, so both\n * calls require an authenticated session (the cookie travels via\n * `credentials: 'include'`). The PUT carries the `X-BFF-Csrf` header the BFF\n * anti-forgery middleware requires.\n *\n * react-query-FREE: plain `HttpClient` calls with `.then/.catch`. Portable\n * across every consumer (Expo RN-web apps AND the kefi/poueni surfaces).\n */\nimport type { HttpClient } from '@dloizides/auth-client';\n\nconst CSRF_HEADER = 'X-BFF-Csrf';\nconst CSRF_HEADER_VALUE = '1';\nconst JSON_CONTENT_TYPE = 'application/json';\n\n/** The default BFF YARP downstream segment that routes to TenantService. */\nconst DEFAULT_TENANTS_SEGMENT = 'tenants';\n\n/** The TenantService routes, relative to the BFF tenants proxy base. */\nconst PREFERENCES_PATH = 'api/v1/me/preferences';\nconst LOGIN_METHOD_PREFERENCE_PATH = 'api/v1/me/login-method-preference';\n\nexport interface PreferencesClientOptions {\n /** Runtime-agnostic HTTP transport (wrap native `fetch` with `createFetchHttpClient`). */\n http: HttpClient;\n /**\n * BFF origin. Defaults to `''` (same-origin) — the production wiring. An\n * explicit origin is only useful for tests or a non-same-origin BFF.\n */\n baseUrl?: string;\n /**\n * The BFF YARP downstream segment that routes to TenantService. Defaults to\n * `'tenants'` — the segment every product BFF (katalogos / erevna / kefi)\n * uses for `tenant-api`.\n */\n tenantsSegment?: string;\n}\n\n/**\n * The narrow client the preferred-method UI depends on. Both methods NEVER\n * reject — they resolve a benign value on any failure so the settings card and\n * the post-login cache sync degrade gracefully rather than throwing.\n */\nexport interface PreferredMethodClient {\n /**\n * `GET /me/preferences` → the stored preferred login method, or `null` when\n * the user never picked one (or on any failure).\n */\n getPreferredLoginMethod(): Promise<string | null>;\n /**\n * `PUT /me/login-method-preference` — set (or clear, with `null`) the stored\n * preference. Resolves `true` on a 2xx, `false` on anything else.\n */\n setPreferredLoginMethod(method: string | null): Promise<boolean>;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null;\n}\n\n/** Read an optional non-empty string field off a record, else `null`. */\nfunction readOptionalString(record: Record<string, unknown>, key: string): string | null {\n const value = record[key];\n if (typeof value !== 'string' || value === '') {\n return null;\n }\n return value;\n}\n\n/**\n * Build a same-origin {@link PreferredMethodClient}. With no `baseUrl` this is\n * the production wiring: same-origin, the session cookie travels automatically.\n */\nexport function createPreferencesClient(options: PreferencesClientOptions): PreferredMethodClient {\n const http = options.http;\n const baseUrl = (options.baseUrl ?? '').replace(/\\/$/, '');\n const segment = options.tenantsSegment ?? DEFAULT_TENANTS_SEGMENT;\n const proxyBase = `${baseUrl}/bff/api/${segment}`;\n\n return {\n async getPreferredLoginMethod(): Promise<string | null> {\n try {\n const response = await http({\n url: `${proxyBase}/${PREFERENCES_PATH}`,\n method: 'GET',\n headers: { Accept: JSON_CONTENT_TYPE },\n credentials: 'include',\n });\n if (!response.ok || !isRecord(response.data)) {\n return null;\n }\n return readOptionalString(response.data, 'preferredLoginMethod');\n } catch {\n return null;\n }\n },\n\n async setPreferredLoginMethod(method: string | null): Promise<boolean> {\n try {\n const response = await http({\n url: `${proxyBase}/${LOGIN_METHOD_PREFERENCE_PATH}`,\n method: 'PUT',\n headers: {\n 'Content-Type': JSON_CONTENT_TYPE,\n Accept: JSON_CONTENT_TYPE,\n [CSRF_HEADER]: CSRF_HEADER_VALUE,\n },\n body: JSON.stringify({ method }),\n credentials: 'include',\n });\n return response.ok;\n } catch {\n return false;\n }\n },\n };\n}\n","/**\n * Seed the device-local preferred-method cache from the server.\n *\n * Call this right AFTER a successful login (any method), while a session\n * exists: it reads the server-owned preference and writes it into\n * `localStorage` so the NEXT visit's login screen can emphasise it before the\n * user authenticates. This is the bridge that makes the preference cross-device\n * (the cache on a new device gets seeded on that device's first login).\n *\n * Fire-and-forget + never throws — a failed sync just leaves the cache as-is;\n * the login hint is an optional nicety, never a blocker.\n */\nimport { cachePreferredMethod } from './preferredMethodCache';\n\nimport type { PreferredMethodClient } from './preferencesClient';\n\n/**\n * Fetch the server-stored preferred login method and mirror it into the\n * device-local cache. Resolves to the value written (or `null`). Safe to\n * `void` — it swallows all errors.\n */\nexport async function syncPreferredMethodFromServer(\n client: PreferredMethodClient,\n): Promise<string | null> {\n try {\n const method = await client.getPreferredLoginMethod();\n cachePreferredMethod(method);\n return method;\n } catch {\n return null;\n }\n}\n","/**\n * `useDemoCredentials` — the wiring between `<DemoCredentialsHint>` and\n * `<LoginForm>`, so a consuming app does not hand-roll it.\n *\n * Without this hook every app would rediscover the same trap: `<LoginForm>`'s\n * `initialUsername` / `initialPassword` seed `useState`, and `useState` ignores\n * its initial argument on re-render — so wiring the hint's button to a plain\n * `setState` would render a form that stubbornly stays empty. The fix (a nonce\n * that re-applies the seed) is package plumbing, not app code.\n *\n * The hook owns that state and hands back two ready-to-spread prop bags:\n *\n * ```tsx\n * const demo = useDemoCredentials({ credentials: DEMO, prefillOnMount: true });\n *\n * <AuthScreen theme={authTheme}>\n * <DemoCredentialsHint {...demo.hintProps} theme={authTheme} />\n * <LoginForm {...demo.loginFormProps} chromeless client={client} theme={authTheme}\n * onSuccess={handleSignedIn} />\n * </AuthScreen>\n * ```\n *\n * Pass a *stable* `credentials` reference (a module-level const, or memoised).\n * An object literal re-created every render re-creates `hintProps` every render.\n */\nimport { useCallback, useMemo, useState } from 'react';\n\nimport { resolveDemoAccounts } from './resolveDemoAccounts';\nimport { PrefillIntent } from '../components/PrefillIntent';\n\nimport type { DemoAccount, DemoCredentials } from './types';\n\n/**\n * Compare two resolved pairs by VALUE.\n *\n * Identity is not usable here: `resolveDemoCredentials` builds a new object\n * whenever the caller's `credentials` reference changes, and a react-query\n * refetch hands back a fresh object carrying identical values on every poll.\n * Comparing by identity would re-seed the form on every refetch — stomping the\n * user's typing on a timer.\n */\nfunction isSamePair(a: DemoCredentials | null, b: DemoCredentials | null): boolean {\n if (a === null || b === null) {\n return a === b;\n }\n return a.username === b.username && a.password === b.password;\n}\n\n/** Options for {@link useDemoCredentials}. */\nexport interface UseDemoCredentialsOptions {\n /**\n * The demo credentials to advertise. Omit (or pass a half-configured pair) and\n * the whole surface disappears: the hint renders nothing and the form is never\n * seeded. See `resolveDemoCredentials`.\n */\n credentials?: DemoCredentials;\n /**\n * When `true` the form arrives ALREADY filled, so signing in as the demo user\n * is a single tap on \"Sign in\" — the hint panel then explains why the fields\n * are populated and re-fills them if the visitor clears them.\n *\n * Defaults to `false`: the fields start empty and the visitor opts in by\n * tapping \"Use these credentials\". Prefer the default unless the page is a\n * genuinely public demo — a login form that arrives pre-filled with someone\n * else's credentials is confusing on a page real account holders also use.\n */\n prefillOnMount?: boolean;\n}\n\n/** The `<LoginForm>` props that carry the demo prefill. Spread onto the form. */\nexport interface DemoCredentialsLoginFormProps {\n initialUsername?: string;\n initialPassword?: string;\n prefillNonce: number;\n prefillIntent: PrefillIntent;\n}\n\n/** The `<DemoCredentialsHint>` props that carry the credentials + fill action. */\nexport interface DemoCredentialsHintWiring {\n credentials?: DemoCredentials;\n /**\n * The resolved list of demo accounts (from `publishedAccounts`, else the legacy\n * single pair wrapped into one). The hint renders one labelled row per entry and\n * prefers this over {@link credentials} when present. Additive — a hint given only\n * `credentials` still resolves the same list itself.\n */\n accounts: DemoAccount[];\n onUse: (credentials: DemoCredentials) => void;\n}\n\n/** What {@link useDemoCredentials} hands back. */\nexport interface UseDemoCredentialsResult {\n /** Spread onto `<LoginForm>`. */\n loginFormProps: DemoCredentialsLoginFormProps;\n /** Spread onto `<DemoCredentialsHint>`. */\n hintProps: DemoCredentialsHintWiring;\n}\n\n/** Wire a demo-credentials hint to a login form. Returns two prop bags to spread. */\nexport function useDemoCredentials({\n credentials,\n prefillOnMount = false,\n}: Readonly<UseDemoCredentialsOptions> = {}): UseDemoCredentialsResult {\n // The full resolved list (multi-account or a single legacy pair wrapped into one).\n const accounts = useMemo(() => resolveDemoAccounts(credentials), [credentials]);\n // The form seeds from the FIRST account — the one the legacy fields mirror, and\n // the natural default when a page arrives pre-filled. As a bare pair (no label)\n // so the value-gated auto-seed below compares it cleanly.\n const resolved = useMemo<DemoCredentials | null>(() => {\n const first = accounts[0];\n return first === undefined\n ? null\n : { username: first.username, password: first.password };\n }, [accounts]);\n\n // The values currently seeded into the form (`null` = nothing seeded).\n const [filled, setFilled] = useState<DemoCredentials | null>(\n prefillOnMount ? resolved : null,\n );\n // Bumped on every fill so `<LoginForm>` re-applies the seed to fields the user\n // may already have edited or cleared.\n const [prefillNonce, setPrefillNonce] = useState<number>(0);\n const [prefillIntent, setPrefillIntent] = useState<PrefillIntent>(\n PrefillIntent.Opportunistic,\n );\n // The pair the auto-seed has already consumed. Initialised to what a\n // synchronous `credentials` already seeded via `useState` above, so the\n // module-const path never double-seeds and its nonce stays at 0.\n const [autoSeeded, setAutoSeeded] = useState<DemoCredentials | null>(\n prefillOnMount ? resolved : null,\n );\n\n // Credentials fetched from `GET /bff/config` land AFTER mount, and `useState`\n // honours its initial argument on the first render only — so without this the\n // `prefillOnMount` seed above silently never happens for any BFF-fronted app,\n // and the panel renders next to a stubbornly empty form. Adjusting state during\n // render (React's documented \"derive state from props\" pattern) rather than in\n // an effect avoids a committed render showing the un-seeded form first.\n //\n // Gated on the pair's VALUE, so this runs at most once per distinct credential\n // pair: re-renders and refetches that carry the same values do nothing, which\n // is what stops it looping.\n const shouldAutoSeed = prefillOnMount && resolved !== null && !isSamePair(resolved, autoSeeded);\n if (shouldAutoSeed) {\n setAutoSeeded(resolved);\n setFilled(resolved);\n setPrefillNonce((current) => current + 1);\n // Offered, not requested: `<LoginForm>` drops this if the user is typing.\n setPrefillIntent(PrefillIntent.Opportunistic);\n }\n\n const handleUse = useCallback((next: DemoCredentials): void => {\n setFilled(next);\n setPrefillNonce((current) => current + 1);\n // The user tapped the button — this one always applies.\n setPrefillIntent(PrefillIntent.Explicit);\n }, []);\n\n return useMemo(\n () => ({\n loginFormProps: {\n initialUsername: filled?.username,\n initialPassword: filled?.password,\n prefillNonce,\n prefillIntent,\n },\n // `credentials` is passed through unresolved on purpose: the hint applies\n // `resolveDemoAccounts` itself, so it fails closed even when it is used\n // standalone, without this hook. `accounts` is the already-resolved list the\n // hint prefers — one labelled row per entry.\n hintProps: { credentials, accounts, onUse: handleUse },\n }),\n [filled, prefillNonce, prefillIntent, credentials, accounts, handleUse],\n );\n}\n","/**\n * `testID` values for `<RegisterForm>`.\n *\n * Kept apart from `AuthTestIds` on purpose: these are the unprefixed\n * `register-*` IDs katalogos-web and erevna-web rendered before the extraction,\n * and the E2E suites (`E2ETests/shared/testIds.ts`,\n * `E2ETests/helpers/katalogos-signup-helpers.ts`) already select on them.\n * Changing a value here breaks those suites.\n *\n * `sonarjs/no-hardcoded-passwords` is disabled for this file: it flags the\n * `passwordInput` keys, but every value here is a UI test ID, not a credential.\n */\n/* eslint-disable sonarjs/no-hardcoded-passwords */\nexport const RegisterTestIds = {\n form: 'register-form',\n firstNameInput: 'register-first-name-input',\n lastNameInput: 'register-last-name-input',\n usernameInput: 'register-username-input',\n emailInput: 'register-email-input',\n passwordInput: 'register-password-input',\n confirmPasswordInput: 'register-confirm-password-input',\n tenantNameInput: 'register-tenant-name-input',\n submitButton: 'register-submit-button',\n websiteInput: 'register-website',\n} as const;\n","/**\n * The inputs of `<RegisterForm>`: the seven visible fields plus the off-screen\n * honeypot. Presentational only; state lives in `useRegisterForm`.\n */\nimport { type ComponentProps, type ReactElement } from 'react';\n\nimport { StyleSheet, Text, TextInput, View } from 'react-native';\n\nimport { RegisterTestIds } from './registerTestIds';\nimport { withTestIdPrefix } from './testIds';\n\nimport type { RegisterFormLabels } from './labels/registerLabels';\nimport type { useAuthStyles } from './useAuthStyles';\nimport type { RegisterField, RegisterFormValues, RegisterInputField } from '../hooks/registerTypes';\nimport type { AuthTheme } from '../theme/AuthTheme';\n\ntype InputProps = ComponentProps<typeof TextInput>;\n\ninterface FieldConfig {\n key: RegisterInputField;\n testId: string;\n secure?: boolean;\n autoComplete?: InputProps['autoComplete'];\n keyboardType?: InputProps['keyboardType'];\n}\n\nconst FIELDS: readonly FieldConfig[] = [\n { key: 'firstName', testId: RegisterTestIds.firstNameInput, autoComplete: 'name' },\n { key: 'lastName', testId: RegisterTestIds.lastNameInput, autoComplete: 'name' },\n { key: 'username', testId: RegisterTestIds.usernameInput, autoComplete: 'username' },\n { key: 'email', testId: RegisterTestIds.emailInput, autoComplete: 'email', keyboardType: 'email-address' },\n { key: 'password', testId: RegisterTestIds.passwordInput, secure: true },\n { key: 'confirmPassword', testId: RegisterTestIds.confirmPasswordInput, secure: true },\n { key: 'tenantName', testId: RegisterTestIds.tenantNameInput },\n];\n\nconst OFF_SCREEN = -9999;\nconst HONEYPOT_SIZE = 1;\n// Never shown to a human; a bot reads it to decide what to type.\nconst HONEYPOT_PLACEHOLDER = 'Website';\n\nconst honeypotStyles = StyleSheet.create({\n honeypot: {\n position: 'absolute',\n left: OFF_SCREEN,\n top: OFF_SCREEN,\n width: HONEYPOT_SIZE,\n height: HONEYPOT_SIZE,\n opacity: 0,\n },\n});\n\nexport interface RegisterFormFieldsProps {\n values: RegisterFormValues;\n labels: RegisterFormLabels;\n disabled: boolean;\n theme: AuthTheme;\n styles: ReturnType<typeof useAuthStyles>;\n onChange: (field: RegisterField, value: string) => void;\n /** Enter in any visible field submits the form. */\n onSubmitEditing?: () => void;\n testIdPrefix?: string;\n}\n\nexport function RegisterFormFields({\n values,\n labels,\n disabled,\n theme,\n styles,\n onChange,\n onSubmitEditing,\n testIdPrefix,\n}: Readonly<RegisterFormFieldsProps>): ReactElement {\n return (\n <>\n {FIELDS.map((config) => {\n const copy = labels.fields[config.key];\n return (\n <View key={config.key} style={styles.fieldGroup}>\n <Text style={styles.label}>{copy.label}</Text>\n <TextInput\n accessibilityHint={copy.hint}\n accessibilityLabel={copy.inputLabel}\n autoCapitalize=\"none\"\n autoComplete={config.autoComplete}\n autoCorrect={false}\n editable={!disabled}\n keyboardType={config.keyboardType ?? 'default'}\n placeholder={copy.placeholder}\n placeholderTextColor={theme.colors.textSecondary}\n returnKeyType=\"go\"\n secureTextEntry={config.secure === true}\n style={styles.input}\n testID={withTestIdPrefix(config.testId, testIdPrefix)}\n value={values[config.key]}\n onChangeText={(text) => onChange(config.key, text)}\n onSubmitEditing={onSubmitEditing}\n />\n </View>\n );\n })}\n <TextInput\n accessibilityElementsHidden\n accessibilityRole=\"none\"\n autoComplete=\"off\"\n focusable={false}\n importantForAccessibility=\"no-hide-descendants\"\n placeholder={HONEYPOT_PLACEHOLDER}\n style={honeypotStyles.honeypot}\n testID={withTestIdPrefix(RegisterTestIds.websiteInput, testIdPrefix)}\n value={values.website}\n onChangeText={(text) => onChange('website', text)}\n />\n </>\n );\n}\n","/**\n * The discrete failure states the registration flow can report.\n *\n * Each member is a stable key the consuming app maps onto a localised message\n * (`FM('register.usernameTaken')`, …). The package never renders copy for these\n * itself — it ships no translations.\n */\nexport const enum RegisterErrorCode {\n /** A required field (anything but the honeypot) is empty. */\n MissingFields = 'missingFields',\n /** The email does not look like an address. */\n InvalidEmail = 'invalidEmail',\n /** The password fails the active password policy. */\n WeakPassword = 'weakPassword',\n /** The confirm field does not match the password. */\n PasswordMismatch = 'passwordMismatch',\n /** The server reported `USERNAME_TAKEN`. */\n UsernameTaken = 'usernameTaken',\n /** The server reported `EMAIL_TAKEN`. */\n EmailTaken = 'emailTaken',\n /** The server reported `REALM_REQUIRED` or `REALM_INVALID`. */\n RealmInvalid = 'realmInvalid',\n /** The server rejected the request with an unrecognised message. */\n ValidationFailed = 'validationFailed',\n /** Generic failure: network error, empty message, or a filled honeypot (never revealed). */\n Failed = 'failed',\n /** A submit is already running; the second press was ignored. Do not surface it. */\n InFlight = 'inFlight',\n}\n","/**\n * Route a finished registration submit to the app's callbacks.\n *\n * Kept out of `<RegisterForm>` so the only branching the component had is unit\n * tested: success goes to `onSuccess`; every failure goes to `onError` except\n * `InFlight`, which marks a press the hook ignored and is never surfaced.\n */\nimport { RegisterErrorCode } from './RegisterErrorCode';\n\nimport type { RegisterSubmitOutcome } from './registerTypes';\n\nexport interface RegisterOutcomeHandlers<TResult> {\n onSuccess: (result: TResult) => void;\n onError?: (error: RegisterErrorCode) => void;\n}\n\n/** Deliver `outcome` to the matching handler. */\nexport function routeRegisterOutcome<TResult>(\n outcome: RegisterSubmitOutcome<TResult>,\n handlers: RegisterOutcomeHandlers<TResult>,\n): void {\n if (outcome.ok) {\n handlers.onSuccess(outcome.result);\n return;\n }\n if (outcome.error !== RegisterErrorCode.InFlight) {handlers.onError?.(outcome.error);}\n}\n","/**\n * Pure registration helpers: trimming, client-side validation and decoding of a\n * TenantService failure (surfaced by the BFF as a plain error whose message\n * carries an error-code substring).\n *\n * Merged from the katalogos-web and erevna-web `useRegisterForm` copies, which\n * were identical apart from katalogos' honeypot.\n */\nimport { RegisterErrorCode } from './RegisterErrorCode';\n\nimport type { RegisterFormValues, RegisterPasswordPolicy } from './registerTypes';\n\nconst MIN_PASSWORD_LENGTH = 8;\nconst WHITESPACE_REGEX = /\\s/;\nconst EMAIL_PART_COUNT = 2;\nconst PASSWORD_LETTER_REGEX = /[a-zA-Z]/;\nconst PASSWORD_DIGIT_REGEX = /\\d/;\nconst PASSWORD_SPECIAL_REGEX = /[^a-zA-Z0-9]/;\n\n/** Server error-code substring → code. First match wins. */\nconst SERVER_ERROR_CODES: ReadonlyArray<readonly [string, RegisterErrorCode]> = [\n ['USERNAME_TAKEN', RegisterErrorCode.UsernameTaken],\n ['EMAIL_TAKEN', RegisterErrorCode.EmailTaken],\n ['REALM_REQUIRED', RegisterErrorCode.RealmInvalid],\n ['REALM_INVALID', RegisterErrorCode.RealmInvalid],\n];\n\n/** The default password rule: 8+ characters with a letter, a digit and a special character. */\nexport function isRegisterPasswordStrong(password: string): boolean {\n if (password.length < MIN_PASSWORD_LENGTH) {return false;}\n if (!PASSWORD_LETTER_REGEX.test(password)) {return false;}\n if (!PASSWORD_DIGIT_REGEX.test(password)) {return false;}\n return PASSWORD_SPECIAL_REGEX.test(password);\n}\n\n/**\n * The pre-extraction app rule `^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$`, written without the\n * regex's super-linear backtracking: no whitespace, exactly one `@`, a non-empty\n * local part, and a dot strictly inside the domain. Rejects `a@b.c@d`. Strict\n * validation is the backend's job.\n */\nfunction isEmailShaped(email: string): boolean {\n if (WHITESPACE_REGEX.test(email)) {return false;}\n const parts = email.split('@');\n if (parts.length !== EMAIL_PART_COUNT) {return false;}\n const [local = '', domain = ''] = parts;\n return local !== '' && domain.slice(1, -1).includes('.');\n}\n\n/** Trim every text field; passwords are left exactly as typed. */\nexport function trimRegisterValues(values: RegisterFormValues): RegisterFormValues {\n return {\n firstName: values.firstName.trim(),\n lastName: values.lastName.trim(),\n username: values.username.trim(),\n email: values.email.trim(),\n password: values.password,\n confirmPassword: values.confirmPassword,\n tenantName: values.tenantName.trim(),\n website: values.website.trim(),\n };\n}\n\nfunction hasMissingRequiredField(values: RegisterFormValues): boolean {\n const required = [\n values.firstName,\n values.lastName,\n values.username,\n values.email,\n values.password,\n values.tenantName,\n ];\n return required.some((value) => value === '');\n}\n\n/** The first client-side problem with already-trimmed values, or `null`. */\nexport function validateRegisterValues(\n values: RegisterFormValues,\n passwordPolicy: RegisterPasswordPolicy,\n): RegisterErrorCode | null {\n if (hasMissingRequiredField(values)) {return RegisterErrorCode.MissingFields;}\n if (!isEmailShaped(values.email)) {return RegisterErrorCode.InvalidEmail;}\n if (!passwordPolicy(values.password)) {return RegisterErrorCode.WeakPassword;}\n if (values.password !== values.confirmPassword) {return RegisterErrorCode.PasswordMismatch;}\n return null;\n}\n\nfunction messageOf(error: unknown): string {\n if (error instanceof Error) {return error.message;}\n return typeof error === 'string' ? error : '';\n}\n\n/** Decode a thrown registration failure into a {@link RegisterErrorCode}. */\nexport function mapRegisterErrorCode(error: unknown): RegisterErrorCode {\n const message = messageOf(error);\n if (message === '') {return RegisterErrorCode.Failed;}\n const match = SERVER_ERROR_CODES.find(([code]) => message.includes(code));\n return match === undefined ? RegisterErrorCode.ValidationFailed : match[1];\n}\n","/**\n * `useRegisterForm` — headless registration state, client validation, honeypot\n * refusal and submit flow.\n *\n * The hook does not know how registration is sent: the app passes `onSubmit`,\n * which builds its own request (realm, verify-URL template) and calls its BFF.\n * Failures come back as a {@link RegisterErrorCode}; the app maps it to copy.\n * No react-query, so it runs on provider-less auth routes.\n */\nimport { useCallback, useRef, useState } from 'react';\n\nimport { isRegisterPasswordStrong, mapRegisterErrorCode, trimRegisterValues, validateRegisterValues } from './registerErrors';\nimport { RegisterErrorCode } from './RegisterErrorCode';\n\nimport type {\n RegisterField,\n RegisterFormValues,\n RegisterPasswordPolicy,\n RegisterSubmitOutcome,\n RegisterSubmitValues,\n} from './registerTypes';\n\nexport interface UseRegisterFormArgs<TResult> {\n /** Send the registration. Throw on failure; the message is decoded to a code. */\n onSubmit: (values: RegisterSubmitValues) => Promise<TResult>;\n /** Password rule. Defaults to {@link isRegisterPasswordStrong}. */\n passwordPolicy?: RegisterPasswordPolicy;\n /**\n * Called once per ACCEPTED submit, before validation (e.g. a \"signup started\"\n * event). A press ignored because a submit is already in flight does not call it.\n */\n onSubmitAttempt?: () => void;\n}\n\nexport interface UseRegisterFormResult<TResult> {\n state: RegisterFormValues;\n setField: (field: RegisterField, value: string) => void;\n submit: () => Promise<RegisterSubmitOutcome<TResult>>;\n isSubmitting: boolean;\n /** The last failure, cleared when a submit starts. */\n error: RegisterErrorCode | null;\n}\n\nconst EMPTY_VALUES: RegisterFormValues = {\n firstName: '',\n lastName: '',\n username: '',\n email: '',\n password: '',\n confirmPassword: '',\n tenantName: '',\n website: '',\n};\n\nfunction toSubmitValues(values: RegisterFormValues): RegisterSubmitValues {\n return {\n firstName: values.firstName,\n lastName: values.lastName,\n username: values.username,\n email: values.email,\n password: values.password,\n tenantName: values.tenantName,\n website: values.website,\n };\n}\n\n/** Headless registration form logic. */\nexport function useRegisterForm<TResult>({\n onSubmit,\n passwordPolicy = isRegisterPasswordStrong,\n onSubmitAttempt,\n}: UseRegisterFormArgs<TResult>): UseRegisterFormResult<TResult> {\n const [state, setState] = useState<RegisterFormValues>(EMPTY_VALUES);\n const [isSubmitting, setIsSubmitting] = useState(false);\n const [error, setError] = useState<RegisterErrorCode | null>(null);\n // A ref, not state: a double press inside one frame must see the flag at once.\n const inFlight = useRef(false);\n\n const setField = useCallback((field: RegisterField, value: string): void => {\n setState((prev) => ({ ...prev, [field]: value }));\n }, []);\n\n const submit = useCallback(async (): Promise<RegisterSubmitOutcome<TResult>> => {\n if (inFlight.current) {return { ok: false, error: RegisterErrorCode.InFlight };}\n onSubmitAttempt?.();\n const trimmed = trimRegisterValues(state);\n // A filled honeypot gets the generic code, so the trap is never revealed.\n const refusal =\n trimmed.website === '' ? validateRegisterValues(trimmed, passwordPolicy) : RegisterErrorCode.Failed;\n if (refusal !== null) {\n setError(refusal);\n return { ok: false, error: refusal };\n }\n\n inFlight.current = true;\n setError(null);\n setIsSubmitting(true);\n try {\n const result = await onSubmit(toSubmitValues(trimmed));\n return { ok: true, result };\n } catch (caught) {\n const code = mapRegisterErrorCode(caught);\n setError(code);\n return { ok: false, error: code };\n } finally {\n inFlight.current = false;\n setIsSubmitting(false);\n }\n }, [onSubmit, onSubmitAttempt, passwordPolicy, state]);\n\n return { state, setField, submit, isSubmitting, error };\n}\n","/**\n * `<RegisterForm>` — the ready-made, themeable sign-up form.\n *\n * Extracted from the identical katalogos-web and erevna-web register screens.\n * The app keeps what differs per product: the request it sends (`onSubmit`, which\n * carries the realm and verify-URL template), where to go afterwards\n * (`onSuccess`), and the localised copy (`labels`, plus mapping a\n * `RegisterErrorCode` to a message in `onError`).\n */\nimport { useCallback, useMemo, type ReactElement, type ReactNode } from 'react';\n\nimport { Text, View } from 'react-native';\n\nimport { Button } from '@dloizides/ui-buttons';\n\nimport { DEFAULT_REGISTER_LABELS, type RegisterFormLabels } from './labels/registerLabels';\nimport { RegisterFormFields } from './RegisterFormFields';\nimport { RegisterTestIds } from './registerTestIds';\nimport { withTestIdPrefix } from './testIds';\nimport { useAuthStyles } from './useAuthStyles';\nimport { useSubmitOnEnter } from './useSubmitOnEnter';\nimport { routeRegisterOutcome } from '../hooks/routeRegisterOutcome';\nimport { useRegisterForm } from '../hooks/useRegisterForm';\nimport { useAuthTheme } from '../theme/AuthThemeProvider';\n\nimport type { RegisterErrorCode } from '../hooks/RegisterErrorCode';\nimport type { RegisterPasswordPolicy, RegisterSubmitValues } from '../hooks/registerTypes';\nimport type { AuthTheme } from '../theme/AuthTheme';\n\nexport interface RegisterFormProps<TResult> {\n /** Send the registration (build the request, call the BFF). Throw on failure. */\n onSubmit: (values: RegisterSubmitValues) => Promise<TResult>;\n /** Called with whatever `onSubmit` resolved to. */\n onSuccess: (result: TResult) => void;\n /** Called with the failure code; map it to localised copy. */\n onError?: (error: RegisterErrorCode) => void;\n /** Called once per accepted submit, before validation (e.g. a \"signup started\" event); never for a press ignored in flight. */\n onSubmitAttempt?: () => void;\n /** Password rule. Defaults to `isRegisterPasswordStrong`. */\n passwordPolicy?: RegisterPasswordPolicy;\n /** Localised copy. Partial: unspecified top-level keys fall back to English defaults. */\n labels?: Partial<RegisterFormLabels>;\n /** Explicit theme; overrides any `<AuthThemeProvider>`. */\n theme?: AuthTheme;\n /** Rendered under the submit button (e.g. \"Already have an account?\"). */\n footer?: ReactNode;\n /** Prefix applied to every `testID`. */\n testIdPrefix?: string;\n}\n\n/** Themeable registration form built on `useRegisterForm`. */\nexport function RegisterForm<TResult>({\n onSubmit,\n onSuccess,\n onError,\n onSubmitAttempt,\n passwordPolicy,\n labels: labelsProp,\n theme: themeProp,\n footer,\n testIdPrefix,\n}: Readonly<RegisterFormProps<TResult>>): ReactElement {\n const theme = useAuthTheme(themeProp);\n const styles = useAuthStyles(theme);\n const labels = useMemo<RegisterFormLabels>(\n () => ({ ...DEFAULT_REGISTER_LABELS, ...labelsProp }),\n [labelsProp],\n );\n const { state, setField, submit, isSubmitting } = useRegisterForm<TResult>({\n onSubmit,\n onSubmitAttempt,\n passwordPolicy,\n });\n\n // The shared Button owns keyboard parity: a held Enter is one press, not one per key-repeat.\n const handlePress = useCallback(async (): Promise<void> => {\n routeRegisterOutcome(await submit(), { onSuccess, onError });\n }, [onError, onSuccess, submit]);\n const handleSubmitEditing = useSubmitOnEnter(handlePress);\n\n return (\n <View style={styles.screen}>\n <View style={styles.card} testID={withTestIdPrefix(RegisterTestIds.form, testIdPrefix)}>\n <Text style={styles.title}>{labels.title}</Text>\n <Text style={styles.subtitle}>{labels.subtitle}</Text>\n\n <RegisterFormFields\n disabled={isSubmitting}\n labels={labels}\n styles={styles}\n testIdPrefix={testIdPrefix}\n theme={theme}\n values={state}\n onChange={setField}\n onSubmitEditing={handleSubmitEditing}\n />\n\n <View style={styles.fieldGroup}>\n <Button\n fullWidth\n accessibilityHint={labels.submitHint}\n accessibilityLabel={isSubmitting ? labels.submitting : labels.submit}\n label={labels.submit}\n loading={isSubmitting}\n testID={withTestIdPrefix(RegisterTestIds.submitButton, testIdPrefix)}\n onPress={handlePress}\n />\n </View>\n\n {footer}\n </View>\n </View>\n );\n}\n","/**\n * `createBffAuthClient` — the one-line wiring of a same-origin `BffAuthClient`.\n *\n * `BffAuthClient` (from `@dloizides/auth-client`) needs an `HttpClient`. Every\n * app wired it the same way — `createFetchHttpClient(fetch)` — and every app\n * hit the same trap: binding `fetch` at module load throws in a non-browser\n * runtime (the Jest/jsdom test environment has no `fetch` global). The lesson\n * of Phase 1 was \"copy-pasted auth adapters ship the same bug N times\", so the\n * correct wiring lives here once.\n *\n * `fetch` is resolved **lazily, per request** — module load stays\n * side-effect-free. `baseUrl` is omitted by default → same-origin: every\n * `/bff/*` call goes to the SPA's own host, which is fronted by the per-app\n * BFF (`bff-katalogos`, `bff-erevna`, ...).\n *\n * Extracted + generalised from `apps/katalogos-web/src/auth/bffAuthClient.ts`.\n */\nimport {\n BffAuthClient,\n createFetchHttpClient,\n type HttpClient,\n type HttpRequest,\n type HttpResponse,\n} from '@dloizides/auth-client';\n\nexport interface CreateBffAuthClientOptions {\n /**\n * BFF origin. Omit (the production default) for same-origin — the SPA's own\n * host is the BFF. An explicit origin is only useful for a non-same-origin\n * BFF or for tests.\n */\n baseUrl?: string;\n /**\n * Override the HTTP transport. Defaults to a lazily-resolved native `fetch`.\n * Tests pass a fake `HttpClient` here; production never needs to.\n */\n http?: HttpClient;\n}\n\n/**\n * Resolve the platform `fetch` lazily, per request.\n *\n * Resolving inside the request — never at module load — keeps importing this\n * module side-effect-free, so a test runtime without a `fetch` global does not\n * blow up the moment any file transitively imports `@dloizides/auth-web`.\n */\nasync function lazyFetchHttpClient(request: HttpRequest): Promise<HttpResponse> {\n const fetchImpl: typeof fetch | undefined =\n typeof fetch === 'function' ? fetch.bind(globalThis) : undefined;\n if (fetchImpl === undefined) {\n throw new Error('createBffAuthClient: fetch is not available in this environment');\n }\n return createFetchHttpClient(fetchImpl)(request);\n}\n\n/**\n * Build a same-origin `BffAuthClient`. With no arguments this is the exact\n * production wiring: same-origin, lazy `fetch`, no token handling.\n */\nexport function createBffAuthClient(options: CreateBffAuthClientOptions = {}): BffAuthClient {\n return new BffAuthClient({\n http: options.http ?? lazyFetchHttpClient,\n baseUrl: options.baseUrl,\n });\n}\n","/**\n * `resolvePostLoginRoute` — the role-based post-login router helper.\n *\n * The unified-auth plan's secondary goal is to kill the \"too many login links\"\n * problem (KUCY V2 has seven, one per role). One login surface; after a\n * successful login the app reads the user's role from the token claims and\n * routes to the right dashboard.\n *\n * This helper is intentionally pure and app-agnostic. The package does NOT\n * know any app's routes — the consuming app supplies a `RoleRouteTable`\n * mapping role → path. The helper picks the highest-priority matching role.\n *\n * Role priority: a user can hold several roles (`superUser` + `admin` + ...).\n * The table is consulted in the order its entries are listed — the FIRST\n * entry whose role the user holds wins. So an app lists the most privileged\n * role first. A `fallback` covers a user whose roles match no entry.\n */\nimport type { BffUser } from '@dloizides/auth-client';\n\n/** One role → route mapping. */\nexport interface RoleRoute {\n /** The Keycloak role name to match against the user's claims. */\n role: string;\n /** The route/path to send a user holding that role to. */\n route: string;\n /**\n * Optional translation key for a human label of this route — consumed by the\n * multi-role dashboard nav (`resolveAccessibleRoutes`) so an app can render a\n * localized link per accessible dashboard. Ignored by `resolvePostLoginRoute`\n * (landing only cares about the path). The package stays i18n-agnostic: it\n * carries the key, the app resolves it.\n */\n labelKey?: string;\n}\n\n/** An app-supplied, ordered role-routing table. */\nexport interface RoleRouteTable {\n /**\n * Ordered list of role → route entries. Order is priority: the first entry\n * whose `role` the user holds is chosen. List the most privileged role first.\n */\n routes: RoleRoute[];\n /**\n * Route used when the user holds none of the listed roles. When omitted and\n * nothing matches, `resolvePostLoginRoute` returns `null` and the caller\n * decides what to do (e.g. show an \"no access\" screen).\n */\n fallback?: string;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null;\n}\n\n/** Read a string array of roles from a `realm_access`-shaped value. */\nfunction readRealmAccessRoles(realmAccess: unknown): string[] {\n if (!isRecord(realmAccess)) {\n return [];\n }\n const roles = realmAccess.roles;\n if (!Array.isArray(roles)) {\n return [];\n }\n return roles.filter((role): role is string => typeof role === 'string');\n}\n\n/**\n * Collect every role on a `BffUser` — both the flat `roles` array and the\n * nested `realm_access.roles` — into a de-duplicated set. The BFF may surface\n * roles in either shape; this normalises both.\n */\nexport function collectUserRoles(user: BffUser): string[] {\n const flat = Array.isArray(user.roles)\n ? user.roles.filter((role): role is string => typeof role === 'string')\n : [];\n const realm = readRealmAccessRoles(user.realm_access);\n return Array.from(new Set([...flat, ...realm]));\n}\n\n/**\n * Resolve the post-login route for a user against an app-supplied table.\n *\n * Returns the route of the first table entry whose role the user holds; if no\n * entry matches, returns the table's `fallback`, or `null` when there is none.\n */\nexport function resolvePostLoginRoute(user: BffUser, table: RoleRouteTable): string | null {\n const userRoles = new Set(collectUserRoles(user));\n for (const entry of table.routes) {\n if (userRoles.has(entry.role)) {\n return entry.route;\n }\n }\n return table.fallback ?? null;\n}\n","/**\n * `resolveAccessibleRoutes` — the multi-role companion to\n * `resolvePostLoginRoute`.\n *\n * Where `resolvePostLoginRoute` answers \"where does this user LAND after login\"\n * (the single highest-priority route), this answers \"which dashboards can this\n * user REACH\" — the full, ordered set of role→route entries the user's role-set\n * unlocks. An app renders that set as a cross-dashboard nav so a user holding\n * several roles (e.g. a tenant owner who also organizes) can move between every\n * surface their roles grant, instead of being trapped on the one they landed on.\n *\n * Pure and app-agnostic, exactly like `resolvePostLoginRoute`: it reuses the\n * same `collectUserRoles` reader (flat `roles` + nested `realm_access.roles`)\n * and the same app-supplied `RoleRouteTable`. Table order is preserved, so the\n * nav lists the most privileged dashboard first. The table `fallback` is NOT\n * included — a fallback is a landing safety net, not a dashboard the user's\n * roles unlock. A user who holds none of the listed roles gets an empty list.\n */\nimport { collectUserRoles } from './resolvePostLoginRoute';\n\nimport type { RoleRoute, RoleRouteTable } from './resolvePostLoginRoute';\nimport type { BffUser } from '@dloizides/auth-client';\n\n/**\n * Resolve every route in `table` whose role the user holds, in table\n * (priority) order.\n *\n * @returns the matching `RoleRoute` entries (each carrying its optional\n * `labelKey`), or an empty array when the user holds none of the roles.\n */\nexport function resolveAccessibleRoutes(user: BffUser, table: RoleRouteTable): RoleRoute[] {\n const userRoles = new Set(collectUserRoles(user));\n return table.routes.filter((entry) => userRoles.has(entry.role));\n}\n","/**\n * `performBffLogout` — the shared logout sequencer.\n *\n * Every app hand-rolled its own logout ordering inside its `AuthProvider`, and\n * the orderings disagreed. Two of them (zygos-web, agora-web) navigated FIRST\n * and called the BFF second:\n *\n * ```ts\n * redirectTo('/(auth)/login'); // window.location.replace() → document unload\n * await bffAuthClient.logout(); // races the unload — may never be sent\n * ```\n *\n * That is wrong twice over:\n *\n * 1. **The BFF call can be cancelled.** A document navigation kills in-flight\n * fetches, so `POST /bff/logout` may never reach the server: the SPA looks\n * logged out while the httpOnly session cookie stays ALIVE. The `catch`\n * logged it \"non-fatal\", so the defect was silent.\n * 2. **The IdP session survives.** `BffAuthClient.logout()` ends the *identity\n * provider's* browser session by doing a top-level navigation to the IdP's\n * RP-initiated logout URL (only a real navigation carries the IdP's own\n * cookie — a back-channel POST cannot clear it). An app that navigates to\n * its own login route first pre-empts that navigation, so the IdP still\n * considers the user signed in and the next authorize round-trip silently\n * re-authenticates them. That is the \"sign-out that signs you back in\" bug\n * the client's own docs warn about.\n *\n * This helper owns the whole sequence so neither can be reintroduced per-app:\n *\n * 1. `onClearSession()` — drop local state immediately so the UI reflects the\n * sign-out right away (perceived performance; no spinner needed).\n * 2. `await client.logout({ redirect: false })` — let the network call SETTLE,\n * and take the IdP logout URL rather than letting the client navigate mid-\n * sequence. Errors are captured, never rethrown.\n * 3. Navigate LAST, exactly once, when nothing is in flight to cancel:\n * - an IdP logout URL → a top-level navigation to the IdP, which ends that\n * session and bounces the user back. `onRedirect` is deliberately NOT\n * called: two competing navigations would race, and the IdP round-trip\n * already returns the user to the app.\n * - otherwise (ROPC / OTP / device-PIN logins never had an IdP cookie, so\n * the URL is `null`) → `onRedirect()`, the app's own login route.\n *\n * Step 3 runs even when step 2 rejects: a BFF that is down must not trap the\n * user on a page they asked to leave. The local session is already gone, so the\n * client-side sign-out holds regardless.\n *\n * Headless and framework-free: it takes callbacks, so an app can pair it with\n * Redux, a context, expo-router, or `window.location` without this package\n * knowing about any of them.\n */\n\n/**\n * The only part of a `BffAuthClient` this helper needs. Structural, so it is\n * trivially fakeable in tests and does not couple to the full client surface.\n */\nexport interface BffLogoutClient {\n /**\n * `POST /bff/logout` — ends the server-side session. With `redirect: false`\n * it returns the IdP's RP-initiated logout URL (or `null` when the session\n * never involved an IdP browser cookie) instead of navigating there itself.\n */\n logout: (options?: { redirect?: boolean }) => Promise<string | null>;\n}\n\n/** Callbacks + client for {@link performBffLogout}. */\nexport interface PerformBffLogoutOptions {\n /** The BFF auth client whose `logout()` ends the server-side session. */\n client: BffLogoutClient;\n /** Drop local session state. Runs BEFORE the network call. Optional. */\n onClearSession?: () => void;\n /**\n * Navigate to the app's logged-out route. Runs only AFTER the network call\n * settles, and only when there is no IdP logout URL to honour. Optional.\n */\n onRedirect?: () => void;\n /** Observe a failed logout step (e.g. to log it). Never rethrown. Optional. */\n onError?: (error: Error) => void;\n /**\n * Test seam: perform the top-level navigation to the IdP logout URL. Defaults\n * to `window.location.assign`. Must be a real navigation — a `fetch` here\n * would not carry the IdP cookie and would silently fail to end the session.\n */\n navigateToIdp?: (url: string) => void;\n}\n\n/** Coerce an unknown thrown value into an `Error`. */\nfunction toError(caught: unknown): Error {\n return caught instanceof Error ? caught : new Error(String(caught));\n}\n\n/** Run a caller callback without letting it break the logout sequence. */\nfunction runGuarded(callback: (() => void) | undefined, onError?: (error: Error) => void): void {\n if (callback === undefined) {\n return;\n }\n try {\n callback();\n } catch (caught) {\n onError?.(toError(caught));\n }\n}\n\n/** Default top-level navigation to the IdP logout URL; SSR-safe. */\nfunction assignLocation(url: string): void {\n if (typeof window === 'undefined') {\n return;\n }\n window.location.assign(url);\n}\n\n/**\n * End the session: clear locally, await the BFF, then navigate exactly once.\n *\n * Never rejects — callers may `void` it safely.\n */\nexport async function performBffLogout(options: Readonly<PerformBffLogoutOptions>): Promise<void> {\n const { client, onClearSession, onRedirect, onError, navigateToIdp = assignLocation } = options;\n\n // 1. Local state first: the UI reflects the sign-out immediately.\n runGuarded(onClearSession, onError);\n\n // 2. Let the server-side logout SETTLE before anything can cancel it. Take\n // the IdP URL instead of letting the client navigate mid-sequence.\n let idpLogoutUrl: string | null = null;\n try {\n idpLogoutUrl = await client.logout({ redirect: false });\n } catch (caught) {\n onError?.(toError(caught));\n }\n\n // 3. Navigate last, exactly once — and always, even if step 2 failed.\n // Honouring the IdP URL is not optional: dropping it leaves the IdP\n // session alive and the next authorize call signs the user straight back in.\n if (idpLogoutUrl !== null) {\n const url = idpLogoutUrl;\n runGuarded(() => navigateToIdp(url), onError);\n return;\n }\n\n runGuarded(onRedirect, onError);\n}\n","/**\n * The client capability the authenticated change-password form depends on, plus\n * a ready-made same-origin BFF implementation.\n *\n * As with the device-PIN surfaces, the UI depends on a **structural** shape\n * ({@link ChangePasswordCapableClient}) — exactly one method — so a consuming app\n * may pass the ready-made client below or a thin hand-rolled object. The ready\n * client POSTs to the same-origin BFF and maps the response to a\n * {@link ChangePasswordResult}; it never rejects for an expected outcome.\n *\n * SECURITY: the password values live only in the request the end user's OWN\n * browser sends to their OWN app's BFF over the session cookie. This package\n * neither stores, logs, nor inspects them — it forwards `currentPassword` /\n * `newPassword` to the BFF and reads back only a status code.\n */\nimport {\n createFetchHttpClient,\n type HttpClient,\n type HttpRequest,\n type HttpResponse,\n} from '@dloizides/auth-client';\n\nimport type { ChangePasswordResult } from './ChangePasswordResult';\n\n/** The request body posted to `POST /bff/account/change-password`. */\nexport interface ChangePasswordRequest {\n currentPassword: string;\n newPassword: string;\n}\n\n/** The single-method capability the change-password form needs. */\nexport interface ChangePasswordCapableClient {\n /** Change the signed-in user's password. Resolves a result; never rejects on an expected outcome. */\n changePassword(request: ChangePasswordRequest): Promise<ChangePasswordResult>;\n}\n\n/** Options for {@link createBffChangePasswordClient}. */\nexport interface CreateBffChangePasswordClientOptions {\n /**\n * BFF origin. Omit (the production default) for same-origin — the SPA's own\n * host is the BFF. An explicit origin is useful only for a non-same-origin BFF\n * or for tests.\n */\n baseUrl?: string;\n /**\n * Override the HTTP transport. Defaults to a lazily-resolved native `fetch`\n * (module load stays side-effect-free, so a `fetch`-less test runtime does not\n * blow up on import). Tests pass a fake `HttpClient`.\n */\n http?: HttpClient;\n}\n\n/** The BFF endpoint the ready client posts to. */\nexport const CHANGE_PASSWORD_ENDPOINT = '/bff/account/change-password';\n\n/** BFF double-submit marker header — mirrors `@dloizides/auth-client`'s `BffAuthClient`. */\nconst CSRF_HEADER = 'X-BFF-Csrf';\nconst CSRF_HEADER_VALUE = '1';\nconst JSON_CONTENT_TYPE = 'application/json';\n\nconst HTTP_NO_CONTENT = 204;\nconst HTTP_OK = 200;\nconst HTTP_BAD_REQUEST = 400;\nconst HTTP_UNAUTHORIZED = 401;\n\n/** Lazy same-origin `fetch` transport — resolved per request, never at module load. */\nasync function lazyFetchHttpClient(request: HttpRequest): Promise<HttpResponse> {\n const fetchImpl: typeof fetch | undefined =\n typeof fetch === 'function' ? fetch.bind(globalThis) : undefined;\n if (fetchImpl === undefined) {\n throw new Error('createBffChangePasswordClient: fetch is not available in this environment');\n }\n return createFetchHttpClient(fetchImpl)(request);\n}\n\n/** Map a BFF status code to the discriminated result the form routes on. */\nfunction resultFromStatus(status: number): ChangePasswordResult {\n if (status === HTTP_NO_CONTENT || status === HTTP_OK) {\n return { status: 'success' };\n }\n if (status === HTTP_BAD_REQUEST) {\n return { status: 'invalidCurrent' };\n }\n if (status === HTTP_UNAUTHORIZED) {\n return { status: 'unauthorized' };\n }\n return { status: 'error' };\n}\n\n/**\n * Build a same-origin change-password client. With no arguments this is the exact\n * production wiring: same-origin, lazy `fetch`, session-cookie auth, the BFF CSRF\n * marker header attached. A thrown transport error resolves to `{ status: 'error' }`\n * so the caller never has to catch.\n */\nexport function createBffChangePasswordClient(\n options: CreateBffChangePasswordClientOptions = {},\n): ChangePasswordCapableClient {\n const http = options.http ?? lazyFetchHttpClient;\n const baseUrl = options.baseUrl ?? '';\n const url = `${baseUrl}${CHANGE_PASSWORD_ENDPOINT}`;\n\n return {\n changePassword: async (request: ChangePasswordRequest): Promise<ChangePasswordResult> => {\n try {\n const response = await http({\n url,\n method: 'POST',\n headers: { 'Content-Type': JSON_CONTENT_TYPE, [CSRF_HEADER]: CSRF_HEADER_VALUE },\n body: JSON.stringify({\n currentPassword: request.currentPassword,\n newPassword: request.newPassword,\n }),\n });\n return resultFromStatus(response.status);\n } catch {\n return { status: 'error' };\n }\n },\n };\n}\n"]}