cloud-run-functions 0.1.0 → 0.1.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/config.schema.json +24 -0
- package/dist/chunk-DG37B63B.js +33 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +1 -1
- package/dist/targets/dev.js +133 -41
- package/dist/tools/build.d.ts +16 -1
- package/dist/tools/dev.d.ts +11 -2
- package/dist/tools/dev.js +1 -1
- package/package.json +3 -2
- package/readme.md +4 -0
- package/dist/chunk-XTHOFO7F.js +0 -25
package/config.schema.json
CHANGED
|
@@ -64,6 +64,30 @@
|
|
|
64
64
|
"type": "null"
|
|
65
65
|
}
|
|
66
66
|
]
|
|
67
|
+
},
|
|
68
|
+
"maxInstanceConcurrency": {
|
|
69
|
+
"oneOf": [
|
|
70
|
+
{
|
|
71
|
+
"description": "The maximum number of instances (per function) that can be run concurrently. You can either set the same limit for all functions or set a different limit for each function.\n\n@default 5",
|
|
72
|
+
"oneOf": [
|
|
73
|
+
{
|
|
74
|
+
"type": "number"
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
"type": "object",
|
|
78
|
+
"propertyNames": {
|
|
79
|
+
"type": "string"
|
|
80
|
+
},
|
|
81
|
+
"additionalProperties": {
|
|
82
|
+
"type": "number"
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
]
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
"type": "null"
|
|
89
|
+
}
|
|
90
|
+
]
|
|
67
91
|
}
|
|
68
92
|
},
|
|
69
93
|
"required": []
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
// src/tools/dev.ts
|
|
2
|
+
import { findUpSync } from "find-up-simple";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import $ from "picospawn";
|
|
5
|
+
function dev(root, { port, define, ...options } = {}) {
|
|
6
|
+
const packageDir = findUpSync("dist", {
|
|
7
|
+
cwd: import.meta.dirname,
|
|
8
|
+
type: "directory"
|
|
9
|
+
});
|
|
10
|
+
const source = path.join(packageDir, "targets/dev.js");
|
|
11
|
+
const binDir = path.resolve(packageDir, "../node_modules/.bin");
|
|
12
|
+
return $(
|
|
13
|
+
"functions-framework --target=dev --source %s",
|
|
14
|
+
[source, port != null && ["--port", port.toString()]],
|
|
15
|
+
{
|
|
16
|
+
stdio: "inherit",
|
|
17
|
+
...options,
|
|
18
|
+
env: {
|
|
19
|
+
...options.env ?? process.env,
|
|
20
|
+
CRF_OPTIONS: JSON.stringify({
|
|
21
|
+
searchDir: root,
|
|
22
|
+
workingDir: process.cwd(),
|
|
23
|
+
define
|
|
24
|
+
}),
|
|
25
|
+
PATH: `${binDir}:${process.env.PATH}`
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export {
|
|
32
|
+
dev
|
|
33
|
+
};
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
package/dist/targets/dev.js
CHANGED
|
@@ -1,19 +1,39 @@
|
|
|
1
1
|
// src/targets/dev.ts
|
|
2
|
+
import "source-map-support/register.js";
|
|
2
3
|
import functions from "@google-cloud/functions-framework";
|
|
3
4
|
import esbuild from "esbuild";
|
|
4
5
|
import { findUpSync } from "find-up-simple";
|
|
6
|
+
import fs2 from "node:fs";
|
|
7
|
+
import { Module } from "node:module";
|
|
5
8
|
import os from "node:os";
|
|
6
9
|
import path2 from "node:path";
|
|
7
10
|
|
|
8
|
-
// src/config/index.ts
|
|
9
|
-
import * as z2 from "@zod/mini";
|
|
10
|
-
import Joycon from "joycon";
|
|
11
|
-
import path from "node:path";
|
|
12
|
-
|
|
13
|
-
// src/config/schema.ts
|
|
14
|
-
import * as z from "@zod/mini";
|
|
15
|
-
|
|
16
11
|
// node_modules/.pnpm/radashi@12.4.0/node_modules/radashi/dist/radashi.js
|
|
12
|
+
var TimeoutError = class extends Error {
|
|
13
|
+
constructor(message) {
|
|
14
|
+
super(message ?? "Operation timed out");
|
|
15
|
+
this.name = "TimeoutError";
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
function timeout(ms, error) {
|
|
19
|
+
return new Promise(
|
|
20
|
+
(_, reject) => setTimeout(
|
|
21
|
+
() => reject(isFunction(error) ? error() : new TimeoutError(error)),
|
|
22
|
+
ms
|
|
23
|
+
)
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
async function toResult(promise) {
|
|
27
|
+
try {
|
|
28
|
+
const result = await promise;
|
|
29
|
+
return [void 0, result];
|
|
30
|
+
} catch (error) {
|
|
31
|
+
if (isError(error)) {
|
|
32
|
+
return [error, void 0];
|
|
33
|
+
}
|
|
34
|
+
throw error;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
17
37
|
function dedent(text, ...values) {
|
|
18
38
|
var _a;
|
|
19
39
|
if (isArray(text)) {
|
|
@@ -41,8 +61,26 @@ var asyncIteratorSymbol = (
|
|
|
41
61
|
/* c8 ignore next */
|
|
42
62
|
Symbol.asyncIterator || Symbol.for("Symbol.asyncIterator")
|
|
43
63
|
);
|
|
64
|
+
function isError(value) {
|
|
65
|
+
return isTagged(value, "[object Error]");
|
|
66
|
+
}
|
|
67
|
+
function isFunction(value) {
|
|
68
|
+
return typeof value === "function";
|
|
69
|
+
}
|
|
70
|
+
function isNumber(value) {
|
|
71
|
+
return typeof value === "number" && !Number.isNaN(value);
|
|
72
|
+
}
|
|
73
|
+
function isTagged(value, tag) {
|
|
74
|
+
return Object.prototype.toString.call(value) === tag;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// src/config/index.ts
|
|
78
|
+
import * as z2 from "@zod/mini";
|
|
79
|
+
import Joycon from "joycon";
|
|
80
|
+
import path from "node:path";
|
|
44
81
|
|
|
45
82
|
// src/config/schema.ts
|
|
83
|
+
import * as z from "@zod/mini";
|
|
46
84
|
var configSchema = z.partial(
|
|
47
85
|
z.interface({
|
|
48
86
|
root: z.string().register(z.globalRegistry, {
|
|
@@ -81,6 +119,13 @@ var configSchema = z.partial(
|
|
|
81
119
|
|
|
82
120
|
@default "node"
|
|
83
121
|
`
|
|
122
|
+
}),
|
|
123
|
+
maxInstanceConcurrency: z.union([z.number(), z.record(z.string(), z.number())]).register(z.globalRegistry, {
|
|
124
|
+
description: dedent`
|
|
125
|
+
The maximum number of instances (per function) that can be run concurrently. You can either set the same limit for all functions or set a different limit for each function.
|
|
126
|
+
|
|
127
|
+
@default 5
|
|
128
|
+
`
|
|
84
129
|
})
|
|
85
130
|
})
|
|
86
131
|
);
|
|
@@ -116,11 +161,10 @@ function hash(data, len) {
|
|
|
116
161
|
|
|
117
162
|
// src/targets/dev.ts
|
|
118
163
|
async function createBuild() {
|
|
119
|
-
const
|
|
120
|
-
const searchDir =
|
|
164
|
+
const options = JSON.parse(process.env.CRF_OPTIONS);
|
|
165
|
+
const searchDir = path2.resolve(options.workingDir, options.searchDir ?? "");
|
|
121
166
|
const config = loadConfig(searchDir);
|
|
122
167
|
const root = config.configDir ? path2.resolve(config.configDir, config.root ?? "") : searchDir;
|
|
123
|
-
let pendingBuild;
|
|
124
168
|
const entryPoints = [];
|
|
125
169
|
const requiredSuffix = config.entrySuffix?.replace(/^\.?/, ".") ?? "";
|
|
126
170
|
const knownSuffixes = /* @__PURE__ */ new Set();
|
|
@@ -142,27 +186,25 @@ async function createBuild() {
|
|
|
142
186
|
const knownSuffixesRE = new RegExp(
|
|
143
187
|
`(${Array.from(knownSuffixes, (e) => e.replace(/\./g, "\\.")).sort((a, b) => b.length - a.length).join("|")})$`
|
|
144
188
|
);
|
|
145
|
-
const
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
nodeModulesDir ? path2.join(nodeModulesDir, `.cache/cloud-run-functions-${hash(root, 8)}`) : path2.join(os.tmpdir(), `cloud-run-functions-${hash(root, 8)}`)
|
|
189
|
+
const cacheDir = emptyDir(
|
|
190
|
+
path2.join(
|
|
191
|
+
fs2.realpathSync(os.tmpdir()),
|
|
192
|
+
"cloud-run-functions-" + hash(root, 8)
|
|
193
|
+
)
|
|
151
194
|
);
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
outDir,
|
|
155
|
-
entryPoints,
|
|
156
|
-
knownSuffixesRE
|
|
157
|
-
});
|
|
195
|
+
let pendingBuild;
|
|
196
|
+
let finishedBuild;
|
|
158
197
|
const context = await esbuild.context({
|
|
159
198
|
entryPoints,
|
|
160
199
|
absWorkingDir: root,
|
|
161
|
-
outdir:
|
|
200
|
+
outdir: cacheDir,
|
|
201
|
+
define: options.define,
|
|
162
202
|
bundle: true,
|
|
163
|
-
format: "
|
|
164
|
-
|
|
203
|
+
format: "cjs",
|
|
204
|
+
platform: "node",
|
|
205
|
+
packages: "bundle",
|
|
165
206
|
sourcemap: true,
|
|
207
|
+
sourcesContent: false,
|
|
166
208
|
metafile: true,
|
|
167
209
|
logOverride: {
|
|
168
210
|
"empty-glob": "silent"
|
|
@@ -171,11 +213,16 @@ async function createBuild() {
|
|
|
171
213
|
{
|
|
172
214
|
name: "build-status",
|
|
173
215
|
setup(build) {
|
|
216
|
+
pendingBuild = Promise.withResolvers();
|
|
174
217
|
build.onStart(() => {
|
|
175
|
-
pendingBuild
|
|
218
|
+
pendingBuild ??= Promise.withResolvers();
|
|
176
219
|
});
|
|
177
220
|
build.onEnd((result) => {
|
|
178
|
-
pendingBuild
|
|
221
|
+
if (pendingBuild) {
|
|
222
|
+
pendingBuild.resolve(result);
|
|
223
|
+
pendingBuild = void 0;
|
|
224
|
+
}
|
|
225
|
+
finishedBuild = result;
|
|
179
226
|
});
|
|
180
227
|
}
|
|
181
228
|
}
|
|
@@ -183,14 +230,22 @@ async function createBuild() {
|
|
|
183
230
|
});
|
|
184
231
|
await context.watch();
|
|
185
232
|
console.log("[esbuild] Watching for changes...");
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
233
|
+
const envPath = findUpSync(".env", { cwd: root });
|
|
234
|
+
if (envPath) {
|
|
235
|
+
try {
|
|
236
|
+
const dotenv = await import("dotenv");
|
|
237
|
+
dotenv.config({ path: envPath });
|
|
238
|
+
console.log("[dotenv] Environment variables loaded.");
|
|
239
|
+
} catch {
|
|
240
|
+
}
|
|
190
241
|
}
|
|
242
|
+
const taskStates = /* @__PURE__ */ new Map();
|
|
191
243
|
return {
|
|
192
244
|
async match(url) {
|
|
193
|
-
const result = await pendingBuild
|
|
245
|
+
const result = await pendingBuild?.promise ?? finishedBuild;
|
|
246
|
+
if (!result) {
|
|
247
|
+
return null;
|
|
248
|
+
}
|
|
194
249
|
for (const [file, output] of Object.entries(
|
|
195
250
|
result.metafile?.outputs ?? {}
|
|
196
251
|
)) {
|
|
@@ -199,18 +254,50 @@ async function createBuild() {
|
|
|
199
254
|
}
|
|
200
255
|
const taskName = output.entryPoint.replace(knownSuffixesRE, "");
|
|
201
256
|
if (url.pathname === "/" + taskName) {
|
|
202
|
-
const
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
257
|
+
const taskState = taskStates.get(taskName) ?? {
|
|
258
|
+
running: 0,
|
|
259
|
+
queue: []
|
|
260
|
+
};
|
|
261
|
+
const taskConcurrency = isNumber(config.maxInstanceConcurrency) ? config.maxInstanceConcurrency : config.maxInstanceConcurrency?.[taskName] ?? 5;
|
|
262
|
+
if (taskState.running >= taskConcurrency) {
|
|
263
|
+
const ticket = Promise.withResolvers();
|
|
264
|
+
taskState.queue.push(ticket);
|
|
265
|
+
const [error] = await toResult(
|
|
266
|
+
Promise.race([ticket.promise, timeout(3e4)])
|
|
267
|
+
);
|
|
268
|
+
if (error) {
|
|
269
|
+
return (_req, res) => {
|
|
270
|
+
res.status(429).end();
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
taskState.running++;
|
|
275
|
+
taskStates.set(taskName, taskState);
|
|
276
|
+
const require2 = Module.createRequire(import.meta.filename);
|
|
277
|
+
let taskHandler = require2(path2.join(root, file));
|
|
278
|
+
while (taskHandler && typeof taskHandler !== "function") {
|
|
279
|
+
taskHandler = taskHandler.default;
|
|
280
|
+
}
|
|
281
|
+
if (!taskHandler) {
|
|
282
|
+
return () => {
|
|
283
|
+
throw new Error(`Task ${taskName} is not a function.`);
|
|
284
|
+
};
|
|
285
|
+
}
|
|
206
286
|
switch (config.adapter) {
|
|
207
287
|
case "hattip": {
|
|
208
288
|
const { createMiddleware } = await import("@hattip/adapter-node");
|
|
209
|
-
|
|
289
|
+
taskHandler = createMiddleware(taskHandler);
|
|
210
290
|
}
|
|
211
|
-
default:
|
|
212
|
-
return taskHandler;
|
|
213
291
|
}
|
|
292
|
+
return (req, res) => {
|
|
293
|
+
const end = res.end.bind(res);
|
|
294
|
+
res.end = (...args) => {
|
|
295
|
+
taskState.running--;
|
|
296
|
+
taskState.queue.shift()?.resolve();
|
|
297
|
+
return end(...args);
|
|
298
|
+
};
|
|
299
|
+
return taskHandler(req, res);
|
|
300
|
+
};
|
|
214
301
|
}
|
|
215
302
|
}
|
|
216
303
|
return null;
|
|
@@ -223,7 +310,12 @@ functions.http("dev", async (req, res) => {
|
|
|
223
310
|
const build = await buildPromise;
|
|
224
311
|
const handler = await build.match(url);
|
|
225
312
|
if (handler) {
|
|
226
|
-
|
|
313
|
+
try {
|
|
314
|
+
await handler(req, res);
|
|
315
|
+
} catch (error) {
|
|
316
|
+
console.error(error);
|
|
317
|
+
res.status(500).end();
|
|
318
|
+
}
|
|
227
319
|
} else {
|
|
228
320
|
res.status(404).end();
|
|
229
321
|
}
|
package/dist/tools/build.d.ts
CHANGED
|
@@ -1,2 +1,17 @@
|
|
|
1
|
+
type BuildOptions = {
|
|
2
|
+
/**
|
|
3
|
+
* Statically replace specific variables in the source code.
|
|
4
|
+
*
|
|
5
|
+
* ⚠️ The value must be valid JavaScript syntax!
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```ts
|
|
9
|
+
* define: {
|
|
10
|
+
* 'process.env.NODE_ENV': '"development"',
|
|
11
|
+
* }
|
|
12
|
+
* ```
|
|
13
|
+
*/
|
|
14
|
+
define?: Record<string, string>;
|
|
15
|
+
};
|
|
1
16
|
|
|
2
|
-
export {
|
|
17
|
+
export type { BuildOptions };
|
package/dist/tools/dev.d.ts
CHANGED
|
@@ -1,8 +1,17 @@
|
|
|
1
1
|
import * as picospawn from 'picospawn';
|
|
2
|
+
import { PicospawnOptions } from 'picospawn';
|
|
3
|
+
import { BuildOptions } from './build.js';
|
|
2
4
|
|
|
5
|
+
interface DevOptions extends PicospawnOptions, BuildOptions {
|
|
6
|
+
/**
|
|
7
|
+
* Customize the port to use for the development server.
|
|
8
|
+
* @default 8080
|
|
9
|
+
*/
|
|
10
|
+
port?: string | number;
|
|
11
|
+
}
|
|
3
12
|
/**
|
|
4
13
|
* Start the development server in a separate process.
|
|
5
14
|
*/
|
|
6
|
-
declare function dev(root?: string): picospawn.PicospawnPromise<
|
|
15
|
+
declare function dev(root?: string, { port, define, ...options }?: DevOptions): picospawn.PicospawnPromise<unknown>;
|
|
7
16
|
|
|
8
|
-
export { dev };
|
|
17
|
+
export { type DevOptions, dev };
|
package/dist/tools/dev.js
CHANGED
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cloud-run-functions",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.2",
|
|
5
5
|
"bin": "./dist/main.js",
|
|
6
6
|
"exports": {
|
|
7
7
|
"types": "./dist/index.d.ts",
|
|
@@ -39,7 +39,8 @@
|
|
|
39
39
|
"find-up-simple": "^1.0.1",
|
|
40
40
|
"joycon": "^3.1.1",
|
|
41
41
|
"ordana": "^0.4.0",
|
|
42
|
-
"picospawn": "^0.3.
|
|
42
|
+
"picospawn": "^0.3.2",
|
|
43
|
+
"source-map-support": "^0.5.21",
|
|
43
44
|
"tinyglobby": "^0.2.13"
|
|
44
45
|
},
|
|
45
46
|
"peerDependencies": {
|
package/readme.md
CHANGED
|
@@ -27,3 +27,7 @@ When you're ready to deploy, use the `build` command to bundle your functions.
|
|
|
27
27
|
```sh
|
|
28
28
|
npx cloud-run-functions build ./path/to/functions/
|
|
29
29
|
```
|
|
30
|
+
|
|
31
|
+
## Tips
|
|
32
|
+
|
|
33
|
+
- If you have the [dotenv](https://www.npmjs.com/package/dotenv) package installed, the dev server will import it and automatically load environment variables from the closest `.env` file. Note that environment variables in `.env` won't override existing `process.env` values.
|
package/dist/chunk-XTHOFO7F.js
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
// src/tools/dev.ts
|
|
2
|
-
import { findUpSync } from "find-up-simple";
|
|
3
|
-
import path from "node:path";
|
|
4
|
-
import $ from "picospawn";
|
|
5
|
-
function dev(root) {
|
|
6
|
-
const packageDir = findUpSync("dist", {
|
|
7
|
-
cwd: import.meta.dirname,
|
|
8
|
-
type: "directory"
|
|
9
|
-
});
|
|
10
|
-
const source = path.join(packageDir, "targets/dev.js");
|
|
11
|
-
const binDir = path.resolve(packageDir, "../node_modules/.bin");
|
|
12
|
-
return $("functions-framework --target=dev --source", [source], {
|
|
13
|
-
stdio: "inherit",
|
|
14
|
-
env: {
|
|
15
|
-
...process.env,
|
|
16
|
-
CRF_ROOT: root,
|
|
17
|
-
CALLER_DIR: process.cwd(),
|
|
18
|
-
PATH: `${binDir}:${process.env.PATH}`
|
|
19
|
-
}
|
|
20
|
-
});
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export {
|
|
24
|
-
dev
|
|
25
|
-
};
|