ruact 0.0.16 → 0.0.17

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 (35) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +21 -1
  3. data/lib/ruact/client_manifest.rb +11 -2
  4. data/lib/ruact/controller.rb +3 -1
  5. data/lib/ruact/doctor.rb +64 -4
  6. data/lib/ruact/flight/renderer.rb +23 -9
  7. data/lib/ruact/flight/request.rb +31 -2
  8. data/lib/ruact/flight/row_emitter.rb +9 -0
  9. data/lib/ruact/flight/serializer.rb +22 -7
  10. data/lib/ruact/render_pipeline.rb +10 -3
  11. data/lib/ruact/testing/component_query.rb +11 -4
  12. data/lib/ruact/testing/flight_wire_parser.rb +2 -2
  13. data/lib/ruact/version.rb +1 -1
  14. data/vendor/javascript/vite-plugin-ruact/bootstrap.test.mjs +44 -2
  15. data/vendor/javascript/vite-plugin-ruact/flight-conformance.test.mjs +286 -0
  16. data/vendor/javascript/vite-plugin-ruact/index.js +89 -14
  17. data/vendor/javascript/vite-plugin-ruact/package-lock.json +804 -3
  18. data/vendor/javascript/vite-plugin-ruact/package.json +5 -1
  19. data/vendor/javascript/vite-plugin-ruact/ruact-router.test.mjs +53 -0
  20. data/vendor/javascript/vite-plugin-ruact/runtime/bootstrap.jsx +46 -17
  21. data/vendor/javascript/vite-plugin-ruact/runtime/flight-modules.js +40 -0
  22. data/vendor/javascript/vite-plugin-ruact/runtime/flight-webpack-globals.js +15 -0
  23. data/vendor/javascript/vite-plugin-ruact/runtime/root-boundary.js +41 -0
  24. data/vendor/javascript/vite-plugin-ruact/runtime/ruact-router.js +65 -83
  25. data/vendor/javascript/vite-plugin-ruact/runtime/suspense-boundary.js +83 -0
  26. data/vendor/javascript/vite-plugin-ruact/runtime/transport.js +41 -0
  27. data/vendor/javascript/vite-plugin-ruact/runtime/vendor/react-server-dom-webpack/LICENSE +21 -0
  28. data/vendor/javascript/vite-plugin-ruact/runtime/vendor/react-server-dom-webpack/VERSION.json +5 -0
  29. data/vendor/javascript/vite-plugin-ruact/runtime/vendor/react-server-dom-webpack/client.browser.development.js +5473 -0
  30. data/vendor/javascript/vite-plugin-ruact/runtime/vendor/react-server-dom-webpack/client.browser.production.js +2126 -0
  31. data/vendor/javascript/vite-plugin-ruact/scripts/vendor-flight-client.mjs +124 -0
  32. data/vendor/javascript/vite-plugin-ruact/vitest.config.mjs +14 -0
  33. metadata +13 -4
  34. data/vendor/javascript/vite-plugin-ruact/flight-client.test.mjs +0 -499
  35. data/vendor/javascript/vite-plugin-ruact/runtime/flight-client.js +0 -436
