@reventlessdev/online-shop-hybrid-ordering 1.0.0-alpha.300 → 1.0.0-alpha.301
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/CHANGELOG.md +8 -0
- package/package.json +9 -9
- package/src/Customer/Aggregate/Customer.res +6 -6
- package/src/Customer/Aggregate/Customer.res.mjs +9 -8
- package/src/Customer/Aggregate/Customer_Decision.res +40 -14
- package/src/Customer/Aggregate/Customer_Decision.res.mjs +43 -18
- package/src/Customer/OutboundTranslation/GeocodeCustomerAddress.res +3 -3
- package/src/Customer/OutboundTranslation/GeocodeCustomerAddress.res.mjs +5 -4
- package/src/Customer/OutboundTranslation/GeocodeCustomerAddress_Translation.res +9 -2
- package/src/Customer/OutboundTranslation/GeocodeCustomerAddress_Translation.res.mjs +21 -5
- package/src/Customer/OutboundTranslation/VerifyCustomerEmail.res +4 -4
- package/src/Customer/OutboundTranslation/VerifyCustomerEmail.res.mjs +6 -5
- package/src/Customer/OutboundTranslation/VerifyCustomerEmail_Translation.res +4 -2
- package/src/Customer/OutboundTranslation/VerifyCustomerEmail_Translation.res.mjs +21 -5
- package/src/Customer/ReadModelStream/Customers_Projections.res +11 -1
- package/src/Customer/ReadModelStream/Customers_Projections.res.mjs +6 -5
- package/src/Customer/StateChange/EmailVerificationChallenges.res +8 -8
- package/src/Customer/StateChange/EmailVerificationChallenges.res.mjs +9 -8
- package/src/Customer/StateChange/EmailVerificationChallenges_Decision.res +6 -4
- package/src/Customer/StateChange/EmailVerificationChallenges_Decision.res.mjs +15 -5
- package/src/Notification/OutboundTranslation/AnnounceRecipientContact.res +4 -4
- package/src/Notification/OutboundTranslation/AnnounceRecipientContact.res.mjs +5 -4
- package/src/Notification/OutboundTranslation/AnnounceRecipientContact_Translation.res +6 -2
- package/src/Notification/OutboundTranslation/AnnounceRecipientContact_Translation.res.mjs +21 -5
- package/src/Notification/OutboundTranslation/SendNotification.res +4 -4
- package/src/Notification/OutboundTranslation/SendNotification.res.mjs +5 -4
- package/src/Notification/OutboundTranslation/SendNotification_Translation.res +10 -3
- package/src/Notification/OutboundTranslation/SendNotification_Translation.res.mjs +28 -11
- package/src/Notification/StateChange/NotificationPreferences.res +6 -6
- package/src/Notification/StateChange/NotificationPreferences.res.mjs +7 -6
- package/src/Notification/StateChange/NotificationPreferences_Decision.res +15 -5
- package/src/Notification/StateChange/NotificationPreferences_Decision.res.mjs +26 -9
- package/src/Notification/StateViewStream/NotificationSubscriptions.res +1 -1
- package/src/Notification/StateViewStream/NotificationSubscriptions.res.mjs +2 -1
- package/src/Notification/StateViewStream/NotificationSubscriptions_Projection.res +4 -1
- package/src/Notification/StateViewStream/NotificationSubscriptions_Projection.res.mjs +11 -3
- package/tests/Customer/AddressGeocodingConformance_GWT.res +17 -7
- package/tests/Customer/AddressGeocodingConformance_GWT.res.mjs +36 -9
- package/tests/Customer/Aggregate/Customer_GWT.res +29 -29
- package/tests/Customer/Aggregate/Customer_GWT.res.mjs +188 -47
- package/tests/Customer/OutboundTranslation/VerifyCustomerEmail_GWT.res +2 -2
- package/tests/Customer/OutboundTranslation/VerifyCustomerEmail_GWT.res.mjs +12 -3
- package/tests/Customer/ReadModelStream/Customers_GWT.res +29 -14
- package/tests/Customer/ReadModelStream/Customers_GWT.res.mjs +88 -22
- package/tests/Customer/StateChange/EmailVerificationChallenges_GWT.res +17 -9
- package/tests/Customer/StateChange/EmailVerificationChallenges_GWT.res.mjs +38 -9
- package/tests/Notification/NotificationConformance_GWT.res +9 -6
- package/tests/Notification/NotificationConformance_GWT.res.mjs +24 -6
- package/tests/Notification/OutboundTranslation/AnnounceRecipientContact_GWT.res +2 -2
- package/tests/Notification/OutboundTranslation/AnnounceRecipientContact_GWT.res.mjs +8 -2
- package/tests/Notification/OutboundTranslation/SendNotification_GWT.res +2 -2
- package/tests/Notification/OutboundTranslation/SendNotification_GWT.res.mjs +8 -2
- package/tests/Notification/StateChange/NotificationPreferences_GWT.res +3 -3
- package/tests/Notification/StateChange/NotificationPreferences_GWT.res.mjs +12 -3
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,14 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
# 1.0.0-alpha.301 (2026-10-30)
|
|
7
|
+
|
|
8
|
+
### Features
|
|
9
|
+
|
|
10
|
+
* **examples:** the customer's email and address are marked personal data ([768e985](https://github.com/ReventlessDev/reventless-core/commit/768e9853c4943eaad8926b9cb4df55e2a54f4fa8))
|
|
11
|
+
* **trait-address-geocoding:** the address is personal data ([865d811](https://github.com/ReventlessDev/reventless-core/commit/865d811b0dc801a32d7f9de3a50e7a5089a13b48))
|
|
12
|
+
|
|
13
|
+
|
|
6
14
|
# 1.0.0-alpha.300 (2026-10-30)
|
|
7
15
|
|
|
8
16
|
**Note:** Version bump only for package @reventlessdev/online-shop-hybrid-ordering
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@reventlessdev/online-shop-hybrid-ordering",
|
|
3
|
-
"version": "1.0.0-alpha.
|
|
3
|
+
"version": "1.0.0-alpha.301",
|
|
4
4
|
"description": "Online Shop Hybrid example — Ordering plugin (Customer aggregate + Order/CatalogProduct DCB)",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"jest": {
|
|
@@ -21,15 +21,15 @@
|
|
|
21
21
|
},
|
|
22
22
|
"dependencies": {
|
|
23
23
|
"sury": "11.0.0",
|
|
24
|
-
"@reventlessdev/online-shop-hybrid-
|
|
25
|
-
"@reventlessdev/
|
|
24
|
+
"@reventlessdev/online-shop-hybrid-ordering-spec": "1.0.0-alpha.185",
|
|
25
|
+
"@reventlessdev/reventless-gwt": "1.0.0-alpha.269",
|
|
26
|
+
"@reventlessdev/online-shop-hybrid-catalog-spec": "1.0.0-alpha.186",
|
|
26
27
|
"@reventlessdev/rescript-pulumi-pulumi": "3.0.0-alpha.0",
|
|
27
|
-
"@reventlessdev/reventless-infra": "3.0.0-alpha.
|
|
28
|
-
"@reventlessdev/reventless-
|
|
29
|
-
"@reventlessdev/reventless-local": "3.0.0-alpha.
|
|
30
|
-
"@reventlessdev/trait-
|
|
31
|
-
"@reventlessdev/
|
|
32
|
-
"@reventlessdev/trait-notification": "1.0.0-alpha.70"
|
|
28
|
+
"@reventlessdev/reventless-infra": "3.0.0-alpha.218",
|
|
29
|
+
"@reventlessdev/reventless-spec": "3.0.0-alpha.189",
|
|
30
|
+
"@reventlessdev/reventless-local": "3.0.0-alpha.312",
|
|
31
|
+
"@reventlessdev/trait-notification": "1.0.0-alpha.71",
|
|
32
|
+
"@reventlessdev/trait-address-geocoding": "1.0.0-alpha.71"
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
35
|
"rescript": "12.3.1",
|
|
@@ -27,8 +27,8 @@ module Id = CustomerId
|
|
|
27
27
|
// wins. That is the whole reason `resolvedFrom` exists.
|
|
28
28
|
@schema
|
|
29
29
|
type command =
|
|
30
|
-
| Register({email: string, address: string})
|
|
31
|
-
| UpdateEmail({email: string})
|
|
30
|
+
| Register({@pii email: string, @pii address: string})
|
|
31
|
+
| UpdateEmail({@pii email: string})
|
|
32
32
|
// The two public address commands, spliced from the trait: `UpdateAddress` and
|
|
33
33
|
// `SetAddressLocation`. They stayed hand-written here for as long as their
|
|
34
34
|
// lifecycle guard had to live on the constructor; `commandTransition` below
|
|
@@ -54,7 +54,7 @@ type command =
|
|
|
54
54
|
//
|
|
55
55
|
// Carries the address it is a verdict about, so a verdict for an address the
|
|
56
56
|
// customer has since changed can be dropped rather than applied.
|
|
57
|
-
| @noApi MarkEmailVerified({email: string})
|
|
57
|
+
| @noApi MarkEmailVerified({@pii email: string})
|
|
58
58
|
| Deactivate
|
|
59
59
|
// The way back. Deactivation withdraws a customer from ordinary use; it does
|
|
60
60
|
// not erase them, so restoring one needs no payload — the profile is still in
|
|
@@ -64,8 +64,8 @@ type command =
|
|
|
64
64
|
|
|
65
65
|
@schema
|
|
66
66
|
type event =
|
|
67
|
-
| Registered({email: string, address: string})
|
|
68
|
-
| EmailUpdated({email: string})
|
|
67
|
+
| Registered({@pii email: string, @pii address: string})
|
|
68
|
+
| EmailUpdated({@pii email: string})
|
|
69
69
|
// The geocoding graft's four facts, spliced from the trait rather than copied:
|
|
70
70
|
// `AddressUpdated`, `LocationSet`, `AddressLocated`, `AddressUnresolvable`.
|
|
71
71
|
// They are matched unqualified below and in the projections, and sury splices
|
|
@@ -74,7 +74,7 @@ type event =
|
|
|
74
74
|
// Names the address that was proven, not just that one was. `EmailUpdated`
|
|
75
75
|
// drops it again, which is what keeps "is this address proven?" decidable
|
|
76
76
|
// instead of assumed.
|
|
77
|
-
| EmailVerified({email: string})
|
|
77
|
+
| EmailVerified({@pii email: string})
|
|
78
78
|
| Deactivated
|
|
79
79
|
| Reactivated
|
|
80
80
|
|
|
@@ -1,22 +1,23 @@
|
|
|
1
1
|
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
2
|
|
|
3
3
|
import * as Sury from "sury";
|
|
4
|
+
import * as Pii$Reventless from "@reventlessdev/reventless-spec/src/components/Pii.res.mjs";
|
|
4
5
|
import * as Api$ReventlessInfra from "@reventlessdev/reventless-infra/src/components/Api.res.mjs";
|
|
5
6
|
import * as AddressGeocoding$TraitAddressGeocoding from "@reventlessdev/trait-address-geocoding/src/AddressGeocoding.res.mjs";
|
|
6
7
|
|
|
7
8
|
let commandSchema = Sury.union([
|
|
8
9
|
Sury.$schema(s => ({
|
|
9
10
|
TAG: "Register",
|
|
10
|
-
email: s.m(Sury.string),
|
|
11
|
-
address: s.m(Sury.string)
|
|
11
|
+
email: s.m(Pii$Reventless.mark("$stream", undefined, Sury.string)),
|
|
12
|
+
address: s.m(Pii$Reventless.mark("$stream", undefined, Sury.string))
|
|
12
13
|
})),
|
|
13
14
|
Sury.$schema(s => ({
|
|
14
15
|
TAG: "UpdateEmail",
|
|
15
|
-
email: s.m(Sury.string)
|
|
16
|
+
email: s.m(Pii$Reventless.mark("$stream", undefined, Sury.string))
|
|
16
17
|
})),
|
|
17
18
|
Sury.$schema(s => ({
|
|
18
19
|
TAG: "MarkEmailVerified",
|
|
19
|
-
email: s.m(Sury.string)
|
|
20
|
+
email: s.m(Pii$Reventless.mark("$stream", undefined, Sury.string))
|
|
20
21
|
})),
|
|
21
22
|
Sury.literal("Deactivate"),
|
|
22
23
|
Sury.literal("Reactivate")
|
|
@@ -25,16 +26,16 @@ let commandSchema = Sury.union([
|
|
|
25
26
|
let eventSchema = Sury.union([
|
|
26
27
|
Sury.$schema(s => ({
|
|
27
28
|
TAG: "Registered",
|
|
28
|
-
email: s.m(Sury.string),
|
|
29
|
-
address: s.m(Sury.string)
|
|
29
|
+
email: s.m(Pii$Reventless.marked("$stream", undefined, Sury.string)),
|
|
30
|
+
address: s.m(Pii$Reventless.marked("$stream", undefined, Sury.string))
|
|
30
31
|
})),
|
|
31
32
|
Sury.$schema(s => ({
|
|
32
33
|
TAG: "EmailUpdated",
|
|
33
|
-
email: s.m(Sury.string)
|
|
34
|
+
email: s.m(Pii$Reventless.marked("$stream", undefined, Sury.string))
|
|
34
35
|
})),
|
|
35
36
|
Sury.$schema(s => ({
|
|
36
37
|
TAG: "EmailVerified",
|
|
37
|
-
email: s.m(Sury.string)
|
|
38
|
+
email: s.m(Pii$Reventless.marked("$stream", undefined, Sury.string))
|
|
38
39
|
})),
|
|
39
40
|
Sury.literal("Deactivated"),
|
|
40
41
|
Sury.literal("Reactivated")
|
|
@@ -48,29 +48,54 @@ let initialState = NotCreated
|
|
|
48
48
|
|
|
49
49
|
let evolve = (state, event) =>
|
|
50
50
|
switch (state, event) {
|
|
51
|
+
// A personal field reads `Erased` once its customer is erased; the state then
|
|
52
|
+
// holds nothing in its place, as a profile never written would.
|
|
51
53
|
| (NotCreated, Registered({email, address})) =>
|
|
52
|
-
Active({
|
|
53
|
-
|
|
54
|
+
Active({
|
|
55
|
+
email: email->Reventless.Pii.getOr(""),
|
|
56
|
+
address: address->Reventless.Pii.getOr(""),
|
|
57
|
+
location: None,
|
|
58
|
+
locationResolvedFrom: None,
|
|
59
|
+
verifiedEmail: None,
|
|
60
|
+
})
|
|
61
|
+
| (Active(s), Registered({email, address})) =>
|
|
62
|
+
Active({
|
|
63
|
+
...s,
|
|
64
|
+
email: email->Reventless.Pii.getOr(""),
|
|
65
|
+
address: address->Reventless.Pii.getOr(""),
|
|
66
|
+
})
|
|
54
67
|
// 🚨 A new address is unproven, whatever was proven before. Dropping the token
|
|
55
68
|
// here is the host half of the staleness guard: without it a proof issued for
|
|
56
69
|
// the old address would settle against the new one, which is exactly the
|
|
57
70
|
// "change the address, then present the old link" takeover.
|
|
58
|
-
| (Active(s), EmailUpdated({email})) =>
|
|
59
|
-
|
|
71
|
+
| (Active(s), EmailUpdated({email})) =>
|
|
72
|
+
Active({...s, email: email->Reventless.Pii.getOr(""), verifiedEmail: None})
|
|
73
|
+
| (Active(s), EmailVerified({email})) =>
|
|
74
|
+
Active({...s, verifiedEmail: email->Reventless.Pii.toOption})
|
|
60
75
|
// A new address invalidates whatever was known about the old one — dropping
|
|
61
76
|
// both is what puts the row back in front of the geocoding slice.
|
|
62
77
|
| (Active(s), AddressUpdated({address})) =>
|
|
63
|
-
Active({
|
|
78
|
+
Active({
|
|
79
|
+
...s,
|
|
80
|
+
address: address->Reventless.Pii.getOr(""),
|
|
81
|
+
location: None,
|
|
82
|
+
locationResolvedFrom: None,
|
|
83
|
+
})
|
|
64
84
|
| (Active(s), LocationSet({location, resolvedFrom})) =>
|
|
65
|
-
Active({
|
|
85
|
+
Active({
|
|
86
|
+
...s,
|
|
87
|
+
location: Some(location),
|
|
88
|
+
locationResolvedFrom: resolvedFrom->Reventless.Pii.toOption,
|
|
89
|
+
})
|
|
66
90
|
// Both halves at once, from a client. `locationResolvedFrom` is the address
|
|
67
91
|
// itself: the caller supplied the pair, so there is nothing left to resolve.
|
|
68
92
|
| (Active(s), AddressLocated({address, location})) =>
|
|
93
|
+
let address = address->Reventless.Pii.getOr("")
|
|
69
94
|
Active({...s, address, location: Some(location), locationResolvedFrom: Some(address)})
|
|
70
95
|
// Tried, and no usable answer. Recording the address keeps the slice from
|
|
71
96
|
// handing it back for another round.
|
|
72
97
|
| (Active(s), AddressUnresolvable({address})) =>
|
|
73
|
-
Active({...s, location: None, locationResolvedFrom:
|
|
98
|
+
Active({...s, location: None, locationResolvedFrom: address->Reventless.Pii.toOption})
|
|
74
99
|
| (
|
|
75
100
|
Active({email, address, location, locationResolvedFrom, verifiedEmail}),
|
|
76
101
|
Customer.Deactivated,
|
|
@@ -116,7 +141,8 @@ let verified = (verdict, event) =>
|
|
|
116
141
|
|
|
117
142
|
let decide = (state, command) =>
|
|
118
143
|
switch (state, command) {
|
|
119
|
-
| (NotCreated, Register({email, address})) =>
|
|
144
|
+
| (NotCreated, Register({email, address})) =>
|
|
145
|
+
Ok([Registered({email: Value(email), address: Value(address)})])
|
|
120
146
|
| (NotCreated, UpdateEmail(_)) => Error(CustomerNotFound)
|
|
121
147
|
| (NotCreated, UpdateAddress(_)) => Error(CustomerNotFound)
|
|
122
148
|
| (NotCreated, SetAddressLocation(_)) => Error(CustomerNotFound)
|
|
@@ -128,32 +154,32 @@ let decide = (state, command) =>
|
|
|
128
154
|
|
|
129
155
|
| (Active(_), Register(_)) => Error(CustomerAlreadyRegistered)
|
|
130
156
|
| (Active(s), UpdateEmail({email})) if email == s.email => Ok([])
|
|
131
|
-
| (Active(_), UpdateEmail({email})) => Ok([EmailUpdated({email: email})])
|
|
157
|
+
| (Active(_), UpdateEmail({email})) => Ok([EmailUpdated({email: Value(email)})])
|
|
132
158
|
| (Active(s), UpdateAddress({address})) =>
|
|
133
159
|
Guards.onSubjectUpdate(
|
|
134
160
|
resolution(s.address, s.location, s.locationResolvedFrom),
|
|
135
161
|
~subject=address,
|
|
136
|
-
)->appended(AddressUpdated({address: address}))
|
|
162
|
+
)->appended(AddressUpdated({address: Value(address)}))
|
|
137
163
|
|
|
138
164
|
| (Active(s), SetAddressLocation({address, location})) =>
|
|
139
165
|
Guards.onSuppliedPair(
|
|
140
166
|
resolution(s.address, s.location, s.locationResolvedFrom),
|
|
141
167
|
~subject=address,
|
|
142
168
|
~location,
|
|
143
|
-
)->appended(AddressLocated({address, location}))
|
|
169
|
+
)->appended(AddressLocated({address: Value(address), location}))
|
|
144
170
|
|
|
145
171
|
| (Active(s), SetLocation({location, resolvedFrom})) =>
|
|
146
172
|
Guards.onLocationReport(
|
|
147
173
|
resolution(s.address, s.location, s.locationResolvedFrom),
|
|
148
174
|
~location,
|
|
149
175
|
~resolvedFrom,
|
|
150
|
-
)->appended(LocationSet({location, resolvedFrom}))
|
|
176
|
+
)->appended(LocationSet({location, resolvedFrom: Value(resolvedFrom)}))
|
|
151
177
|
|
|
152
178
|
| (Active(s), MarkAddressUnresolvable({address, reason})) =>
|
|
153
179
|
Guards.onUnresolvableReport(
|
|
154
180
|
resolution(s.address, s.location, s.locationResolvedFrom),
|
|
155
181
|
~subject=address,
|
|
156
|
-
)->appended(AddressUnresolvable({address, reason}))
|
|
182
|
+
)->appended(AddressUnresolvable({address: Value(address), reason}))
|
|
157
183
|
|
|
158
184
|
// 🚨 The security control at the host boundary. A verdict naming an address
|
|
159
185
|
// the customer has since changed is dropped rather than applied — and it is
|
|
@@ -164,7 +190,7 @@ let decide = (state, command) =>
|
|
|
164
190
|
Verification.onVerifiedReport(
|
|
165
191
|
verification(s.email, s.verifiedEmail),
|
|
166
192
|
~contact=ByEmail(email),
|
|
167
|
-
)->verified(EmailVerified({email: email}))
|
|
193
|
+
)->verified(EmailVerified({email: Value(email)}))
|
|
168
194
|
|
|
169
195
|
| (Active(_), Deactivate) => Ok([Customer.Deactivated])
|
|
170
196
|
// Already where the caller is asking it to be.
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import * as Sury from "sury";
|
|
4
4
|
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
5
|
+
import * as Pii$Reventless from "@reventlessdev/reventless-spec/src/components/Pii.res.mjs";
|
|
5
6
|
import * as GeoPoint$Reventless from "@reventlessdev/reventless-spec/src/semantic/GeoPoint.res.mjs";
|
|
6
7
|
import * as ContactVerification_Guards$OrderingPlugin from "../../ContactVerification_Guards.res.mjs";
|
|
7
8
|
import * as AddressGeocoding_Guards$TraitAddressGeocoding from "@reventlessdev/trait-address-geocoding/src/AddressGeocoding_Guards.res.mjs";
|
|
@@ -33,8 +34,8 @@ function evolve(state, event) {
|
|
|
33
34
|
} else {
|
|
34
35
|
return {
|
|
35
36
|
TAG: "Active",
|
|
36
|
-
email: event.email,
|
|
37
|
-
address: event.address,
|
|
37
|
+
email: Pii$Reventless.getOr(event.email, ""),
|
|
38
|
+
address: Pii$Reventless.getOr(event.address, ""),
|
|
38
39
|
location: undefined,
|
|
39
40
|
locationResolvedFrom: undefined,
|
|
40
41
|
verifiedEmail: undefined
|
|
@@ -73,8 +74,8 @@ function evolve(state, event) {
|
|
|
73
74
|
case "Registered" :
|
|
74
75
|
return {
|
|
75
76
|
TAG: "Active",
|
|
76
|
-
email: event.email,
|
|
77
|
-
address: event.address,
|
|
77
|
+
email: Pii$Reventless.getOr(event.email, ""),
|
|
78
|
+
address: Pii$Reventless.getOr(event.address, ""),
|
|
78
79
|
location: state.location,
|
|
79
80
|
locationResolvedFrom: state.locationResolvedFrom,
|
|
80
81
|
verifiedEmail: state.verifiedEmail
|
|
@@ -82,7 +83,7 @@ function evolve(state, event) {
|
|
|
82
83
|
case "EmailUpdated" :
|
|
83
84
|
return {
|
|
84
85
|
TAG: "Active",
|
|
85
|
-
email: event.email,
|
|
86
|
+
email: Pii$Reventless.getOr(event.email, ""),
|
|
86
87
|
address: state.address,
|
|
87
88
|
location: state.location,
|
|
88
89
|
locationResolvedFrom: state.locationResolvedFrom,
|
|
@@ -92,7 +93,7 @@ function evolve(state, event) {
|
|
|
92
93
|
return {
|
|
93
94
|
TAG: "Active",
|
|
94
95
|
email: state.email,
|
|
95
|
-
address: event.address,
|
|
96
|
+
address: Pii$Reventless.getOr(event.address, ""),
|
|
96
97
|
location: undefined,
|
|
97
98
|
locationResolvedFrom: undefined,
|
|
98
99
|
verifiedEmail: state.verifiedEmail
|
|
@@ -103,11 +104,11 @@ function evolve(state, event) {
|
|
|
103
104
|
email: state.email,
|
|
104
105
|
address: state.address,
|
|
105
106
|
location: event.location,
|
|
106
|
-
locationResolvedFrom: event.resolvedFrom,
|
|
107
|
+
locationResolvedFrom: Pii$Reventless.toOption(event.resolvedFrom),
|
|
107
108
|
verifiedEmail: state.verifiedEmail
|
|
108
109
|
};
|
|
109
110
|
case "AddressLocated" :
|
|
110
|
-
let address = event.address;
|
|
111
|
+
let address = Pii$Reventless.getOr(event.address, "");
|
|
111
112
|
return {
|
|
112
113
|
TAG: "Active",
|
|
113
114
|
email: state.email,
|
|
@@ -122,7 +123,7 @@ function evolve(state, event) {
|
|
|
122
123
|
email: state.email,
|
|
123
124
|
address: state.address,
|
|
124
125
|
location: undefined,
|
|
125
|
-
locationResolvedFrom: event.address,
|
|
126
|
+
locationResolvedFrom: Pii$Reventless.toOption(event.address),
|
|
126
127
|
verifiedEmail: state.verifiedEmail
|
|
127
128
|
};
|
|
128
129
|
case "EmailVerified" :
|
|
@@ -132,7 +133,7 @@ function evolve(state, event) {
|
|
|
132
133
|
address: state.address,
|
|
133
134
|
location: state.location,
|
|
134
135
|
locationResolvedFrom: state.locationResolvedFrom,
|
|
135
|
-
verifiedEmail: event.email
|
|
136
|
+
verifiedEmail: Pii$Reventless.toOption(event.email)
|
|
136
137
|
};
|
|
137
138
|
}
|
|
138
139
|
}
|
|
@@ -198,8 +199,14 @@ function decide(state, command) {
|
|
|
198
199
|
TAG: "Ok",
|
|
199
200
|
_0: [{
|
|
200
201
|
TAG: "Registered",
|
|
201
|
-
email:
|
|
202
|
-
|
|
202
|
+
email: {
|
|
203
|
+
TAG: "Value",
|
|
204
|
+
_0: command.email
|
|
205
|
+
},
|
|
206
|
+
address: {
|
|
207
|
+
TAG: "Value",
|
|
208
|
+
_0: command.address
|
|
209
|
+
}
|
|
203
210
|
}]
|
|
204
211
|
};
|
|
205
212
|
}
|
|
@@ -236,7 +243,10 @@ function decide(state, command) {
|
|
|
236
243
|
TAG: "Ok",
|
|
237
244
|
_0: [{
|
|
238
245
|
TAG: "EmailUpdated",
|
|
239
|
-
email:
|
|
246
|
+
email: {
|
|
247
|
+
TAG: "Value",
|
|
248
|
+
_0: email
|
|
249
|
+
}
|
|
240
250
|
}]
|
|
241
251
|
};
|
|
242
252
|
}
|
|
@@ -248,7 +258,10 @@ function decide(state, command) {
|
|
|
248
258
|
resolvedFrom: state.locationResolvedFrom
|
|
249
259
|
}, address), {
|
|
250
260
|
TAG: "AddressUpdated",
|
|
251
|
-
address:
|
|
261
|
+
address: {
|
|
262
|
+
TAG: "Value",
|
|
263
|
+
_0: address
|
|
264
|
+
}
|
|
252
265
|
});
|
|
253
266
|
case "SetAddressLocation" :
|
|
254
267
|
let location = command.location;
|
|
@@ -259,7 +272,10 @@ function decide(state, command) {
|
|
|
259
272
|
resolvedFrom: state.locationResolvedFrom
|
|
260
273
|
}, address$1, location), {
|
|
261
274
|
TAG: "AddressLocated",
|
|
262
|
-
address:
|
|
275
|
+
address: {
|
|
276
|
+
TAG: "Value",
|
|
277
|
+
_0: address$1
|
|
278
|
+
},
|
|
263
279
|
location: location
|
|
264
280
|
});
|
|
265
281
|
case "SetLocation" :
|
|
@@ -272,7 +288,10 @@ function decide(state, command) {
|
|
|
272
288
|
}, location$1, resolvedFrom), {
|
|
273
289
|
TAG: "LocationSet",
|
|
274
290
|
location: location$1,
|
|
275
|
-
resolvedFrom:
|
|
291
|
+
resolvedFrom: {
|
|
292
|
+
TAG: "Value",
|
|
293
|
+
_0: resolvedFrom
|
|
294
|
+
}
|
|
276
295
|
});
|
|
277
296
|
case "MarkAddressUnresolvable" :
|
|
278
297
|
let address$2 = command.address;
|
|
@@ -282,7 +301,10 @@ function decide(state, command) {
|
|
|
282
301
|
resolvedFrom: state.locationResolvedFrom
|
|
283
302
|
}, address$2), {
|
|
284
303
|
TAG: "AddressUnresolvable",
|
|
285
|
-
address:
|
|
304
|
+
address: {
|
|
305
|
+
TAG: "Value",
|
|
306
|
+
_0: address$2
|
|
307
|
+
},
|
|
286
308
|
reason: command.reason
|
|
287
309
|
});
|
|
288
310
|
case "MarkEmailVerified" :
|
|
@@ -292,7 +314,10 @@ function decide(state, command) {
|
|
|
292
314
|
_0: email$1
|
|
293
315
|
}), {
|
|
294
316
|
TAG: "EmailVerified",
|
|
295
|
-
email:
|
|
317
|
+
email: {
|
|
318
|
+
TAG: "Value",
|
|
319
|
+
_0: email$1
|
|
320
|
+
}
|
|
296
321
|
});
|
|
297
322
|
}
|
|
298
323
|
} else {
|
|
@@ -12,11 +12,11 @@
|
|
|
12
12
|
// and the conformance suite asserts that this set is no wider than `collect`.
|
|
13
13
|
@schema
|
|
14
14
|
type consumedEvent =
|
|
15
|
-
| Registered({email: string, address: string})
|
|
16
|
-
| AddressUpdated({address: string})
|
|
15
|
+
| Registered({@pii email: string, @pii address: string})
|
|
16
|
+
| AddressUpdated({@pii address: string})
|
|
17
17
|
|
|
18
18
|
@schema
|
|
19
|
-
type outboundItem = {customerId: string, address: string}
|
|
19
|
+
type outboundItem = {customerId: string, @pii("customerId") address: string}
|
|
20
20
|
|
|
21
21
|
@schema
|
|
22
22
|
type inboundCommand =
|
|
@@ -1,24 +1,25 @@
|
|
|
1
1
|
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
2
|
|
|
3
3
|
import * as Sury from "sury";
|
|
4
|
+
import * as Pii$Reventless from "@reventlessdev/reventless-spec/src/components/Pii.res.mjs";
|
|
4
5
|
import * as GeoPoint$Reventless from "@reventlessdev/reventless-spec/src/semantic/GeoPoint.res.mjs";
|
|
5
6
|
import * as AddressGeocoding$TraitAddressGeocoding from "@reventlessdev/trait-address-geocoding/src/AddressGeocoding.res.mjs";
|
|
6
7
|
|
|
7
8
|
let consumedEventSchema = Sury.union([
|
|
8
9
|
Sury.$schema(s => ({
|
|
9
10
|
TAG: "Registered",
|
|
10
|
-
email: s.m(Sury.string),
|
|
11
|
-
address: s.m(Sury.string)
|
|
11
|
+
email: s.m(Pii$Reventless.marked("$stream", undefined, Sury.string)),
|
|
12
|
+
address: s.m(Pii$Reventless.marked("$stream", undefined, Sury.string))
|
|
12
13
|
})),
|
|
13
14
|
Sury.$schema(s => ({
|
|
14
15
|
TAG: "AddressUpdated",
|
|
15
|
-
address: s.m(Sury.string)
|
|
16
|
+
address: s.m(Pii$Reventless.marked("$stream", undefined, Sury.string))
|
|
16
17
|
}))
|
|
17
18
|
]);
|
|
18
19
|
|
|
19
20
|
let outboundItemSchema = Sury.$schema(s => ({
|
|
20
21
|
customerId: s.m(Sury.string),
|
|
21
|
-
address: s.m(Sury.string)
|
|
22
|
+
address: s.m(Pii$Reventless.mark("customerId", undefined, Sury.string))
|
|
22
23
|
}));
|
|
23
24
|
|
|
24
25
|
let inboundCommandSchema = Sury.union([
|
|
@@ -5,8 +5,15 @@
|
|
|
5
5
|
// which an aggregate's event payload does not repeat.
|
|
6
6
|
let collect = (event, ~sourceId) =>
|
|
7
7
|
switch event {
|
|
8
|
-
| Registered({address}) => [
|
|
9
|
-
|
|
8
|
+
| Registered({address: Value(address)}) => [
|
|
9
|
+
(`${sourceId}:${address}`, {customerId: sourceId, address}),
|
|
10
|
+
]
|
|
11
|
+
// An erased customer is owed nothing.
|
|
12
|
+
| Registered(_) => []
|
|
13
|
+
| AddressUpdated({address: Value(address)}) => [
|
|
14
|
+
(`${sourceId}:${address}`, {customerId: sourceId, address}),
|
|
15
|
+
]
|
|
16
|
+
| AddressUpdated(_) => []
|
|
10
17
|
}
|
|
11
18
|
|
|
12
19
|
// Asking the geocoder and reading its answer are the trait's — including the
|
|
@@ -6,20 +6,36 @@ import * as AddressGeocoding_Translate$TraitAddressGeocoding from "@reventlessde
|
|
|
6
6
|
function collect(event, sourceId) {
|
|
7
7
|
if (event.TAG === "Registered") {
|
|
8
8
|
let address = event.address;
|
|
9
|
+
if (typeof address !== "object") {
|
|
10
|
+
if (address === "Erased") {
|
|
11
|
+
return [];
|
|
12
|
+
} else {
|
|
13
|
+
return [];
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
let address$1 = address._0;
|
|
9
17
|
return [[
|
|
10
|
-
sourceId + `:` + address,
|
|
18
|
+
sourceId + `:` + address$1,
|
|
11
19
|
{
|
|
12
20
|
customerId: sourceId,
|
|
13
|
-
address: address
|
|
21
|
+
address: address$1
|
|
14
22
|
}
|
|
15
23
|
]];
|
|
16
24
|
}
|
|
17
|
-
let address$
|
|
25
|
+
let address$2 = event.address;
|
|
26
|
+
if (typeof address$2 !== "object") {
|
|
27
|
+
if (address$2 === "Erased") {
|
|
28
|
+
return [];
|
|
29
|
+
} else {
|
|
30
|
+
return [];
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
let address$3 = address$2._0;
|
|
18
34
|
return [[
|
|
19
|
-
sourceId + `:` + address$
|
|
35
|
+
sourceId + `:` + address$3,
|
|
20
36
|
{
|
|
21
37
|
customerId: sourceId,
|
|
22
|
-
address: address$
|
|
38
|
+
address: address$3
|
|
23
39
|
}
|
|
24
40
|
]];
|
|
25
41
|
}
|
|
@@ -11,11 +11,11 @@
|
|
|
11
11
|
// because a settled address owes nothing and the slice must not re-open it.
|
|
12
12
|
@schema
|
|
13
13
|
type consumedEvent =
|
|
14
|
-
| Registered({email: string, address: string})
|
|
15
|
-
| EmailUpdated({email: string})
|
|
14
|
+
| Registered({@pii email: string, @pii address: string})
|
|
15
|
+
| EmailUpdated({@pii email: string})
|
|
16
16
|
|
|
17
17
|
@schema
|
|
18
|
-
type outboundItem = {customerId: string, email: string}
|
|
18
|
+
type outboundItem = {customerId: string, @pii("customerId") email: string}
|
|
19
19
|
|
|
20
20
|
// Reported to the challenge ledger rather than to `Customer` — the aggregate
|
|
21
21
|
// learns nothing until a proof settles. Mirrors that slice's command exactly.
|
|
@@ -23,7 +23,7 @@ type outboundItem = {customerId: string, email: string}
|
|
|
23
23
|
type inboundCommand =
|
|
24
24
|
| IssueEmailChallenge({
|
|
25
25
|
customerId: CustomerId.t,
|
|
26
|
-
email: string,
|
|
26
|
+
@pii("customerId") email: string,
|
|
27
27
|
purpose: string,
|
|
28
28
|
proofHash: string,
|
|
29
29
|
issuedAt: string,
|
|
@@ -1,30 +1,31 @@
|
|
|
1
1
|
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
2
|
|
|
3
3
|
import * as Sury from "sury";
|
|
4
|
+
import * as Pii$Reventless from "@reventlessdev/reventless-spec/src/components/Pii.res.mjs";
|
|
4
5
|
import * as DcbTag$Reventless from "@reventlessdev/reventless-spec/src/components/DcbTag.res.mjs";
|
|
5
6
|
import * as CustomerId$OrderingPlugin from "../CustomerId.res.mjs";
|
|
6
7
|
|
|
7
8
|
let consumedEventSchema = Sury.union([
|
|
8
9
|
Sury.$schema(s => ({
|
|
9
10
|
TAG: "Registered",
|
|
10
|
-
email: s.m(Sury.string),
|
|
11
|
-
address: s.m(Sury.string)
|
|
11
|
+
email: s.m(Pii$Reventless.marked("$stream", undefined, Sury.string)),
|
|
12
|
+
address: s.m(Pii$Reventless.marked("$stream", undefined, Sury.string))
|
|
12
13
|
})),
|
|
13
14
|
Sury.$schema(s => ({
|
|
14
15
|
TAG: "EmailUpdated",
|
|
15
|
-
email: s.m(Sury.string)
|
|
16
|
+
email: s.m(Pii$Reventless.marked("$stream", undefined, Sury.string))
|
|
16
17
|
}))
|
|
17
18
|
]);
|
|
18
19
|
|
|
19
20
|
let outboundItemSchema = Sury.$schema(s => ({
|
|
20
21
|
customerId: s.m(Sury.string),
|
|
21
|
-
email: s.m(Sury.string)
|
|
22
|
+
email: s.m(Pii$Reventless.mark("customerId", undefined, Sury.string))
|
|
22
23
|
}));
|
|
23
24
|
|
|
24
25
|
let inboundCommandSchema = Sury.$schema(s => ({
|
|
25
26
|
TAG: "IssueEmailChallenge",
|
|
26
27
|
customerId: s.m(DcbTag$Reventless.mark(CustomerId$OrderingPlugin.schema)),
|
|
27
|
-
email: s.m(Sury.string),
|
|
28
|
+
email: s.m(Pii$Reventless.mark("customerId", undefined, Sury.string)),
|
|
28
29
|
purpose: s.m(Sury.string),
|
|
29
30
|
proofHash: s.m(Sury.string),
|
|
30
31
|
issuedAt: s.m(Sury.string)
|
|
@@ -7,8 +7,10 @@ module V = ContactVerification
|
|
|
7
7
|
// reason. `~sourceId` is the entity id, which an aggregate's payload omits.
|
|
8
8
|
let collect = (event, ~sourceId) =>
|
|
9
9
|
switch event {
|
|
10
|
-
| Registered({email}) => [(`${sourceId}:${email}`, {customerId: sourceId, email})]
|
|
11
|
-
| EmailUpdated({email}) => [(`${sourceId}:${email}`, {customerId: sourceId, email})]
|
|
10
|
+
| Registered({email: Value(email)}) => [(`${sourceId}:${email}`, {customerId: sourceId, email})]
|
|
11
|
+
| EmailUpdated({email: Value(email)}) => [(`${sourceId}:${email}`, {customerId: sourceId, email})]
|
|
12
|
+
// An erased customer is owed nothing.
|
|
13
|
+
| Registered(_) | EmailUpdated(_) => []
|
|
12
14
|
}
|
|
13
15
|
|
|
14
16
|
let policy = V.emailPolicy
|
|
@@ -8,20 +8,36 @@ import * as ContactVerification$OrderingPlugin from "../../ContactVerification.r
|
|
|
8
8
|
function collect(event, sourceId) {
|
|
9
9
|
if (event.TAG === "Registered") {
|
|
10
10
|
let email = event.email;
|
|
11
|
+
if (typeof email !== "object") {
|
|
12
|
+
if (email === "Erased") {
|
|
13
|
+
return [];
|
|
14
|
+
} else {
|
|
15
|
+
return [];
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
let email$1 = email._0;
|
|
11
19
|
return [[
|
|
12
|
-
sourceId + `:` + email,
|
|
20
|
+
sourceId + `:` + email$1,
|
|
13
21
|
{
|
|
14
22
|
customerId: sourceId,
|
|
15
|
-
email: email
|
|
23
|
+
email: email$1
|
|
16
24
|
}
|
|
17
25
|
]];
|
|
18
26
|
}
|
|
19
|
-
let email$
|
|
27
|
+
let email$2 = event.email;
|
|
28
|
+
if (typeof email$2 !== "object") {
|
|
29
|
+
if (email$2 === "Erased") {
|
|
30
|
+
return [];
|
|
31
|
+
} else {
|
|
32
|
+
return [];
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
let email$3 = email$2._0;
|
|
20
36
|
return [[
|
|
21
|
-
sourceId + `:` + email$
|
|
37
|
+
sourceId + `:` + email$3,
|
|
22
38
|
{
|
|
23
39
|
customerId: sourceId,
|
|
24
|
-
email: email$
|
|
40
|
+
email: email$3
|
|
25
41
|
}
|
|
26
42
|
]];
|
|
27
43
|
}
|