create-nodejs-fn 0.0.1 → 0.0.3
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/README.md +37 -19
- package/package.json +5 -4
- package/dist/cli.d.ts +0 -1
- package/dist/cli.js +0 -356
- package/dist/index.d.ts +0 -36
- package/dist/index.js +0 -1013
package/README.md
CHANGED
|
@@ -162,27 +162,33 @@ Visit `http://localhost:5173/clock` to see a dynamically generated image with th
|
|
|
162
162
|
|
|
163
163
|
## 🪄 The Black Magic Revealed
|
|
164
164
|
|
|
165
|
-
### 1️⃣
|
|
165
|
+
### 1️⃣ Extract `nodejsFn` Contents (Clip & Crop)
|
|
166
166
|
|
|
167
|
-
|
|
168
|
-
Detects exported functions and **auto-generates proxy functions with identical type signatures**.
|
|
167
|
+
The plugin uses `ts-morph` to **statically analyze** `*.container.ts` files and **extracts the function bodies** wrapped in `nodejsFn()`.
|
|
169
168
|
|
|
170
169
|
```typescript
|
|
171
170
|
// Your code (clock.container.ts)
|
|
172
171
|
export const renderClock = nodejsFn(async () => {
|
|
173
|
-
|
|
172
|
+
const canvas = createCanvas(600, 200);
|
|
173
|
+
// ... Node.js native processing
|
|
174
174
|
return pngDataUrl;
|
|
175
175
|
});
|
|
176
176
|
|
|
177
|
-
// 🧙
|
|
178
|
-
// →
|
|
179
|
-
// → Calls are routed to the container via RPC!
|
|
177
|
+
// 🧙 Plugin extracts the inner function from nodejsFn()
|
|
178
|
+
// → Only the function body is clipped out for the container!
|
|
180
179
|
```
|
|
181
180
|
|
|
182
|
-
### 2️⃣
|
|
181
|
+
### 2️⃣ Bundle & Build Docker Image
|
|
182
|
+
|
|
183
|
+
The extracted functions are **bundled with esbuild** and combined with an auto-generated **Dockerfile** to create a Docker image.
|
|
184
|
+
|
|
185
|
+
- Functions are bundled as a Cap'n Proto RPC server
|
|
186
|
+
- Native dependencies specified in `external` are auto-extracted to `package.json`
|
|
187
|
+
- Dockerfile is auto-generated and image is built
|
|
183
188
|
|
|
184
|
-
|
|
185
|
-
|
|
189
|
+
### 3️⃣ Deploy as Cloudflare Containers
|
|
190
|
+
|
|
191
|
+
The generated Docker image is **bundled as Cloudflare Containers**, with **Durable Objects** managing the container lifecycle.
|
|
186
192
|
|
|
187
193
|
```typescript
|
|
188
194
|
// Route to specific instances with containerKey
|
|
@@ -195,11 +201,21 @@ export const renderClock = nodejsFn(
|
|
|
195
201
|
);
|
|
196
202
|
```
|
|
197
203
|
|
|
198
|
-
###
|
|
204
|
+
### 4️⃣ Auto-Replace Imports with Container Calls
|
|
205
|
+
|
|
206
|
+
Imports to `*.container.ts` files are **automatically replaced with proxy module imports** by the Vite plugin.
|
|
207
|
+
|
|
208
|
+
```typescript
|
|
209
|
+
// Your code
|
|
210
|
+
import { renderClock } from "./clock.container";
|
|
211
|
+
|
|
212
|
+
// 🧙 Plugin auto-transforms this!
|
|
213
|
+
// → Actually imports a generated proxy function
|
|
214
|
+
// → Calls are transparently converted to Container RPC!
|
|
215
|
+
// → Types are fully preserved! IDE autocomplete works!
|
|
216
|
+
```
|
|
199
217
|
|
|
200
|
-
|
|
201
|
-
- **Auto-generates Dockerfile**
|
|
202
|
-
- Native deps specified in `external` are auto-extracted to `package.json`
|
|
218
|
+
**Result**: Code that looks like normal function calls actually executes inside Docker containers!
|
|
203
219
|
|
|
204
220
|
|
|
205
221
|
## ⚙️ Plugin Options
|
|
@@ -259,11 +275,13 @@ project/
|
|
|
259
275
|
│ ├── clock.container.ts # Your code
|
|
260
276
|
│ ├── index.ts # Worker entry
|
|
261
277
|
│ └── __generated__/ # 🧙 Auto-generated magic
|
|
262
|
-
│ ├── create-nodejs-fn.ts
|
|
263
|
-
│ ├── create-nodejs-fn.do.ts
|
|
264
|
-
│ ├── create-nodejs-fn.context.ts
|
|
265
|
-
│ ├── create-nodejs-fn.runtime.ts
|
|
266
|
-
│
|
|
278
|
+
│ ├── create-nodejs-fn.ts # RPC client & type definitions
|
|
279
|
+
│ ├── create-nodejs-fn.do.ts # Durable Object class
|
|
280
|
+
│ ├── create-nodejs-fn.context.ts # Container key resolution
|
|
281
|
+
│ ├── create-nodejs-fn.runtime.ts # nodejsFn / containerKey helpers
|
|
282
|
+
│ ├── create-nodejs-fn-stub-batch.ts # Cap'n Proto RPC batch client
|
|
283
|
+
│ └── __proxies__/
|
|
284
|
+
│ └── p-XXXXXXXX.ts # Proxy functions (hashed)
|
|
267
285
|
│
|
|
268
286
|
└── .create-nodejs-fn/ # 🐳 Container build artifacts
|
|
269
287
|
├── Dockerfile # Auto-generated
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-nodejs-fn",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"description": "Vite plugin to enable calling Node.js-dependent functions directly from Cloudflare Workers",
|
|
3
|
+
"version": "0.0.3",
|
|
4
|
+
"description": "Vite plugin to enable calling Node.js-dependent functions directly from Cloudflare Workers!!",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
7
7
|
"types": "dist/index.d.ts",
|
|
@@ -37,11 +37,12 @@
|
|
|
37
37
|
"dist"
|
|
38
38
|
],
|
|
39
39
|
"publishConfig": {
|
|
40
|
-
"access": "public"
|
|
40
|
+
"access": "public",
|
|
41
|
+
"provenance": true
|
|
41
42
|
},
|
|
42
43
|
"repository": {
|
|
43
44
|
"type": "git",
|
|
44
|
-
"url": "
|
|
45
|
+
"url": "https://github.com/inaridiy/create-nodejs-fn.git"
|
|
45
46
|
},
|
|
46
47
|
"bugs": {
|
|
47
48
|
"url": "https://github.com/inaridiy/create-nodejs-fn/issues"
|
package/dist/cli.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
package/dist/cli.js
DELETED
|
@@ -1,356 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
"use strict";
|
|
3
|
-
var __create = Object.create;
|
|
4
|
-
var __defProp = Object.defineProperty;
|
|
5
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
8
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
-
var __copyProps = (to, from, except, desc) => {
|
|
10
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
|
-
for (let key of __getOwnPropNames(from))
|
|
12
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
13
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
14
|
-
}
|
|
15
|
-
return to;
|
|
16
|
-
};
|
|
17
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
18
|
-
// If the importer is in node compatibility mode or this is not an ESM
|
|
19
|
-
// file that has been converted to a CommonJS file using a Babel-
|
|
20
|
-
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
21
|
-
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
22
|
-
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
23
|
-
mod
|
|
24
|
-
));
|
|
25
|
-
|
|
26
|
-
// src/cli.ts
|
|
27
|
-
var import_node_fs2 = __toESM(require("fs"));
|
|
28
|
-
var import_node_path2 = __toESM(require("path"));
|
|
29
|
-
var import_node_url = require("url");
|
|
30
|
-
var import_promises = __toESM(require("readline/promises"));
|
|
31
|
-
var import_gunshi = require("gunshi");
|
|
32
|
-
|
|
33
|
-
// src/fs-utils.ts
|
|
34
|
-
var import_node_fs = __toESM(require("fs"));
|
|
35
|
-
var import_node_path = __toESM(require("path"));
|
|
36
|
-
function ensureDir(p) {
|
|
37
|
-
import_node_fs.default.mkdirSync(p, { recursive: true });
|
|
38
|
-
}
|
|
39
|
-
function writeFileIfChanged(filePath, content) {
|
|
40
|
-
ensureDir(import_node_path.default.dirname(filePath));
|
|
41
|
-
const current = import_node_fs.default.existsSync(filePath) ? import_node_fs.default.readFileSync(filePath, "utf8") : null;
|
|
42
|
-
if (current === content) return;
|
|
43
|
-
import_node_fs.default.writeFileSync(filePath, content);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
// src/cli.ts
|
|
47
|
-
var import_meta = {};
|
|
48
|
-
var moduleDir = typeof __dirname === "string" ? __dirname : import_node_path2.default.dirname((0, import_node_url.fileURLToPath)(import_meta.url));
|
|
49
|
-
var pkgJsonPath = import_node_path2.default.resolve(moduleDir, "../package.json");
|
|
50
|
-
var pkg = import_node_fs2.default.existsSync(pkgJsonPath) ? JSON.parse(import_node_fs2.default.readFileSync(pkgJsonPath, "utf8")) : { version: "0.0.0" };
|
|
51
|
-
var VERSION = pkg.version ?? "0.0.0";
|
|
52
|
-
var initCommand = (0, import_gunshi.define)({
|
|
53
|
-
name: "init",
|
|
54
|
-
description: "Interactively scaffold create-nodejs-fn files",
|
|
55
|
-
args: {
|
|
56
|
-
yes: {
|
|
57
|
-
type: "boolean",
|
|
58
|
-
short: "y",
|
|
59
|
-
description: "Use defaults and skip prompts"
|
|
60
|
-
},
|
|
61
|
-
force: {
|
|
62
|
-
type: "boolean",
|
|
63
|
-
short: "f",
|
|
64
|
-
description: "Overwrite existing files without asking"
|
|
65
|
-
}
|
|
66
|
-
},
|
|
67
|
-
run: async (ctx) => {
|
|
68
|
-
const yes = Boolean(ctx.values.yes);
|
|
69
|
-
const force = Boolean(ctx.values.force);
|
|
70
|
-
await runInit({ yes, force });
|
|
71
|
-
}
|
|
72
|
-
});
|
|
73
|
-
async function runInit(opts) {
|
|
74
|
-
const cwd = process.cwd();
|
|
75
|
-
const defaults = await gatherDefaults(cwd);
|
|
76
|
-
const prompter = createPrompter(opts.yes);
|
|
77
|
-
const answers = {
|
|
78
|
-
name: await prompter.text("Worker name", defaults.name),
|
|
79
|
-
main: normalizeEntry(await prompter.text("Entry file", defaults.main)),
|
|
80
|
-
className: await prompter.text("Container class name", defaults.className),
|
|
81
|
-
binding: await prompter.text("Durable Object binding", defaults.binding),
|
|
82
|
-
image: await prompter.text("Container image path", defaults.image),
|
|
83
|
-
compatibilityDate: await prompter.text("Compatibility date", defaults.compatibilityDate),
|
|
84
|
-
maxInstances: await prompter.number("Max container instances", defaults.maxInstances)
|
|
85
|
-
};
|
|
86
|
-
const results = [];
|
|
87
|
-
if (await ensureDockerfile(cwd, opts, prompter)) {
|
|
88
|
-
results.push(".create-nodejs-fn/Dockerfile");
|
|
89
|
-
}
|
|
90
|
-
if (updateGitignore(cwd)) {
|
|
91
|
-
results.push(".gitignore");
|
|
92
|
-
}
|
|
93
|
-
if (ensureGeneratedDir(cwd)) {
|
|
94
|
-
results.push("src/__generated__/");
|
|
95
|
-
}
|
|
96
|
-
const wranglerResult = await writeWranglerJsonc(cwd, answers, opts, prompter);
|
|
97
|
-
if (wranglerResult) {
|
|
98
|
-
results.push("wrangler.jsonc");
|
|
99
|
-
}
|
|
100
|
-
if (ensureEntryExportsDo(cwd, answers, opts)) {
|
|
101
|
-
results.push(answers.main);
|
|
102
|
-
}
|
|
103
|
-
prompter.close();
|
|
104
|
-
if (results.length === 0) {
|
|
105
|
-
console.log("All files already up to date. Nothing to do.");
|
|
106
|
-
return;
|
|
107
|
-
}
|
|
108
|
-
console.log("Updated:");
|
|
109
|
-
for (const r of results) {
|
|
110
|
-
console.log(` - ${r}`);
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
async function ensureDockerfile(cwd, opts, prompter) {
|
|
114
|
-
const dockerfilePath = import_node_path2.default.join(cwd, ".create-nodejs-fn", "Dockerfile");
|
|
115
|
-
const dockerDir = import_node_path2.default.dirname(dockerfilePath);
|
|
116
|
-
ensureDir(dockerDir);
|
|
117
|
-
if (import_node_fs2.default.existsSync(dockerfilePath) && !opts.force) {
|
|
118
|
-
const overwrite = await prompter.confirm(
|
|
119
|
-
"Dockerfile already exists. Overwrite it?",
|
|
120
|
-
false
|
|
121
|
-
);
|
|
122
|
-
if (!overwrite) return false;
|
|
123
|
-
}
|
|
124
|
-
const content = [
|
|
125
|
-
"# create-nodejs-fn container image",
|
|
126
|
-
"# Generated by `create-nodejs-fn init`. The build step will refresh this file.",
|
|
127
|
-
"FROM node:20-slim",
|
|
128
|
-
"WORKDIR /app",
|
|
129
|
-
"RUN corepack enable",
|
|
130
|
-
"# Dependencies are injected via the generated package.json during build.",
|
|
131
|
-
"COPY package.json ./",
|
|
132
|
-
"RUN pnpm install --prod --no-frozen-lockfile",
|
|
133
|
-
"# The server bundle is generated at build time.",
|
|
134
|
-
"COPY ./server.mjs ./server.mjs",
|
|
135
|
-
"ENV NODE_ENV=production",
|
|
136
|
-
"EXPOSE 8080",
|
|
137
|
-
'CMD ["node", "./server.mjs"]',
|
|
138
|
-
""
|
|
139
|
-
].join("\n");
|
|
140
|
-
writeFileIfChanged(dockerfilePath, content);
|
|
141
|
-
return true;
|
|
142
|
-
}
|
|
143
|
-
function updateGitignore(cwd) {
|
|
144
|
-
const target = import_node_path2.default.join(cwd, ".gitignore");
|
|
145
|
-
const existing = import_node_fs2.default.existsSync(target) ? import_node_fs2.default.readFileSync(target, "utf8").split(/\r?\n/) : [];
|
|
146
|
-
const block = [
|
|
147
|
-
"# create-nodejs-fn",
|
|
148
|
-
".create-nodejs-fn/*",
|
|
149
|
-
"!.create-nodejs-fn/Dockerfile",
|
|
150
|
-
"src/__generated__"
|
|
151
|
-
];
|
|
152
|
-
const lines = [...existing];
|
|
153
|
-
const present = new Set(lines);
|
|
154
|
-
const missing = block.filter((line) => !present.has(line));
|
|
155
|
-
const changed = missing.length > 0;
|
|
156
|
-
if (changed) {
|
|
157
|
-
if (lines.length && lines[lines.length - 1] !== "") {
|
|
158
|
-
lines.push("");
|
|
159
|
-
}
|
|
160
|
-
for (const line of block) {
|
|
161
|
-
if (!present.has(line)) {
|
|
162
|
-
lines.push(line);
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
if (changed) {
|
|
167
|
-
const cleaned = trimBlankDuplicates(lines).join("\n");
|
|
168
|
-
import_node_fs2.default.writeFileSync(target, cleaned.endsWith("\n") ? cleaned : `${cleaned}
|
|
169
|
-
`);
|
|
170
|
-
}
|
|
171
|
-
return changed;
|
|
172
|
-
}
|
|
173
|
-
function ensureGeneratedDir(cwd) {
|
|
174
|
-
const dir = import_node_path2.default.join(cwd, "src", "__generated__");
|
|
175
|
-
if (import_node_fs2.default.existsSync(dir)) return false;
|
|
176
|
-
ensureDir(dir);
|
|
177
|
-
return true;
|
|
178
|
-
}
|
|
179
|
-
async function writeWranglerJsonc(cwd, answers, opts, prompter) {
|
|
180
|
-
const target = import_node_path2.default.join(cwd, "wrangler.jsonc");
|
|
181
|
-
const exists = import_node_fs2.default.existsSync(target);
|
|
182
|
-
if (exists && !opts.force) {
|
|
183
|
-
const proceed = await prompter.confirm("wrangler.jsonc already exists. Merge updates?", true);
|
|
184
|
-
if (!proceed) return false;
|
|
185
|
-
}
|
|
186
|
-
const existing = exists ? readJsonc(target) : {};
|
|
187
|
-
const merged = mergeWranglerConfig(existing, answers);
|
|
188
|
-
writeFileIfChanged(target, `${JSON.stringify(merged, null, 2)}
|
|
189
|
-
`);
|
|
190
|
-
return true;
|
|
191
|
-
}
|
|
192
|
-
function readJsonc(filePath) {
|
|
193
|
-
try {
|
|
194
|
-
const raw = import_node_fs2.default.readFileSync(filePath, "utf8");
|
|
195
|
-
const withoutBlock = raw.replace(/\/\*[\s\S]*?\*\//g, "");
|
|
196
|
-
const withoutLine = withoutBlock.replace(/(^|[^:])\/\/.*$/gm, "$1");
|
|
197
|
-
return JSON.parse(withoutLine);
|
|
198
|
-
} catch {
|
|
199
|
-
return {};
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
function mergeWranglerConfig(base, answers) {
|
|
203
|
-
const out = { ...base };
|
|
204
|
-
out.$schema = out.$schema ?? "node_modules/wrangler/config-schema.json";
|
|
205
|
-
out.name = out.name ?? answers.name;
|
|
206
|
-
out.main = out.main ?? (answers.main.startsWith("./") ? answers.main : `./${answers.main}`);
|
|
207
|
-
out.compatibility_date = out.compatibility_date ?? answers.compatibilityDate;
|
|
208
|
-
const flags = Array.isArray(out.compatibility_flags) ? out.compatibility_flags : [];
|
|
209
|
-
if (!flags.includes("nodejs_compat")) flags.push("nodejs_compat");
|
|
210
|
-
out.compatibility_flags = flags;
|
|
211
|
-
const containers = Array.isArray(out.containers) ? [...out.containers] : [];
|
|
212
|
-
const containerIdx = containers.findIndex((c) => c?.class_name === answers.className);
|
|
213
|
-
const containerEntry = {
|
|
214
|
-
class_name: answers.className,
|
|
215
|
-
image: answers.image,
|
|
216
|
-
max_instances: answers.maxInstances
|
|
217
|
-
};
|
|
218
|
-
if (containerIdx >= 0) {
|
|
219
|
-
containers[containerIdx] = { ...containers[containerIdx], ...containerEntry };
|
|
220
|
-
} else {
|
|
221
|
-
containers.push(containerEntry);
|
|
222
|
-
}
|
|
223
|
-
out.containers = containers;
|
|
224
|
-
const durable = typeof out.durable_objects === "object" && out.durable_objects !== null ? { ...out.durable_objects } : {};
|
|
225
|
-
const bindings = Array.isArray(durable.bindings) ? [...durable.bindings] : [];
|
|
226
|
-
const bindingIdx = bindings.findIndex((b) => b?.name === answers.binding);
|
|
227
|
-
const bindingEntry = { name: answers.binding, class_name: answers.className };
|
|
228
|
-
if (bindingIdx >= 0) {
|
|
229
|
-
bindings[bindingIdx] = { ...bindings[bindingIdx], ...bindingEntry };
|
|
230
|
-
} else {
|
|
231
|
-
bindings.push(bindingEntry);
|
|
232
|
-
}
|
|
233
|
-
durable.bindings = bindings;
|
|
234
|
-
out.durable_objects = durable;
|
|
235
|
-
const migrations = Array.isArray(out.migrations) ? [...out.migrations] : [];
|
|
236
|
-
const migIdx = migrations.findIndex((m) => m?.tag === "v1");
|
|
237
|
-
const ensureNewSqlite = (entry) => {
|
|
238
|
-
const classes = Array.isArray(entry.new_sqlite_classes) ? [...entry.new_sqlite_classes] : [];
|
|
239
|
-
if (!classes.includes(answers.className)) classes.push(answers.className);
|
|
240
|
-
entry.new_sqlite_classes = classes;
|
|
241
|
-
return entry;
|
|
242
|
-
};
|
|
243
|
-
if (migIdx >= 0) {
|
|
244
|
-
migrations[migIdx] = ensureNewSqlite({ ...migrations[migIdx], tag: migrations[migIdx].tag ?? "v1" });
|
|
245
|
-
} else {
|
|
246
|
-
migrations.push(ensureNewSqlite({ tag: "v1" }));
|
|
247
|
-
}
|
|
248
|
-
out.migrations = migrations;
|
|
249
|
-
return out;
|
|
250
|
-
}
|
|
251
|
-
function ensureEntryExportsDo(cwd, answers, opts) {
|
|
252
|
-
const entryRel = answers.main.startsWith("./") ? answers.main.slice(2) : answers.main;
|
|
253
|
-
const entryAbs = import_node_path2.default.join(cwd, entryRel);
|
|
254
|
-
ensureDir(import_node_path2.default.dirname(entryAbs));
|
|
255
|
-
const doAbs = import_node_path2.default.join(cwd, "src", "__generated__", "create-nodejs-fn.do.ts");
|
|
256
|
-
const doRel = import_node_path2.default.relative(import_node_path2.default.dirname(entryAbs), doAbs).replace(/\\/g, "/").replace(/\.ts$/, "");
|
|
257
|
-
const exportLine = `export { ${answers.className} } from "${doRel.startsWith(".") ? doRel : `./${doRel}`}";`;
|
|
258
|
-
if (import_node_fs2.default.existsSync(entryAbs)) {
|
|
259
|
-
const content = import_node_fs2.default.readFileSync(entryAbs, "utf8");
|
|
260
|
-
if (content.includes(exportLine) || content.match(new RegExp(`export\\s+\\{\\s*${answers.className}\\s*\\}.*create-nodejs-fn\\.do`))) {
|
|
261
|
-
return false;
|
|
262
|
-
}
|
|
263
|
-
const next = content.endsWith("\n") ? `${content}${exportLine}
|
|
264
|
-
` : `${content}
|
|
265
|
-
${exportLine}
|
|
266
|
-
`;
|
|
267
|
-
writeFileIfChanged(entryAbs, next);
|
|
268
|
-
return true;
|
|
269
|
-
}
|
|
270
|
-
const template = `${exportLine}
|
|
271
|
-
`;
|
|
272
|
-
writeFileIfChanged(entryAbs, template);
|
|
273
|
-
return true;
|
|
274
|
-
}
|
|
275
|
-
async function gatherDefaults(cwd) {
|
|
276
|
-
const pkgPath = import_node_path2.default.join(cwd, "package.json");
|
|
277
|
-
const pkgJson = import_node_fs2.default.existsSync(pkgPath) ? JSON.parse(import_node_fs2.default.readFileSync(pkgPath, "utf8")) : {};
|
|
278
|
-
return {
|
|
279
|
-
name: pkgJson.name ?? import_node_path2.default.basename(cwd),
|
|
280
|
-
main: "src/index.ts",
|
|
281
|
-
className: "NodejsFnContainer",
|
|
282
|
-
binding: "NODEJS_FN",
|
|
283
|
-
image: "./.create-nodejs-fn/Dockerfile",
|
|
284
|
-
compatibilityDate: defaultCompatibilityDate(),
|
|
285
|
-
maxInstances: 10
|
|
286
|
-
};
|
|
287
|
-
}
|
|
288
|
-
function defaultCompatibilityDate() {
|
|
289
|
-
const d = /* @__PURE__ */ new Date();
|
|
290
|
-
const yyyy = d.getUTCFullYear();
|
|
291
|
-
const mm = `${d.getUTCMonth() + 1}`.padStart(2, "0");
|
|
292
|
-
const dd = `${d.getUTCDate()}`.padStart(2, "0");
|
|
293
|
-
return `${yyyy}-${mm}-${dd}`;
|
|
294
|
-
}
|
|
295
|
-
function normalizeEntry(input) {
|
|
296
|
-
if (!input) return "src/index.ts";
|
|
297
|
-
const withSlash = input.startsWith("./") ? input : `./${input}`;
|
|
298
|
-
return withSlash.replace(/\\/g, "/");
|
|
299
|
-
}
|
|
300
|
-
function createPrompter(skip) {
|
|
301
|
-
if (skip || !process.stdin.isTTY) {
|
|
302
|
-
return {
|
|
303
|
-
text: async (_message, defaultValue) => defaultValue,
|
|
304
|
-
number: async (_message, defaultValue) => defaultValue,
|
|
305
|
-
confirm: async (_message, defaultValue = false) => defaultValue,
|
|
306
|
-
close: () => {
|
|
307
|
-
}
|
|
308
|
-
};
|
|
309
|
-
}
|
|
310
|
-
const rl = import_promises.default.createInterface({
|
|
311
|
-
input: process.stdin,
|
|
312
|
-
output: process.stdout
|
|
313
|
-
});
|
|
314
|
-
return {
|
|
315
|
-
async text(message, defaultValue) {
|
|
316
|
-
const answer = await rl.question(formatPrompt(message, defaultValue));
|
|
317
|
-
return answer.trim() || defaultValue;
|
|
318
|
-
},
|
|
319
|
-
async number(message, defaultValue) {
|
|
320
|
-
const answer = await rl.question(formatPrompt(message, String(defaultValue)));
|
|
321
|
-
const parsed = Number.parseInt(answer.trim(), 10);
|
|
322
|
-
return Number.isFinite(parsed) ? parsed : defaultValue;
|
|
323
|
-
},
|
|
324
|
-
async confirm(message, defaultValue = false) {
|
|
325
|
-
const suffix = defaultValue ? " [Y/n] " : " [y/N] ";
|
|
326
|
-
const answer = (await rl.question(`${message}${suffix}`)).trim().toLowerCase();
|
|
327
|
-
if (!answer) return defaultValue;
|
|
328
|
-
return answer.startsWith("y");
|
|
329
|
-
},
|
|
330
|
-
close() {
|
|
331
|
-
rl.close();
|
|
332
|
-
}
|
|
333
|
-
};
|
|
334
|
-
}
|
|
335
|
-
function formatPrompt(message, defaultValue) {
|
|
336
|
-
const suffix = defaultValue !== void 0 && defaultValue !== null ? ` (${defaultValue})` : "";
|
|
337
|
-
return `${message}${suffix}: `;
|
|
338
|
-
}
|
|
339
|
-
function trimBlankDuplicates(lines) {
|
|
340
|
-
const out = [];
|
|
341
|
-
for (const line of lines) {
|
|
342
|
-
if (line === "" && out.length > 0 && out[out.length - 1] === "") continue;
|
|
343
|
-
out.push(line);
|
|
344
|
-
}
|
|
345
|
-
return out;
|
|
346
|
-
}
|
|
347
|
-
async function main() {
|
|
348
|
-
await (0, import_gunshi.cli)(process.argv.slice(2), initCommand, {
|
|
349
|
-
name: "create-nodejs-fn",
|
|
350
|
-
version: VERSION
|
|
351
|
-
});
|
|
352
|
-
}
|
|
353
|
-
main().catch((err) => {
|
|
354
|
-
console.error(err);
|
|
355
|
-
process.exitCode = 1;
|
|
356
|
-
});
|
package/dist/index.d.ts
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import { Plugin } from 'vite';
|
|
2
|
-
|
|
3
|
-
type DockerOptions = {
|
|
4
|
-
baseImage?: string;
|
|
5
|
-
systemPackages?: string[];
|
|
6
|
-
preInstallCommands?: string[];
|
|
7
|
-
postInstallCommands?: string[];
|
|
8
|
-
env?: Record<string, string>;
|
|
9
|
-
extraLines?: string[];
|
|
10
|
-
};
|
|
11
|
-
type Opts = {
|
|
12
|
-
files?: string[];
|
|
13
|
-
generatedDir?: string;
|
|
14
|
-
binding?: string;
|
|
15
|
-
className?: string;
|
|
16
|
-
containerPort?: number;
|
|
17
|
-
external?: string[];
|
|
18
|
-
docker?: DockerOptions;
|
|
19
|
-
/**
|
|
20
|
-
* Worker env vars to forward into the container via Container.envVars.
|
|
21
|
-
* Accepts an array of names (same name) or a map of containerName -> workerEnvKey.
|
|
22
|
-
*/
|
|
23
|
-
workerEnvVars?: string[] | Record<string, string>;
|
|
24
|
-
/**
|
|
25
|
-
* Automatically rebuild containers in local dev when *.container.ts files change. default: true
|
|
26
|
-
*/
|
|
27
|
-
autoRebuildContainers?: boolean;
|
|
28
|
-
/**
|
|
29
|
-
* Debounce duration in milliseconds for container rebuilds during dev. default: 200
|
|
30
|
-
*/
|
|
31
|
-
rebuildDebounceMs?: number;
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
declare function createNodejsFnPlugin(opts?: Opts): Plugin;
|
|
35
|
-
|
|
36
|
-
export { createNodejsFnPlugin };
|