@reventlessdev/reventless-core 3.0.0-alpha.212 → 3.0.0-alpha.214
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 +19 -0
- package/package.json +6 -6
- package/src/Projection.res +5 -2
- package/src/Projection.res.mjs +2 -1
- package/src/adapter/EventLogProvisioning/EventLogProvisioning.res +165 -0
- package/src/adapter/EventLogProvisioning/EventLogProvisioning.res.mjs +49 -0
- package/src/components/AutomationSlice/AutomationSlice_Callback.res +30 -0
- package/src/components/AutomationSlice/AutomationSlice_Callback.res.mjs +12 -0
- package/src/components/Dcb/Dcb_Builder.res +6 -2
- package/src/components/Dcb/Dcb_Builder.res.mjs +2 -2
- package/src/components/DcbEventLog/DcbEventLog_Builder.res +17 -4
- package/src/components/DcbEventLog/DcbEventLog_Builder.res.mjs +9 -5
- package/src/components/EventLog/EventLog_Builder.res +10 -2
- package/src/components/EventLog/EventLog_Builder.res.mjs +4 -1
- package/src/components/OutboundTranslationSlice/OutboundTranslationSlice_Callback.res +32 -0
- package/src/components/OutboundTranslationSlice/OutboundTranslationSlice_Callback.res.mjs +13 -0
- package/src/plugin/component/Plugin_Builder.res +6 -13
- package/src/plugin/component/Plugin_Builder.res.mjs +2 -16
- package/src/plugin/component/Plugin_Helpers.res +21 -3
- package/src/plugin/component/Plugin_Helpers.res.mjs +16 -0
- package/src/util/LogFormat.res +52 -1
- package/src/util/LogFormat.res.mjs +21 -2
- package/src/util/StoreLayout.res +38 -0
- package/src/util/StoreLayout.res.mjs +22 -0
- package/tests/adapter/EventLogProvisioningTest.res +207 -0
- package/tests/adapter/EventLogProvisioningTest.res.mjs +150 -0
- package/tests/api/GraphQL_FragmentGeneratorTest.res +40 -0
- package/tests/api/GraphQL_FragmentGeneratorTest.res.mjs +35 -0
- package/tests/logger/LogFormatTest.res +42 -0
- package/tests/logger/LogFormatTest.res.mjs +37 -0
|
@@ -4,6 +4,7 @@ import * as S from "sury/src/S.res.mjs";
|
|
|
4
4
|
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
5
5
|
import * as GraphQL_Stitcher$ReventlessCore from "../../src/components/Api/GraphQL_Stitcher.res.mjs";
|
|
6
6
|
import * as GraphQL_FragmentGenerator$ReventlessCore from "../../src/components/Api/GraphQL_FragmentGenerator.res.mjs";
|
|
7
|
+
import * as OutboundTranslationSlice_Callback$ReventlessCore from "../../src/components/OutboundTranslationSlice/OutboundTranslationSlice_Callback.res.mjs";
|
|
7
8
|
|
|
8
9
|
let commandSchema = S.union([
|
|
9
10
|
S.schema(s => ({
|
|
@@ -50,8 +51,42 @@ globalThis.describe("GraphQL_FragmentGenerator.generate mutation id injection",
|
|
|
50
51
|
});
|
|
51
52
|
});
|
|
52
53
|
|
|
54
|
+
let outboundItemSchema = S.schema(s => ({
|
|
55
|
+
customerId: s.m(S.string),
|
|
56
|
+
address: s.m(S.string)
|
|
57
|
+
}));
|
|
58
|
+
|
|
59
|
+
let GeocodeItem = {
|
|
60
|
+
outboundItemSchema: outboundItemSchema,
|
|
61
|
+
externalSystem: undefined
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
function typeDefFor(fragment, needle) {
|
|
65
|
+
return GraphQL_Stitcher$ReventlessCore.decode(fragment).types.find(t => t.includes(needle));
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
globalThis.describe("GraphQL_FragmentGenerator slice TODO rows", () => {
|
|
69
|
+
globalThis.test("item carries the slice's item type, not String", () => {
|
|
70
|
+
let fragment = GraphQL_FragmentGenerator$ReventlessCore.generate([], [{
|
|
71
|
+
singleFieldName: "Ordering_GeocodeCustomerAddressTodo",
|
|
72
|
+
listFieldName: "Ordering_GeocodeCustomerAddressTodos",
|
|
73
|
+
returnTypeName: "Ordering_GeocodeCustomerAddressTodo",
|
|
74
|
+
stateSchema: OutboundTranslationSlice_Callback$ReventlessCore.todoRowSchemaFor(outboundItemSchema),
|
|
75
|
+
authorization: undefined,
|
|
76
|
+
connectionSpec: true
|
|
77
|
+
}]);
|
|
78
|
+
let row = Stdlib_Option.getOr(typeDefFor(fragment, "type Ordering_GeocodeCustomerAddressTodo "), "");
|
|
79
|
+
globalThis.expect(row.includes("item: Ordering_GeocodeCustomerAddressTodoItem!")).toBe(true);
|
|
80
|
+
let item = Stdlib_Option.getOr(typeDefFor(fragment, "type Ordering_GeocodeCustomerAddressTodoItem "), "");
|
|
81
|
+
globalThis.expect(item.includes("customerId: ID!")).toBe(true);
|
|
82
|
+
globalThis.expect(item.includes("address: String!")).toBe(true);
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
|
|
53
86
|
export {
|
|
54
87
|
OrderSliceCmd,
|
|
55
88
|
mutationFor,
|
|
89
|
+
GeocodeItem,
|
|
90
|
+
typeDefFor,
|
|
56
91
|
}
|
|
57
92
|
/* commandSchema Not a pure module */
|
|
@@ -127,6 +127,48 @@ describe("LogFormat", () => {
|
|
|
127
127
|
},
|
|
128
128
|
)
|
|
129
129
|
})
|
|
130
|
+
|
|
131
|
+
// A ReScript record's absent optional field survives encoding as an own
|
|
132
|
+
// property whose value is `undefined` — the one thing `JSON.t` cannot hold and
|
|
133
|
+
// `JSON.stringify` answers with `undefined` instead of a string. Rendering a
|
|
134
|
+
// command carrying one must not reach a string function with that `undefined`:
|
|
135
|
+
// `variantFields` runs inside the CommandGenerator's log tap, so a throw there
|
|
136
|
+
// takes the command down with it and the slice never sees it.
|
|
137
|
+
describe("variantFields", () => {
|
|
138
|
+
module OptionalFieldCmd = {
|
|
139
|
+
@schema
|
|
140
|
+
type command = AddProduct({productId: string, name: string, imageUrl?: string})
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
testSync("omits an absent optional field", () => {
|
|
144
|
+
let json =
|
|
145
|
+
OptionalFieldCmd.AddProduct({productId: "prd-1", name: "Cirrus"})
|
|
146
|
+
->Message.encode(OptionalFieldCmd.commandSchema)
|
|
147
|
+
expect(variantFields(json))->toEqual(`, {productId:"prd-1",name:"Cirrus"}`)
|
|
148
|
+
})
|
|
149
|
+
|
|
150
|
+
testSync("keeps a present optional field", () => {
|
|
151
|
+
let json =
|
|
152
|
+
OptionalFieldCmd.AddProduct({productId: "prd-1", name: "Cirrus", imageUrl: "/u/a.png"})
|
|
153
|
+
->Message.encode(OptionalFieldCmd.commandSchema)
|
|
154
|
+
expect(variantFields(json))->toEqual(
|
|
155
|
+
`, {productId:"prd-1",name:"Cirrus",imageUrl:"/u/a.png"}`,
|
|
156
|
+
)
|
|
157
|
+
})
|
|
158
|
+
|
|
159
|
+
testSync("elides a value past the budget rather than dropping it", () => {
|
|
160
|
+
let long = String.repeat("x", maxValueChars + 20)
|
|
161
|
+
let json =
|
|
162
|
+
OptionalFieldCmd.AddProduct({productId: "prd-1", name: long})
|
|
163
|
+
->Message.encode(OptionalFieldCmd.commandSchema)
|
|
164
|
+
let rendered = variantFields(json)
|
|
165
|
+
expect(rendered->String.includes("…(+22 chars)"))->toBe(true)
|
|
166
|
+
// The oversized value is capped, not the line: the neighbouring field that
|
|
167
|
+
// says which product this is stays intact.
|
|
168
|
+
expect(rendered->String.includes(long))->toBe(false)
|
|
169
|
+
expect(rendered->String.includes(`productId:"prd-1"`))->toBe(true)
|
|
170
|
+
})
|
|
171
|
+
})
|
|
130
172
|
})
|
|
131
173
|
|
|
132
174
|
// ─── JSON sink (non-TTY collector: CloudWatch / Datadog / …) ─────────────────
|
|
@@ -124,6 +124,43 @@ globalThis.describe("LogFormat", () => {
|
|
|
124
124
|
globalThis.expect(msg).toEqual(`\x1b[1mVersionDetected\x1b[0m(testId): {"event":{"TAG":"VersionDetected","_0":"0.0.0"},"meta":{"service":"testService","time":"testTime","ip":"testIp","user":"testUser","msgId":"testMsgId","correlationId":"testCorrelationId"},"id":"testId"}`);
|
|
125
125
|
});
|
|
126
126
|
});
|
|
127
|
+
globalThis.describe("variantFields", () => {
|
|
128
|
+
let commandSchema = S.schema(s => ({
|
|
129
|
+
TAG: "AddProduct",
|
|
130
|
+
productId: s.m(S.string),
|
|
131
|
+
name: s.m(S.string),
|
|
132
|
+
imageUrl: s.m(S.option(S.string))
|
|
133
|
+
}));
|
|
134
|
+
globalThis.test("omits an absent optional field", () => {
|
|
135
|
+
let json = Message$ReventlessCore.encode({
|
|
136
|
+
TAG: "AddProduct",
|
|
137
|
+
productId: "prd-1",
|
|
138
|
+
name: "Cirrus"
|
|
139
|
+
}, commandSchema);
|
|
140
|
+
globalThis.expect(LogFormat$ReventlessCore.variantFields(json)).toEqual(`, {productId:"prd-1",name:"Cirrus"}`);
|
|
141
|
+
});
|
|
142
|
+
globalThis.test("keeps a present optional field", () => {
|
|
143
|
+
let json = Message$ReventlessCore.encode({
|
|
144
|
+
TAG: "AddProduct",
|
|
145
|
+
productId: "prd-1",
|
|
146
|
+
name: "Cirrus",
|
|
147
|
+
imageUrl: "/u/a.png"
|
|
148
|
+
}, commandSchema);
|
|
149
|
+
globalThis.expect(LogFormat$ReventlessCore.variantFields(json)).toEqual(`, {productId:"prd-1",name:"Cirrus",imageUrl:"/u/a.png"}`);
|
|
150
|
+
});
|
|
151
|
+
globalThis.test("elides a value past the budget rather than dropping it", () => {
|
|
152
|
+
let long = "x".repeat(LogFormat$ReventlessCore.maxValueChars + 20 | 0);
|
|
153
|
+
let json = Message$ReventlessCore.encode({
|
|
154
|
+
TAG: "AddProduct",
|
|
155
|
+
productId: "prd-1",
|
|
156
|
+
name: long
|
|
157
|
+
}, commandSchema);
|
|
158
|
+
let rendered = LogFormat$ReventlessCore.variantFields(json);
|
|
159
|
+
globalThis.expect(rendered.includes("…(+22 chars)")).toBe(true);
|
|
160
|
+
globalThis.expect(rendered.includes(long)).toBe(false);
|
|
161
|
+
globalThis.expect(rendered.includes(`productId:"prd-1"`)).toBe(true);
|
|
162
|
+
});
|
|
163
|
+
});
|
|
127
164
|
});
|
|
128
165
|
|
|
129
166
|
function hasAnsi(s) {
|