electron-effect-rpc 0.8.0 → 0.10.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.
@@ -1,35 +1,39 @@
1
- import { isRecord } from "./protocol.js";
2
- import { defaultChannelPrefix, } from "./types.js";
1
+ import { isFunctionValue, isRecord } from "./boundary.js";
2
+ import { assertValidChannelPrefix, defaultChannelPrefix, } from "./types.js";
3
3
  function isContextBridgeLike(value) {
4
- return isRecord(value) && typeof value.exposeInMainWorld === "function";
4
+ return isRecord(value) && isFunctionValue(value.exposeInMainWorld);
5
5
  }
6
6
  function isIpcRendererLike(value) {
7
7
  return (isRecord(value) &&
8
- typeof value.invoke === "function" &&
9
- typeof value.on === "function" &&
10
- typeof value.removeListener === "function");
8
+ isFunctionValue(value.invoke) &&
9
+ isFunctionValue(value.on) &&
10
+ isFunctionValue(value.removeListener));
11
+ }
12
+ function isElectronRendererBindings(value) {
13
+ return (isRecord(value) &&
14
+ isContextBridgeLike(value.contextBridge) &&
15
+ isIpcRendererLike(value.ipcRenderer));
16
+ }
17
+ function parseElectronRendererBindings(value) {
18
+ return isElectronRendererBindings(value) ? value : null;
11
19
  }
