@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.
Files changed (119) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +63 -0
  3. package/dist/admin/api/pwa-client.d.ts +15 -0
  4. package/dist/admin/api/pwa-client.d.ts.map +1 -0
  5. package/dist/admin/api/pwa-client.js +56 -0
  6. package/dist/admin/api/pwa-client.js.map +1 -0
  7. package/dist/admin/components/PushAudienceRuleBuilder.d.ts +19 -0
  8. package/dist/admin/components/PushAudienceRuleBuilder.d.ts.map +1 -0
  9. package/dist/admin/components/PushAudienceRuleBuilder.js +211 -0
  10. package/dist/admin/components/PushAudienceRuleBuilder.js.map +1 -0
  11. package/dist/admin/index.d.ts +39 -0
  12. package/dist/admin/index.d.ts.map +1 -0
  13. package/dist/admin/index.js +61 -0
  14. package/dist/admin/index.js.map +1 -0
  15. package/dist/admin/pages/PwaPage.d.ts +16 -0
  16. package/dist/admin/pages/PwaPage.d.ts.map +1 -0
  17. package/dist/admin/pages/PwaPage.js +207 -0
  18. package/dist/admin/pages/PwaPage.js.map +1 -0
  19. package/dist/backend/entities/push-message-delivery.entity.d.ts +18 -0
  20. package/dist/backend/entities/push-message-delivery.entity.d.ts.map +1 -0
  21. package/dist/backend/entities/push-message-delivery.entity.js +68 -0
  22. package/dist/backend/entities/push-message-delivery.entity.js.map +1 -0
  23. package/dist/backend/entities/push-message.entity.d.ts +26 -0
  24. package/dist/backend/entities/push-message.entity.d.ts.map +1 -0
  25. package/dist/backend/entities/push-message.entity.js +102 -0
  26. package/dist/backend/entities/push-message.entity.js.map +1 -0
  27. package/dist/backend/entities/push-subscription.entity.d.ts +49 -0
  28. package/dist/backend/entities/push-subscription.entity.d.ts.map +1 -0
  29. package/dist/backend/entities/push-subscription.entity.js +117 -0
  30. package/dist/backend/entities/push-subscription.entity.js.map +1 -0
  31. package/dist/backend/entities/pwa-icon-rendition.entity.d.ts +21 -0
  32. package/dist/backend/entities/pwa-icon-rendition.entity.d.ts.map +1 -0
  33. package/dist/backend/entities/pwa-icon-rendition.entity.js +69 -0
  34. package/dist/backend/entities/pwa-icon-rendition.entity.js.map +1 -0
  35. package/dist/backend/index.d.ts +100 -0
  36. package/dist/backend/index.d.ts.map +1 -0
  37. package/dist/backend/index.js +107 -0
  38. package/dist/backend/index.js.map +1 -0
  39. package/dist/backend/plugin.d.ts +119 -0
  40. package/dist/backend/plugin.d.ts.map +1 -0
  41. package/dist/backend/plugin.js +109 -0
  42. package/dist/backend/plugin.js.map +1 -0
  43. package/dist/backend/request-actor.d.ts +24 -0
  44. package/dist/backend/request-actor.d.ts.map +1 -0
  45. package/dist/backend/request-actor.js +29 -0
  46. package/dist/backend/request-actor.js.map +1 -0
  47. package/dist/backend/routes.admin.d.ts +52 -0
  48. package/dist/backend/routes.admin.d.ts.map +1 -0
  49. package/dist/backend/routes.admin.js +222 -0
  50. package/dist/backend/routes.admin.js.map +1 -0
  51. package/dist/backend/routes.storefront.d.ts +29 -0
  52. package/dist/backend/routes.storefront.d.ts.map +1 -0
  53. package/dist/backend/routes.storefront.js +66 -0
  54. package/dist/backend/routes.storefront.js.map +1 -0
  55. package/dist/backend/services/cross-module-context.d.ts +90 -0
  56. package/dist/backend/services/cross-module-context.d.ts.map +1 -0
  57. package/dist/backend/services/cross-module-context.js +84 -0
  58. package/dist/backend/services/cross-module-context.js.map +1 -0
  59. package/dist/backend/services/providers/web-push-provider.d.ts +31 -0
  60. package/dist/backend/services/providers/web-push-provider.d.ts.map +1 -0
  61. package/dist/backend/services/providers/web-push-provider.js +72 -0
  62. package/dist/backend/services/providers/web-push-provider.js.map +1 -0
  63. package/dist/backend/services/push-audience-evaluator.d.ts +24 -0
  64. package/dist/backend/services/push-audience-evaluator.d.ts.map +1 -0
  65. package/dist/backend/services/push-audience-evaluator.js +29 -0
  66. package/dist/backend/services/push-audience-evaluator.js.map +1 -0
  67. package/dist/backend/services/push-delivery-queue.d.ts +14 -0
  68. package/dist/backend/services/push-delivery-queue.d.ts.map +1 -0
  69. package/dist/backend/services/push-delivery-queue.js +30 -0
  70. package/dist/backend/services/push-delivery-queue.js.map +1 -0
  71. package/dist/backend/services/push-event-subscriber.d.ts +86 -0
  72. package/dist/backend/services/push-event-subscriber.d.ts.map +1 -0
  73. package/dist/backend/services/push-event-subscriber.js +109 -0
  74. package/dist/backend/services/push-event-subscriber.js.map +1 -0
  75. package/dist/backend/services/push-message-service.d.ts +58 -0
  76. package/dist/backend/services/push-message-service.d.ts.map +1 -0
  77. package/dist/backend/services/push-message-service.js +145 -0
  78. package/dist/backend/services/push-message-service.js.map +1 -0
  79. package/dist/backend/services/push-provider-registry.d.ts +17 -0
  80. package/dist/backend/services/push-provider-registry.d.ts.map +1 -0
  81. package/dist/backend/services/push-provider-registry.js +32 -0
  82. package/dist/backend/services/push-provider-registry.js.map +1 -0
  83. package/dist/backend/services/push-subscription-service.d.ts +67 -0
  84. package/dist/backend/services/push-subscription-service.d.ts.map +1 -0
  85. package/dist/backend/services/push-subscription-service.js +165 -0
  86. package/dist/backend/services/push-subscription-service.js.map +1 -0
  87. package/dist/backend/services/pwa-config-resolver.d.ts +29 -0
  88. package/dist/backend/services/pwa-config-resolver.d.ts.map +1 -0
  89. package/dist/backend/services/pwa-config-resolver.js +92 -0
  90. package/dist/backend/services/pwa-config-resolver.js.map +1 -0
  91. package/dist/backend/services/pwa-icon-service.d.ts +44 -0
  92. package/dist/backend/services/pwa-icon-service.d.ts.map +1 -0
  93. package/dist/backend/services/pwa-icon-service.js +105 -0
  94. package/dist/backend/services/pwa-icon-service.js.map +1 -0
  95. package/dist/backend/workers/push-delivery-worker.d.ts +17 -0
  96. package/dist/backend/workers/push-delivery-worker.d.ts.map +1 -0
  97. package/dist/backend/workers/push-delivery-worker.js +105 -0
  98. package/dist/backend/workers/push-delivery-worker.js.map +1 -0
  99. package/dist/manifest.d.ts +184 -0
  100. package/dist/manifest.d.ts.map +1 -0
  101. package/dist/manifest.js +207 -0
  102. package/dist/manifest.js.map +1 -0
  103. package/dist/migrations/20260625T144228_pwa_init.d.ts +18 -0
  104. package/dist/migrations/20260625T144228_pwa_init.d.ts.map +1 -0
  105. package/dist/migrations/20260625T144228_pwa_init.js +105 -0
  106. package/dist/migrations/20260625T144228_pwa_init.js.map +1 -0
  107. package/dist/migrations/20260830T172022_pwa_organization_attribution.d.ts +102 -0
  108. package/dist/migrations/20260830T172022_pwa_organization_attribution.d.ts.map +1 -0
  109. package/dist/migrations/20260830T172022_pwa_organization_attribution.js +169 -0
  110. package/dist/migrations/20260830T172022_pwa_organization_attribution.js.map +1 -0
  111. package/dist/migrations/index.d.ts +28 -0
  112. package/dist/migrations/index.d.ts.map +1 -0
  113. package/dist/migrations/index.js +31 -0
  114. package/dist/migrations/index.js.map +1 -0
  115. package/docs/pwa.md +93 -0
  116. package/i18n/en.json +43 -0
  117. package/i18n/pl.json +43 -0
  118. package/package.json +105 -0
  119. package/tailwind.css +14 -0
