@reventlessdev/reventless-spec 3.0.0-alpha.100

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 (139) hide show
  1. package/CHANGELOG.md +931 -0
  2. package/LICENSE +202 -0
  3. package/README.md +109 -0
  4. package/package.json +49 -0
  5. package/rescript.json +32 -0
  6. package/run-generator.mjs +2 -0
  7. package/run-platform-generator.mjs +2 -0
  8. package/scripts/generate-currency.mjs +215 -0
  9. package/scripts/iso-4217-list-one.xml +1956 -0
  10. package/src/AnsiStyle.res +40 -0
  11. package/src/AnsiStyle.res.mjs +54 -0
  12. package/src/LogPrefix.res +192 -0
  13. package/src/LogPrefix.res.mjs +159 -0
  14. package/src/PackageVersion.res +67 -0
  15. package/src/PackageVersion.res.mjs +81 -0
  16. package/src/components/Aggregate.res +64 -0
  17. package/src/components/Aggregate.res.mjs +2 -0
  18. package/src/components/AutomationSlice.res +279 -0
  19. package/src/components/AutomationSlice.res.mjs +30 -0
  20. package/src/components/CapabilityManifest.res +74 -0
  21. package/src/components/CapabilityManifest.res.mjs +61 -0
  22. package/src/components/ComponentKind.res +99 -0
  23. package/src/components/ComponentKind.res.mjs +125 -0
  24. package/src/components/Counter.res +24 -0
  25. package/src/components/Counter.res.mjs +2 -0
  26. package/src/components/DcbDecode.res +118 -0
  27. package/src/components/DcbDecode.res.mjs +100 -0
  28. package/src/components/DcbScopeInference.res +244 -0
  29. package/src/components/DcbScopeInference.res.mjs +177 -0
  30. package/src/components/DcbTag.res +1335 -0
  31. package/src/components/DcbTag.res.mjs +898 -0
  32. package/src/components/DcbValidation.res +427 -0
  33. package/src/components/DcbValidation.res.mjs +423 -0
  34. package/src/components/DisplayName.res +40 -0
  35. package/src/components/DisplayName.res.mjs +26 -0
  36. package/src/components/ExtensionPoint.res +27 -0
  37. package/src/components/ExtensionPoint.res.mjs +2 -0
  38. package/src/components/InboundTranslationSlice.res +85 -0
  39. package/src/components/InboundTranslationSlice.res.mjs +2 -0
  40. package/src/components/OutboundTranslationSlice.res +153 -0
  41. package/src/components/OutboundTranslationSlice.res.mjs +2 -0
  42. package/src/components/Plugin.res +538 -0
  43. package/src/components/Plugin.res.mjs +264 -0
  44. package/src/components/PluginName.res +39 -0
  45. package/src/components/PluginName.res.mjs +45 -0
  46. package/src/components/ReadModel.res +199 -0
  47. package/src/components/ReadModel.res.mjs +18 -0
  48. package/src/components/Reference.res +55 -0
  49. package/src/components/Reference.res.mjs +50 -0
  50. package/src/components/Snapshot.res +26 -0
  51. package/src/components/Snapshot.res.mjs +2 -0
  52. package/src/components/StateAnnotations.res +97 -0
  53. package/src/components/StateAnnotations.res.mjs +15 -0
  54. package/src/components/StateChangeSlice.res +131 -0
  55. package/src/components/StateChangeSlice.res.mjs +2 -0
  56. package/src/components/StateViewSlice.res +123 -0
  57. package/src/components/StateViewSlice.res.mjs +2 -0
  58. package/src/components/Task.res +62 -0
  59. package/src/components/Task.res.mjs +2 -0
  60. package/src/generator/Codegen.res +842 -0
  61. package/src/generator/Codegen.res.mjs +565 -0
  62. package/src/generator/Config.res +106 -0
  63. package/src/generator/Config.res.mjs +69 -0
  64. package/src/generator/Discovery.res +230 -0
  65. package/src/generator/Discovery.res.mjs +198 -0
  66. package/src/generator/Generator_Node.res +14 -0
  67. package/src/generator/Generator_Node.res.mjs +18 -0
  68. package/src/generator/Pairing.res +460 -0
  69. package/src/generator/Pairing.res.mjs +415 -0
  70. package/src/generator/PlatformCodegen.res +207 -0
  71. package/src/generator/PlatformCodegen.res.mjs +154 -0
  72. package/src/generator/PlatformGenerator.res +126 -0
  73. package/src/generator/PlatformGenerator.res.mjs +114 -0
  74. package/src/generator/PlatformManifests.res +203 -0
  75. package/src/generator/PlatformManifests.res.mjs +212 -0
  76. package/src/generator/PluginGenerator.res +57 -0
  77. package/src/generator/PluginGenerator.res.mjs +73 -0
  78. package/src/semantic/Bytes.res +54 -0
  79. package/src/semantic/Bytes.res.mjs +38 -0
  80. package/src/semantic/Capabilities.res +43 -0
  81. package/src/semantic/Capabilities.res.mjs +17 -0
  82. package/src/semantic/Color.res +51 -0
  83. package/src/semantic/Color.res.mjs +29 -0
  84. package/src/semantic/Currency.res +598 -0
  85. package/src/semantic/Currency.res.mjs +743 -0
  86. package/src/semantic/DateRange.res +148 -0
  87. package/src/semantic/DateRange.res.mjs +74 -0
  88. package/src/semantic/Duration.res +53 -0
  89. package/src/semantic/Duration.res.mjs +26 -0
  90. package/src/semantic/Email.res +51 -0
  91. package/src/semantic/Email.res.mjs +31 -0
  92. package/src/semantic/GeoPoint.res +226 -0
  93. package/src/semantic/GeoPoint.res.mjs +190 -0
  94. package/src/semantic/Geocoding.res +127 -0
  95. package/src/semantic/Geocoding.res.mjs +36 -0
  96. package/src/semantic/Money.res +196 -0
  97. package/src/semantic/Money.res.mjs +138 -0
  98. package/src/semantic/Offload.res +294 -0
  99. package/src/semantic/Offload.res.mjs +191 -0
  100. package/src/semantic/Percent.res +53 -0
  101. package/src/semantic/Percent.res.mjs +33 -0
  102. package/src/semantic/Phone.res +55 -0
  103. package/src/semantic/Phone.res.mjs +29 -0
  104. package/src/semantic/Semantic.res +162 -0
  105. package/src/semantic/Semantic.res.mjs +95 -0
  106. package/src/semantic/StorageRef.res +164 -0
  107. package/src/semantic/StorageRef.res.mjs +111 -0
  108. package/src/semantic/Url.res +66 -0
  109. package/src/semantic/Url.res.mjs +48 -0
  110. package/src/types/Authorization.res +23 -0
  111. package/src/types/Authorization.res.mjs +33 -0
  112. package/src/types/Behavior.res +86 -0
  113. package/src/types/Behavior.res.mjs +2 -0
  114. package/src/types/DateTime.res +29 -0
  115. package/src/types/DateTime.res.mjs +16 -0
  116. package/src/types/EventMapping.res +100 -0
  117. package/src/types/EventMapping.res.mjs +15 -0
  118. package/src/types/Handler.res +30 -0
  119. package/src/types/Handler.res.mjs +2 -0
  120. package/src/types/Id.res +75 -0
  121. package/src/types/Id.res.mjs +37 -0
  122. package/src/types/Identity.res +46 -0
  123. package/src/types/Identity.res.mjs +51 -0
  124. package/src/types/Message.res +326 -0
  125. package/src/types/Message.res.mjs +186 -0
  126. package/src/types/Projection.res +220 -0
  127. package/src/types/Projection.res.mjs +44 -0
  128. package/src/types/QueryEngine.res +123 -0
  129. package/src/types/QueryEngine.res.mjs +12 -0
  130. package/src/types/ReadConsistency.res +38 -0
  131. package/src/types/ReadConsistency.res.mjs +29 -0
  132. package/src/types/Schedule.res +65 -0
  133. package/src/types/Schedule.res.mjs +68 -0
  134. package/src/types/SideEffect.res +45 -0
  135. package/src/types/SideEffect.res.mjs +2 -0
  136. package/src/types/StoredEvent.res +46 -0
  137. package/src/types/StoredEvent.res.mjs +32 -0
  138. package/src/types/Visibility.res +24 -0
  139. package/src/types/Visibility.res.mjs +25 -0
