@monimesl/dot-dash 0.1.0-alpha.2 → 0.1.0-alpha.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,27 +1,638 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.js";
2
- import { HostError, callHost } from "@monimesl/dot-core";
2
+ import { DEFAULT_DASH_API_VERSION, HostError, HostError as DashError, HostError as HostError$1, callHost, createHostRequest, offersDashApiVersion } from "@monimesl/dot-core";
3
+ //#region src/api-versions.ts
4
+ const DASH_API_VERSION = "1.0";
5
+ const DASH_API_SINCE = {
6
+ "account.readProfile": "1.0",
7
+ "contacts.pickPhone": "1.0",
8
+ "crypto.hmac": "1.0",
9
+ "crypto.randomBytes": "1.0",
10
+ "crypto.randomUUID": "1.0",
11
+ "crypto.sha256": "1.0",
12
+ "crypto.sha512": "1.0",
13
+ "dot.close": "1.0",
14
+ "media.pickFile": "1.0",
15
+ "media.pickPhoto": "1.0",
16
+ "media.scanCode": "1.0",
17
+ "network.http.download": "1.0",
18
+ "network.http.request": "1.0",
19
+ "network.http.upload": "1.0",
20
+ "network.status": "1.0",
21
+ "storage.cache.clear": "1.0",
22
+ "storage.cache.exists": "1.0",
23
+ "storage.cache.get": "1.0",
24
+ "storage.cache.keys": "1.0",
25
+ "storage.cache.remove": "1.0",
26
+ "storage.cache.set": "1.0",
27
+ "storage.file.copy": "1.0",
28
+ "storage.file.createFolder": "1.0",
29
+ "storage.file.list": "1.0",
30
+ "storage.file.move": "1.0",
31
+ "storage.file.open": "1.0",
32
+ "storage.file.read": "1.0",
33
+ "storage.file.remove": "1.0",
34
+ "storage.file.save": "1.0",
35
+ "storage.file.stat": "1.0",
36
+ "storage.file.usage": "1.0",
37
+ "storage.file.write": "1.0",
38
+ "storage.secret.clear": "1.0",
39
+ "storage.secret.get": "1.0",
40
+ "storage.secret.remove": "1.0",
41
+ "storage.secret.set": "1.0",
42
+ "system.brightness": "1.0",
43
+ "system.copyText": "1.0",
44
+ "system.delay": "1.0",
45
+ "system.dial": "1.0",
46
+ "system.info": "1.0",
47
+ "system.keepAwake": "1.0",
48
+ "system.openUrl": "1.0",
49
+ "system.share": "1.0",
50
+ "system.torch": "1.0",
51
+ "system.vibrate": "1.0",
52
+ "ui.alert": "1.0",
53
+ "ui.pickDate": "1.0",
54
+ "ui.pickTime": "1.0"
55
+ };
56
+ let hostApiVersions = [DEFAULT_DASH_API_VERSION];
57
+ let dotMinApiVersion;
58
+ const checkedFeatures = /* @__PURE__ */ new Set();
59
+ const warnedFeatures = /* @__PURE__ */ new Set();
60
+ function useHostDashApiVersions(versions) {
61
+ hostApiVersions = versions;
62
+ }
63
+ function warnAboveDashApiVersion(minApiVersion) {
64
+ dotMinApiVersion = minApiVersion;
65
+ }
66
+ /**
67
+ * Whether the Dash the dot runs in has `feature`: a call, such as "contacts.pickPhone", or a field
68
+ * added to a call later. Check it before using one that's newer than the dot's minApiVersion.
69
+ * @since 1.0
70
+ */
71
+ function supports(feature) {
72
+ checkedFeatures.add(feature);
73
+ const since = sinceOf(feature);
74
+ return since !== void 0 && offersDashApiVersion(hostApiVersions, since);
75
+ }
76
+ function warnIfNewerThanDot(method, params) {
77
+ if (dotMinApiVersion === void 0) return;
78
+ const callName = method.replace(/^dash\./, "");
79
+ for (const feature of [callName, ...fieldsSent(callName, params)]) {
80
+ const since = sinceOf(feature);
81
+ if (since === void 0) continue;
82
+ if (checkedFeatures.has(feature) || warnedFeatures.has(feature)) continue;
83
+ if (offersDashApiVersion([dotMinApiVersion], since)) continue;
84
+ warnedFeatures.add(feature);
85
+ console.warn(`dash.${feature} came in Dash API ${since}, but this dot's minApiVersion is ${dotMinApiVersion}, so older Dash doesn't have it. Raise "minApiVersion" in dot.json, or check dash.supports('${feature}') first.`);
86
+ }
87
+ }
88
+ function sinceOf(feature) {
89
+ const table = DASH_API_SINCE;
90
+ return Object.hasOwn(table, feature) ? table[feature] : void 0;
91
+ }
92
+ function fieldsSent(callName, params) {
93
+ if (typeof params !== "object" || params === null) return [];
94
+ return Object.keys(params).map((field) => `${callName}.${field}`).filter((feature) => sinceOf(feature) !== void 0);
95
+ }
96
+ //#endregion
3
97
  //#region src/call.ts