@@ -0,0 +1,117 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ var __metadata = (this && this.__metadata) || function (k, v) {
8
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
+ };
10
+ import { Entity, Index, OptionalProps, PrimaryKey, Property, Unique } from '@mikro-orm/core';
11
+ import { CustomerScoped } from '@endora-commerce/platform/tenancy';
12
+ import { randomUUID } from 'crypto';
13
+ /**
14
+ * PushSubscription (feature 046, US4). One subscribed storefront device/browser —
15
+ * a standard Web-Push subscription (endpoint + p256dh + auth). Idempotent on
16
+ * `endpoint` (upsert on re-subscribe). `customerAccountId` is null for anonymous
17
+ * devices (FR-023). Constraints/indexes are declared in migration 080.
18
+ */
19
+ let PushSubscription = class PushSubscription {
20
+ [OptionalProps];
21
+ id = randomUUID();
22
+ salesChannelId;
23
+ customerAccountId;
24
+ /**
25
+ * The organisation that owns this subscription — feature 087 Group B, ruling
26
+ * D-187.
27
+ *
28
+ * Derived from {@link customerAccountId}'s account and stamped at the write,
29
+ * never resolved on read: `customerOrganizationColumn` asks the ORM's own
30
+ * metadata whether this property exists, so its presence is what makes
31
+ * `customerFilterCond`'s `allowed-set` arm **grant** on this table rather
32
+ * than refuse it whole. A sales representative assigned to the buyer's
33
+ * organisation sees this device because this column is here.
34
+ *
35
+ * Nullable, and the constraint is an implication rather than an equivalence:
36
+ * `push_subscriptions_organization_attribution_chk` requires an organisation
37
+ * of a row that names an account and says nothing about a row that names
38
+ * none. An **anonymous** device is a representable state (FR-011, FR-023) —
39
+ * a browser subscribes before anybody signs in — and who such a row belongs
40
+ * to is R-6's open question, which a constraint must not answer.
41
+ *
42
+ * It moves in **both** directions with {@link customerAccountId}, because
43
+ * this table's write is an upsert on `endpoint`: signing in on a device
44
+ * stamps the account and the organisation together, and re-subscribing that
45
+ * same device anonymously clears both. The second direction is the one the
46
+ * implication does not cover — an ownerless row keeping an organisation is
47
+ * a disclosure the schema permits — so it is held by the service's resolved
48
+ * owner type and by a test, not by the check.
49
+ */
50
+ organizationId;
51
+ endpoint;
52
+ p256dh;
53
+ auth;
54
+ provider = 'web_push';
55
+ status = 'active';
56
+ userAgent;
57
+ createdAt = new Date();
58
+ lastSeenAt = new Date();
59
+ };
60
+ __decorate([
61
+ PrimaryKey({ type: 'uuid' }),
62
+ __metadata("design:type", String)
63
+ ], PushSubscription.prototype, "id", void 0);
64
+ __decorate([
65
+ Property({ type: 'uuid' }),
66
+ Index(),
67
+ __metadata("design:type", String)
68
+ ], PushSubscription.prototype, "salesChannelId", void 0);
69
+ __decorate([
70
+ Property({ type: 'uuid', nullable: true }),
71
+ Index(),
72
+ __metadata("design:type", Object)
73
+ ], PushSubscription.prototype, "customerAccountId", void 0);
74
+ __decorate([
75
+ Property({ type: 'uuid', nullable: true }),
76
+ Index(),
77
+ __metadata("design:type", Object)
78
+ ], PushSubscription.prototype, "organizationId", void 0);
79
+ __decorate([
80
+ Property({ type: 'text' }),
81
+ __metadata("design:type", String)
82
+ ], PushSubscription.prototype, "endpoint", void 0);
83
+ __decorate([
84
+ Property({ type: 'text' }),
85
+ __metadata("design:type", String)
86
+ ], PushSubscription.prototype, "p256dh", void 0);
87
+ __decorate([
88
+ Property({ type: 'text' }),
89
+ __metadata("design:type", String)
90
+ ], PushSubscription.prototype, "auth", void 0);
91
+ __decorate([
92
+ Property({ type: 'string', length: 32 }),
93
+ __metadata("design:type", String)
94
+ ], PushSubscription.prototype, "provider", void 0);
95
+ __decorate([
96
+ Property({ type: 'string', length: 16 }),
97
+ __metadata("design:type", String)
98
+ ], PushSubscription.prototype, "status", void 0);
99
+ __decorate([
100
+ Property({ type: 'text', nullable: true }),
101
+ __metadata("design:type", Object)
102
+ ], PushSubscription.prototype, "userAgent", void 0);
103
+ __decorate([
104
+ Property({ type: 'datetime', onCreate: () => new Date() }),
105
+ __metadata("design:type", Date)
106
+ ], PushSubscription.prototype, "createdAt", void 0);
107
+ __decorate([
108
+ Property({ type: 'datetime' }),
109
+ __metadata("design:type", Date)
110
+ ], PushSubscription.prototype, "lastSeenAt", void 0);
111
+ PushSubscription = __decorate([
112
+ CustomerScoped(),
113
+ Entity({ tableName: 'push_subscriptions' }),
114
+ Unique({ properties: ['endpoint'] })
115
+ ], PushSubscription);
116
+ export { PushSubscription };
117
+ //# sourceMappingURL=push-subscription.entity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"push-subscription.entity.js","sourceRoot":"","sources":["../../../src/backend/entities/push-subscription.entity.ts"],"names":[],"mappings":";;;;;;;;;AAAA,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,aAAa,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAC7F,OAAO,EAAE,cAAc,EAAE,MAAM,mCAAmC,CAAC;AACnE,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAEpC;;;;;GAKG;AAII,IAAM,gBAAgB,GAAtB,MAAM,gBAAgB;IAC3B,CAAC,aAAa,CAAC,CAQC;IAGhB,EAAE,GAAW,UAAU,EAAE,CAAC;IAI1B,cAAc,CAAU;IAIxB,iBAAiB,CAAiB;IAElC;;;;;;;;;;;;;;;;;;;;;;;;;OAyBG;IAGH,cAAc,CAAiB;IAG/B,QAAQ,CAAU;IAGlB,MAAM,CAAU;IAGhB,IAAI,CAAU;IAGd,QAAQ,GAAW,UAAU,CAAC;IAG9B,MAAM,GAAyB,QAAQ,CAAC;IAGxC,SAAS,CAAiB;IAG1B,SAAS,GAAS,IAAI,IAAI,EAAE,CAAC;IAG7B,UAAU,GAAS,IAAI,IAAI,EAAE,CAAC;CAC/B,CAAA;AA/DC;IADC,UAAU,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;;4CACH;AAI1B;IAFC,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;IAC1B,KAAK,EAAE;;wDACgB;AAIxB;IAFC,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IAC1C,KAAK,EAAE;;2DAC0B;AA8BlC;IAFC,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IAC1C,KAAK,EAAE;;wDACuB;AAG/B;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;;kDACT;AAGlB;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;;gDACX;AAGhB;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;;8CACb;AAGd;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;;kDACX;AAG9B;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;;gDACD;AAGxC;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;mDACjB;AAG1B;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,IAAI,IAAI,EAAE,EAAE,CAAC;8BAChD,IAAI;mDAAc;AAG7B;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC;8BACnB,IAAI;oDAAc;AA1EnB,gBAAgB;IAH5B,cAAc,EAAE;IAChB,MAAM,CAAC,EAAE,SAAS,EAAE,oBAAoB,EAAE,CAAC;IAC3C,MAAM,CAAC,EAAE,UAAU,EAAE,CAAC,UAAU,CAAC,EAAE,CAAC;GACxB,gBAAgB,CA2E5B"}
@@ -0,0 +1,21 @@
1
+ import { OptionalProps } from '@mikro-orm/core';
2
+ import type { PwaIconPurpose } from '@endora-commerce/contracts';
3
+ /**
4
+ * PwaIconRendition (feature 046, US2). A derived icon size for a channel's PWA
5
+ * identity, produced by `sharp` from the admin-uploaded source. `salesChannelId`
6
+ * null = global default identity; non-null = per-channel override (FR-011).
7
+ * `(salesChannelId, size, purpose)` is unique (NULLS NOT DISTINCT for the global
8
+ * row — enforced in migration 080).
9
+ */
10
+ export declare class PwaIconRendition {
11
+ [OptionalProps]?: 'id' | 'createdAt' | 'salesChannelId';
12
+ id: string;
13
+ salesChannelId?: string | null;
14
+ sourceAssetId: string;
15
+ size: number;
16
+ purpose: PwaIconPurpose;
17
+ assetId: string;
18
+ contentHash: string;
19
+ createdAt: Date;
20
+ }
21
+ //# sourceMappingURL=pwa-icon-rendition.entity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pwa-icon-rendition.entity.d.ts","sourceRoot":"","sources":["../../../src/backend/entities/pwa-icon-rendition.entity.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,aAAa,EAAgC,MAAM,iBAAiB,CAAC;AAGtF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAEjE;;;;;;GAMG;AACH,qBAGa,gBAAgB;IAC3B,CAAC,aAAa,CAAC,CAAC,EAAE,IAAI,GAAG,WAAW,GAAG,gBAAgB,CAAC;IAGxD,EAAE,EAAE,MAAM,CAAgB;IAG1B,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAG/B,aAAa,EAAG,MAAM,CAAC;IAGvB,IAAI,EAAG,MAAM,CAAC;IAGd,OAAO,EAAG,cAAc,CAAC;IAGzB,OAAO,EAAG,MAAM,CAAC;IAGjB,WAAW,EAAG,MAAM,CAAC;IAGrB,SAAS,EAAE,IAAI,CAAc;CAC9B"}
@@ -0,0 +1,69 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ var __metadata = (this && this.__metadata) || function (k, v) {
8
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
+ };
10
+ import { Entity, OptionalProps, PrimaryKey, Property, Unique } from '@mikro-orm/core';
11
+ import { GlobalEntity } from '@endora-commerce/platform/tenancy';
12
+ import { randomUUID } from 'crypto';
13
+ /**
14
+ * PwaIconRendition (feature 046, US2). A derived icon size for a channel's PWA
15
+ * identity, produced by `sharp` from the admin-uploaded source. `salesChannelId`
16
+ * null = global default identity; non-null = per-channel override (FR-011).
17
+ * `(salesChannelId, size, purpose)` is unique (NULLS NOT DISTINCT for the global
18
+ * row — enforced in migration 080).
19
+ */
20
+ let PwaIconRendition = class PwaIconRendition {
21
+ [OptionalProps];
22
+ id = randomUUID();
23
+ salesChannelId;
24
+ sourceAssetId;
25
+ size;
26
+ purpose;
27
+ assetId;
28
+ contentHash;
29
+ createdAt = new Date();
30
+ };
31
+ __decorate([
32
+ PrimaryKey({ type: 'uuid' }),
33
+ __metadata("design:type", String)
34
+ ], PwaIconRendition.prototype, "id", void 0);
35
+ __decorate([
36
+ Property({ type: 'uuid', nullable: true }),
37
+ __metadata("design:type", Object)
38
+ ], PwaIconRendition.prototype, "salesChannelId", void 0);
39
+ __decorate([
40
+ Property({ type: 'uuid' }),
41
+ __metadata("design:type", String)
42
+ ], PwaIconRendition.prototype, "sourceAssetId", void 0);
43
+ __decorate([
44
+ Property({ type: 'integer' }),
45
+ __metadata("design:type", Number)
46
+ ], PwaIconRendition.prototype, "size", void 0);
47
+ __decorate([
48
+ Property({ type: 'string', length: 16 }),
49
+ __metadata("design:type", String)
50
+ ], PwaIconRendition.prototype, "purpose", void 0);
51
+ __decorate([
52
+ Property({ type: 'uuid' }),
53
+ __metadata("design:type", String)
54
+ ], PwaIconRendition.prototype, "assetId", void 0);
55
+ __decorate([
56
+ Property({ type: 'string', length: 64 }),
57
+ __metadata("design:type", String)
58
+ ], PwaIconRendition.prototype, "contentHash", void 0);
59
+ __decorate([
60
+ Property({ type: 'datetime', onCreate: () => new Date() }),
61
+ __metadata("design:type", Date)
62
+ ], PwaIconRendition.prototype, "createdAt", void 0);
63
+ PwaIconRendition = __decorate([
64
+ GlobalEntity(),
65
+ Entity({ tableName: 'pwa_icon_renditions' }),
66
+ Unique({ properties: ['salesChannelId', 'size', 'purpose'] })
67
+ ], PwaIconRendition);
68
+ export { PwaIconRendition };
69
+ //# sourceMappingURL=pwa-icon-rendition.entity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pwa-icon-rendition.entity.js","sourceRoot":"","sources":["../../../src/backend/entities/pwa-icon-rendition.entity.ts"],"names":[],"mappings":";;;;;;;;;AAAA,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AACtF,OAAO,EAAE,YAAY,EAAE,MAAM,mCAAmC,CAAC;AACjE,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAGpC;;;;;;GAMG;AAII,IAAM,gBAAgB,GAAtB,MAAM,gBAAgB;IAC3B,CAAC,aAAa,CAAC,CAAyC;IAGxD,EAAE,GAAW,UAAU,EAAE,CAAC;IAG1B,cAAc,CAAiB;IAG/B,aAAa,CAAU;IAGvB,IAAI,CAAU;IAGd,OAAO,CAAkB;IAGzB,OAAO,CAAU;IAGjB,WAAW,CAAU;IAGrB,SAAS,GAAS,IAAI,IAAI,EAAE,CAAC;CAC9B,CAAA;AAtBC;IADC,UAAU,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;;4CACH;AAG1B;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;wDACZ;AAG/B;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;;uDACJ;AAGvB;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;;8CAChB;AAGd;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;;iDAChB;AAGzB;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;;iDACV;AAGjB;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;;qDACpB;AAGrB;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,IAAI,IAAI,EAAE,EAAE,CAAC;8BAChD,IAAI;mDAAc;AAzBlB,gBAAgB;IAH5B,YAAY,EAAE;IACd,MAAM,CAAC,EAAE,SAAS,EAAE,qBAAqB,EAAE,CAAC;IAC5C,MAAM,CAAC,EAAE,UAAU,EAAE,CAAC,gBAAgB,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,CAAC;GACjD,gBAAgB,CA0B5B"}
@@ -0,0 +1,100 @@
1
+ import type { EntityManager } from '@mikro-orm/postgresql';
2
+ import type { Redis } from 'ioredis';
3
+ import type { ModuleContext } from '@endora-commerce/platform/kernel';
4
+ import type { RequireAdminFactory } from '@endora-commerce/platform/kernel';
5
+ import { type PwaModuleOptions, type PwaModuleResult } from './plugin.js';
6
+ import { PushMessageDelivery } from './entities/push-message-delivery.entity.js';
7
+ import { PushMessage } from './entities/push-message.entity.js';
8
+ import { PushSubscription } from './entities/push-subscription.entity.js';
9
+ import { PwaIconRendition } from './entities/pwa-icon-rendition.entity.js';
10
+ /**
11
+ * `pwa` — and **there is no bridge any more**
12
+ * (`specs/110-instance-repository/` T118c).
13
+ *
14
+ * `PwaBridge` was one contributed name carrying eight members, written as
15
+ * closures in `backend/src/composition.ts` and again in
16
+ * `backend/test/helpers/test-server.ts`, on the reasoning that "a composition
17
+ * knows how to reach `assets_library` and `sales_channels`, or it does not".
18
+ * Re-derived member by member, none of the eight was a composition's answer to
19
+ * give:
20
+ *
21
+ * - `assetUpload` and `resolveAssetUrl` are `assets_library`' published
22
+ * `assetsLibraryPort`. The first was a *structural subset* of
23
+ * `AssetsLibraryPort.upload` all along — a Node `Readable` satisfies
24
+ * `AssetUploadStream`, `AssetDetail` satisfies `{ id: string }` — and the
25
+ * second is `getAsset(id).url` under D-223, which is why `resolveUrl` is
26
+ * published on no port.
27
+ * - `defaultChannelId` and `channelCodeForId` are the kernel's own
28
+ * `salesChannelResolutionPort`, a **platform** name (Constitution XII), so
29
+ * they add nothing to this module's manifest. The second replaces a root's
30
+ * hand-written `em.findOne(SalesChannel, { id })`, which is what `getById`
31
+ * already is.
32
+ * - `resolveAuditContext` was byte-identical to `adminAuditActorResolver`,
33
+ * which the platform contributes in `compose-app.ts` and whose own comment
34
+ * says it exists because "six modules each declared an identically-shaped
35
+ * `resolveAuditContext` option". This was one of the six. The harness's copy
36
+ * was **not** identical — it answered `TEST_ADMIN_ID` where production
37
+ * answered `null` — so draining it also settles a divergence.
38
+ * - `resolveCustomerAccountId` is a read of `request.actor`, whose
39
+ * augmentation became the platform's at T118b; see `request-actor.ts`.
40
+ * - `resolveOrderTarget` is `orders`' published `orderReadPort` plus a
41
+ * sentence, and `orders` joins `dependencies` for it.
42
+ * - `resolveChannelIdByCode` was **called by nothing** and is deleted rather
43
+ * than drained; see the note in `routes.storefront.ts`.
44
+ *
45
+ * What is left of the coupling is {@link PwaCrossModulePorts} — three published
46
+ * ports and no closure, resolved here and mapped in
47
+ * `services/cross-module-context.ts`.
48
+ *
49
+ * `vapidSubject` comes from the environment, read here rather than threaded
50
+ * from a root — a packaged module reads its own configuration.
51
+ *
52
+ * `runWorkers` is **root-supplied, not env-derived**, and that is a correction
53
+ * rather than a preference. My first attempt read `BACKEND_ROLE` here and gave
54
+ * the queue `moduleQueueRedis` — copying what `google_tag_manager` needed. Both
55
+ * were wrong for this module: the harness passes a real Redis *and*
56
+ * `runWorkers: false`, so it has a producer and no consumer. Deriving either
57
+ * from the environment made the harness start a delivery worker it never wants
58
+ * and hand BullMQ an undefined connection. What a composition does with queue
59
+ * consumers is a deployment decision, and the two deployments here genuinely
60
+ * differ.
61
+ */
62
+ export interface PwaCradle {
63
+ readonly emFactory: () => EntityManager;
64
+ readonly redis: Redis;
65
+ /**
66
+ * Whether this composition runs the push-delivery consumer (Principle X).
67
+ * Root-supplied rather than env-derived: the harness runs no consumer at all,
68
+ * and a module should not have to know which of its callers is a test.
69
+ */
70
+ readonly pwaRunWorkers: boolean;
71
+ readonly requireAdmin: RequireAdminFactory;
72
+ readonly settingsReadPort: PwaModuleOptions['settings'];
73
+ readonly settingsAdminService: PwaModuleOptions['settingsWrite'];
74
+ /**
75
+ * How this deployment names the acting admin on an audit record: the admin's
76
+ * id, or `null` for a non-admin caller.
77
+ *
78
+ * A **cradle** read rather than a port, which is what the eight other modules
79
+ * taking this name already do (`autopay`, `catalog`, `dhl_parcel`,
80
+ * `google_analytics`, `inpost`, …): it is a contribution the platform makes in
81
+ * `compose-app.ts`, not a capability any module owns, so there is nothing to
82
+ * gate and nothing to declare.
83
+ */
84
+ readonly adminAuditActorResolver: PwaModuleOptions['resolveAuditContext'];
85
+ readonly pwa: PwaModuleResult;
86
+ }
87
+ export declare function registerModule(ctx: ModuleContext): void;
88
+ /**
89
+ * The module's persisted entity classes, on the `./backend` subpath, as one
90
+ * array and **no named class export** (D-168).
91
+ *
92
+ * This is the shape the platform reads when the package is *installed*: the
93
+ * boot-time loader (`src/packages/package-runtime.ts`, `exported['entities']`)
94
+ * and the static declaration reader (`scripts/lib/package-declarations.ts`),
95
+ * which is the third source of `check:module-boundary`'s `table→owner` map and
96
+ * the package pass of `check-entity-tenant-classification`. A missing array is
97
+ * answered with `[]` — zero entities registered, no error anywhere.
98
+ */
99
+ export declare const entities: (typeof PwaIconRendition | typeof PushSubscription | typeof PushMessage | typeof PushMessageDelivery)[];
100
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/backend/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAE3D,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAQrC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kCAAkC,CAAC;AAEtE,OAAO,KAAK,EACV,mBAAmB,EAEpB,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EAAa,KAAK,gBAAgB,EAAE,KAAK,eAAe,EAAE,MAAM,aAAa,CAAC;AAQrF,OAAO,EAAE,mBAAmB,EAAE,MAAM,4CAA4C,CAAC;AACjF,OAAO,EAAE,WAAW,EAAE,MAAM,mCAAmC,CAAC;AAChE,OAAO,EAAE,gBAAgB,EAAE,MAAM,wCAAwC,CAAC;AAC1E,OAAO,EAAE,gBAAgB,EAAE,MAAM,yCAAyC,CAAC;AAE3E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmDG;AAEH,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,SAAS,EAAE,MAAM,aAAa,CAAC;IACxC,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IACtB;;;;OAIG;IACH,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC;IAChC,QAAQ,CAAC,YAAY,EAAE,mBAAmB,CAAC;IAC3C,QAAQ,CAAC,gBAAgB,EAAE,gBAAgB,CAAC,UAAU,CAAC,CAAC;IACxD,QAAQ,CAAC,oBAAoB,EAAE,gBAAgB,CAAC,eAAe,CAAC,CAAC;IACjE;;;;;;;;;OASG;IACH,QAAQ,CAAC,uBAAuB,EAAE,gBAAgB,CAAC,qBAAqB,CAAC,CAAC;IAC1E,QAAQ,CAAC,GAAG,EAAE,eAAe,CAAC;CAC/B;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI,CAyFvD;AAED;;;;;;;;;;GAUG;AACH,eAAO,MAAM,QAAQ,yGAKpB,CAAC"}
@@ -0,0 +1,107 @@
1
+ import { lazyPort } from '@endora-commerce/platform/kernel';
2
+ import { pwaModule } from './plugin.js';
3
+ import { createAssetUrlResolver, createChannelCodeResolver, createDefaultChannelIdResolver, createOrderPushTargetResolver, } from './services/cross-module-context.js';
4
+ import { PushMessageDelivery } from './entities/push-message-delivery.entity.js';
5
+ import { PushMessage } from './entities/push-message.entity.js';
6
+ import { PushSubscription } from './entities/push-subscription.entity.js';
7
+ import { PwaIconRendition } from './entities/pwa-icon-rendition.entity.js';
8
+ export function registerModule(ctx) {
9
+ ctx.di.register({
10
+ pwa: ctx
11
+ .asFunction(({ emFactory, redis, pwaRunWorkers }) => {
12
+ // T118c — the three ports that replace `PwaBridge`. Each is a `lazyPort`
13
+ // proxy, so it resolves per call and nothing here captures a
14
+ // registration: a switched-off owner refuses at the call site rather
15
+ // than through a gate frozen when this singleton was built.
16
+ const ports = {
17
+ assets: lazyPort(ctx, 'assetsLibraryPort'),
18
+ channels: lazyPort(ctx, 'salesChannelResolutionPort'),
19
+ orders: lazyPort(ctx, 'orderReadPort'),
20
+ };
21
+ return pwaModule({
22
+ emFactory,
23
+ redis,
24
+ runWorkers: pwaRunWorkers,
25
+ settings: lazyPort(ctx, 'settingsReadPort'),
26
+ settingsWrite: lazyPort(ctx, 'settingsAdminService'),
27
+ // Feature 075, Phase C — the three rows this module used to query out
28
+ // of other modules' tables. `lazyPort` proxies resolve per call, so a
29
+ // switched-off owner answers 503 `MODULE_DISABLED` at the call rather
30
+ // than through a gate frozen at composition time.
31
+ customerAccounts: lazyPort(ctx, 'customerAccountReadPort'),
32
+ organizationDetails: lazyPort(ctx, 'organizationDetailsPort'),
33
+ customerGroups: lazyPort(ctx, 'customerGroupReadPort'),
34
+ requireAdmin: (permission) => async (req, reply) => ctx.cradle().requireAdmin(permission)(req, reply),
35
+ vapidSubject: process.env['PWA_VAPID_SUBJECT'] ?? 'mailto:admin@b2b-platform.local',
36
+ // Pre-route fallback for the FR-024 handlers' log — see
37
+ // `PwaModuleOptions.log`. The module swaps to `app.log` when its
38
+ // routes register.
39
+ log: ctx.log,
40
+ // `AssetsLibraryPort` is a structural supertype of `AssetUploadPort`:
41
+ // the icon pipeline names the one method it calls, and the port
42
+ // satisfies it. That was true before T118c too, which is why draining
43
+ // this member cost nothing but the deletion of two closures.
44
+ assetUpload: ports.assets,
45
+ resolveAssetUrl: createAssetUrlResolver(ports.assets),
46
+ defaultChannelId: createDefaultChannelIdResolver(ports.channels),
47
+ channelCodeForId: createChannelCodeResolver(ports.channels),
48
+ // The platform's contribution, read through the cradle per request so
49
+ // a deployment that supplies its own still wins.
50
+ resolveAuditContext: (request) => ctx.cradle().adminAuditActorResolver(request),
51
+ resolveOrderTarget: createOrderPushTargetResolver(ports.orders),
52
+ // `resolveQuoteTarget` is passed by nobody and never has been — see
53
+ // `PwaModuleOptions`, where the measurement is written down.
54
+ });
55
+ })
56
+ .singleton(),
57
+ });
58
+ /**
59
+ * The two FR-024 auto-triggers (issue #107).
60
+ *
61
+ * They were bare `eventBus.on` calls inside `pwaModule`, so an order reaching
62
+ * its status or a quote request being updated still wrote a `push_messages`
63
+ * row and still pushed to the customer's device with `pwa` switched off — the
64
+ * module's own admin and storefront surfaces refused at the same time, which
65
+ * is what made it invisible. `ctx.subscribe` gates both.
66
+ */
67
+ const handlers = () => ctx.cradle().pwa.handle.pushEventHandlers;
68
+ ctx.subscribe('order.status_changed.v1', async (payload) => {
69
+ await handlers().onOrderStatusChanged(payload);
70
+ });
71
+ ctx.subscribe('quote_request.updated.v1', async (payload) => {
72
+ await handlers().onQuoteRequestUpdated(payload);
73
+ });
74
+ ctx.routes(async (app) => {
75
+ // `ctx.worker` applies `defineModuleWorker('pwa', …)`, which is what puts
76
+ // the push-delivery consumer in the registry the presence reconcile and
77
+ // `pauseWorkersFor` iterate (Constitution XVII). Until this landed the
78
+ // module built the worker and dropped it, so switching `pwa` off refused
79
+ // its admin and storefront surfaces and went on delivering pushes.
80
+ // Attached here rather than at registration for `ksef`'s reason: this is
81
+ // where `app.log` exists, and a `BACKEND_ROLE=worker` process reaches it —
82
+ // `src/worker.ts` builds the server precisely to register module plugins
83
+ // and simply never listens.
84
+ for (const worker of ctx.cradle().pwa.workers) {
85
+ ctx.worker(worker, { logger: app.log });
86
+ }
87
+ await ctx.cradle().pwa.plugin(app);
88
+ });
89
+ }
90
+ /**
91
+ * The module's persisted entity classes, on the `./backend` subpath, as one
92
+ * array and **no named class export** (D-168).
93
+ *
94
+ * This is the shape the platform reads when the package is *installed*: the
95
+ * boot-time loader (`src/packages/package-runtime.ts`, `exported['entities']`)
96
+ * and the static declaration reader (`scripts/lib/package-declarations.ts`),
97
+ * which is the third source of `check:module-boundary`'s `table→owner` map and
98
+ * the package pass of `check-entity-tenant-classification`. A missing array is
99
+ * answered with `[]` — zero entities registered, no error anywhere.
100
+ */
101
+ export const entities = [
102
+ PushMessageDelivery,
103
+ PushMessage,
104
+ PushSubscription,
105
+ PwaIconRendition,
106
+ ];
107
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/backend/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,119 @@
1
+ import type { FastifyInstance, FastifyRequest } from 'fastify';
2
+ import type { EntityManager } from '@mikro-orm/postgresql';
3
+ import type { Redis } from 'ioredis';
4
+ import type { Queue, Worker } from 'bullmq';
5
+ import { z } from 'zod';
6
+ import type { CustomerAccountReadPort, CustomerGroupReadPort, OrganizationDetailsPort } from '@endora-commerce/contracts';
7
+ import { PwaConfigResolver, type SettingsReadPort } from './services/pwa-config-resolver.js';
8
+ import { PwaIconService, type AssetUploadPort } from './services/pwa-icon-service.js';
9
+ import { PushSubscriptionService } from './services/push-subscription-service.js';
10
+ import { PushMessageService } from './services/push-message-service.js';
11
+ import { PushProviderRegistry } from './services/push-provider-registry.js';
12
+ import { createPushEventHandlers, type PushEventLogger, type PushEventTarget } from './services/push-event-subscriber.js';
13
+ import { type PushDeliveryJobData } from './services/push-delivery-queue.js';
14
+ import { type AdminAuditContext, type SettingsWritePort } from './routes.admin.js';
15
+ import type { RequireAdminFactory } from '@endora-commerce/platform/kernel';
16
+ export interface PwaModuleOptions {
17
+ emFactory: () => EntityManager;
18
+ redis: Redis;
19
+ /** Principle X dial — start the push-delivery consumer co-located (true) or only in the worker process. */
20
+ runWorkers: boolean;
21
+ settings: SettingsReadPort & {
22
+ get<T>(code: string, channelId: string, schema: z.ZodType<T>): Promise<T>;
23
+ };
24
+ settingsWrite: SettingsWritePort;
25
+ requireAdmin: RequireAdminFactory;
26
+ /**
27
+ * The three rows this module reads out of other modules (feature 075,
28
+ * Phase C). Resolved as gated ports in `backend.ts`, never captured, so a
29
+ * switched-off owner refuses at the call and not at composition time.
30
+ */
31
+ customerAccounts: CustomerAccountReadPort;
32
+ organizationDetails: OrganizationDetailsPort;
33
+ customerGroups: CustomerGroupReadPort;
34
+ /**
35
+ * The upload half of `assets_library`' published `assetsLibraryPort`, narrowed
36
+ * to the one method the icon pipeline calls
37
+ * (`specs/110-instance-repository/` T118c). `backend/index.ts` resolves the
38
+ * whole port; this names the demand.
39
+ */
40
+ assetUpload: AssetUploadPort;
41
+ resolveAssetUrl: (assetId: string) => Promise<string | null>;
42
+ /**
43
+ * `null` = this deployment has no channel to read for, so `pwa` resolves its
44
+ * configuration platform-wide (feature 072, D-41). It used to fall back to the
45
+ * root's `'default'` sentinel — a channel *code* against a `uuid` column.
46
+ *
47
+ * `resolveChannelIdByCode` stood beside these two until T118c and was called
48
+ * by nothing; see the note in `routes.storefront.ts`.
49
+ */
50
+ defaultChannelId: () => Promise<string | null>;
51
+ channelCodeForId: (channelId: string) => Promise<string | null>;
52
+ resolveAuditContext: (request: FastifyRequest) => AdminAuditContext;
53
+ /** mailto: subject for VAPID. */
54
+ vapidSubject: string;
55
+ /**
56
+ * The module's logger, as the composition can supply it — `ctx.log`. It is
57
+ * the fallback rather than the destination: the FR-024 handlers upgrade to
58
+ * the application's own logger as soon as this module's routes register, and
59
+ * only the window before that (where no event can reach them anyway) lands
60
+ * here.
61
+ */
62
+ log: PushEventLogger;
63
+ /**
64
+ * The FR-024 order-status auto-trigger, and **required** since T118c.
65
+ *
66
+ * It was optional while a composition root had to supply it, on the reasoning
67
+ * that a deployment which pushes on no order event has nothing to give. This
68
+ * module resolves `orderReadPort` itself now and declares the edge, so the
69
+ * absent branch is one no composition can reach — and an option nothing can
70
+ * omit that is nonetheless typed as omittable is a branch no test can drive.
71
+ */
72
+ resolveOrderTarget: (payload: {
73
+ orderId: string;
74
+ salesChannelId: string;
75
+ from: string;
76
+ to: string;
77
+ }) => Promise<PushEventTarget | null>;
78
+ /**
79
+ * The quote-request auto-trigger, and it stays optional because **nothing
80
+ * supplies it**.
81
+ *
82
+ * Measured on the tree T118c drained: `resolveQuoteTarget` appears in this
83
+ * file, in `push-event-subscriber.ts`, in the barrel's `PwaBridge` — and in
84
+ * neither composition root. So `onQuoteRequestUpdated` has returned at its
85
+ * first line on every deployment since the option was written, the handler is
86
+ * registered, the subscription is gated, and the push it exists to send has
87
+ * never been sent by anybody.
88
+ *
89
+ * It is left optional rather than deleted or implemented: implementing it is a
90
+ * design act (a `quote_requests` read port this module does not declare, and a
91
+ * second sentence to compose), and deleting it would erase the only record
92
+ * that the feature was specified. The gap is in T118c's own report.
93
+ */
94
+ resolveQuoteTarget?: (payload: {
95
+ quoteRequestId: string;
96
+ sourceEventId: string;
97
+ }) => Promise<PushEventTarget | null>;
98
+ }
99
+ export interface PwaModuleHandle {
100
+ /** The FR-024 auto-trigger handlers; `backend.ts` owns their registration. */
101
+ pushEventHandlers: ReturnType<typeof createPushEventHandlers>;
102
+ configResolver: PwaConfigResolver;
103
+ iconService: PwaIconService;
104
+ subscriptionService: PushSubscriptionService;
105
+ messageService: PushMessageService;
106
+ providerRegistry: PushProviderRegistry;
107
+ deliveryQueue: Queue<PushDeliveryJobData>;
108
+ }
109
+ export interface PwaModuleResult {
110
+ plugin: (app: FastifyInstance) => Promise<void>;
111
+ handle: PwaModuleHandle;
112
+ /**
113
+ * The push-delivery consumer, for `backend.ts` to hand to `ctx.worker` — the
114
+ * shape `ksef` and `catalog` use. Empty when `runWorkers` is false.
115
+ */
116
+ workers: Worker<PushDeliveryJobData>[];
117
+ }
118
+ export declare function pwaModule(options: PwaModuleOptions): PwaModuleResult;
119
+ //# sourceMappingURL=plugin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../src/backend/plugin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAC/D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC5C,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EACV,uBAAuB,EACvB,qBAAqB,EACrB,uBAAuB,EACxB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,iBAAiB,EAAE,KAAK,gBAAgB,EAAE,MAAM,mCAAmC,CAAC;AAC7F,OAAO,EAAE,cAAc,EAAE,KAAK,eAAe,EAAE,MAAM,gCAAgC,CAAC;AACtF,OAAO,EAAE,uBAAuB,EAAE,MAAM,yCAAyC,CAAC;AAClF,OAAO,EAAE,kBAAkB,EAAE,MAAM,oCAAoC,CAAC;AACxE,OAAO,EAAE,oBAAoB,EAAE,MAAM,sCAAsC,CAAC;AAE5E,OAAO,EACL,uBAAuB,EACvB,KAAK,eAAe,EACpB,KAAK,eAAe,EACrB,MAAM,qCAAqC,CAAC;AAC7C,OAAO,EAGL,KAAK,mBAAmB,EACzB,MAAM,mCAAmC,CAAC;AAK3C,OAAO,EAEL,KAAK,iBAAiB,EACtB,KAAK,iBAAiB,EACvB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AAI5E,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,MAAM,aAAa,CAAC;IAC/B,KAAK,EAAE,KAAK,CAAC;IACb,2GAA2G;IAC3G,UAAU,EAAE,OAAO,CAAC;IACpB,QAAQ,EAAE,gBAAgB,GAAG;QAAE,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAA;KAAE,CAAC;IAC3G,aAAa,EAAE,iBAAiB,CAAC;IACjC,YAAY,EAAE,mBAAmB,CAAC;IAClC;;;;OAIG;IACH,gBAAgB,EAAE,uBAAuB,CAAC;IAC1C,mBAAmB,EAAE,uBAAuB,CAAC;IAC7C,cAAc,EAAE,qBAAqB,CAAC;IACtC;;;;;OAKG;IACH,WAAW,EAAE,eAAe,CAAC;IAC7B,eAAe,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAC7D;;;;;;;OAOG;IACH,gBAAgB,EAAE,MAAM,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAC/C,gBAAgB,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAChE,mBAAmB,EAAE,CAAC,OAAO,EAAE,cAAc,KAAK,iBAAiB,CAAC;IACpE,iCAAiC;IACjC,YAAY,EAAE,MAAM,CAAC;IACrB;;;;;;OAMG;IACH,GAAG,EAAE,eAAe,CAAC;IACrB;;;;;;;;OAQG;IACH,kBAAkB,EAAE,CAAC,OAAO,EAAE;QAC5B,OAAO,EAAE,MAAM,CAAC;QAChB,cAAc,EAAE,MAAM,CAAC;QACvB,IAAI,EAAE,MAAM,CAAC;QACb,EAAE,EAAE,MAAM,CAAC;KACZ,KAAK,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CAAC;IACtC;;;;;;;;;;;;;;;OAeG;IACH,kBAAkB,CAAC,EAAE,CAAC,OAAO,EAAE;QAC7B,cAAc,EAAE,MAAM,CAAC;QACvB,aAAa,EAAE,MAAM,CAAC;KACvB,KAAK,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CAAC;CACvC;AAED,MAAM,WAAW,eAAe;IAC9B,8EAA8E;IAC9E,iBAAiB,EAAE,UAAU,CAAC,OAAO,uBAAuB,CAAC,CAAC;IAC9D,cAAc,EAAE,iBAAiB,CAAC;IAClC,WAAW,EAAE,cAAc,CAAC;IAC5B,mBAAmB,EAAE,uBAAuB,CAAC;IAC7C,cAAc,EAAE,kBAAkB,CAAC;IACnC,gBAAgB,EAAE,oBAAoB,CAAC;IACvC,aAAa,EAAE,KAAK,CAAC,mBAAmB,CAAC,CAAC;CAC3C;AAED,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,CAAC,GAAG,EAAE,eAAe,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAChD,MAAM,EAAE,eAAe,CAAC;IACxB;;;OAGG;IACH,OAAO,EAAE,MAAM,CAAC,mBAAmB,CAAC,EAAE,CAAC;CACxC;AAED,wBAAgB,SAAS,CAAC,OAAO,EAAE,gBAAgB,GAAG,eAAe,CAiHpE"}