@wix/himalaya-cli 0.982.0 → 0.984.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/stdlib/wix-sdk/notification-preferences/src/index.d.ts +105 -33
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-notification-preferences.mjs +66 -5
- package/dist/cli.mjs +3437 -331
- package/fixtures/wix-canned.json +36 -29
- package/guides/sdk-reference.json +86 -49
- package/package.json +3 -2
- package/templates/beauty-salon/dev/index.ts +27 -2
- package/templates/beauty-salon/tier5-src/himi-branded-lite-order/index.ts +14 -6
- package/templates/beauty-salon/tier5-src/himi-store-account/index.ts +59 -20
- package/templates/branded-lite/dev/index.ts +27 -2
- package/templates/branded-lite/tier5-src/himi-branded-lite-notifsettings/index.ts +42 -14
- package/templates/branded-lite/tier5-src/himi-branded-lite-order/index.ts +14 -6
- package/templates/branded-lite/tier5-src/himi-store-account/index.ts +59 -20
- package/templates/community-club/tier5-src/himi-store-account/index.ts +59 -20
- package/templates/events-meetups/tier5-src/himi-store-account/index.ts +59 -20
- package/templates/gym-fitness/dev/index.ts +27 -2
- package/templates/gym-fitness/tier5-src/himi-branded-lite-order/index.ts +14 -6
- package/templates/gym-fitness/tier5-src/himi-store-account/index.ts +59 -20
- package/templates/nonprofit-cause/tier5-src/himi-store-account/index.ts +59 -20
- package/templates/podcast-creator/tier5-src/himi-store-account/index.ts +59 -20
- package/templates/portfolio-creative/dev/index.ts +25 -1
- package/templates/portfolio-creative/tier5-src/himi-branded-lite-order/index.ts +14 -6
- package/templates/portfolio-creative/tier5-src/himi-store-account/index.ts +59 -20
- package/templates/restaurant/tier5-src/himi-store-account/index.ts +59 -20
- package/templates/retail-store/dev/index.ts +25 -1
- package/templates/retail-store/tier5-src/himi-branded-lite-order/index.ts +14 -6
- package/templates/retail-store/tier5-src/himi-store-account/index.ts +59 -20
- package/templates/yoga-studio/dev/index.ts +2 -1
- package/templates/yoga-studio/tier5-src/himi-store-account/index.ts +59 -20
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
// `wix-site-id` header and nothing else, so every read stayed on the baked site while the
|
|
9
9
|
// UI claimed otherwise. Managing several businesses is Owner Lite's job (account auth, a
|
|
10
10
|
// real Sites List, and per-call site scope via `site.forSite`).
|
|
11
|
-
import { defineService } from "@himalaya/state";
|
|
11
|
+
import { defineService, navigate, type NavDirective } from "@himalaya/state";
|
|
12
12
|
import { dispatch } from "@himalaya/dispatch";
|
|
13
13
|
import { searchOrders, type WixOrder } from "@himalaya/wix-ecom";
|
|
14
14
|
import { guestProfile, loadMemberProfile, strOf, fmtDate, titleCase, type AccountActivityRow } from "../_shared/himi-account";
|
|
@@ -21,6 +21,9 @@ interface AuthRouteInput {
|
|
|
21
21
|
returnId?: string;
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
+
// The screen's boot input survives refresh; consuming it must survive too.
|
|
25
|
+
let routeInputConsumed = false;
|
|
26
|
+
|
|
24
27
|
/** Mid-flow open params land on `himalaya.input` (paramKeys on himi_account). */
|
|
25
28
|
function routeInput(): AuthRouteInput {
|
|
26
29
|
const input = (globalThis as { himalaya?: { input?: AuthRouteInput } }).himalaya?.input;
|
|
@@ -35,7 +38,7 @@ function strField(arg: unknown, key: string): string {
|
|
|
35
38
|
|
|
36
39
|
/** Mid-flow auth (UX F3): intent + return path from himi.open / himalaya.input. */
|
|
37
40
|
function authIntentFromArg(arg: unknown, prev: Pick<S, "authIntent" | "authContextName" | "returnScreenId" | "returnId">): Pick<S, "authIntent" | "authContextName" | "returnScreenId" | "returnId"> {
|
|
38
|
-
const route = routeInput();
|
|
41
|
+
const route = routeInputConsumed ? {} : routeInput();
|
|
39
42
|
return {
|
|
40
43
|
authIntent: strField(arg, "intent") || route.intent || prev.authIntent || "",
|
|
41
44
|
authContextName: strField(arg, "contextName") || route.contextName || prev.authContextName || "",
|
|
@@ -44,6 +47,42 @@ function authIntentFromArg(arg: unknown, prev: Pick<S, "authIntent" | "authConte
|
|
|
44
47
|
};
|
|
45
48
|
}
|
|
46
49
|
|
|
50
|
+
/** Where a successful sign-in returns to, or null. Never Account itself — that would
|
|
51
|
+
* only push a second copy of the screen the member is already on. */
|
|
52
|
+
function resumeTarget(s: Pick<S, "returnScreenId" | "returnId">): NavDirective | null {
|
|
53
|
+
if (!s.returnScreenId || s.returnScreenId === "himi_account") return null;
|
|
54
|
+
return s.returnId ? { screenId: s.returnScreenId, args: { id: s.returnId } } : { screenId: s.returnScreenId };
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** Resume the member-only screen that sent the visitor here, once. The return path is
|
|
58
|
+
* consumed so a later refresh cannot fire it again; the host opens the target only if
|
|
59
|
+
* it is linkable, the same check an authored `himi.open` gets. */
|
|
60
|
+
function resumeAfterAuth(next: S): S {
|
|
61
|
+
const target = resumeTarget(next);
|
|
62
|
+
if (!next.isMember || !target) return next;
|
|
63
|
+
routeInputConsumed = true;
|
|
64
|
+
return navigate(derive({ ...next, authIntent: "", authContextName: "", returnScreenId: "", returnId: "" }), target);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Actions are not serialized: two quick Sign in taps both run against the pre-tap
|
|
68
|
+
// state, so without this both would submit credentials and both would resume.
|
|
69
|
+
let authInFlight = false;
|
|
70
|
+
|
|
71
|
+
async function authenticate(s: S, submit: () => Promise<unknown>, notMemberMessage: string, failedMessage: string): Promise<S | undefined> {
|
|
72
|
+
if (authInFlight) return undefined;
|
|
73
|
+
authInFlight = true;
|
|
74
|
+
try {
|
|
75
|
+
await submit();
|
|
76
|
+
const next = await probe(optimisticMember(s, s.email));
|
|
77
|
+
if (!next.isMember) return derive({ ...next, message: notMemberMessage });
|
|
78
|
+
return resumeAfterAuth(derive({ ...next, message: "" }));
|
|
79
|
+
} catch {
|
|
80
|
+
return derive({ ...s, message: failedMessage });
|
|
81
|
+
} finally {
|
|
82
|
+
authInFlight = false;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
47
86
|
// Next value of a focus token: monotonic, and never empty once requested. A counter
|
|
48
87
|
// rather than Date.now() — deterministic under test, and immune to two focus
|
|
49
88
|
// requests landing inside the same millisecond.
|
|
@@ -123,7 +162,8 @@ interface S {
|
|
|
123
162
|
authContextName: string;
|
|
124
163
|
returnScreenId: string;
|
|
125
164
|
returnId: string;
|
|
126
|
-
/** Show Continue
|
|
165
|
+
/** Show Continue when an already-signed-in member opens Account with a return path.
|
|
166
|
+
* A sign-in made here resumes on its own (resumeAfterAuth). */
|
|
127
167
|
hasReturnPath: boolean;
|
|
128
168
|
noReturnPath: boolean;
|
|
129
169
|
returnCta: string;
|
|
@@ -296,8 +336,8 @@ const svc = defineService<S, {
|
|
|
296
336
|
showSignIn: (s: S) => S;
|
|
297
337
|
showRecovery: (s: S) => S;
|
|
298
338
|
resetPassword: (s: S) => Promise<S>;
|
|
299
|
-
signIn: (s: S) => Promise<S>;
|
|
300
|
-
register: (s: S) => Promise<S>;
|
|
339
|
+
signIn: (s: S) => Promise<S | undefined>;
|
|
340
|
+
register: (s: S) => Promise<S | undefined>;
|
|
301
341
|
signOut: (s: S) => Promise<S>;
|
|
302
342
|
}>("himiStoreAccount", {
|
|
303
343
|
state: derive({
|
|
@@ -381,30 +421,29 @@ const svc = defineService<S, {
|
|
|
381
421
|
},
|
|
382
422
|
signIn: async (s) => {
|
|
383
423
|
if (!s.email || !s.password) return derive({ ...s, message: copyParam("storeAccount.validationEmailPassword", "Enter your email and password.") });
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
}
|
|
424
|
+
return authenticate(
|
|
425
|
+
s,
|
|
426
|
+
() => dispatch("himi.wix.signInDirect", { email: s.email, password: s.password }),
|
|
427
|
+
copyParam("storeAccount.signInCheckDetails", "Sign in failed. Check your details."),
|
|
428
|
+
copyParam("storeAccount.signInFailed", "Sign in failed. Try again."),
|
|
429
|
+
);
|
|
391
430
|
},
|
|
392
431
|
register: async (s) => {
|
|
393
432
|
if (!s.email || !s.password) return derive({ ...s, message: copyParam("storeAccount.validationEmailPassword", "Enter your email and password.") });
|
|
394
|
-
|
|
395
|
-
|
|
433
|
+
return authenticate(
|
|
434
|
+
s,
|
|
435
|
+
() => dispatch("himi.wix.registerDirect", {
|
|
396
436
|
email: s.email,
|
|
397
437
|
password: s.password,
|
|
398
438
|
firstName: s.firstName,
|
|
399
439
|
lastName: s.lastName,
|
|
400
|
-
})
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
return derive({ ...s, message: copyParam("storeAccount.registerFailed", "Account creation failed. Try another email.") });
|
|
405
|
-
}
|
|
440
|
+
}),
|
|
441
|
+
copyParam("storeAccount.registerTrySignIn", "Account creation failed. Try signing in."),
|
|
442
|
+
copyParam("storeAccount.registerFailed", "Account creation failed. Try another email."),
|
|
443
|
+
);
|
|
406
444
|
},
|
|
407
445
|
signOut: async (s) => {
|
|
446
|
+
routeInputConsumed = true;
|
|
408
447
|
try { await dispatch("himi.wix.signOut"); } catch { /* ignore */ }
|
|
409
448
|
// Do NOT re-probe via getMyData after logout — visitor-scoped my-data can
|
|
410
449
|
// still return a site nickname and resurrect isMember (BUG-3). Trust the
|