@camstack/types 1.2.430 → 1.2.431

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/CHANGELOG.md CHANGED
@@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [1.2.431] - 2026-10-27
11
+
12
+ ### Changed
13
+
14
+ - Addons can now offer a vendor sign-in that opens the vendor's login page through the hub and finishes on the CamStack result page.
15
+
10
16
  ## [1.2.430] - 2026-10-27
11
17
 
12
18
  ### Added
package/dist/index.d.ts CHANGED
@@ -353,6 +353,7 @@ export { errMsg } from './utils/err-msg.js';
353
353
  export { hfModelUrl } from './utils/hf-url.js';
354
354
  export { asBoolean, asJsonArray, asJsonObject, asNumber, asString, parseJsonArray, parseJsonObject, parseJsonUnknown, } from './utils/json-safe.js';
355
355
  export { maskUrlCredentials } from './utils/mask-url.js';
356
+ export { VendorLoginProxy, rewriteBody as rewriteLoginProxyBody, rewriteLocation as rewriteLoginProxyLocation, rewriteReferer as rewriteLoginProxyReferer, rewriteSetCookie as rewriteLoginProxySetCookie, type LoginProxyAttemptSpec, type LoginProxyResponseView, type LoginProxyRoute, type LoginProxyScheme, type LoginProxyUpstream, type LoginProxyVerdict, type VendorLoginProxyOptions, } from './vendor-login-proxy/index.js';
356
357
  export { OAUTH_LANDING_PATH, OAUTH_LANDING_REASONS, isOauthLandingReason, oauthLandingUrl, parseOauthLandingFragment, type OauthLandingOutcome, type OauthLandingReason, } from './utils/oauth-landing.js';
357
358
  export { commitWatchdogRestart, DEFAULT_POOL_MEMORY_POLICY, evaluatePoolMemory, initialPoolMemoryState, type PoolMemoryAction, type PoolMemoryPolicy, type PoolMemoryState, type PoolMemoryTelemetry, type PoolMemoryVerdict, PoolMemoryWatchdog, type PoolMemoryWatchdogOptions, type ProcMemory, parseProcStatus, pickRestartCandidate, poolMemoryThreshold, type RestartCandidate, resetPoolBaseline, resolvePoolMemoryPolicy, } from './utils/pool-memory-watchdog.js';
358
359
  export { cellsToRects, type NormRect, rectsToCells } from './utils/privacy-grid-raster.js';
package/dist/index.js CHANGED
@@ -43694,7 +43694,7 @@ function autoRankFor(role, endpoint) {
43694
43694
  if (isPlausibleLan(endpoint)) return 3;
43695
43695
  return null;
43696
43696
  }
