@wix/himalaya-cli 0.1526.0 → 0.1528.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/sdk/state/src/connectivity.d.ts +5 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/sdk/state/src/index.d.ts +1 -0
- package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/state.mjs +14 -0
- package/dist/cli.mjs +3633 -3260
- package/dist/preview-assets.generated.bin +0 -0
- package/guides/himi-json-output.md +45 -0
- package/guides/himi-mcp.md +41 -0
- package/guides/himi-test.md +3 -3
- package/guides/iap-products.md +88 -23
- package/package.json +2 -2
- package/templates/beauty-salon/dev/index.ts +2027 -759
- package/templates/beauty-salon/tier5-src/_shared/collection-service.ts +5 -1
- package/templates/beauty-salon/tier5-src/_shared/online-actions.ts +76 -0
- package/templates/beauty-salon/tier5-src/himi-booking-bookings/index.ts +1 -0
- package/templates/beauty-salon/tier5-src/himi-booking-time/index.ts +803 -284
- package/templates/beauty-salon/tier5-src/himi-branded-lite-address/index.ts +3 -1
- package/templates/beauty-salon/tier5-src/himi-branded-lite-addresses/index.ts +3 -1
- package/templates/beauty-salon/tier5-src/himi-branded-lite-cart/index.ts +3 -0
- package/templates/beauty-salon/tier5-src/himi-branded-lite-order/index.ts +3 -1
- package/templates/beauty-salon/tier5-src/himi-branded-lite-plans/index.ts +13 -1
- package/templates/beauty-salon/tier5-src/himi-branded-lite-wallet/index.ts +3 -1
- package/templates/beauty-salon/tier5-src/himi-store-product/index.ts +10 -4
- package/templates/beauty-salon-owner/tier5-src/_shared/collection-service.ts +5 -1
- package/templates/beauty-salon-owner/tier5-src/_shared/online-actions.ts +76 -0
- package/templates/branded-lite/dev/index.ts +1910 -603
- package/templates/branded-lite/tier5-src/_shared/collection-service.ts +5 -1
- package/templates/branded-lite/tier5-src/_shared/online-actions.ts +76 -0
- package/templates/branded-lite/tier5-src/himi-booking-bookings/index.ts +1 -0
- package/templates/branded-lite/tier5-src/himi-booking-time/index.ts +803 -284
- package/templates/branded-lite/tier5-src/himi-branded-lite-address/index.ts +3 -1
- package/templates/branded-lite/tier5-src/himi-branded-lite-addresses/index.ts +3 -1
- package/templates/branded-lite/tier5-src/himi-branded-lite-cart/index.ts +3 -0
- package/templates/branded-lite/tier5-src/himi-branded-lite-feed/index.ts +3 -1
- package/templates/branded-lite/tier5-src/himi-branded-lite-group/index.ts +3 -1
- package/templates/branded-lite/tier5-src/himi-branded-lite-notifications/index.ts +6 -4
- package/templates/branded-lite/tier5-src/himi-branded-lite-notifsettings/index.ts +6 -4
- package/templates/branded-lite/tier5-src/himi-branded-lite-order/index.ts +3 -1
- package/templates/branded-lite/tier5-src/himi-branded-lite-plans/index.ts +13 -1
- package/templates/branded-lite/tier5-src/himi-branded-lite-program/index.ts +3 -1
- package/templates/branded-lite/tier5-src/himi-branded-lite-reservations/index.ts +6 -4
- package/templates/branded-lite/tier5-src/himi-branded-lite-reserve/index.ts +3 -1
- package/templates/branded-lite/tier5-src/himi-branded-lite-wallet/index.ts +3 -1
- package/templates/branded-lite/tier5-src/himi-events-detail/index.ts +8 -1
- package/templates/branded-lite/tier5-src/himi-events-rsvp/index.ts +7 -4
- package/templates/branded-lite/tier5-src/himi-store-product/index.ts +10 -4
- package/templates/community-club/tier5-src/_shared/collection-service.ts +5 -1
- package/templates/community-club/tier5-src/_shared/online-actions.ts +76 -0
- package/templates/community-club/tier5-src/himi-branded-lite-feed/index.ts +3 -1
- package/templates/community-club/tier5-src/himi-branded-lite-group/index.ts +3 -1
- package/templates/community-club/tier5-src/himi-events-detail/index.ts +8 -1
- package/templates/community-club/tier5-src/himi-events-rsvp/index.ts +7 -4
- package/templates/community-club-owner/tier5-src/_shared/collection-service.ts +5 -1
- package/templates/community-club-owner/tier5-src/_shared/online-actions.ts +76 -0
- package/templates/events-meetups/tier5-src/_shared/collection-service.ts +5 -1
- package/templates/events-meetups/tier5-src/_shared/online-actions.ts +76 -0
- package/templates/events-meetups/tier5-src/himi-branded-lite-feed/index.ts +3 -1
- package/templates/events-meetups/tier5-src/himi-branded-lite-group/index.ts +3 -1
- package/templates/events-meetups/tier5-src/himi-events-detail/index.ts +8 -1
- package/templates/events-meetups/tier5-src/himi-events-rsvp/index.ts +7 -4
- package/templates/events-meetups-owner/tier5-src/_shared/collection-service.ts +5 -1
- package/templates/events-meetups-owner/tier5-src/_shared/online-actions.ts +76 -0
- package/templates/gym-fitness/dev/index.ts +2024 -756
- package/templates/gym-fitness/tier5-src/_shared/collection-service.ts +5 -1
- package/templates/gym-fitness/tier5-src/_shared/online-actions.ts +76 -0
- package/templates/gym-fitness/tier5-src/himi-booking-bookings/index.ts +1 -0
- package/templates/gym-fitness/tier5-src/himi-booking-time/index.ts +803 -284
- package/templates/gym-fitness/tier5-src/himi-branded-lite-address/index.ts +3 -1
- package/templates/gym-fitness/tier5-src/himi-branded-lite-addresses/index.ts +3 -1
- package/templates/gym-fitness/tier5-src/himi-branded-lite-cart/index.ts +3 -0
- package/templates/gym-fitness/tier5-src/himi-branded-lite-order/index.ts +3 -1
- package/templates/gym-fitness/tier5-src/himi-branded-lite-plans/index.ts +13 -1
- package/templates/gym-fitness/tier5-src/himi-branded-lite-wallet/index.ts +3 -1
- package/templates/gym-fitness/tier5-src/himi-events-detail/index.ts +8 -1
- package/templates/gym-fitness/tier5-src/himi-events-rsvp/index.ts +7 -4
- package/templates/gym-fitness/tier5-src/himi-store-product/index.ts +10 -4
- package/templates/gym-fitness-owner/tier5-src/_shared/collection-service.ts +5 -1
- package/templates/gym-fitness-owner/tier5-src/_shared/online-actions.ts +76 -0
- package/templates/nonprofit-cause/tier5-src/_shared/collection-service.ts +5 -1
- package/templates/nonprofit-cause/tier5-src/_shared/online-actions.ts +76 -0
- package/templates/nonprofit-cause/tier5-src/himi-branded-lite-feed/index.ts +3 -1
- package/templates/nonprofit-cause/tier5-src/himi-branded-lite-group/index.ts +3 -1
- package/templates/nonprofit-cause/tier5-src/himi-branded-lite-plans/index.ts +13 -1
- package/templates/nonprofit-cause/tier5-src/himi-branded-lite-wallet/index.ts +3 -1
- package/templates/nonprofit-cause/tier5-src/himi-events-detail/index.ts +8 -1
- package/templates/nonprofit-cause/tier5-src/himi-events-rsvp/index.ts +7 -4
- package/templates/nonprofit-cause-owner/tier5-src/_shared/collection-service.ts +5 -1
- package/templates/nonprofit-cause-owner/tier5-src/_shared/online-actions.ts +76 -0
- package/templates/owner-lite/tier5-src/_shared/collection-service.ts +5 -1
- package/templates/owner-lite/tier5-src/_shared/online-actions.ts +76 -0
- package/templates/podcast-creator/tier5-src/_shared/collection-service.ts +5 -1
- package/templates/podcast-creator/tier5-src/_shared/online-actions.ts +76 -0
- package/templates/podcast-creator/tier5-src/himi-branded-lite-feed/index.ts +3 -1
- package/templates/podcast-creator/tier5-src/himi-branded-lite-plans/index.ts +13 -1
- package/templates/podcast-creator/tier5-src/himi-branded-lite-wallet/index.ts +3 -1
- package/templates/podcast-creator/tier5-src/himi-events-detail/index.ts +8 -1
- package/templates/podcast-creator/tier5-src/himi-events-rsvp/index.ts +7 -4
- package/templates/podcast-creator-owner/tier5-src/_shared/collection-service.ts +5 -1
- package/templates/podcast-creator-owner/tier5-src/_shared/online-actions.ts +76 -0
- package/templates/portfolio-creative/tier5-src/_shared/collection-service.ts +5 -1
- package/templates/portfolio-creative/tier5-src/_shared/online-actions.ts +76 -0
- package/templates/portfolio-creative/tier5-src/himi-branded-lite-address/index.ts +3 -1
- package/templates/portfolio-creative/tier5-src/himi-branded-lite-addresses/index.ts +3 -1
- package/templates/portfolio-creative/tier5-src/himi-branded-lite-cart/index.ts +3 -0
- package/templates/portfolio-creative/tier5-src/himi-branded-lite-order/index.ts +3 -1
- package/templates/portfolio-creative/tier5-src/himi-branded-lite-wallet/index.ts +3 -1
- package/templates/portfolio-creative/tier5-src/himi-events-detail/index.ts +8 -1
- package/templates/portfolio-creative/tier5-src/himi-events-rsvp/index.ts +7 -4
- package/templates/portfolio-creative/tier5-src/himi-store-product/index.ts +10 -4
- package/templates/portfolio-creative-owner/tier5-src/_shared/collection-service.ts +5 -1
- package/templates/portfolio-creative-owner/tier5-src/_shared/online-actions.ts +76 -0
- package/templates/restaurant/tier5-src/_shared/collection-service.ts +5 -1
- package/templates/restaurant/tier5-src/_shared/online-actions.ts +76 -0
- package/templates/restaurant/tier5-src/himi-branded-lite-address/index.ts +3 -1
- package/templates/restaurant/tier5-src/himi-branded-lite-addresses/index.ts +3 -1
- package/templates/restaurant/tier5-src/himi-branded-lite-reserve/index.ts +3 -1
- package/templates/restaurant/tier5-src/himi-branded-lite-wallet/index.ts +3 -1
- package/templates/restaurant/tier5-src/himi-events-detail/index.ts +8 -1
- package/templates/restaurant/tier5-src/himi-events-rsvp/index.ts +7 -4
- package/templates/restaurant-owner/tier5-src/_shared/collection-service.ts +5 -1
- package/templates/restaurant-owner/tier5-src/_shared/online-actions.ts +76 -0
- package/templates/retail-store/tier5-src/_shared/collection-service.ts +5 -1
- package/templates/retail-store/tier5-src/_shared/online-actions.ts +76 -0
- package/templates/retail-store/tier5-src/himi-branded-lite-address/index.ts +3 -1
- package/templates/retail-store/tier5-src/himi-branded-lite-addresses/index.ts +3 -1
- package/templates/retail-store/tier5-src/himi-branded-lite-cart/index.ts +3 -0
- package/templates/retail-store/tier5-src/himi-branded-lite-order/index.ts +3 -1
- package/templates/retail-store/tier5-src/himi-branded-lite-wallet/index.ts +3 -1
- package/templates/retail-store/tier5-src/himi-store-product/index.ts +10 -4
- package/templates/retail-store-owner/tier5-src/_shared/collection-service.ts +5 -1
- package/templates/retail-store-owner/tier5-src/_shared/online-actions.ts +76 -0
- package/templates/yoga-studio/dev/index.ts +2054 -786
- package/templates/yoga-studio/tier5-src/_shared/collection-service.ts +5 -1
- package/templates/yoga-studio/tier5-src/_shared/online-actions.ts +76 -0
- package/templates/yoga-studio/tier5-src/himi-booking-bookings/index.ts +1 -0
- package/templates/yoga-studio/tier5-src/himi-booking-time/index.ts +803 -284
- package/templates/yoga-studio/tier5-src/himi-branded-lite-plans/index.ts +13 -1
- package/templates/yoga-studio/tier5-src/himi-branded-lite-program/index.ts +3 -1
- package/templates/yoga-studio/tier5-src/himi-branded-lite-wallet/index.ts +3 -1
- package/templates/yoga-studio/tier5-src/himi-events-detail/index.ts +8 -1
- package/templates/yoga-studio/tier5-src/himi-events-rsvp/index.ts +7 -4
- package/templates/yoga-studio-owner/tier5-src/_shared/collection-service.ts +5 -1
- package/templates/yoga-studio-owner/tier5-src/_shared/online-actions.ts +76 -0
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { withOnlineWrites } from './online-actions.js';
|
|
1
2
|
import { defineService as register, type ServiceDefinition } from '@himalaya/state';
|
|
2
3
|
import { COLLECTIONS, COLLECTION_CHROME_MIN_ITEMS, initialCollection, normalizeCollection, projectCollection, collectionId, collectionActionsLabel, type CollectionRow } from './collection-contract.js';
|
|
3
4
|
import { localPreferences, type PreferenceRuntime } from './local-preferences.js';
|
|
@@ -331,6 +332,8 @@ export function decorateCollection(name: string, def: { state: State; actions?:
|
|
|
331
332
|
* reducer and reads the private controller snapshot, never an SDUI payload. */
|
|
332
333
|
export function defineBackendCollection<S extends object, Row extends object>(name: string, options: {
|
|
333
334
|
register?: typeof register;
|
|
335
|
+
/** Explicit mutation preflight; unrelated collection services keep their current reducers. */
|
|
336
|
+
onlineWrites?: boolean;
|
|
334
337
|
/** Revalidate already opened pages on navigation return; explicit refresh resets. */
|
|
335
338
|
restorePagesOnLoad?: boolean;
|
|
336
339
|
/** The load action's argument (onAppear params beyond `copy`), before the query runs — for a
|
|
@@ -350,7 +353,8 @@ export function defineBackendCollection<S extends object, Row extends object>(na
|
|
|
350
353
|
controller: controller as unknown as BackendCollection['controller'],
|
|
351
354
|
apply: (state, page) => options.apply(state as S, page as unknown as CollectionQueryState<Row>) as State,
|
|
352
355
|
});
|
|
353
|
-
const
|
|
356
|
+
const registerService = options.onlineWrites ? withOnlineWrites(options.register ?? register, ['confirmCancel', 'confirmOperation', 'retryOperation', 'commitWrite'], { messageFields: ['actionMessage'] }) : (options.register ?? register);
|
|
357
|
+
const handle = registerService(name, definition);
|
|
354
358
|
// Registration restored the state a cold boot saved: the page it showed is this run's, before the first load. Only
|
|
355
359
|
// when the service's own rows came back with it: a bundle that keeps them out of the restore (its `notHydrated`)
|
|
356
360
|
// starts its first load as before, never from rows it chose not to restore. Rows that came back empty are the
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { connectivity, defineService as register, type ServiceDefinition } from '@himalaya/state';
|
|
2
|
+
|
|
3
|
+
// Template generation enables this behavior only in the selected two starter families.
|
|
4
|
+
export const offlineWritesEnabled = true;
|
|
5
|
+
|
|
6
|
+
export const offlineWriteMessage = 'You’re offline. Connect to save this change, then submit it again.';
|
|
7
|
+
|
|
8
|
+
/** The guard runs before the reducer: entered values survive and no optimistic
|
|
9
|
+
* changes, success state, or queued writes can occur. It never submits on reconnect. */
|
|
10
|
+
export function offlineWriteState<S extends object>(state: S): S {
|
|
11
|
+
const next: Record<string, unknown> = { ...state, error: offlineWriteMessage, message: offlineWriteMessage };
|
|
12
|
+
for (const key of ['saving', 'isSaving', 'submitting', 'isSubmitting', 'adding', 'added', 'bookingInFlight']) {
|
|
13
|
+
if (key in next) next[key] = false;
|
|
14
|
+
}
|
|
15
|
+
for (const key of ['savedMessage', 'successMessage']) {
|
|
16
|
+
if (key in next) next[key] = '';
|
|
17
|
+
}
|
|
18
|
+
// A saved/favourited item is business state, not a submission-success flag.
|
|
19
|
+
return next as S;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
interface OfflineWriteOptions<S> {
|
|
23
|
+
derive?: (state: S) => S;
|
|
24
|
+
/** Exempt only non-mutating branches of a registered action. */
|
|
25
|
+
requiresConnectivity?: (action: string, state: S, argument?: unknown) => boolean;
|
|
26
|
+
messageFields?: readonly string[] | ((action: string) => readonly string[]);
|
|
27
|
+
draftFields?: readonly string[] | Readonly<Record<string, string>>;
|
|
28
|
+
secretFields?: readonly string[];
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function withOnlineWrites<S extends object>(registerService: typeof register, names: readonly string[], options: OfflineWriteOptions<S> = {}): typeof register {
|
|
32
|
+
if (!offlineWritesEnabled) return registerService;
|
|
33
|
+
return ((name: string, definition: ServiceDefinition<Record<string, unknown>>) => {
|
|
34
|
+
let currentState: (() => Record<string, unknown>) | undefined;
|
|
35
|
+
const handle = registerService(name, {
|
|
36
|
+
...definition,
|
|
37
|
+
notHydrated: [...new Set([...(definition.notHydrated ?? []), ...(options.secretFields ?? [])])],
|
|
38
|
+
actions: Object.fromEntries(Object.entries(definition.actions ?? {}).map(([action, reduce]) => [action,
|
|
39
|
+
(state: Record<string, unknown>, ...args: never[]) => {
|
|
40
|
+
if (!names.includes(action)) return reduce(state, ...args);
|
|
41
|
+
if (options.requiresConnectivity?.(action, state as S, args[0]) === false) return reduce(state, ...args);
|
|
42
|
+
const fields = typeof options.messageFields === 'function' ? options.messageFields(action) : options.messageFields ?? ['message'];
|
|
43
|
+
if (connectivity().online) {
|
|
44
|
+
let cleared = false;
|
|
45
|
+
for (const field of ['error', 'message', ...fields]) {
|
|
46
|
+
if (state[field] === offlineWriteMessage) { state[field] = ''; cleared = true; }
|
|
47
|
+
}
|
|
48
|
+
// Keep the runtime's state object: reducers may mutate it and return undefined.
|
|
49
|
+
const result = reduce(state, ...args);
|
|
50
|
+
if (!cleared) return result;
|
|
51
|
+
// Publish cleared feedback even for a void reducer. An async completion must
|
|
52
|
+
// keep any newer state published by another action while it was awaiting.
|
|
53
|
+
const finish = (next: Record<string, unknown> | undefined) => next === undefined ? currentState?.() ?? state : next;
|
|
54
|
+
return result && typeof (result as Promise<unknown>).then === 'function'
|
|
55
|
+
? Promise.resolve(result).then(finish)
|
|
56
|
+
: finish(result as Record<string, unknown> | undefined);
|
|
57
|
+
}
|
|
58
|
+
const draft = { ...state };
|
|
59
|
+
const argument = args[0] as Record<string, unknown> | undefined;
|
|
60
|
+
const draftFields = options.draftFields ?? [];
|
|
61
|
+
const entries = Array.isArray(draftFields) ? draftFields.map(key => [key, key]) : Object.entries(draftFields);
|
|
62
|
+
for (const [key, source] of entries) {
|
|
63
|
+
if (argument && key in state && typeof argument[source] === typeof state[key]) draft[key] = argument[source];
|
|
64
|
+
}
|
|
65
|
+
for (const key of options.secretFields ?? []) draft[key] = '';
|
|
66
|
+
const feedback = Object.fromEntries(fields.map(key => [key, offlineWriteMessage]));
|
|
67
|
+
let next = { ...offlineWriteState(draft), ...feedback };
|
|
68
|
+
if (options.derive) next = options.derive(next as S) as Record<string, unknown>;
|
|
69
|
+
return { ...next, ...feedback };
|
|
70
|
+
},
|
|
71
|
+
])),
|
|
72
|
+
});
|
|
73
|
+
if (typeof handle.getState === 'function') currentState = () => handle.getState();
|
|
74
|
+
return handle;
|
|
75
|
+
}) as typeof register;
|
|
76
|
+
}
|
|
@@ -71,6 +71,7 @@ function derive(s: S): S {
|
|
|
71
71
|
cancelPresented: !!cancelTarget, cancelTitle: cancelTarget ? `${cancelTarget.row.title} · ${cancelTarget.row.subtitle}` : "" };
|
|
72
72
|
}
|
|
73
73
|
const svc = defineBackendCollection<S, MemberBookingRow>("himiBookingBookings", {
|
|
74
|
+
onlineWrites: true,
|
|
74
75
|
restorePagesOnLoad: true,
|
|
75
76
|
state: derive({ status: "loading", rows: [], isMember: false, identityLine: "", emptyText: "", isLoading: true, notLoading: false,
|
|
76
77
|
errored: false, notErrored: true, noEmpty: true, actionMessage: "", cancelPresented: false, cancelTitle: "",
|