@reventlessdev/reventless-local 3.0.0-alpha.317 → 3.0.0-alpha.318
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 +8 -0
- package/package.json +10 -10
- package/src/LocalPlatformRegistry.res +19 -0
- package/src/LocalPlatformRegistry.res.mjs +19 -1
- package/src/Platform.res +24 -2
- package/src/Platform.res.mjs +22 -2
- package/src/adapter/DcbEventLog/DcbEventLogStorage_InMemory.res +38 -0
- package/src/adapter/DcbEventLog/DcbEventLogStorage_InMemory.res.mjs +29 -0
- package/src/adapter/DcbEventLog/DcbEventLogStorage_Sqlite.res +87 -0
- package/src/adapter/DcbEventLog/DcbEventLogStorage_Sqlite.res.mjs +76 -0
- package/src/adapter/DcbEventLog/LocalDcbEventLogStorage.res +8 -1
- package/src/adapter/DcbEventLog/LocalDcbEventLogStorage.res.mjs +17 -4
- package/src/adapter/EventLog/EventLogStorage_InMemory.res +49 -2
- package/src/adapter/EventLog/EventLogStorage_InMemory.res.mjs +57 -21
- package/src/adapter/EventLog/EventLogStorage_Sqlite.res +85 -0
- package/src/adapter/EventLog/EventLogStorage_Sqlite.res.mjs +50 -0
- package/src/adapter/EventLog/LocalEventLogStorage.res +3 -0
- package/src/adapter/EventLog/LocalEventLogStorage.res.mjs +6 -2
- package/src/adapter/LocalBus.res +32 -5
- package/src/adapter/LocalBus.res.mjs +27 -7
- package/src/adapter/LocalEventLogRead.res +477 -0
- package/src/adapter/LocalEventLogRead.res.mjs +507 -0
- package/src/adapter/LocalEventTap.res +18 -80
- package/src/adapter/LocalEventTap.res.mjs +19 -108
- package/src/adapter/LocalFeed.res +433 -0
- package/src/adapter/LocalFeed.res.mjs +419 -0
- package/src/adapter/LocalLogFeed.res +217 -0
- package/src/adapter/LocalLogFeed.res.mjs +295 -0
- package/src/adapter/LocalPgEventLogRead.res +85 -0
- package/src/adapter/LocalPgEventLogRead.res.mjs +91 -0
- package/src/adapter/LocalPlatformObserve.res +456 -0
- package/src/adapter/LocalPlatformObserve.res.mjs +505 -0
- package/src/adapter/LocalTapLines.res +147 -0
- package/src/adapter/LocalTapLines.res.mjs +229 -0
- package/src/adapter/PlatformGraphQL_Server.res +36 -3
- package/src/adapter/PlatformGraphQL_Server.res.mjs +15 -1
- package/src/reexport/CommandTopic.res.mjs +5 -2
- package/tests/adapter/GraphQLWsFixtures.mjs +46 -0
- package/tests/adapter/LocalEventLogReadTest.res +539 -0
- package/tests/adapter/LocalEventLogReadTest.res.mjs +466 -0
- package/tests/adapter/LocalFeedTest.res +314 -0
- package/tests/adapter/LocalFeedTest.res.mjs +329 -0
- package/tests/adapter/LocalPlatformObserveTest.res +165 -0
- package/tests/adapter/LocalPlatformObserveTest.res.mjs +183 -0
- package/tests/adapter/LocalTapLinesTest.res +182 -0
- package/tests/adapter/LocalTapLinesTest.res.mjs +242 -0
- package/tests/adapter/PlatformSubscriptionsTest.res +123 -0
- package/tests/adapter/PlatformSubscriptionsTest.res.mjs +132 -0
- package/tests/components/automationslice/AutomationSliceCallbackTest.res +80 -0
- package/tests/components/automationslice/AutomationSliceCallbackTest.res.mjs +81 -0
- package/tests/components/automationslice/AutomationSliceSelfDeadlockFixtures.res +17 -0
- package/tests/components/automationslice/AutomationSliceSelfDeadlockFixtures.res.mjs +24 -0
- package/tests/components/automationslice/AutomationSliceSelfDeadlockTest.res +30 -0
- package/tests/components/automationslice/AutomationSliceSelfDeadlockTest.res.mjs +28 -0
- package/tests/components/outboundtranslationslice/OutboundTranslationSliceCallbackTest.res +58 -0
- package/tests/components/outboundtranslationslice/OutboundTranslationSliceCallbackTest.res.mjs +71 -19
- package/tests/components/outboundtranslationslice/OutboundTranslationSlicePiiTest.res.mjs +7 -7
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,14 @@
|
|
|
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.318 (2026-11-01)
|
|
7
|
+
|
|
8
|
+
### Features
|
|
9
|
+
|
|
10
|
+
* **core:** a command's outcome, the flow through automations, and each view change are told ([dcaeed2](https://github.com/ReventlessDev/reventless-core/commit/dcaeed2fabe2047a21797b459f2931618474dec3))
|
|
11
|
+
* **local:** the local platform serves its logs and events to whoever watches it ([0c29b0d](https://github.com/ReventlessDev/reventless-core/commit/0c29b0d08c668ad5b948a8017178dad8692647d0))
|
|
12
|
+
|
|
13
|
+
|
|
6
14
|
# 3.0.0-alpha.317 (2026-10-31)
|
|
7
15
|
|
|
8
16
|
**Note:** Version bump only for package @reventlessdev/reventless-local
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@reventlessdev/reventless-local",
|
|
3
|
-
"version": "3.0.0-alpha.
|
|
3
|
+
"version": "3.0.0-alpha.318",
|
|
4
4
|
"description": "Local platform for Reventless (in-memory or SQLite backend, for development and testing without AWS)",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"bin": {
|
|
@@ -34,19 +34,19 @@
|
|
|
34
34
|
"graphql-yoga": "^5.21.0",
|
|
35
35
|
"sury": "11.0.0",
|
|
36
36
|
"ws": "^8.18.0",
|
|
37
|
+
"@reventlessdev/rescript-graphql-yoga": "1.0.0-alpha.30",
|
|
37
38
|
"@reventlessdev/rescript-effect": "1.0.0-alpha.1",
|
|
38
|
-
"@reventlessdev/rescript-graphql-yoga": "1.0.0-alpha.29",
|
|
39
39
|
"@reventlessdev/rescript-jest": "1.0.0-alpha.13",
|
|
40
40
|
"@reventlessdev/rescript-mcp-sdk": "1.0.0-alpha.24",
|
|
41
|
-
"@reventlessdev/rescript-node": "2.0.0-alpha.
|
|
41
|
+
"@reventlessdev/rescript-node": "2.0.0-alpha.25",
|
|
42
42
|
"@reventlessdev/rescript-pulumi-pulumi": "3.0.0-alpha.0",
|
|
43
|
-
"@reventlessdev/reventless-core": "3.0.0-alpha.
|
|
44
|
-
"@reventlessdev/reventless-
|
|
45
|
-
"@reventlessdev/reventless-
|
|
46
|
-
"@reventlessdev/reventless-
|
|
47
|
-
"@reventlessdev/reventless-
|
|
48
|
-
"@reventlessdev/reventless-
|
|
49
|
-
"@reventlessdev/reventless-
|
|
43
|
+
"@reventlessdev/reventless-core": "3.0.0-alpha.326",
|
|
44
|
+
"@reventlessdev/reventless-gwt": "1.0.0-alpha.275",
|
|
45
|
+
"@reventlessdev/reventless-infra": "3.0.0-alpha.221",
|
|
46
|
+
"@reventlessdev/reventless-seed": "1.0.0-alpha.40",
|
|
47
|
+
"@reventlessdev/reventless-graphql-server": "1.0.0-alpha.174",
|
|
48
|
+
"@reventlessdev/reventless-spec": "3.0.0-alpha.192",
|
|
49
|
+
"@reventlessdev/reventless-postgres": "3.0.0-alpha.190"
|
|
50
50
|
},
|
|
51
51
|
"devDependencies": {
|
|
52
52
|
"rescript": "12.3.1",
|
|
@@ -27,6 +27,9 @@ type entry = {
|
|
|
27
27
|
// DELETES an entry it cannot decode, so requiring it would silently hide every
|
|
28
28
|
// platform from an older build. Absent ⇒ stdout only.
|
|
29
29
|
tapPort?: int,
|
|
30
|
+
// Where the log feed is served, when it is: the platform's recent and live log
|
|
31
|
+
// records. Optional for the same reason as `tapPort`.
|
|
32
|
+
logPort?: int,
|
|
30
33
|
}
|
|
31
34
|
|
|
32
35
|
// Threaded rather than read at each use, so tests need not move the process.
|
|
@@ -159,6 +162,22 @@ let publishTapPort = (~port: int, ~tapPort: int, ~cwd=NodeProcess.cwd()): unit =
|
|
|
159
162
|
}
|
|
160
163
|
}
|
|
161
164
|
|
|
165
|
+
/** Adds the log feed's port to an entry already written, once its socket is
|
|
166
|
+
bound; see {!publishTapPort}. */
|
|
167
|
+
let publishLogPort = (~port: int, ~logPort: int, ~cwd=NodeProcess.cwd()): unit => {
|
|
168
|
+
let path = entryPath(~port, ~cwd)
|
|
169
|
+
switch readEntry(path) {
|
|
170
|
+
| None => ()
|
|
171
|
+
| Some(entry) =>
|
|
172
|
+
try NodeFs.writeFileSync(
|
|
173
|
+
path,
|
|
174
|
+
{...entry, logPort}->Reventless.Util_Sury.toJson(entrySchema)->JSON.stringify(~space=2),
|
|
175
|
+
) catch {
|
|
176
|
+
| _ => ()
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
162
181
|
/** Publishes this process, and unpublishes it on the way out. Both paths are
|
|
163
182
|
needed: `exit` is sync-only, and registering a signal handler suppresses
|
|
164
183
|
Node's default exit, so each signal must leave explicitly. */
|
|
@@ -22,7 +22,8 @@ let entrySchema = Sury.$schema(s => ({
|
|
|
22
22
|
loginEndpoint: s.m(Sury.string),
|
|
23
23
|
store: s.m(storeSchema),
|
|
24
24
|
startedAt: s.m(Sury.string),
|
|
25
|
-
tapPort: s.m(Sury.$option(Sury.int32))
|
|
25
|
+
tapPort: s.m(Sury.$option(Sury.int32)),
|
|
26
|
+
logPort: s.m(Sury.$option(Sury.int32))
|
|
26
27
|
}));
|
|
27
28
|
|
|
28
29
|
function runningDir(cwdOpt, param) {
|
|
@@ -152,6 +153,22 @@ function publishTapPort(port, tapPort, cwdOpt) {
|
|
|
152
153
|
}
|
|
153
154
|
}
|
|
154
155
|
|
|
156
|
+
function publishLogPort(port, logPort, cwdOpt) {
|
|
157
|
+
let cwd = cwdOpt !== undefined ? cwdOpt : process.cwd();
|
|
158
|
+
let path = entryPath(port, cwd);
|
|
159
|
+
let entry = readEntry(path);
|
|
160
|
+
if (entry === undefined) {
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
try {
|
|
164
|
+
let newrecord = {...entry};
|
|
165
|
+
Nodefs.writeFileSync(path, JSON.stringify(Util_Sury$Reventless.toJson((newrecord.logPort = logPort, newrecord), entrySchema), undefined, 2), "utf8");
|
|
166
|
+
return;
|
|
167
|
+
} catch (exn) {
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
155
172
|
function register(port, endpoint, loginEndpoint, store, tapPort) {
|
|
156
173
|
let path = write(port, endpoint, loginEndpoint, store, tapPort, undefined, undefined);
|
|
157
174
|
process.on("exit", param => removeQuietly(path));
|
|
@@ -177,6 +194,7 @@ export {
|
|
|
177
194
|
list,
|
|
178
195
|
write,
|
|
179
196
|
publishTapPort,
|
|
197
|
+
publishLogPort,
|
|
180
198
|
register,
|
|
181
199
|
}
|
|
182
200
|
/* storeSchema Not a pure module */
|
package/src/Platform.res
CHANGED
|
@@ -106,6 +106,13 @@ module MakeWithConfig = (
|
|
|
106
106
|
// local platform has no per-component process boundary.
|
|
107
107
|
let _ = Config.commandHandlerConfig
|
|
108
108
|
|
|
109
|
+
// Keep the recent log records from here on, for the log feed and the MCP
|
|
110
|
+
// resource that read them.
|
|
111
|
+
LocalLogFeed.install()
|
|
112
|
+
// What became of each command, and each row a projection changed, on the
|
|
113
|
+
// event tap; a rejected command also in the problem ring.
|
|
114
|
+
LocalTapLines.install()
|
|
115
|
+
|
|
109
116
|
// What this platform provides for the roles its plugins need: every account it
|
|
110
117
|
// can sign in as, built-in and loaded alike, or the file the store will load
|
|
111
118
|
// when the servers start — after the plugins are built and checked.
|
|
@@ -327,8 +334,13 @@ module MakeWithConfig = (
|
|
|
327
334
|
// Event-history queries — the historical read counterpart of the Source A
|
|
328
335
|
// subscription bridged further down. Same `eventLogEntries`, so the two
|
|
329
336
|
// always describe the same set of streams.
|
|
330
|
-
eventQueryResolverHook: params =>
|
|
331
|
-
|
|
337
|
+
eventQueryResolverHook: params => {
|
|
338
|
+
// The read across every log names each event's plugin.
|
|
339
|
+
params.eventLogEntries->Array.forEach(entry =>
|
|
340
|
+
LocalEventLogRead.notePlugin(~log=entry.busKey, ~plugin=params.pluginName)
|
|
341
|
+
)
|
|
342
|
+
EventHistoryResolvers.register(~server=resolveTargetGraphQL(), params)
|
|
343
|
+
},
|
|
332
344
|
// MCP tools and resources — registered during plugin construction.
|
|
333
345
|
// See the large lambda below; it references Bus for QueryDb lookups.
|
|
334
346
|
mcpSchemaRegistrationHook: ({
|
|
@@ -1418,6 +1430,11 @@ module MakeWithConfig = (
|
|
|
1418
1430
|
~onBound=tapPort => LocalPlatformRegistry.publishTapPort(~port=domainPort, ~tapPort),
|
|
1419
1431
|
(),
|
|
1420
1432
|
)
|
|
1433
|
+
// The log feed, the same way: its port is filled in once it is bound.
|
|
1434
|
+
LocalLogFeed.start(
|
|
1435
|
+
~onBound=logPort => LocalPlatformRegistry.publishLogPort(~port=domainPort, ~logPort),
|
|
1436
|
+
(),
|
|
1437
|
+
)
|
|
1421
1438
|
// Fire onPlatformDeployed after all servers are started so late-deployed
|
|
1422
1439
|
// plugins (e.g. PlatformInspector) have their handler refs populated.
|
|
1423
1440
|
ReventlessCore.Plugin_Helpers.firePlatformDeployedHook({
|
|
@@ -2113,6 +2130,11 @@ module MakeWithConfig = (
|
|
|
2113
2130
|
|
|
2114
2131
|
platformGraphQL.registerQueries(~sdlFields=baseParts.queries, ~resolvers=queryResolvers)
|
|
2115
2132
|
|
|
2133
|
+
// What a tool watching this platform reads: every event of every log, and
|
|
2134
|
+
// the log level while running.
|
|
2135
|
+
LocalPlatformObserve.registerGraphQL(platformGraphQL)
|
|
2136
|
+
LocalPlatformObserve.registerMcp(platformMCP)
|
|
2137
|
+
|
|
2116
2138
|
// Admin Plugin lifecycle mutations (Activate / Deactivate / Retire) now flow
|
|
2117
2139
|
// through the LocalPluginAggregate, mirroring AWS. The resolver looks up the
|
|
2118
2140
|
// plugin's current version from the "Plugins" read model (the aggregate is
|
package/src/Platform.res.mjs
CHANGED
|
@@ -38,11 +38,13 @@ import * as ShellConfig$ReventlessLocal from "./ShellConfig.res.mjs";
|
|
|
38
38
|
import * as AccountStore$ReventlessLocal from "./adapter/Auth/AccountStore.res.mjs";
|
|
39
39
|
import * as BackendState$ReventlessLocal from "./adapter/BackendState.res.mjs";
|
|
40
40
|
import * as ComponentType$ReventlessCore from "@reventlessdev/reventless-core/src/ComponentType.res.mjs";
|
|
41
|
+
import * as LocalLogFeed$ReventlessLocal from "./adapter/LocalLogFeed.res.mjs";
|
|
41
42
|
import * as SqliteDriver$ReventlessLocal from "./adapter/SqliteDriver.res.mjs";
|
|
42
43
|
import * as Task_Builder$ReventlessLocal from "./components/Task_Builder.res.mjs";
|
|
43
44
|
import * as BakedManifest$ReventlessLocal from "./BakedManifest.res.mjs";
|
|
44
45
|
import * as HostShellDist$ReventlessLocal from "./HostShellDist.res.mjs";
|
|
45
46
|
import * as LocalEventTap$ReventlessLocal from "./adapter/LocalEventTap.res.mjs";
|
|
47
|
+
import * as LocalTapLines$ReventlessLocal from "./adapter/LocalTapLines.res.mjs";
|
|
46
48
|
import * as Platform_Admin$ReventlessCore from "@reventlessdev/reventless-core/src/admin/Platform_Admin.res.mjs";
|
|
47
49
|
import * as PluginDecision$ReventlessCore from "@reventlessdev/reventless-core/src/plugin/lifecycle/PluginDecision.res.mjs";
|
|
48
50
|
import * as Plugin_Helpers$ReventlessCore from "@reventlessdev/reventless-core/src/plugin/component/Plugin_Helpers.res.mjs";
|
|
@@ -63,6 +65,7 @@ import * as Scheduler_Builder$ReventlessCore from "@reventlessdev/reventless-cor
|
|
|
63
65
|
import * as Aggregate_Builder$ReventlessLocal from "./components/Aggregate_Builder.res.mjs";
|
|
64
66
|
import * as LocalCapabilities$ReventlessLocal from "./adapter/LocalCapabilities.res.mjs";
|
|
65
67
|
import * as LocalClonerRunner$ReventlessLocal from "./adapter/Cloner/LocalClonerRunner.res.mjs";
|
|
68
|
+
import * as LocalEventLogRead$ReventlessLocal from "./adapter/LocalEventLogRead.res.mjs";
|
|
66
69
|
import * as PluginBaseFragment$ReventlessCore from "@reventlessdev/reventless-core/src/plugin/api/PluginBaseFragment.res.mjs";
|
|
67
70
|
import * as ProjectionPending$ReventlessLocal from "./adapter/ProjectionPending.res.mjs";
|
|
68
71
|
import * as ReadModel_Builder$ReventlessLocal from "./components/ReadModel_Builder.res.mjs";
|
|
@@ -77,6 +80,7 @@ import * as PluginsReadModelSpec$ReventlessCore from "@reventlessdev/reventless-
|
|
|
77
80
|
import * as StorePrefixCollision$ReventlessCore from "@reventlessdev/reventless-core/src/util/StorePrefixCollision.res.mjs";
|
|
78
81
|
import * as DomainGraphQL_Server$ReventlessLocal from "./adapter/DomainGraphQL_Server.res.mjs";
|
|
79
82
|
import * as EventPublish_Callback$ReventlessCore from "@reventlessdev/reventless-core/src/components/EventLog/EventPublish_Callback.res.mjs";
|
|
83
|
+
import * as LocalPlatformObserve$ReventlessLocal from "./adapter/LocalPlatformObserve.res.mjs";
|
|
80
84
|
import * as LocalUploadResolvers$ReventlessLocal from "./adapter/LocalUploadResolvers.res.mjs";
|
|
81
85
|
import * as ProjectionCheckpoint$ReventlessLocal from "./adapter/ProjectionCheckpoint.res.mjs";
|
|
82
86
|
import * as ExtensionPointMapping$ReventlessInfra from "@reventlessdev/reventless-infra/src/types/ExtensionPointMapping.res.mjs";
|
|
@@ -146,6 +150,8 @@ function decodeUiFragmentRegistryEventEnvelope(eventJson) {
|
|
|
146
150
|
}
|
|
147
151
|
|
|
148
152
|
function MakeWithConfig(Config) {
|
|
153
|
+
LocalLogFeed$ReventlessLocal.install(undefined);
|
|
154
|
+
LocalTapLines$ReventlessLocal.install();
|
|
149
155
|
Role$Reventless.provideGroupsFrom(AccountStore$ReventlessLocal.providedGroups);
|
|
150
156
|
TestRunner$ReventlessLocal.setup();
|
|
151
157
|
let match = Config.backend;
|
|
@@ -444,7 +450,10 @@ function MakeWithConfig(Config) {
|
|
|
444
450
|
});
|
|
445
451
|
LocalGraphQL_SubscriptionResolvers$ReventlessLocal.registerAll(server, subscriptionFields, sourceAEntries, []);
|
|
446
452
|
};
|
|
447
|
-
let hooks_eventQueryResolverHook = params =>
|
|
453
|
+
let hooks_eventQueryResolverHook = params => {
|
|
454
|
+
params.eventLogEntries.forEach(entry => LocalEventLogRead$ReventlessLocal.notePlugin(entry.busKey, params.pluginName));
|
|
455
|
+
EventHistoryResolvers.register(resolveTargetGraphQL(), params);
|
|
456
|
+
};
|
|
448
457
|
let hooks_adminExtensionPoints = {
|
|
449
458
|
contents: Pulumi.output({})
|
|
450
459
|
};
|
|
@@ -1169,6 +1178,7 @@ function MakeWithConfig(Config) {
|
|
|
1169
1178
|
path: match[1]
|
|
1170
1179
|
}, undefined);
|
|
1171
1180
|
LocalEventTap$ReventlessLocal.start(undefined, tapPort => LocalPlatformRegistry$ReventlessLocal.publishTapPort(domainPort, tapPort, undefined), undefined);
|
|
1181
|
+
LocalLogFeed$ReventlessLocal.start(undefined, logPort => LocalPlatformRegistry$ReventlessLocal.publishLogPort(domainPort, logPort, undefined), undefined);
|
|
1172
1182
|
Plugin_Helpers$ReventlessCore.firePlatformDeployedHook({
|
|
1173
1183
|
name: "local",
|
|
1174
1184
|
environment: Pulumi.getStack(),
|
|
@@ -1545,6 +1555,8 @@ function MakeWithConfig(Config) {
|
|
|
1545
1555
|
};
|
|
1546
1556
|
registerAdminItemsAndIndexResolvers(queryResolvers, true);
|
|
1547
1557
|
platformGraphQL.registerQueries(baseParts.queries, queryResolvers);
|
|
1558
|
+
LocalPlatformObserve$ReventlessLocal.registerGraphQL(platformGraphQL);
|
|
1559
|
+
LocalPlatformObserve$ReventlessLocal.registerMcp(platformMCP);
|
|
1548
1560
|
let argId = args => Stdlib_Option.getOr(Stdlib_Option.flatMap(Stdlib_Option.flatMap(Stdlib_JSON.Decode.object(args), d => d["id"]), Stdlib_JSON.Decode.string), "");
|
|
1549
1561
|
let currentVersionOf = pluginName => {
|
|
1550
1562
|
let scanAll = Bus.getQueryDbScan(PluginsReadModelSpec$ReventlessCore.name);
|
|
@@ -1946,6 +1958,8 @@ function MakeWithConfig(Config) {
|
|
|
1946
1958
|
|
|
1947
1959
|
function Make($star) {
|
|
1948
1960
|
let backend = Backend$ReventlessLocal.fromEnv();
|
|
1961
|
+
LocalLogFeed$ReventlessLocal.install(undefined);
|
|
1962
|
+
LocalTapLines$ReventlessLocal.install();
|
|
1949
1963
|
Role$Reventless.provideGroupsFrom(AccountStore$ReventlessLocal.providedGroups);
|
|
1950
1964
|
TestRunner$ReventlessLocal.setup();
|
|
1951
1965
|
if (typeof backend !== "object") {
|
|
@@ -2237,7 +2251,10 @@ function Make($star) {
|
|
|
2237
2251
|
});
|
|
2238
2252
|
LocalGraphQL_SubscriptionResolvers$ReventlessLocal.registerAll(server, subscriptionFields, sourceAEntries, []);
|
|
2239
2253
|
};
|
|
2240
|
-
let hooks_eventQueryResolverHook = params =>
|
|
2254
|
+
let hooks_eventQueryResolverHook = params => {
|
|
2255
|
+
params.eventLogEntries.forEach(entry => LocalEventLogRead$ReventlessLocal.notePlugin(entry.busKey, params.pluginName));
|
|
2256
|
+
EventHistoryResolvers.register(resolveTargetGraphQL(), params);
|
|
2257
|
+
};
|
|
2241
2258
|
let hooks_adminExtensionPoints = {
|
|
2242
2259
|
contents: Pulumi.output({})
|
|
2243
2260
|
};
|
|
@@ -2958,6 +2975,7 @@ function Make($star) {
|
|
|
2958
2975
|
path: match[1]
|
|
2959
2976
|
}, undefined);
|
|
2960
2977
|
LocalEventTap$ReventlessLocal.start(undefined, tapPort => LocalPlatformRegistry$ReventlessLocal.publishTapPort(domainPort, tapPort, undefined), undefined);
|
|
2978
|
+
LocalLogFeed$ReventlessLocal.start(undefined, logPort => LocalPlatformRegistry$ReventlessLocal.publishLogPort(domainPort, logPort, undefined), undefined);
|
|
2961
2979
|
Plugin_Helpers$ReventlessCore.firePlatformDeployedHook({
|
|
2962
2980
|
name: "local",
|
|
2963
2981
|
environment: Pulumi.getStack(),
|
|
@@ -3333,6 +3351,8 @@ function Make($star) {
|
|
|
3333
3351
|
};
|
|
3334
3352
|
registerAdminItemsAndIndexResolvers(queryResolvers, true);
|
|
3335
3353
|
platformGraphQL.registerQueries(baseParts.queries, queryResolvers);
|
|
3354
|
+
LocalPlatformObserve$ReventlessLocal.registerGraphQL(platformGraphQL);
|
|
3355
|
+
LocalPlatformObserve$ReventlessLocal.registerMcp(platformMCP);
|
|
3336
3356
|
let argId = args => Stdlib_Option.getOr(Stdlib_Option.flatMap(Stdlib_Option.flatMap(Stdlib_JSON.Decode.object(args), d => d["id"]), Stdlib_JSON.Decode.string), "");
|
|
3337
3357
|
let currentVersionOf = pluginName => {
|
|
3338
3358
|
let scanAll = Bus.getQueryDbScan(PluginsReadModelSpec$ReventlessCore.name);
|
|
@@ -128,6 +128,39 @@ let makeStorage = (~name as _name, ~indexes as _, ~partitionTag as _, ~opts as _
|
|
|
128
128
|
}
|
|
129
129
|
}
|
|
130
130
|
|
|
131
|
+
// Newest first, for the read across every log.
|
|
132
|
+
LocalEventLogRead.register(~log=_name, ~kind=Dcb, async (~bound, ~limit, ~correlationId) => {
|
|
133
|
+
let out = []
|
|
134
|
+
let i = ref(events.contents->Array.length - 1)
|
|
135
|
+
while i.contents >= 0 && out->Array.length < limit {
|
|
136
|
+
let ev = events.contents->Array.getUnsafe(i.contents)
|
|
137
|
+
let position = ev.position->posToInt->Int.toFloat
|
|
138
|
+
let inBound = switch bound {
|
|
139
|
+
| Some(LocalEventLogRead.Below(p)) => position < p
|
|
140
|
+
| Some(AtMost(p)) => position <= p
|
|
141
|
+
| None => true
|
|
142
|
+
}
|
|
143
|
+
let inFlow = correlationId->Option.mapOr(true, id => ev.meta.correlationId == id)
|
|
144
|
+
if inBound && inFlow {
|
|
145
|
+
out->Array.push(
|
|
146
|
+
(
|
|
147
|
+
{
|
|
148
|
+
log: _name,
|
|
149
|
+
position,
|
|
150
|
+
eventType: ev.eventType,
|
|
151
|
+
tags: ev.tags,
|
|
152
|
+
payload: ev.data,
|
|
153
|
+
meta: ev.meta->Reventless.Util_Sury.toJson(Reventless.Message.metaSchema),
|
|
154
|
+
recordedAt: ev.recordedAt,
|
|
155
|
+
}: LocalEventLogRead.stored
|
|
156
|
+
),
|
|
157
|
+
)
|
|
158
|
+
}
|
|
159
|
+
i := i.contents - 1
|
|
160
|
+
}
|
|
161
|
+
out
|
|
162
|
+
})
|
|
163
|
+
|
|
131
164
|
let read = async (~query, ~after=?) => {
|
|
132
165
|
let filtered = matchingEvents(~query, ~after)
|
|
133
166
|
let headPosition =
|
|
@@ -165,6 +198,11 @@ let makeStorage = (~name as _name, ~indexes as _, ~partitionTag as _, ~opts as _
|
|
|
165
198
|
recordedAt: Message.nowAsISOString(),
|
|
166
199
|
}
|
|
167
200
|
indexEvent(base + j, stored)
|
|
201
|
+
LocalEventLogRead.note(
|
|
202
|
+
~log=_name,
|
|
203
|
+
~msgId=event.meta.msgId,
|
|
204
|
+
~position=position.contents->Int.toFloat,
|
|
205
|
+
)
|
|
168
206
|
stored
|
|
169
207
|
})
|
|
170
208
|
events := events.contents->Array.concat(storedEvents)
|
|
@@ -6,7 +6,10 @@ import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
|
6
6
|
import * as Effect from "effect/Effect";
|
|
7
7
|
import * as Stream from "effect/Stream";
|
|
8
8
|
import * as Pulumi from "@pulumi/pulumi";
|
|
9
|
+
import * as Message$Reventless from "@reventlessdev/reventless-spec/src/types/Message.res.mjs";
|
|
10
|
+
import * as Util_Sury$Reventless from "@reventlessdev/reventless-spec/src/util/Util_Sury.res.mjs";
|
|
9
11
|
import * as Message$ReventlessCore from "@reventlessdev/reventless-core/src/Message.res.mjs";
|
|
12
|
+
import * as LocalEventLogRead$ReventlessLocal from "../LocalEventLogRead.res.mjs";
|
|
10
13
|
|
|
11
14
|
function posToInt(pos) {
|
|
12
15
|
return Stdlib_Option.getOr(Stdlib_Int.fromString(pos, undefined), 0);
|
|
@@ -130,6 +133,31 @@ function makeStorage(_name, param, param$1, param$2) {
|
|
|
130
133
|
});
|
|
131
134
|
}
|
|
132
135
|
};
|
|
136
|
+
LocalEventLogRead$ReventlessLocal.register(_name, "Dcb", async (bound, limit, correlationId) => {
|
|
137
|
+
let out = [];
|
|
138
|
+
let i = events.contents.length - 1 | 0;
|
|
139
|
+
while (i >= 0 && out.length < limit) {
|
|
140
|
+
let ev = events.contents[i];
|
|
141
|
+
let position = posToInt(ev.position);
|
|
142
|
+
let inBound = bound !== undefined ? (
|
|
143
|
+
bound.TAG === "Below" ? position < bound._0 : position <= bound._0
|
|
144
|
+
) : true;
|
|
145
|
+
let inFlow = Stdlib_Option.mapOr(correlationId, true, id => ev.meta.correlationId === id);
|
|
146
|
+
if (inBound && inFlow) {
|
|
147
|
+
out.push({
|
|
148
|
+
log: _name,
|
|
149
|
+
position: position,
|
|
150
|
+
eventType: ev.eventType,
|
|
151
|
+
tags: ev.tags,
|
|
152
|
+
payload: ev.data,
|
|
153
|
+
meta: Util_Sury$Reventless.toJson(ev.meta, Message$Reventless.metaSchema),
|
|
154
|
+
recordedAt: ev.recordedAt
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
i = i - 1 | 0;
|
|
158
|
+
};
|
|
159
|
+
return out;
|
|
160
|
+
});
|
|
133
161
|
let read = async (query, after) => {
|
|
134
162
|
let filtered = matchingEvents(query, after);
|
|
135
163
|
let headPosition = Stdlib_Option.map(events.contents[events.contents.length - 1 | 0], e => e.position);
|
|
@@ -164,6 +192,7 @@ function makeStorage(_name, param, param$1, param$2) {
|
|
|
164
192
|
recordedAt: stored_recordedAt
|
|
165
193
|
};
|
|
166
194
|
indexEvent(base + j | 0, stored);
|
|
195
|
+
LocalEventLogRead$ReventlessLocal.note(_name, event.meta.msgId, position.contents);
|
|
167
196
|
return stored;
|
|
168
197
|
});
|
|
169
198
|
events.contents = events.contents.concat(storedEvents);
|
|
@@ -38,6 +38,11 @@ let ensureSchema = (db: SqliteDriver.t) => {
|
|
|
38
38
|
// IN (...)` batch). The `_by_kv` index leads with tag_key/tag_value, so it
|
|
39
39
|
// cannot answer a position lookup — without this the batch scanned dcb_tag.
|
|
40
40
|
db->SqliteDriver.exec("CREATE INDEX IF NOT EXISTS dcb_tag_by_pos ON dcb_tag(log_name, position)")
|
|
41
|
+
// Finding every event of one flow in one log. Created on open, so an existing store gains
|
|
42
|
+
// it; a query must use this exact expression for the index to apply.
|
|
43
|
+
db->SqliteDriver.exec(
|
|
44
|
+
"CREATE INDEX IF NOT EXISTS dcb_event_by_correlation ON dcb_event(log_name, json_extract(meta, '$.correlationId'), position)",
|
|
45
|
+
)
|
|
41
46
|
}
|
|
42
47
|
|
|
43
48
|
let posToInt = (pos: string) => pos->Int.fromString->Option.getOr(0)
|
|
@@ -157,6 +162,81 @@ let buildQuerySql = (~logName: string, ~query: DcbTag.query, ~after: option<int>
|
|
|
157
162
|
)
|
|
158
163
|
}
|
|
159
164
|
|
|
165
|
+
/** The SQL of one backwards read, and its parameters. */
|
|
166
|
+
let readBackSql = (
|
|
167
|
+
~name: string,
|
|
168
|
+
~bound: option<LocalEventLogRead.bound>,
|
|
169
|
+
~limit: int,
|
|
170
|
+
~correlationId: option<string>,
|
|
171
|
+
): (string, array<JSON.t>) => {
|
|
172
|
+
let parts = ["log_name = ?"]
|
|
173
|
+
let params = [JSON.Encode.string(name)]
|
|
174
|
+
switch bound {
|
|
175
|
+
| Some(LocalEventLogRead.Below(p)) =>
|
|
176
|
+
parts->Array.push("position < ?")
|
|
177
|
+
params->Array.push(JSON.Encode.float(p))
|
|
178
|
+
| Some(AtMost(p)) =>
|
|
179
|
+
parts->Array.push("position <= ?")
|
|
180
|
+
params->Array.push(JSON.Encode.float(p))
|
|
181
|
+
| None => ()
|
|
182
|
+
}
|
|
183
|
+
switch correlationId {
|
|
184
|
+
| Some(id) =>
|
|
185
|
+
parts->Array.push("json_extract(meta, '$.correlationId') = ?")
|
|
186
|
+
params->Array.push(JSON.Encode.string(id))
|
|
187
|
+
| None => ()
|
|
188
|
+
}
|
|
189
|
+
params->Array.push(JSON.Encode.int(limit))
|
|
190
|
+
(
|
|
191
|
+
`SELECT position, event_type, data, meta, recorded_at FROM dcb_event WHERE ${parts->Array.join(
|
|
192
|
+
" AND ",
|
|
193
|
+
)} ORDER BY position DESC LIMIT ?`,
|
|
194
|
+
params,
|
|
195
|
+
)
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/** Reads one log newest first by position, with each event's tags. */
|
|
199
|
+
let readBack = (~db: SqliteDriver.t, ~name: string): LocalEventLogRead.readBack =>
|
|
200
|
+
async (~bound, ~limit, ~correlationId) => {
|
|
201
|
+
let (sql, params) = readBackSql(~name, ~bound, ~limit, ~correlationId)
|
|
202
|
+
let rows = db->SqliteDriver.prepare(sql)->SqliteDriver.all(params)
|
|
203
|
+
let positions =
|
|
204
|
+
rows->Array.map(row => row->Dict.get("position")->Option.mapOr(0, coercePosition))
|
|
205
|
+
let tagsByPos: Dict.t<array<DcbTag.tag>> = Dict.make()
|
|
206
|
+
if positions->Array.length > 0 {
|
|
207
|
+
let placeholders = positions->Array.map(_ => "?")->Array.join(",")
|
|
208
|
+
db
|
|
209
|
+
->SqliteDriver.prepare(
|
|
210
|
+
`SELECT position, tag_key, tag_value FROM dcb_tag WHERE log_name = ? AND position IN (${placeholders}) ORDER BY position ASC, rowid ASC`,
|
|
211
|
+
)
|
|
212
|
+
->SqliteDriver.all(
|
|
213
|
+
[JSON.Encode.string(name)]->Array.concat(positions->Array.map(JSON.Encode.int)),
|
|
214
|
+
)
|
|
215
|
+
->Array.forEach(row => {
|
|
216
|
+
let k = row->Dict.get("position")->Option.mapOr(0, coercePosition)->Int.toString
|
|
217
|
+
let str = key => row->Dict.get(key)->Option.flatMap(JSON.Decode.string)->Option.getOr("")
|
|
218
|
+
let tag: DcbTag.tag = {key: str("tag_key"), value: str("tag_value")}
|
|
219
|
+
switch tagsByPos->Dict.get(k) {
|
|
220
|
+
| Some(list) => list->Array.push(tag)
|
|
221
|
+
| None => tagsByPos->Dict.set(k, [tag])
|
|
222
|
+
}
|
|
223
|
+
})
|
|
224
|
+
}
|
|
225
|
+
rows->Array.map((row): LocalEventLogRead.stored => {
|
|
226
|
+
let position = row->Dict.get("position")->Option.mapOr(0, coercePosition)
|
|
227
|
+
let str = key => row->Dict.get(key)->Option.flatMap(JSON.Decode.string)->Option.getOr("")
|
|
228
|
+
{
|
|
229
|
+
log: name,
|
|
230
|
+
position: position->Int.toFloat,
|
|
231
|
+
eventType: str("event_type"),
|
|
232
|
+
tags: tagsByPos->Dict.get(position->Int.toString)->Option.getOr([]),
|
|
233
|
+
payload: parseDataPayload(str("data")),
|
|
234
|
+
meta: parseDataPayload(str("meta")),
|
|
235
|
+
recordedAt: str("recorded_at"),
|
|
236
|
+
}
|
|
237
|
+
})
|
|
238
|
+
}
|
|
239
|
+
|
|
160
240
|
let makeStorage = (
|
|
161
241
|
~db: SqliteDriver.t,
|
|
162
242
|
~name: string,
|
|
@@ -165,6 +245,7 @@ let makeStorage = (
|
|
|
165
245
|
~opts as _,
|
|
166
246
|
) => {
|
|
167
247
|
ensureSchema(db)
|
|
248
|
+
LocalEventLogRead.register(~log=name, ~kind=Dcb, readBack(~db, ~name))
|
|
168
249
|
|
|
169
250
|
let insertEventStmt =
|
|
170
251
|
db->SqliteDriver.prepare(
|
|
@@ -327,6 +408,8 @@ let makeStorage = (
|
|
|
327
408
|
// each event insert — before the tag inserts move last_insert_rowid() to
|
|
328
409
|
// the dcb_tag table. Registered only after the transaction commits.
|
|
329
410
|
let appended: array<(string, int)> = []
|
|
411
|
+
// (msgId, position) per inserted event, for the tap line that publishes it.
|
|
412
|
+
let positionsOf: array<(string, int)> = []
|
|
330
413
|
try {
|
|
331
414
|
db->SqliteDriver.transaction(() => {
|
|
332
415
|
switch condition {
|
|
@@ -371,12 +454,16 @@ let makeStorage = (
|
|
|
371
454
|
])
|
|
372
455
|
},
|
|
373
456
|
)
|
|
457
|
+
positionsOf->Array.push((event.meta.msgId, pos))
|
|
374
458
|
lastPos := pos
|
|
375
459
|
})
|
|
376
460
|
|
|
377
461
|
result := Ok(Int.toString(lastPos.contents))
|
|
378
462
|
})
|
|
379
463
|
ProjectionPending.trackAppended(~axis=ProjectionPending.Dcb, appended)
|
|
464
|
+
positionsOf->Array.forEach(((msgId, pos)) =>
|
|
465
|
+
LocalEventLogRead.note(~log=name, ~msgId, ~position=pos->Int.toFloat)
|
|
466
|
+
)
|
|
380
467
|
result.contents
|
|
381
468
|
} catch {
|
|
382
469
|
// The deliberate append-condition failure throws Failure("conflict: …").
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
2
|
|
|
3
3
|
import * as Stdlib_Int from "@rescript/runtime/lib/es6/Stdlib_Int.js";
|
|
4
|
+
import * as Stdlib_JSON from "@rescript/runtime/lib/es6/Stdlib_JSON.js";
|
|
4
5
|
import * as Stdlib_JsExn from "@rescript/runtime/lib/es6/Stdlib_JsExn.js";
|
|
5
6
|
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
6
7
|
import * as Effect from "effect/Effect";
|
|
@@ -13,6 +14,7 @@ import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_excep
|
|
|
13
14
|
import * as Util_Sury$Reventless from "@reventlessdev/reventless-spec/src/util/Util_Sury.res.mjs";
|
|
14
15
|
import * as Message$ReventlessCore from "@reventlessdev/reventless-core/src/Message.res.mjs";
|
|
15
16
|
import * as SqliteDriver$ReventlessLocal from "../SqliteDriver.res.mjs";
|
|
17
|
+
import * as LocalEventLogRead$ReventlessLocal from "../LocalEventLogRead.res.mjs";
|
|
16
18
|
import * as ProjectionPending$ReventlessLocal from "../ProjectionPending.res.mjs";
|
|
17
19
|
|
|
18
20
|
function ensureSchema(db) {
|
|
@@ -20,6 +22,7 @@ function ensureSchema(db) {
|
|
|
20
22
|
SqliteDriver$ReventlessLocal.exec(db, "CREATE TABLE IF NOT EXISTS dcb_tag (log_name TEXT NOT NULL, position INTEGER NOT NULL, tag_key TEXT NOT NULL, tag_value TEXT NOT NULL)");
|
|
21
23
|
SqliteDriver$ReventlessLocal.exec(db, "CREATE INDEX IF NOT EXISTS dcb_tag_by_kv ON dcb_tag(log_name, tag_key, tag_value, position)");
|
|
22
24
|
SqliteDriver$ReventlessLocal.exec(db, "CREATE INDEX IF NOT EXISTS dcb_tag_by_pos ON dcb_tag(log_name, position)");
|
|
25
|
+
SqliteDriver$ReventlessLocal.exec(db, "CREATE INDEX IF NOT EXISTS dcb_event_by_correlation ON dcb_event(log_name, json_extract(meta, '$.correlationId'), position)");
|
|
23
26
|
}
|
|
24
27
|
|
|
25
28
|
function posToInt(pos) {
|
|
@@ -128,8 +131,73 @@ function buildQuerySql(logName, query, after) {
|
|
|
128
131
|
];
|
|
129
132
|
}
|
|
130
133
|
|
|
134
|
+
function readBackSql(name, bound, limit, correlationId) {
|
|
135
|
+
let parts = ["log_name = ?"];
|
|
136
|
+
let params = [name];
|
|
137
|
+
if (bound !== undefined) {
|
|
138
|
+
if (bound.TAG === "Below") {
|
|
139
|
+
parts.push("position < ?");
|
|
140
|
+
params.push(bound._0);
|
|
141
|
+
} else {
|
|
142
|
+
parts.push("position <= ?");
|
|
143
|
+
params.push(bound._0);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
if (correlationId !== undefined) {
|
|
147
|
+
parts.push("json_extract(meta, '$.correlationId') = ?");
|
|
148
|
+
params.push(correlationId);
|
|
149
|
+
}
|
|
150
|
+
params.push(limit);
|
|
151
|
+
return [
|
|
152
|
+
`SELECT position, event_type, data, meta, recorded_at FROM dcb_event WHERE ` + parts.join(" AND ") + ` ORDER BY position DESC LIMIT ?`,
|
|
153
|
+
params
|
|
154
|
+
];
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function readBack(db, name) {
|
|
158
|
+
return async (bound, limit, correlationId) => {
|
|
159
|
+
let match = readBackSql(name, bound, limit, correlationId);
|
|
160
|
+
let rows = SqliteDriver$ReventlessLocal.all(SqliteDriver$ReventlessLocal.prepare(db, match[0]), match[1]);
|
|
161
|
+
let positions = rows.map(row => Stdlib_Option.mapOr(row["position"], 0, coercePosition));
|
|
162
|
+
let tagsByPos = {};
|
|
163
|
+
if (positions.length !== 0) {
|
|
164
|
+
let placeholders = positions.map(param => "?").join(",");
|
|
165
|
+
SqliteDriver$ReventlessLocal.all(SqliteDriver$ReventlessLocal.prepare(db, `SELECT position, tag_key, tag_value FROM dcb_tag WHERE log_name = ? AND position IN (` + placeholders + `) ORDER BY position ASC, rowid ASC`), [name].concat(positions.map(prim => prim))).forEach(row => {
|
|
166
|
+
let k = Stdlib_Option.mapOr(row["position"], 0, coercePosition).toString();
|
|
167
|
+
let str = key => Stdlib_Option.getOr(Stdlib_Option.flatMap(row[key], Stdlib_JSON.Decode.string), "");
|
|
168
|
+
let tag_key = str("tag_key");
|
|
169
|
+
let tag_value = str("tag_value");
|
|
170
|
+
let tag = {
|
|
171
|
+
key: tag_key,
|
|
172
|
+
value: tag_value
|
|
173
|
+
};
|
|
174
|
+
let list = tagsByPos[k];
|
|
175
|
+
if (list !== undefined) {
|
|
176
|
+
list.push(tag);
|
|
177
|
+
} else {
|
|
178
|
+
tagsByPos[k] = [tag];
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
return rows.map(row => {
|
|
183
|
+
let position = Stdlib_Option.mapOr(row["position"], 0, coercePosition);
|
|
184
|
+
let str = key => Stdlib_Option.getOr(Stdlib_Option.flatMap(row[key], Stdlib_JSON.Decode.string), "");
|
|
185
|
+
return {
|
|
186
|
+
log: name,
|
|
187
|
+
position: position,
|
|
188
|
+
eventType: str("event_type"),
|
|
189
|
+
tags: Stdlib_Option.getOr(tagsByPos[position.toString()], []),
|
|
190
|
+
payload: parseDataPayload(str("data")),
|
|
191
|
+
meta: parseDataPayload(str("meta")),
|
|
192
|
+
recordedAt: str("recorded_at")
|
|
193
|
+
};
|
|
194
|
+
});
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
|
|
131
198
|
function makeStorage(db, name, param, param$1, param$2) {
|
|
132
199
|
ensureSchema(db);
|
|
200
|
+
LocalEventLogRead$ReventlessLocal.register(name, "Dcb", readBack(db, name));
|
|
133
201
|
let insertEventStmt = SqliteDriver$ReventlessLocal.prepare(db, "INSERT INTO dcb_event(log_name, position, event_type, data, meta, recorded_at) VALUES(?,?,?,?,?,?)");
|
|
134
202
|
let lastRowidStmt = SqliteDriver$ReventlessLocal.prepare(db, "SELECT last_insert_rowid() AS r");
|
|
135
203
|
let insertTagStmt = SqliteDriver$ReventlessLocal.prepare(db, "INSERT INTO dcb_tag(log_name, position, tag_key, tag_value) VALUES(?,?,?,?)");
|
|
@@ -263,6 +331,7 @@ function makeStorage(db, name, param, param$1, param$2) {
|
|
|
263
331
|
}
|
|
264
332
|
};
|
|
265
333
|
let appended = [];
|
|
334
|
+
let positionsOf = [];
|
|
266
335
|
try {
|
|
267
336
|
SqliteDriver$ReventlessLocal.transaction(db, () => {
|
|
268
337
|
if (condition !== undefined) {
|
|
@@ -310,6 +379,10 @@ function makeStorage(db, name, param, param$1, param$2) {
|
|
|
310
379
|
tag.key,
|
|
311
380
|
tag.value
|
|
312
381
|
]));
|
|
382
|
+
positionsOf.push([
|
|
383
|
+
event.meta.msgId,
|
|
384
|
+
pos
|
|
385
|
+
]);
|
|
313
386
|
lastPos.contents = pos;
|
|
314
387
|
});
|
|
315
388
|
result.contents = {
|
|
@@ -318,6 +391,7 @@ function makeStorage(db, name, param, param$1, param$2) {
|
|
|
318
391
|
};
|
|
319
392
|
});
|
|
320
393
|
ProjectionPending$ReventlessLocal.trackAppended("Dcb", appended);
|
|
394
|
+
positionsOf.forEach(param => LocalEventLogRead$ReventlessLocal.note(name, param[0], param[1]));
|
|
321
395
|
return result.contents;
|
|
322
396
|
} catch (raw_msg) {
|
|
323
397
|
let msg = Primitive_exceptions.internalToException(raw_msg);
|
|
@@ -380,6 +454,8 @@ export {
|
|
|
380
454
|
buildClauseSql,
|
|
381
455
|
buildQueryWhere,
|
|
382
456
|
buildQuerySql,
|
|
457
|
+
readBackSql,
|
|
458
|
+
readBack,
|
|
383
459
|
makeStorage,
|
|
384
460
|
}
|
|
385
461
|
/* Stdlib_JsExn Not a pure module */
|
|
@@ -37,7 +37,14 @@ module Make = (Bus: LocalBus.T) => {
|
|
|
37
37
|
~opts,
|
|
38
38
|
)
|
|
39
39
|
Bus.registerDcbEventLogRead(storageName, ops.read)
|
|
40
|
-
|
|
40
|
+
LocalPgEventLogRead.registerDcb(~pool, ~name=storageName)
|
|
41
|
+
{
|
|
42
|
+
ReventlessCore.DcbEventLog_Adapter.resources: storage.resources,
|
|
43
|
+
operations: Pulumi.Output.make({
|
|
44
|
+
...ops,
|
|
45
|
+
append: LocalPgEventLogRead.notingDcbAppend(~pool, ~name=storageName, ops.append),
|
|
46
|
+
}),
|
|
47
|
+
}
|
|
41
48
|
| (None, None) =>
|
|
42
49
|
let (storageName, read, storage) = DcbEventLogStorage_InMemory.makeStorage(
|
|
43
50
|
~name,
|