@@ -0,0 +1,124 @@
1
+ #!/usr/bin/env node
2
+ // Story 18-1 — vendor React's Flight client into the gem.
3
+ //
4
+ // ruact decodes Flight with `react-server-dom-webpack/client.browser`, the
5
+ // client React publishes (docs/internal/decisions/flight-client-compatibility.md).
6
+ // The npm package declares `webpack` as a required peer, so the gem ships its
7
+ // own copy instead (packaging option C); an app that installs
8
+ // `react-server-dom-webpack` itself gets that one (see `flightClientSource` in
9
+ // ../index.js).
10
+ //
11
+ // The published files are CommonJS. The runtime is served from the gem's
12
+ // directory, which Vite does not pre-bundle, so this script wraps each one as
13
+ // an ES module:
14
+ //
15
+ // - `require("react")` / `require("react-dom")` become imports of the app's
16
+ // React (one React instance);
17
+ // - `__webpack_require__` / `__webpack_chunk_load__` become module-local
18
+ // functions over ruact's component registry (../runtime/flight-modules.js),
19
+ // so nothing named after webpack lands on `globalThis`;
20
+ // - `process.env.NODE_ENV` is fixed per variant.
21
+ //
22
+ // Usage: node scripts/vendor-flight-client.mjs (writes runtime/vendor/…)
23
+ // Re-running with the same VERSION/INTEGRITY writes identical bytes.
24
+
25
+ import { execFileSync } from "node:child_process";
26
+ import { createHash } from "node:crypto";
27
+ import fs from "node:fs";
28
+ import os from "node:os";
29
+ import path from "node:path";
30
+ import { fileURLToPath } from "node:url";
31
+
32
+ export const PACKAGE = "react-server-dom-webpack";
33
+ export const VERSION = "19.3.0";
34
+ const INTEGRITY =
35
+ "sha512-ymt9RkvWtW4OpIhWf1wj4u5CxnBaVbDCkz/bw3/QFmOE7+/wg8C30uiJ/QqkEdWn/UqT5c7/rOUW/eWYMwceCg==";
36
+
37
+ const HERE = path.dirname(fileURLToPath(import.meta.url));
38
+ const OUT_DIR = path.join(HERE, "..", "runtime", "vendor", PACKAGE);
39
+
40
+ // What the client exports (both variants export the same names).
41
+ const EXPORTS = [
42
+ "createFromFetch",
43
+ "createFromReadableStream",
44
+ "createServerReference",
45
+ "createTemporaryReferenceSet",
46
+ "encodeReply",
47
+ "registerServerReference",
48
+ ];
49
+
50
+ const VARIANTS = {
51
+ production: "cjs/react-server-dom-webpack-client.browser.production.js",
52
+ development: "cjs/react-server-dom-webpack-client.browser.development.js",
53
+ };
54
+
55
+ function fetchTarball(workDir) {
56
+ const out = execFileSync("npm", ["pack", `${PACKAGE}@${VERSION}`, "--silent", "--pack-destination", workDir], {
57
+ encoding: "utf8",
58
+ });
59
+ const file = path.join(workDir, out.trim().split("\n").pop());
60
+ const digest = `sha512-${createHash("sha512").update(fs.readFileSync(file)).digest("base64")}`;
61
+ if (digest !== INTEGRITY) {
62
+ throw new Error(`${PACKAGE}@${VERSION}: integrity mismatch\n expected ${INTEGRITY}\n got ${digest}`);
63
+ }
64
+ execFileSync("tar", ["-xzf", file, "-C", workDir]);
65
+ return path.join(workDir, "package");
66
+ }
67
+
68
+ export function wrap(cjsSource, mode) {
69
+ const usesReact = cjsSource.includes('require("react")');
70
+ const header = [
71
+ `// GENERATED by scripts/vendor-flight-client.mjs from ${PACKAGE}@${VERSION}`,
72
+ `// (${VARIANTS[mode]}, MIT — see LICENSE). Do not edit; re-run the script.`,
73
+ usesReact ? 'import React from "react";' : null,
74
+ 'import ReactDOM from "react-dom";',
75
+ 'import { requireModule, loadChunk } from "../../flight-modules.js";',
76
+ "",
77
+ "const module = { exports: {} };",
78
+ "const exports = module.exports;",
79
+ `const process = { env: { NODE_ENV: ${JSON.stringify(mode)} } };`,
80
+ "function require(id) {",
81
+ usesReact ? ' if (id === "react") return React;' : null,
82
+ ' if (id === "react-dom") return ReactDOM;',
83
+ ' throw new Error("[ruact] vendored Flight client required an unexpected module: " + id);',
84
+ "}",
85
+ "// What webpack's runtime would provide, over ruact's component registry.",
86
+ "function __webpack_require__(id) { return requireModule(id); }",
87
+ "function __webpack_chunk_load__(chunkId) { return loadChunk(chunkId); }",
88
+ "function __webpack_get_script_filename__(chunkId) { return chunkId; }",
89
+ "",
90
+ "(function () {",
91
+ ].filter((line) => line !== null);
92
+ const footer = [
93
+ "})();",
94
+ "",
95
+ ...EXPORTS.map((name) => `export const ${name} = module.exports.${name};`),
96
+ "",
97
+ ];
98
+ return `${header.join("\n")}\n${cjsSource.trimEnd()}\n${footer.join("\n")}`;
99
+ }
100
+
101
+ function main() {
102
+ const workDir = fs.mkdtempSync(path.join(os.tmpdir(), "ruact-vendor-"));
103
+ try {
104
+ const pkg = fetchTarball(workDir);
105
+ fs.mkdirSync(OUT_DIR, { recursive: true });
106
+ for (const [mode, rel] of Object.entries(VARIANTS)) {
107
+ const source = fs.readFileSync(path.join(pkg, rel), "utf8");
108
+ for (const name of EXPORTS) {
109
+ if (!source.includes(`exports.${name} =`)) throw new Error(`${rel}: export ${name} not found`);
110
+ }
111
+ fs.writeFileSync(path.join(OUT_DIR, `client.browser.${mode}.js`), wrap(source, mode));
112
+ }
113
+ fs.copyFileSync(path.join(pkg, "LICENSE"), path.join(OUT_DIR, "LICENSE"));
114
+ fs.writeFileSync(
115
+ path.join(OUT_DIR, "VERSION.json"),
116
+ `${JSON.stringify({ package: PACKAGE, version: VERSION, integrity: INTEGRITY }, null, 2)}\n`,
117
+ );
118
+ console.log(`vendored ${PACKAGE}@${VERSION} → ${path.relative(process.cwd(), OUT_DIR)}`);
119
+ } finally {
120
+ fs.rmSync(workDir, { recursive: true, force: true });
121
+ }
122
+ }
123
+
124
+ if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) main();
@@ -4,9 +4,23 @@
4
4
  // src/ + dist/ layout. Until then, run tests against the in-tree `.mjs` source