43697
- var LOOPBACK_HOSTS = new Set([
43697
+ var LOOPBACK_HOSTS$1 = new Set([
43698
43698
  "localhost",
43699
43699
  "0.0.0.0",
43700
43700
  "::1",
@@ -43702,9 +43702,9 @@ var LOOPBACK_HOSTS = new Set([
43702
43702
  "::",
43703
43703
  "[::]"
43704
43704
  ]);
43705
- function isLoopbackHost(hostname) {
43705
+ function isLoopbackHost$1(hostname) {
43706
43706
  const h = hostname.toLowerCase();
43707
- if (LOOPBACK_HOSTS.has(h) || h.endsWith(".localhost")) return true;
43707
+ if (LOOPBACK_HOSTS$1.has(h) || h.endsWith(".localhost")) return true;
43708
43708
  return /^127\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.test(h);
43709
43709
  }
43710
43710
  /**
@@ -43739,7 +43739,7 @@ function validateCustomAddress(raw) {
43739
43739
  ok: false,
43740
43740
  reason: "The address has no host."
43741
43741
  };
43742
- if (isLoopbackHost(parsed.hostname)) return {
43742
+ if (isLoopbackHost$1(parsed.hostname)) return {
43743
43743
  ok: false,
43744
43744
  reason: "A loopback address names whoever dials it, never this hub — use an address other machines reach."
43745
43745
  };
@@ -117845,6 +117845,421 @@ function parseOauthLandingFragment(hash) {
117845
117845
  };
117846
117846
  }
117847
117847
  //#endregion
117848
+ //#region src/vendor-login-proxy/url-rewrite.ts
117849
+ var LOOPBACK_HOSTS = new Set([
117850
+ "127.0.0.1",
117851
+ "localhost",
117852
+ "[::1]"
117853
+ ]);
117854
+ function hostWithoutPort(host) {
117855
+ if (host.startsWith("[")) return host.slice(0, host.indexOf("]") + 1);
117856
+ const colon = host.indexOf(":");
117857
+ return colon === -1 ? host : host.slice(0, colon);
117858
+ }
117859
+ function isLoopbackHost(host) {
117860
+ return LOOPBACK_HOSTS.has(hostWithoutPort(host.toLowerCase()));
117861
+ }
117862
+ /** An allow-list entry is valid when it is a bare host[:port] and `http` only targets loopback. */
117863
+ function isValidUpstream(upstream) {
117864
+ if (upstream.host.length === 0 || !/^[a-z0-9.[\]:-]+$/.test(upstream.host)) return false;
117865
+ return upstream.scheme === "https" || isLoopbackHost(upstream.host);
117866
+ }
117867
+ function findUpstream(route, host) {
117868
+ const wanted = host.toLowerCase();
117869
+ return route.upstreams.find((upstream) => upstream.host === wanted);
117870
+ }
117871
+ /** `<basePath>/<host><pathname><search>` — what the browser is sent to. */
117872
+ function proxyPathFor(route, host, pathname, search = "") {
117873
+ return `${route.basePath}/${host}${pathname.startsWith("/") ? pathname : `/${pathname}`}${search}`;
117874
+ }
117875
+ /** Split `/<attemptId>/<host>/<rest…>[?query]` (the data-plane view of a request). */
117876
+ function parseProxyPath(rawUrl) {
117877
+ const queryAt = rawUrl.indexOf("?");
117878
+ const path = queryAt === -1 ? rawUrl : rawUrl.slice(0, queryAt);
117879
+ const search = queryAt === -1 ? "" : rawUrl.slice(queryAt);
117880
+ const match = /^\/([A-Za-z0-9_-]{8,128})\/([^/]+)(\/.*)?$/.exec(path);
117881
+ if (match === null) return null;
117882
+ const attemptId = match[1];
117883
+ const host = match[2];
117884
+ if (attemptId === void 0 || host === void 0) return null;
117885
+ return {
117886
+ attemptId,
117887
+ host: host.toLowerCase(),
117888
+ pathname: match[3] ?? "/",
117889
+ search
117890
+ };
117891
+ }
117892
+ /** The vendor URL a proxied request targets, or null when the host would not stay `host`. */
117893
+ function upstreamUrlFor(upstream, parsed) {
117894
+ try {
117895
+ const url = new URL(`${upstream.scheme}://${upstream.host}${parsed.pathname}${parsed.search}`);
117896
+ return url.host.toLowerCase() === upstream.host ? url : null;
117897
+ } catch {
117898
+ return null;
117899
+ }
117900
+ }
117901
+ function escapeRegex(value) {
117902
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
117903
+ }
117904
+ /** A Location (or any URL value) to a vendor host becomes a proxy path; anything else is unchanged. */
117905
+ function rewriteLocation(location, currentUpstream, route) {
117906
+ let resolved;
117907
+ try {
117908
+ resolved = new URL(location, `${currentUpstream.scheme}://${currentUpstream.host}/`);
117909
+ } catch {
117910
+ return location;
117911
+ }
117912
+ if (resolved.protocol !== "https:" && resolved.protocol !== "http:") return location;
117913
+ const target = findUpstream(route, resolved.host);
117914
+ if (target === void 0) return location;
117915
+ return `${proxyPathFor(route, target.host, resolved.pathname, resolved.search)}${resolved.hash}`;
117916
+ }
117917
+ /** Characters that may precede a URL that STARTS a value (never `=`, `?`, `&`, `%3D`). */
117918
+ var VALUE_START = String.raw`(?<=^|["'(\s>,\[{])`;
117919
+ /**
117920
+ * Rewrite vendor URLs in a text body: absolute (`https://host/…`), protocol-relative
117921
+ * (`//host/…`) and JSON-escaped (`https:\/\/host\/…`) when they start a value; and, in
117922
+ * HTML/CSS, root-relative references (`href="/x"`, `url(/x)`) which would otherwise
117923
+ * escape the proxy mount and land on the hub.
117924
+ */
117925
+ function rewriteBody(body, kind, currentUpstream, route) {
117926
+ let out = body;
117927
+ for (const upstream of route.upstreams) {
117928
+ const host = escapeRegex(upstream.host);
117929
+ const plain = new RegExp(`${VALUE_START}(?:https?:)?//${host}(?=[/"'?#\\s)\\]},<]|$)`, "g");
117930
+ out = out.replace(plain, `${route.basePath}/${upstream.host}`);
117931
+ const escapedBase = `${route.basePath}/${upstream.host}`.replace(/\//g, "\\/");
117932
+ const escaped = new RegExp(`${VALUE_START}(?:https?:)?\\\\/\\\\/${host}(?=\\\\/|["'?#\\s)\\]},<]|$)`, "g");
117933
+ out = out.replace(escaped, escapedBase);
117934
+ }
117935
+ const current = `${route.basePath}/${currentUpstream.host}/`;
117936
+ const notMounted = `(?!/)(?!${escapeRegex(route.basePath.slice(1))}/)`;
117937
+ if (kind === "html") {
117938
+ const attribute = String.raw`(\b(?:href|src|action|formaction|poster|data-href|data-src)\s*=\s*["'])/`;
117939
+ out = out.replace(new RegExp(`${attribute}${notMounted}`, "gi"), `$1${current}`);
117940
+ }
117941
+ if (kind === "html" || kind === "css") {
117942
+ const cssUrl = String.raw`(url\(\s*["']?)/`;
117943
+ out = out.replace(new RegExp(`${cssUrl}${notMounted}`, "gi"), `$1${current}`);
117944
+ }
117945
+ return out;
117946
+ }
117947
+ /**
117948
+ * A vendor `Set-Cookie` for the browser: no `Domain` (the cookie belongs to the hub
117949
+ * origin), `Path` narrowed to this attempt's prefix, `Secure` kept (the hub is HTTPS).
117950
+ */
117951
+ function rewriteSetCookie(cookie, route) {
117952
+ const kept = cookie.split(";").map((part) => part.trim()).filter((part, index) => {
117953
+ if (index === 0) return true;
117954
+ const name = part.split("=")[0]?.trim().toLowerCase() ?? "";
117955
+ return name !== "domain" && name !== "path";
117956
+ });
117957
+ kept.push(`Path=${route.basePath}/`);
117958
+ return kept.join("; ");
117959
+ }
117960
+ /**
117961
+ * A browser `Referer` that points into this proxy, turned back into the vendor URL it
117962
+ * stands for. A Referer that is not ours is dropped (null): it names the hub.
117963
+ */
117964
+ function rewriteReferer(referer, route) {
117965
+ let url;
117966
+ try {
117967
+ url = new URL(referer, "http://hub.invalid");
117968
+ } catch {
117969
+ return null;
117970
+ }
117971
+ if (!url.pathname.startsWith(`${route.basePath}/`)) return null;
117972
+ const rest = /^\/([^/]+)(\/.*)?$/.exec(url.pathname.slice(route.basePath.length));
117973
+ const host = rest?.[1]?.toLowerCase();
117974
+ if (host === void 0) return null;
117975
+ const upstream = findUpstream(route, host);
117976
+ if (upstream === void 0) return null;
117977
+ return `${upstream.scheme}://${upstream.host}${rest?.[2] ?? "/"}${url.search}`;
117978
+ }
117979
+ /** Cookies the browser holds for the hub itself must never reach a vendor. */
117980
+ function filterForwardedCookies(cookieHeader) {
117981
+ return cookieHeader.split(";").map((part) => part.trim()).filter((part) => part.length > 0 && !part.toLowerCase().startsWith("camstack_")).join("; ");
117982
+ }
117983
+ //#endregion
117984
+ //#region src/vendor-login-proxy/login-proxy.ts
117985
+ var MAX_REQUEST_BODY_BYTES = 2 * 1024 * 1024;
117986
+ var MAX_TEXT_BODY_BYTES = 4 * 1024 * 1024;
117987
+ /** Request headers that are never forwarded to the vendor. */
117988
+ var DROP_REQUEST_HEADERS = new Set([
117989
+ "host",
117990
+ "connection",
117991
+ "keep-alive",
117992
+ "proxy-authorization",
117993
+ "proxy-connection",
117994
+ "te",
117995
+ "trailer",
117996
+ "transfer-encoding",
117997
+ "upgrade",
117998
+ "content-length",
117999
+ "accept-encoding",
118000
+ "authorization",
118001
+ "cookie",
118002
+ "origin",
118003
+ "referer",
118004
+ "x-camstack-dataplane-secret",
118005
+ "x-forwarded-for",
118006
+ "x-forwarded-host",
118007
+ "x-forwarded-proto",
118008
+ "x-forwarded-prefix",
118009
+ "x-real-ip",
118010
+ "forwarded"
118011
+ ]);
118012
+ /**
118013
+ * Response headers dropped: framing/CSP/HSTS that break a page under another origin, and
118014
+ * the ones that no longer describe the (decoded, possibly rewritten) body.
118015
+ */
118016
+ var DROP_RESPONSE_HEADERS = new Set([
118017
+ "content-security-policy",
118018
+ "content-security-policy-report-only",
118019
+ "x-frame-options",
118020
+ "strict-transport-security",
118021
+ "public-key-pins",
118022
+ "report-to",
118023
+ "nel",
118024
+ "content-encoding",
118025
+ "content-length",
118026
+ "transfer-encoding",
118027
+ "connection",
118028
+ "keep-alive",
118029
+ "set-cookie",
118030
+ "location"
118031
+ ]);
118032
+ function bodyKindOf(contentType) {
118033
+ const type = contentType.toLowerCase();
118034
+ if (type.includes("text/html") || type.includes("application/xhtml")) return "html";
118035
+ if (type.includes("text/css")) return "css";
118036
+ if (type.startsWith("text/") || type.includes("javascript") || type.includes("json") || type.includes("xml")) return "other";
118037
+ return null;
118038
+ }
118039
+ function firstHeader(value) {
118040
+ return Array.isArray(value) ? value[0] : value;
118041
+ }
118042
+ async function readRequestBody(req) {
118043
+ const chunks = [];
118044
+ let size = 0;
118045
+ for await (const chunk of req) {
118046
+ const buf = typeof chunk === "string" ? Buffer.from(chunk) : Buffer.from(chunk);
118047
+ size += buf.length;
118048
+ if (size > MAX_REQUEST_BODY_BYTES) return "too-large";
118049
+ chunks.push(buf);
118050
+ }
118051
+ return Buffer.concat(chunks);
118052
+ }
118053
+ function sendPlain(res, status, text) {
118054
+ res.writeHead(status, {
118055
+ "content-type": "text/plain; charset=utf-8",
118056
+ "cache-control": "no-store"
118057
+ });
118058
+ res.end(text);
118059
+ }
118060
+ var VendorLoginProxy = class {
118061
+ #addonId;
118062
+ #prefix;
118063
+ #logger;
118064
+ #now;
118065
+ #fetch;
118066
+ #attempts = /* @__PURE__ */ new Map();
118067
+ constructor(options) {
118068
+ this.#addonId = options.addonId;
118069
+ this.#prefix = options.prefix;
118070
+ this.#logger = options.logger;
118071
+ this.#now = options.now ?? (() => Date.now());
118072
+ this.#fetch = options.fetchFn ?? globalThis.fetch.bind(globalThis);
118073
+ }
118074
+ /** The `DataPlaneHandler` to pass to `ctx.dataPlane.serve({ prefix, access: 'admin', … })`. */
118075
+ handler = (req, res) => this.#handle(req, res);
118076
+ /** Register an attempt. A one-shot capability: refused hosts are rejected up front. */
118077
+ open(spec) {
118078
+ for (const upstream of spec.upstreams) if (!isValidUpstream(upstream)) throw new Error(`vendor login proxy: upstream ${upstream.host} is not allowed`);
118079
+ this.#attempts.set(spec.attemptId, {
118080
+ expiresAtMs: spec.expiresAtMs,
118081
+ upstreams: spec.upstreams,
118082
+ evaluate: async (view) => {
118083
+ const verdict = await spec.terminal(view);
118084
+ if (verdict.kind === "continue") return verdict;
118085
+ return {
118086
+ kind: "done",
118087
+ landing: await spec.onDone(verdict.payload)
118088
+ };
118089
+ }
118090
+ });
118091
+ }
118092
+ close(attemptId) {
118093
+ this.#attempts.delete(attemptId);
118094
+ }
118095
+ isOpen(attemptId) {
118096
+ const attempt = this.#attempts.get(attemptId);
118097
+ return attempt !== void 0 && this.#now() <= attempt.expiresAtMs;
118098
+ }
118099
+ /**
118100
+ * The hub-relative path that opens `vendorUrl` through the proxy for this attempt:
118101
+ * the URL the browser is sent to. Null when the host is not in the attempt's list.
118102
+ */
118103
+ entryPath(attemptId, vendorUrl) {
118104
+ const attempt = this.#attempts.get(attemptId);
118105
+ if (attempt === void 0) return null;
118106
+ const url = new URL(vendorUrl);
118107
+ if (findUpstream({
118108
+ basePath: "",
118109
+ upstreams: attempt.upstreams
118110
+ }, url.host) === void 0) return null;
118111
+ return `/addon/${this.#addonId}/${this.#prefix}/${attemptId}/${url.host}${url.pathname}${url.search}`;
118112
+ }
118113
+ #routeFor(attemptId, attempt, forwardedPrefix) {
118114
+ return {
118115
+ basePath: `${forwardedPrefix}/addon/${this.#addonId}/${this.#prefix}/${attemptId}`,
118116
+ upstreams: attempt.upstreams
118117
+ };
118118
+ }
118119
+ async #handle(req, res) {
118120
+ try {
118121
+ await this.#serve(req, res);
118122
+ } catch (err) {
118123
+ this.#logger.warn("vendor login proxy: request failed", { meta: {
118124
+ addonId: this.#addonId,
118125
+ error: err instanceof Error ? err.name : "unknown"
118126
+ } });
118127
+ if (!res.headersSent) sendPlain(res, 502, "The sign-in page could not be reached.");
118128
+ else res.end();
118129
+ }
118130
+ }
118131
+ async #serve(req, res) {
118132
+ const parsed = parseProxyPath(req.url ?? "/");
118133
+ if (parsed === null) {
118134
+ sendPlain(res, 404, "Not found");
118135
+ return;
118136
+ }
118137
+ const forwardedPrefix = (firstHeader(req.headers["x-forwarded-prefix"]) ?? "").replace(/\/+$/, "");
118138
+ const attempt = this.#attempts.get(parsed.attemptId);
118139
+ if (attempt === void 0 || this.#now() > attempt.expiresAtMs) {
118140
+ if (attempt !== void 0) this.#attempts.delete(parsed.attemptId);
118141
+ this.#logger.info("vendor login proxy: attempt refused", { meta: {
118142
+ addonId: this.#addonId,
118143
+ reason: attempt === void 0 ? "missing" : "expired"
118144
+ } });
118145
+ this.#redirect(res, forwardedPrefix, {
118146
+ status: "error",
118147
+ addonId: this.#addonId,
118148
+ reason: "invalid_state"
118149
+ });
118150
+ return;
118151
+ }
118152
+ const route = this.#routeFor(parsed.attemptId, attempt, forwardedPrefix);
118153
+ const upstream = findUpstream(route, parsed.host);
118154
+ const target = upstream === void 0 ? null : upstreamUrlFor(upstream, parsed);
118155
+ if (upstream === void 0 || target === null) {
118156
+ this.#logger.warn("vendor login proxy: host refused", { meta: {
118157
+ addonId: this.#addonId,
118158
+ host: parsed.host
118159
+ } });
118160
+ sendPlain(res, 404, "Not found");
118161
+ return;
118162
+ }
118163
+ const method = (req.method ?? "GET").toUpperCase();
118164
+ let body;
118165
+ if (method !== "GET" && method !== "HEAD") {
118166
+ const read = await readRequestBody(req);
118167
+ if (read === "too-large") {
118168
+ sendPlain(res, 413, "Request too large");
118169
+ return;
118170
+ }
118171
+ body = read;
118172
+ }
118173
+ const headers = this.#requestHeaders(req, route, upstream);
118174
+ const upstreamRes = await this.#fetch(target, {
118175
+ method,
118176
+ headers,
118177
+ redirect: "manual",
118178
+ ...body !== void 0 && body.length > 0 ? { body: new Uint8Array(body) } : {}
118179
+ });
118180
+ const location = upstreamRes.headers.get("location");
118181
+ const setCookies = upstreamRes.headers.getSetCookie();
118182
+ const kind = bodyKindOf(upstreamRes.headers.get("content-type") ?? "");
118183
+ const declaredLength = Number(upstreamRes.headers.get("content-length") ?? "0");
118184
+ const text = kind !== null && !(declaredLength > MAX_TEXT_BODY_BYTES) && method !== "HEAD" ? await upstreamRes.text() : null;
118185
+ this.#logger.debug("vendor login proxy: upstream answered", { meta: {
118186
+ addonId: this.#addonId,
118187
+ host: upstream.host,
118188
+ status: upstreamRes.status,
118189
+ method
118190
+ } });
118191
+ const settled = await attempt.evaluate({
118192
+ status: upstreamRes.status,
118193
+ url: target.toString(),
118194
+ location,
118195
+ setCookies,
118196
+ bodyText: text
118197
+ });
118198
+ if (settled.kind === "done") {
118199
+ this.#attempts.delete(parsed.attemptId);
118200
+ this.#logger.info("vendor login proxy: sign-in finished", { meta: {
118201
+ addonId: this.#addonId,
118202
+ status: settled.landing.status
118203
+ } });
118204
+ this.#redirect(res, forwardedPrefix, settled.landing);
118205
+ return;
118206
+ }
118207
+ const out = {};
118208
+ upstreamRes.headers.forEach((value, name) => {
118209
+ if (!DROP_RESPONSE_HEADERS.has(name.toLowerCase())) out[name] = value;
118210
+ });
118211
+ if (setCookies.length > 0) out["set-cookie"] = setCookies.map((c) => rewriteSetCookie(c, route));
118212
+ if (location !== null) out["location"] = rewriteLocation(location, upstream, route);
118213
+ out["cache-control"] = "no-store";
118214
+ if (text !== null && kind !== null) {
118215
+ const rewritten = rewriteBody(text, kind, upstream, route);
118216
+ res.writeHead(upstreamRes.status, out);
118217
+ res.end(rewritten);
118218
+ return;
118219
+ }
118220
+ res.writeHead(upstreamRes.status, out);
118221
+ await this.#pipeBody(upstreamRes, res);
118222
+ }
118223
+ #requestHeaders(req, route, upstream) {
118224
+ const headers = {};
118225
+ for (const [name, value] of Object.entries(req.headers)) {
118226
+ const lower = name.toLowerCase();
118227
+ if (DROP_REQUEST_HEADERS.has(lower) || value === void 0) continue;
118228
+ headers[lower] = Array.isArray(value) ? value.join(", ") : value;
118229
+ }
118230
+ const cookie = filterForwardedCookies(firstHeader(req.headers["cookie"]) ?? "");
118231
+ if (cookie.length > 0) headers["cookie"] = cookie;
118232
+ if (req.headers["origin"] !== void 0) headers["origin"] = `${upstream.scheme}://${upstream.host}`;
118233
+ const referer = firstHeader(req.headers["referer"]);
118234
+ if (referer !== void 0) {
118235
+ const back = rewriteReferer(referer, route);
118236
+ if (back !== null) headers["referer"] = back;
118237
+ }
118238
+ return headers;
118239
+ }
118240
+ async #pipeBody(upstreamRes, res) {
118241
+ if (upstreamRes.body === null) {
118242
+ res.end();
118243
+ return;
118244
+ }
118245
+ for await (const chunk of upstreamRes.body) {
118246
+ if (!res.write(chunk)) await new Promise((resolve) => {
118247
+ res.once("drain", resolve);
118248
+ res.once("close", resolve);
118249
+ });
118250
+ if (res.destroyed) return;
118251
+ }
118252
+ res.end();
118253
+ }
118254
+ #redirect(res, forwardedPrefix, outcome) {
118255
+ res.writeHead(302, {
118256
+ location: `${forwardedPrefix}${oauthLandingUrl(null, outcome)}`,
118257
+ "cache-control": "no-store"
118258
+ });
118259
+ res.end();
118260
+ }
118261
+ };
118262
+ //#endregion
117848
118263
  //#region src/utils/pool-memory-watchdog.ts
