@endora-commerce/mod-pwa 0.100.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/LICENSE +21 -0
- package/README.md +63 -0
- package/dist/admin/api/pwa-client.d.ts +15 -0
- package/dist/admin/api/pwa-client.d.ts.map +1 -0
- package/dist/admin/api/pwa-client.js +56 -0
- package/dist/admin/api/pwa-client.js.map +1 -0
- package/dist/admin/components/PushAudienceRuleBuilder.d.ts +19 -0
- package/dist/admin/components/PushAudienceRuleBuilder.d.ts.map +1 -0
- package/dist/admin/components/PushAudienceRuleBuilder.js +211 -0
- package/dist/admin/components/PushAudienceRuleBuilder.js.map +1 -0
- package/dist/admin/index.d.ts +39 -0
- package/dist/admin/index.d.ts.map +1 -0
- package/dist/admin/index.js +61 -0
- package/dist/admin/index.js.map +1 -0
- package/dist/admin/pages/PwaPage.d.ts +16 -0
- package/dist/admin/pages/PwaPage.d.ts.map +1 -0
- package/dist/admin/pages/PwaPage.js +207 -0
- package/dist/admin/pages/PwaPage.js.map +1 -0
- package/dist/backend/entities/push-message-delivery.entity.d.ts +18 -0
- package/dist/backend/entities/push-message-delivery.entity.d.ts.map +1 -0
- package/dist/backend/entities/push-message-delivery.entity.js +68 -0
- package/dist/backend/entities/push-message-delivery.entity.js.map +1 -0
- package/dist/backend/entities/push-message.entity.d.ts +26 -0
- package/dist/backend/entities/push-message.entity.d.ts.map +1 -0
- package/dist/backend/entities/push-message.entity.js +102 -0
- package/dist/backend/entities/push-message.entity.js.map +1 -0
- package/dist/backend/entities/push-subscription.entity.d.ts +49 -0
- package/dist/backend/entities/push-subscription.entity.d.ts.map +1 -0
- package/dist/backend/entities/push-subscription.entity.js +117 -0
- package/dist/backend/entities/push-subscription.entity.js.map +1 -0
- package/dist/backend/entities/pwa-icon-rendition.entity.d.ts +21 -0
- package/dist/backend/entities/pwa-icon-rendition.entity.d.ts.map +1 -0
- package/dist/backend/entities/pwa-icon-rendition.entity.js +69 -0
- package/dist/backend/entities/pwa-icon-rendition.entity.js.map +1 -0
- package/dist/backend/index.d.ts +100 -0
- package/dist/backend/index.d.ts.map +1 -0
- package/dist/backend/index.js +107 -0
- package/dist/backend/index.js.map +1 -0
- package/dist/backend/plugin.d.ts +119 -0
- package/dist/backend/plugin.d.ts.map +1 -0
- package/dist/backend/plugin.js +109 -0
- package/dist/backend/plugin.js.map +1 -0
- package/dist/backend/request-actor.d.ts +24 -0
- package/dist/backend/request-actor.d.ts.map +1 -0
- package/dist/backend/request-actor.js +29 -0
- package/dist/backend/request-actor.js.map +1 -0
- package/dist/backend/routes.admin.d.ts +52 -0
- package/dist/backend/routes.admin.d.ts.map +1 -0
- package/dist/backend/routes.admin.js +222 -0
- package/dist/backend/routes.admin.js.map +1 -0
- package/dist/backend/routes.storefront.d.ts +29 -0
- package/dist/backend/routes.storefront.d.ts.map +1 -0
- package/dist/backend/routes.storefront.js +66 -0
- package/dist/backend/routes.storefront.js.map +1 -0
- package/dist/backend/services/cross-module-context.d.ts +90 -0
- package/dist/backend/services/cross-module-context.d.ts.map +1 -0
- package/dist/backend/services/cross-module-context.js +84 -0
- package/dist/backend/services/cross-module-context.js.map +1 -0
- package/dist/backend/services/providers/web-push-provider.d.ts +31 -0
- package/dist/backend/services/providers/web-push-provider.d.ts.map +1 -0
- package/dist/backend/services/providers/web-push-provider.js +72 -0
- package/dist/backend/services/providers/web-push-provider.js.map +1 -0
- package/dist/backend/services/push-audience-evaluator.d.ts +24 -0
- package/dist/backend/services/push-audience-evaluator.d.ts.map +1 -0
- package/dist/backend/services/push-audience-evaluator.js +29 -0
- package/dist/backend/services/push-audience-evaluator.js.map +1 -0
- package/dist/backend/services/push-delivery-queue.d.ts +14 -0
- package/dist/backend/services/push-delivery-queue.d.ts.map +1 -0
- package/dist/backend/services/push-delivery-queue.js +30 -0
- package/dist/backend/services/push-delivery-queue.js.map +1 -0
- package/dist/backend/services/push-event-subscriber.d.ts +86 -0
- package/dist/backend/services/push-event-subscriber.d.ts.map +1 -0
- package/dist/backend/services/push-event-subscriber.js +109 -0
- package/dist/backend/services/push-event-subscriber.js.map +1 -0
- package/dist/backend/services/push-message-service.d.ts +58 -0
- package/dist/backend/services/push-message-service.d.ts.map +1 -0
- package/dist/backend/services/push-message-service.js +145 -0
- package/dist/backend/services/push-message-service.js.map +1 -0
- package/dist/backend/services/push-provider-registry.d.ts +17 -0
- package/dist/backend/services/push-provider-registry.d.ts.map +1 -0
- package/dist/backend/services/push-provider-registry.js +32 -0
- package/dist/backend/services/push-provider-registry.js.map +1 -0
- package/dist/backend/services/push-subscription-service.d.ts +67 -0
- package/dist/backend/services/push-subscription-service.d.ts.map +1 -0
- package/dist/backend/services/push-subscription-service.js +165 -0
- package/dist/backend/services/push-subscription-service.js.map +1 -0
- package/dist/backend/services/pwa-config-resolver.d.ts +29 -0
- package/dist/backend/services/pwa-config-resolver.d.ts.map +1 -0
- package/dist/backend/services/pwa-config-resolver.js +92 -0
- package/dist/backend/services/pwa-config-resolver.js.map +1 -0
- package/dist/backend/services/pwa-icon-service.d.ts +44 -0
- package/dist/backend/services/pwa-icon-service.d.ts.map +1 -0
- package/dist/backend/services/pwa-icon-service.js +105 -0
- package/dist/backend/services/pwa-icon-service.js.map +1 -0
- package/dist/backend/workers/push-delivery-worker.d.ts +17 -0
- package/dist/backend/workers/push-delivery-worker.d.ts.map +1 -0
- package/dist/backend/workers/push-delivery-worker.js +105 -0
- package/dist/backend/workers/push-delivery-worker.js.map +1 -0
- package/dist/manifest.d.ts +184 -0
- package/dist/manifest.d.ts.map +1 -0
- package/dist/manifest.js +207 -0
- package/dist/manifest.js.map +1 -0
- package/dist/migrations/20260625T144228_pwa_init.d.ts +18 -0
- package/dist/migrations/20260625T144228_pwa_init.d.ts.map +1 -0
- package/dist/migrations/20260625T144228_pwa_init.js +105 -0
- package/dist/migrations/20260625T144228_pwa_init.js.map +1 -0
- package/dist/migrations/20260830T172022_pwa_organization_attribution.d.ts +102 -0
- package/dist/migrations/20260830T172022_pwa_organization_attribution.d.ts.map +1 -0
- package/dist/migrations/20260830T172022_pwa_organization_attribution.js +169 -0
- package/dist/migrations/20260830T172022_pwa_organization_attribution.js.map +1 -0
- package/dist/migrations/index.d.ts +28 -0
- package/dist/migrations/index.d.ts.map +1 -0
- package/dist/migrations/index.js +31 -0
- package/dist/migrations/index.js.map +1 -0
- package/docs/pwa.md +93 -0
- package/i18n/en.json +43 -0
- package/i18n/pl.json +43 -0
- package/package.json +105 -0
- package/tailwind.css +14 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Endora sp. z o.o. and the Endora Commerce contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
<!-- Generated by `pnpm --filter backend run manifests:generate`. Delete this line to take the file over; a README without it is never regenerated. -->
|
|
2
|
+
|
|
3
|
+
# @endora-commerce/mod-pwa
|
|
4
|
+
|
|
5
|
+
Installability, static-asset caching, controlled service-worker updates, and provider-agnostic push notifications for the storefront and admin.
|
|
6
|
+
|
|
7
|
+
## What this is
|
|
8
|
+
|
|
9
|
+
An **Endora Commerce module package**. Its module id is `pwa` — the identity of record in the platform's registries, in its migrations and in its setting, permission and translation codes.
|
|
10
|
+
|
|
11
|
+
A module is not imported by application code. The platform discovers the extension packages an instance has installed, reads the manifest on the root subpath and composes the module from it, so installing this package and starting the instance is the whole integration.
|
|
12
|
+
|
|
13
|
+
## Entry points
|
|
14
|
+
|
|
15
|
+
| Import | Contents |
|
|
16
|
+
| --- | --- |
|
|
17
|
+
| `@endora-commerce/mod-pwa` | the module manifest — its id, version, dependencies, settings and activation |
|
|
18
|
+
| `@endora-commerce/mod-pwa/admin` | the Admin UI contribution: the screens, navigation and palette actions it adds |
|
|
19
|
+
| `@endora-commerce/mod-pwa/backend` | the composition root the platform calls, with the entities, services, routes and workers it registers |
|
|
20
|
+
| `@endora-commerce/mod-pwa/migrations` | the module’s own schema migrations, in the order the platform runs them |
|
|
21
|
+
| `@endora-commerce/mod-pwa/tailwind.css` | the Tailwind source declaration for the admin code above |
|
|
22
|
+
|
|
23
|
+
## Depends on
|
|
24
|
+
|
|
25
|
+
Everything below is a **peer** dependency, so the application resolves exactly one copy of each — two copies of a host or of React are a runtime failure rather than a type error. An entry marked *optional* is needed only by the layers that use it.
|
|
26
|
+
|
|
27
|
+
**Endora packages**
|
|
28
|
+
|
|
29
|
+
- `@endora-commerce/admin-kit` — *optional*
|
|
30
|
+
- `@endora-commerce/contracts`
|
|
31
|
+
- `@endora-commerce/platform`
|
|
32
|
+
|
|
33
|
+
**Third-party**
|
|
34
|
+
|
|
35
|
+
- `@fastify/multipart` ^10
|
|
36
|
+
- `@mikro-orm/core` ^6
|
|
37
|
+
- `@mikro-orm/migrations` ^6
|
|
38
|
+
- `@mikro-orm/postgresql` ^6
|
|
39
|
+
- `bullmq` ^5
|
|
40
|
+
- `fastify` ^5
|
|
41
|
+
- `ioredis` ^5
|
|
42
|
+
- `lucide-react` ^1 — *optional*
|
|
43
|
+
- `react` ^19 — *optional*
|
|
44
|
+
- `sharp` ^0
|
|
45
|
+
- `web-push` ^3
|
|
46
|
+
- `zod` ^4
|
|
47
|
+
|
|
48
|
+
## What the tarball carries
|
|
49
|
+
|
|
50
|
+
- `dist/` — the compiled JavaScript and its type declarations
|
|
51
|
+
- `i18n/` — the translation bundles this package ships (`en`, `pl`), loaded by the platform
|
|
52
|
+
- `docs/` — the package’s own pages in the Endora Commerce documentation site
|
|
53
|
+
- `tailwind.css` — the Tailwind source declaration
|
|
54
|
+
|
|
55
|
+
## Install
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
pnpm add @endora-commerce/mod-pwa
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Licence
|
|
62
|
+
|
|
63
|
+
MIT — the text is in `LICENSE`, beside this file.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { CreatePushMessageRequest, CreatePushMessageResponse, PwaAdminConfig, PwaIconUploadResponse, PushSubscriptionStats, UpdatePwaConfigRequest, VapidKeyPairResponse } from '@endora-commerce/contracts';
|
|
2
|
+
export declare const pwaClient: {
|
|
3
|
+
getConfig(salesChannelId?: string | null): Promise<PwaAdminConfig>;
|
|
4
|
+
updateConfig(body: UpdatePwaConfigRequest): Promise<{
|
|
5
|
+
updated: number;
|
|
6
|
+
}>;
|
|
7
|
+
resetConfig(salesChannelId: string): Promise<{
|
|
8
|
+
reset: number;
|
|
9
|
+
}>;
|
|
10
|
+
generateVapid(): Promise<VapidKeyPairResponse>;
|
|
11
|
+
getSubscriptionStats(salesChannelId?: string | null): Promise<PushSubscriptionStats>;
|
|
12
|
+
sendMessage(body: CreatePushMessageRequest): Promise<CreatePushMessageResponse>;
|
|
13
|
+
uploadIcon(file: File, salesChannelId?: string | null): Promise<PwaIconUploadResponse>;
|
|
14
|
+
};
|
|
15
|
+
//# sourceMappingURL=pwa-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pwa-client.d.ts","sourceRoot":"","sources":["../../../src/admin/api/pwa-client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,wBAAwB,EACxB,yBAAyB,EACzB,cAAc,EACd,qBAAqB,EACrB,qBAAqB,EACrB,sBAAsB,EACtB,oBAAoB,EACrB,MAAM,4BAA4B,CAAC;AAyBpC,eAAO,MAAM,SAAS;+BACM,MAAM,GAAG,IAAI,GAAU,OAAO,CAAC,cAAc,CAAC;uBAIrD,sBAAsB,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;gCAI5C,MAAM,GAAG,OAAO,CAAC;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;qBAI9C,OAAO,CAAC,oBAAoB,CAAC;0CAIT,MAAM,GAAG,IAAI,GAAU,OAAO,CAAC,qBAAqB,CAAC;sBAMxE,wBAAwB,GAAG,OAAO,CAAC,yBAAyB,CAAC;qBAIxD,IAAI,mBAAkB,MAAM,GAAG,IAAI,GAAU,OAAO,CAAC,qBAAqB,CAAC;CAcnG,CAAC"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { apiBaseUrl, apiClient } from '@endora-commerce/admin-kit/lib';
|
|
2
|
+
/**
|
|
3
|
+
* Typed wrapper around `/api/v1/admin/pwa/*` (feature 046). Source-of-truth
|
|
4
|
+
* schemas live in `@endora-commerce/contracts`. Icon upload uses a raw `fetch` because the
|
|
5
|
+
* shared JSON api-client does not send multipart bodies.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* The API origin the multipart upload posts to.
|
|
9
|
+
*
|
|
10
|
+
* It read `import.meta.env.VITE_API_BASE_URL` with a `http://localhost:3001`
|
|
11
|
+
* fallback until feature 091's batch 10 moved this file into the package —
|
|
12
|
+
* a second copy of the two-branch resolution `apiClient` is already built from,
|
|
13
|
+
* and one this package's `tsconfig.ui.json` cannot compile, because it carries
|
|
14
|
+
* no `vite/client` types. Deliberately: a screen that reaches for the bundler's
|
|
15
|
+
* environment is reaching past the seam. This is the same repair batch 8 made
|
|
16
|
+
* to `SeoPage` and batch 9 to `AssetDetailDrawer`.
|
|
17
|
+
*/
|
|
18
|
+
const baseUrl = apiBaseUrl;
|
|
19
|
+
function channelQuery(salesChannelId) {
|
|
20
|
+
return salesChannelId ? `?salesChannelId=${encodeURIComponent(salesChannelId)}` : '';
|
|
21
|
+
}
|
|
22
|
+
export const pwaClient = {
|
|
23
|
+
getConfig(salesChannelId = null) {
|
|
24
|
+
return apiClient.get(`/api/v1/admin/pwa/config${channelQuery(salesChannelId)}`);
|
|
25
|
+
},
|
|
26
|
+
updateConfig(body) {
|
|
27
|
+
return apiClient.put(`/api/v1/admin/pwa/config`, body);
|
|
28
|
+
},
|
|
29
|
+
resetConfig(salesChannelId) {
|
|
30
|
+
return apiClient.post(`/api/v1/admin/pwa/config/reset`, { salesChannelId });
|
|
31
|
+
},
|
|
32
|
+
generateVapid() {
|
|
33
|
+
return apiClient.post(`/api/v1/admin/pwa/vapid/generate`, {});
|
|
34
|
+
},
|
|
35
|
+
getSubscriptionStats(salesChannelId = null) {
|
|
36
|
+
return apiClient.get(`/api/v1/admin/pwa/subscriptions${channelQuery(salesChannelId)}`);
|
|
37
|
+
},
|
|
38
|
+
sendMessage(body) {
|
|
39
|
+
return apiClient.post(`/api/v1/admin/pwa/messages`, body);
|
|
40
|
+
},
|
|
41
|
+
async uploadIcon(file, salesChannelId = null) {
|
|
42
|
+
const form = new FormData();
|
|
43
|
+
form.append('file', file);
|
|
44
|
+
const res = await fetch(`${baseUrl}/api/v1/admin/pwa/icon${channelQuery(salesChannelId)}`, {
|
|
45
|
+
method: 'POST',
|
|
46
|
+
credentials: 'include',
|
|
47
|
+
body: form,
|
|
48
|
+
});
|
|
49
|
+
if (!res.ok) {
|
|
50
|
+
const body = (await res.json().catch(() => null));
|
|
51
|
+
throw new Error(body?.error?.message ?? `Icon upload failed (${res.status})`);
|
|
52
|
+
}
|
|
53
|
+
return (await res.json());
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
//# sourceMappingURL=pwa-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pwa-client.js","sourceRoot":"","sources":["../../../src/admin/api/pwa-client.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,gCAAgC,CAAC;AACvE;;;;GAIG;AAEH;;;;;;;;;;GAUG;AACH,MAAM,OAAO,GAAG,UAAU,CAAC;AAE3B,SAAS,YAAY,CAAC,cAA6B;IACjD,OAAO,cAAc,CAAC,CAAC,CAAC,mBAAmB,kBAAkB,CAAC,cAAc,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;AACvF,CAAC;AAED,MAAM,CAAC,MAAM,SAAS,GAAG;IACvB,SAAS,CAAC,iBAAgC,IAAI;QAC5C,OAAO,SAAS,CAAC,GAAG,CAAiB,2BAA2B,YAAY,CAAC,cAAc,CAAC,EAAE,CAAC,CAAC;IAClG,CAAC;IAED,YAAY,CAAC,IAA4B;QACvC,OAAO,SAAS,CAAC,GAAG,CAAsB,0BAA0B,EAAE,IAAI,CAAC,CAAC;IAC9E,CAAC;IAED,WAAW,CAAC,cAAsB;QAChC,OAAO,SAAS,CAAC,IAAI,CAAoB,gCAAgC,EAAE,EAAE,cAAc,EAAE,CAAC,CAAC;IACjG,CAAC;IAED,aAAa;QACX,OAAO,SAAS,CAAC,IAAI,CAAuB,kCAAkC,EAAE,EAAE,CAAC,CAAC;IACtF,CAAC;IAED,oBAAoB,CAAC,iBAAgC,IAAI;QACvD,OAAO,SAAS,CAAC,GAAG,CAClB,kCAAkC,YAAY,CAAC,cAAc,CAAC,EAAE,CACjE,CAAC;IACJ,CAAC;IAED,WAAW,CAAC,IAA8B;QACxC,OAAO,SAAS,CAAC,IAAI,CAA4B,4BAA4B,EAAE,IAAI,CAAC,CAAC;IACvF,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,IAAU,EAAE,iBAAgC,IAAI;QAC/D,MAAM,IAAI,GAAG,IAAI,QAAQ,EAAE,CAAC;QAC5B,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QAC1B,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,OAAO,yBAAyB,YAAY,CAAC,cAAc,CAAC,EAAE,EAAE;YACzF,MAAM,EAAE,MAAM;YACd,WAAW,EAAE,SAAS;YACtB,IAAI,EAAE,IAAI;SACX,CAAC,CAAC;QACH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;YACZ,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAA4C,CAAC;YAC7F,MAAM,IAAI,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,OAAO,IAAI,uBAAuB,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC;QAChF,CAAC;QACD,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAA0B,CAAC;IACrD,CAAC;CACF,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { type ReactNode } from 'react';
|
|
2
|
+
import type { PushAudienceRule } from '@endora-commerce/contracts';
|
|
3
|
+
/**
|
|
4
|
+
* PushAudienceRuleBuilder — recursive editor over the AST defined in
|
|
5
|
+
* `@endora-commerce/contracts/pwa#PushAudienceRule`. It reuses the same Rule Builder UX as
|
|
6
|
+
* the price-list `ApplicationRuleBuilder`, scoped to push targeting criteria
|
|
7
|
+
* (Sales Channel, Customer Group, Organization, Customer List).
|
|
8
|
+
*
|
|
9
|
+
* The contract caps depth at 5 nested groups; the UI disables "add subgroup"
|
|
10
|
+
* once that limit is reached. Pickers are loaded lazily from
|
|
11
|
+
* `/api/v1/admin/pwa/rule-targets/*`. Fully controlled — the parent owns the
|
|
12
|
+
* AST and receives a new tree on every edit.
|
|
13
|
+
*/
|
|
14
|
+
export declare function PushAudienceRuleBuilder(props: {
|
|
15
|
+
value: PushAudienceRule;
|
|
16
|
+
onChange: (next: PushAudienceRule) => void;
|
|
17
|
+
disabled?: boolean;
|
|
18
|
+
}): ReactNode;
|
|
19
|
+
//# sourceMappingURL=PushAudienceRuleBuilder.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PushAudienceRuleBuilder.d.ts","sourceRoot":"","sources":["../../../src/admin/components/PushAudienceRuleBuilder.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAqD,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAY1F,OAAO,KAAK,EACV,gBAAgB,EAIjB,MAAM,4BAA4B,CAAC;AA8BpC;;;;;;;;;;GAUG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE;IAC7C,KAAK,EAAE,gBAAgB,CAAC;IACxB,QAAQ,EAAE,CAAC,IAAI,EAAE,gBAAgB,KAAK,IAAI,CAAC;IAC3C,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,GAAG,SAAS,CA6CZ"}
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
3
|
+
import { ChevronDown, ChevronRight, Plus, Trash2, ArrowDown, ArrowUp, CheckSquare, Square, Search, } from 'lucide-react';
|
|
4
|
+
import { apiClient, ApiError, normalize } from '@endora-commerce/admin-kit/lib';
|
|
5
|
+
const DEPTH_CAP = 5;
|
|
6
|
+
const CRITERION_TYPES = [
|
|
7
|
+
'salesChannel',
|
|
8
|
+
'customerGroup',
|
|
9
|
+
'organization',
|
|
10
|
+
'customer',
|
|
11
|
+
];
|
|
12
|
+
const CRITERION_LABEL = {
|
|
13
|
+
salesChannel: 'Sales Channel',
|
|
14
|
+
customerGroup: 'Customer Group',
|
|
15
|
+
organization: 'Organization',
|
|
16
|
+
customer: 'Customer List',
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* PushAudienceRuleBuilder — recursive editor over the AST defined in
|
|
20
|
+
* `@endora-commerce/contracts/pwa#PushAudienceRule`. It reuses the same Rule Builder UX as
|
|
21
|
+
* the price-list `ApplicationRuleBuilder`, scoped to push targeting criteria
|
|
22
|
+
* (Sales Channel, Customer Group, Organization, Customer List).
|
|
23
|
+
*
|
|
24
|
+
* The contract caps depth at 5 nested groups; the UI disables "add subgroup"
|
|
25
|
+
* once that limit is reached. Pickers are loaded lazily from
|
|
26
|
+
* `/api/v1/admin/pwa/rule-targets/*`. Fully controlled — the parent owns the
|
|
27
|
+
* AST and receives a new tree on every edit.
|
|
28
|
+
*/
|
|
29
|
+
export function PushAudienceRuleBuilder(props) {
|
|
30
|
+
const { value, onChange, disabled } = props;
|
|
31
|
+
const [pickers, setPickers] = useState(() => ({
|
|
32
|
+
salesChannel: { loading: false, options: [], error: null },
|
|
33
|
+
customerGroup: { loading: false, options: [], error: null },
|
|
34
|
+
organization: { loading: false, options: [], error: null },
|
|
35
|
+
customer: { loading: false, options: [], error: null },
|
|
36
|
+
}));
|
|
37
|
+
const attemptedRef = useRef(new Set());
|
|
38
|
+
const ensurePicker = useCallback(async (type) => {
|
|
39
|
+
if (attemptedRef.current.has(type))
|
|
40
|
+
return;
|
|
41
|
+
attemptedRef.current.add(type);
|
|
42
|
+
setPickers((prev) => ({ ...prev, [type]: { ...prev[type], loading: true } }));
|
|
43
|
+
try {
|
|
44
|
+
const options = await loadPicker(type);
|
|
45
|
+
setPickers((prev) => ({ ...prev, [type]: { loading: false, options, error: null } }));
|
|
46
|
+
}
|
|
47
|
+
catch (err) {
|
|
48
|
+
const message = err instanceof ApiError ? err.envelope.error.message : 'Failed to load options.';
|
|
49
|
+
setPickers((prev) => ({ ...prev, [type]: { ...prev[type], loading: false, error: message } }));
|
|
50
|
+
}
|
|
51
|
+
}, []);
|
|
52
|
+
return (_jsxs("div", { className: "b2b-col", style: { gap: 12 }, children: [_jsx("div", { className: "b2b-help", children: "Send to subscribers matching these criteria. An empty rule targets every active subscriber in this channel." }), _jsx(RuleNodeView, { node: value, depth: 0, disabled: disabled ?? false, pickers: pickers, ensurePicker: ensurePicker, onReplace: (next) => onChange(next ?? { kind: 'all' }) }), _jsxs("div", { className: "b2b-help", style: { marginTop: 4 }, children: ["Up to ", DEPTH_CAP, " nested groups. Anonymous subscribers only match Sales Channel criteria."] })] }));
|
|
53
|
+
}
|
|
54
|
+
function RuleNodeView(props) {
|
|
55
|
+
const { node, depth, disabled, pickers, ensurePicker, onReplace } = props;
|
|
56
|
+
if (node.kind === 'all') {
|
|
57
|
+
return (_jsx("div", { className: "b2b-card", style: { padding: 12, border: '1px dashed var(--border-color)', background: 'var(--surface-muted)' }, children: _jsxs("div", { className: "b2b-row", style: { alignItems: 'center', gap: 8 }, children: [_jsxs("div", { className: "b2b-grow", style: { fontSize: 13 }, children: [_jsx("strong", { children: "All subscribers." }), " Add a criterion to narrow the audience."] }), _jsxs("button", { type: "button", className: "b2b-btn b2b-btn--default b2b-btn--sm", disabled: disabled, onClick: () => onReplace({ kind: 'group', op: 'AND', children: [emptyCriterion()] }), children: [_jsx(Plus, { size: 12 }), " Add criterion"] })] }) }));
|
|
58
|
+
}
|
|
59
|
+
if (node.kind === 'criterion') {
|
|
60
|
+
return (_jsx(CriterionView, { node: node, disabled: disabled, pickers: pickers, ensurePicker: ensurePicker, onChange: (next) => onReplace(next), onDelete: () => onReplace(null) }));
|
|
61
|
+
}
|
|
62
|
+
return (_jsx(GroupView, { node: node, depth: depth, disabled: disabled, pickers: pickers, ensurePicker: ensurePicker, onChange: (next) => onReplace(next) }));
|
|
63
|
+
}
|
|
64
|
+
function GroupView(props) {
|
|
65
|
+
const { node, depth, disabled, pickers, ensurePicker, onChange } = props;
|
|
66
|
+
const [collapsed, setCollapsed] = useState(false);
|
|
67
|
+
const updateChild = (idx, next) => {
|
|
68
|
+
const children = [...node.children];
|
|
69
|
+
if (next === null)
|
|
70
|
+
children.splice(idx, 1);
|
|
71
|
+
else
|
|
72
|
+
children[idx] = next;
|
|
73
|
+
if (children.length === 0) {
|
|
74
|
+
onChange(depth === 0 ? { kind: 'all' } : null);
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
onChange({ ...node, children });
|
|
78
|
+
};
|
|
79
|
+
const moveChild = (idx, direction) => {
|
|
80
|
+
const newIdx = idx + direction;
|
|
81
|
+
if (newIdx < 0 || newIdx >= node.children.length)
|
|
82
|
+
return;
|
|
83
|
+
const children = [...node.children];
|
|
84
|
+
const [moved] = children.splice(idx, 1);
|
|
85
|
+
children.splice(newIdx, 0, moved);
|
|
86
|
+
onChange({ ...node, children });
|
|
87
|
+
};
|
|
88
|
+
const addCriterion = () => {
|
|
89
|
+
onChange({ ...node, children: [...node.children, emptyCriterion()] });
|
|
90
|
+
};
|
|
91
|
+
const addGroup = () => {
|
|
92
|
+
if (depth + 1 >= DEPTH_CAP)
|
|
93
|
+
return;
|
|
94
|
+
onChange({
|
|
95
|
+
...node,
|
|
96
|
+
children: [...node.children, { kind: 'group', op: 'AND', children: [emptyCriterion()] }],
|
|
97
|
+
});
|
|
98
|
+
};
|
|
99
|
+
const subgroupBlocked = depth + 1 >= DEPTH_CAP;
|
|
100
|
+
return (_jsxs("div", { className: "b2b-card", style: {
|
|
101
|
+
padding: 0,
|
|
102
|
+
border: '1px solid var(--border-color)',
|
|
103
|
+
background: depth === 0 ? 'var(--surface-color)' : 'var(--surface-muted)',
|
|
104
|
+
}, children: [_jsxs("div", { className: "b2b-row", style: {
|
|
105
|
+
padding: '8px 10px',
|
|
106
|
+
alignItems: 'center',
|
|
107
|
+
gap: 8,
|
|
108
|
+
borderBottom: collapsed ? 'none' : '1px solid var(--border-color)',
|
|
109
|
+
}, children: [_jsx("button", { type: "button", className: "b2b-btn b2b-btn--ghost b2b-btn--icon b2b-btn--sm", onClick: () => setCollapsed((v) => !v), children: collapsed ? _jsx(ChevronRight, { size: 13 }) : _jsx(ChevronDown, { size: 13 }) }), _jsx("div", { className: "b2b-row", style: { gap: 4 }, children: ['AND', 'OR'].map((op) => (_jsx("button", { type: "button", className: "b2b-btn b2b-btn--sm", disabled: disabled, onClick: () => onChange({ ...node, op }), style: {
|
|
110
|
+
background: node.op === op ? 'var(--primary-color)' : 'var(--surface-color)',
|
|
111
|
+
color: node.op === op ? '#fff' : 'var(--fg-default)',
|
|
112
|
+
border: `1px solid ${node.op === op ? 'var(--primary-color)' : 'var(--border-color)'}`,
|
|
113
|
+
fontWeight: node.op === op ? 600 : 400,
|
|
114
|
+
}, children: op }, op))) }), _jsxs("div", { className: "b2b-grow b2b-help", children: [node.children.length, " ", node.children.length === 1 ? 'rule' : 'rules', " \u00B7 depth ", depth + 1, "/", DEPTH_CAP] }), depth > 0 ? (_jsx("button", { type: "button", className: "b2b-btn b2b-btn--ghost b2b-btn--icon b2b-btn--sm", disabled: disabled, onClick: () => onChange(null), title: "Remove group", style: { color: 'hsl(8 80% 50%)' }, children: _jsx(Trash2, { size: 13 }) })) : null] }), !collapsed ? (_jsxs("div", { style: { padding: 10, display: 'flex', flexDirection: 'column', gap: 8 }, children: [node.children.map((child, idx) => (_jsxs("div", { className: "b2b-row", style: { alignItems: 'flex-start', gap: 6 }, children: [_jsxs("div", { className: "b2b-col", style: { gap: 2 }, children: [_jsx("button", { type: "button", className: "b2b-btn b2b-btn--ghost b2b-btn--icon b2b-btn--sm", disabled: disabled || idx === 0, onClick: () => moveChild(idx, -1), title: "Move up", children: _jsx(ArrowUp, { size: 12 }) }), _jsx("button", { type: "button", className: "b2b-btn b2b-btn--ghost b2b-btn--icon b2b-btn--sm", disabled: disabled || idx === node.children.length - 1, onClick: () => moveChild(idx, 1), title: "Move down", children: _jsx(ArrowDown, { size: 12 }) })] }), _jsx("div", { className: "b2b-grow", children: _jsx(RuleNodeView, { node: child, depth: depth + 1, disabled: disabled, pickers: pickers, ensurePicker: ensurePicker, onReplace: (next) => updateChild(idx, next) }) })] }, idx))), _jsxs("div", { className: "b2b-row", style: { gap: 6, marginTop: 4 }, children: [_jsxs("button", { type: "button", className: "b2b-btn b2b-btn--default b2b-btn--sm", disabled: disabled, onClick: addCriterion, children: [_jsx(Plus, { size: 12 }), " Add criterion"] }), _jsxs("button", { type: "button", className: "b2b-btn b2b-btn--default b2b-btn--sm", disabled: disabled || subgroupBlocked, title: subgroupBlocked ? `Maximum nesting depth (${DEPTH_CAP}) reached` : undefined, onClick: addGroup, children: [_jsx(Plus, { size: 12 }), " Add subgroup"] })] })] })) : null] }));
|
|
115
|
+
}
|
|
116
|
+
function CriterionView(props) {
|
|
117
|
+
const { node, disabled, pickers, ensurePicker, onChange, onDelete } = props;
|
|
118
|
+
const [open, setOpen] = useState(false);
|
|
119
|
+
useEffect(() => {
|
|
120
|
+
void ensurePicker(node.type);
|
|
121
|
+
}, [node.type, ensurePicker]);
|
|
122
|
+
const handleType = (type) => {
|
|
123
|
+
onChange({ kind: 'criterion', type, values: [] });
|
|
124
|
+
void ensurePicker(type);
|
|
125
|
+
};
|
|
126
|
+
const cache = pickers[node.type];
|
|
127
|
+
const labelMap = useMemo(() => {
|
|
128
|
+
const m = new Map();
|
|
129
|
+
for (const opt of cache.options)
|
|
130
|
+
m.set(opt.value, opt.label);
|
|
131
|
+
return m;
|
|
132
|
+
}, [cache.options]);
|
|
133
|
+
return (_jsxs("div", { className: "b2b-card", style: { padding: 8, border: '1px solid var(--border-color)', background: 'var(--surface-color)' }, children: [_jsxs("div", { className: "b2b-row", style: { gap: 8, alignItems: 'center' }, children: [_jsx("select", { className: "b2b-field", style: { width: 150 }, value: node.type, disabled: disabled, onChange: (e) => handleType(e.target.value), children: CRITERION_TYPES.map((ct) => (_jsx("option", { value: ct, children: CRITERION_LABEL[ct] }, ct))) }), _jsx("span", { className: "b2b-help", children: "\u2208" }), _jsx("button", { type: "button", className: "b2b-btn b2b-btn--default b2b-btn--sm b2b-grow", style: { justifyContent: 'flex-start', textAlign: 'left' }, disabled: disabled, onClick: () => {
|
|
134
|
+
setOpen((v) => !v);
|
|
135
|
+
void ensurePicker(node.type);
|
|
136
|
+
}, children: node.values.length === 0 ? (_jsxs("span", { className: "b2b-help", children: ["Pick ", CRITERION_LABEL[node.type].toLowerCase(), "\u2026"] })) : (_jsxs("span", { style: { fontSize: 12 }, children: [node.values
|
|
137
|
+
.slice(0, 3)
|
|
138
|
+
.map((v) => labelMap.get(v) ?? v)
|
|
139
|
+
.join(', '), node.values.length > 3 ? ` +${node.values.length - 3} more` : ''] })) }), _jsx("button", { type: "button", className: "b2b-btn b2b-btn--ghost b2b-btn--icon b2b-btn--sm", disabled: disabled, onClick: onDelete, title: "Remove criterion", style: { color: 'hsl(8 80% 50%)' }, children: _jsx(Trash2, { size: 13 }) })] }), open ? (_jsx(ValuePicker, { values: node.values, cache: cache, onClose: () => setOpen(false), onChange: (values) => onChange({ ...node, values }) })) : null] }));
|
|
140
|
+
}
|
|
141
|
+
function ValuePicker(props) {
|
|
142
|
+
const { values, cache, onChange } = props;
|
|
143
|
+
const [search, setSearch] = useState('');
|
|
144
|
+
const [draft, setDraft] = useState(new Set(values));
|
|
145
|
+
const toggle = (v) => {
|
|
146
|
+
setDraft((prev) => {
|
|
147
|
+
const next = new Set(prev);
|
|
148
|
+
if (next.has(v))
|
|
149
|
+
next.delete(v);
|
|
150
|
+
else
|
|
151
|
+
next.add(v);
|
|
152
|
+
return next;
|
|
153
|
+
});
|
|
154
|
+
};
|
|
155
|
+
const filtered = cache.options.filter((opt) => {
|
|
156
|
+
const q = normalize(search);
|
|
157
|
+
if (q === '')
|
|
158
|
+
return true;
|
|
159
|
+
return normalize(opt.label).includes(q) || normalize(opt.value).includes(q);
|
|
160
|
+
});
|
|
161
|
+
const apply = () => {
|
|
162
|
+
onChange(Array.from(draft));
|
|
163
|
+
props.onClose();
|
|
164
|
+
};
|
|
165
|
+
return (_jsxs("div", { style: {
|
|
166
|
+
marginTop: 8,
|
|
167
|
+
padding: 8,
|
|
168
|
+
border: '1px solid var(--border-color)',
|
|
169
|
+
borderRadius: 6,
|
|
170
|
+
background: 'var(--surface-muted)',
|
|
171
|
+
}, children: [_jsxs("div", { className: "b2b-input-wrap", style: { marginBottom: 6 }, children: [_jsx(Search, { size: 13, className: "lead" }), _jsx("input", { autoFocus: true, className: "b2b-field b2b-field--addon", placeholder: "Search\u2026", value: search, onChange: (e) => setSearch(e.target.value) })] }), cache.error ? (_jsx("div", { className: "b2b-help", style: { color: 'hsl(8 80% 40%)' }, children: cache.error })) : cache.loading ? (_jsx("div", { className: "b2b-help", children: "Loading\u2026" })) : filtered.length === 0 ? (_jsx("div", { className: "b2b-help", children: "No options." })) : (_jsx("ul", { style: { margin: 0, padding: 0, listStyle: 'none', maxHeight: 220, overflow: 'auto' }, children: filtered.slice(0, 200).map((opt) => {
|
|
172
|
+
const isOn = draft.has(opt.value);
|
|
173
|
+
return (_jsxs("li", { onClick: () => toggle(opt.value), style: {
|
|
174
|
+
padding: '4px 6px',
|
|
175
|
+
cursor: 'pointer',
|
|
176
|
+
display: 'flex',
|
|
177
|
+
alignItems: 'center',
|
|
178
|
+
gap: 6,
|
|
179
|
+
fontSize: 12,
|
|
180
|
+
}, children: [isOn ? _jsx(CheckSquare, { size: 13 }) : _jsx(Square, { size: 13 }), _jsx("span", { children: opt.label }), opt.hint ? _jsxs("span", { className: "b2b-help", children: ["\u00B7 ", opt.hint] }) : null] }, opt.value));
|
|
181
|
+
}) })), _jsxs("div", { className: "b2b-row", style: { marginTop: 8, gap: 6, justifyContent: 'flex-end' }, children: [_jsx("button", { type: "button", className: "b2b-btn b2b-btn--ghost b2b-btn--sm", onClick: props.onClose, children: "Cancel" }), _jsxs("button", { type: "button", className: "b2b-btn b2b-btn--primary b2b-btn--sm", onClick: apply, children: ["Apply (", draft.size, ")"] })] })] }));
|
|
182
|
+
}
|
|
183
|
+
function emptyCriterion() {
|
|
184
|
+
return { kind: 'criterion', type: 'salesChannel', values: [] };
|
|
185
|
+
}
|
|
186
|
+
function flattenName(name, fallback) {
|
|
187
|
+
if (typeof name === 'string')
|
|
188
|
+
return name || fallback;
|
|
189
|
+
return name['en-US'] ?? name['pl-PL'] ?? Object.values(name)[0] ?? fallback;
|
|
190
|
+
}
|
|
191
|
+
async function loadPicker(type) {
|
|
192
|
+
switch (type) {
|
|
193
|
+
case 'salesChannel': {
|
|
194
|
+
const res = await apiClient.get('/api/v1/admin/pwa/rule-targets/sales-channels');
|
|
195
|
+
return res.data.items.map((i) => ({ value: i.id, label: flattenName(i.name, i.code), hint: i.code }));
|
|
196
|
+
}
|
|
197
|
+
case 'customerGroup': {
|
|
198
|
+
const res = await apiClient.get('/api/v1/admin/pwa/rule-targets/customer-groups');
|
|
199
|
+
return res.data.items.map((i) => ({ value: i.id, label: flattenName(i.name, i.code), hint: i.code }));
|
|
200
|
+
}
|
|
201
|
+
case 'organization': {
|
|
202
|
+
const res = await apiClient.get('/api/v1/admin/pwa/rule-targets/organizations?limit=200');
|
|
203
|
+
return res.data.items.map((i) => ({ value: i.id, label: flattenName(i.name, i.taxId), hint: i.taxId }));
|
|
204
|
+
}
|
|
205
|
+
case 'customer': {
|
|
206
|
+
const res = await apiClient.get('/api/v1/admin/pwa/rule-targets/customers?limit=200');
|
|
207
|
+
return res.data.items.map((i) => ({ value: i.id, label: i.email }));
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
//# sourceMappingURL=PushAudienceRuleBuilder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PushAudienceRuleBuilder.js","sourceRoot":"","sources":["../../../src/admin/components/PushAudienceRuleBuilder.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAkB,MAAM,OAAO,CAAC;AAC1F,OAAO,EACL,WAAW,EACX,YAAY,EACZ,IAAI,EACJ,MAAM,EACN,SAAS,EACT,OAAO,EACP,WAAW,EACX,MAAM,EACN,MAAM,GACP,MAAM,cAAc,CAAC;AAOtB,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,gCAAgC,CAAC;AAChF,MAAM,SAAS,GAAG,CAAC,CAAC;AAEpB,MAAM,eAAe,GAAgC;IACnD,cAAc;IACd,eAAe;IACf,cAAc;IACd,UAAU;CACX,CAAC;AAEF,MAAM,eAAe,GAA8C;IACjE,YAAY,EAAE,eAAe;IAC7B,aAAa,EAAE,gBAAgB;IAC/B,YAAY,EAAE,cAAc;IAC5B,QAAQ,EAAE,eAAe;CAC1B,CAAC;AAcF;;;;;;;;;;GAUG;AACH,MAAM,UAAU,uBAAuB,CAAC,KAIvC;IACC,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,GAAG,KAAK,CAAC;IAC5C,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAiD,GAAG,EAAE,CAAC,CAAC;QAC5F,YAAY,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE;QAC1D,aAAa,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE;QAC3D,YAAY,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE;QAC1D,QAAQ,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE;KACvD,CAAC,CAAC,CAAC;IAEJ,MAAM,YAAY,GAAG,MAAM,CAAiC,IAAI,GAAG,EAAE,CAAC,CAAC;IAEvE,MAAM,YAAY,GAAG,WAAW,CAAC,KAAK,EAAE,IAA+B,EAAiB,EAAE;QACxF,IAAI,YAAY,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC;YAAE,OAAO;QAC3C,YAAY,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAC/B,UAAU,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,IAAI,EAAE,CAAC,IAAI,CAAC,EAAE,EAAE,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC;QAC9E,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,UAAU,CAAC,IAAI,CAAC,CAAC;YACvC,UAAU,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,IAAI,EAAE,CAAC,IAAI,CAAC,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC;QACxF,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,OAAO,GAAG,GAAG,YAAY,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,yBAAyB,CAAC;YACjG,UAAU,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,IAAI,EAAE,CAAC,IAAI,CAAC,EAAE,EAAE,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;QACjG,CAAC;IACH,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,OAAO,CACL,eAAK,SAAS,EAAC,SAAS,EAAC,KAAK,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,aACzC,cAAK,SAAS,EAAC,UAAU,4HAGnB,EAEN,KAAC,YAAY,IACX,IAAI,EAAE,KAAK,EACX,KAAK,EAAE,CAAC,EACR,QAAQ,EAAE,QAAQ,IAAI,KAAK,EAC3B,OAAO,EAAE,OAAO,EAChB,YAAY,EAAE,YAAY,EAC1B,SAAS,EAAE,CAAC,IAAI,EAAQ,EAAE,CAAC,QAAQ,CAAC,IAAI,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,GAC5D,EAEF,eAAK,SAAS,EAAC,UAAU,EAAC,KAAK,EAAE,EAAE,SAAS,EAAE,CAAC,EAAE,uBACxC,SAAS,gFACZ,IACF,CACP,CAAC;AACJ,CAAC;AAED,SAAS,YAAY,CAAC,KAOrB;IACC,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,GAAG,KAAK,CAAC;IAE1E,IAAI,IAAI,CAAC,IAAI,KAAK,KAAK,EAAE,CAAC;QACxB,OAAO,CACL,cACE,SAAS,EAAC,UAAU,EACpB,KAAK,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,EAAE,gCAAgC,EAAE,UAAU,EAAE,sBAAsB,EAAE,YAEpG,eAAK,SAAS,EAAC,SAAS,EAAC,KAAK,EAAE,EAAE,UAAU,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,EAAE,aAC9D,eAAK,SAAS,EAAC,UAAU,EAAC,KAAK,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,aAC/C,gDAAiC,gDAC7B,EACN,kBACE,IAAI,EAAC,QAAQ,EACb,SAAS,EAAC,sCAAsC,EAChD,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,GAAS,EAAE,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,cAAc,EAAE,CAAC,EAAE,CAAC,aAE1F,KAAC,IAAI,IAAC,IAAI,EAAE,EAAE,GAAI,sBACX,IACL,GACF,CACP,CAAC;IACJ,CAAC;IAED,IAAI,IAAI,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;QAC9B,OAAO,CACL,KAAC,aAAa,IACZ,IAAI,EAAE,IAAI,EACV,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,OAAO,EAChB,YAAY,EAAE,YAAY,EAC1B,QAAQ,EAAE,CAAC,IAAI,EAAQ,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,EACzC,QAAQ,EAAE,GAAS,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,GACrC,CACH,CAAC;IACJ,CAAC;IAED,OAAO,CACL,KAAC,SAAS,IACR,IAAI,EAAE,IAAI,EACV,KAAK,EAAE,KAAK,EACZ,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,OAAO,EAChB,YAAY,EAAE,YAAY,EAC1B,QAAQ,EAAE,CAAC,IAAI,EAAQ,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,GACzC,CACH,CAAC;AACJ,CAAC;AAED,SAAS,SAAS,CAAC,KAOlB;IACC,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,GAAG,KAAK,CAAC;IACzE,MAAM,CAAC,SAAS,EAAE,YAAY,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAElD,MAAM,WAAW,GAAG,CAAC,GAAW,EAAE,IAA6B,EAAQ,EAAE;QACvE,MAAM,QAAQ,GAAG,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC;QACpC,IAAI,IAAI,KAAK,IAAI;YAAE,QAAQ,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;;YACtC,QAAQ,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC;QAC1B,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC1B,QAAQ,CAAC,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;YAC/C,OAAO;QACT,CAAC;QACD,QAAQ,CAAC,EAAE,GAAG,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC;IAClC,CAAC,CAAC;IAEF,MAAM,SAAS,GAAG,CAAC,GAAW,EAAE,SAAiB,EAAQ,EAAE;QACzD,MAAM,MAAM,GAAG,GAAG,GAAG,SAAS,CAAC;QAC/B,IAAI,MAAM,GAAG,CAAC,IAAI,MAAM,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM;YAAE,OAAO;QACzD,MAAM,QAAQ,GAAG,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC;QACpC,MAAM,CAAC,KAAK,CAAC,GAAG,QAAQ,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;QACxC,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,KAAM,CAAC,CAAC;QACnC,QAAQ,CAAC,EAAE,GAAG,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC;IAClC,CAAC,CAAC;IAEF,MAAM,YAAY,GAAG,GAAS,EAAE;QAC9B,QAAQ,CAAC,EAAE,GAAG,IAAI,EAAE,QAAQ,EAAE,CAAC,GAAG,IAAI,CAAC,QAAQ,EAAE,cAAc,EAAE,CAAC,EAAE,CAAC,CAAC;IACxE,CAAC,CAAC;IAEF,MAAM,QAAQ,GAAG,GAAS,EAAE;QAC1B,IAAI,KAAK,GAAG,CAAC,IAAI,SAAS;YAAE,OAAO;QACnC,QAAQ,CAAC;YACP,GAAG,IAAI;YACP,QAAQ,EAAE,CAAC,GAAG,IAAI,CAAC,QAAQ,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,cAAc,EAAE,CAAC,EAAE,CAAC;SACzF,CAAC,CAAC;IACL,CAAC,CAAC;IAEF,MAAM,eAAe,GAAG,KAAK,GAAG,CAAC,IAAI,SAAS,CAAC;IAE/C,OAAO,CACL,eACE,SAAS,EAAC,UAAU,EACpB,KAAK,EAAE;YACL,OAAO,EAAE,CAAC;YACV,MAAM,EAAE,+BAA+B;YACvC,UAAU,EAAE,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,sBAAsB;SAC1E,aAED,eACE,SAAS,EAAC,SAAS,EACnB,KAAK,EAAE;oBACL,OAAO,EAAE,UAAU;oBACnB,UAAU,EAAE,QAAQ;oBACpB,GAAG,EAAE,CAAC;oBACN,YAAY,EAAE,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,+BAA+B;iBACnE,aAED,iBACE,IAAI,EAAC,QAAQ,EACb,SAAS,EAAC,kDAAkD,EAC5D,OAAO,EAAE,GAAS,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,YAE3C,SAAS,CAAC,CAAC,CAAC,KAAC,YAAY,IAAC,IAAI,EAAE,EAAE,GAAI,CAAC,CAAC,CAAC,KAAC,WAAW,IAAC,IAAI,EAAE,EAAE,GAAI,GAC5D,EACT,cAAK,SAAS,EAAC,SAAS,EAAC,KAAK,EAAE,EAAE,GAAG,EAAE,CAAC,EAAE,YACtC,CAAC,KAAK,EAAE,IAAI,CAAW,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CACpC,iBAEE,IAAI,EAAC,QAAQ,EACb,SAAS,EAAC,qBAAqB,EAC/B,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,GAAS,EAAE,CAAC,QAAQ,CAAC,EAAE,GAAG,IAAI,EAAE,EAAE,EAAE,CAAC,EAC9C,KAAK,EAAE;gCACL,UAAU,EAAE,IAAI,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,sBAAsB;gCAC5E,KAAK,EAAE,IAAI,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,mBAAmB;gCACpD,MAAM,EAAE,aAAa,IAAI,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,qBAAqB,EAAE;gCACtF,UAAU,EAAE,IAAI,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG;6BACvC,YAEA,EAAE,IAZE,EAAE,CAaA,CACV,CAAC,GACE,EACN,eAAK,SAAS,EAAC,mBAAmB,aAC/B,IAAI,CAAC,QAAQ,CAAC,MAAM,OAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,oBAAW,KAAK,GAAG,CAAC,OAAG,SAAS,IACjG,EACL,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CACX,iBACE,IAAI,EAAC,QAAQ,EACb,SAAS,EAAC,kDAAkD,EAC5D,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,GAAS,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,EACnC,KAAK,EAAC,cAAc,EACpB,KAAK,EAAE,EAAE,KAAK,EAAE,gBAAgB,EAAE,YAElC,KAAC,MAAM,IAAC,IAAI,EAAE,EAAE,GAAI,GACb,CACV,CAAC,CAAC,CAAC,IAAI,IACJ,EAEL,CAAC,SAAS,CAAC,CAAC,CAAC,CACZ,eAAK,KAAK,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,EAAE,aAC1E,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE,CAAC,CACjC,eAAe,SAAS,EAAC,SAAS,EAAC,KAAK,EAAE,EAAE,UAAU,EAAE,YAAY,EAAE,GAAG,EAAE,CAAC,EAAE,aAC5E,eAAK,SAAS,EAAC,SAAS,EAAC,KAAK,EAAE,EAAE,GAAG,EAAE,CAAC,EAAE,aACxC,iBACE,IAAI,EAAC,QAAQ,EACb,SAAS,EAAC,kDAAkD,EAC5D,QAAQ,EAAE,QAAQ,IAAI,GAAG,KAAK,CAAC,EAC/B,OAAO,EAAE,GAAS,EAAE,CAAC,SAAS,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,EACvC,KAAK,EAAC,SAAS,YAEf,KAAC,OAAO,IAAC,IAAI,EAAE,EAAE,GAAI,GACd,EACT,iBACE,IAAI,EAAC,QAAQ,EACb,SAAS,EAAC,kDAAkD,EAC5D,QAAQ,EAAE,QAAQ,IAAI,GAAG,KAAK,IAAI,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,EACtD,OAAO,EAAE,GAAS,EAAE,CAAC,SAAS,CAAC,GAAG,EAAE,CAAC,CAAC,EACtC,KAAK,EAAC,WAAW,YAEjB,KAAC,SAAS,IAAC,IAAI,EAAE,EAAE,GAAI,GAChB,IACL,EACN,cAAK,SAAS,EAAC,UAAU,YACvB,KAAC,YAAY,IACX,IAAI,EAAE,KAAK,EACX,KAAK,EAAE,KAAK,GAAG,CAAC,EAChB,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,OAAO,EAChB,YAAY,EAAE,YAAY,EAC1B,SAAS,EAAE,CAAC,IAAI,EAAQ,EAAE,CAAC,WAAW,CAAC,GAAG,EAAE,IAAI,CAAC,GACjD,GACE,KA9BE,GAAG,CA+BP,CACP,CAAC,EACF,eAAK,SAAS,EAAC,SAAS,EAAC,KAAK,EAAE,EAAE,GAAG,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,aACtD,kBACE,IAAI,EAAC,QAAQ,EACb,SAAS,EAAC,sCAAsC,EAChD,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,YAAY,aAErB,KAAC,IAAI,IAAC,IAAI,EAAE,EAAE,GAAI,sBACX,EACT,kBACE,IAAI,EAAC,QAAQ,EACb,SAAS,EAAC,sCAAsC,EAChD,QAAQ,EAAE,QAAQ,IAAI,eAAe,EACrC,KAAK,EAAE,eAAe,CAAC,CAAC,CAAC,0BAA0B,SAAS,WAAW,CAAC,CAAC,CAAC,SAAS,EACnF,OAAO,EAAE,QAAQ,aAEjB,KAAC,IAAI,IAAC,IAAI,EAAE,EAAE,GAAI,qBACX,IACL,IACF,CACP,CAAC,CAAC,CAAC,IAAI,IACJ,CACP,CAAC;AACJ,CAAC;AAED,SAAS,aAAa,CAAC,KAOtB;IACC,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,QAAQ,EAAE,GAAG,KAAK,CAAC;IAC5E,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAExC,SAAS,CAAC,GAAG,EAAE;QACb,KAAK,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC/B,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC,CAAC;IAE9B,MAAM,UAAU,GAAG,CAAC,IAA+B,EAAQ,EAAE;QAC3D,QAAQ,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,CAAC;QAClD,KAAK,YAAY,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC,CAAC;IAEF,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACjC,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,EAAE;QAC5B,MAAM,CAAC,GAAG,IAAI,GAAG,EAAkB,CAAC;QACpC,KAAK,MAAM,GAAG,IAAI,KAAK,CAAC,OAAO;YAAE,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC;QAC7D,OAAO,CAAC,CAAC;IACX,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;IAEpB,OAAO,CACL,eACE,SAAS,EAAC,UAAU,EACpB,KAAK,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,MAAM,EAAE,+BAA+B,EAAE,UAAU,EAAE,sBAAsB,EAAE,aAElG,eAAK,SAAS,EAAC,SAAS,EAAC,KAAK,EAAE,EAAE,GAAG,EAAE,CAAC,EAAE,UAAU,EAAE,QAAQ,EAAE,aAC9D,iBACE,SAAS,EAAC,WAAW,EACrB,KAAK,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,EACrB,KAAK,EAAE,IAAI,CAAC,IAAI,EAChB,QAAQ,EAAE,QAAQ,EAClB,QAAQ,EAAE,CAAC,CAAC,EAAQ,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,KAAkC,CAAC,YAE7E,eAAe,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAC3B,iBAAiB,KAAK,EAAE,EAAE,YACvB,eAAe,CAAC,EAAE,CAAC,IADT,EAAE,CAEN,CACV,CAAC,GACK,EACT,eAAM,SAAS,EAAC,UAAU,uBAAS,EACnC,iBACE,IAAI,EAAC,QAAQ,EACb,SAAS,EAAC,+CAA+C,EACzD,KAAK,EAAE,EAAE,cAAc,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,EAAE,EAC1D,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,GAAS,EAAE;4BAClB,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;4BACnB,KAAK,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;wBAC/B,CAAC,YAEA,IAAI,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,CAC1B,gBAAM,SAAS,EAAC,UAAU,sBAAO,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,cAAS,CACnF,CAAC,CAAC,CAAC,CACF,gBAAM,KAAK,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,aAC1B,IAAI,CAAC,MAAM;qCACT,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;qCACX,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;qCAChC,IAAI,CAAC,IAAI,CAAC,EACZ,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,IAC5D,CACR,GACM,EACT,iBACE,IAAI,EAAC,QAAQ,EACb,SAAS,EAAC,kDAAkD,EAC5D,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,QAAQ,EACjB,KAAK,EAAC,kBAAkB,EACxB,KAAK,EAAE,EAAE,KAAK,EAAE,gBAAgB,EAAE,YAElC,KAAC,MAAM,IAAC,IAAI,EAAE,EAAE,GAAI,GACb,IACL,EAEL,IAAI,CAAC,CAAC,CAAC,CACN,KAAC,WAAW,IACV,MAAM,EAAE,IAAI,CAAC,MAAM,EACnB,KAAK,EAAE,KAAK,EACZ,OAAO,EAAE,GAAS,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,EACnC,QAAQ,EAAE,CAAC,MAAM,EAAQ,EAAE,CAAC,QAAQ,CAAC,EAAE,GAAG,IAAI,EAAE,MAAM,EAAE,CAAC,GACzD,CACH,CAAC,CAAC,CAAC,IAAI,IACJ,CACP,CAAC;AACJ,CAAC;AAED,SAAS,WAAW,CAAC,KAKpB;IACC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,KAAK,CAAC;IAC1C,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAC;IACzC,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAc,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;IAEjE,MAAM,MAAM,GAAG,CAAC,CAAS,EAAQ,EAAE;QACjC,QAAQ,CAAC,CAAC,IAAI,EAAE,EAAE;YAChB,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,CAAC;YAC3B,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;gBAAE,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;;gBAC3B,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;YACjB,OAAO,IAAI,CAAC;QACd,CAAC,CAAC,CAAC;IACL,CAAC,CAAC;IAEF,MAAM,QAAQ,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE;QAC5C,MAAM,CAAC,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC;QAC5B,IAAI,CAAC,KAAK,EAAE;YAAE,OAAO,IAAI,CAAC;QAC1B,OAAO,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;IAC9E,CAAC,CAAC,CAAC;IAEH,MAAM,KAAK,GAAG,GAAS,EAAE;QACvB,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;QAC5B,KAAK,CAAC,OAAO,EAAE,CAAC;IAClB,CAAC,CAAC;IAEF,OAAO,CACL,eACE,KAAK,EAAE;YACL,SAAS,EAAE,CAAC;YACZ,OAAO,EAAE,CAAC;YACV,MAAM,EAAE,+BAA+B;YACvC,YAAY,EAAE,CAAC;YACf,UAAU,EAAE,sBAAsB;SACnC,aAED,eAAK,SAAS,EAAC,gBAAgB,EAAC,KAAK,EAAE,EAAE,YAAY,EAAE,CAAC,EAAE,aACxD,KAAC,MAAM,IAAC,IAAI,EAAE,EAAE,EAAE,SAAS,EAAC,MAAM,GAAG,EACrC,gBACE,SAAS,QACT,SAAS,EAAC,4BAA4B,EACtC,WAAW,EAAC,cAAS,EACrB,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,CAAC,CAAC,EAAQ,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,GAChD,IACE,EACL,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CACb,cAAK,SAAS,EAAC,UAAU,EAAC,KAAK,EAAE,EAAE,KAAK,EAAE,gBAAgB,EAAE,YACzD,KAAK,CAAC,KAAK,GACR,CACP,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAClB,cAAK,SAAS,EAAC,UAAU,8BAAe,CACzC,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,CAC1B,cAAK,SAAS,EAAC,UAAU,4BAAkB,CAC5C,CAAC,CAAC,CAAC,CACF,aAAI,KAAK,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,EAAE,YACtF,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE;oBAClC,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;oBAClC,OAAO,CACL,cAEE,OAAO,EAAE,GAAS,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,EACtC,KAAK,EAAE;4BACL,OAAO,EAAE,SAAS;4BAClB,MAAM,EAAE,SAAS;4BACjB,OAAO,EAAE,MAAM;4BACf,UAAU,EAAE,QAAQ;4BACpB,GAAG,EAAE,CAAC;4BACN,QAAQ,EAAE,EAAE;yBACb,aAEA,IAAI,CAAC,CAAC,CAAC,KAAC,WAAW,IAAC,IAAI,EAAE,EAAE,GAAI,CAAC,CAAC,CAAC,KAAC,MAAM,IAAC,IAAI,EAAE,EAAE,GAAI,EACxD,yBAAO,GAAG,CAAC,KAAK,GAAQ,EACvB,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,gBAAM,SAAS,EAAC,UAAU,wBAAI,GAAG,CAAC,IAAI,IAAQ,CAAC,CAAC,CAAC,IAAI,KAb5D,GAAG,CAAC,KAAK,CAcX,CACN,CAAC;gBACJ,CAAC,CAAC,GACC,CACN,EACD,eAAK,SAAS,EAAC,SAAS,EAAC,KAAK,EAAE,EAAE,SAAS,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,cAAc,EAAE,UAAU,EAAE,aAClF,iBAAQ,IAAI,EAAC,QAAQ,EAAC,SAAS,EAAC,oCAAoC,EAAC,OAAO,EAAE,KAAK,CAAC,OAAO,uBAElF,EACT,kBAAQ,IAAI,EAAC,QAAQ,EAAC,SAAS,EAAC,sCAAsC,EAAC,OAAO,EAAE,KAAK,wBAC3E,KAAK,CAAC,IAAI,SACX,IACL,IACF,CACP,CAAC;AACJ,CAAC;AAED,SAAS,cAAc;IACrB,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,cAAc,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;AACjE,CAAC;AAID,SAAS,WAAW,CAAC,IAAmB,EAAE,QAAgB;IACxD,IAAI,OAAO,IAAI,KAAK,QAAQ;QAAE,OAAO,IAAI,IAAI,QAAQ,CAAC;IACtD,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,QAAQ,CAAC;AAC9E,CAAC;AAED,KAAK,UAAU,UAAU,CAAC,IAA+B;IACvD,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,cAAc,CAAC,CAAC,CAAC;YACpB,MAAM,GAAG,GAAG,MAAM,SAAS,CAAC,GAAG,CAC7B,+CAA+C,CAChD,CAAC;YACF,OAAO,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,EAAE,EAAE,KAAK,EAAE,WAAW,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;QACxG,CAAC;QACD,KAAK,eAAe,CAAC,CAAC,CAAC;YACrB,MAAM,GAAG,GAAG,MAAM,SAAS,CAAC,GAAG,CAC7B,gDAAgD,CACjD,CAAC;YACF,OAAO,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,EAAE,EAAE,KAAK,EAAE,WAAW,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;QACxG,CAAC;QACD,KAAK,cAAc,CAAC,CAAC,CAAC;YACpB,MAAM,GAAG,GAAG,MAAM,SAAS,CAAC,GAAG,CAC7B,wDAAwD,CACzD,CAAC;YACF,OAAO,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,EAAE,EAAE,KAAK,EAAE,WAAW,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;QAC1G,CAAC;QACD,KAAK,UAAU,CAAC,CAAC,CAAC;YAChB,MAAM,GAAG,GAAG,MAAM,SAAS,CAAC,GAAG,CAC7B,oDAAoD,CACrD,CAAC;YACF,OAAO,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;QACtE,CAAC;IACH,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `pwa`' admin surface — one route and one sidebar entry, declared by the
|
|
3
|
+
* module that owns them (feature 091, Phase 4, batches six and ten;
|
|
4
|
+
* `specs/091-module-owned-admin-surfaces/contracts/admin-contribution.md`).
|
|
5
|
+
*
|
|
6
|
+
* **The nav-only shape came first, and batch ten closed it.** Batch six moved
|
|
7
|
+
* the sidebar entry alone, which was the half of `AdminContributions` nothing
|
|
8
|
+
* had exercised — the type's own doc block says *"a module shipping only a nav
|
|
9
|
+
* entry pointing at a host route is legal"* — and left the route in `App.tsx`
|
|
10
|
+
* because `PwaPage` lived under `admin/src/modules/settings/pages/`, a
|
|
11
|
+
* directory `settings` owns. That batch recorded the consequence rather than
|
|
12
|
+
* hiding it: a host `<Route>` is ungated, so an operator who switched `pwa`
|
|
13
|
+
* **off** still reached `/settings/pwa` and met this module's own 503 field by
|
|
14
|
+
* field, *"unchanged by this batch and closes when `settings` moves"*.
|
|
15
|
+
*
|
|
16
|
+
* **`settings` moved in batch ten, so the screen came here.** `PwaPage`,
|
|
17
|
+
* `PushAudienceRuleBuilder` and `pwa-client.ts` are this package's now and the
|
|
18
|
+
* route is declared beside the entry that advertises it, gated on **this**
|
|
19
|
+
* module's presence rather than on `settings`'. That is the `/admin-roles`
|
|
20
|
+
* split of batch four resolving in the other direction: it existed because two
|
|
21
|
+
* modules' code sat in one directory, and it ends when the directory does.
|
|
22
|
+
* `admin/test/modules/pwa.module-owned-surface.test.tsx` is the proof, and it
|
|
23
|
+
* kept an assertion from batch six that the advertisement's destination is a
|
|
24
|
+
* route the admin declares somewhere — the route is this module's now.
|
|
25
|
+
*
|
|
26
|
+
* **`pwa` was batch four's sixth member and was deferred for a collision**,
|
|
27
|
+
* not for a criterion — feature 087's Group B B2 was then in flight on this
|
|
28
|
+
* package and both merge requests would have run `manifests:generate` over its
|
|
29
|
+
* `package.json`. That work landed in `e12188dac`, so the collision is gone.
|
|
30
|
+
*
|
|
31
|
+
* **This entry exports data and nothing else** (R2), like every `./admin`
|
|
32
|
+
* layer: `check:module-boundary`'s D-171 rule designates a subpath as contract
|
|
33
|
+
* surface when it emits no runtime binding, and `./admin` deliberately does not
|
|
34
|
+
* qualify, so a consumer reaching into another module's `./admin` stays a
|
|
35
|
+
* counted boundary reach.
|
|
36
|
+
*/
|
|
37
|
+
import type { AdminContributions } from '@endora-commerce/admin-kit/contributions';
|
|
38
|
+
export declare const contributions: AdminContributions;
|
|
39
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/admin/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0CAA0C,CAAC;AA4BnF,eAAO,MAAM,aAAa,EAAE,kBAmC3B,CAAC"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The screen's route, which is this module's own since batch ten.
|
|
3
|
+
*
|
|
4
|
+
* The **path** keeps the `/settings/` prefix it has had since feature 034: it
|
|
5
|
+
* is where an operator's bookmarks point and where `pwa`'s own documentation
|
|
6
|
+
* sends them, and moving a URL is a product change this conversion has no
|
|
7
|
+
* reason to make. A path is not an ownership claim — `inpost`'s and the five
|
|
8
|
+
* gateways' routes are `/settings/<id>` on the same terms.
|
|
9
|
+
*
|
|
10
|
+
* Spelled once so the route, the nav entry and the test that drives them cannot
|
|
11
|
+
* drift.
|
|
12
|
+
*/
|
|
13
|
+
const NAV_TARGET = '/settings/pwa';
|
|
14
|
+
/**
|
|
15
|
+
* The code that opens the screen.
|
|
16
|
+
*
|
|
17
|
+
* Every route under `GET /api/v1/admin/pwa/*` that this page calls on mount is
|
|
18
|
+
* `requireAdmin('pwa:read')`. Its writes enforce `pwa:write` and
|
|
19
|
+
* `pwa:send_push`, and neither of those opens it — the codes are opaque
|
|
20
|
+
* strings, so declaring one of them would advertise a screen the operator
|
|
21
|
+
* cannot read. It is the code the sidebar entry has carried since batch six,
|
|
22
|
+
* and the route now carries the same one.
|
|
23
|
+
*/
|
|
24
|
+
const READ_PERMISSION = 'pwa:read';
|
|
25
|
+
export const contributions = {
|
|
26
|
+
routes: [
|
|
27
|
+
{
|
|
28
|
+
path: NAV_TARGET,
|
|
29
|
+
component: () => import('./pages/PwaPage.js'),
|
|
30
|
+
requiredPermission: READ_PERMISSION,
|
|
31
|
+
index: true,
|
|
32
|
+
},
|
|
33
|
+
],
|
|
34
|
+
nav: [
|
|
35
|
+
{
|
|
36
|
+
to: NAV_TARGET,
|
|
37
|
+
// Module-relative (R8), resolved in this module's own namespace out of
|
|
38
|
+
// `packages/modules/pwa/i18n/`. It was `appShell.nav.pwa` in the shared
|
|
39
|
+
// `_i18n` bundle, one of the four shared files a module author had to
|
|
40
|
+
// edit.
|
|
41
|
+
labelKey: 'nav.pwa.label',
|
|
42
|
+
// The icon the hand-written NAV entry carried. `Smartphone` joins
|
|
43
|
+
// `KnownIconNameSchema` and the kit's `icon-map.ts` in this merge request
|
|
44
|
+
// so the sidebar renders the same glyph it did before the move; swapping
|
|
45
|
+
// to a name already on the allowlist would have been a visible change
|
|
46
|
+
// bought for nothing.
|
|
47
|
+
icon: 'Smartphone',
|
|
48
|
+
section: 'system',
|
|
49
|
+
// The hand-written table's position times a hundred — the convention
|
|
50
|
+
// batch four set. `/settings/pwa` was fourteenth of fourteen in the
|
|
51
|
+
// *System* section and 1400 keeps it last among the converted entries,
|
|
52
|
+
// which are 200, 300, 600 and 700 today.
|
|
53
|
+
weight: 1400,
|
|
54
|
+
// The code enforced on the destination, which is the route declared
|
|
55
|
+
// above — the two are one statement now rather than a module's guess
|
|
56
|
+
// about a host registration.
|
|
57
|
+
requiredPermission: READ_PERMISSION,
|
|
58
|
+
},
|
|
59
|
+
],
|
|
60
|
+
};
|
|
61
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/admin/index.ts"],"names":[],"mappings":"AAsCA;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,GAAG,eAAe,CAAC;AAEnC;;;;;;;;;GASG;AACH,MAAM,eAAe,GAAG,UAAU,CAAC;AAEnC,MAAM,CAAC,MAAM,aAAa,GAAuB;IAC/C,MAAM,EAAE;QACN;YACE,IAAI,EAAE,UAAU;YAChB,SAAS,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,oBAAoB,CAAC;YAC7C,kBAAkB,EAAE,eAAe;YACnC,KAAK,EAAE,IAAI;SACZ;KACF;IACD,GAAG,EAAE;QACH;YACE,EAAE,EAAE,UAAU;YACd,uEAAuE;YACvE,wEAAwE;YACxE,sEAAsE;YACtE,QAAQ;YACR,QAAQ,EAAE,eAAe;YACzB,kEAAkE;YAClE,0EAA0E;YAC1E,yEAAyE;YACzE,sEAAsE;YACtE,sBAAsB;YACtB,IAAI,EAAE,YAAY;YAClB,OAAO,EAAE,QAAQ;YACjB,qEAAqE;YACrE,oEAAoE;YACpE,uEAAuE;YACvE,yCAAyC;YACzC,MAAM,EAAE,IAAI;YACZ,oEAAoE;YACpE,qEAAqE;YACrE,6BAA6B;YAC7B,kBAAkB,EAAE,eAAe;SACpC;KACF;CACF,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type ReactNode } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* PWA configuration page (feature 046, US2 + US4 admin surface). Edits the
|
|
4
|
+
* global PWA identity + toggles, uploads the icon (sharp-derived sizes),
|
|
5
|
+
* generates VAPID keys, and sends a broadcast push. The Scope selector switches
|
|
6
|
+
* between the global value and a per-Sales-Channel override; a per-channel scope
|
|
7
|
+
* can be reset back to the global value with "Reset to global".
|
|
8
|
+
*/
|
|
9
|
+
export declare function PwaPage(): ReactNode;
|
|
10
|
+
/**
|
|
11
|
+
* The registry loads a route component through a dynamic-import factory and
|
|
12
|
+
* reads its default export (feature 091, FR-013). The named export stays: it is
|
|
13
|
+
* the spelling this module's own code and its tests use.
|
|
14
|
+
*/
|
|
15
|
+
export default PwaPage;
|
|
16
|
+
//# sourceMappingURL=PwaPage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PwaPage.d.ts","sourceRoot":"","sources":["../../../src/admin/pages/PwaPage.tsx"],"names":[],"mappings":"AAAA,OAAO,EAA4C,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAyCjF;;;;;;GAMG;AACH,wBAAgB,OAAO,IAAI,SAAS,CAqXnC;AAED;;;;GAIG;AACH,eAAe,OAAO,CAAC"}
|