@wix/himalaya-cli 0.1632.0 → 0.1634.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.
Files changed (95) hide show
  1. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/sdk/iap/src/wix-payments-contract.d.ts +4 -14
  2. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/sdk/iap/src/wix-payments-wire.d.ts +2 -1
  3. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/sdk/iap/src/wix-payments.d.ts +1 -2
  4. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/flows/iap-checkout/src/apple-iap-contract.d.ts +26 -13
  5. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/flows/iap-checkout/src/apple-iap-core.d.ts +0 -2
  6. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/flows/iap-checkout/src/checkout-source.d.ts +3 -10
  7. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/flows/iap-checkout/src/commerce-core.d.ts +0 -2
  8. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/flows/iap-checkout/src/iap-order-backend.d.ts +0 -3
  9. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/flows/iap-checkout/src/iap-verticals/stores.d.ts +2 -2
  10. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/flows/iap-checkout/src/index.d.ts +2 -2
  11. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/loyalty/src/index.d.ts +64 -0
  12. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/members-feed-viewer/src/index.d.ts +10 -6
  13. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/members-v1/src/index.d.ts +36 -0
  14. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/iap-checkout.mjs +13 -45
  15. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/iap.mjs +2 -4
  16. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/screens.mjs +7 -11
  17. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-loyalty.mjs +39 -0
  18. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-members-feed-viewer.mjs +8 -7
  19. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-members.mjs +29 -0
  20. package/dist/browser-plane/assets.json +166 -0
  21. package/dist/browser-plane/host.html +156 -0
  22. package/dist/browser-plane/package-reader.js +4 -0
  23. package/dist/browser-plane/preview-deferred/368faca44fb9f7207e4af784e94750b1ee59c1098b8689e0f4a918926f244fb5.bin +0 -0
  24. package/dist/browser-plane/preview-deferred/37c179b4fefb63ea9637322b84583a2df53aa226c150294eea1675c14b1b8e29.bin +0 -0
  25. package/dist/browser-plane/preview-deferred/4ecf270136af928612c76fe4ebade91d8156975e5ea4c0cf9225501dd1788e02.bin +0 -0
  26. package/dist/browser-plane/preview-deferred/521a0e528916d678d7588b2cddf3dadd3bb959a6d62426382f61c77a82017e35.bin +1 -0
  27. package/dist/browser-plane/preview-deferred/62e2fe4718129f36ecdb0ae4de385bd6b81ecc876146447167c6c140fad699a9.bin +0 -0
  28. package/dist/browser-plane/preview-deferred/642feab8a48ddf6c7a89d7c2a7c0edfa0e6e773f671287e460e222703563191e.bin +0 -0
  29. package/dist/browser-plane/preview-deferred/97ed8f1a6772abe26e3d8af5cecfc4b02faa94497d585b0398b5053b739a70c1.bin +0 -0
  30. package/dist/browser-plane/preview-deferred/a33cfe728c584fdba4fcc1fd54bcdc2f9f2f13889ddbb5b2bd1d0f8cbe49b84e.bin +28 -0
  31. package/dist/browser-plane/preview-deferred/bf4c16a2774edd38a921edf3099469866cd74c094fd596f3fa4e81f54a04dfaa.bin +0 -0
  32. package/dist/browser-plane/preview-deferred/c3457ce58c96b65f303fec0ddf5f06733004eaf9e21e62302b155ec63a7765f7.bin +56 -0
  33. package/dist/browser-plane/preview-deferred/d7598e12c5dbef095ff8272cfc55da0250bd07fbdecbac8a530b9b277872a134.bin +0 -0
  34. package/dist/browser-plane/preview-deferred/dced97a77624bc5f8b1ae65850360908297f4588e09feb6f22792d29dc7e765b.bin +0 -0
  35. package/dist/browser-plane/preview-deferred/dee56f09fd3efc127c1ea95557edc74110c1460a46287da36e0af25efd341ef5.bin +0 -0
  36. package/dist/browser-plane/preview-deferred/ec4c7d63772d980d6e147b2df6215fd2737e4b04cebe0cf7e11dc695fb63cdcf.bin +0 -0
  37. package/dist/browser-plane/sw.js +13 -0
  38. package/dist/browser-plane/t5-frame.html +350 -0
  39. package/dist/browser-plane/t5-worker-frame.html +350 -0
  40. package/dist/cli.mjs +6499 -5089
  41. package/dist/preview-assets.generated.bin +0 -0
  42. package/fixtures/wix-canned.json +34 -1
  43. package/guides/getting-started.md +2 -1
  44. package/guides/himi-json-output.md +8 -0
  45. package/guides/himi-skill.md +2 -1
  46. package/guides/iap-screen-adoption.md +4 -4
  47. package/guides/importable-sdks.md +1 -1
  48. package/guides/one-app-section-mappings.md +3 -3
  49. package/guides/one-app-to-himi-app.md +81 -5
  50. package/guides/sdk-reference.json +8862 -4388
  51. package/guides/skill.md +11 -1
  52. package/package.json +3 -3
  53. package/templates/beauty-salon/tier5-src/_shared/branded-lite-hosted.ts +1 -0
  54. package/templates/beauty-salon/tier5-src/himi-store-product/index.ts +1 -1
  55. package/templates/branded-lite/config.ts +7 -0
  56. package/templates/branded-lite/dev/index.ts +3340 -1890
  57. package/templates/branded-lite/himalaya.content.json +3 -0
  58. package/templates/branded-lite/l10n/en.json +8 -4
  59. package/templates/branded-lite/tier5-src/_shared/branded-lite-hosted.ts +1 -0
  60. package/templates/branded-lite/tier5-src/_shared/business-chat-history.ts +4 -1
  61. package/templates/branded-lite/tier5-src/_shared/business-chat-presenter.ts +2 -7
  62. package/templates/branded-lite/tier5-src/_shared/header-badges.ts +1 -1
  63. package/templates/branded-lite/tier5-src/_shared/inbox-rooms.ts +68 -0
  64. package/templates/branded-lite/tier5-src/_shared/loyalty-offerings.ts +73 -0
  65. package/templates/branded-lite/tier5-src/_shared/member-activity.ts +34 -0
  66. package/templates/branded-lite/tier5-src/_shared/member-row-extras.ts +167 -0
  67. package/templates/branded-lite/tier5-src/_shared/notification-target.ts +141 -0
  68. package/templates/branded-lite/tier5-src/_shared/source-badges.ts +6 -4
  69. package/templates/branded-lite/tier5-src/_shared/wix-member-links.ts +114 -0
  70. package/templates/branded-lite/tier5-src/business-chat/index.ts +114 -59
  71. package/templates/branded-lite/tier5-src/himi-branded-lite-inbox/index.ts +83 -0
  72. package/templates/branded-lite/tier5-src/himi-branded-lite-loyalty/earning.ts +148 -0
  73. package/templates/branded-lite/tier5-src/himi-branded-lite-loyalty/index.ts +57 -31
  74. package/templates/branded-lite/tier5-src/himi-branded-lite-loyalty-rewards/index.ts +208 -0
  75. package/templates/branded-lite/tier5-src/himi-branded-lite-notifications/index.ts +62 -7
  76. package/templates/branded-lite/tier5-src/himi-store-product/index.ts +1 -1
  77. package/templates/branded-lite/tier5-src/wix-spaces-members/index.ts +60 -12
  78. package/templates/community-club/tier5-src/_shared/branded-lite-hosted.ts +1 -0
  79. package/templates/events-meetups/tier5-src/_shared/branded-lite-hosted.ts +1 -0
  80. package/templates/gym-fitness/tier5-src/_shared/branded-lite-hosted.ts +1 -0
  81. package/templates/gym-fitness/tier5-src/himi-store-product/index.ts +1 -1
  82. package/templates/nonprofit-cause/tier5-src/_shared/branded-lite-hosted.ts +1 -0
  83. package/templates/podcast-creator/tier5-src/_shared/branded-lite-hosted.ts +1 -0
  84. package/templates/portfolio-creative/tier5-src/_shared/branded-lite-hosted.ts +1 -0
  85. package/templates/portfolio-creative/tier5-src/himi-store-product/index.ts +1 -1
  86. package/templates/restaurant/tier5-src/_shared/branded-lite-hosted.ts +1 -0
  87. package/templates/retail-store/tier5-src/_shared/branded-lite-hosted.ts +1 -0
  88. package/templates/retail-store/tier5-src/himi-store-product/index.ts +1 -1
  89. package/templates/salon-spa/dev/index.ts +112 -70
  90. package/templates/salon-spa/tier5-src/_shared/branded-lite-hosted.ts +1 -0
  91. package/templates/salon-spa/tier5-src/_shared/business-chat-history.ts +4 -1
  92. package/templates/salon-spa/tier5-src/_shared/business-chat-presenter.ts +2 -7
  93. package/templates/salon-spa/tier5-src/_shared/inbox-rooms.ts +68 -0
  94. package/templates/salon-spa/tier5-src/business-chat/index.ts +114 -59
  95. package/templates/yoga-studio/tier5-src/_shared/branded-lite-hosted.ts +1 -0
