@reventlessdev/reventless-local 3.0.0-alpha.113

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 (334) hide show
  1. package/CHANGELOG.md +1197 -0
  2. package/LICENSE +202 -0
  3. package/__mocks__/emptyModule.js +2 -0
  4. package/__mocks__/nodeSqlite.mjs +6 -0
  5. package/package.json +67 -0
  6. package/rescript.json +39 -0
  7. package/src/Platform.res +2162 -0
  8. package/src/Platform.res.mjs +3389 -0
  9. package/src/adapter/Api/LocalGraphQL_Adapter.res +29 -0
  10. package/src/adapter/Api/LocalGraphQL_Adapter.res.mjs +26 -0
  11. package/src/adapter/Api/LocalGraphQL_SubscriptionResolvers.res +146 -0
  12. package/src/adapter/Api/LocalGraphQL_SubscriptionResolvers.res.mjs +88 -0
  13. package/src/adapter/Auth/Auth_GraphqlContext.res +83 -0
  14. package/src/adapter/Auth/Auth_GraphqlContext.res.mjs +76 -0
  15. package/src/adapter/Auth/LocalAuth.res +239 -0
  16. package/src/adapter/Auth/LocalAuth.res.mjs +247 -0
  17. package/src/adapter/Auth/UserStore.res +134 -0
  18. package/src/adapter/Auth/UserStore.res.mjs +146 -0
  19. package/src/adapter/Backend.res +46 -0
  20. package/src/adapter/Backend.res.mjs +66 -0
  21. package/src/adapter/BackendState.res +34 -0
  22. package/src/adapter/BackendState.res.mjs +42 -0
  23. package/src/adapter/Cloner/LocalClonerRunner.res +13 -0
  24. package/src/adapter/Cloner/LocalClonerRunner.res.mjs +12 -0
  25. package/src/adapter/CommandGenerator/CommandGeneratorResolvers_GraphQL.res +329 -0
  26. package/src/adapter/CommandGenerator/CommandGeneratorResolvers_GraphQL.res.mjs +301 -0
  27. package/src/adapter/CommandGenerator/InboundTranslationResolvers_GraphQL.res +76 -0
  28. package/src/adapter/CommandGenerator/InboundTranslationResolvers_GraphQL.res.mjs +57 -0
  29. package/src/adapter/CommandGenerator/LocalCommandGeneratorResolvers.res +19 -0
  30. package/src/adapter/CommandGenerator/LocalCommandGeneratorResolvers.res.mjs +19 -0
  31. package/src/adapter/CommandTopic/LocalCommandTopicChannel.res +104 -0
  32. package/src/adapter/CommandTopic/LocalCommandTopicChannel.res.mjs +82 -0
  33. package/src/adapter/CommandTopic/LocalCommandTopicRemoteChannel.res +32 -0
  34. package/src/adapter/CommandTopic/LocalCommandTopicRemoteChannel.res.mjs +38 -0
  35. package/src/adapter/Counter/LocalCounterHandler.res +42 -0
  36. package/src/adapter/Counter/LocalCounterHandler.res.mjs +45 -0
  37. package/src/adapter/DcbEventLog/DcbEventLogStorage_InMemory.res +131 -0
  38. package/src/adapter/DcbEventLog/DcbEventLogStorage_InMemory.res.mjs +140 -0
  39. package/src/adapter/DcbEventLog/DcbEventLogStorage_Sqlite.res +334 -0
  40. package/src/adapter/DcbEventLog/DcbEventLogStorage_Sqlite.res.mjs +299 -0
  41. package/src/adapter/DomainGraphQL_Server.res +565 -0
  42. package/src/adapter/DomainGraphQL_Server.res.mjs +576 -0
  43. package/src/adapter/DomainMCP_Server.res +369 -0
  44. package/src/adapter/DomainMCP_Server.res.mjs +358 -0
  45. package/src/adapter/EventCollector/LocalEventCollectorChannel.res +87 -0
  46. package/src/adapter/EventCollector/LocalEventCollectorChannel.res.mjs +45 -0
  47. package/src/adapter/EventLog/EventLogStorage_InMemory.res +105 -0
  48. package/src/adapter/EventLog/EventLogStorage_InMemory.res.mjs +117 -0
  49. package/src/adapter/EventLog/EventLogStorage_Sqlite.res +145 -0
  50. package/src/adapter/EventLog/EventLogStorage_Sqlite.res.mjs +155 -0
  51. package/src/adapter/EventTopic/LocalEventTopicPublisher.res +36 -0
  52. package/src/adapter/EventTopic/LocalEventTopicPublisher.res.mjs +31 -0
  53. package/src/adapter/GraphQL_Server.res +6 -0
  54. package/src/adapter/GraphQL_Server.res.mjs +154 -0
  55. package/src/adapter/GraphQL_ServerInstance.res +310 -0
  56. package/src/adapter/GraphQL_ServerInstance.res.mjs +257 -0
  57. package/src/adapter/Heartbeat/LocalHeartbeatRunner.res +57 -0
  58. package/src/adapter/Heartbeat/LocalHeartbeatRunner.res.mjs +34 -0
  59. package/src/adapter/LocalBus.res +498 -0
  60. package/src/adapter/LocalBus.res.mjs +1011 -0
  61. package/src/adapter/LocalPluginSpec.res +16 -0
  62. package/src/adapter/LocalPluginSpec.res.mjs +33 -0
  63. package/src/adapter/LocalSideEffectHandler.res +44 -0
  64. package/src/adapter/LocalSideEffectHandler.res.mjs +34 -0
  65. package/src/adapter/MCP_Server.res +4 -0
  66. package/src/adapter/MCP_Server.res.mjs +67 -0
  67. package/src/adapter/MCP_ServerInstance.res +362 -0
  68. package/src/adapter/MCP_ServerInstance.res.mjs +313 -0
  69. package/src/adapter/PlatformGraphQL_Server.res +75 -0
  70. package/src/adapter/PlatformGraphQL_Server.res.mjs +84 -0
  71. package/src/adapter/PlatformMCP_Server.res +23 -0
  72. package/src/adapter/PlatformMCP_Server.res.mjs +46 -0
  73. package/src/adapter/QueryDb/QueryDbResolvers_GraphQL.res +793 -0
  74. package/src/adapter/QueryDb/QueryDbResolvers_GraphQL.res.mjs +569 -0
  75. package/src/adapter/QueryDb/QueryDbStorage_InMemory.res +242 -0
  76. package/src/adapter/QueryDb/QueryDbStorage_InMemory.res.mjs +241 -0
  77. package/src/adapter/QueryDb/QueryDbStorage_Sqlite.res +339 -0
  78. package/src/adapter/QueryDb/QueryDbStorage_Sqlite.res.mjs +318 -0
  79. package/src/adapter/QueryDb/SortKey_Filter.res +48 -0
  80. package/src/adapter/QueryDb/SortKey_Filter.res.mjs +46 -0
  81. package/src/adapter/QueryEngine/LocalQueryEngine.res +57 -0
  82. package/src/adapter/QueryEngine/LocalQueryEngine.res.mjs +56 -0
  83. package/src/adapter/Runtime/LocalAggregateRuntime_Builder.res +91 -0
  84. package/src/adapter/Runtime/LocalAggregateRuntime_Builder.res.mjs +50 -0
  85. package/src/adapter/Runtime/LocalEventCollectorRuntime_Builder.res +47 -0
  86. package/src/adapter/Runtime/LocalEventCollectorRuntime_Builder.res.mjs +37 -0
  87. package/src/adapter/Runtime/LocalPluginRuntime_Builder.res +11 -0
  88. package/src/adapter/Runtime/LocalPluginRuntime_Builder.res.mjs +30 -0
  89. package/src/adapter/Runtime/LocalRuntimeEnvironment.res +54 -0
  90. package/src/adapter/Runtime/LocalRuntimeEnvironment.res.mjs +40 -0
  91. package/src/adapter/Scheduler/LocalScheduledPublisher.res +102 -0
  92. package/src/adapter/Scheduler/LocalScheduledPublisher.res.mjs +84 -0
  93. package/src/adapter/SqliteDriver.res +52 -0
  94. package/src/adapter/SqliteDriver.res.mjs +76 -0
  95. package/src/adapter/SqliteDriver.resi +31 -0
  96. package/src/adapter/Task/LocalTaskBucket.res +75 -0
  97. package/src/adapter/Task/LocalTaskBucket.res.mjs +48 -0
  98. package/src/adapter/Task/TaskBucket_Sqlite.res +47 -0
  99. package/src/adapter/Task/TaskBucket_Sqlite.res.mjs +40 -0
  100. package/src/components/Aggregate_Builder.res +55 -0
  101. package/src/components/Aggregate_Builder.res.mjs +140 -0
  102. package/src/components/AutomationSlice_Builder.res +41 -0
  103. package/src/components/AutomationSlice_Builder.res.mjs +57 -0
  104. package/src/components/Counter_Builder.res +14 -0
  105. package/src/components/Counter_Builder.res.mjs +32 -0
  106. package/src/components/DcbEventLog_Builder.res +18 -0
  107. package/src/components/DcbEventLog_Builder.res.mjs +24 -0
  108. package/src/components/ExtensionPoint_Builder.res +25 -0
  109. package/src/components/ExtensionPoint_Builder.res.mjs +44 -0
  110. package/src/components/InboundTranslationSlice_Builder.res +34 -0
  111. package/src/components/InboundTranslationSlice_Builder.res.mjs +45 -0
  112. package/src/components/OutboundTranslationSlice_Builder.res +43 -0
  113. package/src/components/OutboundTranslationSlice_Builder.res.mjs +59 -0
  114. package/src/components/Plugin_Builder.res +37 -0
  115. package/src/components/Plugin_Builder.res.mjs +67 -0
  116. package/src/components/ReadModel_Builder.res +47 -0
  117. package/src/components/ReadModel_Builder.res.mjs +54 -0
  118. package/src/components/StateChangeSlice_Builder.res +19 -0
  119. package/src/components/StateChangeSlice_Builder.res.mjs +21 -0
  120. package/src/components/StateViewSlice_Builder.res +42 -0
  121. package/src/components/StateViewSlice_Builder.res.mjs +58 -0
  122. package/src/components/Task_Builder.res +28 -0
  123. package/src/components/Task_Builder.res.mjs +41 -0
  124. package/src/reexport/CommandTopic.res +3 -0
  125. package/src/reexport/CommandTopic.res.mjs +55 -0
  126. package/src/test/Mocks/MockDcbEventLogStorage.res +136 -0
  127. package/src/test/Mocks/MockDcbEventLogStorage.res.mjs +146 -0
  128. package/src/test/Mocks/MockEventLogStorage.res +57 -0
  129. package/src/test/Mocks/MockEventLogStorage.res.mjs +65 -0
  130. package/src/test/Mocks/MockPublisher.res +29 -0
  131. package/src/test/Mocks/MockPublisher.res.mjs +28 -0
  132. package/src/test/Mocks/MockQueryDbStorage.res +104 -0
  133. package/src/test/Mocks/MockQueryDbStorage.res.mjs +136 -0
  134. package/src/test/TestRunner.res +96 -0
  135. package/src/test/TestRunner.res.mjs +71 -0
  136. package/tests/SplitApiFixtures.res +84 -0
  137. package/tests/SplitApiFixtures.res.mjs +88 -0
  138. package/tests/SplitApiTest.res +102 -0
  139. package/tests/SplitApiTest.res.mjs +82 -0
  140. package/tests/TestFixtures.res +54 -0
  141. package/tests/TestFixtures.res.mjs +65 -0
  142. package/tests/adapter/BackendParityTest.res +94 -0
  143. package/tests/adapter/BackendParityTest.res.mjs +96 -0
  144. package/tests/adapter/CollectNEventsTest.res +82 -0
  145. package/tests/adapter/CollectNEventsTest.res.mjs +83 -0
  146. package/tests/adapter/CommandAuthorizationTest.res +200 -0
  147. package/tests/adapter/CommandAuthorizationTest.res.mjs +190 -0
  148. package/tests/adapter/CommandTopicChannelTest.res +174 -0
  149. package/tests/adapter/CommandTopicChannelTest.res.mjs +170 -0
  150. package/tests/adapter/CounterHandlerTest.res +113 -0
  151. package/tests/adapter/CounterHandlerTest.res.mjs +96 -0
  152. package/tests/adapter/DcbEventLogStorageSqliteTest.res +157 -0
  153. package/tests/adapter/DcbEventLogStorageSqliteTest.res.mjs +165 -0
  154. package/tests/adapter/DcbEventLogStorageTest.res +187 -0
  155. package/tests/adapter/DcbEventLogStorageTest.res.mjs +195 -0
  156. package/tests/adapter/EventCollectorChannelTest.res +166 -0
  157. package/tests/adapter/EventCollectorChannelTest.res.mjs +178 -0
  158. package/tests/adapter/EventLogStorageSqliteTest.res +105 -0
  159. package/tests/adapter/EventLogStorageSqliteTest.res.mjs +116 -0
  160. package/tests/adapter/EventTapTest.res +102 -0
  161. package/tests/adapter/EventTapTest.res.mjs +94 -0
  162. package/tests/adapter/EventTopicPublisherTest.res +76 -0
  163. package/tests/adapter/EventTopicPublisherTest.res.mjs +86 -0
  164. package/tests/adapter/GraphQL_SchemaInspectorTest.res +763 -0
  165. package/tests/adapter/GraphQL_SchemaInspectorTest.res.mjs +578 -0
  166. package/tests/adapter/GraphQL_SubscriptionResolversTest.res +161 -0
  167. package/tests/adapter/GraphQL_SubscriptionResolversTest.res.mjs +134 -0
  168. package/tests/adapter/HeartbeatRunnerTest.res +136 -0
  169. package/tests/adapter/HeartbeatRunnerTest.res.mjs +96 -0
  170. package/tests/adapter/LocalAuthHttpTest.res +224 -0
  171. package/tests/adapter/LocalAuthHttpTest.res.mjs +237 -0
  172. package/tests/adapter/LocalAuthLoginTest.res +180 -0
  173. package/tests/adapter/LocalAuthLoginTest.res.mjs +207 -0
  174. package/tests/adapter/LocalAuthTest.res +106 -0
  175. package/tests/adapter/LocalAuthTest.res.mjs +145 -0
  176. package/tests/adapter/LocalAuthUserStoreTest.res +172 -0
  177. package/tests/adapter/LocalAuthUserStoreTest.res.mjs +208 -0
  178. package/tests/adapter/LocalBusBoundedTest.res +157 -0
  179. package/tests/adapter/LocalBusBoundedTest.res.mjs +168 -0
  180. package/tests/adapter/LocalBusPubSubTest.res +81 -0
  181. package/tests/adapter/LocalBusPubSubTest.res.mjs +81 -0
  182. package/tests/adapter/QueryDbGsiTtlTest.res +268 -0
  183. package/tests/adapter/QueryDbGsiTtlTest.res.mjs +209 -0
  184. package/tests/adapter/QueryDbListResolverTest.res +361 -0
  185. package/tests/adapter/QueryDbListResolverTest.res.mjs +426 -0
  186. package/tests/adapter/QueryDbStorageSqliteTest.res +159 -0
  187. package/tests/adapter/QueryDbStorageSqliteTest.res.mjs +126 -0
  188. package/tests/adapter/QueryDbStorageTest.res +171 -0
  189. package/tests/adapter/QueryDbStorageTest.res.mjs +170 -0
  190. package/tests/adapter/QueryEngineTest.res +152 -0
  191. package/tests/adapter/QueryEngineTest.res.mjs +148 -0
  192. package/tests/adapter/ScheduledPublisherTest.res +199 -0
  193. package/tests/adapter/ScheduledPublisherTest.res.mjs +203 -0
  194. package/tests/adapter/SortKey_FilterTest.res +103 -0
  195. package/tests/adapter/SortKey_FilterTest.res.mjs +135 -0
  196. package/tests/adapter/SqliteDriverTest.res +86 -0
  197. package/tests/adapter/SqliteDriverTest.res.mjs +101 -0
  198. package/tests/adapter/TaskBucketSqliteTest.res +44 -0
  199. package/tests/adapter/TaskBucketSqliteTest.res.mjs +40 -0
  200. package/tests/adapter/TaskBucketTest.res +106 -0
  201. package/tests/adapter/TaskBucketTest.res.mjs +118 -0
  202. package/tests/components/aggregate/AggregateFixtures.res +78 -0
  203. package/tests/components/aggregate/AggregateFixtures.res.mjs +109 -0
  204. package/tests/components/aggregate/AggregateTest.res +129 -0
  205. package/tests/components/aggregate/AggregateTest.res.mjs +129 -0
  206. package/tests/components/automationslice/AutomationSliceCallbackTest.res +212 -0
  207. package/tests/components/automationslice/AutomationSliceCallbackTest.res.mjs +233 -0
  208. package/tests/components/automationslice/AutomationSliceFixtures.res +189 -0
  209. package/tests/components/automationslice/AutomationSliceFixtures.res.mjs +276 -0
  210. package/tests/components/automationslice/AutomationSliceSelfDeadlockFixtures.res +289 -0
  211. package/tests/components/automationslice/AutomationSliceSelfDeadlockFixtures.res.mjs +453 -0
  212. package/tests/components/automationslice/AutomationSliceSelfDeadlockTest.res +47 -0
  213. package/tests/components/automationslice/AutomationSliceSelfDeadlockTest.res.mjs +31 -0
  214. package/tests/components/automationslice/MixedSourceAutomationSliceFixtures.res +213 -0
  215. package/tests/components/automationslice/MixedSourceAutomationSliceFixtures.res.mjs +268 -0
  216. package/tests/components/automationslice/MixedSourceAutomationSliceTest.res +118 -0
  217. package/tests/components/automationslice/MixedSourceAutomationSliceTest.res.mjs +99 -0
  218. package/tests/components/commandgenerator/CommandGeneratorFixtures.res +73 -0
  219. package/tests/components/commandgenerator/CommandGeneratorFixtures.res.mjs +109 -0
  220. package/tests/components/commandgenerator/CommandGeneratorTest.res +43 -0
  221. package/tests/components/commandgenerator/CommandGeneratorTest.res.mjs +46 -0
  222. package/tests/components/commandtopic/CommandTopicFixtures.res +37 -0
  223. package/tests/components/commandtopic/CommandTopicFixtures.res.mjs +68 -0
  224. package/tests/components/commandtopic/CommandTopicStreamFixtures.res +43 -0
  225. package/tests/components/commandtopic/CommandTopicStreamFixtures.res.mjs +91 -0
  226. package/tests/components/commandtopic/CommandTopicStreamTest.res +30 -0
  227. package/tests/components/commandtopic/CommandTopicStreamTest.res.mjs +35 -0
  228. package/tests/components/commandtopic/CommandTopicTest.res +55 -0
  229. package/tests/components/commandtopic/CommandTopicTest.res.mjs +62 -0
  230. package/tests/components/counter/CounterFixtures.res +42 -0
  231. package/tests/components/counter/CounterFixtures.res.mjs +34 -0
  232. package/tests/components/counter/CounterTest.res +46 -0
  233. package/tests/components/counter/CounterTest.res.mjs +61 -0
  234. package/tests/components/dcb/DcbCrossPartitionFixtures.res +170 -0
  235. package/tests/components/dcb/DcbCrossPartitionFixtures.res.mjs +276 -0
  236. package/tests/components/dcb/DcbCrossPartitionReadTest.res +68 -0
  237. package/tests/components/dcb/DcbCrossPartitionReadTest.res.mjs +78 -0
  238. package/tests/components/dcb/DcbEventLogAppendStreamTest.res +72 -0
  239. package/tests/components/dcb/DcbEventLogAppendStreamTest.res.mjs +82 -0
  240. package/tests/components/dcb/DcbEventLogStreamTest.res +103 -0
  241. package/tests/components/dcb/DcbEventLogStreamTest.res.mjs +91 -0
  242. package/tests/components/dcb/DcbFixtures.res +145 -0
  243. package/tests/components/dcb/DcbFixtures.res.mjs +221 -0
  244. package/tests/components/dcb/DcbTest.res +55 -0
  245. package/tests/components/dcb/DcbTest.res.mjs +55 -0
  246. package/tests/components/eventcollector/EventCollectorFixtures.res +42 -0
  247. package/tests/components/eventcollector/EventCollectorFixtures.res.mjs +49 -0
  248. package/tests/components/eventcollector/EventCollectorTest.res +37 -0
  249. package/tests/components/eventcollector/EventCollectorTest.res.mjs +36 -0
  250. package/tests/components/eventlog/EventLogAppendStreamTest.res +93 -0
  251. package/tests/components/eventlog/EventLogAppendStreamTest.res.mjs +113 -0
  252. package/tests/components/eventlog/EventLogConflictTest.res +86 -0
  253. package/tests/components/eventlog/EventLogConflictTest.res.mjs +81 -0
  254. package/tests/components/eventlog/EventLogFixtures.res +52 -0
  255. package/tests/components/eventlog/EventLogFixtures.res.mjs +80 -0
  256. package/tests/components/eventlog/EventLogStreamTest.res +98 -0
  257. package/tests/components/eventlog/EventLogStreamTest.res.mjs +142 -0
  258. package/tests/components/eventlog/EventLogTest.res +53 -0
  259. package/tests/components/eventlog/EventLogTest.res.mjs +74 -0
  260. package/tests/components/eventtopic/EventTopicFixtures.res +47 -0
  261. package/tests/components/eventtopic/EventTopicFixtures.res.mjs +77 -0
  262. package/tests/components/eventtopic/EventTopicStreamFixtures.res +27 -0
  263. package/tests/components/eventtopic/EventTopicStreamFixtures.res.mjs +62 -0
  264. package/tests/components/eventtopic/EventTopicStreamTest.res +35 -0
  265. package/tests/components/eventtopic/EventTopicStreamTest.res.mjs +44 -0
  266. package/tests/components/eventtopic/EventTopicTest.res +35 -0
  267. package/tests/components/eventtopic/EventTopicTest.res.mjs +43 -0
  268. package/tests/components/extensionpoint/ExtensionPointFixtures.res +145 -0
  269. package/tests/components/extensionpoint/ExtensionPointFixtures.res.mjs +188 -0
  270. package/tests/components/extensionpoint/ExtensionPointTest.res +62 -0
  271. package/tests/components/extensionpoint/ExtensionPointTest.res.mjs +55 -0
  272. package/tests/components/heartbeat/HeartbeatFixtures.res +48 -0
  273. package/tests/components/heartbeat/HeartbeatFixtures.res.mjs +46 -0
  274. package/tests/components/heartbeat/HeartbeatTest.res +67 -0
  275. package/tests/components/heartbeat/HeartbeatTest.res.mjs +65 -0
  276. package/tests/components/inboundtranslationslice/InboundTranslationSliceCallbackTest.res +241 -0
  277. package/tests/components/inboundtranslationslice/InboundTranslationSliceCallbackTest.res.mjs +239 -0
  278. package/tests/components/inboundtranslationslice/InboundTranslationSliceFixtures.res +36 -0
  279. package/tests/components/inboundtranslationslice/InboundTranslationSliceFixtures.res.mjs +73 -0
  280. package/tests/components/outboundtranslationslice/OutboundTranslationSliceCallbackTest.res +191 -0
  281. package/tests/components/outboundtranslationslice/OutboundTranslationSliceCallbackTest.res.mjs +297 -0
  282. package/tests/components/outboundtranslationslice/OutboundTranslationSliceFixtures.res +78 -0
  283. package/tests/components/outboundtranslationslice/OutboundTranslationSliceFixtures.res.mjs +137 -0
  284. package/tests/components/querydb/QueryDbFixtures.res +39 -0
  285. package/tests/components/querydb/QueryDbFixtures.res.mjs +73 -0
  286. package/tests/components/querydb/QueryDbSubIdFixtures.res +44 -0
  287. package/tests/components/querydb/QueryDbSubIdFixtures.res.mjs +80 -0
  288. package/tests/components/querydb/QueryDbSubIdTest.res +104 -0
  289. package/tests/components/querydb/QueryDbSubIdTest.res.mjs +104 -0
  290. package/tests/components/querydb/QueryDbTest.res +81 -0
  291. package/tests/components/querydb/QueryDbTest.res.mjs +126 -0
  292. package/tests/components/readmodel/DcbReadModelE2EFixtures.res +215 -0
  293. package/tests/components/readmodel/DcbReadModelE2EFixtures.res.mjs +308 -0
  294. package/tests/components/readmodel/DcbReadModelE2ETest.res +45 -0
  295. package/tests/components/readmodel/DcbReadModelE2ETest.res.mjs +37 -0
  296. package/tests/components/readmodel/DcbReadModelTypoFailFastTest.res +88 -0
  297. package/tests/components/readmodel/DcbReadModelTypoFailFastTest.res.mjs +152 -0
  298. package/tests/components/readmodel/MixedSourceReadModelFixtures.res +181 -0
  299. package/tests/components/readmodel/MixedSourceReadModelFixtures.res.mjs +277 -0
  300. package/tests/components/readmodel/MixedSourceReadModelTest.res +61 -0
  301. package/tests/components/readmodel/MixedSourceReadModelTest.res.mjs +68 -0
  302. package/tests/components/readmodel/ReadModelFixtures.res +138 -0
  303. package/tests/components/readmodel/ReadModelFixtures.res.mjs +169 -0
  304. package/tests/components/readmodel/ReadModelTest.res +46 -0
  305. package/tests/components/readmodel/ReadModelTest.res.mjs +36 -0
  306. package/tests/components/scheduler/SchedulerFixtures.res +59 -0
  307. package/tests/components/scheduler/SchedulerFixtures.res.mjs +63 -0
  308. package/tests/components/scheduler/SchedulerTest.res +76 -0
  309. package/tests/components/scheduler/SchedulerTest.res.mjs +86 -0
  310. package/tests/components/sideeffecthandler/SideEffectHandlerFixtures.res +133 -0
  311. package/tests/components/sideeffecthandler/SideEffectHandlerFixtures.res.mjs +149 -0
  312. package/tests/components/sideeffecthandler/SideEffectHandlerTest.res +39 -0
  313. package/tests/components/sideeffecthandler/SideEffectHandlerTest.res.mjs +28 -0
  314. package/tests/components/stateviewslice/StateViewSliceFixtures.res +117 -0
  315. package/tests/components/stateviewslice/StateViewSliceFixtures.res.mjs +188 -0
  316. package/tests/components/stateviewslice/StateViewSliceSubIdFixtures.res +117 -0
  317. package/tests/components/stateviewslice/StateViewSliceSubIdFixtures.res.mjs +183 -0
  318. package/tests/components/stateviewslice/StateViewSliceSubIdTest.res +78 -0
  319. package/tests/components/stateviewslice/StateViewSliceSubIdTest.res.mjs +107 -0
  320. package/tests/components/stateviewslice/StateViewSliceTest.res +59 -0
  321. package/tests/components/stateviewslice/StateViewSliceTest.res.mjs +72 -0
  322. package/tests/components/task/TaskFixtures.res +87 -0
  323. package/tests/components/task/TaskFixtures.res.mjs +82 -0
  324. package/tests/components/task/TaskTest.res +98 -0
  325. package/tests/components/task/TaskTest.res.mjs +46 -0
  326. package/tests/plugin/PluginBehavior_GWT.res +146 -0
  327. package/tests/plugin/PluginBehavior_GWT.res.mjs +281 -0
  328. package/tests/plugin/Plugin_Fixtures.res +61 -0
  329. package/tests/plugin/Plugin_Fixtures.res.mjs +105 -0
  330. package/tests/plugin/PluginsProjection_GWT.res +95 -0
  331. package/tests/plugin/PluginsProjection_GWT.res.mjs +120 -0
  332. package/tests/plugin/UIFragmentRegistryProjection_GWT.res +72 -0
  333. package/tests/plugin/UIFragmentRegistryProjection_GWT.res.mjs +117 -0
  334. package/tests/setup/sqliteGlobal.cjs +12 -0
