@reventlessdev/reventless-infra 3.0.0-alpha.100

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 (78) hide show
  1. package/CHANGELOG.md +853 -0
  2. package/LICENSE +202 -0
  3. package/README.md +92 -0
  4. package/package.json +46 -0
  5. package/rescript.json +34 -0
  6. package/src/adapter/Adapter.res +88 -0
  7. package/src/adapter/Adapter.res.mjs +29 -0
  8. package/src/components/Aggregate.res +73 -0
  9. package/src/components/Aggregate.res.mjs +2 -0
  10. package/src/components/Api.res +120 -0
  11. package/src/components/Api.res.mjs +31 -0
  12. package/src/components/Api_Adapter.res +29 -0
  13. package/src/components/Api_Adapter.res.mjs +2 -0
  14. package/src/components/AutomationSlice.res +48 -0
  15. package/src/components/AutomationSlice.res.mjs +2 -0
  16. package/src/components/CommandGenerator.res +8 -0
  17. package/src/components/CommandGenerator.res.mjs +2 -0
  18. package/src/components/CommandTopic.res +70 -0
  19. package/src/components/CommandTopic.res.mjs +2 -0
  20. package/src/components/Component.js +56 -0
  21. package/src/components/Component.mjs +10 -0
  22. package/src/components/Component.res +90 -0
  23. package/src/components/Component.res.mjs +57 -0
  24. package/src/components/Component.resi +21 -0
  25. package/src/components/Counter.res +81 -0
  26. package/src/components/Counter.res.mjs +2 -0
  27. package/src/components/DcbEventLog.res +130 -0
  28. package/src/components/DcbEventLog.res.mjs +2 -0
  29. package/src/components/DeployBootstrap.res +83 -0
  30. package/src/components/DeployBootstrap.res.mjs +69 -0
  31. package/src/components/EventCollector.res +19 -0
  32. package/src/components/EventCollector.res.mjs +2 -0
  33. package/src/components/EventLog.res +24 -0
  34. package/src/components/EventLog.res.mjs +2 -0
  35. package/src/components/EventMapper.res +37 -0
  36. package/src/components/EventMapper.res.mjs +2 -0
  37. package/src/components/EventTopic.res +51 -0
  38. package/src/components/EventTopic.res.mjs +2 -0
  39. package/src/components/Extension.res +64 -0
  40. package/src/components/Extension.res.mjs +2 -0
  41. package/src/components/ExtensionPoint.res +62 -0
  42. package/src/components/ExtensionPoint.res.mjs +2 -0
  43. package/src/components/Heartbeat.res +7 -0
  44. package/src/components/Heartbeat.res.mjs +2 -0
  45. package/src/components/InboundTranslationSlice.res +41 -0
  46. package/src/components/InboundTranslationSlice.res.mjs +2 -0
  47. package/src/components/OutboundTranslationSlice.res +44 -0
  48. package/src/components/OutboundTranslationSlice.res.mjs +2 -0
  49. package/src/components/Plugin.res +93 -0
  50. package/src/components/Plugin.res.mjs +2 -0
  51. package/src/components/QueryDb.res +48 -0
  52. package/src/components/QueryDb.res.mjs +33 -0
  53. package/src/components/ReadModel.res +56 -0
  54. package/src/components/ReadModel.res.mjs +2 -0
  55. package/src/components/Scheduler.res +32 -0
  56. package/src/components/Scheduler.res.mjs +2 -0
  57. package/src/components/StateChangeSlice.res +45 -0
  58. package/src/components/StateChangeSlice.res.mjs +2 -0
  59. package/src/components/StateViewSlice.res +38 -0
  60. package/src/components/StateViewSlice.res.mjs +2 -0
  61. package/src/components/Task.res +89 -0
  62. package/src/components/Task.res.mjs +2 -0
  63. package/src/types/ExtensionMapping.res +448 -0
  64. package/src/types/ExtensionMapping.res.mjs +252 -0
  65. package/src/types/ExtensionPointMapping.res +303 -0
  66. package/src/types/ExtensionPointMapping.res.mjs +116 -0
  67. package/src/types/Message.res +3 -0
  68. package/src/types/Message.res.mjs +2 -0
  69. package/src/types/NoEventMappings.res +25 -0
  70. package/src/types/NoEventMappings.res.mjs +17 -0
  71. package/src/types/Platform.res +269 -0
  72. package/src/types/Platform.res.mjs +2 -0
  73. package/src/types/PluginExtensionPointSpec.res +55 -0
  74. package/src/types/PluginExtensionPointSpec.res.mjs +209 -0
  75. package/src/types/ResourceNaming.res +12 -0
  76. package/src/types/ResourceNaming.res.mjs +2 -0
  77. package/tests/DeployBootstrapTest.res +72 -0
  78. package/tests/DeployBootstrapTest.res.mjs +100 -0
