@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.
@@ -1,12 +1,12 @@
1
- import { installNodeHostPorts } from './chunk-23YAOI6P.js';
2
- import { loadNativeKernelModule, resolveNativeAddon, loadKernelModule, loadHttpKernel } from './chunk-UBZT5LDW.js';
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, join, resolve } from 'path';
6
+ import { dirname, resolve, join } from 'path';
7
7
  import { spawn } from 'child_process';
8
8
  import { createRequire } from 'module';
9
- import { createHttpPorts, NativeMemoryPersistenceAdapter, kernelOsGrants, InFlightCalls, KernelEngine, dispatchInbound, anchoredGrants, expandAnchor } from '@almadar/shell-runtime';
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
- return { value: this.lookupEnv(name) };
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 (or its number)");
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
- fs;
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 (this.fs.closeOwned(args) || this.net.closeOwned(args)) return {};
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 this.fs.run(op, args);
1918
- if (isProcessOp(op)) return this.process.run(op, args);
1919
- if (isNetOp(op)) return this.net.run(op, args);
1920
- if (isSysOp(op)) return this.sys.run(op);
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 this.process.waitLater(args);
1946
+ return process2.waitLater(args);
1935
1947
  case "os/read":
1936
- return this.fs.readLater(op, args);
1948
+ return fs.readLater(op, args);
1937
1949
  case "os/send":
1938
- return this.net.sendLater(op, args);
1950
+ return net.sendLater(op, args);
1939
1951
  case "os/recv":
1940
- return this.net.recvLater(op, args);
1952
+ return net.recvLater(op, args);
1941
1953
  case "os/recvfrom":
1942
- return this.net.recvfromLater(op, args);
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
- blocking = this.deferral(op, this.resolved(op, args));
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, http, persistence) {
2050
+ constructor(engine, os, schema, secretPorts, persistence) {
2038
2051
  this.engine = engine;
2039
2052
  this.os = os;
2040
2053
  this.schema = schema;
2041
- this.http = http;
2054
+ this.secretPorts = secretPorts;
2042
2055
  this.persistence = persistence;
2043
2056
  }
2044
2057
  engine;
2045
2058
  os;
2046
2059
  schema;
2047
- http;
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
- http,
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, http, persistence);
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 `http` ask included), and return what it emitted. */
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, ...user !== void 0 ? { user } : {} }
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.schema, name, delivery, (orbital, request) => this.engine.evaluate(orbital, request, { orbital }), (credential) => this.http.secrets.get(credential, void 0));
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 { GCS_ENDPOINT, KernelProgram, WORKSPACE_HMAC_KEY_ID, WORKSPACE_HMAC_SECRET, createNodeOsHost, emitPayload, kernelWorkspaceHost, processAnchors, resolveKernelDir, resolveProgramFile, workspaceBucketFromEnv, workspacesRoot };
2229
+ export { KernelProgram, createNodeOsHost, emitPayload, kernelWorkspaceHost, processAnchors, resolveProgramFile, workspaceBucketFromEnv, workspacesRoot };
@@ -1,5 +1,5 @@
1
- import { workspacesRoot, kernelWorkspaceHost, workspaceBucketFromEnv } from './chunk-BJA6GYC5.js';
2
- import { runProgramEffect } from './chunk-QYAPNUBH.js';
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-WZFQ7T7V.js';
2
- import './chunk-BJA6GYC5.js';
3
- import './chunk-23YAOI6P.js';
4
- import './chunk-UBZT5LDW.js';
5
- import './chunk-QYAPNUBH.js';
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';