@reset-framework/sdk 1.0.2 → 1.1.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reset-framework/sdk",
3
- "version": "1.0.2",
3
+ "version": "1.1.0",
4
4
  "type": "module",
5
5
  "description": "Browser-side SDK for Reset Framework applications.",
6
6
  "license": "MIT",
package/src/client.js CHANGED
@@ -62,6 +62,45 @@ function requireNumberField(record, field, command) {
62
62
  return value
63
63
  }
64
64
 
65
+ function optionalStringField(record, field, fallback, command) {
66
+ const value = record[field]
67
+
68
+ if (value === undefined || value === null) {
69
+ return fallback
70
+ }
71
+
72
+ if (typeof value !== "string") {
73
+ throw new ResetProtocolError(
74
+ `Reset runtime returned an invalid '${field}' field for '${command}'.`,
75
+ { command }
76
+ )
77
+ }
78
+
79
+ return value
80
+ }
81
+
82
+ function normalizeStringArray(value, field, command) {
83
+ if (!Array.isArray(value)) {
84
+ throw new ResetProtocolError(
85
+ `Reset runtime returned an invalid '${field}' field for '${command}'.`,
86
+ { command }
87
+ )
88
+ }
89
+
90
+ return Object.freeze(
91
+ value.map((entry) => {
92
+ if (typeof entry !== "string") {
93
+ throw new ResetProtocolError(
94
+ `Reset runtime returned an invalid '${field}' field for '${command}'.`,
95
+ { command }
96
+ )
97
+ }
98
+
99
+ return entry
100
+ })
101
+ )
102
+ }
103
+
65
104
  function normalizeAppInfo(payload, command) {
66
105
  const record = requireObject(payload, command)
67
106
 
@@ -97,6 +136,63 @@ function normalizeCapabilities(payload, command) {
97
136
  })
98
137
  }
99
138
 
