@almadar/shell-node 0.1.0 → 1.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/dist/OrbitalServerRuntime.d.ts +46 -267
- package/dist/OrbitalServerRuntime.js +3 -3
- package/dist/chunk-34JOE763.js +845 -0
- package/dist/{chunk-QYAPNUBH.js → chunk-7QE32QQR.js} +107 -182
- package/dist/{chunk-UBZT5LDW.js → chunk-EEYGL7AB.js} +3 -13
- package/dist/{chunk-BJA6GYC5.js → chunk-HXA6OB35.js} +65 -55
- package/dist/{chunk-WZFQ7T7V.js → chunk-LNEOE5TD.js} +2 -2
- package/dist/chunk-VQVAHUAX.js +183 -0
- package/dist/createProgramHandlers.js +5 -5
- package/dist/index.d.ts +97 -61
- package/dist/index.js +7 -7
- package/dist/kernel-loader-3JR6LJV5.js +1 -0
- package/dist/{kernel-workspace-host-CU56iOlt.d.ts → kernel-workspace-host-cT9JGJur.d.ts} +7 -12
- package/dist/kernelWorkspace.d.ts +1 -1
- package/dist/kernelWorkspace.js +3 -3
- package/dist/program-6DB6LK5B.js +2 -0
- package/package.json +9 -7
- package/dist/chunk-23YAOI6P.js +0 -42
- package/dist/chunk-A2TIXOLJ.js +0 -1326
- package/dist/kernel-loader-24KWM5C7.js +0 -1
- package/dist/program-35OTIG6Y.js +0 -2
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import { installNodeHostPorts } from './chunk-
|
|
2
|
-
import { loadNativeKernelModule, resolveNativeAddon, loadKernelModule
|
|
1
|
+
import { installNodeHostPorts, createNodeTokenPost } from './chunk-VQVAHUAX.js';
|
|
2
|
+
import { loadNativeKernelModule, resolveNativeAddon, loadKernelModule } from './chunk-EEYGL7AB.js';
|
|
3
3
|
import { workspaceOwnerSegment } from './chunk-BWMLDDCL.js';
|
|
4
4
|
import { mkdirSync, realpathSync, mkdtempSync, writeFileSync, rmSync, constants as constants$1 } from 'fs';
|
|
5
5
|
import { constants, homedir, tmpdir, loadavg, uptime, machine, version, release, hostname, type, userInfo } from 'os';
|
|
6
|
-
import { dirname,
|
|
6
|
+
import { dirname, resolve, join } from 'path';
|
|
7
7
|
import { spawn } from 'child_process';
|
|
8
8
|
import { createRequire } from 'module';
|
|
9
|
-
import {
|
|
9
|
+
import { createSecretPorts, NativeMemoryPersistenceAdapter, kernelOsGrants, InFlightCalls, KernelEngine, dispatchInbound, anchoredGrants, expandAnchor } from '@almadar/shell-runtime';
|
|
10
10
|
import { resolveOrbBinary } from '@almadar/core/behavior-package';
|
|
11
11
|
import { tickEventKey } from '@almadar/core';
|
|
12
12
|
import { lstat, chmod, stat, readlink, symlink, link, unlink, rename, copyFile, open, mkdir, readdir, rm, rmdir, access, chown } from 'fs/promises';
|
|
@@ -1140,6 +1140,7 @@ var SOCKET_HIGH_WATER = 1024 * 1024;
|
|
|
1140
1140
|
var NET_OPS = /* @__PURE__ */ new Set([
|
|
1141
1141
|
"os/tcp-connect",
|
|
1142
1142
|
"os/tcp-listen",
|
|
1143
|
+
"os/tls-upgrade",
|
|
1143
1144
|
"os/send",
|
|
1144
1145
|
"os/recv",
|
|
1145
1146
|
"os/udp-bind",
|
|
@@ -1147,7 +1148,8 @@ var NET_OPS = /* @__PURE__ */ new Set([
|
|
|
1147
1148
|
"os/recvfrom",
|
|
1148
1149
|
"os/dns-resolve",
|
|
1149
1150
|
"os/shutdown",
|
|
1150
|
-
"os/watch-port"
|
|
1151
|
+
"os/watch-port",
|
|
1152
|
+
"os/fetch"
|
|
1151
1153
|
]);
|
|
1152
1154
|
function isNetOp(op) {
|
|
1153
1155
|
return NET_OPS.has(op);
|
|
@@ -1231,6 +1233,8 @@ var NetOps = class {
|
|
|
1231
1233
|
throw invalid(op, "a stream needs a key and a call site");
|
|
1232
1234
|
case "os/tcp-connect":
|
|
1233
1235
|
return this.tcpConnect(op, args);
|
|
1236
|
+
case "os/tls-upgrade":
|
|
1237
|
+
throw osFailure("unsupported", op, "a kernel op: the kernel owns TLS and a host implements none");
|
|
1234
1238
|
case "os/send":
|
|
1235
1239
|
return this.send(op, args);
|
|
1236
1240
|
case "os/recv":
|
|
@@ -1245,6 +1249,8 @@ var NetOps = class {
|
|
|
1245
1249
|
return this.dnsResolve(op, args);
|
|
1246
1250
|
case "os/shutdown":
|
|
1247
1251
|
return this.shutdown(op, args);
|
|
1252
|
+
case "os/fetch":
|
|
1253
|
+
throw osFailure("unsupported", op, "a browser host performs a fetch; this host speaks the protocol over os/tcp-connect and os/tls-upgrade");
|
|
1248
1254
|
default:
|
|
1249
1255
|
throw osFailure("unsupported", op, "streaming host not implemented");
|
|
1250
1256
|
}
|
|
@@ -1569,7 +1575,8 @@ var ProcessOps = class {
|
|
|
1569
1575
|
case "os/getenv": {
|
|
1570
1576
|
const name = argStr(args, 0, op);
|
|
1571
1577
|
this.envGranted(op, name);
|
|
1572
|
-
|
|
1578
|
+
const value = this.lookupEnv(name);
|
|
1579
|
+
return value === null ? {} : { value };
|
|
1573
1580
|
}
|
|
1574
1581
|
case "os/setenv":
|
|
1575
1582
|
case "os/unsetenv":
|
|
@@ -1722,9 +1729,8 @@ var ProcessOps = class {
|
|
|
1722
1729
|
const op = "os/kill";
|
|
1723
1730
|
let found;
|
|
1724
1731
|
if (typeof value === "string") found = SIGNAL_SET.find(([name]) => name === value)?.[1];
|
|
1725
|
-
else if (typeof value === "number" && Number.isInteger(value)) found = SIGNAL_SET.find(([, number]) => number === value)?.[1];
|
|
1726
1732
|
if (found === void 0) {
|
|
1727
|
-
throw invalid(op, "signal must be one of TERM, KILL, INT, HUP, QUIT, USR1, USR2, STOP, CONT
|
|
1733
|
+
throw invalid(op, "signal must be one of TERM, KILL, INT, HUP, QUIT, USR1, USR2, STOP, CONT");
|
|
1728
1734
|
}
|
|
1729
1735
|
return found;
|
|
1730
1736
|
}
|
|
@@ -1873,6 +1879,8 @@ var SysOps = class {
|
|
|
1873
1879
|
};
|
|
1874
1880
|
var log = createLogger("almadar:host:os");
|
|
1875
1881
|
var DEVICE_OPS = /* @__PURE__ */ new Set(["os/mmio-read", "os/mmio-write", "os/irq-wait", "os/irq-ack"]);
|
|
1882
|
+
var isGpuOp = (op) => op.startsWith("gpu/");
|
|
1883
|
+
var noGpu = (op) => osFailure("unsupported", op, "this host has no gpu");
|
|
1876
1884
|
function failureOf(op, raised) {
|
|
1877
1885
|
if (raised instanceof OsFailure) return raised.error;
|
|
1878
1886
|
return { kind: "io", message: `${op}: ${raised instanceof Error ? raised.message : String(raised)}` };
|
|
@@ -1882,22 +1890,23 @@ var NodeOsHost = class {
|
|
|
1882
1890
|
this.given = given;
|
|
1883
1891
|
this.anchors = anchors;
|
|
1884
1892
|
this.state = new OsState(anchors);
|
|
1885
|
-
const grants = anchoredGrants(given, anchors);
|
|
1886
|
-
this.fs = new FsOps(this.state, grants);
|
|
1887
|
-
this.process = new ProcessOps(this.state, grants);
|
|
1888
|
-
this.net = new NetOps(this.state, grants);
|
|
1889
|
-
this.sys = new SysOps(grants);
|
|
1890
1893
|
}
|
|
1891
1894
|
given;
|
|
1892
1895
|
anchors;
|
|
1893
1896
|
state;
|
|
1894
|
-
|
|
1895
|
-
process;
|
|
1896
|
-
net;
|
|
1897
|
-
sys;
|
|
1897
|
+
ops = /* @__PURE__ */ new Map();
|
|
1898
1898
|
placed = false;
|
|
1899
1899
|
/** The listener handle of each open stream, by its key. */
|
|
1900
1900
|
streams = /* @__PURE__ */ new Map();
|
|
1901
|
+
/** The ops that check `orbital`'s grants (the app level alone with none): every grant decision is the kernel's, asked with the orbital. */
|
|
1902
|
+
opsFor(orbital) {
|
|
1903
|
+
const held = this.ops.get(orbital);
|
|
1904
|
+
if (held !== void 0) return held;
|
|
1905
|
+
const grants = anchoredGrants({ ...this.given, allows: (need) => this.given.allows(need, orbital) }, this.anchors);
|
|
1906
|
+
const made = { fs: new FsOps(this.state, grants), process: new ProcessOps(this.state, grants), net: new NetOps(this.state, grants), sys: new SysOps(grants) };
|
|
1907
|
+
this.ops.set(orbital, made);
|
|
1908
|
+
return made;
|
|
1909
|
+
}
|
|
1901
1910
|
/** The call's arguments with every anchored part resolved by the kernel, the program's anchors placed on the first call. */
|
|
1902
1911
|
resolved(op, args) {
|
|
1903
1912
|
if (!this.placed) {
|
|
@@ -1908,47 +1917,51 @@ var NodeOsHost = class {
|
|
|
1908
1917
|
if ("error" in resolved) throw new OsFailure(resolved.error);
|
|
1909
1918
|
return resolved.ok;
|
|
1910
1919
|
}
|
|
1911
|
-
async dispatch(op, given) {
|
|
1920
|
+
async dispatch(op, given, orbital) {
|
|
1921
|
+
if (isGpuOp(op)) throw noGpu(op);
|
|
1912
1922
|
const args = this.resolved(op, given);
|
|
1923
|
+
const { fs, process: process2, net, sys } = this.opsFor(orbital);
|
|
1913
1924
|
if (op === "os/close") {
|
|
1914
|
-
if (
|
|
1925
|
+
if (fs.closeOwned(args) || net.closeOwned(args)) return {};
|
|
1915
1926
|
throw osFailure("closed", op, "not an open handle");
|
|
1916
1927
|
}
|
|
1917
|
-
if (isFsOp(op)) return
|
|
1918
|
-
if (isProcessOp(op)) return
|
|
1919
|
-
if (isNetOp(op)) return
|
|
1920
|
-
if (isSysOp(op)) return
|
|
1928
|
+
if (isFsOp(op)) return fs.run(op, args);
|
|
1929
|
+
if (isProcessOp(op)) return process2.run(op, args);
|
|
1930
|
+
if (isNetOp(op)) return net.run(op, args);
|
|
1931
|
+
if (isSysOp(op)) return sys.run(op);
|
|
1921
1932
|
if (DEVICE_OPS.has(op)) throw osFailure("unsupported", op, "this host has no devices");
|
|
1922
1933
|
throw osFailure("unsupported", op, "this host does not implement the operation yet");
|
|
1923
1934
|
}
|
|
1924
|
-
async answer(op, args) {
|
|
1935
|
+
async answer(op, args, orbital) {
|
|
1925
1936
|
try {
|
|
1926
|
-
return { ok: await this.dispatch(op, args) };
|
|
1937
|
+
return { ok: await this.dispatch(op, args, orbital) };
|
|
1927
1938
|
} catch (raised) {
|
|
1928
1939
|
return { error: failureOf(op, raised) };
|
|
1929
1940
|
}
|
|
1930
1941
|
}
|
|
1931
|
-
deferral(op, args) {
|
|
1942
|
+
deferral(op, args, orbital) {
|
|
1943
|
+
const { fs, process: process2, net } = this.opsFor(orbital);
|
|
1932
1944
|
switch (op) {
|
|
1933
1945
|
case "os/wait":
|
|
1934
|
-
return
|
|
1946
|
+
return process2.waitLater(args);
|
|
1935
1947
|
case "os/read":
|
|
1936
|
-
return
|
|
1948
|
+
return fs.readLater(op, args);
|
|
1937
1949
|
case "os/send":
|
|
1938
|
-
return
|
|
1950
|
+
return net.sendLater(op, args);
|
|
1939
1951
|
case "os/recv":
|
|
1940
|
-
return
|
|
1952
|
+
return net.recvLater(op, args);
|
|
1941
1953
|
case "os/recvfrom":
|
|
1942
|
-
return
|
|
1954
|
+
return net.recvfromLater(op, args);
|
|
1943
1955
|
default:
|
|
1944
1956
|
throw osFailure("unsupported", op, "this operation does not defer its completion");
|
|
1945
1957
|
}
|
|
1946
1958
|
}
|
|
1947
1959
|
/** `Completions::run_later`: the checks fail in place, the wait runs in the background and its outcome goes to `deliver` unless the key is cancelled first. */
|
|
1948
|
-
defer(op, args, key, deliver) {
|
|
1960
|
+
defer(op, args, key, deliver, orbital) {
|
|
1949
1961
|
let blocking;
|
|
1950
1962
|
try {
|
|
1951
|
-
|
|
1963
|
+
if (isGpuOp(op)) throw noGpu(op);
|
|
1964
|
+
blocking = this.deferral(op, this.resolved(op, args), orbital);
|
|
1952
1965
|
} catch (raised) {
|
|
1953
1966
|
return { error: failureOf(op, raised) };
|
|
1954
1967
|
}
|
|
@@ -1967,11 +1980,11 @@ var NodeOsHost = class {
|
|
|
1967
1980
|
return { ok: null };
|
|
1968
1981
|
}
|
|
1969
1982
|
/** A keyed stream (EXEC-QUEUE-12): `os/tcp-listen` binds and answers in place, then each connection reaches `message`. */
|
|
1970
|
-
async stream(op, args, key, message, fail2) {
|
|
1983
|
+
async stream(op, args, key, message, fail2, orbital) {
|
|
1971
1984
|
try {
|
|
1972
1985
|
if (op !== "os/tcp-listen") throw osFailure("unsupported", op, "this host streams only os/tcp-listen");
|
|
1973
1986
|
if (this.streams.has(key)) throw invalid(op, `key ${key} already has a stream open`);
|
|
1974
|
-
const answer = await this.net.listen(op, this.resolved(op, args), message, (error) => {
|
|
1987
|
+
const answer = await this.opsFor(orbital).net.listen(op, this.resolved(op, args), message, (error) => {
|
|
1975
1988
|
this.streams.delete(key);
|
|
1976
1989
|
fail2(error);
|
|
1977
1990
|
});
|
|
@@ -1985,7 +1998,7 @@ var NodeOsHost = class {
|
|
|
1985
1998
|
const listener = this.streams.get(key);
|
|
1986
1999
|
if (listener !== void 0) {
|
|
1987
2000
|
this.streams.delete(key);
|
|
1988
|
-
this.net.stopListening(listener);
|
|
2001
|
+
this.opsFor(void 0).net.stopListening(listener);
|
|
1989
2002
|
return true;
|
|
1990
2003
|
}
|
|
1991
2004
|
return this.state.completions.cancel(key);
|
|
@@ -1997,7 +2010,7 @@ var NodeOsHost = class {
|
|
|
1997
2010
|
function processAnchors() {
|
|
1998
2011
|
const env = {};
|
|
1999
2012
|
for (const [name, value] of Object.entries(process.env)) if (value !== void 0) env[name] = value;
|
|
2000
|
-
return { home: homedir(), start: process.cwd(), exeDir: dirname(process.execPath), env };
|
|
2013
|
+
return { home: homedir(), start: process.cwd(), exeDir: dirname(process.execPath), exe: process.execPath, env };
|
|
2001
2014
|
}
|
|
2002
2015
|
function createNodeOsHost(grants, options = {}) {
|
|
2003
2016
|
return new NodeOsHost(grants, options.anchors ?? processAnchors());
|
|
@@ -2034,17 +2047,17 @@ async function resolveProgramFile(path, cwd = dirname(resolve(path)), orb = reso
|
|
|
2034
2047
|
});
|
|
2035
2048
|
}
|
|
2036
2049
|
var KernelProgram = class _KernelProgram {
|
|
2037
|
-
constructor(engine, os, schema,
|
|
2050
|
+
constructor(engine, os, schema, secretPorts, persistence) {
|
|
2038
2051
|
this.engine = engine;
|
|
2039
2052
|
this.os = os;
|
|
2040
2053
|
this.schema = schema;
|
|
2041
|
-
this.
|
|
2054
|
+
this.secretPorts = secretPorts;
|
|
2042
2055
|
this.persistence = persistence;
|
|
2043
2056
|
}
|
|
2044
2057
|
engine;
|
|
2045
2058
|
os;
|
|
2046
2059
|
schema;
|
|
2047
|
-
|
|
2060
|
+
secretPorts;
|
|
2048
2061
|
persistence;
|
|
2049
2062
|
static async open(schema, options) {
|
|
2050
2063
|
const languageFrom = { languageFrom: options.languageFrom };
|
|
@@ -2053,20 +2066,17 @@ var KernelProgram = class _KernelProgram {
|
|
|
2053
2066
|
const kernelDir = addon === void 0 ? options.kernelDir ?? resolveKernelDir() : "";
|
|
2054
2067
|
const kernel = addon ?? await loadKernelModule(kernelDir, languageFrom);
|
|
2055
2068
|
installNodeHostPorts();
|
|
2056
|
-
const http = createHttpPorts({
|
|
2057
|
-
kernel: addon !== void 0 ? async () => addon : () => loadHttpKernel(kernelDir, languageFrom),
|
|
2058
|
-
...options.http,
|
|
2059
|
-
egress: schema.egress ?? []
|
|
2060
|
-
});
|
|
2061
|
-
const persistence = new NativeMemoryPersistenceAdapter(new kernel.MemoryStore());
|
|
2062
|
-
for (const [entityType, rows] of Object.entries(options.seed ?? {})) {
|
|
2063
|
-
for (const row of rows) await persistence.writeWhere({ kind: "upsert", entityType, data: row });
|
|
2064
|
-
}
|
|
2065
2069
|
let engine;
|
|
2066
2070
|
const requireEngine = () => {
|
|
2067
2071
|
if (engine === void 0) throw new Error("KernelProgram: an os ask arrived before the program opened");
|
|
2068
2072
|
return engine;
|
|
2069
2073
|
};
|
|
2074
|
+
const tokenPost = createNodeTokenPost({ egressAllows: (url) => requireEngine().egressAllows(url), isPublicAddress: (ip) => kernel.isPublicAddress(ip) });
|
|
2075
|
+
const secretPorts = createSecretPorts({ tokenPost, ...options.secretPorts });
|
|
2076
|
+
const persistence = new NativeMemoryPersistenceAdapter(new kernel.MemoryStore());
|
|
2077
|
+
for (const [entityType, rows] of Object.entries(options.seed ?? {})) {
|
|
2078
|
+
for (const row of rows) await persistence.writeWhere({ kind: "upsert", entityType, data: row });
|
|
2079
|
+
}
|
|
2070
2080
|
const os = options.os === true ? createNodeOsHost(kernelOsGrants(kernel, requireEngine)) : void 0;
|
|
2071
2081
|
const ports = {
|
|
2072
2082
|
persistence,
|
|
@@ -2078,18 +2088,18 @@ var KernelProgram = class _KernelProgram {
|
|
|
2078
2088
|
}, read: async () => [] }),
|
|
2079
2089
|
deliverLive: () => void 0,
|
|
2080
2090
|
deferCallOutcome: () => void 0,
|
|
2081
|
-
|
|
2091
|
+
secretPorts,
|
|
2082
2092
|
...os !== void 0 ? { os } : {}
|
|
2083
2093
|
};
|
|
2084
2094
|
engine = KernelEngine.open(kernel, schema, ports);
|
|
2085
|
-
return new _KernelProgram(engine, os, schema,
|
|
2095
|
+
return new _KernelProgram(engine, os, schema, secretPorts, persistence);
|
|
2086
2096
|
}
|
|
2087
|
-
/** Fire `event` at the orbital as `user` (the program's `@user`), wait for its whole cascade (every
|
|
2097
|
+
/** Fire `event` at the orbital as `user` (the program's `@user`), wait for its whole cascade (every secret ask included), and return what it emitted. */
|
|
2088
2098
|
async dispatch(orbital, event, payload = {}, targetTrait, user) {
|
|
2089
2099
|
const response = await this.engine.evaluate(
|
|
2090
2100
|
orbital,
|
|
2091
2101
|
{ event, payload, ...targetTrait !== void 0 ? { targetTrait } : {}, ...user !== void 0 ? { user } : {} },
|
|
2092
|
-
{ orbital
|
|
2102
|
+
{ orbital }
|
|
2093
2103
|
);
|
|
2094
2104
|
return {
|
|
2095
2105
|
success: response.success,
|
|
@@ -2110,7 +2120,7 @@ var KernelProgram = class _KernelProgram {
|
|
|
2110
2120
|
}
|
|
2111
2121
|
/** Deliver an `/api/hooks/<name>` request to the program and return the answer it gave (EXEC-INBOUND-1). */
|
|
2112
2122
|
async deliverInbound(name, delivery) {
|
|
2113
|
-
return dispatchInbound(this.
|
|
2123
|
+
return dispatchInbound(this.engine, name, delivery, (orbital, request) => this.engine.evaluate(orbital, request, { orbital }), (credential) => this.secretPorts.secrets.get(credential, void 0));
|
|
2114
2124
|
}
|
|
2115
2125
|
/** The rows the host's in-memory store holds for `entity` (empty when the native kernel keeps its own `store`). */
|
|
2116
2126
|
async rows(entity) {
|
|
@@ -2216,4 +2226,4 @@ function kernelWorkspaceHost(options) {
|
|
|
2216
2226
|
};
|
|
2217
2227
|
}
|
|
2218
2228
|
|
|
2219
|
-
export {
|
|
2229
|
+
export { KernelProgram, createNodeOsHost, emitPayload, kernelWorkspaceHost, processAnchors, resolveProgramFile, workspaceBucketFromEnv, workspacesRoot };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { workspacesRoot, kernelWorkspaceHost, workspaceBucketFromEnv } from './chunk-
|
|
2
|
-
import { runProgramEffect } from './chunk-
|
|
1
|
+
import { workspacesRoot, kernelWorkspaceHost, workspaceBucketFromEnv } from './chunk-HXA6OB35.js';
|
|
2
|
+
import { runProgramEffect } from './chunk-7QE32QQR.js';
|
|
3
3
|
import { installedWorkspaceHost, installWorkspaceHost } from './chunk-BWMLDDCL.js';
|
|
4
4
|
|
|
5
5
|
// src/program/createProgramHandlers.ts
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import { readFile, mkdir, writeFile, rename } from 'fs/promises';
|
|
2
|
+
import { join, dirname } from 'path';
|
|
3
|
+
import { EntityRowSchema, runRowWrite } from '@almadar/core';
|
|
4
|
+
import { AsyncLocalStorage } from 'async_hooks';
|
|
5
|
+
import { installCredentialScopeStorage, CREDENTIAL_MASTER_KEY_ENV, CREDENTIAL_PREVIOUS_MASTER_KEY_ENV, CredentialVault, installCredentialStore } from '@almadar/shell-runtime';
|
|
6
|
+
import { lookup } from 'dns/promises';
|
|
7
|
+
import { request } from 'https';
|
|
8
|
+
import { isIP } from 'net';
|
|
9
|
+
|
|
10
|
+
// src/credential-rows.ts
|
|
11
|
+
var CREDENTIALS_FILE_ENV = "ALMADAR_CREDENTIALS_FILE";
|
|
12
|
+
var DEFAULT_CREDENTIALS_FILE = ".almadar/dev-credentials.json";
|
|
13
|
+
var CREDENTIAL_ROWS_ENTITY = "AlmadarIntegrationCredential";
|
|
14
|
+
function credentialsFilePath(env = process.env, cwd = process.cwd()) {
|
|
15
|
+
const named = env[CREDENTIALS_FILE_ENV];
|
|
16
|
+
return named !== void 0 && named !== "" ? named : join(cwd, DEFAULT_CREDENTIALS_FILE);
|
|
17
|
+
}
|
|
18
|
+
var gates = /* @__PURE__ */ new Map();
|
|
19
|
+
function gateOf(path) {
|
|
20
|
+
const held = gates.get(path);
|
|
21
|
+
if (held !== void 0) return held;
|
|
22
|
+
const gate = { tail: Promise.resolve() };
|
|
23
|
+
gates.set(path, gate);
|
|
24
|
+
return gate;
|
|
25
|
+
}
|
|
26
|
+
function isMissing(error) {
|
|
27
|
+
return "code" in error && error.code === "ENOENT";
|
|
28
|
+
}
|
|
29
|
+
function fileCredentialRows(path) {
|
|
30
|
+
const gate = gateOf(path);
|
|
31
|
+
const read = async () => {
|
|
32
|
+
let text;
|
|
33
|
+
try {
|
|
34
|
+
text = await readFile(path, "utf8");
|
|
35
|
+
} catch (error) {
|
|
36
|
+
if (error instanceof Error && isMissing(error)) return [];
|
|
37
|
+
throw error;
|
|
38
|
+
}
|
|
39
|
+
let parsed;
|
|
40
|
+
try {
|
|
41
|
+
parsed = JSON.parse(text);
|
|
42
|
+
} catch (error) {
|
|
43
|
+
throw new Error(`credential file ${path} is not JSON: ${error instanceof Error ? error.message : String(error)}`);
|
|
44
|
+
}
|
|
45
|
+
const rows = EntityRowSchema.array().safeParse(parsed);
|
|
46
|
+
if (!rows.success) throw new Error(`credential file ${path} is not an array of rows: ${rows.error.message}`);
|
|
47
|
+
const at = rows.data.findIndex((row) => typeof row.id !== "string");
|
|
48
|
+
if (at >= 0) throw new Error(`credential file ${path}: row ${at} carries no id`);
|
|
49
|
+
return rows.data;
|
|
50
|
+
};
|
|
51
|
+
const write = async (rows) => {
|
|
52
|
+
await mkdir(dirname(path), { recursive: true });
|
|
53
|
+
const temporary = `${path}.tmp`;
|
|
54
|
+
await writeFile(temporary, JSON.stringify(rows, null, 2));
|
|
55
|
+
await rename(temporary, path);
|
|
56
|
+
};
|
|
57
|
+
const change = (work) => {
|
|
58
|
+
const next = gate.tail.then(async () => {
|
|
59
|
+
const { rows, result, changed } = work(await read());
|
|
60
|
+
if (changed) await write(rows);
|
|
61
|
+
return result;
|
|
62
|
+
});
|
|
63
|
+
gate.tail = next.then(
|
|
64
|
+
() => void 0,
|
|
65
|
+
() => void 0
|
|
66
|
+
);
|
|
67
|
+
return next;
|
|
68
|
+
};
|
|
69
|
+
return {
|
|
70
|
+
async list() {
|
|
71
|
+
await gate.tail;
|
|
72
|
+
return read();
|
|
73
|
+
},
|
|
74
|
+
create: (row) => change((rows) => ({ rows: [...rows, row], result: void 0, changed: true })),
|
|
75
|
+
update: (id, data) => change((rows) => ({
|
|
76
|
+
rows: rows.map((row) => row.id === id ? { ...row, ...data, id } : row),
|
|
77
|
+
result: void 0,
|
|
78
|
+
changed: rows.some((row) => row.id === id)
|
|
79
|
+
})),
|
|
80
|
+
delete: (id) => change((rows) => {
|
|
81
|
+
const written = runRowWrite(rows, { kind: "delete", entityType: CREDENTIAL_ROWS_ENTITY, id });
|
|
82
|
+
const removed = written.outcome.kind === "deleted";
|
|
83
|
+
return { rows: written.rows, result: removed, changed: removed };
|
|
84
|
+
})
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
function nodeCredentialScope() {
|
|
88
|
+
return new AsyncLocalStorage();
|
|
89
|
+
}
|
|
90
|
+
var installed = false;
|
|
91
|
+
function installNodeHostPorts() {
|
|
92
|
+
if (installed) return;
|
|
93
|
+
installed = true;
|
|
94
|
+
installCredentialScopeStorage(nodeCredentialScope());
|
|
95
|
+
}
|
|
96
|
+
async function installNodeCredentialVault(options) {
|
|
97
|
+
const env = options.env ?? process.env;
|
|
98
|
+
const master = env[CREDENTIAL_MASTER_KEY_ENV];
|
|
99
|
+
if (master === void 0) return null;
|
|
100
|
+
const previous = env[CREDENTIAL_PREVIOUS_MASTER_KEY_ENV];
|
|
101
|
+
const vault = await CredentialVault.open(
|
|
102
|
+
new options.kernel.CredentialVault(master, previous === void 0 || previous === "" ? void 0 : previous),
|
|
103
|
+
fileCredentialRows(credentialsFilePath(env, options.cwd))
|
|
104
|
+
);
|
|
105
|
+
installCredentialStore(vault);
|
|
106
|
+
return vault;
|
|
107
|
+
}
|
|
108
|
+
var IO_TIMEOUT_MS = 5e3;
|
|
109
|
+
async function systemResolve(host) {
|
|
110
|
+
return lookup(host, { all: true });
|
|
111
|
+
}
|
|
112
|
+
var TokenPostRefusal = class extends Error {
|
|
113
|
+
constructor(message) {
|
|
114
|
+
super(message);
|
|
115
|
+
this.name = "TokenPostRefusal";
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
function urlOf(endpoint) {
|
|
119
|
+
try {
|
|
120
|
+
return new URL(endpoint);
|
|
121
|
+
} catch {
|
|
122
|
+
throw new TokenPostRefusal("the token endpoint is not a url");
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
function createNodeTokenPost(options) {
|
|
126
|
+
const send = options.request ?? request;
|
|
127
|
+
const resolve = options.resolve ?? systemResolve;
|
|
128
|
+
return async ({ endpoint, headers, body }) => {
|
|
129
|
+
const url = urlOf(endpoint);
|
|
130
|
+
if (url.protocol !== "https:") throw new TokenPostRefusal("the token endpoint must be https");
|
|
131
|
+
if (!options.egressAllows(endpoint)) throw new TokenPostRefusal(`${url.host} is not an origin the program declares in egress`);
|
|
132
|
+
const host = url.hostname.replace(/^\[/, "").replace(/\]$/, "");
|
|
133
|
+
const addresses = isIP(host) !== 0 ? [{ address: host, family: isIP(host) }] : await resolve(host);
|
|
134
|
+
if (addresses.length === 0) throw new TokenPostRefusal(`${host} has no addresses`);
|
|
135
|
+
const private_ = addresses.find((entry) => !options.isPublicAddress(entry.address));
|
|
136
|
+
if (private_ !== void 0) throw new TokenPostRefusal(`${host} resolves to ${private_.address}, not a public address`);
|
|
137
|
+
const checked = addresses[0];
|
|
138
|
+
const payload = Buffer.from(body, "utf8");
|
|
139
|
+
const requestHeaders = {};
|
|
140
|
+
for (const [name, value] of headers) requestHeaders[name] = value;
|
|
141
|
+
requestHeaders["Content-Length"] = payload.length;
|
|
142
|
+
requestHeaders["Connection"] = "close";
|
|
143
|
+
return new Promise((settle, reject) => {
|
|
144
|
+
const req = send(
|
|
145
|
+
{
|
|
146
|
+
method: "POST",
|
|
147
|
+
protocol: "https:",
|
|
148
|
+
host,
|
|
149
|
+
port: url.port === "" ? 443 : Number(url.port),
|
|
150
|
+
path: `${url.pathname}${url.search}`,
|
|
151
|
+
headers: requestHeaders,
|
|
152
|
+
timeout: IO_TIMEOUT_MS,
|
|
153
|
+
servername: isIP(host) === 0 ? host : void 0,
|
|
154
|
+
lookup: (_name, lookupOptions, callback) => {
|
|
155
|
+
if (lookupOptions.all === true) callback(null, [{ address: checked.address, family: checked.family }]);
|
|
156
|
+
else callback(null, checked.address, checked.family);
|
|
157
|
+
}
|
|
158
|
+
},
|
|
159
|
+
(response) => {
|
|
160
|
+
const status = response.statusCode ?? 0;
|
|
161
|
+
if (status >= 300 && status < 400) {
|
|
162
|
+
response.resume();
|
|
163
|
+
reject(new TokenPostRefusal(`the token endpoint answered a redirect (${status}); redirects are not followed`));
|
|
164
|
+
req.destroy();
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
const chunks = [];
|
|
168
|
+
response.on("data", (chunk) => chunks.push(chunk));
|
|
169
|
+
response.on("end", () => settle({ status, body: Buffer.concat(chunks).toString("utf8") }));
|
|
170
|
+
response.on("error", () => reject(new TokenPostRefusal("the token endpoint response failed")));
|
|
171
|
+
}
|
|
172
|
+
);
|
|
173
|
+
req.on("timeout", () => {
|
|
174
|
+
reject(new TokenPostRefusal("the token endpoint timed out"));
|
|
175
|
+
req.destroy();
|
|
176
|
+
});
|
|
177
|
+
req.on("error", (error) => reject(new TokenPostRefusal(`could not reach the token endpoint${error.code !== void 0 ? ` (${error.code})` : ""}`)));
|
|
178
|
+
req.end(payload);
|
|
179
|
+
});
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
export { DEFAULT_CREDENTIALS_FILE, TokenPostRefusal, createNodeTokenPost, credentialsFilePath, fileCredentialRows, installNodeCredentialVault, installNodeHostPorts };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export { createProgramHandlers } from './chunk-
|
|
2
|
-
import './chunk-
|
|
3
|
-
import './chunk-
|
|
4
|
-
import './chunk-
|
|
5
|
-
import './chunk-
|
|
1
|
+
export { createProgramHandlers } from './chunk-LNEOE5TD.js';
|
|
2
|
+
import './chunk-HXA6OB35.js';
|
|
3
|
+
import './chunk-VQVAHUAX.js';
|
|
4
|
+
import './chunk-EEYGL7AB.js';
|
|
5
|
+
import './chunk-7QE32QQR.js';
|
|
6
6
|
import './chunk-BWMLDDCL.js';
|