@wix/himalaya-cli 0.1397.0 → 0.1399.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/serve-runtime/src/wix-bridge.d.ts +30 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/ts/src/icon-catalog.generated.d.ts +1 -1
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/ts/src/schema.d.ts +2 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/ts/src/validation.d.ts +1 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/flows/auth/src/copy.generated.d.ts +109 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/flows/auth/src/feedback.d.ts +15 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/flows/auth/src/index.d.ts +3 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/flows/screens/src/index.d.ts +44 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/auth.mjs +304 -18
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/core/validation.mjs +1 -1
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/core.mjs +72 -1
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/screens.mjs +377 -20
- package/dist/cli.mjs +983 -342
- package/dist/preview-assets.generated.bin +0 -0
- package/guides/component-reference.json +1 -1
- package/guides/component-reference.md +2 -0
- package/guides/headless-loop.md +1 -1
- package/guides/importable-sdks.md +2 -1
- package/guides/one-app-to-himi-app.md +30 -0
- package/guides/one-app-viewer.md +8 -1
- package/guides/sdk-reference.json +92 -1
- package/package.json +2 -2
- package/templates/beauty-salon/dev/index.ts +41 -1
- package/templates/beauty-salon/tier5-src/himi-store-account/index.ts +90 -76
- package/templates/beauty-salon-owner/dev/index.ts +304 -7
- package/templates/beauty-salon-owner/tier5-src/_shared/aria-chat.ts +39 -33
- package/templates/beauty-salon-owner/tier5-src/_shared/aria-widget-model.ts +26 -4
- package/templates/beauty-salon-owner/tier5-src/_shared/aria-widget-view.ts +63 -16
- package/templates/branded-lite/dev/index.ts +41 -1
- package/templates/branded-lite/tier5-src/himi-store-account/index.ts +90 -76
- package/templates/community-club/dev/index.ts +41 -1
- package/templates/community-club/tier5-src/himi-store-account/index.ts +90 -76
- package/templates/community-club-owner/dev/index.ts +304 -7
- package/templates/community-club-owner/tier5-src/_shared/aria-chat.ts +39 -33
- package/templates/community-club-owner/tier5-src/_shared/aria-widget-model.ts +26 -4
- package/templates/community-club-owner/tier5-src/_shared/aria-widget-view.ts +63 -16
- package/templates/events-meetups/dev/index.ts +41 -1
- package/templates/events-meetups/tier5-src/himi-store-account/index.ts +90 -76
- package/templates/events-meetups-owner/dev/index.ts +304 -7
- package/templates/events-meetups-owner/tier5-src/_shared/aria-chat.ts +39 -33
- package/templates/events-meetups-owner/tier5-src/_shared/aria-widget-model.ts +26 -4
- package/templates/events-meetups-owner/tier5-src/_shared/aria-widget-view.ts +63 -16
- package/templates/gym-fitness/dev/index.ts +41 -1
- package/templates/gym-fitness/tier5-src/himi-store-account/index.ts +90 -76
- package/templates/gym-fitness-owner/dev/index.ts +304 -7
- package/templates/gym-fitness-owner/tier5-src/_shared/aria-chat.ts +39 -33
- package/templates/gym-fitness-owner/tier5-src/_shared/aria-widget-model.ts +26 -4
- package/templates/gym-fitness-owner/tier5-src/_shared/aria-widget-view.ts +63 -16
- package/templates/nonprofit-cause/dev/index.ts +41 -1
- package/templates/nonprofit-cause/tier5-src/himi-store-account/index.ts +90 -76
- package/templates/nonprofit-cause-owner/dev/index.ts +304 -7
- package/templates/nonprofit-cause-owner/tier5-src/_shared/aria-chat.ts +39 -33
- package/templates/nonprofit-cause-owner/tier5-src/_shared/aria-widget-model.ts +26 -4
- package/templates/nonprofit-cause-owner/tier5-src/_shared/aria-widget-view.ts +63 -16
- package/templates/owner-lite/dev/index.ts +304 -7
- package/templates/owner-lite/tier5-src/_shared/aria-chat.ts +39 -33
- package/templates/owner-lite/tier5-src/_shared/aria-widget-model.ts +26 -4
- package/templates/owner-lite/tier5-src/_shared/aria-widget-view.ts +63 -16
- package/templates/podcast-creator/dev/index.ts +41 -1
- package/templates/podcast-creator/tier5-src/himi-store-account/index.ts +90 -76
- package/templates/podcast-creator-owner/dev/index.ts +304 -7
- package/templates/podcast-creator-owner/tier5-src/_shared/aria-chat.ts +39 -33
- package/templates/podcast-creator-owner/tier5-src/_shared/aria-widget-model.ts +26 -4
- package/templates/podcast-creator-owner/tier5-src/_shared/aria-widget-view.ts +63 -16
- package/templates/portfolio-creative/dev/index.ts +41 -1
- package/templates/portfolio-creative/tier5-src/himi-store-account/index.ts +90 -76
- package/templates/portfolio-creative-owner/dev/index.ts +304 -7
- package/templates/portfolio-creative-owner/tier5-src/_shared/aria-chat.ts +39 -33
- package/templates/portfolio-creative-owner/tier5-src/_shared/aria-widget-model.ts +26 -4
- package/templates/portfolio-creative-owner/tier5-src/_shared/aria-widget-view.ts +63 -16
- package/templates/restaurant/dev/index.ts +41 -1
- package/templates/restaurant/tier5-src/himi-store-account/index.ts +90 -76
- package/templates/restaurant-owner/dev/index.ts +304 -7
- package/templates/restaurant-owner/tier5-src/_shared/aria-chat.ts +39 -33
- package/templates/restaurant-owner/tier5-src/_shared/aria-widget-model.ts +26 -4
- package/templates/restaurant-owner/tier5-src/_shared/aria-widget-view.ts +63 -16
- package/templates/retail-store/dev/index.ts +41 -1
- package/templates/retail-store/tier5-src/himi-store-account/index.ts +90 -76
- package/templates/retail-store-owner/dev/index.ts +304 -7
- package/templates/retail-store-owner/tier5-src/_shared/aria-chat.ts +39 -33
- package/templates/retail-store-owner/tier5-src/_shared/aria-widget-model.ts +26 -4
- package/templates/retail-store-owner/tier5-src/_shared/aria-widget-view.ts +63 -16
- package/templates/yoga-studio/dev/index.ts +41 -1
- package/templates/yoga-studio/tier5-src/himi-store-account/index.ts +90 -76
- package/templates/yoga-studio-owner/dev/index.ts +304 -7
- package/templates/yoga-studio-owner/tier5-src/_shared/aria-chat.ts +39 -33
- package/templates/yoga-studio-owner/tier5-src/_shared/aria-widget-model.ts +26 -4
- package/templates/yoga-studio-owner/tier5-src/_shared/aria-widget-view.ts +63 -16
|
@@ -259,4 +259,34 @@ export declare function memberInstanceRefusal(e: unknown): {
|
|
|
259
259
|
reason?: string;
|
|
260
260
|
};
|
|
261
261
|
};
|
|
262
|
+
export declare const MEMBER_SESSION_URL = "https://manage.wix.com/_api/users-members/v1/user-member-connections/member-session";
|
|
263
|
+
/** Wix will not issue a member session on this site to this account: it holds no role there (a site it only
|
|
264
|
+
* JOINED refuses it — a plain member needs an IAM-scoped OAuth app). The host opens the page as a visitor. */
|
|
265
|
+
export declare class MemberSessionRefused extends Error {
|
|
266
|
+
readonly metaSiteId: string;
|
|
267
|
+
readonly reason: string;
|
|
268
|
+
readonly code = "MemberSessionRefused";
|
|
269
|
+
constructor(metaSiteId: string, reason: string);
|
|
270
|
+
}
|
|
271
|
+
/** A one-time site-member session token for [metaSiteId], minted from the account [sessionCookie] (already
|
|
272
|
+
* narrowed to `forwardableWixSessionCookies`). Throws `AccountSessionExpired` (a 401 on either step),
|
|
273
|
+
* `MemberSessionRefused` (403/404), or `SiteInstanceUnavailable` (anything transient). Never follows a
|
|
274
|
+
* redirect, never caches. */
|
|
275
|
+
export declare function mintMemberSessionToken(sessionCookie: string, metaSiteId: string, fetchImpl?: typeof fetch, timeoutMs?: number): Promise<string>;
|
|
276
|
+
/** The bridge's answer for a member-session failure, in the `{ error }` shape every bridge refusal has. */
|
|
277
|
+
export declare function memberSessionRefusal(e: unknown): {
|
|
278
|
+
status: number;
|
|
279
|
+
body: {
|
|
280
|
+
error: string;
|
|
281
|
+
};
|
|
282
|
+
};
|
|
283
|
+
/** `https://wix.app/mobile.apps/<shortId>`, or null for anything that is not an id. */
|
|
284
|
+
export declare function inviteShortLinkUrl(shortId: string): string | null;
|
|
285
|
+
/** A URL a short link's redirects name the invite in: `https://wix.app/invite/<site>/<invite>` or a wix.com
|
|
286
|
+
* `…/place-invites/invite-lp/<invite>` page (native `SpacesLinks.isInviteLanding`). */
|
|
287
|
+
export declare function isInviteLanding(url: URL): boolean;
|
|
288
|
+
export declare const INVITE_MAX_HOPS = 8;
|
|
289
|
+
/** Follow [shortId]'s short link to its invite landing; null when it lands nowhere an invite is named. No
|
|
290
|
+
* cookies, no credentials; each hop bounded by [timeoutMs]. */
|
|
291
|
+
export declare function resolveInviteShortLink(shortId: string, fetchImpl?: typeof fetch, timeoutMs?: number): Promise<string | null>;
|
|
262
292
|
export {};
|
|
@@ -28,7 +28,7 @@ export declare const ICON_CATALOG: Readonly<Record<string, IconCatalogEntry>>;
|
|
|
28
28
|
/** normalized (lowercased, separators stripped) → canonical key, aliases included. */
|
|
29
29
|
export declare const ICON_NORMALIZED_INDEX: Readonly<Record<string, string>>;
|
|
30
30
|
/** Every authorable name, aliases included. `_unknown` is deliberately absent. */
|
|
31
|
-
export declare const ICON_NAMES: readonly ["ai", "arrow_down", "arrow_left", "arrow_right", "arrow_up", "back", "bag", "bag_fill", "barcode", "bell", "bell_fill", "bell_off", "bell_slash", "book", "bookmark", "bookmark_fill", "boxes", "branch", "calendar", "camera", "cart", "cart_fill", "chart", "chat", "check", "checklist", "checkmark", "chevron_down", "chevron_left", "chevron_right", "chevron_up", "circle", "circle_fill", "clock", "close", "cookie", "copy", "dashboard", "doc", "document", "download", "edit", "ellipsis", "error", "expand", "external_link", "filter", "folder", "forward", "fullscreen", "gear", "globe", "grid", "grid_fill", "grip", "heart", "heart_fill", "help", "home", "home_fill", "house", "image", "inbox", "info", "layers", "link", "list", "location", "lock", "logout", "mail", "map", "menu", "message", "mic", "mic_fill", "microphone", "microphone_fill", "minus", "moon", "more", "more_vertical", "music", "newspaper", "newspaper_fill", "next", "pause", "pencil", "people", "person", "person_fill", "phone", "photo", "pin", "play", "play_circle", "play_circle_fill", "plus", "plus_circle", "plus_circle_fill", "prev", "question", "refresh", "repeat", "rss", "search", "send", "send_arrow", "settings", "settings_fill", "share", "shuffle", "skip_back", "skip_forward", "skip_next", "skip_previous", "star", "star_fill", "stop", "success", "tag", "ticket", "ticket_fill", "trash", "tray", "undo", "user", "visible", "volume", "warning", "wifi", "xmark"];
|
|
31
|
+
export declare const ICON_NAMES: readonly ["ai", "arrow_down", "arrow_left", "arrow_right", "arrow_up", "back", "bag", "bag_fill", "barcode", "bell", "bell_fill", "bell_off", "bell_slash", "book", "bookmark", "bookmark_fill", "boxes", "branch", "calendar", "camera", "cart", "cart_fill", "chart", "chat", "check", "checklist", "checkmark", "chevron_down", "chevron_left", "chevron_right", "chevron_up", "circle", "circle_fill", "clock", "close", "concealed", "cookie", "copy", "dashboard", "doc", "document", "download", "edit", "ellipsis", "error", "expand", "external_link", "eye", "eye_slash", "filter", "folder", "forward", "fullscreen", "gear", "gift", "globe", "grid", "grid_fill", "grip", "heart", "heart_fill", "help", "home", "home_fill", "house", "image", "inbox", "info", "layers", "link", "list", "location", "lock", "logout", "mail", "map", "menu", "message", "mic", "mic_fill", "microphone", "microphone_fill", "minus", "moon", "more", "more_vertical", "music", "newspaper", "newspaper_fill", "next", "paper_plane", "pause", "pencil", "people", "person", "person_fill", "phone", "photo", "pin", "play", "play_circle", "play_circle_fill", "plus", "plus_circle", "plus_circle_fill", "prev", "question", "refresh", "repeat", "rss", "search", "send", "send_arrow", "settings", "settings_fill", "share", "shuffle", "skip_back", "skip_forward", "skip_next", "skip_previous", "star", "star_fill", "stop", "success", "tag", "ticket", "ticket_fill", "trash", "tray", "undo", "user", "visible", "volume", "warning", "wifi", "xmark"];
|
|
32
32
|
export type IconName = (typeof ICON_NAMES)[number];
|
|
33
33
|
/** Resolve any authored string to a row, falling back to `_unknown`. Never returns undefined. */
|
|
34
34
|
export declare function resolveIcon(name: string): IconCatalogEntry;
|
package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/ts/src/schema.d.ts
CHANGED
|
@@ -805,6 +805,8 @@ export interface TextFieldProps {
|
|
|
805
805
|
/** LITERAL error string for a server-rendered screen with no worker to bind.
|
|
806
806
|
* Lower precedence than `errorPath`, higher than the rules. */
|
|
807
807
|
errorText?: string;
|
|
808
|
+
/** Opt-in accessible show/hide button. Only applies to secure fields; initially masked. */
|
|
809
|
+
visibilityToggle?: boolean;
|
|
808
810
|
}
|
|
809
811
|
export interface ToggleProps {
|
|
810
812
|
label?: string;
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
declare const _default: {
|
|
2
|
+
readonly "auth.gate.title": "Welcome";
|
|
3
|
+
readonly "auth.gate.subtitle": "Sign in to continue";
|
|
4
|
+
readonly "auth.gate.signIn": "Sign In";
|
|
5
|
+
readonly "auth.gate.createAccount": "Create account";
|
|
6
|
+
readonly "auth.gate.resetPassword": "Reset password";
|
|
7
|
+
readonly "auth.gate.verifyTitle": "Verify it's you";
|
|
8
|
+
readonly "auth.gate.sendResetLink": "Send reset link";
|
|
9
|
+
readonly "auth.gate.verify": "Verify";
|
|
10
|
+
readonly "auth.gate.continue": "Continue";
|
|
11
|
+
readonly "auth.gate.forgotPassword": "Forgot password?";
|
|
12
|
+
readonly "auth.gate.backToSignIn": "Back to sign in";
|
|
13
|
+
readonly "auth.gate.continueWith": "Continue with {provider}";
|
|
14
|
+
readonly "auth.gate.sendCodeVia": "Send code via";
|
|
15
|
+
readonly "auth.gate.resendCode": "Didn't get it? Resend code";
|
|
16
|
+
readonly "auth.gate.field.code": "Verification code";
|
|
17
|
+
readonly "auth.gate.field.email": "Email";
|
|
18
|
+
readonly "auth.gate.field.name": "Name";
|
|
19
|
+
readonly "auth.gate.field.password": "Password";
|
|
20
|
+
readonly "auth.gate.field.captcha": "reCAPTCHA token (account only)";
|
|
21
|
+
readonly "auth.gate.password.show": "Show password";
|
|
22
|
+
readonly "auth.gate.password.hide": "Hide password";
|
|
23
|
+
readonly "auth.gate.notice.codeResent": "A new code was sent.";
|
|
24
|
+
readonly "auth.gate.notice.codeSentVia": "Code sent via {method}.";
|
|
25
|
+
readonly "auth.gate.notice.resetSent": "If that email is registered, a reset link is on its way.";
|
|
26
|
+
readonly "auth.biometric.unlockWith": "Unlock with {method}";
|
|
27
|
+
readonly "auth.biometric.orPassword": "or sign in with your password";
|
|
28
|
+
readonly "auth.biometric.label.faceId": "Face ID";
|
|
29
|
+
readonly "auth.biometric.label.touchId": "Touch ID";
|
|
30
|
+
readonly "auth.biometric.label.faceUnlock": "Face Unlock";
|
|
31
|
+
readonly "auth.biometric.label.fingerprint": "Fingerprint";
|
|
32
|
+
readonly "auth.biometric.label.generic": "biometrics";
|
|
33
|
+
readonly "auth.biometric.prompt.usePassword": "Use password";
|
|
34
|
+
readonly "auth.biometric.error.unavailable": "Biometric unlock isn't available on this device.";
|
|
35
|
+
readonly "auth.biometric.error.cancelled": "Biometric unlock was cancelled.";
|
|
36
|
+
readonly "auth.biometric.error.notEnrolled": "No Face ID / Touch ID is enrolled.";
|
|
37
|
+
readonly "auth.biometric.error.failed": "Biometric unlock failed.";
|
|
38
|
+
readonly "auth.biometric.error.invalidated": "Biometrics changed; sign in again.";
|
|
39
|
+
readonly "auth.biometric.prompt.unlock": "Unlock your account";
|
|
40
|
+
readonly "auth.biometric.prompt.disable": "Confirm to turn off biometric unlock";
|
|
41
|
+
readonly "auth.biometric.enrollTitle": "Unlock with {method}?";
|
|
42
|
+
readonly "auth.biometric.enrollMessage": "Use {method} instead of your password the next time you open the app.";
|
|
43
|
+
readonly "auth.biometric.enrollAccept": "Use {method}";
|
|
44
|
+
readonly "auth.biometric.enrollDecline": "Not now";
|
|
45
|
+
readonly "auth.error.invalidCredentials": "Wrong email or password.";
|
|
46
|
+
readonly "auth.error.accountNotFound": "We couldn't find an account for that email.";
|
|
47
|
+
readonly "auth.error.emailInUse": "That email is already registered.";
|
|
48
|
+
readonly "auth.error.verificationRequired": "Additional verification is required.";
|
|
49
|
+
readonly "auth.error.verifyEmail": "Check your email to verify your account, then sign in.";
|
|
50
|
+
readonly "auth.error.incorrectCode": "Incorrect code.";
|
|
51
|
+
readonly "auth.error.network": "Network error.";
|
|
52
|
+
readonly "auth.error.visitorToken": "Could not obtain a visitor token.";
|
|
53
|
+
readonly "auth.error.noSessionToken": "Login succeeded but no session token.";
|
|
54
|
+
readonly "auth.error.authSession": "Could not create an auth session.";
|
|
55
|
+
readonly "auth.error.signInIncomplete": "Sign-in did not complete.";
|
|
56
|
+
readonly "auth.error.tokenExchange": "Token exchange failed.";
|
|
57
|
+
readonly "auth.error.noRedirect": "No auth redirect.";
|
|
58
|
+
readonly "auth.error.registrationFailed": "Registration failed ({code}).";
|
|
59
|
+
readonly "auth.error.twoFactorRequired": "Two-factor verification required.";
|
|
60
|
+
readonly "auth.error.noPendingVerification": "No pending verification.";
|
|
61
|
+
readonly "auth.error.verificationCancelled": "Verification cancelled.";
|
|
62
|
+
readonly "auth.error.biometricSignInFirst": "Sign in before enabling biometric unlock.";
|
|
63
|
+
readonly "auth.error.noSessionToProtect": "No session to protect.";
|
|
64
|
+
readonly "auth.error.biometricEnableFailed": "Couldn't enable biometric unlock.";
|
|
65
|
+
readonly "auth.error.biometricUnlockFailed": "Couldn't unlock. Sign in with your password.";
|
|
66
|
+
readonly "auth.error.biometricsUnavailable": "Biometrics unavailable.";
|
|
67
|
+
readonly "auth.error.noBiometricsEnrolled": "No biometrics enrolled.";
|
|
68
|
+
readonly "auth.error.biometricNotEnabled": "Biometric unlock not enabled.";
|
|
69
|
+
readonly "auth.error.unsupported": "Unsupported.";
|
|
70
|
+
readonly "auth.error.methodUnavailable": "This sign-in method isn't available.";
|
|
71
|
+
readonly "auth.error.verificationRequiredRetry": "Additional verification is required. Please try again.";
|
|
72
|
+
readonly "auth.error.networkRetry": "Network error. Please try again.";
|
|
73
|
+
readonly "auth.error.signInCancelled": "Sign-in was cancelled.";
|
|
74
|
+
readonly "auth.error.genericRetry": "Something went wrong. Please try again.";
|
|
75
|
+
readonly "auth.error.biometricLocked": "Locked: unlock with biometrics first.";
|
|
76
|
+
readonly "auth.error.googleNoPresenter": "No presenter for Google sign-in.";
|
|
77
|
+
readonly "auth.error.googleNoToken": "Google sign-in returned no id_token.";
|
|
78
|
+
readonly "auth.error.appleNoToken": "Apple sign-in returned no token.";
|
|
79
|
+
readonly "auth.error.memberSettingsUnreadable": "Could not read the site's member settings.";
|
|
80
|
+
readonly "auth.error.memberSettingsMalformed": "Member settings response was not a JSON object.";
|
|
81
|
+
readonly "auth.biometric.error.noCipher": "No cipher.";
|
|
82
|
+
readonly "auth.error.unlockOvertaken": "Unlock overtaken by a sign-in or sign-out.";
|
|
83
|
+
readonly "auth.gate.code.show": "Show code";
|
|
84
|
+
readonly "auth.gate.code.hide": "Hide code";
|
|
85
|
+
readonly "auth.feedback.invalid_input": "Check the highlighted fields and try again.";
|
|
86
|
+
readonly "auth.feedback.invalid_credentials": "The email or password is incorrect. Check your details or reset your password.";
|
|
87
|
+
readonly "auth.feedback.registration_failed": "We could not create an account. Check your details, or try signing in or resetting your password.";
|
|
88
|
+
readonly "auth.feedback.invalid_code": "That code is invalid or has expired. Check the code or request a new one.";
|
|
89
|
+
readonly "auth.feedback.expired_code": "That code has expired. Request a new code and try again.";
|
|
90
|
+
readonly "auth.feedback.totp": "That code did not work. Enter the current code from your authenticator app.";
|
|
91
|
+
readonly "auth.feedback.network": "We could not connect. Check your connection and try again.";
|
|
92
|
+
readonly "auth.feedback.rate_limited": "Too many attempts. Wait a few minutes and try again.";
|
|
93
|
+
readonly "auth.feedback.unavailable": "This action is not available here. Use a supported sign-in method or open the app.";
|
|
94
|
+
readonly "auth.feedback.cancelled": "Sign-in was cancelled. Try again when you are ready.";
|
|
95
|
+
readonly "auth.feedback.verification_required": "Complete verification to continue, then try again.";
|
|
96
|
+
readonly "auth.feedback.unknown": "We could not complete this action. Please try again.";
|
|
97
|
+
readonly "auth.validation.emailRequired": "Enter your email address.";
|
|
98
|
+
readonly "auth.validation.emailInvalid": "Enter a valid email address.";
|
|
99
|
+
readonly "auth.validation.passwordMinimum": "Use at least 8 characters for your new password.";
|
|
100
|
+
readonly "auth.validation.passwordRequired": "Enter your password.";
|
|
101
|
+
readonly "auth.validation.codeRequired": "Enter your verification code.";
|
|
102
|
+
readonly "auth.validation.nameRequired": "Enter your name.";
|
|
103
|
+
readonly "auth.feedback.busy": "Please wait…";
|
|
104
|
+
readonly "auth.gate.verify.title": "Verify your email";
|
|
105
|
+
readonly "auth.gate.verify.body": "Enter the confirmation code sent to your email to finish signing in.";
|
|
106
|
+
readonly "auth.gate.cancel": "Cancel";
|
|
107
|
+
readonly "auth.gate.codePlaceholder": "Confirmation code";
|
|
108
|
+
};
|
|
109
|
+
export default _default;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export type AuthFailureCode = "invalid_input" | "invalid_credentials" | "registration_failed" | "invalid_code" | "expired_code" | "network" | "rate_limited" | "unavailable" | "cancelled" | "verification_required" | "unknown";
|
|
2
|
+
export type AuthOperation = "signIn" | "register" | "reset" | "verify";
|
|
3
|
+
export declare function authMessage(key: string, translate?: (key: string) => string | undefined): string;
|
|
4
|
+
/** Only structured failure identities cross into UI copy. Never echo server/error text. */
|
|
5
|
+
export declare function authFailure(raw: unknown, operation?: AuthOperation, translate?: (key: string) => string | undefined): {
|
|
6
|
+
code: AuthFailureCode;
|
|
7
|
+
reason: string;
|
|
8
|
+
};
|
|
9
|
+
/** Shared predicates; credentials are never normalized like an email. */
|
|
10
|
+
export declare function identityErrors(input: {
|
|
11
|
+
email?: string;
|
|
12
|
+
password?: string;
|
|
13
|
+
code?: string;
|
|
14
|
+
name?: string;
|
|
15
|
+
}, operation: AuthOperation, requireName?: boolean): Record<string, string>;
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { type AuthFailureCode } from "./feedback.js";
|
|
2
|
+
export * from "./feedback.js";
|
|
1
3
|
/** Action-id prefix the host registered the Wix auth actions under. Matches
|
|
2
4
|
* `WixConsumerAuthActions.register(actionIdPrefix:)` — default `himi.wix`. */
|
|
3
5
|
export declare const DEFAULT_AUTH_PREFIX = "himi.wix";
|
|
@@ -12,6 +14,7 @@ export type AuthResult = {
|
|
|
12
14
|
} | {
|
|
13
15
|
ok: false;
|
|
14
16
|
reason: string;
|
|
17
|
+
code?: AuthFailureCode;
|
|
15
18
|
};
|
|
16
19
|
/** Who the session belongs to right now. `signedIn` is false for a visitor. */
|
|
17
20
|
export interface AuthState {
|
|
@@ -1,4 +1,48 @@
|
|
|
1
1
|
import { entitlement } from "@wix/himalaya/checkout";
|
|
2
|
+
type Node = Record<string, any>;
|
|
3
|
+
/** An action shown by `detailedHeader`. */
|
|
4
|
+
export interface DetailedHeaderAction {
|
|
5
|
+
label: string;
|
|
6
|
+
action: Node;
|
|
7
|
+
style?: "primary" | "secondary" | "plain";
|
|
8
|
+
}
|
|
9
|
+
/** Options for the shared One App-style detailed header composition. */
|
|
10
|
+
export interface DetailedHeaderOptions {
|
|
11
|
+
/** Prefix for stable SDUI node IDs. Use a unique value for each header. */
|
|
12
|
+
id?: string;
|
|
13
|
+
/** Page nodes that scroll beneath the hero and detail card. */
|
|
14
|
+
content?: Node[];
|
|
15
|
+
/** Cover image selected by the migration from the source cover list. */
|
|
16
|
+
imageUrl?: string;
|
|
17
|
+
title: string;
|
|
18
|
+
subtitle?: string;
|
|
19
|
+
logoUrl?: string;
|
|
20
|
+
locationLabel?: string;
|
|
21
|
+
locationAction?: DetailedHeaderAction;
|
|
22
|
+
memberCaption?: string;
|
|
23
|
+
memberAvatars?: Array<{
|
|
24
|
+
imageUrl?: string;
|
|
25
|
+
initials?: string;
|
|
26
|
+
}>;
|
|
27
|
+
/** Live member rows from a service. This takes precedence over `memberAvatars`. */
|
|
28
|
+
memberAvatarsPath?: string;
|
|
29
|
+
inviteAction?: DetailedHeaderAction;
|
|
30
|
+
primaryAction?: DetailedHeaderAction;
|
|
31
|
+
aboutAction?: DetailedHeaderAction;
|
|
32
|
+
/** Keep the hero at one height when the source header is not collapsible. */
|
|
33
|
+
collapsible?: boolean;
|
|
34
|
+
expandedHeight?: number;
|
|
35
|
+
collapsedHeight?: number;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Build the shared Detailed header used by One App migrations.
|
|
39
|
+
*
|
|
40
|
+
* The header uses Himalaya's cross-platform `CollapsingHeader` and standard
|
|
41
|
+
* components for the detail card, logo, member strip, and actions. A migration
|
|
42
|
+
* calls this builder instead of copying header layout into each app. Himalaya's
|
|
43
|
+
* hero accepts one image, so pass the first source cover image here.
|
|
44
|
+
*/
|
|
45
|
+
export declare function detailedHeader(opts: DetailedHeaderOptions): Node;
|
|
2
46
|
export interface ScreenEnvelope {
|
|
3
47
|
screenId: string;
|
|
4
48
|
renderer: string;
|
|
@@ -1,3 +1,290 @@
|
|
|
1
|
+
// ../../core/ts/src/validation.ts
|
|
2
|
+
var EMAIL_RE = /^[A-Za-z0-9._%+-]+@[A-Za-z0-9-]+(\.[A-Za-z0-9-]+)*\.[A-Za-z]{2,}$/;
|
|
3
|
+
var URL_HOST_RE = /^[A-Za-z0-9-]+(\.[A-Za-z0-9-]+)*(:[0-9]+)?$/;
|
|
4
|
+
var INTEGER_RE = /^[+-]?[0-9]+$/;
|
|
5
|
+
var NUMBER_RE = /^[+-]?([0-9]+(\.[0-9]+)?|\.[0-9]+)$/;
|
|
6
|
+
function isEmail(value) {
|
|
7
|
+
if (!EMAIL_RE.test(value)) return false;
|
|
8
|
+
if (value.includes("..")) return false;
|
|
9
|
+
const local = value.slice(0, value.indexOf("@"));
|
|
10
|
+
return !local.startsWith(".") && !local.endsWith(".");
|
|
11
|
+
}
|
|
12
|
+
function isPhone(value) {
|
|
13
|
+
let s = "";
|
|
14
|
+
for (const ch of value) {
|
|
15
|
+
if (" -().\xA0 ".includes(ch)) continue;
|
|
16
|
+
s += ch;
|
|
17
|
+
}
|
|
18
|
+
if (s.startsWith("+")) s = s.slice(1);
|
|
19
|
+
if (s.length < 7 || s.length > 15) return false;
|
|
20
|
+
for (const ch of s) if (ch < "0" || ch > "9") return false;
|
|
21
|
+
return true;
|
|
22
|
+
}
|
|
23
|
+
function isUrl(value) {
|
|
24
|
+
if (/\s/.test(value)) return false;
|
|
25
|
+
let rest = value;
|
|
26
|
+
const lower = value.toLowerCase();
|
|
27
|
+
if (lower.startsWith("http://")) rest = value.slice(7);
|
|
28
|
+
else if (lower.startsWith("https://")) rest = value.slice(8);
|
|
29
|
+
else if (value.includes("://")) return false;
|
|
30
|
+
if (rest.length === 0) return false;
|
|
31
|
+
let end = rest.length;
|
|
32
|
+
for (let i = 0; i < rest.length; i++) {
|
|
33
|
+
const c = rest[i];
|
|
34
|
+
if (c === "/" || c === "?" || c === "#") {
|
|
35
|
+
end = i;
|
|
36
|
+
break;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
const hostPort = rest.slice(0, end);
|
|
40
|
+
if (!URL_HOST_RE.test(hostPort)) return false;
|
|
41
|
+
const host = hostPort.split(":")[0];
|
|
42
|
+
if (host === "localhost") return true;
|
|
43
|
+
const dot = host.lastIndexOf(".");
|
|
44
|
+
if (dot < 1) return false;
|
|
45
|
+
const tld = host.slice(dot + 1);
|
|
46
|
+
if (tld.length < 2) return false;
|
|
47
|
+
for (const ch of tld) {
|
|
48
|
+
const isAlpha = ch >= "A" && ch <= "Z" || ch >= "a" && ch <= "z";
|
|
49
|
+
if (!isAlpha) return false;
|
|
50
|
+
}
|
|
51
|
+
return true;
|
|
52
|
+
}
|
|
53
|
+
function parseNumeric(value) {
|
|
54
|
+
if (!NUMBER_RE.test(value)) return null;
|
|
55
|
+
const n = Number(value);
|
|
56
|
+
return Number.isFinite(n) ? n : null;
|
|
57
|
+
}
|
|
58
|
+
function matchesType(type, value) {
|
|
59
|
+
switch (type) {
|
|
60
|
+
case "email":
|
|
61
|
+
return isEmail(value);
|
|
62
|
+
case "phone":
|
|
63
|
+
return isPhone(value);
|
|
64
|
+
case "url":
|
|
65
|
+
return isUrl(value);
|
|
66
|
+
case "number":
|
|
67
|
+
return NUMBER_RE.test(value);
|
|
68
|
+
case "integer":
|
|
69
|
+
return INTEGER_RE.test(value);
|
|
70
|
+
// Additive decoding: an unknown type is NOT a failure. A renderer that has
|
|
71
|
+
// not shipped a new type yet must let the value through rather than block a
|
|
72
|
+
// form it cannot understand — the server still re-validates on submit.
|
|
73
|
+
default:
|
|
74
|
+
return true;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
function validate(rule, rawValue) {
|
|
78
|
+
if (!rule) return null;
|
|
79
|
+
const value = rawValue ?? "";
|
|
80
|
+
if (value.length === 0) {
|
|
81
|
+
return rule.required === true ? { rule: "required" } : null;
|
|
82
|
+
}
|
|
83
|
+
if (rule.type && !matchesType(rule.type, value)) {
|
|
84
|
+
return { rule: "type", type: rule.type };
|
|
85
|
+
}
|
|
86
|
+
if (rule.regex) {
|
|
87
|
+
let ok;
|
|
88
|
+
try {
|
|
89
|
+
ok = new RegExp(`^(?:${rule.regex})$`).test(value);
|
|
90
|
+
} catch {
|
|
91
|
+
ok = true;
|
|
92
|
+
}
|
|
93
|
+
if (!ok) return { rule: "regex" };
|
|
94
|
+
}
|
|
95
|
+
if (typeof rule.minLength === "number" && rule.minLength > 0 && value.length < rule.minLength) {
|
|
96
|
+
return { rule: "minLength", limit: rule.minLength };
|
|
97
|
+
}
|
|
98
|
+
if (typeof rule.maxLength === "number" && rule.maxLength > 0 && value.length > rule.maxLength) {
|
|
99
|
+
return { rule: "maxLength", limit: rule.maxLength };
|
|
100
|
+
}
|
|
101
|
+
if (typeof rule.minValue === "number" || typeof rule.maxValue === "number") {
|
|
102
|
+
const n = parseNumeric(value);
|
|
103
|
+
if (n !== null) {
|
|
104
|
+
if (typeof rule.minValue === "number" && n < rule.minValue) {
|
|
105
|
+
return { rule: "minValue", limit: rule.minValue };
|
|
106
|
+
}
|
|
107
|
+
if (typeof rule.maxValue === "number" && n > rule.maxValue) {
|
|
108
|
+
return { rule: "maxValue", limit: rule.maxValue };
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
return null;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// ../../stdlib/flows/auth/src/copy.generated.ts
|
|
116
|
+
var copy_generated_default = {
|
|
117
|
+
"auth.gate.title": "Welcome",
|
|
118
|
+
"auth.gate.subtitle": "Sign in to continue",
|
|
119
|
+
"auth.gate.signIn": "Sign In",
|
|
120
|
+
"auth.gate.createAccount": "Create account",
|
|
121
|
+
"auth.gate.resetPassword": "Reset password",
|
|
122
|
+
"auth.gate.verifyTitle": "Verify it's you",
|
|
123
|
+
"auth.gate.sendResetLink": "Send reset link",
|
|
124
|
+
"auth.gate.verify": "Verify",
|
|
125
|
+
"auth.gate.continue": "Continue",
|
|
126
|
+
"auth.gate.forgotPassword": "Forgot password?",
|
|
127
|
+
"auth.gate.backToSignIn": "Back to sign in",
|
|
128
|
+
"auth.gate.continueWith": "Continue with {provider}",
|
|
129
|
+
"auth.gate.sendCodeVia": "Send code via",
|
|
130
|
+
"auth.gate.resendCode": "Didn't get it? Resend code",
|
|
131
|
+
"auth.gate.field.code": "Verification code",
|
|
132
|
+
"auth.gate.field.email": "Email",
|
|
133
|
+
"auth.gate.field.name": "Name",
|
|
134
|
+
"auth.gate.field.password": "Password",
|
|
135
|
+
"auth.gate.field.captcha": "reCAPTCHA token (account only)",
|
|
136
|
+
"auth.gate.password.show": "Show password",
|
|
137
|
+
"auth.gate.password.hide": "Hide password",
|
|
138
|
+
"auth.gate.notice.codeResent": "A new code was sent.",
|
|
139
|
+
"auth.gate.notice.codeSentVia": "Code sent via {method}.",
|
|
140
|
+
"auth.gate.notice.resetSent": "If that email is registered, a reset link is on its way.",
|
|
141
|
+
"auth.biometric.unlockWith": "Unlock with {method}",
|
|
142
|
+
"auth.biometric.orPassword": "or sign in with your password",
|
|
143
|
+
"auth.biometric.label.faceId": "Face ID",
|
|
144
|
+
"auth.biometric.label.touchId": "Touch ID",
|
|
145
|
+
"auth.biometric.label.faceUnlock": "Face Unlock",
|
|
146
|
+
"auth.biometric.label.fingerprint": "Fingerprint",
|
|
147
|
+
"auth.biometric.label.generic": "biometrics",
|
|
148
|
+
"auth.biometric.prompt.usePassword": "Use password",
|
|
149
|
+
"auth.biometric.error.unavailable": "Biometric unlock isn't available on this device.",
|
|
150
|
+
"auth.biometric.error.cancelled": "Biometric unlock was cancelled.",
|
|
151
|
+
"auth.biometric.error.notEnrolled": "No Face ID / Touch ID is enrolled.",
|
|
152
|
+
"auth.biometric.error.failed": "Biometric unlock failed.",
|
|
153
|
+
"auth.biometric.error.invalidated": "Biometrics changed; sign in again.",
|
|
154
|
+
"auth.biometric.prompt.unlock": "Unlock your account",
|
|
155
|
+
"auth.biometric.prompt.disable": "Confirm to turn off biometric unlock",
|
|
156
|
+
"auth.biometric.enrollTitle": "Unlock with {method}?",
|
|
157
|
+
"auth.biometric.enrollMessage": "Use {method} instead of your password the next time you open the app.",
|
|
158
|
+
"auth.biometric.enrollAccept": "Use {method}",
|
|
159
|
+
"auth.biometric.enrollDecline": "Not now",
|
|
160
|
+
"auth.error.invalidCredentials": "Wrong email or password.",
|
|
161
|
+
"auth.error.accountNotFound": "We couldn't find an account for that email.",
|
|
162
|
+
"auth.error.emailInUse": "That email is already registered.",
|
|
163
|
+
"auth.error.verificationRequired": "Additional verification is required.",
|
|
164
|
+
"auth.error.verifyEmail": "Check your email to verify your account, then sign in.",
|
|
165
|
+
"auth.error.incorrectCode": "Incorrect code.",
|
|
166
|
+
"auth.error.network": "Network error.",
|
|
167
|
+
"auth.error.visitorToken": "Could not obtain a visitor token.",
|
|
168
|
+
"auth.error.noSessionToken": "Login succeeded but no session token.",
|
|
169
|
+
"auth.error.authSession": "Could not create an auth session.",
|
|
170
|
+
"auth.error.signInIncomplete": "Sign-in did not complete.",
|
|
171
|
+
"auth.error.tokenExchange": "Token exchange failed.",
|
|
172
|
+
"auth.error.noRedirect": "No auth redirect.",
|
|
173
|
+
"auth.error.registrationFailed": "Registration failed ({code}).",
|
|
174
|
+
"auth.error.twoFactorRequired": "Two-factor verification required.",
|
|
175
|
+
"auth.error.noPendingVerification": "No pending verification.",
|
|
176
|
+
"auth.error.verificationCancelled": "Verification cancelled.",
|
|
177
|
+
"auth.error.biometricSignInFirst": "Sign in before enabling biometric unlock.",
|
|
178
|
+
"auth.error.noSessionToProtect": "No session to protect.",
|
|
179
|
+
"auth.error.biometricEnableFailed": "Couldn't enable biometric unlock.",
|
|
180
|
+
"auth.error.biometricUnlockFailed": "Couldn't unlock. Sign in with your password.",
|
|
181
|
+
"auth.error.biometricsUnavailable": "Biometrics unavailable.",
|
|
182
|
+
"auth.error.noBiometricsEnrolled": "No biometrics enrolled.",
|
|
183
|
+
"auth.error.biometricNotEnabled": "Biometric unlock not enabled.",
|
|
184
|
+
"auth.error.unsupported": "Unsupported.",
|
|
185
|
+
"auth.error.methodUnavailable": "This sign-in method isn't available.",
|
|
186
|
+
"auth.error.verificationRequiredRetry": "Additional verification is required. Please try again.",
|
|
187
|
+
"auth.error.networkRetry": "Network error. Please try again.",
|
|
188
|
+
"auth.error.signInCancelled": "Sign-in was cancelled.",
|
|
189
|
+
"auth.error.genericRetry": "Something went wrong. Please try again.",
|
|
190
|
+
"auth.error.biometricLocked": "Locked: unlock with biometrics first.",
|
|
191
|
+
"auth.error.googleNoPresenter": "No presenter for Google sign-in.",
|
|
192
|
+
"auth.error.googleNoToken": "Google sign-in returned no id_token.",
|
|
193
|
+
"auth.error.appleNoToken": "Apple sign-in returned no token.",
|
|
194
|
+
"auth.error.memberSettingsUnreadable": "Could not read the site's member settings.",
|
|
195
|
+
"auth.error.memberSettingsMalformed": "Member settings response was not a JSON object.",
|
|
196
|
+
"auth.biometric.error.noCipher": "No cipher.",
|
|
197
|
+
"auth.error.unlockOvertaken": "Unlock overtaken by a sign-in or sign-out.",
|
|
198
|
+
"auth.gate.code.show": "Show code",
|
|
199
|
+
"auth.gate.code.hide": "Hide code",
|
|
200
|
+
"auth.feedback.invalid_input": "Check the highlighted fields and try again.",
|
|
201
|
+
"auth.feedback.invalid_credentials": "The email or password is incorrect. Check your details or reset your password.",
|
|
202
|
+
"auth.feedback.registration_failed": "We could not create an account. Check your details, or try signing in or resetting your password.",
|
|
203
|
+
"auth.feedback.invalid_code": "That code is invalid or has expired. Check the code or request a new one.",
|
|
204
|
+
"auth.feedback.expired_code": "That code has expired. Request a new code and try again.",
|
|
205
|
+
"auth.feedback.totp": "That code did not work. Enter the current code from your authenticator app.",
|
|
206
|
+
"auth.feedback.network": "We could not connect. Check your connection and try again.",
|
|
207
|
+
"auth.feedback.rate_limited": "Too many attempts. Wait a few minutes and try again.",
|
|
208
|
+
"auth.feedback.unavailable": "This action is not available here. Use a supported sign-in method or open the app.",
|
|
209
|
+
"auth.feedback.cancelled": "Sign-in was cancelled. Try again when you are ready.",
|
|
210
|
+
"auth.feedback.verification_required": "Complete verification to continue, then try again.",
|
|
211
|
+
"auth.feedback.unknown": "We could not complete this action. Please try again.",
|
|
212
|
+
"auth.validation.emailRequired": "Enter your email address.",
|
|
213
|
+
"auth.validation.emailInvalid": "Enter a valid email address.",
|
|
214
|
+
"auth.validation.passwordMinimum": "Use at least 8 characters for your new password.",
|
|
215
|
+
"auth.validation.passwordRequired": "Enter your password.",
|
|
216
|
+
"auth.validation.codeRequired": "Enter your verification code.",
|
|
217
|
+
"auth.validation.nameRequired": "Enter your name.",
|
|
218
|
+
"auth.feedback.busy": "Please wait\u2026",
|
|
219
|
+
"auth.gate.verify.title": "Verify your email",
|
|
220
|
+
"auth.gate.verify.body": "Enter the confirmation code sent to your email to finish signing in.",
|
|
221
|
+
"auth.gate.cancel": "Cancel",
|
|
222
|
+
"auth.gate.codePlaceholder": "Confirmation code"
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
// ../../stdlib/flows/auth/src/feedback.ts
|
|
226
|
+
var failureKeys = {
|
|
227
|
+
invalid_input: "auth.feedback.invalid_input",
|
|
228
|
+
invalid_credentials: "auth.feedback.invalid_credentials",
|
|
229
|
+
registration_failed: "auth.feedback.registration_failed",
|
|
230
|
+
invalid_code: "auth.feedback.invalid_code",
|
|
231
|
+
expired_code: "auth.feedback.expired_code",
|
|
232
|
+
network: "auth.feedback.network",
|
|
233
|
+
rate_limited: "auth.feedback.rate_limited",
|
|
234
|
+
unavailable: "auth.feedback.unavailable",
|
|
235
|
+
cancelled: "auth.feedback.cancelled",
|
|
236
|
+
verification_required: "auth.feedback.verification_required",
|
|
237
|
+
unknown: "auth.feedback.unknown"
|
|
238
|
+
};
|
|
239
|
+
var codes = new Set(Object.keys(failureKeys));
|
|
240
|
+
var aliases = {
|
|
241
|
+
invalidCredentials: "invalid_credentials",
|
|
242
|
+
emailInUse: "registration_failed",
|
|
243
|
+
unsupported: "unavailable",
|
|
244
|
+
recaptchaRequired: "verification_required",
|
|
245
|
+
needsTwoFactor: "verification_required",
|
|
246
|
+
INVALID_CREDENTIALS: "invalid_credentials",
|
|
247
|
+
EMAIL_IN_USE: "registration_failed",
|
|
248
|
+
UNSUPPORTED: "unavailable",
|
|
249
|
+
NETWORK: "network",
|
|
250
|
+
CANCELLED: "cancelled",
|
|
251
|
+
RECAPTCHA_REQUIRED: "verification_required",
|
|
252
|
+
INVALID_CODE: "invalid_code",
|
|
253
|
+
EXPIRED_CODE: "expired_code",
|
|
254
|
+
TOO_MANY_REQUESTS: "rate_limited"
|
|
255
|
+
};
|
|
256
|
+
function authMessage(key, translate) {
|
|
257
|
+
const translated = translate?.(key);
|
|
258
|
+
return translated && translated !== key ? translated : copy_generated_default[key] ?? copy_generated_default["auth.feedback.unknown"];
|
|
259
|
+
}
|
|
260
|
+
function authFailure(raw, operation = "signIn", translate) {
|
|
261
|
+
const value = raw && typeof raw === "object" ? raw : {};
|
|
262
|
+
const payload = value.payload && typeof value.payload === "object" ? value.payload : value;
|
|
263
|
+
const named = payload.code ?? value.code ?? value.kind;
|
|
264
|
+
const status = value.statusCode ?? value.status;
|
|
265
|
+
let code = codes.has(named) ? named : aliases[named] ?? "unknown";
|
|
266
|
+
if (status === 429) code = "rate_limited";
|
|
267
|
+
else if ([404, 405, 501].includes(status)) code = "unavailable";
|
|
268
|
+
else if ([401, 403].includes(status) && operation === "signIn") code = "invalid_credentials";
|
|
269
|
+
else if (status === 0 || status >= 500 || value.name === "TypeError" || value.name === "TimeoutError") code = "network";
|
|
270
|
+
if (operation === "verify" && code === "invalid_credentials") code = "invalid_code";
|
|
271
|
+
if (operation === "register" && code === "invalid_credentials") code = "registration_failed";
|
|
272
|
+
return { code, reason: authMessage(failureKeys[code], translate) };
|
|
273
|
+
}
|
|
274
|
+
function identityErrors(input, operation, requireName = false) {
|
|
275
|
+
const errors = {};
|
|
276
|
+
if (operation === "verify") {
|
|
277
|
+
if (!input.code?.trim()) errors.code = "auth.validation.codeRequired";
|
|
278
|
+
return errors;
|
|
279
|
+
}
|
|
280
|
+
const email = input.email?.trim() ?? "";
|
|
281
|
+
if (!email) errors.email = "auth.validation.emailRequired";
|
|
282
|
+
else if (validate({ type: "email" }, email)) errors.email = "auth.validation.emailInvalid";
|
|
283
|
+
if ((operation === "signIn" || operation === "register") && !input.password?.length) errors.password = "auth.validation.passwordRequired";
|
|
284
|
+
if (operation === "register" && requireName && !input.name?.trim()) errors.name = "auth.validation.nameRequired";
|
|
285
|
+
return errors;
|
|
286
|
+
}
|
|
287
|
+
|
|
1
288
|
// ../../stdlib/flows/auth/src/index.ts
|
|
2
289
|
async function dispatch(handlerId, params) {
|
|
3
290
|
const fn = globalThis.himalaya?.dispatch;
|
|
@@ -12,12 +299,6 @@ function emailOf(raw) {
|
|
|
12
299
|
const email = direct?.email ?? wrapped?.payload?.email;
|
|
13
300
|
return typeof email === "string" ? email : "";
|
|
14
301
|
}
|
|
15
|
-
function reasonOf(raw, fallback) {
|
|
16
|
-
const direct = raw;
|
|
17
|
-
const wrapped = raw;
|
|
18
|
-
const err = direct?.error ?? wrapped?.payload?.error;
|
|
19
|
-
return typeof err === "string" && err ? err : fallback;
|
|
20
|
-
}
|
|
21
302
|
function reportedOk(raw) {
|
|
22
303
|
const status = raw?.status;
|
|
23
304
|
if (typeof status !== "string") return true;
|
|
@@ -41,9 +322,9 @@ async function attempt(action, params, failureText, opts) {
|
|
|
41
322
|
try {
|
|
42
323
|
raw = await dispatch(id(opts, action), params);
|
|
43
324
|
} catch (e) {
|
|
44
|
-
return { ok: false,
|
|
325
|
+
return { ok: false, ...authFailure(e, action === "registerDirect" ? "register" : "signIn") };
|
|
45
326
|
}
|
|
46
|
-
if (!reportedOk(raw)) return { ok: false,
|
|
327
|
+
if (!reportedOk(raw) || raw?.error || raw?.payload?.error) return { ok: false, ...authFailure(raw, action === "registerDirect" ? "register" : "signIn") };
|
|
47
328
|
const state = await authState(opts);
|
|
48
329
|
if (!state.signedIn) {
|
|
49
330
|
return { ok: false, reason: failureText };
|
|
@@ -51,12 +332,12 @@ async function attempt(action, params, failureText, opts) {
|
|
|
51
332
|
return { ok: true, email: state.email };
|
|
52
333
|
}
|
|
53
334
|
function signInDirect(email, password, opts) {
|
|
54
|
-
if (
|
|
55
|
-
return Promise.resolve({ ok: false,
|
|
335
|
+
if (Object.keys(identityErrors({ email: email.trim(), password }, "signIn")).length) {
|
|
336
|
+
return Promise.resolve({ ok: false, code: "invalid_input", reason: authMessage("auth.feedback.invalid_input") });
|
|
56
337
|
}
|
|
57
338
|
return attempt(
|
|
58
339
|
"signInDirect",
|
|
59
|
-
{ email, password },
|
|
340
|
+
{ email: email.trim(), password },
|
|
60
341
|
"Sign-in did not complete. Please try again.",
|
|
61
342
|
opts
|
|
62
343
|
);
|
|
@@ -65,13 +346,13 @@ function signIn(opts) {
|
|
|
65
346
|
return attempt("signIn", {}, "Sign-in did not complete. Please try again.", opts);
|
|
66
347
|
}
|
|
67
348
|
function registerMember(email, password, profile, opts) {
|
|
68
|
-
if (
|
|
69
|
-
return Promise.resolve({ ok: false,
|
|
349
|
+
if (Object.keys(identityErrors({ email: email.trim(), password }, "register")).length) {
|
|
350
|
+
return Promise.resolve({ ok: false, code: "invalid_input", reason: authMessage("auth.feedback.invalid_input") });
|
|
70
351
|
}
|
|
71
352
|
return attempt(
|
|
72
353
|
"registerDirect",
|
|
73
354
|
{
|
|
74
|
-
email,
|
|
355
|
+
email: email.trim(),
|
|
75
356
|
password,
|
|
76
357
|
...profile?.firstName ? { firstName: profile.firstName } : {},
|
|
77
358
|
...profile?.lastName ? { lastName: profile.lastName } : {}
|
|
@@ -81,15 +362,17 @@ function registerMember(email, password, profile, opts) {
|
|
|
81
362
|
);
|
|
82
363
|
}
|
|
83
364
|
async function resetPassword(email, opts) {
|
|
84
|
-
|
|
365
|
+
const errors = identityErrors({ email }, "reset");
|
|
366
|
+
if (errors.email) return { ok: false, code: "invalid_input", reason: authMessage(errors.email) };
|
|
367
|
+
email = email.trim();
|
|
85
368
|
try {
|
|
86
369
|
const raw = await dispatch(id(opts, "resetPassword"), { email });
|
|
87
|
-
if (!reportedOk(raw)) {
|
|
88
|
-
return { ok: false,
|
|
370
|
+
if (!reportedOk(raw) || raw?.error || raw?.payload?.error) {
|
|
371
|
+
return { ok: false, ...authFailure(raw, "reset") };
|
|
89
372
|
}
|
|
90
373
|
return { ok: true, email };
|
|
91
374
|
} catch (e) {
|
|
92
|
-
return { ok: false,
|
|
375
|
+
return { ok: false, ...authFailure(e, "reset") };
|
|
93
376
|
}
|
|
94
377
|
}
|
|
95
378
|
async function signOut(opts) {
|
|
@@ -101,7 +384,10 @@ async function signOut(opts) {
|
|
|
101
384
|
}
|
|
102
385
|
export {
|
|
103
386
|
DEFAULT_AUTH_PREFIX,
|
|
387
|
+
authFailure,
|
|
388
|
+
authMessage,
|
|
104
389
|
authState,
|
|
390
|
+
identityErrors,
|
|
105
391
|
registerMember,
|
|
106
392
|
resetPassword,
|
|
107
393
|
signIn,
|