@wix/himalaya-cli 0.1117.0 → 0.1118.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/cli.mjs CHANGED
@@ -13266,12 +13266,12 @@ function stripBrandFromIdiom(tokens) {
13266
13266
  for (const key2 of BRAND_COLOR_TOKENS) delete colors[key2];
13267
13267
  if (Object.keys(colors).length === 0) delete o.colors;
13268
13268
  }
13269
- const shadows = o.shadows;
13270
- const glow = shadows && typeof shadows === "object" && !Array.isArray(shadows) ? shadows[BRAND_GLOW_SHADOW] : void 0;
13269
+ const shadows2 = o.shadows;
13270
+ const glow = shadows2 && typeof shadows2 === "object" && !Array.isArray(shadows2) ? shadows2[BRAND_GLOW_SHADOW] : void 0;
13271
13271
  if (glow && typeof glow === "object" && !Array.isArray(glow) && "color" in glow) {
13272
13272
  delete glow.color;
13273
- if (Object.keys(glow).length === 0) delete shadows[BRAND_GLOW_SHADOW];
13274
- if (Object.keys(shadows).length === 0) delete o.shadows;
13273
+ if (Object.keys(glow).length === 0) delete shadows2[BRAND_GLOW_SHADOW];
13274
+ if (Object.keys(shadows2).length === 0) delete o.shadows;
13275
13275
  }
13276
13276
  }
13277
13277
  }
@@ -13363,9 +13363,9 @@ function tokenColorIssues(dir, tokensPathOverride) {
13363
13363
  error(`${tokensPath}: must be an object`);
13364
13364
  return issues;
13365
13365
  }
