@dvmkit/sdk 0.2.1-rc.9 → 0.3.0-rc.9
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/{chunk-JAHRF5X3.js → chunk-HHTL3ZFT.js} +8 -5
- package/dist/{chunk-JNKQZVZX.js → chunk-LTAIBLS2.js} +442 -0
- package/dist/{credit-menu-kDA9RVzD.d.ts → credit-menu-BlCL7gZx.d.ts} +40 -1
- package/dist/internal/server.d.ts +2 -2
- package/dist/internal/server.js +2 -1
- package/dist/{postgres-job-store-MZZZMS2B.js → postgres-job-store-VE2JRUEC.js} +1 -1
- package/dist/server/index.d.ts +5 -2
- package/dist/server/index.js +15 -6
- package/package.json +1 -1
|
@@ -1053,10 +1053,13 @@ var PostgresJobStore = class {
|
|
|
1053
1053
|
);
|
|
1054
1054
|
}
|
|
1055
1055
|
cancelStaleJob(jobId, expectedActivityBefore, reason, terminalStatus) {
|
|
1056
|
-
return this.terminateJob(jobId, reason, terminalStatus, expectedActivityBefore);
|
|
1056
|
+
return this.terminateJob(jobId, reason, terminalStatus, expectedActivityBefore, null);
|
|
1057
1057
|
}
|
|
1058
1058
|
cancelJob(jobId, reason) {
|
|
1059
|
-
return this.terminateJob(jobId, reason, "cancelled", null);
|
|
1059
|
+
return this.terminateJob(jobId, reason, "cancelled", null, "caller");
|
|
1060
|
+
}
|
|
1061
|
+
cancelJobForHosting(jobId, reason) {
|
|
1062
|
+
return this.terminateJob(jobId, reason, "cancelled", null, "provider");
|
|
1060
1063
|
}
|
|
1061
1064
|
async getCounters(jobId) {
|
|
1062
1065
|
const { rows } = await this.pool.query(
|
|
@@ -1209,7 +1212,7 @@ var PostgresJobStore = class {
|
|
|
1209
1212
|
* machine running the handler wakes as soon as the terminal status is
|
|
1210
1213
|
* visible.
|
|
1211
1214
|
*/
|
|
1212
|
-
async terminateJob(jobId, reason, terminalStatus, expectedActivityBefore) {
|
|
1215
|
+
async terminateJob(jobId, reason, terminalStatus, expectedActivityBefore, endedBy) {
|
|
1213
1216
|
const staleOnly = expectedActivityBefore !== null;
|
|
1214
1217
|
const client = await this.pool.connect();
|
|
1215
1218
|
try {
|
|
@@ -1241,7 +1244,7 @@ var PostgresJobStore = class {
|
|
|
1241
1244
|
);
|
|
1242
1245
|
await client.query(
|
|
1243
1246
|
`UPDATE jobs SET
|
|
1244
|
-
ended_by =
|
|
1247
|
+
ended_by = COALESCE($7::text, CASE WHEN status = 'awaiting-input' THEN 'caller' ELSE 'provider' END),
|
|
1245
1248
|
terminal_at_ms = $5,
|
|
1246
1249
|
caller_wait_ms = caller_wait_ms + CASE WHEN status = 'awaiting-input'
|
|
1247
1250
|
THEN GREATEST(0, $5 - COALESCE(awaiting_input_at_ms, last_activity_at)) ELSE 0 END,
|
|
@@ -1253,7 +1256,7 @@ var PostgresJobStore = class {
|
|
|
1253
1256
|
next_seq = $4 + 1,
|
|
1254
1257
|
last_activity_at = $5
|
|
1255
1258
|
WHERE id = $1`,
|
|
1256
|
-
[jobId, reason, JSON.stringify([cancelMsg]), nextSeq, now, terminalStatus,
|
|
1259
|
+
[jobId, reason, JSON.stringify([cancelMsg]), nextSeq, now, terminalStatus, endedBy]
|
|
1257
1260
|
);
|
|
1258
1261
|
await client.query("SELECT pg_notify('job_messages', $1)", [jobId]);
|
|
1259
1262
|
await client.query("COMMIT");
|
|
@@ -11,6 +11,9 @@ import {
|
|
|
11
11
|
import {
|
|
12
12
|
MemoryCreditLedger
|
|
13
13
|
} from "./chunk-U5VNEALI.js";
|
|
14
|
+
import {
|
|
15
|
+
PostgresJobStore
|
|
16
|
+
} from "./chunk-HHTL3ZFT.js";
|
|
14
17
|
import {
|
|
15
18
|
SIGNED_ENVELOPE_FIELDS,
|
|
16
19
|
SignedRequestError,
|
|
@@ -6756,6 +6759,18 @@ async function handleCreditRequest(c, deps) {
|
|
|
6756
6759
|
await deps.settleLightning(callerPubkey, body.credit_id);
|
|
6757
6760
|
return handleDrain(c, deps, { callerPubkey, body, envelope });
|
|
6758
6761
|
case "fund":
|
|
6762
|
+
if (deps.withFundingAdmission && body.fund) {
|
|
6763
|
+
const creditId = body.credit_id ?? derivedFundCreditId(callerPubkey, body.fund.fund_id);
|
|
6764
|
+
const [prior, invoice] = await Promise.all([
|
|
6765
|
+
deps.ledger.getFunding({ creditId, fundId: body.fund.fund_id }),
|
|
6766
|
+
body.fund.method === "lightning" ? deps.ledger.getInvoice({ creditId, fundId: body.fund.fund_id }) : Promise.resolve(void 0)
|
|
6767
|
+
]);
|
|
6768
|
+
const priorCredit = prior ? await deps.ledger.get(creditId) : void 0;
|
|
6769
|
+
if (priorCredit?.callerPubkey === callerPubkey || invoice?.callerPubkey === callerPubkey) {
|
|
6770
|
+
return handleFund(c, deps, { callerPubkey, body, envelope, menu });
|
|
6771
|
+
}
|
|
6772
|
+
return deps.withFundingAdmission(c, body, () => handleFund(c, deps, { callerPubkey, body, envelope, menu }));
|
|
6773
|
+
}
|
|
6759
6774
|
return handleFund(c, deps, { callerPubkey, body, envelope, menu });
|
|
6760
6775
|
}
|
|
6761
6776
|
}
|
|
@@ -9071,6 +9086,269 @@ function safeError(err) {
|
|
|
9071
9086
|
return "settlement_transport_error";
|
|
9072
9087
|
}
|
|
9073
9088
|
|
|
9089
|
+
// src/sdk/server/hosting-control.ts
|
|
9090
|
+
import { createHmac, timingSafeEqual } from "crypto";
|
|
9091
|
+
function signHostingControl(secret, command) {
|
|
9092
|
+
return createHmac("sha256", secret).update(JSON.stringify([
|
|
9093
|
+
"dvmkit-hosting-v1",
|
|
9094
|
+
command.action,
|
|
9095
|
+
command.scope,
|
|
9096
|
+
command.dvmId,
|
|
9097
|
+
command.generation ?? null,
|
|
9098
|
+
command.deadlineMs ?? null,
|
|
9099
|
+
command.timestampMs,
|
|
9100
|
+
command.nonce
|
|
9101
|
+
])).digest("hex");
|
|
9102
|
+
}
|
|
9103
|
+
var HostingControl = class {
|
|
9104
|
+
constructor(pool, dvmId, config) {
|
|
9105
|
+
this.pool = pool;
|
|
9106
|
+
this.dvmId = dvmId;
|
|
9107
|
+
this.config = config;
|
|
9108
|
+
if (Buffer.byteLength(config.secret) < 32 || !config.scope) {
|
|
9109
|
+
throw new Error("Hosting control requires a 32-byte secret and a non-empty scope");
|
|
9110
|
+
}
|
|
9111
|
+
}
|
|
9112
|
+
pool;
|
|
9113
|
+
dvmId;
|
|
9114
|
+
config;
|
|
9115
|
+
async init() {
|
|
9116
|
+
await withSdkInitLock(this.pool, async () => {
|
|
9117
|
+
await this.pool.query(`
|
|
9118
|
+
CREATE TABLE IF NOT EXISTS sdk_hosting_control (
|
|
9119
|
+
dvm_id TEXT NOT NULL, scope TEXT NOT NULL, state TEXT NOT NULL,
|
|
9120
|
+
generation BIGINT NOT NULL, deadline_ms BIGINT,
|
|
9121
|
+
PRIMARY KEY (dvm_id, scope)
|
|
9122
|
+
);
|
|
9123
|
+
CREATE TABLE IF NOT EXISTS sdk_hosting_nonces (
|
|
9124
|
+
dvm_id TEXT NOT NULL, scope TEXT NOT NULL, nonce TEXT NOT NULL,
|
|
9125
|
+
created_at_ms BIGINT NOT NULL,
|
|
9126
|
+
PRIMARY KEY (dvm_id, scope, nonce)
|
|
9127
|
+
);
|
|
9128
|
+
CREATE TABLE IF NOT EXISTS sdk_hosting_admissions (
|
|
9129
|
+
id TEXT PRIMARY KEY, dvm_id TEXT NOT NULL, scope TEXT NOT NULL,
|
|
9130
|
+
job_id TEXT NOT NULL, admitted_at_ms BIGINT NOT NULL,
|
|
9131
|
+
outcome TEXT NOT NULL DEFAULT 'pending', drain_deadline_ms BIGINT,
|
|
9132
|
+
credit_id TEXT, fund_id TEXT, payment_artifact_hash TEXT
|
|
9133
|
+
);
|
|
9134
|
+
ALTER TABLE sdk_hosting_admissions ADD COLUMN IF NOT EXISTS drain_deadline_ms BIGINT;
|
|
9135
|
+
ALTER TABLE sdk_hosting_admissions ADD COLUMN IF NOT EXISTS credit_id TEXT;
|
|
9136
|
+
ALTER TABLE sdk_hosting_admissions ADD COLUMN IF NOT EXISTS fund_id TEXT;
|
|
9137
|
+
ALTER TABLE sdk_hosting_admissions ADD COLUMN IF NOT EXISTS payment_artifact_hash TEXT;
|
|
9138
|
+
CREATE INDEX IF NOT EXISTS sdk_hosting_admissions_pending
|
|
9139
|
+
ON sdk_hosting_admissions (dvm_id, scope) WHERE outcome = 'pending';
|
|
9140
|
+
CREATE INDEX IF NOT EXISTS sdk_hosting_admissions_unresolved
|
|
9141
|
+
ON sdk_hosting_admissions (dvm_id, scope) WHERE outcome = 'unresolved';
|
|
9142
|
+
CREATE INDEX IF NOT EXISTS sdk_hosting_admissions_artifact
|
|
9143
|
+
ON sdk_hosting_admissions (dvm_id, scope, payment_artifact_hash)
|
|
9144
|
+
WHERE payment_artifact_hash IS NOT NULL;
|
|
9145
|
+
CREATE INDEX IF NOT EXISTS sdk_hosting_admissions_job
|
|
9146
|
+
ON sdk_hosting_admissions (dvm_id, job_id, scope);
|
|
9147
|
+
CREATE INDEX IF NOT EXISTS sdk_hosting_nonces_age ON sdk_hosting_nonces (created_at_ms);
|
|
9148
|
+
`);
|
|
9149
|
+
await this.pool.query(
|
|
9150
|
+
`INSERT INTO sdk_hosting_control (dvm_id, scope, state, generation)
|
|
9151
|
+
VALUES ($1, $2, 'accepting', 0) ON CONFLICT DO NOTHING`,
|
|
9152
|
+
[this.dvmId, this.config.scope]
|
|
9153
|
+
);
|
|
9154
|
+
});
|
|
9155
|
+
}
|
|
9156
|
+
async authorize(command, signature) {
|
|
9157
|
+
if (command.scope !== this.config.scope || command.dvmId !== this.dvmId || !Number.isSafeInteger(command.timestampMs) || Math.abs(Date.now() - command.timestampMs) > 3e5 || typeof command.nonce !== "string" || !/^[A-Za-z0-9_-]{16,128}$/.test(command.nonce) || !signature || !/^[0-9a-f]{64}$/i.test(signature)) return false;
|
|
9158
|
+
const actual = Buffer.from(signature, "hex");
|
|
9159
|
+
const expected = Buffer.from(signHostingControl(this.config.secret, command), "hex");
|
|
9160
|
+
if (!timingSafeEqual(actual, expected)) return false;
|
|
9161
|
+
const result = await this.pool.query(
|
|
9162
|
+
`INSERT INTO sdk_hosting_nonces (dvm_id, scope, nonce, created_at_ms)
|
|
9163
|
+
VALUES ($1, $2, $3, $4) ON CONFLICT DO NOTHING`,
|
|
9164
|
+
[this.dvmId, this.config.scope, command.nonce, Date.now()]
|
|
9165
|
+
);
|
|
9166
|
+
await this.pool.query("DELETE FROM sdk_hosting_nonces WHERE created_at_ms < $1", [Date.now() - 6e5]);
|
|
9167
|
+
return result.rowCount === 1;
|
|
9168
|
+
}
|
|
9169
|
+
async admit(id, jobId, details) {
|
|
9170
|
+
const client = await this.pool.connect();
|
|
9171
|
+
try {
|
|
9172
|
+
await client.query("BEGIN");
|
|
9173
|
+
const { rows } = await client.query(
|
|
9174
|
+
`SELECT state FROM sdk_hosting_control WHERE dvm_id=$1 AND scope=$2 FOR UPDATE`,
|
|
9175
|
+
[this.dvmId, this.config.scope]
|
|
9176
|
+
);
|
|
9177
|
+
if (rows[0]?.state !== "accepting") {
|
|
9178
|
+
await client.query("ROLLBACK");
|
|
9179
|
+
return false;
|
|
9180
|
+
}
|
|
9181
|
+
await client.query(
|
|
9182
|
+
`INSERT INTO sdk_hosting_admissions
|
|
9183
|
+
(id, dvm_id, scope, job_id, admitted_at_ms, credit_id, fund_id, payment_artifact_hash)
|
|
9184
|
+
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)`,
|
|
9185
|
+
[
|
|
9186
|
+
id,
|
|
9187
|
+
this.dvmId,
|
|
9188
|
+
this.config.scope,
|
|
9189
|
+
jobId,
|
|
9190
|
+
Date.now(),
|
|
9191
|
+
details?.creditId ?? null,
|
|
9192
|
+
details?.fundId ?? null,
|
|
9193
|
+
details?.paymentArtifactHash ?? null
|
|
9194
|
+
]
|
|
9195
|
+
);
|
|
9196
|
+
await client.query("COMMIT");
|
|
9197
|
+
return true;
|
|
9198
|
+
} catch (error) {
|
|
9199
|
+
await client.query("ROLLBACK").catch(() => void 0);
|
|
9200
|
+
throw error;
|
|
9201
|
+
} finally {
|
|
9202
|
+
client.release();
|
|
9203
|
+
}
|
|
9204
|
+
}
|
|
9205
|
+
async acceptedJobByPaymentArtifactHash(hash2) {
|
|
9206
|
+
const { rows } = await this.pool.query(
|
|
9207
|
+
`SELECT a.job_id FROM sdk_hosting_admissions a
|
|
9208
|
+
JOIN jobs j ON j.id=a.job_id
|
|
9209
|
+
WHERE a.dvm_id=$1 AND a.scope=$2 AND a.payment_artifact_hash=$3
|
|
9210
|
+
AND a.outcome IN ('accepted', 'unresolved', 'pending')
|
|
9211
|
+
ORDER BY a.admitted_at_ms DESC LIMIT 1`,
|
|
9212
|
+
[this.dvmId, this.config.scope, hash2]
|
|
9213
|
+
);
|
|
9214
|
+
return rows[0]?.job_id;
|
|
9215
|
+
}
|
|
9216
|
+
async rebindAdmissionJob(id, jobId) {
|
|
9217
|
+
await this.pool.query(
|
|
9218
|
+
`UPDATE sdk_hosting_admissions SET job_id=$2 WHERE id=$1 AND outcome='pending'`,
|
|
9219
|
+
[id, jobId]
|
|
9220
|
+
);
|
|
9221
|
+
}
|
|
9222
|
+
async finishAdmission(id, outcome, jobId) {
|
|
9223
|
+
await this.pool.query(
|
|
9224
|
+
`UPDATE sdk_hosting_admissions SET outcome=$2, job_id=COALESCE($3, job_id)
|
|
9225
|
+
WHERE id=$1 AND outcome='pending'`,
|
|
9226
|
+
[id, outcome, jobId ?? null]
|
|
9227
|
+
);
|
|
9228
|
+
}
|
|
9229
|
+
async jobDeadline(jobId) {
|
|
9230
|
+
const { rows } = await this.pool.query(
|
|
9231
|
+
`SELECT MAX(drain_deadline_ms)::text AS drain_deadline_ms
|
|
9232
|
+
FROM sdk_hosting_admissions WHERE dvm_id=$1 AND scope=$2 AND job_id=$3`,
|
|
9233
|
+
[this.dvmId, this.config.scope, jobId]
|
|
9234
|
+
);
|
|
9235
|
+
return rows[0]?.drain_deadline_ms === null || !rows[0] ? null : Number(rows[0].drain_deadline_ms);
|
|
9236
|
+
}
|
|
9237
|
+
async transition(command) {
|
|
9238
|
+
if (command.action !== "drain" && command.action !== "resume" || !Number.isSafeInteger(command.generation) || command.generation < 1 || command.action === "drain" && !Number.isSafeInteger(command.deadlineMs) || command.action === "resume" && command.deadlineMs !== void 0) return "conflict";
|
|
9239
|
+
const client = await this.pool.connect();
|
|
9240
|
+
try {
|
|
9241
|
+
await client.query("BEGIN");
|
|
9242
|
+
const { rows } = await client.query(
|
|
9243
|
+
`SELECT state, generation, deadline_ms FROM sdk_hosting_control
|
|
9244
|
+
WHERE dvm_id=$1 AND scope=$2 FOR UPDATE`,
|
|
9245
|
+
[this.dvmId, this.config.scope]
|
|
9246
|
+
);
|
|
9247
|
+
const prior = rows[0];
|
|
9248
|
+
const generation = Number(prior.generation);
|
|
9249
|
+
const nextState = command.action === "drain" ? "draining" : "accepting";
|
|
9250
|
+
if (command.generation === generation && prior.state === nextState && Number(prior.deadline_ms ?? 0) === (command.deadlineMs ?? 0)) {
|
|
9251
|
+
await client.query("COMMIT");
|
|
9252
|
+
return "ok";
|
|
9253
|
+
}
|
|
9254
|
+
if (command.generation <= generation) {
|
|
9255
|
+
await client.query("ROLLBACK");
|
|
9256
|
+
return "conflict";
|
|
9257
|
+
}
|
|
9258
|
+
if (command.action === "drain" && (command.deadlineMs <= Date.now() || command.deadlineMs > Date.now() + 864e5)) {
|
|
9259
|
+
await client.query("ROLLBACK");
|
|
9260
|
+
return "conflict";
|
|
9261
|
+
}
|
|
9262
|
+
await client.query(
|
|
9263
|
+
`UPDATE sdk_hosting_control SET state=$3, generation=$4, deadline_ms=$5
|
|
9264
|
+
WHERE dvm_id=$1 AND scope=$2`,
|
|
9265
|
+
[this.dvmId, this.config.scope, nextState, command.generation, command.deadlineMs ?? null]
|
|
9266
|
+
);
|
|
9267
|
+
if (command.action === "drain") {
|
|
9268
|
+
await client.query(
|
|
9269
|
+
`UPDATE sdk_hosting_admissions SET drain_deadline_ms=$3
|
|
9270
|
+
WHERE dvm_id=$1 AND scope=$2 AND outcome='pending'`,
|
|
9271
|
+
[this.dvmId, this.config.scope, command.deadlineMs]
|
|
9272
|
+
);
|
|
9273
|
+
}
|
|
9274
|
+
await client.query("COMMIT");
|
|
9275
|
+
return "ok";
|
|
9276
|
+
} catch (error) {
|
|
9277
|
+
await client.query("ROLLBACK").catch(() => void 0);
|
|
9278
|
+
throw error;
|
|
9279
|
+
} finally {
|
|
9280
|
+
client.release();
|
|
9281
|
+
}
|
|
9282
|
+
}
|
|
9283
|
+
async status() {
|
|
9284
|
+
await this.pool.query(
|
|
9285
|
+
`UPDATE sdk_hosting_admissions a SET outcome='accepted'
|
|
9286
|
+
WHERE a.dvm_id=$1 AND a.scope=$2 AND a.outcome='pending'
|
|
9287
|
+
AND EXISTS (SELECT 1 FROM jobs j WHERE j.id=a.job_id)`,
|
|
9288
|
+
[this.dvmId, this.config.scope]
|
|
9289
|
+
);
|
|
9290
|
+
const creditTable = await this.pool.query(
|
|
9291
|
+
"SELECT to_regclass('credit_fundings') IS NOT NULL AS present"
|
|
9292
|
+
);
|
|
9293
|
+
await this.pool.query(
|
|
9294
|
+
`UPDATE sdk_hosting_admissions a SET outcome='accepted'
|
|
9295
|
+
WHERE a.dvm_id=$1 AND a.scope=$2 AND a.outcome='unresolved'
|
|
9296
|
+
AND (EXISTS (SELECT 1 FROM jobs j WHERE j.id=a.job_id)
|
|
9297
|
+
${creditTable.rows[0].present ? `OR (a.credit_id IS NOT NULL AND EXISTS (
|
|
9298
|
+
SELECT 1 FROM credit_fundings f WHERE f.credit_id=a.credit_id AND f.fund_id=a.fund_id
|
|
9299
|
+
))` : ""})`,
|
|
9300
|
+
[this.dvmId, this.config.scope]
|
|
9301
|
+
);
|
|
9302
|
+
const { rows } = await this.pool.query(
|
|
9303
|
+
`SELECT state, generation, deadline_ms FROM sdk_hosting_control WHERE dvm_id=$1 AND scope=$2`,
|
|
9304
|
+
[this.dvmId, this.config.scope]
|
|
9305
|
+
);
|
|
9306
|
+
const active = await this.pool.query(
|
|
9307
|
+
`SELECT j.id FROM jobs j WHERE j.dvm_id=$1
|
|
9308
|
+
AND j.status IN ('processing', 'working', 'awaiting-input')
|
|
9309
|
+
AND EXISTS (SELECT 1 FROM sdk_hosting_admissions a
|
|
9310
|
+
WHERE a.dvm_id=j.dvm_id AND a.job_id=j.id AND a.scope=$2)
|
|
9311
|
+
ORDER BY j.id`,
|
|
9312
|
+
[this.dvmId, this.config.scope]
|
|
9313
|
+
);
|
|
9314
|
+
const unowned = await this.pool.query(
|
|
9315
|
+
`SELECT j.id FROM jobs j WHERE j.dvm_id=$1
|
|
9316
|
+
AND j.status IN ('processing', 'working', 'awaiting-input')
|
|
9317
|
+
AND NOT EXISTS (SELECT 1 FROM sdk_hosting_admissions a
|
|
9318
|
+
WHERE a.dvm_id=j.dvm_id AND a.job_id=j.id)
|
|
9319
|
+
ORDER BY j.id`,
|
|
9320
|
+
[this.dvmId]
|
|
9321
|
+
);
|
|
9322
|
+
const pending = await this.pool.query(
|
|
9323
|
+
`SELECT COUNT(*) FILTER (WHERE outcome='pending')::text AS pending,
|
|
9324
|
+
COUNT(*) FILTER (WHERE outcome='unresolved')::text AS unresolved
|
|
9325
|
+
FROM sdk_hosting_admissions WHERE dvm_id=$1 AND scope=$2`,
|
|
9326
|
+
[this.dvmId, this.config.scope]
|
|
9327
|
+
);
|
|
9328
|
+
const unresolved = await this.pool.query(
|
|
9329
|
+
`SELECT id, job_id FROM sdk_hosting_admissions
|
|
9330
|
+
WHERE dvm_id=$1 AND scope=$2 AND outcome='unresolved' ORDER BY admitted_at_ms, id`,
|
|
9331
|
+
[this.dvmId, this.config.scope]
|
|
9332
|
+
);
|
|
9333
|
+
const inFlight = await this.pool.query(
|
|
9334
|
+
`SELECT id, job_id FROM sdk_hosting_admissions
|
|
9335
|
+
WHERE dvm_id=$1 AND scope=$2 AND outcome='pending' ORDER BY admitted_at_ms, id`,
|
|
9336
|
+
[this.dvmId, this.config.scope]
|
|
9337
|
+
);
|
|
9338
|
+
return {
|
|
9339
|
+
state: rows[0].state,
|
|
9340
|
+
generation: Number(rows[0].generation),
|
|
9341
|
+
deadlineMs: rows[0].deadline_ms === null ? null : Number(rows[0].deadline_ms),
|
|
9342
|
+
activeJobIds: active.rows.map((row) => row.id),
|
|
9343
|
+
unownedActiveJobIds: unowned.rows.map((row) => row.id),
|
|
9344
|
+
pendingAdmissionCount: Number(pending.rows[0].pending),
|
|
9345
|
+
pendingAdmissions: inFlight.rows.map((row) => ({ admissionId: row.id, workId: row.job_id })),
|
|
9346
|
+
unresolvedAdmissionCount: Number(pending.rows[0].unresolved),
|
|
9347
|
+
unresolvedAdmissions: unresolved.rows.map((row) => ({ admissionId: row.id, jobId: row.job_id }))
|
|
9348
|
+
};
|
|
9349
|
+
}
|
|
9350
|
+
};
|
|
9351
|
+
|
|
9074
9352
|
// src/sdk/server/job-credential.ts
|
|
9075
9353
|
function jobCredentialGate(opts) {
|
|
9076
9354
|
const alternative = opts.acceptsBearer ? ", or the Authorization: Bearer token the job was submitted with" : "";
|
|
@@ -16730,6 +17008,7 @@ async function createDVMServer(descriptor, opts) {
|
|
|
16730
17008
|
let x402ChannelStorage;
|
|
16731
17009
|
let x402BatchSettlement;
|
|
16732
17010
|
let server;
|
|
17011
|
+
let hostingControl;
|
|
16733
17012
|
let shutdownPromise;
|
|
16734
17013
|
const shutdown = () => shutdownPromise ??= (async () => {
|
|
16735
17014
|
const errors = [];
|
|
@@ -16923,8 +17202,19 @@ async function createDVMServer(descriptor, opts) {
|
|
|
16923
17202
|
});
|
|
16924
17203
|
}
|
|
16925
17204
|
}) : void 0;
|
|
17205
|
+
if (opts.hostingControl) {
|
|
17206
|
+
if (!opts.db || !opts.dvmId || !(opts.jobStore instanceof PostgresJobStore)) {
|
|
17207
|
+
throw new Error("Hosting control requires a Postgres pool, dvmId, and PostgresJobStore");
|
|
17208
|
+
}
|
|
17209
|
+
if (descriptor.credit && !opts.creditLedger?.durable) {
|
|
17210
|
+
throw new Error("Hosting control with credit requires a durable credit ledger");
|
|
17211
|
+
}
|
|
17212
|
+
hostingControl = new HostingControl(opts.db, opts.dvmId, opts.hostingControl);
|
|
17213
|
+
await hostingControl.init();
|
|
17214
|
+
}
|
|
16926
17215
|
server = new DVMServer(descriptor, {
|
|
16927
17216
|
...opts,
|
|
17217
|
+
hostingControlInstance: hostingControl,
|
|
16928
17218
|
creditLedger,
|
|
16929
17219
|
processedPayments,
|
|
16930
17220
|
onJobCompleted: effectiveOnJobCompleted,
|
|
@@ -17001,6 +17291,7 @@ var DVMServer = class {
|
|
|
17001
17291
|
x402ExactSettlement;
|
|
17002
17292
|
/** Withdraws this mount's Tempo session capability from the poll. */
|
|
17003
17293
|
undeclareSessionCapability;
|
|
17294
|
+
hostingSweepTimer;
|
|
17004
17295
|
constructor(descriptor, opts) {
|
|
17005
17296
|
this.descriptor = descriptor;
|
|
17006
17297
|
this.pricingCurrency = descriptor.currency ?? "usd";
|
|
@@ -17084,6 +17375,17 @@ var DVMServer = class {
|
|
|
17084
17375
|
this.app = new Hono();
|
|
17085
17376
|
try {
|
|
17086
17377
|
this.registerRoutes();
|
|
17378
|
+
if (opts.hostingControlInstance) {
|
|
17379
|
+
this.hostingSweepTimer = setInterval(() => {
|
|
17380
|
+
void this.sweepHostingDeadline().catch((error) => {
|
|
17381
|
+
console.error("Hosting deadline sweep failed:", error);
|
|
17382
|
+
});
|
|
17383
|
+
}, 1e3);
|
|
17384
|
+
this.hostingSweepTimer.unref();
|
|
17385
|
+
void this.sweepHostingDeadline().catch((error) => {
|
|
17386
|
+
console.error("Hosting deadline sweep failed:", error);
|
|
17387
|
+
});
|
|
17388
|
+
}
|
|
17087
17389
|
if (this.ownsMintHealthTracker) this.mintHealthTracker?.start();
|
|
17088
17390
|
if (this.opts.tempoObserverHealth?.declareSessionCapability) {
|
|
17089
17391
|
this.undeclareSessionCapability = this.opts.tempoObserverHealth.declareSessionCapability(
|
|
@@ -17117,6 +17419,7 @@ var DVMServer = class {
|
|
|
17117
17419
|
* and host teardown layers can finish later cleanup before surfacing it.
|
|
17118
17420
|
*/
|
|
17119
17421
|
shutdown() {
|
|
17422
|
+
if (this.hostingSweepTimer) clearInterval(this.hostingSweepTimer);
|
|
17120
17423
|
this.jobManager.shutdown();
|
|
17121
17424
|
const settlement = this.x402BatchSettlementInit ?? Promise.resolve(this.x402BatchSettlement);
|
|
17122
17425
|
const stopped = settlement.then((s) => s?.stop());
|
|
@@ -17125,6 +17428,42 @@ var DVMServer = class {
|
|
|
17125
17428
|
this.undeclareSessionCapability = void 0;
|
|
17126
17429
|
return stopped;
|
|
17127
17430
|
}
|
|
17431
|
+
async sweepHostingDeadline() {
|
|
17432
|
+
const control = this.opts.hostingControlInstance;
|
|
17433
|
+
if (!control) return;
|
|
17434
|
+
const status = await control.status();
|
|
17435
|
+
if (status.state !== "draining" || status.deadlineMs === null || Date.now() < status.deadlineMs)
|
|
17436
|
+
return;
|
|
17437
|
+
const store = this.jobManager.store;
|
|
17438
|
+
if (!(store instanceof PostgresJobStore)) return;
|
|
17439
|
+
for (const jobId of status.activeJobIds) {
|
|
17440
|
+
if (await store.cancelJobForHosting(jobId, "Hosting drain deadline reached")) {
|
|
17441
|
+
await this.jobManager.finalizeStoredTerminal(jobId);
|
|
17442
|
+
}
|
|
17443
|
+
}
|
|
17444
|
+
}
|
|
17445
|
+
async handleHostingCommand(c, statusOnly) {
|
|
17446
|
+
const control = this.opts.hostingControlInstance;
|
|
17447
|
+
if (!control) return c.json({ error: "not_found" }, 404);
|
|
17448
|
+
let command;
|
|
17449
|
+
try {
|
|
17450
|
+
command = await c.req.json();
|
|
17451
|
+
} catch {
|
|
17452
|
+
return c.json({ error: "invalid_hosting_control" }, 400);
|
|
17453
|
+
}
|
|
17454
|
+
if (!command || (statusOnly ? command.action !== "status" : command.action !== "drain" && command.action !== "resume")) {
|
|
17455
|
+
return c.json({ error: "invalid_hosting_control" }, 400);
|
|
17456
|
+
}
|
|
17457
|
+
if (!await control.authorize(command, c.req.header("X-DVM-Hosting-Signature"))) {
|
|
17458
|
+
return c.json({ error: "hosting_control_unauthorized" }, 401);
|
|
17459
|
+
}
|
|
17460
|
+
if (!statusOnly && command.action === "resume") await this.sweepHostingDeadline();
|
|
17461
|
+
if (!statusOnly && await control.transition(command) === "conflict") {
|
|
17462
|
+
return c.json({ error: "hosting_generation_conflict" }, 409);
|
|
17463
|
+
}
|
|
17464
|
+
if (!statusOnly) await this.sweepHostingDeadline();
|
|
17465
|
+
return c.json(await control.status());
|
|
17466
|
+
}
|
|
17128
17467
|
registerRoutes() {
|
|
17129
17468
|
const dvmSlug = this.descriptor.name;
|
|
17130
17469
|
const builderPubkey = this.opts.builder?.pubkey;
|
|
@@ -17232,6 +17571,10 @@ var DVMServer = class {
|
|
|
17232
17571
|
this.app.get("/v1/info", (c) => this.handleInfo(c));
|
|
17233
17572
|
this.app.post("/v1/quote", (c) => this.handleQuote(c));
|
|
17234
17573
|
this.app.post("/v1/job", (c) => this.handleCreateJob(c));
|
|
17574
|
+
if (this.opts.hostingControlInstance) {
|
|
17575
|
+
this.app.post("/_hosting/control", (c) => this.handleHostingCommand(c, false));
|
|
17576
|
+
this.app.post("/_hosting/status", (c) => this.handleHostingCommand(c, true));
|
|
17577
|
+
}
|
|
17235
17578
|
this.app.post("/v1/request-resume/:requestId", (c) => this.handleCreateJob(c, true));
|
|
17236
17579
|
this.app.post("/v1/request-result/:requestId", (c) => this.handleRequestResult(c));
|
|
17237
17580
|
this.app.get("/v1/job/:id", (c) => this.handleGetJob(c));
|
|
@@ -17850,6 +18193,32 @@ var DVMServer = class {
|
|
|
17850
18193
|
receiptIssuer: this.receiptIssuer,
|
|
17851
18194
|
lightning: this.opts.lightningReceive ? { receive: this.opts.lightningReceive } : void 0,
|
|
17852
18195
|
settleLightning: (callerPubkey, creditId) => this.settleLightningFunding(callerPubkey, creditId),
|
|
18196
|
+
withFundingAdmission: this.opts.hostingControlInstance ? async (ctx, body, run) => {
|
|
18197
|
+
const control = this.opts.hostingControlInstance;
|
|
18198
|
+
const admissionId = randomUUID4();
|
|
18199
|
+
const fundId = body.fund?.fund_id ?? admissionId;
|
|
18200
|
+
const creditId = body.credit_id ?? derivedFundCreditId(body.pubkey, fundId);
|
|
18201
|
+
const workId = `credit-fund:${creditId}:${fundId}`;
|
|
18202
|
+
if (!await control.admit(admissionId, workId, { creditId, fundId })) {
|
|
18203
|
+
return ctx.json({
|
|
18204
|
+
error: "hosting_draining",
|
|
18205
|
+
message: "This service is draining and is not accepting new credit funding.",
|
|
18206
|
+
hint: "Balance, reclaim, and already-issued funding recovery remain available."
|
|
18207
|
+
}, 503);
|
|
18208
|
+
}
|
|
18209
|
+
const authorization = ctx.req.header("Authorization");
|
|
18210
|
+
const paymentArtifact = Boolean(
|
|
18211
|
+
ctx.req.header("X-Cashu") || ctx.req.header("PAYMENT-SIGNATURE") || ctx.req.header("X-PAYMENT") || authorization && /^Payment\s/i.test(authorization)
|
|
18212
|
+
);
|
|
18213
|
+
let outcome = paymentArtifact ? "unresolved" : "failed";
|
|
18214
|
+
try {
|
|
18215
|
+
const response = await run();
|
|
18216
|
+
if (response.ok || body.fund?.method === "lightning" && await this.creditLedger.getInvoice({ creditId, fundId })) outcome = "accepted";
|
|
18217
|
+
return response;
|
|
18218
|
+
} finally {
|
|
18219
|
+
await control.finishAdmission(admissionId, outcome);
|
|
18220
|
+
}
|
|
18221
|
+
} : void 0,
|
|
17853
18222
|
tempoSettlementReadiness: this.opts.tempoSettlementReadiness
|
|
17854
18223
|
});
|
|
17855
18224
|
}
|
|
@@ -18514,8 +18883,40 @@ var DVMServer = class {
|
|
|
18514
18883
|
{ capability: capabilityName, input: body.input, params: body.params, data: body.data },
|
|
18515
18884
|
{ stripAuthEnvelope: false }
|
|
18516
18885
|
) : void 0;
|
|
18886
|
+
const authorization = c.req.header("Authorization");
|
|
18887
|
+
const attachedPayment = c.req.header("X-Cashu") ?? c.req.header("PAYMENT-SIGNATURE") ?? c.req.header("X-PAYMENT") ?? (authorization && /^Payment\s/i.test(authorization) ? authorization : void 0);
|
|
18888
|
+
const hostingPaymentArtifactHash = attachedPayment ? createHash7("sha256").update(attachedPayment).digest("hex") : void 0;
|
|
18889
|
+
if (!resumeOnly && this.opts.hostingControlInstance && hostingPaymentArtifactHash) {
|
|
18890
|
+
const priorId = await this.opts.hostingControlInstance.acceptedJobByPaymentArtifactHash(
|
|
18891
|
+
hostingPaymentArtifactHash
|
|
18892
|
+
);
|
|
18893
|
+
const prior = priorId ? await this.jobManager.store.get(priorId) : void 0;
|
|
18894
|
+
if (prior && prior.requestFingerprint === fingerprint && prior.requesterId === c.get("requesterId") && (!this.descriptor.auth || prior.requesterPubkey === authPubkey)) {
|
|
18895
|
+
await this.jobManager.ensureReceipt(prior);
|
|
18896
|
+
return buildSubmitResponse(c, prior, prior.requesterToken);
|
|
18897
|
+
}
|
|
18898
|
+
}
|
|
18899
|
+
if (!resumeOnly && this.opts.hostingControlInstance && creditEnvelope && authPubkey) {
|
|
18900
|
+
const draw = await this.creditLedger.getDraw({
|
|
18901
|
+
creditId: creditEnvelope.creditId,
|
|
18902
|
+
drawId: creditEnvelope.drawId
|
|
18903
|
+
});
|
|
18904
|
+
if (draw?.jobId && await this.jobManager.store.get(draw.jobId)) {
|
|
18905
|
+
const recovered = await this.recoverDrawnJob(c, {
|
|
18906
|
+
creditId: creditEnvelope.creditId,
|
|
18907
|
+
drawId: creditEnvelope.drawId,
|
|
18908
|
+
jobId: draw.jobId,
|
|
18909
|
+
fingerprint,
|
|
18910
|
+
callerPubkey: authPubkey
|
|
18911
|
+
});
|
|
18912
|
+
if (recovered) return recovered;
|
|
18913
|
+
}
|
|
18914
|
+
}
|
|
18517
18915
|
let publicRequestClaim;
|
|
18518
18916
|
let publicRequestClaimResult;
|
|
18917
|
+
let hostingAdmissionId;
|
|
18918
|
+
let hostingAdmissionAccepted = false;
|
|
18919
|
+
let hostingPaymentMayHaveLanded = false;
|
|
18519
18920
|
if (publicRequestId && authPubkey && recoveryStore) {
|
|
18520
18921
|
publicRequestClaim = {
|
|
18521
18922
|
requestId: publicRequestId,
|
|
@@ -18538,6 +18939,18 @@ var DVMServer = class {
|
|
|
18538
18939
|
}
|
|
18539
18940
|
}
|
|
18540
18941
|
let jobId = publicRequestClaimResult?.jobId ?? this.jobManager.allocateJobId();
|
|
18942
|
+
if (!resumeOnly && this.opts.hostingControlInstance) {
|
|
18943
|
+
hostingAdmissionId = randomUUID4();
|
|
18944
|
+
if (!await this.opts.hostingControlInstance.admit(hostingAdmissionId, jobId, {
|
|
18945
|
+
paymentArtifactHash: hostingPaymentArtifactHash
|
|
18946
|
+
})) {
|
|
18947
|
+
return c.json({
|
|
18948
|
+
error: "hosting_draining",
|
|
18949
|
+
message: "This service is draining and is not accepting new jobs or payments.",
|
|
18950
|
+
hint: "Keep any existing job token to fetch its result or reclaim unused credit. Retry a new job after service resumes."
|
|
18951
|
+
}, 503);
|
|
18952
|
+
}
|
|
18953
|
+
}
|
|
18541
18954
|
let payment = { paidMsats: 0, receivedProofs: [] };
|
|
18542
18955
|
let resumedAcceptedPayment = false;
|
|
18543
18956
|
if (resumeOnly) {
|
|
@@ -18594,6 +19007,9 @@ var DVMServer = class {
|
|
|
18594
19007
|
const skipPayment = devModeSkipsPaymentVerification(this.opts);
|
|
18595
19008
|
if (!skipPayment && !resumedAcceptedPayment) {
|
|
18596
19009
|
const railOpts = await this.railVerifyOpts(c);
|
|
19010
|
+
hostingPaymentMayHaveLanded = Boolean(
|
|
19011
|
+
creditEnvelope || railOpts.cashuToken || railOpts.x402Payment || railOpts.mppCredential
|
|
19012
|
+
);
|
|
18597
19013
|
try {
|
|
18598
19014
|
payment = await loggers.isolate.span(
|
|
18599
19015
|
"dvm.payment.validate",
|
|
@@ -18707,8 +19123,12 @@ var DVMServer = class {
|
|
|
18707
19123
|
);
|
|
18708
19124
|
}
|
|
18709
19125
|
const exactAdmission = payment.x402ExactAdmission;
|
|
19126
|
+
hostingPaymentMayHaveLanded ||= resumedAcceptedPayment || payment.paidMsats > 0 || Boolean(payment.funding || exactAdmission);
|
|
18710
19127
|
if (exactAdmission) {
|
|
18711
19128
|
jobId = exactAdmission.jobId;
|
|
19129
|
+
if (hostingAdmissionId) {
|
|
19130
|
+
await this.opts.hostingControlInstance.rebindAdmissionJob(hostingAdmissionId, jobId);
|
|
19131
|
+
}
|
|
18712
19132
|
const prior = await this.jobManager.store.get(jobId);
|
|
18713
19133
|
if (prior) {
|
|
18714
19134
|
if (prior.requestFingerprint !== fingerprint || prior.requesterPubkey !== authPubkey || prior.requesterId !== c.get("requesterId")) {
|
|
@@ -18769,6 +19189,21 @@ var DVMServer = class {
|
|
|
18769
19189
|
}
|
|
18770
19190
|
);
|
|
18771
19191
|
await jm.persistJob(job);
|
|
19192
|
+
if (hostingAdmissionId) {
|
|
19193
|
+
await this.opts.hostingControlInstance.finishAdmission(hostingAdmissionId, "accepted", jobId);
|
|
19194
|
+
hostingAdmissionAccepted = true;
|
|
19195
|
+
}
|
|
19196
|
+
const reservedDrainDeadline = this.opts.hostingControlInstance ? await this.opts.hostingControlInstance.jobDeadline(jobId) : null;
|
|
19197
|
+
const hostingStatus = await this.opts.hostingControlInstance?.status();
|
|
19198
|
+
const currentDrainDeadline = hostingStatus?.state === "draining" ? hostingStatus.deadlineMs : null;
|
|
19199
|
+
if (reservedDrainDeadline !== null && Date.now() >= reservedDrainDeadline || currentDrainDeadline !== null && currentDrainDeadline !== void 0 && Date.now() >= currentDrainDeadline) {
|
|
19200
|
+
const store = jm.store;
|
|
19201
|
+
if (store instanceof PostgresJobStore && await store.cancelJobForHosting(jobId, "Hosting drain deadline reached")) {
|
|
19202
|
+
await jm.finalizeStoredTerminal(jobId);
|
|
19203
|
+
}
|
|
19204
|
+
const terminal = await store.get(jobId);
|
|
19205
|
+
if (terminal) return buildSubmitResponse(c, terminal, jobToken);
|
|
19206
|
+
}
|
|
18772
19207
|
if (exactAdmission) {
|
|
18773
19208
|
await this.x402ExactSettlement?.completeAdmission(
|
|
18774
19209
|
this.opts.dvmId ?? "",
|
|
@@ -18790,6 +19225,12 @@ var DVMServer = class {
|
|
|
18790
19225
|
}
|
|
18791
19226
|
return response;
|
|
18792
19227
|
} finally {
|
|
19228
|
+
if (hostingAdmissionId && !hostingAdmissionAccepted) {
|
|
19229
|
+
await this.opts.hostingControlInstance.finishAdmission(
|
|
19230
|
+
hostingAdmissionId,
|
|
19231
|
+
hostingPaymentMayHaveLanded ? "unresolved" : "failed"
|
|
19232
|
+
);
|
|
19233
|
+
}
|
|
18793
19234
|
if (publicRequestClaim && recoveryStore) {
|
|
18794
19235
|
await recoveryStore.releaseRequestIdClaim(publicRequestClaim);
|
|
18795
19236
|
}
|
|
@@ -19921,6 +20362,7 @@ export {
|
|
|
19921
20362
|
createAdminCashuNonceStore,
|
|
19922
20363
|
X402ExactSettlementServer,
|
|
19923
20364
|
X402ExactSettlementEvidenceMissingError,
|
|
20365
|
+
signHostingControl,
|
|
19924
20366
|
jobCredentialGate,
|
|
19925
20367
|
REQUEST_ID_FIELD,
|
|
19926
20368
|
protocolEnvelopeIgnoreFields,
|
|
@@ -181,6 +181,41 @@ interface CreditExpirySweepOpts {
|
|
|
181
181
|
limit?: number;
|
|
182
182
|
}
|
|
183
183
|
|
|
184
|
+
interface HostingControlConfig {
|
|
185
|
+
/** Dedicated management key. Use at least 32 random bytes; never reuse a caller or builder key. */
|
|
186
|
+
secret: string;
|
|
187
|
+
/** Deployment scope shared by the platform and this DVM, independent of its caller origin. */
|
|
188
|
+
scope: string;
|
|
189
|
+
}
|
|
190
|
+
interface HostingControlCommand {
|
|
191
|
+
action: "drain" | "resume" | "status";
|
|
192
|
+
scope: string;
|
|
193
|
+
dvmId: string;
|
|
194
|
+
timestampMs: number;
|
|
195
|
+
nonce: string;
|
|
196
|
+
generation?: number;
|
|
197
|
+
deadlineMs?: number;
|
|
198
|
+
}
|
|
199
|
+
/** The ordered JSON array is the version-one wire signing contract. */
|
|
200
|
+
declare function signHostingControl(secret: string, command: HostingControlCommand): string;
|
|
201
|
+
interface HostingControlStatus {
|
|
202
|
+
state: "accepting" | "draining";
|
|
203
|
+
generation: number;
|
|
204
|
+
deadlineMs: number | null;
|
|
205
|
+
activeJobIds: string[];
|
|
206
|
+
unownedActiveJobIds: string[];
|
|
207
|
+
pendingAdmissionCount: number;
|
|
208
|
+
pendingAdmissions: {
|
|
209
|
+
admissionId: string;
|
|
210
|
+
workId: string;
|
|
211
|
+
}[];
|
|
212
|
+
unresolvedAdmissionCount: number;
|
|
213
|
+
unresolvedAdmissions: {
|
|
214
|
+
admissionId: string;
|
|
215
|
+
jobId: string;
|
|
216
|
+
}[];
|
|
217
|
+
}
|
|
218
|
+
|
|
184
219
|
interface PromptResolver {
|
|
185
220
|
resolve: (value: ResponseContent) => void;
|
|
186
221
|
reject: (reason: Error) => void;
|
|
@@ -3676,6 +3711,8 @@ interface DVMServeResult {
|
|
|
3676
3711
|
paymentModes: PaymentMode[];
|
|
3677
3712
|
}
|
|
3678
3713
|
interface DVMHostOpts {
|
|
3714
|
+
/** Dedicated hosting-management authority for each mounted DVM. Requires durable Postgres. */
|
|
3715
|
+
hostingControl?: HostingControlConfig;
|
|
3679
3716
|
/**
|
|
3680
3717
|
* Postgres connection string. Defaults to `DATABASE_URL` env.
|
|
3681
3718
|
* Required at runtime. Boot fails when missing unless `jobStore`
|
|
@@ -4054,6 +4091,8 @@ interface SDKServerOpts {
|
|
|
4054
4091
|
canonicalDvmId?: string;
|
|
4055
4092
|
/** Postgres pool for builder admin state and wallet accumulator persistence. */
|
|
4056
4093
|
db?: Pool;
|
|
4094
|
+
/** Enables authenticated, durable hosting admission and bounded drain. Requires Postgres and dvmId. */
|
|
4095
|
+
hostingControl?: HostingControlConfig;
|
|
4057
4096
|
/**
|
|
4058
4097
|
* Host strict-mode flag. Reporter readiness follows hosted context regardless
|
|
4059
4098
|
* of this value.
|
|
@@ -4370,4 +4409,4 @@ declare function attachCreditMenu(body: Record<string, unknown>, menu: CreditMen
|
|
|
4370
4409
|
*/
|
|
4371
4410
|
declare function toCreditTerms(menu: CreditMenu): CreditTerms;
|
|
4372
4411
|
|
|
4373
|
-
export { isTerminal as $, type AccumulatorPool as A, buildPaymentErrorResponse as B, type ConsumedCredentialStore as C, clearAccumulatorForDvm as D, createDVMServer as E, type FiatDenomination as F, creditDepositPayload as G, derivedFundCreditId as H, type IncomingPaymentOpts as I, JobCancelledError as J, devModeSkipsPaymentVerification as K, fromJobRecord as L, MintHealthTracker as M, fundedMicroFor as N, hasPaymentProof as O, PAYMENT_PROOF_KEYS as P, hashLockKey as Q, type ReporterBannerOpts as R, type SDKServerOpts as S, type TempoChannelReport as T, type UpfrontPaymentOpts as U, type VerifiedIncomingPayment as V, implicitCreditId as W, type X402BatchChannelObservation as X, initWalletAccumulatorTable as Y, insertAccumulatorRows as Z, isDerivedCreditId as _, type AccumulatorQuerier as a, type
|
|
4412
|
+
export { isTerminal as $, type AccumulatorPool as A, buildPaymentErrorResponse as B, type ConsumedCredentialStore as C, clearAccumulatorForDvm as D, createDVMServer as E, type FiatDenomination as F, creditDepositPayload as G, derivedFundCreditId as H, type IncomingPaymentOpts as I, JobCancelledError as J, devModeSkipsPaymentVerification as K, fromJobRecord as L, MintHealthTracker as M, fundedMicroFor as N, hasPaymentProof as O, PAYMENT_PROOF_KEYS as P, hashLockKey as Q, type ReporterBannerOpts as R, type SDKServerOpts as S, type TempoChannelReport as T, type UpfrontPaymentOpts as U, type VerifiedIncomingPayment as V, implicitCreditId as W, type X402BatchChannelObservation as X, initWalletAccumulatorTable as Y, insertAccumulatorRows as Z, isDerivedCreditId as _, type AccumulatorQuerier as a, type X402BatchSettlementServer as a$, isYieldMessage as a0, issueUpfrontChallenges as a1, msatsToFiatMicro as a2, paymentErrorBody as a3, pinAskFiat as a4, priceFiatMicro as a5, processIncomingPayment as a6, providerMessage as a7, repairX402ExactSettlementEffect as a8, resolveFxSnapshot as a9, type HostingControlCommand as aA, type HostingControlConfig as aB, type HostingControlStatus as aC, JobManager as aD, type JobManagerOpts as aE, type LightningReceiveConfig as aF, MIN_INVOICE_TTL_SECONDS as aG, MemoryConsumedCredentialStore as aH, type MemoryConsumedCredentialStoreOpts as aI, MemoryProcessedPaymentStore as aJ, MemoryX402ExactSettlementStore as aK, type MountOpts as aL, type OwnerDisplay as aM, type PaidJobCompletion as aN, type PaymentMode as aO, type PlatformReporterOpts as aP, PostgresProcessedPaymentStore as aQ, PostgresX402ExactSettlementStore as aR, type PriceFiat as aS, type ProcessedPaymentQuerier as aT, type ProcessedPaymentRail as aU, type ProcessedPaymentRecord as aV, ProcessedPaymentReplayError as aW, type ProcessedPaymentStore as aX, type X402BatchAcceptance as aY, type X402BatchFunding as aZ, type X402BatchRefusal as a_, resolvePriceFiat as aa, revenueReporterBannerState as ab, toCreditTerms as ac, toJobRecord as ad, unknownRouteNotFound as ae, verifyIncomingPayment as af, verifyTempoSessionManagementCredential as ag, verifyUpfrontPayment as ah, x402RequiredUsdcMicro as ai, x402SettledShare as aj, type CreditMenu as ak, ReceiptIssuer as al, LightningReceive as am, TempoSettlementReadiness as an, type DVMHostOpts as ao, type DVMServeResult as ap, type BuildCreditMenuArgs as aq, type BuilderIdentity as ar, CREDIT_ENVELOPE_KEYS as as, type CreateX402BatchSettlementServerOpts as at, type CreditEnvelope as au, CreditEnvelopeError as av, type CreditFundCommitment as aw, type CreditTerms as ax, DEFAULT_INVOICE_TTL_SECONDS as ay, type DVMHost as az, type AppEnv as b, type X402ExactAcceptance as b0, X402ExactIntentConflictError as b1, type X402ExactSettlementAttempt as b2, type X402ExactSettlementChainEvidence as b3, type X402ExactSettlementEffect as b4, X402ExactSettlementEvidenceMissingError as b5, type X402ExactSettlementEvidenceReader as b6, type X402ExactSettlementIntent as b7, X402ExactSettlementNotReadyError as b8, X402ExactSettlementServer as b9, type X402ExactSettlementServerOpts as ba, type X402ExactSettlementStatus as bb, type X402ExactSettlementStore as bc, type X402SettlementChainEvidence as bd, type X402SettlementEvidenceReader as be, X402SettlementSubmissionError as bf, X402_BATCH_AUTO_SETTLEMENT as bg, X402_BATCH_MIN_WITHDRAW_DELAY_SECONDS as bh, X402_BATCH_SETTLEMENT_NETWORK as bi, attachCreditMenu as bj, buildCreditMenu as bk, createDVMHost as bl, createX402BatchSettlementServer as bm, creditEnvelopeIgnoreFields as bn, drawSettlementRef as bo, extractCreditEnvelope as bp, fundingCommitment as bq, selectPrimaryCredit as br, signHostingControl as bs, stripCreditEnvelope as bt, toCreditView as bu, type CreditFundingReport as c, type FiatDenominationFailure as d, type FundOnlyRequest as e, type PaymentErrorCode as f, type PaymentErrorDetail as g, type PaymentInfo as h, type ResolvedFx as i, type RevenueBootCheckOpts as j, type ServerJob as k, type ShortPayForfeit as l, type TempoObserverHealth as m, TempoSessionChannelMismatchError as n, type VerifyIncomingSnapshot as o, X402FacilitatorHealth as p, type X402SettlementEvidenceOutcome as q, type X402SettlementRepair as r, type X402SettlementRepairRefusal as s, type X402SettlementRepaired as t, type X402WedgedSettlement as u, type X402WedgedSettlementPage as v, X402_BATCH_SETTLEMENT_MAINNET_NETWORK as w, abortJob as x, applyPaymentInfoToJob as y, assertRevenueReporterReady as z };
|
|
@@ -6,8 +6,8 @@ import { Env, BlankSchema } from 'hono/types';
|
|
|
6
6
|
import { Pool } from 'pg';
|
|
7
7
|
export { Pool } from 'pg';
|
|
8
8
|
import { g as getWallet } from '../wallet-Dwjs5n_M.js';
|
|
9
|
-
import { A as AccumulatorPool, a as AccumulatorQuerier, C as ConsumedCredentialStore } from '../credit-menu-
|
|
10
|
-
export { b as AppEnv, c as CreditFundingReport, F as FiatDenomination, d as FiatDenominationFailure, e as FundOnlyRequest, I as IncomingPaymentOpts, J as JobCancelledError, M as MintHealthTracker, P as PAYMENT_PROOF_KEYS, f as PaymentErrorCode, g as PaymentErrorDetail, h as PaymentInfo, R as ReporterBannerOpts, i as ResolvedFx, j as RevenueBootCheckOpts, S as SDKServerOpts, k as ServerJob, l as ShortPayForfeit, T as TempoChannelReport, m as TempoObserverHealth, n as TempoSessionChannelMismatchError, U as UpfrontPaymentOpts, V as VerifiedIncomingPayment, o as VerifyIncomingSnapshot, X as X402BatchChannelObservation, p as X402FacilitatorHealth, q as X402SettlementEvidenceOutcome, r as X402SettlementRepair, s as X402SettlementRepairRefusal, t as X402SettlementRepaired, u as X402WedgedSettlement, v as X402WedgedSettlementPage, w as X402_BATCH_SETTLEMENT_MAINNET_NETWORK, x as abortJob, y as applyPaymentInfoToJob, z as assertRevenueReporterReady, B as buildPaymentErrorResponse, D as clearAccumulatorForDvm, E as createDVMServer, G as creditDepositPayload, H as derivedFundCreditId, K as devModeSkipsPaymentVerification, L as fromJobRecord, N as fundedMicroFor, O as hasPaymentProof, Q as hashLockKey, W as implicitCreditId, Y as initWalletAccumulatorTable, Z as insertAccumulatorRows, _ as isDerivedCreditId, $ as isTerminal, a0 as isYieldMessage, a1 as issueUpfrontChallenges, a2 as msatsToFiatMicro, a3 as paymentErrorBody, a4 as pinAskFiat, a5 as priceFiatMicro, a6 as processIncomingPayment, a7 as providerMessage, a8 as repairX402ExactSettlementEffect, a9 as resolveFxSnapshot, aa as resolvePriceFiat, ab as revenueReporterBannerState, ac as toCreditTerms, ad as toJobRecord, ae as unknownRouteNotFound, af as verifyIncomingPayment, ag as verifyTempoSessionManagementCredential, ah as verifyUpfrontPayment, ai as x402RequiredUsdcMicro, aj as x402SettledShare } from '../credit-menu-
|
|
9
|
+
import { A as AccumulatorPool, a as AccumulatorQuerier, C as ConsumedCredentialStore } from '../credit-menu-BlCL7gZx.js';
|
|
10
|
+
export { b as AppEnv, c as CreditFundingReport, F as FiatDenomination, d as FiatDenominationFailure, e as FundOnlyRequest, I as IncomingPaymentOpts, J as JobCancelledError, M as MintHealthTracker, P as PAYMENT_PROOF_KEYS, f as PaymentErrorCode, g as PaymentErrorDetail, h as PaymentInfo, R as ReporterBannerOpts, i as ResolvedFx, j as RevenueBootCheckOpts, S as SDKServerOpts, k as ServerJob, l as ShortPayForfeit, T as TempoChannelReport, m as TempoObserverHealth, n as TempoSessionChannelMismatchError, U as UpfrontPaymentOpts, V as VerifiedIncomingPayment, o as VerifyIncomingSnapshot, X as X402BatchChannelObservation, p as X402FacilitatorHealth, q as X402SettlementEvidenceOutcome, r as X402SettlementRepair, s as X402SettlementRepairRefusal, t as X402SettlementRepaired, u as X402WedgedSettlement, v as X402WedgedSettlementPage, w as X402_BATCH_SETTLEMENT_MAINNET_NETWORK, x as abortJob, y as applyPaymentInfoToJob, z as assertRevenueReporterReady, B as buildPaymentErrorResponse, D as clearAccumulatorForDvm, E as createDVMServer, G as creditDepositPayload, H as derivedFundCreditId, K as devModeSkipsPaymentVerification, L as fromJobRecord, N as fundedMicroFor, O as hasPaymentProof, Q as hashLockKey, W as implicitCreditId, Y as initWalletAccumulatorTable, Z as insertAccumulatorRows, _ as isDerivedCreditId, $ as isTerminal, a0 as isYieldMessage, a1 as issueUpfrontChallenges, a2 as msatsToFiatMicro, a3 as paymentErrorBody, a4 as pinAskFiat, a5 as priceFiatMicro, a6 as processIncomingPayment, a7 as providerMessage, a8 as repairX402ExactSettlementEffect, a9 as resolveFxSnapshot, aa as resolvePriceFiat, ab as revenueReporterBannerState, ac as toCreditTerms, ad as toJobRecord, ae as unknownRouteNotFound, af as verifyIncomingPayment, ag as verifyTempoSessionManagementCredential, ah as verifyUpfrontPayment, ai as x402RequiredUsdcMicro, aj as x402SettledShare } from '../credit-menu-BlCL7gZx.js';
|
|
11
11
|
import { g as LockPubkey } from '../lightning-backend-BhsyrBLa.js';
|
|
12
12
|
export { t as lockPubkeyStoreToLockPubkey } from '../lightning-backend-BhsyrBLa.js';
|
|
13
13
|
export { O as OutgoingMessage, S as StaleJobReapable, i as isStaleJobReapable } from '../job-store-D3CcZp_g.js';
|
package/dist/internal/server.js
CHANGED
|
@@ -65,13 +65,14 @@ import {
|
|
|
65
65
|
verifyUpfrontPayment,
|
|
66
66
|
x402RequiredUsdcMicro,
|
|
67
67
|
x402SettledShare
|
|
68
|
-
} from "../chunk-
|
|
68
|
+
} from "../chunk-LTAIBLS2.js";
|
|
69
69
|
import "../chunk-XRLKGCAW.js";
|
|
70
70
|
import {
|
|
71
71
|
settleWithFacilitator,
|
|
72
72
|
verifyWithFacilitator
|
|
73
73
|
} from "../chunk-BQ2NMWKE.js";
|
|
74
74
|
import "../chunk-U5VNEALI.js";
|
|
75
|
+
import "../chunk-HHTL3ZFT.js";
|
|
75
76
|
import {
|
|
76
77
|
SIGNED_ENVELOPE_FIELDS,
|
|
77
78
|
SIGNED_ENVELOPE_TYPES,
|
package/dist/server/index.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { ab as CashuMode, bK as CreditDrainEnqueue, R as ResolvedCreditConfig, bL as DVMAuthScheme, z as SignedRequestDomain, bM as CreditLedgerLike, bN as X402RefundSettlementGate, bO as CreditSnapshot, bP as DrawResult, bQ as X402SettlementStatus, bR as X402UnresolvedRefund, bS as GrownDrawResult, bT as DrawResolution, bU as FundingRecord, X as FundingReceipt, bV as CreditInvoiceRecord, bW as InvoiceSettlement, bX as BlockedInvoiceCursor, bY as InvoiceReconciliation, bZ as InvoiceWriteOff, b_ as DrawRecord, b$ as StalePendingDrawCursor, c0 as TempoCreditLossEvidence, c1 as CreditLedgerQuerier, c2 as TempoCreditLoss, c3 as X402CreditLossEvidence, c4 as X402CreditLoss, c5 as DrainMethod, c6 as DrainRequestResult, c7 as BitcoinDepositLiability, bo as FundingLot, c8 as CreditDrainRecord, c9 as ChannelDrainCursor, ca as DrainWriteOff, cb as DrainReleaseResult, cc as DrainFulfilment, cd as DrainTransitionResult, Y as JobReceipt, a1 as Message, K as KVStore, F as SignedRequestReplayStore, Z as ZodLike, a as DVMDescriptor } from '../step-cache-v2yhyhSZ.js';
|
|
2
2
|
export { ce as CLIENT_COMPATIBILITY_HEADERS, d as CanonicalEnvelope, cf as ClientCompatibility, cg as ClientCompatibilityEnv, ch as ClientCompatibilityGate, ci as ClientCompatibilityRequirement, cj as ClientSemVer, e as CreateSignedRequestVerifierOpts, ck as CreditFundingBasis, cl as CreditInvoiceStatus, cm as CreditLedger, cn as CreditLedgerError, co as CreditLedgerErrorCode, cp as CreditLedgerErrorDetails, cq as CreditLedgerPool, cr as CreditStatus, cs as DRAIN_DELIVERY_RESERVE_SATS, ct as DVM_PROTOCOL_VERSION, cu as DrainConflictReason, cv as DrawRailValue, cw as DrawStatus, cx as JobCostReportPayload, cy as JobTerminalReportPayload, cz as PostgresX402ChannelStorage, cA as ReplayStoreBackend, cB as RevenueSkippedNoRailPayload, cC as RevenueSkippedNoRailReason, w as SIGNED_REQUEST_AUTH_ID, x as SIGNED_REQUEST_STATEMENT_VERSION, cD as Secp256k1AuthOpts, y as SignedRequestAudience, B as SignedRequestError, E as SignedRequestFailure, G as SignedRequestSignOpts, H as SignedRequestStatementHeader, M as SignedRequestVerifier, cE as X402ChannelStorageOpts, cF as X402RelayLockHolder, cG as X402RelaySubmissionLock, cH as X402RelaySubmissionLockError, cI as allocateDrawValue, cJ as clientCompatibilityAttributes, cK as clientCompatibilityMiddleware, cL as clientUpgradeRequired, N as createSignedRequestVerifier, cM as parseClientCapabilities, cN as parseClientCompatibility, cO as parseDvmClient, cP as parseProtocolVersion, cQ as requireClientCompatibility, cR as secp256k1Auth, cS as signedRequestInput, T as signedRequestStatementHeader } from '../step-cache-v2yhyhSZ.js';
|
|
3
3
|
import { Pool } from 'pg';
|
|
4
|
-
import { ak as CreditMenu, b as AppEnv, U as UpfrontPaymentOpts, h as PaymentInfo, al as ReceiptIssuer, am as LightningReceive, an as TempoSettlementReadiness, ao as DVMHostOpts, ap as DVMServeResult } from '../credit-menu-
|
|
5
|
-
export { aq as BuildCreditMenuArgs, ar as BuilderIdentity, as as CREDIT_ENVELOPE_KEYS, C as ConsumedCredentialStore, at as CreateX402BatchSettlementServerOpts, au as CreditEnvelope, av as CreditEnvelopeError, aw as CreditFundCommitment, ax as CreditTerms, ay as DEFAULT_INVOICE_TTL_SECONDS, az as DVMHost, aA as
|
|
4
|
+
import { ak as CreditMenu, b as AppEnv, U as UpfrontPaymentOpts, h as PaymentInfo, al as ReceiptIssuer, am as LightningReceive, an as TempoSettlementReadiness, ao as DVMHostOpts, ap as DVMServeResult } from '../credit-menu-BlCL7gZx.js';
|
|
5
|
+
export { aq as BuildCreditMenuArgs, ar as BuilderIdentity, as as CREDIT_ENVELOPE_KEYS, C as ConsumedCredentialStore, at as CreateX402BatchSettlementServerOpts, au as CreditEnvelope, av as CreditEnvelopeError, aw as CreditFundCommitment, ax as CreditTerms, ay as DEFAULT_INVOICE_TTL_SECONDS, az as DVMHost, aA as HostingControlCommand, aB as HostingControlConfig, aC as HostingControlStatus, aD as JobManager, aE as JobManagerOpts, aF as LightningReceiveConfig, aG as MIN_INVOICE_TTL_SECONDS, aH as MemoryConsumedCredentialStore, aI as MemoryConsumedCredentialStoreOpts, aJ as MemoryProcessedPaymentStore, aK as MemoryX402ExactSettlementStore, aL as MountOpts, aM as OwnerDisplay, aN as PaidJobCompletion, aO as PaymentMode, aP as PlatformReporterOpts, aQ as PostgresProcessedPaymentStore, aR as PostgresX402ExactSettlementStore, aS as PriceFiat, aT as ProcessedPaymentQuerier, aU as ProcessedPaymentRail, aV as ProcessedPaymentRecord, aW as ProcessedPaymentReplayError, aX as ProcessedPaymentStore, aY as X402BatchAcceptance, aZ as X402BatchFunding, a_ as X402BatchRefusal, a$ as X402BatchSettlementServer, b0 as X402ExactAcceptance, b1 as X402ExactIntentConflictError, b2 as X402ExactSettlementAttempt, b3 as X402ExactSettlementChainEvidence, b4 as X402ExactSettlementEffect, b5 as X402ExactSettlementEvidenceMissingError, b6 as X402ExactSettlementEvidenceReader, b7 as X402ExactSettlementIntent, b8 as X402ExactSettlementNotReadyError, b9 as X402ExactSettlementServer, ba as X402ExactSettlementServerOpts, bb as X402ExactSettlementStatus, bc as X402ExactSettlementStore, bd as X402SettlementChainEvidence, be as X402SettlementEvidenceReader, bf as X402SettlementSubmissionError, bg as X402_BATCH_AUTO_SETTLEMENT, bh as X402_BATCH_MIN_WITHDRAW_DELAY_SECONDS, bi as X402_BATCH_SETTLEMENT_NETWORK, bj as attachCreditMenu, bk as buildCreditMenu, bl as createDVMHost, bm as createX402BatchSettlementServer, bn as creditEnvelopeIgnoreFields, bo as drawSettlementRef, bp as extractCreditEnvelope, bq as fundingCommitment, br as selectPrimaryCredit, bs as signHostingControl, bt as stripCreditEnvelope, bu as toCreditView } from '../credit-menu-BlCL7gZx.js';
|
|
6
6
|
import { Context } from 'hono';
|
|
7
7
|
import { z } from 'zod';
|
|
8
8
|
import { F as FxFetcher } from '../fx-DhyT1Cjh.js';
|
|
@@ -129,6 +129,8 @@ interface CreditRouteDeps {
|
|
|
129
129
|
* invoice on the same credit is swept with it.
|
|
130
130
|
*/
|
|
131
131
|
settleLightning: (callerPubkey: string, creditId?: string) => Promise<void>;
|
|
132
|
+
/** Hosting gate around a fresh funding operation, after caller auth and before any rail effect. */
|
|
133
|
+
withFundingAdmission?: (c: Context<AppEnv>, body: CreditRequest, run: () => Promise<Response>) => Promise<Response>;
|
|
132
134
|
tempoSettlementReadiness?: TempoSettlementReadiness;
|
|
133
135
|
}
|
|
134
136
|
declare function handleCreditRequest(c: Context<AppEnv>, deps: CreditRouteDeps): Promise<Response>;
|
|
@@ -401,6 +403,7 @@ declare class PostgresJobStore implements StreamableJobStore, ReceiptIssuingStor
|
|
|
401
403
|
heartbeatActiveJobs(jobIds: string[], now: number): Promise<void>;
|
|
402
404
|
cancelStaleJob(jobId: string, expectedActivityBefore: number, reason: string, terminalStatus: "failed" | "cancelled"): Promise<boolean>;
|
|
403
405
|
cancelJob(jobId: string, reason: string): Promise<boolean>;
|
|
406
|
+
cancelJobForHosting(jobId: string, reason: string): Promise<boolean>;
|
|
404
407
|
getCounters(jobId: string): Promise<JobCounters | undefined>;
|
|
405
408
|
claimForProcessing(jobId: string): Promise<boolean>;
|
|
406
409
|
tryReactivationLock<T>(jobId: string, fn: () => Promise<T>): Promise<{
|
package/dist/server/index.js
CHANGED
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
PostgresReplayStore
|
|
3
3
|
} from "../chunk-AJNFXR7J.js";
|
|
4
|
-
import {
|
|
5
|
-
PostgresJobStore
|
|
6
|
-
} from "../chunk-JAHRF5X3.js";
|
|
7
4
|
import {
|
|
8
5
|
PostgresKVStore
|
|
9
6
|
} from "../chunk-V5ZRATJH.js";
|
|
@@ -74,11 +71,12 @@ import {
|
|
|
74
71
|
revenueReporterBannerState,
|
|
75
72
|
seedLockPubkeyState,
|
|
76
73
|
selectPrimaryCredit,
|
|
74
|
+
signHostingControl,
|
|
77
75
|
stripCreditEnvelope,
|
|
78
76
|
stripProtocolEnvelope,
|
|
79
77
|
toCreditView,
|
|
80
78
|
unknownRouteNotFound
|
|
81
|
-
} from "../chunk-
|
|
79
|
+
} from "../chunk-LTAIBLS2.js";
|
|
82
80
|
import {
|
|
83
81
|
MemoryProcessedPaymentStore,
|
|
84
82
|
PostgresProcessedPaymentStore,
|
|
@@ -88,6 +86,9 @@ import "../chunk-BQ2NMWKE.js";
|
|
|
88
86
|
import {
|
|
89
87
|
MemoryCreditLedger
|
|
90
88
|
} from "../chunk-U5VNEALI.js";
|
|
89
|
+
import {
|
|
90
|
+
PostgresJobStore
|
|
91
|
+
} from "../chunk-HHTL3ZFT.js";
|
|
91
92
|
import {
|
|
92
93
|
SignedRequestError,
|
|
93
94
|
createDefaultReplayStore,
|
|
@@ -1098,6 +1099,12 @@ function createDVMHost(opts = {}) {
|
|
|
1098
1099
|
)
|
|
1099
1100
|
);
|
|
1100
1101
|
const envMaybe = env;
|
|
1102
|
+
const hostingSecret = envMaybe.DVMKIT_HOSTING_CONTROL_SECRET;
|
|
1103
|
+
const hostingScope = envMaybe.DVMKIT_HOSTING_CONTROL_SCOPE;
|
|
1104
|
+
if (!opts.hostingControl && Boolean(hostingSecret) !== Boolean(hostingScope)) {
|
|
1105
|
+
throw new Error("Hosting control requires both DVMKIT_HOSTING_CONTROL_SECRET and DVMKIT_HOSTING_CONTROL_SCOPE");
|
|
1106
|
+
}
|
|
1107
|
+
const hostingControl = opts.hostingControl ?? (hostingSecret && hostingScope ? { secret: hostingSecret, scope: hostingScope } : void 0);
|
|
1101
1108
|
const port = serveOpts?.port ?? opts.port ?? Number(envMaybe.PORT ?? "8080");
|
|
1102
1109
|
const bootStart = Date.now();
|
|
1103
1110
|
const phaseMarks = [];
|
|
@@ -1127,7 +1134,7 @@ function createDVMHost(opts = {}) {
|
|
|
1127
1134
|
});
|
|
1128
1135
|
applyRetryToPool(pool, "dvm-host");
|
|
1129
1136
|
pgPool = pool;
|
|
1130
|
-
const { PostgresJobStore: PostgresJobStore2 } = await import("../postgres-job-store-
|
|
1137
|
+
const { PostgresJobStore: PostgresJobStore2 } = await import("../postgres-job-store-VE2JRUEC.js");
|
|
1131
1138
|
const pgJobStore = new PostgresJobStore2(pool);
|
|
1132
1139
|
pendingInits.push(pgJobStore.init(), pgJobStore.initStreaming());
|
|
1133
1140
|
jobStore = pgJobStore;
|
|
@@ -1547,7 +1554,8 @@ ${config.facilitatorAuth?.keyId ?? ""}`;
|
|
|
1547
1554
|
lockPubkey: cashuOpts.lockPubkey,
|
|
1548
1555
|
lockPubkeyGraceSeconds: cashuOpts.lockPubkeyGraceSeconds,
|
|
1549
1556
|
canonicalDvmId: cashuOpts.canonicalDvmId,
|
|
1550
|
-
db: cashuOpts.db,
|
|
1557
|
+
db: hostingControl ? pgPool : cashuOpts.db,
|
|
1558
|
+
hostingControl,
|
|
1551
1559
|
dvmId: cashuOpts.dvmId,
|
|
1552
1560
|
failFast,
|
|
1553
1561
|
mintHealthTracker: opts.mintHealthTracker,
|
|
@@ -2116,6 +2124,7 @@ export {
|
|
|
2116
2124
|
secp256k1Auth,
|
|
2117
2125
|
selectPrimaryCredit,
|
|
2118
2126
|
serve,
|
|
2127
|
+
signHostingControl,
|
|
2119
2128
|
signedRequestInput,
|
|
2120
2129
|
signedRequestStatementHeader,
|
|
2121
2130
|
stripCreditEnvelope,
|