@wix/himalaya-cli 0.1579.0 → 0.1580.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.
@@ -1,7 +1,7 @@
1
1
  import type { PermissionStatus } from "@wix/himalaya/sdk-types";
2
2
  export type { PermissionStatus } from "@wix/himalaya/sdk-types";
3
- /** Which sensor a watch streams. */
4
- export type MotionSensor = "steps" | "altitude" | "heading";
3
+ /** Which sensor (or gesture event) a watch streams. */
4
+ export type MotionSensor = "steps" | "altitude" | "heading" | "accelerometer" | "gyroscope" | "magnetometer" | "shake" | "tilt" | "significantMotion";
5
5
  /**
6
6
  * Whether `getStepCount` can answer a PAST window right now, and if not, what would fix it.
7
7
  *
@@ -26,6 +26,18 @@ export interface MotionAvailability {
26
26
  /** Whether `getStepCount` can answer a past window — see {@link StepHistoryStatus}. An
27
27
  * unknown or absent value reads as "unsupported", never as "available". */
28
28
  stepHistory: StepHistoryStatus;
29
+ /** Accelerometer present (web: DeviceMotion exists — false on desktop browsers). */
30
+ accelerometer: boolean;
31
+ /** Gyroscope present (web: DeviceMotion rotationRate). */
32
+ gyroscope: boolean;
33
+ /** Raw magnetometer present. Always false on web — no browser exposes one by default. */
34
+ magnetometer: boolean;
35
+ /** Shake events can be detected (needs an accelerometer). */
36
+ shake: boolean;
37
+ /** Tilt events can be detected (needs an accelerometer). */
38
+ tilt: boolean;
39
+ /** Significant-motion events can be detected (a hardware trigger or an accelerometer). */
40
+ significantMotion: boolean;
29
41
  }