13366
- const shadows = raw.shadows;
13367
- if (shadows !== null && typeof shadows === "object" && !Array.isArray(shadows)) {
13368
- for (const [name, token] of Object.entries(shadows)) {
13366
+ const shadows2 = raw.shadows;
13367
+ if (shadows2 !== null && typeof shadows2 === "object" && !Array.isArray(shadows2)) {
13368
+ for (const [name, token] of Object.entries(shadows2)) {
13369
13369
  const value = token?.color;
13370
13370
  if (value === void 0) continue;
13371
13371
  if (typeof value === "string" && isCanonicalHex(value)) continue;
@@ -19946,6 +19946,7 @@ function deriveAppMeta(name, m, platforms = {}) {
19946
19946
  drawer: config.navigation?.drawer,
19947
19947
  navKind: config.navigation?.navKind,
19948
19948
  orientation: config.navigation?.orientation,
19949
+ cache: config.cache,
19949
19950
  sidebar: config.navigation?.sidebar,
19950
19951
  navLogicBundle: config.navigation?.navLogicBundle,
19951
19952
  appIconBadgeSources: config.navigation?.appIconBadgeSources,
@@ -24718,6 +24719,7 @@ function shouldRevealError(args) {
24718
24719
  var EMAIL_RE, URL_HOST_RE, INTEGER_RE, NUMBER_RE;
24719
24720
  var init_validation = __esm({
24720
24721
  "../../core/ts/src/validation.ts"() {
24722
+ "use strict";
24721
24723
  EMAIL_RE = /^[A-Za-z0-9._%+-]+@[A-Za-z0-9-]+(\.[A-Za-z0-9-]+)*\.[A-Za-z]{2,}$/;
24722
24724
  URL_HOST_RE = /^[A-Za-z0-9-]+(\.[A-Za-z0-9-]+)*(:[0-9]+)?$/;
24723
24725
  INTEGER_RE = /^[+-]?[0-9]+$/;
@@ -29118,6 +29120,7 @@ function validateWorkerSubtree(raw, slotId, policy, actionCatalog) {
29118
29120
  var WORKER_SUBTREE_CEILINGS, ID_PART, ACTION_ID;
29119
29121
  var init_worker_subtree = __esm({
29120
29122
  "../../core/ts/src/worker-subtree.ts"() {
29123
+ "use strict";
29121
29124
  init_worker_subtree_safe_types_generated();
29122
29125
  WORKER_SUBTREE_CEILINGS = Object.freeze({
29123
29126
  maxEncodedBytes: 65536,
@@ -36087,6 +36090,108 @@ var init_render_fonts = __esm({
36087
36090
  }
36088
36091
  });
36089
36092
 
36093
+ // ../../core/dev-server/src/wix-cache-defaults.generated.ts
36094
+ var PLATFORM_DEFAULT_WIX_CACHE_RULES;
36095
+ var init_wix_cache_defaults_generated = __esm({
36096
+ "../../core/dev-server/src/wix-cache-defaults.generated.ts"() {
36097
+ PLATFORM_DEFAULT_WIX_CACHE_RULES = [
36098
+ { method: "POST", pathPrefix: "/_api/bookings/v2/services/search", cacheable: true, ttl: 60, swr: 86400, tag: "bookings/services" },
36099
+ { method: "POST", pathPrefix: "/blog/v3/categories/query", cacheable: true, ttl: 60, swr: 86400, tag: "blog" },
36100
+ { method: "GET", pathPrefix: "/blog/v3/posts/", cacheable: true, ttl: 60, swr: 86400, tag: "blog" },
36101
+ { method: "POST", pathPrefix: "/blog/v3/posts/query", cacheable: true, ttl: 60, swr: 86400, tag: "blog" },
36102
+ { method: "GET", pathPrefix: "/bookings/v2/services/", cacheable: true, ttl: 60, swr: 86400, tag: "bookings/services" },
36103
+ { method: "POST", pathPrefix: "/bookings/v2/services/query", cacheable: true, ttl: 60, swr: 86400, tag: "bookings/services" },
36104
+ { method: "GET", pathPrefix: "/donation-campaigns/v2/donation-campaigns/", cacheable: true, ttl: 60, swr: 86400, tag: "donations" },
36105
+ { method: "POST", pathPrefix: "/donation-campaigns/v2/donation-campaigns/query", cacheable: true, ttl: 60, swr: 86400, tag: "donations" },
36106
+ { method: "GET", pathPrefix: "/events/v3/events/", cacheable: true, ttl: 60, swr: 86400, tag: "events" },
36107
+ { method: "GET", pathPrefix: "/events/v3/events/category/", cacheable: true, ttl: 60, swr: 86400, tag: "events" },
36108
+ { method: "POST", pathPrefix: "/events/v3/events/query", cacheable: true, ttl: 60, swr: 86400, tag: "events" },
36109
+ { method: "GET", pathPrefix: "/events/v3/events/slug/", cacheable: true, ttl: 60, swr: 86400, tag: "events" },
36110
+ { method: "GET", pathPrefix: "/faq/v2/categories", cacheable: true, ttl: 60, swr: 86400, tag: "faq" },
36111
+ { method: "GET", pathPrefix: "/faq/v2/categories/", cacheable: true, ttl: 60, swr: 86400, tag: "faq" },
36112
+ { method: "POST", pathPrefix: "/faq/v2/categories/query", cacheable: true, ttl: 60, swr: 86400, tag: "faq" },
36113
+ { method: "GET", pathPrefix: "/faq/v2/question-entries", cacheable: true, ttl: 60, swr: 86400, tag: "faq" },
36114
+ { method: "GET", pathPrefix: "/faq/v2/question-entries/", cacheable: true, ttl: 60, swr: 86400, tag: "faq" },
36115
+ { method: "POST", pathPrefix: "/faq/v2/question-entries/query", cacheable: true, ttl: 60, swr: 86400, tag: "faq" },
36116
+ { method: "POST", pathPrefix: "/online-programs/v3/programs/query", cacheable: true, ttl: 60, swr: 86400, tag: "online-programs" },
36117
+ { method: "GET", pathPrefix: "/portfolio/v1/collections", cacheable: true, ttl: 60, swr: 86400, tag: "portfolio" },
36118
+ { method: "GET", pathPrefix: "/portfolio/v1/collections/", cacheable: true, ttl: 60, swr: 86400, tag: "portfolio" },
36119
+ { method: "POST", pathPrefix: "/portfolio/v1/collections/query", cacheable: true, ttl: 60, swr: 86400, tag: "portfolio" },
36120
+ { method: "GET", pathPrefix: "/portfolio/v1/projects", cacheable: true, ttl: 60, swr: 86400, tag: "portfolio" },
36121
+ { method: "GET", pathPrefix: "/portfolio/v1/projects/", cacheable: true, ttl: 60, swr: 86400, tag: "portfolio" },
36122
+ { method: "POST", pathPrefix: "/portfolio/v1/projects/collections/query", cacheable: true, ttl: 60, swr: 86400, tag: "portfolio" },
36123
+ { method: "POST", pathPrefix: "/portfolio/v1/projects/query", cacheable: true, ttl: 60, swr: 86400, tag: "portfolio" },
36124
+ { method: "GET", pathPrefix: "/pricing-plans/v2/plans/public", cacheable: true, ttl: 60, swr: 86400, tag: "pricing-plans" },
36125
+ { method: "POST", pathPrefix: "/pricing-plans/v2/plans/public/query", cacheable: true, ttl: 60, swr: 86400, tag: "pricing-plans" },
36126
+ { method: "GET", pathPrefix: "/restaurants/menus/v1/items/", cacheable: true, ttl: 60, swr: 86400, tag: "restaurants/menus" },
36127
+ { method: "POST", pathPrefix: "/restaurants/menus/v1/items/query", cacheable: true, ttl: 60, swr: 86400, tag: "restaurants/menus" },
36128
+ { method: "GET", pathPrefix: "/restaurants/menus/v1/menus/", cacheable: true, ttl: 60, swr: 86400, tag: "restaurants/menus" },
36129
+ { method: "POST", pathPrefix: "/restaurants/menus/v1/menus/query", cacheable: true, ttl: 60, swr: 86400, tag: "restaurants/menus" },
36130
+ { method: "POST", pathPrefix: "/restaurants/menus/v1/sections/query", cacheable: true, ttl: 60, swr: 86400, tag: "restaurants/menus" },
36131
+ { method: "GET", pathPrefix: "/reviews/v1/reviews/", cacheable: true, ttl: 60, swr: 86400, tag: "reviews" },
36132
+ { method: "POST", pathPrefix: "/reviews/v1/reviews/query", cacheable: true, ttl: 60, swr: 86400, tag: "reviews" },
36133
+ { method: "GET", pathPrefix: "/stores/v1/products/", cacheable: true, ttl: 60, swr: 86400, tag: "stores/products" },
36134
+ { method: "POST", pathPrefix: "/stores/v1/products/query", cacheable: true, ttl: 60, swr: 86400, tag: "stores/products" },
36135
+ { method: "POST", pathPrefix: "/stores/v3/categories/query", cacheable: true, ttl: 60, swr: 86400, tag: "stores/categories" },
36136
+ { method: "GET", pathPrefix: "/stores/v3/products/", cacheable: true, ttl: 60, swr: 86400, tag: "stores/products" },
36137
+ { method: "POST", pathPrefix: "/stores/v3/products/query", cacheable: true, ttl: 60, swr: 86400, tag: "stores/products" },
36138
+ { method: "POST", pathPrefix: "/stores/v3/products/search", cacheable: true, ttl: 60, swr: 86400, tag: "stores/products" },
36139
+ { method: "DELETE", pathPrefix: "/blog/v3/categories", cacheable: false, ttl: 0, swr: 0, tag: "blog" },
36140
+ { method: "PATCH", pathPrefix: "/blog/v3/categories", cacheable: false, ttl: 0, swr: 0, tag: "blog" },
36141
+ { method: "POST", pathPrefix: "/blog/v3/categories", cacheable: false, ttl: 0, swr: 0, tag: "blog" },
36142
+ { method: "DELETE", pathPrefix: "/blog/v3/posts", cacheable: false, ttl: 0, swr: 0, tag: "blog" },
36143
+ { method: "PATCH", pathPrefix: "/blog/v3/posts", cacheable: false, ttl: 0, swr: 0, tag: "blog" },
36144
+ { method: "POST", pathPrefix: "/blog/v3/posts", cacheable: false, ttl: 0, swr: 0, tag: "blog" },
36145
+ { method: "DELETE", pathPrefix: "/bookings/v1/services", cacheable: false, ttl: 0, swr: 0, tag: "bookings/services" },
36146
+ { method: "POST", pathPrefix: "/bookings/v1/services", cacheable: false, ttl: 0, swr: 0, tag: "bookings/services" },
36147
+ { method: "PUT", pathPrefix: "/bookings/v1/services", cacheable: false, ttl: 0, swr: 0, tag: "bookings/services" },
36148
+ { method: "DELETE", pathPrefix: "/bookings/v2/services", cacheable: false, ttl: 0, swr: 0, tag: "bookings/services" },
36149
+ { method: "PATCH", pathPrefix: "/bookings/v2/services", cacheable: false, ttl: 0, swr: 0, tag: "bookings/services" },
36150
+ { method: "POST", pathPrefix: "/bookings/v2/services", cacheable: false, ttl: 0, swr: 0, tag: "bookings/services" },
36151
+ { method: "PATCH", pathPrefix: "/donation-campaigns/v2/donation-campaigns", cacheable: false, ttl: 0, swr: 0, tag: "donations" },
36152
+ { method: "POST", pathPrefix: "/donation-campaigns/v2/donation-campaigns", cacheable: false, ttl: 0, swr: 0, tag: "donations" },
36153
+ { method: "PATCH", pathPrefix: "/events/v1/events", cacheable: false, ttl: 0, swr: 0, tag: "events" },
36154
+ { method: "POST", pathPrefix: "/events/v1/events", cacheable: false, ttl: 0, swr: 0, tag: "events" },
36155
+ { method: "POST", pathPrefix: "/events/v1/events/orders", cacheable: false, ttl: 0, swr: 0, tag: "events" },
36156
+ { method: "DELETE", pathPrefix: "/events/v3/events", cacheable: false, ttl: 0, swr: 0, tag: "events" },
36157
+ { method: "POST", pathPrefix: "/events/v3/events", cacheable: false, ttl: 0, swr: 0, tag: "events" },
36158
+ { method: "POST", pathPrefix: "/events/v3/events/count-by-status", cacheable: false, ttl: 0, swr: 0, tag: "events" },
36159
+ { method: "DELETE", pathPrefix: "/faq/v2/categories", cacheable: false, ttl: 0, swr: 0, tag: "faq" },
36160
+ { method: "PATCH", pathPrefix: "/faq/v2/categories", cacheable: false, ttl: 0, swr: 0, tag: "faq" },
36161
+ { method: "POST", pathPrefix: "/faq/v2/categories", cacheable: false, ttl: 0, swr: 0, tag: "faq" },
36162
+ { method: "DELETE", pathPrefix: "/faq/v2/question-entries", cacheable: false, ttl: 0, swr: 0, tag: "faq" },
36163
+ { method: "PATCH", pathPrefix: "/faq/v2/question-entries", cacheable: false, ttl: 0, swr: 0, tag: "faq" },
36164
+ { method: "POST", pathPrefix: "/faq/v2/question-entries", cacheable: false, ttl: 0, swr: 0, tag: "faq" },
36165
+ { method: "DELETE", pathPrefix: "/online-programs/v3/programs", cacheable: false, ttl: 0, swr: 0, tag: "online-programs" },
36166
+ { method: "PATCH", pathPrefix: "/online-programs/v3/programs", cacheable: false, ttl: 0, swr: 0, tag: "online-programs" },
36167
+ { method: "POST", pathPrefix: "/online-programs/v3/programs", cacheable: false, ttl: 0, swr: 0, tag: "online-programs" },
36168
+ { method: "DELETE", pathPrefix: "/portfolio/v1/collections", cacheable: false, ttl: 0, swr: 0, tag: "portfolio" },
36169
+ { method: "POST", pathPrefix: "/portfolio/v1/collections", cacheable: false, ttl: 0, swr: 0, tag: "portfolio" },
36170
+ { method: "DELETE", pathPrefix: "/portfolio/v1/projects", cacheable: false, ttl: 0, swr: 0, tag: "portfolio" },
36171
+ { method: "PATCH", pathPrefix: "/portfolio/v1/projects", cacheable: false, ttl: 0, swr: 0, tag: "portfolio" },
36172
+ { method: "DELETE", pathPrefix: "/pricing-plans/v2/plans", cacheable: false, ttl: 0, swr: 0, tag: "pricing-plans" },
36173
+ { method: "PATCH", pathPrefix: "/pricing-plans/v2/plans", cacheable: false, ttl: 0, swr: 0, tag: "pricing-plans" },
36174
+ { method: "POST", pathPrefix: "/pricing-plans/v2/plans", cacheable: false, ttl: 0, swr: 0, tag: "pricing-plans" },
36175
+ { method: "DELETE", pathPrefix: "/restaurants/menus/v1/sections", cacheable: false, ttl: 0, swr: 0, tag: "restaurants/menus" },
36176
+ { method: "PATCH", pathPrefix: "/restaurants/menus/v1/sections", cacheable: false, ttl: 0, swr: 0, tag: "restaurants/menus" },
36177
+ { method: "POST", pathPrefix: "/restaurants/menus/v1/sections", cacheable: false, ttl: 0, swr: 0, tag: "restaurants/menus" },
36178
+ { method: "DELETE", pathPrefix: "/reviews/v1/reviews", cacheable: false, ttl: 0, swr: 0, tag: "reviews" },
36179
+ { method: "PATCH", pathPrefix: "/reviews/v1/reviews", cacheable: false, ttl: 0, swr: 0, tag: "reviews" },
36180
+ { method: "POST", pathPrefix: "/reviews/v1/reviews", cacheable: false, ttl: 0, swr: 0, tag: "reviews" },
36181
+ { method: "POST", pathPrefix: "/reviews/v1/reviews/count", cacheable: false, ttl: 0, swr: 0, tag: "reviews" },
36182
+ { method: "DELETE", pathPrefix: "/stores/v1/products", cacheable: false, ttl: 0, swr: 0, tag: "stores/products" },
36183
+ { method: "PATCH", pathPrefix: "/stores/v1/products", cacheable: false, ttl: 0, swr: 0, tag: "stores/products" },
36184
+ { method: "POST", pathPrefix: "/stores/v1/products", cacheable: false, ttl: 0, swr: 0, tag: "stores/products" },
36185
+ { method: "DELETE", pathPrefix: "/stores/v3/categories", cacheable: false, ttl: 0, swr: 0, tag: "stores/categories" },
36186
+ { method: "PATCH", pathPrefix: "/stores/v3/categories", cacheable: false, ttl: 0, swr: 0, tag: "stores/categories" },
36187
+ { method: "POST", pathPrefix: "/stores/v3/categories", cacheable: false, ttl: 0, swr: 0, tag: "stores/categories" },
36188
+ { method: "DELETE", pathPrefix: "/stores/v3/products", cacheable: false, ttl: 0, swr: 0, tag: "stores/products" },
36189
+ { method: "PATCH", pathPrefix: "/stores/v3/products", cacheable: false, ttl: 0, swr: 0, tag: "stores/products" },
36190
+ { method: "POST", pathPrefix: "/stores/v3/products", cacheable: false, ttl: 0, swr: 0, tag: "stores/products" }
36191
+ ];
36192
+ }
36193
+ });
36194
+
36090
36195
  // ../../core/dev-server/src/wix-cache-policy.ts
36091
36196
  function clampRule(rule, denyPrefixes, maxTTL) {
36092
36197
  const denied2 = denyPrefixes.some((p) => rule.pathPrefix.startsWith(p));
@@ -36096,15 +36201,61 @@ function clampRule(rule, denyPrefixes, maxTTL) {
36096
36201
  ttl: Math.min(rule.ttl, maxTTL)
36097
36202
  };
36098
36203
  }
36099
- function resolveWixCachePolicy(appName2) {
36100
- const appRules = CACHE_OVERRIDES[appName2] ?? [];
36101
- const rules = appRules.map((r) => clampRule(r, PLATFORM_DENY_PREFIXES, PLATFORM_MAX_TTL));
36102
- return { rules, defaultCacheable: false };
36204
+ function shadows(own3, dflt) {
36205
+ const methodCovers = own3.method === null || own3.method.toUpperCase() === (dflt.method ?? "").toUpperCase();
36206
+ return methodCovers && dflt.pathPrefix.startsWith(own3.pathPrefix);
36207
+ }
36208
+ function resolveWixCachePolicy(appName2, declared) {
36209
+ const own3 = (declared?.rules ?? []).map((r) => ({
36210
+ method: r.method ?? null,
36211
+ pathPrefix: r.pathPrefix,
36212
+ cacheable: r.cacheable,
36213
+ ttl: r.ttl,
36214
+ swr: r.swr ?? 0,
36215
+ tag: r.tag ?? null
36216
+ }));
36217
+ const legacy = CACHE_OVERRIDES[appName2] ?? [];
36218
+ const appLevel = [...own3, ...legacy];
36219
+ const defaults = declared?.platformDefaults === false ? [] : PLATFORM_DEFAULT_WIX_CACHE_RULES.filter((d) => !appLevel.some((a) => shadows(a, d)));
36220
+ const denies = [
36221
+ ...[...PLATFORM_DENY_PREFIXES, ...PERSONAL_DATA_PREFIXES].map((pathPrefix) => ({ method: null, pathPrefix, cacheable: false, ttl: 0, swr: 0, tag: null })),
36222
+ ...PERSONAL_DATA_READS.map(([method, pathPrefix]) => ({ method, pathPrefix, cacheable: false, ttl: 0, swr: 0, tag: null }))
36223
+ ];
36224
+ const rules = [...appLevel, ...defaults, ...denies].map((r) => clampRule(r, PLATFORM_DENY_PREFIXES, PLATFORM_MAX_TTL));
36225
+ return { rules, defaultCacheable: declared?.defaultCacheable ?? false };
36103
36226
  }
36104
- var PLATFORM_DENY_PREFIXES, PLATFORM_MAX_TTL, CACHE_OVERRIDES;
36227
+ var PLATFORM_DENY_PREFIXES, PERSONAL_DATA_PREFIXES, PERSONAL_DATA_READS, PLATFORM_MAX_TTL, CACHE_OVERRIDES;
36105
36228
  var init_wix_cache_policy = __esm({
36106
36229
  "../../core/dev-server/src/wix-cache-policy.ts"() {
36230
+ init_wix_cache_defaults_generated();
36107
36231
  PLATFORM_DENY_PREFIXES = ["/stores/v2/orders", "/stores/v3/orders"];
36232
+ PERSONAL_DATA_PREFIXES = [
36233
+ "/ecom/v1/carts",
36234
+ "/ecom/v1/checkouts",
36235
+ "/ecom/v1/orders",
36236
+ "/members/",
36237
+ "/contacts/",
36238
+ "/invoices/",
36239
+ "/bookings/v1/bookings",
36240
+ "/bookings/v2/bookings",
36241
+ "/events/v1/orders",
36242
+ "/events/v1/tickets",
36243
+ "/events/v2/rsvps",
36244
+ "/gift-cards/",
36245
+ "/loyalty/",
36246
+ "/inbox/",
36247
+ "/pricing-plans/v2/orders",
36248
+ // Every answer below depends on who is asking, like the ones above — the generator's
36249
+ // NEVER_CACHED set (codegen/wix/scripts/gen-cache-defaults.ts), which the platform-defaults
36250
+ // fixture pins. Denied HERE so an app opting into `defaultCacheable` cannot cache them either
36251
+ // (tests/wix-cache-policy.test.ts walks that fixture against the fallback).
36252
+ "/social-groups-proxy/",
36253
+ "/stores/v2/coupons",
36254
+ "/analytics/",
36255
+ "/site-list/",
36256
+ "/blog/v3/draft-posts"
36257
+ ];
36258
+ PERSONAL_DATA_READS = [["GET", "/events/v1/events/"]];
36108
36259
  PLATFORM_MAX_TTL = 3600;
36109
36260
  CACHE_OVERRIDES = {
36110
36261
  // The reference fixture exercises the cache-policy contract (products cacheable).
@@ -36255,7 +36406,7 @@ function deriveNavigationConfig(app, bundleCtx) {
36255
36406
  scheme: app.urlScheme,
36256
36407
  deepLinkPatterns: app.deepLinkPatterns ?? ov?.deepLinkPatterns ?? [],
36257
36408
  linkableScreens,
36258
- wixCachePolicy: resolveWixCachePolicy(appName2),
36409
+ wixCachePolicy: resolveWixCachePolicy(appName2, app.cache),
36259
36410
  // Fail-open baseline; tightened OTA via the admin app-config override. The
36260
36411
  // DESTINATION(s) are derived generically from the app's config (no app-name
36261
36412
  // special-casing) so the app chooses where telemetry goes via OTA:
@@ -57253,21 +57404,21 @@ var init_preview_assets_generated = __esm({
57253
57404
  "../../packages/serve/src/preview-assets.generated.ts"() {
57254
57405
  init_preview_assets_format();
57255
57406
  PREVIEW_ASSET_MANIFEST = [
57256
- { key: "assets/index-DRJmxLKY.js", contentType: "application/javascript; charset=utf-8", offset: 8, length: 1102618, sha256: "9976a79a9d6842770adfdc5605a486bef46bfe8a3570538b6f585fc1ef100f82" },
57257
- { key: "fonts/Roboto-LICENSE.txt", contentType: "application/octet-stream", offset: 1102626, length: 4610, sha256: "994062dd7af4186a739de55dd9e151c63b6301f8e2cbafc608d35c2e87da0cd2" },
57258
- { key: "fonts/Roboto-Variable.ttf", contentType: "font/ttf", offset: 1107236, length: 488584, sha256: "d7598e12c5dbef095ff8272cfc55da0250bd07fbdecbac8a530b9b277872a134" },
57259
- { key: "fonts/WixMadeforDisplay-Bold.ttf", contentType: "font/ttf", offset: 1595820, length: 90924, sha256: "ec4c7d63772d980d6e147b2df6215fd2737e4b04cebe0cf7e11dc695fb63cdcf" },
57260
- { key: "fonts/WixMadeforDisplay-ExtraBold.ttf", contentType: "font/ttf", offset: 1686744, length: 90984, sha256: "bf4c16a2774edd38a921edf3099469866cd74c094fd596f3fa4e81f54a04dfaa" },
57261
- { key: "fonts/WixMadeforDisplay-Medium.ttf", contentType: "font/ttf", offset: 1777728, length: 90980, sha256: "368faca44fb9f7207e4af784e94750b1ee59c1098b8689e0f4a918926f244fb5" },
57262
- { key: "fonts/WixMadeforDisplay-Regular.ttf", contentType: "font/ttf", offset: 1868708, length: 90872, sha256: "97ed8f1a6772abe26e3d8af5cecfc4b02faa94497d585b0398b5053b739a70c1" },
57263
- { key: "fonts/WixMadeforDisplay-SemiBold.ttf", contentType: "font/ttf", offset: 1959580, length: 90980, sha256: "642feab8a48ddf6c7a89d7c2a7c0edfa0e6e773f671287e460e222703563191e" },
57264
- { key: "fonts/WixMadeforText-Bold.ttf", contentType: "font/ttf", offset: 2050560, length: 108636, sha256: "37c179b4fefb63ea9637322b84583a2df53aa226c150294eea1675c14b1b8e29" },
57265
- { key: "fonts/WixMadeforText-ExtraBold.ttf", contentType: "font/ttf", offset: 2159196, length: 109084, sha256: "62e2fe4718129f36ecdb0ae4de385bd6b81ecc876146447167c6c140fad699a9" },
57266
- { key: "fonts/WixMadeforText-Medium.ttf", contentType: "font/ttf", offset: 2268280, length: 109048, sha256: "4ecf270136af928612c76fe4ebade91d8156975e5ea4c0cf9225501dd1788e02" },
57267
- { key: "fonts/WixMadeforText-Regular.ttf", contentType: "font/ttf", offset: 2377328, length: 107700, sha256: "dee56f09fd3efc127c1ea95557edc74110c1460a46287da36e0af25efd341ef5" },
57268
- { key: "fonts/WixMadeforText-SemiBold.ttf", contentType: "font/ttf", offset: 2485028, length: 88108, sha256: "dced97a77624bc5f8b1ae65850360908297f4588e09feb6f22792d29dc7e765b" },
57269
- { key: "index.html", contentType: "text/html; charset=utf-8", offset: 2573136, length: 4947, sha256: "1217e0b9a45c53ee3c35fd8dfe751a50b2276661a3e699efde98c17152c1b960" },
57270
- { key: "t5-frame.html", contentType: "text/html; charset=utf-8", offset: 2578083, length: 17209, sha256: "dffc9718e2faa63ae2cc919e0a842f585ed565aaaa7c53778e90379442c731b6" }
57407
+ { key: "assets/index-nG7b3MPu.js", contentType: "application/javascript; charset=utf-8", offset: 8, length: 1104209, sha256: "88839c5eb15058f706e50664752a75646d690de5148f8b504eb82c0f87a70a15" },
57408
+ { key: "fonts/Roboto-LICENSE.txt", contentType: "application/octet-stream", offset: 1104217, length: 4610, sha256: "994062dd7af4186a739de55dd9e151c63b6301f8e2cbafc608d35c2e87da0cd2" },
57409
+ { key: "fonts/Roboto-Variable.ttf", contentType: "font/ttf", offset: 1108827, length: 488584, sha256: "d7598e12c5dbef095ff8272cfc55da0250bd07fbdecbac8a530b9b277872a134" },
57410
+ { key: "fonts/WixMadeforDisplay-Bold.ttf", contentType: "font/ttf", offset: 1597411, length: 90924, sha256: "ec4c7d63772d980d6e147b2df6215fd2737e4b04cebe0cf7e11dc695fb63cdcf" },
57411
+ { key: "fonts/WixMadeforDisplay-ExtraBold.ttf", contentType: "font/ttf", offset: 1688335, length: 90984, sha256: "bf4c16a2774edd38a921edf3099469866cd74c094fd596f3fa4e81f54a04dfaa" },
57412
+ { key: "fonts/WixMadeforDisplay-Medium.ttf", contentType: "font/ttf", offset: 1779319, length: 90980, sha256: "368faca44fb9f7207e4af784e94750b1ee59c1098b8689e0f4a918926f244fb5" },
57413
+ { key: "fonts/WixMadeforDisplay-Regular.ttf", contentType: "font/ttf", offset: 1870299, length: 90872, sha256: "97ed8f1a6772abe26e3d8af5cecfc4b02faa94497d585b0398b5053b739a70c1" },
57414
+ { key: "fonts/WixMadeforDisplay-SemiBold.ttf", contentType: "font/ttf", offset: 1961171, length: 90980, sha256: "642feab8a48ddf6c7a89d7c2a7c0edfa0e6e773f671287e460e222703563191e" },
57415
+ { key: "fonts/WixMadeforText-Bold.ttf", contentType: "font/ttf", offset: 2052151, length: 108636, sha256: "37c179b4fefb63ea9637322b84583a2df53aa226c150294eea1675c14b1b8e29" },
57416
+ { key: "fonts/WixMadeforText-ExtraBold.ttf", contentType: "font/ttf", offset: 2160787, length: 109084, sha256: "62e2fe4718129f36ecdb0ae4de385bd6b81ecc876146447167c6c140fad699a9" },
57417
+ { key: "fonts/WixMadeforText-Medium.ttf", contentType: "font/ttf", offset: 2269871, length: 109048, sha256: "4ecf270136af928612c76fe4ebade91d8156975e5ea4c0cf9225501dd1788e02" },
57418
+ { key: "fonts/WixMadeforText-Regular.ttf", contentType: "font/ttf", offset: 2378919, length: 107700, sha256: "dee56f09fd3efc127c1ea95557edc74110c1460a46287da36e0af25efd341ef5" },
57419
+ { key: "fonts/WixMadeforText-SemiBold.ttf", contentType: "font/ttf", offset: 2486619, length: 88108, sha256: "dced97a77624bc5f8b1ae65850360908297f4588e09feb6f22792d29dc7e765b" },
57420
+ { key: "index.html", contentType: "text/html; charset=utf-8", offset: 2574727, length: 4947, sha256: "5c0a3e1b1d5bda7b6bc8cc2a025321bf6d0aa74d1f14b073861f188fd7b13a8b" },
57421
+ { key: "t5-frame.html", contentType: "text/html; charset=utf-8", offset: 2579674, length: 17209, sha256: "dffc9718e2faa63ae2cc919e0a842f585ed565aaaa7c53778e90379442c731b6" }
57271
57422
  ];
57272
57423
  }
57273
57424
  });
@@ -59412,7 +59563,7 @@ var init_push_send = __esm({
59412
59563
  });
59413
59564
 
59414
59565
  // ../../core/serve-control/src/push-send-service.ts
59415
- var PUSH_SEND_ERROR_CODES;
59566
+ var PUSH_SEND_ERROR_CODES, PushSendError;
59416
59567
  var init_push_send_service = __esm({
59417
59568
  "../../core/serve-control/src/push-send-service.ts"() {
59418
59569
  PUSH_SEND_ERROR_CODES = [
@@ -59454,6 +59605,160 @@ var init_push_send_service = __esm({
59454
59605
  "ping_rate_limited",
59455
59606
  "send_outcome_unknown"
59456
59607
  ];
59608
+ PushSendError = class extends Error {
59609
+ constructor(code, status, retryAfterSec) {
59610
+ super(code);
59611
+ this.code = code;
59612
+ this.status = status;
59613
+ this.retryAfterSec = retryAfterSec;
59614
+ }
59615
+ };
59616
+ }
59617
+ });
59618
+
59619
+ // ../../core/serve-control/src/site-member.ts
59620
+ async function assertOwnerSiteToken(input, fetchImpl = input.fetch ?? fetch) {
59621
+ const info2 = await upstreamJson(fetchImpl, {
59622
+ path: "/oauth2/token-info",
59623
+ body: { token: input.siteToken },
59624
+ unavailable: "site_token_unverifiable",
59625
+ // An expired, revoked or malformed token is answered with a 4xx: the caller's to fix, not an outage.
59626
+ rejected: { code: "site_token_invalid", when: (status) => status >= 400 && status < 500 }
59627
+ });
59628
+ const owned = info2.active === true && info2.subjectType === "USER" && info2.siteId === input.site && info2.accountId === input.ownerAccountId;
59629
+ if (!owned) throw new PushSendError("site_token_invalid", 403);
59630
+ }
59631
+ async function upstreamJson(fetchImpl, call) {
59632
+ let response;
59633
+ try {
59634
+ response = await fetchImpl(`${WIXAPIS}${call.path}`, {
59635
+ method: "POST",
59636
+ redirect: "error",
59637
+ signal: AbortSignal.timeout(TIMEOUT_MS2),
59638
+ headers: {
59639
+ "content-type": "application/json",
59640
+ accept: "application/json",
59641
+ ...call.authorization ? { Authorization: call.authorization } : {},
59642
+ ...call.siteId ? { "wix-site-id": call.siteId } : {}
59643
+ },
59644
+ body: JSON.stringify(call.body)
59645
+ });
59646
+ } catch {
59647
+ throw new PushSendError(call.unavailable, 503);
59648
+ }
59649
+ if (call.rejected?.when(response.status)) throw new PushSendError(call.rejected.code, 403);
59650
+ if (!response.ok) throw new PushSendError(call.unavailable, 503);
59651
+ try {
59652
+ return await response.json();
59653
+ } catch {
59654
+ throw new PushSendError(call.unavailable, 503);
59655
+ }
59656
+ }
59657
+ var WIXAPIS, TIMEOUT_MS2;
59658
+ var init_site_member = __esm({
59659
+ "../../core/serve-control/src/site-member.ts"() {
59660
+ init_push_send_service();
59661
+ WIXAPIS = "https://www.wixapis.com";
59662
+ TIMEOUT_MS2 = 1e4;
59663
+ }
59664
+ });
59665
+
59666
+ // src/notify-ping-all.ts
59667
+ import { createHash as createHash31 } from "node:crypto";
59668
+ async function listApprovedMembers(input) {
59669
+ const first = await scanMembers(input);
59670
+ const second = await scanMembers(input);
59671
+ if (JSON.stringify(first.fingerprint) !== JSON.stringify(second.fingerprint)) throw new Error("member_roster_unstable");
59672
+ return second.recipients;
59673
+ }
59674
+ async function scanMembers(input) {
59675
+ const recipients = [];
59676
+ const fingerprint = [];
59677
+ const seenIds = /* @__PURE__ */ new Set();
59678
+ const seenEmails = /* @__PURE__ */ new Set();
59679
+ const fetchImpl = input.fetchImpl ?? fetch;
59680
+ for (let offset = 0; ; ) {
59681
+ let response;
59682
+ try {
59683
+ response = await fetchImpl(`${WIXAPIS2}/members/v1/members/query`, {
59684
+ method: "POST",
59685
+ headers: { Authorization: input.siteToken, "wix-site-id": input.site, "content-type": "application/json", accept: "application/json" },
59686
+ redirect: "error",
59687
+ signal: AbortSignal.timeout(1e4),
59688
+ body: JSON.stringify({ query: { paging: { limit: PAGE_SIZE, offset } }, fieldsets: ["FULL"] })
59689
+ });
59690
+ } catch {
59691
+ throw new Error("member_lookup_unavailable");
59692
+ }
59693
+ if (!response.ok) throw new Error("member_lookup_unavailable");
59694
+ let raw;
59695
+ try {
59696
+ raw = await response.json();
59697
+ } catch {
59698
+ throw new Error("member_lookup_unavailable");
59699
+ }
59700
+ if (raw === null || typeof raw !== "object" || Array.isArray(raw)) throw new Error("member_lookup_unavailable");
59701
+ const result = raw;
59702
+ if (!Array.isArray(result.members)) throw new Error("member_lookup_unavailable");
59703
+ if (result.members.length === 0) return { recipients, fingerprint };
59704
+ if (result.members.length > PAGE_SIZE) throw new Error("member_roster_unstable");
59705
+ for (const member of result.members) {
59706
+ if (member === null || typeof member !== "object" || Array.isArray(member)) throw new Error("member_lookup_unavailable");
59707
+ if (typeof member.id !== "string" || !member.id || seenIds.has(member.id)) throw new Error("member_roster_unstable");
59708
+ seenIds.add(member.id);
59709
+ fingerprint.push(JSON.stringify([member.id, member.loginEmail, member.contactId, member.status]));
59710
+ if (member.status !== "APPROVED") continue;
59711
+ if (typeof member.loginEmail !== "string" || !member.loginEmail || typeof member.contactId !== "string" || !member.contactId) throw new Error("member_roster_incomplete");
59712
+ const email = member.loginEmail.toLowerCase();
59713
+ if (seenEmails.has(email)) throw new Error("member_ambiguous");
59714
+ seenEmails.add(email);
59715
+ recipients.push({ id: member.id, email: member.loginEmail });
59716
+ }
59717
+ offset += result.members.length;
59718
+ }
59719
+ }
59720
+ function campaignRequestId(campaignId, memberId) {
59721
+ const bytes2 = createHash31("sha256").update(JSON.stringify(["himi-push-campaign", campaignId, memberId])).digest().subarray(0, 16);
59722
+ bytes2[6] = bytes2[6] & 15 | 80;
59723
+ bytes2[8] = bytes2[8] & 63 | 128;
59724
+ const hex2 = bytes2.toString("hex");
59725
+ return `${hex2.slice(0, 8)}-${hex2.slice(8, 12)}-${hex2.slice(12, 16)}-${hex2.slice(16, 20)}-${hex2.slice(20)}`;
59726
+ }
59727
+ async function sendCampaign(input) {
59728
+ let accepted = 0;
59729
+ let deduplicated = 0;
59730
+ for (const [index, recipient] of input.recipients.entries()) {
59731
+ if (index > 0) await input.wait(6100);
59732
+ const requestId2 = campaignRequestId(input.campaignId, recipient.id);
59733
+ let outcome = await input.send(recipient, requestId2);
59734
+ let retries = 0;
59735
+ while (outcome.state === "rate_limited" && outcome.retryAfterSec > 0 && retries < 3) {
59736
+ retries += 1;
59737
+ await input.wait(outcome.retryAfterSec * 1e3);
59738
+ outcome = await input.send(recipient, requestId2);
59739
+ }
59740
+ if (outcome.state !== "accepted") {
59741
+ throw new CampaignFailure(outcome.state === "failed" ? outcome.code : "rate_limited", index, recipient.email);
59742
+ }
59743
+ if (outcome.deduplicated) deduplicated += 1;
59744
+ else accepted += 1;
59745
+ input.onProgress?.(index + 1);
59746
+ }
59747
+ return { accepted, deduplicated };
59748
+ }
59749
+ var CampaignFailure, PAGE_SIZE, WIXAPIS2;
59750
+ var init_notify_ping_all = __esm({
59751
+ "src/notify-ping-all.ts"() {
59752
+ CampaignFailure = class extends Error {
59753
+ constructor(code, completed, memberEmail) {
59754
+ super(code);
59755
+ this.code = code;
59756
+ this.completed = completed;
59757
+ this.memberEmail = memberEmail;
59758
+ }
59759
+ };
59760
+ PAGE_SIZE = 100;
59761
+ WIXAPIS2 = "https://www.wixapis.com";
59457
59762
  }
59458
59763
  });
59459
59764
 
@@ -59471,8 +59776,11 @@ function refuse5(io, error, hint, exit = 2, extra = {}) {
59471
59776
  async function runNotifyPing(flags, io, deps = {}) {
59472
59777
  const flagError = flagRefusal(flags);
59473
59778
  if (flagError) return refuse5(io, flagError);
59779
+ const allMembers = flags["all-members"] === true;
59780
+ if (allMembers && text7(flags["member-email"])) return refuse5(io, "recipient_conflict", "Choose --all-members or --member-email.");
59781
+ if (allMembers && flags["dry-run"] !== true && flags.yes !== true) return refuse5(io, "confirmation_required", "Preview with --dry-run, then add --yes to send to every approved member.");
59474
59782
  const input = mergePushInputs(pushInputsFromContent(resolve50(text7(flags.content) ?? process.cwd())), flags);
59475
- const missing = [...input.app ? [] : ["app"], ...input.site ? [] : ["site"], ...REQUIRED_FLAGS.filter((f) => !text7(flags[f]))];
59783
+ const missing = [...input.app ? [] : ["app"], ...input.site ? [] : ["site"], ...REQUIRED_FLAGS.filter((f) => !(allMembers && f === "member-email") && !text7(flags[f]))];
59476
59784
  if (missing.length) return refuse5(io, "needs_input", "Name the app and site (or --content), the member's login email, a title and a link.", 2, { missing });
59477
59785
  const requestId2 = text7(flags["request-id"]) ?? (deps.newRequestId ?? randomUUID5)();
59478
59786
  if (!UUID_RE.test(requestId2)) return refuse5(io, "invalid_request_id", "Reuse the requestId a previous send printed.");
@@ -59487,6 +59795,7 @@ async function runNotifyPing(flags, io, deps = {}) {
59487
59795
  } catch {
59488
59796
  return refuse5(io, "wix_site_token_required", "Run wix login as the site owner; the site token reads this site's members.", 1);
59489
59797
  }
59798
+ if (allMembers) return runAllMembers({ input: { app: ownership.slug, site: input.site }, siteToken: siteToken2, session, requestId: requestId2, flags, io, deps });
59490
59799
  const body = {
59491
59800
  app: ownership.slug,
59492
59801
  site: input.site,
@@ -59500,6 +59809,88 @@ async function runNotifyPing(flags, io, deps = {}) {
59500
59809
  const http = await pushSendRequest({ target: session.target, wixToken: session.wixToken, siteToken: siteToken2, body, previewTag: session.previewTag, fetchImpl: deps.fetchImpl });
59501
59810
  return report2(http, body, flags, io);
59502
59811
  }
59812
+ async function runAllMembers(args) {
59813
+ const { input, siteToken: siteToken2, session, requestId: requestId2, flags, io, deps } = args;
59814
+ const ownerAccountId = decodeControlTokenClaims(session.controlToken)?.sub;
59815
+ if (!ownerAccountId) return refuse5(io, "owner_login_required");
59816
+ const readiness = await pushSetupRequest({
59817
+ target: session.target,
59818
+ wixToken: session.wixToken,
59819
+ operation: "status",
59820
+ query: input,
59821
+ previewTag: session.previewTag,
59822
+ fetchImpl: deps.fetchImpl
59823
+ });
59824
+ if (!readiness.ok) {
59825
+ const reported = String(readiness.body?.error ?? "");
59826
+ const code = KNOWN_CODES.has(reported) ? reported : "push_setup_unavailable";
59827
+ return refuse5(io, code, HINTS[code], 1);
59828
+ }
59829
+ if (readiness.body?.app !== input.app || readiness.body?.site !== input.site || readiness.body?.state !== "ready") {
59830
+ return refuse5(io, "push_not_ready", HINTS.push_not_ready, 1);
59831
+ }
59832
+ let recipients;
59833
+ try {
59834
+ await assertOwnerSiteToken({
59835
+ site: input.site,
59836
+ siteToken: siteToken2,
59837
+ ownerAccountId,
59838
+ fetch: deps.fetchImpl
59839
+ });
59840
+ recipients = await listApprovedMembers({ site: input.site, siteToken: siteToken2, fetchImpl: deps.fetchImpl });
59841
+ } catch (error) {
59842
+ const code = error instanceof PushSendError ? error.code : error instanceof Error && ROSTER_CODES.has(error.message) ? error.message : "member_lookup_unavailable";
59843
+ return refuse5(io, code, void 0, 1);
59844
+ }
59845
+ const base = { app: input.app, site: input.site, title: text7(flags.title), ...text7(flags.body) ? { body: text7(flags.body) } : {}, link: text7(flags.link) };
59846
+ const send2 = (recipient, memberRequestId, dryRun = false) => pushSendRequest({
59847
+ target: session.target,
59848
+ wixToken: session.wixToken,
59849
+ siteToken: siteToken2,
59850
+ previewTag: session.previewTag,
59851
+ fetchImpl: deps.fetchImpl,
59852
+ body: { ...base, memberEmail: recipient.email, requestId: memberRequestId, ...dryRun ? { dryRun: true } : {} }
59853
+ });
59854
+ if (flags["dry-run"] === true) {
59855
+ if (recipients.length) {
59856
+ const result = await send2(recipients[0], requestId2, true);
59857
+ const code = refusalCode(result);
59858
+ if (code) return refuse5(io, code, HINTS[code], 1);
59859
+ }
59860
+ io.log(JSON.stringify({ ok: true, state: "dry_run", campaignId: requestId2, recipients: recipients.length, sent: false }));
59861
+ return 0;
59862
+ }
59863
+ io.log(JSON.stringify({ ok: true, state: "started", campaignId: requestId2, recipients: recipients.length }));
59864
+ try {
59865
+ const result = await sendCampaign({
59866
+ recipients,
59867
+ campaignId: requestId2,
59868
+ wait: deps.wait ?? ((ms) => new Promise((resolve54) => setTimeout(resolve54, ms))),
59869
+ onProgress: (completed) => {
59870
+ if (completed % 10 === 0 || completed === recipients.length) {
59871
+ io.log(JSON.stringify({ ok: true, state: "progress", campaignId: requestId2, completed, recipients: recipients.length }));
59872
+ }
59873
+ },
59874
+ send: async (recipient, memberRequestId) => {
59875
+ const response = await send2(recipient, memberRequestId);
59876
+ const code = refusalCode(response);
59877
+ if (code === "rate_limited" && response.retryAfterSec) return { state: "rate_limited", retryAfterSec: response.retryAfterSec };
59878
+ if (code) return { state: "failed", code };
59879
+ return { state: "accepted", deduplicated: response.body?.deduplicated === true };
59880
+ }
59881
+ });
59882
+ io.log(JSON.stringify({ ok: true, state: "completed", campaignId: requestId2, recipients: recipients.length, ...result }));
59883
+ return 0;
59884
+ } catch (error) {
59885
+ if (!(error instanceof CampaignFailure)) return refuse5(io, "send_outcome_unknown", void 0, 1, { campaignId: requestId2 });
59886
+ const hint = error.code === "send_outcome_unknown" || error.code === "rate_limited" ? `Re-run the same command with --request-id ${requestId2} within Ping's 24-hour deduplication window.` : HINTS[error.code];
59887
+ return refuse5(io, error.code, hint, 1, {
59888
+ campaignId: requestId2,
59889
+ completed: error.completed,
59890
+ memberEmail: error.memberEmail
59891
+ });
59892
+ }
59893
+ }
59503
59894
  function flagRefusal(flags) {
59504
59895
  if (LOCAL_SENDER_FLAGS.some((f) => flags[f] !== void 0)) return "flag_not_supported_with_ping";
59505
59896
  if (SWITCHES.some((f) => flags[f] !== void 0 && typeof flags[f] !== "boolean")) return "invalid_boolean_flag";
@@ -59534,20 +59925,24 @@ function summary(result, sent) {
59534
59925
  }
59535
59926
  return `Ping accepted request ${sent.requestId} for ${sent.memberEmail}. Ping does not confirm delivery: it reaches the member's signed-in devices with notifications allowed.`;
59536
59927
  }
59537
- var LOCAL_SENDER_FLAGS, SWITCHES, REQUIRED_FLAGS, UUID_RE, KNOWN_CODES, HINTS, text7;
59928
+ var LOCAL_SENDER_FLAGS, SWITCHES, REQUIRED_FLAGS, UUID_RE, KNOWN_CODES, ROSTER_CODES, HINTS, text7;
59538
59929
  var init_notify_ping = __esm({
59539
59930
  "src/notify-ping.ts"() {
59540
59931
  init_push_send();
59932
+ init_push_setup();
59933
+ init_site_member();
59541
59934
  init_push_send_service();
59542
59935
  init_hosted_owner();
59936
+ init_notify_ping_all();
59543
59937
  init_owner_claim();
59544
59938
  init_push_onboarding();
59545
59939
  init_wix_owner();
59546
59940
  LOCAL_SENDER_FLAGS = ["token", "device", "all", "admin-url", "admin-session", "silent", "badge", "data", "category", "channel", "platform", "bundle-id"];
59547
- SWITCHES = ["json", "dry-run"];
59941
+ SWITCHES = ["json", "dry-run", "all-members"];
59548
59942
  REQUIRED_FLAGS = ["member-email", "title", "link"];
59549
59943
  UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
59550
59944
  KNOWN_CODES = new Set(PUSH_SEND_ERROR_CODES);
59945
+ ROSTER_CODES = /* @__PURE__ */ new Set(["member_lookup_unavailable", "member_roster_unstable", "member_roster_incomplete", "member_ambiguous"]);
59551
59946
  HINTS = {
59552
59947
  push_not_ready: "Run himi notify setup for this app and site first; status must be ready.",
59553
59948
  member_not_found: "Use the login email of an approved member of this site.",
@@ -63882,8 +64277,8 @@ async function applyOverlays(input) {
63882
64277
  if (bringsBrand) {
63883
64278
  const accent = tokens.colors?.accentPrimary;
63884
64279
  const primary = typeof accent === "string" ? accent : accent?.light;
63885
- const shadows = merged.shadows;
63886
- const glow = shadows && typeof shadows === "object" && !Array.isArray(shadows) ? shadows[BRAND_GLOW_SHADOW] : void 0;
64280
+ const shadows2 = merged.shadows;
64281
+ const glow = shadows2 && typeof shadows2 === "object" && !Array.isArray(shadows2) ? shadows2[BRAND_GLOW_SHADOW] : void 0;
63887
64282
  if (primary && glow && typeof glow.color === "string") glow.color = primary;
63888
64283
  stripBrandFromIdiom(merged);
63889
64284
  }
@@ -69498,7 +69893,7 @@ var init_context = __esm({
69498
69893
  import { mkdtempSync as mkdtempSync4, readFileSync as readFileSync80, mkdirSync as mkdirSync33, writeFileSync as writeFileSync29, existsSync as existsSync67, rmSync as rmSync16, readdirSync as readdirSync31, statSync as statSync19, lstatSync as lstatSync14, accessSync, constants as constants3, renameSync as renameSync8, cpSync as cpSync3 } from "node:fs";
69499
69894
  import { execFile, execFileSync as execFileSync7, spawnSync as spawnSync5, spawn as spawn7 } from "node:child_process";
69500
69895
  import { AsyncLocalStorage } from "node:async_hooks";
69501
- import { createHash as createHash31, randomUUID as randomUUID7 } from "node:crypto";
69896
+ import { createHash as createHash32, randomUUID as randomUUID7 } from "node:crypto";
69502
69897
  import { tmpdir as tmpdir5, homedir as homedir7, hostname } from "node:os";
69503
69898
  import { join as join65, resolve as resolve53, relative as relative14, basename as basename17, dirname as dirname37 } from "node:path";
69504
69899
  import { fileURLToPath as fileURLToPath26 } from "node:url";
@@ -71520,6 +71915,7 @@ var BOOLEAN_FLAGS = /* @__PURE__ */ new Set([
71520
71915
  "allow-destructive",
71521
71916
  "allow-draft",
71522
71917
  "all",
71918
+ "all-members",
71523
71919
  "all-screens",
71524
71920
  "ai",
71525
71921
  "binary",
@@ -71554,6 +71950,7 @@ var BOOLEAN_FLAGS = /* @__PURE__ */ new Set([
71554
71950
  "wait",
71555
71951
  "wix",
71556
71952
  "silent",
71953
+ "with-files",
71557
71954
  "include-disabled",
71558
71955
  "skip-build",
71559
71956
  "refresh",
@@ -72120,6 +72517,12 @@ var USAGE = `himi \u2014 the Himalaya authoring CLI (remote dev loop)
72120
72517
  wix login as the site owner, and a ready notify setup. Acceptance is not delivery.
72121
72518
  --dry-run checks ownership, member, link and readiness without sending. After an unknown
72122
72519
  outcome, re-run the same command with the printed --request-id; Ping never runs it twice.
72520
+ himi notify send --provider ping --target wix --app <a> --site <msid> --all-members
72521
+ --title <s> [--body <s>] --link <scheme>://screen/<id>[?\u2026] [--dry-run | --yes] [--request-id <uuid>]
72522
+ Sends to every approved site member with a login email. --dry-run counts recipients and
72523
+ checks one member's server gates; --yes is required to send. The CLI paces sends for the
72524
+ owner's 10/minute limit. Reuse the campaign ID with --request-id after an interrupted run
72525
+ within Ping's 24-hour deduplication window. Acceptance is not delivery.
72123
72526
  himi notify send --app <a> (--token <t> | --device <id> | --all) --title <s> [--body <s>] [--link <url>]
72124
72527
  deliver a REAL push notification to registered devices \u2014
72125
72528
  APNs (.p8) for iOS, FCM v1 for Android. --all fans out to
@@ -72312,7 +72715,7 @@ var COMMANDS = [
72312
72715
  { name: "icon", summary: "the app's LAUNCHER icon \u2014 the home-screen / store mark, which is BINARY-floor and never over-the-air (distinct from `himi icons`, the in-screen glyph vocabulary). `status`/`check` report what this app would actually ship and validate it against both stores: exact 1024x1024, no tRNS chunk, non-interlaced, and \u2014 when the optional image toolchain is installed \u2014 no transparent regions (Apple permits an alpha channel but not transparent pixels: ITMS-90717), no pre-masked corners, no letterboxed wordmark; they also print the store-policy checklist no checker can decide. `set <file.png>` installs supplied art, `from-site` installs the logo `himi site analyze` downloaded, and `generate` makes a gradient tile + glyph \u2014 all three trim, flatten onto the app's accent, write the 1024 opaque master plus the 512 Play listing icon (Play wants 32-bit WITH alpha, so it is a separate file), and DECLARE it in himalaya.content.json, without which the release bakes no icon at all", required: "[status|check] | set <file.png> | from-site [--book <dir>] | generate [--glyph <g>] [--accent <hex>] | glyphs [--content <dir>] [--json]" },
72313
72716
  { name: "login", summary: "obtain a scoped serve-control token from Wix identity and store it in ~/.himalaya/serve-targets.json (so push/promote need no hand-pasted token). Three modes: --browser (your own Wix account, no VPN/BO), --wix (HEADLESS \u2014 the machine's own Wix CLI credential; the mode a CI pod or agent container can satisfy), --dpx (Wix employee, reads ~/.dpx/session/token). RFC 0026 WS3.", required: "[--browser|--wix|--dpx] [--target <t>] [--issue-url <url>]" },
72314
72717
  { name: "logout", summary: "remove the stored control token for a target", required: "[--target <t>]" },
72315
- { name: "notify", summary: "`setup` optionally configures Branded/Ping from local customer key files; `status --refresh` reads live backend readiness. Setup may be deferred while building. These use serve-control and require owner plus Wix account authentication. `send`, `tokens`, `doctor`: send a REAL push notification to registered devices (RFC 0036 WS5) \u2014 APNs .p8 over HTTP/2 for iOS, FCM v1 for Android. `send` targets one device (--token / --device <registry id>) or fans out to the whole app (--all), reporting a per-device result; a token the provider says is uninstalled (APNs 410 Unregistered / FCM UNREGISTERED) is auto-disabled, while a merely wrong one (BadDeviceToken \u2014 usually a sandbox/production mismatch) is recorded and left enabled. `tokens` lists the registry. `doctor` reports which credentials resolve and which sender each platform picks. Talks to the admin-server via --admin-url/HIMALAYA_ADMIN_URL, authenticated with --admin-session/HIMALAYA_ADMIN_SESSION. `send --provider ping` is the hosted alternative: the serve plane sends one test notification to one site member through Ping as Himalaya, with owner login instead of provider keys, and reports acceptance, never delivery. NOT `himi push`, which publishes a release.", required: "setup|status [--content <dir>] [--target <t>] [--refresh] [--yes] [--no-push-setup] | send --provider ping [--content <dir>] [--app <a>] [--site <msid>] --member-email <email> --title <s> [--body <s>] --link <url> [--request-id <uuid>] [--dry-run] [--json] | send|tokens|doctor [--app <a>] [--token <t> | --device <id> | --all] [--title <s>] [--body <s>] [--link <url>] [--platform ios|android] [--badge <n>] [--channel <id>] [--silent] [--dry-run] [--json]" },
72718
+ { name: "notify", summary: "Hosted --all-members requires --yes for a live send; --dry-run checks ownership/readiness and counts approved recipients without sending. `setup` optionally configures Branded/Ping from local customer key files; `status --refresh` reads live backend readiness. Setup may be deferred while building. These use serve-control and require owner plus Wix account authentication. `send`, `tokens`, `doctor`: send a REAL push notification to registered devices (RFC 0036 WS5) \u2014 APNs .p8 over HTTP/2 for iOS, FCM v1 for Android. `send` targets one device (--token / --device <registry id>) or fans out to the whole app (--all), reporting a per-device result; a token the provider says is uninstalled (APNs 410 Unregistered / FCM UNREGISTERED) is auto-disabled, while a merely wrong one (BadDeviceToken \u2014 usually a sandbox/production mismatch) is recorded and left enabled. `tokens` lists the registry. `doctor` reports which credentials resolve and which sender each platform picks. Talks to the admin-server via --admin-url/HIMALAYA_ADMIN_URL, authenticated with --admin-session/HIMALAYA_ADMIN_SESSION. `send --provider ping` is the hosted alternative: the serve plane sends to one site member (--member-email) or all approved members (--all-members) through Ping as Himalaya, with owner login instead of provider keys, and reports acceptance, never delivery. NOT `himi push`, which publishes a release.", required: "setup|status [--content <dir>] [--target <t>] [--refresh] [--yes] [--no-push-setup] | send --provider ping [--content <dir>] [--app <a>] [--site <msid>] (--member-email <email> | --all-members (--dry-run | --yes)) --title <s> [--body <s>] --link <url> [--request-id <uuid>] [--dry-run] [--json] | send|tokens|doctor [--app <a>] [--token <t> | --device <id> | --all] [--title <s>] [--body <s>] [--link <url>] [--platform ios|android] [--badge <n>] [--channel <id>] [--silent] [--dry-run] [--json]" },
72316
72719
  { name: "site", summary: "PROVISION a Wix project, then analyze or extend it. `create` is the one door that makes a site instead of adopting one: POST /funnel/projects/v1/create (a WIX site, a HEADLESS backend, a BRANDED_APP, or a VIBE site), and for headless it also mints the OAuth app whose id IS the `WIX_CLIENT_ID` \u2014 with --redirect-uri already registered, because an unregistered redirect makes native signInDirect fail at redirect-session. `--verticals` REQUIRES `--template` and reports only what Wix confirmed: measured, installing onto a project created from the BLANK template returns 200 while the vertical's API answers 428 forever, because there is no site for it to attach to (the install asks for CREATE_SITE). A real template ships its verticals installed and populated, and installing further ones onto it then works. It MUTATES your Wix account and needs --yes; without it you get the payload and nothing is sent. `list` is the read-only site inventory (with each site's premium flag, which is what explains an installed-but-428 vertical). Auth is the account-scoped `wix token` (no --site), falling back to WIX_API_KEY + WIX_ACCOUNT_ID. `client` is the same OAuth step for a site that ALREADY exists \u2014 the one himi adopts rather than makes \u2014 so a clientId no longer means a manual trip to the dashboard: `client ensure` reconciles rather than mints, because a site can already carry a client with NO registered redirect and shipping that one fails signInDirect at runtime; it reuses a client that carries --redirect-uri, PATCHes one that matches --name but lacks it (unioning, so another app's redirect survives), and creates only when there is nothing to reuse (--new forces a fresh one). --name IS the idempotency key. `client` auth is SITE-scoped (`wix token --site <msid>`) because minting is owner-of-that-site, and --yes gates every mutation: a site that already has a usable client resolves WITHOUT it, but --write-provisioning needs --yes even then because it rewrites a manifest on disk (the dry run's planned.provisioning names the file). That query endpoint IGNORES paging (measured: query.paging, cursorPaging and a top-level paging all return the full set at offset 0), so when pagingMetadata reports more clients than came back, `ensure` REFUSES EVERY outcome \u2014 create, patch AND reuse. Reuse is refused too because pickClient breaks ties on the OLDEST createdDate, so an omitted older same-named MOBILE client with the same redirect would win a later complete read and the resolved clientId would MOVE between runs \u2014 and it gets written into provisioning.json; convergence is what makes a stray duplicate untidy rather than harmful. --name cannot narrow the query (no filter is sent; the name is applied to the rows after they arrive), so the recovery is the dashboard; --new skips the query entirely. A `patched` result is verified against what Wix STORED \u2014 the redirect list is read off the PATCH response, and re-read via GET when the response omits it, because falling back to the list himi just sent would make the guard pass vacuously on exactly the silent no-op it exists to catch. `client list` is the read-only inventory of a site's clients: act on its `shippable` column rather than `hasRedirect`, because shippable ALSO requires a MOBILE applicationType and `ensure` refuses a WEB client \u2014 a WEB one carrying your redirect looks right and is not a candidate \u2014 and it sets truncated:true rather than presenting a partial inventory as the whole one. `analyze --read-only` returns API-only generation context as JSON (identity, access probes, CMS permissions and selected redacted Velo source); it needs no URL/browser and never uploads or applies anything. `analyze` reads a site into a business-book folder (REST + Playwright, GET-only); `--url` alone is the visitor-only pass over the published pages, and `--client-id` adds the vertical probes and the app binding `--apply` requires; `site function` list/get/put/publish/invokes that site's Velo HTTP functions and is not `himi functions` (serve-plane jobs). `--apply` bakes into a brandable shell (a site shell needs no `--client-id`: it is visitor-only and binds no client); `--shell` takes the same names `himi dist --shell` does and defaults to branded-lite, and a shell that ships no prepare:customer is refused by name rather than half-built. `--shell brandy` (the site shell, RFC 0062) also derives the site's page map from its published pages and header menu \u2014 Home first, up to four tabs for the pages a visitor returns to, the rest in the drawer \u2014 into the overlay's `site` block, so it can be edited before `--apply`; only a site shell ever receives that block. It never overwrites any shell's committed apps/<shell>/provisioning.json.", required: "create <name> [--type wix|headless|branded-app|vibe] [--template <guid>] [--verticals stores,bookings,\u2026] [--folder <guid>] [--redirect-uri <uri>] [--no-oauth-app] [--write-provisioning [path]] [--site-url <url>] [--json] --yes | list | client ensure|list --site <msid> [--name <name>] [--redirect-uri <uri>] [--new] [--write-provisioning [path]] [--site-url <url>] [--json] --yes | analyze --read-only [--site <msid>] [--client-id <id>] [--json] | analyze --url <https> [--client-id <id>] [--site <msid>] [--out <dir>] [--redirect-uri <uri>] [--apply] [--shell " + SHELL_ENUM + "] | function list|get|put|publish|invoke [--site <msid>] [--url <https>] [--method GET|POST|PUT|DELETE] [--source <file>] [--body <json>] [--publish] [--invoke]" },
72317
72720
  { name: "doctor", summary: 'off-VPN preflight in one shot: probe the PUBLIC data plane (www.wixapis.com \u2014 reachable off-VPN), the INTERNAL serve/control plane for the selected target (VPN-gated), and report auth state (dpx session on disk + stored control token). --dpx additionally runs a live, EADDRINUSE-safe `dpx whoami`. Machine-readable with --json (an unreachable internal plane carries a stable code:"needs_vpn" so an agent branches on the code, not the prose); human-readable otherwise. Never loads the authoring runtime \u2014 works off-repo.', required: "[--target <t>] [--dpx] [--json] [--data-url <url>] [--timeout <ms>]" },
72318
72721
  { name: "upgrade", summary: "install the newest published CLI (`npm i -g @wix/himalaya-cli@latest`) and report what moved. This is the explicit door: himi also updates itself when the running build is more than a week old \u2014 unattended it just does it and re-runs your command, at a terminal it asks first \u2014 and `HIMI_NO_UPDATE_CHECK=1` turns that off, leaving this command as the way to catch up. Reports `unchanged` rather than claiming success when npm exits 0 without moving the version, which is what a registry mirror serving its own pinned copy looks like.", required: "[--json]" },
@@ -74611,7 +75014,7 @@ ${doNow.map((l) => ` ${l}`).join("\n")}`);
74611
75014
  try {
74612
75015
  const bytes2 = readFileSync80(iconPath);
74613
75016
  payload.icon = bytes2.toString("base64");
74614
- iconHash = createHash31("sha256").update(bytes2).digest("hex");
75017
+ iconHash = createHash32("sha256").update(bytes2).digest("hex");
74615
75018
  } catch {
74616
75019
  }
74617
75020
  }
@@ -76401,7 +76804,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
76401
76804
  let localSourceHash;
76402
76805
  try {
76403
76806
  const { collectAppSource: collectAppSource2, zipAppSource: zipAppSource2 } = await Promise.resolve().then(() => (init_app_source(), app_source_exports));
76404
- localSourceHash = createHash31("sha256").update(zipAppSource2(collectAppSource2(dir).entries).toString("base64")).digest("hex");
76807
+ localSourceHash = createHash32("sha256").update(zipAppSource2(collectAppSource2(dir).entries).toString("base64")).digest("hex");
76405
76808
  } catch {
76406
76809
  }
76407
76810
  return runReleasePatch({
@@ -78017,7 +78420,7 @@ default (no --glyph): ${DEFAULT_GLYPH2} \u2014 a mark that claims nothing, so th
78017
78420
  });
78018
78421
  }
78019
78422
  const bytes2 = readFileSync80(file);
78020
- const sha = createHash31("sha256").update(bytes2).digest("hex");
78423
+ const sha = createHash32("sha256").update(bytes2).digest("hex");
78021
78424
  const forScreens = (str8(flags["for-screen"]) ?? "").split(",").map((s) => s.trim()).filter(Boolean);
78022
78425
  if (flags["no-rebind"] !== void 0 && flags["no-rebind"] !== true) {
78023
78426
  io.error(JSON.stringify({ ok: false, error: "no_rebind_takes_no_value", message: "--no-rebind is a switch and takes no value; pass it bare.", usage: PATCH_USAGE }));