@reventlessdev/trait-address-geocoding 1.0.0-alpha.5 → 1.0.0-alpha.51

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/README.md CHANGED
@@ -19,7 +19,7 @@ Most of this graft is not emitted at all. The four facts and the two `@noApi` re
19
19
  commands are real constructors the host **splices** — `...AddressGeocoding.events` and
20
20
  `...AddressGeocoding.reportCommands` — so the compiler carries them, annotations and
21
21
  schema included. The emitter writes the outbound slice, which the host does not have
22
- yet, and prints the arms that belong inside the aggregate, its behavior and the
22
+ yet, and prints the arms that belong inside the aggregate, its decision and the
23
23
  projection: those interleave with the host's own state machine, and placing an arm in
24
24
  an ordered `switch` is an AST operation a text splice gets silently wrong.
25
25
 
@@ -54,7 +54,7 @@ pnpm exec graft-trait @reventlessdev/trait-address-geocoding \
54
54
  the suite below needs no hand-written file — and prints three patches.
55
55
 
56
56
  2. Paste the three patches. The aggregate's is two spread lines plus the arms for
57
- `commandTransition`; the behavior's is the state fields and the `evolve` / `decide`
57
+ `commandTransition`; the decision's is the state fields and the `evolve` / `decide`
58
58
  arms; the projection's is the view's `geolocation` field and its arms.
59
59
 
60
60
  Policy is yours and is not config. Which states an address may change in goes in
@@ -62,7 +62,8 @@ pnpm exec graft-trait @reventlessdev/trait-address-geocoding \
62
62
  you declare beside it — the compiler resolves the constructors, the switch is
63
63
  exhaustive so it names any spliced command you have not answered for, and every
64
64
  arm has to draw on that one lifecycle. Who may send the commands goes in
65
- `commandAuthorization` the same way.
65
+ `@@reventless.authorize`, or in an `authorizationOf` switch on their names for a
66
+ rule per command.
66
67
 
67
68
  A host whose subject is not called `address`, or is not a `string`, gets the same
68
69
  graft with the constructors spelled out instead of spliced — pass `--subject`, and
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reventlessdev/trait-address-geocoding",
3
- "version": "1.0.0-alpha.5",
3
+ "version": "1.0.0-alpha.51",
4
4
  "description": "Address-geocoding domain trait: rules, host contract, conformance suite and emitter for grafting geocoding onto an aggregate",
5
5
  "license": "Apache-2.0",
6
6
  "files": [
@@ -11,18 +11,18 @@
11
11
  "README.md"
12
12
  ],
13
13
  "dependencies": {
14
- "sury": "11.0.0-rc.2",
15
- "sury-ppx": "11.0.0-rc.2",
16
- "@reventlessdev/reventless-gwt": "1.0.0-alpha.203",
17
- "@reventlessdev/reventless-infra": "3.0.0-alpha.157",
18
- "@reventlessdev/reventless-ppx": "1.0.0-alpha.77",
19
- "@reventlessdev/reventless-spec": "3.0.0-alpha.129"
14
+ "sury": "11.0.0",
15
+ "sury-ppx": "11.0.0",
16
+ "@reventlessdev/reventless-gwt": "1.0.0-alpha.249",
17
+ "@reventlessdev/reventless-infra": "3.0.0-alpha.198",
18
+ "@reventlessdev/reventless-spec": "3.0.0-alpha.170",
19
+ "@reventlessdev/reventless-ppx": "1.0.0-alpha.103"
20
20
  },
21
21
  "devDependencies": {
22
- "rescript": "12.3.0"
22
+ "rescript": "12.3.1"
23
23
  },
24
24
  "peerDependencies": {
25
- "rescript": "12.3.0"
25
+ "rescript": "^12.3.1"
26
26
  },
