@reventlessdev/reventless-core 3.0.0-alpha.294 → 3.0.0-alpha.296

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. package/CHANGELOG.md +39 -0
  2. package/package.json +8 -8
  3. package/src/admin/Platform_ComponentDefinitionsApi.res +3 -1
  4. package/src/admin/Platform_ComponentDefinitionsApi.res.mjs +5 -1
  5. package/src/components/AutomationSlice/AutomationSlice.res +2 -0
  6. package/src/components/AutomationSlice/AutomationSlice_Builder.res +133 -8
  7. package/src/components/AutomationSlice/AutomationSlice_Builder.res.mjs +89 -7
  8. package/src/components/AutomationSlice/AutomationSlice_Callback.res +136 -3
  9. package/src/components/AutomationSlice/AutomationSlice_Callback.res.mjs +122 -4
  10. package/src/components/AutomationSlice/AutomationSlice_Route.res +3 -1
  11. package/src/components/AutomationSlice/AutomationSlice_Route.res.mjs +2 -1
  12. package/src/components/AutomationSlice/AutomationSlice_Schedules.res +149 -0
  13. package/src/components/AutomationSlice/AutomationSlice_Schedules.res.mjs +193 -0
  14. package/src/components/Dcb/Dcb_Builder.res +28 -4
  15. package/src/components/Dcb/Dcb_Builder.res.mjs +27 -5
  16. package/src/plugin/component/Plugin_Builder.res +10 -3
  17. package/src/plugin/component/Plugin_Builder.res.mjs +8 -2
  18. package/src/plugin/component/Plugin_Structure.res +7 -0
  19. package/src/plugin/component/Plugin_Structure.res.mjs +5 -2
  20. package/src/plugin/connect/PluginExtensionPoint_Plugin.res +1 -1
  21. package/src/plugin/connect/PluginExtensionPoint_Plugin.res.mjs +1 -1
  22. package/src/util/ScheduleOps.res +1 -55
  23. package/src/util/ScheduleOps.res.mjs +10 -57
  24. package/src/util/ScheduleTime.res +266 -0
  25. package/src/util/ScheduleTime.res.mjs +451 -0
  26. package/tests/admin/AdminApiSchemaDriftTest.res +1 -0
  27. package/tests/admin/AdminApiSchemaDriftTest.res.mjs +4 -1
  28. package/tests/automationslice/AutomationSliceSchedulesTest.res +143 -0
  29. package/tests/automationslice/AutomationSliceSchedulesTest.res.mjs +247 -0
  30. package/tests/util/ScheduleTimeTest.res +256 -0
  31. package/tests/util/ScheduleTimeTest.res.mjs +532 -0