4
98
  function call(method, params, options = {}) {
99
+ warnIfNewerThanDot(method, params);
5
100
  return callHost(method, params, options);
6
101
  }
7
102
  //#endregion
103
+ //#region src/account/index.ts
104
+ var account_exports = /* @__PURE__ */ __exportAll({ readProfile: () => readProfile });
105
+ /**
106
+ * The person signed in to Dash: their full name, and a token that names them in this dot. Needs the
107
+ * `account` permission. Rejects with `invalid` for a nonce that's empty or longer than 128
108
+ * characters, and with `failed` when no one is signed in.
109
+ * @since 1.0
110
+ */
111
+ function readProfile(options, callOptions) {
112
+ return call("dash.account.readProfile", { nonce: options.nonce }, callOptions);
113
+ }
114
+ //#endregion
115
+ //#region src/contacts/pick-phone.ts
116
+ /**
117
+ * Shows the phone's contacts so the person chooses one phone number, such as who to send money to.
118
+ * Needs the `contacts` permission. The dot sees only the chosen contact. Rejects with `cancelled` if
119
+ * the person closes it.
120
+ * @since 1.0
121
+ */
122
+ function pickPhone(callOptions) {
123
+ return call("dash.contacts.pickPhone", {}, callOptions);
124
+ }
125
+ //#endregion
126
+ //#region src/contacts/index.ts
127
+ var contacts_exports = /* @__PURE__ */ __exportAll({ pickPhone: () => pickPhone });
128
+ //#endregion
129
+ //#region src/crypto/index.ts
130
+ var crypto_exports = /* @__PURE__ */ __exportAll({
131
+ hmac: () => hmac,
132
+ randomBytes: () => randomBytes,
133
+ randomUUID: () => randomUUID,
134
+ sha256: () => sha256,
135
+ sha512: () => sha512
136
+ });
137
+ /** @since 1.0 */
138
+ function sha256(data, options = {}, callOptions) {
139
+ return call("dash.crypto.sha256", wireInput(data, options), callOptions);
140
+ }
141
+ /** @since 1.0 */
142
+ function sha512(data, options = {}, callOptions) {
143
+ return call("dash.crypto.sha512", wireInput(data, options), callOptions);
144
+ }
145
+ /**
146
+ * Signs `data` with `key`, as HMAC-SHA256 or HMAC-SHA512.
147
+ * @since 1.0
148
+ */
149
+ function hmac(algorithm, key, data, options = {}, callOptions) {
150
+ const wireKey = valueAndEncoding(key);
151
+ return call("dash.crypto.hmac", {
152
+ ...wireInput(data, options),
153
+ algorithm,
154
+ key: wireKey.value,
155
+ keyEncoding: wireKey.encoding
156
+ }, callOptions);
157
+ }
158
+ /**
159
+ * `count` secure random bytes, from 1 to 1024, such as for a nonce.
160
+ * @since 1.0
161
+ */
162
+ function randomBytes(count, options = {}, callOptions) {
163
+ return call("dash.crypto.randomBytes", {
164
+ count,
165
+ as: outputEncoding(options)
166
+ }, callOptions);
167
+ }
168
+ /**
169
+ * A random version 4 UUID, such as "3f0e5c3a-6d1b-4c8e-9a2f-1b7d4e6a9c05".
170
+ * @since 1.0
171
+ */
172
+ function randomUUID(callOptions) {
173
+ return call("dash.crypto.randomUUID", {}, callOptions);
174
+ }
175
+ function wireInput(data, options) {
176
+ const { value, encoding } = valueAndEncoding(data);
177
+ return {
178
+ data: value,
179
+ dataEncoding: encoding,
180
+ as: outputEncoding(options)
181
+ };
182
+ }
183
+ function outputEncoding(options) {
184
+ return options.as ?? "hex";
185
+ }
186
+ function valueAndEncoding(input) {
187
+ if (typeof input === "string") return {
188
+ value: input,
189
+ encoding: "text"
190
+ };
191
+ return {
192
+ value: input.base64,
193
+ encoding: "base64"
194
+ };
195
+ }
196
+ //#endregion
197
+ //#region src/dot/index.ts
198
+ var dot_exports = /* @__PURE__ */ __exportAll({ close: () => close });
199
+ /**
200
+ * Closes the dot, as going back from its first page does. Calls still running are cancelled.
201
+ * @since 1.0
202
+ */
203
+ function close(callOptions) {
204
+ return call("dash.dot.close", {}, callOptions);
205
+ }
206
+ //#endregion
207
+ //#region src/media/pick-file.ts
208
+ /**
209
+ * Lets the person choose a file from their phone, of at most 25 MB. Needs the `files` permission.
210
+ * Rejects with `cancelled` if they close the picker, and with `invalid` for a larger file. Like a
211
+ * download, it lasts until the dot closes, so `dash.storage.file.save` it to keep it.
212
+ * @since 1.0
213
+ */
214
+ function pickFile(options = {}, callOptions) {
215
+ const params = {};
216
+ if (options.types) params.types = options.types;
217
+ return call("dash.media.pickFile", params, callOptions);
218
+ }
219
+ //#endregion
220
+ //#region src/media/pick-photo.ts
221
+ /**
222
+ * Lets the person choose a photo or take one. Resolves with it as a JPEG of at most 2048 pixels on its
223
+ * longest side, without its location or other details. Rejects with `cancelled` if they close the
224
+ * picker, and with `unsupported` on a device without a camera. Save it with `dash.storage.file.save`
225
+ * to keep it after the dot closes.
226
+ * @since 1.0
227
+ */
228
+ function pickPhoto(options, callOptions) {
229
+ return call("dash.media.pickPhoto", { source: options.source }, callOptions);
230
+ }
231
+ //#endregion
232
+ //#region src/media/scan-code.ts
233
+ /**
234
+ * Opens Dash's scanner until it reads a QR code. Needs the `camera` permission. Rejects with
235
+ * `cancelled` if the person closes it, and with `unsupported` where Dash has no scanner.
236
+ * @since 1.0
237
+ */
238
+ function scanCode(callOptions) {
239
+ return call("dash.media.scanCode", {}, callOptions);
240
+ }
241
+ //#endregion
242
+ //#region src/media/index.ts
243
+ var media_exports = /* @__PURE__ */ __exportAll({
244
+ pickFile: () => pickFile,
245
+ pickPhoto: () => pickPhoto,
246
+ scanCode: () => scanCode
247
+ });
248
+ //#endregion
249
+ //#region src/network/http.ts
250
+ var http_exports = /* @__PURE__ */ __exportAll({
251
+ download: () => download,
252
+ request: () => request,
253
+ upload: () => upload
254
+ });
255
+ /**
256
+ * Like fetch, resolves with any response, even a 404. An object body is sent as JSON.
257
+ * @since 1.0
258
+ */
259
+ function request(options, callOptions) {
260
+ const { as: readAs, ...request } = options;
261
+ return readBody(call("dash.network.http.request", wireRequest(request, readAs), callOptions), readAs);
262
+ }
263
+ /**
264
+ * Saves a 2xx response's body, up to 256 MB, to a temporary file.
265
+ * @since 1.0
266
+ */
267
+ function download(options, callOptions) {
268
+ return call("dash.network.http.download", wireRequest(options), callOptions);
269
+ }
270
+ /**
271
+ * Sends the dot's files as a multipart form.
272
+ * @since 1.0
273
+ */
274
+ function upload(options, callOptions) {
275
+ const { as: readAs, ...request } = options;
276
+ const files = request.files.map((upload) => ({
277
+ ...upload,
278
+ file: upload.file.id
279
+ }));
280
+ const params = {
281
+ ...request,
282
+ files
283
+ };
284
+ if (readAs === "json") params.headers = withDefaultHeader(request.headers, "Accept", "application/json");
285
+ return readBody(call("dash.network.http.upload", params, callOptions), readAs);
286
+ }
287
+ function wireRequest(request, readAs) {
288
+ let headers = request.headers;
289
+ let body;
290
+ if (readAs === "json") headers = withDefaultHeader(headers, "Accept", "application/json");
291
+ if (typeof request.body === "string") body = request.body;
292
+ else if (request.body !== void 0) {
293
+ headers = withDefaultHeader(headers, "Content-Type", "application/json");
294
+ body = JSON.stringify(request.body);
295
+ }
296
+ return {
297
+ ...request,
298
+ headers,
299
+ body
300
+ };
301
+ }
302
+ function withDefaultHeader(headers, name, value) {
303
+ if (headers === void 0) return { [name]: value };
304
+ const lowerName = name.toLowerCase();
305
+ if (Object.keys(headers).some((existing) => existing.toLowerCase() === lowerName)) return headers;
306
+ return {
307
+ ...headers,
308
+ [name]: value
309
+ };
310
+ }
311
+ function readBody(response, readAs) {
312
+ if (readAs !== "json") return response;
313
+ const parsed = response.then((result) => ({
314
+ ...result,
315
+ body: parseJson(result)
316
+ }));
317
+ return createHostRequest(parsed, () => response.cancel());
318
+ }
319
+ function parseJson({ status, statusText, body }) {
320
+ try {
321
+ return JSON.parse(body);
322
+ } catch (error) {
323
+ const message = error instanceof Error ? error.message : String(error);
324
+ throw new HostError$1("failed", `The response (${status} ${statusText}) isn't JSON: ${message}`);
325
+ }
326
+ }
327
+ //#endregion
328
+ //#region src/network/status.ts
329
+ /**
330
+ * Whether the phone is online now, and how. It can still be online without reaching a server.
331
+ * @since 1.0
332
+ */
333
+ function status(callOptions) {
334
+ return call("dash.network.status", {}, callOptions);
335
+ }
336
+ //#endregion
337
+ //#region src/network/index.ts
338
+ var network_exports = /* @__PURE__ */ __exportAll({
339
+ http: () => http_exports,
340
+ status: () => status
341
+ });
342
+ //#endregion
343
+ //#region src/storage/cache.ts
344
+ var cache_exports = /* @__PURE__ */ __exportAll({
345
+ clear: () => clear$1,
346
+ exists: () => exists,
347
+ get: () => get$1,
348
+ keys: () => keys,
349
+ remove: () => remove$2,
350
+ set: () => set$1
351
+ });
352
+ /**
353
+ * Resolves with null for a missing or expired key.
354
+ * @since 1.0
355
+ */
356
+ function get$1(key, callOptions) {
357
+ return call("dash.storage.cache.get", { key }, callOptions);
358
+ }
359
+ /** @since 1.0 */
360
+ function set$1(key, value, options = {}, callOptions) {
361
+ return call("dash.storage.cache.set", {
362
+ key,
363
+ value,
364
+ ...options
365
+ }, callOptions);
366
+ }
367
+ /** @since 1.0 */
368
+ function remove$2(key, callOptions) {
369
+ return call("dash.storage.cache.remove", { key }, callOptions);
370
+ }
371
+ /** @since 1.0 */
372
+ function exists(key, callOptions) {
373
+ return call("dash.storage.cache.exists", { key }, callOptions);
374
+ }
375
+ /**
376
+ * The keys, sorted.
377
+ * @since 1.0
378
+ */
379
+ function keys(callOptions) {
380
+ return call("dash.storage.cache.keys", {}, callOptions);
381
+ }
382
+ /** @since 1.0 */
383
+ function clear$1(callOptions) {
384
+ return call("dash.storage.cache.clear", {}, callOptions);
385
+ }
386
+ //#endregion
387
+ //#region src/storage/file.ts
388
+ var file_exports = /* @__PURE__ */ __exportAll({
389
+ copy: () => copy,
390
+ createFolder: () => createFolder,
391
+ list: () => list,
392
+ move: () => move,
393
+ open: () => open,
394
+ read: () => read,
395
+ remove: () => remove$1,
396
+ save: () => save,
397
+ stat: () => stat,
398
+ usage: () => usage,
399
+ write: () => write
400
+ });
401
+ /**
402
+ * Reads a file of up to 5 MB.
403
+ * @since 1.0
404
+ */
405
+ function read(path, options = {}, callOptions) {
406
+ return call("dash.storage.file.read", {
407
+ path,
408
+ ...options
409
+ }, callOptions);
410
+ }
411
+ /**
412
+ * Creates any missing folders above the file.
413
+ * @since 1.0
414
+ */
415
+ function write(path, data, options = {}, callOptions) {
416
+ return call("dash.storage.file.write", {
417
+ path,
418
+ data,
419
+ ...options
420
+ }, callOptions);
421
+ }
422
+ /** @since 1.0 */
423
+ function stat(path, callOptions) {
424
+ return call("dash.storage.file.stat", { path }, callOptions);
425
+ }
426
+ /**
427
+ * Sorted by path.
428
+ * @since 1.0
429
+ */
430
+ function list(path = "", options = {}, callOptions) {
431
+ return call("dash.storage.file.list", {
432
+ path,
433
+ ...options
434
+ }, callOptions);
435
+ }
436
+ /** @since 1.0 */
437
+ function createFolder(path, callOptions) {
438
+ return call("dash.storage.file.createFolder", { path }, callOptions);
439
+ }
440
+ /** @since 1.0 */
441
+ function move(from, to, options = {}, callOptions) {
442
+ return call("dash.storage.file.move", {
443
+ from,
444
+ to,
445
+ ...options
446
+ }, callOptions);
447
+ }
448
+ /** @since 1.0 */
449
+ function copy(from, to, options = {}, callOptions) {
450
+ return call("dash.storage.file.copy", {
451
+ from,
452
+ to,
453
+ ...options
454
+ }, callOptions);
455
+ }
456
+ /**
457
+ * Removing a folder that isn't empty needs `recursive`.
458
+ * @since 1.0
459
+ */
460
+ function remove$1(path, options = {}, callOptions) {
461
+ return call("dash.storage.file.remove", {
462
+ path,
463
+ ...options
464
+ }, callOptions);
465
+ }
466
+ /**
467
+ * Keeps a temporary file, such as a download, at `path`.
468
+ * @since 1.0
469
+ */
470
+ function save(file, path, options = {}, callOptions) {
471
+ return call("dash.storage.file.save", {
472
+ file: file.id,
473
+ path,
474
+ ...options
475
+ }, callOptions);
476
+ }
477
+ /**
478
+ * A stored file as a DotFile, to show with its `url` or send with `http.upload`.
479
+ * @since 1.0
480
+ */
481
+ function open(path, callOptions) {
482
+ return call("dash.storage.file.open", { path }, callOptions);
483
+ }
484
+ /** @since 1.0 */
485
+ function usage(callOptions) {
486
+ return call("dash.storage.file.usage", {}, callOptions);
487
+ }
488
+ //#endregion
489
+ //#region src/storage/secret.ts
490
+ var secret_exports = /* @__PURE__ */ __exportAll({
491
+ clear: () => clear,
492
+ get: () => get,
493
+ remove: () => remove,
494
+ set: () => set
495
+ });
496
+ /** @since 1.0 */
497
+ function get(key, callOptions) {
498
+ return call("dash.storage.secret.get", { key }, callOptions);
499
+ }
500
+ /** @since 1.0 */
501
+ function set(key, value, callOptions) {
502
+ return call("dash.storage.secret.set", {
503
+ key,
504
+ value
505
+ }, callOptions);
506
+ }
507
+ /** @since 1.0 */
508
+ function remove(key, callOptions) {
509
+ return call("dash.storage.secret.remove", { key }, callOptions);
510
+ }
511
+ /** @since 1.0 */
512
+ function clear(callOptions) {
513
+ return call("dash.storage.secret.clear", {}, callOptions);
514
+ }
515
+ //#endregion
516
+ //#region src/storage/index.ts
517
+ var storage_exports = /* @__PURE__ */ __exportAll({
518
+ cache: () => cache_exports,
519
+ file: () => file_exports,
520
+ secret: () => secret_exports
521
+ });
522
+ //#endregion
523
+ //#region src/system/clipboard.ts
524
+ /** @since 1.0 */
525
+ function copyText(text, callOptions) {
526
+ return call("dash.system.copyText", { text }, callOptions);
527
+ }
528
+ //#endregion
529
+ //#region src/system/delay.ts
530
+ /**
531
+ * Resolves after `milliseconds`. The host keeps the time, since a dot's logic has no timers.
532
+ * @since 1.0
533
+ */
534
+ function delay(milliseconds, callOptions) {
535
+ return call("dash.system.delay", { milliseconds }, callOptions);
536
+ }
537
+ //#endregion
538
+ //#region src/system/dial.ts
539
+ /**
540
+ * Opens the phone's dialer with `number` ready, such as "+232 76 123456" or a USSD code such as
541
+ * "*715#". The person taps Call. Spaces and dashes are fine; anything else but digits, +, * and #
542
+ * rejects with `invalid`.
543
+ * @since 1.0
544
+ */
545
+ function dial(number, callOptions) {
546
+ return call("dash.system.dial", { number }, callOptions);
547
+ }
548
+ //#endregion
8
549
  //#region src/system/haptics.ts
