@base44/functions-compiler 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/README.md +103 -37
- package/lib/src/assembly.d.ts +43 -0
- package/lib/src/assembly.js +167 -0
- package/lib/src/assembly.js.map +1 -0
- package/lib/src/deno-bundle.js +3 -0
- package/lib/src/deno-bundle.js.map +1 -1
- package/lib/src/index.d.ts +8 -0
- package/lib/src/index.js +4 -0
- package/lib/src/index.js.map +1 -1
- package/lib/src/invocation-logs.d.ts +6 -0
- package/lib/src/invocation-logs.js +51 -0
- package/lib/src/invocation-logs.js.map +1 -0
- package/lib/src/shards/build.d.ts +55 -0
- package/lib/src/shards/build.js +156 -0
- package/lib/src/shards/build.js.map +1 -0
- package/lib/src/shards/plan.d.ts +50 -0
- package/lib/src/shards/plan.js +78 -0
- package/lib/src/shards/plan.js.map +1 -0
- package/lib/src/shards/size.d.ts +45 -0
- package/lib/src/shards/size.js +64 -0
- package/lib/src/shards/size.js.map +1 -0
- package/lib/src/version.d.ts +15 -0
- package/lib/src/version.js +16 -0
- package/lib/src/version.js.map +1 -0
- package/lib/src/worker-entry.d.ts +2 -3
- package/lib/src/worker-entry.js +46 -10
- package/lib/src/worker-entry.js.map +1 -1
- package/package.json +6 -1
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compile an app's functions into the final Cloudflare Workers shards.
|
|
3
|
+
*
|
|
4
|
+
* The loop is: plan the partition, compile each shard, measure it, and halve any
|
|
5
|
+
* shard whose module is over a ceiling before anything is uploaded. Ported from
|
|
6
|
+
* `_build_shard_with_split` in apper's `cloudflare_wfp_runtime.py`.
|
|
7
|
+
*
|
|
8
|
+
* That function also splits on two exceptions, and neither is a trigger here.
|
|
9
|
+
* The bundler's 413 is its HTTP request-body cap — a property of the shard's
|
|
10
|
+
* packed SOURCE going over the wire, not of the module coming out, and there is
|
|
11
|
+
* no request to reject locally. Cloudflare's 10027 is a real Worker limit, but
|
|
12
|
+
* it is the same 64 MiB `workerRawSizeBreach` already computes from the bytes in
|
|
13
|
+
* hand, so reaching it from a rejected upload is a failsafe, not the design.
|
|
14
|
+
* Measuring is the design, and it happens here.
|
|
15
|
+
*
|
|
16
|
+
* Unlike the compiler's own `bundleApp`, this refuses a partial result. A module
|
|
17
|
+
* missing a handler is not a smaller success, it is a broken app.
|
|
18
|
+
*/
|
|
19
|
+
import { bundleApp } from "../bundler.js";
|
|
20
|
+
import { planFreshShards } from "./plan.js";
|
|
21
|
+
import { judgeBundleSize } from "./size.js";
|
|
22
|
+
/** Shards compile independently; bound how many esbuild runs are in flight so
|
|
23
|
+
* peak memory does not scale with the app's function count. */
|
|
24
|
+
const MAX_PARALLEL_SHARDS = 4;
|
|
25
|
+
/**
|
|
26
|
+
* Compile every function into shards, or fail the whole build.
|
|
27
|
+
*
|
|
28
|
+
* Succeeds only when each declared function appears exactly once across the
|
|
29
|
+
* shards and every one of them compiled.
|
|
30
|
+
*/
|
|
31
|
+
export async function compileFunctionShards(functions, policy, options = {}) {
|
|
32
|
+
const duplicate = firstDuplicate(functions.map((fn) => fn.name));
|
|
33
|
+
if (duplicate) {
|
|
34
|
+
return fail([{ message: `Duplicate function name "${duplicate}".` }]);
|
|
35
|
+
}
|
|
36
|
+
const byName = new Map(functions.map((fn) => [fn.name, fn]));
|
|
37
|
+
const plan = planFreshShards(functions.map((fn) => fn.name), policy);
|
|
38
|
+
const groups = plan.map((names) => names.map((name) => byName.get(name)));
|
|
39
|
+
const outcomes = await mapWithConcurrency(groups, MAX_PARALLEL_SHARDS, (group) => buildWithSplit(group, policy, options));
|
|
40
|
+
const failures = outcomes.flatMap((o) => (o.ok ? [] : o.failures));
|
|
41
|
+
if (failures.length > 0)
|
|
42
|
+
return fail(failures);
|
|
43
|
+
const shards = outcomes
|
|
44
|
+
.flatMap((o) => (o.ok ? o.shards : []))
|
|
45
|
+
.map((shard, index) => ({ ...shard, index }));
|
|
46
|
+
const missing = assertEveryFunctionPlacedOnce(functions, shards);
|
|
47
|
+
if (missing.length > 0)
|
|
48
|
+
return fail(missing);
|
|
49
|
+
return { ok: true, shards };
|
|
50
|
+
}
|
|
51
|
+
/** Compile one planned group, halving it when its module is over a ceiling. The
|
|
52
|
+
* verdict comes from the bytes, so nothing is uploaded to discover it. */
|
|
53
|
+
async function buildWithSplit(group, policy, options) {
|
|
54
|
+
const response = await bundleApp({ functions: group, ...options });
|
|
55
|
+
const compileFailures = response.functions
|
|
56
|
+
.filter((fn) => !fn.ok)
|
|
57
|
+
.map((fn) => ({
|
|
58
|
+
function: fn.name,
|
|
59
|
+
message: `Function "${fn.name}" failed to compile.`,
|
|
60
|
+
errors: fn.ok ? undefined : fn.errors,
|
|
61
|
+
}));
|
|
62
|
+
// A partial module is what the service ships and a whole-app build must not:
|
|
63
|
+
// the peers compiled, but the app is missing a handler.
|
|
64
|
+
if (compileFailures.length > 0)
|
|
65
|
+
return { ok: false, failures: compileFailures };
|
|
66
|
+
if (!response.ok) {
|
|
67
|
+
return fail([{ message: "The combined build produced no module." }]);
|
|
68
|
+
}
|
|
69
|
+
const verdict = await judgeBundleSize(response.module, policy.gzipCapBytes);
|
|
70
|
+
if (!verdict.breach) {
|
|
71
|
+
return {
|
|
72
|
+
ok: true,
|
|
73
|
+
shards: [shardOf(group, response.module, response.main_module, verdict)],
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
if (group.length === 1) {
|
|
77
|
+
// Splitting is exhausted: one function's module alone is over the ceiling.
|
|
78
|
+
return {
|
|
79
|
+
ok: false,
|
|
80
|
+
failures: [{ function: group[0].name, message: verdict.breach }],
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
const mid = Math.floor(group.length / 2);
|
|
84
|
+
const halves = await Promise.all([
|
|
85
|
+
buildWithSplit(group.slice(0, mid), policy, options),
|
|
86
|
+
buildWithSplit(group.slice(mid), policy, options),
|
|
87
|
+
]);
|
|
88
|
+
const halfFailures = halves.flatMap((h) => (h.ok ? [] : h.failures));
|
|
89
|
+
if (halfFailures.length > 0)
|
|
90
|
+
return { ok: false, failures: halfFailures };
|
|
91
|
+
return { ok: true, shards: halves.flatMap((h) => (h.ok ? h.shards : [])) };
|
|
92
|
+
}
|
|
93
|
+
function shardOf(group, module, mainModule, verdict) {
|
|
94
|
+
return {
|
|
95
|
+
functions: group.map((fn) => fn.name),
|
|
96
|
+
module,
|
|
97
|
+
mainModule,
|
|
98
|
+
rawBytes: verdict.rawBytes,
|
|
99
|
+
gzipBytes: verdict.gzipBytes,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
/** Every declared function must land in exactly one emitted shard. A name that
|
|
103
|
+
* vanished, or turned up twice after a split, would deploy a broken app. */
|
|
104
|
+
function assertEveryFunctionPlacedOnce(functions, shards) {
|
|
105
|
+
const placed = new Map();
|
|
106
|
+
for (const shard of shards) {
|
|
107
|
+
for (const name of shard.functions) {
|
|
108
|
+
placed.set(name, (placed.get(name) ?? 0) + 1);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
const failures = [];
|
|
112
|
+
for (const fn of functions) {
|
|
113
|
+
const count = placed.get(fn.name) ?? 0;
|
|
114
|
+
if (count !== 1) {
|
|
115
|
+
failures.push({
|
|
116
|
+
function: fn.name,
|
|
117
|
+
message: `Function "${fn.name}" appears in ${count} shards; expected exactly 1.`,
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
for (const name of placed.keys()) {
|
|
122
|
+
if (!functions.some((fn) => fn.name === name)) {
|
|
123
|
+
failures.push({
|
|
124
|
+
function: name,
|
|
125
|
+
message: `Shard holds unknown function "${name}".`,
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return failures;
|
|
130
|
+
}
|
|
131
|
+
function firstDuplicate(names) {
|
|
132
|
+
const seen = new Set();
|
|
133
|
+
for (const name of names) {
|
|
134
|
+
if (seen.has(name))
|
|
135
|
+
return name;
|
|
136
|
+
seen.add(name);
|
|
137
|
+
}
|
|
138
|
+
return null;
|
|
139
|
+
}
|
|
140
|
+
function fail(failures) {
|
|
141
|
+
return { ok: false, failures };
|
|
142
|
+
}
|
|
143
|
+
/** Bounded concurrency, input order preserved. */
|
|
144
|
+
async function mapWithConcurrency(items, limit, fn) {
|
|
145
|
+
const results = new Array(items.length);
|
|
146
|
+
let cursor = 0;
|
|
147
|
+
const worker = async () => {
|
|
148
|
+
while (cursor < items.length) {
|
|
149
|
+
const index = cursor++;
|
|
150
|
+
results[index] = await fn(items[index]);
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
await Promise.all(Array.from({ length: Math.min(limit, items.length) }, () => worker()));
|
|
154
|
+
return results;
|
|
155
|
+
}
|
|
156
|
+
//# sourceMappingURL=build.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"build.js","sourceRoot":"","sources":["../../../src/shards/build.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which functions go in which shard, for a build with no previous deploy to
|
|
3
|
+
* reuse. Ported from apper's `shard_planning.py` (`target_shard_count`,
|
|
4
|
+
* `full_repartition`) and the capacity refusal in `deploy_app`.
|
|
5
|
+
*
|
|
6
|
+
* Only the fresh path crosses over. Incremental reuse needs the previous
|
|
7
|
+
* deployment map, and the per-app shard-size ratchet is state written across
|
|
8
|
+
* deploys; both stay with the service.
|
|
9
|
+
*/
|
|
10
|
+
/** Everything the planner is allowed to know. It reads no settings and no
|
|
11
|
+
* entitlements — the caller resolves these and passes them in. */
|
|
12
|
+
export interface ShardPolicy {
|
|
13
|
+
/** Functions packed into one shard. May be lower than `globalShardSize` when
|
|
14
|
+
* the caller carries a ratcheted override. */
|
|
15
|
+
shardSize: number;
|
|
16
|
+
/** The size capacity is judged at. A lowered `shardSize` changes packing only
|
|
17
|
+
* and must never lock an app out of deploying. */
|
|
18
|
+
globalShardSize: number;
|
|
19
|
+
maxShards: number;
|
|
20
|
+
/** Compressed ceiling for one shard's module, in bytes. */
|
|
21
|
+
gzipCapBytes: number;
|
|
22
|
+
}
|
|
23
|
+
export declare class ShardCapacityError extends Error {
|
|
24
|
+
constructor(message: string);
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* How many shards the desired set needs. `maxShards === 1` — sharding off — is
|
|
28
|
+
* always one shard whatever the function count: the whole app bundles into a
|
|
29
|
+
* single Worker, which is the legacy per-app behaviour. Going through the
|
|
30
|
+
* division would trip the capacity check for a flag-off app.
|
|
31
|
+
*/
|
|
32
|
+
export declare function targetShardCount(functionCount: number, shardSize: number, maxShards: number): number;
|
|
33
|
+
/**
|
|
34
|
+
* Refuse a set the product cannot hold. Judged at the GLOBAL shard size: a
|
|
35
|
+
* ratcheted-down `shardSize` affects packing only, so judging at it would lock
|
|
36
|
+
* a recovered app out of deploys. The resulting plan may therefore hold more
|
|
37
|
+
* shards than `maxShards` — bounded by the function count, which is no more
|
|
38
|
+
* Workers than the legacy per-function topology used. Do not "tidy" this into a
|
|
39
|
+
* check on the final shard count.
|
|
40
|
+
*/
|
|
41
|
+
export declare function assertWithinCapacity(functionCount: number, policy: ShardPolicy): void;
|
|
42
|
+
/**
|
|
43
|
+
* The fresh partition, as a list of shards holding function names.
|
|
44
|
+
*
|
|
45
|
+
* A single planned shard keeps the caller's order; a multi-shard plan sorts by
|
|
46
|
+
* name before chunking. The two differ in apper and the difference is load
|
|
47
|
+
* bearing — function order inside a combined module changes the emitted bytes,
|
|
48
|
+
* so normalising them would be a byte change wearing a cleanup's clothes.
|
|
49
|
+
*/
|
|
50
|
+
export declare function planFreshShards(names: string[], policy: ShardPolicy): string[][];
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which functions go in which shard, for a build with no previous deploy to
|
|
3
|
+
* reuse. Ported from apper's `shard_planning.py` (`target_shard_count`,
|
|
4
|
+
* `full_repartition`) and the capacity refusal in `deploy_app`.
|
|
5
|
+
*
|
|
6
|
+
* Only the fresh path crosses over. Incremental reuse needs the previous
|
|
7
|
+
* deployment map, and the per-app shard-size ratchet is state written across
|
|
8
|
+
* deploys; both stay with the service.
|
|
9
|
+
*/
|
|
10
|
+
export class ShardCapacityError extends Error {
|
|
11
|
+
constructor(message) {
|
|
12
|
+
super(message);
|
|
13
|
+
this.name = "ShardCapacityError";
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
/** The three counts have to be whole numbers of at least one. A zero or
|
|
17
|
+
* negative `shardSize` made the chunking loop below never advance — it hung
|
|
18
|
+
* rather than refusing, where the Python raises on the same input. */
|
|
19
|
+
function assertUsablePolicy(policy) {
|
|
20
|
+
for (const field of ["shardSize", "globalShardSize", "maxShards"]) {
|
|
21
|
+
const value = policy[field];
|
|
22
|
+
if (!Number.isInteger(value) || value < 1) {
|
|
23
|
+
throw new Error(`ShardPolicy.${field} must be an integer of at least 1, got ${value}`);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
function ceilDiv(a, b) {
|
|
28
|
+
return Math.ceil(a / b);
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* How many shards the desired set needs. `maxShards === 1` — sharding off — is
|
|
32
|
+
* always one shard whatever the function count: the whole app bundles into a
|
|
33
|
+
* single Worker, which is the legacy per-app behaviour. Going through the
|
|
34
|
+
* division would trip the capacity check for a flag-off app.
|
|
35
|
+
*/
|
|
36
|
+
export function targetShardCount(functionCount, shardSize, maxShards) {
|
|
37
|
+
if (maxShards === 1)
|
|
38
|
+
return 1;
|
|
39
|
+
return ceilDiv(functionCount, shardSize);
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Refuse a set the product cannot hold. Judged at the GLOBAL shard size: a
|
|
43
|
+
* ratcheted-down `shardSize` affects packing only, so judging at it would lock
|
|
44
|
+
* a recovered app out of deploys. The resulting plan may therefore hold more
|
|
45
|
+
* shards than `maxShards` — bounded by the function count, which is no more
|
|
46
|
+
* Workers than the legacy per-function topology used. Do not "tidy" this into a
|
|
47
|
+
* check on the final shard count.
|
|
48
|
+
*/
|
|
49
|
+
export function assertWithinCapacity(functionCount, policy) {
|
|
50
|
+
const needed = targetShardCount(functionCount, policy.globalShardSize, policy.maxShards);
|
|
51
|
+
if (needed > policy.maxShards) {
|
|
52
|
+
throw new ShardCapacityError(`App has ${functionCount} functions — over the per-app Worker capacity of ` +
|
|
53
|
+
`${policy.globalShardSize * policy.maxShards} ` +
|
|
54
|
+
`(${policy.maxShards} shards × ${policy.globalShardSize}).`);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* The fresh partition, as a list of shards holding function names.
|
|
59
|
+
*
|
|
60
|
+
* A single planned shard keeps the caller's order; a multi-shard plan sorts by
|
|
61
|
+
* name before chunking. The two differ in apper and the difference is load
|
|
62
|
+
* bearing — function order inside a combined module changes the emitted bytes,
|
|
63
|
+
* so normalising them would be a byte change wearing a cleanup's clothes.
|
|
64
|
+
*/
|
|
65
|
+
export function planFreshShards(names, policy) {
|
|
66
|
+
assertUsablePolicy(policy);
|
|
67
|
+
assertWithinCapacity(names.length, policy);
|
|
68
|
+
const target = targetShardCount(names.length, policy.shardSize, policy.maxShards);
|
|
69
|
+
if (target <= 1)
|
|
70
|
+
return [[...names]];
|
|
71
|
+
const sorted = [...names].sort();
|
|
72
|
+
const shards = [];
|
|
73
|
+
for (let i = 0; i < sorted.length; i += policy.shardSize) {
|
|
74
|
+
shards.push(sorted.slice(i, i + policy.shardSize));
|
|
75
|
+
}
|
|
76
|
+
return shards;
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=plan.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plan.js","sourceRoot":"","sources":["../../../src/shards/plan.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAgBH,MAAM,OAAO,kBAAmB,SAAQ,KAAK;IAC3C,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,oBAAoB,CAAC;IACnC,CAAC;CACF;AAED;;uEAEuE;AACvE,SAAS,kBAAkB,CAAC,MAAmB;IAC7C,KAAK,MAAM,KAAK,IAAI,CAAC,WAAW,EAAE,iBAAiB,EAAE,WAAW,CAAU,EAAE,CAAC;QAC3E,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;QAC5B,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;YAC1C,MAAM,IAAI,KAAK,CACb,eAAe,KAAK,0CAA0C,KAAK,EAAE,CACtE,CAAC;QACJ,CAAC;IACH,CAAC;AACH,CAAC;AAED,SAAS,OAAO,CAAC,CAAS,EAAE,CAAS;IACnC,OAAO,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;AAC1B,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAC9B,aAAqB,EACrB,SAAiB,EACjB,SAAiB;IAEjB,IAAI,SAAS,KAAK,CAAC;QAAE,OAAO,CAAC,CAAC;IAC9B,OAAO,OAAO,CAAC,aAAa,EAAE,SAAS,CAAC,CAAC;AAC3C,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,oBAAoB,CAClC,aAAqB,EACrB,MAAmB;IAEnB,MAAM,MAAM,GAAG,gBAAgB,CAC7B,aAAa,EACb,MAAM,CAAC,eAAe,EACtB,MAAM,CAAC,SAAS,CACjB,CAAC;IACF,IAAI,MAAM,GAAG,MAAM,CAAC,SAAS,EAAE,CAAC;QAC9B,MAAM,IAAI,kBAAkB,CAC1B,WAAW,aAAa,mDAAmD;YACzE,GAAG,MAAM,CAAC,eAAe,GAAG,MAAM,CAAC,SAAS,GAAG;YAC/C,IAAI,MAAM,CAAC,SAAS,aAAa,MAAM,CAAC,eAAe,IAAI,CAC9D,CAAC;IACJ,CAAC;AACH,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,eAAe,CAC7B,KAAe,EACf,MAAmB;IAEnB,kBAAkB,CAAC,MAAM,CAAC,CAAC;IAC3B,oBAAoB,CAAC,KAAK,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAE3C,MAAM,MAAM,GAAG,gBAAgB,CAC7B,KAAK,CAAC,MAAM,EACZ,MAAM,CAAC,SAAS,EAChB,MAAM,CAAC,SAAS,CACjB,CAAC;IACF,IAAI,MAAM,IAAI,CAAC;QAAE,OAAO,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC;IAErC,MAAM,MAAM,GAAG,CAAC,GAAG,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC;IACjC,MAAM,MAAM,GAAe,EAAE,CAAC;IAC9B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,IAAI,MAAM,CAAC,SAAS,EAAE,CAAC;QACzD,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC;IACrD,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How large a compiled Worker module is, and whether Cloudflare will take it.
|
|
3
|
+
*
|
|
4
|
+
* Ported from apper's `cloudflare_wfp_runtime.py` (`measure_bundle_bytes`,
|
|
5
|
+
* `worker_raw_size_breach`, `worker_gzip_cap_breach`, `judge_bundle_size`).
|
|
6
|
+
* Deciding this before an upload is the whole point: the one real production
|
|
7
|
+
* rejection spent 30 seconds uploading 97 MB to be told the same thing this
|
|
8
|
+
* computes for free.
|
|
9
|
+
*/
|
|
10
|
+
/** zlib's default, and the level `wrangler --dry-run` reports — so the number
|
|
11
|
+
* here means the same thing as the one in Cloudflare's docs, in a support
|
|
12
|
+
* thread and on a developer's terminal. It is not a claim about Cloudflare's
|
|
13
|
+
* own server-side compressor, which is unpublished; the safety margin lives in
|
|
14
|
+
* the cap instead. */
|
|
15
|
+
export declare const BUNDLE_GZIP_LEVEL = 6;
|
|
16
|
+
/** Cloudflare's uncompressed per-Worker ceiling, in the units Cloudflare states
|
|
17
|
+
* it in. Taken from a real 10027 in production, which reads verbatim: "Your
|
|
18
|
+
* Worker exceeded the uncompressed size limit of 64 MiB." Decimal 64_000_000
|
|
19
|
+
* would refuse 3 MiB early for no reason. */
|
|
20
|
+
export declare const WORKER_RAW_SIZE_CEILING_BYTES: number;
|
|
21
|
+
export interface BundleSize {
|
|
22
|
+
rawBytes: number;
|
|
23
|
+
gzipBytes: number;
|
|
24
|
+
}
|
|
25
|
+
export interface SizeVerdict extends BundleSize {
|
|
26
|
+
/** Why the module is over a ceiling, or `null` when it is within both. */
|
|
27
|
+
breach: string | null;
|
|
28
|
+
}
|
|
29
|
+
/** `(raw, gzip)` for a compiled module. Compression runs off the event loop:
|
|
30
|
+
* a multi-megabyte gzip is long enough to matter when several shards are in
|
|
31
|
+
* flight. */
|
|
32
|
+
export declare function measureBundleBytes(module: string): Promise<BundleSize>;
|
|
33
|
+
/** Why Cloudflare will reject this module outright, or `null`. The only verdict
|
|
34
|
+
* taken on a number Cloudflare states itself — no estimate, no compression, no
|
|
35
|
+
* headroom to argue about. */
|
|
36
|
+
export declare function workerRawSizeBreach(rawBytes: number): string | null;
|
|
37
|
+
/** Why the module is over the compressed ceiling, or `null`. Our side of the
|
|
38
|
+
* comparison is the estimate, not Cloudflare's number: it compresses
|
|
39
|
+
* server-side with an unpublished algorithm, so level-6 gzip is a proxy for
|
|
40
|
+
* the figure it measures. The cap carries the margin. */
|
|
41
|
+
export declare function workerGzipCapBreach(gzipBytes: number, gzipCapBytes: number): string | null;
|
|
42
|
+
/** Measure a module and say whether it breaches either ceiling. Never throws:
|
|
43
|
+
* what a breach costs depends on whether the caller can re-partition, and only
|
|
44
|
+
* the caller knows that. */
|
|
45
|
+
export declare function judgeBundleSize(module: string, gzipCapBytes: number): Promise<SizeVerdict>;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How large a compiled Worker module is, and whether Cloudflare will take it.
|
|
3
|
+
*
|
|
4
|
+
* Ported from apper's `cloudflare_wfp_runtime.py` (`measure_bundle_bytes`,
|
|
5
|
+
* `worker_raw_size_breach`, `worker_gzip_cap_breach`, `judge_bundle_size`).
|
|
6
|
+
* Deciding this before an upload is the whole point: the one real production
|
|
7
|
+
* rejection spent 30 seconds uploading 97 MB to be told the same thing this
|
|
8
|
+
* computes for free.
|
|
9
|
+
*/
|
|
10
|
+
import { promisify } from "node:util";
|
|
11
|
+
import { gzip } from "node:zlib";
|
|
12
|
+
const gzipAsync = promisify(gzip);
|
|
13
|
+
/** zlib's default, and the level `wrangler --dry-run` reports — so the number
|
|
14
|
+
* here means the same thing as the one in Cloudflare's docs, in a support
|
|
15
|
+
* thread and on a developer's terminal. It is not a claim about Cloudflare's
|
|
16
|
+
* own server-side compressor, which is unpublished; the safety margin lives in
|
|
17
|
+
* the cap instead. */
|
|
18
|
+
export const BUNDLE_GZIP_LEVEL = 6;
|
|
19
|
+
/** Cloudflare's uncompressed per-Worker ceiling, in the units Cloudflare states
|
|
20
|
+
* it in. Taken from a real 10027 in production, which reads verbatim: "Your
|
|
21
|
+
* Worker exceeded the uncompressed size limit of 64 MiB." Decimal 64_000_000
|
|
22
|
+
* would refuse 3 MiB early for no reason. */
|
|
23
|
+
export const WORKER_RAW_SIZE_CEILING_BYTES = 64 * 1024 * 1024;
|
|
24
|
+
/** `(raw, gzip)` for a compiled module. Compression runs off the event loop:
|
|
25
|
+
* a multi-megabyte gzip is long enough to matter when several shards are in
|
|
26
|
+
* flight. */
|
|
27
|
+
export async function measureBundleBytes(module) {
|
|
28
|
+
const raw = Buffer.from(module, "utf8");
|
|
29
|
+
const compressed = await gzipAsync(raw, { level: BUNDLE_GZIP_LEVEL });
|
|
30
|
+
return { rawBytes: raw.byteLength, gzipBytes: compressed.byteLength };
|
|
31
|
+
}
|
|
32
|
+
/** Why Cloudflare will reject this module outright, or `null`. The only verdict
|
|
33
|
+
* taken on a number Cloudflare states itself — no estimate, no compression, no
|
|
34
|
+
* headroom to argue about. */
|
|
35
|
+
export function workerRawSizeBreach(rawBytes) {
|
|
36
|
+
if (rawBytes > WORKER_RAW_SIZE_CEILING_BYTES) {
|
|
37
|
+
return (`bundled module is ${rawBytes} bytes uncompressed, over Cloudflare's ` +
|
|
38
|
+
`${WORKER_RAW_SIZE_CEILING_BYTES}-byte (64 MiB) per-Worker ceiling`);
|
|
39
|
+
}
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
/** Why the module is over the compressed ceiling, or `null`. Our side of the
|
|
43
|
+
* comparison is the estimate, not Cloudflare's number: it compresses
|
|
44
|
+
* server-side with an unpublished algorithm, so level-6 gzip is a proxy for
|
|
45
|
+
* the figure it measures. The cap carries the margin. */
|
|
46
|
+
export function workerGzipCapBreach(gzipBytes, gzipCapBytes) {
|
|
47
|
+
if (gzipBytes > gzipCapBytes) {
|
|
48
|
+
return (`bundled module is ${gzipBytes} bytes gzipped (level ${BUNDLE_GZIP_LEVEL}), ` +
|
|
49
|
+
`over the ${gzipCapBytes}-byte cap for a Cloudflare Worker script`);
|
|
50
|
+
}
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
/** Measure a module and say whether it breaches either ceiling. Never throws:
|
|
54
|
+
* what a breach costs depends on whether the caller can re-partition, and only
|
|
55
|
+
* the caller knows that. */
|
|
56
|
+
export async function judgeBundleSize(module, gzipCapBytes) {
|
|
57
|
+
const { rawBytes, gzipBytes } = await measureBundleBytes(module);
|
|
58
|
+
// Uncompressed first: it is the exact one, so when both are over it is the
|
|
59
|
+
// verdict worth reporting.
|
|
60
|
+
const breach = workerRawSizeBreach(rawBytes) ??
|
|
61
|
+
workerGzipCapBreach(gzipBytes, gzipCapBytes);
|
|
62
|
+
return { rawBytes, gzipBytes, breach };
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=size.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"size.js","sourceRoot":"","sources":["../../../src/shards/size.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,MAAM,SAAS,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;AAElC;;;;uBAIuB;AACvB,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,CAAC;AAEnC;;;8CAG8C;AAC9C,MAAM,CAAC,MAAM,6BAA6B,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,CAAC;AAY9D;;cAEc;AACd,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,MAAc;IACrD,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACxC,MAAM,UAAU,GAAG,MAAM,SAAS,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,iBAAiB,EAAE,CAAC,CAAC;IACtE,OAAO,EAAE,QAAQ,EAAE,GAAG,CAAC,UAAU,EAAE,SAAS,EAAE,UAAU,CAAC,UAAU,EAAE,CAAC;AACxE,CAAC;AAED;;+BAE+B;AAC/B,MAAM,UAAU,mBAAmB,CAAC,QAAgB;IAClD,IAAI,QAAQ,GAAG,6BAA6B,EAAE,CAAC;QAC7C,OAAO,CACL,qBAAqB,QAAQ,yCAAyC;YACtE,GAAG,6BAA6B,mCAAmC,CACpE,CAAC;IACJ,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;0DAG0D;AAC1D,MAAM,UAAU,mBAAmB,CACjC,SAAiB,EACjB,YAAoB;IAEpB,IAAI,SAAS,GAAG,YAAY,EAAE,CAAC;QAC7B,OAAO,CACL,qBAAqB,SAAS,yBAAyB,iBAAiB,KAAK;YAC7E,YAAY,YAAY,0CAA0C,CACnE,CAAC;IACJ,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;6BAE6B;AAC7B,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,MAAc,EACd,YAAoB;IAEpB,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,MAAM,kBAAkB,CAAC,MAAM,CAAC,CAAC;IACjE,2EAA2E;IAC3E,2BAA2B;IAC3B,MAAM,MAAM,GACV,mBAAmB,CAAC,QAAQ,CAAC;QAC7B,mBAAmB,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC;IAC/C,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC;AACzC,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This package's version, as a literal.
|
|
3
|
+
*
|
|
4
|
+
* It goes into every compiled shard's banner, which means it is part of the
|
|
5
|
+
* emitted bytes and therefore part of a deployed version's identity. Reading it
|
|
6
|
+
* from `package.json` at runtime cannot work: a host that bundles this module
|
|
7
|
+
* into an artifact of its own — which the CLI does — ships no `package.json`
|
|
8
|
+
* beside it, and the read silently degraded to "unknown", so the same functions
|
|
9
|
+
* compiled to different bytes in the CLI and in the service.
|
|
10
|
+
*
|
|
11
|
+
* A literal resolves in every host. `version.test.ts` fails the build if it
|
|
12
|
+
* drifts from `package.json`, so bumping the package still means editing two
|
|
13
|
+
* files but cannot mean forgetting one.
|
|
14
|
+
*/
|
|
15
|
+
export declare const COMPILER_VERSION = "0.1.2";
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This package's version, as a literal.
|
|
3
|
+
*
|
|
4
|
+
* It goes into every compiled shard's banner, which means it is part of the
|
|
5
|
+
* emitted bytes and therefore part of a deployed version's identity. Reading it
|
|
6
|
+
* from `package.json` at runtime cannot work: a host that bundles this module
|
|
7
|
+
* into an artifact of its own — which the CLI does — ships no `package.json`
|
|
8
|
+
* beside it, and the read silently degraded to "unknown", so the same functions
|
|
9
|
+
* compiled to different bytes in the CLI and in the service.
|
|
10
|
+
*
|
|
11
|
+
* A literal resolves in every host. `version.test.ts` fails the build if it
|
|
12
|
+
* drifts from `package.json`, so bumping the package still means editing two
|
|
13
|
+
* files but cannot mean forgetting one.
|
|
14
|
+
*/
|
|
15
|
+
export const COMPILER_VERSION = "0.1.2";
|
|
16
|
+
//# sourceMappingURL=version.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version.js","sourceRoot":"","sources":["../../src/version.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,OAAO,CAAC"}
|
|
@@ -10,6 +10,8 @@ export declare const ACTIVATION_FILENAME = "__base44_activation.mjs";
|
|
|
10
10
|
export interface PreparedWorker {
|
|
11
11
|
entry: string;
|
|
12
12
|
files: Record<string, string>;
|
|
13
|
+
/** Prepended verbatim to the compiled module. Only the app path sets it. */
|
|
14
|
+
banner?: string;
|
|
13
15
|
}
|
|
14
16
|
export declare function workerRuntimeFiles(): Record<string, string>;
|
|
15
17
|
/** Shared console-patching prelude injected into every generated Worker entry.
|
|
@@ -17,9 +19,6 @@ export declare function workerRuntimeFiles(): Record<string, string>;
|
|
|
17
19
|
export declare const CONSOLE_PATCH: string;
|
|
18
20
|
/** Assemble a single Deno function into a bundle-ready Worker. */
|
|
19
21
|
export declare function prepareFunction(entry: string, files: Record<string, string>, postResponseTelemetry?: boolean, runtimeSecrets?: boolean): Promise<PreparedWorker>;
|
|
20
|
-
/** One app function paired with the stable key its files and diagnostics are
|
|
21
|
-
* namespaced under (`fn_<index>`). The index is the function's original
|
|
22
|
-
* position so attribution stays correct across an exclude-and-rebuild. */
|
|
23
22
|
export interface AppFunctionEntry {
|
|
24
23
|
index: number;
|
|
25
24
|
fn: AppFunctionInput;
|
package/lib/src/worker-entry.js
CHANGED
|
@@ -7,7 +7,9 @@
|
|
|
7
7
|
import { readFileSync } from "node:fs";
|
|
8
8
|
import { DenoCompatError } from "./errors.js";
|
|
9
9
|
import { RUNTIME_CONTEXT_SPECIFIER } from "./esbuild/runtime-context-virtual.js";
|
|
10
|
+
import { ASCII_ESCAPE, CAPTURE_PATCH, INVOCATION_LOGS_PATCH, } from "./invocation-logs.js";
|
|
10
11
|
import { TELEMETRY_PATCH, TELEMETRY_STORE_FIELDS } from "./telemetry.js";
|
|
12
|
+
import { COMPILER_VERSION } from "./version.js";
|
|
11
13
|
// Pre-built by scripts/build-shim.ts; regenerate it after changing the shim.
|
|
12
14
|
// Read LAZILY, not at module load: build-shim.ts transitively imports this
|
|
13
15
|
// module through the esbuild plugins, and on a fresh checkout dist/ doesn't
|
|
@@ -58,7 +60,9 @@ export const CONSOLE_PATCH = [
|
|
|
58
60
|
// by per-app bundles, where one script serves every function and log queries
|
|
59
61
|
// need per-function attribution. `secrets` and `workerEnv` reference the
|
|
60
62
|
// request's authoritative Worker env binding.
|
|
61
|
-
|
|
63
|
+
ASCII_ESCAPE,
|
|
64
|
+
CAPTURE_PATCH,
|
|
65
|
+
"const _b44Wrap = (lvl, a) => { const _c = _b44Context() ?? {}; const _m = _b44Fmt(a); _b44Capture(_c, lvl, _m); _b44Orig({ _b44_env: _c.env ?? 'preview', ...(_c.fn ? { _b44_function: _c.fn } : {}), level: lvl, message: _m }); };",
|
|
62
66
|
"console.log = (...a) => _b44Wrap('info', a);",
|
|
63
67
|
"console.info = (...a) => _b44Wrap('info', a);",
|
|
64
68
|
"console.warn = (...a) => _b44Wrap('warn', a);",
|
|
@@ -102,6 +106,30 @@ export async function prepareFunction(entry, files, postResponseTelemetry = fals
|
|
|
102
106
|
},
|
|
103
107
|
};
|
|
104
108
|
}
|
|
109
|
+
/** One app function paired with the stable key its files and diagnostics are
|
|
110
|
+
* namespaced under (`fn_<index>`). The index is the function's original
|
|
111
|
+
* position so attribution stays correct across an exclude-and-rebuild. */
|
|
112
|
+
/** Bumped only when the payload's shape changes, never for a new field. */
|
|
113
|
+
const BANNER_FORMAT = 1;
|
|
114
|
+
/** The bundle's self-description, as its first line: `//!b44:<format> <json>`.
|
|
115
|
+
* A fixed sentinel so `head -1` finds it and a reader can version the format,
|
|
116
|
+
* and JSON so it parses in one call. Before this, a compiled module named its
|
|
117
|
+
* functions only as scattered `registerLazy` literals in minified output.
|
|
118
|
+
*
|
|
119
|
+
* Nothing volatile belongs in here. A version's identity is the hash of these
|
|
120
|
+
* bytes, so a timestamp, a build id or anything else that moves on its own
|
|
121
|
+
* would re-mint a version for code that did not change; the app id would make
|
|
122
|
+
* the same functions compile differently per app; the shard's position would
|
|
123
|
+
* make two identical shards differ. Names are sorted for the same reason — the
|
|
124
|
+
* module below is assembled in caller order, this line is not. */
|
|
125
|
+
function buildBanner(entries, telemetry, runtimeSecrets) {
|
|
126
|
+
return `//!b44:${BANNER_FORMAT} ${JSON.stringify({
|
|
127
|
+
functions: entries.map(({ fn }) => fn.name).sort(),
|
|
128
|
+
telemetry,
|
|
129
|
+
runtimeSecrets,
|
|
130
|
+
compiler: COMPILER_VERSION,
|
|
131
|
+
})}`;
|
|
132
|
+
}
|
|
105
133
|
/** Assemble the whole app into ONE bundle-ready Worker: every function's files
|
|
106
134
|
* namespaced under `fn_<index>/`, one shared shim, and a router that routes by
|
|
107
135
|
* function name. A single compile resolves and DEDUPES npm deps across all
|
|
@@ -128,7 +156,11 @@ export function prepareApp(entries, postResponseTelemetry = false, runtimeSecret
|
|
|
128
156
|
return wrapper;
|
|
129
157
|
});
|
|
130
158
|
files[ENTRY_FILENAME] = buildAppEntrySource(moduleFiles, postResponseTelemetry, runtimeSecrets);
|
|
131
|
-
return {
|
|
159
|
+
return {
|
|
160
|
+
entry: ENTRY_FILENAME,
|
|
161
|
+
files,
|
|
162
|
+
banner: buildBanner(entries, postResponseTelemetry, runtimeSecrets),
|
|
163
|
+
};
|
|
132
164
|
}
|
|
133
165
|
// Activation prelude for runtime-secrets bundles: gate on the encrypted
|
|
134
166
|
// handshake BEFORE any user module is imported (so a needs-activation response
|
|
@@ -208,9 +240,9 @@ function buildAppEntrySource(functionModules, telemetry, runtimeSecrets = false)
|
|
|
208
240
|
const moduleImports = functionModules
|
|
209
241
|
.map((file) => `import "./${file}";`)
|
|
210
242
|
.join("\n");
|
|
211
|
-
const handlerExpr = telemetry
|
|
243
|
+
const handlerExpr = `_b44AttachInvocationLogs(${telemetry
|
|
212
244
|
? "_b44AttachTelemetry(await handler(request, info))"
|
|
213
|
-
: "await handler(request, info)"
|
|
245
|
+
: "await handler(request, info)"})`;
|
|
214
246
|
const returnExpr = runtimeSecrets
|
|
215
247
|
? `withoutActivationSignal(${handlerExpr})`
|
|
216
248
|
: handlerExpr;
|
|
@@ -221,6 +253,7 @@ import { installStaticEgressFetch, resolveHandler } from "./${SHIM_FILENAME}";${
|
|
|
221
253
|
${moduleImports}
|
|
222
254
|
|
|
223
255
|
${CONSOLE_PATCH}
|
|
256
|
+
${INVOCATION_LOGS_PATCH}
|
|
224
257
|
// Static egress reads workerEnv from the active request store. Install it
|
|
225
258
|
// before telemetry so telemetry remains the outermost fetch wrapper.
|
|
226
259
|
installStaticEgressFetch();
|
|
@@ -230,7 +263,7 @@ export default {
|
|
|
230
263
|
async fetch(request, env, ctx) {
|
|
231
264
|
const _b44Env = (request.headers.get('base44-functions-version') ?? '') === 'prod' ? 'prod' : 'preview';
|
|
232
265
|
const functionName = request.headers.get("Base44-Function-Name");
|
|
233
|
-
return _b44Run({ env: _b44Env, fn: functionName ?? '', secrets: ${runtimeSecrets ? "process.env" : "env"}, workerEnv: env, waitUntil: (p) => ctx.waitUntil(p)${telemetry ? `, ${TELEMETRY_STORE_FIELDS}` : ""} }, async () => {
|
|
266
|
+
return _b44Run({ env: _b44Env, fn: functionName ?? '', secrets: ${runtimeSecrets ? "process.env" : "env"}, workerEnv: env, waitUntil: (p) => ctx.waitUntil(p), ..._b44CaptureStore(request)${telemetry ? `, ${TELEMETRY_STORE_FIELDS}` : ""} }, async () => {
|
|
234
267
|
${runtimeSecrets ? ACTIVATION_GATE : ""} // Each early return below logs through the patch first: per-function log
|
|
235
268
|
// queries on per-app scripts keep only stamped lines, so a bare return
|
|
236
269
|
// would leave the failing invocation with no trace in its own logs.
|
|
@@ -238,22 +271,22 @@ ${runtimeSecrets ? ACTIVATION_GATE : ""} // Each early return below logs th
|
|
|
238
271
|
if (pendingHandler === undefined) {
|
|
239
272
|
const message = \`No function registered for "\${functionName ?? ""}"\`;
|
|
240
273
|
console.error(message);
|
|
241
|
-
return new Response(message, { status: 404 });
|
|
274
|
+
return _b44AttachInvocationLogs(new Response(message, { status: 404 }));
|
|
242
275
|
}
|
|
243
276
|
let handler;
|
|
244
277
|
try {
|
|
245
278
|
handler = await pendingHandler;
|
|
246
279
|
} catch (e) {
|
|
247
280
|
console.error(\`Function "\${functionName}" failed to initialize:\`, e);
|
|
248
|
-
return new Response(
|
|
281
|
+
return _b44AttachInvocationLogs(new Response(
|
|
249
282
|
\`Function "\${functionName}" failed to initialize: \${e instanceof Error ? e.message : String(e)}\`,
|
|
250
283
|
{ status: 500 },
|
|
251
|
-
);
|
|
284
|
+
));
|
|
252
285
|
}
|
|
253
286
|
if (handler === null) {
|
|
254
287
|
const message = \`Function "\${functionName}" must export default a request handler or call Deno.serve()\`;
|
|
255
288
|
console.error(message);
|
|
256
|
-
return new Response(message, { status: 503 });
|
|
289
|
+
return _b44AttachInvocationLogs(new Response(message, { status: 503 }));
|
|
257
290
|
}
|
|
258
291
|
// Real client IP is in the "cf-connecting-ip" header, not this placeholder.
|
|
259
292
|
const info = {
|
|
@@ -266,11 +299,14 @@ ${runtimeSecrets ? ACTIVATION_GATE : ""} // Each early return below logs th
|
|
|
266
299
|
// stamped lines (see log_query.event_matches_function). Known gap:
|
|
267
300
|
// exceptions thrown while a response body streams happen after this
|
|
268
301
|
// frame returns and cannot be stamped — those crash events are
|
|
269
|
-
// dropped from per-function views
|
|
302
|
+
// dropped from per-function views, and lines logged after the response
|
|
303
|
+
// starts streaming are past the invocation-logs header too.
|
|
270
304
|
try {
|
|
271
305
|
return ${returnExpr};
|
|
272
306
|
} catch (e) {
|
|
273
307
|
console.error(e);
|
|
308
|
+
const crash = _b44CrashResponse(e);
|
|
309
|
+
if (crash) return crash;
|
|
274
310
|
throw e;
|
|
275
311
|
}
|
|
276
312
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"worker-entry.js","sourceRoot":"","sources":["../../src/worker-entry.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEvC,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAE,yBAAyB,EAAE,MAAM,sCAAsC,CAAC;AACjF,OAAO,EAAE,eAAe,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"worker-entry.js","sourceRoot":"","sources":["../../src/worker-entry.ts"],"names":[],"mappings":"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"}
|