@endora-commerce/mod-customer-accounts 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 (127) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +59 -0
  3. package/dist/admin/api/customer-groups-client.d.ts +27 -0
  4. package/dist/admin/api/customer-groups-client.d.ts.map +1 -0
  5. package/dist/admin/api/customer-groups-client.js +17 -0
  6. package/dist/admin/api/customer-groups-client.js.map +1 -0
  7. package/dist/admin/index.d.ts +33 -0
  8. package/dist/admin/index.d.ts.map +1 -0
  9. package/dist/admin/index.js +38 -0
  10. package/dist/admin/index.js.map +1 -0
  11. package/dist/admin/pages/CustomerGroupsPage.d.ts +18 -0
  12. package/dist/admin/pages/CustomerGroupsPage.d.ts.map +1 -0
  13. package/dist/admin/pages/CustomerGroupsPage.js +108 -0
  14. package/dist/admin/pages/CustomerGroupsPage.js.map +1 -0
  15. package/dist/backend/entities/customer-account.entity.d.ts +111 -0
  16. package/dist/backend/entities/customer-account.entity.d.ts.map +1 -0
  17. package/dist/backend/entities/customer-account.entity.js +230 -0
  18. package/dist/backend/entities/customer-account.entity.js.map +1 -0
  19. package/dist/backend/entities/customer-group.entity.d.ts +29 -0
  20. package/dist/backend/entities/customer-group.entity.d.ts.map +1 -0
  21. package/dist/backend/entities/customer-group.entity.js +70 -0
  22. package/dist/backend/entities/customer-group.entity.js.map +1 -0
  23. package/dist/backend/entities/password-reset-token.entity.d.ts +16 -0
  24. package/dist/backend/entities/password-reset-token.entity.d.ts.map +1 -0
  25. package/dist/backend/entities/password-reset-token.entity.js +59 -0
  26. package/dist/backend/entities/password-reset-token.entity.js.map +1 -0
  27. package/dist/backend/index.d.ts +144 -0
  28. package/dist/backend/index.d.ts.map +1 -0
  29. package/dist/backend/index.js +407 -0
  30. package/dist/backend/index.js.map +1 -0
  31. package/dist/backend/routes.admin.d.ts +26 -0
  32. package/dist/backend/routes.admin.d.ts.map +1 -0
  33. package/dist/backend/routes.admin.js +35 -0
  34. package/dist/backend/routes.admin.js.map +1 -0
  35. package/dist/backend/services/audit-references.d.ts +22 -0
  36. package/dist/backend/services/audit-references.d.ts.map +1 -0
  37. package/dist/backend/services/audit-references.js +46 -0
  38. package/dist/backend/services/audit-references.js.map +1 -0
  39. package/dist/backend/services/customer-account-lifecycle-ports.d.ts +168 -0
  40. package/dist/backend/services/customer-account-lifecycle-ports.d.ts.map +1 -0
  41. package/dist/backend/services/customer-account-lifecycle-ports.js +420 -0
  42. package/dist/backend/services/customer-account-lifecycle-ports.js.map +1 -0
  43. package/dist/backend/services/customer-account-ports.d.ts +143 -0
  44. package/dist/backend/services/customer-account-ports.d.ts.map +1 -0
  45. package/dist/backend/services/customer-account-ports.js +422 -0
  46. package/dist/backend/services/customer-account-ports.js.map +1 -0
  47. package/dist/backend/services/customer-auth-service.d.ts +62 -0
  48. package/dist/backend/services/customer-auth-service.d.ts.map +1 -0
  49. package/dist/backend/services/customer-auth-service.js +105 -0
  50. package/dist/backend/services/customer-auth-service.js.map +1 -0
  51. package/dist/backend/services/customer-group-read-port.d.ts +24 -0
  52. package/dist/backend/services/customer-group-read-port.d.ts.map +1 -0
  53. package/dist/backend/services/customer-group-read-port.js +44 -0
  54. package/dist/backend/services/customer-group-read-port.js.map +1 -0
  55. package/dist/backend/services/customer-group-service.d.ts +21 -0
  56. package/dist/backend/services/customer-group-service.d.ts.map +1 -0
  57. package/dist/backend/services/customer-group-service.js +97 -0
  58. package/dist/backend/services/customer-group-service.js.map +1 -0
  59. package/dist/backend/services/customer-rollup-scope.d.ts +30 -0
  60. package/dist/backend/services/customer-rollup-scope.d.ts.map +1 -0
  61. package/dist/backend/services/customer-rollup-scope.js +42 -0
  62. package/dist/backend/services/customer-rollup-scope.js.map +1 -0
  63. package/dist/backend/services/password-reset-service.d.ts +15 -0
  64. package/dist/backend/services/password-reset-service.d.ts.map +1 -0
  65. package/dist/backend/services/password-reset-service.js +90 -0
  66. package/dist/backend/services/password-reset-service.js.map +1 -0
  67. package/dist/backend/services/role-service.d.ts +22 -0
  68. package/dist/backend/services/role-service.d.ts.map +1 -0
  69. package/dist/backend/services/role-service.js +83 -0
  70. package/dist/backend/services/role-service.js.map +1 -0
  71. package/dist/backend/services/two-factor-enrolments.d.ts +18 -0
  72. package/dist/backend/services/two-factor-enrolments.d.ts.map +1 -0
  73. package/dist/backend/services/two-factor-enrolments.js +2 -0
  74. package/dist/backend/services/two-factor-enrolments.js.map +1 -0
  75. package/dist/manifest.d.ts +169 -0
  76. package/dist/manifest.d.ts.map +1 -0
  77. package/dist/manifest.js +212 -0
  78. package/dist/manifest.js.map +1 -0
  79. package/dist/migrations/20260425T055041_customer_accounts_password_reset_tokens.d.ts +6 -0
  80. package/dist/migrations/20260425T055041_customer_accounts_password_reset_tokens.d.ts.map +1 -0
  81. package/dist/migrations/20260425T055041_customer_accounts_password_reset_tokens.js +25 -0
  82. package/dist/migrations/20260425T055041_customer_accounts_password_reset_tokens.js.map +1 -0
  83. package/dist/migrations/20260611T140351_customer_accounts_organization_optional.d.ts +34 -0
  84. package/dist/migrations/20260611T140351_customer_accounts_organization_optional.d.ts.map +1 -0
  85. package/dist/migrations/20260611T140351_customer_accounts_organization_optional.js +43 -0
  86. package/dist/migrations/20260611T140351_customer_accounts_organization_optional.js.map +1 -0
  87. package/dist/migrations/20260611T140403_customer_accounts_lifecycle.d.ts +54 -0
  88. package/dist/migrations/20260611T140403_customer_accounts_lifecycle.d.ts.map +1 -0
  89. package/dist/migrations/20260611T140403_customer_accounts_lifecycle.js +97 -0
  90. package/dist/migrations/20260611T140403_customer_accounts_lifecycle.js.map +1 -0
  91. package/dist/migrations/20260718T200341_customer_accounts_customer_account_custom_field_values.d.ts +12 -0
  92. package/dist/migrations/20260718T200341_customer_accounts_customer_account_custom_field_values.d.ts.map +1 -0
  93. package/dist/migrations/20260718T200341_customer_accounts_customer_account_custom_field_values.js +16 -0
  94. package/dist/migrations/20260718T200341_customer_accounts_customer_account_custom_field_values.js.map +1 -0
  95. package/dist/migrations/20260720T044255_customer_accounts_customer_subtree_rollup.d.ts +14 -0
  96. package/dist/migrations/20260720T044255_customer_accounts_customer_subtree_rollup.d.ts.map +1 -0
  97. package/dist/migrations/20260720T044255_customer_accounts_customer_subtree_rollup.js +18 -0
  98. package/dist/migrations/20260720T044255_customer_accounts_customer_subtree_rollup.js.map +1 -0
  99. package/dist/migrations/20260819T074816_customer_accounts_password_set_at.d.ts +22 -0
  100. package/dist/migrations/20260819T074816_customer_accounts_password_set_at.d.ts.map +1 -0
  101. package/dist/migrations/20260819T074816_customer_accounts_password_set_at.js +26 -0
  102. package/dist/migrations/20260819T074816_customer_accounts_password_set_at.js.map +1 -0
  103. package/dist/migrations/20260819T142837_customer_accounts_fold_email_case.d.ts +46 -0
  104. package/dist/migrations/20260819T142837_customer_accounts_fold_email_case.d.ts.map +1 -0
  105. package/dist/migrations/20260819T142837_customer_accounts_fold_email_case.js +97 -0
  106. package/dist/migrations/20260819T142837_customer_accounts_fold_email_case.js.map +1 -0
  107. package/dist/migrations/20260825T124759_customer_accounts_drop_legacy_two_factor_secret.d.ts +31 -0
  108. package/dist/migrations/20260825T124759_customer_accounts_drop_legacy_two_factor_secret.d.ts.map +1 -0
  109. package/dist/migrations/20260825T124759_customer_accounts_drop_legacy_two_factor_secret.js +35 -0
  110. package/dist/migrations/20260825T124759_customer_accounts_drop_legacy_two_factor_secret.js.map +1 -0
  111. package/dist/migrations/20260825T141659_customer_accounts_organization_required.d.ts +58 -0
  112. package/dist/migrations/20260825T141659_customer_accounts_organization_required.d.ts.map +1 -0
  113. package/dist/migrations/20260825T141659_customer_accounts_organization_required.js +133 -0
  114. package/dist/migrations/20260825T141659_customer_accounts_organization_required.js.map +1 -0
  115. package/dist/migrations/20260912T094701_customer_accounts_sales_channel_customer_accounts.d.ts +27 -0
  116. package/dist/migrations/20260912T094701_customer_accounts_sales_channel_customer_accounts.d.ts.map +1 -0
  117. package/dist/migrations/20260912T094701_customer_accounts_sales_channel_customer_accounts.js +44 -0
  118. package/dist/migrations/20260912T094701_customer_accounts_sales_channel_customer_accounts.js.map +1 -0
  119. package/dist/migrations/index.d.ts +36 -0
  120. package/dist/migrations/index.d.ts.map +1 -0
  121. package/dist/migrations/index.js +47 -0
  122. package/dist/migrations/index.js.map +1 -0
  123. package/docs/customer_accounts.md +38 -0
  124. package/i18n/en.json +30 -0
  125. package/i18n/pl.json +30 -0
  126. package/package.json +94 -0
  127. package/tailwind.css +14 -0