@@ -0,0 +1,269 @@
1
+ // Platform module type — abstract factory interface for platform-agnostic component assembly.
2
+ //
3
+ // Lives in reventless-infra so application plugin assembly code can depend on
4
+ // reventless-infra. The concrete implementation in reventless-aws satisfies this type.
5
+ //
6
+ // Usage pattern:
7
+ //
8
+ // // app/MyPlugin.res — imports reventless-infra
9
+ // module Make = (Platform: ReventlessInfra.Platform.T) => {
10
+ // module MyAggregate = Platform.Aggregate.Make(MySpec, MyBehavior, MyMappings)
11
+ // module MyReadModel = Platform.ReadModel.Make(MyRmSpec, MyMappings)
12
+ // // ...
13
+ // }
14
+ //
15
+ // // index.res — Composition Root; the only file that imports reventless-aws
16
+ // module Platform = ReventlessAws.Platform.Make(Config)
17
+ // module App = MyPlugin.Make(Platform)
18
+
19
+ // Type alias for admin extension points dict — defined at file scope so it
20
+ // remains accessible inside module type T even though T re-declares
21
+ // `module ExtensionPoint` with a different local type, which would otherwise
22
+ // shadow the package-level ExtensionPoint.outputs.
23
+ /**
24
+ Abstract factory interface for creating Reventless components without coupling
25
+ application code to a specific infrastructure provider.
26
+
27
+ Inject a `Platform.T` module (e.g. `ReventlessAws.Platform.Make(Config)`) at
28
+ the composition root, and use its nested `Make` functors everywhere else.
29
+
30
+ @example
31
+ ```rescript
32
+ // CatalogPlugin.res — depends on reventless-infra
33
+ module Make = (Platform: Platform.T) => {
34
+ module CategoryAggregate = Platform.Aggregate.Make(
35
+ Category,
36
+ CategoryBehavior,
37
+ NoEventMappings.Make(Category),
38
+ )
39
+ module CategoryReadModel = Platform.ReadModel.Make(CategoriesReadModel, CategoryMappings)
40
+ }
41
+
42
+ // index.res — the only file that imports reventless-aws
43
+ module Platform = ReventlessAws.Platform.Make(AwsConfig)
44
+ module App = CatalogPlugin.Make(Platform)
45
+ ```
46
+ */
47
+
48
+ // Type alias so `deployPlugin` can reference `Plugin.outputs` inside module type T,
49
+ // where `module Plugin: Plugin.T` shadows the package-level Plugin module.
50
+ type pluginOutputs = Plugin.outputs
51
+
52
+ // Module type alias so StateViewSliceStream can reference the component T
53
+ // without being confused by the `module StateViewSlice` declaration inside T.
54
+ module type StateViewSliceComponentT = StateViewSlice.T
55
+
56
+ // Same trick for ReadModelStream: the nested `module ReadModel` declaration
57
+ // inside T shadows the package-level ReadModel for later declarations, so
58
+ // reference its component T through this file-scope alias.
59
+ module type ReadModelComponentT = ReadModel.T
60
+
61
+ module type T = {
62
+ /** Platform-specific API type (e.g. `Types.AppSync.api` for AWS, `unit` for in-memory). */
63
+ type api
64
+
65
+ /** Platform-specific role type (e.g. `Types.AppSync.role` for AWS, `unit` for in-memory). */
66
+ type role
67
+
68
+ /** The platform's API instance — used by bundled DCB slice builders that need
69
+ to create QueryDb resolvers inside the Platform functor. */
70
+ let api: api
71
+
72
+ /** The platform's API role instance — used alongside `api` for QueryDb resolvers. */
73
+ let apiRole: role
74
+
75
+ /** Factory for event-sourced aggregate components. */
76
+ module Aggregate: {
77
+ module Make: (
78
+ Spec: Reventless.Aggregate.Spec,
79
+ Behavior: Reventless.Behavior.T with module Spec := Spec,
80
+ EventMappings: EventMapper.Mappings with module Target := Spec,
81
+ ) => Aggregate.T with type api = api
82
+ /** Async variant — uses FIFO channel, returns `CommandPending`. */
83
+ module MakeAsync: (
84
+ Spec: Reventless.Aggregate.Spec,
85
+ Behavior: Reventless.Behavior.T with module Spec := Spec,
86
+ EventMappings: EventMapper.Mappings with module Target := Spec,
87
+ ) => Aggregate.T with type api = api
88
+ }
89
+
90
+ /** Factory for read model (query-side projection) components. */
91
+ module ReadModel: {
92
+ module Make: (
93
+ Spec: Reventless.ReadModel.Spec,
94
+ Mappings: Reventless.Projection.Mappings with module Target := Spec,
95
+ ) => ReadModel.T with module Spec = Spec and type api = api and type role = role
96
+ }
97
+
98
+ /** Factory for stream-enabled read model components — identical to `ReadModel`
99
+ but the QueryDb table has a DynamoDB Stream so the platform wires a
100
+ `StateTopic` Lambda that pushes row changes to the AppSync Events API
101
+ (Source B subscriptions / AutoUI live updates). In-memory: same as
102
+ `ReadModel` (no streams). */
103
+ module ReadModelStream: {
104
+ module Make: (
105
+ Spec: Reventless.ReadModel.Spec,
106
+ Mappings: Reventless.Projection.Mappings with module Target := Spec,
107
+ ) => ReadModelComponentT with module Spec = Spec and type api = api and type role = role
108
+ }
109
+
110
+ /** Factory for extension point components (single mapping). */
111
+ module ExtensionPoint: {
112
+ module Make: (
113
+ Mapping: ExtensionPointMapping.Mapping,
114
+ ) => ExtensionPoint.T
115
+
116
+ /** Two-mapping variant — merges per-slice EP mappings. */
117
+ module Make2: (
118
+ Mapping1: ExtensionPointMapping.Mapping,
119
+ Mapping2: ExtensionPointMapping.Mapping
120
+ with module ExtensionPoint = Mapping1.ExtensionPoint,
121
+ ) => ExtensionPoint.T
122
+
123
+ /** Three-mapping variant — merges per-slice EP mappings. */
124
+ module Make3: (
125
+ Mapping1: ExtensionPointMapping.Mapping,
126
+ Mapping2: ExtensionPointMapping.Mapping
127
+ with module ExtensionPoint = Mapping1.ExtensionPoint,
128
+ Mapping3: ExtensionPointMapping.Mapping
129
+ with module ExtensionPoint = Mapping1.ExtensionPoint,
130
+ ) => ExtensionPoint.T
131
+
132
+ /** Multi-mapping variant with full control over name and mappings array. */
133
+ module MakeMulti: (
134
+ Spec: ExtensionPointMapping.Spec,
135
+ Mappings: ExtensionPoint.Mappings with module Spec := Spec,
136
+ ) => ExtensionPoint.T
137
+ }
138
+
139
+ /** Factory for extension blueprints (single mapping).
140
+ Returns a blueprint — not a built component. `Plugin.make` builds it,
141
+ using the plugin name for the extension's component name and auto-merging
142
+ blueprints that target the same extension point. */
143
+ module Extension: {
144
+ module Make: (
145
+ Mapping: ExtensionMapping.Mapping,
146
+ ) => Extension.Blueprint
147
+ }
148
+
149
+ /** Factory for task (background job / S3 trigger) components. */
150
+ module Task: {
151
+ module Make: (Spec: Task.Spec) => Task.T with module Spec = Spec
152
+ }
153
+
154
+ /** Ready-to-use counter component (no Make required). */
155
+ module Counter: Counter.T
156
+
157
+ /** Factory for DCB write-side state-change slice components. */
158
+ module StateChangeSlice: {
159
+ module Make: (
160
+ Spec: Reventless.StateChangeSlice.Spec,
161
+ Behavior: Reventless.StateChangeSlice.Behavior with module Spec := Spec,
162
+ ) => StateChangeSlice.T with module Spec = Spec
163
+ /** Async variant — uses FIFO channel, returns `CommandPending`. */
164
+ module MakeAsync: (
165
+ Spec: Reventless.StateChangeSlice.Spec,
166
+ Behavior: Reventless.StateChangeSlice.Behavior with module Spec := Spec,
167
+ ) => StateChangeSlice.T with module Spec = Spec
168
+ }
169
+
170
+ /** Factory for DCB read-side state-view slice components. */
171
+ module StateViewSlice: {
172
+ module Make: (
173
+ Spec: Reventless.StateViewSlice.Spec,
174
+ Projection: Reventless.StateViewSlice.Projection with module Spec := Spec,
175
+ ) => StateViewSlice.T with module Spec = Spec
176
+ }
177
+
178
+ /** Factory for stream-enabled state-view slice components (enables Source B subscriptions). */
179
+ module StateViewSliceStream: {
180
+ module Make: (
181
+ Spec: Reventless.StateViewSlice.Spec,
182
+ Projection: Reventless.StateViewSlice.Projection with module Spec := Spec,
183
+ ) => StateViewSliceComponentT with module Spec = Spec
184
+ }
185
+
186
+ /** Factory for DCB automation slice components (TODO list pattern). */
187
+ module AutomationSlice: {
188
+ module Make: (
189
+ Spec: Reventless.AutomationSlice.Spec,
190
+ Automation: Reventless.AutomationSlice.Automation with module Spec := Spec,
191
+ ) => AutomationSlice.T with module Spec = Spec
192
+ }
193
+
194
+ /** Factory for DCB outbound translation slice components (tracked external calls). */
195
+ module OutboundTranslationSlice: {
196
+ module Make: (
197
+ Spec: Reventless.OutboundTranslationSlice.Spec,
198
+ Translation: Reventless.OutboundTranslationSlice.Translation with module Spec := Spec,
199
+ ) => OutboundTranslationSlice.T with module Spec = Spec
200
+ }
201
+
202
+ /** Factory for DCB inbound translation slice components (external input to commands). */
203
+ module InboundTranslationSlice: {
204
+ module Make: (
205
+ Spec: Reventless.InboundTranslationSlice.Spec,
206
+ Translation: Reventless.InboundTranslationSlice.Translation with module Spec := Spec,
207
+ ) => InboundTranslationSlice.T with module Spec = Spec
208
+ }
209
+
210
+ /** Whether this platform supports MCP (Model Context Protocol) for AI agent access.
211
+ In-memory: starts an MCP server alongside GraphQL in makePlatform.
212
+ AWS: deploys a Lambda Function URL with Streamable HTTP transport. */
213
+ type mcpSupported = | @as(true) McpSupported | @as(false) McpNotSupported
214
+ let mcpSupported: mcpSupported
215
+
216
+ /** Which AppSync API a plugin's resolvers and schema are deployed to.
217
+ Domain — the application-facing API (default, backwards-compatible).
218
+ Platform — the admin/Platform_Sync* API (for framework-internal plugins). */
219
+ type apiTarget = Domain | Platform
220
+
221
+ /** Factory for plugin deployment units. */
222
+ module Plugin: Plugin.T with type api = api and type role = role
223
+
224
+ /** Module type for plugin assembly — matches the `make` function produced by
225
+ every plugin's `Make` functor. Pass first-class modules to `makePlatform`. */
226
+ module type PluginMaker = {
227
+ let make: unit => Plugin.component
228
+ }
229
+
230
+ /** Optional host UI shell bundle. When set, the platform hosts the static
231
+ shell (e.g. reventless-ui's host-shell `dist/`) on its own CDN and writes
232
+ a `config.json` next to `index.html` so the shell discovers the API
233
+ endpoint at boot. In-memory platforms typically ignore this — the shell
234
+ is served by `vite dev` against the running in-process GraphQL server. */
235
+ type hostUiBundleConfig = {
236
+ assetsDir: string,
237
+ bundleVersion: string,
238
+ }
239
+
240
+ /** Deploy a complete platform: creates the scheduler, builds each plugin,
241
+ creates admin components internally, and wires everything (schema stitching + stack exports). */
242
+ let makePlatform: (
243
+ ~version: string,
244
+ ~plugins: array<module(PluginMaker)>,
245
+ ) => unit
246
+
247
+ /** Deploy only the platform (admin components, scheduler, shared API).
248
+ No plugins are deployed — each plugin deploys independently via `deployPlugin`.
249
+ Pass `~hostUiBundle` to also host a static host-shell SPA from this stack.
250
+ Returns the Pulumi stack outputs dict for use as the ESM `default` export. */
251
+ let deployPlatform: (
252
+ ~version: string,
253
+ ~hostUiBundle: hostUiBundleConfig=?,
254
+ ) => dict<Pulumi.Output.t<JSON.t>>
255
+
256
+ /** Deploy a single plugin as an independent stack.
257
+ Creates its own scheduler and exports stack outputs for cross-stack consumption.
258
+ Pass `~apiTarget=Platform` to route the plugin's resolvers and schema to the Platform API.
259
+ Defaults to `Domain`.
260
+ Returns the Pulumi stack outputs dict for use as the ESM `default` export. */
261
+ let deployPlugin: (~plugin: module(PluginMaker), ~apiTarget: apiTarget=?) => dict<Pulumi.Output.t<JSON.t>>
262
+
263
+ /** Start all servers after all makePlatform/deployPlugin calls are complete.
264
+ In split in-memory mode, servers are deferred until this is called so all
265
+ plugins (domain and platform) can register their schema before serving requests.
266
+ In AWS and unified in-memory mode this is a no-op — server lifecycle is managed
267
+ by Pulumi / existing inline start() calls. */
268
+ let startServers: unit => unit
269
+ }
@@ -0,0 +1,2 @@
1
+ // Generated by ReScript, PLEASE EDIT WITH CARE
2
+ /* This output is empty. Its source's type definitions, externals and/or unused code got optimized away. */
@@ -0,0 +1,55 @@
1
+ let name = "Core.Plugin"
2
+
3
+ include Reventless.Plugin
4
+
5
+ @schema
6
+ type timeout = int // in minutes
7
+
8
+ @schema
9
+ type forwardCommand = {
10
+ extensionPointName: string,
11
+ id: string,
12
+ command: string,
13
+ }
14
+
15
+ @schema
16
+ type command =
17
+ | Heartbeat(timeout)
18
+ | ConnectPlugin(pluginDefinition)
19
+ | DisconnectPlugin
20
+ | ForwardCommand(forwardCommand)
21
+ // Registers this plugin's UI-fragment manifest with the admin UiFragmentRegistry slice.
22
+ // Sent by the plugin's connect extension alongside ConnectPlugin (see
23
+ // docs/plans/event-sourced-fragment-registries.md). Routed by the admin EP's UI-fragment
24
+ // mapping to UiFragmentRegistry.RegisterUiFragment; DisconnectPlugin drives the matching
25
+ // DeregisterUiFragment. Decoupling the manifest from the Plugin aggregate's lifecycle.
26
+ | RegisterUiFragment(uiFragmentManifest)
27
+ // Deploy-time re-detect: fired once by `deployPlugin` on every (re)deploy. Unlike
28
+ // a keep-alive `Heartbeat`, this forces the connect handshake to run again for an
29
+ // already-connected version so its current definition (e.g. a newly added `kind`,
30
+ // updated uiFragments/protocols) is re-serialized onto the lifecycle row. Carries
31
+ // the timeout so it also re-arms the disconnect schedule like a heartbeat.
32
+ | RedetectPlugin(timeout)
33
+
34
+ @schema
35
+ type event =
36
+ | UnknownPluginDetected
37
+ // Emitted when a connecting plugin declared incompatible protocol versions.
38
+ // The plugin is still connected; this event gives operators visibility.
39
+ | IncompatiblePlugin(pluginDefinition)
40
+ | PluginConnected(pluginDefinition)
41
+ | PluginReconnected(pluginDefinition)
42
+ | PluginDisconnected(pluginDefinition)
43
+ | PluginDeactivated(pluginDefinition)
44
+ | PluginActivated(pluginDefinition)
45
+ | PluginRetired(pluginDefinition)
46
+
47
+ @schema
48
+ type directive =
49
+ | CreateDisconnectSchedule(string, timeout)
50
+ | DeleteDisconnectSchedule(string)
51
+ | DoConnectPlugin(pluginDefinition)
52
+ | DoDisconnectPlugin(pluginDefinition)
53
+ | ForwardCommand(forwardCommand)
54
+
55
+ let moduleUrl: string = %raw(`import.meta.url`)
@@ -0,0 +1,209 @@
1
+ // Generated by ReScript, PLEASE EDIT WITH CARE
2
+
3
+ import * as S from "sury/src/S.res.mjs";
4
+ import * as Plugin$Reventless from "@reventlessdev/reventless-spec/src/components/Plugin.res.mjs";
5
+
6
+ let forwardCommandSchema = S.schema(s => ({
7
+ extensionPointName: s.m(S.string),
8
+ id: s.m(S.string),
9
+ command: s.m(S.string)
10
+ }));
11
+
12
+ let commandSchema = S.union([
13
+ S.schema(s => ({
14
+ TAG: "Heartbeat",
15
+ _0: s.m(S.int)
16
+ })),
17
+ S.schema(s => ({
18
+ TAG: "ConnectPlugin",
19
+ _0: s.m(Plugin$Reventless.pluginDefinitionSchema)
20
+ })),
21
+ S.literal("DisconnectPlugin"),
22
+ S.schema(s => ({
23
+ TAG: "ForwardCommand",
24
+ _0: s.m(forwardCommandSchema)
25
+ })),
26
+ S.schema(s => ({
27
+ TAG: "RegisterUiFragment",
28
+ _0: s.m(Plugin$Reventless.uiFragmentManifestSchema)
29
+ })),
30
+ S.schema(s => ({
31
+ TAG: "RedetectPlugin",
32
+ _0: s.m(S.int)
33
+ }))
34
+ ]);
35
+
36
+ let eventSchema = S.union([
37
+ S.literal("UnknownPluginDetected"),
38
+ S.schema(s => ({
39
+ TAG: "IncompatiblePlugin",
40
+ _0: s.m(Plugin$Reventless.pluginDefinitionSchema)
41
+ })),
42
+ S.schema(s => ({
43
+ TAG: "PluginConnected",
44
+ _0: s.m(Plugin$Reventless.pluginDefinitionSchema)
45
+ })),
46
+ S.schema(s => ({
47
+ TAG: "PluginReconnected",
48
+ _0: s.m(Plugin$Reventless.pluginDefinitionSchema)
49
+ })),
50
+ S.schema(s => ({
51
+ TAG: "PluginDisconnected",
52
+ _0: s.m(Plugin$Reventless.pluginDefinitionSchema)
53
+ })),
54
+ S.schema(s => ({
55
+ TAG: "PluginDeactivated",
56
+ _0: s.m(Plugin$Reventless.pluginDefinitionSchema)
57
+ })),
58
+ S.schema(s => ({
59
+ TAG: "PluginActivated",
60
+ _0: s.m(Plugin$Reventless.pluginDefinitionSchema)
61
+ })),
62
+ S.schema(s => ({
63
+ TAG: "PluginRetired",
64
+ _0: s.m(Plugin$Reventless.pluginDefinitionSchema)
65
+ }))
66
+ ]);
67
+
68
+ let directiveSchema = S.union([
69
+ S.schema(s => ({
70
+ TAG: "CreateDisconnectSchedule",
71
+ _0: s.m(S.string),
72
+ _1: s.m(S.int)
73
+ })),
74
+ S.schema(s => ({
75
+ TAG: "DeleteDisconnectSchedule",
76
+ _0: s.m(S.string)
77
+ })),
78
+ S.schema(s => ({
79
+ TAG: "DoConnectPlugin",
80
+ _0: s.m(Plugin$Reventless.pluginDefinitionSchema)
81
+ })),
82
+ S.schema(s => ({
83
+ TAG: "DoDisconnectPlugin",
84
+ _0: s.m(Plugin$Reventless.pluginDefinitionSchema)
85
+ })),
86
+ S.schema(s => ({
87
+ TAG: "ForwardCommand",
88
+ _0: s.m(forwardCommandSchema)
89
+ }))
90
+ ]);
91
+
92
+ let moduleUrl = import.meta.url;
93
+
94
+ let name = "Core.Plugin";
95
+
96
+ let nameSchema = Plugin$Reventless.nameSchema;
97
+
98
+ let versionSchema = Plugin$Reventless.versionSchema;
99
+
100
+ let pluginKindSchema = Plugin$Reventless.pluginKindSchema;
101
+
102
+ let extensionPointDefinitionSchema = Plugin$Reventless.extensionPointDefinitionSchema;
103
+
104
+ let extensionDefinitionSchema = Plugin$Reventless.extensionDefinitionSchema;
105
+
106
+ let dcbEventLogDefinitionSchema = Plugin$Reventless.dcbEventLogDefinitionSchema;
107
+
108
+ let extensionProtocolSchema = Plugin$Reventless.extensionProtocolSchema;
109
+
110
+ let apiSchemaFragmentSchema = Plugin$Reventless.apiSchemaFragmentSchema;
111
+
112
+ let apiTargetSchema = Plugin$Reventless.apiTargetSchema;
113
+
114
+ let apiSchemaFragmentOptionSchema = Plugin$Reventless.apiSchemaFragmentOptionSchema;
115
+
116
+ let dcbEventLogOptionSchema = Plugin$Reventless.dcbEventLogOptionSchema;
117
+
118
+ let stringOptionSchema = Plugin$Reventless.stringOptionSchema;
119
+
120
+ let stringArrayOptionSchema = Plugin$Reventless.stringArrayOptionSchema;
121
+
122
+ let boolOptionSchema = Plugin$Reventless.boolOptionSchema;
123
+
124
+ let panelManifestEntrySchema = Plugin$Reventless.panelManifestEntrySchema;
125
+
126
+ let menuEntrySchema = Plugin$Reventless.menuEntrySchema;
127
+
128
+ let pageManifestEntrySchema = Plugin$Reventless.pageManifestEntrySchema;
129
+
130
+ let uiFragmentManifestSchema = Plugin$Reventless.uiFragmentManifestSchema;
131
+
132
+ let uiFragmentManifestOptionSchema = Plugin$Reventless.uiFragmentManifestOptionSchema;
133
+
134
+ let commandLevelSchema = Plugin$Reventless.commandLevelSchema;
135
+
136
+ let fieldReferenceSchema = Plugin$Reventless.fieldReferenceSchema;
137
+
138
+ let commandDefSchema = Plugin$Reventless.commandDefSchema;
139
+
140
+ let queryableDefSchema = Plugin$Reventless.queryableDefSchema;
141
+
142
+ let eventDefSchema = Plugin$Reventless.eventDefSchema;
143
+
144
+ let writableDefSchema = Plugin$Reventless.writableDefSchema;
145
+
146
+ let automationSliceDefSchema = Plugin$Reventless.automationSliceDefSchema;
147
+
148
+ let outboundTranslationSliceDefSchema = Plugin$Reventless.outboundTranslationSliceDefSchema;
149
+
150
+ let inboundTranslationSliceDefSchema = Plugin$Reventless.inboundTranslationSliceDefSchema;
151
+
152
+ let extensionDefSchema = Plugin$Reventless.extensionDefSchema;
153
+
154
+ let extensionPointDefSchema = Plugin$Reventless.extensionPointDefSchema;
155
+
156
+ let extensionPointDefArrayOptionSchema = Plugin$Reventless.extensionPointDefArrayOptionSchema;
157
+
158
+ let pluginStructureSchema = Plugin$Reventless.pluginStructureSchema;
159
+
160
+ let pluginStructureOptionSchema = Plugin$Reventless.pluginStructureOptionSchema;
161
+
162
+ let pluginDefinitionSchema = Plugin$Reventless.pluginDefinitionSchema;
163
+
164
+ let timeoutSchema = S.int;
165
+
166
+ export {
167
+ name,
168
+ nameSchema,
169
+ versionSchema,
170
+ pluginKindSchema,
171
+ extensionPointDefinitionSchema,
172
+ extensionDefinitionSchema,
173
+ dcbEventLogDefinitionSchema,
174
+ extensionProtocolSchema,
175
+ apiSchemaFragmentSchema,
176
+ apiTargetSchema,
177
+ apiSchemaFragmentOptionSchema,
178
+ dcbEventLogOptionSchema,
179
+ stringOptionSchema,
180
+ stringArrayOptionSchema,
181
+ boolOptionSchema,
182
+ panelManifestEntrySchema,
183
+ menuEntrySchema,
184
+ pageManifestEntrySchema,
185
+ uiFragmentManifestSchema,
186
+ uiFragmentManifestOptionSchema,
187
+ commandLevelSchema,
188
+ fieldReferenceSchema,
189
+ commandDefSchema,
190
+ queryableDefSchema,
191
+ eventDefSchema,
192
+ writableDefSchema,
193
+ automationSliceDefSchema,
194
+ outboundTranslationSliceDefSchema,
195
+ inboundTranslationSliceDefSchema,
196
+ extensionDefSchema,
197
+ extensionPointDefSchema,
198
+ extensionPointDefArrayOptionSchema,
199
+ pluginStructureSchema,
200
+ pluginStructureOptionSchema,
201
+ pluginDefinitionSchema,
202
+ timeoutSchema,
203
+ forwardCommandSchema,
204
+ commandSchema,
205
+ eventSchema,
206
+ directiveSchema,
207
+ moduleUrl,
208
+ }
209
+ /* forwardCommandSchema Not a pure module */
@@ -0,0 +1,12 @@
1
+ /**
2
+ Provider-agnostic interface for naming infrastructure resources.
3
+
4
+ Injected into extension points and tasks so they can derive unique,
5
+ valid resource names without coupling to a specific cloud provider.
6
+ */
7
+ type operations = {
8
+ /** Validates and sanitizes a proposed resource name to comply with provider rules. */
9
+ validateName: string => string,
10
+ /** Derives a URN-safe name for use in Pulumi resource URNs. */
11
+ urnName: string => string,
12
+ }
@@ -0,0 +1,2 @@
1
+ // Generated by ReScript, PLEASE EDIT WITH CARE
2
+ /* This output is empty. Its source's type definitions, externals and/or unused code got optimized away. */
@@ -0,0 +1,72 @@
1
+ open JestGlobals
2
+
3
+ module DB = DeployBootstrap
4
+
5
+ describe("DeployBootstrap", () => {
6
+ // The seam holds module-level state, so each case resets first for isolation.
7
+ describe("run with no registrations", () => {
8
+ testSync("is a no-op that does not throw", () => {
9
+ DB.reset()
10
+ DB.run(PreDeploy)
11
+ DB.run(PostDeploy)
12
+ expect(true)->toBe(true)
13
+ })
14
+ })
15
+
16
+ describe("registration order within a phase", () => {
17
+ testSync("runs contributions in the order they were registered", () => {
18
+ DB.reset()
19
+ let calls = []
20
+ DB.register(() => calls->Array.push("a"))
21
+ DB.register(() => calls->Array.push("b"))
22
+ DB.register(() => calls->Array.push("c"))
23
+ DB.run(PreDeploy)
24
+ expect(calls)->toEqual(["a", "b", "c"])
25
+ })
26
+ })
27
+
28
+ describe("phase isolation", () => {
29
+ testSync("run(PreDeploy) fires only PreDeploy contributions", () => {
30
+ DB.reset()
31
+ let calls = []
32
+ DB.register(~phase=PreDeploy, () => calls->Array.push("pre"))
33
+ DB.register(~phase=PostDeploy, () => calls->Array.push("post"))
34
+ DB.run(PreDeploy)
35
+ expect(calls)->toEqual(["pre"])
36
+ DB.run(PostDeploy)
37
+ expect(calls)->toEqual(["pre", "post"])
38
+ })
39
+
40
+ testSync("defaults to PreDeploy when no phase is given", () => {
41
+ DB.reset()
42
+ let calls = []
43
+ DB.register(() => calls->Array.push("default"))
44
+ DB.run(PostDeploy)
45
+ expect(calls)->toEqual([])
46
+ DB.run(PreDeploy)
47
+ expect(calls)->toEqual(["default"])
48
+ })
49
+ })
50
+
51
+ describe("idempotent run per phase", () => {
52
+ testSync("running an already-run phase does nothing", () => {
53
+ DB.reset()
54
+ let count = ref(0)
55
+ DB.register(() => count := count.contents + 1)
56
+ DB.run(PreDeploy)
57
+ DB.run(PreDeploy)
58
+ DB.run(PreDeploy)
59
+ expect(count.contents)->toBe(1)
60
+ })
61
+
62
+ testSync("a contribution registered after run does not fire", () => {
63
+ DB.reset()
64
+ let calls = []
65
+ DB.register(() => calls->Array.push("before"))
66
+ DB.run(PreDeploy)
67
+ DB.register(() => calls->Array.push("after"))
68
+ DB.run(PreDeploy)
69
+ expect(calls)->toEqual(["before"])
70
+ })
71
+ })
72
+ })