@enricai/barnacle 1.9.7 → 1.9.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/README.md +6 -6
- package/dist/api/errors.d.ts +1 -1
- package/dist/api/errors.d.ts.map +1 -1
- package/dist/api/errors.js +3 -3
- package/dist/api/errors.js.map +1 -1
- package/dist/api/plugins/error-handler.js +1 -1
- package/dist/api/plugins/error-handler.js.map +1 -1
- package/dist/api/routes/submissions.d.ts +1 -1
- package/dist/api/schemas/telemetry.d.ts +1 -1
- package/dist/api/schemas/telemetry.js +1 -1
- package/dist/cache/response-cache.d.ts +1 -1
- package/dist/cache/response-cache.js +2 -2
- package/dist/config.d.ts +4 -4
- package/dist/lib/llm/judges/invalid-fields.d.ts +1 -1
- package/dist/lib/llm/judges/invalid-fields.d.ts.map +1 -1
- package/dist/lib/llm/judges/invalid-fields.js +1 -1
- package/dist/lib/llm/judges/verify-submit.js +1 -1
- package/dist/lib/logging.d.ts +1 -1
- package/dist/lib/logging.js +1 -1
- package/dist/lib/telemetry/beacon-capture.d.ts +1 -1
- package/dist/lib/telemetry/beacon-capture.js +1 -1
- package/dist/lib/telemetry/call-capture.d.ts +1 -1
- package/dist/lib/telemetry/call-capture.js +1 -1
- package/dist/lib/telemetry/reconciliation-source.d.ts +4 -4
- package/dist/lib/telemetry/reconciliation-source.js +5 -5
- package/dist/lib/telemetry/run-telemetry.d.ts +1 -1
- package/dist/lib/telemetry/run-telemetry.js +1 -1
- package/dist/lib/telemetry/s3-sink.d.ts +1 -1
- package/dist/lib/telemetry/s3-sink.js +1 -1
- package/dist/lib/telemetry/submissions-s3-objects.d.ts +1 -1
- package/dist/lib/telemetry/submissions-s3-objects.js +1 -1
- package/dist/lib/telemetry/submissions-s3-reader.d.ts +1 -1
- package/dist/lib/telemetry/submissions-s3-reader.js +1 -1
- package/dist/plugins/config-plugin.js +2 -2
- package/dist/recon/load-form-schema.d.ts +1 -1
- package/dist/recon/load-form-schema.js +1 -1
- package/dist/recon/load-vocabulary.d.ts +1 -1
- package/dist/recon/load-vocabulary.js +2 -2
- package/dist/scraper/deep-locator-actuate.d.ts +1 -1
- package/dist/scraper/deep-locator-actuate.js +3 -3
- package/dist/scraper/deep-locator-candidates.d.ts +2 -2
- package/dist/scraper/deep-locator-candidates.js +3 -3
- package/dist/scraper/deep-locator-fake.d.ts +8 -8
- package/dist/scraper/deep-locator-fake.d.ts.map +1 -1
- package/dist/scraper/deep-locator-fake.js +5 -5
- package/dist/scraper/deep-locator-fake.js.map +1 -1
- package/dist/scraper/deep-locator-scan.d.ts +5 -5
- package/dist/scraper/deep-locator-scan.js +7 -7
- package/dist/scraper/deep-query.js +1 -1
- package/dist/scraper/errors.d.ts +2 -2
- package/dist/scraper/errors.js +2 -2
- package/dist/scraper/flow-runner.d.ts +6 -6
- package/dist/scraper/flow-runner.js +18 -18
- package/dist/scraper/flow-runner.js.map +1 -1
- package/dist/scraper/frame-target.js +1 -1
- package/dist/scraper/http-client.js +1 -1
- package/dist/scraper/metrics.d.ts +1 -1
- package/dist/scraper/metrics.js +1 -1
- package/dist/scraper/phantom-click.d.ts +1 -1
- package/dist/scraper/phantom-click.d.ts.map +1 -1
- package/dist/scraper/retry.js +1 -1
- package/dist/scraper/retry.js.map +1 -1
- package/dist/scraper/session-browserbase.d.ts +3 -3
- package/dist/scraper/session-browserbase.js +4 -4
- package/dist/scraper/session-browserbase.js.map +1 -1
- package/dist/scraper/session-shared.d.ts +2 -2
- package/dist/scraper/stagehand-guard.d.ts +4 -4
- package/dist/scraper/stagehand-guard.js +5 -5
- package/dist/scraper/submit-control.js +1 -1
- package/dist/scripts/judge-llm-batch.d.ts +1 -1
- package/dist/scripts/llm-heal.d.ts +1 -1
- package/dist/scripts/recon-browser.d.ts +1 -1
- package/dist/scripts/recon-browser.js +2 -2
- package/dist/scripts/recon-generate-multicall-fixture.d.ts +1 -1
- package/dist/scripts/recon-generate.d.ts +11 -1
- package/dist/scripts/recon-generate.d.ts.map +1 -1
- package/dist/scripts/recon-generate.js +182 -22
- package/dist/scripts/recon-generate.js.map +1 -1
- package/dist/scripts/recon-heal.js +1 -1
- package/dist/scripts/recon-heal.js.map +1 -1
- package/dist/scripts/recon-http.d.ts +1 -1
- package/dist/scripts/recon-http.js +1 -1
- package/dist/scripts/recon-shared.d.ts +1 -1
- package/dist/server.js +1 -1
- package/dist/site-plugin.d.ts +1 -1
- package/dist/testing/contract-parity-suite.d.mts +1 -1
- package/dist/testing/contract-parity-suite.mjs +1 -1
- package/dist/testing/coverage-guard-suite.d.mts +1 -1
- package/dist/testing/coverage-guard-suite.mjs +1 -1
- package/dist/testing/replay-integration-suite.d.mts +1 -1
- package/package.json +2 -2
|
@@ -1657,10 +1657,10 @@ function locateFormEnvelopePath(parsedBody) {
|
|
|
1657
1657
|
if (candidates.length === 0)
|
|
1658
1658
|
return [];
|
|
1659
1659
|
const maxP = Math.max(...candidates.map((c) => c.primitives));
|
|
1660
|
-
// The analytics blob (`eventData`)
|
|
1660
|
+
// The analytics blob (`eventData`) parallels the form, so the object with the
|
|
1661
1661
|
// MOST primitives can be a deep descendant of the true envelope. Pick the
|
|
1662
1662
|
// SHALLOWEST primitive-rich object (≥ half the max) instead — that is the
|
|
1663
|
-
// form envelope itself, whose analytics
|
|
1663
|
+
// form envelope itself, whose analytics copy sits below it. Tie-break on a
|
|
1664
1664
|
// higher primitive count. Threshold is relative, not a magic key name.
|
|
1665
1665
|
const rich = candidates.filter((c) => c.primitives >= Math.max(1, maxP / 2));
|
|
1666
1666
|
// No object carries a scalar field (maxP === 0): the body root is the only
|
|
@@ -2147,20 +2147,7 @@ function resolveResponsePathValue(responseBody, path) {
|
|
|
2147
2147
|
* 36-char UUID).
|
|
2148
2148
|
*/
|
|
2149
2149
|
function interpolateStateValues(template, priorSteps, payloadAccessorByValue = new Map()) {
|
|
2150
|
-
const varNameByValue =
|
|
2151
|
-
for (const step of priorSteps) {
|
|
2152
|
-
for (const p of step.produces) {
|
|
2153
|
-
// Header/cookie-origin produces have no body path — their value never
|
|
2154
|
-
// appears as a literal in a URL/body template (http-client's `bind`
|
|
2155
|
-
// forwards it directly as a request header), so there's nothing to
|
|
2156
|
-
// interpolate here.
|
|
2157
|
-
if (p.kind === "header")
|
|
2158
|
-
continue;
|
|
2159
|
-
const value = resolveResponsePathValue(step.capture.responseBody, p.path);
|
|
2160
|
-
if (value !== null)
|
|
2161
|
-
varNameByValue.set(value, p.name);
|
|
2162
|
-
}
|
|
2163
|
-
}
|
|
2150
|
+
const varNameByValue = deriveStateVarByValue(priorSteps);
|
|
2164
2151
|
let result = template;
|
|
2165
2152
|
// Pass 1: substitute state values (length-descending to avoid prefix
|
|
2166
2153
|
// conflicts). `\$` is a literal dollar sign (NOT an interpolation);
|
|
@@ -2213,6 +2200,16 @@ function interpolateStateValues(template, priorSteps, payloadAccessorByValue = n
|
|
|
2213
2200
|
* coordinate — and only WHOLE request-body leaves qualify, so every returned
|
|
2214
2201
|
* value is one the whole-value pass will bind (and whose field must be declared).
|
|
2215
2202
|
*
|
|
2203
|
+
* A field is NOT a caller coordinate when it is a per-step POSITION CONSTANT — the
|
|
2204
|
+
* step's own identifier that the harness varies as it walks the wizard (like
|
|
2205
|
+
* `stepIndex`). Such a field is produced-and-re-sent on every step, so it looks
|
|
2206
|
+
* like a coordinate, but each producer step echoes a DIFFERENT value; a genuine
|
|
2207
|
+
* coordinate (a jobId) is echoed with the SAME value on every step and the
|
|
2208
|
+
* per-value dedupe below leaves it a single entry. So any field bound to ≥2
|
|
2209
|
+
* distinct values across its producer steps is dropped wholesale: each step keeps
|
|
2210
|
+
* its own captured literal and the field is never declared as caller input.
|
|
2211
|
+
* Site-agnostic — the signal is value cardinality per field, not any field name.
|
|
2212
|
+
*
|
|
2216
2213
|
* @param actions the compiled action steps (carry produces[] + request bodies)
|
|
2217
2214
|
* @param alreadyBound capture value → existing accessor; a `payload.*` accessor
|
|
2218
2215
|
* is reused, a non-payload one (e.g. `txnId`) vetoes the value
|
|
@@ -2273,6 +2270,20 @@ function deriveProducerBoundaryBindings(actions, alreadyBound) {
|
|
|
2273
2270
|
bindings.set(value, { accessor: `payload.${field}`, field, producerIndex: i });
|
|
2274
2271
|
}
|
|
2275
2272
|
}
|
|
2273
|
+
// Drop per-step position constants: a field bound to ≥2 distinct values across
|
|
2274
|
+
// its producer steps is the step's own identifier the harness walked, not a
|
|
2275
|
+
// caller coordinate (which is echoed with one stable value). Removing every
|
|
2276
|
+
// entry leaves each step's captured literal in place and undeclared.
|
|
2277
|
+
const distinctValuesByField = new Map();
|
|
2278
|
+
for (const [value, binding] of bindings) {
|
|
2279
|
+
const values = distinctValuesByField.get(binding.field) ?? new Set();
|
|
2280
|
+
values.add(value);
|
|
2281
|
+
distinctValuesByField.set(binding.field, values);
|
|
2282
|
+
}
|
|
2283
|
+
for (const [value, binding] of [...bindings]) {
|
|
2284
|
+
if ((distinctValuesByField.get(binding.field)?.size ?? 0) >= 2)
|
|
2285
|
+
bindings.delete(value);
|
|
2286
|
+
}
|
|
2276
2287
|
return bindings;
|
|
2277
2288
|
}
|
|
2278
2289
|
/**
|
|
@@ -2319,6 +2330,132 @@ function applyWholeValuePayloadSubstitutions(template, parsedBody, producerScope
|
|
|
2319
2330
|
}
|
|
2320
2331
|
return result;
|
|
2321
2332
|
}
|
|
2333
|
+
/** Maximum number of nested URL-encodings a query-param value is probed for
|
|
2334
|
+
* before giving up. Real captures observed a doubly-encoded value (`%2520`); the
|
|
2335
|
+
* extra headroom costs one cheap `decodeURIComponent` per level and stops runaway. */
|
|
2336
|
+
const MAX_URL_PARAM_DECODE_DEPTH = 3;
|
|
2337
|
+
/**
|
|
2338
|
+
* Maps each response-produced value to the `${var}` name later steps thread it as.
|
|
2339
|
+
* Shared by {@link interpolateStateValues} (the body/URL substitution) and the
|
|
2340
|
+
* URL-param pass, so a threaded coordinate (e.g. a jobId a prior step produced)
|
|
2341
|
+
* resolves to the same var in both — one source of truth, they can never diverge.
|
|
2342
|
+
*
|
|
2343
|
+
* Header/cookie-origin produces are skipped: they have no body path and their
|
|
2344
|
+
* value never appears as a literal in a URL/body template (http-client's `bind`
|
|
2345
|
+
* forwards it directly as a request header), so there is nothing to interpolate.
|
|
2346
|
+
*/
|
|
2347
|
+
function deriveStateVarByValue(priorSteps) {
|
|
2348
|
+
const varNameByValue = new Map();
|
|
2349
|
+
for (const step of priorSteps) {
|
|
2350
|
+
for (const p of step.produces) {
|
|
2351
|
+
if (p.kind === "header")
|
|
2352
|
+
continue;
|
|
2353
|
+
const value = resolveResponsePathValue(step.capture.responseBody, p.path);
|
|
2354
|
+
if (value !== null)
|
|
2355
|
+
varNameByValue.set(value, p.name);
|
|
2356
|
+
}
|
|
2357
|
+
}
|
|
2358
|
+
return varNameByValue;
|
|
2359
|
+
}
|
|
2360
|
+
/** One `decodeURIComponent`, or null when the input is not validly percent-encoded
|
|
2361
|
+
* (a stray `%` throws) — lets the progressive-decode loop stop instead of crash. */
|
|
2362
|
+
function safeDecodeOnce(value) {
|
|
2363
|
+
try {
|
|
2364
|
+
return decodeURIComponent(value);
|
|
2365
|
+
}
|
|
2366
|
+
catch {
|
|
2367
|
+
return null;
|
|
2368
|
+
}
|
|
2369
|
+
}
|
|
2370
|
+
/** True when a JSON string leaf is itself an http(s) URL, the only leaves whose
|
|
2371
|
+
* query string this pass rewrites. Site-agnostic: a structural test, not a key name. */
|
|
2372
|
+
function isHttpUrlLeaf(value) {
|
|
2373
|
+
if (!value.includes("://"))
|
|
2374
|
+
return false;
|
|
2375
|
+
try {
|
|
2376
|
+
const u = new URL(value);
|
|
2377
|
+
return u.protocol === "http:" || u.protocol === "https:";
|
|
2378
|
+
}
|
|
2379
|
+
catch {
|
|
2380
|
+
return false;
|
|
2381
|
+
}
|
|
2382
|
+
}
|
|
2383
|
+
/** Wraps an accessor expression in `encodeURIComponent(...)` `depth` times, so a
|
|
2384
|
+
* value the capture stored URL-encoded is re-encoded to the same nesting at call
|
|
2385
|
+
* time (a caller value with `&`/`=`/spaces then survives inside the query string). */
|
|
2386
|
+
function wrapEncode(expr, depth) {
|
|
2387
|
+
let out = expr;
|
|
2388
|
+
for (let d = 0; d < depth; d++)
|
|
2389
|
+
out = `encodeURIComponent(${out})`;
|
|
2390
|
+
return out;
|
|
2391
|
+
}
|
|
2392
|
+
/**
|
|
2393
|
+
* Binds caller coordinates that were copied into a URL-valued body field's query
|
|
2394
|
+
* string. Every other substitution pass matches whole leaf values, so a job
|
|
2395
|
+
* coordinate re-encoded inside a redirect/thank-you URL stays frozen at the recon
|
|
2396
|
+
* persona's value. This runs on the PRISTINE parsed body leaf — before state
|
|
2397
|
+
* threading fragments a composite — and rewrites each query-param value that
|
|
2398
|
+
* matches the unified binding table (after bounded progressive URL-decoding, so a
|
|
2399
|
+
* double-encoded copy is caught) into a `${encodeURIComponent(<accessor>)}`
|
|
2400
|
+
* fragment nested to the matched encode depth. Unmatched params (and the delimiters
|
|
2401
|
+
* around them) stay byte-for-byte. Site-agnostic: keys off "leaf parses as an
|
|
2402
|
+
* http(s) URL", never a field name.
|
|
2403
|
+
*/
|
|
2404
|
+
function applyUrlParamPayloadSubstitutions(template, parsedBody, bindings) {
|
|
2405
|
+
if (bindings.size === 0)
|
|
2406
|
+
return template;
|
|
2407
|
+
let result = template;
|
|
2408
|
+
for (const { value, path } of walkStringLeaves(parsedBody)) {
|
|
2409
|
+
if (!isHttpUrlLeaf(value))
|
|
2410
|
+
continue;
|
|
2411
|
+
const qIdx = value.indexOf("?");
|
|
2412
|
+
if (qIdx < 0)
|
|
2413
|
+
continue;
|
|
2414
|
+
const prefix = value.slice(0, qIdx + 1);
|
|
2415
|
+
const rawQuery = value.slice(qIdx + 1);
|
|
2416
|
+
let changed = false;
|
|
2417
|
+
const newParams = rawQuery.split("&").map((pair) => {
|
|
2418
|
+
const eq = pair.indexOf("=");
|
|
2419
|
+
if (eq < 0)
|
|
2420
|
+
return pair;
|
|
2421
|
+
const name = pair.slice(0, eq);
|
|
2422
|
+
const rawVal = pair.slice(eq + 1);
|
|
2423
|
+
if (rawVal.length < MIN_STATE_VALUE_LENGTH)
|
|
2424
|
+
return pair;
|
|
2425
|
+
if (CACHE_BUSTER_QUERY_KEYS.has(name))
|
|
2426
|
+
return pair;
|
|
2427
|
+
let candidate = rawVal;
|
|
2428
|
+
let matched = null;
|
|
2429
|
+
let depth = 0;
|
|
2430
|
+
for (let d = 0; d <= MAX_URL_PARAM_DECODE_DEPTH; d++) {
|
|
2431
|
+
const accessor = bindings.get(candidate);
|
|
2432
|
+
if (accessor !== undefined) {
|
|
2433
|
+
matched = accessor;
|
|
2434
|
+
depth = d;
|
|
2435
|
+
break;
|
|
2436
|
+
}
|
|
2437
|
+
const next = safeDecodeOnce(candidate);
|
|
2438
|
+
if (next === null || next === candidate)
|
|
2439
|
+
break;
|
|
2440
|
+
candidate = next;
|
|
2441
|
+
}
|
|
2442
|
+
if (matched === null)
|
|
2443
|
+
return pair;
|
|
2444
|
+
changed = true;
|
|
2445
|
+
return `${name}=\${${wrapEncode(matched, depth)}}`;
|
|
2446
|
+
});
|
|
2447
|
+
if (!changed)
|
|
2448
|
+
continue;
|
|
2449
|
+
const newUrl = prefix + newParams.join("&");
|
|
2450
|
+
const key = path[path.length - 1] ?? "";
|
|
2451
|
+
if (key.length === 0)
|
|
2452
|
+
continue;
|
|
2453
|
+
const target = `"${key}":${JSON.stringify(value)}`;
|
|
2454
|
+
const replacement = `"${key}":"${newUrl}"`;
|
|
2455
|
+
result = result.split(target).join(replacement);
|
|
2456
|
+
}
|
|
2457
|
+
return result;
|
|
2458
|
+
}
|
|
2322
2459
|
/**
|
|
2323
2460
|
* Substitutes literal JSON key/value pairs in a body template with payload
|
|
2324
2461
|
* interpolations. Catches short strings (e.g. Culture: "en"), booleans
|
|
@@ -2405,7 +2542,7 @@ function applyPayloadKeyValueSubstitutions(template, inputBody, additionalBodies
|
|
|
2405
2542
|
* Documented closed set of JSON-key-name fragments (matched case-insensitively)
|
|
2406
2543
|
* that mark a value as a per-request TIMESTAMP the plugin must generate fresh at
|
|
2407
2544
|
* call time, not replay from the capture. Closed set per the no-regex-on-open-
|
|
2408
|
-
* sets feedback,
|
|
2545
|
+
* sets feedback, matching {@link CACHE_BUSTER_QUERY_KEYS}'s posture. A frozen
|
|
2409
2546
|
* capture timestamp would make every submission claim the recon instant.
|
|
2410
2547
|
*/
|
|
2411
2548
|
const VOLATILE_TIMESTAMP_KEY_FRAGMENTS = ["timestamp", "esign", "signeddate", "signedat"];
|
|
@@ -2766,8 +2903,28 @@ function emitMultiStepExecuteHttp(actions, inputBody, errorSignals, fieldNameMap
|
|
|
2766
2903
|
const rawBodyWithProducerBoundary = parsedBody !== null
|
|
2767
2904
|
? applyWholeValuePayloadSubstitutions(rawBodyWithStructuredSubs, parsedBody, producerBoundaryBindings, entryUrlParams, i)
|
|
2768
2905
|
: rawBodyWithStructuredSubs;
|
|
2769
|
-
|
|
2770
|
-
|
|
2906
|
+
// Coordinates copied into a URL-valued leaf's query string bind here, BEFORE
|
|
2907
|
+
// interpolateStateValues — same discipline as the whole-value pass above. A
|
|
2908
|
+
// composite (a jobSeqNo whose prefix a prior step produces as a state var)
|
|
2909
|
+
// would otherwise be fragmented mid-URL by Pass 1's global split, stranding
|
|
2910
|
+
// the tail frozen. The unified table is highest-priority-last: a per-step
|
|
2911
|
+
// state var (jobId2) wins over the caller payload accessor for that same
|
|
2912
|
+
// coordinate on steps that thread it, matching the top-level slot's behaviour.
|
|
2913
|
+
const urlParamBindings = new Map(payloadAccessorByValue);
|
|
2914
|
+
for (const [value, accessor] of entryUrlParams)
|
|
2915
|
+
urlParamBindings.set(value, accessor);
|
|
2916
|
+
for (const [value, binding] of producerBoundaryBindings) {
|
|
2917
|
+
if (binding.producerIndex === i)
|
|
2918
|
+
urlParamBindings.set(value, binding.accessor);
|
|
2919
|
+
}
|
|
2920
|
+
for (const [value, varName] of deriveStateVarByValue(prior)) {
|
|
2921
|
+
urlParamBindings.set(value, varName);
|
|
2922
|
+
}
|
|
2923
|
+
const rawBodyWithUrlParams = parsedBody !== null
|
|
2924
|
+
? applyUrlParamPayloadSubstitutions(rawBodyWithProducerBoundary, parsedBody, urlParamBindings)
|
|
2925
|
+
: rawBodyWithProducerBoundary;
|
|
2926
|
+
const bodyAfterStateAndKv = rawBodyWithUrlParams
|
|
2927
|
+
? applyPayloadKeyValueSubstitutions(interpolateStateValues(rawBodyWithUrlParams, prior, payloadAccessorByValue), inputBody, additionalBodies, outDiscoveredAdditionalBodyKeys)
|
|
2771
2928
|
: "";
|
|
2772
2929
|
// Mechanism A — generic (plain-JSON, wire-key-anchored) dropdown label→code
|
|
2773
2930
|
// rewrite. Runs AFTER interpolateStateValues + the payload-KV pass, not
|
|
@@ -2833,7 +2990,10 @@ function emitMultiStepExecuteHttp(actions, inputBody, errorSignals, fieldNameMap
|
|
|
2833
2990
|
}
|
|
2834
2991
|
// Identifier scan against the rendered text — captures `${foo}`, `${foo.bar}`,
|
|
2835
2992
|
// etc. The first segment (anchored at `${`) is the binding's name. Closed
|
|
2836
|
-
// grammar (template-literal syntax we generated ourselves).
|
|
2993
|
+
// grammar (template-literal syntax we generated ourselves). The optional
|
|
2994
|
+
// `encodeURIComponent(` prefixes let the URL-param pass wrap a bound accessor
|
|
2995
|
+
// (`${encodeURIComponent(jobTitle2)}`) without hiding the inner state var from
|
|
2996
|
+
// this scan — otherwise its `const` would be pruned and the reference dangle.
|
|
2837
2997
|
// For multipart steps the bodyArg isn't emitted (the body is a FormData
|
|
2838
2998
|
// built inline), but the URL and headers ARE in executable code — scan
|
|
2839
2999
|
// only those two haystacks for multipart.
|
|
@@ -2844,7 +3004,7 @@ function emitMultiStepExecuteHttp(actions, inputBody, errorSignals, fieldNameMap
|
|
|
2844
3004
|
? [r.url, r.headersExpr]
|
|
2845
3005
|
: [r.url, r.headersExpr, r.bodyArg];
|
|
2846
3006
|
for (const haystack of haystacks) {
|
|
2847
|
-
for (const match of haystack.matchAll(/\$\{([A-Za-z_$][A-Za-z0-9_$]*)/g)) {
|
|
3007
|
+
for (const match of haystack.matchAll(/\$\{(?:encodeURIComponent\()*([A-Za-z_$][A-Za-z0-9_$]*)/g)) {
|
|
2848
3008
|
referencedNames.add(match[1]);
|
|
2849
3009
|
}
|
|
2850
3010
|
}
|
|
@@ -3163,7 +3323,7 @@ function emitContractTs(opts) {
|
|
|
3163
3323
|
: "";
|
|
3164
3324
|
// optionSchemaExtension is appended LAST so option enums show up at the
|
|
3165
3325
|
// end of the payload type — the section ordering (base, multipart fields,
|
|
3166
|
-
// form-schema fields, option enums, raw-option fields)
|
|
3326
|
+
// form-schema fields, option enums, raw-option fields) matches the body
|
|
3167
3327
|
// emit order and keeps the generated payload type readable.
|
|
3168
3328
|
const payloadSchemaExpr = hasMultipartStep
|
|
3169
3329
|
? `${basePayloadSchemaExpr}.extend({\n Resume: z.instanceof(Buffer),\n ResumeContentType: z.string(),\n ResumeFilename: z.string(),\n})${formFieldsExtension}${splicedFieldsExtension}${optionSchemaExtension}${rawOptionSchemaExtension}${additionalBodyKeysExtension}${structuredKeysExtension}`
|