@base44/functions-compiler 0.1.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/README.md +137 -0
- package/lib/dist/activation-shim.mjs +237 -0
- package/lib/dist/actor.mjs +1129 -0
- package/lib/dist/deno-shim.mjs +2347 -0
- package/lib/src/actor-compat.d.ts +24 -0
- package/lib/src/actor-compat.js +302 -0
- package/lib/src/actor-compat.js.map +1 -0
- package/lib/src/bundler.d.ts +51 -0
- package/lib/src/bundler.js +321 -0
- package/lib/src/bundler.js.map +1 -0
- package/lib/src/contracts.d.ts +108 -0
- package/lib/src/contracts.js +39 -0
- package/lib/src/contracts.js.map +1 -0
- package/lib/src/deno-bundle.d.ts +30 -0
- package/lib/src/deno-bundle.js +146 -0
- package/lib/src/deno-bundle.js.map +1 -0
- package/lib/src/errors.d.ts +16 -0
- package/lib/src/errors.js +11 -0
- package/lib/src/errors.js.map +1 -0
- package/lib/src/esbuild/deno-resolver.d.ts +26 -0
- package/lib/src/esbuild/deno-resolver.js +436 -0
- package/lib/src/esbuild/deno-resolver.js.map +1 -0
- package/lib/src/esbuild/node-builtin-require.d.ts +2 -0
- package/lib/src/esbuild/node-builtin-require.js +33 -0
- package/lib/src/esbuild/node-builtin-require.js.map +1 -0
- package/lib/src/esbuild/private-data-sources-virtual.d.ts +3 -0
- package/lib/src/esbuild/private-data-sources-virtual.js +127 -0
- package/lib/src/esbuild/private-data-sources-virtual.js.map +1 -0
- package/lib/src/esbuild/runtime-context-virtual.d.ts +3 -0
- package/lib/src/esbuild/runtime-context-virtual.js +42 -0
- package/lib/src/esbuild/runtime-context-virtual.js.map +1 -0
- package/lib/src/esbuild/runtime-virtual.d.ts +2 -0
- package/lib/src/esbuild/runtime-virtual.js +52 -0
- package/lib/src/esbuild/runtime-virtual.js.map +1 -0
- package/lib/src/esbuild/user-files.d.ts +15 -0
- package/lib/src/esbuild/user-files.js +73 -0
- package/lib/src/esbuild/user-files.js.map +1 -0
- package/lib/src/fetch-guard.d.ts +26 -0
- package/lib/src/fetch-guard.js +67 -0
- package/lib/src/fetch-guard.js.map +1 -0
- package/lib/src/index.d.ts +12 -0
- package/lib/src/index.js +11 -0
- package/lib/src/index.js.map +1 -0
- package/lib/src/log.d.ts +7 -0
- package/lib/src/log.js +39 -0
- package/lib/src/log.js.map +1 -0
- package/lib/src/private-data-sources/build-http.ts +51 -0
- package/lib/src/private-data-sources/elasticsearch.ts +8 -0
- package/lib/src/private-data-sources/http-url.ts +23 -0
- package/lib/src/private-data-sources/http.ts +6 -0
- package/lib/src/private-data-sources/hyperdrive.ts +48 -0
- package/lib/src/private-data-sources/ioredis-adapter.ts +229 -0
- package/lib/src/private-data-sources/manifest.ts +150 -0
- package/lib/src/private-data-sources/mariadb.ts +8 -0
- package/lib/src/private-data-sources/mongodb.ts +70 -0
- package/lib/src/private-data-sources/mysql.ts +8 -0
- package/lib/src/private-data-sources/node-net-adapter.ts +244 -0
- package/lib/src/private-data-sources/postgres.ts +8 -0
- package/lib/src/private-data-sources/redis-auth.ts +83 -0
- package/lib/src/private-data-sources/redis.ts +47 -0
- package/lib/src/private-data-sources/runtime-environment.ts +4 -0
- package/lib/src/private-data-sources/runtime-manifest-store.ts +32 -0
- package/lib/src/private-data-sources/sqlserver.ts +22 -0
- package/lib/src/private-data-sources/tcp.ts +86 -0
- package/lib/src/private-data-sources/tedious-adapter.ts +67 -0
- package/lib/src/private-data-sources/types.ts +29 -0
- package/lib/src/runtime/index.ts +30 -0
- package/lib/src/runtime-context.ts +29 -0
- package/lib/src/static-egress-marker.d.ts +1 -0
- package/lib/src/static-egress-marker.js +7 -0
- package/lib/src/static-egress-marker.js.map +1 -0
- package/lib/src/telemetry.d.ts +32 -0
- package/lib/src/telemetry.js +84 -0
- package/lib/src/telemetry.js.map +1 -0
- package/lib/src/tracing.d.ts +9 -0
- package/lib/src/tracing.js +21 -0
- package/lib/src/tracing.js.map +1 -0
- package/lib/src/worker-entry.d.ts +36 -0
- package/lib/src/worker-entry.js +320 -0
- package/lib/src/worker-entry.js.map +1 -0
- package/package.json +43 -0
package/README.md
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# @base44/functions-compiler
|
|
2
|
+
|
|
3
|
+
Production compiler for Base44 backend functions. Takes function sources as
|
|
4
|
+
data and returns a single Cloudflare Workers module — the generated worker
|
|
5
|
+
entry, the Deno shim, the runtime and private-data-source modules, and npm/jsr
|
|
6
|
+
dependency resolution through `@deno/loader` + esbuild.
|
|
7
|
+
|
|
8
|
+
Two consumers share this one engine:
|
|
9
|
+
|
|
10
|
+
- the **Base44 CLI**, which compiles locally (and inside the platform's build
|
|
11
|
+
sandbox) with no network service in the path;
|
|
12
|
+
- apper's **`base44-userapp-bundler`** HTTP service, which keeps its own
|
|
13
|
+
endpoints, auth, worker pool and telemetry around it.
|
|
14
|
+
|
|
15
|
+
## Status and scope
|
|
16
|
+
|
|
17
|
+
Internal to Base44 — published **public** so apper's bundler service can install
|
|
18
|
+
it, but it is not a supported public API: the CLI bundles it at build time so
|
|
19
|
+
end users never install it, and it carries no compatibility promise to anyone
|
|
20
|
+
outside this repo. It compiles functions and nothing else: shard planning, size
|
|
21
|
+
splitting, artifact writing, version creation and deploy all live above it.
|
|
22
|
+
|
|
23
|
+
The package carries no credentials and reads no configuration of its own. It
|
|
24
|
+
names the environment variables and headers the generated worker will use at
|
|
25
|
+
runtime (`BASE44_*`, `X-Base44-*`) but holds none of their values, and the code
|
|
26
|
+
it ships is the same code already compiled into every deployed user worker.
|
|
27
|
+
|
|
28
|
+
## What is missing: shards, and whole-app CFW bundles
|
|
29
|
+
|
|
30
|
+
Today this package compiles **one module per call**. It does not decide which
|
|
31
|
+
functions belong in which module, how large the result may be, or what to do
|
|
32
|
+
when it is too large. That work is still Python in apper's
|
|
33
|
+
`backend/app/cloudflare_functions/` and moves here next — it is what turns
|
|
34
|
+
"compile this set of sources" into "produce the deployable Cloudflare Workers
|
|
35
|
+
bundles for this app".
|
|
36
|
+
|
|
37
|
+
| Missing piece | Where it lives today | What it has to do |
|
|
38
|
+
|---|---|---|
|
|
39
|
+
| Source assembly | `function_bundle.py` — `cfw_bundle_input`, `collect_reachable_backend_files` | Turn a function's directory plus the shared files it reaches into the `entry` + `files` this package takes, keeping the flat single-file case and the refusal to escape into the frontend tree |
|
|
40
|
+
| Fresh shard planning | `shard_planning.py` — `full_repartition`, `target_shard_count` | Group an app's functions into shards deterministically, and refuse a set that exceeds the supplied product capacity |
|
|
41
|
+
| Size measurement | `cloudflare_wfp_runtime.py` — `measure_bundle_bytes`, `judge_bundle_size` | Raw UTF-8 bytes and level-6 gzip, against Cloudflare's 64 MiB uncompressed limit and our compressed cap |
|
|
42
|
+
| Split on overflow | `cloudflare_wfp_runtime.py` — `_build_shard_with_split` | Halve an oversized multi-function shard deterministically and recompile; fail the build when one function alone is too big |
|
|
43
|
+
| Whole-build validation | apper PR #23460 | Reject a partial result: every declared function in exactly one successful shard, or no build at all |
|
|
44
|
+
|
|
45
|
+
Only the **fresh-build** slice comes across. Everything that remembers a
|
|
46
|
+
previous deploy stays in apper: incremental shard reuse (it needs the previous
|
|
47
|
+
deployment map), the per-app `shard_size_override` ratchet, entitlement and
|
|
48
|
+
settings reads, provider upload, binding resolution and secret delivery. Policy
|
|
49
|
+
numbers — shard size, shard count, the gzip cap, whether the gate is enforced —
|
|
50
|
+
arrive as inputs; the package never reads them itself.
|
|
51
|
+
|
|
52
|
+
Two details from the Python that must survive the port, both verified against
|
|
53
|
+
the current code:
|
|
54
|
+
|
|
55
|
+
- The single-shard path builds in caller order while the multi-shard path sorts
|
|
56
|
+
by name. Function order changes the emitted bytes, so both branches carry
|
|
57
|
+
over as they are — normalising them is a byte change dressed as a cleanup.
|
|
58
|
+
- Capacity is judged at the *global* shard size while packing may use a smaller
|
|
59
|
+
ratcheted one, so a legal plan can hold more shards than `max_shards`. A
|
|
60
|
+
final "shard count ≤ max_shards" assertion would lock out apps that deploy
|
|
61
|
+
fine today.
|
|
62
|
+
|
|
63
|
+
Also deliberately out of scope for the new lane: Deno deployment targets,
|
|
64
|
+
existing-Worker reuse, incremental deploy state, and actors — though the engine
|
|
65
|
+
keeps its actor support for the legacy service that still uses it.
|
|
66
|
+
|
|
67
|
+
## Using it
|
|
68
|
+
|
|
69
|
+
```ts
|
|
70
|
+
import { bundle, bundleApp } from "@base44/functions-compiler";
|
|
71
|
+
|
|
72
|
+
const result = await bundle({
|
|
73
|
+
entry: "main.ts",
|
|
74
|
+
files: { "main.ts": "export default { fetch: () => new Response('hi') }" },
|
|
75
|
+
});
|
|
76
|
+
if (result.ok) console.log(result.module);
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
`bundleApp` compiles several functions into one combined module and reports
|
|
80
|
+
per-function status; a successful response can still contain failed functions,
|
|
81
|
+
so a caller that needs a whole-app build must reject those itself.
|
|
82
|
+
|
|
83
|
+
### Process isolation
|
|
84
|
+
|
|
85
|
+
`installFetchGuard()` blocks outbound `fetch` other than the dependency
|
|
86
|
+
resolution the compiler itself performs. Install it in the worker or child
|
|
87
|
+
process that runs a compile — not in a process that later needs the network.
|
|
88
|
+
|
|
89
|
+
### Diagnostics
|
|
90
|
+
|
|
91
|
+
The compiler ships no tracer and no service credentials. Hosts that want spans
|
|
92
|
+
or structured logs register their own, in the thread that runs the compile:
|
|
93
|
+
|
|
94
|
+
```ts
|
|
95
|
+
import { setCompilerTracer, setLogSink } from "@base44/functions-compiler";
|
|
96
|
+
|
|
97
|
+
setCompilerTracer({ withSpan, setSpanTags }); // e.g. a dd-trace adapter
|
|
98
|
+
setLogSink((level, event, fields) => myLogger[level](event, fields));
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Without a sink, `logEvent` writes the Datadog-shaped JSON line it always has.
|
|
102
|
+
|
|
103
|
+
## Layout
|
|
104
|
+
|
|
105
|
+
| Path | What it is |
|
|
106
|
+
|---|---|
|
|
107
|
+
| `src/bundler.ts` | Single-function and combined-app compilation, error attribution |
|
|
108
|
+
| `src/deno-bundle.ts`, `src/esbuild/` | esbuild execution and the resolver/virtual-module plugins |
|
|
109
|
+
| `src/worker-entry.ts`, `src/actor-compat.ts` | Generated worker entry and the Actor wrapper |
|
|
110
|
+
| `src/shim/`, `src/static-egress.ts` | Shim sources — esbuild inputs for `build:shim`, never imported |
|
|
111
|
+
| `src/runtime/`, `src/runtime-context.ts`, `src/private-data-sources/` | Compile-time assets read as **text** and injected into the user bundle |
|
|
112
|
+
|
|
113
|
+
The compile-time assets must stay TypeScript: the virtual plugins load them
|
|
114
|
+
with esbuild's `ts` loader. `scripts/copy-assets.ts` copies them into `lib/`
|
|
115
|
+
next to the compiled JS so the published package resolves them the same way.
|
|
116
|
+
|
|
117
|
+
**Do not reformat an asset.** Their text goes into the user's bundle, so
|
|
118
|
+
whitespace is part of the emitted worker bytes — running Biome over
|
|
119
|
+
`src/shim/`, `src/private-data-sources/`, `src/runtime/`, `runtime-context.ts`,
|
|
120
|
+
`static-egress.ts` or `static-egress-marker.ts` changes what every compiled
|
|
121
|
+
function hashes to. `biome.json` excludes those paths for that reason. The
|
|
122
|
+
`test/` directory is likewise held byte-identical to apper's copy until that
|
|
123
|
+
copy is deleted; it sits outside the repo's `packages/*/src` lint glob.
|
|
124
|
+
|
|
125
|
+
## Commands
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
bun run build:shim # regenerate dist/{deno-shim,activation-shim,actor}.mjs
|
|
129
|
+
bun run test # vitest (builds the shims first)
|
|
130
|
+
bun run typecheck # tsc --noEmit over src/, test/, scripts/
|
|
131
|
+
bun run build # shims + tsc -> lib/ + assets; what gets published
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
`exports` points only at `lib/`, so anything consuming this package — including
|
|
135
|
+
a sibling workspace — needs `bun run build` here first. There is deliberately
|
|
136
|
+
no source-resolving export condition: the tarball ships `lib/` alone, and a
|
|
137
|
+
second resolution path would mean two answers to "which code ran".
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
// GENERATED by scripts/build-shim.ts from src/shim/activation.ts — do not edit.
|
|
2
|
+
// Regenerate with `npm run build:shim`.
|
|
3
|
+
|
|
4
|
+
// src/shim/activation.ts
|
|
5
|
+
import { inflateSync } from "node:zlib";
|
|
6
|
+
import { setRuntimeManifest } from "base44:private-data-sources/runtime-manifest-store";
|
|
7
|
+
var NEEDS_ACTIVATION_HEADER = "X-Base44-Needs-Activation";
|
|
8
|
+
var RUNTIME_SECRETS_HEADER = "Base44-Runtime-Secrets";
|
|
9
|
+
var HKDF_INFO = "base44-runtime-secrets-v1";
|
|
10
|
+
var BACKEND_PUBKEY_LEN = 65;
|
|
11
|
+
var NONCE_LEN = 12;
|
|
12
|
+
var DATA_KEY_LEN = 32;
|
|
13
|
+
var WRAP_BLOCK_LEN = NONCE_LEN + DATA_KEY_LEN + 16;
|
|
14
|
+
var BLOB_BINDING_PREFIX = "BASE44_SECRETS_BLOB";
|
|
15
|
+
var BLOB_KEY_ID_LEN = 1;
|
|
16
|
+
var MANIFEST_KEY = "BASE44_PRIVATE_DATA_SOURCES";
|
|
17
|
+
var _subtle = crypto.subtle;
|
|
18
|
+
var _subtleGenerateKey = _subtle.generateKey.bind(_subtle);
|
|
19
|
+
var _subtleExportKey = _subtle.exportKey.bind(_subtle);
|
|
20
|
+
var _subtleImportKey = _subtle.importKey.bind(_subtle);
|
|
21
|
+
var _subtleDeriveBits = _subtle.deriveBits.bind(_subtle);
|
|
22
|
+
var _subtleDecrypt = _subtle.decrypt.bind(_subtle);
|
|
23
|
+
var _JSONparse = JSON.parse;
|
|
24
|
+
var _TextDecoder = TextDecoder;
|
|
25
|
+
var _TextEncoder = TextEncoder;
|
|
26
|
+
var _decodeUtf8 = TextDecoder.prototype.decode;
|
|
27
|
+
var _encodeUtf8 = TextEncoder.prototype.encode;
|
|
28
|
+
var _Uint8Array = Uint8Array;
|
|
29
|
+
var _atob = atob;
|
|
30
|
+
var _btoa = btoa;
|
|
31
|
+
var _DOMException = DOMException;
|
|
32
|
+
var _ObjectEntries = Object.entries;
|
|
33
|
+
var _Headers = Headers;
|
|
34
|
+
var _Request = Request;
|
|
35
|
+
var _Response = Response;
|
|
36
|
+
var _headersGet = Headers.prototype.get;
|
|
37
|
+
var _headersAppend = Headers.prototype.append;
|
|
38
|
+
var _headersEntries = Headers.prototype.entries;
|
|
39
|
+
var _iterNext = Object.getPrototypeOf(new Headers().entries()).next;
|
|
40
|
+
function accessor(proto, name) {
|
|
41
|
+
for (let o = proto; o; o = Object.getPrototypeOf(o)) {
|
|
42
|
+
const d = Object.getOwnPropertyDescriptor(o, name);
|
|
43
|
+
if (d?.get) return d.get;
|
|
44
|
+
}
|
|
45
|
+
return void 0;
|
|
46
|
+
}
|
|
47
|
+
var _reqHeaders = accessor(Request.prototype, "headers");
|
|
48
|
+
var _resHeaders = accessor(Response.prototype, "headers");
|
|
49
|
+
var _resStatus = accessor(Response.prototype, "status");
|
|
50
|
+
var _resStatusText = accessor(Response.prototype, "statusText");
|
|
51
|
+
var _resBody = accessor(Response.prototype, "body");
|
|
52
|
+
var _resWebSocket = accessor(Response.prototype, "webSocket");
|
|
53
|
+
var NEEDS_ACTIVATION_HEADER_LC = "x-base44-needs-activation";
|
|
54
|
+
var RUNTIME_SECRETS_HEADER_LC = "base44-runtime-secrets";
|
|
55
|
+
function headersWithout(src, dropLowercased) {
|
|
56
|
+
const out = new _Headers();
|
|
57
|
+
const it = _headersEntries.call(src);
|
|
58
|
+
for (; ; ) {
|
|
59
|
+
const step = _iterNext.call(it);
|
|
60
|
+
if (step.done) break;
|
|
61
|
+
if (step.value[0] !== dropLowercased) _headersAppend.call(out, step.value[0], step.value[1]);
|
|
62
|
+
}
|
|
63
|
+
return out;
|
|
64
|
+
}
|
|
65
|
+
var keyPairPromise = null;
|
|
66
|
+
var installed = false;
|
|
67
|
+
var pendingInstall = null;
|
|
68
|
+
var installChain = Promise.resolve();
|
|
69
|
+
function getKeyPair() {
|
|
70
|
+
keyPairPromise ??= _subtleGenerateKey(
|
|
71
|
+
{ name: "ECDH", namedCurve: "P-256" },
|
|
72
|
+
false,
|
|
73
|
+
["deriveBits"]
|
|
74
|
+
).catch((e) => {
|
|
75
|
+
keyPairPromise = null;
|
|
76
|
+
throw e;
|
|
77
|
+
});
|
|
78
|
+
return keyPairPromise;
|
|
79
|
+
}
|
|
80
|
+
async function needsActivationResponse() {
|
|
81
|
+
const { publicKey } = await getKeyPair();
|
|
82
|
+
const raw = await _subtleExportKey("raw", publicKey);
|
|
83
|
+
return new Response(null, {
|
|
84
|
+
status: 503,
|
|
85
|
+
headers: {
|
|
86
|
+
[NEEDS_ACTIVATION_HEADER]: toBase64Url(new _Uint8Array(raw)),
|
|
87
|
+
"Cache-Control": "no-store"
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
async function install(envelopeB64, env) {
|
|
92
|
+
const envelope = fromBase64Url(envelopeB64);
|
|
93
|
+
const backendPub = envelope.slice(0, BACKEND_PUBKEY_LEN);
|
|
94
|
+
const recipientCount = envelope[BACKEND_PUBKEY_LEN];
|
|
95
|
+
const { privateKey } = await getKeyPair();
|
|
96
|
+
const peer = await _subtleImportKey(
|
|
97
|
+
"raw",
|
|
98
|
+
backendPub,
|
|
99
|
+
{ name: "ECDH", namedCurve: "P-256" },
|
|
100
|
+
false,
|
|
101
|
+
[]
|
|
102
|
+
);
|
|
103
|
+
const shared = await _subtleDeriveBits({ name: "ECDH", public: peer }, privateKey, 256);
|
|
104
|
+
const hkdfKey = await _subtleImportKey("raw", shared, "HKDF", false, ["deriveBits"]);
|
|
105
|
+
const keyBits = await _subtleDeriveBits(
|
|
106
|
+
{
|
|
107
|
+
name: "HKDF",
|
|
108
|
+
hash: "SHA-256",
|
|
109
|
+
salt: new _Uint8Array(0),
|
|
110
|
+
info: _encodeUtf8.call(new _TextEncoder(), HKDF_INFO)
|
|
111
|
+
},
|
|
112
|
+
hkdfKey,
|
|
113
|
+
256
|
|
114
|
+
);
|
|
115
|
+
const kek = await _subtleImportKey("raw", keyBits, "AES-GCM", false, ["decrypt"]);
|
|
116
|
+
const appId = env?.BASE44_APP_ID;
|
|
117
|
+
const aad = _encodeUtf8.call(new _TextEncoder(), typeof appId === "string" ? appId : "");
|
|
118
|
+
let dataKeyBytes = null;
|
|
119
|
+
for (let i = 0; i < recipientCount && dataKeyBytes === null; i++) {
|
|
120
|
+
const blockStart = BACKEND_PUBKEY_LEN + 1 + i * WRAP_BLOCK_LEN;
|
|
121
|
+
const wrapNonce = envelope.slice(blockStart, blockStart + NONCE_LEN);
|
|
122
|
+
const wrapped = envelope.slice(blockStart + NONCE_LEN, blockStart + WRAP_BLOCK_LEN);
|
|
123
|
+
try {
|
|
124
|
+
dataKeyBytes = await _subtleDecrypt(
|
|
125
|
+
{ name: "AES-GCM", iv: wrapNonce, additionalData: aad },
|
|
126
|
+
kek,
|
|
127
|
+
wrapped
|
|
128
|
+
);
|
|
129
|
+
} catch {
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
if (dataKeyBytes === null) {
|
|
133
|
+
throw new _DOMException("no wrap block for this isolate", "OperationError");
|
|
134
|
+
}
|
|
135
|
+
const bindings = env ?? {};
|
|
136
|
+
let blobB64 = "";
|
|
137
|
+
for (let i = 0; ; i++) {
|
|
138
|
+
const part = bindings[`${BLOB_BINDING_PREFIX}_${i}`];
|
|
139
|
+
if (typeof part !== "string") break;
|
|
140
|
+
blobB64 += part;
|
|
141
|
+
}
|
|
142
|
+
if (blobB64 === "") {
|
|
143
|
+
throw new _DOMException("no secret blob bindings on this script", "OperationError");
|
|
144
|
+
}
|
|
145
|
+
const blob = fromBase64Url(blobB64);
|
|
146
|
+
const blobNonce = blob.slice(BLOB_KEY_ID_LEN, BLOB_KEY_ID_LEN + NONCE_LEN);
|
|
147
|
+
const blobCiphertext = blob.slice(BLOB_KEY_ID_LEN + NONCE_LEN);
|
|
148
|
+
const dataKey = await _subtleImportKey("raw", dataKeyBytes, "AES-GCM", false, ["decrypt"]);
|
|
149
|
+
const plaintext = await _subtleDecrypt(
|
|
150
|
+
{ name: "AES-GCM", iv: blobNonce, additionalData: aad },
|
|
151
|
+
dataKey,
|
|
152
|
+
blobCiphertext
|
|
153
|
+
);
|
|
154
|
+
const payload = _JSONparse(
|
|
155
|
+
_decodeUtf8.call(new _TextDecoder(), inflateSync(new _Uint8Array(plaintext)))
|
|
156
|
+
);
|
|
157
|
+
const secrets = payload && typeof payload === "object" && payload.secrets ? payload.secrets : {};
|
|
158
|
+
const manifestValue = secrets[MANIFEST_KEY];
|
|
159
|
+
setRuntimeManifest(typeof manifestValue === "string" ? manifestValue : "");
|
|
160
|
+
for (const [key, value] of _ObjectEntries(secrets)) {
|
|
161
|
+
if (key !== MANIFEST_KEY && typeof value === "string") process.env[key] = value;
|
|
162
|
+
}
|
|
163
|
+
installed = true;
|
|
164
|
+
}
|
|
165
|
+
function installOnce(envelopeB64, env) {
|
|
166
|
+
if (installed) return Promise.resolve();
|
|
167
|
+
const afterPrevious = installChain.then(void 0, () => {
|
|
168
|
+
});
|
|
169
|
+
const run = afterPrevious.then(() => installed ? void 0 : install(envelopeB64, env));
|
|
170
|
+
installChain = run.then(void 0, () => {
|
|
171
|
+
});
|
|
172
|
+
pendingInstall = run;
|
|
173
|
+
const clear = () => {
|
|
174
|
+
if (pendingInstall === run) pendingInstall = null;
|
|
175
|
+
};
|
|
176
|
+
run.then(clear, clear);
|
|
177
|
+
return run;
|
|
178
|
+
}
|
|
179
|
+
async function ensureActivation(request, env) {
|
|
180
|
+
const header = _headersGet.call(_reqHeaders.call(request), RUNTIME_SECRETS_HEADER);
|
|
181
|
+
if (header) {
|
|
182
|
+
try {
|
|
183
|
+
await installOnce(header, env);
|
|
184
|
+
return null;
|
|
185
|
+
} catch (e) {
|
|
186
|
+
console.error(
|
|
187
|
+
`Base44 runtime-secrets activation failed, re-signaling: ${e?.name ?? "error"}`
|
|
188
|
+
);
|
|
189
|
+
return needsActivationResponse();
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
if (installed) return null;
|
|
193
|
+
if (pendingInstall) {
|
|
194
|
+
try {
|
|
195
|
+
await pendingInstall;
|
|
196
|
+
} catch {
|
|
197
|
+
}
|
|
198
|
+
if (installed) return null;
|
|
199
|
+
}
|
|
200
|
+
return needsActivationResponse();
|
|
201
|
+
}
|
|
202
|
+
function withoutRuntimeSecretsHeader(request) {
|
|
203
|
+
const raw = _reqHeaders.call(request);
|
|
204
|
+
if (_headersGet.call(raw, RUNTIME_SECRETS_HEADER) === null) return request;
|
|
205
|
+
return new _Request(request, { headers: headersWithout(raw, RUNTIME_SECRETS_HEADER_LC) });
|
|
206
|
+
}
|
|
207
|
+
function withoutActivationSignal(response) {
|
|
208
|
+
const raw = _resHeaders.call(response);
|
|
209
|
+
if (_headersGet.call(raw, NEEDS_ACTIVATION_HEADER) === null) return response;
|
|
210
|
+
return new _Response(_resBody.call(response), {
|
|
211
|
+
status: _resStatus.call(response),
|
|
212
|
+
statusText: _resStatusText.call(response),
|
|
213
|
+
headers: headersWithout(raw, NEEDS_ACTIVATION_HEADER_LC),
|
|
214
|
+
// Preserved or a 101 upgrade would fail to reconstruct.
|
|
215
|
+
webSocket: _resWebSocket ? _resWebSocket.call(response) : void 0
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
function toBase64Url(bytes) {
|
|
219
|
+
let bin = "";
|
|
220
|
+
for (const b of bytes) bin += String.fromCharCode(b);
|
|
221
|
+
return _btoa(bin).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
222
|
+
}
|
|
223
|
+
function fromBase64Url(value) {
|
|
224
|
+
const b64 = value.replace(/-/g, "+").replace(/_/g, "/");
|
|
225
|
+
const padded = b64 + "=".repeat((4 - b64.length % 4) % 4);
|
|
226
|
+
const bin = _atob(padded);
|
|
227
|
+
const bytes = new _Uint8Array(bin.length);
|
|
228
|
+
for (let i = 0; i < bin.length; i++) bytes[i] = bin.charCodeAt(i);
|
|
229
|
+
return bytes;
|
|
230
|
+
}
|
|
231
|
+
export {
|
|
232
|
+
NEEDS_ACTIVATION_HEADER,
|
|
233
|
+
RUNTIME_SECRETS_HEADER,
|
|
234
|
+
ensureActivation,
|
|
235
|
+
withoutActivationSignal,
|
|
236
|
+
withoutRuntimeSecretsHeader
|
|
237
|
+
};
|