@reventlessdev/reventless-core 3.0.0-alpha.254 → 3.0.0-alpha.256
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 +48 -0
- package/package.json +8 -8
- package/src/admin/Platform_ComponentDefinitionsApi.res +5 -1
- package/src/admin/Platform_ComponentDefinitionsApi.res.mjs +5 -1
- package/src/components/Api/GraphQL_FragmentGenerator.res +55 -14
- package/src/components/Api/GraphQL_FragmentGenerator.res.mjs +43 -12
- package/src/components/Api/SchemaType.res +1 -0
- package/src/components/Api/SchemaType.res.mjs +4 -0
- package/src/components/Api/SuryToJsonSchema.res +41 -0
- package/src/components/Api/SuryToJsonSchema.res.mjs +50 -17
- package/src/components/StateChangeSlice/StateChangeSlice_Callback.res +2 -2
- package/src/plugin/component/Plugin_Structure.res +13 -0
- package/src/plugin/component/Plugin_Structure.res.mjs +5 -1
- package/src/plugin/lifecycle/PluginsReadModelSpec.res +1 -1
- package/src/plugin/lifecycle/PluginsReadModelSpec.res.mjs +1 -1
- package/tests/admin/AdminApiSchemaDriftTest.res +1 -0
- package/tests/admin/AdminApiSchemaDriftTest.res.mjs +4 -1
- package/tests/admin/Platform_ComponentDefinitionsApiTest.res +2 -0
- package/tests/admin/Platform_ComponentDefinitionsApiTest.res.mjs +4 -2
- package/tests/admin/Platform_PluginStructuresApiTest.res +26 -0
- package/tests/admin/Platform_PluginStructuresApiTest.res.mjs +9 -0
- package/tests/api/GraphQL_FragmentGeneratorTest.res +47 -0
- package/tests/api/GraphQL_FragmentGeneratorTest.res.mjs +32 -0
- package/tests/api/SuryToJsonSchemaTest.res +157 -0
- package/tests/api/SuryToJsonSchemaTest.res.mjs +81 -0
- package/tests/fixtures/plugin-lifecycle/2026-07-22-versionconnected-no-requiredstores.json +1 -1
- package/tests/fixtures/plugin-lifecycle/2026-07-22-versionsuperseded-nested-definitions.json +1 -1
- package/tests/fixtures/plugin-lifecycle/2026-07-28-versionconnected-requiredstores-only.json +1 -1
- package/tests/fixtures/plugin-lifecycle/2026-07-30-versionconnected-declarations-without-annotation.json +1 -1
- package/tests/fixtures/plugin-lifecycle/2026-07-30-versiondisconnected-declarations-without-annotation.json +1 -1
- package/tests/fixtures/plugin-lifecycle/README.md +12 -0
- package/tests/logger/LogFormatTest.res +1 -1
- package/tests/logger/LogFormatTest.res.mjs +1 -1
- package/tests/plugin/PluginDefinitionRequiredScalarsTest.res +1 -1
- package/tests/plugin/PluginDefinitionScalars.res +13 -8
- package/tests/plugin/PluginDefinitionScalars.res.mjs +13 -5
- package/tests/plugin/PluginStructureTest.res +22 -0
- package/tests/plugin/PluginStructureTest.res.mjs +7 -0
- package/tests/plugin/StateViewSlice/PsAnnotatedView.res +13 -3
- package/tests/plugin/StateViewSlice/PsAnnotatedView.res.mjs +7 -3
- package/tests/plugin/pluginDefinitionRequiredScalars.txt +17 -12
|
@@ -199,13 +199,16 @@ let outbound_externalSystem = "Shipper";
|
|
|
199
199
|
|
|
200
200
|
let outbound_chapter = "Fulfilment";
|
|
201
201
|
|
|
202
|
+
let outbound_consumedSources = ["OrderingDcbEventLog"];
|
|
203
|
+
|
|
202
204
|
let outbound = {
|
|
203
205
|
name: "ToShipper",
|
|
204
206
|
consumedEventTypes: outbound_consumedEventTypes,
|
|
205
207
|
inboundCommandTypes: outbound_inboundCommandTypes,
|
|
206
208
|
targetName: outbound_targetName,
|
|
207
209
|
externalSystem: outbound_externalSystem,
|
|
208
|
-
chapter: outbound_chapter
|
|
210
|
+
chapter: outbound_chapter,
|
|
211
|
+
consumedSources: outbound_consumedSources
|
|
209
212
|
};
|
|
210
213
|
|
|
211
214
|
let inbound_commandTypes = ["RecordPayment"];
|
|
@@ -77,6 +77,7 @@ let structure: pluginStructure = {
|
|
|
77
77
|
targetName: None,
|
|
78
78
|
externalSystem: None,
|
|
79
79
|
chapter: None,
|
|
80
|
+
consumedSources: None,
|
|
80
81
|
},
|
|
81
82
|
],
|
|
82
83
|
inboundTranslationSlices: [
|
|
@@ -227,6 +228,7 @@ describe("translation-slice externalSystem round-trip", () => {
|
|
|
227
228
|
targetName: None,
|
|
228
229
|
externalSystem: Some("ShipperGateway"),
|
|
229
230
|
chapter: None,
|
|
231
|
+
consumedSources: None,
|
|
230
232
|
},
|
|
231
233
|
],
|
|
232
234
|
inboundTranslationSlices: [
|
|
@@ -118,7 +118,8 @@ let structure_outboundTranslationSlices = [{
|
|
|
118
118
|
inboundCommandTypes: ["Ship"],
|
|
119
119
|
targetName: undefined,
|
|
120
120
|
externalSystem: undefined,
|
|
121
|
-
chapter: undefined
|
|
121
|
+
chapter: undefined,
|
|
122
|
+
consumedSources: undefined
|
|
122
123
|
}];
|
|
123
124
|
|
|
124
125
|
let structure_inboundTranslationSlices = [{
|
|
@@ -245,7 +246,8 @@ globalThis.describe("translation-slice externalSystem round-trip", () => {
|
|
|
245
246
|
inboundCommandTypes: ["Ship"],
|
|
246
247
|
targetName: undefined,
|
|
247
248
|
externalSystem: "ShipperGateway",
|
|
248
|
-
chapter: undefined
|
|
249
|
+
chapter: undefined,
|
|
250
|
+
consumedSources: undefined
|
|
249
251
|
}];
|
|
250
252
|
let externalStructure_inboundTranslationSlices = [{
|
|
251
253
|
name: "FromBilling",
|
|
@@ -183,4 +183,30 @@ describe("absent optional collections", () => {
|
|
|
183
183
|
testSync("encodes absent requiredStores as null", () =>
|
|
184
184
|
expect(bareJson->String.includes("\"requiredStores\":null"))->toEqual(true)
|
|
185
185
|
)
|
|
186
|
+
|
|
187
|
+
// The case the frozen corpus cannot reach: every fixture in it carries
|
|
188
|
+
// `"outboundTranslationSlices":[]`, so no stored payload has an outbound slice
|
|
189
|
+
// to be missing a field. A structure written before `consumedSources` existed
|
|
190
|
+
// has no such key. `parseJsonTolerant` is what makes the absence survivable,
|
|
191
|
+
// and it is the path the Plugin aggregate replays through.
|
|
192
|
+
testSync("an outbound slice stored before consumedSources existed still replays", () =>
|
|
193
|
+
expect(
|
|
194
|
+
`{"name":"ToShipper","consumedEventTypes":[],"inboundCommandTypes":[]}`
|
|
195
|
+
->JSON.parseOrThrow
|
|
196
|
+
->Reventless.Message.parseJsonTolerant(outboundTranslationSliceDefSchema)
|
|
197
|
+
->(slice => slice.consumedSources),
|
|
198
|
+
)->toEqual(None)
|
|
199
|
+
)
|
|
200
|
+
|
|
201
|
+
// Absent needs no healer: an omitted key IS the optional encoding, so strict
|
|
202
|
+
// decode takes it. `parseJsonTolerant` above is for the fields a stale payload
|
|
203
|
+
// is missing that are NOT optional.
|
|
204
|
+
testSync("an omitted optional decodes as None on the strict path", () =>
|
|
205
|
+
expect(
|
|
206
|
+
`{"name":"ToShipper","consumedEventTypes":[],"inboundCommandTypes":[]}`
|
|
207
|
+
->JSON.parseOrThrow
|
|
208
|
+
->Reventless.Util_Sury.fromJson(outboundTranslationSliceDefSchema)
|
|
209
|
+
->(slice => slice.consumedSources),
|
|
210
|
+
)->toEqual(None)
|
|
211
|
+
)
|
|
186
212
|
})
|
|
@@ -4,6 +4,9 @@ import * as Stdlib_JSON from "@rescript/runtime/lib/es6/Stdlib_JSON.js";
|
|
|
4
4
|
import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
|
|
5
5
|
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
6
6
|
import * as Primitive_string from "@rescript/runtime/lib/es6/Primitive_string.js";
|
|
7
|
+
import * as Plugin$Reventless from "@reventlessdev/reventless-spec/src/components/Plugin.res.mjs";
|
|
8
|
+
import * as Message$Reventless from "@reventlessdev/reventless-spec/src/types/Message.res.mjs";
|
|
9
|
+
import * as Util_Sury$Reventless from "@reventlessdev/reventless-spec/src/util/Util_Sury.res.mjs";
|
|
7
10
|
import * as Platform_PluginStructuresApi$ReventlessCore from "../../src/admin/Platform_PluginStructuresApi.res.mjs";
|
|
8
11
|
|
|
9
12
|
let publicRm_consumedEventTypes = ["ProductAdded"];
|
|
@@ -237,6 +240,12 @@ globalThis.describe("absent optional collections", () => {
|
|
|
237
240
|
globalThis.test("encodes absent requiredStores as null", () => {
|
|
238
241
|
globalThis.expect(bareJson.includes("\"requiredStores\":null")).toEqual(true);
|
|
239
242
|
});
|
|
243
|
+
globalThis.test("an outbound slice stored before consumedSources existed still replays", () => {
|
|
244
|
+
globalThis.expect(Message$Reventless.parseJsonTolerant(JSON.parse(`{"name":"ToShipper","consumedEventTypes":[],"inboundCommandTypes":[]}`), Plugin$Reventless.outboundTranslationSliceDefSchema).consumedSources).toEqual(undefined);
|
|
245
|
+
});
|
|
246
|
+
globalThis.test("an omitted optional decodes as None on the strict path", () => {
|
|
247
|
+
globalThis.expect(Util_Sury$Reventless.fromJson(JSON.parse(`{"name":"ToShipper","consumedEventTypes":[],"inboundCommandTypes":[]}`), Plugin$Reventless.outboundTranslationSliceDefSchema).consumedSources).toEqual(undefined);
|
|
248
|
+
});
|
|
240
249
|
});
|
|
241
250
|
|
|
242
251
|
export {
|
|
@@ -139,6 +139,53 @@ describe("resolveKeyField — the ladder", () => {
|
|
|
139
139
|
})
|
|
140
140
|
})
|
|
141
141
|
|
|
142
|
+
// Losing the key is invisible — the view keeps every field and every row, and
|
|
143
|
+
// drops its `<field>Eq` filter and its whole `orderBy` from the SDL. These pin
|
|
144
|
+
// which of the two ways to lose it is worth saying out loud.
|
|
145
|
+
describe("keyFieldGapMessage — which gap is worth a warning", () => {
|
|
146
|
+
let gapFor = (~entityName, schema) =>
|
|
147
|
+
GraphQL_FragmentGenerator.classifyKeyField(~entityName, schema->S.castToUnknown)
|
|
148
|
+
->GraphQL_FragmentGenerator.keyFieldGapMessage
|
|
149
|
+
|
|
150
|
+
// The accident §14b.2 named: the view had `productId` alone and somebody added
|
|
151
|
+
// `categoryId`, so `sole` stopped firing and the name matches neither.
|
|
152
|
+
testSync("a second `*Id` field taking the key away is named, with both fields", () => {
|
|
153
|
+
let schema = S.schema(s =>
|
|
154
|
+
{"productId": s.matches(S.string), "categoryId": s.matches(S.string)}
|
|
155
|
+
)
|
|
156
|
+
let message = gapFor(~entityName="ProductDemand", schema)->Option.getOr("")
|
|
157
|
+
expect(message->String.includes("productId, categoryId"))->toBe(true)
|
|
158
|
+
expect(message->String.includes("productDemandId"))->toBe(true)
|
|
159
|
+
})
|
|
160
|
+
|
|
161
|
+
// A read model over an aggregate keeps the row's id on the row key, not in its
|
|
162
|
+
// state. Warning here would fire on most of them and get the rule silenced —
|
|
163
|
+
// six views across the example plugins are exactly this shape.
|
|
164
|
+
testSync("a state with no `*Id` field at all is silent, not warned about", () =>
|
|
165
|
+
expect(
|
|
166
|
+
gapFor(
|
|
167
|
+
~entityName="Customers",
|
|
168
|
+
S.schema(s => {"email": s.matches(S.string), "address": s.matches(S.string)}),
|
|
169
|
+
),
|
|
170
|
+
)->toEqual(None)
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
testSync("a resolved key says nothing", () =>
|
|
174
|
+
expect(
|
|
175
|
+
gapFor(~entityName="Orders", S.schema(s => {"orderId": s.matches(S.string)})),
|
|
176
|
+
)->toEqual(None)
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
testSync("an @id-less view whose name picks one of its `*Id` fields is fine", () =>
|
|
180
|
+
expect(
|
|
181
|
+
gapFor(
|
|
182
|
+
~entityName="Products",
|
|
183
|
+
S.schema(s => {"productId": s.matches(S.string), "categoryId": s.matches(S.string)}),
|
|
184
|
+
),
|
|
185
|
+
)->toEqual(None)
|
|
186
|
+
)
|
|
187
|
+
})
|
|
188
|
+
|
|
142
189
|
describe("deriveServerCapability — inferred keys reach the SDL surface", () => {
|
|
143
190
|
let capabilityFor = (~entityName, schema) =>
|
|
144
191
|
GraphQL_FragmentGenerator.deriveServerCapability(~entityName, schema->S.castToUnknown)
|
|
@@ -148,6 +148,38 @@ globalThis.describe("resolveKeyField — the ladder", () => {
|
|
|
148
148
|
});
|
|
149
149
|
});
|
|
150
150
|
|
|
151
|
+
globalThis.describe("keyFieldGapMessage — which gap is worth a warning", () => {
|
|
152
|
+
globalThis.test("a second `*Id` field taking the key away is named, with both fields", () => {
|
|
153
|
+
let schema = Sury.$schema(s => ({
|
|
154
|
+
productId: s.m(Sury.string),
|
|
155
|
+
categoryId: s.m(Sury.string)
|
|
156
|
+
}));
|
|
157
|
+
let message = Stdlib_Option.getOr(GraphQL_FragmentGenerator$ReventlessCore.keyFieldGapMessage(GraphQL_FragmentGenerator$ReventlessCore.classifyKeyField("ProductDemand", schema)), "");
|
|
158
|
+
globalThis.expect(message.includes("productId, categoryId")).toBe(true);
|
|
159
|
+
globalThis.expect(message.includes("productDemandId")).toBe(true);
|
|
160
|
+
});
|
|
161
|
+
globalThis.test("a state with no `*Id` field at all is silent, not warned about", () => {
|
|
162
|
+
let schema = Sury.$schema(s => ({
|
|
163
|
+
email: s.m(Sury.string),
|
|
164
|
+
address: s.m(Sury.string)
|
|
165
|
+
}));
|
|
166
|
+
globalThis.expect(GraphQL_FragmentGenerator$ReventlessCore.keyFieldGapMessage(GraphQL_FragmentGenerator$ReventlessCore.classifyKeyField("Customers", schema))).toEqual(undefined);
|
|
167
|
+
});
|
|
168
|
+
globalThis.test("a resolved key says nothing", () => {
|
|
169
|
+
let schema = Sury.$schema(s => ({
|
|
170
|
+
orderId: s.m(Sury.string)
|
|
171
|
+
}));
|
|
172
|
+
globalThis.expect(GraphQL_FragmentGenerator$ReventlessCore.keyFieldGapMessage(GraphQL_FragmentGenerator$ReventlessCore.classifyKeyField("Orders", schema))).toEqual(undefined);
|
|
173
|
+
});
|
|
174
|
+
globalThis.test("an @id-less view whose name picks one of its `*Id` fields is fine", () => {
|
|
175
|
+
let schema = Sury.$schema(s => ({
|
|
176
|
+
productId: s.m(Sury.string),
|
|
177
|
+
categoryId: s.m(Sury.string)
|
|
178
|
+
}));
|
|
179
|
+
globalThis.expect(GraphQL_FragmentGenerator$ReventlessCore.keyFieldGapMessage(GraphQL_FragmentGenerator$ReventlessCore.classifyKeyField("Products", schema))).toEqual(undefined);
|
|
180
|
+
});
|
|
181
|
+
});
|
|
182
|
+
|
|
151
183
|
globalThis.describe("deriveServerCapability — inferred keys reach the SDL surface", () => {
|
|
152
184
|
globalThis.test("an inferred key yields an eq filter and a sort field", () => {
|
|
153
185
|
let schema = Sury.$schema(s => ({
|
|
@@ -119,6 +119,78 @@ describe("SuryToJsonSchema:", () => {
|
|
|
119
119
|
})
|
|
120
120
|
})
|
|
121
121
|
|
|
122
|
+
describe("deriveObjectSchema with a sensitive field:", () => {
|
|
123
|
+
let sensitiveOf = (json, name) =>
|
|
124
|
+
getPropertyOf(json, name)->Option.flatMap(s => getProperty(s, "x-reventless-sensitive"))
|
|
125
|
+
let ownerOf = (json, name) =>
|
|
126
|
+
getPropertyOf(json, name)->Option.flatMap(s => getProperty(s, "x-reventless-owner"))
|
|
127
|
+
|
|
128
|
+
let json = SuryToJsonSchema.deriveObjectSchema(
|
|
129
|
+
S.schema(s =>
|
|
130
|
+
{
|
|
131
|
+
"resetToken": s.matches(Reventless.Sensitive.string),
|
|
132
|
+
"note": s.matches(S.string),
|
|
133
|
+
"contact": s.matches(Reventless.Email.schema),
|
|
134
|
+
}
|
|
135
|
+
)->S.castToUnknown,
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
testSync("the marked field carries x-reventless-sensitive", () =>
|
|
139
|
+
expect(sensitiveOf(json, "resetToken"))->toEqual(Some(JSON.Encode.bool(true)))
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
// The control. Absent means "not stated", and a reader that misses the
|
|
143
|
+
// marker renders the value — so a bug that marked everything would look like
|
|
144
|
+
// caution while a bug that marked nothing leaks. Both need catching, and
|
|
145
|
+
// only this assertion catches the first.
|
|
146
|
+
testSync("an unmarked string field carries nothing", () =>
|
|
147
|
+
expect(sensitiveOf(json, "note"))->toBe(None)
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
// A contact detail is sensitive whether or not anybody wrote it down: the
|
|
151
|
+
// whole meaning of the semantic is "how to reach a particular person".
|
|
152
|
+
testSync("an email field is sensitive with no annotation", () =>
|
|
153
|
+
expect(sensitiveOf(json, "contact"))->toEqual(Some(JSON.Encode.bool(true)))
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
testSync("the field is still a plain string on the wire", () =>
|
|
157
|
+
expect(
|
|
158
|
+
getPropertyOf(json, "resetToken")->Option.flatMap(s => getProperty(s, "type")),
|
|
159
|
+
)->toEqual(Some(JSON.Encode.string("string")))
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
// Same trap as the owner case, and worse in consequence: a reader that only
|
|
163
|
+
// inspects the outer schema answers "not sensitive" for an optional field,
|
|
164
|
+
// and the value goes into a message.
|
|
165
|
+
testSync("an optional sensitive field is still recognised", () => {
|
|
166
|
+
let optJson = SuryToJsonSchema.deriveObjectSchema(
|
|
167
|
+
S.schema(s =>
|
|
168
|
+
{
|
|
169
|
+
"resetToken": s.matches(S.option(Reventless.Sensitive.string)),
|
|
170
|
+
}
|
|
171
|
+
)->S.castToUnknown,
|
|
172
|
+
)
|
|
173
|
+
expect(sensitiveOf(optJson, "resetToken"))->toEqual(Some(JSON.Encode.bool(true)))
|
|
174
|
+
})
|
|
175
|
+
|
|
176
|
+
// The composition rule. `mark` wraps rather than replaces, so a field that
|
|
177
|
+
// is both an owner and sensitive keeps both — a marker that silently
|
|
178
|
+
// replaced the other would unscope a view or unmask a value.
|
|
179
|
+
testSync("sensitivity composes with ownership on one field", () => {
|
|
180
|
+
let bothJson = SuryToJsonSchema.deriveObjectSchema(
|
|
181
|
+
S.schema(s =>
|
|
182
|
+
{
|
|
183
|
+
"customerId": s.matches(Reventless.Sensitive.mark(Reventless.Owner.string)),
|
|
184
|
+
}
|
|
185
|
+
)->S.castToUnknown,
|
|
186
|
+
)
|
|
187
|
+
expect((sensitiveOf(bothJson, "customerId"), ownerOf(bothJson, "customerId")))->toEqual((
|
|
188
|
+
Some(JSON.Encode.bool(true)),
|
|
189
|
+
Some(JSON.Encode.bool(true)),
|
|
190
|
+
))
|
|
191
|
+
})
|
|
192
|
+
})
|
|
193
|
+
|
|
122
194
|
describe("deriveObjectSchema with stateAnnotations metadata:", () => {
|
|
123
195
|
let withSpec = (schema, spec) =>
|
|
124
196
|
schema->S.Metadata.set(~id=Reventless.StateAnnotations.stateAnnotationsId, spec)
|
|
@@ -927,6 +999,91 @@ describe("SuryToJsonSchema:", () => {
|
|
|
927
999
|
})
|
|
928
1000
|
})
|
|
929
1001
|
|
|
1002
|
+
// A selection, not an input. The whole point of the id is that it travels the
|
|
1003
|
+
// same channel as a store declaration and says something a store declaration
|
|
1004
|
+
// cannot: the candidates are on the row, so nothing is provisioned for it.
|
|
1005
|
+
describe("a member-reference field:", () => {
|
|
1006
|
+
let targetOf = (json, name) =>
|
|
1007
|
+
getPropertyOf(json, name)->Option.flatMap(s =>
|
|
1008
|
+
getProperty(s, "x-reventless-semantic-target")
|
|
1009
|
+
)
|
|
1010
|
+
|
|
1011
|
+
testSync("carries the collection, the view holding it, and what a member is", () => {
|
|
1012
|
+
let json = SuryToJsonSchema.deriveObjectSchema(
|
|
1013
|
+
S.schema(s =>
|
|
1014
|
+
{
|
|
1015
|
+
"productImage": s.matches(
|
|
1016
|
+
Reventless.MemberRef.of_(
|
|
1017
|
+
~view="Products",
|
|
1018
|
+
~content=Reventless.Semantic.Id.imageRef,
|
|
1019
|
+
~field="productImages",
|
|
1020
|
+
),
|
|
1021
|
+
),
|
|
1022
|
+
}
|
|
1023
|
+
)->S.castToUnknown,
|
|
1024
|
+
)
|
|
1025
|
+
expect(
|
|
1026
|
+
getPropertyOf(json, "productImage")->Option.flatMap(s =>
|
|
1027
|
+
getProperty(s, "x-reventless-semantic")
|
|
1028
|
+
),
|
|
1029
|
+
)->toEqual(Some(JSON.Encode.string("memberRef")))
|
|
1030
|
+
expect(targetOf(json, "productImage"))->toEqual(
|
|
1031
|
+
Some(
|
|
1032
|
+
JSON.Encode.object(
|
|
1033
|
+
Dict.fromArray([
|
|
1034
|
+
("field", JSON.Encode.string("productImages")),
|
|
1035
|
+
("view", JSON.Encode.string("Products")),
|
|
1036
|
+
("content", JSON.Encode.string("imageRef")),
|
|
1037
|
+
]),
|
|
1038
|
+
),
|
|
1039
|
+
),
|
|
1040
|
+
)
|
|
1041
|
+
})
|
|
1042
|
+
|
|
1043
|
+
// The second position: a declaration on a view's own state, where the
|
|
1044
|
+
// collection is on the same record and naming a view would invite the reader
|
|
1045
|
+
// to think another one could be meant.
|
|
1046
|
+
testSync("omits the view where the collection is on this very record", () =>
|
|
1047
|
+
expect(
|
|
1048
|
+
targetOf(
|
|
1049
|
+
SuryToJsonSchema.deriveObjectSchema(
|
|
1050
|
+
S.schema(s =>
|
|
1051
|
+
{"productImage": s.matches(Reventless.MemberRef.of_(~field="productImages"))}
|
|
1052
|
+
)->S.castToUnknown,
|
|
1053
|
+
),
|
|
1054
|
+
"productImage",
|
|
1055
|
+
),
|
|
1056
|
+
)->toEqual(
|
|
1057
|
+
Some(JSON.Encode.object(Dict.fromArray([("field", JSON.Encode.string("productImages"))]))),
|
|
1058
|
+
)
|
|
1059
|
+
)
|
|
1060
|
+
|
|
1061
|
+
// The assertion the whole design rests on, and the one a reader will want to
|
|
1062
|
+
// see rather than infer: a `memberRef` field declares NO store, so the
|
|
1063
|
+
// provisioning walk passes it by and no upload endpoint is bound. This is
|
|
1064
|
+
// exactly what `imageRef` gets today, reached through a different payload.
|
|
1065
|
+
testSync("declares no store, so nothing is provisioned for it", () =>
|
|
1066
|
+
expect(
|
|
1067
|
+
Reventless.StorageRef.getFieldStore(
|
|
1068
|
+
Reventless.MemberRef.of_(~view="Products", ~field="productImages"),
|
|
1069
|
+
),
|
|
1070
|
+
)->toBe(None)
|
|
1071
|
+
)
|
|
1072
|
+
|
|
1073
|
+
testSync("stays a plain string on the wire", () =>
|
|
1074
|
+
expect(
|
|
1075
|
+
getPropertyOf(
|
|
1076
|
+
SuryToJsonSchema.deriveObjectSchema(
|
|
1077
|
+
S.schema(s =>
|
|
1078
|
+
{"productImage": s.matches(Reventless.MemberRef.of_(~field="productImages"))}
|
|
1079
|
+
)->S.castToUnknown,
|
|
1080
|
+
),
|
|
1081
|
+
"productImage",
|
|
1082
|
+
)->Option.flatMap(s => getProperty(s, "type")),
|
|
1083
|
+
)->toEqual(Some(JSON.Encode.string("string")))
|
|
1084
|
+
)
|
|
1085
|
+
})
|
|
1086
|
+
|
|
930
1087
|
// The claim the branded scalars rest on: marking a field adds an annotation,
|
|
931
1088
|
// not a shape. A string stays a string and a number stays a number on the
|
|
932
1089
|
// wire, which is what makes them retrofittable onto a log that already has
|
|
@@ -13,8 +13,11 @@ import * as Percent$Reventless from "@reventlessdev/reventless-spec/src/semantic
|
|
|
13
13
|
import * as Currency$Reventless from "@reventlessdev/reventless-spec/src/semantic/Currency.res.mjs";
|
|
14
14
|
import * as DateTime$Reventless from "@reventlessdev/reventless-spec/src/types/DateTime.res.mjs";
|
|
15
15
|
import * as GeoPoint$Reventless from "@reventlessdev/reventless-spec/src/semantic/GeoPoint.res.mjs";
|
|
16
|
+
import * as Semantic$Reventless from "@reventlessdev/reventless-spec/src/semantic/Semantic.res.mjs";
|
|
16
17
|
import * as DateRange$Reventless from "@reventlessdev/reventless-spec/src/semantic/DateRange.res.mjs";
|
|
18
|
+
import * as MemberRef$Reventless from "@reventlessdev/reventless-spec/src/semantic/MemberRef.res.mjs";
|
|
17
19
|
import * as Reference$Reventless from "@reventlessdev/reventless-spec/src/components/Reference.res.mjs";
|
|
20
|
+
import * as Sensitive$Reventless from "@reventlessdev/reventless-spec/src/components/Sensitive.res.mjs";
|
|
18
21
|
import * as StorageRef$Reventless from "@reventlessdev/reventless-spec/src/semantic/StorageRef.res.mjs";
|
|
19
22
|
import * as StateAnnotations$Reventless from "@reventlessdev/reventless-spec/src/components/StateAnnotations.res.mjs";
|
|
20
23
|
import * as SuryToJsonSchema$ReventlessCore from "../../src/components/Api/SuryToJsonSchema.res.mjs";
|
|
@@ -130,6 +133,45 @@ globalThis.describe("SuryToJsonSchema:", () => {
|
|
|
130
133
|
globalThis.expect(ownerOf(optJson, "customerId")).toEqual(true);
|
|
131
134
|
});
|
|
132
135
|
});
|
|
136
|
+
globalThis.describe("deriveObjectSchema with a sensitive field:", () => {
|
|
137
|
+
let sensitiveOf = (json, name) => Stdlib_Option.flatMap(getPropertyOf(json, name), s => getProperty(s, "x-reventless-sensitive"));
|
|
138
|
+
let ownerOf = (json, name) => Stdlib_Option.flatMap(getPropertyOf(json, name), s => getProperty(s, "x-reventless-owner"));
|
|
139
|
+
let json = SuryToJsonSchema$ReventlessCore.deriveObjectSchema(Sury.$schema(s => ({
|
|
140
|
+
resetToken: s.m(Sensitive$Reventless.string),
|
|
141
|
+
note: s.m(Sury.string),
|
|
142
|
+
contact: s.m(Email$Reventless.schema)
|
|
143
|
+
})));
|
|
144
|
+
globalThis.test("the marked field carries x-reventless-sensitive", () => {
|
|
145
|
+
globalThis.expect(sensitiveOf(json, "resetToken")).toEqual(true);
|
|
146
|
+
});
|
|
147
|
+
globalThis.test("an unmarked string field carries nothing", () => {
|
|
148
|
+
globalThis.expect(sensitiveOf(json, "note")).toBe(undefined);
|
|
149
|
+
});
|
|
150
|
+
globalThis.test("an email field is sensitive with no annotation", () => {
|
|
151
|
+
globalThis.expect(sensitiveOf(json, "contact")).toEqual(true);
|
|
152
|
+
});
|
|
153
|
+
globalThis.test("the field is still a plain string on the wire", () => {
|
|
154
|
+
globalThis.expect(Stdlib_Option.flatMap(getPropertyOf(json, "resetToken"), s => getProperty(s, "type"))).toEqual("string");
|
|
155
|
+
});
|
|
156
|
+
globalThis.test("an optional sensitive field is still recognised", () => {
|
|
157
|
+
let optJson = SuryToJsonSchema$ReventlessCore.deriveObjectSchema(Sury.$schema(s => ({
|
|
158
|
+
resetToken: s.m(Sury.$option(Sensitive$Reventless.string))
|
|
159
|
+
})));
|
|
160
|
+
globalThis.expect(sensitiveOf(optJson, "resetToken")).toEqual(true);
|
|
161
|
+
});
|
|
162
|
+
globalThis.test("sensitivity composes with ownership on one field", () => {
|
|
163
|
+
let bothJson = SuryToJsonSchema$ReventlessCore.deriveObjectSchema(Sury.$schema(s => ({
|
|
164
|
+
customerId: s.m(Sensitive$Reventless.mark(Owner$Reventless.string))
|
|
165
|
+
})));
|
|
166
|
+
globalThis.expect([
|
|
167
|
+
sensitiveOf(bothJson, "customerId"),
|
|
168
|
+
ownerOf(bothJson, "customerId")
|
|
169
|
+
]).toEqual([
|
|
170
|
+
true,
|
|
171
|
+
true
|
|
172
|
+
]);
|
|
173
|
+
});
|
|
174
|
+
});
|
|
133
175
|
globalThis.describe("deriveObjectSchema with stateAnnotations metadata:", () => {
|
|
134
176
|
globalThis.test("emits x-reventless-id on field listed in ids", () => {
|
|
135
177
|
let schema = Sury.$schema(s => ({
|
|
@@ -872,6 +914,45 @@ globalThis.describe("SuryToJsonSchema:", () => {
|
|
|
872
914
|
globalThis.expect(semanticOf(json, "imageUrl")).toEqual("storageRef");
|
|
873
915
|
});
|
|
874
916
|
});
|
|
917
|
+
globalThis.describe("a member-reference field:", () => {
|
|
918
|
+
let targetOf = (json, name) => Stdlib_Option.flatMap(getPropertyOf(json, name), s => getProperty(s, "x-reventless-semantic-target"));
|
|
919
|
+
globalThis.test("carries the collection, the view holding it, and what a member is", () => {
|
|
920
|
+
let json = SuryToJsonSchema$ReventlessCore.deriveObjectSchema(Sury.$schema(s => ({
|
|
921
|
+
productImage: s.m(MemberRef$Reventless.of_(undefined, "Products", Semantic$Reventless.Id.imageRef, "productImages"))
|
|
922
|
+
})));
|
|
923
|
+
globalThis.expect(Stdlib_Option.flatMap(getPropertyOf(json, "productImage"), s => getProperty(s, "x-reventless-semantic"))).toEqual("memberRef");
|
|
924
|
+
globalThis.expect(targetOf(json, "productImage")).toEqual(Object.fromEntries([
|
|
925
|
+
[
|
|
926
|
+
"field",
|
|
927
|
+
"productImages"
|
|
928
|
+
],
|
|
929
|
+
[
|
|
930
|
+
"view",
|
|
931
|
+
"Products"
|
|
932
|
+
],
|
|
933
|
+
[
|
|
934
|
+
"content",
|
|
935
|
+
"imageRef"
|
|
936
|
+
]
|
|
937
|
+
]));
|
|
938
|
+
});
|
|
939
|
+
globalThis.test("omits the view where the collection is on this very record", () => {
|
|
940
|
+
globalThis.expect(targetOf(SuryToJsonSchema$ReventlessCore.deriveObjectSchema(Sury.$schema(s => ({
|
|
941
|
+
productImage: s.m(MemberRef$Reventless.of_(undefined, undefined, undefined, "productImages"))
|
|
942
|
+
}))), "productImage")).toEqual(Object.fromEntries([[
|
|
943
|
+
"field",
|
|
944
|
+
"productImages"
|
|
945
|
+
]]));
|
|
946
|
+
});
|
|
947
|
+
globalThis.test("declares no store, so nothing is provisioned for it", () => {
|
|
948
|
+
globalThis.expect(StorageRef$Reventless.getFieldStore(MemberRef$Reventless.of_(undefined, "Products", undefined, "productImages"))).toBe(undefined);
|
|
949
|
+
});
|
|
950
|
+
globalThis.test("stays a plain string on the wire", () => {
|
|
951
|
+
globalThis.expect(Stdlib_Option.flatMap(getPropertyOf(SuryToJsonSchema$ReventlessCore.deriveObjectSchema(Sury.$schema(s => ({
|
|
952
|
+
productImage: s.m(MemberRef$Reventless.of_(undefined, undefined, undefined, "productImages"))
|
|
953
|
+
}))), "productImage"), s => getProperty(s, "type"))).toEqual("string");
|
|
954
|
+
});
|
|
955
|
+
});
|
|
875
956
|
globalThis.describe("branded scalars keep their underlying shape:", () => {
|
|
876
957
|
let keyOf = (json, name, key) => Stdlib_Option.flatMap(getPropertyOf(json, name), s => getProperty(s, key));
|
|
877
958
|
let json = SuryToJsonSchema$ReventlessCore.deriveObjectSchema(Sury.$schema(s => ({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"event":"VersionConnected","data":{"_0":{"dcbEventLog":{"name":"CatalogDcbEventLog","eventTopicArn":"arn:aws:dynamodb:eu-west-1:000000000000:table/CatalogDcbEventLog-925103d/stream/2026-07-14T08:45:33.852"},"extensions":[{"name":"Ordering.Orders.Catalog","extensionPointName":"Ordering.Orders","dcbSources":[]}],"extensionProtocols":[],"extensionPoints":[{"name":"Catalog.Products","commandTopic":"https://sqs.eu-west-1.amazonaws.com/000000000000/CatalogProductsExtPointCmdTopic-1dd983b","eventTopic":"arn:aws:sns:eu-west-1:000000000000:CatalogProductsExtPointEventTopic-5cb0b5e"}],"kind":"Domain","name":"Catalog","apiTarget":"Domain","id":"Catalog@1.0.0-alpha.149","version":"1.0.0-alpha.149","apiSchemaFragment":{"protocol":"graphql","encoded":"{\"types\":[\"type Catalog_Category implements Node {\\n id: ID!\\n categoryId: ID!\\n name: String!\\n archived: Boolean!\\n}\",\"type Catalog_CategoryEdge {\\n node: Catalog_Category!\\n cursor: String!\\n}\",\"type Catalog_CategoryConnection {\\n edges: [Catalog_CategoryEdge!]!\\n pageInfo: PageInfo!\\n}\",\"input Catalog_CategoryFilter {\\n search: String\\n searchPrefix: String\\n ids: [ID!]\\n}\",\"type Catalog_ProductDemand implements Node {\\n id: ID!\\n productId: ID!\\n name: String!\\n categoryId: ID!\\n orderCount: Float!\\n}\",\"type Catalog_ProductDemandEdge {\\n node: Catalog_ProductDemand!\\n cursor: String!\\n}\",\"type Catalog_ProductDemandConnection {\\n edges: [Catalog_ProductDemandEdge!]!\\n pageInfo: PageInfo!\\n}\",\"input Catalog_ProductDemandFilter {\\n search: String\\n searchPrefix: String\\n ids: [ID!]\\n}\",\"type Catalog_Product implements Node {\\n id: ID!\\n productId: ID!\\n name: String!\\n description: String!\\n price: Float!\\n categoryId: ID!\\n}\",\"type Catalog_ProductEdge {\\n node: Catalog_Product!\\n cursor: String!\\n}\",\"type Catalog_ProductConnection {\\n edges: [Catalog_ProductEdge!]!\\n pageInfo: PageInfo!\\n}\",\"input Catalog_ProductFilter {\\n search: String\\n searchPrefix: String\\n ids: [ID!]\\n}\",\"enum Catalog_ImportProductAuditStatus {\\n Success\\n Failure\\n}\",\"type Catalog_ImportProductAudit implements Node {\\n id: ID!\\n input: String!\\n status: Catalog_ImportProductAuditStatus!\\n targetIds: [ID!]\\n commandCount: Float\\n error: String\\n receivedAt: String!\\n}\",\"type Catalog_ImportProductAuditEdge {\\n node: Catalog_ImportProductAudit!\\n cursor: String!\\n}\",\"type Catalog_ImportProductAuditConnection {\\n edges: [Catalog_ImportProductAuditEdge!]!\\n pageInfo: PageInfo!\\n}\",\"input Catalog_ImportProductAuditFilter {\\n search: String\\n searchPrefix: String\\n ids: [ID!]\\n}\",\"union CommandResult = CommandAccepted | CommandRejected | CommandPending\",\"type CommandAccepted {\\n msgId: ID!\\n entityId: ID\\n eventCount: Int!\\n}\",\"type CommandRejected {\\n msgId: ID!\\n errorCode: String!\\n errorDetail: String\\n}\",\"type CommandPending {\\n msgId: ID!\\n}\",\"type CatalogEventLogEvent {\\n position: String!\\n eventType: String!\\n payload: AWSJSON!\\n}\"],\"mutations\":[\" Catalog_AddCategory(categoryId: ID!, name: String!): CommandResult!\",\" Catalog_AddProduct(productId: ID!, name: String!, description: String!, price: Float!, categoryId: ID!): CommandResult!\",\" Catalog_ArchiveCategory(categoryId: ID!): CommandResult!\\n @aws_auth(cognito_groups: [\\\"Admin\\\"])\",\" Catalog_ChangeProductDescription(productId: ID!, description: String!): CommandResult!\",\" Catalog_ChangeProductName(productId: ID!, name: String!): CommandResult!\",\" Catalog_ChangeProductPrice(productId: ID!, price: Float!): CommandResult!\",\" Catalog_RenameCategory(categoryId: ID!, name: String!): CommandResult!\",\" Catalog_ImportProduct(sku: String!, title: String!, desc: String!, unitPrice: Float!, currency: String!, category: String!): CommandResult!\"],\"queries\":[\" Catalog_Category(id: ID!): Catalog_Category\",\" Catalog_CategoriesByIds(ids: [String!]!): [Catalog_Category!]!\",\" Catalog_Categories(filter: Catalog_CategoryFilter, first: Int, after: String, last: Int, before: String): Catalog_CategoryConnection!\",\" Catalog_ProductDemand(id: ID!): Catalog_ProductDemand\",\" Catalog_ProductDemandsByIds(ids: [String!]!): [Catalog_ProductDemand!]!\",\" Catalog_ProductDemands(filter: Catalog_ProductDemandFilter, first: Int, after: String, last: Int, before: String): Catalog_ProductDemandConnection!\",\" Catalog_Product(id: ID!): Catalog_Product\",\" Catalog_ProductsByIds(ids: [String!]!): [Catalog_Product!]!\",\" Catalog_Products(filter: Catalog_ProductFilter, first: Int, after: String, last: Int, before: String): Catalog_ProductConnection!\",\" Catalog_ImportProductAudit(id: ID!): Catalog_ImportProductAudit\",\" Catalog_ImportProductAuditsByIds(ids: [String!]!): [Catalog_ImportProductAudit!]!\",\" Catalog_ImportProductAudits(filter: Catalog_ImportProductAuditFilter, first: Int, after: String, last: Int, before: String): Catalog_ImportProductAuditConnection!\"],\"subscriptions\":[\" onCatalog_AddCategory(id: ID): CommandResult\",\" onCatalog_AddProduct(id: ID): CommandResult\",\" onCatalog_ArchiveCategory(id: ID): CommandResult\",\" onCatalog_ChangeProductDescription(id: ID): CommandResult\",\" onCatalog_ChangeProductName(id: ID): CommandResult\",\" onCatalog_ChangeProductPrice(id: ID): CommandResult\",\" onCatalog_RenameCategory(id: ID): CommandResult\",\" onCatalog_ImportProduct(id: ID): CommandResult\",\" onCatalogEventLog_eventAppended: CatalogEventLogEvent\"],\"subscriptionSources\":[{\"field\":\"onCatalog_AddCategory\",\"mutations\":[\"Catalog_AddCategory\"]},{\"field\":\"onCatalog_AddProduct\",\"mutations\":[\"Catalog_AddProduct\"]},{\"field\":\"onCatalog_ArchiveCategory\",\"mutations\":[\"Catalog_ArchiveCategory\"]},{\"field\":\"onCatalog_ChangeProductDescription\",\"mutations\":[\"Catalog_ChangeProductDescription\"]},{\"field\":\"onCatalog_ChangeProductName\",\"mutations\":[\"Catalog_ChangeProductName\"]},{\"field\":\"onCatalog_ChangeProductPrice\",\"mutations\":[\"Catalog_ChangeProductPrice\"]},{\"field\":\"onCatalog_RenameCategory\",\"mutations\":[\"Catalog_RenameCategory\"]},{\"field\":\"onCatalog_ImportProduct\",\"mutations\":[\"Catalog_ImportProduct\"]}]}"},"eventCollector":"arn:aws:sqs:eu-west-1:000000000000:CatalogPluginEventColl-fc85d05","structure":{"outboundTranslationSlices":[],"extensions":[{"name":"Ordering.Orders","delegateNames":["RecordProductDemand"],"eventTypes":["Ordering.Orders.ItemOrdered","Ordering.Orders.ItemOrderCancelled"],"commandTypes":[]}],"stateChangeSlices":[{"consistencyRead":null,"chapter":"Category","linkedViews":["Categories"],"producedEventTypes":["Catalog.CategoryAdded"],"name":"AddCategory","commands":[{"schema":"{\"type\":\"object\",\"properties\":{\"TAG\":{\"type\":\"string\",\"const\":\"AddCategory\"},\"categoryId\":{\"type\":\"string\"},\"name\":{\"type\":\"string\"}},\"additionalProperties\":true,\"required\":[\"TAG\",\"categoryId\",\"name\"]}","aggregateIdField":"categoryId","mutationField":"Catalog_AddCategory","references":[],"level":"Collection","apiExposed":true,"name":"AddCategory","allowedStates":null}],"events":[{"name":"CategoryAdded","schema":"{\"type\":\"object\",\"properties\":{\"TAG\":{\"type\":\"string\",\"const\":\"CategoryAdded\"},\"categoryId\":{\"type\":\"string\"},\"name\":{\"type\":\"string\"}},\"additionalProperties\":true,\"required\":[\"TAG\",\"categoryId\",\"name\"]}","references":[]}],"consumedEventTypes":[]},{"consistencyRead":"Categories","chapter":"Product","linkedViews":["ProductDemand","Products"],"producedEventTypes":["Catalog.ProductAdded"],"name":"AddProduct","commands":[{"schema":"{\"type\":\"object\",\"properties\":{\"TAG\":{\"type\":\"string\",\"const\":\"AddProduct\"},\"productId\":{\"type\":\"string\"},\"name\":{\"type\":\"string\"},\"description\":{\"type\":\"string\"},\"price\":{\"type\":\"number\"},\"categoryId\":{\"type\":\"string\"}},\"additionalProperties\":true,\"required\":[\"TAG\",\"productId\",\"name\",\"description\",\"price\",\"categoryId\"]}","aggregateIdField":"productId","mutationField":"Catalog_AddProduct","references":[{"plugin":null,"entity":"Categories","fieldName":"categoryId"}],"level":"Collection","apiExposed":true,"name":"AddProduct","allowedStates":null}],"events":[{"name":"ProductAdded","schema":"{\"type\":\"object\",\"properties\":{\"TAG\":{\"type\":\"string\",\"const\":\"ProductAdded\"},\"productId\":{\"type\":\"string\"},\"name\":{\"type\":\"string\"},\"description\":{\"type\":\"string\"},\"price\":{\"type\":\"number\"},\"categoryId\":{\"type\":\"string\"}},\"additionalProperties\":true,\"required\":[\"TAG\",\"productId\",\"name\",\"description\",\"price\",\"categoryId\"]}","references":[]}],"consumedEventTypes":["Catalog.ProductAdded","Catalog.CategoryAdded","Catalog.CategoryArchived"]},{"consistencyRead":null,"chapter":"Category","linkedViews":["Categories"],"producedEventTypes":["Catalog.CategoryArchived"],"name":"ArchiveCategory","commands":[{"schema":"{\"type\":\"object\",\"properties\":{\"TAG\":{\"type\":\"string\",\"const\":\"ArchiveCategory\"},\"categoryId\":{\"type\":\"string\"}},\"additionalProperties\":true,\"required\":[\"TAG\",\"categoryId\"]}","aggregateIdField":"categoryId","mutationField":"Catalog_ArchiveCategory","references":[],"level":"Instance","apiExposed":true,"name":"ArchiveCategory","allowedStates":null}],"events":[{"name":"CategoryArchived","schema":"{\"type\":\"object\",\"properties\":{\"TAG\":{\"type\":\"string\",\"const\":\"CategoryArchived\"},\"categoryId\":{\"type\":\"string\"}},\"additionalProperties\":true,\"required\":[\"TAG\",\"categoryId\"]}","references":[]}],"consumedEventTypes":[]},{"consistencyRead":"Products","chapter":"Product","linkedViews":["Products"],"producedEventTypes":["Catalog.ProductDescriptionChanged"],"name":"ChangeProductDescription","commands":[{"schema":"{\"type\":\"object\",\"properties\":{\"TAG\":{\"type\":\"string\",\"const\":\"ChangeProductDescription\"},\"productId\":{\"type\":\"string\"},\"description\":{\"type\":\"string\"}},\"additionalProperties\":true,\"required\":[\"TAG\",\"productId\",\"description\"]}","aggregateIdField":"productId","mutationField":"Catalog_ChangeProductDescription","references":[],"level":"Instance","apiExposed":true,"name":"ChangeProductDescription","allowedStates":null}],"events":[{"name":"ProductDescriptionChanged","schema":"{\"type\":\"object\",\"properties\":{\"TAG\":{\"type\":\"string\",\"const\":\"ProductDescriptionChanged\"},\"productId\":{\"type\":\"string\"},\"description\":{\"type\":\"string\"}},\"additionalProperties\":true,\"required\":[\"TAG\",\"productId\",\"description\"]}","references":[]}],"consumedEventTypes":["Catalog.ProductAdded","Catalog.ProductDescriptionChanged"]},{"consistencyRead":"Products","chapter":"Product","linkedViews":["Products"],"producedEventTypes":["Catalog.ProductNameChanged"],"name":"ChangeProductName","commands":[{"schema":"{\"type\":\"object\",\"properties\":{\"TAG\":{\"type\":\"string\",\"const\":\"ChangeProductName\"},\"productId\":{\"type\":\"string\"},\"name\":{\"type\":\"string\"}},\"additionalProperties\":true,\"required\":[\"TAG\",\"productId\",\"name\"]}","aggregateIdField":"productId","mutationField":"Catalog_ChangeProductName","references":[],"level":"Instance","apiExposed":true,"name":"ChangeProductName","allowedStates":null}],"events":[{"name":"ProductNameChanged","schema":"{\"type\":\"object\",\"properties\":{\"TAG\":{\"type\":\"string\",\"const\":\"ProductNameChanged\"},\"productId\":{\"type\":\"string\"},\"name\":{\"type\":\"string\"}},\"additionalProperties\":true,\"required\":[\"TAG\",\"productId\",\"name\"]}","references":[]}],"consumedEventTypes":["Catalog.ProductAdded","Catalog.ProductNameChanged"]},{"consistencyRead":"Products","chapter":"Product","linkedViews":["Products"],"producedEventTypes":["Catalog.ProductPriceChanged"],"name":"ChangeProductPrice","commands":[{"schema":"{\"type\":\"object\",\"properties\":{\"TAG\":{\"type\":\"string\",\"const\":\"ChangeProductPrice\"},\"productId\":{\"type\":\"string\"},\"price\":{\"type\":\"number\"}},\"additionalProperties\":true,\"required\":[\"TAG\",\"productId\",\"price\"]}","aggregateIdField":"productId","mutationField":"Catalog_ChangeProductPrice","references":[],"level":"Instance","apiExposed":true,"name":"ChangeProductPrice","allowedStates":null}],"events":[{"name":"ProductPriceChanged","schema":"{\"type\":\"object\",\"properties\":{\"TAG\":{\"type\":\"string\",\"const\":\"ProductPriceChanged\"},\"productId\":{\"type\":\"string\"},\"price\":{\"type\":\"number\"}},\"additionalProperties\":true,\"required\":[\"TAG\",\"productId\",\"price\"]}","references":[]}],"consumedEventTypes":["Catalog.ProductAdded","Catalog.ProductPriceChanged"]},{"consistencyRead":"ProductDemand","chapter":"ProductDemand","linkedViews":["ProductDemand"],"producedEventTypes":["Catalog.ProductDemandRecorded","Catalog.ProductDemandRevoked"],"name":"RecordProductDemand","commands":[{"schema":"{\"type\":\"object\",\"properties\":{\"TAG\":{\"type\":\"string\",\"const\":\"RecordDemand\"},\"productId\":{\"type\":\"string\"},\"orderId\":{\"type\":\"string\"}},\"additionalProperties\":true,\"required\":[\"TAG\",\"productId\",\"orderId\"]}","aggregateIdField":"productId","mutationField":"Catalog_RecordDemand","references":[],"level":"Instance","apiExposed":false,"name":"RecordDemand","allowedStates":null},{"schema":"{\"type\":\"object\",\"properties\":{\"TAG\":{\"type\":\"string\",\"const\":\"RevokeDemand\"},\"productId\":{\"type\":\"string\"},\"orderId\":{\"type\":\"string\"}},\"additionalProperties\":true,\"required\":[\"TAG\",\"productId\",\"orderId\"]}","aggregateIdField":"productId","mutationField":"Catalog_RevokeDemand","references":[],"level":"Instance","apiExposed":false,"name":"RevokeDemand","allowedStates":null}],"events":[{"name":"ProductDemandRecorded","schema":"{\"type\":\"object\",\"properties\":{\"TAG\":{\"type\":\"string\",\"const\":\"ProductDemandRecorded\"},\"productId\":{\"type\":\"string\"},\"orderId\":{\"type\":\"string\"}},\"additionalProperties\":true,\"required\":[\"TAG\",\"productId\",\"orderId\"]}","references":[]},{"name":"ProductDemandRevoked","schema":"{\"type\":\"object\",\"properties\":{\"TAG\":{\"type\":\"string\",\"const\":\"ProductDemandRevoked\"},\"productId\":{\"type\":\"string\"},\"orderId\":{\"type\":\"string\"}},\"additionalProperties\":true,\"required\":[\"TAG\",\"productId\",\"orderId\"]}","references":[]}],"consumedEventTypes":["Catalog.ProductDemandRecorded","Catalog.ProductDemandRevoked"]},{"consistencyRead":"Categories","chapter":"Category","linkedViews":["Categories"],"producedEventTypes":["Catalog.CategoryRenamed"],"name":"RenameCategory","commands":[{"schema":"{\"type\":\"object\",\"properties\":{\"TAG\":{\"type\":\"string\",\"const\":\"RenameCategory\"},\"categoryId\":{\"type\":\"string\"},\"name\":{\"type\":\"string\"}},\"additionalProperties\":true,\"required\":[\"TAG\",\"categoryId\",\"name\"]}","aggregateIdField":"categoryId","mutationField":"Catalog_RenameCategory","references":[],"level":"Instance","apiExposed":true,"name":"RenameCategory","allowedStates":null}],"events":[{"name":"CategoryRenamed","schema":"{\"type\":\"object\",\"properties\":{\"TAG\":{\"type\":\"string\",\"const\":\"CategoryRenamed\"},\"categoryId\":{\"type\":\"string\"},\"name\":{\"type\":\"string\"}},\"additionalProperties\":true,\"required\":[\"TAG\",\"categoryId\",\"name\"]}","references":[]}],"consumedEventTypes":["Catalog.CategoryAdded","Catalog.CategoryRenamed"]}],"extensionPoints":[{"name":"Catalog.Products","sourceEventTypes":["Catalog.ProductAdded","Catalog.ProductPriceChanged"],"delegateNames":["CatalogDcbEventLog"],"commandTypes":[]}],"readModels":[],"stateViewSlices":[{"schema":"{\"type\":\"object\",\"properties\":{\"categoryId\":{\"type\":\"string\",\"format\":\"uuid\"},\"name\":{\"type\":\"string\"},\"archived\":{\"type\":\"boolean\"}},\"required\":[\"categoryId\",\"name\",\"archived\"]}","searchableFields":["name"],"chapter":"Category","linkedWriteSide":["AddCategory","ArchiveCategory","RenameCategory"],"statusField":null,"visibility":null,"queryField":"Catalog_Categories","name":"Categories","consumedEventTypes":["Catalog.CategoryAdded","Catalog.CategoryRenamed","Catalog.CategoryArchived"],"labelField":"name"},{"schema":"{\"type\":\"object\",\"properties\":{\"productId\":{\"type\":\"string\",\"format\":\"uuid\"},\"name\":{\"type\":\"string\"},\"categoryId\":{\"type\":\"string\",\"format\":\"uuid\"},\"orderCount\":{\"type\":\"number\"}},\"required\":[\"productId\",\"name\",\"categoryId\",\"orderCount\"]}","searchableFields":["name"],"chapter":"Product","linkedWriteSide":["AddProduct","RecordProductDemand"],"statusField":null,"visibility":null,"queryField":"Catalog_ProductDemands","name":"ProductDemand","consumedEventTypes":["Catalog.ProductAdded","Catalog.ProductDemandRecorded","Catalog.ProductDemandRevoked"],"labelField":"name"},{"schema":"{\"type\":\"object\",\"properties\":{\"productId\":{\"type\":\"string\",\"format\":\"uuid\"},\"name\":{\"type\":\"string\"},\"description\":{\"type\":\"string\"},\"price\":{\"type\":\"number\"},\"categoryId\":{\"type\":\"string\",\"format\":\"uuid\"}},\"required\":[\"productId\",\"name\",\"description\",\"price\",\"categoryId\"]}","searchableFields":["name"],"chapter":"Product","linkedWriteSide":["AddProduct","ChangeProductDescription","ChangeProductName","ChangeProductPrice"],"statusField":null,"visibility":null,"queryField":"Catalog_Products","name":"Products","consumedEventTypes":["Catalog.ProductAdded","Catalog.ProductNameChanged","Catalog.ProductDescriptionChanged","Catalog.ProductPriceChanged"],"labelField":"name"}],"aggregates":[],"inboundTranslationSlices":[{"name":"ImportProduct","chapter":"Product","targetName":"AddProduct","commandTypes":["Catalog.AddProduct"],"externalSystem":"SupplierFeed"}],"automationSlices":[]}}}}
|
|
1
|
+
{"event":"VersionConnected","data":{"_0":{"dcbEventLog":{"name":"CatalogDcbEventLog","eventTopicArn":"arn:aws:dynamodb:eu-west-1:000000000000:table/CatalogDcbEventLog-925103d/stream/2026-07-14T08:45:33.852"},"extensions":[{"name":"Ordering.Orders.Catalog","extensionPointName":"Ordering.Orders","dcbSources":[]}],"extensionProtocols":[],"extensionPoints":[{"name":"Catalog.Products","commandTopic":"https://sqs.eu-west-1.amazonaws.com/000000000000/CatalogProductsExtPointCmdTopic-1dd983b","eventTopic":"arn:aws:sns:eu-west-1:000000000000:CatalogProductsExtPointEventTopic-5cb0b5e"}],"kind":"Domain","name":"Catalog","apiTarget":"Domain","id":"Catalog@1.0.0-alpha.149","version":"1.0.0-alpha.149","apiSchemaFragment":{"protocol":"graphql","encoded":"{\"types\":[\"type Catalog_Category implements Node {\\n id: ID!\\n categoryId: ID!\\n name: String!\\n archived: Boolean!\\n}\",\"type Catalog_CategoryEdge {\\n node: Catalog_Category!\\n cursor: String!\\n}\",\"type Catalog_CategoryConnection {\\n edges: [Catalog_CategoryEdge!]!\\n pageInfo: PageInfo!\\n}\",\"input Catalog_CategoryFilter {\\n search: String\\n searchPrefix: String\\n ids: [ID!]\\n}\",\"type Catalog_ProductDemand implements Node {\\n id: ID!\\n productId: ID!\\n name: String!\\n categoryId: ID!\\n orderCount: Float!\\n}\",\"type Catalog_ProductDemandEdge {\\n node: Catalog_ProductDemand!\\n cursor: String!\\n}\",\"type Catalog_ProductDemandConnection {\\n edges: [Catalog_ProductDemandEdge!]!\\n pageInfo: PageInfo!\\n}\",\"input Catalog_ProductDemandFilter {\\n search: String\\n searchPrefix: String\\n ids: [ID!]\\n}\",\"type Catalog_Product implements Node {\\n id: ID!\\n productId: ID!\\n name: String!\\n description: String!\\n price: Float!\\n categoryId: ID!\\n}\",\"type Catalog_ProductEdge {\\n node: Catalog_Product!\\n cursor: String!\\n}\",\"type Catalog_ProductConnection {\\n edges: [Catalog_ProductEdge!]!\\n pageInfo: PageInfo!\\n}\",\"input Catalog_ProductFilter {\\n search: String\\n searchPrefix: String\\n ids: [ID!]\\n}\",\"enum Catalog_ImportProductAuditStatus {\\n Success\\n Failure\\n}\",\"type Catalog_ImportProductAudit implements Node {\\n id: ID!\\n input: String!\\n status: Catalog_ImportProductAuditStatus!\\n targetIds: [ID!]\\n commandCount: Float\\n error: String\\n receivedAt: String!\\n}\",\"type Catalog_ImportProductAuditEdge {\\n node: Catalog_ImportProductAudit!\\n cursor: String!\\n}\",\"type Catalog_ImportProductAuditConnection {\\n edges: [Catalog_ImportProductAuditEdge!]!\\n pageInfo: PageInfo!\\n}\",\"input Catalog_ImportProductAuditFilter {\\n search: String\\n searchPrefix: String\\n ids: [ID!]\\n}\",\"union CommandResult = CommandAccepted | CommandRejected | CommandPending\",\"type CommandAccepted {\\n msgId: ID!\\n entityId: ID\\n eventCount: Int!\\n}\",\"type CommandRejected {\\n msgId: ID!\\n errorCode: String!\\n errorDetail: String\\n}\",\"type CommandPending {\\n msgId: ID!\\n}\",\"type CatalogEventLogEvent {\\n position: String!\\n eventType: String!\\n payload: AWSJSON!\\n}\"],\"mutations\":[\" Catalog_AddCategory(categoryId: ID!, name: String!): CommandResult!\",\" Catalog_AddProduct(productId: ID!, name: String!, description: String!, price: Float!, categoryId: ID!): CommandResult!\",\" Catalog_ArchiveCategory(categoryId: ID!): CommandResult!\\n @aws_auth(cognito_groups: [\\\"Admin\\\"])\",\" Catalog_ChangeProductDescription(productId: ID!, description: String!): CommandResult!\",\" Catalog_ChangeProductName(productId: ID!, name: String!): CommandResult!\",\" Catalog_ChangeProductPrice(productId: ID!, price: Float!): CommandResult!\",\" Catalog_RenameCategory(categoryId: ID!, name: String!): CommandResult!\",\" Catalog_ImportProduct(sku: String!, title: String!, desc: String!, unitPrice: Float!, currency: String!, category: String!): CommandResult!\"],\"queries\":[\" Catalog_Category(id: ID!): Catalog_Category\",\" Catalog_CategoriesByIds(ids: [String!]!): [Catalog_Category!]!\",\" Catalog_Categories(filter: Catalog_CategoryFilter, first: Int, after: String, last: Int, before: String): Catalog_CategoryConnection!\",\" Catalog_ProductDemand(id: ID!): Catalog_ProductDemand\",\" Catalog_ProductDemandsByIds(ids: [String!]!): [Catalog_ProductDemand!]!\",\" Catalog_ProductDemands(filter: Catalog_ProductDemandFilter, first: Int, after: String, last: Int, before: String): Catalog_ProductDemandConnection!\",\" Catalog_Product(id: ID!): Catalog_Product\",\" Catalog_ProductsByIds(ids: [String!]!): [Catalog_Product!]!\",\" Catalog_Products(filter: Catalog_ProductFilter, first: Int, after: String, last: Int, before: String): Catalog_ProductConnection!\",\" Catalog_ImportProductAudit(id: ID!): Catalog_ImportProductAudit\",\" Catalog_ImportProductAuditsByIds(ids: [String!]!): [Catalog_ImportProductAudit!]!\",\" Catalog_ImportProductAudits(filter: Catalog_ImportProductAuditFilter, first: Int, after: String, last: Int, before: String): Catalog_ImportProductAuditConnection!\"],\"subscriptions\":[\" onCatalog_AddCategory(id: ID): CommandResult\",\" onCatalog_AddProduct(id: ID): CommandResult\",\" onCatalog_ArchiveCategory(id: ID): CommandResult\",\" onCatalog_ChangeProductDescription(id: ID): CommandResult\",\" onCatalog_ChangeProductName(id: ID): CommandResult\",\" onCatalog_ChangeProductPrice(id: ID): CommandResult\",\" onCatalog_RenameCategory(id: ID): CommandResult\",\" onCatalog_ImportProduct(id: ID): CommandResult\",\" onCatalogEventLog_eventAppended: CatalogEventLogEvent\"],\"subscriptionSources\":[{\"field\":\"onCatalog_AddCategory\",\"mutations\":[\"Catalog_AddCategory\"]},{\"field\":\"onCatalog_AddProduct\",\"mutations\":[\"Catalog_AddProduct\"]},{\"field\":\"onCatalog_ArchiveCategory\",\"mutations\":[\"Catalog_ArchiveCategory\"]},{\"field\":\"onCatalog_ChangeProductDescription\",\"mutations\":[\"Catalog_ChangeProductDescription\"]},{\"field\":\"onCatalog_ChangeProductName\",\"mutations\":[\"Catalog_ChangeProductName\"]},{\"field\":\"onCatalog_ChangeProductPrice\",\"mutations\":[\"Catalog_ChangeProductPrice\"]},{\"field\":\"onCatalog_RenameCategory\",\"mutations\":[\"Catalog_RenameCategory\"]},{\"field\":\"onCatalog_ImportProduct\",\"mutations\":[\"Catalog_ImportProduct\"]}]}"},"eventCollector":"arn:aws:sqs:eu-west-1:000000000000:CatalogPluginEventColl-fc85d05","structure":{"outboundTranslationSlices":[],"extensions":[{"name":"Ordering.Orders","delegateNames":["RecordProductDemand"],"eventTypes":["Ordering.Orders.ItemOrdered","Ordering.Orders.ItemOrderCancelled"],"commandTypes":[]}],"stateChangeSlices":[{"chapter":"Category","linkedViews":["Categories"],"producedEventTypes":["Catalog.CategoryAdded"],"name":"AddCategory","commands":[{"schema":"{\"type\":\"object\",\"properties\":{\"TAG\":{\"type\":\"string\",\"const\":\"AddCategory\"},\"categoryId\":{\"type\":\"string\"},\"name\":{\"type\":\"string\"}},\"additionalProperties\":true,\"required\":[\"TAG\",\"categoryId\",\"name\"]}","aggregateIdField":"categoryId","mutationField":"Catalog_AddCategory","references":[],"level":"Collection","apiExposed":true,"name":"AddCategory"}],"events":[{"name":"CategoryAdded","schema":"{\"type\":\"object\",\"properties\":{\"TAG\":{\"type\":\"string\",\"const\":\"CategoryAdded\"},\"categoryId\":{\"type\":\"string\"},\"name\":{\"type\":\"string\"}},\"additionalProperties\":true,\"required\":[\"TAG\",\"categoryId\",\"name\"]}","references":[]}],"consumedEventTypes":[]},{"consistencyRead":"Categories","chapter":"Product","linkedViews":["ProductDemand","Products"],"producedEventTypes":["Catalog.ProductAdded"],"name":"AddProduct","commands":[{"schema":"{\"type\":\"object\",\"properties\":{\"TAG\":{\"type\":\"string\",\"const\":\"AddProduct\"},\"productId\":{\"type\":\"string\"},\"name\":{\"type\":\"string\"},\"description\":{\"type\":\"string\"},\"price\":{\"type\":\"number\"},\"categoryId\":{\"type\":\"string\"}},\"additionalProperties\":true,\"required\":[\"TAG\",\"productId\",\"name\",\"description\",\"price\",\"categoryId\"]}","aggregateIdField":"productId","mutationField":"Catalog_AddProduct","references":[{"entity":"Categories","fieldName":"categoryId"}],"level":"Collection","apiExposed":true,"name":"AddProduct"}],"events":[{"name":"ProductAdded","schema":"{\"type\":\"object\",\"properties\":{\"TAG\":{\"type\":\"string\",\"const\":\"ProductAdded\"},\"productId\":{\"type\":\"string\"},\"name\":{\"type\":\"string\"},\"description\":{\"type\":\"string\"},\"price\":{\"type\":\"number\"},\"categoryId\":{\"type\":\"string\"}},\"additionalProperties\":true,\"required\":[\"TAG\",\"productId\",\"name\",\"description\",\"price\",\"categoryId\"]}","references":[]}],"consumedEventTypes":["Catalog.ProductAdded","Catalog.CategoryAdded","Catalog.CategoryArchived"]},{"chapter":"Category","linkedViews":["Categories"],"producedEventTypes":["Catalog.CategoryArchived"],"name":"ArchiveCategory","commands":[{"schema":"{\"type\":\"object\",\"properties\":{\"TAG\":{\"type\":\"string\",\"const\":\"ArchiveCategory\"},\"categoryId\":{\"type\":\"string\"}},\"additionalProperties\":true,\"required\":[\"TAG\",\"categoryId\"]}","aggregateIdField":"categoryId","mutationField":"Catalog_ArchiveCategory","references":[],"level":"Instance","apiExposed":true,"name":"ArchiveCategory"}],"events":[{"name":"CategoryArchived","schema":"{\"type\":\"object\",\"properties\":{\"TAG\":{\"type\":\"string\",\"const\":\"CategoryArchived\"},\"categoryId\":{\"type\":\"string\"}},\"additionalProperties\":true,\"required\":[\"TAG\",\"categoryId\"]}","references":[]}],"consumedEventTypes":[]},{"consistencyRead":"Products","chapter":"Product","linkedViews":["Products"],"producedEventTypes":["Catalog.ProductDescriptionChanged"],"name":"ChangeProductDescription","commands":[{"schema":"{\"type\":\"object\",\"properties\":{\"TAG\":{\"type\":\"string\",\"const\":\"ChangeProductDescription\"},\"productId\":{\"type\":\"string\"},\"description\":{\"type\":\"string\"}},\"additionalProperties\":true,\"required\":[\"TAG\",\"productId\",\"description\"]}","aggregateIdField":"productId","mutationField":"Catalog_ChangeProductDescription","references":[],"level":"Instance","apiExposed":true,"name":"ChangeProductDescription"}],"events":[{"name":"ProductDescriptionChanged","schema":"{\"type\":\"object\",\"properties\":{\"TAG\":{\"type\":\"string\",\"const\":\"ProductDescriptionChanged\"},\"productId\":{\"type\":\"string\"},\"description\":{\"type\":\"string\"}},\"additionalProperties\":true,\"required\":[\"TAG\",\"productId\",\"description\"]}","references":[]}],"consumedEventTypes":["Catalog.ProductAdded","Catalog.ProductDescriptionChanged"]},{"consistencyRead":"Products","chapter":"Product","linkedViews":["Products"],"producedEventTypes":["Catalog.ProductNameChanged"],"name":"ChangeProductName","commands":[{"schema":"{\"type\":\"object\",\"properties\":{\"TAG\":{\"type\":\"string\",\"const\":\"ChangeProductName\"},\"productId\":{\"type\":\"string\"},\"name\":{\"type\":\"string\"}},\"additionalProperties\":true,\"required\":[\"TAG\",\"productId\",\"name\"]}","aggregateIdField":"productId","mutationField":"Catalog_ChangeProductName","references":[],"level":"Instance","apiExposed":true,"name":"ChangeProductName"}],"events":[{"name":"ProductNameChanged","schema":"{\"type\":\"object\",\"properties\":{\"TAG\":{\"type\":\"string\",\"const\":\"ProductNameChanged\"},\"productId\":{\"type\":\"string\"},\"name\":{\"type\":\"string\"}},\"additionalProperties\":true,\"required\":[\"TAG\",\"productId\",\"name\"]}","references":[]}],"consumedEventTypes":["Catalog.ProductAdded","Catalog.ProductNameChanged"]},{"consistencyRead":"Products","chapter":"Product","linkedViews":["Products"],"producedEventTypes":["Catalog.ProductPriceChanged"],"name":"ChangeProductPrice","commands":[{"schema":"{\"type\":\"object\",\"properties\":{\"TAG\":{\"type\":\"string\",\"const\":\"ChangeProductPrice\"},\"productId\":{\"type\":\"string\"},\"price\":{\"type\":\"number\"}},\"additionalProperties\":true,\"required\":[\"TAG\",\"productId\",\"price\"]}","aggregateIdField":"productId","mutationField":"Catalog_ChangeProductPrice","references":[],"level":"Instance","apiExposed":true,"name":"ChangeProductPrice"}],"events":[{"name":"ProductPriceChanged","schema":"{\"type\":\"object\",\"properties\":{\"TAG\":{\"type\":\"string\",\"const\":\"ProductPriceChanged\"},\"productId\":{\"type\":\"string\"},\"price\":{\"type\":\"number\"}},\"additionalProperties\":true,\"required\":[\"TAG\",\"productId\",\"price\"]}","references":[]}],"consumedEventTypes":["Catalog.ProductAdded","Catalog.ProductPriceChanged"]},{"consistencyRead":"ProductDemand","chapter":"ProductDemand","linkedViews":["ProductDemand"],"producedEventTypes":["Catalog.ProductDemandRecorded","Catalog.ProductDemandRevoked"],"name":"RecordProductDemand","commands":[{"schema":"{\"type\":\"object\",\"properties\":{\"TAG\":{\"type\":\"string\",\"const\":\"RecordDemand\"},\"productId\":{\"type\":\"string\"},\"orderId\":{\"type\":\"string\"}},\"additionalProperties\":true,\"required\":[\"TAG\",\"productId\",\"orderId\"]}","aggregateIdField":"productId","mutationField":"Catalog_RecordDemand","references":[],"level":"Instance","apiExposed":false,"name":"RecordDemand"},{"schema":"{\"type\":\"object\",\"properties\":{\"TAG\":{\"type\":\"string\",\"const\":\"RevokeDemand\"},\"productId\":{\"type\":\"string\"},\"orderId\":{\"type\":\"string\"}},\"additionalProperties\":true,\"required\":[\"TAG\",\"productId\",\"orderId\"]}","aggregateIdField":"productId","mutationField":"Catalog_RevokeDemand","references":[],"level":"Instance","apiExposed":false,"name":"RevokeDemand"}],"events":[{"name":"ProductDemandRecorded","schema":"{\"type\":\"object\",\"properties\":{\"TAG\":{\"type\":\"string\",\"const\":\"ProductDemandRecorded\"},\"productId\":{\"type\":\"string\"},\"orderId\":{\"type\":\"string\"}},\"additionalProperties\":true,\"required\":[\"TAG\",\"productId\",\"orderId\"]}","references":[]},{"name":"ProductDemandRevoked","schema":"{\"type\":\"object\",\"properties\":{\"TAG\":{\"type\":\"string\",\"const\":\"ProductDemandRevoked\"},\"productId\":{\"type\":\"string\"},\"orderId\":{\"type\":\"string\"}},\"additionalProperties\":true,\"required\":[\"TAG\",\"productId\",\"orderId\"]}","references":[]}],"consumedEventTypes":["Catalog.ProductDemandRecorded","Catalog.ProductDemandRevoked"]},{"consistencyRead":"Categories","chapter":"Category","linkedViews":["Categories"],"producedEventTypes":["Catalog.CategoryRenamed"],"name":"RenameCategory","commands":[{"schema":"{\"type\":\"object\",\"properties\":{\"TAG\":{\"type\":\"string\",\"const\":\"RenameCategory\"},\"categoryId\":{\"type\":\"string\"},\"name\":{\"type\":\"string\"}},\"additionalProperties\":true,\"required\":[\"TAG\",\"categoryId\",\"name\"]}","aggregateIdField":"categoryId","mutationField":"Catalog_RenameCategory","references":[],"level":"Instance","apiExposed":true,"name":"RenameCategory"}],"events":[{"name":"CategoryRenamed","schema":"{\"type\":\"object\",\"properties\":{\"TAG\":{\"type\":\"string\",\"const\":\"CategoryRenamed\"},\"categoryId\":{\"type\":\"string\"},\"name\":{\"type\":\"string\"}},\"additionalProperties\":true,\"required\":[\"TAG\",\"categoryId\",\"name\"]}","references":[]}],"consumedEventTypes":["Catalog.CategoryAdded","Catalog.CategoryRenamed"]}],"extensionPoints":[{"name":"Catalog.Products","sourceEventTypes":["Catalog.ProductAdded","Catalog.ProductPriceChanged"],"delegateNames":["CatalogDcbEventLog"],"commandTypes":[]}],"readModels":[],"stateViewSlices":[{"schema":"{\"type\":\"object\",\"properties\":{\"categoryId\":{\"type\":\"string\",\"format\":\"uuid\"},\"name\":{\"type\":\"string\"},\"archived\":{\"type\":\"boolean\"}},\"required\":[\"categoryId\",\"name\",\"archived\"]}","searchableFields":["name"],"chapter":"Category","linkedWriteSide":["AddCategory","ArchiveCategory","RenameCategory"],"queryField":"Catalog_Categories","name":"Categories","consumedEventTypes":["Catalog.CategoryAdded","Catalog.CategoryRenamed","Catalog.CategoryArchived"],"labelField":"name"},{"schema":"{\"type\":\"object\",\"properties\":{\"productId\":{\"type\":\"string\",\"format\":\"uuid\"},\"name\":{\"type\":\"string\"},\"categoryId\":{\"type\":\"string\",\"format\":\"uuid\"},\"orderCount\":{\"type\":\"number\"}},\"required\":[\"productId\",\"name\",\"categoryId\",\"orderCount\"]}","searchableFields":["name"],"chapter":"Product","linkedWriteSide":["AddProduct","RecordProductDemand"],"queryField":"Catalog_ProductDemands","name":"ProductDemand","consumedEventTypes":["Catalog.ProductAdded","Catalog.ProductDemandRecorded","Catalog.ProductDemandRevoked"],"labelField":"name"},{"schema":"{\"type\":\"object\",\"properties\":{\"productId\":{\"type\":\"string\",\"format\":\"uuid\"},\"name\":{\"type\":\"string\"},\"description\":{\"type\":\"string\"},\"price\":{\"type\":\"number\"},\"categoryId\":{\"type\":\"string\",\"format\":\"uuid\"}},\"required\":[\"productId\",\"name\",\"description\",\"price\",\"categoryId\"]}","searchableFields":["name"],"chapter":"Product","linkedWriteSide":["AddProduct","ChangeProductDescription","ChangeProductName","ChangeProductPrice"],"queryField":"Catalog_Products","name":"Products","consumedEventTypes":["Catalog.ProductAdded","Catalog.ProductNameChanged","Catalog.ProductDescriptionChanged","Catalog.ProductPriceChanged"],"labelField":"name"}],"aggregates":[],"inboundTranslationSlices":[{"name":"ImportProduct","chapter":"Product","targetName":"AddProduct","commandTypes":["Catalog.AddProduct"],"externalSystem":"SupplierFeed"}],"automationSlices":[]}}}}
|