@@ -48,7 +48,43 @@ function getLoyaltyTiersProgram(readOptions) {
48
48
  function listMyLoyaltyCoupons(readOptions) {
49
49
  return wixCall("GET", "/loyalty-coupons/v1/coupons/my-coupons", void 0, readOptions);
50
50
  }
51
+ function redeemMyLoyaltyReward(rewardId, options) {
52
+ if (!rewardId) return Promise.reject(new Error("A reward ID is required"));
53
+ return wixCall("POST", "/loyalty-coupons/v1/coupons/redeem-my-coupon", { rewardId }, options?.site ? { site: options.site } : void 0);
54
+ }
55
+ function listMyLoyaltyFollowedChannels(options) {
56
+ return wixCall("GET", "/loyalty-social-media/v1/followed-channels", void 0, options);
57
+ }
58
+ function followMyLoyaltyChannel(channel, options) {
59
+ if (!["FACEBOOK", "INSTAGRAM", "LINKEDIN", "TIKTOK", "X"].includes(channel)) return Promise.reject(new Error("Unsupported loyalty channel"));
60
+ return wixCall("POST", "/loyalty-social-media/v1/followed-channels", { followedChannel: { channel } }, options?.site ? { site: options.site } : void 0);
61
+ }
62
+ async function listMyReferralRewards(options) {
63
+ const rewards = [], seen = /* @__PURE__ */ new Set();
64
+ let cursor = "";
65
+ for (let page = 0; page < 20; page++) {
66
+ let response;
67
+ try {
68
+ response = await wixCall("POST", "/_api/referral-rewards/v1/referral-rewards/query", {
69
+ contactId: "me",
70
+ query: { filter: { rewardType: "CouponReward" }, cursorPaging: { limit: 100, ...cursor ? { cursor } : {} } }
71
+ }, options);
72
+ } catch (error) {
73
+ if (/\bAPP_NOT_INSTALLED\b/.test(String(error)) && page === 0) return { referralRewards: [] };
74
+ throw error;
75
+ }
76
+ if (!response || typeof response !== "object" || Array.isArray(response) || response.referralRewards !== void 0 && !Array.isArray(response.referralRewards)) throw new Error("Referral rewards response is incomplete");
77
+ rewards.push(...response.referralRewards ?? []);
78
+ const next = response.metadata?.cursors?.next;
79
+ if (!next) return { referralRewards: rewards };
80
+ if (seen.has(next)) throw new Error("Referral rewards cursor repeated");
81
+ seen.add(next);
82
+ cursor = next;
83
+ }
84
+ throw new Error("Referral rewards exceed the supported page limit");
85
+ }
51
86
  export {
87
+ followMyLoyaltyChannel,
52
88
  getCurrentMemberLoyaltyAccount,
53
89
  getLoyaltyBffDashboard,
54
90
  getLoyaltyProgram,
@@ -57,6 +93,9 @@ export {
57
93
  listLoyaltyRewards,
58
94
  listLoyaltyTiers,
59
95
  listMyLoyaltyCoupons,
96
+ listMyLoyaltyFollowedChannels,
97
+ listMyReferralRewards,
98
+ redeemMyLoyaltyReward,
60
99
  wixCall
61
100
  };
62
101
  //# sourceMappingURL=wix-loyalty.mjs.map
@@ -46,10 +46,11 @@ async function mfvCall(method, suffix, body, options) {
46
46
  }
47
47
  }
48
48
  }
