@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
|
@@ -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":"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"}
|