@@ -0,0 +1,565 @@
1
+ // Domain (plugin-facing) in-memory GraphQL server — singleton.
2
+ // Collects SDL fragments and resolver functions from CommandGeneratorResolvers_GraphQL
3
+ // (mutations), QueryDbResolvers_GraphQL (queries), and InboundTranslationResolvers_GraphQL
4
+ // during Platform.Make().
5
+ // start() is called once after all components are built.
6
+ //
7
+ // Contains domain-specific extras not present in the platform server:
8
+ // - Relay Global ID encoding/decoding (encodeGlobalId / decodeGlobalId)
9
+ // - Node type registry (registerNodeType / registerNodeResolverCallback)
10
+ // - /sdl HTTP endpoint for Relay compiler
11
+ // - rebuildSchema for schema stitching
12
+ //
13
+ // Note: the old setRegistrationTarget redirect hack has been removed. Routing
14
+ // to the platform server is now done explicitly via resolveTargetGraphQL() in
15
+ // Platform.res (mirroring the AWS resolveTargetApi() pattern).
16
+
17
+ module YG = GraphqlYoga
18
+
19
+ let log = ReventlessCore.Logger.fromEnv()
20
+
21
+ // -- Node.js HTTP bindings ---------------------------------------------------
22
+ // /sdl serves the printed schema; /__inmemory/login & /logout serve the A4
23
+ // token-issuance endpoints. Everything else falls through to graphql-yoga.
24
+
25
+ type nodeRequest = {url: string, method: string, headers: dict<string>}
26
+ type nodeResponse
27
+ @send external writeHead: (nodeResponse, int, {..}) => unit = "writeHead"
28
+ @send external end_: (nodeResponse, string) => unit = "end"
29
+ @send external endEmpty: (nodeResponse, @as(json`null`) _) => unit = "end"
30
+
31
+ // Streaming body collector — request data fires once per chunk, end once at EOF.
32
+ @send external _onData: (nodeRequest, @as("data") _, string => unit) => unit = "on"
33
+ @send external _onEnd: (nodeRequest, @as("end") _, unit => unit) => unit = "on"
34
+ @send external _setEncoding: (nodeRequest, string) => unit = "setEncoding"
35
+
36
+ let readBody = (req: nodeRequest, onBody: string => unit): unit => {
37
+ let buf = ref("")
38
+ req->_setEncoding("utf8")
39
+ req->_onData(chunk => buf := buf.contents ++ chunk)
40
+ req->_onEnd(() => onBody(buf.contents))
41
+ }
42
+
43
+ type requestHandler = (nodeRequest, nodeResponse) => unit
44
+ @module("http") external createServerWithHandler: requestHandler => YG.httpServer = "createServer"
45
+
46
+ // -- /__inmemory/login + /logout handlers -----------------------------------
47
+
48
+ let _writeJson = (res: nodeResponse, ~status: int, body: JSON.t): unit => {
49
+ res->writeHead(
50
+ status,
51
+ {"Content-Type": "application/json", "Access-Control-Allow-Origin": "*"},
52
+ )
53
+ res->end_(body->JSON.stringify)
54
+ }
55
+
56
+ let _loginRejected = (res: nodeResponse, ~error: string): unit =>
57
+ _writeJson(
58
+ res,
59
+ ~status=401,
60
+ JSON.Encode.object(Dict.fromArray([("error", JSON.Encode.string(error))])),
61
+ )
62
+
63
+ type _loginBody = {username: string, password: string}
64
+
65
+ let handleLogin = (req: nodeRequest, res: nodeResponse): unit =>
66
+ readBody(req, body => {
67
+ let parsed = try {
68
+ Some((body->JSON.parseOrThrow->Obj.magic: _loginBody))
69
+ } catch {
70
+ | _ => None
71
+ }
72
+ switch parsed {
73
+ | None => _loginRejected(res, ~error="Invalid JSON body")
74
+ | Some({username, password}) =>
75
+ let _ = LocalAuth.Login.issue(~username, ~password)->Promise.then(result => {
76
+ switch result {
77
+ | Error(msg) => _loginRejected(res, ~error=msg)
78
+ | Ok(token) =>
79
+ // Echo back the identity the client will see in subsequent
80
+ // ctx.identity values, so the SPA doesn't need a second round-trip.
81
+ let identity = switch LocalAuth.lookupUser(username) {
82
+ | Some(i) => i
83
+ | None => Reventless.Identity.anonymous
84
+ }
85
+ let identityJson =
86
+ identity->S.reverseConvertToJsonOrThrow(Reventless.Identity.schema)
87
+ _writeJson(
88
+ res,
89
+ ~status=200,
90
+ JSON.Encode.object(
91
+ Dict.fromArray([
92
+ ("token", JSON.Encode.string(token)),
93
+ ("identity", identityJson),
94
+ ]),
95
+ ),
96
+ )
97
+ }
98
+ Promise.resolve()
99
+ })
100
+ }
101
+ })
102
+
103
+ let handleLogout = (_req: nodeRequest, res: nodeResponse): unit => {
104
+ res->writeHead(204, {"Access-Control-Allow-Origin": "*"})
105
+ res->endEmpty
106
+ }
107
+
108
+ // Returns true when the request carries an `Authorization: Bearer <token>`
109
+ // header whose token fails HMAC verification. No header (anonymous), or a
110
+ // non-Bearer scheme (e.g. X-User flows), returns false — only an *invalid*
111
+ // Bearer is a rejection. Mirrors the LocalAuth.authenticate decoding
112
+ // rule so HTTP-level rejection matches resolver-level identity.
113
+ let _isInvalidBearer = (req: nodeRequest): bool =>
114
+ switch req.headers->Dict.get("authorization") {
115
+ | Some(h) if String.startsWith(h, "Bearer ") =>
116
+ let token =
117
+ String.slice(h, ~start=7, ~end=String.length(h))->String.trim
118
+ LocalAuth.Login.verifyAndDecode(token)->Option.isNone
119
+ | _ => false
120
+ }
121
+
122
+ // Shared dispatch for start() and rebuildSchema(). Order matters: built-in
123
+ // endpoints win over the yoga catch-all so they aren't shadowed by graphql.
124
+ let _dispatch = (req: nodeRequest, res: nodeResponse, yoga: YG.yoga, getSdl: unit => string): unit => {
125
+ // Strip query string before path matching.
126
+ let path = req.url->String.split("?")->Array.get(0)->Option.getOr(req.url)
127
+ // /__inmemory/login is the path that *issues* tokens — it never carries
128
+ // one. Every other path must reject an unverifiable Bearer with 401 so
129
+ // the host-shell's `on401` logout path can fire on stale tokens.
130
+ if path != "/__inmemory/login" && _isInvalidBearer(req) {
131
+ _writeJson(
132
+ res,
133
+ ~status=401,
134
+ JSON.Encode.object(
135
+ Dict.fromArray([("error", JSON.Encode.string("Invalid bearer token"))]),
136
+ ),
137
+ )
138
+ } else if path == "/sdl" {
139
+ res->writeHead(200, {"Content-Type": "text/plain", "Access-Control-Allow-Origin": "*"})
140
+ res->end_(getSdl())
141
+ } else if path == "/__inmemory/login" && req.method == "POST" {
142
+ handleLogin(req, res)
143
+ } else if path == "/__inmemory/logout" && req.method == "POST" {
144
+ handleLogout(req, res)
145
+ } else {
146
+ (yoga->Obj.magic)(req, res)
147
+ }
148
+ }
149
+
150
+ // -- Auth context factory ----------------------------------------------------
151
+ //
152
+ // Yoga's initial context wraps the Fetch API Request. The shared
153
+ // `Auth_GraphqlContext.buildAuthContext` flattens headers into a lowercase
154
+ // dict, runs them through `LocalAuth.authenticate`, and attaches the
155
+ // resolved identity to the resolver context. Lifted into its own module so
156
+ // the split-mode admin server (`GraphQL_ServerInstance`) enforces the same
157
+ // bearer-token rules instead of leaving admin queries wide open.
158
+
159
+ let buildAuthContext = Auth_GraphqlContext.buildAuthContext
160
+
161
+ // -- Resolver type alias ---------------------------------------------------
162
+
163
+ type resolverFn = YG.resolverFn
164
+
165
+ // -- Relay Global ID encoding/decoding -------------------------------------
166
+
167
+ @val external btoa: string => string = "btoa"
168
+ @val external atob: string => string = "atob"
169
+
170
+ let encodeGlobalId = (~typeName: string, ~localId: string): string =>
171
+ btoa(`${typeName}:${localId}`)
172
+
173
+ let decodeGlobalId = (globalId: string): option<(string, string)> =>
174
+ try {
175
+ let decoded = atob(globalId)
176
+ let idx = decoded->String.indexOf(":")
177
+ if idx > 0 {
178
+ let typeName = decoded->String.slice(~start=0, ~end=idx)
179
+ let localId = decoded->String.slice(~start=idx + 1, ~end=decoded->String.length)
180
+ Some((typeName, localId))
181
+ } else {
182
+ None
183
+ }
184
+ } catch {
185
+ | _ => None
186
+ }
187
+
188
+ // -- Registry --------------------------------------------------------------
189
+
190
+ let mutationResolvers: ref<dict<resolverFn>> = ref(Dict.make())
191
+ let queryResolvers: ref<dict<resolverFn>> = ref(Dict.make())
192
+ let subscriptionResolvers: ref<dict<resolverFn>> = ref(Dict.make())
193
+
194
+ let mutationFields: ref<array<string>> = ref([])
195
+ let queryFields: ref<array<string>> = ref([])
196
+ let subscriptionFields: ref<array<string>> = ref([])
197
+ let typeDefinitions: ref<array<string>> = ref([])
198
+
199
+ let registerMutations = (~sdlFields: array<string>, ~resolvers: dict<resolverFn>) => {
200
+ mutationFields.contents = mutationFields.contents->Array.concat(sdlFields)
201
+ resolvers->Dict.toArray->Array.forEach(((k, v)) => mutationResolvers.contents->Dict.set(k, v))
202
+ }
203
+
204
+ let registerQueries = (~sdlFields: array<string>, ~resolvers: dict<resolverFn>) => {
205
+ queryFields.contents = queryFields.contents->Array.concat(sdlFields)
206
+ resolvers->Dict.toArray->Array.forEach(((k, v)) => queryResolvers.contents->Dict.set(k, v))
207
+ }
208
+
209
+ let registerSubscriptions = (~sdlFields: array<string>, ~resolvers: dict<resolverFn>) => {
210
+ subscriptionFields.contents = subscriptionFields.contents->Array.concat(sdlFields)
211
+ resolvers->Dict.toArray->Array.forEach(((k, v)) =>
212
+ subscriptionResolvers.contents->Dict.set(k, v)
213
+ )
214
+ }
215
+
216
+ /** Look up a registered mutation resolver by field name (used by MCP_Server). */
217
+ let getMutationResolver = (fieldName: string): option<resolverFn> =>
218
+ mutationResolvers.contents->Dict.get(fieldName)
219
+
220
+ /** Look up a registered query resolver by field name (used by MCP_Server). */
221
+ let getQueryResolver = (fieldName: string): option<resolverFn> =>
222
+ queryResolvers.contents->Dict.get(fieldName)
223
+
224
+ let registerTypes = (~sdlTypes: array<string>) =>
225
+ typeDefinitions.contents = typeDefinitions.contents->Array.concat(sdlTypes)
226
+
227
+ // -- Relay Node type registry -----------------------------------------------
228
+ // Maps GraphQL type names to QueryDb component names for node(id: ID!) resolution.
229
+ let nodeTypeRegistry: ref<dict<string>> = ref(Dict.make())
230
+
231
+ let registerNodeType = (~typeName: string, ~queryDbName: string) =>
232
+ nodeTypeRegistry.contents->Dict.set(typeName, queryDbName)
233
+
234
+ // -- Relay Node resolver callback ------------------------------------------
235
+ // Set by QueryDbResolvers_GraphQL to resolve node(id: ID!) queries.
236
+ // Takes (typeName, localId) and returns the entity JSON with __typename.
237
+ type nodeResolverCallback = (~typeName: string, ~localId: string) => promise<option<JSON.t>>
238
+ let nodeResolverCallback: ref<option<nodeResolverCallback>> = ref(None)
239
+ let registerNodeResolverCallback = (cb: nodeResolverCallback) =>
240
+ nodeResolverCallback.contents = Some(cb)
241
+
242
+ // Builds the internal node resolver using the registered callback and type registry.
243
+ let buildNodeResolver = (): option<(string, resolverFn)> =>
244
+ switch nodeResolverCallback.contents {
245
+ | None => None
246
+ | Some(resolve) =>
247
+ let resolver: resolverFn = async (_root, args, _ctx) => {
248
+ let id =
249
+ args
250
+ ->JSON.Decode.object
251
+ ->Option.flatMap(d => d->Dict.get("id"))
252
+ ->Option.flatMap(JSON.Decode.string)
253
+ ->Option.getOr("")
254
+ switch decodeGlobalId(id) {
255
+ | Some((typeName, localId)) =>
256
+ switch await resolve(~typeName, ~localId) {
257
+ | Some(entity) => entity
258
+ | None => JSON.Encode.null
259
+ }
260
+ | None => JSON.Encode.null
261
+ }
262
+ }
263
+ Some(("node", resolver))
264
+ }
265
+
266
+ // -- Server lifecycle ------------------------------------------------------
267
+
268
+ @val external processEnv: dict<string> = "process.env"
269
+ let debug = processEnv->Dict.get("GRAPHQL_DEBUG")->Option.isSome
270
+
271
+ let activeServer: ref<option<YG.httpServer>> = ref(None)
272
+ let activeSchema: ref<option<YG.schema>> = ref(None)
273
+ let lastFullSdl: ref<option<string>> = ref(None)
274
+
275
+ let buildSdl = () => {
276
+ let typesSdl = typeDefinitions.contents->Array.length > 0
277
+ ? typeDefinitions.contents->Array.join("\n\n")
278
+ : ""
279
+ let mutations =
280
+ mutationFields.contents->Array.length > 0
281
+ ? mutationFields.contents->Array.join("\n")
282
+ : " _noop: String"
283
+ let queries =
284
+ queryFields.contents->Array.length > 0
285
+ ? queryFields.contents->Array.join("\n")
286
+ : " _noop: String"
287
+ let queriesMutationsSdl = `type Query {
288
+ ${queries}
289
+ }
290
+ type Mutation {
291
+ ${mutations}
292
+ }`
293
+ let subscriptionsSdl =
294
+ subscriptionFields.contents->Array.length > 0
295
+ ? `\n\ntype Subscription {\n${subscriptionFields.contents->Array.join("\n")}\n}`
296
+ : ""
297
+ let base =
298
+ typesSdl->String.length > 0
299
+ ? typesSdl ++ "\n\n" ++ queriesMutationsSdl
300
+ : queriesMutationsSdl
301
+ base ++ subscriptionsSdl
302
+ }
303
+
304
+ // `~contextFactory` is accepted to satisfy the `GraphQL_ServerInstance.t`
305
+ // interface but ignored — the data server always wires `buildAuthContext`
306
+ // internally so the bearer-token rules + /__inmemory/login + /sdl dispatch
307
+ // stay consistent across callers.
308
+ let start = (~port: int=4000, ~contextFactory as _: option<YG.contextFactory>=?, ()) => {
309
+ // Register node resolver if callback is set
310
+ switch buildNodeResolver() {
311
+ | Some((name, resolver)) => queryResolvers.contents->Dict.set(name, resolver)
312
+ | None => ()
313
+ }
314
+ let resolvers = Dict.make()
315
+ resolvers->Dict.set("Query", queryResolvers.contents)
316
+ resolvers->Dict.set("Mutation", mutationResolvers.contents)
317
+ if subscriptionResolvers.contents->Dict.keysToArray->Array.length > 0 {
318
+ resolvers->Dict.set("Subscription", subscriptionResolvers.contents)
319
+ }
320
+ let sdl = buildSdl()
321
+ lastFullSdl.contents = Some(sdl)
322
+ let schema = YG.createSchema({"typeDefs": sdl, "resolvers": resolvers})
323
+ activeSchema.contents = Some(schema)
324
+ let yoga = YG.createYogaWithContext({
325
+ "schema": schema,
326
+ "graphiql": true,
327
+ "logging": debug,
328
+ "maskedErrors": !debug,
329
+ "context": buildAuthContext,
330
+ })
331
+ // Custom HTTP handler: serves /sdl + /__inmemory/{login,logout}, else yoga.
332
+ let getSdl = () =>
333
+ switch activeSchema.contents {
334
+ | Some(s) => YG.printSchema(s)
335
+ | None => lastFullSdl.contents->Option.getOr("")
336
+ }
337
+ let server = createServerWithHandler((req, res) => _dispatch(req, res, yoga, getSdl))
338
+ server->YG.listen(port, () =>
339
+ log.info(~comp="GraphQL:Domain", `listening on http://localhost:${port->Int.toString}/graphql (SDL: /sdl)`)
340
+ )
341
+ activeServer.contents = Some(server)
342
+ }
343
+
344
+ let stop = () =>
345
+ switch activeServer.contents {
346
+ | Some(server) =>
347
+ server->YG.close(() => ())
348
+ activeServer.contents = None
349
+ activeSchema.contents = None
350
+ | None => ()
351
+ }
352
+
353
+ // Rebuild the server schema by stitching plugin fragments with registered resolvers.
354
+ // Merges any additional type definitions from fragments into the type registry,
355
+ // then uses buildSdl() which includes types + Query + Mutation.
356
+ // Stops the existing server and restarts with the new SDL.
357
+ let rebuildSchema = (
358
+ ~baseFragment: Reventless.Plugin.apiSchemaFragment,
359
+ ~pluginFragments: array<Reventless.Plugin.apiSchemaFragment>,
360
+ ) => {
361
+ stop()
362
+ // Merge any fragment types not already registered via the hook
363
+ let allFragments = Array.concat([baseFragment], pluginFragments)
364
+ let fragmentTypes = allFragments->Array.flatMap(frag => ReventlessCore.GraphQL_Stitcher.decode(frag).types)
365
+ let existingNames = Set.fromArray(typeDefinitions.contents->Array.map(ReventlessCore.GraphQL_Stitcher.extractLeadingName))
366
+ fragmentTypes->Array.forEach(typeDef => {
367
+ let name = ReventlessCore.GraphQL_Stitcher.extractLeadingName(typeDef)
368
+ if !(existingNames->Set.has(name)) {
369
+ typeDefinitions.contents->Array.push(typeDef)
370
+ existingNames->Set.add(name)
371
+ }
372
+ })
373
+ // Register node resolver if callback is set
374
+ switch buildNodeResolver() {
375
+ | Some((name, resolver)) => queryResolvers.contents->Dict.set(name, resolver)
376
+ | None => ()
377
+ }
378
+ let fullSdl = buildSdl()
379
+ lastFullSdl.contents = Some(fullSdl)
380
+ let resolvers = Dict.make()
381
+ resolvers->Dict.set("Query", queryResolvers.contents)
382
+ resolvers->Dict.set("Mutation", mutationResolvers.contents)
383
+ if subscriptionResolvers.contents->Dict.keysToArray->Array.length > 0 {
384
+ resolvers->Dict.set("Subscription", subscriptionResolvers.contents)
385
+ }
386
+ let schema = YG.createSchema({"typeDefs": fullSdl, "resolvers": resolvers})
387
+ activeSchema.contents = Some(schema)
388
+ let yoga = YG.createYogaWithContext({
389
+ "schema": schema,
390
+ "graphiql": true,
391
+ "logging": debug,
392
+ "maskedErrors": !debug,
393
+ "context": buildAuthContext,
394
+ })
395
+ let getSdl = () =>
396
+ switch activeSchema.contents {
397
+ | Some(s) => YG.printSchema(s)
398
+ | None => lastFullSdl.contents->Option.getOr("")
399
+ }
400
+ let server = createServerWithHandler((req, res) => _dispatch(req, res, yoga, getSdl))
401
+ server->YG.listen(4000, () =>
402
+ log.info(~comp="GraphQL:Domain", "rebuilt schema - http://localhost:4000/graphql (SDL: /sdl)")
403
+ )
404
+ activeServer.contents = Some(server)
405
+ }
406
+
407
+ // Reset registry state (call between isolated test suites).
408
+ let reset = () => {
409
+ mutationResolvers.contents = Dict.make()
410
+ queryResolvers.contents = Dict.make()
411
+ subscriptionResolvers.contents = Dict.make()
412
+ mutationFields.contents = []
413
+ queryFields.contents = []
414
+ subscriptionFields.contents = []
415
+ typeDefinitions.contents = []
416
+ nodeTypeRegistry.contents = Dict.make()
417
+ nodeResolverCallback.contents = None
418
+ activeSchema.contents = None
419
+ lastFullSdl.contents = None
420
+ }
421
+
422
+ // -- Inspection & diagnostics ---------------------------------------------
423
+
424
+ let getRegisteredSdl = () => buildSdl()
425
+
426
+ type resolverNames = {mutations: array<string>, queries: array<string>}
427
+
428
+ let getRegisteredResolverNames = (): resolverNames => {
429
+ mutations: mutationResolvers.contents->Dict.keysToArray,
430
+ queries: queryResolvers.contents->Dict.keysToArray,
431
+ }
432
+
433
+ let getFullSdl = () => lastFullSdl.contents
434
+
435
+ let getSchema = () => activeSchema.contents
436
+
437
+ let getLiveSdl = () => activeSchema.contents->Option.map(YG.printSchema)
438
+
439
+ let printLiveSdl = () =>
440
+ switch getLiveSdl() {
441
+ | Some(sdl) =>
442
+ log.info(~comp="GraphQL:Domain", "Live SDL:")
443
+ Console.log(sdl)
444
+ | None => log.info(~comp="GraphQL:Domain", "no active schema")
445
+ }
446
+
447
+ type diagnostics = GraphQL_ServerInstance.diagnostics
448
+
449
+ let extractFieldName = (sdlField: string): string => {
450
+ let trimmed = sdlField->String.trim
451
+ trimmed
452
+ ->String.split("(")
453
+ ->Array.get(0)
454
+ ->Option.getOr("")
455
+ ->String.trim
456
+ ->String.split(":")
457
+ ->Array.get(0)
458
+ ->Option.getOr("")
459
+ ->String.trim
460
+ }
461
+
462
+ let diagnostics = (): diagnostics => {
463
+ let mutFieldNames =
464
+ mutationFields.contents->Array.map(extractFieldName)->Array.filter(n => n != "_noop")
465
+ let queryFieldNames =
466
+ queryFields.contents->Array.map(extractFieldName)->Array.filter(n => n != "_noop")
467
+ let mutResolverNames = mutationResolvers.contents->Dict.keysToArray
468
+ let queryResolverNames = queryResolvers.contents->Dict.keysToArray
469
+
470
+ let mismatches: array<string> = []
471
+
472
+ // SDL fields without resolvers
473
+ let mutResolverSet = Set.fromArray(mutResolverNames)
474
+ mutFieldNames->Array.forEach(name =>
475
+ if !(mutResolverSet->Set.has(name)) {
476
+ mismatches->Array.push(`Mutation "${name}": SDL field but no resolver`)
477
+ }
478
+ )
479
+ let queryResolverSet = Set.fromArray(queryResolverNames)
480
+ queryFieldNames->Array.forEach(name =>
481
+ if !(queryResolverSet->Set.has(name)) {
482
+ mismatches->Array.push(`Query "${name}": SDL field but no resolver`)
483
+ }
484
+ )
485
+
486
+ // Resolvers without SDL fields
487
+ let mutFieldSet = Set.fromArray(mutFieldNames)
488
+ mutResolverNames->Array.forEach(name =>
489
+ if !(mutFieldSet->Set.has(name)) {
490
+ mismatches->Array.push(`Mutation "${name}": resolver but no SDL field`)
491
+ }
492
+ )
493
+ let queryFieldSet = Set.fromArray(queryFieldNames)
494
+ queryResolverNames->Array.forEach(name =>
495
+ if !(queryFieldSet->Set.has(name)) {
496
+ mismatches->Array.push(`Query "${name}": resolver but no SDL field`)
497
+ }
498
+ )
499
+
500
+ let typeNames = typeDefinitions.contents->Array.map(ReventlessCore.GraphQL_Stitcher.extractLeadingName)
501
+
502
+ {
503
+ registeredTypeDefinitions: typeNames,
504
+ registeredMutationFields: mutFieldNames,
505
+ registeredQueryFields: queryFieldNames,
506
+ registeredMutationResolvers: mutResolverNames,
507
+ registeredQueryResolvers: queryResolverNames,
508
+ typeCount: typeNames->Array.length,
509
+ sdlMutationCount: mutFieldNames->Array.length,
510
+ sdlQueryCount: queryFieldNames->Array.length,
511
+ resolverMutationCount: mutResolverNames->Array.length,
512
+ resolverQueryCount: queryResolverNames->Array.length,
513
+ mismatches,
514
+ fullSdl: lastFullSdl.contents,
515
+ serverRunning: activeServer.contents->Option.isSome,
516
+ }
517
+ }
518
+
519
+ let printDiagnostics = () => {
520
+ let p = s => log.info(~comp="GraphQL:Domain", s)
521
+ let d = diagnostics()
522
+ p("Diagnostics")
523
+ p(` Types: ${d.typeCount->Int.toString}`)
524
+ p(
525
+ ` Mutations: ${d.sdlMutationCount->Int.toString} SDL fields, ${d.resolverMutationCount->Int.toString} resolvers`,
526
+ )
527
+ p(
528
+ ` Queries: ${d.sdlQueryCount->Int.toString} SDL fields, ${d.resolverQueryCount->Int.toString} resolvers`,
529
+ )
530
+ if d.mismatches->Array.length > 0 {
531
+ p(` Mismatches (${d.mismatches->Array.length->Int.toString}):`)
532
+ d.mismatches->Array.forEach(m => p(` ⚠ ${m}`))
533
+ } else {
534
+ p(" No mismatches")
535
+ }
536
+ p(` Server running: ${d.serverRunning ? "yes" : "no"}`)
537
+ switch d.fullSdl {
538
+ | Some(sdl) =>
539
+ p("")
540
+ p("--- Full SDL ---")
541
+ sdl->String.split("\n")->Array.forEach(line => p(line))
542
+ p("--- End ---")
543
+ | None => p(" No SDL recorded")
544
+ }
545
+ }
546
+
547
+ // -- GraphQL_ServerInstance.t interface ----------------------------------
548
+ // Exposes this singleton as a GraphQL_ServerInstance.t for use by
549
+ // resolveTargetGraphQL() in Platform.res (mirrors AWS resolveTargetApi() pattern).
550
+ let asInterface: GraphQL_ServerInstance.t = {
551
+ registerMutations,
552
+ registerQueries,
553
+ registerSubscriptions,
554
+ registerTypes,
555
+ getMutationResolver,
556
+ getQueryResolver,
557
+ start,
558
+ stop,
559
+ reset,
560
+ buildSdl,
561
+ getFullSdl,
562
+ getSchema,
563
+ diagnostics,
564
+ printDiagnostics,
565
+ }