550
+ /**
551
+ * Plays a short vibration. Resolves once it's done.
552
+ * @since 1.0
553
+ */
9
554
  function vibrate(options = {}, callOptions) {
10
555
  return call("dash.system.vibrate", { style: options.style ?? "medium" }, callOptions);
11
556
  }
12
557
  //#endregion
558
+ //#region src/system/info.ts
559
+ /**
560
+ * The phone and the Dash the dot runs in. It has nothing that identifies the person or the phone.
561
+ * @since 1.0
562
+ */
563
+ function info(callOptions) {
564
+ return call("dash.system.info", {}, callOptions);
565
+ }
566
+ //#endregion
567
+ //#region src/system/open-url.ts
568
+ /**
569
+ * Opens an https address in the device's browser. Any other address rejects with `invalid`.
570
+ * @since 1.0
571
+ */
572
+ function openUrl(url, callOptions) {
573
+ return call("dash.system.openUrl", { url }, callOptions);
574
+ }
575
+ //#endregion
576
+ //#region src/system/screen.ts
577
+ /**
578
+ * Keeps the screen from dimming and locking while the dot shows, such as while a ticket's QR code is
579
+ * up. Dash undoes it when the dot closes.
580
+ * @since 1.0
581
+ */
582
+ function keepAwake(on, callOptions) {
583
+ return call("dash.system.keepAwake", { on }, callOptions);
584
+ }
585
+ /**
586
+ * `max` makes the screen as bright as it goes, so a scanner can read a QR code on it, and `normal`
587
+ * puts it back. Dash puts it back too when the dot closes or the person leaves the app.
588
+ * @since 1.0
589
+ */
590
+ function brightness(level, callOptions) {
591
+ return call("dash.system.brightness", { level }, callOptions);
592
+ }
593
+ //#endregion
594
+ //#region src/system/share.ts
595
+ /**
596
+ * Opens the device's share sheet. Resolves once it shows.
597
+ * @since 1.0
598
+ */
599
+ function share(options, callOptions) {
600
+ const { file, ...content } = options;
601
+ if (file === void 0) return call("dash.system.share", content, callOptions);
602
+ return call("dash.system.share", {
603
+ ...content,
604
+ file: file.id
605
+ }, callOptions);
606
+ }
607
+ //#endregion
13
608
  //#region src/system/torch.ts
