@reventlessdev/reventless-spec 3.0.0-alpha.130 → 3.0.0-alpha.131

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.
@@ -0,0 +1,66 @@
1
+ // Reading a built plugin's declared structure.
2
+ //
3
+ // A plugin's generated definition module is a functor over the platform type
4
+ // that exposes `pluginStructure` as an ordinary value, and the local platform's
5
+ // `Make` takes no configuration — so applying one to the other is enough to hold
6
+ // a real structure. No deploy program, no database, no server, nothing left
7
+ // running.
8
+ //
9
+ // This lives in a companion `.mjs` because it is untyped reflection: `import` is
10
+ // syntax rather than a value, so a computed specifier cannot be bound as an
11
+ // external, and the value that comes back is shaped by the plugin rather than by
12
+ // anything this repository can name.
13
+ //
14
+ // The structure is handed back as plain JSON and read field by field on the
15
+ // ReScript side, rather than parsed through the published schema. A
16
+ // `pluginStructure` has two legitimate representations — an absent optional is
17
+ // `undefined` in memory and an explicit `null` on the wire — and the published
18
+ // schema describes the wire form, so validating an in-memory structure against
19
+ // it fails on every optional that happens to be empty.
20
+ import { existsSync } from "node:fs";
21
+ import { join } from "node:path";
22
+
23
+ const localPlatformPath = (pluginDir) =>
24
+ join(
25
+ pluginDir,
26
+ "node_modules/@reventlessdev/reventless-local/src/Platform.res.mjs",
27
+ );
28
+
29
+ const pluginEntryPath = (pluginDir) => join(pluginDir, "src/Plugin.res.mjs");
30
+
31
+ /**
32
+ * @returns {Promise<{ok: true, structure: unknown} | {ok: false, error: string}>}
33
+ */
34
+ export const loadPluginStructure = async (pluginDir) => {
35
+ const entry = pluginEntryPath(pluginDir);
36
+ const local = localPlatformPath(pluginDir);
37
+ if (!existsSync(entry)) {
38
+ return {
39
+ ok: false,
40
+ error: `no compiled plugin at ${entry} — build the plugin first`,
41
+ };
42
+ }
43
+ if (!existsSync(local)) {
44
+ return {
45
+ ok: false,
46
+ error: `no local platform installed at ${local}`,
47
+ };
48
+ }
49
+ try {
50
+ const localMod = await import(local);
51
+ const pluginMod = await import(entry);
52
+ const structure = pluginMod.Make(localMod.Make()).pluginStructure;
53
+ // A structure whose component arrays are absent came from a release this
54
+ // reader cannot understand. Saying so beats reporting a model that is
55
+ // quietly half-empty.
56
+ const present = ["readModels", "stateViewSlices", "stateChangeSlices", "aggregates"].every(
57
+ (k) => Array.isArray(structure?.[k]),
58
+ );
59
+ return present
60
+ ? { ok: true, structure }
61
+ : { ok: false, error: "the plugin structure declares no component arrays" };
62
+ } catch (e) {
63
+ const message = e && (e.message || e.RE_EXN_ID) ? String(e.message || e.RE_EXN_ID) : "unknown error";
64
+ return { ok: false, error: `reading the plugin structure: ${message}` };
65
+ }
66
+ };