dualsense-ts 6.3.0 → 6.4.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.
Files changed (76) hide show
  1. package/LINUX_HID.md +85 -0
  2. package/README.md +66 -10
  3. package/dist/dualsense.d.ts +24 -8
  4. package/dist/dualsense.d.ts.map +1 -1
  5. package/dist/dualsense.js +53 -17
  6. package/dist/dualsense.js.map +1 -1
  7. package/dist/hid/bt_checksum.d.ts +7 -0
  8. package/dist/hid/bt_checksum.d.ts.map +1 -1
  9. package/dist/hid/bt_checksum.js +33 -1
  10. package/dist/hid/bt_checksum.js.map +1 -1
  11. package/dist/hid/dualsense_hid.d.ts +77 -0
  12. package/dist/hid/dualsense_hid.d.ts.map +1 -1
  13. package/dist/hid/dualsense_hid.js +193 -0
  14. package/dist/hid/dualsense_hid.js.map +1 -1
  15. package/dist/hid/factory_info.d.ts +53 -0
  16. package/dist/hid/factory_info.d.ts.map +1 -0
  17. package/dist/hid/factory_info.js +166 -0
  18. package/dist/hid/factory_info.js.map +1 -0
  19. package/dist/hid/firmware_info.d.ts +46 -0
  20. package/dist/hid/firmware_info.d.ts.map +1 -0
  21. package/dist/hid/firmware_info.js +109 -0
  22. package/dist/hid/firmware_info.js.map +1 -0
  23. package/dist/hid/hid_provider.d.ts +8 -0
  24. package/dist/hid/hid_provider.d.ts.map +1 -1
  25. package/dist/hid/hid_provider.js +7 -0
  26. package/dist/hid/hid_provider.js.map +1 -1
  27. package/dist/hid/index.d.ts +3 -0
  28. package/dist/hid/index.d.ts.map +1 -1
  29. package/dist/hid/index.js +3 -0
  30. package/dist/hid/index.js.map +1 -1
  31. package/dist/hid/node_hid_provider.d.ts +2 -0
  32. package/dist/hid/node_hid_provider.d.ts.map +1 -1
  33. package/dist/hid/node_hid_provider.js +14 -0
  34. package/dist/hid/node_hid_provider.js.map +1 -1
  35. package/dist/hid/pairing_info.d.ts +9 -0
  36. package/dist/hid/pairing_info.d.ts.map +1 -0
  37. package/dist/hid/pairing_info.js +33 -0
  38. package/dist/hid/pairing_info.js.map +1 -0
  39. package/dist/hid/web_hid_provider.d.ts +14 -0
  40. package/dist/hid/web_hid_provider.d.ts.map +1 -1
  41. package/dist/hid/web_hid_provider.js +79 -8
  42. package/dist/hid/web_hid_provider.js.map +1 -1
  43. package/dist/manager.d.ts +57 -4
  44. package/dist/manager.d.ts.map +1 -1
  45. package/dist/manager.js +248 -66
  46. package/dist/manager.js.map +1 -1
  47. package/nodehid_example/debug.ts +35 -13
  48. package/nodehid_example/single.ts +21 -0
  49. package/package.json +1 -1
  50. package/src/dualsense.ts +65 -23
  51. package/src/hid/bt_checksum.ts +39 -0
  52. package/src/hid/dualsense_hid.ts +230 -0
  53. package/src/hid/factory_info.ts +206 -0
  54. package/src/hid/firmware_info.ts +157 -0
  55. package/src/hid/hid_provider.ts +14 -0
  56. package/src/hid/index.ts +3 -0
  57. package/src/hid/node_hid_provider.ts +14 -0
  58. package/src/hid/pairing_info.ts +33 -0
  59. package/src/hid/web_hid_provider.ts +87 -8
  60. package/src/manager.ts +285 -71
  61. package/webhid_example/build/asset-manifest.json +3 -3
  62. package/webhid_example/build/index.html +1 -1
  63. package/webhid_example/build/static/js/main.1c1a2c23.js +3 -0
  64. package/webhid_example/build/static/js/main.1c1a2c23.js.map +1 -0
  65. package/webhid_example/src/App.tsx +5 -1
  66. package/webhid_example/src/hud/AudioIndicator.tsx +4 -2
  67. package/webhid_example/src/hud/BatteryIndicator.tsx +4 -2
  68. package/webhid_example/src/hud/ColorIndicator.tsx +72 -0
  69. package/webhid_example/src/hud/ControllerConnection.tsx +29 -2
  70. package/webhid_example/src/hud/Debugger.tsx +31 -1
  71. package/webhid_example/src/hud/LightbarFadeButtons.tsx +2 -2
  72. package/webhid_example/src/hud/MuteLedControls.tsx +3 -2
  73. package/webhid_example/src/hud/index.tsx +1 -0
  74. package/webhid_example/build/static/js/main.fcf0c900.js +0 -3
  75. package/webhid_example/build/static/js/main.fcf0c900.js.map +0 -1
  76. /package/webhid_example/build/static/js/{main.fcf0c900.js.LICENSE.txt → main.1c1a2c23.js.LICENSE.txt} +0 -0
@@ -1,7 +1,11 @@
1
1
  import { PulseOptions, Brightness } from "./command";
2
2
  import { HIDProvider, DualsenseHIDState } from "./hid_provider";
3
+ import { FirmwareInfo } from "./firmware_info";
4
+ import { FactoryInfo } from "./factory_info";
3
5
  export type HIDCallback = (state: DualsenseHIDState) => void;
4
6
  export type ErrorCallback = (error: Error) => void;
7
+ export type ReadyCallback = () => void;
8
+ export type ConnectionCallback = (connected: boolean) => void;
5
9
  /** Coordinates a HIDProvider and tracks the latest HID state */