12
20
  export function resolveElectronRendererBindings(moduleCandidate) {
13
- const moduleDefault = isRecord(moduleCandidate) ? moduleCandidate.default : undefined;
14
- const source = isRecord(moduleCandidate)
15
- ? moduleCandidate
16
- : isRecord(moduleDefault)
17
- ? moduleDefault
18
- : undefined;
19
- if (!source) {
20
- throw new Error("electron-effect-rpc/preload requires Electron preload runtime bindings.");
21
+ const direct = parseElectronRendererBindings(moduleCandidate);
22
+ if (direct) {
23
+ return direct;
21
24
  }
22
- const { contextBridge, ipcRenderer } = source;
23
- if (!isContextBridgeLike(contextBridge) || !isIpcRendererLike(ipcRenderer)) {
24
- throw new Error("electron-effect-rpc/preload requires Electron preload runtime bindings.");
25
+ if (isRecord(moduleCandidate)) {
26
+ const fromDefault = parseElectronRendererBindings(moduleCandidate.default);
27
+ if (fromDefault) {
28
+ return fromDefault;
29
+ }
25
30
  }
26
- return {
27
- contextBridge,
28
- ipcRenderer,
29
- };
31
+ throw new Error("electron-effect-rpc/preload requires Electron preload runtime bindings.");
30
32
  }
31
33
  export function createBridgeAdaptersFromBindings(bindings, options) {
32
- const channelPrefix = options?.channelPrefix ?? defaultChannelPrefix;
34
+ const channelPrefix = options?.channelPrefix
35
+ ? assertValidChannelPrefix(options.channelPrefix)
36
+ : defaultChannelPrefix;
33
37
  const { ipcRenderer } = bindings;
34
38
  const invoke = (method, payload) => ipcRenderer.invoke(`${channelPrefix.rpc}${method}`, payload);
35
39
  const subscribe = (event, listener) => {
@@ -1,29 +1,29 @@
1
+ import { type IpcEncodedValue } from "./boundary.ts";
1
2
  export type RpcSuccessEnvelope = {
2
3
  readonly type: "success";
3
- readonly data: unknown;
4
+ readonly data: IpcEncodedValue;
4
5
  };
5
6
  export type RpcFailureEnvelope = {
6
7
  readonly type: "failure";
7
8
  readonly error: {
8
9
  readonly tag: string;
9
- readonly data: unknown;
10
+ readonly data: IpcEncodedValue;
10
11
  };
11
12
  };
12
13
  export type RpcDefectEnvelope = {
13
14
  readonly type: "defect";
14
15
  readonly message: string;
15
- readonly cause?: unknown;
16
+ readonly cause?: IpcEncodedValue;
16
17
  };
17
18
  export type RpcResponseEnvelope = RpcSuccessEnvelope | RpcFailureEnvelope | RpcDefectEnvelope;
18
- export declare function isRecord(value: unknown): value is Record<string, unknown>;
19
- export declare function formatUnknown(value: unknown): string;
20
- export declare function extractErrorTag(error: unknown): string;
21
- export declare function toDefectEnvelope(cause: unknown, prefix?: string): RpcDefectEnvelope;
19
+ export { formatUnknown, isRecord, isStringValue } from "./boundary.ts";
20
+ export declare function extractErrorTag<T>(error: T): string;
21
+ export declare function toDefectEnvelope<T>(cause: T, prefix?: string): RpcDefectEnvelope;
22
22
  export declare function safelyCall<T>(callback: ((context: T) => void) | undefined, context: T): void;
23
23
  export type StreamDataFrame = {
24
24
  readonly type: "data";
25
25
  readonly streamId: string;
26
- readonly payload: unknown;
26
+ readonly payload: IpcEncodedValue;
27
27
  };
28
28
  export type StreamEndFrame = {
29
29
  readonly type: "end";
@@ -34,7 +34,7 @@ export type StreamErrorFrame = {
34
34
  readonly streamId: string;
35
35
  readonly error: {
36
36
  readonly tag: string;
37
- readonly data: unknown;
37
+ readonly data: IpcEncodedValue;
38
38
  };
39
39
  };
40
40
  export type StreamDefectFrame = {
@@ -43,7 +43,7 @@ export type StreamDefectFrame = {
43
43
  readonly message: string;
44
44
  };
45
45
  export type StreamFrame = StreamDataFrame | StreamEndFrame | StreamErrorFrame | StreamDefectFrame;
46
- export declare function extractStreamIdFromRaw(value: unknown): string | null;
47
- export declare function parseStreamFrame(value: unknown): StreamFrame | null;
48
- export declare function parseRpcResponseEnvelope(value: unknown): RpcResponseEnvelope | null;
46
+ export declare function extractStreamIdFromRaw<T>(value: T): string | null;
47
+ export declare function parseStreamFrame<T>(value: T): StreamFrame | null;
48
+ export declare function parseRpcResponseEnvelope<T>(value: T): RpcResponseEnvelope | null;
49
49
  //# sourceMappingURL=protocol.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,kBAAkB,GAAG;IAC/B,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE;QACd,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;QACrB,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;KACxB,CAAC;CACH,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IACxB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;CAC1B,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG,kBAAkB,GAAG,kBAAkB,GAAG,iBAAiB,CAAC;AAM9F,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAEzE;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAEpD;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAUtD;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,iBAAiB,CAOnF;AAED,wBAAgB,UAAU,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,KAAK,IAAI,CAAC,GAAG,SAAS,EAAE,OAAO,EAAE,CAAC,GAAG,IAAI,CAU5F;AAED,MAAM,MAAM,eAAe,GAAG;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;CAC3B,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC3B,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC;IACrB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE;QACd,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;QACrB,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;KACxB,CAAC;CACH,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IACxB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG,eAAe,GAAG,cAAc,GAAG,gBAAgB,GAAG,iBAAiB,CAAC;AAElG,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAKpE;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,WAAW,GAAG,IAAI,CA4CnE;AAED,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,OAAO,GAAG,mBAAmB,GAAG,IAAI,CA+CnF"}
1
+ {"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"AACA,OAAO,EAKL,KAAK,eAAe,EACrB,MAAM,eAAe,CAAC;AAEvB,MAAM,MAAM,kBAAkB,GAAG;IAC/B,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,eAAe,CAAC;CAChC,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE;QACd,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;QACrB,QAAQ,CAAC,IAAI,EAAE,eAAe,CAAC;KAChC,CAAC;CACH,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IACxB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,CAAC,EAAE,eAAe,CAAC;CAClC,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG,kBAAkB,GAAG,kBAAkB,GAAG,iBAAiB,CAAC;AAM9F,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAEvE,wBAAgB,eAAe,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,MAAM,CAUnD;AAED,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,iBAAiB,CAOhF;AAED,wBAAgB,UAAU,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,KAAK,IAAI,CAAC,GAAG,SAAS,EAAE,OAAO,EAAE,CAAC,GAAG,IAAI,CAU5F;AAED,MAAM,MAAM,eAAe,GAAG;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,OAAO,EAAE,eAAe,CAAC;CACnC,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC3B,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC;IACrB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE;QACd,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;QACrB,QAAQ,CAAC,IAAI,EAAE,eAAe,CAAC;KAChC,CAAC;CACH,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IACxB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG,eAAe,GAAG,cAAc,GAAG,gBAAgB,GAAG,iBAAiB,CAAC;AAMlG,wBAAgB,sBAAsB,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,MAAM,GAAG,IAAI,CAMjE;AAED,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,WAAW,GAAG,IAAI,CAiChE;AAED,wBAAgB,wBAAwB,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,mBAAmB,GAAG,IAAI,CAyBhF"}
package/dist/protocol.js CHANGED
@@ -1,14 +1,11 @@
1
- function hasOwn(record, key) {
2
- return Object.prototype.hasOwnProperty.call(record, key);
3
- }
4
- export function isRecord(value) {
5
- return typeof value === "object" && value !== null;
6
- }
7
- export function formatUnknown(value) {
8
- return value instanceof Error ? value.message : String(value);
9
- }
1
+ import * as S from "effect/Schema";
2
+ import { formatUnknown, isRecord, isStringValue, } from "./boundary.js";
3
+ const TaggedValue = S.Struct({
4
+ _tag: S.String,
5
+ });
6
+ export { formatUnknown, isRecord, isStringValue } from "./boundary.js";
10
7
  export function extractErrorTag(error) {
11
- if (isRecord(error) && typeof error._tag === "string") {
8
+ if (S.is(TaggedValue)(error)) {
12
9
  return error._tag;
13
10
  }
14
11
  if (error instanceof Error && error.name.length > 0) {
@@ -35,84 +32,69 @@ export function safelyCall(callback, context) {
35
32
  // Diagnostics hooks must never crash transport internals.
36
33
  }
37
34
  }
35
+ function hasOwn(record, key) {
36
+ return Object.prototype.hasOwnProperty.call(record, key);
37
+ }
38
38
  export function extractStreamIdFromRaw(value) {
39
- if (!isRecord(value) || typeof value.streamId !== "string") {
39
+ if (!isRecord(value)) {
40
40
  return null;
41
41
  }
42
- return value.streamId;
42
+ const streamId = value.streamId;
43
+ return isStringValue(streamId) ? streamId : null;
43
44
  }
44
45
  export function parseStreamFrame(value) {
45
- if (!isRecord(value) || typeof value.type !== "string") {
46
+ if (!isRecord(value)) {
46
47
  return null;
47
48
  }
48
- if (typeof value.streamId !== "string") {
49
+ const streamId = extractStreamIdFromRaw(value);
50
+ if (streamId === null) {
49
51
  return null;
50
52
  }
51
- const streamId = value.streamId;
52
53
  switch (value.type) {
53
54
  case "data":
54
- if (!hasOwn(value, "payload")) {
55
- return null;
56
- }
57
- return { type: "data", streamId, payload: value.payload };
55
+ return hasOwn(value, "payload") ? { type: "data", streamId, payload: value.payload } : null;
58
56
  case "end":
59
57
  return { type: "end", streamId };
60
- case "error":
61
- if (!isRecord(value.error) ||
62
- typeof value.error.tag !== "string" ||
63
- !hasOwn(value.error, "data")) {
58
+ case "error": {
59
+ const error = value.error;
60
+ if (!isRecord(error) || !isStringValue(error.tag) || !hasOwn(error, "data")) {
64
61
  return null;
65
62
  }
66
63
  return {
67
64
  type: "error",
68
65
  streamId,
69
- error: { tag: value.error.tag, data: value.error.data },
66
+ error: { tag: error.tag, data: error.data },
70
67
  };
68
+ }
71
69
  case "defect":
72
- if (typeof value.message !== "string") {
73
- return null;
74
- }
75
- return { type: "defect", streamId, message: value.message };
70
+ return isStringValue(value.message)
71
+ ? { type: "defect", streamId, message: value.message }
72
+ : null;
76
73
  default:
77
74
  return null;
78
75
  }
79
76
  }
80
77
  export function parseRpcResponseEnvelope(value) {
81
- if (!isRecord(value) || typeof value.type !== "string") {
78
+ if (!isRecord(value)) {
82
79
  return null;
83
80
  }
84
81
  switch (value.type) {
85
82
  case "success":
86
- if (!hasOwn(value, "data")) {
87
- return null;
88
- }
89
- return {
90
- type: "success",
91
- data: value.data,
92
- };
93
- case "failure":
94
- if (!isRecord(value.error) || typeof value.error.tag !== "string") {
95
- return null;
96
- }
97
- if (!hasOwn(value.error, "data")) {
83
+ return hasOwn(value, "data") ? { type: "success", data: value.data } : null;
84
+ case "failure": {
85
+ const error = value.error;
86
+ if (!isRecord(error) || !isStringValue(error.tag) || !hasOwn(error, "data")) {
98
87
  return null;
99
88
  }
100
89
  return {
101
90
  type: "failure",
102
- error: {
103
- tag: value.error.tag,
104
- data: value.error.data,
105
- },
91
+ error: { tag: error.tag, data: error.data },
106
92
  };
93
+ }
107
94
  case "defect":
108
- if (typeof value.message !== "string") {
109
- return null;
110
- }
111
- return {
112
- type: "defect",
113
- message: value.message,
114
- cause: value.cause,
115
- };
95
+ return isStringValue(value.message)
96
+ ? { type: "defect", message: value.message, cause: value.cause }
97
+ : null;
116
98
  default:
117
99
  return null;
118
100
  }
@@ -1 +1 @@
1
- {"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../src/renderer.ts"],"names":[],"mappings":"AAEA,OAAO,EAGL,KAAK,eAAe,EACpB,KAAK,WAAW,EAMjB,MAAM,eAAe,CAAC;AAUvB,OAAO,EAEL,KAAK,QAAQ,EACb,KAAK,SAAS,EAGd,KAAK,eAAe,EACpB,KAAK,sBAAsB,EAE3B,KAAK,SAAS,EACd,KAAK,gBAAgB,EAMrB,KAAK,qBAAqB,EAC1B,KAAK,sBAAsB,EAC5B,MAAM,YAAY,CAAC;AAsEpB,wBAAgB,eAAe,CAC7B,KAAK,CAAC,OAAO,SAAS,aAAa,CAAC,SAAS,CAAC,EAC9C,KAAK,CAAC,MAAM,SAAS,aAAa,CAAC,QAAQ,CAAC,EAC5C,KAAK,CAAC,aAAa,SAAS,aAAa,CAAC,eAAe,CAAC,GAAG,SAAS,EAAE,EAExE,QAAQ,EAAE,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,aAAa,CAAC,EACrD,OAAO,EAAE,gBAAgB,GACxB,SAAS,CAAC,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,aAAa,CAAC,CAAC,CA0JxD;AAqBD,wBAAgB,qBAAqB,CACnC,KAAK,CAAC,OAAO,SAAS,aAAa,CAAC,SAAS,CAAC,EAC9C,KAAK,CAAC,MAAM,SAAS,aAAa,CAAC,QAAQ,CAAC,EAC5C,KAAK,CAAC,aAAa,SAAS,aAAa,CAAC,eAAe,CAAC,GAAG,SAAS,EAAE,EAExE,QAAQ,EAAE,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,aAAa,CAAC,EACrD,OAAO,EAAE,sBAAsB,GAC9B,eAAe,CAAC,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,aAAa,CAAC,CAAC,CAsF9D;AAUD,wBAAgB,qBAAqB,CACnC,KAAK,CAAC,OAAO,SAAS,aAAa,CAAC,SAAS,CAAC,EAC9C,KAAK,CAAC,MAAM,SAAS,aAAa,CAAC,QAAQ,CAAC,EAC5C,KAAK,CAAC,aAAa,SAAS,aAAa,CAAC,eAAe,CAAC,EAE1D,QAAQ,EAAE,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,aAAa,CAAC,EACrD,OAAO,EAAE,sBAAsB,GAC9B,qBAAqB,CAAC,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,aAAa,CAAC,CAAC,CA0OpE;AAED,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../src/renderer.ts"],"names":[],"mappings":"AAQA,OAAO,EAGL,KAAK,eAAe,EACpB,KAAK,WAAW,EAMjB,MAAM,eAAe,CAAC;AASvB,OAAO,EAEL,KAAK,QAAQ,EACb,KAAK,SAAS,EAGd,KAAK,eAAe,EACpB,KAAK,sBAAsB,EAE3B,KAAK,SAAS,EACd,KAAK,gBAAgB,EAMrB,KAAK,qBAAqB,EAC1B,KAAK,sBAAsB,EAC5B,MAAM,YAAY,CAAC;AA4EpB,wBAAgB,eAAe,CAC7B,KAAK,CAAC,OAAO,SAAS,aAAa,CAAC,SAAS,CAAC,EAC9C,KAAK,CAAC,MAAM,SAAS,aAAa,CAAC,QAAQ,CAAC,EAC5C,KAAK,CAAC,aAAa,SAAS,aAAa,CAAC,eAAe,CAAC,GAAG,SAAS,EAAE,EAExE,QAAQ,EAAE,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,aAAa,CAAC,EACrD,OAAO,EAAE,gBAAgB,GACxB,SAAS,CAAC,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,aAAa,CAAC,CAAC,CAyJxD;AAqBD,wBAAgB,qBAAqB,CACnC,KAAK,CAAC,OAAO,SAAS,aAAa,CAAC,SAAS,CAAC,EAC9C,KAAK,CAAC,MAAM,SAAS,aAAa,CAAC,QAAQ,CAAC,EAC5C,KAAK,CAAC,aAAa,SAAS,aAAa,CAAC,eAAe,CAAC,GAAG,SAAS,EAAE,EAExE,QAAQ,EAAE,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,aAAa,CAAC,EACrD,OAAO,EAAE,sBAAsB,GAC9B,eAAe,CAAC,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,aAAa,CAAC,CAAC,CAmG9D;AAUD,wBAAgB,qBAAqB,CACnC,KAAK,CAAC,OAAO,SAAS,aAAa,CAAC,SAAS,CAAC,EAC9C,KAAK,CAAC,MAAM,SAAS,aAAa,CAAC,QAAQ,CAAC,EAC5C,KAAK,CAAC,aAAa,SAAS,aAAa,CAAC,eAAe,CAAC,EAE1D,QAAQ,EAAE,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,aAAa,CAAC,EACrD,OAAO,EAAE,sBAAsB,GAC9B,qBAAqB,CAAC,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,aAAa,CAAC,CAAC,CAsTpE;AAED,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC"}