@wix/himalaya-cli 0.1231.0 → 0.1233.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 (22) hide show
  1. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/sdk/health/src/index.d.ts +93 -0
  2. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/sdk/sdk-types/src/capabilities.generated.d.ts +2 -1
  3. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/ts/src/define-app.d.ts +1 -1
  4. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/ts/src/wix-push-links.d.ts +9 -4
  5. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/audio-record.mjs +1 -0
  6. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/calendar.mjs +1 -0
  7. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/calls.mjs +1 -0
  8. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/contacts.mjs +1 -0
  9. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/health.mjs +127 -0
  10. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/location.mjs +1 -0
  11. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/motion.mjs +1 -0
  12. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/photos.mjs +1 -0
  13. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/sdk-types.mjs +1 -0
  14. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/tasks.mjs +1 -0
  15. package/dist/authoring-runtime/node_modules/@wix/himalaya/package.json +4 -0
  16. package/dist/cli.mjs +170 -26
  17. package/dist/preview-assets.generated.bin +0 -0
  18. package/guides/app-config.md +1 -1
  19. package/guides/importable-sdks.md +1 -0
  20. package/guides/push-cli-onboarding.md +7 -5
  21. package/guides/sdk-reference.json +145 -0
  22. package/package.json +2 -2
@@ -0,0 +1,93 @@
1
+ /** A readable health data type. */
2
+ export type HealthType = "steps" | "heartRate" | "activeEnergy" | "distance" | "workouts";
3
+ /** A writable health data type. v1 writes workouts only. */
4
+ export type HealthWriteType = "workouts";
5
+ export type HealthPermissionState = "granted" | "denied" | "notDetermined";
6
+ /** Aggregation bucket for `query`. Omitted ⇒ one total (cumulative types) or raw samples. */
7
+ export type HealthBucket = "hour" | "day";
8
+ export type WorkoutActivity = "running" | "walking" | "cycling" | "strength" | "other";
9
+ export type HealthErrorCode = "unavailable" | "not_authorized" | "invalid_argument" | "failed";
10
+ export declare const HEALTH_TYPES: readonly HealthType[];
11
+ export declare const WORKOUT_ACTIVITIES: readonly WorkoutActivity[];
12
+ /** The fixed unit each type's `value` is reported in. */
13
+ export declare const HEALTH_UNITS: Readonly<Record<HealthType, string>>;
14
+ export interface HealthAvailability {
15
+ available: boolean;
16
+ /** Why not, when `available` is false — e.g. "web has no health store",
17
+ * "Health Connect is not installed". */
18
+ reason?: string;
19
+ }
20
+ export interface HealthSample {
21
+ /** ISO-8601. */
22
+ start: string;
23
+ /** ISO-8601. */
24
+ end: string;
25
+ value: number;
26
+ unit: string;
27
+ /** Workouts only: the activity, mapped back onto the v1 set ("other" for anything else). */
28
+ activity?: WorkoutActivity;
29
+ }
30
+ export interface HealthQuery {
31
+ type: HealthType;
32
+ /** ISO-8601, inclusive. */
33
+ from: string;
34
+ /** ISO-8601, exclusive. */
35
+ to: string;
36
+ /** steps / activeEnergy / distance are SUMMED per bucket; heartRate is AVERAGED per bucket;
37
+ * workouts ignore it (one sample per workout). */
38
+ bucket?: HealthBucket;
39
+ }
40
+ export interface Workout {
41
+ activity: WorkoutActivity;
42
+ /** ISO-8601. */
43
+ start: string;
44
+ /** ISO-8601, after `start`. */
45
+ end: string;
46
+ energyKcal?: number;
47
+ distanceM?: number;
48
+ }
49
+ /** The typed rejection every verb throws. A plain Error carrying `code` — worker bundles are
50
+ * compiled to a target without class syntax, so this is a factory, not a subclass. */
51
+ export interface HealthError extends Error {
52
+ name: "HealthError";
53
+ code: HealthErrorCode;
54
+ }
55
+ /** Build a [HealthError] — what the binding throws for every native `{ error }` reply. */
56
+ export declare function healthError(code: HealthErrorCode, message: string): HealthError;
57
+ /** Narrow a caught value: `catch (e) { if (isHealthError(e) && e.code === "unavailable") … }`. */
58
+ export declare function isHealthError(e: unknown): e is HealthError;
59
+ /** Whether this device has a health store the app can reach. Call it first and branch. */
60
+ export declare function availability(): Promise<HealthAvailability>;
61
+ /**
62
+ * Prompt for read (and optionally write) access. Resolves with the types the platform
63
+ * reports as granted — on iOS a read type counts as granted once asked (see header).
64
+ * Writing workouts also covers the energy + distance samples a saved workout carries.
65
+ */
66
+ export declare function requestPermission(p: {
67
+ read: HealthType[];
68
+ write?: HealthWriteType[];
69
+ }): Promise<{
70
+ granted: HealthType[];
71
+ }>;
72
+ /** Current READ permission per type, without prompting. iOS reads are always "notDetermined". */
73
+ export declare function getPermissionStatus(p: {
74
+ types: HealthType[];
75
+ }): Promise<Record<HealthType, HealthPermissionState>>;
76
+ /** Read samples of one type over [from, to). */
77
+ export declare function query(p: HealthQuery): Promise<{
78
+ samples: HealthSample[];
79
+ }>;
80
+ /** Save a completed workout (with its energy/distance, when given). Resolves with its store id. */
81
+ export declare function saveWorkout(w: Workout): Promise<{
82
+ id: string;
83
+ }>;
84
+ export declare const version = 1;
85
+ /** The whole surface as one namespace: `import { health } from "@wix/himalaya/health"`. */
86
+ export declare const health: {
87
+ availability: typeof availability;
88
+ requestPermission: typeof requestPermission;
89
+ getPermissionStatus: typeof getPermissionStatus;
90
+ query: typeof query;
91
+ saveWorkout: typeof saveWorkout;
92
+ version: number;
93
+ };
@@ -14,6 +14,7 @@ export declare const CAPABILITY_REGISTRY: {
14
14
  readonly files: readonly ["list", "readText", "remove", "stat", "write"];
15
15
  readonly godot: readonly ["loadPack", "release", "send"];
16
16
  readonly haptic: readonly ["play"];
17
+ readonly health: readonly ["availability", "getPermissionStatus", "query", "requestPermission", "saveWorkout"];
17
18
  readonly himi_apps: readonly ["canOpen", "current", "hostInfo", "open"];
18
19
  readonly iap: readonly ["consume", "entitlements", "finishTransaction", "getPaywallConfig", "getProducts", "getUnfinishedTransactions", "purchase", "purchaseForVerification", "restore"];
19
20
  readonly keyboard: readonly ["dismiss"];
@@ -39,7 +40,7 @@ export declare const CAPABILITY_REGISTRY: {
39
40
  readonly wix_cashier: readonly ["isAvailable", "proceedToPayment"];
40
41
  };
41
42
  /** A capability id backed by an @himalaya/* SDK binding. */
42
- export type SdkCapability = "app_info" | "audio_record" | "base44" | "biometrics" | "browser_auth" | "calendar" | "calls" | "camera" | "clipboard" | "contacts" | "file_picker" | "files" | "godot" | "haptic" | "himi_apps" | "iap" | "keyboard" | "live_activity" | "local_database" | "location" | "media_playback" | "motion" | "on_device_ai" | "open_url" | "pdf" | "photos" | "presigned_upload" | "push" | "release_control" | "secure_storage" | "share" | "speaker_diarization" | "speech" | "system_intents" | "tasks" | "ui" | "wix_cashier";
43
+ export type SdkCapability = "app_info" | "audio_record" | "base44" | "biometrics" | "browser_auth" | "calendar" | "calls" | "camera" | "clipboard" | "contacts" | "file_picker" | "files" | "godot" | "haptic" | "health" | "himi_apps" | "iap" | "keyboard" | "live_activity" | "local_database" | "location" | "media_playback" | "motion" | "on_device_ai" | "open_url" | "pdf" | "photos" | "presigned_upload" | "push" | "release_control" | "secure_storage" | "share" | "speaker_diarization" | "speech" | "system_intents" | "tasks" | "ui" | "wix_cashier";
43
44
  /** All `capability.<id>.<verb>` action ids, flattened (the worker-bridge wire vocabulary). */
44
45
  export declare const CAPABILITY_ACTION_IDS: readonly string[];
45
46
  /** Capability id → the @himalaya/* package(s) a worker imports to reach it — every dispatch
@@ -734,7 +734,7 @@ export interface OrientationEnvelope {
734
734
  export declare const DEFAULT_ORIENTATION_ENVELOPE: Required<OrientationEnvelope>;
735
735
  /** Fill in the absent families. Total, so callers never branch on `undefined`. */
736
736
  export declare function resolveOrientationEnvelope(env?: OrientationEnvelope): Required<OrientationEnvelope>;
737
- export type Capability = "camera" | "barcode_scanner" | "biometrics" | "secure_storage" | "share" | "push" | "file_picker" | "files" | "open_url" | "pdf" | "clipboard" | "photos" | "presigned_upload" | "ui" | "calendar" | "contacts" | "tasks" | "audio_record" | "audio_record_background" | "calls" | "location" | "location_background" | "motion" | "media_playback" | "webview" | "browser_auth" | "haptic" | "himi_apps" | "iap" | "keyboard" | "wix_cashier" | "live_activity" | "local_database" | "speech" | "speaker_diarization" | "system_intents" | "on_device_ai" | "app_info" | "release_control" | "godot" | "base44";
737
+ export type Capability = "camera" | "barcode_scanner" | "biometrics" | "secure_storage" | "share" | "push" | "file_picker" | "files" | "open_url" | "pdf" | "clipboard" | "photos" | "presigned_upload" | "ui" | "calendar" | "contacts" | "tasks" | "audio_record" | "audio_record_background" | "calls" | "location" | "location_background" | "motion" | "health" | "media_playback" | "webview" | "browser_auth" | "haptic" | "himi_apps" | "iap" | "keyboard" | "wix_cashier" | "live_activity" | "local_database" | "speech" | "speaker_diarization" | "system_intents" | "on_device_ai" | "app_info" | "release_control" | "godot" | "base44";
738
738
  /** `defineApp({ base44 })` — which Base44 app `@himalaya/base44` talks to. */
739
739
  export interface Base44Config {
740
740
  /** The Base44 app id (24 hex chars, e.g. `69725232345f461f64ad1623`). */
@@ -1,10 +1,15 @@
1
1
  import type { PushRoute } from "./push-routes.js";
2
2
  /**
3
- * The Ping app family a customer app's members register under. Ping treats it exactly as
4
- * `WixBrandedLite`: member recipients, the site's own credentials by `filterForMetaSite`,
5
- * the BRANDED link format. One constant, so a revert is a one-line change.
3
+ * The Ping app family a customer app's members register under: member recipients, the site's own
4
+ * credentials by `filterForMetaSite`, the BRANDED link format. Not `WixWebShell`, the family Ping
5
+ * renamed `WixBrandedWebApp` to: a send with `isForBrandedApp` (Ping automations addressed to a
6
+ * contact, and the hosted test send) targets `Branded` and keeps only registrations whose family
7
+ * starts with `WixBranded` (`RegistrationsFetcher.getMobileRegistrationsForTarget`). One constant,
8
+ * so a change of family is a one-line change.
6
9
  */
7
- export declare const DEFAULT_PING_APP_NAME = "WixBrandedWebApp";
10
+ export declare const DEFAULT_PING_APP_NAME = "WixBrandedLite";
11
+ /** The family to register under instead of `name`, or undefined when `name` is not retired. */
12
+ export declare function replacementPingFamily(name: string): string | undefined;
8
13
  /** One place a member notification can open, and every Wix link shape that names it. */
9
14
  export interface WixPushDestination {
10
15
  /** `<vertical>.<thing>`, the key an author uses in `push.screens`. */
@@ -29,6 +29,7 @@ var CAPABILITY_REGISTRY = {
29
29
  "files": ["list", "readText", "remove", "stat", "write"],
30
30
  "godot": ["loadPack", "release", "send"],
31
31
  "haptic": ["play"],
32
+ "health": ["availability", "getPermissionStatus", "query", "requestPermission", "saveWorkout"],
32
33
  "himi_apps": ["canOpen", "current", "hostInfo", "open"],
33
34
  "iap": ["consume", "entitlements", "finishTransaction", "getPaywallConfig", "getProducts", "getUnfinishedTransactions", "purchase", "purchaseForVerification", "restore"],
34
35
  "keyboard": ["dismiss"],
@@ -29,6 +29,7 @@ var CAPABILITY_REGISTRY = {
29
29
  "files": ["list", "readText", "remove", "stat", "write"],
30
30
  "godot": ["loadPack", "release", "send"],
31
31
  "haptic": ["play"],
32
+ "health": ["availability", "getPermissionStatus", "query", "requestPermission", "saveWorkout"],
32
33
  "himi_apps": ["canOpen", "current", "hostInfo", "open"],
33
34
  "iap": ["consume", "entitlements", "finishTransaction", "getPaywallConfig", "getProducts", "getUnfinishedTransactions", "purchase", "purchaseForVerification", "restore"],
34
35
  "keyboard": ["dismiss"],
@@ -29,6 +29,7 @@ var CAPABILITY_REGISTRY = {
29
29
  "files": ["list", "readText", "remove", "stat", "write"],
30
30
  "godot": ["loadPack", "release", "send"],
31
31
  "haptic": ["play"],
32
+ "health": ["availability", "getPermissionStatus", "query", "requestPermission", "saveWorkout"],
32
33
  "himi_apps": ["canOpen", "current", "hostInfo", "open"],
33
34
  "iap": ["consume", "entitlements", "finishTransaction", "getPaywallConfig", "getProducts", "getUnfinishedTransactions", "purchase", "purchaseForVerification", "restore"],
34
35
  "keyboard": ["dismiss"],
@@ -29,6 +29,7 @@ var CAPABILITY_REGISTRY = {
29
29
  "files": ["list", "readText", "remove", "stat", "write"],
30
30
  "godot": ["loadPack", "release", "send"],
31
31
  "haptic": ["play"],
32
+ "health": ["availability", "getPermissionStatus", "query", "requestPermission", "saveWorkout"],
32
33
  "himi_apps": ["canOpen", "current", "hostInfo", "open"],
33
34
  "iap": ["consume", "entitlements", "finishTransaction", "getPaywallConfig", "getProducts", "getUnfinishedTransactions", "purchase", "purchaseForVerification", "restore"],
34
35
  "keyboard": ["dismiss"],
@@ -0,0 +1,127 @@
1
+ // ../../core/sdk/dispatch/src/index.ts
2
+ function dispatch(handlerId, params, _options) {
3
+ const himalaya = globalThis.himalaya;
4
+ if (!himalaya) {
5
+ return Promise.reject(
6
+ new Error("@himalaya/dispatch: called outside a Himalaya runtime. This bundle must run inside a JSWorker (Tier 5).")
7
+ );
8
+ }
9
+ const stringParams = {};
10
+ if (params) {
11
+ for (const [k, v] of Object.entries(params)) stringParams[k] = String(v);
12
+ }
13
+ return himalaya.dispatch(handlerId, stringParams);
14
+ }
15
+
16
+ // ../../core/sdk/health/src/index.ts
17
+ var HEALTH_TYPES = ["steps", "heartRate", "activeEnergy", "distance", "workouts"];
18
+ var WORKOUT_ACTIVITIES = ["running", "walking", "cycling", "strength", "other"];
19
+ var HEALTH_UNITS = {
20
+ steps: "count",
21
+ heartRate: "bpm",
22
+ activeEnergy: "kcal",
23
+ distance: "m",
24
+ workouts: "s"
25
+ };
26
+ function healthError(code, message) {
27
+ const e = new Error(message);
28
+ e.name = "HealthError";
29
+ e.code = code;
30
+ return e;
31
+ }
32
+ function isHealthError(e) {
33
+ return e instanceof Error && e.name === "HealthError" && typeof e.code === "string";
34
+ }
35
+ var ERROR_CODES = ["unavailable", "not_authorized", "invalid_argument", "failed"];
36
+ function unwrap(r) {
37
+ const err = r?.error;
38
+ if (err) {
39
+ const code = ERROR_CODES.includes(err.code ?? "") ? err.code : "failed";
40
+ throw healthError(code, err.message ?? code);
41
+ }
42
+ return r ?? {};
43
+ }
44
+ function assertTypes(types, allowed, what) {
45
+ for (const t of types) {
46
+ if (!allowed.includes(t)) throw healthError("invalid_argument", `health: unknown ${what} "${t}"`);
47
+ }
48
+ }
49
+ function assertRange(from, to) {
50
+ const a = Date.parse(from), b = Date.parse(to);
51
+ if (Number.isNaN(a) || Number.isNaN(b)) throw healthError("invalid_argument", "health: from/to must be ISO-8601");
52
+ if (b <= a) throw healthError("invalid_argument", "health: `to` must be after `from`");
53
+ }
54
+ async function availability() {
55
+ const r = await dispatch("capability.health.availability");
56
+ const out = { available: r?.available === true };
57
+ if (typeof r?.reason === "string" && r.reason) out.reason = r.reason;
58
+ return out;
59
+ }
60
+ async function requestPermission(p) {
61
+ const read = p.read ?? [];
62
+ const write = p.write ?? [];
63
+ assertTypes(read, HEALTH_TYPES, "read type");
64
+ assertTypes(write, ["workouts"], "write type");
65
+ const r = unwrap(
66
+ await dispatch("capability.health.requestPermission", { read: read.join(","), write: write.join(",") })
67
+ );
68
+ const granted = Array.isArray(r.granted) ? r.granted : [];
69
+ return { granted: granted.filter((t) => HEALTH_TYPES.includes(t)) };
70
+ }
71
+ async function getPermissionStatus(p) {
72
+ const types = p.types ?? [];
73
+ assertTypes(types, HEALTH_TYPES, "type");
74
+ const r = unwrap(
75
+ await dispatch("capability.health.getPermissionStatus", { types: types.join(",") })
76
+ );
77
+ const out = {};
78
+ for (const t of types) {
79
+ const s = r.statuses?.[t];
80
+ out[t] = s === "granted" || s === "denied" ? s : "notDetermined";
81
+ }
82
+ return out;
83
+ }
84
+ async function query(p) {
85
+ assertTypes([p.type], HEALTH_TYPES, "type");
86
+ assertRange(p.from, p.to);
87
+ if (p.bucket !== void 0 && p.bucket !== "hour" && p.bucket !== "day") {
88
+ throw healthError("invalid_argument", `health: unknown bucket "${String(p.bucket)}"`);
89
+ }
90
+ const params = { type: p.type, from: p.from, to: p.to };
91
+ if (p.bucket) params.bucket = p.bucket;
92
+ const r = unwrap(await dispatch("capability.health.query", params));
93
+ return { samples: Array.isArray(r.samples) ? r.samples : [] };
94
+ }
95
+ async function saveWorkout(w) {
96
+ assertTypes([w.activity], WORKOUT_ACTIVITIES, "activity");
97
+ assertRange(w.start, w.end);
98
+ const params = { activity: w.activity, start: w.start, end: w.end };
99
+ if (typeof w.energyKcal === "number") {
100
+ if (!Number.isFinite(w.energyKcal) || w.energyKcal < 0) throw healthError("invalid_argument", "health: energyKcal must be a finite number >= 0");
101
+ params.energyKcal = w.energyKcal;
102
+ }
103
+ if (typeof w.distanceM === "number") {
104
+ if (!Number.isFinite(w.distanceM) || w.distanceM < 0) throw healthError("invalid_argument", "health: distanceM must be a finite number >= 0");
105
+ params.distanceM = w.distanceM;
106
+ }
107
+ const r = unwrap(await dispatch("capability.health.saveWorkout", params));
108
+ if (!r.id) throw healthError("failed", "health.saveWorkout: native returned no id");
109
+ return { id: r.id };
110
+ }
111
+ var version = 1;
112
+ var health = { availability, requestPermission, getPermissionStatus, query, saveWorkout, version };
113
+ export {
114
+ HEALTH_TYPES,
115
+ HEALTH_UNITS,
116
+ WORKOUT_ACTIVITIES,
117
+ availability,
118
+ getPermissionStatus,
119
+ health,
120
+ healthError,
121
+ isHealthError,
122
+ query,
123
+ requestPermission,
124
+ saveWorkout,
125
+ version
126
+ };
127
+ //# sourceMappingURL=health.mjs.map
@@ -29,6 +29,7 @@ var CAPABILITY_REGISTRY = {
29
29
  "files": ["list", "readText", "remove", "stat", "write"],
30
30
  "godot": ["loadPack", "release", "send"],
31
31
  "haptic": ["play"],
32
+ "health": ["availability", "getPermissionStatus", "query", "requestPermission", "saveWorkout"],
32
33
  "himi_apps": ["canOpen", "current", "hostInfo", "open"],
33
34
  "iap": ["consume", "entitlements", "finishTransaction", "getPaywallConfig", "getProducts", "getUnfinishedTransactions", "purchase", "purchaseForVerification", "restore"],
34
35
  "keyboard": ["dismiss"],
@@ -29,6 +29,7 @@ var CAPABILITY_REGISTRY = {
29
29
  "files": ["list", "readText", "remove", "stat", "write"],
30
30
  "godot": ["loadPack", "release", "send"],
31
31
  "haptic": ["play"],
32
+ "health": ["availability", "getPermissionStatus", "query", "requestPermission", "saveWorkout"],
32
33
  "himi_apps": ["canOpen", "current", "hostInfo", "open"],
33
34
  "iap": ["consume", "entitlements", "finishTransaction", "getPaywallConfig", "getProducts", "getUnfinishedTransactions", "purchase", "purchaseForVerification", "restore"],
34
35
  "keyboard": ["dismiss"],
@@ -29,6 +29,7 @@ var CAPABILITY_REGISTRY = {
29
29
  "files": ["list", "readText", "remove", "stat", "write"],
30
30
  "godot": ["loadPack", "release", "send"],
31
31
  "haptic": ["play"],
32
+ "health": ["availability", "getPermissionStatus", "query", "requestPermission", "saveWorkout"],
32
33
  "himi_apps": ["canOpen", "current", "hostInfo", "open"],
33
34
  "iap": ["consume", "entitlements", "finishTransaction", "getPaywallConfig", "getProducts", "getUnfinishedTransactions", "purchase", "purchaseForVerification", "restore"],
34
35
  "keyboard": ["dismiss"],
@@ -14,6 +14,7 @@ var CAPABILITY_REGISTRY = {
14
14
  "files": ["list", "readText", "remove", "stat", "write"],
15
15
  "godot": ["loadPack", "release", "send"],
16
16
  "haptic": ["play"],
17
+ "health": ["availability", "getPermissionStatus", "query", "requestPermission", "saveWorkout"],
17
18
  "himi_apps": ["canOpen", "current", "hostInfo", "open"],
18
19
  "iap": ["consume", "entitlements", "finishTransaction", "getPaywallConfig", "getProducts", "getUnfinishedTransactions", "purchase", "purchaseForVerification", "restore"],
19
20
  "keyboard": ["dismiss"],
@@ -29,6 +29,7 @@ var CAPABILITY_REGISTRY = {
29
29
  "files": ["list", "readText", "remove", "stat", "write"],
30
30
  "godot": ["loadPack", "release", "send"],
31
31
  "haptic": ["play"],
32
+ "health": ["availability", "getPermissionStatus", "query", "requestPermission", "saveWorkout"],
32
33
  "himi_apps": ["canOpen", "current", "hostInfo", "open"],
33
34
  "iap": ["consume", "entitlements", "finishTransaction", "getPaywallConfig", "getProducts", "getUnfinishedTransactions", "purchase", "purchaseForVerification", "restore"],
34
35
  "keyboard": ["dismiss"],
@@ -114,6 +114,10 @@
114
114
  "types": "./dist/_types/core/sdk/haptic/src/index.d.ts",
115
115
  "import": "./dist/haptic.mjs"
116
116
  },
117
+ "./health": {
118
+ "types": "./dist/_types/core/sdk/health/src/index.d.ts",
119
+ "import": "./dist/health.mjs"
120
+ },
117
121
  "./himi-apps": {
118
122
  "types": "./dist/_types/core/sdk/himi-apps/src/index.d.ts",
119
123
  "import": "./dist/himi-apps.mjs"
package/dist/cli.mjs CHANGED
@@ -5002,6 +5002,7 @@ var init_build_lib = __esm({
5002
5002
  // module comments — so the committed artifact differed per machine (a clone whose
5003
5003
  // node_modules points elsewhere emitted /Users/<name>/... into a tracked file).
5004
5004
  "@himalaya/motion": resolve8(REPO_ROOT4, "core/sdk/motion/src/index.ts"),
5005
+ "@himalaya/health": resolve8(REPO_ROOT4, "core/sdk/health/src/index.ts"),
5005
5006
  // Pure TypeScript (GPX parse/serialize + track stats) — no dispatch, so no capability
5006
5007
  // grant, same class as @himalaya/state.
5007
5008
  "@himalaya/gpx": resolve8(REPO_ROOT4, "core/sdk/gpx/src/index.ts"),
@@ -6826,7 +6827,6 @@ function walk(node, registry, path2, out2) {
6826
6827
  var SYSTEM_FONT_FAMILY, TONAL_ELEVATION_ALPHA, COLOR_TOKEN_PROPS, TYPOGRAPHY_TOKEN_PROPS;
6827
6828
  var init_tokens = __esm({
6828
6829
  "../../core/ts/src/tokens.ts"() {
6829
- "use strict";
6830
6830
  SYSTEM_FONT_FAMILY = "$system";
6831
6831
  TONAL_ELEVATION_ALPHA = [0, 0.05, 0.08, 0.11, 0.12, 0.14];
6832
6832
  COLOR_TOKEN_PROPS = {
@@ -6877,7 +6877,6 @@ function resolveTranslation(value, catalog, sourceCatalog) {
6877
6877
  var BINDING_SIGILS, BINDING_SIGIL_RE, TRANSLATION_PREFIX, TRANSLATION_KEY_RE;
6878
6878
  var init_bindings = __esm({
6879
6879
  "../../core/ts/src/bindings.ts"() {
6880
- "use strict";
6881
6880
  BINDING_SIGILS = ["service", "flag", "item", "t"];
6882
6881
  BINDING_SIGIL_RE = new RegExp(
6883
6882
  `^\\$(?:${BINDING_SIGILS.filter((s2) => s2 !== "t").join("|")})\\b|^\\$t:`
@@ -17165,6 +17164,86 @@ var init_native_requirements = __esm({
17165
17164
  ]
17166
17165
  }
17167
17166
  },
17167
+ health: {
17168
+ // Apple Health (HealthKit) / Health Connect (@himalaya/health): read steps, heart rate,
17169
+ // active energy, distance and workouts; write a completed workout back. A different
17170
+ // privacy class from `motion` (the platform HEALTH store, not raw sensors), so its own row.
17171
+ ios: {
17172
+ // HealthKit throws (and App Review rejects) when either key is missing for the
17173
+ // direction the app uses. Both are declared because the surface is read + write.
17174
+ usageStrings: [
17175
+ { key: "NSHealthShareUsageDescription", suggested: "Read your steps, heart rate, energy and workouts from Apple Health to show your activity." },
17176
+ { key: "NSHealthUpdateUsageDescription", suggested: "Save the workouts you complete to Apple Health." }
17177
+ ],
17178
+ // The App ID must have the HealthKit capability enabled for a DEVICE / TestFlight
17179
+ // build to sign with this — see docs/capability-native-config.md. Simulator builds
17180
+ // do not need the App ID step.
17181
+ entitlements: { "com.apple.developer.healthkit": true }
17182
+ },
17183
+ // macOS has no Health store (HKHealthStore.isHealthDataAvailable() is false on Mac), so
17184
+ // the capability answers `available: false` there and contributes no config.
17185
+ android: {
17186
+ // Health Connect permissions are runtime-granted through Health Connect's own dialog,
17187
+ // but the dialog only offers a permission the manifest declares.
17188
+ permissions: [
17189
+ "android.permission.health.READ_ACTIVE_CALORIES_BURNED",
17190
+ "android.permission.health.READ_DISTANCE",
17191
+ "android.permission.health.READ_EXERCISE",
17192
+ "android.permission.health.READ_HEART_RATE",
17193
+ "android.permission.health.READ_STEPS",
17194
+ // A saved workout carries its energy + distance as their OWN records alongside the
17195
+ // ExerciseSessionRecord, so writing them needs their write permissions too.
17196
+ "android.permission.health.WRITE_ACTIVE_CALORIES_BURNED",
17197
+ "android.permission.health.WRITE_DISTANCE",
17198
+ "android.permission.health.WRITE_EXERCISE"
17199
+ ],
17200
+ // Health Connect will not show its permission dialog to an app with no privacy-
17201
+ // rationale screen. Android ≤13 finds it by the ACTION_SHOW_PERMISSIONS_RATIONALE
17202
+ // intent-filter; Android 14+ by a VIEW_PERMISSION_USAGE alias that only the system's
17203
+ // permission controller may start (START_VIEW_PERMISSION_USAGE).
17204
+ activities: [
17205
+ {
17206
+ name: "io.himalaya.health.HealthPermissionsRationaleActivity",
17207
+ exported: true,
17208
+ intentFilters: [{ actions: ["androidx.health.ACTION_SHOW_PERMISSIONS_RATIONALE"] }]
17209
+ },
17210
+ {
17211
+ name: "io.himalaya.health.HealthViewPermissionUsageActivity",
17212
+ targetActivity: "io.himalaya.health.HealthPermissionsRationaleActivity",
17213
+ exported: true,
17214
+ permission: "android.permission.START_VIEW_PERMISSION_USAGE",
17215
+ intentFilters: [
17216
+ {
17217
+ actions: ["android.intent.action.VIEW_PERMISSION_USAGE"],
17218
+ categories: ["android.intent.category.HEALTH_PERMISSIONS"]
17219
+ }
17220
+ ]
17221
+ }
17222
+ ],
17223
+ // On Android ≤13 Health Connect is a separate APK; without package visibility the
17224
+ // client reports it as not installed even when it is.
17225
+ queries: ["com.google.android.apps.healthdata"]
17226
+ },
17227
+ privacy: {
17228
+ // Health = heart rate; Fitness = steps / energy / distance / workouts. NOT linked and
17229
+ // NOT tracking: read on device for the app's own display. An app that syncs these to
17230
+ // a server must mark them linked in its native-config overrides.
17231
+ collectedDataTypes: [
17232
+ { type: "NSPrivacyCollectedDataTypeHealth", linked: false, tracking: false, purposes: [APP_FUNCTIONALITY] },
17233
+ { type: "NSPrivacyCollectedDataTypeFitness", linked: false, tracking: false, purposes: [APP_FUNCTIONALITY] }
17234
+ ],
17235
+ dataSafety: [
17236
+ { category: "Health and fitness", dataType: "Health info", purpose: "App functionality" },
17237
+ { category: "Health and fitness", dataType: "Fitness info", purpose: "App functionality" }
17238
+ ],
17239
+ reviewNotes: [
17240
+ "health: HealthKit (iOS) / Health Connect (Android). Apple Guideline 5.1.3 and Google Play's Health Connect policy both forbid using health data for advertising or selling it, and both require a privacy policy that names the health data read.",
17241
+ "Google Play requires a Health Connect declaration form in the Play Console for every android.permission.health.* permission requested; an app that ships these permissions without it is rejected.",
17242
+ "iOS hides READ denials: HealthKit never reports whether read access was refused, so `getPermissionStatus` answers `notDetermined` for reads and a denied read simply returns no samples.",
17243
+ "The HealthKit entitlement requires the HealthKit capability on the App ID for device and TestFlight builds."
17244
+ ]
17245
+ }
17246
+ },
17168
17247
  media_playback: {
17169
17248
  ios: {
17170
17249
  // Background audio for SDUI MediaPlayer sessions that opt into background playback.
@@ -17403,17 +17482,27 @@ function androidPlanFor(ids, ov = {}) {
17403
17482
  const perms = /* @__PURE__ */ new Set();
17404
17483
  const feats = /* @__PURE__ */ new Map();
17405
17484
  const svcs = /* @__PURE__ */ new Map();
17485
+ const acts = /* @__PURE__ */ new Map();
17486
+ const queries = /* @__PURE__ */ new Set();
17406
17487
  const add = (req) => {
17407
17488
  for (const p2 of req?.permissions ?? []) perms.add(p2);
17408
17489
  for (const f2 of req?.features ?? []) feats.set(f2.name, (feats.get(f2.name) ?? false) || f2.required);
17409
17490
  for (const s2 of req?.services ?? []) svcs.set(s2.name, s2);
17491
+ for (const a2 of req?.activities ?? []) acts.set(a2.name, a2);
17492
+ for (const q2 of req?.queries ?? []) queries.add(q2);
17410
17493
  };
17411
17494
  for (const id of ids) add(nativeRequirementsFor(id)?.android);
17412
17495
  add(ov);
17413
17496
  return {
17414
17497
  permissions: [...perms].sort(),
17415
17498
  features: [...feats.entries()].sort((a2, b2) => a2[0].localeCompare(b2[0])).map(([name, required3]) => ({ name, required: required3 })),
17416
- services: [...svcs.values()].sort((a2, b2) => a2.name.localeCompare(b2.name))
17499
+ services: [...svcs.values()].sort((a2, b2) => a2.name.localeCompare(b2.name)),
17500
+ // An <activity-alias> must come AFTER the activity it targets, or the manifest merger
17501
+ // rejects it — so aliases sort after plain activities, then by name.
17502
+ activities: [...acts.values()].sort(
17503
+ (a2, b2) => Number(!!a2.targetActivity) - Number(!!b2.targetActivity) || a2.name.localeCompare(b2.name)
17504
+ ),
17505
+ queries: [...queries].sort()
17417
17506
  };
17418
17507
  }
17419
17508
  var init_plan = __esm({
@@ -17448,6 +17537,9 @@ var init_builtins = __esm({
17448
17537
  "files",
17449
17538
  "godot",
17450
17539
  "haptic",
17540
+ // Registered on every arm. Web (and the macOS build of the iOS arm) answer
17541
+ // `availability → { available: false }` and refuse the rest with `unavailable`.
17542
+ "health",
17451
17543
  "himi_apps",
17452
17544
  "iap",
17453
17545
  "keyboard",
@@ -17561,6 +17653,7 @@ var init_known = __esm({
17561
17653
  local_database: "registering it without the app's dataSchema writes declared-encrypted entities in plaintext (#1896) \u2014 the shell has to install the schema first",
17562
17654
  live_activity: "needs a WidgetKit extension target in the shell's project, which a build cannot add",
17563
17655
  base44: "needs the opt-in HimalayaCoreBase44 / :core-runtime-base44 SDK linked into the shell",
17656
+ health: "needs the opt-in HimalayaCoreHealth / :core-runtime-health store linked into the shell (unlinked, every verb answers `unavailable`)",
17564
17657
  godot: "needs the opt-in Godot SPM product linked into the shell",
17565
17658
  wix_platform: "needs the shell's boot to configure it with a Wix API client and launch services",
17566
17659
  himi_apps: "is a multi-app host surface (Himi Player), not something one app's binary serves",
@@ -18356,12 +18449,34 @@ function renderAndroidXml(plan, indent) {
18356
18449
  const lines = [];
18357
18450
  for (const p2 of plan.permissions) lines.push(`${indent}<uses-permission android:name="${p2}" />`);
18358
18451
  for (const f2 of plan.features) lines.push(`${indent}<uses-feature android:name="${f2.name}" android:required="${f2.required}" />`);
18452
+ const queries = plan.queries ?? [];
18453
+ if (queries.length > 0) {
18454
+ lines.push(`${indent}<queries>`);
18455
+ for (const q2 of queries) lines.push(`${indent} <package android:name="${q2}" />`);
18456
+ lines.push(`${indent}</queries>`);
18457
+ }
18359
18458
  return lines;
18360
18459
  }
18361
18460
  function renderAndroidServicesXml(plan, indent) {
18362
- return plan.services.map(
18461
+ const lines = plan.services.map(
18363
18462
  (s2) => `${indent}<service android:name="${s2.name}" android:exported="false" android:foregroundServiceType="${s2.foregroundServiceType}" />`
18364
18463
  );
18464
+ for (const a2 of plan.activities ?? []) {
18465
+ const tag = a2.targetActivity ? "activity-alias" : "activity";
18466
+ const attrs = [`android:name="${a2.name}"`];
18467
+ if (a2.targetActivity) attrs.push(`android:targetActivity="${a2.targetActivity}"`);
18468
+ attrs.push(`android:exported="${a2.exported}"`);
18469
+ if (a2.permission) attrs.push(`android:permission="${a2.permission}"`);
18470
+ lines.push(`${indent}<${tag} ${attrs.join(" ")}>`);
18471
+ for (const f2 of a2.intentFilters) {
18472
+ lines.push(`${indent} <intent-filter>`);
18473
+ for (const act of f2.actions) lines.push(`${indent} <action android:name="${act}" />`);
18474
+ for (const c2 of f2.categories ?? []) lines.push(`${indent} <category android:name="${c2}" />`);
18475
+ lines.push(`${indent} </intent-filter>`);
18476
+ }
18477
+ lines.push(`${indent}</${tag}>`);
18478
+ }
18479
+ return lines;
18365
18480
  }
18366
18481
  function isBegin(line, kind, label2) {
18367
18482
  const s2 = line.trim();
@@ -22504,6 +22619,7 @@ var init_capabilities_generated = __esm({
22504
22619
  "files": ["list", "readText", "remove", "stat", "write"],
22505
22620
  "godot": ["loadPack", "release", "send"],
22506
22621
  "haptic": ["play"],
22622
+ "health": ["availability", "getPermissionStatus", "query", "requestPermission", "saveWorkout"],
22507
22623
  "himi_apps": ["canOpen", "current", "hostInfo", "open"],
22508
22624
  "iap": ["consume", "entitlements", "finishTransaction", "getPaywallConfig", "getProducts", "getUnfinishedTransactions", "purchase", "purchaseForVerification", "restore"],
22509
22625
  "keyboard": ["dismiss"],
@@ -22546,6 +22662,7 @@ var init_capabilities_generated = __esm({
22546
22662
  "files": ["@himalaya/files"],
22547
22663
  "godot": ["@himalaya/godot"],
22548
22664
  "haptic": ["@himalaya/haptic"],
22665
+ "health": ["@himalaya/health"],
22549
22666
  "himi_apps": ["@himalaya/himi-apps"],
22550
22667
  "iap": ["@himalaya/iap"],
22551
22668
  "keyboard": ["@himalaya/keyboard"],
@@ -22605,8 +22722,8 @@ var init_shell_capabilities_generated = __esm({
22605
22722
  appDir: "apps/demo-app",
22606
22723
  shared: false,
22607
22724
  extensible: false,
22608
- built: ["base44", "biometrics", "calendar", "calls", "contacts", "haptic", "keyboard", "live_activity", "location", "media_playback", "on_device_ai", "photos", "push", "speech", "tasks", "ui"],
22609
- serves: ["base44", "biometrics", "calendar", "calls", "contacts", "haptic", "keyboard", "live_activity", "location", "media_playback", "on_device_ai", "photos", "push", "speech", "tasks", "ui"]
22725
+ built: ["base44", "biometrics", "calendar", "calls", "contacts", "haptic", "health", "keyboard", "live_activity", "location", "media_playback", "on_device_ai", "photos", "push", "speech", "tasks", "ui"],
22726
+ serves: ["base44", "biometrics", "calendar", "calls", "contacts", "haptic", "health", "keyboard", "live_activity", "location", "media_playback", "on_device_ai", "photos", "push", "speech", "tasks", "ui"]
22610
22727
  },
22611
22728
  "owner-lite": {
22612
22729
  appDir: "apps/himi-owner-lite",
@@ -24054,6 +24171,9 @@ var init_l10n = __esm({
24054
24171
  });
24055
24172
 
24056
24173
  // ../../core/ts/src/wix-push-links.ts
24174
+ function replacementPingFamily(name) {
24175
+ return RETIRED_PING_FAMILIES.has(name) ? DEFAULT_PING_APP_NAME : void 0;
24176
+ }
24057
24177
  function derivesWixPushRoutes(push, installedVerticals) {
24058
24178
  return push?.payloadAdapter === "wix-ping" && push.routes === void 0 && installedVerticals !== void 0;
24059
24179
  }
@@ -24097,10 +24217,14 @@ function itemParamKey(paramKeys) {
24097
24217
  if (paramKeys.includes("id")) return "id";
24098
24218
  return paramKeys.length === 1 ? paramKeys[0] : void 0;
24099
24219
  }
24100
- var DEFAULT_PING_APP_NAME, EVENTS_APP_ID, WIX_MEMBER_PUSH_DESTINATIONS;
24220
+ var DEFAULT_PING_APP_NAME, RETIRED_PING_FAMILIES, EVENTS_APP_ID, WIX_MEMBER_PUSH_DESTINATIONS;
24101
24221
  var init_wix_push_links = __esm({
24102
24222
  "../../core/ts/src/wix-push-links.ts"() {
24103
- DEFAULT_PING_APP_NAME = "WixBrandedWebApp";
24223
+ DEFAULT_PING_APP_NAME = "WixBrandedLite";
24224
+ RETIRED_PING_FAMILIES = /* @__PURE__ */ new Set([
24225
+ // Renamed to WixWebShell by wix-private/wixos #22625, 2026-10-04.
24226
+ "WixBrandedWebApp"
24227
+ ]);
24104
24228
  EVENTS_APP_ID = "140603ad-af8d-84a5-2c80-a0f60cb47351";
24105
24229
  WIX_MEMBER_PUSH_DESTINATIONS = [
24106
24230
  {
@@ -133446,7 +133570,7 @@ import { lstatSync as lstatSync11, readFileSync as readFileSync53 } from "node:f
133446
133570
  import { basename as basename13, join as join46 } from "node:path";
133447
133571
  import ts2 from "typescript";
133448
133572
  function enablePushInConfig(source, options) {
133449
- const pingAppName = options.pingAppName ?? DEFAULT_PING_APP_NAME;
133573
+ const pingAppName = DEFAULT_PING_APP_NAME;
133450
133574
  const fileName = options.fileName ?? "config.ts";
133451
133575
  const kind = fileName.endsWith(".ts") ? ts2.ScriptKind.TS : ts2.ScriptKind.JS;
133452
133576
  const file = ts2.createSourceFile(fileName, source, ts2.ScriptTarget.Latest, true, kind);
@@ -133487,6 +133611,7 @@ function planPush(app, pingAppName, plan) {
133487
133611
  }
133488
133612
  const block = push.kind === "written" ? push.node.initializer : void 0;
133489
133613
  plan.pushOn = !!block && stringValue(block, "registrar") === "wix-ping" && stringValue(block, "payloadAdapter") === "wix-ping";
133614
+ if (block && stringValue(block, "registrar") === "wix-ping") planRetiredFamily(block, plan);
133490
133615
  const lacking = [
133491
133616
  ...block && stringValue(block, "registrar") === "wix-ping" ? [] : ['registrar: "wix-ping"'],
133492
133617
  ...block && stringValue(block, "pingAppName") ? [] : [`pingAppName: ${JSON.stringify(pingAppName)}`],
@@ -133498,6 +133623,15 @@ function planPush(app, pingAppName, plan) {
133498
133623
  );
133499
133624
  }
133500
133625
  }
133626
+ function planRetiredFamily(block, plan) {
133627
+ const literal = unwrap(block);
133628
+ const found = ts2.isObjectLiteralExpression(literal) ? lookup2(literal, "pingAppName") : void 0;
133629
+ const value = found?.kind === "written" ? unwrap(found.node.initializer) : void 0;
133630
+ const replacement = value && ts2.isStringLiteralLike(value) ? replacementPingFamily(value.text) : void 0;
133631
+ if (!value || !replacement) return;
133632
+ plan.splices.push({ at: value.getStart(), end: value.end, text: JSON.stringify(replacement) });
133633
+ plan.applied.push(`pingAppName ${JSON.stringify(replacement)} in place of ${value.getText()}`);
133634
+ }
133501
133635
  function planCapability(app, plan) {
133502
133636
  const capabilities = lookup2(app, "capabilities");
133503
133637
  if (capabilities.kind === "absent") {
@@ -136556,6 +136690,7 @@ async function navIssues(dir, strict) {
136556
136690
  pushRouteIssues(cfg.push, nav, provisioning, warn3);
136557
136691
  pushScreenMapIssues(cfg.push, provisioning, warn3);
136558
136692
  pushAuthIssues(cfg.push, cfg.auth, provisioning, warn3);
136693
+ pushFamilyIssues(cfg.push, warn3);
136559
136694
  if (nav === void 0 || nav === null) return issues;
136560
136695
  if (!isPlainObject2(nav)) {
136561
136696
  error("nav-not-an-object", `navigation must be an object (got ${Array.isArray(nav) ? "array" : typeof nav}).`);
@@ -136676,6 +136811,15 @@ function pushAuthIssues(push, auth, provisioning, warn3) {
136676
136811
  `push.registrar is "wix-ping", which registers a signed-in member's device with Wix Ping, but ${problem}. Use auth: WixConsumerAuthProvider({ siteId: "${provisioning.siteId ?? "<metaSiteId>"}", \u2026 }).`
136677
136812
  );
136678
136813
  }
136814
+ function pushFamilyIssues(push, warn3) {
136815
+ if (!isPlainObject2(push) || push.registrar !== "wix-ping" || typeof push.pingAppName !== "string") return;
136816
+ const replacement = replacementPingFamily(push.pingAppName);
136817
+ if (!replacement) return;
136818
+ warn3(
136819
+ "push-ping-family-retired",
136820
+ `push.pingAppName "${push.pingAppName}" is a family Ping no longer has, and it kept no alias: a device registering under it gets no notifications. Use pingAppName: "${replacement}".`
136821
+ );
136822
+ }
136679
136823
  function pushRouteAdvisories(pushRoutes) {
136680
136824
  if (!pushRoutes) return [];
136681
136825
  const linked = new Set(WIX_MEMBER_PUSH_DESTINATIONS.map((d2) => d2.vertical));
@@ -143329,23 +143473,23 @@ var init_preview_assets_generated = __esm({
143329
143473
  "../../packages/serve/src/preview-assets.generated.ts"() {
143330
143474
  init_preview_assets_format();
143331
143475
  PREVIEW_ASSET_MANIFEST = [
143332
- { key: "assets/index-DiC0HNa3.js", contentType: "application/javascript; charset=utf-8", offset: 8, length: 1187655, sha256: "08fb74d8752e2f7ae5dcffd520eb03d2eb3def8db9d8fa4b9d5de1a7ae293100" },
143333
- { key: "assets/pdf.worker.min-BmVo14Nb.mjs", contentType: "application/octet-stream", offset: 1187663, length: 1317034, sha256: "a33cfe728c584fdba4fcc1fd54bcdc2f9f2f13889ddbb5b2bd1d0f8cbe49b84e" },
143334
- { key: "assets/pdfDocument-CXSifjpc.js", contentType: "application/javascript; charset=utf-8", offset: 2504697, length: 489166, sha256: "7dd04afebfbeeede2222a8beb5d87e58391ed36493b57a190a3e2eed4da35356" },
143335
- { key: "fonts/Roboto-LICENSE.txt", contentType: "application/octet-stream", offset: 2993863, length: 4610, sha256: "994062dd7af4186a739de55dd9e151c63b6301f8e2cbafc608d35c2e87da0cd2" },
143336
- { key: "fonts/Roboto-Variable.ttf", contentType: "font/ttf", offset: 2998473, length: 488584, sha256: "d7598e12c5dbef095ff8272cfc55da0250bd07fbdecbac8a530b9b277872a134" },
143337
- { key: "fonts/WixMadeforDisplay-Bold.ttf", contentType: "font/ttf", offset: 3487057, length: 90924, sha256: "ec4c7d63772d980d6e147b2df6215fd2737e4b04cebe0cf7e11dc695fb63cdcf" },
143338
- { key: "fonts/WixMadeforDisplay-ExtraBold.ttf", contentType: "font/ttf", offset: 3577981, length: 90984, sha256: "bf4c16a2774edd38a921edf3099469866cd74c094fd596f3fa4e81f54a04dfaa" },
143339
- { key: "fonts/WixMadeforDisplay-Medium.ttf", contentType: "font/ttf", offset: 3668965, length: 90980, sha256: "368faca44fb9f7207e4af784e94750b1ee59c1098b8689e0f4a918926f244fb5" },
143340
- { key: "fonts/WixMadeforDisplay-Regular.ttf", contentType: "font/ttf", offset: 3759945, length: 90872, sha256: "97ed8f1a6772abe26e3d8af5cecfc4b02faa94497d585b0398b5053b739a70c1" },
143341
- { key: "fonts/WixMadeforDisplay-SemiBold.ttf", contentType: "font/ttf", offset: 3850817, length: 90980, sha256: "642feab8a48ddf6c7a89d7c2a7c0edfa0e6e773f671287e460e222703563191e" },
143342
- { key: "fonts/WixMadeforText-Bold.ttf", contentType: "font/ttf", offset: 3941797, length: 108636, sha256: "37c179b4fefb63ea9637322b84583a2df53aa226c150294eea1675c14b1b8e29" },
143343
- { key: "fonts/WixMadeforText-ExtraBold.ttf", contentType: "font/ttf", offset: 4050433, length: 109084, sha256: "62e2fe4718129f36ecdb0ae4de385bd6b81ecc876146447167c6c140fad699a9" },
143344
- { key: "fonts/WixMadeforText-Medium.ttf", contentType: "font/ttf", offset: 4159517, length: 109048, sha256: "4ecf270136af928612c76fe4ebade91d8156975e5ea4c0cf9225501dd1788e02" },
143345
- { key: "fonts/WixMadeforText-Regular.ttf", contentType: "font/ttf", offset: 4268565, length: 107700, sha256: "dee56f09fd3efc127c1ea95557edc74110c1460a46287da36e0af25efd341ef5" },
143346
- { key: "fonts/WixMadeforText-SemiBold.ttf", contentType: "font/ttf", offset: 4376265, length: 88108, sha256: "dced97a77624bc5f8b1ae65850360908297f4588e09feb6f22792d29dc7e765b" },
143347
- { key: "index.html", contentType: "text/html; charset=utf-8", offset: 4464373, length: 4947, sha256: "e46144d08f1a73203c2313ca0ed8b607fd383f4889a82701d6c37f00e4720c95" },
143348
- { key: "t5-frame.html", contentType: "text/html; charset=utf-8", offset: 4469320, length: 17344, sha256: "d057298d75e7373e5e2c4d11b7d1bcbea88e03af555ba63d97641c78509c58e4" }
143476
+ { key: "assets/index-DcqakqyW.js", contentType: "application/javascript; charset=utf-8", offset: 8, length: 1191096, sha256: "83e1d51efc75dc63a19cd5bd9072d50e8b831d6c39152922cdc491225f43d696" },
143477
+ { key: "assets/pdf.worker.min-BmVo14Nb.mjs", contentType: "application/octet-stream", offset: 1191104, length: 1317034, sha256: "a33cfe728c584fdba4fcc1fd54bcdc2f9f2f13889ddbb5b2bd1d0f8cbe49b84e" },
143478
+ { key: "assets/pdfDocument-CITrNgUQ.js", contentType: "application/javascript; charset=utf-8", offset: 2508138, length: 489166, sha256: "202328a260c149a8bdf211a58a04cb74114e40510a4c0dd0511045b3a6279b47" },
143479
+ { key: "fonts/Roboto-LICENSE.txt", contentType: "application/octet-stream", offset: 2997304, length: 4610, sha256: "994062dd7af4186a739de55dd9e151c63b6301f8e2cbafc608d35c2e87da0cd2" },
143480
+ { key: "fonts/Roboto-Variable.ttf", contentType: "font/ttf", offset: 3001914, length: 488584, sha256: "d7598e12c5dbef095ff8272cfc55da0250bd07fbdecbac8a530b9b277872a134" },
143481
+ { key: "fonts/WixMadeforDisplay-Bold.ttf", contentType: "font/ttf", offset: 3490498, length: 90924, sha256: "ec4c7d63772d980d6e147b2df6215fd2737e4b04cebe0cf7e11dc695fb63cdcf" },
143482
+ { key: "fonts/WixMadeforDisplay-ExtraBold.ttf", contentType: "font/ttf", offset: 3581422, length: 90984, sha256: "bf4c16a2774edd38a921edf3099469866cd74c094fd596f3fa4e81f54a04dfaa" },
143483
+ { key: "fonts/WixMadeforDisplay-Medium.ttf", contentType: "font/ttf", offset: 3672406, length: 90980, sha256: "368faca44fb9f7207e4af784e94750b1ee59c1098b8689e0f4a918926f244fb5" },
143484
+ { key: "fonts/WixMadeforDisplay-Regular.ttf", contentType: "font/ttf", offset: 3763386, length: 90872, sha256: "97ed8f1a6772abe26e3d8af5cecfc4b02faa94497d585b0398b5053b739a70c1" },
143485
+ { key: "fonts/WixMadeforDisplay-SemiBold.ttf", contentType: "font/ttf", offset: 3854258, length: 90980, sha256: "642feab8a48ddf6c7a89d7c2a7c0edfa0e6e773f671287e460e222703563191e" },
143486
+ { key: "fonts/WixMadeforText-Bold.ttf", contentType: "font/ttf", offset: 3945238, length: 108636, sha256: "37c179b4fefb63ea9637322b84583a2df53aa226c150294eea1675c14b1b8e29" },
143487
+ { key: "fonts/WixMadeforText-ExtraBold.ttf", contentType: "font/ttf", offset: 4053874, length: 109084, sha256: "62e2fe4718129f36ecdb0ae4de385bd6b81ecc876146447167c6c140fad699a9" },
143488
+ { key: "fonts/WixMadeforText-Medium.ttf", contentType: "font/ttf", offset: 4162958, length: 109048, sha256: "4ecf270136af928612c76fe4ebade91d8156975e5ea4c0cf9225501dd1788e02" },
143489
+ { key: "fonts/WixMadeforText-Regular.ttf", contentType: "font/ttf", offset: 4272006, length: 107700, sha256: "dee56f09fd3efc127c1ea95557edc74110c1460a46287da36e0af25efd341ef5" },
143490
+ { key: "fonts/WixMadeforText-SemiBold.ttf", contentType: "font/ttf", offset: 4379706, length: 88108, sha256: "dced97a77624bc5f8b1ae65850360908297f4588e09feb6f22792d29dc7e765b" },
143491
+ { key: "index.html", contentType: "text/html; charset=utf-8", offset: 4467814, length: 4947, sha256: "2189ce1438ed15f3a041d5e9950c92b27a18d288103ac04249b184c369137721" },
143492
+ { key: "t5-frame.html", contentType: "text/html; charset=utf-8", offset: 4472761, length: 17344, sha256: "d057298d75e7373e5e2c4d11b7d1bcbea88e03af555ba63d97641c78509c58e4" }
143349
143493
  ];
143350
143494
  }
143351
143495
  });
Binary file
@@ -115,7 +115,7 @@ with a native footprint only arrives with a new binary. `himi docs capabilities`
115
115
  loop — discover, declare, validate, ship — and `himi capabilities <id>` shows the import and which
116
116
  shells' binaries serve it.
117
117
 
118
- App-level capability vocabulary: `camera`, `barcode_scanner`, `biometrics`, `secure_storage`, `share`, `push`, `file_picker`, `files`, `open_url`, `pdf`, `clipboard`, `photos`, `presigned_upload`, `ui`, `calendar`, `contacts`, `tasks`, `audio_record`, `audio_record_background`, `calls`, `location`, `location_background`, `motion`, `media_playback`, `webview`, `browser_auth`, `haptic`, `himi_apps`, `iap`, `keyboard`, `wix_cashier`, `live_activity`, `local_database`, `speech`, `speaker_diarization`, `system_intents`, `on_device_ai`, `app_info`, `release_control`, `godot`, `base44`.
118
+ App-level capability vocabulary: `camera`, `barcode_scanner`, `biometrics`, `secure_storage`, `share`, `push`, `file_picker`, `files`, `open_url`, `pdf`, `clipboard`, `photos`, `presigned_upload`, `ui`, `calendar`, `contacts`, `tasks`, `audio_record`, `audio_record_background`, `calls`, `location`, `location_background`, `motion`, `health`, `media_playback`, `webview`, `browser_auth`, `haptic`, `himi_apps`, `iap`, `keyboard`, `wix_cashier`, `live_activity`, `local_database`, `speech`, `speaker_diarization`, `system_intents`, `on_device_ai`, `app_info`, `release_control`, `godot`, `base44`.
119
119
 
120
120
  ## What `himi validate` checks (7 passes)
121
121
 
@@ -31,6 +31,7 @@ package in one greppable file) or `GET /v1/sdk/<name>` over HTTP; in the CLI,
31
31
  - `@himalaya/godot` — Tier-5 typed binding for a Godot game surface.
32
32
  - `@himalaya/gpx` — read and write GPX 1.1, and compute track statistics.
33
33
  - `@himalaya/haptic` — Tier-5 typed binding for the platform's haptic capability.
34
+ - `@himalaya/health` — Tier-5 typed binding for the platform HEALTH store.
34
35
  - `@himalaya/himi-apps` — Tier-5 typed binding for cross-app open / host queries.
35
36
  - `@himalaya/iap` — Tier-5 typed binding to the platform's in-app-purchase capability.
36
37
  - `@himalaya/keyboard` — Tier-5 typed binding for the platform's keyboard capability.
@@ -116,16 +116,18 @@ capabilities: ["push" /* , … */],
116
116
  // Routes are derived at build time from provisioning.json and your screens; see himi validate.
117
117
  push: {
118
118
  registrar: "wix-ping",
119
- pingAppName: "WixBrandedWebApp",
119
+ pingAppName: "WixBrandedLite",
120
120
  requestPermissionOnLaunch: true,
121
121
  payloadAdapter: "wix-ping",
122
122
  },
123
123
  ```
124
124
 
125
- - `pingAppName` is the Ping app family the device registers under. Use `WixBrandedWebApp`:
126
- Ping allows it for site members and uses the credentials `himi notify setup` stored for
127
- the site. A build signed for the APNs development environment appends `.sandbox` itself;
128
- do not add it.
125
+ - `pingAppName` is the Ping app family the device registers under. Use `WixBrandedLite`:
126
+ Ping allows it for site members, uses the credentials `himi notify setup` stored for the
127
+ site, and delivers the site's member notifications to it. A build signed for the APNs
128
+ development environment appends `.sandbox` itself; do not add it. `WixBrandedWebApp` no
129
+ longer exists in Ping: `himi validate` reports it as `push-ping-family-retired`, and
130
+ re-running `himi notify setup` replaces it.
129
131
  - The device registers only after a member signs in; a visitor's device receives nothing.
130
132
  Keep `siteId` in `auth` on the site `himi notify setup` configured. A changed `siteId` or
131
133
  `clientId` ships with `himi push` like the rest of the config, and the app picks it up on
@@ -1368,6 +1368,151 @@
1368
1368
  }
1369
1369
  ]
1370
1370
  },
1371
+ {
1372
+ "name": "@himalaya/health",
1373
+ "source": "core/sdk/health/src/index.ts",
1374
+ "description": "Tier-5 typed binding for the platform HEALTH store.",
1375
+ "api": [
1376
+ {
1377
+ "name": "HealthType",
1378
+ "kind": "type",
1379
+ "jsdoc": "/** A readable health data type. */",
1380
+ "decl": "export type HealthType = \"steps\" | \"heartRate\" | \"activeEnergy\" | \"distance\" | \"workouts\";"
1381
+ },
1382
+ {
1383
+ "name": "HealthWriteType",
1384
+ "kind": "type",
1385
+ "jsdoc": "/** A writable health data type. v1 writes workouts only. */",
1386
+ "decl": "export type HealthWriteType = \"workouts\";"
1387
+ },
1388
+ {
1389
+ "name": "HealthPermissionState",
1390
+ "kind": "type",
1391
+ "jsdoc": "",
1392
+ "decl": "export type HealthPermissionState = \"granted\" | \"denied\" | \"notDetermined\";"
1393
+ },
1394
+ {
1395
+ "name": "HealthBucket",
1396
+ "kind": "type",
1397
+ "jsdoc": "/** Aggregation bucket for `query`. Omitted ⇒ one total (cumulative types) or raw samples. */",
1398
+ "decl": "export type HealthBucket = \"hour\" | \"day\";"
1399
+ },
1400
+ {
1401
+ "name": "WorkoutActivity",
1402
+ "kind": "type",
1403
+ "jsdoc": "",
1404
+ "decl": "export type WorkoutActivity = \"running\" | \"walking\" | \"cycling\" | \"strength\" | \"other\";"
1405
+ },
1406
+ {
1407
+ "name": "HealthErrorCode",
1408
+ "kind": "type",
1409
+ "jsdoc": "",
1410
+ "decl": "export type HealthErrorCode = \"unavailable\" | \"not_authorized\" | \"invalid_argument\" | \"failed\";"
1411
+ },
1412
+ {
1413
+ "name": "HEALTH_TYPES",
1414
+ "kind": "const",
1415
+ "jsdoc": "",
1416
+ "decl": "export const HEALTH_TYPES: readonly HealthType[] = [\"steps\", \"heartRate\", \"activeEnergy\", \"distance\", \"workouts\"];"
1417
+ },
1418
+ {
1419
+ "name": "WORKOUT_ACTIVITIES",
1420
+ "kind": "const",
1421
+ "jsdoc": "",
1422
+ "decl": "export const WORKOUT_ACTIVITIES: readonly WorkoutActivity[] = [\"running\", \"walking\", \"cycling\", \"strength\", \"other\"];"
1423
+ },
1424
+ {
1425
+ "name": "HEALTH_UNITS",
1426
+ "kind": "const",
1427
+ "jsdoc": "/** The fixed unit each type's `value` is reported in. */",
1428
+ "decl": "export const HEALTH_UNITS: Readonly<Record<HealthType, string>> = {\n steps: \"count\",\n heartRate: \"bpm\",\n activeEnergy: \"kcal\",\n distance: \"m\",\n workouts: \"s\",\n};"
1429
+ },
1430
+ {
1431
+ "name": "HealthAvailability",
1432
+ "kind": "interface",
1433
+ "jsdoc": "",
1434
+ "decl": "export interface HealthAvailability {\n available: boolean;\n /** Why not, when `available` is false — e.g. \"web has no health store\",\n * \"Health Connect is not installed\". */\n reason?: string;\n}"
1435
+ },
1436
+ {
1437
+ "name": "HealthSample",
1438
+ "kind": "interface",
1439
+ "jsdoc": "",
1440
+ "decl": "export interface HealthSample {\n /** ISO-8601. */\n start: string;\n /** ISO-8601. */\n end: string;\n value: number;\n unit: string;\n /** Workouts only: the activity, mapped back onto the v1 set (\"other\" for anything else). */\n activity?: WorkoutActivity;\n}"
1441
+ },
1442
+ {
1443
+ "name": "HealthQuery",
1444
+ "kind": "interface",
1445
+ "jsdoc": "",
1446
+ "decl": "export interface HealthQuery {\n type: HealthType;\n /** ISO-8601, inclusive. */\n from: string;\n /** ISO-8601, exclusive. */\n to: string;\n /** steps / activeEnergy / distance are SUMMED per bucket; heartRate is AVERAGED per bucket;\n * workouts ignore it (one sample per workout). */\n bucket?: HealthBucket;\n}"
1447
+ },
1448
+ {
1449
+ "name": "Workout",
1450
+ "kind": "interface",
1451
+ "jsdoc": "",
1452
+ "decl": "export interface Workout {\n activity: WorkoutActivity;\n /** ISO-8601. */\n start: string;\n /** ISO-8601, after `start`. */\n end: string;\n energyKcal?: number;\n distanceM?: number;\n}"
1453
+ },
1454
+ {
1455
+ "name": "HealthError",
1456
+ "kind": "interface",
1457
+ "jsdoc": "/** The typed rejection every verb throws. A plain Error carrying `code` — worker bundles are\n * compiled to a target without class syntax, so this is a factory, not a subclass. */",
1458
+ "decl": "export interface HealthError extends Error {\n name: \"HealthError\";\n code: HealthErrorCode;\n}"
1459
+ },
1460
+ {
1461
+ "name": "healthError",
1462
+ "kind": "function",
1463
+ "jsdoc": "/** Build a [HealthError] — what the binding throws for every native `{ error }` reply. */",
1464
+ "decl": "export function healthError(code: HealthErrorCode, message: string): HealthError;"
1465
+ },
1466
+ {
1467
+ "name": "isHealthError",
1468
+ "kind": "function",
1469
+ "jsdoc": "/** Narrow a caught value: `catch (e) { if (isHealthError(e) && e.code === \"unavailable\") … }`. */",
1470
+ "decl": "export function isHealthError(e: unknown): e is HealthError;"
1471
+ },
1472
+ {
1473
+ "name": "availability",
1474
+ "kind": "function",
1475
+ "jsdoc": "/** Whether this device has a health store the app can reach. Call it first and branch. */",
1476
+ "decl": "export async function availability(): Promise<HealthAvailability>;"
1477
+ },
1478
+ {
1479
+ "name": "requestPermission",
1480
+ "kind": "function",
1481
+ "jsdoc": "/**\n * Prompt for read (and optionally write) access. Resolves with the types the platform\n * reports as granted — on iOS a read type counts as granted once asked (see header).\n * Writing workouts also covers the energy + distance samples a saved workout carries.\n */",
1482
+ "decl": "export async function requestPermission(p: { read: HealthType[]; write?: HealthWriteType[] }): Promise<{ granted: HealthType[] }>;"
1483
+ },
1484
+ {
1485
+ "name": "getPermissionStatus",
1486
+ "kind": "function",
1487
+ "jsdoc": "/** Current READ permission per type, without prompting. iOS reads are always \"notDetermined\". */",
1488
+ "decl": "export async function getPermissionStatus(p: { types: HealthType[] }): Promise<Record<HealthType, HealthPermissionState>>;"
1489
+ },
1490
+ {
1491
+ "name": "query",
1492
+ "kind": "function",
1493
+ "jsdoc": "/** Read samples of one type over [from, to). */",
1494
+ "decl": "export async function query(p: HealthQuery): Promise<{ samples: HealthSample[] }>;"
1495
+ },
1496
+ {
1497
+ "name": "saveWorkout",
1498
+ "kind": "function",
1499
+ "jsdoc": "/** Save a completed workout (with its energy/distance, when given). Resolves with its store id. */",
1500
+ "decl": "export async function saveWorkout(w: Workout): Promise<{ id: string }>;"
1501
+ },
1502
+ {
1503
+ "name": "version",
1504
+ "kind": "const",
1505
+ "jsdoc": "",
1506
+ "decl": "export const version = 1;"
1507
+ },
1508
+ {
1509
+ "name": "health",
1510
+ "kind": "const",
1511
+ "jsdoc": "/** The whole surface as one namespace: `import { health } from \"@himalaya/health\"`. */",
1512
+ "decl": "export const health = { availability, requestPermission, getPermissionStatus, query, saveWorkout, version };"
1513
+ }
1514
+ ]
1515
+ },
1371
1516
  {
1372
1517
  "name": "@himalaya/himi-apps",
1373
1518
  "source": "core/sdk/himi-apps/src/index.ts",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wix/himalaya-cli",
3
- "version": "0.1231.0",
3
+ "version": "0.1233.0",
4
4
  "type": "module",
5
5
  "description": "himi — the Himalaya authoring CLI. Build a Tier-5 content package on your own machine, push it to the production serve as a draft, preview it on web + Himi Player, and read worker logs back — the remote dev loop. Wraps @himalaya/serve-cli for transport.",
6
6
  "keywords": [
@@ -67,5 +67,5 @@
67
67
  "artifactId": "himalaya-cli"
68
68
  }
69
69
  },
70
- "falconPackageHash": "520a08a2a0a67dbaa3d551c2628049f08b1481f99918c3890592c9cf"
70
+ "falconPackageHash": "275f14082a30c282271a3f592ad642e90be8aa534e36c4920d763121"
71
71
  }