@spotpatch/dev-server 0.3.0 → 0.5.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/index.cjs +393 -114
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +44 -2
- package/dist/index.d.ts +44 -2
- package/dist/index.js +390 -102
- package/dist/index.js.map +1 -1
- package/package.json +5 -4
package/dist/index.cjs
CHANGED
|
@@ -36,6 +36,7 @@ __export(index_exports, {
|
|
|
36
36
|
createAgentJobManager: () => createAgentJobManager,
|
|
37
37
|
createIntegrationFileChange: () => createIntegrationFileChange,
|
|
38
38
|
createRuntimeAiConfig: () => createRuntimeAiConfig,
|
|
39
|
+
createRuntimeDataFlowConfig: () => createRuntimeDataFlowConfig,
|
|
39
40
|
createSession: () => createSession,
|
|
40
41
|
createSourceRegistrationService: () => createSourceRegistrationService,
|
|
41
42
|
createSourceRegistry: () => createSourceRegistry,
|
|
@@ -252,7 +253,11 @@ function createAgentJobManager(options) {
|
|
|
252
253
|
}
|
|
253
254
|
};
|
|
254
255
|
const applyChange = async (job, preparedChange) => {
|
|
255
|
-
transition(
|
|
256
|
+
transition(
|
|
257
|
+
job,
|
|
258
|
+
"applying",
|
|
259
|
+
job.applyMode === "trusted-auto" ? "Applying trusted change directly to the project." : "Applying validated changes to the project."
|
|
260
|
+
);
|
|
256
261
|
try {
|
|
257
262
|
await dependencies.applyChange(preparedChange);
|
|
258
263
|
transition(job, "applied", "Changes were applied to local project files.");
|
|
@@ -291,11 +296,15 @@ function createAgentJobManager(options) {
|
|
|
291
296
|
);
|
|
292
297
|
}
|
|
293
298
|
};
|
|
299
|
+
const execution = Object.freeze({
|
|
300
|
+
...options.ai.execution,
|
|
301
|
+
applyMode: job.applyMode
|
|
302
|
+
});
|
|
294
303
|
const preparedChange = await dependencies.executeChange({
|
|
295
304
|
annotation: job.annotation,
|
|
296
305
|
callbacks,
|
|
297
306
|
credential: job.credential,
|
|
298
|
-
execution
|
|
307
|
+
execution,
|
|
299
308
|
jobId: job.id,
|
|
300
309
|
model: job.model,
|
|
301
310
|
provider: job.provider,
|
|
@@ -777,7 +786,7 @@ var DEFAULT_EXCLUDE = Object.freeze([
|
|
|
777
786
|
/(?:^|\/)dist(?:\/|$)/,
|
|
778
787
|
/(?:^|\/)coverage(?:\/|$)/
|
|
779
788
|
]);
|
|
780
|
-
var DEFAULT_INCLUDE = Object.freeze([/(?:^|[/\\])src[/\\].+\.(?:jsx|tsx)$/]);
|
|
789
|
+
var DEFAULT_INCLUDE = Object.freeze([/(?:^|[/\\])src[/\\].+\.(?:js|jsx|ts|tsx)$/]);
|
|
781
790
|
var DEFAULT_BUDGET = Object.freeze({
|
|
782
791
|
totalCharacters: 16e3,
|
|
783
792
|
domCharacters: 3e3,
|
|
@@ -798,7 +807,12 @@ var DEFAULT_OPTIONS = Object.freeze({
|
|
|
798
807
|
debug: false,
|
|
799
808
|
locale: "auto",
|
|
800
809
|
maxTargets: 8,
|
|
801
|
-
ai: false
|
|
810
|
+
ai: false,
|
|
811
|
+
dataFlow: Object.freeze({
|
|
812
|
+
enabled: false,
|
|
813
|
+
runtime: "dispatch",
|
|
814
|
+
limits: import_shared2.DEFAULT_DATA_FLOW_LIMITS
|
|
815
|
+
})
|
|
802
816
|
});
|
|
803
817
|
var PROFILE_ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/;
|
|
804
818
|
var ENV_NAME_PATTERN = /^[A-Z][A-Z0-9_]{1,127}$/;
|
|
@@ -1090,6 +1104,36 @@ function assertPositiveBudget(budget) {
|
|
|
1090
1104
|
}
|
|
1091
1105
|
}
|
|
1092
1106
|
}
|
|
1107
|
+
function resolveDataFlowOptions(options) {
|
|
1108
|
+
if (options === void 0 || options === false) {
|
|
1109
|
+
return DEFAULT_OPTIONS.dataFlow;
|
|
1110
|
+
}
|
|
1111
|
+
const candidate = options;
|
|
1112
|
+
if (typeof candidate !== "object" || candidate === null) {
|
|
1113
|
+
throw new RangeError("SpotPatch dataFlow configuration is invalid.");
|
|
1114
|
+
}
|
|
1115
|
+
const runtime = options.runtime ?? "dispatch";
|
|
1116
|
+
if (runtime !== "dispatch") {
|
|
1117
|
+
throw new RangeError("SpotPatch dataFlow runtime mode is invalid.");
|
|
1118
|
+
}
|
|
1119
|
+
return Object.freeze({
|
|
1120
|
+
enabled: true,
|
|
1121
|
+
runtime,
|
|
1122
|
+
limits: import_shared2.DEFAULT_DATA_FLOW_LIMITS
|
|
1123
|
+
});
|
|
1124
|
+
}
|
|
1125
|
+
function createRuntimeDataFlowConfig(options) {
|
|
1126
|
+
return Object.freeze({
|
|
1127
|
+
enabled: options.enabled,
|
|
1128
|
+
runtime: options.runtime,
|
|
1129
|
+
limits: Object.freeze({
|
|
1130
|
+
observationMaxEntries: options.limits.observationMaxEntries,
|
|
1131
|
+
observationMaxBytes: options.limits.observationMaxBytes,
|
|
1132
|
+
observationTtlMs: options.limits.observationTtlMs,
|
|
1133
|
+
reportMaxBytes: options.limits.reportMaxBytes
|
|
1134
|
+
})
|
|
1135
|
+
});
|
|
1136
|
+
}
|
|
1093
1137
|
function resolveOptions(options = {}, environmentAi) {
|
|
1094
1138
|
if (options.trustedFastMode !== void 0 && typeof options.trustedFastMode !== "boolean") {
|
|
1095
1139
|
throw new RangeError("SpotPatch trustedFastMode must be a boolean.");
|
|
@@ -1125,7 +1169,8 @@ function resolveOptions(options = {}, environmentAi) {
|
|
|
1125
1169
|
debug: options.debug ?? DEFAULT_OPTIONS.debug,
|
|
1126
1170
|
locale,
|
|
1127
1171
|
maxTargets,
|
|
1128
|
-
ai: resolveAiOptions(options.ai ?? environmentAi)
|
|
1172
|
+
ai: resolveAiOptions(options.ai ?? environmentAi),
|
|
1173
|
+
dataFlow: resolveDataFlowOptions(options.dataFlow)
|
|
1129
1174
|
};
|
|
1130
1175
|
if (resolved.shortcut.trim().length === 0 || resolved.shortcut.length > 128 || resolved.shortcut.includes("\0")) {
|
|
1131
1176
|
throw new RangeError("SpotPatch shortcut is invalid.");
|
|
@@ -1311,33 +1356,58 @@ function createSourceRegistry(options = {}) {
|
|
|
1311
1356
|
const createId = options.createId ?? createRandomSourceId;
|
|
1312
1357
|
const pathToId = /* @__PURE__ */ new Map();
|
|
1313
1358
|
const idToPath = /* @__PURE__ */ new Map();
|
|
1359
|
+
const componentAnchors = /* @__PURE__ */ new Map();
|
|
1360
|
+
const componentIdsByPath = /* @__PURE__ */ new Map();
|
|
1361
|
+
function registerSourcePath(absolutePath) {
|
|
1362
|
+
const normalizedPath = normalizeAbsolutePath(absolutePath);
|
|
1363
|
+
const existingId = pathToId.get(normalizedPath);
|
|
1364
|
+
if (existingId !== void 0) {
|
|
1365
|
+
return existingId;
|
|
1366
|
+
}
|
|
1367
|
+
let fileId = createId();
|
|
1368
|
+
while (idToPath.has(fileId)) fileId = createId();
|
|
1369
|
+
pathToId.set(normalizedPath, fileId);
|
|
1370
|
+
idToPath.set(fileId, normalizedPath);
|
|
1371
|
+
return fileId;
|
|
1372
|
+
}
|
|
1314
1373
|
return Object.freeze({
|
|
1315
1374
|
register(absolutePath) {
|
|
1375
|
+
return registerSourcePath(absolutePath);
|
|
1376
|
+
},
|
|
1377
|
+
registerDataFlowComponents(absolutePath, sourceVersion, components) {
|
|
1316
1378
|
const normalizedPath = normalizeAbsolutePath(absolutePath);
|
|
1317
|
-
const
|
|
1318
|
-
|
|
1319
|
-
|
|
1379
|
+
const previousIds = componentIdsByPath.get(normalizedPath);
|
|
1380
|
+
for (const componentSourceId of previousIds ?? []) {
|
|
1381
|
+
componentAnchors.delete(componentSourceId);
|
|
1320
1382
|
}
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1383
|
+
const fileId = registerSourcePath(normalizedPath);
|
|
1384
|
+
const currentIds = /* @__PURE__ */ new Set();
|
|
1385
|
+
for (const component of components) {
|
|
1386
|
+
currentIds.add(component.componentSourceId);
|
|
1387
|
+
componentAnchors.set(
|
|
1388
|
+
component.componentSourceId,
|
|
1389
|
+
Object.freeze({ ...component, fileId, sourceVersion })
|
|
1390
|
+
);
|
|
1324
1391
|
}
|
|
1325
|
-
|
|
1326
|
-
idToPath.set(fileId, normalizedPath);
|
|
1327
|
-
return fileId;
|
|
1392
|
+
componentIdsByPath.set(normalizedPath, currentIds);
|
|
1328
1393
|
},
|
|
1329
1394
|
resolve(fileId) {
|
|
1330
1395
|
return idToPath.get(fileId);
|
|
1331
1396
|
},
|
|
1397
|
+
resolveDataFlowComponent(componentSourceId) {
|
|
1398
|
+
return componentAnchors.get(componentSourceId);
|
|
1399
|
+
},
|
|
1332
1400
|
clear() {
|
|
1333
1401
|
pathToId.clear();
|
|
1334
1402
|
idToPath.clear();
|
|
1403
|
+
componentAnchors.clear();
|
|
1404
|
+
componentIdsByPath.clear();
|
|
1335
1405
|
}
|
|
1336
1406
|
});
|
|
1337
1407
|
}
|
|
1338
1408
|
|
|
1339
1409
|
// src/server/middleware.ts
|
|
1340
|
-
var
|
|
1410
|
+
var import_shared11 = require("@spotpatch/shared");
|
|
1341
1411
|
|
|
1342
1412
|
// src/server/agent-http.ts
|
|
1343
1413
|
var import_shared7 = require("@spotpatch/shared");
|
|
@@ -2150,10 +2220,177 @@ function createEditorLauncher(dependencies = DEFAULT_DEPENDENCIES2) {
|
|
|
2150
2220
|
}
|
|
2151
2221
|
var launchConfiguredEditor = createEditorLauncher();
|
|
2152
2222
|
|
|
2153
|
-
// src/server/
|
|
2223
|
+
// src/server/data-flow-http.ts
|
|
2154
2224
|
var import_node_crypto4 = require("crypto");
|
|
2155
|
-
var
|
|
2225
|
+
var import_analyzer = require("@spotpatch/analyzer");
|
|
2156
2226
|
var import_shared8 = require("@spotpatch/shared");
|
|
2227
|
+
function envelopeBytes(report) {
|
|
2228
|
+
return Buffer.byteLength(JSON.stringify({ ok: true, data: report }), "utf8");
|
|
2229
|
+
}
|
|
2230
|
+
function limitDataFlowReportToBytes(report, maximumBytes) {
|
|
2231
|
+
const structurallyLimited = (0, import_shared8.limitDataFlowReportCollections)(report);
|
|
2232
|
+
if (envelopeBytes(structurallyLimited) <= maximumBytes) {
|
|
2233
|
+
return structurallyLimited;
|
|
2234
|
+
}
|
|
2235
|
+
let limited = (0, import_shared8.limitDataFlowReportCollections)(structurallyLimited, {
|
|
2236
|
+
forceTruncation: true,
|
|
2237
|
+
maximumDependencies: 0,
|
|
2238
|
+
truncatedBy: "bytes"
|
|
2239
|
+
});
|
|
2240
|
+
if (envelopeBytes(limited) > maximumBytes) {
|
|
2241
|
+
throw new import_shared8.SpotPatchError(import_shared8.ERROR_CODES.INTERNAL_ERROR);
|
|
2242
|
+
}
|
|
2243
|
+
for (let maximumDependencies = 1; maximumDependencies <= structurallyLimited.dependencies.length; maximumDependencies += 1) {
|
|
2244
|
+
const candidate = (0, import_shared8.limitDataFlowReportCollections)(structurallyLimited, {
|
|
2245
|
+
forceTruncation: true,
|
|
2246
|
+
maximumDependencies,
|
|
2247
|
+
truncatedBy: "bytes"
|
|
2248
|
+
});
|
|
2249
|
+
if (envelopeBytes(candidate) > maximumBytes) break;
|
|
2250
|
+
limited = candidate;
|
|
2251
|
+
}
|
|
2252
|
+
return limited;
|
|
2253
|
+
}
|
|
2254
|
+
function createDataFlowAnalyzer(options) {
|
|
2255
|
+
if (!options.options.dataFlow.enabled) return void 0;
|
|
2256
|
+
return (0, import_analyzer.createStaticDataFlowAnalyzer)({
|
|
2257
|
+
root: options.root,
|
|
2258
|
+
registryEpoch: options.session.id,
|
|
2259
|
+
registerSource: (absolutePath) => options.registry.register(absolutePath),
|
|
2260
|
+
limits: options.options.dataFlow.limits
|
|
2261
|
+
});
|
|
2262
|
+
}
|
|
2263
|
+
async function analyzeTarget(request, analyzer, options) {
|
|
2264
|
+
const resolvedRequest = (() => {
|
|
2265
|
+
if ("componentSourceId" in request) {
|
|
2266
|
+
const anchor = options.registry.resolveDataFlowComponent(
|
|
2267
|
+
request.componentSourceId
|
|
2268
|
+
);
|
|
2269
|
+
if (anchor?.sourceVersion !== request.sourceVersion) {
|
|
2270
|
+
throw new import_shared8.SpotPatchError(import_shared8.ERROR_CODES.DATA_FLOW_SOURCE_STALE);
|
|
2271
|
+
}
|
|
2272
|
+
return anchor;
|
|
2273
|
+
}
|
|
2274
|
+
return request;
|
|
2275
|
+
})();
|
|
2276
|
+
const absolutePath = await resolveSourceFile({
|
|
2277
|
+
fileId: resolvedRequest.fileId,
|
|
2278
|
+
registry: options.registry,
|
|
2279
|
+
root: options.root
|
|
2280
|
+
});
|
|
2281
|
+
const report = analyzer.analyzeComponent({
|
|
2282
|
+
absolutePath,
|
|
2283
|
+
line: resolvedRequest.line,
|
|
2284
|
+
column: resolvedRequest.column
|
|
2285
|
+
});
|
|
2286
|
+
if (resolvedRequest.sourceVersion !== void 0 && resolvedRequest.sourceVersion !== report.component.source.sourceVersion) {
|
|
2287
|
+
throw new import_shared8.SpotPatchError(import_shared8.ERROR_CODES.DATA_FLOW_SOURCE_STALE);
|
|
2288
|
+
}
|
|
2289
|
+
return limitDataFlowReportToBytes(
|
|
2290
|
+
report,
|
|
2291
|
+
options.options.dataFlow.limits.reportMaxBytes
|
|
2292
|
+
);
|
|
2293
|
+
}
|
|
2294
|
+
function requireAnalyzer(analyzer) {
|
|
2295
|
+
if (analyzer === void 0) {
|
|
2296
|
+
throw new import_shared8.SpotPatchError(import_shared8.ERROR_CODES.DATA_FLOW_DISABLED);
|
|
2297
|
+
}
|
|
2298
|
+
return analyzer;
|
|
2299
|
+
}
|
|
2300
|
+
async function handleComponentDataFlowReport(request, analyzer, options) {
|
|
2301
|
+
const parsed = import_shared8.dataFlowComponentReportRequestSchema.safeParse(
|
|
2302
|
+
await readJsonRequestBody(
|
|
2303
|
+
request,
|
|
2304
|
+
options.options.dataFlow.limits.protocolRequestMaxBytes
|
|
2305
|
+
)
|
|
2306
|
+
);
|
|
2307
|
+
if (!parsed.success) {
|
|
2308
|
+
throw new import_shared8.SpotPatchError(import_shared8.ERROR_CODES.INVALID_REQUEST);
|
|
2309
|
+
}
|
|
2310
|
+
return analyzeTarget(parsed.data, requireAnalyzer(analyzer), options);
|
|
2311
|
+
}
|
|
2312
|
+
async function handlePageDataFlowReport(request, analyzer, options) {
|
|
2313
|
+
const parsed = import_shared8.dataFlowPageReportRequestSchema.safeParse(
|
|
2314
|
+
await readJsonRequestBody(
|
|
2315
|
+
request,
|
|
2316
|
+
options.options.dataFlow.limits.protocolRequestMaxBytes
|
|
2317
|
+
)
|
|
2318
|
+
);
|
|
2319
|
+
if (!parsed.success) {
|
|
2320
|
+
throw new import_shared8.SpotPatchError(import_shared8.ERROR_CODES.INVALID_REQUEST);
|
|
2321
|
+
}
|
|
2322
|
+
const activeAnalyzer = requireAnalyzer(analyzer);
|
|
2323
|
+
const componentReports = await Promise.all(
|
|
2324
|
+
parsed.data.targets.map((target) => analyzeTarget(target, activeAnalyzer, options))
|
|
2325
|
+
);
|
|
2326
|
+
const dependencies = new Map(
|
|
2327
|
+
componentReports.flatMap(
|
|
2328
|
+
(report2) => report2.dependencies.map((dependency) => [dependency.id, dependency])
|
|
2329
|
+
)
|
|
2330
|
+
);
|
|
2331
|
+
const evidence = new Map(
|
|
2332
|
+
componentReports.flatMap(
|
|
2333
|
+
(report2) => report2.evidence.map((entry) => [entry.id, entry])
|
|
2334
|
+
)
|
|
2335
|
+
);
|
|
2336
|
+
const diagnostics = new Map(
|
|
2337
|
+
componentReports.flatMap(
|
|
2338
|
+
(report2) => report2.diagnostics.map((entry) => [entry.id, entry])
|
|
2339
|
+
)
|
|
2340
|
+
);
|
|
2341
|
+
const analyzedVersions = new Set(
|
|
2342
|
+
componentReports.flatMap((report2) => report2.baseline.analyzedSourceVersions)
|
|
2343
|
+
);
|
|
2344
|
+
const reportId = `page_${(0, import_node_crypto4.createHash)("sha256").update(componentReports.map((report2) => report2.reportId).join("\0")).digest("base64url").slice(0, 22)}`;
|
|
2345
|
+
const complete = componentReports.every((report2) => report2.completeness.complete);
|
|
2346
|
+
const report = Object.freeze({
|
|
2347
|
+
schemaVersion: import_shared8.DATA_FLOW_SCHEMA_VERSION,
|
|
2348
|
+
reportId,
|
|
2349
|
+
baseline: Object.freeze({
|
|
2350
|
+
registryEpoch: options.session.id,
|
|
2351
|
+
analyzerVersion: componentReports[0]?.baseline.analyzerVersion ?? "unavailable",
|
|
2352
|
+
adapterSetHash: componentReports[0]?.baseline.adapterSetHash ?? "unavailable",
|
|
2353
|
+
analyzedSourceVersions: Object.freeze([...analyzedVersions].sort())
|
|
2354
|
+
}),
|
|
2355
|
+
capability: Object.freeze({
|
|
2356
|
+
enabled: true,
|
|
2357
|
+
staticAnalysis: complete ? "available" : "partial",
|
|
2358
|
+
runtimeObservation: "dispatch-only",
|
|
2359
|
+
responseShape: "consumed-fields-only",
|
|
2360
|
+
aiAssistance: "disabled",
|
|
2361
|
+
reasons: Object.freeze(
|
|
2362
|
+
componentReports.flatMap((report2) => report2.capability.reasons)
|
|
2363
|
+
)
|
|
2364
|
+
}),
|
|
2365
|
+
dependencies: Object.freeze([...dependencies.values()]),
|
|
2366
|
+
evidence: Object.freeze([...evidence.values()]),
|
|
2367
|
+
diagnostics: Object.freeze([...diagnostics.values()]),
|
|
2368
|
+
completeness: Object.freeze({
|
|
2369
|
+
complete,
|
|
2370
|
+
visitedModules: componentReports.reduce(
|
|
2371
|
+
(total, report2) => total + report2.completeness.visitedModules,
|
|
2372
|
+
0
|
|
2373
|
+
),
|
|
2374
|
+
visitedCallsites: componentReports.reduce(
|
|
2375
|
+
(total, report2) => total + report2.completeness.visitedCallsites,
|
|
2376
|
+
0
|
|
2377
|
+
),
|
|
2378
|
+
frontierCount: componentReports.reduce(
|
|
2379
|
+
(total, report2) => total + report2.completeness.frontierCount,
|
|
2380
|
+
0
|
|
2381
|
+
)
|
|
2382
|
+
})
|
|
2383
|
+
});
|
|
2384
|
+
return limitDataFlowReportToBytes(
|
|
2385
|
+
report,
|
|
2386
|
+
options.options.dataFlow.limits.reportMaxBytes
|
|
2387
|
+
);
|
|
2388
|
+
}
|
|
2389
|
+
|
|
2390
|
+
// src/server/request-security.ts
|
|
2391
|
+
var import_node_crypto5 = require("crypto");
|
|
2392
|
+
var import_node_net = require("net");
|
|
2393
|
+
var import_shared9 = require("@spotpatch/shared");
|
|
2157
2394
|
function getSingleHeader(request, name) {
|
|
2158
2395
|
const value = request.headers[name.toLowerCase()];
|
|
2159
2396
|
return Array.isArray(value) ? value[0] : value;
|
|
@@ -2164,7 +2401,7 @@ function tokensMatch(actual, expected) {
|
|
|
2164
2401
|
}
|
|
2165
2402
|
const actualBytes = Buffer.from(actual);
|
|
2166
2403
|
const expectedBytes = Buffer.from(expected);
|
|
2167
|
-
return actualBytes.byteLength === expectedBytes.byteLength && (0,
|
|
2404
|
+
return actualBytes.byteLength === expectedBytes.byteLength && (0, import_node_crypto5.timingSafeEqual)(actualBytes, expectedBytes);
|
|
2168
2405
|
}
|
|
2169
2406
|
function isLoopbackHostname(hostname) {
|
|
2170
2407
|
const normalized = hostname.toLowerCase().replace(/^\[|\]$/g, "");
|
|
@@ -2198,32 +2435,32 @@ function parseOrigin(value) {
|
|
|
2198
2435
|
}
|
|
2199
2436
|
}
|
|
2200
2437
|
function assertRequestAuthorized(request, options) {
|
|
2201
|
-
const actualToken = getSingleHeader(request,
|
|
2438
|
+
const actualToken = getSingleHeader(request, import_shared9.SPOTPATCH_TOKEN_HEADER);
|
|
2202
2439
|
if (!tokensMatch(actualToken, options.sessionToken)) {
|
|
2203
|
-
throw new
|
|
2440
|
+
throw new import_shared9.SpotPatchError(import_shared9.ERROR_CODES.INVALID_TOKEN);
|
|
2204
2441
|
}
|
|
2205
2442
|
const hostHeader = getSingleHeader(request, "host");
|
|
2206
2443
|
const originHeader = getSingleHeader(request, "origin");
|
|
2207
2444
|
const host = hostHeader === void 0 ? void 0 : parseHost(hostHeader);
|
|
2208
2445
|
const origin = originHeader === void 0 ? void 0 : parseOrigin(originHeader);
|
|
2209
2446
|
if (host === void 0 || origin === void 0) {
|
|
2210
|
-
throw new
|
|
2447
|
+
throw new import_shared9.SpotPatchError(import_shared9.ERROR_CODES.ORIGIN_NOT_ALLOWED);
|
|
2211
2448
|
}
|
|
2212
2449
|
const hostIsLoopback = isLoopbackHostname(host.hostname);
|
|
2213
2450
|
const originIsLoopback = isLoopbackHostname(origin.hostname);
|
|
2214
2451
|
if (!options.allowLan) {
|
|
2215
2452
|
if (!hostIsLoopback || !originIsLoopback) {
|
|
2216
|
-
throw new
|
|
2453
|
+
throw new import_shared9.SpotPatchError(import_shared9.ERROR_CODES.ORIGIN_NOT_ALLOWED);
|
|
2217
2454
|
}
|
|
2218
2455
|
return;
|
|
2219
2456
|
}
|
|
2220
2457
|
if (!originIsLoopback && origin.host.toLowerCase() !== host.host.toLowerCase()) {
|
|
2221
|
-
throw new
|
|
2458
|
+
throw new import_shared9.SpotPatchError(import_shared9.ERROR_CODES.ORIGIN_NOT_ALLOWED);
|
|
2222
2459
|
}
|
|
2223
2460
|
}
|
|
2224
2461
|
|
|
2225
2462
|
// src/server/runtime-bootstrap.ts
|
|
2226
|
-
var
|
|
2463
|
+
var import_shared10 = require("@spotpatch/shared");
|
|
2227
2464
|
function getSingleHeader2(request, name) {
|
|
2228
2465
|
const value = request.headers[name.toLowerCase()];
|
|
2229
2466
|
return Array.isArray(value) ? value[0] : value;
|
|
@@ -2238,7 +2475,7 @@ function resolveRuntimeBootstrapOptions(options) {
|
|
|
2238
2475
|
if (expectedOrigin.origin !== options.expectedOrigin || expectedOrigin.protocol !== "http:" || !isLoopbackHostname(expectedOrigin.hostname)) {
|
|
2239
2476
|
throw new TypeError("The SpotPatch bootstrap origin must be a loopback origin.");
|
|
2240
2477
|
}
|
|
2241
|
-
const parsedConfig =
|
|
2478
|
+
const parsedConfig = import_shared10.runtimeConfigSchema.safeParse(options.runtimeConfig);
|
|
2242
2479
|
if (!parsedConfig.success) {
|
|
2243
2480
|
throw new TypeError("The SpotPatch Runtime configuration is invalid.");
|
|
2244
2481
|
}
|
|
@@ -2250,7 +2487,7 @@ function resolveRuntimeBootstrapOptions(options) {
|
|
|
2250
2487
|
function assertRuntimeBootstrapRequest(request, expectedOrigin) {
|
|
2251
2488
|
const contentType = getSingleHeader2(request, "content-type")?.split(";", 1)[0]?.trim().toLowerCase();
|
|
2252
2489
|
if (request.method !== "POST" || contentType !== "application/json") {
|
|
2253
|
-
throw new
|
|
2490
|
+
throw new import_shared10.SpotPatchError(import_shared10.ERROR_CODES.INVALID_REQUEST);
|
|
2254
2491
|
}
|
|
2255
2492
|
const host = getSingleHeader2(request, "host");
|
|
2256
2493
|
let hostIsLoopback = false;
|
|
@@ -2262,90 +2499,96 @@ function assertRuntimeBootstrapRequest(request, expectedOrigin) {
|
|
|
2262
2499
|
}
|
|
2263
2500
|
}
|
|
2264
2501
|
if (!hostIsLoopback || getSingleHeader2(request, "origin") !== expectedOrigin || getSingleHeader2(request, "sec-fetch-site") !== "same-origin") {
|
|
2265
|
-
throw new
|
|
2502
|
+
throw new import_shared10.SpotPatchError(import_shared10.ERROR_CODES.ORIGIN_NOT_ALLOWED);
|
|
2266
2503
|
}
|
|
2267
2504
|
}
|
|
2268
2505
|
async function readRuntimeBootstrap(request, options) {
|
|
2269
2506
|
assertRuntimeBootstrapRequest(request, options.expectedOrigin);
|
|
2270
|
-
const parsedBody =
|
|
2507
|
+
const parsedBody = import_shared10.runtimeBootstrapRequestSchema.safeParse(
|
|
2271
2508
|
await readJsonRequestBody(request)
|
|
2272
2509
|
);
|
|
2273
2510
|
if (!parsedBody.success) {
|
|
2274
|
-
throw new
|
|
2511
|
+
throw new import_shared10.SpotPatchError(import_shared10.ERROR_CODES.INVALID_REQUEST);
|
|
2275
2512
|
}
|
|
2276
2513
|
return options.runtimeConfig;
|
|
2277
2514
|
}
|
|
2278
2515
|
|
|
2279
2516
|
// src/server/middleware.ts
|
|
2280
2517
|
var STATUS_BY_ERROR = Object.freeze({
|
|
2281
|
-
[
|
|
2282
|
-
[
|
|
2283
|
-
[
|
|
2284
|
-
[
|
|
2285
|
-
[
|
|
2286
|
-
[
|
|
2287
|
-
[
|
|
2288
|
-
[
|
|
2289
|
-
[
|
|
2290
|
-
[
|
|
2291
|
-
[
|
|
2292
|
-
[
|
|
2293
|
-
[
|
|
2294
|
-
[
|
|
2295
|
-
[
|
|
2296
|
-
[
|
|
2297
|
-
[
|
|
2298
|
-
[
|
|
2299
|
-
[
|
|
2300
|
-
[
|
|
2301
|
-
[
|
|
2302
|
-
[
|
|
2303
|
-
[
|
|
2304
|
-
[
|
|
2305
|
-
[
|
|
2306
|
-
[
|
|
2307
|
-
[
|
|
2308
|
-
[
|
|
2309
|
-
[
|
|
2310
|
-
[
|
|
2311
|
-
[
|
|
2312
|
-
[
|
|
2313
|
-
[
|
|
2518
|
+
[import_shared11.ERROR_CODES.INVALID_REQUEST]: 400,
|
|
2519
|
+
[import_shared11.ERROR_CODES.INVALID_TOKEN]: 401,
|
|
2520
|
+
[import_shared11.ERROR_CODES.ORIGIN_NOT_ALLOWED]: 403,
|
|
2521
|
+
[import_shared11.ERROR_CODES.SOURCE_NOT_FOUND]: 404,
|
|
2522
|
+
[import_shared11.ERROR_CODES.SOURCE_OUTSIDE_ROOT]: 403,
|
|
2523
|
+
[import_shared11.ERROR_CODES.SOURCE_TOO_LARGE]: 413,
|
|
2524
|
+
[import_shared11.ERROR_CODES.EDITOR_OPEN_FAILED]: 500,
|
|
2525
|
+
[import_shared11.ERROR_CODES.DATA_FLOW_DISABLED]: 404,
|
|
2526
|
+
[import_shared11.ERROR_CODES.DATA_FLOW_SOURCE_STALE]: 409,
|
|
2527
|
+
[import_shared11.ERROR_CODES.DATA_FLOW_ANALYSIS_CANCELLED]: 409,
|
|
2528
|
+
[import_shared11.ERROR_CODES.AI_DISABLED]: 404,
|
|
2529
|
+
[import_shared11.ERROR_CODES.PROVIDER_NOT_CONFIGURED]: 503,
|
|
2530
|
+
[import_shared11.ERROR_CODES.PROVIDER_AUTH_FAILED]: 502,
|
|
2531
|
+
[import_shared11.ERROR_CODES.PROVIDER_PROTOCOL_UNSUPPORTED]: 502,
|
|
2532
|
+
[import_shared11.ERROR_CODES.MODEL_NOT_ALLOWED]: 400,
|
|
2533
|
+
[import_shared11.ERROR_CODES.MODEL_TOOL_CALL_UNSUPPORTED]: 422,
|
|
2534
|
+
[import_shared11.ERROR_CODES.PROVIDER_RATE_LIMITED]: 429,
|
|
2535
|
+
[import_shared11.ERROR_CODES.AGENT_BUSY]: 409,
|
|
2536
|
+
[import_shared11.ERROR_CODES.AGENT_LIMIT_EXCEEDED]: 413,
|
|
2537
|
+
[import_shared11.ERROR_CODES.AGENT_CANCELLED]: 409,
|
|
2538
|
+
[import_shared11.ERROR_CODES.WORKTREE_DIRTY]: 409,
|
|
2539
|
+
[import_shared11.ERROR_CODES.WORKTREE_NOT_REPOSITORY]: 409,
|
|
2540
|
+
[import_shared11.ERROR_CODES.WORKTREE_OPERATION_IN_PROGRESS]: 409,
|
|
2541
|
+
[import_shared11.ERROR_CODES.WORKTREE_CONFLICTED]: 409,
|
|
2542
|
+
[import_shared11.ERROR_CODES.WORKTREE_LOCAL_CHANGES_TOO_LARGE]: 413,
|
|
2543
|
+
[import_shared11.ERROR_CODES.WORKTREE_UNTRACKED_UNSUPPORTED]: 409,
|
|
2544
|
+
[import_shared11.ERROR_CODES.WORKTREE_LOCAL_CHANGES_UNSUPPORTED]: 409,
|
|
2545
|
+
[import_shared11.ERROR_CODES.TOOL_DENIED]: 403,
|
|
2546
|
+
[import_shared11.ERROR_CODES.TOOL_INPUT_INVALID]: 422,
|
|
2547
|
+
[import_shared11.ERROR_CODES.TOOL_ARGUMENTS_INVALID]: 422,
|
|
2548
|
+
[import_shared11.ERROR_CODES.TOOL_CALL_ID_CONFLICT]: 422,
|
|
2549
|
+
[import_shared11.ERROR_CODES.TOOL_PATH_DENIED]: 403,
|
|
2550
|
+
[import_shared11.ERROR_CODES.PATCH_REJECTED]: 422,
|
|
2551
|
+
[import_shared11.ERROR_CODES.VALIDATION_FAILED]: 422,
|
|
2552
|
+
[import_shared11.ERROR_CODES.APPLY_CONFLICT]: 409,
|
|
2553
|
+
[import_shared11.ERROR_CODES.INTERNAL_ERROR]: 500
|
|
2314
2554
|
});
|
|
2315
2555
|
var PUBLIC_MESSAGES = Object.freeze({
|
|
2316
|
-
[
|
|
2317
|
-
[
|
|
2318
|
-
[
|
|
2319
|
-
[
|
|
2320
|
-
[
|
|
2321
|
-
[
|
|
2322
|
-
[
|
|
2323
|
-
[
|
|
2324
|
-
[
|
|
2325
|
-
[
|
|
2326
|
-
[
|
|
2327
|
-
[
|
|
2328
|
-
[
|
|
2329
|
-
[
|
|
2330
|
-
[
|
|
2331
|
-
[
|
|
2332
|
-
[
|
|
2333
|
-
[
|
|
2334
|
-
[
|
|
2335
|
-
[
|
|
2336
|
-
[
|
|
2337
|
-
[
|
|
2338
|
-
[
|
|
2339
|
-
[
|
|
2340
|
-
[
|
|
2341
|
-
[
|
|
2342
|
-
[
|
|
2343
|
-
[
|
|
2344
|
-
[
|
|
2345
|
-
[
|
|
2346
|
-
[
|
|
2347
|
-
[
|
|
2348
|
-
[
|
|
2556
|
+
[import_shared11.ERROR_CODES.INVALID_REQUEST]: "The request is invalid.",
|
|
2557
|
+
[import_shared11.ERROR_CODES.INVALID_TOKEN]: "The session token is invalid.",
|
|
2558
|
+
[import_shared11.ERROR_CODES.ORIGIN_NOT_ALLOWED]: "The request origin is not allowed.",
|
|
2559
|
+
[import_shared11.ERROR_CODES.SOURCE_NOT_FOUND]: "The source file is unavailable.",
|
|
2560
|
+
[import_shared11.ERROR_CODES.SOURCE_OUTSIDE_ROOT]: "The source file is outside the project root.",
|
|
2561
|
+
[import_shared11.ERROR_CODES.SOURCE_TOO_LARGE]: "The source file exceeds the size limit.",
|
|
2562
|
+
[import_shared11.ERROR_CODES.EDITOR_OPEN_FAILED]: "The editor request could not be started.",
|
|
2563
|
+
[import_shared11.ERROR_CODES.DATA_FLOW_DISABLED]: "Component data-flow analysis is not enabled.",
|
|
2564
|
+
[import_shared11.ERROR_CODES.DATA_FLOW_SOURCE_STALE]: "The selected source version is stale.",
|
|
2565
|
+
[import_shared11.ERROR_CODES.DATA_FLOW_ANALYSIS_CANCELLED]: "The data-flow analysis was cancelled.",
|
|
2566
|
+
[import_shared11.ERROR_CODES.AI_DISABLED]: "AI execution is not enabled.",
|
|
2567
|
+
[import_shared11.ERROR_CODES.PROVIDER_NOT_CONFIGURED]: "The AI provider is unavailable.",
|
|
2568
|
+
[import_shared11.ERROR_CODES.PROVIDER_AUTH_FAILED]: "The AI provider rejected authentication.",
|
|
2569
|
+
[import_shared11.ERROR_CODES.PROVIDER_PROTOCOL_UNSUPPORTED]: "The AI provider protocol is unsupported.",
|
|
2570
|
+
[import_shared11.ERROR_CODES.MODEL_NOT_ALLOWED]: "The selected model is not allowed.",
|
|
2571
|
+
[import_shared11.ERROR_CODES.MODEL_TOOL_CALL_UNSUPPORTED]: "The selected model cannot run SpotPatch tools.",
|
|
2572
|
+
[import_shared11.ERROR_CODES.PROVIDER_RATE_LIMITED]: "The AI provider is rate limited.",
|
|
2573
|
+
[import_shared11.ERROR_CODES.AGENT_BUSY]: "Another Agent job is already running.",
|
|
2574
|
+
[import_shared11.ERROR_CODES.AGENT_LIMIT_EXCEEDED]: "The Agent job exceeded a safety limit.",
|
|
2575
|
+
[import_shared11.ERROR_CODES.AGENT_CANCELLED]: "The Agent job was cancelled.",
|
|
2576
|
+
[import_shared11.ERROR_CODES.WORKTREE_DIRTY]: "Local changes require explicit inclusion consent.",
|
|
2577
|
+
[import_shared11.ERROR_CODES.WORKTREE_NOT_REPOSITORY]: "The project root is not a Git repository.",
|
|
2578
|
+
[import_shared11.ERROR_CODES.WORKTREE_OPERATION_IN_PROGRESS]: "A Git operation is currently in progress.",
|
|
2579
|
+
[import_shared11.ERROR_CODES.WORKTREE_CONFLICTED]: "The local workspace contains unresolved merge conflicts.",
|
|
2580
|
+
[import_shared11.ERROR_CODES.WORKTREE_LOCAL_CHANGES_TOO_LARGE]: "The local workspace exceeds the safe isolation size limit.",
|
|
2581
|
+
[import_shared11.ERROR_CODES.WORKTREE_UNTRACKED_UNSUPPORTED]: "An untracked path cannot be isolated safely.",
|
|
2582
|
+
[import_shared11.ERROR_CODES.WORKTREE_LOCAL_CHANGES_UNSUPPORTED]: "The local workspace state cannot be isolated safely.",
|
|
2583
|
+
[import_shared11.ERROR_CODES.TOOL_DENIED]: "The Agent tool request was denied.",
|
|
2584
|
+
[import_shared11.ERROR_CODES.TOOL_INPUT_INVALID]: "The Agent tool input was invalid.",
|
|
2585
|
+
[import_shared11.ERROR_CODES.TOOL_ARGUMENTS_INVALID]: "The Agent tool arguments are invalid.",
|
|
2586
|
+
[import_shared11.ERROR_CODES.TOOL_CALL_ID_CONFLICT]: "A tool call ID conflicts within one Agent turn.",
|
|
2587
|
+
[import_shared11.ERROR_CODES.TOOL_PATH_DENIED]: "The Agent tool path was denied.",
|
|
2588
|
+
[import_shared11.ERROR_CODES.PATCH_REJECTED]: "The proposed patch was rejected.",
|
|
2589
|
+
[import_shared11.ERROR_CODES.VALIDATION_FAILED]: "The proposed change failed validation.",
|
|
2590
|
+
[import_shared11.ERROR_CODES.APPLY_CONFLICT]: "The change conflicts with the current worktree.",
|
|
2591
|
+
[import_shared11.ERROR_CODES.INTERNAL_ERROR]: "The request could not be completed."
|
|
2349
2592
|
});
|
|
2350
2593
|
function writeJson(response, status, payload) {
|
|
2351
2594
|
response.statusCode = status;
|
|
@@ -2354,11 +2597,11 @@ function writeJson(response, status, payload) {
|
|
|
2354
2597
|
response.end(JSON.stringify(payload));
|
|
2355
2598
|
}
|
|
2356
2599
|
function asSpotPatchError(error) {
|
|
2357
|
-
return error instanceof
|
|
2600
|
+
return error instanceof import_shared11.SpotPatchError ? error : new import_shared11.SpotPatchError(import_shared11.ERROR_CODES.INTERNAL_ERROR, void 0, { cause: error });
|
|
2358
2601
|
}
|
|
2359
2602
|
function writeError(response, error, logger) {
|
|
2360
2603
|
const normalized = asSpotPatchError(error);
|
|
2361
|
-
if (normalized.code ===
|
|
2604
|
+
if (normalized.code === import_shared11.ERROR_CODES.INTERNAL_ERROR) {
|
|
2362
2605
|
logger?.warn("[spotpatch:server] Internal request failure.");
|
|
2363
2606
|
}
|
|
2364
2607
|
writeJson(response, STATUS_BY_ERROR[normalized.code], {
|
|
@@ -2377,11 +2620,11 @@ function requestPath(request) {
|
|
|
2377
2620
|
}
|
|
2378
2621
|
}
|
|
2379
2622
|
async function handleSourceContext(request, options) {
|
|
2380
|
-
const parsed =
|
|
2623
|
+
const parsed = import_shared11.sourceContextRequestSchema.safeParse(
|
|
2381
2624
|
await readJsonRequestBody(request)
|
|
2382
2625
|
);
|
|
2383
2626
|
if (!parsed.success) {
|
|
2384
|
-
throw new
|
|
2627
|
+
throw new import_shared11.SpotPatchError(import_shared11.ERROR_CODES.INVALID_REQUEST);
|
|
2385
2628
|
}
|
|
2386
2629
|
return readSourceContext({
|
|
2387
2630
|
request: parsed.data,
|
|
@@ -2392,9 +2635,9 @@ async function handleSourceContext(request, options) {
|
|
|
2392
2635
|
});
|
|
2393
2636
|
}
|
|
2394
2637
|
async function handleOpenEditor(request, options) {
|
|
2395
|
-
const parsed =
|
|
2638
|
+
const parsed = import_shared11.openEditorRequestSchema.safeParse(await readJsonRequestBody(request));
|
|
2396
2639
|
if (!parsed.success) {
|
|
2397
|
-
throw new
|
|
2640
|
+
throw new import_shared11.SpotPatchError(import_shared11.ERROR_CODES.INVALID_REQUEST);
|
|
2398
2641
|
}
|
|
2399
2642
|
const body = parsed.data;
|
|
2400
2643
|
const sourcePath = await resolveSourceFile({
|
|
@@ -2411,22 +2654,23 @@ async function handleOpenEditor(request, options) {
|
|
|
2411
2654
|
options.logger?.warn(
|
|
2412
2655
|
`[spotpatch:server] ${options.options.editor === "auto" ? "The detected editor" : options.options.editor} rejected an editor request.`
|
|
2413
2656
|
);
|
|
2414
|
-
throw new
|
|
2657
|
+
throw new import_shared11.SpotPatchError(import_shared11.ERROR_CODES.EDITOR_OPEN_FAILED, void 0, {
|
|
2415
2658
|
cause: error
|
|
2416
2659
|
});
|
|
2417
2660
|
}
|
|
2418
2661
|
}
|
|
2419
2662
|
function createSpotPatchMiddleware(options) {
|
|
2420
2663
|
const bootstrap = options.bootstrap === void 0 ? void 0 : resolveRuntimeBootstrapOptions(options.bootstrap);
|
|
2664
|
+
const dataFlowAnalyzer = createDataFlowAnalyzer(options);
|
|
2421
2665
|
return (request, response, next) => {
|
|
2422
2666
|
const path8 = requestPath(request);
|
|
2423
2667
|
const agentRoute = matchAgentRequestPath(path8);
|
|
2424
|
-
if (path8 !==
|
|
2668
|
+
if (path8 !== import_shared11.SPOTPATCH_ENDPOINTS.sourceContext && path8 !== import_shared11.SPOTPATCH_ENDPOINTS.openEditor && path8 !== import_shared11.SPOTPATCH_ENDPOINTS.dataFlowComponentReport && path8 !== import_shared11.SPOTPATCH_ENDPOINTS.dataFlowPageReport && agentRoute === void 0 && !path8.startsWith(`${import_shared11.SPOTPATCH_API_BASE}/`)) {
|
|
2425
2669
|
next();
|
|
2426
2670
|
return;
|
|
2427
2671
|
}
|
|
2428
2672
|
const handle = async () => {
|
|
2429
|
-
if (path8 ===
|
|
2673
|
+
if (path8 === import_shared11.SPOTPATCH_ENDPOINTS.bootstrap && bootstrap !== void 0) {
|
|
2430
2674
|
const data = await readRuntimeBootstrap(
|
|
2431
2675
|
request,
|
|
2432
2676
|
bootstrap
|
|
@@ -2438,24 +2682,44 @@ function createSpotPatchMiddleware(options) {
|
|
|
2438
2682
|
allowLan: options.options.allowLan,
|
|
2439
2683
|
sessionToken: options.session.token
|
|
2440
2684
|
});
|
|
2441
|
-
if (path8 ===
|
|
2685
|
+
if (path8 === import_shared11.SPOTPATCH_ENDPOINTS.sourceContext) {
|
|
2442
2686
|
if (request.method !== "POST") {
|
|
2443
|
-
throw new
|
|
2687
|
+
throw new import_shared11.SpotPatchError(import_shared11.ERROR_CODES.INVALID_REQUEST);
|
|
2444
2688
|
}
|
|
2445
2689
|
const data = await handleSourceContext(request, options);
|
|
2446
2690
|
writeJson(response, 200, { ok: true, data });
|
|
2447
2691
|
return;
|
|
2448
2692
|
}
|
|
2449
|
-
if (path8 ===
|
|
2693
|
+
if (path8 === import_shared11.SPOTPATCH_ENDPOINTS.openEditor) {
|
|
2450
2694
|
if (request.method !== "POST") {
|
|
2451
|
-
throw new
|
|
2695
|
+
throw new import_shared11.SpotPatchError(import_shared11.ERROR_CODES.INVALID_REQUEST);
|
|
2452
2696
|
}
|
|
2453
2697
|
const data = await handleOpenEditor(request, options);
|
|
2454
2698
|
writeJson(response, 200, { ok: true, data });
|
|
2455
2699
|
return;
|
|
2456
2700
|
}
|
|
2701
|
+
if (path8 === import_shared11.SPOTPATCH_ENDPOINTS.dataFlowComponentReport) {
|
|
2702
|
+
if (request.method !== "POST") {
|
|
2703
|
+
throw new import_shared11.SpotPatchError(import_shared11.ERROR_CODES.INVALID_REQUEST);
|
|
2704
|
+
}
|
|
2705
|
+
const data = await handleComponentDataFlowReport(
|
|
2706
|
+
request,
|
|
2707
|
+
dataFlowAnalyzer,
|
|
2708
|
+
options
|
|
2709
|
+
);
|
|
2710
|
+
writeJson(response, 200, { ok: true, data });
|
|
2711
|
+
return;
|
|
2712
|
+
}
|
|
2713
|
+
if (path8 === import_shared11.SPOTPATCH_ENDPOINTS.dataFlowPageReport) {
|
|
2714
|
+
if (request.method !== "POST") {
|
|
2715
|
+
throw new import_shared11.SpotPatchError(import_shared11.ERROR_CODES.INVALID_REQUEST);
|
|
2716
|
+
}
|
|
2717
|
+
const data = await handlePageDataFlowReport(request, dataFlowAnalyzer, options);
|
|
2718
|
+
writeJson(response, 200, { ok: true, data });
|
|
2719
|
+
return;
|
|
2720
|
+
}
|
|
2457
2721
|
if (agentRoute === void 0) {
|
|
2458
|
-
throw new
|
|
2722
|
+
throw new import_shared11.SpotPatchError(import_shared11.ERROR_CODES.INVALID_REQUEST);
|
|
2459
2723
|
}
|
|
2460
2724
|
await handleAgentRequest(
|
|
2461
2725
|
request,
|
|
@@ -2474,7 +2738,7 @@ function createSpotPatchMiddleware(options) {
|
|
|
2474
2738
|
}
|
|
2475
2739
|
|
|
2476
2740
|
// src/server/source-registration.ts
|
|
2477
|
-
var
|
|
2741
|
+
var import_node_crypto6 = require("crypto");
|
|
2478
2742
|
var import_promises6 = require("fs/promises");
|
|
2479
2743
|
var import_node_path7 = __toESM(require("path"), 1);
|
|
2480
2744
|
var import_compiler = require("@spotpatch/compiler");
|
|
@@ -2497,7 +2761,7 @@ function identitiesMatch(actual, expected) {
|
|
|
2497
2761
|
}
|
|
2498
2762
|
const actualBytes = Buffer.from(actual);
|
|
2499
2763
|
const expectedBytes = Buffer.from(expected);
|
|
2500
|
-
return actualBytes.byteLength === expectedBytes.byteLength && (0,
|
|
2764
|
+
return actualBytes.byteLength === expectedBytes.byteLength && (0, import_node_crypto6.timingSafeEqual)(actualBytes, expectedBytes);
|
|
2501
2765
|
}
|
|
2502
2766
|
function isWithinRoot(root, candidate) {
|
|
2503
2767
|
const relative = import_node_path7.default.relative(root, candidate);
|
|
@@ -2592,11 +2856,11 @@ async function createSourceRegistrationService(input) {
|
|
|
2592
2856
|
}
|
|
2593
2857
|
|
|
2594
2858
|
// src/session/session.ts
|
|
2595
|
-
var
|
|
2859
|
+
var import_node_crypto7 = require("crypto");
|
|
2596
2860
|
function createSession() {
|
|
2597
2861
|
return Object.freeze({
|
|
2598
|
-
id: (0,
|
|
2599
|
-
token: (0,
|
|
2862
|
+
id: (0, import_node_crypto7.randomBytes)(16).toString("base64url"),
|
|
2863
|
+
token: (0, import_node_crypto7.randomBytes)(16).toString("base64url")
|
|
2600
2864
|
});
|
|
2601
2865
|
}
|
|
2602
2866
|
|
|
@@ -2606,6 +2870,7 @@ var OPTION_KEYS = Object.freeze([
|
|
|
2606
2870
|
"allowLan",
|
|
2607
2871
|
"budget",
|
|
2608
2872
|
"debug",
|
|
2873
|
+
"dataFlow",
|
|
2609
2874
|
"editor",
|
|
2610
2875
|
"enabled",
|
|
2611
2876
|
"exclude",
|
|
@@ -2693,6 +2958,9 @@ function serializeResolvedSpotPatchOptions(options) {
|
|
|
2693
2958
|
allowLan: options.allowLan,
|
|
2694
2959
|
budget: options.budget,
|
|
2695
2960
|
debug: options.debug,
|
|
2961
|
+
dataFlow: options.dataFlow.enabled ? Object.freeze({
|
|
2962
|
+
runtime: options.dataFlow.runtime
|
|
2963
|
+
}) : false,
|
|
2696
2964
|
editor: options.editor,
|
|
2697
2965
|
enabled: options.enabled,
|
|
2698
2966
|
exclude: Object.freeze(options.exclude.map(serializeFilter)),
|
|
@@ -2735,6 +3003,15 @@ function parseBudget(value) {
|
|
|
2735
3003
|
);
|
|
2736
3004
|
return Object.freeze(budget);
|
|
2737
3005
|
}
|
|
3006
|
+
function parseDataFlow(value) {
|
|
3007
|
+
if (value === false) return false;
|
|
3008
|
+
if (!isRecord2(value) || !hasExactKeys(value, ["runtime"]) || value.runtime !== "dispatch") {
|
|
3009
|
+
throw new TypeError("The SpotPatch data-flow transport is invalid.");
|
|
3010
|
+
}
|
|
3011
|
+
return Object.freeze({
|
|
3012
|
+
runtime: value.runtime
|
|
3013
|
+
});
|
|
3014
|
+
}
|
|
2738
3015
|
function parseSerializedSpotPatchOptions(value) {
|
|
2739
3016
|
if (!isRecord2(value) || !hasExactKeys(value, OPTION_KEYS)) {
|
|
2740
3017
|
throw new TypeError("The SpotPatch options transport is invalid.");
|
|
@@ -2748,6 +3025,7 @@ function parseSerializedSpotPatchOptions(value) {
|
|
|
2748
3025
|
allowLan: value.allowLan,
|
|
2749
3026
|
budget: parseBudget(value.budget),
|
|
2750
3027
|
debug: value.debug,
|
|
3028
|
+
dataFlow: parseDataFlow(value.dataFlow),
|
|
2751
3029
|
editor: value.editor,
|
|
2752
3030
|
enabled: value.enabled,
|
|
2753
3031
|
exclude: parseFilterList(value.exclude),
|
|
@@ -2771,6 +3049,7 @@ function parseSerializedSpotPatchOptions(value) {
|
|
|
2771
3049
|
createAgentJobManager,
|
|
2772
3050
|
createIntegrationFileChange,
|
|
2773
3051
|
createRuntimeAiConfig,
|
|
3052
|
+
createRuntimeDataFlowConfig,
|
|
2774
3053
|
createSession,
|
|
2775
3054
|
createSourceRegistrationService,
|
|
2776
3055
|
createSourceRegistry,
|