@@ -0,0 +1,40 @@
1
+ /** ANSI terminal style primitives + sink detection for log output.
2
+ Kept in reventless-spec so both reventless-core (Logger / LogFormat) and
3
+ reventless-infra (compLog in ExtensionMapping/ExtensionPointMapping)
4
+ can share the same styling helpers AND the same sink decision.
5
+
6
+ This is the lowest layer in the logging stack — LogPrefix and Logger
7
+ depend on it, so the sink decision lives here as the single source of
8
+ truth. `useAnsi()` ⇒ TTY text mode (colour/bold); `isJsonSink()` ⇒
9
+ structured JSON for any non-TTY collector (CloudWatch, Datadog, …). */
10
+
11
+ @val external _isTty: option<bool> = "process.stdout.isTTY"
12
+ @val external _logFormat: option<string> = "process.env.REVENTLESS_LOG_FORMAT"
13
+
14
+ // "json" | "text". Explicit REVENTLESS_LOG_FORMAT override always wins; otherwise
15
+ // a TTY stdout ⇒ human-readable text, everything else (Lambda, Fargate, ECS,
16
+ // Azure, GCP, Docker, CI runners, piped stdout) ⇒ structured JSON.
17
+ let _resolveFormat = (): string =>
18
+ switch (_logFormat, _isTty) {
19
+ | (Some("json"), _) => "json"
20
+ | (Some("text"), _) => "text"
21
+ | (_, Some(true)) => "text"
22
+ | _ => "json"
23
+ }
24
+
25
+ // Resolved once at module init; recomputable via `reload()` (test-only — after a
26
+ // test mutates process.env / process.stdout.isTTY). Not a hot path, but caching
27
+ // keeps every log call off `process.env`.
28
+ let _format = ref(_resolveFormat())
29
+
30
+ /** Test-only: re-evaluate REVENTLESS_LOG_FORMAT / process.stdout.isTTY. */
31
+ let reload = () => _format := _resolveFormat()
32
+
33
+ /** True when output should be structured JSON (non-TTY sink). */
34
+ let isJsonSink = () => _format.contents == "json"
35
+
36
+ /** True when output should carry ANSI colour/bold (TTY text mode). */
37
+ let useAnsi = () => _format.contents == "text"
38
+
39
+ /** Wrap a string in ANSI bold escape codes — no-op in a JSON sink. */
40
+ let bold = s => useAnsi() ? `\x1b[1m${s}\x1b[0m` : s
@@ -0,0 +1,54 @@
1
+ // Generated by ReScript, PLEASE EDIT WITH CARE
2
+
3
+
4
+ function _resolveFormat() {
5
+ let match = process.env.REVENTLESS_LOG_FORMAT;
6
+ let match$1 = process.stdout.isTTY;
7
+ if (match !== undefined) {
8
+ switch (match) {
9
+ case "json" :
10
+ return "json";
11
+ case "text" :
12
+ return "text";
13
+ }
14
+ }
15
+ if (match$1 !== undefined && match$1) {
16
+ return "text";
17
+ } else {
18
+ return "json";
19
+ }
20
+ }
21
+
22
+ let _format = {
23
+ contents: _resolveFormat()
24
+ };
25
+
26
+ function reload() {
27
+ _format.contents = _resolveFormat();
28
+ }
29
+
30
+ function isJsonSink() {
31
+ return _format.contents === "json";
32
+ }
33
+
34
+ function useAnsi() {
35
+ return _format.contents === "text";
36
+ }
37
+
38
+ function bold(s) {
39
+ if (_format.contents === "text") {
40
+ return `\x1b[1m` + s + `\x1b[0m`;
41
+ } else {
42
+ return s;
43
+ }
44
+ }
45
+
46
+ export {
47
+ _resolveFormat,
48
+ _format,
49
+ reload,
50
+ isJsonSink,
51
+ useAnsi,
52
+ bold,
53
+ }
54
+ /* _format Not a pure module */
@@ -0,0 +1,192 @@
1
+ /** Plugin-name resolution for log prefixes.
2
+
3
+ Shared between `ReventlessCore.Logger` (terminal/CloudWatch emit) and
4
+ `ReventlessInfra.{ExtensionPoint,Extension}Mapping.compLog` so logs from
5
+ either layer carry the same `[PluginName][Comp]` prefix.
6
+
7
+ Resolution priority for a comp string like `"Kind(Name)"`:
8
+ 1. The inner name (e.g. `"AddProduct"`) looked up in `componentPluginRegistry`.
9
+ 2. The ambient `currentPluginName` ref (set by `Plugin_Builder.construct`).
10
+ 3. Transformations of the inner name, each tried against the registry:
11
+ - strip `@version` suffix (handles `Plugin(Foo@1.2.3)`)
12
+ - strip trailing `Plugin` (handles `CommandTopic(FooPlugin)`)
13
+ - last dot segment (handles `Extension(Catalog.Products.Ordering)`)
14
+ - first dot segment (handles `ExtensionPoint(Catalog.Products)`)
15
+ 4. Longest registered component name that prefixes the inner name (handles
16
+ kind-suffixed resource names like `EventCollector(CustomersReadModel)`).
17
+
18
+ `Plugin_Builder` registers every component (and the plugin's self-name) when
19
+ constructing a plugin, so all transformation candidates resolve to a
20
+ real plugin name. */
21
+
22
+ // Ambient plugin name. Set inside `Plugin_Builder.Make.construct` so
23
+ // synchronous logs during construction carry a `[Name]` prefix.
24
+ let currentPluginName: ref<option<string>> = ref(None)
25
+
26
+ // Registry: component name → owning plugin name. Populated at construct time.
27
+ let componentPluginRegistry: ref<dict<string>> = ref(Dict.make())
28
+
29
+ let registerComponentPlugin = (~componentName: string, ~pluginName: string) =>
30
+ componentPluginRegistry.contents->Dict.set(componentName, pluginName)
31
+
32
+ // Stable hash for picking a color from the palette.
33
+ let hashStr = (s: string): int => {
34
+ let h = ref(0)
35
+ for i in 0 to s->String.length - 1 {
36
+ let code = s->String.charCodeAt(i)->Option.getOr(0)
37
+ h := h.contents + code * (i + 1)
38
+ }
39
+ h.contents
40
+ }
41
+
42
+ // Foreground colors that don't collide with level indicators (cyan / yellow / red).
43
+ let pluginColors = [
44
+ "\x1b[32m", // green
45
+ "\x1b[34m", // blue
46
+ "\x1b[35m", // magenta
47
+ "\x1b[92m", // bright green
48
+ "\x1b[94m", // bright blue
49
+ "\x1b[95m", // bright magenta
50
+ ]
51
+
52
+ let pluginColor = (name: string): string =>
53
+ pluginColors->Array.getUnsafe(mod(hashStr(name), pluginColors->Array.length))
54
+
55
+ // Extract the inner argument from a comp like `"Kind(Name)"`.
56
+ let extractInnerName = (comp: string): option<string> => {
57
+ let openIdx = comp->String.indexOf("(")
58
+ let closeIdx = comp->String.lastIndexOf(")")
59
+ if openIdx > 0 && closeIdx > openIdx + 1 {
60
+ Some(comp->String.slice(~start=openIdx + 1, ~end=closeIdx))
61
+ } else {
62
+ None
63
+ }
64
+ }
65
+
66
+ let stripAtVersion = (s: string): option<string> => {
67
+ let idx = s->String.indexOf("@")
68
+ if idx > 0 {
69
+ Some(s->String.slice(~start=0, ~end=idx))
70
+ } else {
71
+ None
72
+ }
73
+ }
74
+
75
+ let stripPluginSuffix = (s: string): option<string> => {
76
+ let suffix = "Plugin"
77
+ if s->String.endsWith(suffix) && s->String.length > suffix->String.length {
78
+ Some(s->String.slice(~start=0, ~end=s->String.length - suffix->String.length))
79
+ } else {
80
+ None
81
+ }
82
+ }
83
+
84
+ let firstDotSegment = (s: string): option<string> => {
85
+ let idx = s->String.indexOf(".")
86
+ if idx > 0 {
87
+ Some(s->String.slice(~start=0, ~end=idx))
88
+ } else {
89
+ None
90
+ }
91
+ }
92
+
93
+ let lastDotSegment = (s: string): option<string> => {
94
+ let idx = s->String.lastIndexOf(".")
95
+ if idx > 0 && idx + 1 < s->String.length {
96
+ Some(s->String.slice(~start=idx + 1, ~end=s->String.length))
97
+ } else {
98
+ None
99
+ }
100
+ }
101
+
102
+ let lookup = (name: string): option<string> =>
103
+ componentPluginRegistry.contents->Dict.get(name)
104
+
105
+ // Last-resort candidate: the inner name is a registered component name carrying a
106
+ // component-kind suffix (`Customers` + `ReadModel` → `CustomersReadModel`), which is
107
+ // how event-collector resources are named. Longest prefix wins so `OrdersReadModel`
108
+ // resolves via `Orders` rather than a shorter `Order` registered by another plugin.
109
+ // LogPrefix sits below `ComponentType`, so this stays suffix-table-free.
110
+ let longestRegisteredPrefix = (name: string): option<string> =>
111
+ componentPluginRegistry.contents
112
+ ->Dict.keysToArray
113
+ ->Array.reduce(None, (acc, key) =>
114
+ if key->String.length < name->String.length && name->String.startsWith(key) {
115
+ switch acc {
116
+ | Some(best) if best->String.length >= key->String.length => acc
117
+ | _ => Some(key)
118
+ }
119
+ } else {
120
+ acc
121
+ }
122
+ )
123
+ ->Option.flatMap(lookup)
124
+
125
+ let resolvePlugin = (~comp=?, ()) =>
126
+ switch comp {
127
+ | Some(c) =>
128
+ switch extractInnerName(c) {
129
+ | Some(inner) =>
130
+ switch lookup(inner) {
131
+ | Some(p) => Some(p)
132
+ | None =>
133
+ switch currentPluginName.contents {
134
+ | Some(p) => Some(p)
135
+ | None =>
136
+ // Try transformations in declaration order; first hit wins.
137
+ let candidates = [
138
+ stripAtVersion(inner),
139
+ stripPluginSuffix(inner),
140
+ lastDotSegment(inner),
141
+ firstDotSegment(inner),
142
+ ]
143
+ candidates
144
+ ->Array.reduce(None, (acc, candidate) =>
145
+ switch acc {
146
+ | Some(_) => acc
147
+ | None => candidate->Option.flatMap(lookup)
148
+ }
149
+ )
150
+ ->Option.orElse(longestRegisteredPrefix(inner))
151
+ }
152
+ }
153
+ | None => currentPluginName.contents
154
+ }
155
+ | None => currentPluginName.contents
156
+ }
157
+
158
+ // Plain (no ANSI) prefix used for Lambda/CloudWatch output.
159
+ let fmtPlainPrefix = (~comp=?, ()) => {
160
+ let plugin = switch resolvePlugin(~comp?, ()) {
161
+ | Some(p) => `[${p}]`
162
+ | None => ""
163
+ }
164
+ let c = switch comp {
165
+ | Some(c) => `[${c}] `
166
+ | None => ""
167
+ }
168
+ plugin ++ c
169
+ }
170
+
171
+ // Bold-bracketed prefix used for terminal output.
172
+ // Plugin bracket is colored (foreground) by a stable hash of the plugin name;
173
+ // no trailing space between `[Plugin]` and `[Comp]`.
174
+ //
175
+ // Sink-aware: in a non-TTY/JSON sink it falls back to `fmtPlainPrefix` so no
176
+ // ANSI colour or bold leaks into structured logs. This makes every caller that
177
+ // pre-formats a prefix before reaching `Logger.emit` (EffectLogger.withComp,
178
+ // the infra-layer `compLog`s) correct without per-call-site changes.
179
+ let fmtComp = (~comp=?, ()) =>
180
+ if !AnsiStyle.useAnsi() {
181
+ fmtPlainPrefix(~comp?, ())
182
+ } else {
183
+ let plugin = switch resolvePlugin(~comp?, ()) {
184
+ | Some(p) => `${pluginColor(p)}${AnsiStyle.bold(`[${p}]`)}`
185
+ | None => ""
186
+ }
187
+ let c = switch comp {
188
+ | Some(c) => `${AnsiStyle.bold(`[${c}]`)} `
189
+ | None => ""
190
+ }
191
+ plugin ++ c
192
+ }
@@ -0,0 +1,159 @@
1
+ // Generated by ReScript, PLEASE EDIT WITH CARE
2
+
3
+ import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
4
+ import * as Primitive_int from "@rescript/runtime/lib/es6/Primitive_int.js";
5
+ import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
6
+ import * as Stdlib_String from "@rescript/runtime/lib/es6/Stdlib_String.js";
7
+ import * as AnsiStyle$Reventless from "./AnsiStyle.res.mjs";
8
+
9
+ let currentPluginName = {
10
+ contents: undefined
11
+ };
12
+
13
+ let componentPluginRegistry = {
14
+ contents: {}
15
+ };
16
+
17
+ function registerComponentPlugin(componentName, pluginName) {
18
+ componentPluginRegistry.contents[componentName] = pluginName;
19
+ }
20
+
21
+ function hashStr(s) {
22
+ let h = 0;
23
+ for (let i = 0, i_finish = s.length; i < i_finish; ++i) {
24
+ let code = Stdlib_Option.getOr(Stdlib_String.charCodeAt(s, i), 0);
25
+ h = h + (code * (i + 1 | 0) | 0) | 0;
26
+ }
27
+ return h;
28
+ }
29
+
30
+ let pluginColors = [
31
+ "\x1b[32m",
32
+ "\x1b[34m",
33
+ "\x1b[35m",
34
+ "\x1b[92m",
35
+ "\x1b[94m",
36
+ "\x1b[95m"
37
+ ];
38
+
39
+ function pluginColor(name) {
40
+ return pluginColors[Primitive_int.mod_(hashStr(name), pluginColors.length)];
41
+ }
42
+
43
+ function extractInnerName(comp) {
44
+ let openIdx = comp.indexOf("(");
45
+ let closeIdx = comp.lastIndexOf(")");
46
+ if (openIdx > 0 && closeIdx > (openIdx + 1 | 0)) {
47
+ return comp.slice(openIdx + 1 | 0, closeIdx);
48
+ }
49
+ }
50
+
51
+ function stripAtVersion(s) {
52
+ let idx = s.indexOf("@");
53
+ if (idx > 0) {
54
+ return s.slice(0, idx);
55
+ }
56
+ }
57
+
58
+ function stripPluginSuffix(s) {
59
+ let suffix = "Plugin";
60
+ if (s.endsWith(suffix) && s.length > suffix.length) {
61
+ return s.slice(0, s.length - suffix.length | 0);
62
+ }
63
+ }
64
+
65
+ function firstDotSegment(s) {
66
+ let idx = s.indexOf(".");
67
+ if (idx > 0) {
68
+ return s.slice(0, idx);
69
+ }
70
+ }
71
+
72
+ function lastDotSegment(s) {
73
+ let idx = s.lastIndexOf(".");
74
+ if (idx > 0 && (idx + 1 | 0) < s.length) {
75
+ return s.slice(idx + 1 | 0, s.length);
76
+ }
77
+ }
78
+
79
+ function lookup(name) {
80
+ return componentPluginRegistry.contents[name];
81
+ }
82
+
83
+ function longestRegisteredPrefix(name) {
84
+ return Stdlib_Option.flatMap(Stdlib_Array.reduce(Object.keys(componentPluginRegistry.contents), undefined, (acc, key) => {
85
+ if (key.length < name.length && name.startsWith(key) && !(acc !== undefined && acc.length >= key.length)) {
86
+ return key;
87
+ } else {
88
+ return acc;
89
+ }
90
+ }), lookup);
91
+ }
92
+
93
+ function resolvePlugin(comp, param) {
94
+ if (comp === undefined) {
95
+ return currentPluginName.contents;
96
+ }
97
+ let inner = extractInnerName(comp);
98
+ if (inner === undefined) {
99
+ return currentPluginName.contents;
100
+ }
101
+ let p = componentPluginRegistry.contents[inner];
102
+ if (p !== undefined) {
103
+ return p;
104
+ }
105
+ let p$1 = currentPluginName.contents;
106
+ if (p$1 !== undefined) {
107
+ return p$1;
108
+ }
109
+ let candidates = [
110
+ stripAtVersion(inner),
111
+ stripPluginSuffix(inner),
112
+ lastDotSegment(inner),
113
+ firstDotSegment(inner)
114
+ ];
115
+ return Stdlib_Option.orElse(Stdlib_Array.reduce(candidates, undefined, (acc, candidate) => {
116
+ if (acc !== undefined) {
117
+ return acc;
118
+ } else {
119
+ return Stdlib_Option.flatMap(candidate, lookup);
120
+ }
121
+ }), longestRegisteredPrefix(inner));
122
+ }
123
+
124
+ function fmtPlainPrefix(comp, param) {
125
+ let p = resolvePlugin(comp, undefined);
126
+ let plugin = p !== undefined ? `[` + p + `]` : "";
127
+ let c = comp !== undefined ? `[` + comp + `] ` : "";
128
+ return plugin + c;
129
+ }
130
+
131
+ function fmtComp(comp, param) {
132
+ if (!AnsiStyle$Reventless.useAnsi()) {
133
+ return fmtPlainPrefix(comp, undefined);
134
+ }
135
+ let p = resolvePlugin(comp, undefined);
136
+ let plugin = p !== undefined ? pluginColor(p) + AnsiStyle$Reventless.bold(`[` + p + `]`) : "";
137
+ let c = comp !== undefined ? AnsiStyle$Reventless.bold(`[` + comp + `]`) + ` ` : "";
138
+ return plugin + c;
139
+ }
140
+
141
+ export {
142
+ currentPluginName,
143
+ componentPluginRegistry,
144
+ registerComponentPlugin,
145
+ hashStr,
146
+ pluginColors,
147
+ pluginColor,
148
+ extractInnerName,
149
+ stripAtVersion,
150
+ stripPluginSuffix,
151
+ firstDotSegment,
152
+ lastDotSegment,
153
+ lookup,
154
+ longestRegisteredPrefix,
155
+ resolvePlugin,
156
+ fmtPlainPrefix,
157
+ fmtComp,
158
+ }
159
+ /* AnsiStyle-Reventless Not a pure module */
@@ -0,0 +1,67 @@
1
+ let readVersion = (path: string) =>
2
+ NodeFs.readFileSync(path)
3
+ ->JSON.parseOrThrow
4
+ ->JSON.Decode.object
5
+ ->Option.flatMap(o => o->Dict.get("version"))
6
+ ->Option.flatMap(JSON.Decode.string)
7
+ ->Option.getOr("0.0.0")
8
+
9
+ let fromCwd = () => readVersion("./package.json")
10
+
11
+ let findVersion = dir => {
12
+ let rec find = dir => {
13
+ let candidate = NodePath.join([dir, "package.json"])
14
+ if NodeFs.existsSync(candidate) {
15
+ readVersion(candidate)
16
+ } else {
17
+ let parent = NodePath.dirname(dir)
18
+ if parent == dir {
19
+ "0.0.0"
20
+ } else {
21
+ find(parent)
22
+ }
23
+ }
24
+ }
25
+ find(dir)
26
+ }
27
+
28
+ let fromModuleUrl = (url: string) => findVersion(url->NodeUrl.fileURLToPath->NodePath.dirname)
29
+
30
+ /** Detect the caller's file via V8 Structured Stack Trace API and read the
31
+ version from the nearest package.json. Skips frames from framework packages
32
+ (reventless-spec, reventless-core, reventless-infra, reventless-local,
33
+ reventless-aws, reventless-interop). Falls back to CWD's package.json. */
34
+ let callerFile: unit => option<string> = %raw(`
35
+ function() {
36
+ var frameworkMarkers = [
37
+ '/reventless/',
38
+ '/@reventlessdev/reventless-',
39
+ ];
40
+ var oldPrepare = Error.prepareStackTrace;
41
+ Error.prepareStackTrace = function(_, stack) { return stack; };
42
+ var err = new Error();
43
+ var stack = err.stack;
44
+ Error.prepareStackTrace = oldPrepare;
45
+ for (var i = 0; i < stack.length; i++) {
46
+ var file = stack[i].getFileName();
47
+ if (!file) continue;
48
+ var isFramework = false;
49
+ for (var j = 0; j < frameworkMarkers.length; j++) {
50
+ if (file.indexOf(frameworkMarkers[j]) !== -1) { isFramework = true; break; }
51
+ }
52
+ if (!isFramework) return file;
53
+ }
54
+ return undefined;
55
+ }
56
+ `)
57
+
58
+ let fromCaller = () =>
59
+ switch callerFile() {
60
+ | Some(file) =>
61
+ if file->String.startsWith("file://") {
62
+ findVersion(file->NodeUrl.fileURLToPath->NodePath.dirname)
63
+ } else {
64
+ findVersion(file->NodePath.dirname)
65
+ }
66
+ | None => fromCwd()
67
+ }
@@ -0,0 +1,81 @@
1
+ // Generated by ReScript, PLEASE EDIT WITH CARE
2
+
3
+ import * as Nodefs from "node:fs";
4
+ import * as Nodeurl from "node:url";
5
+ import * as Nodepath from "node:path";
6
+ import * as Stdlib_JSON from "@rescript/runtime/lib/es6/Stdlib_JSON.js";
7
+ import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
8
+
9
+ function readVersion(path) {
10
+ return Stdlib_Option.getOr(Stdlib_Option.flatMap(Stdlib_Option.flatMap(Stdlib_JSON.Decode.object(JSON.parse(Nodefs.readFileSync(path, "utf8"))), o => o["version"]), Stdlib_JSON.Decode.string), "0.0.0");
11
+ }
12
+
13
+ function fromCwd() {
14
+ return readVersion("./package.json");
15
+ }
16
+
17
+ function findVersion(dir) {
18
+ let _dir = dir;
19
+ while (true) {
20
+ let dir$1 = _dir;
21
+ let candidate = Nodepath.join(dir$1, "package.json");
22
+ if (Nodefs.existsSync(candidate)) {
23
+ return readVersion(candidate);
24
+ }
25
+ let parent = Nodepath.dirname(dir$1);
26
+ if (parent === dir$1) {
27
+ return "0.0.0";
28
+ }
29
+ _dir = parent;
30
+ continue;
31
+ };
32
+ }
33
+
34
+ function fromModuleUrl(url) {
35
+ return findVersion(Nodepath.dirname(Nodeurl.fileURLToPath(url)));
36
+ }
37
+
38
+ let callerFile = (function() {
39
+ var frameworkMarkers = [
40
+ '/reventless/',
41
+ '/@reventlessdev/reventless-',
42
+ ];
43
+ var oldPrepare = Error.prepareStackTrace;
44
+ Error.prepareStackTrace = function(_, stack) { return stack; };
45
+ var err = new Error();
46
+ var stack = err.stack;
47
+ Error.prepareStackTrace = oldPrepare;
48
+ for (var i = 0; i < stack.length; i++) {
49
+ var file = stack[i].getFileName();
50
+ if (!file) continue;
51
+ var isFramework = false;
52
+ for (var j = 0; j < frameworkMarkers.length; j++) {
53
+ if (file.indexOf(frameworkMarkers[j]) !== -1) { isFramework = true; break; }
54
+ }
55
+ if (!isFramework) return file;
56
+ }
57
+ return undefined;
58
+ });
59
+
60
+ function fromCaller() {
61
+ let file = callerFile();
62
+ if (file !== undefined) {
63
+ if (file.startsWith("file://")) {
64
+ return findVersion(Nodepath.dirname(Nodeurl.fileURLToPath(file)));
65
+ } else {
66
+ return findVersion(Nodepath.dirname(file));
67
+ }
68
+ } else {
69
+ return readVersion("./package.json");
70
+ }
71
+ }
72
+
73
+ export {
74
+ readVersion,
75
+ fromCwd,
76
+ findVersion,
77
+ fromModuleUrl,
78
+ callerFile,
79
+ fromCaller,
80
+ }
81
+ /* node:fs Not a pure module */
@@ -0,0 +1,64 @@
1
+ /**
2
+ Module type for an aggregate's identity and schema specification.
3
+
4
+ Every aggregate defines a `Spec` module satisfying this type. The `Spec` is
5
+ used by `Platform.Aggregate.Make` and by `Behavior.T` to fix the aggregate's
6
+ command, event, and error types.
7
+
8
+ @example
9
+ ```rescript
10
+ // Category.res
11
+ module Id = Id.String
12
+ let name = "Category"
13
+
14
+ @schema
15
+ type command =
16
+ | AddCategory({categoryId: string, name: string})
17
+ | RenameCategory({categoryId: string, name: string})
18
+ | ArchiveCategory({categoryId: string})
19
+
20
+ @schema
21
+ type event =
22
+ | CategoryAdded({categoryId: string, name: string})
23
+ | CategoryRenamed({categoryId: string, name: string})
24
+ | CategoryArchived({categoryId: string})
25
+
26
+ @schema
27
+ type error =
28
+ | CategoryAlreadyExists
29
+ | CategoryNotFound
30
+ | CategoryAlreadyArchived
31
+ ```
32
+ */
33
+ module type Spec = {
34
+ module Id: Id.T
35
+
36
+ /** Logical aggregate name used as a prefix for infrastructure resource names. */
37
+ let name: string
38
+
39
+ /** Commands this aggregate accepts. Must carry `@schema`. */
40
+ @schema
41
+ type command
42
+
43
+ /** Events this aggregate emits. Must carry `@schema`. */
44
+ @schema
45
+ type event
46
+
47
+ /** Business rule violation errors. Must carry `@schema`. */
48
+ @schema
49
+ type error
50
+
51
+ /** Sury schema for the command type — generated automatically by `@schema`. */
52
+ let commandSchema: S.t<command>
53
+
54
+ /** File URL of this module (`import.meta.url`). Used by AWS builders to derive
55
+ the npm specifier for runtime dynamic imports. */
56
+ let moduleUrl: string
57
+
58
+ /** Authorization rule evaluated at the GraphQL resolver entry before any
59
+ command is dispatched. Auto-injected by `@@reventless.spec` and on
60
+ structurally-detected inline spec modules — defaults to
61
+ `AllowAuthenticated`; override at the file/module level with
62
+ `@@reventless.authorize(<rule>)`. */
63
+ let commandAuthorization: command => Authorization.permission
64
+ }
@@ -0,0 +1,2 @@
1
+ // Generated by ReScript, PLEASE EDIT WITH CARE
2
+ /* This output is empty. Its source's type definitions, externals and/or unused code got optimized away. */