5
5
  // directly.
6
6
 
7
+ import { fileURLToPath } from "node:url";
7
8
  import { defineConfig } from "vitest/config";
8
9
 
10
+ // Story 18-1 — the runtime imports React's Flight client through a virtual id
11
+ // the plugin answers; under vitest it is the vendored copy. FLIGHT_CLIENT_MODE
12
+ // picks the build (the conformance suite runs both).
13
+ const flightClient = fileURLToPath(
14
+ new URL(
15
+ `./runtime/vendor/react-server-dom-webpack/client.browser.${process.env.FLIGHT_CLIENT_MODE || "development"}.js`,
16
+ import.meta.url,
17
+ ),
18
+ );
19
+
9
20
  export default defineConfig({
21
+ resolve: {
22
+ alias: { "virtual:ruact/flight-client": flightClient },
23
+ },
10
24
  test: {
11
25
  environment: "node",
12
26
  // The runtime's `index.test.mjs` is node-environment + dependency-free, so
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruact
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.16
4
+ version: 0.0.17
5
5
  platform: ruby
6
6
  authors:
7
7
  - Luiz Garcia
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-10-04 00:00:00.000000000 Z
11
+ date: 2026-10-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: nokogiri
@@ -148,7 +148,7 @@ files:
148
148
  - vendor/javascript/ruact-server-functions-runtime/package.json
149
149
  - vendor/javascript/ruact-server-functions-runtime/usequery.test.mjs
150
150
  - vendor/javascript/vite-plugin-ruact/bootstrap.test.mjs
151
- - vendor/javascript/vite-plugin-ruact/flight-client.test.mjs
151
+ - vendor/javascript/vite-plugin-ruact/flight-conformance.test.mjs
152
152
  - vendor/javascript/vite-plugin-ruact/index.js
153
153
  - vendor/javascript/vite-plugin-ruact/manifest-contract.test.mjs
154
154
  - vendor/javascript/vite-plugin-ruact/manifest-http.test.mjs
@@ -157,8 +157,17 @@ files:
157
157
  - vendor/javascript/vite-plugin-ruact/registry.test.mjs
158
158
  - vendor/javascript/vite-plugin-ruact/ruact-router.test.mjs
159
159
  - vendor/javascript/vite-plugin-ruact/runtime/bootstrap.jsx
160
- - vendor/javascript/vite-plugin-ruact/runtime/flight-client.js
160
+ - vendor/javascript/vite-plugin-ruact/runtime/flight-modules.js
161
+ - vendor/javascript/vite-plugin-ruact/runtime/flight-webpack-globals.js
162
+ - vendor/javascript/vite-plugin-ruact/runtime/root-boundary.js
161
163
  - vendor/javascript/vite-plugin-ruact/runtime/ruact-router.js
164
+ - vendor/javascript/vite-plugin-ruact/runtime/suspense-boundary.js
165
+ - vendor/javascript/vite-plugin-ruact/runtime/transport.js
166
+ - vendor/javascript/vite-plugin-ruact/runtime/vendor/react-server-dom-webpack/LICENSE
167
+ - vendor/javascript/vite-plugin-ruact/runtime/vendor/react-server-dom-webpack/VERSION.json
168
+ - vendor/javascript/vite-plugin-ruact/runtime/vendor/react-server-dom-webpack/client.browser.development.js
169
+ - vendor/javascript/vite-plugin-ruact/runtime/vendor/react-server-dom-webpack/client.browser.production.js
170
+ - vendor/javascript/vite-plugin-ruact/scripts/vendor-flight-client.mjs
162
171
  - vendor/javascript/vite-plugin-ruact/server-functions-codegen.mjs
163
172
  - vendor/javascript/vite-plugin-ruact/server-functions-codegen.test.mjs
164
173
  - vendor/javascript/vite-plugin-ruact/tsconfig.json