49
+ var APPS_WIX = "https://apps.wix.com/_api/members-feed-viewer/v1";
49
50
  async function queryNotifications(limit = 25, options) {
50
- const res = await mfvCall(
51
+ const res = await wixCall(
51
52
  "POST",
52
- "/members-viewer-feed-notifications/query",
53
+ `${APPS_WIX}/members-viewer-feed-notifications/query`,
53
54
  {
54
55
  query: {
55
56
  cursorPaging: { limit },
@@ -59,18 +60,18 @@ async function queryNotifications(limit = 25, options) {
59
60
  },
60
61
  options
61
62
  );
62
- return res.viewerFeedNotifications ?? [];
63
+ return res?.viewerFeedNotifications ?? [];
63
64
  }
64
65
  async function countUnseenNotifications(options) {
65
66
  const site = options?.site;
66
- if (typeof site !== "string" || !/^[a-f\d]{8}-[a-f\d]{4}-[a-f\d]{4}-[a-f\d]{4}-[a-f\d]{12}$/i.test(site)) {
67
- throw new Error("@himalaya/wix-members-feed-viewer: notification count requires its bound site");
67
+ if (site !== void 0 && (typeof site !== "string" || !/^[a-f\d]{8}-[a-f\d]{4}-[a-f\d]{4}-[a-f\d]{4}-[a-f\d]{12}$/i.test(site))) {
68
+ throw new Error("@himalaya/wix-members-feed-viewer: notification count site must be a canonical bound site id");
68
69
  }
69
70
  const res = await wixCall(
70
71
  "POST",
71
- "https://apps.wix.com/_api/members-feed-viewer/v1/members-viewer-feed-notifications/count",
72
+ `${APPS_WIX}/members-viewer-feed-notifications/count`,
72
73
  { filter: { channel: "MOBILE", status: "UNSEEN" }, maxCount: 100 },
73
- { site }
74
+ site === void 0 ? void 0 : { site }
74
75
  );
75
76
  const count = res?.count;
76
77
  if (typeof count !== "number" || !Number.isSafeInteger(count) || count < 0 || count > 100) {
@@ -107,6 +107,33 @@ async function isFollowingMember(targetId) {
107
107
  );
108
108
  return res.connectedMembers?.[0]?.isFollowing === true;
109
109
  }
110
+ async function queryMemberActivity(ids) {
111
+ const unique = [...new Set(ids.filter(Boolean))];
112
+ if (!unique.length) return [];
113
+ if (unique.length > 100) throw new Error("queryMemberActivity: at most 100 ids per call");
114
+ const res = await wixCall(
115
+ "POST",
116
+ "https://apps.wix.com/_api/members-one-app/api/members?filter=members",
117
+ // The service reads its query as a JSON string, the shape the One App client sends.
118
+ { query: JSON.stringify({ paging: { limit: unique.length, offset: 0 }, sort: [{ nickname: "asc" }], isOwnerApp: false, filter: { id: { $in: unique } } }) }
119
+ );
120
+ return (res?.items ?? []).filter((item) => item?.id).map((item) => ({
121
+ id: item.id,
122
+ role: item.member?.role,
123
+ online: item.member?.online === true,
124
+ lastOpenApp: item.member?.lastOpenApp ?? null
125
+ }));
126
+ }
127
+ async function listFollowedMembers(targetIds) {
128
+ const ids = [...new Set(targetIds.filter(Boolean))];
129
+ if (!ids.length) return [];
130
+ const res = await wixCall(
131
+ "POST",
132
+ "/members/v3/followers/my/connections",
133
+ { connectedMemberIds: ids }
134
+ );
135
+ return (res.connectedMembers ?? []).filter((c) => c.isFollowing === true && c.memberId).map((c) => c.memberId);
136
+ }
110
137
  export {
111
138
  approveMember,
112
139
  blockMember,
@@ -120,6 +147,8 @@ export {
120
147
  joinCommunity,
121
148
  leaveCommunity,
122
149
  listCurrentMemberBlocking,
150
+ listFollowedMembers,
151
+ queryMemberActivity,
123
152
  queryMembers,
124
153
  unblockCurrentMember,
125
154
  unfollowMember,
@@ -0,0 +1,166 @@
1
+ {
2
+ "files": [
3
+ {
4
+ "name": "sw.js",
5
+ "bytes": 2452155
6
+ },
7
+ {
8
+ "name": "host.html",
9
+ "bytes": 6795
10
+ },
11
+ {
12
+ "name": "package-reader.js",
13
+ "bytes": 9864
14
+ },
15
+ {
16
+ "name": "t5-frame.html",
17
+ "bytes": 23047
18
+ },
19
+ {
20
+ "name": "t5-worker-frame.html",
21
+ "bytes": 23064
22
+ },
23
+ {
24
+ "name": "preview-deferred/c3457ce58c96b65f303fec0ddf5f06733004eaf9e21e62302b155ec63a7765f7.bin",
25
+ "bytes": 488215
26
+ },
27
+ {
28
+ "name": "preview-deferred/521a0e528916d678d7588b2cddf3dadd3bb959a6d62426382f61c77a82017e35.bin",
29
+ "bytes": 90
30
+ },
31
+ {
32
+ "name": "preview-deferred/a33cfe728c584fdba4fcc1fd54bcdc2f9f2f13889ddbb5b2bd1d0f8cbe49b84e.bin",
33
+ "bytes": 1317034
34
+ },
35
+ {
36
+ "name": "preview-deferred/d7598e12c5dbef095ff8272cfc55da0250bd07fbdecbac8a530b9b277872a134.bin",
37
+ "bytes": 488584
38
+ },
39
+ {
40
+ "name": "preview-deferred/ec4c7d63772d980d6e147b2df6215fd2737e4b04cebe0cf7e11dc695fb63cdcf.bin",
41
+ "bytes": 90924
42
+ },
43
+ {
44
+ "name": "preview-deferred/bf4c16a2774edd38a921edf3099469866cd74c094fd596f3fa4e81f54a04dfaa.bin",
45
+ "bytes": 90984
46
+ },
47
+ {
48
+ "name": "preview-deferred/368faca44fb9f7207e4af784e94750b1ee59c1098b8689e0f4a918926f244fb5.bin",
49
+ "bytes": 90980
50
+ },
51
+ {
52
+ "name": "preview-deferred/97ed8f1a6772abe26e3d8af5cecfc4b02faa94497d585b0398b5053b739a70c1.bin",
53
+ "bytes": 90872
54
+ },
55
+ {
56
+ "name": "preview-deferred/642feab8a48ddf6c7a89d7c2a7c0edfa0e6e773f671287e460e222703563191e.bin",
57
+ "bytes": 90980
58
+ },
59
+ {
60
+ "name": "preview-deferred/37c179b4fefb63ea9637322b84583a2df53aa226c150294eea1675c14b1b8e29.bin",
61
+ "bytes": 108636
62
+ },
63
+ {
64
+ "name": "preview-deferred/62e2fe4718129f36ecdb0ae4de385bd6b81ecc876146447167c6c140fad699a9.bin",
65
+ "bytes": 109084
66
+ },
67
+ {
68
+ "name": "preview-deferred/4ecf270136af928612c76fe4ebade91d8156975e5ea4c0cf9225501dd1788e02.bin",
69
+ "bytes": 109048
70
+ },
71
+ {
72
+ "name": "preview-deferred/dee56f09fd3efc127c1ea95557edc74110c1460a46287da36e0af25efd341ef5.bin",
73
+ "bytes": 107700
74
+ },
75
+ {
76
+ "name": "preview-deferred/dced97a77624bc5f8b1ae65850360908297f4588e09feb6f22792d29dc7e765b.bin",
77
+ "bytes": 88108
78
+ }
79
+ ],
80
+ "deferred": [
81
+ {
82
+ "key": "assets/pdf-m0Fd7UDI.js",
83
+ "contentType": "application/javascript; charset=utf-8",
84
+ "sha256": "c3457ce58c96b65f303fec0ddf5f06733004eaf9e21e62302b155ec63a7765f7",
85
+ "file": "preview-deferred/c3457ce58c96b65f303fec0ddf5f06733004eaf9e21e62302b155ec63a7765f7.bin"
86
+ },
87
+ {
88
+ "key": "assets/pdf.worker.min-BGnVRhRG.js",
89
+ "contentType": "application/javascript; charset=utf-8",
90
+ "sha256": "521a0e528916d678d7588b2cddf3dadd3bb959a6d62426382f61c77a82017e35",
91
+ "file": "preview-deferred/521a0e528916d678d7588b2cddf3dadd3bb959a6d62426382f61c77a82017e35.bin"
92
+ },
93
+ {
94
+ "key": "assets/pdf.worker.min-BmVo14Nb.mjs",
95
+ "contentType": "application/javascript; charset=utf-8",
96
+ "sha256": "a33cfe728c584fdba4fcc1fd54bcdc2f9f2f13889ddbb5b2bd1d0f8cbe49b84e",
97
+ "file": "preview-deferred/a33cfe728c584fdba4fcc1fd54bcdc2f9f2f13889ddbb5b2bd1d0f8cbe49b84e.bin"
98
+ },
99
+ {
100
+ "key": "fonts/Roboto-Variable.ttf",
101
+ "contentType": "font/ttf",
102
+ "sha256": "d7598e12c5dbef095ff8272cfc55da0250bd07fbdecbac8a530b9b277872a134",
103
+ "file": "preview-deferred/d7598e12c5dbef095ff8272cfc55da0250bd07fbdecbac8a530b9b277872a134.bin"
104
+ },
105
+ {
106
+ "key": "fonts/WixMadeforDisplay-Bold.ttf",
107
+ "contentType": "font/ttf",
108
+ "sha256": "ec4c7d63772d980d6e147b2df6215fd2737e4b04cebe0cf7e11dc695fb63cdcf",
109
+ "file": "preview-deferred/ec4c7d63772d980d6e147b2df6215fd2737e4b04cebe0cf7e11dc695fb63cdcf.bin"
110
+ },
111
+ {
112
+ "key": "fonts/WixMadeforDisplay-ExtraBold.ttf",
113
+ "contentType": "font/ttf",
114
+ "sha256": "bf4c16a2774edd38a921edf3099469866cd74c094fd596f3fa4e81f54a04dfaa",
115
+ "file": "preview-deferred/bf4c16a2774edd38a921edf3099469866cd74c094fd596f3fa4e81f54a04dfaa.bin"
116
+ },
117
+ {
118
+ "key": "fonts/WixMadeforDisplay-Medium.ttf",
119
+ "contentType": "font/ttf",
120
+ "sha256": "368faca44fb9f7207e4af784e94750b1ee59c1098b8689e0f4a918926f244fb5",
121
+ "file": "preview-deferred/368faca44fb9f7207e4af784e94750b1ee59c1098b8689e0f4a918926f244fb5.bin"
122
+ },
123
+ {
124
+ "key": "fonts/WixMadeforDisplay-Regular.ttf",
125
+ "contentType": "font/ttf",
126
+ "sha256": "97ed8f1a6772abe26e3d8af5cecfc4b02faa94497d585b0398b5053b739a70c1",
127
+ "file": "preview-deferred/97ed8f1a6772abe26e3d8af5cecfc4b02faa94497d585b0398b5053b739a70c1.bin"
128
+ },
129
+ {
130
+ "key": "fonts/WixMadeforDisplay-SemiBold.ttf",
131
+ "contentType": "font/ttf",
132
+ "sha256": "642feab8a48ddf6c7a89d7c2a7c0edfa0e6e773f671287e460e222703563191e",
133
+ "file": "preview-deferred/642feab8a48ddf6c7a89d7c2a7c0edfa0e6e773f671287e460e222703563191e.bin"
134
+ },
135
+ {
136
+ "key": "fonts/WixMadeforText-Bold.ttf",
137
+ "contentType": "font/ttf",
138
+ "sha256": "37c179b4fefb63ea9637322b84583a2df53aa226c150294eea1675c14b1b8e29",
139
+ "file": "preview-deferred/37c179b4fefb63ea9637322b84583a2df53aa226c150294eea1675c14b1b8e29.bin"
140
+ },
141
+ {
142
+ "key": "fonts/WixMadeforText-ExtraBold.ttf",
143
+ "contentType": "font/ttf",
144
+ "sha256": "62e2fe4718129f36ecdb0ae4de385bd6b81ecc876146447167c6c140fad699a9",
145
+ "file": "preview-deferred/62e2fe4718129f36ecdb0ae4de385bd6b81ecc876146447167c6c140fad699a9.bin"
146
+ },
147
+ {
148
+ "key": "fonts/WixMadeforText-Medium.ttf",
149
+ "contentType": "font/ttf",
150
+ "sha256": "4ecf270136af928612c76fe4ebade91d8156975e5ea4c0cf9225501dd1788e02",
151
+ "file": "preview-deferred/4ecf270136af928612c76fe4ebade91d8156975e5ea4c0cf9225501dd1788e02.bin"
152
+ },
153
+ {
154
+ "key": "fonts/WixMadeforText-Regular.ttf",
155
+ "contentType": "font/ttf",
156
+ "sha256": "dee56f09fd3efc127c1ea95557edc74110c1460a46287da36e0af25efd341ef5",
157
+ "file": "preview-deferred/dee56f09fd3efc127c1ea95557edc74110c1460a46287da36e0af25efd341ef5.bin"
158
+ },
159
+ {
160
+ "key": "fonts/WixMadeforText-SemiBold.ttf",
161
+ "contentType": "font/ttf",
162
+ "sha256": "dced97a77624bc5f8b1ae65850360908297f4588e09feb6f22792d29dc7e765b",
163
+ "file": "preview-deferred/dced97a77624bc5f8b1ae65850360908297f4588e09feb6f22792d29dc7e765b.bin"
164
+ }
165
+ ]
166
+ }
@@ -0,0 +1,156 @@
1
+ <!doctype html>
2
+ <meta charset="utf-8">
3
+ <meta name="viewport" content="width=device-width, initial-scale=1">
4
+ <title>Himi — the app, in your browser</title>
5
+ <!--
6
+ The host page for the browser plane.
7
+
8
+ Its whole job is: register the worker, WAIT until it is controlling this client, hand it a
9
+ release, then get out of the way by navigating into the app.
10
+
11
+ THE WAIT IS NOT OPTIONAL. The web host fires its boot-document fetch before React mounts, so a
12
+ first load that is not yet controlled sends those `/v1` requests to the network, where they 404 —
13
+ and the app renders its "no release" state against a plane that is actually fine. Measured in the
14
+ spike that preceded this: `/v1/__spike` reached the origin server on the uncontrolled load and
15
+ was intercepted only after control. Hence `navigator.serviceWorker.controller` is polled, not
16
+ assumed, and the page reloads once if it has to.
17
+ -->
18
+ <style>
19
+ :root { color-scheme: light dark; }
20
+ body { font: 15px/1.5 system-ui, -apple-system, "Segoe UI", sans-serif; margin: 0;
21
+ display: grid; place-items: center; min-height: 100vh; }
22
+ main { max-width: 34rem; padding: 2rem; }
23
+ h1 { font-size: 1.25rem; margin: 0 0 .5rem; }
24
+ p { margin: .25rem 0; color: #555; }
25
+ @media (prefers-color-scheme: dark) { p { color: #aaa; } }
26
+ ol { padding-left: 1.1rem; margin: 1rem 0 0; }
27
+ li { margin: .3rem 0; }
28
+ li[data-state="done"]::marker { content: "✓ "; }
29
+ li[data-state="fail"]::marker { content: "✗ "; }
30
+ li[data-state="fail"] { color: #b91c1c; }
31
+ code { background: #0001; padding: .1rem .3rem; border-radius: 3px; }
32
+ #drop { margin-top: 1.25rem; padding: 1.5rem; border: 2px dashed #0003; border-radius: 8px;
33
+ text-align: center; color: #666; }
34
+ #drop.over { border-color: #2563eb; background: #2563eb11; }
35
+ </style>
36
+ <main>
37
+ <h1>Himi — the app, in your browser</h1>
38
+ <p>Build, preview and drive a Himi app locally. No server, and nothing leaves this machine.</p>
39
+ <ol id="steps"></ol>
40
+ <div id="drop" hidden>Drop a <code>.himi</code> package here, or pass one from the CLI.</div>
41
+ </main>
42
+ <script type="module">
43
+ const steps = document.getElementById("steps");
44
+ const drop = document.getElementById("drop");
45
+ const step = (label) => {
46
+ const li = document.createElement("li");
47
+ li.textContent = label;
48
+ steps.append(li);
49
+ return {
50
+ done: (extra) => { li.dataset.state = "done"; if (extra) li.textContent = `${label} — ${extra}`; },
51
+ fail: (why) => { li.dataset.state = "fail"; li.textContent = `${label} — ${why}`; },
52
+ };
53
+ };
54
+
55
+ async function register() {
56
+ const s = step("Starting the local plane");
57
+ if (!("serviceWorker" in navigator)) {
58
+ s.fail("this browser has no service worker; the plane needs one");
59
+ return null;
60
+ }
61
+ try {
62
+ await navigator.serviceWorker.register("./sw.js", { scope: "./" });
63
+ await navigator.serviceWorker.ready;
64
+ // `ready` resolves on ACTIVATION, which is not the same as this client being controlled.
65
+ // Only `controller` says the interception is live for us.
66
+ if (!navigator.serviceWorker.controller) {
67
+ // ONE reload, enforced. A worker that never claims this client would otherwise put the page
68
+ // in a silent reload loop; a bounded retry that then FAILS VISIBLY is the difference between
69
+ // a bug someone can report and a tab that just blinks.
70
+ if (sessionStorage.getItem("himi.sw.retried") === "1") {
71
+ s.fail("the worker activated but never took control of this page — reloading again would loop");
72
+ return null;
73
+ }
74
+ try { sessionStorage.setItem("himi.sw.retried", "1"); } catch { /* private mode: fall through */ }
75
+ s.done("reloading to take control");
76
+ location.reload();
77
+ return null;
78
+ }
79
+ try { sessionStorage.removeItem("himi.sw.retried"); } catch { /* nothing to clear */ }
80
+ s.done("controlling this page");
81
+ return navigator.serviceWorker.controller;
82
+ } catch (e) {
83
+ s.fail(String(e));
84
+ return null;
85
+ }
86
+ }
87
+
88
+ /** postMessage with a reply port, so `load` is awaitable rather than fire-and-hope. */
89
+ function ask(worker, message) {
90
+ return new Promise((resolve, reject) => {
91
+ const ch = new MessageChannel();
92
+ ch.port1.onmessage = (e) => (e.data?.ok ? resolve(e.data) : reject(new Error(e.data?.error ?? "worker refused")));
93
+ setTimeout(() => reject(new Error("the worker did not answer")), 30_000);
94
+ worker.postMessage(message, [ch.port2]);
95
+ });
96
+ }
97
+
98
+ async function loadAndGo(worker, payload) {
99
+ const s = step(`Loading ${payload.app}`);
100
+ try {
101
+ // The clientId rides INSIDE the payload — it belongs to the app, not to the worker, so a
102
+ // second release for a different app brings its own.
103
+ const { stats } = await ask(worker, { type: "load-release", payload });
104
+ s.done(`${(stats.bytes / 1024).toFixed(0)} KB in memory`);
105
+ } catch (e) {
106
+ s.fail(String(e));
107
+ return;
108
+ }
109
+ step("Opening the app").done();
110
+ // The MOUNT follows the release's own chrome choice. Hardcoding `/preview` made
111
+ // `himi run --browser --chrome app` render the device chassis anyway — the usage string and the
112
+ // non-browser path both promise otherwise.
113
+ const mount = payload.chrome === "app" ? "app" : "preview";
114
+ location.href = `/${mount}/a/${encodeURIComponent(payload.app)}`;
115
+ }
116
+
117
+ const worker = await register();
118
+ if (worker) {
119
+ // Three ways in, all the same payload shape.
120
+ // 1. the CLI, which posts the release to this page and names it in the fragment
121
+ // 2. a URL the host page was given
122
+ // 3. a dropped .himi
123
+ const hash = new URLSearchParams(location.hash.slice(1));
124
+ const src = hash.get("release") ?? new URLSearchParams(location.search).get("release");
125
+ if (src) {
126
+ const s = step("Fetching the release");
127
+ try {
128
+ const res = await fetch(src);
129
+ if (!res.ok) throw new Error(`the release URL answered HTTP ${res.status}`);
130
+ const payload = await res.json();
131
+ s.done();
132
+ await loadAndGo(worker, payload);
133
+ } catch (e) { s.fail(String(e)); }
134
+ } else {
135
+ drop.hidden = false;
136
+ step("Waiting for a release").done("drop a .himi below");
137
+ for (const ev of ["dragenter", "dragover"]) {
138
+ drop.addEventListener(ev, (e) => { e.preventDefault(); drop.classList.add("over"); });
139
+ }
140
+ drop.addEventListener("dragleave", () => drop.classList.remove("over"));
141
+ drop.addEventListener("drop", async (e) => {
142
+ e.preventDefault();
143
+ drop.classList.remove("over");
144
+ const file = e.dataTransfer?.files?.[0];
145
+ if (!file) return;
146
+ const s = step(`Reading ${file.name}`);
147
+ try {
148
+ const { openPackageAsPayload } = await import("./package-reader.js");
149
+ const payload = await openPackageAsPayload(file);
150
+ s.done();
151
+ await loadAndGo(worker, payload);
152
+ } catch (err) { s.fail(String(err)); }
153
+ });
154
+ }
155
+ }
156
+ </script>
@@ -0,0 +1,4 @@
1
+ var m="himi-package/2",E="himi-package/1",g="himi-package.json",b="release-manifest.json",H="source.zip";function w(n){return n?.contents==="dev"?"dev":"release"}var B=/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/,A=/^[a-f0-9]{64}$/;function S(n){return B.test(n)}function D(n){return Array.isArray(n.handlers)?n.handlers:[]}var v=n=>{if(typeof TextDecoder>"u")throw new Error("this JS host has no TextDecoder, so package text cannot be decoded safely");return new TextDecoder().decode(n)};function I(n,t,e){let s=n(t);if(!s)return null;try{return JSON.parse(v(s))}catch(r){return e.push(`${t} is not valid JSON: ${r.message}`),null}}function _(n,t={}){let e=[],s=[],r=I(n,g,e);if(!r&&t.requireHeader&&e.push(`${g} is missing \u2014 not a .himi package`),r&&r.format!==m&&r.format!==E&&e.push(`unsupported package format ${JSON.stringify(r.format)} (this build reads ${E} and ${m})`),r?.format===m&&r.launchMode!=="live"&&r.launchMode!=="snapshot"&&e.push(`${g} format ${m} needs launchMode "live" or "snapshot"`),r?.format===m&&(typeof r.contentHash!="string"||r.contentHash.trim()==="")&&e.push(`${g} format ${m} needs contentHash`),r&&r.contents!==void 0&&r.contents!=="release"&&r.contents!=="dev")e.push(`${g} has an unreadable contents ${JSON.stringify(r.contents)} (expected "release" or "dev")`);else if(r){let i=n(H)!==null;w(r)==="dev"&&!i&&e.push(`${H} is missing \u2014 the header says this package carries source`),w(r)==="release"&&i&&e.push(`${H} is present in a package whose header declares no source`)}let a=I(n,b,e);if(!a)return e.some(i=>i.startsWith(b))||e.push(`${b} is missing`),{ok:!1,errors:e,warnings:s,header:r,manifest:null};let p=a.screens,c=a.bundles;if((!p||typeof p!="object")&&e.push("release-manifest.json missing 'screens' object"),(!c||typeof c!="object")&&e.push("release-manifest.json missing 'bundles' object"),e.length>0)return{ok:!1,errors:e,warnings:s,header:r,manifest:a};r&&(r.app&&a.app&&r.app!==a.app&&e.push(`header app ${JSON.stringify(r.app)} disagrees with manifest app ${JSON.stringify(a.app)}`),r.releaseId&&a.releaseId&&r.releaseId!==a.releaseId&&e.push(`header releaseId ${JSON.stringify(r.releaseId)} disagrees with manifest releaseId ${JSON.stringify(a.releaseId)}`),t.contentHash&&r.contentHash&&t.contentHash!==r.contentHash&&e.push("contentHash mismatch \u2014 the package was truncated or modified after packing"));for(let[i,o]of Object.entries(p??{})){if(!S(i)){e.push(`screen id ${JSON.stringify(i)} is not a safe entry name`);continue}n(`screens/${i}.json`)||e.push(`screens/${i}.json missing (referenced in manifest)`);let u=o?.bundle;u!=null&&!(u in(c??{}))&&e.push(`screen "${i}" references bundle "${u}" which is absent from manifest.bundles`)}for(let[i,o]of Object.entries(c??{})){if(!o?.sha256||!A.test(o.sha256)){e.push(`bundle "${i}" has no valid sha256`);continue}n(`bundles/${o.sha256}.bundle.js`)||e.push(`bundles/${o.sha256}.bundle.js missing (bundle "${i}")`)}a.handlers!=null&&!Array.isArray(a.handlers)&&e.push(`manifest.handlers must be an array (got ${typeof a.handlers})`);for(let i of D(a)){let o=JSON.stringify(i?.id??"?");if(!i?.bundleHash||!A.test(i.bundleHash)){e.push(`handler ${o} has no valid bundleHash`);continue}n(`bundles/${i.bundleHash}.bundle.js`)||e.push(`bundles/${i.bundleHash}.bundle.js missing (handler ${o})`)}for(let[i,o]of Object.entries(a.assets??{})){if(!o?.sha256||!A.test(o.sha256)){e.push(`asset "${i}" has no valid sha256`);continue}n(`assets/${o.sha256}`)||e.push(`assets/${o.sha256} missing (asset "${i}")`)}for(let i of Object.keys(a.widgets??{})){if(!S(i)){e.push(`widget id ${JSON.stringify(i)} is not a safe entry name`);continue}n(`widgets/${i}.json`)||e.push(`widgets/${i}.json missing (referenced in manifest)`)}return(t.warnMissingDocs??!0)&&(n("app-config.json")||s.push("app-config.json is absent \u2014 the host has no navigation baseline"),n("tokens.json")||s.push("tokens.json is absent \u2014 the host falls back to default design tokens")),{ok:e.length===0,errors:e,warnings:s,header:r,manifest:a}}function j(n){return n.filter(t=>t.path!==g).slice().sort((t,e)=>t.path<e.path?-1:t.path>e.path?1:0).map(t=>`${t.path} ${t.hash}`).join(`
2
+ `)}var L=67324752,V=33639248,G=101010256,P=null;function J(n){if(!P){P=new Uint32Array(256);for(let e=0;e<256;e++){let s=e;for(let r=0;r<8;r++)s=s&1?3988292384^s>>>1:s>>>1;P[e]=s>>>0}}let t=4294967295;for(let e=0;e<n.length;e++)t=P[(t^n[e])&255]^t>>>8;return(t^4294967295)>>>0}function Z(n){return!n||n.length>512||n.startsWith("/")||n.includes("\\")||n.includes("\0")||/^[A-Za-z]:/.test(n)?!1:!n.split("/").some(t=>t===""||t==="."||t==="..")}var F={maxCompressedBytes:64*1024*1024,maxExpandedBytes:256*1024*1024,maxEntries:1e4,maxDecompressionRatio:1e3};function M(n,t,e=F){if(n>e.maxCompressedBytes)throw new Error(`package archive is ${n} bytes, over the ${e.maxCompressedBytes}-byte compressed-size limit`);if(t.length>e.maxEntries)throw new Error(`package archive has ${t.length} entries, over the ${e.maxEntries}-entry limit`);let s=0;for(let r of t){if(s+=r.rawSize,s>e.maxExpandedBytes)throw new Error(`package expands to more than the ${e.maxExpandedBytes}-byte expanded-size limit`);if(r.rawSize>0&&(r.compSize===0||r.rawSize/r.compSize>e.maxDecompressionRatio))throw new Error(`package entry ${JSON.stringify(r.name)} exceeds the ${e.maxDecompressionRatio}:1 decompression-ratio limit`)}}function O(n){let t=new DataView(n.buffer,n.byteOffset,n.byteLength),e=o=>t.getUint32(o,!0),s=o=>t.getUint16(o,!0),r=-1,a=Math.max(0,n.length-65535-22);for(let o=n.length-22;o>=a;o--)if(e(o)===G){r=o;break}if(r<0)throw new Error("not a zip archive (no end-of-central-directory record)");let p=s(r+10),c=e(r+16),i=[];for(let o=0;o<p;o++){if(c+46>n.length||e(c)!==V)throw new Error("corrupt zip central directory");let u=s(c+10),d=e(c+16),f=e(c+20),l=e(c+24),$=s(c+28),N=s(c+30),z=s(c+32),k=e(c+42),h=v(n.subarray(c+46,c+46+$));if(c+=46+$+N+z,h.endsWith("/"))continue;if(!Z(h))throw new Error(`unsafe zip entry name: ${JSON.stringify(h)}`);if(k+30>n.length||e(k)!==L)throw new Error(`corrupt zip local header for ${h}`);let R=k+30+s(k+26)+s(k+28);if(R+f>n.length)throw new Error(`truncated zip entry ${h}`);i.push({name:h,method:u,crc:d,dataStart:R,compSize:f,rawSize:l})}return i}function C(n,t){if(t.length!==n.rawSize)throw new Error(`size mismatch for zip entry ${n.name}`);if(J(t)!==n.crc)throw new Error(`checksum mismatch for zip entry ${n.name} \u2014 the package is damaged`)}function q(){return typeof DecompressionStream<"u"}var K="this browser cannot open a compressed .himi package (DecompressionStream is unavailable) \u2014 open it with `himi run`, or host the package unpacked with `himi pack --format dir`";async function Y(n){if(!q())throw new Error(K);let t=new Blob([n]).stream().pipeThrough(new DecompressionStream("deflate-raw"));return new Uint8Array(await new Response(t).arrayBuffer())}async function W(n,t){let e=n.subarray(t.dataStart,t.dataStart+t.compSize),s;if(t.method===0)s=e.slice();else if(t.method===8)try{s=await Y(e)}catch(r){throw new Error(`corrupt entry ${t.name} \u2014 the package is damaged (${r.message})`)}else throw new Error(`unsupported compression method ${t.method} for ${t.name}`);return C(t,s),s}async function T(n){let t=n instanceof Uint8Array?n:new Uint8Array(n),e=new Map,s=O(t);M(t.length,s);for(let r of s)e.set(r.name,await W(t,r));return e}async function X(n,t,e){let s=c=>n.get(c)??null,r=await ee(n),a=_(s,{requireHeader:e.requireHeader,contentHash:r});if(!a.ok||!a.manifest)throw new Error(a.errors.length?`not a Himi package:
3
+ ${a.errors.join(`
4
+ `)}`:`not a Himi package \u2014 no ${b}`);if(w(a.header)==="dev")throw new Error("this package carries the app's source (a dev package). The web host opens release packages only \u2014 restore it with `himi import <package.himi>` instead.");let p=a.header?.app??a.manifest.app;if(!p)throw new Error("package declares no app id");return{app:p,header:a.header,manifest:a.manifest,read:s,validation:a,source:t}}async function Q(n){let t=await crypto.subtle.digest("SHA-256",n);return Array.from(new Uint8Array(t),e=>e.toString(16).padStart(2,"0")).join("")}async function ee(n){let t=await Promise.all(Array.from(n,async([s,r])=>({path:s,hash:await Q(r)}))),e=await crypto.subtle.digest("SHA-256",new TextEncoder().encode(j(t)));return"sha256-"+btoa(String.fromCharCode(...new Uint8Array(e)))}async function U(n){return X(await T(await n.arrayBuffer()),{kind:"file",name:n.name},{requireHeader:!0})}var y=n=>n?new TextDecoder().decode(n):void 0;function x(n){if(!n)return;let t="",e=32768;for(let s=0;s<n.length;s+=e)t+=String.fromCharCode(...n.subarray(s,s+e));return btoa(t)}function ne(n){if(n)try{return JSON.parse(n)?.authConfig?.config?.clientId}catch{return}}function te(n){let t=n.manifest,e=d=>n.read(d),s={},r={};for(let[d,f]of Object.entries(t.screens??{})){let l=y(e(`screens/${d}.json`));l!==void 0&&(s[d]=l,f.descriptorHash&&(r[f.descriptorHash]=l))}let a=(d,f)=>{if(!d||r[d]!==void 0)return;let l=y(e(f))??y(e(`docs/${d}.json`));l!==void 0&&(r[d]=l)};for(let[d,f]of Object.entries(t.catalogs??{}))a(f,`catalogs/${d}.json`);a(t.tokensHash,"tokens.json"),a(t.appConfigHash,"app-config.json");let p={};for(let d of Object.values(t.bundles??{})){let f=x(e(`bundles/${d.sha256}.bundle.js`));f!==void 0&&(p[d.sha256]=f)}let c={};for(let d of Object.values(t.assets??{})){let f=x(e(`assets/${d.sha256}`));f!==void 0&&(c[d.sha256]={base64:f,contentType:d.contentType})}let i={};for(let d of Object.keys(t.widgets??{})){let f=y(e(`widgets/${d}.json`));f!==void 0&&(i[d]=f)}let o=y(e("app-config.json")),u=ne(o);return{app:n.app,manifest:t,screens:s,bundles:p,docs:r,assets:c,widgets:i,tokens:y(e("tokens.json")),appConfig:o,icon:x(e("icon.png")),header:n.header,...u?{wixClientId:u}:{}}}async function pe(n){let t=await U(n);return te(t)}export{pe as openPackageAsPayload,te as payloadFromPackage};
@@ -0,0 +1 @@
1
+ var e=``+new URL(`pdf.worker.min-BmVo14Nb.mjs`,import.meta.url).href;export{e as default};