wawesome 0.22.0 → 0.24.0
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/dist/assets-Cgw3_rAq.mjs +336 -0
- package/dist/index.mjs +124 -398
- package/dist/local-modules-DvEInmfO.mjs +225 -0
- package/dist/local-modules.d.mts +16 -0
- package/dist/local-modules.mjs +2 -0
- package/dist/vite.d.mts +8 -2
- package/dist/vite.mjs +53 -3
- package/dist/vitest-setup.mjs +7 -0
- package/package.json +6 -2
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
import { f as readFunctionConfig, i as listFiles } from "./assets-Cgw3_rAq.mjs";
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
//#region ../../server/guest-surface/private-files.js
|
|
5
|
+
const constants = Object.freeze({
|
|
6
|
+
F_OK: 0,
|
|
7
|
+
R_OK: 4,
|
|
8
|
+
W_OK: 2,
|
|
9
|
+
X_OK: 1
|
|
10
|
+
});
|
|
11
|
+
function fsError(code, description, syscall, path) {
|
|
12
|
+
const error = /* @__PURE__ */ new Error(`${code}: ${description}, ${syscall} '${path}'`);
|
|
13
|
+
error.code = code;
|
|
14
|
+
error.syscall = syscall;
|
|
15
|
+
error.path = path;
|
|
16
|
+
return error;
|
|
17
|
+
}
|
|
18
|
+
function pathOf(path) {
|
|
19
|
+
if (path instanceof URL) return decodeURIComponent(path.pathname);
|
|
20
|
+
return String(path);
|
|
21
|
+
}
|
|
22
|
+
function keyOf(path) {
|
|
23
|
+
const segments = [];
|
|
24
|
+
for (const segment of path.split("/")) {
|
|
25
|
+
if (segment === "" || segment === ".") continue;
|
|
26
|
+
if (segment === "..") segments.pop();
|
|
27
|
+
else segments.push(segment);
|
|
28
|
+
}
|
|
29
|
+
return segments.join("/");
|
|
30
|
+
}
|
|
31
|
+
var Kind = class {
|
|
32
|
+
#folder;
|
|
33
|
+
constructor(folder) {
|
|
34
|
+
this.#folder = folder;
|
|
35
|
+
}
|
|
36
|
+
isFile() {
|
|
37
|
+
return !this.#folder;
|
|
38
|
+
}
|
|
39
|
+
isDirectory() {
|
|
40
|
+
return this.#folder;
|
|
41
|
+
}
|
|
42
|
+
isSymbolicLink() {
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
isBlockDevice() {
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
isCharacterDevice() {
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
isFIFO() {
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
isSocket() {
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
var Stats = class extends Kind {
|
|
59
|
+
constructor(entry) {
|
|
60
|
+
super(entry.folder);
|
|
61
|
+
this.size = entry.size;
|
|
62
|
+
this.mode = entry.folder ? 16749 : 33060;
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
var Dirent = class extends Kind {
|
|
66
|
+
constructor(name, parentPath, folder) {
|
|
67
|
+
super(folder);
|
|
68
|
+
this.name = name;
|
|
69
|
+
this.parentPath = parentPath;
|
|
70
|
+
this.path = parentPath;
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
function readOnly(syscall) {
|
|
74
|
+
return async (path) => {
|
|
75
|
+
throw fsError("EROFS", "read-only file system", syscall, pathOf(path));
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* `listing` is `[path, size]` pairs. `fetchFile(path)` answers a Response:
|
|
80
|
+
* 200 with the bytes, 404 for a file that is gone, 413 with the reason for a
|
|
81
|
+
* read past the invocation's cap.
|
|
82
|
+
*/
|
|
83
|
+
function privateFiles(listing, fetchFile) {
|
|
84
|
+
const sizes = new Map(listing);
|
|
85
|
+
const folders = /* @__PURE__ */ new Map([["", /* @__PURE__ */ new Set()]]);
|
|
86
|
+
for (const path of sizes.keys()) {
|
|
87
|
+
const segments = path.split("/");
|
|
88
|
+
for (let depth = 0; depth < segments.length; depth++) {
|
|
89
|
+
const parent = segments.slice(0, depth).join("/");
|
|
90
|
+
if (!folders.has(parent)) folders.set(parent, /* @__PURE__ */ new Set());
|
|
91
|
+
folders.get(parent).add(segments[depth]);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
function entryAt(name, syscall) {
|
|
95
|
+
const key = keyOf(name);
|
|
96
|
+
if (sizes.has(key)) return {
|
|
97
|
+
key,
|
|
98
|
+
folder: false,
|
|
99
|
+
size: sizes.get(key)
|
|
100
|
+
};
|
|
101
|
+
if (folders.has(key)) return {
|
|
102
|
+
key,
|
|
103
|
+
folder: true,
|
|
104
|
+
size: 0
|
|
105
|
+
};
|
|
106
|
+
throw fsError("ENOENT", "no such file or directory", syscall, name);
|
|
107
|
+
}
|
|
108
|
+
async function readFile(path, options) {
|
|
109
|
+
const name = pathOf(path);
|
|
110
|
+
const encoding = typeof options === "string" ? options : options?.encoding;
|
|
111
|
+
const entry = entryAt(name, "open");
|
|
112
|
+
if (entry.folder) throw fsError("EISDIR", "illegal operation on a directory", "read", name);
|
|
113
|
+
const response = await fetchFile(entry.key);
|
|
114
|
+
if (response.status === 404) throw fsError("ENOENT", "no such file or directory", "open", name);
|
|
115
|
+
if (response.status === 413) throw fsError("EFBIG", await response.text(), "read", name);
|
|
116
|
+
if (!response.ok) throw fsError("EIO", "i/o error", "read", name);
|
|
117
|
+
if (encoding == null) return new Uint8Array(await response.arrayBuffer());
|
|
118
|
+
if (/^utf-?8$/i.test(encoding)) return response.text();
|
|
119
|
+
return new TextDecoder(encoding).decode(await response.arrayBuffer());
|
|
120
|
+
}
|
|
121
|
+
async function readdir(path, options) {
|
|
122
|
+
const name = pathOf(path);
|
|
123
|
+
const entry = entryAt(name, "scandir");
|
|
124
|
+
if (!entry.folder) throw fsError("ENOTDIR", "not a directory", "scandir", name);
|
|
125
|
+
const listed = [];
|
|
126
|
+
const walk = (key, relative, parentPath) => {
|
|
127
|
+
for (const child of [...folders.get(key)].sort()) {
|
|
128
|
+
const childKey = key === "" ? child : `${key}/${child}`;
|
|
129
|
+
const folder = folders.has(childKey);
|
|
130
|
+
const childRelative = relative === "" ? child : `${relative}/${child}`;
|
|
131
|
+
listed.push(options?.withFileTypes ? new Dirent(child, parentPath, folder) : childRelative);
|
|
132
|
+
if (options?.recursive && folder) walk(childKey, childRelative, `${parentPath}/${child}`);
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
walk(entry.key, "", name);
|
|
136
|
+
return listed;
|
|
137
|
+
}
|
|
138
|
+
async function stat(path) {
|
|
139
|
+
return new Stats(entryAt(pathOf(path), "stat"));
|
|
140
|
+
}
|
|
141
|
+
async function lstat(path) {
|
|
142
|
+
return new Stats(entryAt(pathOf(path), "lstat"));
|
|
143
|
+
}
|
|
144
|
+
async function access(path, mode = constants.F_OK) {
|
|
145
|
+
const name = pathOf(path);
|
|
146
|
+
const entry = entryAt(name, "access");
|
|
147
|
+
if (mode & constants.W_OK) throw fsError("EROFS", "read-only file system", "access", name);
|
|
148
|
+
if (mode & constants.X_OK && !entry.folder) throw fsError("EACCES", "permission denied", "access", name);
|
|
149
|
+
}
|
|
150
|
+
return {
|
|
151
|
+
constants,
|
|
152
|
+
readFile,
|
|
153
|
+
readdir,
|
|
154
|
+
stat,
|
|
155
|
+
lstat,
|
|
156
|
+
access,
|
|
157
|
+
appendFile: readOnly("open"),
|
|
158
|
+
chmod: readOnly("chmod"),
|
|
159
|
+
chown: readOnly("chown"),
|
|
160
|
+
copyFile: readOnly("copyfile"),
|
|
161
|
+
cp: readOnly("cp"),
|
|
162
|
+
lchown: readOnly("lchown"),
|
|
163
|
+
link: readOnly("link"),
|
|
164
|
+
lutimes: readOnly("lutime"),
|
|
165
|
+
mkdir: readOnly("mkdir"),
|
|
166
|
+
mkdtemp: readOnly("mkdtemp"),
|
|
167
|
+
rename: readOnly("rename"),
|
|
168
|
+
rm: readOnly("rm"),
|
|
169
|
+
rmdir: readOnly("rmdir"),
|
|
170
|
+
symlink: readOnly("symlink"),
|
|
171
|
+
truncate: readOnly("open"),
|
|
172
|
+
unlink: readOnly("unlink"),
|
|
173
|
+
utimes: readOnly("utime"),
|
|
174
|
+
writeFile: readOnly("open")
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
//#endregion
|
|
178
|
+
//#region src/local-modules.ts
|
|
179
|
+
/**
|
|
180
|
+
* `DEFAULT_MAX_PRIVATE_FILE_READ_BYTES` in the runner. Production counts it over
|
|
181
|
+
* every read of one invocation; a local run has no invocation, so it holds for
|
|
182
|
+
* each read alone.
|
|
183
|
+
*/
|
|
184
|
+
const MAX_PRIVATE_FILE_READ_BYTES = 8388608;
|
|
185
|
+
const LOCAL_MODULES = { "fs-promises": localFsPromises };
|
|
186
|
+
/** A declared module as the guest gets it, backed by the project on disk. */
|
|
187
|
+
function localModule(shim, projectDir) {
|
|
188
|
+
const create = LOCAL_MODULES[shim];
|
|
189
|
+
if (!create) throw new Error(`wawesome: the guest surface declares the module '${shim}', and no local implementation is registered for it.`);
|
|
190
|
+
const exports = create(projectDir);
|
|
191
|
+
return {
|
|
192
|
+
...exports,
|
|
193
|
+
default: exports
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
/** Where `wawesome deploy` would take the private files from, if anywhere. */
|
|
197
|
+
function privateFilesDir(projectDir) {
|
|
198
|
+
const files = readFunctionConfig(projectDir)?.files;
|
|
199
|
+
return files ? path.resolve(projectDir, files) : null;
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* The platform's own rules over a listing read fresh on every call, so a file
|
|
203
|
+
* edited while the dev server runs is what the next request reads.
|
|
204
|
+
*/
|
|
205
|
+
function localFsPromises(projectDir) {
|
|
206
|
+
const dir = privateFilesDir(projectDir);
|
|
207
|
+
const current = () => onDisk(dir);
|
|
208
|
+
return Object.fromEntries(Object.entries(onDisk(null)).map(([name, value]) => [name, typeof value === "function" ? (...args) => current()[name](...args) : value]));
|
|
209
|
+
}
|
|
210
|
+
function onDisk(dir) {
|
|
211
|
+
const files = dir ? listFiles(dir) : [];
|
|
212
|
+
const byPath = new Map(files.map((file) => [file.path, file]));
|
|
213
|
+
return privateFiles(files.map((file) => [file.path, file.size_bytes]), async (key) => {
|
|
214
|
+
const file = byPath.get(key);
|
|
215
|
+
if (!file) return new Response(null, { status: 404 });
|
|
216
|
+
if (file.size_bytes > 8388608) return new Response(`one invocation may read at most ${MAX_PRIVATE_FILE_READ_BYTES} bytes of private files`, { status: 413 });
|
|
217
|
+
try {
|
|
218
|
+
return new Response(await fs.promises.readFile(file.source));
|
|
219
|
+
} catch {
|
|
220
|
+
return new Response(null, { status: 404 });
|
|
221
|
+
}
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
//#endregion
|
|
225
|
+
export { localModule as n, privateFilesDir as r, MAX_PRIVATE_FILE_READ_BYTES as t };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
//#region src/local-modules.d.ts
|
|
2
|
+
type LocalModule = Record<string, unknown> & {
|
|
3
|
+
default: Record<string, unknown>;
|
|
4
|
+
};
|
|
5
|
+
/**
|
|
6
|
+
* `DEFAULT_MAX_PRIVATE_FILE_READ_BYTES` in the runner. Production counts it over
|
|
7
|
+
* every read of one invocation; a local run has no invocation, so it holds for
|
|
8
|
+
* each read alone.
|
|
9
|
+
*/
|
|
10
|
+
declare const MAX_PRIVATE_FILE_READ_BYTES: number;
|
|
11
|
+
/** A declared module as the guest gets it, backed by the project on disk. */
|
|
12
|
+
declare function localModule(shim: string, projectDir: string): LocalModule;
|
|
13
|
+
/** Where `wawesome deploy` would take the private files from, if anywhere. */
|
|
14
|
+
declare function privateFilesDir(projectDir: string): string | null;
|
|
15
|
+
//#endregion
|
|
16
|
+
export { LocalModule, MAX_PRIVATE_FILE_READ_BYTES, localModule, privateFilesDir };
|
package/dist/vite.d.mts
CHANGED
|
@@ -18,6 +18,12 @@ interface WawesomeReactOptions {
|
|
|
18
18
|
* route and answer with an empty shell that fails to hydrate. Every URL it
|
|
19
19
|
* carries is a **Request-time base** away from the mount.
|
|
20
20
|
*/
|
|
21
|
-
declare function wawesomeReact(options?: WawesomeReactOptions): Plugin;
|
|
21
|
+
declare function wawesomeReact(options?: WawesomeReactOptions): Plugin[];
|
|
22
|
+
/**
|
|
23
|
+
* Hands the server code the dev server runs the platform's `node:fs/promises`,
|
|
24
|
+
* reading the project's `files` folder. Only the build leaves the import for
|
|
25
|
+
* the platform, so this is a no-op there.
|
|
26
|
+
*/
|
|
27
|
+
declare function wawesomePrivateFiles(): Plugin;
|
|
22
28
|
//#endregion
|
|
23
|
-
export { WawesomeReactOptions, wawesomeReact as default, wawesomeReact };
|
|
29
|
+
export { WawesomeReactOptions, wawesomeReact as default, wawesomeReact, wawesomePrivateFiles };
|
package/dist/vite.mjs
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
|
-
import { i as polyfilledGlobals, o as unsupportedGlobals, r as methodRemedy, t as declaredMethods } from "./guest-surface-BwrNP2Cz.mjs";
|
|
1
|
+
import { i as polyfilledGlobals, n as declaredModules, o as unsupportedGlobals, r as methodRemedy, t as declaredMethods } from "./guest-surface-BwrNP2Cz.mjs";
|
|
2
|
+
import { n as localModule, r as privateFilesDir, t as MAX_PRIVATE_FILE_READ_BYTES } from "./local-modules-DvEInmfO.mjs";
|
|
2
3
|
import fs from "node:fs";
|
|
3
4
|
import path from "node:path";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
4
6
|
//#region src/vite.ts
|
|
7
|
+
const LOCAL_MODULE_PREFIX = "\0wawesome:module:";
|
|
8
|
+
const LOCAL_MODULES_FILE = fileURLToPath(new URL(`./local-modules${path.extname(fileURLToPath(import.meta.url))}`, import.meta.url));
|
|
5
9
|
const DOCUMENT_MODULE_ID = "virtual:wawesome/document";
|
|
6
10
|
const BASE_MODULE_ID = "virtual:wawesome/base";
|
|
7
11
|
const RESOLVED_DOCUMENT = `\0${DOCUMENT_MODULE_ID}`;
|
|
@@ -32,7 +36,7 @@ function wawesomeReact(options = {}) {
|
|
|
32
36
|
let root = process.cwd();
|
|
33
37
|
let dev = null;
|
|
34
38
|
let clientBuild = null;
|
|
35
|
-
return {
|
|
39
|
+
return [wawesomePrivateFiles(), {
|
|
36
40
|
name: "wawesome:react-ssr",
|
|
37
41
|
config(_userConfig, env) {
|
|
38
42
|
const building = env.command === "build";
|
|
@@ -124,6 +128,52 @@ function wawesomeReact(options = {}) {
|
|
|
124
128
|
}
|
|
125
129
|
return documentModule(html, clientEntry, clientBuild);
|
|
126
130
|
}
|
|
131
|
+
}];
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Hands the server code the dev server runs the platform's `node:fs/promises`,
|
|
135
|
+
* reading the project's `files` folder. Only the build leaves the import for
|
|
136
|
+
* the platform, so this is a no-op there.
|
|
137
|
+
*/
|
|
138
|
+
function wawesomePrivateFiles() {
|
|
139
|
+
const shims = new Map(declaredModules().flatMap((module) => module.specifiers.map((specifier) => [specifier, module.shim])));
|
|
140
|
+
let root = process.cwd();
|
|
141
|
+
return {
|
|
142
|
+
name: "wawesome:private-files",
|
|
143
|
+
apply: "serve",
|
|
144
|
+
enforce: "pre",
|
|
145
|
+
config() {
|
|
146
|
+
return { resolve: { alias: [...shims.keys()].map((specifier) => ({
|
|
147
|
+
find: new RegExp(`^${specifier.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}$`),
|
|
148
|
+
replacement: specifier
|
|
149
|
+
})) } };
|
|
150
|
+
},
|
|
151
|
+
configResolved(config) {
|
|
152
|
+
root = config.root;
|
|
153
|
+
},
|
|
154
|
+
configureServer(server) {
|
|
155
|
+
const dir = privateFilesDir(root);
|
|
156
|
+
if (!dir) return;
|
|
157
|
+
server.config.logger.info(` wawesome node:fs/promises reads ${path.relative(root, dir) || "."} here, as on the guest`);
|
|
158
|
+
server.config.logger.warn(` each read here may take ${MAX_PRIVATE_FILE_READ_BYTES / 1024 / 1024} MiB; the guest counts that over a whole invocation`);
|
|
159
|
+
},
|
|
160
|
+
resolveId(id) {
|
|
161
|
+
if (this.environment.config.consumer !== "server") return;
|
|
162
|
+
const shim = shims.get(id);
|
|
163
|
+
if (shim) return LOCAL_MODULE_PREFIX + shim;
|
|
164
|
+
},
|
|
165
|
+
load(id) {
|
|
166
|
+
if (!id.startsWith(LOCAL_MODULE_PREFIX)) return;
|
|
167
|
+
const shim = id.slice(17);
|
|
168
|
+
const names = Object.keys(localModule(shim, root)).filter((name) => name !== "default");
|
|
169
|
+
return [
|
|
170
|
+
`import { localModule } from ${JSON.stringify(LOCAL_MODULES_FILE)};`,
|
|
171
|
+
`const module = localModule(${JSON.stringify(shim)}, ${JSON.stringify(root)});`,
|
|
172
|
+
`export const { ${names.join(", ")} } = module;`,
|
|
173
|
+
"export default module.default;",
|
|
174
|
+
""
|
|
175
|
+
].join("\n");
|
|
176
|
+
}
|
|
127
177
|
};
|
|
128
178
|
}
|
|
129
179
|
/**
|
|
@@ -244,4 +294,4 @@ function normalize(file) {
|
|
|
244
294
|
return file.replace(/\\/g, "/").replace(/^\.?\//, "");
|
|
245
295
|
}
|
|
246
296
|
//#endregion
|
|
247
|
-
export { wawesomeReact as default, wawesomeReact };
|
|
297
|
+
export { wawesomeReact as default, wawesomeReact, wawesomePrivateFiles };
|
package/dist/vitest-setup.mjs
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
|
+
import { n as declaredModules } from "./guest-surface-BwrNP2Cz.mjs";
|
|
1
2
|
import { t as applyGuestParity } from "./guest-parity-DA7x-8BC.mjs";
|
|
3
|
+
import { n as localModule } from "./local-modules-DvEInmfO.mjs";
|
|
4
|
+
import { vi } from "vitest";
|
|
2
5
|
//#region src/vitest-setup.ts
|
|
3
6
|
applyGuestParity();
|
|
7
|
+
for (const declared of declaredModules()) {
|
|
8
|
+
const module = localModule(declared.shim, process.cwd());
|
|
9
|
+
for (const specifier of declared.specifiers) vi.doMock(specifier, () => module);
|
|
10
|
+
}
|
|
4
11
|
//#endregion
|
|
5
12
|
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wawesome",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.24.0",
|
|
4
4
|
"description": "CLI tool for building and deploying serverless functions on wawesome.io platform",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -69,11 +69,15 @@
|
|
|
69
69
|
"vitest": "^4.1.10"
|
|
70
70
|
},
|
|
71
71
|
"peerDependencies": {
|
|
72
|
-
"vite": "^8.0.0"
|
|
72
|
+
"vite": "^8.0.0",
|
|
73
|
+
"vitest": "^4.0.0"
|
|
73
74
|
},
|
|
74
75
|
"peerDependenciesMeta": {
|
|
75
76
|
"vite": {
|
|
76
77
|
"optional": true
|
|
78
|
+
},
|
|
79
|
+
"vitest": {
|
|
80
|
+
"optional": true
|
|
77
81
|
}
|
|
78
82
|
}
|
|
79
83
|
}
|