@reset-framework/sdk 0.2.0 → 1.0.1

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/src/client.js CHANGED
@@ -1,53 +1,656 @@
1
- import { ResetRuntimeUnavailableError } from "./errors.js"
1
+ import {
2
+ createResetTransport,
3
+ getResetRuntime,
4
+ invoke,
5
+ invokeRaw,
6
+ isResetRuntimeAvailable
7
+ } from "./transport.js"
8
+ import { createEventApi } from "./events.js"
9
+ import { ResetProtocolError } from "./errors.js"
2
10
 
3
- function getDefaultWindowTarget() {
4
- if (typeof window === "undefined") {
5
- return undefined
11
+ function isObjectLike(value) {
12
+ return typeof value === "object" && value !== null && !Array.isArray(value)
13
+ }
14
+
15
+ function requireObject(value, command) {
16
+ if (!isObjectLike(value)) {
17
+ throw new ResetProtocolError(
18
+ `Reset runtime returned an invalid payload for '${command}'.`,
19
+ { command }
20
+ )
6
21
  }
7
22
 
8
- return window
23
+ return value
9
24
  }
10
25
 
11
- export function isResetRuntimeAvailable(target = getDefaultWindowTarget()) {
12
- return Boolean(
13
- target &&
14
- target.reset &&
15
- typeof target.reset.invoke === "function"
16
- )
17
- }
26
+ function requireStringField(record, field, command) {
27
+ const value = record[field]
18
28
 
19
- export function getResetRuntime(target = getDefaultWindowTarget()) {
20
- if (!isResetRuntimeAvailable(target)) {
21
- throw new ResetRuntimeUnavailableError()
29
+ if (typeof value !== "string" || value.trim() === "") {
30
+ throw new ResetProtocolError(
31
+ `Reset runtime returned an invalid '${field}' field for '${command}'.`,
32
+ { command }
33
+ )
22
34
  }
23
35
 
24
- return target.reset
36
+ return value
25
37
  }
26
38
 
27
- export async function invokeRaw(command, payload = {}, target = getDefaultWindowTarget()) {
28
- return getResetRuntime(target).invoke(command, payload)
39
+ function requireBooleanField(record, field, command) {
40
+ const value = record[field]
41
+
42
+ if (typeof value !== "boolean") {
43
+ throw new ResetProtocolError(
44
+ `Reset runtime returned an invalid '${field}' field for '${command}'.`,
45
+ { command }
46
+ )
47
+ }
48
+
49
+ return value
29
50
  }
30
51
 
31
- export async function invoke(command, payload = {}, target = getDefaultWindowTarget()) {
32
- const response = await invokeRaw(command, payload, target)
52
+ function requireNumberField(record, field, command) {
53
+ const value = record[field]
33
54
 
34
- if (!response.ok) {
35
- throw new Error(response.error)
55
+ if (typeof value !== "number" || Number.isNaN(value)) {
56
+ throw new ResetProtocolError(
57
+ `Reset runtime returned an invalid '${field}' field for '${command}'.`,
58
+ { command }
59
+ )
36
60
  }
37
61
 
38
- return response.result
62
+ return value
39
63
  }
40
64
 
41
- export function createResetClient(target = getDefaultWindowTarget()) {
42
- return {
43
- isAvailable() {
44
- return isResetRuntimeAvailable(target)
45
- },
65
+ function normalizeAppInfo(payload, command) {
66
+ const record = requireObject(payload, command)
67
+
68
+ return Object.freeze({
69
+ id: requireStringField(record, "id", command),
70
+ name: requireStringField(record, "name", command),
71
+ slug: requireStringField(record, "slug", command),
72
+ version: requireStringField(record, "version", command),
73
+ windowTitle: requireStringField(record, "windowTitle", command)
74
+ })
75
+ }
76
+
77
+ function normalizeRuntimeInfo(payload, command) {
78
+ const record = requireObject(payload, command)
79
+
80
+ return Object.freeze({
81
+ platform: requireStringField(record, "platform", command),
82
+ arch: requireStringField(record, "arch", command),
83
+ frameworkVersion: requireStringField(record, "frameworkVersion", command),
84
+ bridgeVersion: requireStringField(record, "bridgeVersion", command),
85
+ debug: requireBooleanField(record, "debug", command)
86
+ })
87
+ }
88
+
89
+ function normalizeCapabilities(payload, command) {
90
+ const record = requireObject(payload, command)
91
+ const commands = Array.isArray(record.commands) ? record.commands : []
92
+ const permissions = Array.isArray(record.permissions) ? record.permissions : []
93
+
94
+ return Object.freeze({
95
+ commands: Object.freeze(commands.map((entry) => Object.freeze({ ...entry }))),
96
+ permissions: Object.freeze([...permissions])
97
+ })
98
+ }
99
+
100
+ function createCommandApi(transport) {
101
+ return Object.freeze({
46
102
  invoke(command, payload = {}) {
47
- return invoke(command, payload, target)
103
+ return transport.invoke(command, payload)
48
104
  },
49
105
  invokeRaw(command, payload = {}) {
50
- return invokeRaw(command, payload, target)
106
+ return transport.invokeRaw(command, payload)
51
107
  }
52
- }
108
+ })
109
+ }
110
+
111
+ function createAppApi(transport) {
112
+ return Object.freeze({
113
+ async getId() {
114
+ const payload = requireObject(await transport.invoke("app.getId"), "app.getId")
115
+ return requireStringField(payload, "id", "app.getId")
116
+ },
117
+ async getName() {
118
+ const payload = requireObject(await transport.invoke("app.getName"), "app.getName")
119
+ return requireStringField(payload, "name", "app.getName")
120
+ },
121
+ async getSlug() {
122
+ const payload = requireObject(await transport.invoke("app.getSlug"), "app.getSlug")
123
+ return requireStringField(payload, "slug", "app.getSlug")
124
+ },
125
+ async getVersion() {
126
+ const payload = requireObject(await transport.invoke("app.getVersion"), "app.getVersion")
127
+ return requireStringField(payload, "version", "app.getVersion")
128
+ },
129
+ async getInfo() {
130
+ return normalizeAppInfo(await transport.invoke("app.getInfo"), "app.getInfo")
131
+ },
132
+ show() {
133
+ return transport.invoke("app.show")
134
+ },
135
+ hide() {
136
+ return transport.invoke("app.hide")
137
+ },
138
+ quit() {
139
+ return transport.invoke("app.quit")
140
+ },
141
+ relaunch() {
142
+ return transport.invoke("app.relaunch")
143
+ }
144
+ })
145
+ }
146
+
147
+ function createRuntimeApi(transport) {
148
+ return Object.freeze({
149
+ async getPlatform() {
150
+ const payload = requireObject(await transport.invoke("runtime.getPlatform"), "runtime.getPlatform")
151
+ return requireStringField(payload, "platform", "runtime.getPlatform")
152
+ },
153
+ async getArchitecture() {
154
+ const payload = requireObject(await transport.invoke("runtime.getArchitecture"), "runtime.getArchitecture")
155
+ return requireStringField(payload, "arch", "runtime.getArchitecture")
156
+ },
157
+ async getFrameworkVersion() {
158
+ const payload = requireObject(
159
+ await transport.invoke("runtime.getFrameworkVersion"),
160
+ "runtime.getFrameworkVersion"
161
+ )
162
+ return requireStringField(payload, "version", "runtime.getFrameworkVersion")
163
+ },
164
+ async getBridgeVersion() {
165
+ const payload = requireObject(
166
+ await transport.invoke("runtime.getBridgeVersion"),
167
+ "runtime.getBridgeVersion"
168
+ )
169
+ return requireStringField(payload, "version", "runtime.getBridgeVersion")
170
+ },
171
+ async getInfo() {
172
+ return normalizeRuntimeInfo(await transport.invoke("runtime.getInfo"), "runtime.getInfo")
173
+ },
174
+ async getCapabilities() {
175
+ return normalizeCapabilities(
176
+ await transport.invoke("runtime.getCapabilities"),
177
+ "runtime.getCapabilities"
178
+ )
179
+ }
180
+ })
181
+ }
182
+
183
+ function createWindowApi(transport) {
184
+ return Object.freeze({
185
+ getCurrent() {
186
+ return transport.invoke("window.getCurrent")
187
+ },
188
+ getInfo() {
189
+ return transport.invoke("window.getInfo")
190
+ },
191
+ list() {
192
+ return transport.invoke("window.list")
193
+ },
194
+ show() {
195
+ return transport.invoke("window.show")
196
+ },
197
+ hide() {
198
+ return transport.invoke("window.hide")
199
+ },
200
+ focus() {
201
+ return transport.invoke("window.focus")
202
+ },
203
+ close() {
204
+ return transport.invoke("window.close")
205
+ },
206
+ minimize() {
207
+ return transport.invoke("window.minimize")
208
+ },
209
+ maximize() {
210
+ return transport.invoke("window.maximize")
211
+ },
212
+ center() {
213
+ return transport.invoke("window.center")
214
+ },
215
+ setTitle(title) {
216
+ return transport.invoke("window.setTitle", { title })
217
+ },
218
+ setSize(width, height) {
219
+ return transport.invoke("window.setSize", { width, height })
220
+ },
221
+ setResizable(resizable) {
222
+ return transport.invoke("window.setResizable", { resizable })
223
+ }
224
+ })
225
+ }
226
+
227
+ function createDialogApi(transport) {
228
+ return Object.freeze({
229
+ openFile(options = {}) {
230
+ return transport.invoke("dialog.openFile", options)
231
+ },
232
+ saveFile(options = {}) {
233
+ return transport.invoke("dialog.saveFile", options)
234
+ },
235
+ message(title, message) {
236
+ return transport.invoke("dialog.message", { title, message })
237
+ },
238
+ confirm(title, message) {
239
+ return transport.invoke("dialog.confirm", { title, message })
240
+ }
241
+ })
242
+ }
243
+
244
+ function createFsApi(transport) {
245
+ return Object.freeze({
246
+ async readTextFile(path) {
247
+ const payload = requireObject(await transport.invoke("fs.readTextFile", { path }), "fs.readTextFile")
248
+ return requireStringField(payload, "text", "fs.readTextFile")
249
+ },
250
+ writeTextFile(path, text, options = {}) {
251
+ return transport.invoke("fs.writeTextFile", {
252
+ path,
253
+ text,
254
+ ...options
255
+ })
256
+ },
257
+ async exists(path) {
258
+ const payload = requireObject(await transport.invoke("fs.exists", { path }), "fs.exists")
259
+ return requireBooleanField(payload, "exists", "fs.exists")
260
+ },
261
+ mkdir(path, options = {}) {
262
+ return transport.invoke("fs.mkdir", {
263
+ path,
264
+ ...options
265
+ })
266
+ },
267
+ remove(path, options = {}) {
268
+ return transport.invoke("fs.remove", {
269
+ path,
270
+ ...options
271
+ })
272
+ },
273
+ rename(from, to) {
274
+ return transport.invoke("fs.rename", { from, to })
275
+ },
276
+ async readDir(path) {
277
+ const payload = requireObject(await transport.invoke("fs.readDir", { path }), "fs.readDir")
278
+ return Array.isArray(payload.entries) ? payload.entries : []
279
+ }
280
+ })
281
+ }
282
+
283
+ function createPathApi(transport) {
284
+ return Object.freeze({
285
+ async join(...segments) {
286
+ const payload = requireObject(await transport.invoke("path.join", { segments }), "path.join")
287
+ return requireStringField(payload, "path", "path.join")
288
+ },
289
+ async basename(path) {
290
+ const payload = requireObject(await transport.invoke("path.basename", { path }), "path.basename")
291
+ return requireStringField(payload, "name", "path.basename")
292
+ },
293
+ async dirname(path) {
294
+ const payload = requireObject(await transport.invoke("path.dirname", { path }), "path.dirname")
295
+ return requireStringField(payload, "path", "path.dirname")
296
+ },
297
+ async resolve(path, base) {
298
+ const payload = requireObject(await transport.invoke("path.resolve", { path, base }), "path.resolve")
299
+ return requireStringField(payload, "path", "path.resolve")
300
+ },
301
+ async getHomeDir() {
302
+ const payload = requireObject(await transport.invoke("path.getHomeDir"), "path.getHomeDir")
303
+ return requireStringField(payload, "path", "path.getHomeDir")
304
+ },
305
+ async getTempDir() {
306
+ const payload = requireObject(await transport.invoke("path.getTempDir"), "path.getTempDir")
307
+ return requireStringField(payload, "path", "path.getTempDir")
308
+ },
309
+ async getAppDataDir() {
310
+ const payload = requireObject(await transport.invoke("path.getAppDataDir"), "path.getAppDataDir")
311
+ return requireStringField(payload, "path", "path.getAppDataDir")
312
+ },
313
+ async getAppConfigDir() {
314
+ const payload = requireObject(await transport.invoke("path.getAppConfigDir"), "path.getAppConfigDir")
315
+ return requireStringField(payload, "path", "path.getAppConfigDir")
316
+ },
317
+ async getCacheDir() {
318
+ const payload = requireObject(await transport.invoke("path.getCacheDir"), "path.getCacheDir")
319
+ return requireStringField(payload, "path", "path.getCacheDir")
320
+ },
321
+ getInfo() {
322
+ return transport.invoke("path.getInfo")
323
+ }
324
+ })
325
+ }
326
+
327
+ function createShellApi(transport) {
328
+ return Object.freeze({
329
+ openExternal(url) {
330
+ return transport.invoke("shell.openExternal", { url })
331
+ },
332
+ openPath(path) {
333
+ return transport.invoke("shell.openPath", { path })
334
+ },
335
+ showItemInFolder(path) {
336
+ return transport.invoke("shell.showItemInFolder", { path })
337
+ }
338
+ })
53
339
  }
340
+
341
+ function createClipboardApi(transport) {
342
+ return Object.freeze({
343
+ async readText() {
344
+ const payload = requireObject(await transport.invoke("clipboard.readText"), "clipboard.readText")
345
+ return requireStringField(payload, "text", "clipboard.readText")
346
+ },
347
+ writeText(text) {
348
+ return transport.invoke("clipboard.writeText", { text })
349
+ }
350
+ })
351
+ }
352
+
353
+ function createNotificationApi(transport) {
354
+ return Object.freeze({
355
+ async isSupported() {
356
+ const payload = requireObject(
357
+ await transport.invoke("notification.isSupported"),
358
+ "notification.isSupported"
359
+ )
360
+ return requireBooleanField(payload, "supported", "notification.isSupported")
361
+ },
362
+ requestPermission() {
363
+ return transport.invoke("notification.requestPermission")
364
+ },
365
+ show(options) {
366
+ return transport.invoke("notification.show", options)
367
+ }
368
+ })
369
+ }
370
+
371
+ function createScreenApi(transport) {
372
+ return Object.freeze({
373
+ getCursorPosition() {
374
+ return transport.invoke("screen.getCursorPosition")
375
+ },
376
+ getPrimaryDisplay() {
377
+ return transport.invoke("screen.getPrimaryDisplay")
378
+ },
379
+ async getDisplays() {
380
+ const payload = requireObject(await transport.invoke("screen.getDisplays"), "screen.getDisplays")
381
+ return Array.isArray(payload.displays) ? payload.displays : []
382
+ }
383
+ })
384
+ }
385
+
386
+ function createStorageApi(transport) {
387
+ return Object.freeze({
388
+ async get(key) {
389
+ const payload = requireObject(await transport.invoke("storage.get", { key }), "storage.get")
390
+ return payload.value
391
+ },
392
+ set(key, value) {
393
+ return transport.invoke("storage.set", { key, value })
394
+ },
395
+ remove(key) {
396
+ return transport.invoke("storage.remove", { key })
397
+ },
398
+ clear() {
399
+ return transport.invoke("storage.clear")
400
+ },
401
+ async getAll() {
402
+ const payload = requireObject(await transport.invoke("storage.getAll"), "storage.getAll")
403
+ return requireObject(payload.entries ?? {}, "storage.getAll")
404
+ }
405
+ })
406
+ }
407
+
408
+ function createWebViewApi(transport) {
409
+ return Object.freeze({
410
+ getInfo() {
411
+ return transport.invoke("webview.getInfo")
412
+ },
413
+ reload() {
414
+ return transport.invoke("webview.reload")
415
+ },
416
+ goBack() {
417
+ return transport.invoke("webview.goBack")
418
+ },
419
+ goForward() {
420
+ return transport.invoke("webview.goForward")
421
+ },
422
+ navigate(options) {
423
+ return transport.invoke("webview.navigate", options)
424
+ },
425
+ setZoomFactor(factor) {
426
+ return transport.invoke("webview.setZoomFactor", { factor })
427
+ }
428
+ })
429
+ }
430
+
431
+ function createCryptoApi(transport) {
432
+ return Object.freeze({
433
+ getInfo() {
434
+ return transport.invoke("crypto.getInfo")
435
+ },
436
+ randomBytes(size, options = {}) {
437
+ return transport.invoke("crypto.randomBytes", {
438
+ size,
439
+ encoding: options.encoding
440
+ })
441
+ },
442
+ async randomUuid() {
443
+ const payload = requireObject(await transport.invoke("crypto.randomUuid"), "crypto.randomUuid")
444
+ return requireStringField(payload, "uuid", "crypto.randomUuid")
445
+ }
446
+ })
447
+ }
448
+
449
+ function createProcessApi(transport) {
450
+ return Object.freeze({
451
+ async getPid() {
452
+ const payload = requireObject(await transport.invoke("process.getPid"), "process.getPid")
453
+ return requireNumberField(payload, "pid", "process.getPid")
454
+ },
455
+ async getCwd() {
456
+ const payload = requireObject(await transport.invoke("process.getCwd"), "process.getCwd")
457
+ return requireStringField(payload, "path", "process.getCwd")
458
+ },
459
+ getInfo() {
460
+ return transport.invoke("process.getInfo")
461
+ }
462
+ })
463
+ }
464
+
465
+ function createPowerApi(transport) {
466
+ return Object.freeze({
467
+ getInfo() {
468
+ return transport.invoke("power.getInfo")
469
+ }
470
+ })
471
+ }
472
+
473
+ function createMenuApi(transport) {
474
+ return Object.freeze({
475
+ getInfo() {
476
+ return transport.invoke("menu.getInfo")
477
+ },
478
+ setApplicationMenu(items) {
479
+ return transport.invoke("menu.setApplicationMenu", { items })
480
+ },
481
+ clearApplicationMenu() {
482
+ return transport.invoke("menu.clearApplicationMenu")
483
+ }
484
+ })
485
+ }
486
+
487
+ function createTrayApi(transport) {
488
+ return Object.freeze({
489
+ getInfo() {
490
+ return transport.invoke("tray.getInfo")
491
+ },
492
+ create(options = {}) {
493
+ return transport.invoke("tray.create", options)
494
+ },
495
+ setTitle(title) {
496
+ return transport.invoke("tray.setTitle", { title })
497
+ },
498
+ setTooltip(tooltip) {
499
+ return transport.invoke("tray.setTooltip", { tooltip })
500
+ },
501
+ setMenu(items) {
502
+ return transport.invoke("tray.setMenu", { items })
503
+ },
504
+ destroy() {
505
+ return transport.invoke("tray.destroy")
506
+ }
507
+ })
508
+ }
509
+
510
+ function createShortcutApi(transport) {
511
+ return Object.freeze({
512
+ getInfo() {
513
+ return transport.invoke("shortcut.getInfo")
514
+ },
515
+ register(accelerator) {
516
+ return transport.invoke("shortcut.register", { accelerator })
517
+ },
518
+ unregister(accelerator) {
519
+ return transport.invoke("shortcut.unregister", { accelerator })
520
+ },
521
+ unregisterAll() {
522
+ return transport.invoke("shortcut.unregisterAll")
523
+ }
524
+ })
525
+ }
526
+
527
+ function createProtocolApi(transport) {
528
+ return Object.freeze({
529
+ getInfo() {
530
+ return transport.invoke("protocol.getInfo")
531
+ },
532
+ register(options = {}) {
533
+ return transport.invoke("protocol.register", options)
534
+ },
535
+ unregister(options = {}) {
536
+ return transport.invoke("protocol.unregister", options)
537
+ }
538
+ })
539
+ }
540
+
541
+ function createUpdaterApi(transport) {
542
+ return Object.freeze({
543
+ getInfo() {
544
+ return transport.invoke("updater.getInfo")
545
+ },
546
+ check(options = {}) {
547
+ return transport.invoke("updater.check", options)
548
+ },
549
+ download(options = {}) {
550
+ return transport.invoke("updater.download", options)
551
+ },
552
+ install(options = {}) {
553
+ return transport.invoke("updater.install", options)
554
+ }
555
+ })
556
+ }
557
+
558
+ function createNetApi(transport) {
559
+ return Object.freeze({
560
+ request(options) {
561
+ return transport.invoke("net.request", options)
562
+ }
563
+ })
564
+ }
565
+
566
+ export function createResetClient(source) {
567
+ const transport = createResetTransport(source)
568
+ const commands = createCommandApi(transport)
569
+ const app = createAppApi(transport)
570
+ const runtime = createRuntimeApi(transport)
571
+ const events = createEventApi(transport)
572
+ const window = createWindowApi(transport)
573
+ const dialog = createDialogApi(transport)
574
+ const fs = createFsApi(transport)
575
+ const path = createPathApi(transport)
576
+ const shell = createShellApi(transport)
577
+ const clipboard = createClipboardApi(transport)
578
+ const notification = createNotificationApi(transport)
579
+ const screen = createScreenApi(transport)
580
+ const storage = createStorageApi(transport)
581
+ const webview = createWebViewApi(transport)
582
+ const crypto = createCryptoApi(transport)
583
+ const process = createProcessApi(transport)
584
+ const power = createPowerApi(transport)
585
+ const menu = createMenuApi(transport)
586
+ const tray = createTrayApi(transport)
587
+ const shortcut = createShortcutApi(transport)
588
+ const protocol = createProtocolApi(transport)
589
+ const updater = createUpdaterApi(transport)
590
+ const net = createNetApi(transport)
591
+
592
+ return Object.freeze({
593
+ isAvailable() {
594
+ return transport.isAvailable()
595
+ },
596
+ getRuntime() {
597
+ return transport.getRuntime()
598
+ },
599
+ commands,
600
+ app,
601
+ runtime,
602
+ events,
603
+ window,
604
+ dialog,
605
+ fs,
606
+ path,
607
+ shell,
608
+ clipboard,
609
+ notification,
610
+ screen,
611
+ storage,
612
+ webview,
613
+ crypto,
614
+ process,
615
+ power,
616
+ menu,
617
+ tray,
618
+ shortcut,
619
+ protocol,
620
+ updater,
621
+ net
622
+ })
623
+ }
624
+
625
+ export {
626
+ createResetTransport,
627
+ getResetRuntime,
628
+ invoke,
629
+ invokeRaw,
630
+ isResetRuntimeAvailable
631
+ } from "./transport.js"
632
+
633
+ export const reset = createResetClient()
634
+ export const commands = reset.commands
635
+ export const app = reset.app
636
+ export const runtime = reset.runtime
637
+ export const events = reset.events
638
+ export const window = reset.window
639
+ export const dialog = reset.dialog
640
+ export const fs = reset.fs
641
+ export const path = reset.path
642
+ export const shell = reset.shell
643
+ export const clipboard = reset.clipboard
644
+ export const notification = reset.notification
645
+ export const screen = reset.screen
646
+ export const storage = reset.storage
647
+ export const webview = reset.webview
648
+ export const crypto = reset.crypto
649
+ export const process = reset.process
650
+ export const power = reset.power
651
+ export const menu = reset.menu
652
+ export const tray = reset.tray
653
+ export const shortcut = reset.shortcut
654
+ export const protocol = reset.protocol
655
+ export const updater = reset.updater
656
+ export const net = reset.net