@@ -0,0 +1,193 @@
1
+ // Generated by ReScript, PLEASE EDIT WITH CARE
2
+
3
+ import * as Sury from "sury";
4
+ import * as Stdlib_Dict from "@rescript/runtime/lib/es6/Stdlib_Dict.js";
5
+ import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
6
+ import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
7
+ import * as Clock$Reventless from "@reventlessdev/reventless-spec/src/components/Clock.res.mjs";
8
+ import * as Primitive_object from "@rescript/runtime/lib/es6/Primitive_object.js";
9
+ import * as Schedule$Reventless from "@reventlessdev/reventless-spec/src/types/Schedule.res.mjs";
10
+ import * as Util_Sury$Reventless from "@reventlessdev/reventless-spec/src/util/Util_Sury.res.mjs";
11
+ import * as ScheduleTime$ReventlessCore from "../../util/ScheduleTime.res.mjs";
12
+
13
+ let declared = "declared";
14
+
15
+ let rowSchema = Sury.$schema(s => ({
16
+ key: s.m(Sury.string),
17
+ time: s.m(Sury.$option(Sury.string)),
18
+ setBy: s.m(Sury.string),
19
+ setAt: s.m(Sury.string)
20
+ }));
21
+
22
+ function encodeTime(time) {
23
+ return JSON.stringify(Util_Sury$Reventless.toJson(time, Schedule$Reventless.timeSchema));
24
+ }
25
+
26
+ function decodeTime(text) {
27
+ return Util_Sury$Reventless.fromJson(JSON.parse(text), Schedule$Reventless.timeSchema);
28
+ }
29
+
30
+ function timeOf(row) {
31
+ return Stdlib_Option.map(row.time, decodeTime);
32
+ }
33
+
34
+ function iso(millis) {
35
+ return new Date(millis).toISOString();
36
+ }
37
+
38
+ function clearRow(rows, key, setBy, setAt) {
39
+ if (key === Clock$Reventless.defaultKey) {
40
+ rows[key] = {
41
+ key: key,
42
+ setBy: setBy,
43
+ setAt: setAt
44
+ };
45
+ return;
46
+ } else {
47
+ return Stdlib_Dict.$$delete(rows, key);
48
+ }
49
+ }
50
+
51
+ function apply(rows, change, setBy, recordedAt) {
52
+ if (change.TAG === "Set") {
53
+ let wanted = change.time;
54
+ let key = change.key;
55
+ let errs = ScheduleTime$ReventlessCore.errors(wanted);
56
+ if (errs.length !== 0) {
57
+ return {
58
+ TAG: "Error",
59
+ _0: `schedule ` + key + `: ` + errs.join("; ")
60
+ };
61
+ }
62
+ let resolved = ScheduleTime$ReventlessCore.resolveOnce(wanted, recordedAt);
63
+ rows[key] = {
64
+ key: key,
65
+ time: encodeTime(resolved),
66
+ setBy: setBy,
67
+ setAt: new Date(recordedAt).toISOString()
68
+ };
69
+ return {
70
+ TAG: "Ok",
71
+ _0: {
72
+ TAG: "Put",
73
+ key: key,
74
+ time: resolved
75
+ }
76
+ };
77
+ }
78
+ let cleared = change.key;
79
+ clearRow(rows, cleared, setBy, new Date(recordedAt).toISOString());
80
+ return {
81
+ TAG: "Ok",
82
+ _0: {
83
+ TAG: "Remove",
84
+ key: cleared
85
+ }
86
+ };
87
+ }
88
+
89
+ function fired(rows, key) {
90
+ Stdlib_Option.forEach(rows[key], row => {
91
+ let match = Stdlib_Option.map(row.time, decodeTime);
92
+ if (match === undefined) {
93
+ return;
94
+ }
95
+ switch (match.TAG) {
96
+ case "Every" :
97
+ case "Calendar" :
98
+ return;
99
+ case "Once" :
100
+ return clearRow(rows, key, row.setBy, row.setAt);
101
+ }
102
+ });
103
+ }
104
+
105
+ function declare(rows, declaredTime, now) {
106
+ let match = rows[Clock$Reventless.defaultKey];
107
+ if (declaredTime !== undefined) {
108
+ if (match !== undefined && !(match.setBy === declared && Primitive_object.notequal(match.time, encodeTime(declaredTime)))) {
109
+ return;
110
+ } else {
111
+ rows[Clock$Reventless.defaultKey] = {
112
+ key: Clock$Reventless.defaultKey,
113
+ time: encodeTime(declaredTime),
114
+ setBy: declared,
115
+ setAt: new Date(now).toISOString()
116
+ };
117
+ return;
118
+ }
119
+ } else if (match !== undefined && match.setBy === declared) {
120
+ return Stdlib_Dict.$$delete(rows, Clock$Reventless.defaultKey);
121
+ } else {
122
+ return;
123
+ }
124
+ }
125
+
126
+ function isPast(time, now) {
127
+ switch (time.TAG) {
128
+ case "Every" :
129
+ case "Calendar" :
130
+ return false;
131
+ case "Once" :
132
+ return Stdlib_Option.isNone(ScheduleTime$ReventlessCore.nextFiring(time, now));
133
+ }
134
+ }
135
+
136
+ async function reconcile(rows, platform, declaredTime, now) {
137
+ declare(rows, declaredTime, now);
138
+ let live = Stdlib_Array.filterMap(Object.values(rows), row => {
139
+ let time = Stdlib_Option.map(row.time, decodeTime);
140
+ if (time !== undefined) {
141
+ if (isPast(time, now)) {
142
+ clearRow(rows, row.key, row.setBy, row.setAt);
143
+ return;
144
+ } else {
145
+ return [
146
+ row,
147
+ time
148
+ ];
149
+ }
150
+ }
151
+ });
152
+ let held = await platform.names();
153
+ for (let i = 0, i_finish = live.length; i < i_finish; ++i) {
154
+ let match = live[i];
155
+ let row = match[0];
156
+ if (row.setBy === declared || !held.includes(platform.nameOf(row.key))) {
157
+ await platform.put(row.key, match[1]);
158
+ }
159
+ }
160
+ let wanted = live.map(param => platform.nameOf(param[0].key));
161
+ let extra = held.filter(name => !wanted.includes(name));
162
+ for (let i$1 = 0, i_finish$1 = extra.length; i$1 < i_finish$1; ++i$1) {
163
+ await platform.removeName(extra[i$1]);
164
+ }
165
+ }
166
+
167
+ async function tell(platform, changes) {
168
+ for (let i = 0, i_finish = changes.length; i < i_finish; ++i) {
169
+ let match = changes[i];
170
+ if (match.TAG === "Put") {
171
+ await platform.put(match.key, match.time);
172
+ } else {
173
+ await platform.removeName(platform.nameOf(match.key));
174
+ }
175
+ }
176
+ }
177
+
178
+ export {
179
+ declared,
180
+ rowSchema,
181
+ encodeTime,
182
+ decodeTime,
183
+ timeOf,
184
+ iso,
185
+ clearRow,
186
+ apply,
187
+ fired,
188
+ declare,
189
+ isPast,
190
+ reconcile,
191
+ tell,
192
+ }
193
+ /* rowSchema Not a pure module */
@@ -188,11 +188,13 @@ module Make = (
188
188
  // its own `sourceEventSchema`. Validation contributes one entry per
189
189
  // (slice, source) pair so unknown variants surface against the right
190
190
  // mapping context.
191
+ // The Clock's ticks come from the slice's schedules, not from a slice.
191
192
  automationSlices->Array.flatMap((module(A: AutomationSlice.T)) =>
192
- A.Automation.mappings->Array.map((module(M: A.Automation.Mapping)) => (
193
- A.Spec.name,
194
- M.sourceEventSchema->S.castToUnknown,
195
- ))
193
+ A.Automation.mappings->Array.filterMap((module(M: A.Automation.Mapping)) =>
194
+ M.sourceName == Reventless.Clock.name
195
+ ? None
196
+ : Some((A.Spec.name, M.sourceEventSchema->S.castToUnknown))
197
+ )
196
198
  ),
197
199
  )
