@reventlessdev/reventless-local 3.0.0-alpha.180 → 3.0.0-alpha.182

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 CHANGED
@@ -3,6 +3,21 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ # 3.0.0-alpha.182 (2026-07-30)
7
+
8
+ **Note:** Version bump only for package @reventlessdev/reventless-local
9
+
10
+
11
+
12
+
13
+
14
+ # 3.0.0-alpha.181 (2026-07-30)
15
+
16
+ ### Features
17
+
18
+ * **spec,local:** resolve capability manifests beyond the example topology ([8bfadd5](https://github.com/ReventlessDev/reventless-core/commit/8bfadd5beef90c0c9f6f6f3fbb753c8b789469ed))
19
+
20
+
6
21
  # 3.0.0-alpha.180 (2026-07-30)
7
22
 
8
23
  ### Bug Fixes
@@ -1,53 +1,3 @@
1
1
  #!/usr/bin/env node
2
- // Emit `capabilities.json` beside a plugin's generated `Plugin.res`.
3
- //
4
- // Applies the plugin's compiled composition root to the local platform and
5
- // renders the structure-derived capability manifest — the same
6
- // `pluginStructure.requiredStores` walk the deployed plugin reports at
7
- // runtime, never a second scan of the sources. Untyped by necessity: a
8
- // dynamically imported module cannot be functor-applied from ReScript, so the
9
- // reflection lives here and everything typed lives in
10
- // `Reventless.CapabilityManifest`.
11
- //
12
- // Usage: emit-capabilities <srcDir> (run from the plugin package, after `rescript build`)
13
-
14
- import fs from "node:fs";
15
- import path from "node:path";
16
- import { pathToFileURL } from "node:url";
17
-
18
- // The local platform defaults to Debug-level logging; a build step should not.
19
- if (process.env.LOG_LEVEL === undefined) process.env.LOG_LEVEL = "warn";
20
-
21
- const srcDirArg = process.argv[2];
22
- if (srcDirArg === undefined || srcDirArg === "") {
23
- console.error("Usage: emit-capabilities <srcDir>");
24
- process.exit(1);
25
- }
26
-
27
- const srcDir = path.resolve(srcDirArg);
28
- const pluginModulePath = path.join(srcDir, "Plugin.res.mjs");
29
- if (!fs.existsSync(pluginModulePath)) {
30
- console.error(
31
- `emit-capabilities: ${pluginModulePath} not found — run \`rescript build\` first.`,
32
- );
33
- process.exit(1);
34
- }
35
-
36
- const LocalPlatform = await import(
37
- new URL("./src/Platform.res.mjs", import.meta.url)
38
- );
39
- const CapabilityManifest = await import(
40
- "@reventlessdev/reventless-spec/src/components/CapabilityManifest.res.mjs"
41
- );
42
-
43
- const Platform = LocalPlatform.Make();
44
- const Plugin = await import(pathToFileURL(pluginModulePath));
45
- const { pluginStructure } = Plugin.Make(Platform);
46
-
47
- const manifestPath = path.join(srcDir, "capabilities.json");
48
- fs.writeFileSync(manifestPath, CapabilityManifest.renderForStructure(pluginStructure));
49
- console.log("Generated: " + manifestPath);
50
-
51
- // Applying the platform functor wires in-process infrastructure; exit
52
- // explicitly so no lingering handle keeps the build step alive.
53
- process.exit(0);
2
+ import { main } from "./src/EmitCapabilities.res.mjs"
3
+ await main()
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reventlessdev/reventless-local",
3
- "version": "3.0.0-alpha.180",
3
+ "version": "3.0.0-alpha.182",
4
4
  "description": "Local platform for Reventless (in-memory or SQLite backend, for development and testing without AWS)",
5
5
  "license": "Apache-2.0",
6
6
  "bin": {
@@ -36,15 +36,15 @@
36
36
  "ws": "^8.18.0",
37
37
  "@reventlessdev/rescript-effect": "0.1.0-alpha.31",
38
38
  "@reventlessdev/rescript-graphql-yoga": "1.0.0-alpha.25",
39
- "@reventlessdev/rescript-jest": "1.0.0-alpha.9",
40
39
  "@reventlessdev/rescript-mcp-sdk": "1.0.0-alpha.20",
40
+ "@reventlessdev/rescript-jest": "1.0.0-alpha.9",
41
41
  "@reventlessdev/rescript-pulumi-pulumi": "2.3.0-alpha.17",
42
- "@reventlessdev/reventless-core": "3.0.0-alpha.192",
43
- "@reventlessdev/reventless-graphql-server": "1.0.0-alpha.40",
44
- "@reventlessdev/reventless-gwt": "1.0.0-alpha.139",
45
- "@reventlessdev/reventless-postgres": "3.0.0-alpha.56",
46
- "@reventlessdev/reventless-spec": "3.0.0-alpha.85",
47
- "@reventlessdev/reventless-infra": "3.0.0-alpha.110"
42
+ "@reventlessdev/reventless-core": "3.0.0-alpha.194",
43
+ "@reventlessdev/reventless-gwt": "1.0.0-alpha.141",
44
+ "@reventlessdev/reventless-graphql-server": "1.0.0-alpha.42",
45
+ "@reventlessdev/reventless-infra": "3.0.0-alpha.112",
46
+ "@reventlessdev/reventless-spec": "3.0.0-alpha.87",
47
+ "@reventlessdev/reventless-postgres": "3.0.0-alpha.58"
48
48
  },
49
49
  "devDependencies": {
50
50
  "rescript": "12.3.0",
@@ -0,0 +1,113 @@
1
+ // Emit `capabilities.json` beside a plugin's compiled composition root.
2
+ //
3
+ // Applies the plugin's composition root to the local platform and renders the
4
+ // structure-derived capability manifest — the same `pluginStructure` walk the
5
+ // deployed plugin reports at runtime, never a second scan of the sources.
6
+ //
7
+ // The two dynamically imported modules are the only untyped surface, and they
8
+ // are typed *at the boundary*: `Platform.res.mjs` and every composition root
9
+ // emit exactly the exports declared below, so `pluginStructure` arrives as
10
+ // `Reventless.Plugin.pluginStructure` and everything downstream is ordinary
11
+ // typed ReScript. Same shape as `ReventlessGwt.LocalHost`, which reflects the
12
+ // domain graph this way.
13
+ //
14
+ // The platform is reached through a dynamic import rather than by applying
15
+ // `Platform.Make` directly: a composition root's `Make` is a JS function
16
+ // expecting the platform *value*, and a ReScript module is not one. Importing
17
+ // it puts both sides on the same footing, and it keeps `LOG_LEVEL` (set below)
18
+ // in force before the platform's logger initialises.
19
+ //
20
+ // Usage: emit-capabilities <srcDir> [<compositionModule>]
21
+ // (run from the plugin package, after `rescript build`)
22
+
23
+ // ── Node ─────────────────────────────────────────────────────────────────────
24
+
25
+ @module("node:fs") external existsSync: string => bool = "existsSync"
26
+ @module("node:fs") external writeFileSync: (string, string, @as("utf8") _) => unit = "writeFileSync"
27
+
28
+ @module("node:path") @variadic external join: array<string> => string = "join"
29
+ @module("node:path") @variadic external resolve: array<string> => string = "resolve"
30
+ @module("node:path") @val external sep: string = "sep"
31
+
32
+ @module("node:url") external pathToFileURL: string => {"href": string} = "pathToFileURL"
33
+
34
+ @val @scope("process") external argv: array<string> = "argv"
35
+ @val @scope("process") external env: Dict.t<string> = "env"
36
+ @val external processExit: int => unit = "process.exit"
37
+
38
+ // Emitted by ReScript as a literal `import(...)` expression — the composition
39
+ // root's path is only known at run time, so it cannot be a static binding.
40
+ @val external dynImport: string => promise<'a> = "import"
41
+
42
+ // ── The dynamic-import boundary ──────────────────────────────────────────────
43
+
44
+ type platform
45
+ type localPlatformExports = {"Make": unit => platform}
46
+ type builtPlugin = {"pluginStructure": Reventless.Plugin.pluginStructure}
47
+ type compositionExports = {"Make": platform => builtPlugin}
48
+
49
+ // ── Which module holds the composition root ──────────────────────────────────
50
+
51
+ /** `Plugin.res.mjs` is what `generate-plugin` emits, so it is the default and
52
+ every existing caller is unaffected. A hand-written composition root is
53
+ named after its plugin instead and says so: a bare module name (`Catalog`)
54
+ resolves inside `<srcDir>`, a path (`../lib/Catalog.res.mjs`) from the
55
+ working directory. */
56
+ let compositionModulePath = (~srcDir: string, ~moduleArg: option<string>): string => {
57
+ let withExtension = name => name->String.endsWith(".mjs") ? name : name ++ ".res.mjs"
58
+ switch moduleArg {
59
+ | None | Some("") => join([srcDir, "Plugin.res.mjs"])
60
+ | Some(name) =>
61
+ name->String.includes("/") || name->String.includes(sep)
62
+ ? resolve([withExtension(name)])
63
+ : join([srcDir, withExtension(name)])
64
+ }
65
+ }
66
+
67
+ // ── Entry point ──────────────────────────────────────────────────────────────
68
+
69
+ let fail = (message: string) => {
70
+ Console.error("emit-capabilities: " ++ message)
71
+ processExit(1)
72
+ }
73
+
74
+ let main = async () => {
75
+ // The local platform defaults to Debug-level logging; a build step should not.
76
+ switch env->Dict.get("LOG_LEVEL") {
77
+ | Some(_) => ()
78
+ | None => env->Dict.set("LOG_LEVEL", "warn")
79
+ }
80
+
81
+ switch argv->Array.get(2) {
82
+ | None | Some("") => {
83
+ Console.error("Usage: emit-capabilities <srcDir> [<compositionModule>]")
84
+ processExit(1)
85
+ }
86
+ | Some(srcDirArg) => {
87
+ let srcDir = resolve([srcDirArg])
88
+ let modulePath = compositionModulePath(~srcDir, ~moduleArg=argv->Array.get(3))
89
+ if !existsSync(modulePath) {
90
+ fail(`${modulePath} not found — run \`rescript build\` first.`)
91
+ }
92
+
93
+ // Relative specifier: resolved against this module, so it finds the
94
+ // sibling compiled platform whatever the working directory is.
95
+ let platformModule: localPlatformExports = await dynImport("./Platform.res.mjs")
96
+ let platform = platformModule["Make"]()
97
+
98
+ let composition: compositionExports = await dynImport(pathToFileURL(modulePath)["href"])
99
+ let built = composition["Make"](platform)
100
+
101
+ let manifestPath = join([srcDir, "capabilities.json"])
102
+ writeFileSync(
103
+ manifestPath,
104
+ Reventless.CapabilityManifest.renderForStructure(built["pluginStructure"]),
105
+ )
106
+ Console.log("Generated: " ++ manifestPath)
107
+
108
+ // Applying the platform functor wires in-process infrastructure; exit
109
+ // explicitly so no lingering handle keeps the build step alive.
110
+ processExit(0)
111
+ }
112
+ }
113
+ }
@@ -0,0 +1,70 @@
1
+ // Generated by ReScript, PLEASE EDIT WITH CARE
2
+
3
+ import * as Nodefs from "node:fs";
4
+ import * as Nodeurl from "node:url";
5
+ import * as Nodepath from "node:path";
6
+ import * as CapabilityManifest$Reventless from "@reventlessdev/reventless-spec/src/components/CapabilityManifest.res.mjs";
7
+
8
+ function compositionModulePath(srcDir, moduleArg) {
9
+ let withExtension = name => {
10
+ if (name.endsWith(".mjs")) {
11
+ return name;
12
+ } else {
13
+ return name + ".res.mjs";
14
+ }
15
+ };
16
+ if (moduleArg !== undefined && moduleArg !== "") {
17
+ if (moduleArg.includes("/") || moduleArg.includes(Nodepath.sep)) {
18
+ return Nodepath.resolve(withExtension(moduleArg));
19
+ } else {
20
+ return Nodepath.join(srcDir, withExtension(moduleArg));
21
+ }
22
+ } else {
23
+ return Nodepath.join(srcDir, "Plugin.res.mjs");
24
+ }
25
+ }
26
+
27
+ function fail(message) {
28
+ console.error("emit-capabilities: " + message);
29
+ process.exit(1);
30
+ }
31
+
32
+ async function main() {
33
+ let match = process.env["LOG_LEVEL"];
34
+ if (match !== undefined) {
35
+
36
+ } else {
37
+ process.env["LOG_LEVEL"] = "warn";
38
+ }
39
+ let srcDirArg = process.argv[2];
40
+ if (srcDirArg !== undefined) {
41
+ if (srcDirArg === "") {
42
+ console.error("Usage: emit-capabilities <srcDir> [<compositionModule>]");
43
+ process.exit(1);
44
+ return;
45
+ }
46
+ let srcDir = Nodepath.resolve(srcDirArg);
47
+ let modulePath = compositionModulePath(srcDir, process.argv[3]);
48
+ if (!Nodefs.existsSync(modulePath)) {
49
+ fail(modulePath + ` not found — run \`rescript build\` first.`);
50
+ }
51
+ let platformModule = await import("./Platform.res.mjs");
52
+ let platform = platformModule.Make();
53
+ let composition = await import(Nodeurl.pathToFileURL(modulePath).href);
54
+ let built = composition.Make(platform);
55
+ let manifestPath = Nodepath.join(srcDir, "capabilities.json");
56
+ Nodefs.writeFileSync(manifestPath, CapabilityManifest$Reventless.renderForStructure(built.pluginStructure), "utf8");
57
+ console.log("Generated: " + manifestPath);
58
+ process.exit(0);
59
+ return;
60
+ }
61
+ console.error("Usage: emit-capabilities <srcDir> [<compositionModule>]");
62
+ process.exit(1);
63
+ }
64
+
65
+ export {
66
+ compositionModulePath,
67
+ fail,
68
+ main,
69
+ }
70
+ /* node:fs Not a pure module */