@reset-framework/sdk 1.0.2 → 1.1.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reset-framework/sdk",
3
- "version": "1.0.2",
3
+ "version": "1.1.1",
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)
@@ -563,6 +717,26 @@ function createNetApi(transport) {
563
717
  })
564
718
  }
565
719
 
720
+ function scheduleFrontendReadySignal(transport) {
721
+ if (typeof window === "undefined") {
722
+ return
723
+ }
724
+
725
+ if (window.__resetFrontendReadySignalScheduled) {
726
+ return
727
+ }
728
+
729
+ window.__resetFrontendReadySignalScheduled = true
730
+
731
+ queueMicrotask(() => {
732
+ if (!transport.isAvailable()) {
733
+ return
734
+ }
735
+
736
+ transport.invokeRaw("runtime.signalFrontendReady", {}).catch(() => {})
737
+ })
738
+ }
739
+
566
740
  export function createResetClient(source) {
567
741
  const transport = createResetTransport(source)
568
742
  const commands = createCommandApi(transport)
@@ -585,11 +759,10 @@ export function createResetClient(source) {
585
759
  const menu = createMenuApi(transport)
586
760
  const tray = createTrayApi(transport)
587
761
  const shortcut = createShortcutApi(transport)
588
- const protocol = createProtocolApi(transport)
762
+ const protocol = createProtocolApi(transport, events)
589
763
  const updater = createUpdaterApi(transport)
590
764
  const net = createNetApi(transport)
591
-
592
- return Object.freeze({
765
+ const client = Object.freeze({
593
766
  isAvailable() {
594
767
  return transport.isAvailable()
595
768
  },
@@ -620,6 +793,10 @@ export function createResetClient(source) {
620
793
  updater,
621
794
  net
622
795
  })
796
+
797
+ scheduleFrontendReadySignal(transport)
798
+
799
+ return client
623
800
  }
624
801
 
625
802
  export {
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>;