@reventlessdev/online-shop-hybrid-ordering 1.0.0-alpha.183 → 1.0.0-alpha.185

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 CHANGED
@@ -3,6 +3,21 @@
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.185 (2026-08-04)
7
+
8
+ **Note:** Version bump only for package @reventlessdev/online-shop-hybrid-ordering
9
+
10
+
11
+
12
+
13
+
14
+ # 1.0.0-alpha.184 (2026-08-04)
15
+
16
+ ### Features
17
+
18
+ * **outbound:** hand translate its geocoder instead of making it fetch one ([fb18312](https://github.com/ReventlessDev/reventless-core/commit/fb1831216b37c9562868c46e1a09054e69418c67))
19
+
20
+
6
21
  # 1.0.0-alpha.183 (2026-08-03)
7
22
 
8
23
  **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.183",
3
+ "version": "1.0.0-alpha.185",
4
4
  "description": "Online Shop Hybrid example — Ordering plugin (Customer aggregate + Order/CatalogProduct DCB)",
5
5
  "license": "Apache-2.0",
6
6
  "jest": {
@@ -21,13 +21,13 @@
21
21
  },
22
22
  "dependencies": {
23
23
  "sury": "^11.0.0-alpha.4",
24
- "@reventlessdev/online-shop-hybrid-catalog-spec": "1.0.0-alpha.94",
25
- "@reventlessdev/online-shop-hybrid-ordering-spec": "1.0.0-alpha.94",
24
+ "@reventlessdev/online-shop-hybrid-catalog-spec": "1.0.0-alpha.95",
25
+ "@reventlessdev/reventless-gwt": "1.0.0-alpha.158",
26
+ "@reventlessdev/reventless-infra": "3.0.0-alpha.126",
27
+ "@reventlessdev/online-shop-hybrid-ordering-spec": "1.0.0-alpha.95",
26
28
  "@reventlessdev/rescript-pulumi-pulumi": "2.3.0-alpha.18",
27
- "@reventlessdev/reventless-gwt": "1.0.0-alpha.156",
28
- "@reventlessdev/reventless-infra": "3.0.0-alpha.124",
29
- "@reventlessdev/reventless-local": "3.0.0-alpha.197",
30
- "@reventlessdev/reventless-spec": "3.0.0-alpha.99"
29
+ "@reventlessdev/reventless-local": "3.0.0-alpha.199",
30
+ "@reventlessdev/reventless-spec": "3.0.0-alpha.100"
31
31
  },
32
32
  "devDependencies": {
33
33
  "rescript": "12.3.0",
@@ -17,9 +17,13 @@ let collect = (event, ~sourceId) =>
17
17
  | AddressUpdated({address}) => [(`${sourceId}:${address}`, {customerId: sourceId, address})]
18
18
  }
19
19
 
20
- let translate = async (_id, item) => {
20
+ // The geocoder arrives as a capability rather than being reached for. This
21
+ // plugin cannot name Amazon Location — it depends on `reventless-spec`, not on
22
+ // `reventless-aws` — and under this shape it does not need to: the deployment
23
+ // decides what answers, and nothing below changes when that answer does.
24
+ let translate = async (_id, item, ~capabilities: Reventless.Capabilities.t) => {
21
25
  let customerId = item.customerId
22
- switch await GeocodingService.search(~text=item.address) {
26
+ switch await capabilities.geocode(~text=item.address) {
23
27
  | Error(Unavailable(why)) =>
24
28
  // Retryable: the service could not answer. Do NOT report a verdict on the
25
29
  // address — one outage would otherwise mark every address in flight bad.
@@ -1,7 +1,6 @@
1
1
  // Generated by ReScript, PLEASE EDIT WITH CARE
2
2
 
3
3
  import * as Geocoding$Reventless from "@reventlessdev/reventless-spec/src/semantic/Geocoding.res.mjs";
4
- import * as GeocodingService$OrderingPlugin from "../../Service/GeocodingService.res.mjs";
5
4
 
6
5
  function collect(event, sourceId) {
7
6
  if (event.TAG === "Registered") {
@@ -24,9 +23,9 @@ function collect(event, sourceId) {
24
23
  ]];
25
24
  }
26
25
 
27
- async function translate(_id, item) {
26
+ async function translate(_id, item, capabilities) {
28
27
  let customerId = item.customerId;
29
- let candidates = await GeocodingService$OrderingPlugin.search(item.address);
28
+ let candidates = await capabilities.geocode(item.address);
30
29
  if (candidates.TAG === "Ok") {
31
30
  let match = Geocoding$Reventless.confidentMatch(candidates._0, undefined, undefined);
32
31
  if (match !== undefined) {
@@ -86,4 +85,4 @@ export {
86
85
  translate,
87
86
  moduleUrl,
88
87
  }
89
- /* GeocodingService-OrderingPlugin Not a pure module */
88
+ /* No side effect */
@@ -6,7 +6,9 @@ let collect = (event, ~sourceId as _) =>
6
6
  | OrderPlaced({orderId, customerId}) => [(orderId, {orderId, customerId})]
7
7
  }
8
8
 
9
- let translate = async (_id, item) => {
9
+ // This slice calls a service the framework does not broker, so it reaches its
10
+ // mailer directly and ignores the injected capabilities.
11
+ let translate = async (_id, item, ~capabilities as _) => {
10
12
  try {
11
13
  await EmailService.sendOrderConfirmation(
12
14
  ~email=item.customerId,
@@ -16,7 +16,7 @@ function collect(event, param) {
16
16
  ]];
17
17
  }
18
18
 
19
- async function translate(_id, item) {
19
+ async function translate(_id, item, param) {
20
20
  try {
21
21
  await EmailService$OrderingPlugin.sendOrderConfirmation(item.customerId, item.orderId);
22
22
  return {
@@ -1,91 +0,0 @@
1
- // The plugin's geocoding client.
2
- //
3
- // A plugin is provider-agnostic — it cannot reach `ReventlessAws` and should not
4
- // know that Amazon Location is what answers. So this talks HTTP to whatever
5
- // endpoint the deployment configured and speaks the framework's provider-neutral
6
- // vocabulary (`Reventless.Geocoding`) on both sides.
7
- //
8
- // The endpoint's contract, which is what makes an unattended caller possible:
9
- // `200` with a (possibly empty) array is an answer, and any other status is the
10
- // service failing to give one. The distinction is the whole reason this returns
11
- // `result` rather than a list — see `Reventless.Geocoding.failure`.
12
-
13
- @val external fetch: (string, 'options) => promise<'response> = "fetch"
14
-
15
- type response = {ok: bool, status: int}
16
- @send external json: response => promise<JSON.t> = "json"
17
-
18
- @val external encodeURIComponent: string => string = "encodeURIComponent"
19
-
20
- // `process.env` without a Node binding — a plugin depends on neither
21
- // rescript-node nor any provider package.
22
- type processT = {env: dict<string>}
23
- @val external process: processT = "process"
24
-
25
- let endpoint = () =>
26
- switch process.env->Dict.get("GEOCODER_ENDPOINT") {
27
- | Some("") | None => None
28
- | Some(v) => Some(v)
29
- }
30
-
31
- // One candidate off the wire. A row missing a coordinate, or carrying one
32
- // outside the valid ranges, is dropped rather than propagated — it cannot be
33
- // stored, and one bad row should not lose the good ones beside it.
34
- let decodeCandidate = (json: JSON.t): option<Reventless.Geocoding.candidate> =>
35
- switch json->JSON.Decode.object {
36
- | None => None
37
- | Some(o) =>
38
- switch (
39
- o->Dict.get("lat")->Option.flatMap(JSON.Decode.float),
40
- o->Dict.get("lng")->Option.flatMap(JSON.Decode.float),
41
- ) {
42
- | (Some(lat), Some(lng)) =>
43
- switch Reventless.GeoPoint.make(~lat, ~lng) {
44
- | Ok(point) =>
45
- Some({
46
- Reventless.Geocoding.label: o
47
- ->Dict.get("label")
48
- ->Option.flatMap(JSON.Decode.string)
49
- ->Option.getOr(""),
50
- point,
51
- relevance: o->Dict.get("relevance")->Option.flatMap(JSON.Decode.float),
52
- })
53
- | Error(_) => None
54
- }
55
- | _ => None
56
- }
57
- }
58
-
59
- // Annotated against the framework's port rather than spelling the signature out
60
- // again. The endpoint this reads is a deployment's *current* answer to "who
61
- // geocodes"; the type is the answer that does not change when that one does, so
62
- // a later supplier swaps in here without `translate` noticing.
63
- let search: Reventless.Geocoding.search = async (~text) => {
64
- let trimmed = text->String.trim
65
- switch endpoint() {
66
- | None => Error(Unavailable("no geocoder endpoint configured (GEOCODER_ENDPOINT unset)"))
67
- | Some(_) if trimmed == "" =>
68
- // An empty query was never going to match; asking would spend a request to
69
- // be told so.
70
- Error(NoMatch)
71
- | Some(base) =>
72
- let url = `${base}?q=${encodeURIComponent(trimmed)}`
73
- switch await fetch(url, {"method": "GET"}) {
74
- | response =>
75
- if !response.ok {
76
- Error(Unavailable(`geocoder responded ${response.status->Int.toString}`))
77
- } else {
78
- switch await response->json {
79
- | body =>
80
- let candidates =
81
- body->JSON.Decode.array->Option.getOr([])->Array.filterMap(decodeCandidate)
82
- candidates->Array.length == 0 ? Error(NoMatch) : Ok(candidates)
83
- | exception _ => Error(Unavailable("geocoder returned a body that is not JSON"))
84
- }
85
- }
86
- | exception exn =>
87
- let msg = exn->JsExn.fromException->Option.flatMap(JsExn.message)->Option.getOr("unknown")
88
- Error(Unavailable(msg))
89
- }
90
- }
91
- }
@@ -1,123 +0,0 @@
1
- // Generated by ReScript, PLEASE EDIT WITH CARE
2
-
3
- import * as Stdlib_JSON from "@rescript/runtime/lib/es6/Stdlib_JSON.js";
4
- import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
5
- import * as Stdlib_JsExn from "@rescript/runtime/lib/es6/Stdlib_JsExn.js";
6
- import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
7
- import * as GeoPoint$Reventless from "@reventlessdev/reventless-spec/src/semantic/GeoPoint.res.mjs";
8
- import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
9
-
10
- function endpoint() {
11
- let v = process.env["GEOCODER_ENDPOINT"];
12
- if (v !== undefined && v !== "") {
13
- return v;
14
- }
15
- }
16
-
17
- function decodeCandidate(json) {
18
- let o = Stdlib_JSON.Decode.object(json);
19
- if (o === undefined) {
20
- return;
21
- }
22
- let match = Stdlib_Option.flatMap(o["lat"], Stdlib_JSON.Decode.float);
23
- let match$1 = Stdlib_Option.flatMap(o["lng"], Stdlib_JSON.Decode.float);
24
- if (match === undefined) {
25
- return;
26
- }
27
- if (match$1 === undefined) {
28
- return;
29
- }
30
- let point = GeoPoint$Reventless.make(match, match$1);
31
- if (point.TAG === "Ok") {
32
- return {
33
- label: Stdlib_Option.getOr(Stdlib_Option.flatMap(o["label"], Stdlib_JSON.Decode.string), ""),
34
- point: point._0,
35
- relevance: Stdlib_Option.flatMap(o["relevance"], Stdlib_JSON.Decode.float)
36
- };
37
- }
38
- }
39
-
40
- async function search(text) {
41
- let trimmed = text.trim();
42
- let base = endpoint();
43
- if (base === undefined) {
44
- return {
45
- TAG: "Error",
46
- _0: {
47
- TAG: "Unavailable",
48
- _0: "no geocoder endpoint configured (GEOCODER_ENDPOINT unset)"
49
- }
50
- };
51
- }
52
- if (trimmed === "") {
53
- return {
54
- TAG: "Error",
55
- _0: "NoMatch"
56
- };
57
- }
58
- let url = base + `?q=` + encodeURIComponent(trimmed);
59
- let exit = 0;
60
- let response;
61
- try {
62
- response = await fetch(url, {
63
- method: "GET"
64
- });
65
- exit = 1;
66
- } catch (raw_exn) {
67
- let exn = Primitive_exceptions.internalToException(raw_exn);
68
- let msg = Stdlib_Option.getOr(Stdlib_Option.flatMap(Stdlib_JsExn.fromException(exn), Stdlib_JsExn.message), "unknown");
69
- return {
70
- TAG: "Error",
71
- _0: {
72
- TAG: "Unavailable",
73
- _0: msg
74
- }
75
- };
76
- }
77
- if (exit === 1) {
78
- if (!response.ok) {
79
- return {
80
- TAG: "Error",
81
- _0: {
82
- TAG: "Unavailable",
83
- _0: `geocoder responded ` + response.status.toString()
84
- }
85
- };
86
- }
87
- let exit$1 = 0;
88
- let body;
89
- try {
90
- body = await response.json();
91
- exit$1 = 2;
92
- } catch (exn$1) {
93
- return {
94
- TAG: "Error",
95
- _0: {
96
- TAG: "Unavailable",
97
- _0: "geocoder returned a body that is not JSON"
98
- }
99
- };
100
- }
101
- if (exit$1 === 2) {
102
- let candidates = Stdlib_Array.filterMap(Stdlib_Option.getOr(Stdlib_JSON.Decode.array(body), []), decodeCandidate);
103
- if (candidates.length === 0) {
104
- return {
105
- TAG: "Error",
106
- _0: "NoMatch"
107
- };
108
- } else {
109
- return {
110
- TAG: "Ok",
111
- _0: candidates
112
- };
113
- }
114
- }
115
- }
116
- }
117
-
118
- export {
119
- endpoint,
120
- decodeCandidate,
121
- search,
122
- }
123
- /* Stdlib_JsExn Not a pure module */