14
- function torch(state, callOptions) {
15
- return call("dash.system.torch", { state }, callOptions);
609
+ /**
610
+ * Turns the torch on or off. Rejects with `unsupported` on a device without one.
611
+ * @since 1.0
612
+ */
613
+ function torch(on, callOptions) {
614
+ return call("dash.system.torch", { on }, callOptions);
16
615
  }
17
616
  //#endregion
18
617
  //#region src/system/index.ts
19
618
  var system_exports = /* @__PURE__ */ __exportAll({
619
+ brightness: () => brightness,
620
+ copyText: () => copyText,
621
+ delay: () => delay,
622
+ dial: () => dial,
623
+ info: () => info,
624
+ keepAwake: () => keepAwake,
625
+ openUrl: () => openUrl,
626
+ share: () => share,
20
627
  torch: () => torch,
21
628
  vibrate: () => vibrate
22
629
  });
23
630
  //#endregion
24
631
  //#region src/ui/dialogs.ts
632
+ /**
633
+ * Shows a native alert. Resolves with the action the person chose.
634
+ * @since 1.0
635
+ */
25
636
  function alert(options, callOptions) {
26
637
  const actions = options.actions ?? [{
27
638
  id: "ok",
@@ -33,12 +644,235 @@ function alert(options, callOptions) {
33
644
  }, callOptions);
34
645
  }
35
646
  //#endregion
647
+ //#region src/ui/pickers.ts
648
+ /**
649
+ * Opens the phone's own calendar. Resolves with the chosen date, such as "2026-10-24", or rejects
650
+ * with `cancelled` if the person closes it.
651
+ * @since 1.0
652
+ */
653
+ function pickDate(options = {}, callOptions) {
654
+ return call("dash.ui.pickDate", options, callOptions);
655
+ }
656
+ /**
657
+ * Opens the phone's own clock. Resolves with the chosen time in 24 hours, such as "19:30", or
658
+ * rejects with `cancelled` if the person closes it.
659
+ * @since 1.0
660
+ */
661
+ function pickTime(options = {}, callOptions) {
662
+ return call("dash.ui.pickTime", options, callOptions);
663
+ }
664
+ //#endregion
665
+ //#region src/ui/index.ts
666
+ var ui_exports = /* @__PURE__ */ __exportAll({
667
+ alert: () => alert,
668
+ pickDate: () => pickDate,
669
+ pickTime: () => pickTime
670
+ });
671
+ //#endregion
672
+ //#region src/utils/encoding.ts
673
+ const BASE64_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
674
+ const BASE64_PATTERN = /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/;
675
+ const HEX_PATTERN = /^(?:[0-9a-fA-F]{2})*$/;
676
+ const base64 = {
677
+ encode(text) {
678
+ return bytesToBase64(utf8Bytes(text));
679
+ },
680
+ decode(encoded) {
681
+ return utf8Text(base64ToBytes(encoded));
682
+ }
683
+ };
684
+ const hex = {
685
+ encode(text) {
686
+ return utf8Bytes(text).map((byte) => byte.toString(16).padStart(2, "0")).join("");
687
+ },
688
+ decode(encoded) {
689
+ if (!HEX_PATTERN.test(encoded)) throw new Error(`"${encoded.slice(0, 20)}" isn't hex. Use pairs of 0-9 and a-f.`);
690
+ const bytes = [];
691
+ for (let index = 0; index < encoded.length; index += 2) bytes.push(parseInt(encoded.slice(index, index + 2), 16));
692
+ return utf8Text(bytes);
693
+ }
694
+ };
695
+ function bytesToBase64(bytes) {
696
+ let encoded = "";
697
+ for (let index = 0; index < bytes.length; index += 3) {
698
+ const group = bytes.slice(index, index + 3);
699
+ const bits = (group[0] ?? 0) << 16 | (group[1] ?? 0) << 8 | (group[2] ?? 0);
700
+ const sextets = [
701
+ bits >> 18 & 63,
702
+ bits >> 12 & 63,
703
+ bits >> 6 & 63,
704
+ bits & 63
705
+ ];
706
+ const characterCount = group.length + 1;
707
+ for (const sextet of sextets.slice(0, characterCount)) encoded += BASE64_ALPHABET[sextet];
708
+ encoded += "=".repeat(4 - characterCount);
709
+ }
710
+ return encoded;
711
+ }
712
+ function base64ToBytes(encoded) {
713
+ if (!BASE64_PATTERN.test(encoded)) throw new Error(`"${encoded.slice(0, 20)}" isn't base64.`);
714
+ const bytes = [];
715
+ for (let index = 0; index < encoded.length; index += 4) {
716
+ const characters = encoded.slice(index, index + 4);
717
+ let bits = 0;
718
+ let padding = 0;
719
+ for (const character of characters) {
720
+ bits <<= 6;
721
+ if (character === "=") padding += 1;
722
+ else bits |= BASE64_ALPHABET.indexOf(character);
723
+ }
724
+ bytes.push(bits >> 16 & 255);
725
+ if (padding < 2) bytes.push(bits >> 8 & 255);
726
+ if (padding < 1) bytes.push(bits & 255);
727
+ }
728
+ return bytes;
729
+ }
730
+ function utf8Bytes(text) {
731
+ const bytes = [];
732
+ for (const character of text) {
733
+ const codePoint = character.codePointAt(0);
734
+ if (codePoint < 128) bytes.push(codePoint);
735
+ else if (codePoint < 2048) bytes.push(192 | codePoint >> 6, 128 | codePoint & 63);
736
+ else if (codePoint < 65536) bytes.push(224 | codePoint >> 12, 128 | codePoint >> 6 & 63, 128 | codePoint & 63);
737
+ else bytes.push(240 | codePoint >> 18, 128 | codePoint >> 12 & 63, 128 | codePoint >> 6 & 63, 128 | codePoint & 63);
738
+ }
739
+ return bytes;
740
+ }
741
+ const MAX_CODE_POINT = 1114111;
742
+ function utf8Text(bytes) {
743
+ let text = "";
744
+ let index = 0;
745
+ while (index < bytes.length) {
746
+ const first = bytes[index];
747
+ const length = sequenceLength(first);
748
+ const continuation = bytes.slice(index + 1, index + length);
749
+ if (length === 0 || !isCompleteContinuation(continuation, length)) {
750
+ text += "�";
751
+ index += 1;
752
+ continue;
753
+ }
754
+ let codePoint = firstByteBits(first, length);
755
+ for (const byte of continuation) codePoint = codePoint << 6 | byte & 63;
756
+ if (codePoint > MAX_CODE_POINT) {
757
+ text += "�";
758
+ index += 1;
759
+ continue;
760
+ }
761
+ text += String.fromCodePoint(codePoint);
762
+ index += length;
763
+ }
764
+ return text;
765
+ }
766
+ function sequenceLength(first) {
767
+ if (first < 128) return 1;
768
+ if (first >= 240) return 4;
769
+ if (first >= 224) return 3;
770
+ if (first >= 192) return 2;
771
+ return 0;
772
+ }
773
+ function isCompleteContinuation(continuation, length) {
774
+ if (continuation.length !== length - 1) return false;
775
+ return continuation.every((byte) => (byte & 192) === 128);
776
+ }
777
+ function firstByteBits(first, length) {
778
+ if (length === 1) return first;
779
+ return first & 255 >> length + 1;
780
+ }
781
+ //#endregion
782
+ //#region src/utils/index.ts
783
+ var utils_exports = /* @__PURE__ */ __exportAll({
784
+ base64: () => base64,
785
+ hex: () => hex
786
+ });
787
+ //#endregion
788
+ //#region src/tracked.ts
789
+ function tracked(group, track) {
790
+ const copy = {};
791
+ for (const [name, member] of Object.entries(group)) if (typeof member === "function") {
792
+ const startCall = member;
793
+ copy[name] = (...args) => {
794
+ const result = startCall(...args);
795
+ if (result instanceof Promise) track(result);
796
+ return result;
797
+ };
798
+ } else copy[name] = tracked(member, track);
799
+ return copy;
800
+ }
801
+ //#endregion
802
+ //#region src/errors.ts
803
+ function isDashError(error, ...codes) {
804
+ if (error instanceof HostError$1) return codes.length === 0 || codes.includes(error.code);
805
+ return false;
806
+ }
807
+ function isDashCancelled(error) {
808
+ return isDashError(error, "cancelled");
809
+ }
810
+ function isDashTimeout(error) {
811
+ return isDashError(error, "timeout");
812
+ }
813
+ function isDashDenied(error) {
814
+ return isDashError(error, "denied");
815
+ }
816
+ function isDashInvalid(error) {
817
+ return isDashError(error, "invalid");
818
+ }
819
+ function isDashUnsupported(error) {
820
+ return isDashError(error, "unsupported");
821
+ }
822
+ function isDashFailed(error) {
823
+ return isDashError(error, "failed");
824
+ }
825
+ function errorMessage(error) {
826
+ if (error instanceof Error) return error.message;
827
+ if (typeof error === "string" && error) return error;
828
+ return "Something went wrong. Try again.";
829
+ }
830
+ async function unlessCancelled(call) {
831
+ try {
832
+ return await call;
833
+ } catch (error) {
834
+ if (isDashCancelled(error)) return;
835
+ throw error;
836
+ }
837
+ }
838
+ //#endregion
839
+ //#region src/latest.ts
840
+ function latest() {
841
+ let running;
842
+ return (call) => {
843
+ running?.cancel();
844
+ running = call;
845
+ return call;
846
+ };
847
+ }
848
+ function debounce(milliseconds) {
849
+ const wait = latest();
850
+ return async (dash) => {
851
+ try {
852
+ await wait(dash.system.delay(milliseconds));
853
+ return true;
854
+ } catch (error) {
855
+ if (isDashCancelled(error)) return false;
856
+ throw error;
857
+ }
858
+ };
859
+ }
860
+ //#endregion
36
861
  //#region src/index.ts
37
862
  const dash = {
38
- ui: /* @__PURE__ */ __exportAll({ alert: () => alert }),
39
- system: system_exports
863
+ ui: ui_exports,
864
+ system: system_exports,
865
+ network: network_exports,
866
+ storage: storage_exports,
867
+ media: media_exports,
868
+ contacts: contacts_exports,
869
+ dot: dot_exports,
870
+ account: account_exports,
871
+ crypto: crypto_exports,
872
+ utils: utils_exports,
873
+ supports
40
874
  };
41
875
  //#endregion
42
- export { HostError, dash };
876
+ export { DASH_API_SINCE, DASH_API_VERSION, DashError, HostError, dash, debounce, errorMessage, isDashCancelled, isDashDenied, isDashError, isDashFailed, isDashInvalid, isDashTimeout, isDashUnsupported, latest, tracked, unlessCancelled, useHostDashApiVersions, warnAboveDashApiVersion };
43
877
 
44
878
  //# sourceMappingURL=index.js.map