27
27
  "publishConfig": {
28
28
  "registry": "https://registry.npmjs.org"
@@ -6,10 +6,9 @@ staleness, redelivery, an outage is not a verdict, the stand-down — live in
6
6
  host by `AddressGeocoding_Conformance`; the confidence rule stays core's
7
7
  (`Reventless.Geocoding`). The spec surface is written by `AddressGeocoding_Scaffold`.
8
8
  */
9
-
10
9
  /** Whether the graft reports back into its host. This trait does — the two `@noApi`
11
10
  commands — and the runner accepts nothing else yet; the flag is here so a
12
- competency that only observes is not mis-modelled as one that writes. */
11
+ competency that only observes is not mis-modeled as one that writes. */
13
12
  type posture = WritesBack | Observes
14
13
 
15
14
  /**
@@ -139,8 +138,8 @@ module type Binding = {
139
138
 
140
139
  let posture: posture
141
140
 
142
- module Spec: ReventlessGwt.Behavior_GWT.AggregateSpec
143
- module Behavior: Reventless.Behavior.T with module Spec = Spec
141
+ module Spec: ReventlessGwt.Decision_GWT.AggregateSpec
142
+ module Decision: Reventless.Decision.T with module Spec = Spec
144
143
 
145
144
  /** History leaving the entity active at `subject` with nothing resolved. */
146
145
  let created: subject => array<Spec.event>
@@ -1,11 +1,3 @@
1
- /**
2
- The conformance suite, run by a host against its own graft. `Make(Binding).register()`
3
- inside a Jest test file registers one `describe` block; every assertion is written
4
- over the binding, never over a host's constructors.
5
- */
6
-
7
- // Warning 23 flags the spread in `geocoder` as redundant today; it is there for
8
- // the day `Capabilities.t` grows a field.
9
1
  @@warning("-23")
10
2
 
11
3
  module Outcome = ReventlessGwt.Outcome
@@ -17,7 +9,7 @@ module Outcome = ReventlessGwt.Outcome
17
9
  let suiteName = (host: string) => `${host} conforms to the address-geocoding trait`
18
10
 
19
11
  module Make = (B: AddressGeocoding.Binding) => {
20
- module A = ReventlessGwt.Behavior_GWT.MakeFromAggregate(B.Spec, B.Behavior)
12
+ module A = ReventlessGwt.Decision_GWT.MakeFromAggregate(B.Spec, B.Decision)
21
13
  module S = ReventlessGwt.OutboundTranslation_GWT.Make(B.Slice)
22
14
 
23
15
  let vienna: Reventless.GeoPoint.t = {lat: 48.2082, lng: 16.3738}
@@ -53,7 +45,9 @@ module Make = (B: AddressGeocoding.Binding) => {
53
45
  let triggers =
54
46
  B.triggers(B.subjectA)
55
47
  ->Array.map(e =>
56
- e->Reventless.Message.encode(B.Slice.consumedEventSchema)->Reventless.Message.variantNameOfJson
48
+ e
49
+ ->Reventless.Message.encode(B.Slice.consumedEventSchema)
50
+ ->Reventless.Message.variantNameOfJson
57
51
  )
58
52
  ->sorted
59
53
  // Encoded through the aggregate's own schema, so a stand-down event is a
@@ -124,7 +118,10 @@ module Make = (B: AddressGeocoding.Binding) => {
124
118
 
125
119
  A.test("a redelivered verdict is a no-op", () =>
126
120
  A.givenEvents(
127
- Array.concat(B.created(B.subjectA), [B.unresolvable(~subject=B.subjectA, ~reason="no match")]),
121
+ Array.concat(
122
+ B.created(B.subjectA),
123
+ [B.unresolvable(~subject=B.subjectA, ~reason="no match")],
124
+ ),
128
125
  )
129
126
  ->A.whenCmd(B.markUnresolvable(~subject=B.subjectA, ~reason="no match"))
130
127
  ->A.thenNoEvent
@@ -147,10 +144,12 @@ module Make = (B: AddressGeocoding.Binding) => {
147
144
  )
148
145
 
149
146
  B.triggers(B.subjectA)->Array.forEachWithIndex((trigger, i) =>
150
- S.testSync(`trigger ${Int.toString(i + 1)} queues one TODO keyed by entity and subject`, () =>
151
- S.givenEvent(trigger)
152
- ->S.whenCollect(~sourceId=entityId)
153
- ->S.thenTodos([(todoKey(B.subjectA), B.item(~entityId, ~subject=B.subjectA))])
147
+ S.testSync(
148
+ `trigger ${Int.toString(i + 1)} queues one TODO keyed by entity and subject`,
149
+ () =>
150
+ S.givenEvent(trigger)
151
+ ->S.whenCollect(~sourceId=entityId)
152
+ ->S.thenTodos([(todoKey(B.subjectA), B.item(~entityId, ~subject=B.subjectA))]),
154
153
  )
155
154
  )
156
155
 
@@ -6,7 +6,7 @@ import * as Message$Reventless from "@reventlessdev/reventless-spec/src/types/Me
6
6
  import * as DcbDecode$Reventless from "@reventlessdev/reventless-spec/src/components/DcbDecode.res.mjs";
7
7
  import * as Outcome$ReventlessGwt from "@reventlessdev/reventless-gwt/src/Outcome.res.mjs";
8
8
  import * as Capabilities$Reventless from "@reventlessdev/reventless-spec/src/semantic/Capabilities.res.mjs";
9
- import * as Behavior_GWT$ReventlessGwt from "@reventlessdev/reventless-gwt/src/Behavior_GWT.res.mjs";
9
+ import * as Decision_GWT$ReventlessGwt from "@reventlessdev/reventless-gwt/src/Decision_GWT.res.mjs";
10
10
  import * as OutboundTranslation_GWT$ReventlessGwt from "@reventlessdev/reventless-gwt/src/OutboundTranslation_GWT.res.mjs";
11
11
 
12
12
  function suiteName(host) {
@@ -14,7 +14,7 @@ function suiteName(host) {
14
14
  }
15
15
 
16
16
  function Make(B) {
17
- let A = Behavior_GWT$ReventlessGwt.MakeFromAggregate(B.Spec)(B.Behavior);
17
+ let A = Decision_GWT$ReventlessGwt.MakeFromAggregate(B.Spec)(B.Decision);
18
18
  let S = OutboundTranslation_GWT$ReventlessGwt.Make(B.Slice);
19
19
  let vienna = {
20
20
  lat: 48.2082,
@@ -28,7 +28,9 @@ function Make(B) {
28
28
  let todoKey = subject => entityId + `:` + B.subjectText(subject);
29
29
  let geocoder = answer => ({
30
30
  geocode: param => Promise.resolve(answer),
31
- messaging: Capabilities$Reventless.none.messaging
31
+ messaging: Capabilities$Reventless.none.messaging,
32
+ identityProvider: Capabilities$Reventless.none.identityProvider,
33
+ secrets: Capabilities$Reventless.none.secrets
32
34
  });
33
35
  let translateWith = answer => ((id, item) => B.translate(id, item, geocoder(answer)));
34
36
  let describeCommand = cmd => JSON.stringify(Message$Reventless.encode(cmd, B.Slice.inboundCommandSchema));
@@ -110,23 +112,17 @@ function Make(B) {
110
112
  relevance: 0.995
111
113
  }]
112
114
  })), "a location", B.isLocation));
113
- S.test("a no-match completes the TODO with a verdict", undefined, () => thenReports(S.whenTranslateMocked(S.givenTodo(todoKey(B.subjectA), B.item(entityId, B.subjectA)), (id, item) => B.translate(id, item, {
114
- geocode: param => Promise.resolve({
115
- TAG: "Error",
116
- _0: "NoMatch"
117
- }),
118
- messaging: Capabilities$Reventless.none.messaging
119
- })), "a verdict", B.isVerdict));
120
- S.test("an outage leaves the TODO pending", undefined, () => S.thenTodoStatus(S.whenTranslateMocked(S.givenTodo(todoKey(B.subjectA), B.item(entityId, B.subjectA)), (id, item) => B.translate(id, item, {
121
- geocode: param => Promise.resolve({
122
- TAG: "Error",
123
- _0: {
124
- TAG: "Unavailable",
125
- _0: "502"
126
- }
127
- }),
128
- messaging: Capabilities$Reventless.none.messaging
129
- })), todoKey(B.subjectA), "Pending"));
115
+ S.test("a no-match completes the TODO with a verdict", undefined, () => thenReports(S.whenTranslateMocked(S.givenTodo(todoKey(B.subjectA), B.item(entityId, B.subjectA)), (id, item) => B.translate(id, item, geocoder({
116
+ TAG: "Error",
117
+ _0: "NoMatch"
118
+ }))), "a verdict", B.isVerdict));
119
+ S.test("an outage leaves the TODO pending", undefined, () => S.thenTodoStatus(S.whenTranslateMocked(S.givenTodo(todoKey(B.subjectA), B.item(entityId, B.subjectA)), (id, item) => B.translate(id, item, geocoder({
120
+ TAG: "Error",
121
+ _0: {
122
+ TAG: "Unavailable",
123
+ _0: "502"
124
+ }
125
+ }))), todoKey(B.subjectA), "Pending"));
130
126
  });
131
127
  return {
132
128
  A: A,
@@ -8,7 +8,6 @@ record in it would make every release that reshapes it a migration — and build
8
8
  `resolution` per call from the fields it already holds. What comes back is a
9
9
  verdict on one command, which the host names in its own event.
10
10
  */
11
-
12
11
  /** The three fields the rules read, as the host holds them. Its invariant, which
13
12
  every host arm must preserve: `resolvedFrom` is `None` or equal to `subject`. */
14
13
  type resolution = {
@@ -28,7 +28,6 @@ address may be changed in, who may change it, what a host's own commands refuse
28
28
  which a trait cannot know. They are config when the host supplies them and absent
29
29
  when it does not.
30
30
  */
31
-
32
31
  /**
33
32
  The names a graft needs, and nothing else.
34
33
 
@@ -46,7 +45,6 @@ type config = {
46
45
  one of the slice's two triggers, because an entity created with an address
47
46
  has never been geocoded. */
48
47
  created: string,
49
-
50
48
  /**
51
49
  What this host calls the thing being geocoded, lowercase: `"address"`.
52
50
 
@@ -58,7 +56,6 @@ type config = {
58
56
  spelled out. The emitted patch says which of the two you are getting.
59
57
  */
60
58
  subject?: string,
61
-
62
59
  /**
63
60
  The creation event's payload *beyond* the subject, as declarations:
64
61
  `["email: string"]`.
@@ -72,7 +69,6 @@ type config = {
72
69
  conformance binding's histories. Omitted ⇒ omitted from the fixtures, which
73
70
  only compiles when `createdFields` is omitted too. */
74
71
  createdValues?: array<string>,
75
-
76
72
  /** The slice component's name. Defaults to `Geocode<Entity><Subject>`. */
77
73
  slice?: string,
78
74
  /** The external box the Event Graph draws. Defaults to `"Geocoder"`; a host on
@@ -81,7 +77,6 @@ type config = {
81
77
  /** The read model the projection patch is addressed to. Defaults to
82
78
  `<Entity>s`. */
83
79
  view?: string,
84
-
85
80
  /** Two subjects that differ, for the histories in which the address changes.
86
81
  Defaulted when absent — they are test data, not a decision. */
87
82
  subjectA?: string,
@@ -186,7 +181,6 @@ let sliceSpec = (c: config): string => {
186
181
  ``,
187
182
  `// Retries are for a geocoder that is down, not one that has answered.`,
188
183
  `let maxRetries = 3`,
189
- `let heartbeatInterval = 60`,
190
184
  `let targetName = Some("${c.entity}")`,
191
185
  ``,
192
186
  `// The ${c.entity} aggregate by its Spec.name; an outbound slice could once only`,
@@ -227,8 +221,7 @@ let sliceTranslation = (c: config): string => {
227
221
  ", {" ++
228
222
  c.entityId ++
229
223
  ": sourceId, " ++
230
- n.subject ++
231
- "})]"
224
+ n.subject ++ "})]"
232
225
  lines([
233
226
  `@@reventless.translation`,
234
227
  ``,
@@ -297,7 +290,7 @@ let conformanceBinding = (c: config): string => {
297
290
  ` let posture = TraitAddressGeocoding.AddressGeocoding.WritesBack`,
298
291
  ``,
299
292
  ` module Spec = ${c.entity}`,
300
- ` module Behavior = ${c.entity}_Behavior`,
293
+ ` module Decision = ${c.entity}_Decision`,
301
294
  ``,
302
295
  ` let created = ${n.subject} => [${c.entity}.${createdValue}]`,
303
296
  ` let subjectChanged = ${n.subject} => ${c.entity}.${n.updated}({${n.subject}: ${n.subject}})`,
@@ -439,12 +432,12 @@ let aggregatePatch = (c: config): patch => {
439
432
  }
440
433
  }
441
434
 
442
- // ── The aggregate behavior patch ─────────────────────────────────────────────
435
+ // ── The aggregate decision patch ─────────────────────────────────────────────
443
436
 
444
- let behaviorPatch = (c: config): patch => {
437
+ let decisionPatch = (c: config): patch => {
445
438
  let n = namesOf(c)
446
439
  {
447
- into: `Aggregate/${c.entity}_Behavior.res`,
440
+ into: `Aggregate/${c.entity}_Decision.res`,
448
441
  at: `the state's fields, the \`evolve\` and \`decide\` switches, and two helpers`,
449
442
  contents: lines([
450
443
  `module Guards = TraitAddressGeocoding.AddressGeocoding_Guards`,
@@ -582,11 +575,11 @@ let emit = (~config: config, ~into: string, ~tests: string): output => {
582
575
  {
583
576
  files: [
584
577
  {
585
- path: `${into}/OutboundTranslationSlice/${n.slice}.res`,
578
+ path: `${into}/OutboundTranslation/${n.slice}.res`,
586
579
  contents: sliceSpec(config),
587
580
  },
588
581
  {
589
- path: `${into}/OutboundTranslationSlice/${n.slice}_Translation.res`,
582
+ path: `${into}/OutboundTranslation/${n.slice}_Translation.res`,
590
583
  contents: sliceTranslation(config),
591
584
  },
592
585
  {
@@ -594,6 +587,6 @@ let emit = (~config: config, ~into: string, ~tests: string): output => {
594
587
  contents: conformanceBinding(config),
595
588
  },
596
589
  ],
597
- patches: [aggregatePatch(config), behaviorPatch(config), projectionPatch(config)],
590
+ patches: [aggregatePatch(config), decisionPatch(config), projectionPatch(config)],
598
591
  }
599
592
  }
@@ -79,7 +79,6 @@ function sliceSpec(c) {
79
79
  ``,
80
80
  `// Retries are for a geocoder that is down, not one that has answered.`,
81
81
  `let maxRetries = 3`,
82
- `let heartbeatInterval = 60`,
83
82
  `let targetName = Some("` + c.entity + `")`,
84
83
  ``,
85
84
  `// The ` + c.entity + ` aggregate by its Spec.name; an outbound slice could once only`,
@@ -169,7 +168,7 @@ function conformanceBinding(c) {
169
168
  ` let posture = TraitAddressGeocoding.AddressGeocoding.WritesBack`,
170
169
  ``,
171
170
  ` module Spec = ` + c.entity,
172
- ` module Behavior = ` + c.entity + `_Behavior`,
171
+ ` module Decision = ` + c.entity + `_Decision`,
173
172
  ``,
174
173
  ` let created = ` + n.subject + ` => [` + c.entity + `.` + createdValue + `]`,
175
174
  ` let subjectChanged = ` + n.subject + ` => ` + c.entity + `.` + n.updated + `({` + n.subject + `: ` + n.subject + `})`,
@@ -285,10 +284,10 @@ function aggregatePatch(c) {
285
284
  };
286
285
  }
287
286
 
288
- function behaviorPatch(c) {
287
+ function decisionPatch(c) {
289
288
  let n = namesOf(c);
290
289
  return {
291
- into: `Aggregate/` + c.entity + `_Behavior.res`,
290
+ into: `Aggregate/` + c.entity + `_Decision.res`,
292
291
  at: `the state's fields, the \`evolve\` and \`decide\` switches, and two helpers`,
293
292
  contents: [
294
293
  `module Guards = TraitAddressGeocoding.AddressGeocoding_Guards`,
@@ -414,11 +413,11 @@ function emit(config, into, tests) {
414
413
  return {
415
414
  files: [
416
415
  {
417
- path: into + `/OutboundTranslationSlice/` + n.slice + `.res`,
416
+ path: into + `/OutboundTranslation/` + n.slice + `.res`,
418
417
  contents: sliceSpec(config)
419
418
  },
420
419
  {
421
- path: into + `/OutboundTranslationSlice/` + n.slice + `_Translation.res`,
420
+ path: into + `/OutboundTranslation/` + n.slice + `_Translation.res`,
422
421
  contents: sliceTranslation(config)
423
422
  },
424
423
  {
@@ -428,7 +427,7 @@ function emit(config, into, tests) {
428
427
  ],
429
428
  patches: [
430
429
  aggregatePatch(config),
431
- behaviorPatch(config),
430
+ decisionPatch(config),
432
431
  projectionPatch(config)
433
432
  ]
434
433
  };
@@ -445,7 +444,7 @@ export {
445
444
  conformanceBinding,
446
445
  transitionArms,
447
446
  aggregatePatch,
448
- behaviorPatch,
447
+ decisionPatch,
449
448
  projectionPatch,
450
449
  emit,
451
450
  }
@@ -7,7 +7,6 @@ An outage is not a verdict — it comes back `Error`, which leaves the TODO pend
7
7
  for another attempt — and once the retries are spent `exhaustedReason` is what the
8
8
  host reports instead, by the same command a confident refusal produces.
9
9
  */
10
-
11
10
  /** The geocoder arrives as a capability, so the deployment decides what answers. */
12
11
  let translate = async (
13
12
  ~text: string,