117849
118264
  var MB = 1024 * 1024;
117850
118265
  var DEFAULT_POOL_MEMORY_POLICY = {
@@ -120952,6 +121367,7 @@ exports.VectorStatsInputSchema = VectorStatsInputSchema;
120952
121367
  exports.VectorStatsResultSchema = VectorStatsResultSchema;
120953
121368
  exports.VectorUpsertInputSchema = VectorUpsertInputSchema;
120954
121369
  exports.VectorUpsertResultSchema = VectorUpsertResultSchema;
121370
+ exports.VendorLoginProxy = VendorLoginProxy;
120955
121371
  exports.VibrationStatusSchema = VibrationStatusSchema;
120956
121372
  exports.VideoEncodeSchema = VideoEncodeSchema;
120957
121373
  exports.ViewerDeviceAllowSchema = ViewerDeviceAllowSchema;
@@ -121849,6 +122265,10 @@ exports.resultCellKey = resultCellKey;
121849
122265
  exports.resultStandings = resultStandings;
121850
122266
  exports.retrainBoxIou = retrainBoxIou;
121851
122267
  exports.retrainRevisionConflictMessage = retrainRevisionConflictMessage;
122268
+ exports.rewriteLoginProxyBody = rewriteBody;
122269
+ exports.rewriteLoginProxyLocation = rewriteLocation;
122270
+ exports.rewriteLoginProxyReferer = rewriteReferer;
122271
+ exports.rewriteLoginProxySetCookie = rewriteSetCookie;
121852
122272
  exports.roleSpec = roleSpec;
121853
122273
  exports.rollingDurationMs = require_composition.rollingDurationMs;
121854
122274
  exports.roomCompositionExample = roomCompositionExample;