craft-native 0.0.55 → 0.0.74

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 (146) hide show
  1. package/dist/android/src/index.d.ts +73 -0
  2. package/dist/android/src/index.js +177 -37
  3. package/dist/android/templates/AndroidManifest.xml.template +10 -36
  4. package/dist/android/templates/CraftBridge.kt.template +192 -60
  5. package/dist/android/templates/CraftHealthConnect.kt.template +200 -0
  6. package/dist/android/templates/CraftHealthConnectStub.kt.template +28 -0
  7. package/dist/android/templates/LocationRecordingService.kt.template +160 -0
  8. package/dist/android/templates/MainActivity.kt.template +140 -19
  9. package/dist/android/templates/build.gradle.kts.app.template +23 -1
  10. package/dist/android/templates/build.gradle.kts.project.template +3 -2
  11. package/dist/android/templates/proguard-rules.pro.template +9 -0
  12. package/dist/api/android-advanced.d.ts +5 -6
  13. package/dist/api/app.d.ts +0 -1
  14. package/dist/api/clipboard.d.ts +0 -1
  15. package/dist/api/crypto.d.ts +1 -2
  16. package/dist/api/db.d.ts +1 -2
  17. package/dist/api/dialog.d.ts +0 -1
  18. package/dist/api/fs.d.ts +1 -2
  19. package/dist/api/gestures.d.ts +66 -0
  20. package/dist/api/http.d.ts +1 -2
  21. package/dist/api/index.d.ts +37 -34
  22. package/dist/api/ios-advanced.d.ts +6 -7
  23. package/dist/api/macos-advanced.d.ts +2 -3
  24. package/dist/api/media.d.ts +0 -1
  25. package/dist/api/mobile.d.ts +109 -1
  26. package/dist/api/process.d.ts +0 -1
  27. package/dist/api/sidebar.d.ts +3 -20
  28. package/dist/api/spaces.d.ts +83 -0
  29. package/dist/api/tray.d.ts +2 -3
  30. package/dist/api/window.d.ts +1 -2
  31. package/dist/api/windows-advanced.d.ts +6 -7
  32. package/dist/assets/index.d.ts +0 -1
  33. package/dist/binary-resolver.d.ts +23 -1
  34. package/dist/bridge/android.d.ts +0 -1
  35. package/dist/bridge/core.d.ts +0 -38
  36. package/dist/bridge/ids.d.ts +0 -1
  37. package/dist/bridge/ios.d.ts +0 -1
  38. package/dist/bridge/webkit-pending.d.ts +0 -1
  39. package/dist/build/bundle-optimizer.d.ts +0 -1
  40. package/dist/cli.js +666 -90
  41. package/dist/components/index.d.ts +6 -7
  42. package/dist/components/native.d.ts +0 -1
  43. package/dist/components/sidebar.d.ts +2 -81
  44. package/dist/dev/devtools.d.ts +0 -1
  45. package/dist/dev/error-overlay.d.ts +0 -1
  46. package/dist/dev/hot-reload.d.ts +0 -1
  47. package/dist/index.cjs +113 -3
  48. package/dist/index.d.cts +16 -16
  49. package/dist/index.d.ts +16 -16
  50. package/dist/index.js +112 -4
  51. package/dist/ios/src/index.d.ts +172 -0
  52. package/dist/ios/src/index.js +440 -42
  53. package/dist/ios/templates/CraftActivityAttributes.swift +14 -0
  54. package/dist/ios/templates/CraftApp.swift +1001 -73
  55. package/dist/ios/templates/CraftLiveActivityWidget.swift.template +62 -0
  56. package/dist/ios/templates/CraftWatchApp.swift.template +155 -0
  57. package/dist/ios/templates/Info.plist.template +10 -9
  58. package/dist/ios/templates/WatchApp.Info.plist.template +26 -0
  59. package/dist/ios/templates/WidgetExtension.Info.plist +31 -0
  60. package/dist/ios/templates/project.yml.template +12 -1
  61. package/dist/logging/index.d.ts +0 -1
  62. package/dist/mobile.d.ts +8 -0
  63. package/dist/mobile.js +755 -0
  64. package/dist/optimizations/index.d.ts +3 -4
  65. package/dist/package.d.ts +11 -1
  66. package/dist/performance/runtime.d.ts +0 -1
  67. package/dist/performance/startup.d.ts +0 -1
  68. package/dist/plugins/index.d.ts +0 -1
  69. package/dist/security/index.d.ts +0 -1
  70. package/dist/sidebar-types.d.ts +102 -0
  71. package/dist/signing/index.d.ts +0 -1
  72. package/dist/styles/headwind.d.ts +0 -1
  73. package/dist/styles/index.d.ts +9 -10
  74. package/dist/styles/sidebar-templates.d.ts +0 -1
  75. package/dist/styles/sidebars.d.ts +0 -1
  76. package/dist/types.d.ts +131 -1
  77. package/dist/updater/index.d.ts +0 -1
  78. package/dist/utils/audio.d.ts +0 -1
  79. package/dist/utils/index.d.ts +4 -5
  80. package/dist/utils/native.d.ts +1 -2
  81. package/dist/utils/react.d.ts +0 -1
  82. package/dist/utils/storage.d.ts +0 -1
  83. package/dist/utils/svelte.d.ts +0 -1
  84. package/dist/utils/timer.d.ts +0 -1
  85. package/dist/utils/vue.d.ts +0 -1
  86. package/package.json +32 -4
  87. package/dist/android/src/index.js.map +0 -10
  88. package/dist/api/android-advanced.d.ts.map +0 -1
  89. package/dist/api/app.d.ts.map +0 -1
  90. package/dist/api/clipboard.d.ts.map +0 -1
  91. package/dist/api/crypto.d.ts.map +0 -1
  92. package/dist/api/db.d.ts.map +0 -1
  93. package/dist/api/dialog.d.ts.map +0 -1
  94. package/dist/api/fs.d.ts.map +0 -1
  95. package/dist/api/http.d.ts.map +0 -1
  96. package/dist/api/index.d.ts.map +0 -1
  97. package/dist/api/ios-advanced.d.ts.map +0 -1
  98. package/dist/api/macos-advanced.d.ts.map +0 -1
  99. package/dist/api/media.d.ts.map +0 -1
  100. package/dist/api/mobile.d.ts.map +0 -1
  101. package/dist/api/process.d.ts.map +0 -1
  102. package/dist/api/sidebar.d.ts.map +0 -1
  103. package/dist/api/tray.d.ts.map +0 -1
  104. package/dist/api/window.d.ts.map +0 -1
  105. package/dist/api/windows-advanced.d.ts.map +0 -1
  106. package/dist/assets/index.d.ts.map +0 -1
  107. package/dist/binary-resolver.d.ts.map +0 -1
  108. package/dist/bridge/android.d.ts.map +0 -1
  109. package/dist/bridge/core.d.ts.map +0 -1
  110. package/dist/bridge/ids.d.ts.map +0 -1
  111. package/dist/bridge/ios.d.ts.map +0 -1
  112. package/dist/bridge/webkit-pending.d.ts.map +0 -1
  113. package/dist/build/bundle-optimizer.d.ts.map +0 -1
  114. package/dist/components/index.d.ts.map +0 -1
  115. package/dist/components/native.d.ts.map +0 -1
  116. package/dist/components/sidebar.d.ts.map +0 -1
  117. package/dist/dev/devtools.d.ts.map +0 -1
  118. package/dist/dev/error-overlay.d.ts.map +0 -1
  119. package/dist/dev/hot-reload.d.ts.map +0 -1
  120. package/dist/index.d.ts.map +0 -1
  121. package/dist/index.js.map +0 -45
  122. package/dist/ios/src/index.js.map +0 -10
  123. package/dist/logging/index.d.ts.map +0 -1
  124. package/dist/optimizations/index.d.ts.map +0 -1
  125. package/dist/package.d.ts.map +0 -1
  126. package/dist/package.test.d.ts +0 -2
  127. package/dist/package.test.d.ts.map +0 -1
  128. package/dist/performance/runtime.d.ts.map +0 -1
  129. package/dist/performance/startup.d.ts.map +0 -1
  130. package/dist/plugins/index.d.ts.map +0 -1
  131. package/dist/security/index.d.ts.map +0 -1
  132. package/dist/signing/index.d.ts.map +0 -1
  133. package/dist/styles/headwind.d.ts.map +0 -1
  134. package/dist/styles/index.d.ts.map +0 -1
  135. package/dist/styles/sidebar-templates.d.ts.map +0 -1
  136. package/dist/styles/sidebars.d.ts.map +0 -1
  137. package/dist/types.d.ts.map +0 -1
  138. package/dist/updater/index.d.ts.map +0 -1
  139. package/dist/utils/audio.d.ts.map +0 -1
  140. package/dist/utils/index.d.ts.map +0 -1
  141. package/dist/utils/native.d.ts.map +0 -1
  142. package/dist/utils/react.d.ts.map +0 -1
  143. package/dist/utils/storage.d.ts.map +0 -1
  144. package/dist/utils/svelte.d.ts.map +0 -1
  145. package/dist/utils/timer.d.ts.map +0 -1
  146. package/dist/utils/vue.d.ts.map +0 -1