@@ -0,0 +1,230 @@
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 { OrgScoped } from '@endora-commerce/platform/tenancy';
12
+ import { randomUUID } from 'crypto';
13
+ /**
14
+ * CustomerAccount — a user inside an Organization. One email ⇒ at most one
15
+ * CustomerAccount installation-wide (FR-041).
16
+ *
17
+ * `passwordHash` is an argon2id-derived key (see services/password-hasher.ts
18
+ * in the auth module).
19
+ */
20
+ let CustomerAccount = class CustomerAccount {
21
+ [OptionalProps];
22
+ id = randomUUID();
23
+ /**
24
+ * The tenant that scopes this account, and the platform's single unit of
25
+ * tenancy (Principle XI).
26
+ *
27
+ * **Not nullable, since D-178.** Feature 026 US2 relaxed it so the platform
28
+ * could serve "no-org / guest-style" accounts falling back to platform
29
+ * defaults for prices, credit limit, allowed payment and delivery methods and
30
+ * warehouse visibility. Feature 051 replaced that design: an individual (B2C)
31
+ * customer is backed by a single-member **personal** organisation, so the
32
+ * guard always has a concrete tenant and there is no "no-organization"
33
+ * scoping path. The column stayed nullable for another year and three write
34
+ * paths went on producing NULLs — self-registration's two-flush window,
35
+ * federated sign-in (which provisioned no organisation at all), and an admin
36
+ * "un-assign" button. All three are closed, and the column is `NOT NULL`,
37
+ * which is the only refusal available: MikroORM applies its tenant filter to
38
+ * `SELECT` / `UPDATE` / `DELETE` and not to `INSERT`, so nothing in the guard
39
+ * can stop a tenant-less row being written.
40
+ *
41
+ * The account and its organisation are created in **one transaction** — see
42
+ * `CustomerAccountLifecycleWriteService.createStandalone` and the
43
+ * federated-sign-in `autoCreate` in this module's `backend.ts`.
44
+ */
45
+ organizationId;
46
+ email;
47
+ passwordHash;
48
+ /**
49
+ * Issue #222 — when a password somebody supplied was last set on this
50
+ * account. `null` means "no such password is on record", which covers both
51
+ * the account federated sign-in auto-created (its hash is a random pair of
52
+ * UUIDs nobody was told) and every row written before this column existed.
53
+ *
54
+ * It exists because `passwordHash` is NOT NULL for *every* account and
55
+ * therefore answers a different question from the one that matters on a
56
+ * security surface: whether the holder has a credential they can actually
57
+ * use. `SocialLinkService` is the first reader — it refuses to sever an
58
+ * account's last federated identity while this is null.
59
+ *
60
+ * Stamped by every write of a caller-supplied password (registration, the
61
+ * member write port, a redeemed reset token, a self-service change) and
62
+ * deliberately **not** by the generated hash. The anonymization sweep clears
63
+ * it back to null with the hash it scrubs.
64
+ */
65
+ passwordSetAt;
66
+ firstName;
67
+ lastName;
68
+ role = 'regular_user';
69
+ emailVerifiedAt;
70
+ /**
71
+ * Never written, and since 2026-08-28 never **read** either.
72
+ *
73
+ * Its only non-null writer was the superseded customer 2FA path, deleted with
74
+ * `two_factor_secret`, so the published `twoFactorEnabled` derived from it
75
+ * was a provably constant `false` — including on `GET /api/v1/me/customer`,
76
+ * which told a buyer their own account was unprotected while it was not.
77
+ * `CustomerAccountRecord.twoFactorEnabled` is now the live `mfa` enrolment,
78
+ * read through `mfaEnrolmentStatePort`, and nothing in the tree reads this
79
+ * column.
80
+ *
81
+ * It is dead schema kept for one more step: dropping it is a migration on
82
+ * this module's table and is deliberately not folded into the repair of the
83
+ * five derivation sites. Do not read it — the honest answer is `mfa`'s.
84
+ */
85
+ twoFactorConfirmedAt;
86
+ lastLoginAt;
87
+ createdAt = new Date();
88
+ updatedAt = new Date();
89
+ // Feature 055 — Custom Fields Layer value bag (inherits host tenant scope).
90
+ customFieldValues = {};
91
+ deletedAt;
92
+ // ── Feature 040 (Customers) lifecycle extensions ────────────────────────
93
+ /**
94
+ * Direct customer→customer-group membership (FR-022). Independent of the
95
+ * Organization's group: the effective pricing group is
96
+ * `customerGroupId ?? organization.customerGroupId`. FK to `customer_groups`
97
+ * (owned by price_lists), ON DELETE SET NULL.
98
+ */
99
+ customerGroupId;
100
+ /**
101
+ * Feature 056 (T032) — customer-side roll-up capability. When `true`, this
102
+ * login sees/acts across its organization's **subtree** (the tenant scope is
103
+ * widened from single-org to `allowed-set(subtreeIds(theirOrg))` server-side,
104
+ * Principle XI). Default `false` ⇒ node-only (flat behavior). Set only by a
105
+ * platform admin on the org member surface; mirrors the admin/sales-rep
106
+ * `organizations:rollup` capability for a buyer account.
107
+ */
108
+ subtreeRollupEnabled = false;
109
+ /** Non-null ⇒ the account is blocked and login is denied (FR-012/FR-016). */
110
+ blockedAt;
111
+ blockReason;
112
+ /** Who applied the block — drives unblock authority (FR-013/FR-015). */
113
+ blockSource;
114
+ blockedByAdminUserId;
115
+ blockedByCustomerAccountId;
116
+ /** Admin who soft-deleted the account (paired with `deletedAt`, FR-039). */
117
+ deletionRequestedByAdminUserId;
118
+ /**
119
+ * Non-null ⇒ PII has been irreversibly scrubbed by the anonymization sweep
120
+ * after the retention window; restore is no longer possible (FR-040).
121
+ */
122
+ anonymizedAt;
123
+ };
124
+ __decorate([
125
+ PrimaryKey({ type: 'uuid' }),
126
+ __metadata("design:type", String)
127
+ ], CustomerAccount.prototype, "id", void 0);
128
+ __decorate([
129
+ Property({ type: 'uuid' }),
130
+ Index(),
131
+ __metadata("design:type", String)
132
+ ], CustomerAccount.prototype, "organizationId", void 0);
133
+ __decorate([
134
+ Property({ type: 'string', length: 320 }),
135
+ Unique(),
136
+ __metadata("design:type", String)
137
+ ], CustomerAccount.prototype, "email", void 0);
138
+ __decorate([
139
+ Property({ type: 'string', length: 512 }),
140
+ __metadata("design:type", String)
141
+ ], CustomerAccount.prototype, "passwordHash", void 0);
142
+ __decorate([
143
+ Property({ type: 'datetime', nullable: true }),
144
+ __metadata("design:type", Object)
145
+ ], CustomerAccount.prototype, "passwordSetAt", void 0);
146
+ __decorate([
147
+ Property({ type: 'string', length: 120 }),
148
+ __metadata("design:type", String)
149
+ ], CustomerAccount.prototype, "firstName", void 0);
150
+ __decorate([
151
+ Property({ type: 'string', length: 120 }),
152
+ __metadata("design:type", String)
153
+ ], CustomerAccount.prototype, "lastName", void 0);
154
+ __decorate([
155
+ Property({ type: 'string', length: 32 }),
156
+ Index(),
157
+ __metadata("design:type", String)
158
+ ], CustomerAccount.prototype, "role", void 0);
159
+ __decorate([
160
+ Property({ type: 'datetime', nullable: true }),
161
+ __metadata("design:type", Object)
162
+ ], CustomerAccount.prototype, "emailVerifiedAt", void 0);
163
+ __decorate([
164
+ Property({ type: 'datetime', nullable: true }),
165
+ __metadata("design:type", Object)
166
+ ], CustomerAccount.prototype, "twoFactorConfirmedAt", void 0);
167
+ __decorate([
168
+ Property({ type: 'datetime', nullable: true }),
169
+ __metadata("design:type", Object)
170
+ ], CustomerAccount.prototype, "lastLoginAt", void 0);
171
+ __decorate([
172
+ Property({ type: 'datetime', onCreate: () => new Date() }),
173
+ __metadata("design:type", Date)
174
+ ], CustomerAccount.prototype, "createdAt", void 0);
175
+ __decorate([
176
+ Property({ type: 'datetime', onUpdate: () => new Date() }),
177
+ __metadata("design:type", Date)
178
+ ], CustomerAccount.prototype, "updatedAt", void 0);
179
+ __decorate([
180
+ Property({ type: 'json' }),
181
+ __metadata("design:type", Object)
182
+ ], CustomerAccount.prototype, "customFieldValues", void 0);
183
+ __decorate([
184
+ Property({ type: 'datetime', nullable: true }),
185
+ __metadata("design:type", Object)
186
+ ], CustomerAccount.prototype, "deletedAt", void 0);
187
+ __decorate([
188
+ Property({ type: 'uuid', nullable: true }),
189
+ Index(),
190
+ __metadata("design:type", Object)
191
+ ], CustomerAccount.prototype, "customerGroupId", void 0);
192
+ __decorate([
193
+ Property({ type: 'boolean' }),
194
+ __metadata("design:type", Boolean)
195
+ ], CustomerAccount.prototype, "subtreeRollupEnabled", void 0);
196
+ __decorate([
197
+ Property({ type: 'datetime', nullable: true }),
198
+ Index(),
199
+ __metadata("design:type", Object)
200
+ ], CustomerAccount.prototype, "blockedAt", void 0);
201
+ __decorate([
202
+ Property({ type: 'text', nullable: true }),
203
+ __metadata("design:type", Object)
204
+ ], CustomerAccount.prototype, "blockReason", void 0);
205
+ __decorate([
206
+ Property({ type: 'string', length: 16, nullable: true }),
207
+ __metadata("design:type", Object)
208
+ ], CustomerAccount.prototype, "blockSource", void 0);
209
+ __decorate([
210
+ Property({ type: 'uuid', nullable: true }),
211
+ __metadata("design:type", Object)
212
+ ], CustomerAccount.prototype, "blockedByAdminUserId", void 0);
213
+ __decorate([
214
+ Property({ type: 'uuid', nullable: true }),
215
+ __metadata("design:type", Object)
216
+ ], CustomerAccount.prototype, "blockedByCustomerAccountId", void 0);
217
+ __decorate([
218
+ Property({ type: 'uuid', nullable: true }),
219
+ __metadata("design:type", Object)
220
+ ], CustomerAccount.prototype, "deletionRequestedByAdminUserId", void 0);
221
+ __decorate([
222
+ Property({ type: 'datetime', nullable: true }),
223
+ __metadata("design:type", Object)
224
+ ], CustomerAccount.prototype, "anonymizedAt", void 0);
225
+ CustomerAccount = __decorate([
226
+ OrgScoped(),
227
+ Entity({ tableName: 'customer_accounts' })
228
+ ], CustomerAccount);
229
+ export { CustomerAccount };
230
+ //# sourceMappingURL=customer-account.entity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"customer-account.entity.js","sourceRoot":"","sources":["../../../src/backend/entities/customer-account.entity.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ import { OptionalProps } from '@mikro-orm/core';
2
+ /**
3
+ * CustomerGroup — the segmentation bucket a customer belongs to.
4
+ *
5
+ * A customer account carries one directly (`CustomerAccount.customerGroupId`,
6
+ * a real foreign key into this table with `on delete set null`) and inherits
7
+ * its Organization's (`Organization.customerGroupId`, an indexed column with no
8
+ * constraint) when it has none of its own. Groups have no behavioural state of
9
+ * their own; they exist as an addressable target — for the feature 011
10
+ * Application Rule's `customerGroup` criterion, for a promotion's audience and
11
+ * for a push audience rule.
12
+ *
13
+ * Feature 076 (D-79) moved this class here from `price_lists`. Table ownership
14
+ * resolves from the module directory the decorated class lives in — its
15
+ * `tableName` read out of the entity decorator below — so the move *is* the
16
+ * ownership change; no SQL was written, the creating migration stayed in
17
+ * `price_lists/migrations/`, and the foreign key from `customer_accounts`
18
+ * became intra-module.
19
+ */
20
+ export declare class CustomerGroup {
21
+ [OptionalProps]?: 'id' | 'createdAt' | 'updatedAt' | 'description';
22
+ id: string;
23
+ code: string;
24
+ name: string;
25
+ description?: string | null;
26
+ createdAt: Date;
27
+ updatedAt: Date;
28
+ }
29
+ //# sourceMappingURL=customer-group.entity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"customer-group.entity.d.ts","sourceRoot":"","sources":["../../../src/backend/entities/customer-group.entity.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,aAAa,EAAgC,MAAM,iBAAiB,CAAC;AAItF;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAEa,aAAa;IACxB,CAAC,aAAa,CAAC,CAAC,EAAE,IAAI,GAAG,WAAW,GAAG,WAAW,GAAG,aAAa,CAAC;IAGnE,EAAE,EAAE,MAAM,CAAgB;IAI1B,IAAI,EAAG,MAAM,CAAC;IAGd,IAAI,EAAG,MAAM,CAAC;IAGd,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAG5B,SAAS,EAAE,IAAI,CAAc;IAG7B,SAAS,EAAE,IAAI,CAAc;CAC9B"}
@@ -0,0 +1,70 @@
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
+ * CustomerGroup — the segmentation bucket a customer belongs to.
15
+ *
16
+ * A customer account carries one directly (`CustomerAccount.customerGroupId`,
17
+ * a real foreign key into this table with `on delete set null`) and inherits
18
+ * its Organization's (`Organization.customerGroupId`, an indexed column with no
19
+ * constraint) when it has none of its own. Groups have no behavioural state of
20
+ * their own; they exist as an addressable target — for the feature 011
21
+ * Application Rule's `customerGroup` criterion, for a promotion's audience and
22
+ * for a push audience rule.
23
+ *
24
+ * Feature 076 (D-79) moved this class here from `price_lists`. Table ownership
25
+ * resolves from the module directory the decorated class lives in — its
26
+ * `tableName` read out of the entity decorator below — so the move *is* the
27
+ * ownership change; no SQL was written, the creating migration stayed in
28
+ * `price_lists/migrations/`, and the foreign key from `customer_accounts`
29
+ * became intra-module.
30
+ */
31
+ let CustomerGroup = class CustomerGroup {
32
+ [OptionalProps];
33
+ id = randomUUID();
34
+ code;
35
+ name;
36
+ description;
37
+ createdAt = new Date();
38
+ updatedAt = new Date();
39
+ };
40
+ __decorate([
41
+ PrimaryKey({ type: 'uuid' }),
42
+ __metadata("design:type", String)
43
+ ], CustomerGroup.prototype, "id", void 0);
44
+ __decorate([
45
+ Property({ type: 'string', length: 64 }),
46
+ Unique(),
47
+ __metadata("design:type", String)
48
+ ], CustomerGroup.prototype, "code", void 0);
49
+ __decorate([
50
+ Property({ type: 'string', length: 160 }),
51
+ __metadata("design:type", String)
52
+ ], CustomerGroup.prototype, "name", void 0);
53
+ __decorate([
54
+ Property({ type: 'string', length: 1000, nullable: true }),
55
+ __metadata("design:type", Object)
56
+ ], CustomerGroup.prototype, "description", void 0);
57
+ __decorate([
58
+ Property({ type: 'datetime', onCreate: () => new Date() }),
59
+ __metadata("design:type", Date)
60
+ ], CustomerGroup.prototype, "createdAt", void 0);
61
+ __decorate([
62
+ Property({ type: 'datetime', onUpdate: () => new Date() }),
63
+ __metadata("design:type", Date)
64
+ ], CustomerGroup.prototype, "updatedAt", void 0);
65
+ CustomerGroup = __decorate([
66
+ GlobalEntity(),
67
+ Entity({ tableName: 'customer_groups' })
68
+ ], CustomerGroup);
69
+ export { CustomerGroup };
70
+ //# sourceMappingURL=customer-group.entity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"customer-group.entity.js","sourceRoot":"","sources":["../../../src/backend/entities/customer-group.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;AAEpC;;;;;;;;;;;;;;;;;GAiBG;AAGI,IAAM,aAAa,GAAnB,MAAM,aAAa;IACxB,CAAC,aAAa,CAAC,CAAoD;IAGnE,EAAE,GAAW,UAAU,EAAE,CAAC;IAI1B,IAAI,CAAU;IAGd,IAAI,CAAU;IAGd,WAAW,CAAiB;IAG5B,SAAS,GAAS,IAAI,IAAI,EAAE,CAAC;IAG7B,SAAS,GAAS,IAAI,IAAI,EAAE,CAAC;CAC9B,CAAA;AAjBC;IADC,UAAU,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;;yCACH;AAI1B;IAFC,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;IACxC,MAAM,EAAE;;2CACK;AAGd;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC;;2CAC5B;AAGd;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;kDAC/B;AAG5B;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,IAAI,IAAI,EAAE,EAAE,CAAC;8BAChD,IAAI;gDAAc;AAG7B;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,IAAI,IAAI,EAAE,EAAE,CAAC;8BAChD,IAAI;gDAAc;AApBlB,aAAa;IAFzB,YAAY,EAAE;IACd,MAAM,CAAC,EAAE,SAAS,EAAE,iBAAiB,EAAE,CAAC;GAC5B,aAAa,CAqBzB"}
@@ -0,0 +1,16 @@
1
+ import { OptionalProps } from '@mikro-orm/core';
2
+ /**
3
+ * One-shot password-reset token. Same shape as EmailVerificationToken — sha256
4
+ * hash stored, expires_at + consumed_at one-shot. Issued by the public
5
+ * /auth/password-reset/request endpoint.
6
+ */
7
+ export declare class PasswordResetToken {
8
+ [OptionalProps]?: 'id' | 'createdAt' | 'consumedAt';
9
+ id: string;
10
+ customerAccountId: string;
11
+ tokenHash: string;
12
+ expiresAt: Date;
13
+ consumedAt?: Date | null;
14
+ createdAt: Date;
15
+ }
16
+ //# sourceMappingURL=password-reset-token.entity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"password-reset-token.entity.d.ts","sourceRoot":"","sources":["../../../src/backend/entities/password-reset-token.entity.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,aAAa,EAAgC,MAAM,iBAAiB,CAAC;AAI7F;;;;GAIG;AACH,qBAEa,kBAAkB;IAC7B,CAAC,aAAa,CAAC,CAAC,EAAE,IAAI,GAAG,WAAW,GAAG,YAAY,CAAC;IAGpD,EAAE,EAAE,MAAM,CAAgB;IAI1B,iBAAiB,EAAG,MAAM,CAAC;IAI3B,SAAS,EAAG,MAAM,CAAC;IAInB,SAAS,EAAG,IAAI,CAAC;IAGjB,UAAU,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IAGzB,SAAS,EAAE,IAAI,CAAc;CAC9B"}
@@ -0,0 +1,59 @@
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
+ * One-shot password-reset token. Same shape as EmailVerificationToken — sha256
15
+ * hash stored, expires_at + consumed_at one-shot. Issued by the public
16
+ * /auth/password-reset/request endpoint.
17
+ */
18
+ let PasswordResetToken = class PasswordResetToken {
19
+ [OptionalProps];
20
+ id = randomUUID();
21
+ customerAccountId;
22
+ tokenHash;
23
+ expiresAt;
24
+ consumedAt;
25
+ createdAt = new Date();
26
+ };
27
+ __decorate([
28
+ PrimaryKey({ type: 'uuid' }),
29
+ __metadata("design:type", String)
30
+ ], PasswordResetToken.prototype, "id", void 0);
31
+ __decorate([
32
+ Property({ type: 'uuid' }),
33
+ Index(),
34
+ __metadata("design:type", String)
35
+ ], PasswordResetToken.prototype, "customerAccountId", void 0);
36
+ __decorate([
37
+ Property({ type: 'string', length: 128 }),
38
+ Unique(),
39
+ __metadata("design:type", String)
40
+ ], PasswordResetToken.prototype, "tokenHash", void 0);
41
+ __decorate([
42
+ Property({ type: 'datetime' }),
43
+ Index(),
44
+ __metadata("design:type", Date)
45
+ ], PasswordResetToken.prototype, "expiresAt", void 0);
46
+ __decorate([
47
+ Property({ type: 'datetime', nullable: true }),
48
+ __metadata("design:type", Object)
49
+ ], PasswordResetToken.prototype, "consumedAt", void 0);
50
+ __decorate([
51
+ Property({ type: 'datetime', onCreate: () => new Date() }),
52
+ __metadata("design:type", Date)
53
+ ], PasswordResetToken.prototype, "createdAt", void 0);
54
+ PasswordResetToken = __decorate([
55
+ CustomerScoped(),
56
+ Entity({ tableName: 'password_reset_tokens' })
57
+ ], PasswordResetToken);
58
+ export { PasswordResetToken };
59
+ //# sourceMappingURL=password-reset-token.entity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"password-reset-token.entity.js","sourceRoot":"","sources":["../../../src/backend/entities/password-reset-token.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;;;;GAIG;AAGI,IAAM,kBAAkB,GAAxB,MAAM,kBAAkB;IAC7B,CAAC,aAAa,CAAC,CAAqC;IAGpD,EAAE,GAAW,UAAU,EAAE,CAAC;IAI1B,iBAAiB,CAAU;IAI3B,SAAS,CAAU;IAInB,SAAS,CAAQ;IAGjB,UAAU,CAAe;IAGzB,SAAS,GAAS,IAAI,IAAI,EAAE,CAAC;CAC9B,CAAA;AAnBC;IADC,UAAU,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;;8CACH;AAI1B;IAFC,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;IAC1B,KAAK,EAAE;;6DACmB;AAI3B;IAFC,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC;IACzC,MAAM,EAAE;;qDACU;AAInB;IAFC,QAAQ,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC;IAC9B,KAAK,EAAE;8BACI,IAAI;qDAAC;AAGjB;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;sDACtB;AAGzB;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,IAAI,IAAI,EAAE,EAAE,CAAC;8BAChD,IAAI;qDAAc;AAtBlB,kBAAkB;IAF9B,cAAc,EAAE;IAChB,MAAM,CAAC,EAAE,SAAS,EAAE,uBAAuB,EAAE,CAAC;GAClC,kBAAkB,CAuB9B"}
@@ -0,0 +1,144 @@
1
+ import type { EntityManager } from '@mikro-orm/postgresql';
2
+ import type { ChannelMemberEntityType } from '@endora-commerce/contracts';
3
+ import type { AuditPort } from '@endora-commerce/platform/kernel';
4
+ import type { CommandBus } from '@endora-commerce/platform/commands';
5
+ import type { ModuleContext } from '@endora-commerce/platform/kernel';
6
+ import type { RequireAdminFactory } from '@endora-commerce/platform/kernel';
7
+ import type { SettingsReadPort } from '@endora-commerce/platform/kernel';
8
+ import { CustomerAccount } from './entities/customer-account.entity.js';
9
+ import { CustomerGroup } from './entities/customer-group.entity.js';
10
+ import { PasswordResetToken } from './entities/password-reset-token.entity.js';
11
+ import { CustomerAuthService } from './services/customer-auth-service.js';
12
+ import { CustomerGroupService } from './services/customer-group-service.js';
13
+ import { PasswordResetService } from './services/password-reset-service.js';
14
+ import { RoleService } from './services/role-service.js';
15
+ /**
16
+ * `customer_accounts` — one customer auth service, where there were two
17
+ * (feature 072, wave 1, T094).
18
+ *
19
+ * The module owns no routes: `organizations` serves customer login and
20
+ * registration, `customers` serves the self-service surface. Both built their
21
+ * own `CustomerAuthService`, and the third constructor argument differed:
22
+ *
23
+ * organizations: new CustomerAuthService(em, sessions, options.getMfaLoginPort, audit)
24
+ * customers: new CustomerAuthService(em, sessions, undefined, audit)
25
+ * ^ "not wired in the
26
+ * customers composition"
27
+ *
28
+ * That comment was accurate rather than careless, and this is **not** a live
29
+ * MFA bypass today: `getMfaLoginPort` is consulted only inside `login()`, the
30
+ * single login route lives in `organizations`, and the `customers` instance is
31
+ * used only for `changePassword`. What it is, is the `addresses` shape — two
32
+ * instances of one service that are not required to agree, one of which cannot
33
+ * enforce a second factor. The day a customer-side route needs `login()`, the
34
+ * divergence stops being latent, and nothing in the tree would flag it.
35
+ *
36
+ * `PasswordResetService` was doubled the same way, with identical arguments.
37
+ *
38
+ * **The MFA port is resolved here now, behind a presence probe** (D-96). It was
39
+ * a contribution both roots filled from one getter — a root resolving a gated
40
+ * port on this module's behalf, which is composition checklist item 6 — and the
41
+ * harness captured that gate at compose time, so `mfa` switched off was
42
+ * unobservable. The edge is declared `degrades-without` in this module's
43
+ * manifest: `mfa` declares `customer_accounts`, so the ordinary declaration
44
+ * would close a cycle and would make customer login refuse the operator's flip.
45
+ *
46
+ * Everything here is a **port**: `organizations` and `customers` resolve these
47
+ * services across a module boundary, so an operator switching customer accounts
48
+ * off should get an explicit 503 rather than a service that half-answers.
49
+ *
50
+ * `customerOrgResolver` moves here from `HOST_REGISTERED_PORTS`, where a
51
+ * composition root stood in for this module. `auth` reads it in its request
52
+ * hook to attach the organization to a customer session; the lookup is a plain
53
+ * read of this module's own table, so it belongs to this module and the root's
54
+ * entry goes away.
55
+ *
56
+ * **Social-login account creation came home in T143a cluster 6, and the two
57
+ * roots disagreed about what it does.** Both wrote `mfaSocialAccountResolvers`
58
+ * closures that read and created rows in this module's table. Production gated
59
+ * the creation on `customers.allow_registration_without_organization`, which
60
+ * ships **off**; the harness gated it on nothing, so federated sign-in
61
+ * auto-created an account in every test run and the gate itself was covered by
62
+ * no test — a policy the platform has and the suite denied. Production
63
+ * system-scoped the identity read (tenancy comes after identity) and the
64
+ * harness did not, and production minted a random password where the harness
65
+ * hashed one fixed string for every auto-created account. One implementation
66
+ * now, and it is this module's, because the table is.
67
+ */
68
+ export interface CustomerAccountsCradle {
69
+ /**
70
+ * Feature 120 (FR-015) — the platform's channel-bridge registry, resolved by
71
+ * **container name** rather than imported. The shape is the narrow one this
72
+ * module needs, which is what `ctx.cradle<C>()` asks an author to declare;
73
+ * the registry itself is the kernel's and is published on no barrel.
74
+ */
75
+ readonly salesChannelBridgeRegistry: {
76
+ register(bridge: {
77
+ entityType: ChannelMemberEntityType;
78
+ table: string;
79
+ entityIdColumn: string;
80
+ }): void;
81
+ };
82
+ readonly emFactory: () => EntityManager;
83
+ readonly auditLogService: AuditPort;
84
+ /** Feature 054 — the customer-group writes audit co-transactionally. */
85
+ readonly commandBus: CommandBus;
86
+ /** `auth`'s admin guard, for the customer-group admin routes. */
87
+ readonly requireAdmin: RequireAdminFactory;
88
+ readonly settingsReadPort: SettingsReadPort;
89
+ /**
90
+ * Which channel a global-scope settings read resolves against — the
91
+ * deployment's system-default channel. A property of the deployment, so a
92
+ * root supplies it; `inventory` reads the same name.
93
+ */
94
+ readonly settingsChannelResolver: () => Promise<string | null>;
95
+ /**
96
+ * The two customer-side halves of `mfa`'s `SocialIdentityDeps` (T143a): match
97
+ * a verified provider e-mail to an account, and create one when nothing
98
+ * matches and the platform allows an org-less registration.
99
+ */
100
+ readonly customerSocialLoginPort: {
101
+ resolveByEmail(email: string): Promise<{
102
+ id: string;
103
+ } | null>;
104
+ autoCreate(email: string): Promise<{
105
+ id: string;
106
+ } | null>;
107
+ };
108
+ readonly customerAuthService: CustomerAuthService;
109
+ readonly passwordResetService: PasswordResetService;
110
+ readonly customerRoleService: RoleService;
111
+ readonly customerGroupService: CustomerGroupService;
112
+ }
113
+ export declare function registerModule(ctx: ModuleContext): void;
114
+ /**
115
+ * The module's persisted entity classes, on the `./backend` subpath, as one
116
+ * array and **no named class export** (D-168).
117
+ *
118
+ * This is the shape the platform reads when the package is *installed*: the
119
+ * boot-time loader (`src/packages/package-runtime.ts`, `exported['entities']`)
120
+ * and the static declaration reader (`scripts/lib/package-declarations.ts`),
121
+ * which is the third source of `check:module-boundary`'s `table->owner` map and
122
+ * the package pass of `check-entity-tenant-classification`. A missing array is
123
+ * answered with `[]` — zero entities registered, no error anywhere.
124
+ *
125
+ * The order is the one `db/entities-registry.generated.ts` declared before this
126
+ * module became a package, so the registered set is the same list in the same
127
+ * sequence.
128
+ */
129
+ export declare const entities: (typeof CustomerAccount | typeof CustomerGroup | typeof PasswordResetToken)[];
130
+ /**
131
+ * The sales-channel membership bridge this module owns (feature 120, FR-015).
132
+ *
133
+ * Exported as well as registered because the owning module is the only honest
134
+ * source for it: a caller that composes no platform — the bare-database test
135
+ * harness, which constructs the kernel's membership service directly — declares
136
+ * these from here rather than from a list of nine it keeps itself, which is
137
+ * exactly the total map this feature deleted.
138
+ */
139
+ export declare const salesChannelBridges: ReadonlyArray<{
140
+ readonly entityType: ChannelMemberEntityType;
141
+ readonly table: string;
142
+ readonly entityIdColumn: string;
143
+ }>;
144
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/backend/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAE3D,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,4BAA4B,CAAC;AAmB1E,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kCAAkC,CAAC;AAClE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oCAAoC,CAAC;AAGrE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kCAAkC,CAAC;AAItE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AAC5E,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AAIzE,OAAO,EAAE,eAAe,EAAE,MAAM,uCAAuC,CAAC;AACxE,OAAO,EAAE,aAAa,EAAE,MAAM,qCAAqC,CAAC;AACpE,OAAO,EAAE,kBAAkB,EAAE,MAAM,2CAA2C,CAAC;AAc/E,OAAO,EAAE,mBAAmB,EAAE,MAAM,qCAAqC,CAAC;AAE1E,OAAO,EAAE,oBAAoB,EAAE,MAAM,sCAAsC,CAAC;AAE5E,OAAO,EAAE,oBAAoB,EAAE,MAAM,sCAAsC,CAAC;AAC5E,OAAO,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAGzD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoDG;AAEH,MAAM,WAAW,sBAAsB;IACrC;;;;;OAKG;IACH,QAAQ,CAAC,0BAA0B,EAAE;QACnC,QAAQ,CAAC,MAAM,EAAE;YACf,UAAU,EAAE,uBAAuB,CAAC;YACpC,KAAK,EAAE,MAAM,CAAC;YACd,cAAc,EAAE,MAAM,CAAC;SACxB,GAAG,IAAI,CAAC;KACV,CAAC;IACF,QAAQ,CAAC,SAAS,EAAE,MAAM,aAAa,CAAC;IACxC,QAAQ,CAAC,eAAe,EAAE,SAAS,CAAC;IACpC,wEAAwE;IACxE,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC;IAChC,iEAAiE;IACjE,QAAQ,CAAC,YAAY,EAAE,mBAAmB,CAAC;IAC3C,QAAQ,CAAC,gBAAgB,EAAE,gBAAgB,CAAC;IAC5C;;;;OAIG;IACH,QAAQ,CAAC,uBAAuB,EAAE,MAAM,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAC/D;;;;OAIG;IACH,QAAQ,CAAC,uBAAuB,EAAE;QAChC,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;YAAE,EAAE,EAAE,MAAM,CAAA;SAAE,GAAG,IAAI,CAAC,CAAC;QAC9D,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;YAAE,EAAE,EAAE,MAAM,CAAA;SAAE,GAAG,IAAI,CAAC,CAAC;KAC3D,CAAC;IACF,QAAQ,CAAC,mBAAmB,EAAE,mBAAmB,CAAC;IAClD,QAAQ,CAAC,oBAAoB,EAAE,oBAAoB,CAAC;IACpD,QAAQ,CAAC,mBAAmB,EAAE,WAAW,CAAC;IAC1C,QAAQ,CAAC,oBAAoB,EAAE,oBAAoB,CAAC;CACrD;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI,CA0evD;AAED;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,QAAQ,+EAAuD,CAAC;AAE7E;;;;;;;;GAQG;AACH,eAAO,MAAM,mBAAmB,EAAE,aAAa,CAAC;IAC9C,QAAQ,CAAC,UAAU,EAAE,uBAAuB,CAAC;IAC7C,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;CACjC,CAEA,CAAC"}