@aglyn/tenant-runtime 1.0.0-beta.228 → 1.0.0-beta.230
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": "@aglyn/tenant-runtime",
|
|
3
|
-
"version": "1.0.0-beta.
|
|
3
|
+
"version": "1.0.0-beta.230",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"homepage": "https://aglyn.com",
|
|
6
6
|
"repository": {
|
|
@@ -25,11 +25,11 @@
|
|
|
25
25
|
"./package.json": "./package.json"
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@aglyn/aglyn": "1.0.0-beta.
|
|
29
|
-
"@aglyn/shared-data-types": "1.0.0-beta.
|
|
30
|
-
"@aglyn/shared-ui-theme": "1.0.0-beta.
|
|
31
|
-
"@aglyn/shared-util-http": "1.0.0-beta.
|
|
32
|
-
"@aglyn/tenant-data-admin": "1.0.0-beta.
|
|
28
|
+
"@aglyn/aglyn": "1.0.0-beta.230",
|
|
29
|
+
"@aglyn/shared-data-types": "1.0.0-beta.230",
|
|
30
|
+
"@aglyn/shared-ui-theme": "1.0.0-beta.230",
|
|
31
|
+
"@aglyn/shared-util-http": "1.0.0-beta.230",
|
|
32
|
+
"@aglyn/tenant-data-admin": "1.0.0-beta.230",
|
|
33
33
|
"@swc/helpers": "0.5.23"
|
|
34
34
|
},
|
|
35
35
|
"peerDependencies": {
|
|
@@ -67,6 +67,13 @@ export interface HostEventActor {
|
|
|
67
67
|
export interface HostEventContext {
|
|
68
68
|
/** Absent when the door that raised the event did not know. */
|
|
69
69
|
actor?: HostEventActor;
|
|
70
|
+
/**
|
|
71
|
+
* The site's recorded visit the event ends (AGL-3605): a form submission
|
|
72
|
+
* names the visit its page was on, so a listener can tie that visit to the
|
|
73
|
+
* person the door verified. Shape-checked by the door; absent when the site
|
|
74
|
+
* records no visits or the visitor's consent did not allow one.
|
|
75
|
+
*/
|
|
76
|
+
journeyId?: string;
|
|
70
77
|
}
|
|
71
78
|
export interface HostEventListener {
|
|
72
79
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../libs/tenant/runtime/src/lib/host-event-listeners.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { SiteAlert } from '@aglyn/aglyn/server'\n\n/**\n * WHO HEARS A HOST EVENT.\n *\n * A host event — a form submitted, a member signed up, a deal won — is raised\n * by the server door that performed the write, through `emitHostEvent`. What\n * runs because of it is not the runtime's business: an automation engine, an\n * integration, a marketplace plugin. Each registers a listener here and the\n * runtime fans every event out to all of them, knowing none by name.\n *\n * ## Registered by a call, at boot\n *\n * A listener is registered by a function the platform calls BY NAME — a\n * plugin's `serverDeclarations` entry, which both apps run once per process\n * from `instrumentation.ts`, and its API register functions, which the plugin\n * loader runs. Never by a bare `import './x'`: a bundler drops a module its\n * package does not list as a side effect, and jest does not, so a registration\n * that relies on one passes every spec and runs in no build (AGL-3025).\n *\n * Boot registration is what lets a core route that never loads a plugin — the\n * form submission, the page-view collector — still reach every listener.\n *\n * ## Isolated, and never thrown into the emitter\n *\n * The event has already happened: the submission is stored, the member exists.\n * A listener that throws is logged against its plugin and the others still\n * run, and the emitting request never sees the failure.\n */\n\n/** What an event carries into everything that listens for it. */\nexport type HostEventPayload = Record<string, string | number | boolean>\n\n/**\n * Who caused an event (AGL-3376): the console member who moved the deal, the\n * integration's key that added the contact, the visitor who submitted the\n * form, or the platform acting on its own (a Stripe webhook, a schedule).\n *\n * Kept OUT of the payload on purpose. The payload seeds a workflow's\n * expression scope and condition editor, and a site's automations have no\n * business reading a console member's address; this rides beside it, for\n * the record of who set a run off.\n */\nexport interface HostEventActor {\n kind: 'member' | 'visitor' | 'apiKey' | 'platform'\n /** The acting account, for a member. */\n uid?: string | null\n /** The address the actor had when they acted, when the door knew it. */\n email?: string | null\n /** The key's name, for an integration. */\n apiKeyName?: string | null\n}\n\n/** What rides beside an event's payload. */\nexport interface HostEventContext {\n /** Absent when the door that raised the event did not know. */\n actor?: HostEventActor\n}\n\nexport interface HostEventListener {\n /**\n * Runs whatever this plugin does when `event` happens on the site.\n *\n * Resolves the site alerts a request/response emitter shows its visitor —\n * a form submission returns them in its response — or nothing.\n */\n onEvent(\n hostId: string,\n event: string,\n payload: HostEventPayload,\n context?: HostEventContext,\n ): Promise<readonly SiteAlert[] | void>\n /**\n * Runs the server half of ONE page interaction, by id, that a published\n * page fired for a site event it evaluated itself — a scroll depth, a\n * click, exit intent. The page has already decided the trigger matched, so\n * the listener runs what that one interaction names rather than everything\n * listening for the event; a listener that does not own the id resolves\n * nothing.\n */\n onDispatch?(\n hostId: string,\n interactionId: string,\n event: string,\n payload: HostEventPayload,\n context?: HostEventContext,\n ): Promise<readonly SiteAlert[] | void>\n}\n\ninterface Registration {\n pluginId: string\n listener: HostEventListener\n}\n\nconst registrations: Registration[] = []\n\n/** Whether the no-listener warning has been printed in this process. */\nlet warnedEmpty = false\n\n/** A listener's answer as a list: nothing it said counts as no alerts. */\nfunction alertsOf(answer: readonly SiteAlert[] | void): SiteAlert[] {\n return Array.isArray(answer) ? [...answer] : []\n}\n\n/**\n * Subscribes a plugin to every host event. Registering again under the same\n * plugin id replaces the earlier listener in place, so a register function\n * the platform calls twice — boot, then the API surface — leaves one.\n */\nexport function registerHostEventListener(\n pluginId: string,\n listener: HostEventListener,\n): void {\n const id = String(pluginId ?? '').trim()\n if (!id) {\n throw new Error('a host event listener needs the id of the plugin it belongs to')\n }\n const at = registrations.findIndex((entry) => entry.pluginId === id)\n if (at >= 0) registrations[at] = { pluginId: id, listener }\n else registrations.push({ pluginId: id, listener })\n}\n\n/** The plugins listening, in registration order, for diagnostics. */\nexport function listHostEventListeners(): string[] {\n return registrations.map((entry) => entry.pluginId)\n}\n\n/** Test seam: forget every listener. */\nexport function resetHostEventListenersForTests(): void {\n registrations.length = 0\n warnedEmpty = false\n}\n\n/**\n * Hands one event to every listener, concurrently, and gathers the alerts\n * they produced. Never rejects.\n */\nexport async function runHostEventListeners(\n hostId: string,\n event: string,\n payload: HostEventPayload = {},\n context: HostEventContext = {},\n): Promise<SiteAlert[]> {\n if (!registrations.length) {\n /*\n * Said once per process rather than per event. No listener means the\n * plugins' server declarations never ran here — every automation on\n * every site served by this process is silent, and a line in the log is\n * the only place that is visible.\n */\n if (!warnedEmpty) {\n warnedEmpty = true\n console.warn(\n `[host-events] nothing is listening; \"${event}\" on ${hostId} ran no ` +\n 'automation. Listeners register from the plugins’ server ' +\n 'declarations at boot.',\n )\n }\n return []\n }\n const settled = await Promise.all(\n registrations.map(async ({ pluginId, listener }) => {\n try {\n return alertsOf(await listener.onEvent(hostId, event, payload, context))\n } catch (error) {\n console.error(`[host-events] ${pluginId} failed on ${event}`, hostId, error)\n return []\n }\n }),\n )\n return settled.flat()\n}\n\n/**\n * Hands one page-dispatched interaction to the listeners that dispatch, and\n * gathers the alerts it produced. Never rejects.\n */\nexport async function dispatchHostAutomation(\n hostId: string,\n interactionId: string,\n event: string,\n payload: HostEventPayload = {},\n context: HostEventContext = {},\n): Promise<SiteAlert[]> {\n const alerts: SiteAlert[] = []\n for (const { pluginId, listener } of registrations) {\n if (!listener.onDispatch) continue\n try {\n alerts.push(\n ...alertsOf(\n await listener.onDispatch(hostId, interactionId, event, payload, context),\n ),\n )\n } catch (error) {\n console.error(\n `[host-events] ${pluginId} failed to dispatch ${interactionId}`,\n hostId,\n error,\n )\n }\n }\n return alerts\n}\n"],"names":["registrations","warnedEmpty","alertsOf","answer","Array","isArray","registerHostEventListener","pluginId","listener","id","String","trim","Error","at","findIndex","entry","push","listHostEventListeners","map","resetHostEventListenersForTests","length","runHostEventListeners","hostId","event","payload","context","console","warn","settled","Promise","all","onEvent","error","flat","dispatchHostAutomation","interactionId","alerts","onDispatch"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAgGD,MAAMA,gBAAgC,EAAE;AAExC,sEAAsE,GACtE,IAAIC,cAAc;AAElB,wEAAwE,GACxE,SAASC,SAASC,MAAmC;IACnD,OAAOC,MAAMC,OAAO,CAACF,UAAU;WAAIA;KAAO,GAAG,EAAE;AACjD;AAEA;;;;CAIC,GACD,OAAO,SAASG,0BACdC,QAAgB,EAChBC,QAA2B;IAE3B,MAAMC,KAAKC,OAAOH,mBAAAA,WAAY,IAAII,IAAI;IACtC,IAAI,CAACF,IAAI;QACP,MAAM,IAAIG,MAAM;IAClB;IACA,MAAMC,KAAKb,cAAcc,SAAS,CAAC,CAACC,QAAUA,MAAMR,QAAQ,KAAKE;IACjE,IAAII,MAAM,GAAGb,aAAa,CAACa,GAAG,GAAG;QAAEN,UAAUE;QAAID;IAAS;SACrDR,cAAcgB,IAAI,CAAC;QAAET,UAAUE;QAAID;IAAS;AACnD;AAEA,mEAAmE,GACnE,OAAO,SAASS;IACd,OAAOjB,cAAckB,GAAG,CAAC,CAACH,QAAUA,MAAMR,QAAQ;AACpD;AAEA,sCAAsC,GACtC,OAAO,SAASY;IACdnB,cAAcoB,MAAM,GAAG;IACvBnB,cAAc;AAChB;AAEA;;;CAGC,GACD,OAAO,eAAeoB,sBACpBC,MAAc,EACdC,KAAa,EACbC,UAA4B,CAAC,CAAC,EAC9BC,UAA4B,CAAC,CAAC;IAE9B,IAAI,CAACzB,cAAcoB,MAAM,EAAE;QACzB;;;;;KAKC,GACD,IAAI,CAACnB,aAAa;YAChBA,cAAc;YACdyB,QAAQC,IAAI,CACV,CAAC,qCAAqC,EAAEJ,MAAM,KAAK,EAAED,OAAO,QAAQ,CAAC,GACnE,6DACA;QAEN;QACA,OAAO,EAAE;IACX;IACA,MAAMM,UAAU,MAAMC,QAAQC,GAAG,CAC/B9B,cAAckB,GAAG,CAAC,OAAO,EAAEX,QAAQ,EAAEC,QAAQ,EAAE;QAC7C,IAAI;YACF,OAAON,SAAS,MAAMM,SAASuB,OAAO,CAACT,QAAQC,OAAOC,SAASC;QACjE,EAAE,OAAOO,OAAO;YACdN,QAAQM,KAAK,CAAC,CAAC,cAAc,EAAEzB,SAAS,WAAW,EAAEgB,OAAO,EAAED,QAAQU;YACtE,OAAO,EAAE;QACX;IACF;IAEF,OAAOJ,QAAQK,IAAI;AACrB;AAEA;;;CAGC,GACD,OAAO,eAAeC,uBACpBZ,MAAc,EACda,aAAqB,EACrBZ,KAAa,EACbC,UAA4B,CAAC,CAAC,EAC9BC,UAA4B,CAAC,CAAC;IAE9B,MAAMW,SAAsB,EAAE;IAC9B,KAAK,MAAM,EAAE7B,QAAQ,EAAEC,QAAQ,EAAE,IAAIR,cAAe;QAClD,IAAI,CAACQ,SAAS6B,UAAU,EAAE;QAC1B,IAAI;YACFD,OAAOpB,IAAI,IACNd,SACD,MAAMM,SAAS6B,UAAU,CAACf,QAAQa,eAAeZ,OAAOC,SAASC;QAGvE,EAAE,OAAOO,OAAO;YACdN,QAAQM,KAAK,CACX,CAAC,cAAc,EAAEzB,SAAS,oBAAoB,EAAE4B,eAAe,EAC/Db,QACAU;QAEJ;IACF;IACA,OAAOI;AACT"}
|
|
1
|
+
{"version":3,"sources":["../../../../../../libs/tenant/runtime/src/lib/host-event-listeners.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { SiteAlert } from '@aglyn/aglyn/server'\n\n/**\n * WHO HEARS A HOST EVENT.\n *\n * A host event — a form submitted, a member signed up, a deal won — is raised\n * by the server door that performed the write, through `emitHostEvent`. What\n * runs because of it is not the runtime's business: an automation engine, an\n * integration, a marketplace plugin. Each registers a listener here and the\n * runtime fans every event out to all of them, knowing none by name.\n *\n * ## Registered by a call, at boot\n *\n * A listener is registered by a function the platform calls BY NAME — a\n * plugin's `serverDeclarations` entry, which both apps run once per process\n * from `instrumentation.ts`, and its API register functions, which the plugin\n * loader runs. Never by a bare `import './x'`: a bundler drops a module its\n * package does not list as a side effect, and jest does not, so a registration\n * that relies on one passes every spec and runs in no build (AGL-3025).\n *\n * Boot registration is what lets a core route that never loads a plugin — the\n * form submission, the page-view collector — still reach every listener.\n *\n * ## Isolated, and never thrown into the emitter\n *\n * The event has already happened: the submission is stored, the member exists.\n * A listener that throws is logged against its plugin and the others still\n * run, and the emitting request never sees the failure.\n */\n\n/** What an event carries into everything that listens for it. */\nexport type HostEventPayload = Record<string, string | number | boolean>\n\n/**\n * Who caused an event (AGL-3376): the console member who moved the deal, the\n * integration's key that added the contact, the visitor who submitted the\n * form, or the platform acting on its own (a Stripe webhook, a schedule).\n *\n * Kept OUT of the payload on purpose. The payload seeds a workflow's\n * expression scope and condition editor, and a site's automations have no\n * business reading a console member's address; this rides beside it, for\n * the record of who set a run off.\n */\nexport interface HostEventActor {\n kind: 'member' | 'visitor' | 'apiKey' | 'platform'\n /** The acting account, for a member. */\n uid?: string | null\n /** The address the actor had when they acted, when the door knew it. */\n email?: string | null\n /** The key's name, for an integration. */\n apiKeyName?: string | null\n}\n\n/** What rides beside an event's payload. */\nexport interface HostEventContext {\n /** Absent when the door that raised the event did not know. */\n actor?: HostEventActor\n /**\n * The site's recorded visit the event ends (AGL-3605): a form submission\n * names the visit its page was on, so a listener can tie that visit to the\n * person the door verified. Shape-checked by the door; absent when the site\n * records no visits or the visitor's consent did not allow one.\n */\n journeyId?: string\n}\n\nexport interface HostEventListener {\n /**\n * Runs whatever this plugin does when `event` happens on the site.\n *\n * Resolves the site alerts a request/response emitter shows its visitor —\n * a form submission returns them in its response — or nothing.\n */\n onEvent(\n hostId: string,\n event: string,\n payload: HostEventPayload,\n context?: HostEventContext,\n ): Promise<readonly SiteAlert[] | void>\n /**\n * Runs the server half of ONE page interaction, by id, that a published\n * page fired for a site event it evaluated itself — a scroll depth, a\n * click, exit intent. The page has already decided the trigger matched, so\n * the listener runs what that one interaction names rather than everything\n * listening for the event; a listener that does not own the id resolves\n * nothing.\n */\n onDispatch?(\n hostId: string,\n interactionId: string,\n event: string,\n payload: HostEventPayload,\n context?: HostEventContext,\n ): Promise<readonly SiteAlert[] | void>\n}\n\ninterface Registration {\n pluginId: string\n listener: HostEventListener\n}\n\nconst registrations: Registration[] = []\n\n/** Whether the no-listener warning has been printed in this process. */\nlet warnedEmpty = false\n\n/** A listener's answer as a list: nothing it said counts as no alerts. */\nfunction alertsOf(answer: readonly SiteAlert[] | void): SiteAlert[] {\n return Array.isArray(answer) ? [...answer] : []\n}\n\n/**\n * Subscribes a plugin to every host event. Registering again under the same\n * plugin id replaces the earlier listener in place, so a register function\n * the platform calls twice — boot, then the API surface — leaves one.\n */\nexport function registerHostEventListener(\n pluginId: string,\n listener: HostEventListener,\n): void {\n const id = String(pluginId ?? '').trim()\n if (!id) {\n throw new Error('a host event listener needs the id of the plugin it belongs to')\n }\n const at = registrations.findIndex((entry) => entry.pluginId === id)\n if (at >= 0) registrations[at] = { pluginId: id, listener }\n else registrations.push({ pluginId: id, listener })\n}\n\n/** The plugins listening, in registration order, for diagnostics. */\nexport function listHostEventListeners(): string[] {\n return registrations.map((entry) => entry.pluginId)\n}\n\n/** Test seam: forget every listener. */\nexport function resetHostEventListenersForTests(): void {\n registrations.length = 0\n warnedEmpty = false\n}\n\n/**\n * Hands one event to every listener, concurrently, and gathers the alerts\n * they produced. Never rejects.\n */\nexport async function runHostEventListeners(\n hostId: string,\n event: string,\n payload: HostEventPayload = {},\n context: HostEventContext = {},\n): Promise<SiteAlert[]> {\n if (!registrations.length) {\n /*\n * Said once per process rather than per event. No listener means the\n * plugins' server declarations never ran here — every automation on\n * every site served by this process is silent, and a line in the log is\n * the only place that is visible.\n */\n if (!warnedEmpty) {\n warnedEmpty = true\n console.warn(\n `[host-events] nothing is listening; \"${event}\" on ${hostId} ran no ` +\n 'automation. Listeners register from the plugins’ server ' +\n 'declarations at boot.',\n )\n }\n return []\n }\n const settled = await Promise.all(\n registrations.map(async ({ pluginId, listener }) => {\n try {\n return alertsOf(await listener.onEvent(hostId, event, payload, context))\n } catch (error) {\n console.error(`[host-events] ${pluginId} failed on ${event}`, hostId, error)\n return []\n }\n }),\n )\n return settled.flat()\n}\n\n/**\n * Hands one page-dispatched interaction to the listeners that dispatch, and\n * gathers the alerts it produced. Never rejects.\n */\nexport async function dispatchHostAutomation(\n hostId: string,\n interactionId: string,\n event: string,\n payload: HostEventPayload = {},\n context: HostEventContext = {},\n): Promise<SiteAlert[]> {\n const alerts: SiteAlert[] = []\n for (const { pluginId, listener } of registrations) {\n if (!listener.onDispatch) continue\n try {\n alerts.push(\n ...alertsOf(\n await listener.onDispatch(hostId, interactionId, event, payload, context),\n ),\n )\n } catch (error) {\n console.error(\n `[host-events] ${pluginId} failed to dispatch ${interactionId}`,\n hostId,\n error,\n )\n }\n }\n return alerts\n}\n"],"names":["registrations","warnedEmpty","alertsOf","answer","Array","isArray","registerHostEventListener","pluginId","listener","id","String","trim","Error","at","findIndex","entry","push","listHostEventListeners","map","resetHostEventListenersForTests","length","runHostEventListeners","hostId","event","payload","context","console","warn","settled","Promise","all","onEvent","error","flat","dispatchHostAutomation","interactionId","alerts","onDispatch"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GAuGD,MAAMA,gBAAgC,EAAE;AAExC,sEAAsE,GACtE,IAAIC,cAAc;AAElB,wEAAwE,GACxE,SAASC,SAASC,MAAmC;IACnD,OAAOC,MAAMC,OAAO,CAACF,UAAU;WAAIA;KAAO,GAAG,EAAE;AACjD;AAEA;;;;CAIC,GACD,OAAO,SAASG,0BACdC,QAAgB,EAChBC,QAA2B;IAE3B,MAAMC,KAAKC,OAAOH,mBAAAA,WAAY,IAAII,IAAI;IACtC,IAAI,CAACF,IAAI;QACP,MAAM,IAAIG,MAAM;IAClB;IACA,MAAMC,KAAKb,cAAcc,SAAS,CAAC,CAACC,QAAUA,MAAMR,QAAQ,KAAKE;IACjE,IAAII,MAAM,GAAGb,aAAa,CAACa,GAAG,GAAG;QAAEN,UAAUE;QAAID;IAAS;SACrDR,cAAcgB,IAAI,CAAC;QAAET,UAAUE;QAAID;IAAS;AACnD;AAEA,mEAAmE,GACnE,OAAO,SAASS;IACd,OAAOjB,cAAckB,GAAG,CAAC,CAACH,QAAUA,MAAMR,QAAQ;AACpD;AAEA,sCAAsC,GACtC,OAAO,SAASY;IACdnB,cAAcoB,MAAM,GAAG;IACvBnB,cAAc;AAChB;AAEA;;;CAGC,GACD,OAAO,eAAeoB,sBACpBC,MAAc,EACdC,KAAa,EACbC,UAA4B,CAAC,CAAC,EAC9BC,UAA4B,CAAC,CAAC;IAE9B,IAAI,CAACzB,cAAcoB,MAAM,EAAE;QACzB;;;;;KAKC,GACD,IAAI,CAACnB,aAAa;YAChBA,cAAc;YACdyB,QAAQC,IAAI,CACV,CAAC,qCAAqC,EAAEJ,MAAM,KAAK,EAAED,OAAO,QAAQ,CAAC,GACnE,6DACA;QAEN;QACA,OAAO,EAAE;IACX;IACA,MAAMM,UAAU,MAAMC,QAAQC,GAAG,CAC/B9B,cAAckB,GAAG,CAAC,OAAO,EAAEX,QAAQ,EAAEC,QAAQ,EAAE;QAC7C,IAAI;YACF,OAAON,SAAS,MAAMM,SAASuB,OAAO,CAACT,QAAQC,OAAOC,SAASC;QACjE,EAAE,OAAOO,OAAO;YACdN,QAAQM,KAAK,CAAC,CAAC,cAAc,EAAEzB,SAAS,WAAW,EAAEgB,OAAO,EAAED,QAAQU;YACtE,OAAO,EAAE;QACX;IACF;IAEF,OAAOJ,QAAQK,IAAI;AACrB;AAEA;;;CAGC,GACD,OAAO,eAAeC,uBACpBZ,MAAc,EACda,aAAqB,EACrBZ,KAAa,EACbC,UAA4B,CAAC,CAAC,EAC9BC,UAA4B,CAAC,CAAC;IAE9B,MAAMW,SAAsB,EAAE;IAC9B,KAAK,MAAM,EAAE7B,QAAQ,EAAEC,QAAQ,EAAE,IAAIR,cAAe;QAClD,IAAI,CAACQ,SAAS6B,UAAU,EAAE;QAC1B,IAAI;YACFD,OAAOpB,IAAI,IACNd,SACD,MAAMM,SAAS6B,UAAU,CAACf,QAAQa,eAAeZ,OAAOC,SAASC;QAGvE,EAAE,OAAOO,OAAO;YACdN,QAAQM,KAAK,CACX,CAAC,cAAc,EAAEzB,SAAS,oBAAoB,EAAE4B,eAAe,EAC/Db,QACAU;QAEJ;IACF;IACA,OAAOI;AACT"}
|