30
42
  export interface StepSample {
31
43
  /** Steps in the sampled window (a DELTA, not a lifetime total). */
@@ -63,7 +75,31 @@ export interface HeadingSample {
63
75
  accuracy: number;
64
76
  timestamp: number;
65
77
  }
66
- export type MotionSample = StepSample | AltitudeSample | HeadingSample;
78
+ export type MotionSample = StepSample | AltitudeSample | HeadingSample
79
+ /** accelerometer / gyroscope / magnetometer: one raw reading. Units: accelerometer g (gravity
80
+ * included; flat face-up ⇒ z ≈ +1 on every platform), gyroscope rad/s, magnetometer µT. */
81
+ | {
82
+ x: number;
83
+ y: number;
84
+ z: number;
85
+ timestampMs: number;
86
+ }
87
+ /** shake: ONE event per shake. `magnitude` is the shake's peak total acceleration, g. */
88
+ | {
89
+ magnitude: number;
90
+ timestampMs: number;
91
+ }
92
+ /** tilt: attitude relative to gravity, degrees. Flat face-up is { pitch: 0, roll: 0 }; pitch is
93
+ * positive when the top edge rises, roll positive when the right edge dips. */
94
+ | {
95
+ pitch: number;
96
+ roll: number;
97
+ timestampMs: number;
98
+ }
99
+ /** significantMotion: the device started moving after a period at rest. */
100
+ | {
101
+ timestampMs: number;
102
+ };
67
103
  /**
68
104
  * Motion permission status. iOS gates CMPedometer behind a motion authorization;
69
105
  * Android 10+ gates the step counter behind runtime ACTIVITY_RECOGNITION. Altitude and
@@ -121,8 +157,11 @@ export declare function getHeading(): Promise<HeadingSample | null>;
121
157
  export interface MotionWatchOptions {
122
158
  /** Which sensor to stream. Defaults to "steps". */
123
159
  sensor?: MotionSensor;
124
- /** Requested sample interval, ms. The platform treats this as a hint and may deliver
125
- * faster (heading is event-driven) or slower (a step sample needs steps to have happened). */
160
+ /** Requested sample interval, ms. For the raw sensors (accelerometer / gyroscope /
161
+ * magnetometer) it is clamped to 16–1000 ms (default 100) and honoured, subject to the
162
+ * 60-samples/s ceiling. For steps / altitude / heading the platform treats it as a hint and
163
+ * may deliver faster (heading is event-driven) or slower (a step sample needs steps to have
164
+ * happened). Ignored by the gesture events, which fire when the gesture happens. */
126
165
  intervalMs?: number;
127
166
  /** Per-poll bridge timeout. Rarely needs changing — see DEFAULT_POLL_TIMEOUT_MS. */
128
167
  pollTimeoutMs?: number;
@@ -149,6 +188,13 @@ export interface MotionWatcher<T extends MotionSample = MotionSample> extends As
149
188
  * ```
150
189
  *
151
190
  * Type the stream by passing the sample type: `watch<HeadingSample>({ sensor: "heading" })`.
191
+ *
192
+ * ```ts
193
+ * // Shake to reroll.
194
+ * for await (const _ of watch({ sensor: "shake" })) reroll();
195
+ * // Tilt to steer.
196
+ * for await (const t of watch<{ pitch: number; roll: number; timestampMs: number }>({ sensor: "tilt" })) steer(t.roll);
197
+ * ```
152
198
  */
153
199
  export declare function watch<T extends MotionSample = MotionSample>(options?: MotionWatchOptions): MotionWatcher<T>;
154
200
  export declare const version = 1;
@@ -57,3 +57,4 @@ export declare function wixMediaUrl(value: unknown, size?: WixImageSize | null):
57
57
  * Wiring a runtime gate to this predicate is tracked separately.
58
58
  */
59
59
  export declare function isUnsizedWixMedia(url: string): boolean;
60
+ export * from "./rendition.js";
@@ -0,0 +1,42 @@
1
+ /** Pure rendition policy shared by web/RN. Native mirrors use the same request fixtures. */
2
+ export interface ImageTarget {
3
+ width: number;
4
+ height: number;
5
+ scale: number;
6
+ mode?: string;
7
+ maxEdge?: number;
8
+ }
9
+ /**
10
+ * The pixel size an image is requested at for a box of `width`×`height` points at `scale`: the box in pixels,
11
+ * its longer edge rounded up to a shared bucket (96 … 1400, or up to `maxEdge`, at most 4096) so nearby sizes
12
+ * share one cached rendition. A size it returns maps to itself. An invalid box asks for `maxEdge` square.
13
+ */
14
+ export declare function imagePixelSize(width: number, height: number, scale: number, maxEdge?: number): {
15
+ width: number;
16
+ height: number;
17
+ };
18
+ /** Keep the caller's source untouched: this URL belongs to a display request, not entity data. */
19
+ export declare function resolveImageRendition(source: string, target: ImageTarget): {
20
+ url: string;
21
+ family: string;
22
+ width: number;
23
+ height: number;
24
+ };
25
+ export interface ImageCandidate {
26
+ url: string;
27
+ width: number;
28
+ height: number;
29
+ }
30
+ /**
31
+ * The renditions a renderer offers for one image, smallest first, so the HOST picks among them by
32
+ * its own layout and pixel density (web `srcset`, a React Native `source` array) with no
33
+ * measurement code of ours. A fixed box gets one candidate per screen density; a fluid one (no
34
+ * numeric width) gets fluid widths, its height from `ratio` when known. A source that cannot be
35
+ * resized safely yields exactly itself.
36
+ */
37
+ export declare function imageCandidates(source: string, box: {
38
+ width?: number;
39
+ height?: number;
40
+ ratio?: number;
41
+ mode?: string;
42
+ }, scales?: number[]): ImageCandidate[];
@@ -66,6 +66,19 @@ function normalizePermissionStatus(s) {
66
66
  }
67
67
 
68
68
  // ../../core/sdk/motion/src/index.ts
69
+ var MIN_RAW_INTERVAL_MS = 16;
70
+ var MAX_RAW_INTERVAL_MS = 1e3;
71
+ var DEFAULT_RAW_INTERVAL_MS = 100;
72
+ var RAW_SENSORS = ["accelerometer", "gyroscope", "magnetometer"];
73
+ function isRawSensor(sensor) {
74
+ return RAW_SENSORS.includes(sensor);
75
+ }
76
+ function clampRawInterval(intervalMs) {
77
+ if (typeof intervalMs !== "number" || !Number.isFinite(intervalMs) || intervalMs <= 0) {
78
+ return DEFAULT_RAW_INTERVAL_MS;
79
+ }
80
+ return Math.min(MAX_RAW_INTERVAL_MS, Math.max(MIN_RAW_INTERVAL_MS, Math.round(intervalMs)));
81
+ }
69
82
  var STEP_HISTORY_STATUSES = [
70
83
  "available",
71
84
  "needs_permission",
@@ -87,7 +100,13 @@ async function availability() {
87
100
  steps: r?.steps === true,
88
101
  altimeter: r?.altimeter === true,
89
102
  heading: r?.heading === true,
90
- stepHistory: normalizeStepHistory(r?.stepHistory)
103
+ stepHistory: normalizeStepHistory(r?.stepHistory),
104
+ accelerometer: r?.accelerometer === true,
105
+ gyroscope: r?.gyroscope === true,
106
+ magnetometer: r?.magnetometer === true,
107
+ shake: r?.shake === true,
108
+ tilt: r?.tilt === true,
109
+ significantMotion: r?.significantMotion === true
91
110
  };
92
111
  }
93
112
  function normalizeStepHistory(raw) {
@@ -113,7 +132,8 @@ var DEFAULT_POLL_TIMEOUT_MS = 3e4;
113
132
  function watch(options) {
114
133
  const sensor = options?.sensor ?? "steps";
115
134
  const startParams = { sensor };
116
- if (typeof options?.intervalMs === "number") startParams.intervalMs = options.intervalMs;
135
+ if (isRawSensor(sensor)) startParams.intervalMs = clampRawInterval(options?.intervalMs);
136
+ else if (typeof options?.intervalMs === "number") startParams.intervalMs = options.intervalMs;
117
137
  const started = (async () => {
118
138
  const r = await dispatch("capability.motion.watchStart", startParams);
119
139
  if (!r?.watchId) throw new Error("motion.watch: native handler returned no watchId");
@@ -1,3 +1,78 @@
1
+ // ../../stdlib/wix-sdk/media/src/rendition.ts
2
+ var BUCKETS = [96, 128, 160, 192, 256, 320, 384, 512, 640, 768, 1024, 1280, 1400, 2048, 2560, 3072, 4096];
3
+ var CREDENTIAL = /(?:[?&])(?:token|expires|signature|x-amz-[^=&#]*|pvt)=/i;
4
+ var WIX = /^(https?:\/\/static\.wixstatic\.com\/media\/([^/?#]+))([^?#]*)([?#].*)?$/i;
5
+ var TRANSFORM = /^\/v1\/(fit|fill)\/([^/]+)\/([^/]+)$/i;
6
+ function imagePixelSize(width, height, scale, maxEdge = 1400) {
7
+ const cap = Number.isFinite(maxEdge) ? Math.max(1, Math.min(4096, Math.floor(maxEdge))) : 1400;
8
+ if (![width, height, scale].every((n) => Number.isFinite(n) && n > 0)) return { width: cap, height: cap };
9
+ const w = Math.ceil(width * scale), h = Math.ceil(height * scale);
10
+ if (!Number.isFinite(w + h)) return { width: cap, height: cap };
11
+ const longest = Math.max(w, h);
12
+ const bucket = Math.min(cap, BUCKETS.find((n) => n >= longest) ?? cap);
13
+ return { width: Math.max(1, Math.ceil(w * bucket / longest)), height: Math.max(1, Math.ceil(h * bucket / longest)) };
14
+ }
15
+ function resolveImageRendition(source, target) {
16
+ const pixels = imagePixelSize(target.width, target.height, target.scale, target.maxEdge);
17
+ const result = { ...pixels, url: source, family: source };
18
+ if (CREDENTIAL.test(source) || /[?&][^=&#]*%[0-9a-f]{2}[^=&#]*=/i.test(source)) return result;
19
+ const wix = WIX.exec(source);
20
+ if (!wix) return result;
21
+ const [, base, id, path, suffix = ""] = wix;
22
+ const transform = path ? TRANSFORM.exec(path) : null;
23
+ if (path && !transform) return result;
24
+ const mode = transform?.[1].toLowerCase() ?? (target.mode === "fill" ? "fill" : "fit");
25
+ const params = transform?.[2].split(",").filter(Boolean) ?? [];
26
+ const dimension = (key) => {
27
+ const param = params.find((p) => new RegExp(`^${key}_[0-9]+$`, "i").test(p));
28
+ return param ? Number(param.slice(2)) : 0;
29
+ };
30
+ const sw = dimension("w"), sh = dimension("h");
31
+ if (transform && (!sw || !sh)) return result;
32
+ const filename = transform?.[3] ?? id;
33
+ const ext = /\.([a-z0-9]+)$/i.exec(filename)?.[1].toLowerCase();
34
+ if (!ext || !["jpg", "jpeg", "png"].includes(ext)) return result;
35
+ const extras = params.filter((p) => !/^(w|h|q)_/i.test(p));
36
+ const quality = params.find((p) => /^q_[0-9]+$/i.test(p)) ?? "q_85";
37
+ let w = pixels.width, h = pixels.height;
38
+ if (transform) {
39
+ if (mode === "fill") {
40
+ const cap = Number.isFinite(target.maxEdge) ? Math.max(1, Math.min(4096, Math.floor(target.maxEdge))) : 1400;
41
+ const covers = target.mode === "fill" || target.mode === "stretch";
42
+ const less = (a, b) => a[0] * b[1] < b[0] * a[1];
43
+ const sx = [w, sw], sy = [h, sh];
44
+ let r = covers === less(sx, sy) ? sy : sx;
45
+ for (const bound of [[1, 1], [cap, Math.max(sw, sh)]]) if (less(bound, r)) r = bound;
46
+ w = Math.max(1, Math.ceil(sw * r[0] / r[1]));
47
+ h = Math.max(1, Math.ceil(sh * r[0] / r[1]));
48
+ } else {
49
+ w = Math.min(w, sw);
50
+ h = Math.min(h, sh);
51
+ }
52
+ }
53
+ const gcd = (a, b) => b ? gcd(b, a % b) : a;
54
+ const divisor = gcd(transform ? sw : w, transform ? sh : h);
55
+ const shape = mode === "fill" ? `${(transform ? sw : w) / divisor}:${(transform ? sh : h) / divisor}` : "";
56
+ result.family = `${base}|${mode}|${shape}|${extras.join(",")}${suffix}`;
57
+ if (transform && sw <= pixels.width && sh <= pixels.height) return result;
58
+ result.url = `${base}/v1/${mode}/w_${w},h_${h},${quality}${extras.length ? "," + extras.join(",") : ""}/${transform ? filename : "image." + ext}${suffix}`;
59
+ return result;
60
+ }
61
+ var FLUID_WIDTHS = [320, 640, 768, 1024, 1280, 1400, 2048];
62
+ function imageCandidates(source, box, scales = [1, 2, 3]) {
63
+ const fixed = typeof box.width === "number" && box.width > 0 && typeof box.height === "number" && box.height > 0;
64
+ const targets = fixed ? scales.map((scale) => ({ width: box.width, height: box.height, scale, mode: box.mode })) : FLUID_WIDTHS.map((width) => ({ width, height: box.ratio ? width / box.ratio : width, scale: 1, mode: box.ratio ? box.mode : "fit" }));
65
+ const seen = /* @__PURE__ */ new Set();
66
+ const out = [];
67
+ for (const target of targets) {
68
+ const r = resolveImageRendition(source, target);
69
+ if (seen.has(r.url)) continue;
70
+ seen.add(r.url);
71
+ out.push({ url: r.url, width: r.width, height: r.height });
72
+ }
73
+ return out.length > 1 || out[0]?.url !== source ? out : [{ url: source, width: 0, height: 0 }];
74
+ }
75
+
1
76
  // ../../stdlib/wix-sdk/media/src/index.ts
2
77
  var WIX_LIST_IMAGE = { width: 1e3, height: 1e3, quality: 85 };
3
78
  var WIX_DETAIL_IMAGE = { width: 1400, height: 1400, quality: 85 };
@@ -94,7 +169,10 @@ function isUnsizedWixMedia(url) {
94
169
  export {
95
170
  WIX_DETAIL_IMAGE,
96
171
  WIX_LIST_IMAGE,
172
+ imageCandidates,
173
+ imagePixelSize,
97
174
  isUnsizedWixMedia,
175
+ resolveImageRendition,
98
176
  wixMediaUrl
99
177
  };
100
178
  //# sourceMappingURL=wix-media.mjs.map