package/dist/mobile.js ADDED
@@ -0,0 +1,755 @@
1
+ // src/bridge/ids.ts
2
+ function secureUUID() {
3
+ const c = globalThis.crypto;
4
+ if (c && typeof c.randomUUID === "function") {
5
+ return c.randomUUID();
6
+ }
7
+ if (c && typeof c.getRandomValues === "function") {
8
+ const bytes = new Uint8Array(16);
9
+ c.getRandomValues(bytes);
10
+ bytes[6] = bytes[6] & 15 | 64;
11
+ bytes[8] = bytes[8] & 63 | 128;
12
+ const hex = Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
13
+ return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20, 32)}`;
14
+ }
15
+ throw new Error("[Craft] No Web Crypto available; cannot generate secure IDs");
16
+ }
17
+
18
+ // src/api/mobile.ts
19
+ var WEB_DEVICE_ID_KEY = "__craft_web_device_id__";
20
+ function _webFallbackDeviceId() {
21
+ if (typeof globalThis !== "undefined" && globalThis.localStorage) {
22
+ try {
23
+ const ls = globalThis.localStorage;
24
+ const existing = ls.getItem(WEB_DEVICE_ID_KEY);
25
+ if (existing && /^web-[0-9a-f-]+$/i.test(existing))
26
+ return existing;
27
+ const fresh = `web-${secureUUID()}`;
28
+ ls.setItem(WEB_DEVICE_ID_KEY, fresh);
29
+ return fresh;
30
+ } catch {}
31
+ }
32
+ return `web-${secureUUID()}`;
33
+ }
34
+ function _resetWebFallbackDeviceIdForTests() {
35
+ if (typeof globalThis !== "undefined" && globalThis.localStorage) {
36
+ try {
37
+ globalThis.localStorage.removeItem(WEB_DEVICE_ID_KEY);
38
+ } catch {}
39
+ }
40
+ }
41
+ var device = {
42
+ async getInfo() {
43
+ const craft = getCraftMobile();
44
+ if (typeof window !== "undefined" && craft?.device) {
45
+ return craft.device.getInfo();
46
+ }
47
+ return {
48
+ platform: detectPlatform(),
49
+ osVersion: "unknown",
50
+ model: "unknown",
51
+ manufacturer: "unknown",
52
+ deviceId: _webFallbackDeviceId(),
53
+ isTablet: false,
54
+ screen: {
55
+ width: typeof window !== "undefined" ? window.innerWidth || 0 : 0,
56
+ height: typeof window !== "undefined" ? window.innerHeight || 0 : 0,
57
+ scale: typeof window !== "undefined" ? window.devicePixelRatio || 1 : 1
58
+ },
59
+ battery: { level: 100, isCharging: false },
60
+ network: { type: "wifi", isConnected: typeof navigator !== "undefined" ? navigator.onLine ?? true : true }
61
+ };
62
+ },
63
+ async getCapabilities() {
64
+ const craft = getCraftMobile();
65
+ if (typeof window !== "undefined" && craft?.device) {
66
+ return craft.device.getCapabilities();
67
+ }
68
+ return {
69
+ camera: true,
70
+ biometrics: false,
71
+ nfc: false,
72
+ bluetooth: false,
73
+ gps: "geolocation" in navigator,
74
+ accelerometer: false,
75
+ gyroscope: false,
76
+ haptics: "vibrate" in navigator,
77
+ ar: false,
78
+ faceId: false,
79
+ touchId: false
80
+ };
81
+ },
82
+ isMobile() {
83
+ const platform = detectPlatform();
84
+ return platform === "ios" || platform === "android";
85
+ },
86
+ isIOS() {
87
+ return detectPlatform() === "ios";
88
+ },
89
+ isAndroid() {
90
+ return detectPlatform() === "android";
91
+ },
92
+ getLocale() {
93
+ return navigator?.language || "en-US";
94
+ },
95
+ getTimezone() {
96
+ return Intl.DateTimeFormat().resolvedOptions().timeZone;
97
+ }
98
+ };
99
+ var haptics = {
100
+ async impact(style = "medium") {
101
+ const craft = getCraftMobile();
102
+ if (typeof window !== "undefined" && craft?.haptics) {
103
+ return craft.haptics.impact(style);
104
+ }
105
+ if ("vibrate" in navigator) {
106
+ const duration = { light: 10, medium: 20, heavy: 30, soft: 5, rigid: 25 }[style];
107
+ navigator.vibrate(duration);
108
+ }
109
+ },
110
+ async notification(type = "success") {
111
+ const craft = getCraftMobile();
112
+ if (typeof window !== "undefined" && craft?.haptics) {
113
+ return craft.haptics.notification(type);
114
+ }
115
+ if ("vibrate" in navigator) {
116
+ const patterns = {
117
+ success: [10, 30, 10],
118
+ warning: [30, 30, 30],
119
+ error: [50, 50, 50, 50, 50]
120
+ };
121
+ navigator.vibrate(patterns[type]);
122
+ }
123
+ },
124
+ async selection() {
125
+ const craft = getCraftMobile();
126
+ if (typeof window !== "undefined" && craft?.haptics) {
127
+ return craft.haptics.selection();
128
+ }
129
+ if ("vibrate" in navigator) {
130
+ navigator.vibrate(5);
131
+ }
132
+ },
133
+ async vibrate(pattern) {
134
+ const craft = getCraftMobile();
135
+ if (typeof window !== "undefined" && craft?.haptics) {
136
+ return craft.haptics.vibrate(pattern);
137
+ }
138
+ if ("vibrate" in navigator) {
139
+ navigator.vibrate(pattern);
140
+ }
141
+ }
142
+ };
143
+ var permissions = {
144
+ async check(permission) {
145
+ const craft = getCraftMobile();
146
+ if (typeof window !== "undefined" && craft?.permissions) {
147
+ return craft.permissions.check(permission);
148
+ }
149
+ try {
150
+ const webPermission = mapToWebPermission(permission);
151
+ if (webPermission && navigator.permissions) {
152
+ const result = await navigator.permissions.query({ name: webPermission });
153
+ return mapWebPermissionStatus(result.state);
154
+ }
155
+ } catch {}
156
+ return "undetermined";
157
+ },
158
+ async request(permission) {
159
+ const craft = getCraftMobile();
160
+ if (typeof window !== "undefined" && craft?.permissions) {
161
+ return craft.permissions.request(permission);
162
+ }
163
+ try {
164
+ if (permission === "camera" || permission === "microphone") {
165
+ const constraints = {};
166
+ if (permission === "camera")
167
+ constraints.video = true;
168
+ if (permission === "microphone")
169
+ constraints.audio = true;
170
+ const stream = await navigator.mediaDevices.getUserMedia(constraints);
171
+ stream.getTracks().forEach((track) => track.stop());
172
+ return "granted";
173
+ }
174
+ if (permission === "location") {
175
+ return new Promise((resolve) => {
176
+ navigator.geolocation.getCurrentPosition(() => resolve("granted"), () => resolve("denied"));
177
+ });
178
+ }
179
+ if (permission === "notifications") {
180
+ const result = await Notification.requestPermission();
181
+ return result === "granted" ? "granted" : "denied";
182
+ }
183
+ } catch {
184
+ return "denied";
185
+ }
186
+ return "undetermined";
187
+ },
188
+ async checkMultiple(permissionList) {
189
+ const results = {};
190
+ for (const perm of permissionList) {
191
+ results[perm] = await this.check(perm);
192
+ }
193
+ return results;
194
+ },
195
+ async requestMultiple(permissionList) {
196
+ const results = {};
197
+ for (const perm of permissionList) {
198
+ results[perm] = await this.request(perm);
199
+ }
200
+ return results;
201
+ },
202
+ async openSettings() {
203
+ const craft = getCraftMobile();
204
+ if (typeof window !== "undefined" && craft?.permissions) {
205
+ return craft.permissions.openSettings();
206
+ }
207
+ }
208
+ };
209
+ var camera = {
210
+ async takePicture(options = {}) {
211
+ const craft = getCraftMobile();
212
+ if (typeof window !== "undefined" && craft?.camera) {
213
+ return craft.camera.takePicture(options);
214
+ }
215
+ throw new Error("Camera API not available. Must run in Craft environment.");
216
+ },
217
+ async pickImage() {
218
+ const craft = getCraftMobile();
219
+ if (typeof window !== "undefined" && craft?.camera) {
220
+ return craft.camera.pickImage();
221
+ }
222
+ return new Promise((resolve, reject) => {
223
+ const input = document.createElement("input");
224
+ input.type = "file";
225
+ input.accept = "image/*";
226
+ input.onchange = async () => {
227
+ const file = input.files?.[0];
228
+ if (file) {
229
+ const reader = new FileReader;
230
+ reader.onload = () => {
231
+ const base64 = reader.result.split(",")[1];
232
+ resolve({
233
+ base64,
234
+ uri: URL.createObjectURL(file),
235
+ width: 0,
236
+ height: 0,
237
+ mimeType: file.type
238
+ });
239
+ };
240
+ reader.onerror = () => reject(new Error("Failed to read file"));
241
+ reader.readAsDataURL(file);
242
+ } else {
243
+ reject(new Error("No file selected"));
244
+ }
245
+ };
246
+ input.click();
247
+ });
248
+ },
249
+ async pickMultiple(options = {}) {
250
+ const craft = getCraftMobile();
251
+ if (typeof window !== "undefined" && craft?.camera) {
252
+ return craft.camera.pickMultiple(options);
253
+ }
254
+ throw new Error("Camera API not available. Must run in Craft environment.");
255
+ },
256
+ async isAvailable() {
257
+ const craft = getCraftMobile();
258
+ if (typeof window !== "undefined" && craft?.camera) {
259
+ return craft.camera.isAvailable();
260
+ }
261
+ try {
262
+ const devices = await navigator.mediaDevices.enumerateDevices();
263
+ return devices.some((d) => d.kind === "videoinput");
264
+ } catch {
265
+ return false;
266
+ }
267
+ }
268
+ };
269
+ var biometrics = {
270
+ async isAvailable() {
271
+ const craft = getCraftMobile();
272
+ if (typeof window !== "undefined" && craft?.biometrics) {
273
+ return craft.biometrics.isAvailable();
274
+ }
275
+ return false;
276
+ },
277
+ async getBiometricType() {
278
+ const craft = getCraftMobile();
279
+ if (typeof window !== "undefined" && craft?.biometrics) {
280
+ return craft.biometrics.getBiometricType();
281
+ }
282
+ return null;
283
+ },
284
+ async authenticate(reason) {
285
+ const craft = getCraftMobile();
286
+ if (typeof window !== "undefined" && craft?.biometrics) {
287
+ return craft.biometrics.authenticate(reason);
288
+ }
289
+ throw new Error("Biometrics not available");
290
+ }
291
+ };
292
+ var secureStorage = {
293
+ async set(key, value) {
294
+ const craft = getCraftMobile();
295
+ if (typeof window !== "undefined" && craft?.secureStorage) {
296
+ return craft.secureStorage.set(key, value);
297
+ }
298
+ if (typeof window !== "undefined" && window.craft)
299
+ throw new Error("Craft secure storage bridge is unavailable");
300
+ localStorage.setItem(`secure_${key}`, value);
301
+ },
302
+ async get(key) {
303
+ const craft = getCraftMobile();
304
+ if (typeof window !== "undefined" && craft?.secureStorage) {
305
+ return craft.secureStorage.get(key);
306
+ }
307
+ if (typeof window !== "undefined" && window.craft)
308
+ throw new Error("Craft secure storage bridge is unavailable");
309
+ return localStorage.getItem(`secure_${key}`);
310
+ },
311
+ async delete(key) {
312
+ const craft = getCraftMobile();
313
+ if (typeof window !== "undefined" && craft?.secureStorage) {
314
+ return craft.secureStorage.delete(key);
315
+ }
316
+ if (typeof window !== "undefined" && window.craft)
317
+ throw new Error("Craft secure storage bridge is unavailable");
318
+ localStorage.removeItem(`secure_${key}`);
319
+ },
320
+ async clear() {
321
+ const craft = getCraftMobile();
322
+ if (typeof window !== "undefined" && craft?.secureStorage) {
323
+ return craft.secureStorage.clear();
324
+ }
325
+ if (typeof window !== "undefined" && window.craft)
326
+ throw new Error("Craft secure storage bridge is unavailable");
327
+ Object.keys(localStorage).filter((k) => k.startsWith("secure_")).forEach((k) => localStorage.removeItem(k));
328
+ }
329
+ };
330
+ var webLocationRecording = {
331
+ id: null,
332
+ active: false,
333
+ paused: false,
334
+ startedAt: null,
335
+ locations: []
336
+ };
337
+ var webLocationRecordingWatchId = null;
338
+ var location = {
339
+ async getCurrentPosition(options = {}) {
340
+ const craft = getCraftMobile();
341
+ if (typeof window !== "undefined" && craft?.location) {
342
+ return craft.location.getCurrentPosition(options);
343
+ }
344
+ return new Promise((resolve, reject) => {
345
+ navigator.geolocation.getCurrentPosition((pos) => resolve({
346
+ latitude: pos.coords.latitude,
347
+ longitude: pos.coords.longitude,
348
+ altitude: pos.coords.altitude ?? undefined,
349
+ accuracy: pos.coords.accuracy,
350
+ heading: pos.coords.heading ?? undefined,
351
+ speed: pos.coords.speed ?? undefined,
352
+ timestamp: pos.timestamp
353
+ }), reject, {
354
+ enableHighAccuracy: options.enableHighAccuracy,
355
+ timeout: options.timeout,
356
+ maximumAge: options.maximumAge
357
+ });
358
+ });
359
+ },
360
+ watchPosition(callback, options = {}) {
361
+ const craft = getCraftMobile();
362
+ if (typeof window !== "undefined" && craft?.location) {
363
+ return craft.location.watchPosition(callback, options);
364
+ }
365
+ return navigator.geolocation.watchPosition((pos) => callback({
366
+ latitude: pos.coords.latitude,
367
+ longitude: pos.coords.longitude,
368
+ altitude: pos.coords.altitude ?? undefined,
369
+ accuracy: pos.coords.accuracy,
370
+ heading: pos.coords.heading ?? undefined,
371
+ speed: pos.coords.speed ?? undefined,
372
+ timestamp: pos.timestamp
373
+ }), console.error, {
374
+ enableHighAccuracy: options.enableHighAccuracy,
375
+ timeout: options.timeout,
376
+ maximumAge: options.maximumAge
377
+ });
378
+ },
379
+ clearWatch(watchId) {
380
+ const craft = getCraftMobile();
381
+ if (typeof window !== "undefined" && craft?.location) {
382
+ return craft.location.clearWatch(watchId);
383
+ }
384
+ navigator.geolocation.clearWatch(watchId);
385
+ },
386
+ async startRecording(options = {}) {
387
+ const craft = getCraftMobile();
388
+ if (typeof window !== "undefined" && craft?.location?.startRecording)
389
+ return craft.location.startRecording(options);
390
+ if (webLocationRecordingWatchId !== null)
391
+ navigator.geolocation.clearWatch(webLocationRecordingWatchId);
392
+ webLocationRecording = {
393
+ id: secureUUID(),
394
+ active: true,
395
+ paused: false,
396
+ startedAt: Date.now(),
397
+ locations: []
398
+ };
399
+ webLocationRecordingWatchId = location.watchPosition((position) => {
400
+ if (!webLocationRecording.paused)
401
+ webLocationRecording.locations.push(position);
402
+ }, options);
403
+ return { ...webLocationRecording, sampleCount: 0 };
404
+ },
405
+ async pauseRecording() {
406
+ const craft = getCraftMobile();
407
+ if (typeof window !== "undefined" && craft?.location?.pauseRecording)
408
+ return craft.location.pauseRecording();
409
+ webLocationRecording.paused = true;
410
+ return { ...webLocationRecording, sampleCount: webLocationRecording.locations.length };
411
+ },
412
+ async resumeRecording() {
413
+ const craft = getCraftMobile();
414
+ if (typeof window !== "undefined" && craft?.location?.resumeRecording)
415
+ return craft.location.resumeRecording();
416
+ webLocationRecording.paused = false;
417
+ return { ...webLocationRecording, sampleCount: webLocationRecording.locations.length };
418
+ },
419
+ async stopRecording() {
420
+ const craft = getCraftMobile();
421
+ if (typeof window !== "undefined" && craft?.location?.stopRecording)
422
+ return craft.location.stopRecording();
423
+ if (webLocationRecordingWatchId !== null) {
424
+ location.clearWatch(webLocationRecordingWatchId);
425
+ webLocationRecordingWatchId = null;
426
+ }
427
+ webLocationRecording.active = false;
428
+ webLocationRecording.paused = false;
429
+ return { ...webLocationRecording, locations: [...webLocationRecording.locations] };
430
+ },
431
+ async getRecordingState() {
432
+ const craft = getCraftMobile();
433
+ if (typeof window !== "undefined" && craft?.location?.getRecordingState)
434
+ return craft.location.getRecordingState();
435
+ return { ...webLocationRecording, sampleCount: webLocationRecording.locations.length };
436
+ },
437
+ async readRecording() {
438
+ const craft = getCraftMobile();
439
+ if (typeof window !== "undefined" && craft?.location?.readRecording)
440
+ return craft.location.readRecording();
441
+ return [...webLocationRecording.locations];
442
+ }
443
+ };
444
+ var share = {
445
+ async share(options) {
446
+ const craft = getCraftMobile();
447
+ if (typeof window !== "undefined" && craft?.share) {
448
+ return craft.share.share(options);
449
+ }
450
+ if (navigator.share) {
451
+ await navigator.share({
452
+ title: options.title,
453
+ text: options.text,
454
+ url: options.url
455
+ });
456
+ } else {
457
+ throw new Error("Share API not available");
458
+ }
459
+ },
460
+ isAvailable() {
461
+ const craft = getCraftMobile();
462
+ if (typeof window !== "undefined" && craft?.share) {
463
+ return true;
464
+ }
465
+ return "share" in navigator;
466
+ }
467
+ };
468
+ var lifecycle = {
469
+ getState() {
470
+ const craft = getCraftMobile();
471
+ if (typeof window !== "undefined" && craft?.lifecycle) {
472
+ return craft.lifecycle.getState();
473
+ }
474
+ return document.visibilityState === "visible" ? "active" : "background";
475
+ },
476
+ onStateChange(callback) {
477
+ const craft = getCraftMobile();
478
+ if (typeof window !== "undefined" && craft?.lifecycle) {
479
+ return craft.lifecycle.onStateChange(callback);
480
+ }
481
+ const handler = () => {
482
+ callback(document.visibilityState === "visible" ? "active" : "background");
483
+ };
484
+ document.addEventListener("visibilitychange", handler);
485
+ return () => document.removeEventListener("visibilitychange", handler);
486
+ }
487
+ };
488
+ var notifications = {
489
+ async show(options) {
490
+ const craft = getCraftMobile();
491
+ if (typeof window !== "undefined" && craft?.notifications) {
492
+ return craft.notifications.show(options);
493
+ }
494
+ if ("Notification" in window && Notification.permission === "granted") {
495
+ new Notification(options.title, { body: options.body });
496
+ }
497
+ },
498
+ async schedule(options) {
499
+ const craft = getCraftMobile();
500
+ if (typeof window !== "undefined" && craft?.notifications) {
501
+ return craft.notifications.schedule(options);
502
+ }
503
+ throw new Error("Scheduled notifications not available in web");
504
+ },
505
+ async cancelAll() {
506
+ const craft = getCraftMobile();
507
+ if (typeof window !== "undefined" && craft?.notifications) {
508
+ return craft.notifications.cancelAll();
509
+ }
510
+ },
511
+ async setBadge(count) {
512
+ const craft = getCraftMobile();
513
+ if (typeof window !== "undefined" && craft?.notifications) {
514
+ return craft.notifications.setBadge(count);
515
+ }
516
+ }
517
+ };
518
+ var webWakeLock = null;
519
+ var keepAwake = {
520
+ async enable() {
521
+ const craft = getCraftRoot();
522
+ if (craft?.setKeepAwake) {
523
+ await craft.setKeepAwake(true);
524
+ return;
525
+ }
526
+ const wakeLock = navigator.wakeLock;
527
+ webWakeLock = await wakeLock?.request("screen") ?? null;
528
+ },
529
+ async disable() {
530
+ const craft = getCraftRoot();
531
+ if (craft?.setKeepAwake) {
532
+ await craft.setKeepAwake(false);
533
+ return;
534
+ }
535
+ await webWakeLock?.release();
536
+ webWakeLock = null;
537
+ }
538
+ };
539
+ var deepLinks = {
540
+ async getInitialURL() {
541
+ return normalizeDeepLinkURL(await getCraftRoot()?.deepLinks?.getInitialURL?.());
542
+ },
543
+ onLink(callback) {
544
+ const craft = getCraftRoot();
545
+ if (craft?.deepLinks?.onLink) {
546
+ return craft.deepLinks.onLink((value) => {
547
+ const url = normalizeDeepLinkURL(value);
548
+ if (url)
549
+ callback(url);
550
+ }) ?? (() => {});
551
+ }
552
+ if (typeof globalThis === "undefined")
553
+ return () => {};
554
+ const listener = (event) => {
555
+ const url = normalizeDeepLinkURL(event.detail);
556
+ if (url)
557
+ callback(url);
558
+ };
559
+ globalThis.addEventListener("craftDeepLink", listener);
560
+ return () => globalThis.removeEventListener("craftDeepLink", listener);
561
+ }
562
+ };
563
+ function normalizeDeepLinkURL(value) {
564
+ if (typeof value === "string")
565
+ return value.trim() || null;
566
+ if (!value || typeof value !== "object")
567
+ return null;
568
+ const url = value.url;
569
+ return typeof url === "string" && url.trim() ? url : null;
570
+ }
571
+ var network = {
572
+ async getStatus() {
573
+ const craft = getCraftRoot();
574
+ if (craft?.getNetworkStatus)
575
+ return await craft.getNetworkStatus();
576
+ return {
577
+ type: "unknown",
578
+ isConnected: typeof navigator === "undefined" ? false : navigator.onLine
579
+ };
580
+ },
581
+ onChange(callback) {
582
+ const craft = getCraftRoot();
583
+ if (craft?.onNetworkChange) {
584
+ craft.onNetworkChange(callback);
585
+ return () => craft.offNetworkChange?.();
586
+ }
587
+ if (typeof globalThis === "undefined")
588
+ return () => {};
589
+ const listener = () => callback({ type: "unknown", isConnected: navigator.onLine });
590
+ globalThis.addEventListener("online", listener);
591
+ globalThis.addEventListener("offline", listener);
592
+ return () => {
593
+ globalThis.removeEventListener("online", listener);
594
+ globalThis.removeEventListener("offline", listener);
595
+ };
596
+ }
597
+ };
598
+ var appReview = {
599
+ async request() {
600
+ const craft = getCraftRoot();
601
+ if (!craft?.requestReview)
602
+ return false;
603
+ return Boolean(await craft.requestReview());
604
+ }
605
+ };
606
+ var pushNotifications = {
607
+ async register() {
608
+ const craft = getCraftRoot();
609
+ if (!craft?.registerPush)
610
+ throw new Error("Push notifications are unavailable");
611
+ return craft.registerPush();
612
+ },
613
+ onToken(callback) {
614
+ return onCraftEvent("craftPushToken", (detail) => callback(String(detail.token ?? "")));
615
+ },
616
+ onNotification(callback) {
617
+ return onCraftEvent("craftNotificationResponse", (detail) => callback(detail));
618
+ }
619
+ };
620
+ var health = {
621
+ async requestAuthorization(types) {
622
+ const craft = getCraftRoot();
623
+ if (!craft?.health?.requestAuthorization)
624
+ throw new Error("Health data is unavailable");
625
+ return Boolean(await craft.health.requestAuthorization(types));
626
+ },
627
+ async getData(type, options = {}) {
628
+ const craft = getCraftRoot();
629
+ if (!craft?.health?.getData)
630
+ throw new Error("Health data is unavailable");
631
+ return craft.health.getData(type, options);
632
+ },
633
+ async saveWorkout(workout) {
634
+ const craft = getCraftRoot();
635
+ if (!craft?.health?.saveWorkout)
636
+ throw new Error("Saving health workouts is unavailable");
637
+ return craft.health.saveWorkout(workout);
638
+ }
639
+ };
640
+ var liveActivities = {
641
+ async start(options) {
642
+ const craft = getCraftRoot();
643
+ if (!craft?.liveActivity?.start)
644
+ throw new Error("Live Activities are unavailable");
645
+ return craft.liveActivity.start(options);
646
+ },
647
+ async update(state) {
648
+ const craft = getCraftRoot();
649
+ if (!craft?.liveActivity?.update)
650
+ return;
651
+ await craft.liveActivity.update(state);
652
+ },
653
+ async end() {
654
+ const craft = getCraftRoot();
655
+ if (!craft?.liveActivity?.end)
656
+ return;
657
+ await craft.liveActivity.end();
658
+ }
659
+ };
660
+ var watchConnectivity = {
661
+ async send(message) {
662
+ const craft = getCraftRoot();
663
+ if (!craft?.watch?.send)
664
+ throw new Error("Apple Watch connectivity is unavailable");
665
+ return craft.watch.send(message);
666
+ },
667
+ async updateContext(context) {
668
+ const craft = getCraftRoot();
669
+ if (!craft?.watch?.updateContext)
670
+ throw new Error("Apple Watch connectivity is unavailable");
671
+ await craft.watch.updateContext(context);
672
+ },
673
+ async isReachable() {
674
+ const result = await getCraftRoot()?.watch?.isReachable?.();
675
+ return Boolean(result?.reachable);
676
+ },
677
+ onMessage(callback) {
678
+ return onCraftEvent("craftWatchMessage", callback);
679
+ },
680
+ onReachabilityChange(callback) {
681
+ return onCraftEvent("craftWatchReachability", (detail) => callback(Boolean(detail.reachable)));
682
+ }
683
+ };
684
+ function onCraftEvent(eventName, callback) {
685
+ if (typeof globalThis === "undefined")
686
+ return () => {};
687
+ const listener = (event) => callback(event.detail ?? {});
688
+ globalThis.addEventListener(eventName, listener);
689
+ return () => globalThis.removeEventListener(eventName, listener);
690
+ }
691
+ function getCraftRoot() {
692
+ if (typeof window === "undefined")
693
+ return;
694
+ return window.craft;
695
+ }
696
+ function detectPlatform() {
697
+ if (typeof window === "undefined")
698
+ return "linux";
699
+ const ua = navigator.userAgent.toLowerCase();
700
+ if (/iphone|ipad|ipod/.test(ua))
701
+ return "ios";
702
+ if (/android/.test(ua))
703
+ return "android";
704
+ if (/macintosh|mac os x/.test(ua))
705
+ return "macos";
706
+ if (/windows/.test(ua))
707
+ return "windows";
708
+ return "linux";
709
+ }
710
+ function mapToWebPermission(permission) {
711
+ const mapping = {
712
+ camera: "camera",
713
+ microphone: "microphone",
714
+ location: "geolocation",
715
+ notifications: "notifications"
716
+ };
717
+ return mapping[permission] || null;
718
+ }
719
+ function mapWebPermissionStatus(state) {
720
+ const mapping = {
721
+ granted: "granted",
722
+ denied: "denied",
723
+ prompt: "undetermined"
724
+ };
725
+ return mapping[state];
726
+ }
727
+ function getCraftMobile() {
728
+ if (typeof window !== "undefined") {
729
+ return window.craft;
730
+ }
731
+ return;
732
+ }
733
+ export {
734
+ watchConnectivity,
735
+ share,
736
+ secureStorage,
737
+ pushNotifications,
738
+ permissions,
739
+ notifications,
740
+ normalizeDeepLinkURL,
741
+ network,
742
+ location,
743
+ liveActivities,
744
+ lifecycle,
745
+ keepAwake,
746
+ health,
747
+ haptics,
748
+ device,
749
+ deepLinks,
750
+ camera,
751
+ biometrics,
752
+ appReview,
753
+ _webFallbackDeviceId,
754
+ _resetWebFallbackDeviceIdForTests
755
+ };