render-workflows-dart 0.8.2
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 +193 -0
- package/LICENSE +21 -0
- package/README.md +678 -0
- package/dart/generator/bin/generate.dart +419 -0
- package/dart/generator/pubspec.lock +149 -0
- package/dart/generator/pubspec.yaml +9 -0
- package/examples/README.md +56 -0
- package/examples/default/README.md +18 -0
- package/examples/default/gitignore +7 -0
- package/examples/default/index.js +2 -0
- package/examples/default/package.json +17 -0
- package/examples/default/pubspec.yaml +7 -0
- package/examples/default/tasks.dart +39 -0
- package/examples/http/README.md +26 -0
- package/examples/http/gitignore +7 -0
- package/examples/http/index.js +2 -0
- package/examples/http/package.json +18 -0
- package/examples/http/pubspec.yaml +13 -0
- package/examples/http/tasks.dart +100 -0
- package/examples/introspect/README.md +50 -0
- package/examples/introspect/gitignore +7 -0
- package/examples/introspect/index.js +2 -0
- package/examples/introspect/node_env.dart +35 -0
- package/examples/introspect/package.json +18 -0
- package/examples/introspect/pubspec.yaml +23 -0
- package/examples/introspect/tasks.dart +144 -0
- package/examples/native/README.md +32 -0
- package/examples/native/gitignore +7 -0
- package/examples/native/index.js +2 -0
- package/examples/native/native/tools_impl.dart +105 -0
- package/examples/native/package.json +23 -0
- package/examples/native/pubspec.yaml +7 -0
- package/examples/native/tasks.dart +35 -0
- package/examples/postgres/README.md +73 -0
- package/examples/postgres/gitignore +7 -0
- package/examples/postgres/index.js +2 -0
- package/examples/postgres/native/db_impl.dart +205 -0
- package/examples/postgres/package.json +26 -0
- package/examples/postgres/pubspec.yaml +14 -0
- package/examples/postgres/seed/bin/seed.dart +56 -0
- package/examples/postgres/seed/bin/show.dart +64 -0
- package/examples/postgres/seed/lib/src/connect.dart +93 -0
- package/examples/postgres/seed/lib/src/schema.dart +46 -0
- package/examples/postgres/seed/pubspec.yaml +17 -0
- package/examples/postgres/tasks.dart +66 -0
- package/package.json +51 -0
- package/runtime/AGENTS.md +141 -0
- package/runtime/CLAUDE.md +2 -0
- package/runtime/native_task.dart +115 -0
- package/runtime/render_dart.dart +428 -0
- package/src/cli.js +396 -0
- package/src/native-worker.js +196 -0
- package/src/node-bridge.js +118 -0
- package/src/runtime.js +108 -0
- package/src/toolchain/compile.js +153 -0
- package/src/toolchain/dart-sdk.js +216 -0
- package/src/toolchain/dart-version.js +113 -0
- package/src/toolchain/generate.js +112 -0
- package/src/toolchain/index.js +8 -0
- package/src/toolchain/native.js +217 -0
- package/src/web-shims.js +281 -0
package/src/web-shims.js
ADDED
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
// Browser-shaped APIs that Dart packages expect and Node does not provide.
|
|
2
|
+
//
|
|
3
|
+
// Kept separate from the Render task bridge: none of this knows what a
|
|
4
|
+
// workflow is, and all of it is independently testable.
|
|
5
|
+
|
|
6
|
+
const { readFile } = require('node:fs/promises');
|
|
7
|
+
const { pathToFileURL, fileURLToPath } = require('node:url');
|
|
8
|
+
const path = require('node:path');
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* dart2js output expects `self` to exist.
|
|
12
|
+
*
|
|
13
|
+
* Without it the async scheduler fails *silently* — the program prints
|
|
14
|
+
* nothing, never completes its futures, and exits 0.
|
|
15
|
+
*/
|
|
16
|
+
function installSelf() {
|
|
17
|
+
globalThis.self ??= globalThis;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Resolves Dart's web package-asset convention against the real pub layout.
|
|
22
|
+
*
|
|
23
|
+
* A Dart web app serves a package's lib/ directory at `packages/<name>/`, and
|
|
24
|
+
* packages that ship assets ask for them at exactly that path. Nothing serves
|
|
25
|
+
* it under Node, so those requests fail — which is why a package like forge2d
|
|
26
|
+
* cannot find its bundled wasm module here.
|
|
27
|
+
*
|
|
28
|
+
* `.dart_tool/package_config.json`, written by `dart pub get`, maps every
|
|
29
|
+
* package to its root, so the mapping is reconstructed exactly rather than
|
|
30
|
+
* guessed. Read lazily and cached: most tasks never load an asset.
|
|
31
|
+
*/
|
|
32
|
+
let packageRootsPromise;
|
|
33
|
+
|
|
34
|
+
function packageRoots() {
|
|
35
|
+
packageRootsPromise ??= (async () => {
|
|
36
|
+
const configPath = path.resolve(
|
|
37
|
+
process.cwd(),
|
|
38
|
+
'.dart_tool',
|
|
39
|
+
'package_config.json',
|
|
40
|
+
);
|
|
41
|
+
try {
|
|
42
|
+
const config = JSON.parse(await readFile(configPath, 'utf8'));
|
|
43
|
+
const roots = new Map();
|
|
44
|
+
for (const pkg of config.packages ?? []) {
|
|
45
|
+
// rootUri may be absolute, or relative to .dart_tool/.
|
|
46
|
+
const root = new URL(pkg.rootUri, pathToFileURL(configPath));
|
|
47
|
+
roots.set(pkg.name, new URL(pkg.packageUri ?? 'lib/', `${root}/`));
|
|
48
|
+
}
|
|
49
|
+
return roots;
|
|
50
|
+
} catch {
|
|
51
|
+
// No pub dependencies, or pub get has not run. Nothing to resolve.
|
|
52
|
+
return new Map();
|
|
53
|
+
}
|
|
54
|
+
})();
|
|
55
|
+
return packageRootsPromise;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** `packages/<name>/<path>` or `package:<name>/<path>` -> a file: URL. */
|
|
59
|
+
async function resolvePackageAsset(url) {
|
|
60
|
+
const match =
|
|
61
|
+
/^package:([A-Za-z_][A-Za-z0-9_]*)\/(.+)$/.exec(url) ??
|
|
62
|
+
/^\/?packages\/([A-Za-z_][A-Za-z0-9_]*)\/(.+)$/.exec(url);
|
|
63
|
+
if (!match) return null;
|
|
64
|
+
|
|
65
|
+
const [, name, rest] = match;
|
|
66
|
+
const libUri = (await packageRoots()).get(name);
|
|
67
|
+
return libUri ? new URL(rest, libUri).href : null;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Teaches fetch the `file:` scheme and Dart's package-asset paths.
|
|
72
|
+
*
|
|
73
|
+
* Node's fetch supports `data:` but not `file:`, so packages that load bundled
|
|
74
|
+
* assets through fetch cannot find them. Anything else is delegated to the
|
|
75
|
+
* real fetch untouched.
|
|
76
|
+
*/
|
|
77
|
+
function installFetch() {
|
|
78
|
+
if (typeof globalThis.fetch !== 'function') return;
|
|
79
|
+
if (globalThis.fetch.__renderDartFilePatch) return;
|
|
80
|
+
|
|
81
|
+
const realFetch = globalThis.fetch;
|
|
82
|
+
|
|
83
|
+
const patched = async (input, init) => {
|
|
84
|
+
const url =
|
|
85
|
+
typeof input === 'string'
|
|
86
|
+
? input
|
|
87
|
+
: input instanceof URL
|
|
88
|
+
? input.href
|
|
89
|
+
: (input && input.url) || String(input);
|
|
90
|
+
|
|
91
|
+
let target = url;
|
|
92
|
+
if (!target.startsWith('file:')) {
|
|
93
|
+
const resolved = await resolvePackageAsset(target);
|
|
94
|
+
if (resolved === null) return realFetch(input, init);
|
|
95
|
+
target = resolved;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
try {
|
|
99
|
+
const bytes = await readFile(new URL(target));
|
|
100
|
+
return new Response(bytes, {
|
|
101
|
+
status: 200,
|
|
102
|
+
headers: {
|
|
103
|
+
'content-type': target.endsWith('.wasm')
|
|
104
|
+
? 'application/wasm'
|
|
105
|
+
: 'application/octet-stream',
|
|
106
|
+
},
|
|
107
|
+
});
|
|
108
|
+
} catch (e) {
|
|
109
|
+
// Match fetch's contract: a missing file is a 404, not a throw, so
|
|
110
|
+
// callers trying several candidate URLs can keep going.
|
|
111
|
+
if (e.code === 'ENOENT' || e.code === 'EISDIR') {
|
|
112
|
+
return new Response(null, { status: 404, statusText: 'Not Found' });
|
|
113
|
+
}
|
|
114
|
+
throw e;
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
patched.__renderDartFilePatch = true;
|
|
119
|
+
globalThis.fetch = patched;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* A minimal XMLHttpRequest over fetch.
|
|
124
|
+
*
|
|
125
|
+
* Most Dart packages reach the network through package:http, which uses fetch
|
|
126
|
+
* and already works. Some load assets with XHR directly — wasm_run does — and
|
|
127
|
+
* would otherwise fail with "XMLHttpRequest is not a constructor".
|
|
128
|
+
*
|
|
129
|
+
* This covers what asset loading needs: GET, arraybuffer and text responses,
|
|
130
|
+
* and the load/error/loadend events Dart listens for. Deliberately not a
|
|
131
|
+
* complete XHR: no sync mode, no upload progress, no response headers.
|
|
132
|
+
*/
|
|
133
|
+
function installXmlHttpRequest() {
|
|
134
|
+
if (typeof globalThis.XMLHttpRequest !== 'undefined') return;
|
|
135
|
+
|
|
136
|
+
globalThis.XMLHttpRequest = class XMLHttpRequest {
|
|
137
|
+
constructor() {
|
|
138
|
+
this.readyState = 0;
|
|
139
|
+
this.status = 0;
|
|
140
|
+
this.response = null;
|
|
141
|
+
this.responseText = '';
|
|
142
|
+
this.responseType = '';
|
|
143
|
+
this.timeout = 0;
|
|
144
|
+
this.withCredentials = false;
|
|
145
|
+
this._headers = {};
|
|
146
|
+
this._listeners = Object.create(null);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
open(method, url) {
|
|
150
|
+
this._method = method;
|
|
151
|
+
this._url = url;
|
|
152
|
+
this.readyState = 1;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
setRequestHeader(key, value) {
|
|
156
|
+
this._headers[key] = value;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
addEventListener(type, fn) {
|
|
160
|
+
(this._listeners[type] ??= []).push(fn);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
removeEventListener(type, fn) {
|
|
164
|
+
this._listeners[type] = (this._listeners[type] ?? []).filter(
|
|
165
|
+
(f) => f !== fn,
|
|
166
|
+
);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
getAllResponseHeaders() {
|
|
170
|
+
return '';
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
abort() {}
|
|
174
|
+
|
|
175
|
+
_emit(type) {
|
|
176
|
+
const event = { type, target: this, currentTarget: this };
|
|
177
|
+
for (const fn of this._listeners[type] ?? []) fn.call(this, event);
|
|
178
|
+
const handler = this[`on${type}`];
|
|
179
|
+
if (typeof handler === 'function') handler.call(this, event);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
send(body) {
|
|
183
|
+
globalThis
|
|
184
|
+
.fetch(this._url, {
|
|
185
|
+
method: this._method ?? 'GET',
|
|
186
|
+
headers: this._headers,
|
|
187
|
+
body,
|
|
188
|
+
})
|
|
189
|
+
.then(async (res) => {
|
|
190
|
+
this.status = res.status;
|
|
191
|
+
this.readyState = 4;
|
|
192
|
+
if (this.responseType === 'arraybuffer') {
|
|
193
|
+
this.response = await res.arrayBuffer();
|
|
194
|
+
} else {
|
|
195
|
+
this.responseText = await res.text();
|
|
196
|
+
this.response = this.responseText;
|
|
197
|
+
}
|
|
198
|
+
this._emit('load');
|
|
199
|
+
this._emit('loadend');
|
|
200
|
+
})
|
|
201
|
+
.catch(() => {
|
|
202
|
+
this.status = 0;
|
|
203
|
+
this.readyState = 4;
|
|
204
|
+
this._emit('error');
|
|
205
|
+
this._emit('loadend');
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Seeds the two globals wasm_run would otherwise load by injecting `<script>`
|
|
213
|
+
* tags into an HTML document.
|
|
214
|
+
*
|
|
215
|
+
* wasm_run's setup checks whether each global is already present and skips
|
|
216
|
+
* injection when it is, so providing them removes its only need for a DOM. Its
|
|
217
|
+
* native executor still requires dart:ffi and is unavailable here; the web
|
|
218
|
+
* executor runs on the host's own WebAssembly, which Node has.
|
|
219
|
+
*
|
|
220
|
+
* Does nothing unless wasm_run is actually a dependency.
|
|
221
|
+
*/
|
|
222
|
+
let wasmRunGlobalsPromise;
|
|
223
|
+
|
|
224
|
+
function ensureWasmRunGlobals() {
|
|
225
|
+
wasmRunGlobalsPromise ??= (async () => {
|
|
226
|
+
const wasmRunLib = (await packageRoots()).get('wasm_run');
|
|
227
|
+
if (!wasmRunLib) return;
|
|
228
|
+
|
|
229
|
+
// Shipped inside the pub package as a UMD bundle that assigns itself to
|
|
230
|
+
// globalThis, so no npm dependency is needed for this one.
|
|
231
|
+
if (globalThis.wasmFeatureDetect === undefined) {
|
|
232
|
+
try {
|
|
233
|
+
require(
|
|
234
|
+
fileURLToPath(new URL('assets/wasm-feature-detect.js', wasmRunLib)),
|
|
235
|
+
);
|
|
236
|
+
} catch {
|
|
237
|
+
// Older wasm_run, or the asset moved. wasm_run falls back to its own
|
|
238
|
+
// loading path and reports the problem itself.
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// The shipped asset pulls this from a CDN and hangs it on `window`; the
|
|
243
|
+
// same module is on npm. Optional: only projects using wasm_run need it.
|
|
244
|
+
if (globalThis.browser_wasi_shim === undefined) {
|
|
245
|
+
try {
|
|
246
|
+
const shim = await import('@bjorn3/browser_wasi_shim');
|
|
247
|
+
globalThis.browser_wasi_shim = {
|
|
248
|
+
WASI: shim.WASI,
|
|
249
|
+
Fd: shim.Fd,
|
|
250
|
+
File: shim.File,
|
|
251
|
+
Directory: shim.Directory,
|
|
252
|
+
OpenFile: shim.OpenFile,
|
|
253
|
+
OpenDirectory: shim.OpenDirectory,
|
|
254
|
+
PreopenDirectory: shim.PreopenDirectory,
|
|
255
|
+
strace: shim.strace,
|
|
256
|
+
};
|
|
257
|
+
} catch {
|
|
258
|
+
// Not installed. Only WASI modules need it, and wasm_run raises a
|
|
259
|
+
// clear error if one turns out to.
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
})();
|
|
263
|
+
return wasmRunGlobalsPromise;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/** Installs every shim. Safe to call more than once. */
|
|
267
|
+
function installWebShims() {
|
|
268
|
+
installSelf();
|
|
269
|
+
installFetch();
|
|
270
|
+
installXmlHttpRequest();
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
module.exports = {
|
|
274
|
+
installWebShims,
|
|
275
|
+
installSelf,
|
|
276
|
+
installFetch,
|
|
277
|
+
installXmlHttpRequest,
|
|
278
|
+
ensureWasmRunGlobals,
|
|
279
|
+
packageRoots,
|
|
280
|
+
resolvePackageAsset,
|
|
281
|
+
};
|