198
200
  ->Array.concat(
@@ -664,6 +666,12 @@ module Make = (
664
666
  automationSlices->Array.forEach((module(A: AutomationSlice.T)) => {
665
667
  let qn = Api_Naming.queryFieldNamesForSliceQueryDb(~plugin=name, ~queryDbName=A.queryDbName)
666
668
  Plugin_Helpers.queryFieldNamesRegistry->Dict.set(A.queryDbName, qn)
669
+ A.schedulesDbName->Option.forEach(queryDbName =>
670
+ Plugin_Helpers.queryFieldNamesRegistry->Dict.set(
671
+ queryDbName,
672
+ Api_Naming.queryFieldNamesForSliceQueryDb(~plugin=name, ~queryDbName),
673
+ )
674
+ )
667
675
  })
668
676
 
669
677
  outboundTranslationSlices->Array.forEach((module(O: OutboundTranslationSlice.T)) => {
@@ -1144,6 +1152,21 @@ module Make = (
1144
1152
  }
1145
1153
  })
1146
1154
 
1155
+ // A scheduled slice's schedules: when it runs, and who set it.
1156
+ let scheduleEntries = automationSlices->Array.filterMap((module(A: AutomationSlice.T)) =>
1157
+ A.schedulesDbName->Option.map(queryDbName => {
1158
+ let qn = Api_Naming.queryFieldNamesForSliceQueryDb(~plugin=name, ~queryDbName)
1159
+ {
1160
+ ReventlessInfra.Api.singleFieldName: qn.singleFieldName,
1161
+ listFieldName: qn.listFieldName,
1162
+ returnTypeName: qn.returnTypeName,
1163
+ stateSchema: AutomationSlice_Schedules.rowSchema->S.castToUnknown,
1164
+ authorization: None,
1165
+ connectionSpec: true,
1166
+ }
1167
+ })
1168
+ )
1169
+
1147
1170
  let outboundEntries =
1148
1171
  outboundTranslationSlices->Array.map((module(O: OutboundTranslationSlice.T)) => {
1149
1172
  let qn = Api_Naming.queryFieldNamesForSliceQueryDb(
@@ -1234,6 +1257,7 @@ module Make = (
1234
1257
  mutationEntries: Array.concat(mutationEntriesFromSlices, mutationEntriesFromInboundSlices),
1235
1258
  queryEntries: stateViewEntries
1236
1259
  ->Array.concat(automationEntries)
1260
+ ->Array.concat(scheduleEntries)
1237
1261
  ->Array.concat(outboundEntries)
1238
1262
  ->Array.concat(inboundEntries),
1239
1263
  eventLogEntries: if allProducedSchemas->Array.length > 0 {
@@ -8,6 +8,7 @@ import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
8
8
  import * as Effect from "effect/Effect";
9
9
  import * as Pulumi from "@pulumi/pulumi";
10
10
  import * as Stdlib_JsError from "@rescript/runtime/lib/es6/Stdlib_JsError.js";
11
+ import * as Clock$Reventless from "@reventlessdev/reventless-spec/src/components/Clock.res.mjs";
11
12
  import * as Primitive_object from "@rescript/runtime/lib/es6/Primitive_object.js";
12
13
  import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
13
14
  import * as DcbTag$Reventless from "@reventlessdev/reventless-spec/src/components/DcbTag.res.mjs";
@@ -25,6 +26,7 @@ import * as Plugin_Structure$ReventlessCore from "../../plugin/component/Plugin_
25
26
  import * as DcbEventLog_Builder$ReventlessCore from "../DcbEventLog/DcbEventLog_Builder.res.mjs";
26
27
  import * as CommandTopic_Builder$ReventlessCore from "../CommandTopic/CommandTopic_Builder.res.mjs";
27
28
  import * as AutomationSlice_Callback$ReventlessCore from "../AutomationSlice/AutomationSlice_Callback.res.mjs";
29
+ import * as AutomationSlice_Schedules$ReventlessCore from "../AutomationSlice/AutomationSlice_Schedules.res.mjs";
28
30
  import * as CommandGenerator_Callback$ReventlessCore from "../CommandGenerator/CommandGenerator_Callback.res.mjs";
29
31
  import * as InboundTranslationSlice_Callback$ReventlessCore from "../InboundTranslationSlice/InboundTranslationSlice_Callback.res.mjs";
30
32
  import * as OutboundTranslationSlice_Callback$ReventlessCore from "../OutboundTranslationSlice/OutboundTranslationSlice_Callback.res.mjs";
@@ -150,10 +152,16 @@ function Make(DcbEventLogStorage) {
150
152
  ]).concat(stateViewSlices.map(V => [
151
153
  V.Spec.name,
152
154
  V.Spec.consumedEventSchema
153
- ])).concat(automationSlices.flatMap(A => A.Automation.mappings.map(M => [
154
- A.Spec.name,
155
- M.sourceEventSchema
156
- ]))).concat(outboundTranslationSlices.map(O => [
155
+ ])).concat(automationSlices.flatMap(A => Stdlib_Array.filterMap(A.Automation.mappings, M => {
156
+ if (M.sourceName === Clock$Reventless.name) {
157
+ return;
158
+ } else {
159
+ return [
160
+ A.Spec.name,
161
+ M.sourceEventSchema
162
+ ];
163
+ }
164
+ }))).concat(outboundTranslationSlices.map(O => [
157
165
  O.Spec.name,
158
166
  O.Spec.consumedEventSchema
159
167
  ]));
@@ -352,6 +360,9 @@ function Make(DcbEventLogStorage) {
352
360
  automationSlices.forEach(A => {
353
361
  let qn = Api_Naming$ReventlessCore.queryFieldNamesForSliceQueryDb(name, A.queryDbName, undefined);
354
362
  Plugin_Helpers$ReventlessCore.queryFieldNamesRegistry[A.queryDbName] = qn;
363
+ Stdlib_Option.forEach(A.schedulesDbName, queryDbName => {
364
+ Plugin_Helpers$ReventlessCore.queryFieldNamesRegistry[queryDbName] = Api_Naming$ReventlessCore.queryFieldNamesForSliceQueryDb(name, queryDbName, undefined);
365
+ });
355
366
  });
356
367
  outboundTranslationSlices.forEach(O => {
357
368
  let qn = Api_Naming$ReventlessCore.queryFieldNamesForSliceQueryDb(name, O.queryDbName, undefined);
@@ -612,6 +623,17 @@ function Make(DcbEventLogStorage) {
612
623
  connectionSpec: true
613
624
  };
614
625
  });
626
+ let scheduleEntries = Stdlib_Array.filterMap(automationSlices, A => Stdlib_Option.map(A.schedulesDbName, queryDbName => {
627
+ let qn = Api_Naming$ReventlessCore.queryFieldNamesForSliceQueryDb(name, queryDbName, undefined);
628
+ return {
629
+ singleFieldName: qn.singleFieldName,
630
+ listFieldName: qn.listFieldName,
631
+ returnTypeName: qn.returnTypeName,
632
+ stateSchema: AutomationSlice_Schedules$ReventlessCore.rowSchema,
633
+ authorization: undefined,
634
+ connectionSpec: true
635
+ };
636
+ }));
615
637
  let outboundEntries = outboundTranslationSlices.map(O => {
616
638
  let qn = Api_Naming$ReventlessCore.queryFieldNamesForSliceQueryDb(name, O.queryDbName, undefined);
617
639
  return {
@@ -655,7 +677,7 @@ function Make(DcbEventLogStorage) {
655
677
  dcbPublishJsons: publishJsons,
656
678
  dcbCommandTopicQueueUrl: dcbCommandTopicQueueUrl,
657
679
  mutationEntries: mutationEntriesFromSlices.concat(mutationEntriesFromInboundSlices),
658
- queryEntries: stateViewEntries.concat(automationEntries).concat(outboundEntries).concat(inboundEntries),
680
+ queryEntries: stateViewEntries.concat(automationEntries).concat(scheduleEntries).concat(outboundEntries).concat(inboundEntries),
659
681
  eventLogEntries: allProducedSchemas.length !== 0 ? [{
660
682
  busKey: name + "DcbEventLog",
661
683
  displayName: name,
@@ -382,7 +382,7 @@ module Make = (
382
382
  // and idResolver paths). Slice output dicts are keyed by Spec.name; the
383
383
  // queryDb name appends a suffix per slice kind:
384
384
  // StateViewSlice — no suffix
385
- // AutomationSlice — "Todo"
385
+ // AutomationSlice — "Todo", and "Schedule" when it maps the Clock
386
386
  // OutboundTranslationSlice — "Todo"
387
387
  // InboundTranslationSlice — "Audit"
388
388
  dcbResult.stateViewSlicesOutputs
@@ -393,7 +393,10 @@ module Make = (
393
393
  ->Array.forEach(((k, v)) => allQueryDbs->Dict.set(k ++ "Audit", v.queryDb))
394
394
  dcbResult.automationSlicesOutputs
395
395
  ->Dict.toArray
396
- ->Array.forEach(((k, v)) => allQueryDbs->Dict.set(k ++ "Todo", v.queryDb))
396
+ ->Array.forEach(((k, v)) => {
397
+ allQueryDbs->Dict.set(k ++ "Todo", v.queryDb)
398
+ v.schedulesDb->Option.forEach(db => allQueryDbs->Dict.set(k ++ "Schedule", db))
399
+ })
397
400
  dcbResult.outboundTranslationSlicesOutputs
398
401
  ->Dict.toArray
399
402
  ->Array.forEach(((k, v)) => allQueryDbs->Dict.set(k ++ "Todo", v.queryDb))
@@ -466,9 +469,13 @@ module Make = (
466
469
  let extractEventTypes = schema => Reventless.DcbTag.extractVariantNames(schema)
467
470
  let routingSchemas: Dict.t<Plugin_Helpers.pluginDeployedSchema> = Dict.make()
468
471
  automationSlices->Array.forEach((module(As: ReventlessInfra.AutomationSlice.T)) => {
469
- // Union of source-event variants across every per-source mapping.
472
+ // Union of source-event variants across every per-source mapping. The
473
+ // Clock's tick is no event of the plugin's; its schedule says when it comes.
470
474
  let consumedEventTypes =
471
475
  As.Automation.mappings
476
+ ->Array.filter((module(M: As.Automation.Mapping)) =>
477
+ M.sourceName != Reventless.Clock.name
478
+ )
472
479
  ->Array.flatMap((module(M: As.Automation.Mapping)) =>
473
480
  extractEventTypes(M.sourceEventSchema->S.castToUnknown)
474
481
  )
@@ -6,6 +6,7 @@ import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
6
6
  import * as Pulumi from "@pulumi/pulumi";
7
7
  import * as Belt_SetString from "@rescript/runtime/lib/es6/Belt_SetString.js";
8
8
  import * as Stdlib_JsError from "@rescript/runtime/lib/es6/Stdlib_JsError.js";
9
+ import * as Clock$Reventless from "@reventlessdev/reventless-spec/src/components/Clock.res.mjs";
9
10
  import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
10
11
  import * as DcbTag$Reventless from "@reventlessdev/reventless-spec/src/components/DcbTag.res.mjs";
11
12
  import * as Plugin$Reventless from "@reventlessdev/reventless-spec/src/components/Plugin.res.mjs";
@@ -284,7 +285,12 @@ function Make(Spec) {
284
285
  allQueryDbs[param[0] + "Audit"] = param[1].queryDb;
285
286
  });
286
287
  Object.entries(dcbResult.automationSlicesOutputs).forEach(param => {
287
- allQueryDbs[param[0] + "Todo"] = param[1].queryDb;
288
+ let v = param[1];
289
+ let k = param[0];
290
+ allQueryDbs[k + "Todo"] = v.queryDb;
291
+ Stdlib_Option.forEach(v.schedulesDb, db => {
292
+ allQueryDbs[k + "Schedule"] = db;
293
+ });
288
294
  });
289
295
  Object.entries(dcbResult.outboundTranslationSlicesOutputs).forEach(param => {
290
296
  allQueryDbs[param[0] + "Todo"] = param[1].queryDb;
@@ -348,7 +354,7 @@ function Make(Spec) {
348
354
  });
349
355
  let routingSchemas = {};
350
356
  automationSlices.forEach(As => {
351
- let consumedEventTypes = Belt_SetString.toArray(Belt_SetString.fromArray(As.Automation.mappings.flatMap(M => DcbTag$Reventless.extractVariantNames(M.sourceEventSchema))));
357
+ let consumedEventTypes = Belt_SetString.toArray(Belt_SetString.fromArray(As.Automation.mappings.filter(M => M.sourceName !== Clock$Reventless.name).flatMap(M => DcbTag$Reventless.extractVariantNames(M.sourceEventSchema))));
352
358
  routingSchemas[As.Spec.name] = {
353
359
  consumedEventTypes: consumedEventTypes,
354
360
  producedCommandTypes: DcbTag$Reventless.extractAllVariantNames(As.Spec.commandSchema),
@@ -1775,6 +1775,8 @@ let make = (
1775
1775
  // contributes that one source's variants.
1776
1776
  let allConsumedVariants =
1777
1777
  AS.Automation.mappings
1778
+ // The Clock's tick is no event of the plugin's; `schedule` says when it comes.
1779
+ ->Array.filter((module(M: AS.Automation.Mapping)) => M.sourceName != Reventless.Clock.name)
1778
1780
  ->Array.flatMap((module(M: AS.Automation.Mapping)) =>
1779
1781
  eventVariantNames(M.sourceEventSchema->S.castToUnknown)
1780
1782
  )
@@ -1788,6 +1790,11 @@ let make = (
1788
1790
  producedCommandTypes: qualify(~prefix=name, commandVariantNames(AS.Spec.commandSchema)),
1789
1791
  targetName: AS.Spec.targetName,
1790
1792
  chapter: chapterOf(AS.Spec.name),
1793
+ schedule: ?(
1794
+ AS.Spec.schedule->Option.map(time =>
1795
+ time->Reventless.Util_Sury.toJson(Reventless.Schedule.timeSchema)->JSON.stringify
1796
+ )
1797
+ ),
1791
1798
  }: Reventless.Plugin.automationSliceDef
1792
1799
  )
1793
1800
  })
@@ -6,12 +6,14 @@ import * as Primitive_int from "@rescript/runtime/lib/es6/Primitive_int.js";
6
6
  import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
7
7
  import * as Belt_SetString from "@rescript/runtime/lib/es6/Belt_SetString.js";
8
8
  import * as Stdlib_JsError from "@rescript/runtime/lib/es6/Stdlib_JsError.js";
9
+ import * as Clock$Reventless from "@reventlessdev/reventless-spec/src/components/Clock.res.mjs";
9
10
  import * as Owner$Reventless from "@reventlessdev/reventless-spec/src/components/Owner.res.mjs";
10
11
  import * as Primitive_object from "@rescript/runtime/lib/es6/Primitive_object.js";
11
12
  import * as Primitive_string from "@rescript/runtime/lib/es6/Primitive_string.js";
12
13
  import * as Trait$Reventless from "@reventlessdev/reventless-spec/src/types/Trait.res.mjs";
13
14
  import * as DcbTag$Reventless from "@reventlessdev/reventless-spec/src/components/DcbTag.res.mjs";
14
15
  import * as Message$Reventless from "@reventlessdev/reventless-spec/src/types/Message.res.mjs";
16
+ import * as Schedule$Reventless from "@reventlessdev/reventless-spec/src/types/Schedule.res.mjs";
15
17
  import * as Semantic$Reventless from "@reventlessdev/reventless-spec/src/semantic/Semantic.res.mjs";
16
18
  import * as Lifecycle$Reventless from "@reventlessdev/reventless-spec/src/types/Lifecycle.res.mjs";
17
19
  import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
@@ -1252,13 +1254,14 @@ function make(name, aggregatesOpt, readModelsOpt, stateViewSlicesOpt, stateChang
1252
1254
  };
1253
1255
  });
1254
1256
  let automationSliceDefs = automationSlices.map(AS => {
1255
- let allConsumedVariants = Belt_SetString.toArray(Belt_SetString.fromArray(AS.Automation.mappings.flatMap(M => DcbTag$Reventless.extractVariantNames(M.sourceEventSchema))));
1257
+ let allConsumedVariants = Belt_SetString.toArray(Belt_SetString.fromArray(AS.Automation.mappings.filter(M => M.sourceName !== Clock$Reventless.name).flatMap(M => DcbTag$Reventless.extractVariantNames(M.sourceEventSchema))));
1256
1258
  return {
1257
1259
  name: AS.Spec.name,
1258
1260
  consumedEventTypes: qualify(name, allConsumedVariants),
1259
1261
  producedCommandTypes: qualify(name, DcbTag$Reventless.extractAllVariantNames(AS.Spec.commandSchema)),
1260
1262
  targetName: AS.Spec.targetName,
1261
- chapter: componentChapters[AS.Spec.name]
1263
+ chapter: componentChapters[AS.Spec.name],
1264
+ schedule: Stdlib_Option.map(AS.Spec.schedule, time => JSON.stringify(Util_Sury$Reventless.toJson(time, Schedule$Reventless.timeSchema)))
1262
1265
  };
1263
1266
  });
1264
1267
  let outboundTranslationSliceDefs = outboundTranslationSlices.map(OTS => ({
@@ -111,7 +111,7 @@ module Make = (Spec: Spec) => {
111
111
  | PluginExtensionPointSpec.CreateDisconnectSchedule(id, timeout) =>
112
112
  await createSchedule({
113
113
  name: id->disconnectScheduleName,
114
- rate: timeout->ScheduleOps.minutesFromNow,
114
+ time: timeout->ScheduleOps.minutesFromNow,
115
115
  payload: {
116
116
  Message.id,
117
117
  meta: Message.generateMeta(~service=PluginExtensionPointSpec.name, ~user="Scheduler"),
@@ -108,7 +108,7 @@ function Make(Spec) {
108
108
  let id = directive._0;
109
109
  return await createSchedule({
110
110
  name: disconnectScheduleName(id),
111
- rate: ScheduleOps$ReventlessCore.minutesFromNow(directive._1),
111
+ time: ScheduleOps$ReventlessCore.minutesFromNow(directive._1),
112
112
  payload: JSON.stringify(Message$ReventlessCore.encodeCommand$p({
113
113
  id: id,
114
114
  meta: Message$ReventlessCore.generateMeta(PluginExtensionPointSpec$ReventlessInfra.name, undefined, "Scheduler", undefined, undefined, undefined, undefined, undefined),
@@ -1,63 +1,9 @@
1
1
  open Reventless.Schedule
2
2
 
3
- module DateCalc = {
4
- /*** Immutable functions to calculate new Dates without mutation the arguments */
5
- @new
6
- external dateFromDate: Date.t => Date.t = "Date"
7
-
8
- let addMinutes: (Date.t, int) => Date.t = (date, minutes) => {
9
- let result = date->dateFromDate
10
- result->Date.setUTCMinutes(result->Date.getUTCMinutes + minutes)
11
- result
12
- }
13
-
14
- let addDays: (Date.t, int) => Date.t = (date, days) => {
15
- let result = date->dateFromDate
16
- result->Date.setUTCDate(result->Date.getUTCDate + days)
17
- result
18
- }
19
- }
20
-
21
3
  let forChannel = (~name, ~channelId, ~resourceNaming: ReventlessInfra.ResourceNaming.operations) =>
22
4
  name->resourceNaming.validateName ++ ("-" ++ channelId->String.split("-")->Array.getUnsafe(1))
23
5
 
24
- let minutesFromNow = minutes => {
25
- let m = Date.make()->DateCalc.addMinutes(minutes)
26
- Single(
27
- m->Date.getUTCFullYear,
28
- m->Date.getUTCMonth + 1,
29
- m->Date.getUTCDate,
30
- m->Date.getUTCHours,
31
- m->Date.getUTCMinutes,
32
- )
33
- }
34
-
35
- let nextTime = (h: hour, m: minute) => {
36
- let now = Date.make()
37
- let today = {
38
- let epoch = Date.make()
39
- epoch->Date.setUTCHours(h)
40
- epoch->Date.setUTCMinutes(m)
41
- epoch->Date.setUTCSeconds(0)
42
- epoch
43
- }
44
- let tomorrow = today->DateCalc.addDays(1)
45
- today < now
46
- ? Single(
47
- tomorrow->Date.getUTCFullYear,
48
- tomorrow->Date.getUTCMonth + 1,
49
- tomorrow->Date.getUTCDate,
50
- tomorrow->Date.getUTCHours,
51
- tomorrow->Date.getUTCMinutes,
52
- )
53
- : Single(
54
- today->Date.getUTCFullYear,
55
- today->Date.getUTCMonth + 1,
56
- today->Date.getUTCDate,
57
- today->Date.getUTCHours,
58
- today->Date.getUTCMinutes,
59
- )
60
- }
6
+ let minutesFromNow = minutes => Once({moment: After(Minutes(minutes))})
61
7
 
62
8
  exception ScheduleNotCreated(schedule)
63
9
  exception ScheduleNotDeleted(string)
@@ -6,72 +6,27 @@ import * as Exit$1 from "effect/Exit";
6
6
  import * as Cause from "effect/Cause";
7
7
  import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
8
8
  import * as Effect$1 from "effect/Effect";
9
- import * as Primitive_object from "@rescript/runtime/lib/es6/Primitive_object.js";
10
9
  import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
11
10
  import * as Util_Error$ReventlessCore from "./Util_Error.res.mjs";
12
11
  import * as EffectLogger$ReventlessCore from "./EffectLogger.res.mjs";
13
12
 
14
- function addMinutes(date, minutes) {
15
- let result = new Date(date);
16
- result.setUTCMinutes(result.getUTCMinutes() + minutes | 0);
17
- return result;
18
- }
19
-
20
- function addDays(date, days) {
21
- let result = new Date(date);
22
- result.setUTCDate(result.getUTCDate() + days | 0);
23
- return result;
24
- }
25
-
26
- let DateCalc = {
27
- addMinutes: addMinutes,
28
- addDays: addDays
29
- };
30
-
31
13
  function forChannel(name, channelId, resourceNaming) {
32
14
  return resourceNaming.validateName(name) + ("-" + channelId.split("-")[1]);
33
15
  }
34
16
 
35
17
  function minutesFromNow(minutes) {
36
- let m = addMinutes(new Date(), minutes);
37
18
  return {
38
- TAG: "Single",
39
- _0: m.getUTCFullYear(),
40
- _1: m.getUTCMonth() + 1 | 0,
41
- _2: m.getUTCDate(),
42
- _3: m.getUTCHours(),
43
- _4: m.getUTCMinutes()
19
+ TAG: "Once",
20
+ moment: {
21
+ TAG: "After",
22
+ _0: {
23
+ TAG: "Minutes",
24
+ _0: minutes
25
+ }
26
+ }
44
27
  };
45
28
  }
46
29
 
47
- function nextTime(h, m) {
48
- let now = new Date();
49
- let epoch = new Date();
50
- epoch.setUTCHours(h);
51
- epoch.setUTCMinutes(m);
52
- epoch.setUTCSeconds(0);
53
- let tomorrow = addDays(epoch, 1);
54
- if (Primitive_object.lessthan(epoch, now)) {
55
- return {
56
- TAG: "Single",
57
- _0: tomorrow.getUTCFullYear(),
58
- _1: tomorrow.getUTCMonth() + 1 | 0,
59
- _2: tomorrow.getUTCDate(),
60
- _3: tomorrow.getUTCHours(),
61
- _4: tomorrow.getUTCMinutes()
62
- };
63
- } else {
64
- return {
65
- TAG: "Single",
66
- _0: epoch.getUTCFullYear(),
67
- _1: epoch.getUTCMonth() + 1 | 0,
68
- _2: epoch.getUTCDate(),
69
- _3: epoch.getUTCHours(),
70
- _4: epoch.getUTCMinutes()
71
- };
72
- }
73
- }
74
-
75
30
  let ScheduleNotCreated = /* @__PURE__ */Primitive_exceptions.create("ScheduleOps-ReventlessCore.ScheduleNotCreated");
76
31
 
77
32
  let ScheduleNotDeleted = /* @__PURE__ */Primitive_exceptions.create("ScheduleOps-ReventlessCore.ScheduleNotDeleted");
@@ -79,11 +34,11 @@ let ScheduleNotDeleted = /* @__PURE__ */Primitive_exceptions.create("ScheduleOps
79
34
  function create(scheduler, channelResources, resourceNaming) {
80
35
  return async schedule => {
81
36
  let name = resourceNaming.validateName(schedule.name);
82
- let schedule_rate = schedule.rate;
37
+ let schedule_time = schedule.time;
83
38
  let schedule_payload = schedule.payload;
84
39
  let schedule$1 = {
85
40
  name: name,
86
- rate: schedule_rate,
41
+ time: schedule_time,
87
42
  payload: schedule_payload
88
43
  };
89
44
  let createSchedule = scheduler.createSchedule;
@@ -120,10 +75,8 @@ function $$delete(scheduler, channelResources, resourceNaming) {
120
75
  }
121
76
 
122
77
  export {
123
- DateCalc,
124
78
  forChannel,
125
79
  minutesFromNow,
126
- nextTime,
127
80
  ScheduleNotCreated,
128
81
  ScheduleNotDeleted,
129
82
  create,