@reventlessdev/reventless-infra 3.0.0-alpha.207 → 3.0.0-alpha.209
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 +30 -0
- package/package.json +3 -3
- package/src/components/Extension.res +0 -2
- package/src/types/ExtensionMapping.res +51 -26
- package/src/types/ExtensionMapping.res.mjs +25 -31
- package/src/types/ExtensionPointMapping.res +12 -13
- package/src/types/ExtensionPointMapping.res.mjs +11 -13
- package/src/types/Message.res +62 -0
- package/src/types/Message.res.mjs +59 -1
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,36 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
# 3.0.0-alpha.209 (2026-10-29)
|
|
7
|
+
|
|
8
|
+
* feat(core)!: the caller's IP address leaves the messages a request causes ([aa9e8c7](https://github.com/ReventlessDev/reventless-core/commit/aa9e8c79c0360528a5cfeda2bb88d1da52f28674))
|
|
9
|
+
|
|
10
|
+
### BREAKING CHANGES
|
|
11
|
+
|
|
12
|
+
* `Message.generateMeta` no longer takes `~ip`. Drop the argument; a
|
|
13
|
+
message that must carry the address declares it as a field of its own payload.
|
|
14
|
+
|
|
15
|
+
Step PD3 of docs/plans/a-personal-field-is-marked-redacted-and-encrypted-at-the-seam.md.
|
|
16
|
+
Claude-Session: https://claude.ai/code/session_01HiQfdxVEsHwLHRoHSUcus1
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
# 3.0.0-alpha.208 (2026-10-29)
|
|
21
|
+
|
|
22
|
+
* refactor!: a read model hears another plugin only through an Extension and a slice ([15c7cae](https://github.com/ReventlessDev/reventless-core/commit/15c7cae214d5aa04404779fcd87a8429aad1965c))
|
|
23
|
+
### Features
|
|
24
|
+
|
|
25
|
+
* **core:** a handler drops a command it has already handled ([605862b](https://github.com/ReventlessDev/reventless-core/commit/605862bba765b1501eb19d08f3924bf619159e21))
|
|
26
|
+
* **infra:** a message a mapping derives gets a stable id and names its parent ([a72a08f](https://github.com/ReventlessDev/reventless-core/commit/a72a08f9af4440eff5fa36e9a364a426bc70918c))
|
|
27
|
+
|
|
28
|
+
### BREAKING CHANGES
|
|
29
|
+
|
|
30
|
+
* `ReventlessInfra.Extension.T.make` and the core
|
|
31
|
+
`Extension_Builder.make` no longer take `~readModelNamesForSourceName` and
|
|
32
|
+
`~publishToReadModels`. Both arguments did nothing; drop them at the call site.
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
|
|
6
36
|
# 3.0.0-alpha.207 (2026-10-25)
|
|
7
37
|
|
|
8
38
|
**Note:** Version bump only for package @reventlessdev/reventless-infra
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@reventlessdev/reventless-infra",
|
|
3
|
-
"version": "3.0.0-alpha.
|
|
3
|
+
"version": "3.0.0-alpha.209",
|
|
4
4
|
"description": "Infrastructure types for Reventless framework",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"jest": {
|
|
@@ -17,9 +17,9 @@
|
|
|
17
17
|
"sury-ppx": "11.0.0",
|
|
18
18
|
"uuid": "^13.0.0",
|
|
19
19
|
"@reventlessdev/rescript-effect": "1.0.0-alpha.1",
|
|
20
|
-
"@reventlessdev/rescript-uuid": "2.0.0-alpha.1",
|
|
21
20
|
"@reventlessdev/rescript-pulumi-pulumi": "3.0.0-alpha.0",
|
|
22
|
-
"@reventlessdev/reventless-spec": "3.0.0-alpha.
|
|
21
|
+
"@reventlessdev/reventless-spec": "3.0.0-alpha.180",
|
|
22
|
+
"@reventlessdev/rescript-uuid": "2.0.0-alpha.1"
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
25
25
|
"rescript": "12.3.1",
|
|
@@ -30,8 +30,6 @@ module type T = {
|
|
|
30
30
|
let make: (
|
|
31
31
|
~publishToPluginExtensionPoint: CommandTopic.publishJsons,
|
|
32
32
|
~publishToAggregates: dict<CommandTopic.publishJsons>,
|
|
33
|
-
~readModelNamesForSourceName: dict<array<string>>,
|
|
34
|
-
~publishToReadModels: dict<EventCollector.enqueueEvent>,
|
|
35
33
|
~queryEngine: Reventless.QueryEngine.operations,
|
|
36
34
|
~opts: option<Pulumi.ComponentResource.options>,
|
|
37
35
|
) => component
|
|
@@ -257,28 +257,32 @@ module Make = (MappingImpl: Mapping): (
|
|
|
257
257
|
let compLog = (comp, msg) =>
|
|
258
258
|
Effect.logInfo(msg)->Effect.annotateLogs("comp", comp)->Effect.runSync
|
|
259
259
|
|
|
260
|
-
let encodeMeta = (meta: Reventless.Message.meta, service) => {
|
|
261
|
-
...meta,
|
|
262
|
-
service,
|
|
263
|
-
msgId: Message.uuid(),
|
|
264
|
-
}
|
|
265
|
-
|
|
266
260
|
let doMapIncomingEvent = (
|
|
267
261
|
mapIncomingEventImpl,
|
|
268
262
|
{Reventless.Message.id: id, event, meta},
|
|
269
263
|
pluginDef,
|
|
270
264
|
queryEngine,
|
|
271
265
|
) => {
|
|
272
|
-
|
|
266
|
+
// Every command here is derived from the published event: `index` is the
|
|
267
|
+
// action's position in the mapping's result, `item` a command's position
|
|
268
|
+
// inside a multi-command action, so a redelivered event yields the same
|
|
269
|
+
// `msgId`s and the handler can drop the repeat.
|
|
270
|
+
let encodeTargetCommandJson = (targetCmd, targetId, ~index, ~item) => {
|
|
273
271
|
let cmdJson = targetCmd->Reventless.Message.encode(Delegate.commandSchema)
|
|
274
272
|
{
|
|
275
273
|
Reventless.Message.id: targetId,
|
|
276
|
-
meta:
|
|
274
|
+
meta: Message.deriveStableMeta(~parent=meta, ~service=delegateName, ~index, ~item),
|
|
277
275
|
commandJson: cmdJson,
|
|
278
276
|
}
|
|
279
277
|
}
|
|
280
278
|
|
|
281
|
-
let encodeExtensionPointCommandJson = (
|
|
279
|
+
let encodeExtensionPointCommandJson = (
|
|
280
|
+
commandJson,
|
|
281
|
+
~id,
|
|
282
|
+
~extensionPointName,
|
|
283
|
+
~action,
|
|
284
|
+
~index,
|
|
285
|
+
) => {
|
|
282
286
|
compLog(
|
|
283
287
|
`Extension(${extensionPointName})`,
|
|
284
288
|
`${action}: ${commandJson
|
|
@@ -287,49 +291,55 @@ module Make = (MappingImpl: Mapping): (
|
|
|
287
291
|
)
|
|
288
292
|
{
|
|
289
293
|
Reventless.Message.id,
|
|
290
|
-
meta:
|
|
294
|
+
meta: Message.deriveStableMeta(~parent=meta, ~service=extensionPointName, ~index),
|
|
291
295
|
commandJson,
|
|
292
296
|
}
|
|
293
297
|
}
|
|
294
298
|
|
|
295
|
-
let encodeExtensionPointCommand = (command, ~id, ~extensionPointName, ~action) =>
|
|
299
|
+
let encodeExtensionPointCommand = (command, ~id, ~extensionPointName, ~action, ~index) =>
|
|
296
300
|
command
|
|
297
301
|
->Reventless.Message.encode(Spec.commandSchema)
|
|
298
|
-
->encodeExtensionPointCommandJson(~id, ~extensionPointName, ~action)
|
|
302
|
+
->encodeExtensionPointCommandJson(~id, ~extensionPointName, ~action, ~index)
|
|
299
303
|
|
|
300
|
-
mapIncomingEventImpl(id, event, meta, pluginDef, queryEngine)->Array.
|
|
304
|
+
mapIncomingEventImpl(id, event, meta, pluginDef, queryEngine)->Array.mapWithIndex((x, index) =>
|
|
301
305
|
switch x {
|
|
302
306
|
| PublishAggregateCommand(targetId, targetCmd) =>
|
|
303
|
-
AbstractPublishAggregateCommand(
|
|
307
|
+
AbstractPublishAggregateCommand(
|
|
308
|
+
delegateName,
|
|
309
|
+
targetCmd->encodeTargetCommandJson(targetId, ~index, ~item=0),
|
|
310
|
+
)
|
|
304
311
|
| PublishAggregateCommandAsync(promise) =>
|
|
305
312
|
let toCommandJson = async promise => {
|
|
306
313
|
let (targetId, targetCmd) = await promise
|
|
307
|
-
(delegateName, targetCmd->encodeTargetCommandJson(targetId))
|
|
314
|
+
(delegateName, targetCmd->encodeTargetCommandJson(targetId, ~index, ~item=0))
|
|
308
315
|
}
|
|
309
316
|
AbstractPublishAggregateCommandAsync(promise->toCommandJson)
|
|
310
317
|
| PublishAggregateCommandsAsync(promise) =>
|
|
311
318
|
let toCommandJsons = async promise =>
|
|
312
|
-
(await promise)->Array.
|
|
319
|
+
(await promise)->Array.mapWithIndex(((targetId, targetCmd), item) => (
|
|
313
320
|
delegateName,
|
|
314
|
-
targetCmd->encodeTargetCommandJson(targetId),
|
|
321
|
+
targetCmd->encodeTargetCommandJson(targetId, ~index, ~item),
|
|
315
322
|
))
|
|
316
323
|
AbstractPublishAggregateCommandsAsync(promise->toCommandJsons)
|
|
317
324
|
| PublishStateChangeSliceCommand(targetCmd) =>
|
|
318
325
|
AbstractPublishAggregateCommand(
|
|
319
326
|
delegateName,
|
|
320
|
-
targetCmd->encodeTargetCommandJson(derivePartitionId(targetCmd)),
|
|
327
|
+
targetCmd->encodeTargetCommandJson(derivePartitionId(targetCmd), ~index, ~item=0),
|
|
321
328
|
)
|
|
322
329
|
| PublishStateChangeSliceCommandAsync(promise) =>
|
|
323
330
|
let toCommandJson = async promise => {
|
|
324
331
|
let targetCmd = await promise
|
|
325
|
-
(
|
|
332
|
+
(
|
|
333
|
+
delegateName,
|
|
334
|
+
targetCmd->encodeTargetCommandJson(derivePartitionId(targetCmd), ~index, ~item=0),
|
|
335
|
+
)
|
|
326
336
|
}
|
|
327
337
|
AbstractPublishAggregateCommandAsync(promise->toCommandJson)
|
|
328
338
|
| PublishStateChangeSliceCommandsAsync(promise) =>
|
|
329
339
|
let toCommandJsons = async promise =>
|
|
330
|
-
(await promise)->Array.
|
|
340
|
+
(await promise)->Array.mapWithIndex((targetCmd, item) => (
|
|
331
341
|
delegateName,
|
|
332
|
-
targetCmd->encodeTargetCommandJson(derivePartitionId(targetCmd)),
|
|
342
|
+
targetCmd->encodeTargetCommandJson(derivePartitionId(targetCmd), ~index, ~item),
|
|
333
343
|
))
|
|
334
344
|
AbstractPublishAggregateCommandsAsync(promise->toCommandJsons)
|
|
335
345
|
| PublishExtensionPointCommand(id, command) if Spec.name == PluginExtensionPointSpec.name =>
|
|
@@ -338,6 +348,7 @@ module Make = (MappingImpl: Mapping): (
|
|
|
338
348
|
~id,
|
|
339
349
|
~extensionPointName,
|
|
340
350
|
~action="Publish PluginExtensionPoint command",
|
|
351
|
+
~index,
|
|
341
352
|
),
|
|
342
353
|
)
|
|
343
354
|
| PublishExtensionPointCommand(id, command) =>
|
|
@@ -347,6 +358,7 @@ module Make = (MappingImpl: Mapping): (
|
|
|
347
358
|
~id,
|
|
348
359
|
~extensionPointName,
|
|
349
360
|
~action="Publish ExtensionPoint command",
|
|
361
|
+
~index,
|
|
350
362
|
),
|
|
351
363
|
)
|
|
352
364
|
| ForwardCommand({extensionPointName, id, commandJson}) =>
|
|
@@ -356,6 +368,7 @@ module Make = (MappingImpl: Mapping): (
|
|
|
356
368
|
~id,
|
|
357
369
|
~extensionPointName,
|
|
358
370
|
~action="Forward ExtensionPoint command",
|
|
371
|
+
~index,
|
|
359
372
|
),
|
|
360
373
|
)
|
|
361
374
|
| HandleDirective(handler, directive) =>
|
|
@@ -383,7 +396,13 @@ module Make = (MappingImpl: Mapping): (
|
|
|
383
396
|
} else {
|
|
384
397
|
let {id, meta, event} =
|
|
385
398
|
targetEvent'Json->Reventless.Message.decodeEvent'(Delegate.Id.schema, Delegate.eventSchema)
|
|
386
|
-
let encodeExtensionPointCommandJson = (
|
|
399
|
+
let encodeExtensionPointCommandJson = (
|
|
400
|
+
commandJson,
|
|
401
|
+
~id,
|
|
402
|
+
~extensionPointName,
|
|
403
|
+
~action,
|
|
404
|
+
~index,
|
|
405
|
+
) => {
|
|
387
406
|
compLog(
|
|
388
407
|
`Extension(${delegateName})`,
|
|
389
408
|
`${action}: ${commandJson
|
|
@@ -392,17 +411,20 @@ module Make = (MappingImpl: Mapping): (
|
|
|
392
411
|
)
|
|
393
412
|
{
|
|
394
413
|
Reventless.Message.id,
|
|
395
|
-
meta:
|
|
414
|
+
meta: Message.deriveStableMeta(~parent=meta, ~service=extensionPointName, ~index),
|
|
396
415
|
commandJson,
|
|
397
416
|
}
|
|
398
417
|
}
|
|
399
418
|
|
|
400
|
-
let encodeExtensionPointCommand = (command, ~id, ~extensionPointName, ~action) =>
|
|
419
|
+
let encodeExtensionPointCommand = (command, ~id, ~extensionPointName, ~action, ~index) =>
|
|
401
420
|
command
|
|
402
421
|
->Reventless.Message.encode(Spec.commandSchema)
|
|
403
|
-
->encodeExtensionPointCommandJson(~id, ~extensionPointName, ~action)
|
|
422
|
+
->encodeExtensionPointCommandJson(~id, ~extensionPointName, ~action, ~index)
|
|
404
423
|
|
|
405
|
-
mapOutgoingEventImpl(id->Delegate.Id.toString, event, meta, pluginDef)->Array.
|
|
424
|
+
mapOutgoingEventImpl(id->Delegate.Id.toString, event, meta, pluginDef)->Array.mapWithIndex((
|
|
425
|
+
x,
|
|
426
|
+
index,
|
|
427
|
+
) =>
|
|
406
428
|
switch x {
|
|
407
429
|
| PublishExtensionPointCommand(id, command) if Spec.name == PluginExtensionPointSpec.name =>
|
|
408
430
|
AbstractPublishPluginExtensionPointCommand(
|
|
@@ -410,6 +432,7 @@ module Make = (MappingImpl: Mapping): (
|
|
|
410
432
|
~id,
|
|
411
433
|
~extensionPointName,
|
|
412
434
|
~action="Publish PluginExtensionPoint command",
|
|
435
|
+
~index,
|
|
413
436
|
),
|
|
414
437
|
)
|
|
415
438
|
|
|
@@ -420,6 +443,7 @@ module Make = (MappingImpl: Mapping): (
|
|
|
420
443
|
~id,
|
|
421
444
|
~extensionPointName,
|
|
422
445
|
~action="Publish ExtensionPoint command",
|
|
446
|
+
~index,
|
|
423
447
|
),
|
|
424
448
|
)
|
|
425
449
|
| ForwardCommand({extensionPointName, id, commandJson}) =>
|
|
@@ -429,6 +453,7 @@ module Make = (MappingImpl: Mapping): (
|
|
|
429
453
|
~id,
|
|
430
454
|
~extensionPointName,
|
|
431
455
|
~action="Forward ExtensionPoint command",
|
|
456
|
+
~index,
|
|
432
457
|
),
|
|
433
458
|
)
|
|
434
459
|
| HandleDirective(handler, directive) =>
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
2
|
|
|
3
3
|
import * as Sury from "sury";
|
|
4
|
-
import * as Uuid from "uuid";
|
|
5
4
|
import * as Stdlib_JSON from "@rescript/runtime/lib/es6/Stdlib_JSON.js";
|
|
6
5
|
import * as Stdlib_JsExn from "@rescript/runtime/lib/es6/Stdlib_JsExn.js";
|
|
7
6
|
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
@@ -11,6 +10,7 @@ import * as DcbTag$Reventless from "@reventlessdev/reventless-spec/src/component
|
|
|
11
10
|
import * as Message$Reventless from "@reventlessdev/reventless-spec/src/types/Message.res.mjs";
|
|
12
11
|
import * as AnsiStyle$Reventless from "@reventlessdev/reventless-spec/src/AnsiStyle.res.mjs";
|
|
13
12
|
import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
|
|
13
|
+
import * as Message$ReventlessInfra from "./Message.res.mjs";
|
|
14
14
|
import * as PluginExtensionPointSpec$ReventlessInfra from "./PluginExtensionPointSpec.res.mjs";
|
|
15
15
|
|
|
16
16
|
let schema = Sury.string;
|
|
@@ -98,46 +98,40 @@ function Make(MappingImpl) {
|
|
|
98
98
|
};
|
|
99
99
|
let derivePartitionId = targetCmd => DcbTag$Reventless.partitionValueOfTags(DcbTag$Reventless.extractTags(Delegate.commandSchema, targetCmd), getDerivedPartitionTag());
|
|
100
100
|
let compLog = (comp, msg) => Effect.runSync(Effect.annotateLogs(Effect.logInfo(msg), "comp", comp));
|
|
101
|
-
let encodeMeta = (meta, service) => {
|
|
102
|
-
let newrecord = {...meta};
|
|
103
|
-
newrecord.msgId = Uuid.v4();
|
|
104
|
-
newrecord.service = service;
|
|
105
|
-
return newrecord;
|
|
106
|
-
};
|
|
107
101
|
let mapIncomingEvent = (extra, extra$1, extra$2) => {
|
|
108
102
|
let mapIncomingEventImpl = MappingImpl.mapIncomingEvent;
|
|
109
103
|
let meta = extra.meta;
|
|
110
|
-
let encodeTargetCommandJson = (targetCmd, targetId) => {
|
|
104
|
+
let encodeTargetCommandJson = (targetCmd, targetId, index, item) => {
|
|
111
105
|
let cmdJson = Message$Reventless.encode(targetCmd, Delegate.commandSchema);
|
|
112
106
|
return {
|
|
113
107
|
id: targetId,
|
|
114
|
-
meta:
|
|
108
|
+
meta: Message$ReventlessInfra.deriveStableMeta(meta, delegateName, index, item),
|
|
115
109
|
commandJson: cmdJson
|
|
116
110
|
};
|
|
117
111
|
};
|
|
118
|
-
let encodeExtensionPointCommandJson = (commandJson, id, extensionPointName, action) => {
|
|
112
|
+
let encodeExtensionPointCommandJson = (commandJson, id, extensionPointName, action, index) => {
|
|
119
113
|
compLog(`Extension(` + extensionPointName + `)`, action + `: ` + AnsiStyle$Reventless.bold(Message$Reventless.variantNameOfJson(commandJson)) + `(` + id + `)`);
|
|
120
114
|
return {
|
|
121
115
|
id: id,
|
|
122
|
-
meta:
|
|
116
|
+
meta: Message$ReventlessInfra.deriveStableMeta(meta, extensionPointName, index, undefined),
|
|
123
117
|
commandJson: commandJson
|
|
124
118
|
};
|
|
125
119
|
};
|
|
126
|
-
let encodeExtensionPointCommand = (command, id, extensionPointName, action) => encodeExtensionPointCommandJson(Message$Reventless.encode(command, Spec.commandSchema), id, extensionPointName, action);
|
|
127
|
-
return mapIncomingEventImpl(extra.id, extra.event, meta, extra$1, extra$2).map(x => {
|
|
120
|
+
let encodeExtensionPointCommand = (command, id, extensionPointName, action, index) => encodeExtensionPointCommandJson(Message$Reventless.encode(command, Spec.commandSchema), id, extensionPointName, action, index);
|
|
121
|
+
return mapIncomingEventImpl(extra.id, extra.event, meta, extra$1, extra$2).map((x, index) => {
|
|
128
122
|
switch (x.TAG) {
|
|
129
123
|
case "PublishAggregateCommand" :
|
|
130
124
|
return {
|
|
131
125
|
TAG: "AbstractPublishAggregateCommand",
|
|
132
126
|
_0: delegateName,
|
|
133
|
-
_1: encodeTargetCommandJson(x._1, x._0)
|
|
127
|
+
_1: encodeTargetCommandJson(x._1, x._0, index, 0)
|
|
134
128
|
};
|
|
135
129
|
case "PublishAggregateCommandAsync" :
|
|
136
130
|
let toCommandJson = async promise => {
|
|
137
131
|
let match = await promise;
|
|
138
132
|
return [
|
|
139
133
|
delegateName,
|
|
140
|
-
encodeTargetCommandJson(match[1], match[0])
|
|
134
|
+
encodeTargetCommandJson(match[1], match[0], index, 0)
|
|
141
135
|
];
|
|
142
136
|
};
|
|
143
137
|
return {
|
|
@@ -145,9 +139,9 @@ function Make(MappingImpl) {
|
|
|
145
139
|
_0: toCommandJson(x._0)
|
|
146
140
|
};
|
|
147
141
|
case "PublishAggregateCommandsAsync" :
|
|
148
|
-
let toCommandJsons = async promise => (await promise).map(param => [
|
|
142
|
+
let toCommandJsons = async promise => (await promise).map((param, item) => [
|
|
149
143
|
delegateName,
|
|
150
|
-
encodeTargetCommandJson(param[1], param[0])
|
|
144
|
+
encodeTargetCommandJson(param[1], param[0], index, item)
|
|
151
145
|
]);
|
|
152
146
|
return {
|
|
153
147
|
TAG: "AbstractPublishAggregateCommandsAsync",
|
|
@@ -158,14 +152,14 @@ function Make(MappingImpl) {
|
|
|
158
152
|
return {
|
|
159
153
|
TAG: "AbstractPublishAggregateCommand",
|
|
160
154
|
_0: delegateName,
|
|
161
|
-
_1: encodeTargetCommandJson(targetCmd, derivePartitionId(targetCmd))
|
|
155
|
+
_1: encodeTargetCommandJson(targetCmd, derivePartitionId(targetCmd), index, 0)
|
|
162
156
|
};
|
|
163
157
|
case "PublishStateChangeSliceCommandAsync" :
|
|
164
158
|
let toCommandJson$1 = async promise => {
|
|
165
159
|
let targetCmd = await promise;
|
|
166
160
|
return [
|
|
167
161
|
delegateName,
|
|
168
|
-
encodeTargetCommandJson(targetCmd, derivePartitionId(targetCmd))
|
|
162
|
+
encodeTargetCommandJson(targetCmd, derivePartitionId(targetCmd), index, 0)
|
|
169
163
|
];
|
|
170
164
|
};
|
|
171
165
|
return {
|
|
@@ -173,9 +167,9 @@ function Make(MappingImpl) {
|
|
|
173
167
|
_0: toCommandJson$1(x._0)
|
|
174
168
|
};
|
|
175
169
|
case "PublishStateChangeSliceCommandsAsync" :
|
|
176
|
-
let toCommandJsons$1 = async promise => (await promise).map(targetCmd => [
|
|
170
|
+
let toCommandJsons$1 = async promise => (await promise).map((targetCmd, item) => [
|
|
177
171
|
delegateName,
|
|
178
|
-
encodeTargetCommandJson(targetCmd, derivePartitionId(targetCmd))
|
|
172
|
+
encodeTargetCommandJson(targetCmd, derivePartitionId(targetCmd), index, item)
|
|
179
173
|
]);
|
|
180
174
|
return {
|
|
181
175
|
TAG: "AbstractPublishAggregateCommandsAsync",
|
|
@@ -187,13 +181,13 @@ function Make(MappingImpl) {
|
|
|
187
181
|
if (Spec.name === PluginExtensionPointSpec$ReventlessInfra.name) {
|
|
188
182
|
return {
|
|
189
183
|
TAG: "AbstractPublishPluginExtensionPointCommand",
|
|
190
|
-
_0: encodeExtensionPointCommand(command, id, extensionPointName, "Publish PluginExtensionPoint command")
|
|
184
|
+
_0: encodeExtensionPointCommand(command, id, extensionPointName, "Publish PluginExtensionPoint command", index)
|
|
191
185
|
};
|
|
192
186
|
} else {
|
|
193
187
|
return {
|
|
194
188
|
TAG: "AbstractPublishExtensionPointCommand",
|
|
195
189
|
_0: extensionPointName,
|
|
196
|
-
_1: encodeExtensionPointCommand(command, id, extensionPointName, "Publish ExtensionPoint command")
|
|
190
|
+
_1: encodeExtensionPointCommand(command, id, extensionPointName, "Publish ExtensionPoint command", index)
|
|
197
191
|
};
|
|
198
192
|
}
|
|
199
193
|
case "ForwardCommand" :
|
|
@@ -202,7 +196,7 @@ function Make(MappingImpl) {
|
|
|
202
196
|
return {
|
|
203
197
|
TAG: "AbstractPublishExtensionPointCommand",
|
|
204
198
|
_0: extensionPointName$1,
|
|
205
|
-
_1: encodeExtensionPointCommandJson(match.commandJson, match.id, extensionPointName$1, "Forward ExtensionPoint command")
|
|
199
|
+
_1: encodeExtensionPointCommandJson(match.commandJson, match.id, extensionPointName$1, "Forward ExtensionPoint command", index)
|
|
206
200
|
};
|
|
207
201
|
case "HandleDirective" :
|
|
208
202
|
let directive = x._1;
|
|
@@ -223,16 +217,16 @@ function Make(MappingImpl) {
|
|
|
223
217
|
}
|
|
224
218
|
let match = Message$Reventless.decodeEvent$p(extra, Delegate.Id.schema, Delegate.eventSchema);
|
|
225
219
|
let meta = match.meta;
|
|
226
|
-
let encodeExtensionPointCommandJson = (commandJson, id, extensionPointName, action) => {
|
|
220
|
+
let encodeExtensionPointCommandJson = (commandJson, id, extensionPointName, action, index) => {
|
|
227
221
|
compLog(`Extension(` + delegateName + `)`, action + `: ` + AnsiStyle$Reventless.bold(Message$Reventless.variantNameOfJson(commandJson)) + `(` + id + `)`);
|
|
228
222
|
return {
|
|
229
223
|
id: id,
|
|
230
|
-
meta:
|
|
224
|
+
meta: Message$ReventlessInfra.deriveStableMeta(meta, extensionPointName, index, undefined),
|
|
231
225
|
commandJson: commandJson
|
|
232
226
|
};
|
|
233
227
|
};
|
|
234
|
-
let encodeExtensionPointCommand = (command, id, extensionPointName, action) => encodeExtensionPointCommandJson(Message$Reventless.encode(command, Spec.commandSchema), id, extensionPointName, action);
|
|
235
|
-
return mapOutgoingEventImpl(Delegate.Id.toString(match.id), match.event, meta, extra$1).map(x => {
|
|
228
|
+
let encodeExtensionPointCommand = (command, id, extensionPointName, action, index) => encodeExtensionPointCommandJson(Message$Reventless.encode(command, Spec.commandSchema), id, extensionPointName, action, index);
|
|
229
|
+
return mapOutgoingEventImpl(Delegate.Id.toString(match.id), match.event, meta, extra$1).map((x, index) => {
|
|
236
230
|
switch (x.TAG) {
|
|
237
231
|
case "PublishExtensionPointCommand" :
|
|
238
232
|
let command = x._1;
|
|
@@ -240,13 +234,13 @@ function Make(MappingImpl) {
|
|
|
240
234
|
if (Spec.name === PluginExtensionPointSpec$ReventlessInfra.name) {
|
|
241
235
|
return {
|
|
242
236
|
TAG: "AbstractPublishPluginExtensionPointCommand",
|
|
243
|
-
_0: encodeExtensionPointCommand(command, id, extensionPointName, "Publish PluginExtensionPoint command")
|
|
237
|
+
_0: encodeExtensionPointCommand(command, id, extensionPointName, "Publish PluginExtensionPoint command", index)
|
|
244
238
|
};
|
|
245
239
|
} else {
|
|
246
240
|
return {
|
|
247
241
|
TAG: "AbstractPublishExtensionPointCommand",
|
|
248
242
|
_0: extensionPointName,
|
|
249
|
-
_1: encodeExtensionPointCommand(command, id, extensionPointName, "Publish ExtensionPoint command")
|
|
243
|
+
_1: encodeExtensionPointCommand(command, id, extensionPointName, "Publish ExtensionPoint command", index)
|
|
250
244
|
};
|
|
251
245
|
}
|
|
252
246
|
case "ForwardCommand" :
|
|
@@ -255,7 +249,7 @@ function Make(MappingImpl) {
|
|
|
255
249
|
return {
|
|
256
250
|
TAG: "AbstractPublishExtensionPointCommand",
|
|
257
251
|
_0: extensionPointName$1,
|
|
258
|
-
_1: encodeExtensionPointCommandJson(match.commandJson, match.id, extensionPointName$1, "Forward ExtensionPoint command")
|
|
252
|
+
_1: encodeExtensionPointCommandJson(match.commandJson, match.id, extensionPointName$1, "Forward ExtensionPoint command", index)
|
|
259
253
|
};
|
|
260
254
|
case "HandleDirective" :
|
|
261
255
|
let directive = x._1;
|
|
@@ -170,7 +170,10 @@ module Make = (MappingImpl: Mapping): (
|
|
|
170
170
|
CommandTopic.reference: reference,
|
|
171
171
|
command: {Reventless.Message.id: id, command, meta},
|
|
172
172
|
}) =>
|
|
173
|
-
mapIncomingEventImpl(id->Reventless.Id.String.toString, command, meta)->Array.
|
|
173
|
+
mapIncomingEventImpl(id->Reventless.Id.String.toString, command, meta)->Array.mapWithIndex((
|
|
174
|
+
x,
|
|
175
|
+
index,
|
|
176
|
+
) =>
|
|
174
177
|
switch x {
|
|
175
178
|
| PublishCommand(targetId, targetCmd) =>
|
|
176
179
|
let cmdJson = targetCmd->Reventless.Message.encode(Delegate.commandSchema)
|
|
@@ -186,11 +189,7 @@ module Make = (MappingImpl: Mapping): (
|
|
|
186
189
|
reference,
|
|
187
190
|
{
|
|
188
191
|
id: targetId,
|
|
189
|
-
meta:
|
|
190
|
-
...meta,
|
|
191
|
-
service: Delegate.name,
|
|
192
|
-
msgId: Message.uuid(),
|
|
193
|
-
},
|
|
192
|
+
meta: Message.deriveStableMeta(~parent=meta, ~service=Delegate.name, ~index),
|
|
194
193
|
commandJson: targetCmd->Reventless.Message.encode(Delegate.commandSchema),
|
|
195
194
|
},
|
|
196
195
|
)
|
|
@@ -230,12 +229,15 @@ module Make = (MappingImpl: Mapping): (
|
|
|
230
229
|
} else {
|
|
231
230
|
let {id, meta, event} =
|
|
232
231
|
targetEventJson'->Reventless.Message.decodeEvent'(Delegate.Id.schema, Delegate.eventSchema)
|
|
232
|
+
// The published event is derived from the Delegate's: `index` is the
|
|
233
|
+
// action's position, so a stream redelivery of the same event publishes
|
|
234
|
+
// the same `msgId`s.
|
|
233
235
|
mapOutgoingEventImpl(
|
|
234
236
|
id->Delegate.Id.toString,
|
|
235
237
|
event,
|
|
236
238
|
meta,
|
|
237
239
|
queryEngine,
|
|
238
|
-
)->Array.
|
|
240
|
+
)->Array.mapWithIndex((eventAction, index) =>
|
|
239
241
|
switch eventAction {
|
|
240
242
|
| PublishEvent(id, event) =>
|
|
241
243
|
let eventJson = event->Reventless.Message.encode(Spec.eventSchema)
|
|
@@ -245,11 +247,7 @@ module Make = (MappingImpl: Mapping): (
|
|
|
245
247
|
->Reventless.Message.variantNameOfJson
|
|
246
248
|
->Reventless.AnsiStyle.bold}(${id})`,
|
|
247
249
|
)
|
|
248
|
-
let meta =
|
|
249
|
-
...meta,
|
|
250
|
-
service: Spec.name,
|
|
251
|
-
msgId: Message.uuid(),
|
|
252
|
-
}
|
|
250
|
+
let meta = Message.deriveStableMeta(~parent=meta, ~service=Spec.name, ~index)
|
|
253
251
|
let eventJson' = Reventless.Message.composeEventJson'(id, meta, eventJson)
|
|
254
252
|
AbstractPublishEvent(id, meta, eventJson')
|
|
255
253
|
| PublishEventAsync(promise) =>
|
|
@@ -262,7 +260,8 @@ module Make = (MappingImpl: Mapping): (
|
|
|
262
260
|
->Reventless.Message.variantNameOfJson
|
|
263
261
|
->Reventless.AnsiStyle.bold}(${id}) (async)`,
|
|
264
262
|
)
|
|
265
|
-
let
|
|
263
|
+
let meta = Message.deriveStableMeta(~parent=meta, ~service=Spec.name, ~index)
|
|
264
|
+
let eventJson' = Reventless.Message.composeEventJson'(id, meta, eventJson)
|
|
266
265
|
(id, meta, eventJson')
|
|
267
266
|
}
|
|
268
267
|
AbstractPublishEventAsync(promise->toEvent')
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
2
|
|
|
3
|
-
import * as Uuid from "uuid";
|
|
4
3
|
import * as Stdlib_JSON from "@rescript/runtime/lib/es6/Stdlib_JSON.js";
|
|
5
4
|
import * as Id$Reventless from "@reventlessdev/reventless-spec/src/types/Id.res.mjs";
|
|
6
5
|
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
@@ -8,6 +7,7 @@ import * as Effect from "effect/Effect";
|
|
|
8
7
|
import * as DcbTag$Reventless from "@reventlessdev/reventless-spec/src/components/DcbTag.res.mjs";
|
|
9
8
|
import * as Message$Reventless from "@reventlessdev/reventless-spec/src/types/Message.res.mjs";
|
|
10
9
|
import * as AnsiStyle$Reventless from "@reventlessdev/reventless-spec/src/AnsiStyle.res.mjs";
|
|
10
|
+
import * as Message$ReventlessInfra from "./Message.res.mjs";
|
|
11
11
|
|
|
12
12
|
function Make(MappingImpl) {
|
|
13
13
|
let Spec = MappingImpl.ExtensionPoint;
|
|
@@ -22,20 +22,19 @@ function Make(MappingImpl) {
|
|
|
22
22
|
let reference = param.reference;
|
|
23
23
|
let match = param.command;
|
|
24
24
|
let meta = match.meta;
|
|
25
|
-
return mapIncomingEventImpl(Id$Reventless.$$String.toString(match.id), match.command, meta).map(x => {
|
|
25
|
+
return mapIncomingEventImpl(Id$Reventless.$$String.toString(match.id), match.command, meta).map((x, index) => {
|
|
26
26
|
if (x.TAG === "PublishCommand") {
|
|
27
27
|
let targetCmd = x._1;
|
|
28
28
|
let targetId = x._0;
|
|
29
29
|
let cmdJson = Message$Reventless.encode(targetCmd, Delegate.commandSchema);
|
|
30
30
|
compLog(`ExtensionPoint(` + extensionPointName + `)`, `EP→` + delegateName + `: ` + AnsiStyle$Reventless.bold(Message$Reventless.variantNameOfJson(cmdJson)) + `(` + targetId + `)`);
|
|
31
|
-
let newrecord = {...meta};
|
|
32
31
|
return {
|
|
33
32
|
TAG: "AbstractPublishCommand",
|
|
34
33
|
_0: delegateName,
|
|
35
34
|
_1: reference,
|
|
36
35
|
_2: {
|
|
37
36
|
id: targetId,
|
|
38
|
-
meta:
|
|
37
|
+
meta: Message$ReventlessInfra.deriveStableMeta(meta, Delegate.name, index, undefined),
|
|
39
38
|
commandJson: Message$Reventless.encode(targetCmd, Delegate.commandSchema)
|
|
40
39
|
}
|
|
41
40
|
};
|
|
@@ -59,20 +58,18 @@ function Make(MappingImpl) {
|
|
|
59
58
|
}
|
|
60
59
|
let match = Message$Reventless.decodeEvent$p(extra, Delegate.Id.schema, Delegate.eventSchema);
|
|
61
60
|
let meta = match.meta;
|
|
62
|
-
return mapOutgoingEventImpl(Delegate.Id.toString(match.id), match.event, meta, extra$3).map(eventAction => {
|
|
61
|
+
return mapOutgoingEventImpl(Delegate.Id.toString(match.id), match.event, meta, extra$3).map((eventAction, index) => {
|
|
63
62
|
switch (eventAction.TAG) {
|
|
64
63
|
case "PublishEvent" :
|
|
65
64
|
let id = eventAction._0;
|
|
66
65
|
let eventJson = Message$Reventless.encode(eventAction._1, Spec.eventSchema);
|
|
67
66
|
compLog(`ExtensionPoint(` + extensionPointName + `)`, `mapped ` + delegateName + ` → ` + AnsiStyle$Reventless.bold(Message$Reventless.variantNameOfJson(eventJson)) + `(` + id + `)`);
|
|
68
|
-
let
|
|
69
|
-
|
|
70
|
-
newrecord.service = Spec.name;
|
|
71
|
-
let eventJson$p = Message$Reventless.composeEventJson$p(id, newrecord, eventJson);
|
|
67
|
+
let meta$1 = Message$ReventlessInfra.deriveStableMeta(meta, Spec.name, index, undefined);
|
|
68
|
+
let eventJson$p = Message$Reventless.composeEventJson$p(id, meta$1, eventJson);
|
|
72
69
|
return {
|
|
73
70
|
TAG: "AbstractPublishEvent",
|
|
74
71
|
_0: id,
|
|
75
|
-
_1:
|
|
72
|
+
_1: meta$1,
|
|
76
73
|
_2: eventJson$p
|
|
77
74
|
};
|
|
78
75
|
case "PublishEventAsync" :
|
|
@@ -81,10 +78,11 @@ function Make(MappingImpl) {
|
|
|
81
78
|
let id = match[0];
|
|
82
79
|
let eventJson = Message$Reventless.encode(match[1], Spec.eventSchema);
|
|
83
80
|
compLog(`ExtensionPoint(` + extensionPointName + `)`, `mapped ` + delegateName + ` → ` + AnsiStyle$Reventless.bold(Message$Reventless.variantNameOfJson(eventJson)) + `(` + id + `) (async)`);
|
|
84
|
-
let
|
|
81
|
+
let meta$2 = Message$ReventlessInfra.deriveStableMeta(meta, Spec.name, index, undefined);
|
|
82
|
+
let eventJson$p = Message$Reventless.composeEventJson$p(id, meta$2, eventJson);
|
|
85
83
|
return [
|
|
86
84
|
id,
|
|
87
|
-
meta,
|
|
85
|
+
meta$2,
|
|
88
86
|
eventJson$p
|
|
89
87
|
];
|
|
90
88
|
};
|
|
@@ -113,4 +111,4 @@ function Make(MappingImpl) {
|
|
|
113
111
|
export {
|
|
114
112
|
Make,
|
|
115
113
|
}
|
|
116
|
-
/*
|
|
114
|
+
/* Id-Reventless Not a pure module */
|
package/src/types/Message.res
CHANGED
|
@@ -1,3 +1,65 @@
|
|
|
1
1
|
/** Generates a new UUID v4 string. */
|
|
2
2
|
@module("uuid") @val
|
|
3
3
|
external uuid: unit => string = "v4"
|
|
4
|
+
|
|
5
|
+
/** The namespace `deriveStableMeta` mints ids in: one fixed value, so the same
|
|
6
|
+
input gives the same id in every process. */
|
|
7
|
+
let derivedIdNamespace = Uuid.Namespace.custom("c4e9c2e6-8b3f-4f0e-9a52-6d2b4c7e1a90")
|
|
8
|
+
|
|
9
|
+
/** The header `deriveStableMeta` sets, which marks a message whose `msgId` is a
|
|
10
|
+
function of its input. A handler reads it as "a repeat of this command can be
|
|
11
|
+
recognized", and `deriveMeta` strips it so the mark never outlives the id. */
|
|
12
|
+
let stableIdHeader = "reventless-stable-id"
|
|
13
|
+
|
|
14
|
+
/** Whether this message's `msgId` was derived from its input, so that a second
|
|
15
|
+
delivery carries the same id. */
|
|
16
|
+
let hasStableMsgId = (meta: Reventless.Message.meta): bool =>
|
|
17
|
+
meta.headers->Option.flatMap(h => h->Dict.get(stableIdHeader))->Option.isSome
|
|
18
|
+
|
|
19
|
+
let withStableIdHeader = (headers: option<dict<string>>): dict<string> => {
|
|
20
|
+
let out = headers->Option.mapOr(Dict.make(), Dict.copy)
|
|
21
|
+
out->Dict.set(stableIdHeader, "true")
|
|
22
|
+
out
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/** The inherited headers without the stable-id mark: a message whose id is fresh
|
|
26
|
+
must not claim otherwise. `None` when nothing is left. */
|
|
27
|
+
let withoutStableIdHeader = (headers: option<dict<string>>): option<dict<string>> =>
|
|
28
|
+
switch headers {
|
|
29
|
+
| Some(h) if h->Dict.has(stableIdHeader) =>
|
|
30
|
+
let out = h->Dict.copy
|
|
31
|
+
out->Dict.delete(stableIdHeader)
|
|
32
|
+
out->Dict.keysToArray->Array.length == 0 ? None : Some(out)
|
|
33
|
+
| other => other
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
The meta of a message a mapping derives from `parent`.
|
|
38
|
+
|
|
39
|
+
The envelope is the one `deriveMeta` documents: `causationId` is the parent's
|
|
40
|
+
`msgId`, `correlationId` and the tracing fields are inherited, `service` is the
|
|
41
|
+
emitter. The `msgId` is a function of the input: the parent's `msgId`, the
|
|
42
|
+
emitter and the action's `index` in the mapping's result (`item` for one command
|
|
43
|
+
of a multi-command action). A mapping run again on the same input produces the
|
|
44
|
+
same ids, which is what lets a handler recognize a redelivered fact; two inputs
|
|
45
|
+
or two actions of one input never collide. The `stableIdHeader` marks the result.
|
|
46
|
+
*/
|
|
47
|
+
let deriveStableMeta = (
|
|
48
|
+
~parent: Reventless.Message.meta,
|
|
49
|
+
~service,
|
|
50
|
+
~index,
|
|
51
|
+
~item=0,
|
|
52
|
+
): Reventless.Message.meta => {
|
|
53
|
+
service,
|
|
54
|
+
time: Date.make()->Date.toISOString,
|
|
55
|
+
msgId: Uuid.v5(
|
|
56
|
+
~name=`${parent.msgId}/${service}/${index->Int.toString}/${item->Int.toString}`,
|
|
57
|
+
~namespace=derivedIdNamespace,
|
|
58
|
+
),
|
|
59
|
+
correlationId: parent.correlationId,
|
|
60
|
+
causationId: parent.msgId,
|
|
61
|
+
user: ?parent.user,
|
|
62
|
+
traceparent: ?parent.traceparent,
|
|
63
|
+
schemaVersion: ?parent.schemaVersion,
|
|
64
|
+
headers: withStableIdHeader(parent.headers),
|
|
65
|
+
}
|
|
@@ -1,2 +1,60 @@
|
|
|
1
1
|
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
-
|
|
2
|
+
|
|
3
|
+
import * as Uuid from "uuid";
|
|
4
|
+
import * as Stdlib_Dict from "@rescript/runtime/lib/es6/Stdlib_Dict.js";
|
|
5
|
+
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
6
|
+
|
|
7
|
+
let derivedIdNamespace = "c4e9c2e6-8b3f-4f0e-9a52-6d2b4c7e1a90";
|
|
8
|
+
|
|
9
|
+
let stableIdHeader = "reventless-stable-id";
|
|
10
|
+
|
|
11
|
+
function hasStableMsgId(meta) {
|
|
12
|
+
return Stdlib_Option.isSome(Stdlib_Option.flatMap(meta.headers, h => h[stableIdHeader]));
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function withStableIdHeader(headers) {
|
|
16
|
+
let out = Stdlib_Option.mapOr(headers, {}, prim => Object.assign({}, prim));
|
|
17
|
+
out[stableIdHeader] = "true";
|
|
18
|
+
return out;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function withoutStableIdHeader(headers) {
|
|
22
|
+
if (headers === undefined) {
|
|
23
|
+
return headers;
|
|
24
|
+
}
|
|
25
|
+
if (!(stableIdHeader in headers)) {
|
|
26
|
+
return headers;
|
|
27
|
+
}
|
|
28
|
+
let out = Object.assign({}, headers);
|
|
29
|
+
Stdlib_Dict.$$delete(out, stableIdHeader);
|
|
30
|
+
if (Object.keys(out).length === 0) {
|
|
31
|
+
return;
|
|
32
|
+
} else {
|
|
33
|
+
return out;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function deriveStableMeta(parent, service, index, itemOpt) {
|
|
38
|
+
let item = itemOpt !== undefined ? itemOpt : 0;
|
|
39
|
+
return {
|
|
40
|
+
service: service,
|
|
41
|
+
time: new Date().toISOString(),
|
|
42
|
+
user: parent.user,
|
|
43
|
+
msgId: Uuid.v5(parent.msgId + `/` + service + `/` + index.toString() + `/` + item.toString(), derivedIdNamespace),
|
|
44
|
+
correlationId: parent.correlationId,
|
|
45
|
+
causationId: parent.msgId,
|
|
46
|
+
traceparent: parent.traceparent,
|
|
47
|
+
schemaVersion: parent.schemaVersion,
|
|
48
|
+
headers: withStableIdHeader(parent.headers)
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export {
|
|
53
|
+
derivedIdNamespace,
|
|
54
|
+
stableIdHeader,
|
|
55
|
+
hasStableMsgId,
|
|
56
|
+
withStableIdHeader,
|
|
57
|
+
withoutStableIdHeader,
|
|
58
|
+
deriveStableMeta,
|
|
59
|
+
}
|
|
60
|
+
/* uuid Not a pure module */
|