@pasko70/pibo 2.3.0 → 2.4.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/apps/vscode-artifacts/latest.vsix +0 -0
- package/dist/apps/vscode-artifacts/{pibo-vscode-ext-2.3.0.vsix → pibo-vscode-ext-2.4.0.vsix} +0 -0
- package/dist/compute/cli.js +13 -0
- package/dist/compute/pool/artifacts.js +116 -0
- package/dist/compute/pool/cli.js +156 -0
- package/dist/compute/pool/config.js +101 -0
- package/dist/compute/pool/docker.js +157 -0
- package/dist/compute/pool/seeds.js +201 -0
- package/dist/compute/pool/service.js +402 -0
- package/dist/compute/pool/store.js +239 -0
- package/dist/compute/pool/types.js +1 -0
- package/dist/resources/lifecycle.js +22 -2
- package/dist/resources/reaper.js +1 -0
- package/dist/web/channel.js +9 -3
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
import { mkdirSync } from "node:fs";
|
|
2
|
+
import { chmodSync } from "node:fs";
|
|
3
|
+
import { dirname, resolve } from "node:path";
|
|
4
|
+
import { DatabaseSync } from "node:sqlite";
|
|
5
|
+
function slotFromRow(row) {
|
|
6
|
+
return {
|
|
7
|
+
id: row.id,
|
|
8
|
+
ordinal: row.ordinal,
|
|
9
|
+
webPort: row.web_port,
|
|
10
|
+
gatewayPort: row.gateway_port,
|
|
11
|
+
publicUrl: row.public_url ?? undefined,
|
|
12
|
+
state: row.state,
|
|
13
|
+
activeLeaseId: row.active_lease_id ?? undefined,
|
|
14
|
+
dirtyReason: row.dirty_reason ?? undefined,
|
|
15
|
+
updatedAt: row.updated_at,
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
function leaseFromRow(row) {
|
|
19
|
+
return {
|
|
20
|
+
id: row.id,
|
|
21
|
+
slotId: row.slot_id,
|
|
22
|
+
holder: row.holder,
|
|
23
|
+
seedMode: row.seed_mode,
|
|
24
|
+
artifactSha256: row.artifact_sha256,
|
|
25
|
+
artifactRuntimePath: row.artifact_runtime_path,
|
|
26
|
+
packageVersion: row.package_version ?? undefined,
|
|
27
|
+
commit: row.commit_sha ?? undefined,
|
|
28
|
+
containerName: row.container_name,
|
|
29
|
+
publicUrl: row.public_url ?? undefined,
|
|
30
|
+
status: row.status,
|
|
31
|
+
createdAt: row.created_at,
|
|
32
|
+
expiresAt: row.expires_at,
|
|
33
|
+
renewedAt: row.renewed_at ?? undefined,
|
|
34
|
+
releasedAt: row.released_at ?? undefined,
|
|
35
|
+
failedAt: row.failed_at ?? undefined,
|
|
36
|
+
failureSnapshotPath: row.failure_snapshot_path ?? undefined,
|
|
37
|
+
lastError: row.last_error ?? undefined,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
export class DeploymentPoolStore {
|
|
41
|
+
path;
|
|
42
|
+
db;
|
|
43
|
+
constructor(path, slots) {
|
|
44
|
+
this.path = path === ":memory:" ? path : resolve(path);
|
|
45
|
+
if (this.path !== ":memory:")
|
|
46
|
+
mkdirSync(dirname(this.path), { recursive: true, mode: 0o700 });
|
|
47
|
+
this.db = new DatabaseSync(this.path);
|
|
48
|
+
this.db.exec("PRAGMA busy_timeout = 10000");
|
|
49
|
+
if (this.path !== ":memory:")
|
|
50
|
+
this.db.exec("PRAGMA journal_mode = WAL");
|
|
51
|
+
this.applySchema();
|
|
52
|
+
this.ensureSlots(slots);
|
|
53
|
+
if (this.path !== ":memory:")
|
|
54
|
+
chmodSync(this.path, 0o600);
|
|
55
|
+
}
|
|
56
|
+
applySchema() {
|
|
57
|
+
this.db.exec(`
|
|
58
|
+
CREATE TABLE IF NOT EXISTS deployment_pool_slots (
|
|
59
|
+
id TEXT PRIMARY KEY,
|
|
60
|
+
ordinal INTEGER NOT NULL UNIQUE,
|
|
61
|
+
web_port INTEGER NOT NULL UNIQUE,
|
|
62
|
+
gateway_port INTEGER NOT NULL UNIQUE,
|
|
63
|
+
public_url TEXT,
|
|
64
|
+
state TEXT NOT NULL,
|
|
65
|
+
active_lease_id TEXT,
|
|
66
|
+
dirty_reason TEXT,
|
|
67
|
+
updated_at TEXT NOT NULL
|
|
68
|
+
);
|
|
69
|
+
CREATE TABLE IF NOT EXISTS deployment_pool_leases (
|
|
70
|
+
id TEXT PRIMARY KEY,
|
|
71
|
+
slot_id TEXT NOT NULL,
|
|
72
|
+
holder TEXT NOT NULL,
|
|
73
|
+
seed_mode TEXT NOT NULL,
|
|
74
|
+
artifact_sha256 TEXT NOT NULL,
|
|
75
|
+
artifact_runtime_path TEXT NOT NULL,
|
|
76
|
+
package_version TEXT,
|
|
77
|
+
commit_sha TEXT,
|
|
78
|
+
container_name TEXT NOT NULL,
|
|
79
|
+
public_url TEXT,
|
|
80
|
+
status TEXT NOT NULL,
|
|
81
|
+
created_at TEXT NOT NULL,
|
|
82
|
+
expires_at TEXT NOT NULL,
|
|
83
|
+
renewed_at TEXT,
|
|
84
|
+
released_at TEXT,
|
|
85
|
+
failed_at TEXT,
|
|
86
|
+
failure_snapshot_path TEXT,
|
|
87
|
+
last_error TEXT
|
|
88
|
+
);
|
|
89
|
+
CREATE INDEX IF NOT EXISTS deployment_pool_leases_status_idx
|
|
90
|
+
ON deployment_pool_leases (status, expires_at);
|
|
91
|
+
CREATE INDEX IF NOT EXISTS deployment_pool_leases_slot_idx
|
|
92
|
+
ON deployment_pool_leases (slot_id, created_at DESC);
|
|
93
|
+
`);
|
|
94
|
+
}
|
|
95
|
+
ensureSlots(slots) {
|
|
96
|
+
const now = new Date().toISOString();
|
|
97
|
+
const insert = this.db.prepare(`
|
|
98
|
+
INSERT INTO deployment_pool_slots (id, ordinal, web_port, gateway_port, public_url, state, updated_at)
|
|
99
|
+
VALUES (?, ?, ?, ?, ?, 'free', ?)
|
|
100
|
+
ON CONFLICT(id) DO UPDATE SET
|
|
101
|
+
ordinal=excluded.ordinal,
|
|
102
|
+
web_port=excluded.web_port,
|
|
103
|
+
gateway_port=excluded.gateway_port,
|
|
104
|
+
public_url=excluded.public_url
|
|
105
|
+
`);
|
|
106
|
+
for (const slot of slots)
|
|
107
|
+
insert.run(slot.id, slot.ordinal, slot.webPort, slot.gatewayPort, slot.publicUrl ?? null, now);
|
|
108
|
+
}
|
|
109
|
+
listSlots() {
|
|
110
|
+
return this.db.prepare("SELECT * FROM deployment_pool_slots ORDER BY ordinal").all().map(slotFromRow);
|
|
111
|
+
}
|
|
112
|
+
getSlot(id) {
|
|
113
|
+
const row = this.db.prepare("SELECT * FROM deployment_pool_slots WHERE id = ?").get(id);
|
|
114
|
+
return row ? slotFromRow(row) : undefined;
|
|
115
|
+
}
|
|
116
|
+
listLeases(options = {}) {
|
|
117
|
+
const where = options.includeInactive ? "" : "WHERE status IN ('provisioning', 'ready', 'releasing')";
|
|
118
|
+
return this.db.prepare(`SELECT * FROM deployment_pool_leases ${where} ORDER BY created_at DESC`).all().map(leaseFromRow);
|
|
119
|
+
}
|
|
120
|
+
getLease(id) {
|
|
121
|
+
const row = this.db.prepare("SELECT * FROM deployment_pool_leases WHERE id = ?").get(id);
|
|
122
|
+
return row ? leaseFromRow(row) : undefined;
|
|
123
|
+
}
|
|
124
|
+
reserveLease(input) {
|
|
125
|
+
this.db.exec("BEGIN IMMEDIATE");
|
|
126
|
+
try {
|
|
127
|
+
const active = this.db.prepare("SELECT COUNT(*) AS count FROM deployment_pool_slots WHERE state IN ('provisioning', 'ready', 'releasing')").get();
|
|
128
|
+
if (Number(active.count) >= input.maxActive) {
|
|
129
|
+
const nearest = this.db.prepare(`
|
|
130
|
+
SELECT MIN(l.expires_at) AS nearest_expiry
|
|
131
|
+
FROM deployment_pool_slots s
|
|
132
|
+
JOIN deployment_pool_leases l ON l.id = s.active_lease_id
|
|
133
|
+
WHERE s.state IN ('provisioning', 'ready', 'releasing')
|
|
134
|
+
`).get();
|
|
135
|
+
throw new Error(`Deployment pool capacity reached (${input.maxActive} active)${nearest.nearest_expiry ? `; nearest expiry ${nearest.nearest_expiry}` : ""}`);
|
|
136
|
+
}
|
|
137
|
+
const row = this.db.prepare("SELECT * FROM deployment_pool_slots WHERE state = 'free' ORDER BY ordinal LIMIT 1").get();
|
|
138
|
+
if (!row)
|
|
139
|
+
throw new Error("No free deployment pool slot is available");
|
|
140
|
+
const slot = slotFromRow(row);
|
|
141
|
+
const containerName = `pibo-pool-${slot.id}`;
|
|
142
|
+
this.db.prepare(`
|
|
143
|
+
INSERT INTO deployment_pool_leases (
|
|
144
|
+
id, slot_id, holder, seed_mode, artifact_sha256, artifact_runtime_path,
|
|
145
|
+
package_version, commit_sha, container_name, public_url, status, created_at, expires_at
|
|
146
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'provisioning', ?, ?)
|
|
147
|
+
`).run(input.id, slot.id, input.holder, input.seedMode, input.artifactSha256, input.artifactRuntimePath, input.packageVersion ?? null, input.commit ?? null, containerName, slot.publicUrl ?? null, input.createdAt, input.expiresAt);
|
|
148
|
+
this.db.prepare("UPDATE deployment_pool_slots SET state='provisioning', active_lease_id=?, dirty_reason=NULL, updated_at=? WHERE id=?")
|
|
149
|
+
.run(input.id, input.createdAt, slot.id);
|
|
150
|
+
this.db.exec("COMMIT");
|
|
151
|
+
return { slot: this.getSlot(slot.id), lease: this.getLease(input.id) };
|
|
152
|
+
}
|
|
153
|
+
catch (error) {
|
|
154
|
+
this.db.exec("ROLLBACK");
|
|
155
|
+
throw error;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
markReady(leaseId, now = new Date().toISOString()) {
|
|
159
|
+
const lease = this.requireLease(leaseId);
|
|
160
|
+
this.db.exec("BEGIN IMMEDIATE");
|
|
161
|
+
try {
|
|
162
|
+
this.db.prepare("UPDATE deployment_pool_leases SET status='ready', last_error=NULL WHERE id=?").run(leaseId);
|
|
163
|
+
this.db.prepare("UPDATE deployment_pool_slots SET state='ready', dirty_reason=NULL, updated_at=? WHERE id=? AND active_lease_id=?")
|
|
164
|
+
.run(now, lease.slotId, leaseId);
|
|
165
|
+
this.db.exec("COMMIT");
|
|
166
|
+
return this.requireLease(leaseId);
|
|
167
|
+
}
|
|
168
|
+
catch (error) {
|
|
169
|
+
this.db.exec("ROLLBACK");
|
|
170
|
+
throw error;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
markReleasing(leaseId, now = new Date().toISOString()) {
|
|
174
|
+
const lease = this.requireLease(leaseId);
|
|
175
|
+
this.db.prepare("UPDATE deployment_pool_leases SET status='releasing' WHERE id=? AND status IN ('provisioning','ready','releasing')").run(leaseId);
|
|
176
|
+
this.db.prepare("UPDATE deployment_pool_slots SET state='releasing', updated_at=? WHERE id=? AND active_lease_id=?").run(now, lease.slotId, leaseId);
|
|
177
|
+
return this.requireLease(leaseId);
|
|
178
|
+
}
|
|
179
|
+
markReleased(leaseId, status, now = new Date().toISOString()) {
|
|
180
|
+
const lease = this.requireLease(leaseId);
|
|
181
|
+
this.db.exec("BEGIN IMMEDIATE");
|
|
182
|
+
try {
|
|
183
|
+
this.db.prepare("UPDATE deployment_pool_leases SET status=?, released_at=?, last_error=NULL WHERE id=?").run(status, now, leaseId);
|
|
184
|
+
this.db.prepare("UPDATE deployment_pool_slots SET state='free', active_lease_id=NULL, dirty_reason=NULL, updated_at=? WHERE id=? AND active_lease_id=?")
|
|
185
|
+
.run(now, lease.slotId, leaseId);
|
|
186
|
+
this.db.exec("COMMIT");
|
|
187
|
+
return this.requireLease(leaseId);
|
|
188
|
+
}
|
|
189
|
+
catch (error) {
|
|
190
|
+
this.db.exec("ROLLBACK");
|
|
191
|
+
throw error;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
markFailed(leaseId, error, snapshotPath, options = { slotClean: false }) {
|
|
195
|
+
const lease = this.requireLease(leaseId);
|
|
196
|
+
const now = options.now ?? new Date().toISOString();
|
|
197
|
+
this.db.exec("BEGIN IMMEDIATE");
|
|
198
|
+
try {
|
|
199
|
+
this.db.prepare("UPDATE deployment_pool_leases SET status='failed', failed_at=?, failure_snapshot_path=?, last_error=? WHERE id=?")
|
|
200
|
+
.run(now, snapshotPath ?? null, error, leaseId);
|
|
201
|
+
if (options.slotClean) {
|
|
202
|
+
this.db.prepare("UPDATE deployment_pool_slots SET state='free', active_lease_id=NULL, dirty_reason=NULL, updated_at=? WHERE id=? AND active_lease_id=?")
|
|
203
|
+
.run(now, lease.slotId, leaseId);
|
|
204
|
+
}
|
|
205
|
+
else {
|
|
206
|
+
this.db.prepare("UPDATE deployment_pool_slots SET state='dirty', dirty_reason=?, updated_at=? WHERE id=? AND active_lease_id=?")
|
|
207
|
+
.run(error, now, lease.slotId, leaseId);
|
|
208
|
+
}
|
|
209
|
+
this.db.exec("COMMIT");
|
|
210
|
+
return this.requireLease(leaseId);
|
|
211
|
+
}
|
|
212
|
+
catch (caught) {
|
|
213
|
+
this.db.exec("ROLLBACK");
|
|
214
|
+
throw caught;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
renewLease(leaseId, holder, expiresAt, now = new Date().toISOString()) {
|
|
218
|
+
const result = this.db.prepare(`
|
|
219
|
+
UPDATE deployment_pool_leases SET expires_at=?, renewed_at=?
|
|
220
|
+
WHERE id=? AND holder=? AND status='ready'
|
|
221
|
+
`).run(expiresAt, now, leaseId, holder);
|
|
222
|
+
if (Number(result.changes ?? 0) !== 1)
|
|
223
|
+
throw new Error(`Active deployment lease "${leaseId}" for holder "${holder}" was not found`);
|
|
224
|
+
return this.requireLease(leaseId);
|
|
225
|
+
}
|
|
226
|
+
freeDirtySlot(slotId, now = new Date().toISOString()) {
|
|
227
|
+
this.db.prepare("UPDATE deployment_pool_slots SET state='free', active_lease_id=NULL, dirty_reason=NULL, updated_at=? WHERE id=?")
|
|
228
|
+
.run(now, slotId);
|
|
229
|
+
}
|
|
230
|
+
requireLease(id) {
|
|
231
|
+
const lease = this.getLease(id);
|
|
232
|
+
if (!lease)
|
|
233
|
+
throw new Error(`Deployment lease "${id}" was not found`);
|
|
234
|
+
return lease;
|
|
235
|
+
}
|
|
236
|
+
close() {
|
|
237
|
+
this.db.close();
|
|
238
|
+
}
|
|
239
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -6,6 +6,8 @@ import { promisify } from "node:util";
|
|
|
6
6
|
import { applyComputeWorkerReapPlan, buildComputeWorkerReapPlan, planReapWorkers, } from "../compute/docker.js";
|
|
7
7
|
import { defaultBrowserPoolRoot, defaultBrowserUseHome, getComputeResourceHealth, parseProcessList, } from "../compute/resource-health.js";
|
|
8
8
|
import { loadBrowserPoolState, reapIdleBrowserPool, } from "../tools/browser-pool.js";
|
|
9
|
+
import { resolveDeploymentPoolConfig } from "../compute/pool/config.js";
|
|
10
|
+
import { applyDeploymentPoolReapPlan, planDeploymentPoolReap } from "../compute/pool/service.js";
|
|
9
11
|
const execFileAsync = promisify(execFile);
|
|
10
12
|
export async function collectManagedBrowserPools(rootDir) {
|
|
11
13
|
const records = [];
|
|
@@ -56,7 +58,7 @@ export async function getActiveResourceLeases(browserPoolRoot = defaultBrowserPo
|
|
|
56
58
|
export async function planResourceReap(options = {}) {
|
|
57
59
|
const now = options.now ?? new Date();
|
|
58
60
|
const resolved = resolveReapOptions(options);
|
|
59
|
-
const [records, staleFiles, compute, health] = await Promise.all([
|
|
61
|
+
const [records, staleFiles, compute, health, deploymentPool] = await Promise.all([
|
|
60
62
|
collectManagedBrowserPools(resolved.browserPoolRoot),
|
|
61
63
|
planStaleCdpFiles(resolved.browserUseHome),
|
|
62
64
|
planComputeReapSafely({ includeDev: resolved.includeDev, maxAgeMinutes: resolved.maxAgeMinutes, now }),
|
|
@@ -66,9 +68,10 @@ export async function planResourceReap(options = {}) {
|
|
|
66
68
|
browserUseHome: resolved.browserUseHome,
|
|
67
69
|
exemptBrowserUserDataDirs: [],
|
|
68
70
|
}),
|
|
71
|
+
planDeploymentPoolReapSafely(now),
|
|
69
72
|
]);
|
|
70
73
|
const unmanagedBrowsers = buildUnmanagedBrowserPlanItems(health.browserProcesses.unassignedMainProcessDetails, resolved.unmanagedBrowserGraceMinutes, new Set(resolved.exemptBrowserPids), new Set(resolved.exemptBrowserUserDataDirs), resolved.browserUseHome);
|
|
71
|
-
return buildResourceReapPlan({ now, options: resolved, records, staleFiles, unmanagedBrowsers, compute });
|
|
74
|
+
return buildResourceReapPlan({ now, options: resolved, records, staleFiles, unmanagedBrowsers, compute, deploymentPool });
|
|
72
75
|
}
|
|
73
76
|
export function buildResourceReapPlan(input) {
|
|
74
77
|
const browserItems = input.records.map((record) => buildBrowserReapPlanItem(record, input.now, input.options.idleTimeoutMinutes));
|
|
@@ -89,6 +92,7 @@ export function buildResourceReapPlan(input) {
|
|
|
89
92
|
skipped: unmanagedBrowsers.filter((item) => item.action === "skip").length,
|
|
90
93
|
},
|
|
91
94
|
compute: input.compute,
|
|
95
|
+
deploymentPool: input.deploymentPool,
|
|
92
96
|
worktreesPreserved: true,
|
|
93
97
|
};
|
|
94
98
|
}
|
|
@@ -112,6 +116,9 @@ export async function applyResourceReapPlan(plan, dependencies = {}) {
|
|
|
112
116
|
}
|
|
113
117
|
const removedStaleFiles = await applyStaleCdpFilePlan(confirmed.staleFiles.items, dependencies.isPidAlive);
|
|
114
118
|
const removedComputeWorkers = await (dependencies.applyCompute ?? applyComputeWorkerReapPlan)(confirmed.compute);
|
|
119
|
+
const deploymentPoolResult = confirmed.deploymentPool
|
|
120
|
+
? await (dependencies.applyDeploymentPool ?? applyDeploymentPoolReapPlan)(confirmed.deploymentPool)
|
|
121
|
+
: undefined;
|
|
115
122
|
return {
|
|
116
123
|
applied: true,
|
|
117
124
|
plan: confirmed,
|
|
@@ -119,6 +126,8 @@ export async function applyResourceReapPlan(plan, dependencies = {}) {
|
|
|
119
126
|
terminatedUnmanagedBrowsers,
|
|
120
127
|
removedStaleFiles,
|
|
121
128
|
removedComputeWorkers,
|
|
129
|
+
deploymentPoolResult,
|
|
130
|
+
removedDeploymentLeases: deploymentPoolResult?.releasedLeases ?? [],
|
|
122
131
|
worktreesPreserved: true,
|
|
123
132
|
};
|
|
124
133
|
}
|
|
@@ -287,6 +296,17 @@ export async function planComputeReapSafely(options, planCompute = planReapWorke
|
|
|
287
296
|
return plan;
|
|
288
297
|
}
|
|
289
298
|
}
|
|
299
|
+
async function planDeploymentPoolReapSafely(now) {
|
|
300
|
+
const config = resolveDeploymentPoolConfig();
|
|
301
|
+
if (!existsSync(config.databasePath))
|
|
302
|
+
return undefined;
|
|
303
|
+
try {
|
|
304
|
+
return await planDeploymentPoolReap({ config, now });
|
|
305
|
+
}
|
|
306
|
+
catch {
|
|
307
|
+
return undefined;
|
|
308
|
+
}
|
|
309
|
+
}
|
|
290
310
|
async function planStaleCdpFiles(browserUseHome, isPidAlive = defaultIsPidAlive) {
|
|
291
311
|
const stateDir = join(browserUseHome, "pibo-cdp");
|
|
292
312
|
let files;
|
package/dist/resources/reaper.js
CHANGED
|
@@ -95,6 +95,7 @@ export class ResourceReaperService {
|
|
|
95
95
|
unmanagedBrowsers: result.terminatedUnmanagedBrowsers.length,
|
|
96
96
|
staleFiles: result.removedStaleFiles.length,
|
|
97
97
|
computeWorkers: result.removedComputeWorkers.length,
|
|
98
|
+
...(result.deploymentPoolResult ? { deploymentLeases: result.removedDeploymentLeases?.length ?? 0 } : {}),
|
|
98
99
|
},
|
|
99
100
|
lastError: undefined,
|
|
100
101
|
};
|
package/dist/web/channel.js
CHANGED
|
@@ -78,7 +78,13 @@ export function stripSocketPeerHeaderFromResponse(response) {
|
|
|
78
78
|
headers,
|
|
79
79
|
});
|
|
80
80
|
}
|
|
81
|
-
function createRequestBaseURL(nodeRequest, host, port) {
|
|
81
|
+
function createRequestBaseURL(nodeRequest, host, port, canonicalBaseURL) {
|
|
82
|
+
const requestHost = firstHeaderValue(nodeRequest.headers.host);
|
|
83
|
+
if (canonicalBaseURL && requestHost) {
|
|
84
|
+
const canonical = new URL(canonicalBaseURL);
|
|
85
|
+
if (requestHost.toLowerCase() === canonical.host.toLowerCase())
|
|
86
|
+
return canonical.origin;
|
|
87
|
+
}
|
|
82
88
|
if (isLoopbackAddress(nodeRequest.socket.remoteAddress)) {
|
|
83
89
|
const forwardedHost = firstHeaderValue(nodeRequest.headers["x-forwarded-host"]);
|
|
84
90
|
const forwardedProto = firstHeaderValue(nodeRequest.headers["x-forwarded-proto"]);
|
|
@@ -86,7 +92,7 @@ function createRequestBaseURL(nodeRequest, host, port) {
|
|
|
86
92
|
return `${forwardedProto}://${forwardedHost}`;
|
|
87
93
|
}
|
|
88
94
|
}
|
|
89
|
-
return `http://${
|
|
95
|
+
return `http://${requestHost ?? `${host}:${port}`}`;
|
|
90
96
|
}
|
|
91
97
|
function isActiveRunStatus(status) {
|
|
92
98
|
return typeof status === "string" && ["queued", "starting", "running", "streaming", "waiting", "blocked", "retrying", "compacting", "pausing"].includes(status);
|
|
@@ -235,7 +241,7 @@ export function createWebHostChannel(options = {}) {
|
|
|
235
241
|
};
|
|
236
242
|
const handleRequest = async (nodeRequest, nodeResponse) => {
|
|
237
243
|
try {
|
|
238
|
-
const baseURL = createRequestBaseURL(nodeRequest, host, port);
|
|
244
|
+
const baseURL = createRequestBaseURL(nodeRequest, host, port, options.canonicalBaseURL);
|
|
239
245
|
const baseRequest = await nodeRequestToWebRequest(nodeRequest, baseURL);
|
|
240
246
|
// Inject the TCP socket peer into every request so the local auth
|
|
241
247
|
// plugin can apply the same loopback predicate from `getSession`
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pasko70/pibo",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.4.0",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@pasko70/pibo",
|
|
9
|
-
"version": "2.
|
|
9
|
+
"version": "2.4.0",
|
|
10
10
|
"workspaces": [
|
|
11
11
|
"packages/workflows"
|
|
12
12
|
],
|