6
10
  export declare class DualsenseHID {
7
11
  readonly provider: HIDProvider;
@@ -9,10 +13,26 @@ export declare class DualsenseHID {
9
13
  private readonly subscribers;
10
14
  /** Subscribers waiting for error updates */
11
15
  private readonly errorSubscribers;
16
+ /** Subscribers waiting for firmware/factory info to become available */
17
+ private readonly readySubscribers;
18
+ /** Subscribers tracking transport-level connect/disconnect events */
19
+ private readonly connectionSubscribers;
20
+ /** True once firmware/factory info has been loaded for the current connection */
21
+ private identityResolved;
22
+ /** Pending retry timer for identity loading after a transient failure */
23
+ private identityRetryTimer?;
24
+ /** Number of identity-load attempts made for the current connection */
25
+ private identityRetryCount;
12
26
  /** Queue of pending HID commands */
13
27
  private pendingCommands;
14
28
  /** Most recent HID state of the device */
15
29
  state: DualsenseHIDState;
30
+ /** Firmware and hardware information, populated after connection */
31
+ firmwareInfo: FirmwareInfo;
32
+ /** Factory information (serial, color, board revision), populated after connection */
33
+ factoryInfo: FactoryInfo;
34
+ /** Bluetooth MAC address from Feature Report 0x09, populated after connection */
35
+ macAddress?: string;
16
36
  constructor(provider: HIDProvider, refreshRate?: number);
17
37
  get wireless(): boolean;
18
38
  /** Register a handler for HID state updates */
@@ -21,10 +41,67 @@ export declare class DualsenseHID {
21
41
  unregister(callback: HIDCallback): void;
22
42
  /** Add a subscriber for errors */
23
43
  on(type: "error" | string, callback: ErrorCallback): void;
44
+ /**
45
+ * Subscribe to notification when firmware/factory info finishes loading
46
+ * after a connect. Fires once per connection — either when identity has
47
+ * been resolved, or when we've given up retrying. If identity is already
48
+ * resolved at the time of subscription, the callback fires synchronously.
49
+ */
50
+ onReady(callback: ReadyCallback): () => void;
51
+ /** True if firmware/factory info has been loaded (or given up on) for the current connection */
52
+ get ready(): boolean;
53
+ /**
54
+ * Subscribe to transport-level connect/disconnect events. Useful for
55
+ * mirroring connection state into an Input without polling. Returns
56
+ * an unsubscribe function.
57
+ */
58
+ onConnectionChange(callback: ConnectionCallback): () => void;
59
+ /**
60
+ * Stable hardware identity for this controller, derived from the most
61
+ * trustworthy info available. Prefers the Bluetooth MAC address (from
62
+ * Feature Report 0x09, works on every transport and platform), then
63
+ * falls back to the factory serial, then firmware deviceInfo.
64
+ * Returns undefined until identity info has been read.
65
+ */
66
+ get identity(): string | undefined;
24
67
  /** Update the HID state and pass it along to all state subscribers */
25
68
  private set;
26
69
  /** Pass errors along to all error subscribers */
27
70
  private handleError;
71
+ /** Maximum identity-load retry attempts per connection */
72
+ private static readonly IDENTITY_MAX_ATTEMPTS;
73
+ /** Backoff schedule (ms) for identity-load retries */
74
+ private static readonly IDENTITY_BACKOFF_MS;
75
+ /**
76
+ * Attempt to read firmware + factory info for the current connection,
77
+ * with retry on failure. Marks identity as resolved on success or after
78
+ * exhausting all attempts (so consumers don't wait forever).
79
+ *
80
+ * If cached firmware/factory info exists from a prior session, identity
81
+ * is resolved immediately (so the connection event has full details),
82
+ * then a background verification re-reads the device to confirm.
83
+ */
84
+ private loadIdentity;
85
+ /** Mark identity loading as complete and notify subscribers */
86
+ private markIdentityResolved;
87
+ /** Cancel any pending identity-load retry */
88
+ private cancelIdentityRetry;
89
+ /** In-flight firmware info fetch, deduped across callers within a connection */
90
+ private firmwareFetch?;
91
+ /** In-flight factory info fetch, deduped across callers within a connection */
92
+ private factoryFetch?;
93
+ /**
94
+ * Read firmware info from the controller (Feature Report 0x20).
95
+ * Idempotent: returns the cached value if already fetched, or the
96
+ * in-flight promise if a fetch is already underway.
97
+ */
98
+ fetchFirmwareInfo(): Promise<FirmwareInfo>;
99
+ /**
100
+ * Read factory info (serial number, body color, board revision) from the controller.
101
+ * Requires firmware info to be fetched first for feature gating.
102
+ * Idempotent across the lifetime of a single connection.
103
+ */
104
+ fetchFactoryInfo(): Promise<FactoryInfo>;
28
105
  /** Condense all pending commands into one HID feature report */
29
106
  private static buildFeatureReport;
30
107
  /** Set intensity for left and right rumbles */
@@ -1 +1 @@
1
- {"version":3,"file":"dualsense_hid.d.ts","sourceRoot":"","sources":["../../src/hid/dualsense_hid.ts"],"names":[],"mappings":"AAAA,OAAO,EAA4C,YAAY,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAC/F,OAAO,EACL,WAAW,EACX,iBAAiB,EAElB,MAAM,gBAAgB,CAAC;AAGxB,MAAM,MAAM,WAAW,GAAG,CAAC,KAAK,EAAE,iBAAiB,KAAK,IAAI,CAAC;AAC7D,MAAM,MAAM,aAAa,GAAG,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;AAenD,gEAAgE;AAChE,qBAAa,YAAY;IAWrB,QAAQ,CAAC,QAAQ,EAAE,WAAW;IAVhC,gDAAgD;IAChD,OAAO,CAAC,QAAQ,CAAC,WAAW,CAA0B;IACtD,4CAA4C;IAC5C,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAA4B;IAC7D,oCAAoC;IACpC,OAAO,CAAC,eAAe,CAAsB;IAC7C,0CAA0C;IACnC,KAAK,EAAE,iBAAiB,CAAmC;gBAGvD,QAAQ,EAAE,WAAW,EAC9B,WAAW,GAAE,MAAW;IAyB1B,IAAW,QAAQ,IAAI,OAAO,CAE7B;IAED,+CAA+C;IACxC,QAAQ,CAAC,QAAQ,EAAE,WAAW,GAAG,IAAI;IAI5C,6CAA6C;IACtC,UAAU,CAAC,QAAQ,EAAE,WAAW,GAAG,IAAI;IAI9C,kCAAkC;IAC3B,EAAE,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,EAAE,QAAQ,EAAE,aAAa,GAAG,IAAI;IAIhE,sEAAsE;IACtE,OAAO,CAAC,GAAG;IAKX,iDAAiD;IACjD,OAAO,CAAC,WAAW;IAInB,gEAAgE;IAChE,OAAO,CAAC,MAAM,CAAC,kBAAkB;IAiDjC,+CAA+C;IACxC,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAiBnD,2DAA2D;IACpD,sBAAsB,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI;IAOtD,4DAA4D;IACrD,uBAAuB,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI;IAOvD,mCAAmC;IAC5B,gBAAgB,CAAC,EAAE,EAAE,OAAO,GAAG,IAAI;IAO1C,oEAAoE;IAC7D,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,GAAE,UAA4B,GAAG,IAAI;IAWrF,+CAA+C;IACxC,WAAW,CAChB,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,EACT,KAAK,GAAE,YAA+B,GACrC,IAAI;CAkBR"}
1
+ {"version":3,"file":"dualsense_hid.d.ts","sourceRoot":"","sources":["../../src/hid/dualsense_hid.ts"],"names":[],"mappings":"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"}
@@ -4,6 +4,9 @@ exports.DualsenseHID = void 0;
4
4
  const command_1 = require("./command");
5
5
  const hid_provider_1 = require("./hid_provider");
6
6
  const bt_checksum_1 = require("./bt_checksum");
7
+ const firmware_info_1 = require("./firmware_info");
8
+ const factory_info_1 = require("./factory_info");
9
+ const pairing_info_1 = require("./pairing_info");
7
10
  const SCOPE_A = 1;
8
11
  const SCOPE_B = 2;
9
12
  /** Coordinates a HIDProvider and tracks the latest HID state */
@@ -14,12 +17,42 @@ class DualsenseHID {
14
17
  this.subscribers = new Set();
15
18
  /** Subscribers waiting for error updates */
16
19
  this.errorSubscribers = new Set();
20
+ /** Subscribers waiting for firmware/factory info to become available */
21
+ this.readySubscribers = new Set();
22
+ /** Subscribers tracking transport-level connect/disconnect events */
23
+ this.connectionSubscribers = new Set();
24
+ /** True once firmware/factory info has been loaded for the current connection */
25
+ this.identityResolved = false;
26
+ /** Number of identity-load attempts made for the current connection */
27
+ this.identityRetryCount = 0;
17
28
  /** Queue of pending HID commands */
18
29
  this.pendingCommands = [];
19
30
  /** Most recent HID state of the device */
20
31
  this.state = { ...hid_provider_1.DefaultDualsenseHIDState };
32
+ /** Firmware and hardware information, populated after connection */
33
+ this.firmwareInfo = firmware_info_1.DefaultFirmwareInfo;
34
+ /** Factory information (serial, color, board revision), populated after connection */
35
+ this.factoryInfo = factory_info_1.DefaultFactoryInfo;
21
36
  provider.onData = this.set.bind(this);
22
37
  provider.onError = this.handleError.bind(this);
38
+ provider.onConnect = () => {
39
+ // Keep cached firmware/factory info from the prior session so that
40
+ // consumers see identity details immediately on a reconnection
41
+ // event. The background loadIdentity() call will verify and refresh
42
+ // the cache — if the hardware identity turns out different (e.g. a
43
+ // different controller grabbed the same slot), the fields get
44
+ // overwritten then.
45
+ this.firmwareFetch = undefined;
46
+ this.factoryFetch = undefined;
47
+ this.identityResolved = false;
48
+ this.cancelIdentityRetry();
49
+ this.connectionSubscribers.forEach((cb) => cb(true));
50
+ void this.loadIdentity();
51
+ };
52
+ provider.onDisconnect = () => {
53
+ this.cancelIdentityRetry();
54
+ this.connectionSubscribers.forEach((cb) => cb(false));
55
+ };
23
56
  setInterval(() => {
24
57
  if (this.pendingCommands.length > 0) {
25
58
  (async () => {
@@ -48,6 +81,52 @@ class DualsenseHID {
48
81
  if (type === "error")
49
82
  this.errorSubscribers.add(callback);
50
83
  }
84
+ /**
85
+ * Subscribe to notification when firmware/factory info finishes loading
86
+ * after a connect. Fires once per connection — either when identity has
87
+ * been resolved, or when we've given up retrying. If identity is already
88
+ * resolved at the time of subscription, the callback fires synchronously.
89
+ */
90
+ onReady(callback) {
91
+ if (this.identityResolved) {
92
+ callback();
93
+ return () => { };
94
+ }
95
+ this.readySubscribers.add(callback);
96
+ return () => this.readySubscribers.delete(callback);
97
+ }
98
+ /** True if firmware/factory info has been loaded (or given up on) for the current connection */
99
+ get ready() {
100
+ return this.identityResolved;
101
+ }
102
+ /**
103
+ * Subscribe to transport-level connect/disconnect events. Useful for
104
+ * mirroring connection state into an Input without polling. Returns
105
+ * an unsubscribe function.
106
+ */
107
+ onConnectionChange(callback) {
108
+ this.connectionSubscribers.add(callback);
109
+ return () => this.connectionSubscribers.delete(callback);
110
+ }
111
+ /**
112
+ * Stable hardware identity for this controller, derived from the most
113
+ * trustworthy info available. Prefers the Bluetooth MAC address (from
114
+ * Feature Report 0x09, works on every transport and platform), then
115
+ * falls back to the factory serial, then firmware deviceInfo.
116
+ * Returns undefined until identity info has been read.
117
+ */
118
+ get identity() {
119
+ if (this.macAddress) {
120
+ return `mac:${this.macAddress}`;
121
+ }
122
+ if (this.factoryInfo.serialNumber !== factory_info_1.DefaultFactoryInfo.serialNumber) {
123
+ return `serial:${this.factoryInfo.serialNumber}`;
124
+ }
125
+ if (this.firmwareInfo.deviceInfo !== firmware_info_1.DefaultFirmwareInfo.deviceInfo) {
126
+ return `device:${this.firmwareInfo.deviceInfo}`;
127
+ }
128
+ return undefined;
129
+ }
51
130
  /** Update the HID state and pass it along to all state subscribers */
52
131
  set(state) {
53
132
  this.state = state;
@@ -57,6 +136,116 @@ class DualsenseHID {
57
136
  handleError(error) {
58
137
  this.errorSubscribers.forEach((callback) => callback(error));
59
138
  }
139
+ /**
140
+ * Attempt to read firmware + factory info for the current connection,
141
+ * with retry on failure. Marks identity as resolved on success or after
142
+ * exhausting all attempts (so consumers don't wait forever).
143
+ *
144
+ * If cached firmware/factory info exists from a prior session, identity
145
+ * is resolved immediately (so the connection event has full details),
146
+ * then a background verification re-reads the device to confirm.
147
+ */
148
+ async loadIdentity() {
149
+ if (!this.provider.connected)
150
+ return;
151
+ // Fast path: if we already have cached identity from a prior session,
152
+ // mark resolved immediately so consumers see it on the connection event.
153
+ // Then continue to the verification read below.
154
+ const hadCachedIdentity = this.identity !== undefined;
155
+ if (hadCachedIdentity) {
156
+ this.markIdentityResolved();
157
+ }
158
+ this.identityRetryCount += 1;
159
+ try {
160
+ // Read MAC address first — simple feature report, no firmware gate.
161
+ const mac = await (0, pairing_info_1.readMacAddress)(this.provider);
162
+ if (mac)
163
+ this.macAddress = mac;
164
+ // Always read fresh from the device (bypass the idempotency cache).
165
+ const fw = await (0, firmware_info_1.readFirmwareInfo)(this.provider);
166
+ if (fw) {
167
+ this.firmwareInfo = fw;
168
+ this.firmwareFetch = Promise.resolve(fw);
169
+ const fi = await (0, factory_info_1.readFactoryInfo)(this.provider, fw.hardwareInfo, fw.mainFirmwareVersionRaw);
170
+ this.factoryInfo = fi ?? factory_info_1.DefaultFactoryInfo;
171
+ this.factoryFetch = Promise.resolve(this.factoryInfo);
172
+ if (!hadCachedIdentity) {
173
+ this.markIdentityResolved();
174
+ }
175
+ return;
176
+ }
177
+ }
178
+ catch {
179
+ // Treat throws the same as undefined — fall through to retry logic.
180
+ }
181
+ // Failure — clear in-flight promises so the next attempt can retry.
182
+ this.firmwareFetch = undefined;
183
+ this.factoryFetch = undefined;
184
+ if (this.identityRetryCount >= DualsenseHID.IDENTITY_MAX_ATTEMPTS ||
185
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
186
+ !this.provider.connected) {
187
+ this.markIdentityResolved();
188
+ return;
189
+ }
190
+ const delay = DualsenseHID.IDENTITY_BACKOFF_MS[Math.min(this.identityRetryCount - 1, DualsenseHID.IDENTITY_BACKOFF_MS.length - 1)];
191
+ this.identityRetryTimer = setTimeout(() => {
192
+ this.identityRetryTimer = undefined;
193
+ void this.loadIdentity();
194
+ }, delay);
195
+ }
196
+ /** Mark identity loading as complete and notify subscribers */
197
+ markIdentityResolved() {
198
+ if (this.identityResolved)
199
+ return;
200
+ this.identityResolved = true;
201
+ this.identityRetryCount = 0;
202
+ const callbacks = Array.from(this.readySubscribers);
203
+ this.readySubscribers.clear();
204
+ callbacks.forEach((cb) => cb());
205
+ }
206
+ /** Cancel any pending identity-load retry */
207
+ cancelIdentityRetry() {
208
+ if (this.identityRetryTimer) {
209
+ clearTimeout(this.identityRetryTimer);
210
+ this.identityRetryTimer = undefined;
211
+ }
212
+ this.identityRetryCount = 0;
213
+ }
214
+ /**
215
+ * Read firmware info from the controller (Feature Report 0x20).
216
+ * Idempotent: returns the cached value if already fetched, or the
217
+ * in-flight promise if a fetch is already underway.
218
+ */
219
+ fetchFirmwareInfo() {
220
+ if (this.firmwareInfo !== firmware_info_1.DefaultFirmwareInfo)
221
+ return Promise.resolve(this.firmwareInfo);
222
+ if (this.firmwareFetch)
223
+ return this.firmwareFetch;
224
+ this.firmwareFetch = (0, firmware_info_1.readFirmwareInfo)(this.provider).then((info) => {
225
+ this.firmwareInfo = info ?? firmware_info_1.DefaultFirmwareInfo;
226
+ return this.firmwareInfo;
227
+ });
228
+ return this.firmwareFetch;
229
+ }
230
+ /**
231
+ * Read factory info (serial number, body color, board revision) from the controller.
232
+ * Requires firmware info to be fetched first for feature gating.
233
+ * Idempotent across the lifetime of a single connection.
234
+ */
235
+ fetchFactoryInfo() {
236
+ if (this.factoryInfo !== factory_info_1.DefaultFactoryInfo)
237
+ return Promise.resolve(this.factoryInfo);
238
+ if (this.factoryFetch)
239
+ return this.factoryFetch;
240
+ if (this.firmwareInfo === firmware_info_1.DefaultFirmwareInfo)
241
+ return Promise.resolve(factory_info_1.DefaultFactoryInfo);
242
+ const fwInfo = this.firmwareInfo;
243
+ this.factoryFetch = (0, factory_info_1.readFactoryInfo)(this.provider, fwInfo.hardwareInfo, fwInfo.mainFirmwareVersionRaw).then((info) => {
244
+ this.factoryInfo = info ?? factory_info_1.DefaultFactoryInfo;
245
+ return this.factoryInfo;
246
+ });
247
+ return this.factoryFetch;
248
+ }
60
249
  /** Condense all pending commands into one HID feature report */
61
250
  static buildFeatureReport(events, wireless) {
62
251
  const usbReport = new Uint8Array(48).fill(0);
@@ -168,4 +357,8 @@ class DualsenseHID {
168
357
  }
169
358
  }
170
359
  exports.DualsenseHID = DualsenseHID;
360
+ /** Maximum identity-load retry attempts per connection */
361
+ DualsenseHID.IDENTITY_MAX_ATTEMPTS = 5;
362
+ /** Backoff schedule (ms) for identity-load retries */
363
+ DualsenseHID.IDENTITY_BACKOFF_MS = [500, 1500, 3000, 5000];
171
364
  //# sourceMappingURL=dualsense_hid.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"dualsense_hid.js","sourceRoot":"","sources":["../../src/hid/dualsense_hid.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"dualsense_hid.js","sourceRoot":"","sources":["../../src/hid/dualsense_hid.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,53 @@
1
+ import { HIDProvider } from "./hid_provider";
2
+ /** Known DualSense body colors */
3
+ export declare enum DualsenseColor {
4
+ Unknown = "Unknown",
5
+ White = "White",
6
+ MidnightBlack = "Midnight Black",
7
+ CosmicRed = "Cosmic Red",
8
+ NovaPink = "Nova Pink",
9
+ GalacticPurple = "Galactic Purple",
10
+ StarlightBlue = "Starlight Blue",
11
+ GreyCamouflage = "Grey Camouflage",
12
+ VolcanicRed = "Volcanic Red",
13
+ SterlingSilver = "Sterling Silver",
14
+ CobaltBlue = "Cobalt Blue",
15
+ ChromaTeal = "Chroma Teal",
16
+ ChromaIndigo = "Chroma Indigo",
17
+ ChromaPearl = "Chroma Pearl",
18
+ Anniversary30th = "30th Anniversary",
19
+ GodOfWarRagnarok = "God of War Ragnarok",
20
+ SpiderMan2 = "Spider-Man 2",
21
+ AstroBot = "Astro Bot",
22
+ Fortnite = "Fortnite",
23
+ TheLastOfUs = "The Last of Us",
24
+ IconBlueLimitedEdition = "Icon Blue Limited Edition",
25
+ GenshinImpact = "Genshin Impact"
26
+ }
27
+ /** Known DualSense body colors, keyed by the 2-char code from the serial number */
28
+ export declare const DualsenseColorMap: Record<string, DualsenseColor>;
29
+ /** Factory information derived from the controller's serial number */
30
+ export interface FactoryInfo {
31
+ /** Raw serial number string */
32
+ serialNumber: string;
33
+ /** Controller body color name (e.g. "Cosmic Red") */
34
+ colorName: string;
35
+ /** Raw 2-character color code from the serial number */
36
+ colorCode: string;
37
+ /** Board revision (e.g. "BDM-030") */
38
+ boardRevision: string;
39
+ }
40
+ /** Default FactoryInfo used when the test command protocol is unavailable (e.g. Linux Bluetooth via node-hid) */
41
+ export declare const DefaultFactoryInfo: FactoryInfo;
42
+ /**
43
+ * Read factory info (serial number, body color, board revision) from a connected controller.
44
+ *
45
+ * Requires firmware support: hardwareInfo >= 777 and mainFirmwareVersion >= 65655.
46
+ * Use the values from FirmwareInfo (Feature Report 0x20) to check this gate.
47
+ *
48
+ * @param provider The HID provider for the connected controller
49
+ * @param hardwareInfo Hardware info word from FirmwareInfo
50
+ * @param mainFwVersionRaw Raw uint32 main firmware version from FirmwareInfo
51
+ */
52
+ export declare function readFactoryInfo(provider: HIDProvider, hardwareInfo: number, mainFwVersionRaw: number): Promise<FactoryInfo | undefined>;
53
+ //# sourceMappingURL=factory_info.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"factory_info.d.ts","sourceRoot":"","sources":["../../src/hid/factory_info.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAE7C,kCAAkC;AAClC,oBAAY,cAAc;IACxB,OAAO,YAAY;IACnB,KAAK,UAAU;IACf,aAAa,mBAAmB;IAChC,SAAS,eAAe;IACxB,QAAQ,cAAc;IACtB,cAAc,oBAAoB;IAClC,aAAa,mBAAmB;IAChC,cAAc,oBAAoB;IAClC,WAAW,iBAAiB;IAC5B,cAAc,oBAAoB;IAClC,UAAU,gBAAgB;IAC1B,UAAU,gBAAgB;IAC1B,YAAY,kBAAkB;IAC9B,WAAW,iBAAiB;IAC5B,eAAe,qBAAqB;IACpC,gBAAgB,wBAAwB;IACxC,UAAU,iBAAiB;IAC3B,QAAQ,cAAc;IACtB,QAAQ,aAAa;IACrB,WAAW,mBAAmB;IAC9B,sBAAsB,8BAA8B;IACpD,aAAa,mBAAmB;CACjC;AAED,mFAAmF;AACnF,eAAO,MAAM,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAsB5D,CAAC;AAWF,sEAAsE;AACtE,MAAM,WAAW,WAAW;IAC1B,+BAA+B;IAC/B,YAAY,EAAE,MAAM,CAAC;IACrB,qDAAqD;IACrD,SAAS,EAAE,MAAM,CAAC;IAClB,wDAAwD;IACxD,SAAS,EAAE,MAAM,CAAC;IAClB,sCAAsC;IACtC,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,iHAAiH;AACjH,eAAO,MAAM,kBAAkB,EAAE,WAKhC,CAAC;AA4EF;;;;;;;;;GASG;AACH,wBAAsB,eAAe,CACnC,QAAQ,EAAE,WAAW,EACrB,YAAY,EAAE,MAAM,EACpB,gBAAgB,EAAE,MAAM,GACvB,OAAO,CAAC,WAAW,GAAG,SAAS,CAAC,CAmClC"}
@@ -0,0 +1,166 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.readFactoryInfo = exports.DefaultFactoryInfo = exports.DualsenseColorMap = exports.DualsenseColor = void 0;
4
+ /** Known DualSense body colors */
5
+ var DualsenseColor;
6
+ (function (DualsenseColor) {
7
+ DualsenseColor["Unknown"] = "Unknown";
8
+ DualsenseColor["White"] = "White";
9
+ DualsenseColor["MidnightBlack"] = "Midnight Black";
10
+ DualsenseColor["CosmicRed"] = "Cosmic Red";
11
+ DualsenseColor["NovaPink"] = "Nova Pink";
12
+ DualsenseColor["GalacticPurple"] = "Galactic Purple";
13
+ DualsenseColor["StarlightBlue"] = "Starlight Blue";
14
+ DualsenseColor["GreyCamouflage"] = "Grey Camouflage";
15
+ DualsenseColor["VolcanicRed"] = "Volcanic Red";
16
+ DualsenseColor["SterlingSilver"] = "Sterling Silver";
17
+ DualsenseColor["CobaltBlue"] = "Cobalt Blue";
18
+ DualsenseColor["ChromaTeal"] = "Chroma Teal";
19
+ DualsenseColor["ChromaIndigo"] = "Chroma Indigo";
20
+ DualsenseColor["ChromaPearl"] = "Chroma Pearl";
21
+ DualsenseColor["Anniversary30th"] = "30th Anniversary";
22
+ DualsenseColor["GodOfWarRagnarok"] = "God of War Ragnarok";
23
+ DualsenseColor["SpiderMan2"] = "Spider-Man 2";
24
+ DualsenseColor["AstroBot"] = "Astro Bot";
25
+ DualsenseColor["Fortnite"] = "Fortnite";
26
+ DualsenseColor["TheLastOfUs"] = "The Last of Us";
27
+ DualsenseColor["IconBlueLimitedEdition"] = "Icon Blue Limited Edition";
28
+ DualsenseColor["GenshinImpact"] = "Genshin Impact";
29
+ })(DualsenseColor = exports.DualsenseColor || (exports.DualsenseColor = {}));
30
+ /** Known DualSense body colors, keyed by the 2-char code from the serial number */
31
+ exports.DualsenseColorMap = {
32
+ "00": DualsenseColor.White,
33
+ "01": DualsenseColor.MidnightBlack,
34
+ "02": DualsenseColor.CosmicRed,
35
+ "03": DualsenseColor.NovaPink,
36
+ "04": DualsenseColor.GalacticPurple,
37
+ "05": DualsenseColor.StarlightBlue,
38
+ "06": DualsenseColor.GreyCamouflage,
39
+ "07": DualsenseColor.VolcanicRed,
40
+ "08": DualsenseColor.SterlingSilver,
41
+ "09": DualsenseColor.CobaltBlue,
42
+ "10": DualsenseColor.ChromaTeal,
43
+ "11": DualsenseColor.ChromaIndigo,
44
+ "12": DualsenseColor.ChromaPearl,
45
+ "30": DualsenseColor.Anniversary30th,
46
+ Z1: DualsenseColor.GodOfWarRagnarok,
47
+ Z2: DualsenseColor.SpiderMan2,
48
+ Z3: DualsenseColor.AstroBot,
49
+ Z4: DualsenseColor.Fortnite,
50
+ Z6: DualsenseColor.TheLastOfUs,
51
+ ZB: DualsenseColor.IconBlueLimitedEdition,
52
+ ZE: DualsenseColor.GenshinImpact,
53
+ };
54
+ /** Board revision names, keyed by the character at serial position 1 */
55
+ const BoardRevisionMap = {
56
+ "1": "BDM-010",
57
+ "2": "BDM-020",
58
+ "3": "BDM-030",
59
+ "4": "BDM-040",
60
+ "5": "BDM-050",
61
+ };
62
+ /** Default FactoryInfo used when the test command protocol is unavailable (e.g. Linux Bluetooth via node-hid) */
63
+ exports.DefaultFactoryInfo = {
64
+ serialNumber: "unknown",
65
+ colorName: "unknown",
66
+ colorCode: "??",
67
+ boardRevision: "unknown",
68
+ };
69
+ /** Feature report IDs for the test command protocol */
70
+ const SEND_REPORT_ID = 0x80;
71
+ const RECV_REPORT_ID = 0x81;
72
+ /** Report size for test command feature reports (report ID + 63 bytes payload) */
73
+ const REPORT_SIZE = 64;
74
+ /** Test command device/action IDs */
75
+ const DEVICE_SYSTEM = 0x01;
76
+ const ACTION_READ_SERIAL = 0x13;
77
+ /** Test command response status values */
78
+ const STATUS_COMPLETE = 0x02;
79
+ /**
80
+ * Send a test command via Feature Report 0x80 and poll 0x81 for the response.
81
+ * Returns the result data bytes (after the header), or undefined on failure.
82
+ */
83
+ async function sendTestCommand(provider, deviceId, actionId, maxAttempts = 20) {
84
+ // Build the send report: report ID at byte 0, then payload.
85
+ // The provider handles platform differences (WebHID strips byte 0, adds CRC for BT).
86
+ const sendBuf = new Uint8Array(REPORT_SIZE).fill(0);
87
+ sendBuf[0] = SEND_REPORT_ID;
88
+ sendBuf[1] = deviceId;
89
+ sendBuf[2] = actionId;
90
+ await provider.sendFeatureReport(SEND_REPORT_ID, sendBuf);
91
+ // Poll for response
92
+ for (let i = 0; i < maxAttempts; i++) {
93
+ await sleep(50);
94
+ const response = await provider.readFeatureReport(RECV_REPORT_ID, REPORT_SIZE);
95
+ if (response.length === 0)
96
+ continue;
97
+ // Response layout: [reportId, deviceId, actionId, status, ...data]
98
+ // Note: node-hid includes the report ID at byte 0; WebHID may not.
99
+ // Find the actual start based on whether byte 0 is the report ID.
100
+ const offset = response[0] === RECV_REPORT_ID ? 1 : 0;
101
+ const respDevice = response[offset];
102
+ const respAction = response[offset + 1];
103
+ const respStatus = response[offset + 2];
104
+ if (respDevice !== deviceId || respAction !== actionId)
105
+ continue;
106
+ if (respStatus === STATUS_COMPLETE) {
107
+ return response.slice(offset + 3);
108
+ }
109
+ }
110
+ return undefined;
111
+ }
112
+ /** Decode a byte array as ASCII, stopping at null terminator */
113
+ function decodeAscii(data, offset, length) {
114
+ let str = "";
115
+ for (let i = 0; i < length; i++) {
116
+ const byte = data[offset + i];
117
+ if (byte === 0)
118
+ break;
119
+ str += String.fromCharCode(byte);
120
+ }
121
+ return str;
122
+ }
123
+ function sleep(ms) {
124
+ return new Promise((resolve) => setTimeout(resolve, ms));
125
+ }
126
+ /**
127
+ * Read factory info (serial number, body color, board revision) from a connected controller.
128
+ *
129
+ * Requires firmware support: hardwareInfo >= 777 and mainFirmwareVersion >= 65655.
130
+ * Use the values from FirmwareInfo (Feature Report 0x20) to check this gate.
131
+ *
132
+ * @param provider The HID provider for the connected controller
133
+ * @param hardwareInfo Hardware info word from FirmwareInfo
134
+ * @param mainFwVersionRaw Raw uint32 main firmware version from FirmwareInfo
135
+ */
136
+ async function readFactoryInfo(provider, hardwareInfo, mainFwVersionRaw) {
137
+ // Firmware gate check
138
+ if ((hardwareInfo & 0xffff) < 777 || mainFwVersionRaw < 65655) {
139
+ return undefined;
140
+ }
141
+ try {
142
+ const result = await sendTestCommand(provider, DEVICE_SYSTEM, ACTION_READ_SERIAL);
143
+ if (!result)
144
+ return undefined;
145
+ const serialNumber = decodeAscii(result, 0, 32);
146
+ if (serialNumber.length < 6)
147
+ return undefined;
148
+ const colorCode = serialNumber.slice(4, 6);
149
+ const revisionChar = serialNumber.slice(1, 2);
150
+ const colorName = colorCode in exports.DualsenseColorMap ? exports.DualsenseColorMap[colorCode] : colorCode;
151
+ const boardRevision = revisionChar in BoardRevisionMap
152
+ ? BoardRevisionMap[revisionChar]
153
+ : "unknown";
154
+ return {
155
+ serialNumber,
156
+ colorName,
157
+ colorCode,
158
+ boardRevision,
159
+ };
160
+ }
161
+ catch {
162
+ return undefined;
163
+ }
164
+ }
165
+ exports.readFactoryInfo = readFactoryInfo;
166
+ //# sourceMappingURL=factory_info.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"factory_info.js","sourceRoot":"","sources":["../../src/hid/factory_info.ts"],"names":[],"mappings":";;;AAEA,kCAAkC;AAClC,IAAY,cAuBX;AAvBD,WAAY,cAAc;IACxB,qCAAmB,CAAA;IACnB,iCAAe,CAAA;IACf,kDAAgC,CAAA;IAChC,0CAAwB,CAAA;IACxB,wCAAsB,CAAA;IACtB,oDAAkC,CAAA;IAClC,kDAAgC,CAAA;IAChC,oDAAkC,CAAA;IAClC,8CAA4B,CAAA;IAC5B,oDAAkC,CAAA;IAClC,4CAA0B,CAAA;IAC1B,4CAA0B,CAAA;IAC1B,gDAA8B,CAAA;IAC9B,8CAA4B,CAAA;IAC5B,sDAAoC,CAAA;IACpC,0DAAwC,CAAA;IACxC,6CAA2B,CAAA;IAC3B,wCAAsB,CAAA;IACtB,uCAAqB,CAAA;IACrB,gDAA8B,CAAA;IAC9B,sEAAoD,CAAA;IACpD,kDAAgC,CAAA;AAClC,CAAC,EAvBW,cAAc,GAAd,sBAAc,KAAd,sBAAc,QAuBzB;AAED,mFAAmF;AACtE,QAAA,iBAAiB,GAAmC;IAC/D,IAAI,EAAE,cAAc,CAAC,KAAK;IAC1B,IAAI,EAAE,cAAc,CAAC,aAAa;IAClC,IAAI,EAAE,cAAc,CAAC,SAAS;IAC9B,IAAI,EAAE,cAAc,CAAC,QAAQ;IAC7B,IAAI,EAAE,cAAc,CAAC,cAAc;IACnC,IAAI,EAAE,cAAc,CAAC,aAAa;IAClC,IAAI,EAAE,cAAc,CAAC,cAAc;IACnC,IAAI,EAAE,cAAc,CAAC,WAAW;IAChC,IAAI,EAAE,cAAc,CAAC,cAAc;IACnC,IAAI,EAAE,cAAc,CAAC,UAAU;IAC/B,IAAI,EAAE,cAAc,CAAC,UAAU;IAC/B,IAAI,EAAE,cAAc,CAAC,YAAY;IACjC,IAAI,EAAE,cAAc,CAAC,WAAW;IAChC,IAAI,EAAE,cAAc,CAAC,eAAe;IACpC,EAAE,EAAE,cAAc,CAAC,gBAAgB;IACnC,EAAE,EAAE,cAAc,CAAC,UAAU;IAC7B,EAAE,EAAE,cAAc,CAAC,QAAQ;IAC3B,EAAE,EAAE,cAAc,CAAC,QAAQ;IAC3B,EAAE,EAAE,cAAc,CAAC,WAAW;IAC9B,EAAE,EAAE,cAAc,CAAC,sBAAsB;IACzC,EAAE,EAAE,cAAc,CAAC,aAAa;CACjC,CAAC;AAEF,wEAAwE;AACxE,MAAM,gBAAgB,GAA2B;IAC/C,GAAG,EAAE,SAAS;IACd,GAAG,EAAE,SAAS;IACd,GAAG,EAAE,SAAS;IACd,GAAG,EAAE,SAAS;IACd,GAAG,EAAE,SAAS;CACf,CAAC;AAcF,iHAAiH;AACpG,QAAA,kBAAkB,GAAgB;IAC7C,YAAY,EAAE,SAAS;IACvB,SAAS,EAAE,SAAS;IACpB,SAAS,EAAE,IAAI;IACf,aAAa,EAAE,SAAS;CACzB,CAAC;AAEF,uDAAuD;AACvD,MAAM,cAAc,GAAG,IAAI,CAAC;AAC5B,MAAM,cAAc,GAAG,IAAI,CAAC;AAC5B,kFAAkF;AAClF,MAAM,WAAW,GAAG,EAAE,CAAC;AAEvB,qCAAqC;AACrC,MAAM,aAAa,GAAG,IAAI,CAAC;AAC3B,MAAM,kBAAkB,GAAG,IAAI,CAAC;AAEhC,0CAA0C;AAC1C,MAAM,eAAe,GAAG,IAAI,CAAC;AAE7B;;;GAGG;AACH,KAAK,UAAU,eAAe,CAC5B,QAAqB,EACrB,QAAgB,EAChB,QAAgB,EAChB,cAAsB,EAAE;IAExB,4DAA4D;IAC5D,qFAAqF;IACrF,MAAM,OAAO,GAAG,IAAI,UAAU,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACpD,OAAO,CAAC,CAAC,CAAC,GAAG,cAAc,CAAC;IAC5B,OAAO,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC;IACtB,OAAO,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC;IAEtB,MAAM,QAAQ,CAAC,iBAAiB,CAAC,cAAc,EAAE,OAAO,CAAC,CAAC;IAE1D,oBAAoB;IACpB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,WAAW,EAAE,CAAC,EAAE,EAAE;QACpC,MAAM,KAAK,CAAC,EAAE,CAAC,CAAC;QAEhB,MAAM,QAAQ,GAAG,MAAM,QAAQ,CAAC,iBAAiB,CAC/C,cAAc,EACd,WAAW,CACZ,CAAC;QACF,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;YAAE,SAAS;QAEpC,mEAAmE;QACnE,mEAAmE;QACnE,kEAAkE;QAClE,MAAM,MAAM,GAAG,QAAQ,CAAC,CAAC,CAAC,KAAK,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACtD,MAAM,UAAU,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC;QACpC,MAAM,UAAU,GAAG,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QACxC,MAAM,UAAU,GAAG,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QAExC,IAAI,UAAU,KAAK,QAAQ,IAAI,UAAU,KAAK,QAAQ;YAAE,SAAS;QACjE,IAAI,UAAU,KAAK,eAAe,EAAE;YAClC,OAAO,QAAQ,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;SACnC;KACF;IAED,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,gEAAgE;AAChE,SAAS,WAAW,CAAC,IAAgB,EAAE,MAAc,EAAE,MAAc;IACnE,IAAI,GAAG,GAAG,EAAE,CAAC;IACb,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,EAAE,CAAC,EAAE,EAAE;QAC/B,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QAC9B,IAAI,IAAI,KAAK,CAAC;YAAE,MAAM;QACtB,GAAG,IAAI,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;KAClC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,SAAS,KAAK,CAAC,EAAU;IACvB,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;AAC3D,CAAC;AAED;;;;;;;;;GASG;AACI,KAAK,UAAU,eAAe,CACnC,QAAqB,EACrB,YAAoB,EACpB,gBAAwB;IAExB,sBAAsB;IACtB,IAAI,CAAC,YAAY,GAAG,MAAM,CAAC,GAAG,GAAG,IAAI,gBAAgB,GAAG,KAAK,EAAE;QAC7D,OAAO,SAAS,CAAC;KAClB;IAED,IAAI;QACF,MAAM,MAAM,GAAG,MAAM,eAAe,CAClC,QAAQ,EACR,aAAa,EACb,kBAAkB,CACnB,CAAC;QACF,IAAI,CAAC,MAAM;YAAE,OAAO,SAAS,CAAC;QAE9B,MAAM,YAAY,GAAG,WAAW,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;QAChD,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC;YAAE,OAAO,SAAS,CAAC;QAE9C,MAAM,SAAS,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QAC3C,MAAM,YAAY,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QAC9C,MAAM,SAAS,GACb,SAAS,IAAI,yBAAiB,CAAC,CAAC,CAAC,yBAAiB,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QAC5E,MAAM,aAAa,GACjB,YAAY,IAAI,gBAAgB;YAC9B,CAAC,CAAC,gBAAgB,CAAC,YAAY,CAAC;YAChC,CAAC,CAAC,SAAS,CAAC;QAEhB,OAAO;YACL,YAAY;YACZ,SAAS;YACT,SAAS;YACT,aAAa;SACd,CAAC;KACH;IAAC,MAAM;QACN,OAAO,SAAS,CAAC;KAClB;AACH,CAAC;AAvCD,0CAuCC"}