139
+ function normalizeProtocolLaunch(payload, command) {
140
+ const record = requireObject(payload, command)
141
+
142
+ return Object.freeze({
143
+ id: requireStringField(record, "id", command),
144
+ url: requireStringField(record, "url", command),
145
+ scheme: requireStringField(record, "scheme", command),
146
+ host: optionalStringField(record, "host", "", command),
147
+ path: optionalStringField(record, "path", "", command),
148
+ query: optionalStringField(record, "query", "", command),
149
+ fragment: optionalStringField(record, "fragment", "", command),
150
+ source: requireStringField(record, "source", command),
151
+ coldStart: requireBooleanField(record, "coldStart", command)
152
+ })
153
+ }
154
+
155
+ function normalizeProtocolLaunchEnvelope(payload, command) {
156
+ const record = requireObject(payload, command)
157
+ const launch = record.launch
158
+
159
+ if (launch === null) {
160
+ return null
161
+ }
162
+
163
+ return normalizeProtocolLaunch(launch, command)
164
+ }
165
+
166
+ function normalizeProtocolLaunchList(payload, command) {
167
+ const record = requireObject(payload, command)
168
+ const launches = record.launches
169
+
170
+ if (!Array.isArray(launches)) {
171
+ throw new ResetProtocolError(
172
+ `Reset runtime returned an invalid 'launches' field for '${command}'.`,
173
+ { command }
174
+ )
175
+ }
176
+
177
+ return Object.freeze(launches.map((entry) => normalizeProtocolLaunch(entry, command)))
178
+ }
179
+
180
+ function normalizeProtocolInfo(payload, command) {
181
+ const record = requireObject(payload, command)
182
+
183
+ return Object.freeze({
184
+ supported: requireBooleanField(record, "supported", command),
185
+ module: requireStringField(record, "module", command),
186
+ platform: requireStringField(record, "platform", command),
187
+ configuredSchemes: normalizeStringArray(record.configuredSchemes ?? [], "configuredSchemes", command),
188
+ bundledSchemes: normalizeStringArray(record.bundledSchemes ?? [], "bundledSchemes", command),
189
+ eventName: requireStringField(record, "eventName", command),
190
+ pendingCount: requireNumberField(record, "pendingCount", command),
191
+ eventStreamActive: requireBooleanField(record, "eventStreamActive", command),
192
+ runtimeRegistration: requireBooleanField(record, "runtimeRegistration", command)
193
+ })
194
+ }
195
+
100
196
  function createCommandApi(transport) {
101
197
  return Object.freeze({
102
198
  invoke(command, payload = {}) {
@@ -524,10 +620,68 @@ function createShortcutApi(transport) {
524
620
  })
525
621
  }
526
622
 
527
- function createProtocolApi(transport) {
623
+ function createProtocolApi(transport, events) {
528
624
  return Object.freeze({
529
- getInfo() {
530
- return transport.invoke("protocol.getInfo")
625
+ async getInfo() {
626
+ return normalizeProtocolInfo(await transport.invoke("protocol.getInfo"), "protocol.getInfo")
627
+ },
628
+ async activate() {
629
+ const payload = requireObject(await transport.invoke("protocol.activate"), "protocol.activate")
630
+ return Object.freeze({
631
+ active: requireBooleanField(payload, "active", "protocol.activate")
632
+ })
633
+ },
634
+ async getCurrentLaunch() {
635
+ return normalizeProtocolLaunchEnvelope(
636
+ await transport.invoke("protocol.getCurrentLaunch"),
637
+ "protocol.getCurrentLaunch"
638
+ )
639
+ },
640
+ async getPendingLaunches() {
641
+ return normalizeProtocolLaunchList(
642
+ await transport.invoke("protocol.getPendingLaunches"),
643
+ "protocol.getPendingLaunches"
644
+ )
645
+ },
646
+ async consumePendingLaunches() {
647
+ return normalizeProtocolLaunchList(
648
+ await transport.invoke("protocol.consumePendingLaunches"),
649
+ "protocol.consumePendingLaunches"
650
+ )
651
+ },
652
+ async listen(handler, options = {}) {
653
+ if (typeof handler !== "function") {
654
+ throw new TypeError("Reset protocol listener must be a function.")
655
+ }
656
+
657
+ const consumePending = options.consumePending !== false
658
+ const seenLaunches = new Set()
659
+ const deliver = (payload) => {
660
+ const launch = normalizeProtocolLaunch(payload, "protocol.open")
661
+ if (seenLaunches.has(launch.id)) {
662
+ return
663
+ }
664
+
665
+ seenLaunches.add(launch.id)
666
+ handler(launch)
667
+ }
668
+
669
+ const dispose = events.listen("protocol.open", deliver)
670
+ await transport.invoke("protocol.activate")
671
+
672
+ if (consumePending) {
673
+ const pending = await transport.invoke("protocol.consumePendingLaunches")
674
+ for (const launch of normalizeProtocolLaunchList(pending, "protocol.consumePendingLaunches")) {
675
+ if (seenLaunches.has(launch.id)) {
676
+ continue
677
+ }
678
+
679
+ seenLaunches.add(launch.id)
680
+ handler(launch)
681
+ }
682
+ }
683
+
684
+ return dispose
531
685
  },
532
686
  register(options = {}) {
533
687
  return transport.invoke("protocol.register", options)
@@ -585,7 +739,7 @@ export function createResetClient(source) {
585
739
  const menu = createMenuApi(transport)
586
740
  const tray = createTrayApi(transport)
587
741
  const shortcut = createShortcutApi(transport)
588
- const protocol = createProtocolApi(transport)
742
+ const protocol = createProtocolApi(transport, events)
589
743
  const updater = createUpdaterApi(transport)
590
744
  const net = createNetApi(transport)
591
745
 
package/src/index.d.ts CHANGED
@@ -382,8 +382,37 @@ export interface ResetShortcutApi {
382
382
  unregisterAll(): Promise<unknown>;
383
383
  }
384
384
 
385
+ export interface ResetProtocolLaunch {
386
+ id: string;
387
+ url: string;
388
+ scheme: string;
389
+ host: string;
390
+ path: string;
391
+ query: string;
392
+ fragment: string;
393
+ source: string;
394
+ coldStart: boolean;
395
+ }
396
+
397
+ export interface ResetProtocolInfo extends ResetSupportInfo {
398
+ configuredSchemes: ReadonlyArray<string>;
399
+ bundledSchemes: ReadonlyArray<string>;
400
+ eventName: string;
401
+ pendingCount: number;
402
+ eventStreamActive: boolean;
403
+ runtimeRegistration: boolean;
404
+ }
405
+
385
406
  export interface ResetProtocolApi {
386
- getInfo(): Promise<ResetSupportInfo>;
407
+ getInfo(): Promise<ResetProtocolInfo>;
408
+ activate(): Promise<{ active: boolean }>;
409
+ getCurrentLaunch(): Promise<ResetProtocolLaunch | null>;
410
+ getPendingLaunches(): Promise<ReadonlyArray<ResetProtocolLaunch>>;
411
+ consumePendingLaunches(): Promise<ReadonlyArray<ResetProtocolLaunch>>;
412
+ listen(
413
+ handler: (launch: ResetProtocolLaunch) => void,
414
+ options?: { consumePending?: boolean }
415
+ ): Promise<() => void>;
387
416
  register(options?: {
388
417
  scheme?: string;
389
418
  }): Promise<unknown>;