@reventlessdev/reventless-local 3.0.0-alpha.249 → 3.0.0-alpha.251
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 +13 -13
- package/src/BakedManifest.res +5 -6
- package/src/EmitCapabilities.res +3 -1
- package/src/LocalPlatformRegistry.res +3 -1
- package/src/LocalPlatformStart.res +7 -6
- package/src/LocalSeedTarget.res +3 -1
- package/src/Platform.res +291 -215
- package/src/ShellConfig.res +10 -17
- package/src/UiHints.res +8 -14
- package/src/UiSlots.res +10 -17
- package/src/adapter/Api/LocalEvents_Server.res +5 -3
- package/src/adapter/Api/LocalGraphQL_Adapter.res +4 -4
- package/src/adapter/Auth/LocalAuth.res +12 -16
- package/src/adapter/Auth/LocalAuth.res.mjs +2 -1
- package/src/adapter/Auth/UserStore.res +13 -40
- package/src/adapter/Auth/UserStore.res.mjs +11 -67
- package/src/adapter/Backend.res +1 -2
- package/src/adapter/CommandGenerator/CommandGeneratorResolvers_GraphQL.res +42 -26
- package/src/adapter/CommandGenerator/InboundTranslationResolvers_GraphQL.res +13 -3
- package/src/adapter/CommandTopic/LocalCommandTopicChannel.res +15 -17
- package/src/adapter/CommandTopic/LocalCommandTopicRemoteChannel.res +18 -22
- package/src/adapter/Counter/LocalCounterHandler.res +1 -1
- package/src/adapter/DcbEventLog/DcbEventLogStorage_InMemory.res +33 -22
- package/src/adapter/DcbEventLog/DcbEventLogStorage_Sqlite.res +57 -57
- package/src/adapter/DomainGraphQL_Server.res +35 -34
- package/src/adapter/DomainMCP_Server.res +45 -41
- package/src/adapter/EventCollector/LocalEventCollectorChannel.res +47 -36
- package/src/adapter/EventHistory/EventHistoryResolvers_GraphQL.res +15 -12
- package/src/adapter/EventLog/EventLogStorage_InMemory.res +9 -4
- package/src/adapter/EventLog/EventLogStorage_Sqlite.res +36 -24
- package/src/adapter/EventTopic/LocalEventTopicPublisher.res +9 -3
- package/src/adapter/Heartbeat/LocalHeartbeatRunner.res +9 -14
- package/src/adapter/LocalBus.res +12 -12
- package/src/adapter/LocalCapabilities.res +6 -0
- package/src/adapter/LocalCapabilities.res.mjs +5 -2
- package/src/adapter/LocalGeocodeResolvers.res +1 -4
- package/src/adapter/LocalSideEffectHandler.res +1 -1
- package/src/adapter/LocalStateChangeDescriptor.res +2 -1
- package/src/adapter/MCP_ServerInstance.res +51 -39
- package/src/adapter/ObjectStore/LocalObjectStore.res +5 -2
- package/src/adapter/ObjectStore/ObjectStoreStorage_FileSystem.res +1 -2
- package/src/adapter/PlatformGraphQL_Server.res +10 -6
- package/src/adapter/PlatformGraphQL_Server.res.mjs +2 -1
- package/src/adapter/ProjectionCheckpoint.res +8 -1
- package/src/adapter/ProjectionPending.res +1 -3
- package/src/adapter/QueryDb/LocalQueryDbStorage.res +2 -1
- package/src/adapter/QueryDb/QueryDbResolvers_GraphQL.res +367 -269
- package/src/adapter/QueryDb/QueryDbStorage_InMemory.res +5 -3
- package/src/adapter/QueryDb/QueryDbStorage_Sqlite.res +63 -40
- package/src/adapter/QueryDb/SortKey_Filter.res +14 -6
- package/src/adapter/Runtime/LocalAggregateRuntime_Builder.res +12 -10
- package/src/adapter/Runtime/LocalEventCollectorRuntime_Builder.res +8 -2
- package/src/adapter/Runtime/LocalPluginRuntime_Builder.res +1 -4
- package/src/adapter/Scheduler/LocalScheduledPublisher.res +12 -12
- package/src/adapter/SqliteDriver.res +16 -4
- package/src/adapter/Task/TaskBucket_Sqlite.res +5 -6
- package/src/components/Aggregate_Builder.res +6 -1
- package/src/components/Counter_Builder.res +1 -5
- package/src/components/DcbEventLog_Builder.res +5 -3
- package/src/components/ExtensionPoint_Builder.res +13 -15
- package/src/components/InboundTranslationSlice_Builder.res +3 -2
- package/src/components/OutboundTranslationSlice_Builder.res +3 -2
- package/src/components/ReadModel_Builder.res +18 -20
- package/src/components/StateViewSlice_Builder.res +3 -2
- package/src/components/Task_Builder.res +12 -13
- package/src/reset/LocalSeedReset.res +2 -5
- package/src/test/Mocks/MockDcbEventLogStorage.res +5 -1
- package/src/test/Mocks/MockEventLogStorage.res +8 -3
- package/src/test/Mocks/MockQueryDbStorage.res +3 -2
- package/src/test/TestRunner.res +1 -1
- package/tests/BakedManifestFilesTest.res +7 -10
- package/tests/LocalEventTapTest.res +26 -21
- package/tests/LocalPlatformStartTest.res +33 -28
- package/tests/PluginEventDecodeTest.res +3 -3
- package/tests/ShellConfigTest.res +30 -21
- package/tests/SplitApiFixtures.res +34 -10
- package/tests/SplitApiTest.res +92 -62
- package/tests/adapter/BackendParityTest.res +180 -130
- package/tests/adapter/CollectNEventsTest.res +6 -4
- package/tests/adapter/CommandAuthorizationTest.res +47 -41
- package/tests/adapter/CommandTopicChannelTest.res +163 -139
- package/tests/adapter/CounterHandlerTest.res +95 -77
- package/tests/adapter/DcbEventLogStorageSqliteTest.res +171 -168
- package/tests/adapter/DcbEventLogStorageTest.res +264 -207
- package/tests/adapter/DomainGraphQL_ServerTest.res +53 -43
- package/tests/adapter/EventCollectorChannelTest.res +153 -124
- package/tests/adapter/EventHistoryResolverTest.res +46 -18
- package/tests/adapter/EventLogSnapshotParityTest.res +57 -45
- package/tests/adapter/EventLogStorageSqliteTest.res +9 -10
- package/tests/adapter/EventTapTest.res +37 -20
- package/tests/adapter/EventTopicPublisherTest.res +74 -50
- package/tests/adapter/GraphQLSubscriptionBridgeTest.res +4 -3
- package/tests/adapter/GraphQL_SchemaInspectorTest.res +666 -568
- package/tests/adapter/GraphQL_SubscriptionResolversTest.res +105 -96
- package/tests/adapter/HeartbeatRunnerTest.res +99 -81
- package/tests/adapter/InboundTranslationMutationTest.res +4 -1
- package/tests/adapter/LocalAuthHttpTest.res +79 -85
- package/tests/adapter/LocalAuthLoginTest.res +42 -50
- package/tests/adapter/LocalAuthTest.res +8 -16
- package/tests/adapter/LocalAuthUserStoreTest.res +2 -7
- package/tests/adapter/LocalBusBoundedTest.res +187 -117
- package/tests/adapter/LocalBusPubSubTest.res +118 -76
- package/tests/adapter/LocalDispatchContextTest.res +1 -2
- package/tests/adapter/LocalEvents_ServerTest.res +242 -187
- package/tests/adapter/PgProjectionCatchupTest.res +44 -10
- package/tests/adapter/ProjectionCheckpointTest.res +261 -206
- package/tests/adapter/QueryDbGsiTtlTest.res +123 -83
- package/tests/adapter/QueryDbListPushdownParityTest.res +107 -67
- package/tests/adapter/QueryDbListResolverTest.res +225 -208
- package/tests/adapter/QueryDbResolvedFieldsTest.res +17 -14
- package/tests/adapter/QueryDbStorageSqliteTest.res +33 -49
- package/tests/adapter/QueryDbStorageTest.res +163 -117
- package/tests/adapter/QueryDbUnionRoundTripTest.res +8 -10
- package/tests/adapter/QueryEngineTest.res +179 -126
- package/tests/adapter/ScheduledPublisherTest.res +171 -135
- package/tests/adapter/ServedBucketHttpTest.res +65 -59
- package/tests/adapter/SortKey_FilterTest.res +19 -3
- package/tests/adapter/SqliteDriverTest.res +13 -10
- package/tests/adapter/TaskBucketTest.res +94 -80
- package/tests/components/aggregate/AggregateTest.res +31 -18
- package/tests/components/automationslice/AutomationSliceCallbackTest.res +259 -222
- package/tests/components/automationslice/AutomationSliceFixtures.res +4 -2
- package/tests/components/automationslice/AutomationSliceSelfDeadlockFixtures.res +38 -38
- package/tests/components/automationslice/MixedSourceAutomationSliceFixtures.res +12 -14
- package/tests/components/automationslice/MixedSourceAutomationSliceTest.res +8 -32
- package/tests/components/commandgenerator/CommandGeneratorFixtures.res +7 -5
- package/tests/components/commandgenerator/CommandGeneratorTest.res +40 -31
- package/tests/components/commandtopic/CommandTopicFixtures.res +3 -4
- package/tests/components/commandtopic/CommandTopicStreamFixtures.res +7 -5
- package/tests/components/commandtopic/CommandTopicTest.res +24 -15
- package/tests/components/counter/CounterFixtures.res +6 -8
- package/tests/components/dcb/DcbCrossPartitionFixtures.res +8 -2
- package/tests/components/dcb/DcbCrossPartitionReadTest.res +20 -13
- package/tests/components/dcb/DcbEventLogAppendStreamTest.res +12 -8
- package/tests/components/dcb/DcbEventLogStreamTest.res +88 -61
- package/tests/components/dcb/DcbFixtures.res +4 -1
- package/tests/components/dcb/DcbTest.res +9 -6
- package/tests/components/eventcollector/EventCollectorFixtures.res +0 -1
- package/tests/components/eventcollector/EventCollectorTest.res +6 -3
- package/tests/components/eventlog/EventLogAppendStreamTest.res +88 -68
- package/tests/components/eventlog/EventLogConflictTest.res +8 -4
- package/tests/components/eventlog/EventLogFixtures.res +3 -3
- package/tests/components/eventlog/EventLogProvisioningSeamTest.res +26 -13
- package/tests/components/eventlog/EventLogStreamTest.res +119 -56
- package/tests/components/eventlog/EventLogTest.res +20 -4
- package/tests/components/eventtopic/EventTopicFixtures.res +3 -3
- package/tests/components/eventtopic/EventTopicStreamFixtures.res +1 -2
- package/tests/components/eventtopic/EventTopicStreamTest.res +7 -1
- package/tests/components/extensionpoint/ExtensionPointFixtures.res +14 -9
- package/tests/components/extensionpoint/ExtensionPointTest.res +3 -2
- package/tests/components/heartbeat/HeartbeatFixtures.res +5 -6
- package/tests/components/heartbeat/HeartbeatTest.res +56 -47
- package/tests/components/inboundtranslationslice/InboundTranslationSliceCallbackTest.res +271 -249
- package/tests/components/inboundtranslationslice/InboundTranslationSliceFixtures.res +3 -2
- package/tests/components/outboundtranslationslice/OutboundTranslationSliceCallbackTest.res +361 -276
- package/tests/components/outboundtranslationslice/OutboundTranslationSliceFixtures.res +8 -10
- package/tests/components/outboundtranslationslice/OutboundTranslationSlicePlatformFixtures.res +37 -43
- package/tests/components/querydb/QueryDbFixtures.res +1 -5
- package/tests/components/querydb/QueryDbTest.res +2 -4
- package/tests/components/readmodel/DcbReadModelE2EFixtures.res +15 -18
- package/tests/components/readmodel/MixedSourceReadModelFixtures.res +5 -7
- package/tests/components/readmodel/ReadModelFixtures.res +8 -8
- package/tests/components/scheduler/SchedulerTest.res +76 -58
- package/tests/components/sideeffecthandler/SideEffectHandlerFixtures.res +4 -4
- package/tests/components/stateviewslice/StateViewSliceDisplayNameFixtures.res +5 -7
- package/tests/components/stateviewslice/StateViewSliceFixtures.res +8 -6
- package/tests/components/stateviewslice/StateViewSliceSubIdFixtures.res +17 -11
- package/tests/components/stateviewslice/StateViewSliceSubIdTest.res +12 -2
- package/tests/components/task/TaskFixtures.res +5 -5
- package/tests/components/task/TaskTest.res +95 -80
- package/tests/plugin/PluginsProjection_GWT.res +3 -1
- package/tests/plugin/UiFragments_GWT.res +6 -1
- package/tests/reset/LocalSeedResetTest.res +1 -0
|
@@ -26,9 +26,21 @@ type diagnostics = {
|
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
type t = {
|
|
29
|
-
registerTool: (
|
|
30
|
-
|
|
31
|
-
|
|
29
|
+
registerTool: (
|
|
30
|
+
~name: string,
|
|
31
|
+
~definition: ReventlessCore.MCP_SchemaGenerator.mcpToolDefinition,
|
|
32
|
+
~handler: toolHandler,
|
|
33
|
+
) => unit,
|
|
34
|
+
registerResource: (
|
|
35
|
+
~name: string,
|
|
36
|
+
~definition: ReventlessCore.MCP_SchemaGenerator.mcpResourceDefinition,
|
|
37
|
+
~handler: resourceHandler,
|
|
38
|
+
) => unit,
|
|
39
|
+
registerResourceTemplate: (
|
|
40
|
+
~name: string,
|
|
41
|
+
~definition: ReventlessCore.MCP_SchemaGenerator.mcpResourceDefinition,
|
|
42
|
+
~handler: resourceHandler,
|
|
43
|
+
) => unit,
|
|
32
44
|
registerToolsFromEntries: (
|
|
33
45
|
~pluginName: string,
|
|
34
46
|
~mutationEntries: array<ReventlessInfra.Api.mutationSchemaEntry>,
|
|
@@ -248,9 +260,7 @@ let make = (~label: string="MCP"): t => {
|
|
|
248
260
|
}
|
|
249
261
|
await handler(uri)
|
|
250
262
|
| None => {
|
|
251
|
-
McpSdk.contents: [
|
|
252
|
-
{McpSdk.uri, text: `{"error": "Resource not found: ${uri}"}`},
|
|
253
|
-
],
|
|
263
|
+
McpSdk.contents: [{McpSdk.uri, text: `{"error": "Resource not found: ${uri}"}`}],
|
|
254
264
|
}
|
|
255
265
|
}
|
|
256
266
|
}
|
|
@@ -261,43 +271,45 @@ let make = (~label: string="MCP"): t => {
|
|
|
261
271
|
|
|
262
272
|
let start = (~port: int=3001, ()) => {
|
|
263
273
|
let httpServer = McpSdk.createHttpServer((req, res) => {
|
|
264
|
-
let _ = (
|
|
265
|
-
|
|
266
|
-
|
|
274
|
+
let _ = (
|
|
275
|
+
async () => {
|
|
276
|
+
let reqMethod = req->McpSdk.method
|
|
277
|
+
let reqUrl = req->McpSdk.url
|
|
267
278
|
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
279
|
+
res->McpSdk.setHeader("Access-Control-Allow-Origin", "*")
|
|
280
|
+
res->McpSdk.setHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, OPTIONS")
|
|
281
|
+
res->McpSdk.setHeader("Access-Control-Allow-Headers", "Content-Type")
|
|
271
282
|
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
283
|
+
if reqUrl == "/mcp" || reqUrl->String.startsWith("/mcp?") {
|
|
284
|
+
switch reqMethod {
|
|
285
|
+
| "OPTIONS" =>
|
|
286
|
+
res->McpSdk.setStatusCode(204)
|
|
287
|
+
res->McpSdk.endResponseNoBody
|
|
288
|
+
| "POST" =>
|
|
289
|
+
let body = await McpSdk_Helpers.parseJsonBody(req)
|
|
290
|
+
let identity = extractIdentity(req)
|
|
291
|
+
let server = createServerInstance(identity)
|
|
292
|
+
let transport = McpSdk.newStreamableHTTPTransport({
|
|
293
|
+
enableJsonResponse: true,
|
|
294
|
+
})
|
|
295
|
+
let _ = await server->McpSdk.connect(transport)
|
|
296
|
+
let _ = await transport->McpSdk.handleRequest(req, res, body)
|
|
297
|
+
| "GET" =>
|
|
298
|
+
res->McpSdk.setHeader("Content-Type", "text/plain")
|
|
299
|
+
res->McpSdk.endResponse(`${label} server running`)
|
|
300
|
+
| "DELETE" =>
|
|
301
|
+
res->McpSdk.setStatusCode(200)
|
|
302
|
+
res->McpSdk.endResponseNoBody
|
|
303
|
+
| _ =>
|
|
304
|
+
res->McpSdk.setStatusCode(405)
|
|
305
|
+
res->McpSdk.endResponse("Method not allowed")
|
|
306
|
+
}
|
|
307
|
+
} else {
|
|
308
|
+
res->McpSdk.setStatusCode(404)
|
|
309
|
+
res->McpSdk.endResponse("Not found")
|
|
295
310
|
}
|
|
296
|
-
} else {
|
|
297
|
-
res->McpSdk.setStatusCode(404)
|
|
298
|
-
res->McpSdk.endResponse("Not found")
|
|
299
311
|
}
|
|
300
|
-
|
|
312
|
+
)()
|
|
301
313
|
})
|
|
302
314
|
|
|
303
315
|
httpServer->McpSdk.listen(port, () => {
|
|
@@ -83,11 +83,14 @@ let declaredStoreList = (): array<(string, string)> => declaredStores->Dict.toAr
|
|
|
83
83
|
// key becomes a path, and `uploads/../../etc/passwd` would otherwise escape the
|
|
84
84
|
// store.
|
|
85
85
|
let servedKey = (path: string): option<string> => {
|
|
86
|
-
let trimmed =
|
|
86
|
+
let trimmed =
|
|
87
|
+
path->String.startsWith("/") ? path->String.slice(~start=1, ~end=path->String.length) : path
|
|
87
88
|
let segments = trimmed->String.split("/")
|
|
88
89
|
let underAPrefix =
|
|
89
90
|
servedPrefixes.contents->Array.some(p =>
|
|
90
|
-
p->String.length > 0 &&
|
|
91
|
+
p->String.length > 0 &&
|
|
92
|
+
trimmed->String.startsWith(p ++ "/") &&
|
|
93
|
+
trimmed->String.length > p->String.length + 1
|
|
91
94
|
)
|
|
92
95
|
if underAPrefix && segments->Array.every(seg => seg != "" && seg != "." && seg != "..") {
|
|
93
96
|
Some(trimmed)
|
|
@@ -178,8 +178,7 @@ let topLevelPrefixes = (~root: string): array<string> =>
|
|
|
178
178
|
| _ => None
|
|
179
179
|
} {
|
|
180
180
|
| None => []
|
|
181
|
-
| Some(entries) =>
|
|
182
|
-
entries->Array.filter(NodeFs.isDirectory)->Array.map(NodeFs.direntName)
|
|
181
|
+
| Some(entries) => entries->Array.filter(NodeFs.isDirectory)->Array.map(NodeFs.direntName)
|
|
183
182
|
}
|
|
184
183
|
|
|
185
184
|
/** Deletes every object under `prefix`, returning how many were removed. Goes
|
|
@@ -27,17 +27,21 @@
|
|
|
27
27
|
// — without the wrapper, anonymous callers could trigger admin mutations
|
|
28
28
|
// (Plugin_Activate / _Deactivate, etc.) just by hitting the platform port.
|
|
29
29
|
|
|
30
|
-
let instance: ReventlessGraphqlServer.GraphQL_ServerInstance.t = ReventlessGraphqlServer.GraphQL_ServerInstance.make(
|
|
30
|
+
let instance: ReventlessGraphqlServer.GraphQL_ServerInstance.t = ReventlessGraphqlServer.GraphQL_ServerInstance.make(
|
|
31
|
+
~label="GraphQL:Platform",
|
|
32
|
+
)
|
|
31
33
|
|
|
32
34
|
// Wrap a resolver dict so every value enforces the Admin group. Keys are
|
|
33
35
|
// preserved; resolvers fall through to the underlying instance once the
|
|
34
36
|
// group check passes.
|
|
35
|
-
let wrapAdmin = (
|
|
36
|
-
|
|
37
|
-
|
|
37
|
+
let wrapAdmin = (resolvers: dict<ReventlessGraphqlServer.GraphQL_ServerInstance.resolverFn>): dict<
|
|
38
|
+
ReventlessGraphqlServer.GraphQL_ServerInstance.resolverFn,
|
|
39
|
+
> => {
|
|
38
40
|
let wrapped = Dict.make()
|
|
39
|
-
resolvers
|
|
40
|
-
|
|
41
|
+
resolvers
|
|
42
|
+
->Dict.toArray
|
|
43
|
+
->Array.forEach(((k, v)) =>
|
|
44
|
+
wrapped->Dict.set(k, Auth_GraphqlContext.requireGroup(~group=Reventless.AdminGroup.name, v))
|
|
41
45
|
)
|
|
42
46
|
wrapped
|
|
43
47
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
2
|
|
|
3
|
+
import * as AdminGroup$Reventless from "@reventlessdev/reventless-spec/src/types/AdminGroup.res.mjs";
|
|
3
4
|
import * as Auth_GraphqlContext$ReventlessLocal from "./Auth/Auth_GraphqlContext.res.mjs";
|
|
4
5
|
import * as GraphQL_ServerInstance$ReventlessGraphqlServer from "@reventlessdev/reventless-graphql-server/src/GraphQL_ServerInstance.res.mjs";
|
|
5
6
|
|
|
@@ -8,7 +9,7 @@ let instance = GraphQL_ServerInstance$ReventlessGraphqlServer.make("GraphQL:Plat
|
|
|
8
9
|
function wrapAdmin(resolvers) {
|
|
9
10
|
let wrapped = {};
|
|
10
11
|
Object.entries(resolvers).forEach(param => {
|
|
11
|
-
wrapped[param[0]] = Auth_GraphqlContext$ReventlessLocal.requireGroup(
|
|
12
|
+
wrapped[param[0]] = Auth_GraphqlContext$ReventlessLocal.requireGroup(AdminGroup$Reventless.name, param[1]);
|
|
12
13
|
});
|
|
13
14
|
return wrapped;
|
|
14
15
|
}
|
|
@@ -259,7 +259,14 @@ let missedRows = (
|
|
|
259
259
|
}
|
|
260
260
|
Some((
|
|
261
261
|
Float.toInt(pos),
|
|
262
|
-
dcbCatchupEnvelope(
|
|
262
|
+
dcbCatchupEnvelope(
|
|
263
|
+
~logName,
|
|
264
|
+
~eventType,
|
|
265
|
+
~dataText,
|
|
266
|
+
~metaText,
|
|
267
|
+
~recordedAt,
|
|
268
|
+
~firstTagValue,
|
|
269
|
+
),
|
|
263
270
|
))
|
|
264
271
|
| _ => None
|
|
265
272
|
}
|
|
@@ -32,9 +32,7 @@ let enableTracking = () => enabled := true
|
|
|
32
32
|
|
|
33
33
|
let trackAppended = (~axis: axis, entries: array<(string, int)>) =>
|
|
34
34
|
if enabled.contents {
|
|
35
|
-
entries->Array.forEach(((msgId, position)) =>
|
|
36
|
-
pendingByMsgId->Dict.set(msgId, (axis, position))
|
|
37
|
-
)
|
|
35
|
+
entries->Array.forEach(((msgId, position)) => pendingByMsgId->Dict.set(msgId, (axis, position)))
|
|
38
36
|
}
|
|
39
37
|
|
|
40
38
|
let resolve = (msgIds: array<string>) =>
|