@apifuse/provider-sdk 2.2.0-beta.3 → 2.2.0-beta.4
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/AUTHORING.md +14 -0
- package/CHANGELOG.md +4 -0
- package/bin/apifuse-check.ts +18 -58
- package/bin/apifuse-create.ts +1 -1
- package/bin/apifuse-dev.ts +27 -52
- package/bin/apifuse-pack-smoke.ts +22 -81
- package/bin/apifuse-pack-types.ts +266 -0
- package/bin/apifuse-perf.ts +45 -127
- package/bin/apifuse-record.ts +23 -61
- package/bin/apifuse-submit-check.ts +26 -21
- package/bin/apifuse.ts +1 -1
- package/bin/submit-check-xml.ts +1 -1
- package/dist/auth-turn/index.d.ts +1 -1
- package/dist/auth.d.ts +2 -2
- package/dist/auth.js +9 -18
- package/dist/ceremonies/index.d.ts +1 -1
- package/dist/ceremonies/index.js +8 -18
- package/dist/config/loader.d.ts +2 -2
- package/dist/config/loader.js +19 -42
- package/dist/contract-serialization.d.ts +2 -2
- package/dist/contract-serialization.js +3 -6
- package/dist/contract-types.d.ts +2 -2
- package/dist/contract.d.ts +3 -3
- package/dist/contract.js +4 -6
- package/dist/define.d.ts +8 -1
- package/dist/define.js +57 -115
- package/dist/dev.d.ts +1 -1
- package/dist/dev.js +1 -1
- package/dist/errors.d.ts +1 -1
- package/dist/errors.js +1 -3
- package/dist/i18n/catalog.d.ts +2 -2
- package/dist/i18n/catalog.js +4 -10
- package/dist/i18n/index.d.ts +2 -2
- package/dist/i18n/index.js +2 -2
- package/dist/i18n/keys.d.ts +2 -2
- package/dist/index.d.ts +43 -42
- package/dist/index.js +38 -37
- package/dist/lint.js +8 -15
- package/dist/provider.d.ts +11 -11
- package/dist/provider.js +9 -9
- package/dist/public-schema-field-lint.d.ts +1 -1
- package/dist/recipes/gov-api.js +1 -1
- package/dist/runtime/auth-flow.d.ts +1 -1
- package/dist/runtime/auth-flow.js +3 -3
- package/dist/runtime/browser.d.ts +1 -1
- package/dist/runtime/browser.js +15 -29
- package/dist/runtime/cache.d.ts +1 -1
- package/dist/runtime/cache.js +4 -8
- package/dist/runtime/choice.d.ts +1 -1
- package/dist/runtime/choice.js +12 -34
- package/dist/runtime/credential.d.ts +1 -1
- package/dist/runtime/credential.js +1 -1
- package/dist/runtime/env.d.ts +1 -1
- package/dist/runtime/executor.d.ts +1 -1
- package/dist/runtime/executor.js +2 -2
- package/dist/runtime/http.d.ts +2 -2
- package/dist/runtime/http.js +5 -5
- package/dist/runtime/insights.d.ts +1 -1
- package/dist/runtime/insights.js +6 -13
- package/dist/runtime/instrumentation.d.ts +2 -2
- package/dist/runtime/instrumentation.js +5 -15
- package/dist/runtime/keyring.js +1 -1
- package/dist/runtime/namespace.js +1 -1
- package/dist/runtime/otlp.d.ts +1 -1
- package/dist/runtime/perf.d.ts +1 -1
- package/dist/runtime/provider.d.ts +1 -1
- package/dist/runtime/provider.js +1 -2
- package/dist/runtime/proxy-errors.d.ts +1 -1
- package/dist/runtime/proxy-errors.js +3 -5
- package/dist/runtime/proxy-retry-policy.d.ts +2 -2
- package/dist/runtime/proxy-retry-policy.js +2 -2
- package/dist/runtime/proxy-telemetry.d.ts +1 -1
- package/dist/runtime/proxy-telemetry.js +16 -48
- package/dist/runtime/redis.d.ts +1 -1
- package/dist/runtime/redis.js +2 -4
- package/dist/runtime/request-options.d.ts +1 -1
- package/dist/runtime/state.d.ts +2 -2
- package/dist/runtime/state.js +3 -3
- package/dist/runtime/stealth.d.ts +2 -2
- package/dist/runtime/stealth.js +6 -6
- package/dist/runtime/stt.d.ts +1 -1
- package/dist/runtime/stt.js +11 -15
- package/dist/runtime/trace.d.ts +2 -2
- package/dist/runtime/trace.js +2 -4
- package/dist/runtime/waterfall.d.ts +1 -1
- package/dist/schema.d.ts +1 -1
- package/dist/schema.js +7 -15
- package/dist/serve.d.ts +1 -1
- package/dist/serve.js +1 -1
- package/dist/server/index.d.ts +7 -7
- package/dist/server/index.js +6 -6
- package/dist/server/self-test-redaction.d.ts +1 -1
- package/dist/server/self-test-redaction.js +1 -1
- package/dist/server/self-test.d.ts +3 -3
- package/dist/server/self-test.js +3 -3
- package/dist/server/serve.d.ts +3 -3
- package/dist/server/serve.js +36 -49
- package/dist/server/types.js +2 -7
- package/dist/stealth/profiles.d.ts +1 -1
- package/dist/stealth/profiles.js +5 -14
- package/dist/stream.d.ts +1 -1
- package/dist/testing/index.d.ts +2 -2
- package/dist/testing/index.js +2 -2
- package/dist/testing/run.d.ts +1 -1
- package/dist/testing/run.js +7 -14
- package/dist/types.d.ts +57 -0
- package/dist/user-input.d.ts +30 -0
- package/dist/user-input.js +66 -0
- package/package.json +6 -4
- package/src/auth-turn/index.ts +1 -1
- package/src/auth.ts +28 -86
- package/src/ceremonies/index.ts +24 -78
- package/src/config/loader.ts +58 -176
- package/src/contract-serialization.ts +5 -11
- package/src/contract-types.ts +2 -2
- package/src/contract.ts +12 -28
- package/src/define.ts +174 -495
- package/src/dev.ts +4 -9
- package/src/errors.ts +4 -11
- package/src/i18n/catalog.ts +10 -32
- package/src/i18n/index.ts +2 -2
- package/src/i18n/keys.ts +5 -11
- package/src/index.ts +44 -42
- package/src/lint.ts +89 -159
- package/src/provider.ts +12 -11
- package/src/public-schema-field-lint.ts +7 -33
- package/src/recipes/gov-api.ts +2 -5
- package/src/runtime/auth-flow.ts +5 -7
- package/src/runtime/browser.ts +64 -187
- package/src/runtime/cache.ts +20 -67
- package/src/runtime/choice.ts +55 -129
- package/src/runtime/credential.ts +2 -2
- package/src/runtime/env.ts +1 -1
- package/src/runtime/executor.ts +9 -19
- package/src/runtime/http.ts +7 -7
- package/src/runtime/insights.ts +15 -53
- package/src/runtime/instrumentation.ts +19 -58
- package/src/runtime/keyring.ts +7 -19
- package/src/runtime/namespace.ts +2 -7
- package/src/runtime/otlp.ts +12 -23
- package/src/runtime/perf.ts +1 -1
- package/src/runtime/provider.ts +4 -9
- package/src/runtime/proxy-errors.ts +17 -38
- package/src/runtime/proxy-retry-policy.ts +3 -3
- package/src/runtime/proxy-telemetry.ts +23 -72
- package/src/runtime/redis.ts +4 -12
- package/src/runtime/request-options.ts +4 -13
- package/src/runtime/state.ts +30 -109
- package/src/runtime/stealth.ts +8 -8
- package/src/runtime/stt.ts +38 -94
- package/src/runtime/trace.ts +14 -44
- package/src/runtime/waterfall.ts +5 -18
- package/src/schema.ts +23 -84
- package/src/serve.ts +1 -1
- package/src/server/index.ts +7 -7
- package/src/server/self-test-redaction.ts +2 -2
- package/src/server/self-test.ts +5 -5
- package/src/server/serve.ts +87 -242
- package/src/server/types.ts +6 -19
- package/src/stealth/profiles.ts +10 -26
- package/src/stream.ts +8 -19
- package/src/testing/index.ts +2 -2
- package/src/testing/run.ts +19 -67
- package/src/types.ts +58 -0
- package/src/user-input.ts +118 -0
package/bin/apifuse-record.ts
CHANGED
|
@@ -20,8 +20,8 @@ import {
|
|
|
20
20
|
type StealthClient,
|
|
21
21
|
TransportError,
|
|
22
22
|
ValidationError,
|
|
23
|
-
} from "../src";
|
|
24
|
-
import { createMemoryProviderRuntimeState } from "../src/runtime/state";
|
|
23
|
+
} from "../src/index.js";
|
|
24
|
+
import { createMemoryProviderRuntimeState } from "../src/runtime/state.js";
|
|
25
25
|
|
|
26
26
|
type CliArgs = {
|
|
27
27
|
append: boolean;
|
|
@@ -64,31 +64,18 @@ export async function main() {
|
|
|
64
64
|
resolveOperationBaseUrl(provider, operationName),
|
|
65
65
|
);
|
|
66
66
|
|
|
67
|
-
console.log(
|
|
68
|
-
`[apifuse record] Calling ${operationName} on ${provider.id}...`,
|
|
69
|
-
);
|
|
67
|
+
console.log(`[apifuse record] Calling ${operationName} on ${provider.id}...`);
|
|
70
68
|
|
|
71
|
-
const result = await executeOperation(
|
|
72
|
-
provider,
|
|
73
|
-
operationName,
|
|
74
|
-
capture.ctx,
|
|
75
|
-
parsedParams,
|
|
76
|
-
);
|
|
69
|
+
const result = await executeOperation(provider, operationName, capture.ctx, parsedParams);
|
|
77
70
|
const captured = capture.getCapturedRaw();
|
|
78
71
|
|
|
79
72
|
if (captured === undefined) {
|
|
80
|
-
throw new Error(
|
|
81
|
-
`No upstream response was captured for ${provider.id}.${operationName}.`,
|
|
82
|
-
);
|
|
73
|
+
throw new Error(`No upstream response was captured for ${provider.id}.${operationName}.`);
|
|
83
74
|
}
|
|
84
75
|
|
|
85
76
|
const rawPayload = args.sanitize ? sanitizeFixture(captured) : captured;
|
|
86
77
|
const fixturePath = resolve(location.rootDir, "__fixtures__", "raw.json");
|
|
87
|
-
const nextPayload = await prepareFixturePayload(
|
|
88
|
-
fixturePath,
|
|
89
|
-
rawPayload,
|
|
90
|
-
args.append,
|
|
91
|
-
);
|
|
78
|
+
const nextPayload = await prepareFixturePayload(fixturePath, rawPayload, args.append);
|
|
92
79
|
|
|
93
80
|
await mkdir(dirname(fixturePath), { recursive: true });
|
|
94
81
|
await writeFile(fixturePath, `${JSON.stringify(nextPayload, null, 2)}\n`);
|
|
@@ -98,9 +85,7 @@ export async function main() {
|
|
|
98
85
|
Buffer.byteLength(JSON.stringify(rawPayload)),
|
|
99
86
|
)})`,
|
|
100
87
|
);
|
|
101
|
-
console.log(
|
|
102
|
-
`[apifuse record] Saved to ${relative(process.cwd(), fixturePath)}`,
|
|
103
|
-
);
|
|
88
|
+
console.log(`[apifuse record] Saved to ${relative(process.cwd(), fixturePath)}`);
|
|
104
89
|
|
|
105
90
|
void result;
|
|
106
91
|
} catch (error) {
|
|
@@ -210,11 +195,7 @@ function formatCliError(error: unknown): string {
|
|
|
210
195
|
}
|
|
211
196
|
|
|
212
197
|
if (error instanceof ProviderError || error instanceof ValidationError) {
|
|
213
|
-
return [
|
|
214
|
-
error.message,
|
|
215
|
-
error.code ? `code=${error.code}` : undefined,
|
|
216
|
-
error.fix,
|
|
217
|
-
]
|
|
198
|
+
return [error.message, error.code ? `code=${error.code}` : undefined, error.fix]
|
|
218
199
|
.filter(Boolean)
|
|
219
200
|
.join(" ");
|
|
220
201
|
}
|
|
@@ -269,8 +250,7 @@ function findProviderRoot(startDirectory: string): string | undefined {
|
|
|
269
250
|
|
|
270
251
|
function looksLikeProviderRoot(directory: string): boolean {
|
|
271
252
|
return (
|
|
272
|
-
existsSync(resolve(directory, "index.ts")) &&
|
|
273
|
-
existsSync(resolve(directory, "package.json"))
|
|
253
|
+
existsSync(resolve(directory, "index.ts")) && existsSync(resolve(directory, "package.json"))
|
|
274
254
|
);
|
|
275
255
|
}
|
|
276
256
|
|
|
@@ -287,15 +267,10 @@ async function loadProvider(rootDir: string): Promise<ProviderRuntime> {
|
|
|
287
267
|
return module.default;
|
|
288
268
|
}
|
|
289
269
|
|
|
290
|
-
function resolveOperationName(
|
|
291
|
-
provider: ProviderRuntime,
|
|
292
|
-
operationName?: string,
|
|
293
|
-
): string {
|
|
270
|
+
function resolveOperationName(provider: ProviderRuntime, operationName?: string): string {
|
|
294
271
|
if (operationName) {
|
|
295
272
|
if (!(operationName in provider.operations)) {
|
|
296
|
-
throw new Error(
|
|
297
|
-
`Unknown operation "${operationName}" for provider "${provider.id}".`,
|
|
298
|
-
);
|
|
273
|
+
throw new Error(`Unknown operation "${operationName}" for provider "${provider.id}".`);
|
|
299
274
|
}
|
|
300
275
|
|
|
301
276
|
return operationName;
|
|
@@ -309,10 +284,7 @@ function resolveOperationName(
|
|
|
309
284
|
return firstOperation;
|
|
310
285
|
}
|
|
311
286
|
|
|
312
|
-
function parseParams(
|
|
313
|
-
operation: ProviderRuntime["operations"][string],
|
|
314
|
-
value: string,
|
|
315
|
-
): unknown {
|
|
287
|
+
function parseParams(operation: ProviderRuntime["operations"][string], value: string): unknown {
|
|
316
288
|
let parsed: unknown;
|
|
317
289
|
|
|
318
290
|
try {
|
|
@@ -326,10 +298,7 @@ function parseParams(
|
|
|
326
298
|
return operation.input ? operation.input.parse(parsed) : parsed;
|
|
327
299
|
}
|
|
328
300
|
|
|
329
|
-
function resolveOperationBaseUrl(
|
|
330
|
-
provider: ProviderRuntime,
|
|
331
|
-
operationName: string,
|
|
332
|
-
): string {
|
|
301
|
+
function resolveOperationBaseUrl(provider: ProviderRuntime, operationName: string): string {
|
|
333
302
|
const baseUrl = provider.operations[operationName]?.upstream?.baseUrl;
|
|
334
303
|
if (!baseUrl) {
|
|
335
304
|
throw new Error(
|
|
@@ -346,12 +315,9 @@ function createCaptureContext(provider: ProviderRuntime, baseUrl: string) {
|
|
|
346
315
|
const http = proxyHttpClient(createHttpClient(baseUrl), (response) => {
|
|
347
316
|
capturedRaw = response.data;
|
|
348
317
|
});
|
|
349
|
-
const stealth = proxyStealthClient(
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
capturedRaw = normalizeCapturedStealthResponse(response);
|
|
353
|
-
},
|
|
354
|
-
);
|
|
318
|
+
const stealth = proxyStealthClient(createStealthClient(baseUrl), (response) => {
|
|
319
|
+
capturedRaw = normalizeCapturedStealthResponse(response);
|
|
320
|
+
});
|
|
355
321
|
|
|
356
322
|
const env = {
|
|
357
323
|
get: (key: string) => process.env[key],
|
|
@@ -464,9 +430,7 @@ function proxyStealthSession(
|
|
|
464
430
|
};
|
|
465
431
|
}
|
|
466
432
|
|
|
467
|
-
function normalizeCapturedStealthResponse(
|
|
468
|
-
response: Awaited<ReturnType<StealthClient["fetch"]>>,
|
|
469
|
-
) {
|
|
433
|
+
function normalizeCapturedStealthResponse(response: Awaited<ReturnType<StealthClient["fetch"]>>) {
|
|
470
434
|
try {
|
|
471
435
|
return JSON.parse(response.body);
|
|
472
436
|
} catch {
|
|
@@ -483,15 +447,13 @@ function sanitizeFixture(value: unknown): unknown {
|
|
|
483
447
|
return value;
|
|
484
448
|
}
|
|
485
449
|
|
|
486
|
-
const entries = Object.entries(value as MutableRecord).map(
|
|
487
|
-
(
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
}
|
|
450
|
+
const entries = Object.entries(value as MutableRecord).map(([key, entryValue]) => {
|
|
451
|
+
if (isSensitiveKey(key)) {
|
|
452
|
+
return [key, "[REDACTED]"] as const;
|
|
453
|
+
}
|
|
491
454
|
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
);
|
|
455
|
+
return [key, sanitizeFixture(entryValue)] as const;
|
|
456
|
+
});
|
|
495
457
|
|
|
496
458
|
return Object.fromEntries(entries);
|
|
497
459
|
}
|
|
@@ -11,16 +11,16 @@ import * as acorn from "acorn";
|
|
|
11
11
|
import { z } from "zod";
|
|
12
12
|
|
|
13
13
|
import packageJson from "../package.json";
|
|
14
|
-
import type { ProviderDefinition } from "../src";
|
|
14
|
+
import type { ProviderDefinition } from "../src/index.js";
|
|
15
15
|
import {
|
|
16
16
|
loadProviderLocaleCatalogs,
|
|
17
17
|
type ProviderLocale,
|
|
18
18
|
validateProviderLocaleCatalogs,
|
|
19
|
-
} from "../src/i18n";
|
|
20
|
-
import { APIFUSE_DESCRIPTION_KEY_META_KEY } from "../src/schema";
|
|
21
|
-
import { safeParseSchemaSync } from "../src/schema";
|
|
22
|
-
import { type CheckResult, runChecks } from "./apifuse-check";
|
|
23
|
-
import { hasSubstantiveXmlStructure } from "./submit-check-xml";
|
|
19
|
+
} from "../src/i18n/index.js";
|
|
20
|
+
import { APIFUSE_DESCRIPTION_KEY_META_KEY } from "../src/schema.js";
|
|
21
|
+
import { safeParseSchemaSync } from "../src/schema.js";
|
|
22
|
+
import { type CheckResult, runChecks } from "./apifuse-check.js";
|
|
23
|
+
import { hasSubstantiveXmlStructure } from "./submit-check-xml.js";
|
|
24
24
|
|
|
25
25
|
const TIERS = ["bronze", "silver", "gold", "diamond"] as const;
|
|
26
26
|
const TIER_VALUES: ReadonlySet<string> = new Set(TIERS);
|
|
@@ -1980,10 +1980,7 @@ function scoreFixtureCoverage(provider: ProviderDefinition): SubmitCheck {
|
|
|
1980
1980
|
|
|
1981
1981
|
const GENERATED_LOCAL_ONLY_SCAFFOLD_REASON = /generated local-only scaffold/i;
|
|
1982
1982
|
|
|
1983
|
-
function scoreFixtureProvenance(
|
|
1984
|
-
providerRoot: string,
|
|
1985
|
-
provider: ProviderDefinition,
|
|
1986
|
-
): SubmitCheck {
|
|
1983
|
+
function scoreFixtureProvenance(providerRoot: string, provider: ProviderDefinition): SubmitCheck {
|
|
1987
1984
|
const rawPath = resolve(providerRoot, "__fixtures__", "raw.json");
|
|
1988
1985
|
let hasRecordedEvidence = false;
|
|
1989
1986
|
if (existsSync(rawPath)) {
|
|
@@ -2090,12 +2087,17 @@ function allOperationsAreGeneratedLocalScaffold(provider: ProviderDefinition): b
|
|
|
2090
2087
|
}
|
|
2091
2088
|
|
|
2092
2089
|
function scoreVendorKeyLeak(providerRoot: string): SubmitCheck {
|
|
2093
|
-
return escapeHatchResult(
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2090
|
+
return escapeHatchResult(
|
|
2091
|
+
providerRoot,
|
|
2092
|
+
"vendor-key-leak",
|
|
2093
|
+
findVendorKeyLeakFindings(providerRoot),
|
|
2094
|
+
{
|
|
2095
|
+
blockerMessage: "Public schema keys leak raw vendor field names.",
|
|
2096
|
+
remediation:
|
|
2097
|
+
"Normalize public request/response fields to APIFuse-standard lowerCamelCase names (e.g. isOpen24h, latitude); keep raw vendor keys only in upstream-parsing schemas (const upstream... = z.object(...)). Add `// @apifuse-allow vendor-key-leak` only with a comment explaining why the vendor name is genuinely canonical.",
|
|
2098
|
+
passMessage: "No vendor field-name leaks detected in public schemas.",
|
|
2099
|
+
},
|
|
2100
|
+
);
|
|
2099
2101
|
}
|
|
2100
2102
|
|
|
2101
2103
|
function scoreVendorTimestampLeak(providerRoot: string): SubmitCheck {
|
|
@@ -2282,9 +2284,7 @@ function collectTopLevelObjectKeys(
|
|
|
2282
2284
|
if (computedQuote === '"' || computedQuote === "'") {
|
|
2283
2285
|
const literalEnd = findStringEnd(source, literalStart);
|
|
2284
2286
|
const afterLiteral =
|
|
2285
|
-
literalEnd === -1
|
|
2286
|
-
? -1
|
|
2287
|
-
: skipWhitespaceAndComments(masked, literalEnd + 1, computedEnd);
|
|
2287
|
+
literalEnd === -1 ? -1 : skipWhitespaceAndComments(masked, literalEnd + 1, computedEnd);
|
|
2288
2288
|
if (literalEnd !== -1 && afterLiteral === computedEnd) {
|
|
2289
2289
|
key = source.slice(literalStart + 1, literalEnd);
|
|
2290
2290
|
}
|
|
@@ -2402,8 +2402,13 @@ function findNamedConstValueRanges(source: string): NamedObjectRange[] {
|
|
|
2402
2402
|
return ranges;
|
|
2403
2403
|
}
|
|
2404
2404
|
|
|
2405
|
-
function findConstValueRangeContaining(
|
|
2406
|
-
|
|
2405
|
+
function findConstValueRangeContaining(
|
|
2406
|
+
source: string,
|
|
2407
|
+
offset: number,
|
|
2408
|
+
): NamedObjectRange | undefined {
|
|
2409
|
+
return findNamedConstValueRanges(source).find(
|
|
2410
|
+
(range) => offset >= range.start && offset <= range.end,
|
|
2411
|
+
);
|
|
2407
2412
|
}
|
|
2408
2413
|
|
|
2409
2414
|
function findStringLiteralsInRange(
|
package/bin/apifuse.ts
CHANGED
package/bin/submit-check-xml.ts
CHANGED
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
normalizedXmlName,
|
|
15
15
|
rootXmlContext,
|
|
16
16
|
type XmlSemanticBranch,
|
|
17
|
-
} from "./submit-check-xml-semantics";
|
|
17
|
+
} from "./submit-check-xml-semantics.js";
|
|
18
18
|
|
|
19
19
|
const MIN_RECORDED_XML_LENGTH = 128;
|
|
20
20
|
// Recorded fixtures must remain reviewable; this pre-allocation cap also bounds the parser tree.
|
package/dist/auth.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { AuthError } from "./errors";
|
|
2
|
-
import type { AuthConfig, AuthFlowTerminalContext, AuthTurn, ContextDeclaration, CredentialDeclaration, FlowContext, ProviderLocaleKeyInput } from "./types";
|
|
1
|
+
import { AuthError } from "./errors.js";
|
|
2
|
+
import type { AuthConfig, AuthFlowTerminalContext, AuthTurn, ContextDeclaration, CredentialDeclaration, FlowContext, ProviderLocaleKeyInput } from "./types.js";
|
|
3
3
|
export type CredentialsAuthFieldType = "string" | "email" | "password" | "otp";
|
|
4
4
|
export interface CredentialsAuthField {
|
|
5
5
|
type?: CredentialsAuthFieldType;
|
package/dist/auth.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AuthError, ProviderError } from "./errors";
|
|
1
|
+
import { AuthError, ProviderError } from "./errors.js";
|
|
2
2
|
const CREDENTIALS_AUTH_CHALLENGE_CONTEXT_KEY = "__credentialsAuthChallenge";
|
|
3
3
|
const DEFAULT_COMPLETE_TURN_ID = "auth.complete";
|
|
4
4
|
const DEFAULT_ABORT_TURN_ID = "auth.abort";
|
|
@@ -97,7 +97,7 @@ export function createAuthFlowHelpers(options = {}) {
|
|
|
97
97
|
},
|
|
98
98
|
};
|
|
99
99
|
},
|
|
100
|
-
abort({ code, message, retry, actionHint, fieldErrors, data, turnId, expiresAt
|
|
100
|
+
abort({ code, message, retry, actionHint, fieldErrors, data, turnId, expiresAt }) {
|
|
101
101
|
return {
|
|
102
102
|
kind: "abort",
|
|
103
103
|
...authTurnBase({ turnId, defaultTurnId: DEFAULT_ABORT_TURN_ID, expiresAt }),
|
|
@@ -169,12 +169,8 @@ function expectedInputFromFields(fields) {
|
|
|
169
169
|
...(field.type === "password" ? { format: "password" } : {}),
|
|
170
170
|
...(field.type === "otp" ? { format: "otp" } : {}),
|
|
171
171
|
...(field.labelKey ? { nameKey: field.labelKey } : {}),
|
|
172
|
-
...(field.descriptionKey
|
|
173
|
-
|
|
174
|
-
: {}),
|
|
175
|
-
...(field.placeholderKey
|
|
176
|
-
? { placeholderKey: field.placeholderKey }
|
|
177
|
-
: {}),
|
|
172
|
+
...(field.descriptionKey ? { descriptionKey: field.descriptionKey } : {}),
|
|
173
|
+
...(field.placeholderKey ? { placeholderKey: field.placeholderKey } : {}),
|
|
178
174
|
...(field.sensitive || field.type === "password" || field.type === "otp"
|
|
179
175
|
? { sensitive: true }
|
|
180
176
|
: {}),
|
|
@@ -291,17 +287,15 @@ function completeTurn(credentialKeys, result, defaultTurnId) {
|
|
|
291
287
|
};
|
|
292
288
|
}
|
|
293
289
|
function challengeTurn(definition, request) {
|
|
294
|
-
const expectedInput = definition.fields
|
|
295
|
-
? expectedInputFromFields(definition.fields)
|
|
296
|
-
: undefined;
|
|
290
|
+
const expectedInput = definition.fields ? expectedInputFromFields(definition.fields) : undefined;
|
|
297
291
|
return {
|
|
298
292
|
kind: expectedInput ? "form" : "pending",
|
|
299
293
|
turnId: request.turnId ?? definition.turnId ?? `credentials.${request.challengeId}`,
|
|
300
294
|
...(request.expiresAt ? { expiresAt: request.expiresAt } : {}),
|
|
301
|
-
...(request.hintKey ?? definition.hintKey
|
|
295
|
+
...((request.hintKey ?? definition.hintKey)
|
|
302
296
|
? { hintKey: request.hintKey ?? definition.hintKey }
|
|
303
297
|
: {}),
|
|
304
|
-
...(request.timing ?? definition.timing
|
|
298
|
+
...((request.timing ?? definition.timing)
|
|
305
299
|
? { timing: request.timing ?? definition.timing }
|
|
306
300
|
: {}),
|
|
307
301
|
...(expectedInput ? { expectedInput } : {}),
|
|
@@ -378,7 +372,7 @@ async function pollPendingChallenge(ctx, credentialKeys, challenges, pending, co
|
|
|
378
372
|
export function defineCredentialsAuth(options) {
|
|
379
373
|
if (Object.keys(options.fields).length === 0) {
|
|
380
374
|
throw new ProviderError("defineCredentialsAuth requires at least one field", {
|
|
381
|
-
fix:
|
|
375
|
+
fix: 'Pass fields such as { email: { type: "email" }, password: { type: "password" } }.',
|
|
382
376
|
});
|
|
383
377
|
}
|
|
384
378
|
const expectedInput = expectedInputFromFields(options.fields);
|
|
@@ -427,10 +421,7 @@ export function defineCredentialsAuth(options) {
|
|
|
427
421
|
...(options.justification ? { justification: options.justification } : {}),
|
|
428
422
|
},
|
|
429
423
|
context: {
|
|
430
|
-
keys: Array.from(new Set([
|
|
431
|
-
CREDENTIALS_AUTH_CHALLENGE_CONTEXT_KEY,
|
|
432
|
-
...(options.contextKeys ?? []),
|
|
433
|
-
])),
|
|
424
|
+
keys: Array.from(new Set([CREDENTIALS_AUTH_CHALLENGE_CONTEXT_KEY, ...(options.contextKeys ?? [])])),
|
|
434
425
|
},
|
|
435
426
|
};
|
|
436
427
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AuthFlowDefinition, AuthTurn } from "../types";
|
|
1
|
+
import type { AuthFlowDefinition, AuthTurn } from "../types.js";
|
|
2
2
|
type JsonObject = Record<string, unknown>;
|
|
3
3
|
export declare function validateCeremonyOutput(turn: unknown): AuthTurn;
|
|
4
4
|
export declare function createOAuth2Ceremony(options: {
|
package/dist/ceremonies/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createHash, randomBytes, randomUUID } from "node:crypto";
|
|
2
2
|
import Ajv2020 from "ajv/dist/2020.js";
|
|
3
|
-
import { AUTH_TURN_SCHEMA } from "../auth-turn";
|
|
4
|
-
import { FlowExpiredError, ProviderSecretError, TurnValidationError, ValidationError, } from "../errors";
|
|
3
|
+
import { AUTH_TURN_SCHEMA } from "../auth-turn/index.js";
|
|
4
|
+
import { FlowExpiredError, ProviderSecretError, TurnValidationError, ValidationError, } from "../errors.js";
|
|
5
5
|
const ajv = new Ajv2020({ allErrors: true, strict: true, strictSchema: true });
|
|
6
6
|
// Runtime ceremony-output validation derives from the exported versioned
|
|
7
7
|
// contract: it compiles the exact AUTH_TURN_SCHEMA document shipped at
|
|
@@ -38,11 +38,7 @@ function getRequiredEnv(ctx, key) {
|
|
|
38
38
|
return value;
|
|
39
39
|
}
|
|
40
40
|
function toBase64Url(input) {
|
|
41
|
-
return input
|
|
42
|
-
.toString("base64")
|
|
43
|
-
.replace(/\+/g, "-")
|
|
44
|
-
.replace(/\//g, "_")
|
|
45
|
-
.replace(/=+$/g, "");
|
|
41
|
+
return input.toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/g, "");
|
|
46
42
|
}
|
|
47
43
|
function createCodeVerifier() {
|
|
48
44
|
return toBase64Url(randomBytes(32));
|
|
@@ -100,8 +96,7 @@ function withDeclaredFormFieldOrder(expectedInput) {
|
|
|
100
96
|
return expectedInput;
|
|
101
97
|
}
|
|
102
98
|
const existingOrder = expectedInput[FORM_FIELD_ORDER_EXTENSION];
|
|
103
|
-
if (Array.isArray(existingOrder) &&
|
|
104
|
-
existingOrder.every((value) => typeof value === "string")) {
|
|
99
|
+
if (Array.isArray(existingOrder) && existingOrder.every((value) => typeof value === "string")) {
|
|
105
100
|
return expectedInput;
|
|
106
101
|
}
|
|
107
102
|
return {
|
|
@@ -218,8 +213,7 @@ export function createDeviceFlowCeremony(options) {
|
|
|
218
213
|
});
|
|
219
214
|
const data = ensureRecord(response.data);
|
|
220
215
|
const errorCode = getString(data, "error");
|
|
221
|
-
if (errorCode === "authorization_pending" ||
|
|
222
|
-
errorCode === "slow_down") {
|
|
216
|
+
if (errorCode === "authorization_pending" || errorCode === "slow_down") {
|
|
223
217
|
return createTurn("poll", {
|
|
224
218
|
data,
|
|
225
219
|
hint: "Authorization pending.",
|
|
@@ -345,7 +339,7 @@ export function createFormCeremony(options) {
|
|
|
345
339
|
return {
|
|
346
340
|
start: async () => validateCeremonyOutput(buildJsonSchemaForm(options.schema, options.hint ?? "Provide the required input to continue.")),
|
|
347
341
|
continue: (ctx, input = {}) => runCeremonyHandler(async () => {
|
|
348
|
-
const { prevalidate } = await import("../runtime/prevalidate");
|
|
342
|
+
const { prevalidate } = await import("../runtime/prevalidate.js");
|
|
349
343
|
const result = prevalidate(options.schema, input);
|
|
350
344
|
if (!result.valid) {
|
|
351
345
|
throw new ValidationError("Form input failed validation.", {
|
|
@@ -354,9 +348,7 @@ export function createFormCeremony(options) {
|
|
|
354
348
|
}
|
|
355
349
|
return createTurn("complete", {
|
|
356
350
|
data: {
|
|
357
|
-
credential: options.mapCredential
|
|
358
|
-
? options.mapCredential(input)
|
|
359
|
-
: input,
|
|
351
|
+
credential: options.mapCredential ? options.mapCredential(input) : input,
|
|
360
352
|
},
|
|
361
353
|
hint: "Form completed.",
|
|
362
354
|
});
|
|
@@ -428,9 +420,7 @@ export function createSwitchCeremony(options) {
|
|
|
428
420
|
})),
|
|
429
421
|
continue: (ctx, input = {}) => runCeremonyHandler(async () => {
|
|
430
422
|
const storedChoice = ctx.context.get(SWITCH_SELECTION_KEY);
|
|
431
|
-
const choice = typeof storedChoice === "string"
|
|
432
|
-
? storedChoice
|
|
433
|
-
: getString(input, "choice");
|
|
423
|
+
const choice = typeof storedChoice === "string" ? storedChoice : getString(input, "choice");
|
|
434
424
|
if (!choice || !options.choices[choice]) {
|
|
435
425
|
throw new ValidationError("A valid choice is required.");
|
|
436
426
|
}
|
package/dist/config/loader.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import Redis from "ioredis";
|
|
2
|
-
import type { ProviderProxyPolicy, TraceConfig } from "../types";
|
|
1
|
+
import { Redis } from "ioredis";
|
|
2
|
+
import type { ProviderProxyPolicy, TraceConfig } from "../types.js";
|
|
3
3
|
export declare const SMARTPROXY_APP_KEY_ENV = "APIFUSE__PROXY__SMARTPROXY_APP_KEY";
|
|
4
4
|
export declare const SMARTPROXY_MAX_LIFETIME_MINUTES = 2000;
|
|
5
5
|
export declare const DEFAULT_SMARTPROXY_POOL_SIZE = 20;
|
package/dist/config/loader.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createHash, randomUUID } from "node:crypto";
|
|
2
2
|
import { existsSync } from "node:fs";
|
|
3
3
|
import path from "node:path";
|
|
4
|
-
import Redis from "ioredis";
|
|
4
|
+
import { Redis } from "ioredis";
|
|
5
5
|
export const SMARTPROXY_APP_KEY_ENV = "APIFUSE__PROXY__SMARTPROXY_APP_KEY";
|
|
6
6
|
export const SMARTPROXY_MAX_LIFETIME_MINUTES = 2000;
|
|
7
7
|
export const DEFAULT_SMARTPROXY_POOL_SIZE = 20;
|
|
@@ -160,9 +160,7 @@ function toProxyDiagnostics(value) {
|
|
|
160
160
|
return undefined;
|
|
161
161
|
const diagnostics = {};
|
|
162
162
|
for (const [key, item] of Object.entries(value)) {
|
|
163
|
-
if (typeof item === "string" ||
|
|
164
|
-
typeof item === "number" ||
|
|
165
|
-
typeof item === "boolean") {
|
|
163
|
+
if (typeof item === "string" || typeof item === "number" || typeof item === "boolean") {
|
|
166
164
|
diagnostics[key] = item;
|
|
167
165
|
}
|
|
168
166
|
}
|
|
@@ -249,9 +247,7 @@ function applyStickyProxySession(proxyUrl) {
|
|
|
249
247
|
}
|
|
250
248
|
function buildSmartproxyUsername(username, sessionId, sessionDuration) {
|
|
251
249
|
const parts = username.split("_");
|
|
252
|
-
const configuredLife = parts
|
|
253
|
-
.find((part) => part.startsWith("life-"))
|
|
254
|
-
?.slice("life-".length);
|
|
250
|
+
const configuredLife = parts.find((part) => part.startsWith("life-"))?.slice("life-".length);
|
|
255
251
|
const baseUsername = parts
|
|
256
252
|
.filter((part) => !part.startsWith("session-") && !part.startsWith("life-"))
|
|
257
253
|
.join("_");
|
|
@@ -259,9 +255,7 @@ function buildSmartproxyUsername(username, sessionId, sessionDuration) {
|
|
|
259
255
|
}
|
|
260
256
|
function buildDecodoUsername(username, sessionId, sessionDuration) {
|
|
261
257
|
const withoutSticky = username.replace(/-session-.+-sessionduration-\d+$/, "");
|
|
262
|
-
const baseUsername = withoutSticky.startsWith("user-")
|
|
263
|
-
? withoutSticky
|
|
264
|
-
: `user-${withoutSticky}`;
|
|
258
|
+
const baseUsername = withoutSticky.startsWith("user-") ? withoutSticky : `user-${withoutSticky}`;
|
|
265
259
|
return `${baseUsername}-session-${sessionId}-sessionduration-${sessionDuration}`;
|
|
266
260
|
}
|
|
267
261
|
function syncProxyEnv(config) {
|
|
@@ -358,18 +352,13 @@ function resolvePolicy(options) {
|
|
|
358
352
|
return undefined;
|
|
359
353
|
}
|
|
360
354
|
function resolveProxyProvider(policy) {
|
|
361
|
-
return (policy.provider ??
|
|
362
|
-
process.env[DEFAULT_PROXY_PROVIDER_ENV]?.trim().toLowerCase() ??
|
|
363
|
-
"custom");
|
|
355
|
+
return (policy.provider ?? process.env[DEFAULT_PROXY_PROVIDER_ENV]?.trim().toLowerCase() ?? "custom");
|
|
364
356
|
}
|
|
365
357
|
function resolveSmartproxyCountry(policy) {
|
|
366
|
-
return (policy.geo?.country ??
|
|
367
|
-
process.env[DEFAULT_PROXY_COUNTRY_ENV]?.trim().toUpperCase() ??
|
|
368
|
-
undefined);
|
|
358
|
+
return (policy.geo?.country ?? process.env[DEFAULT_PROXY_COUNTRY_ENV]?.trim().toUpperCase() ?? undefined);
|
|
369
359
|
}
|
|
370
360
|
function resolveSmartproxyLifetime(policy) {
|
|
371
|
-
const configuredLifetime = policy.session?.lifetimeMinutes ??
|
|
372
|
-
readPositiveNumberEnv(DEFAULT_PROXY_LIFETIME_ENV, 30);
|
|
361
|
+
const configuredLifetime = policy.session?.lifetimeMinutes ?? readPositiveNumberEnv(DEFAULT_PROXY_LIFETIME_ENV, 30);
|
|
373
362
|
return Math.min(SMARTPROXY_MAX_LIFETIME_MINUTES, Math.max(1, Math.floor(configuredLifetime)));
|
|
374
363
|
}
|
|
375
364
|
function readPositiveNumberEnv(name, fallback) {
|
|
@@ -389,9 +378,7 @@ function selectProxyPoolIndex(poolSize, attempt = 0) {
|
|
|
389
378
|
if (poolSize <= 1) {
|
|
390
379
|
return 0;
|
|
391
380
|
}
|
|
392
|
-
const normalizedAttempt = Number.isFinite(attempt)
|
|
393
|
-
? Math.max(0, Math.floor(attempt))
|
|
394
|
-
: 0;
|
|
381
|
+
const normalizedAttempt = Number.isFinite(attempt) ? Math.max(0, Math.floor(attempt)) : 0;
|
|
395
382
|
return normalizedAttempt % poolSize;
|
|
396
383
|
}
|
|
397
384
|
function buildSmartproxyCacheKey(policy, affinityKey, lifetimeMinutes) {
|
|
@@ -400,9 +387,7 @@ function buildSmartproxyCacheKey(policy, affinityKey, lifetimeMinutes) {
|
|
|
400
387
|
provider: "smartproxy",
|
|
401
388
|
country: resolveSmartproxyCountry(policy),
|
|
402
389
|
affinity: policy.session?.affinity ?? "request",
|
|
403
|
-
affinityKey: (policy.session?.affinity ?? "request") === "request"
|
|
404
|
-
? undefined
|
|
405
|
-
: affinityKey,
|
|
390
|
+
affinityKey: (policy.session?.affinity ?? "request") === "request" ? undefined : affinityKey,
|
|
406
391
|
lifetimeMinutes,
|
|
407
392
|
poolSize,
|
|
408
393
|
});
|
|
@@ -499,9 +484,7 @@ async function allocateSmartproxyShared(cacheKey, policy, appKey, lifetimeMinute
|
|
|
499
484
|
if (acquired === "OK") {
|
|
500
485
|
try {
|
|
501
486
|
return await allocateAndStoreSmartproxyPool(cacheKey, policy, appKey, lifetimeMinutes, startedAt, {
|
|
502
|
-
cacheStatus: options.background
|
|
503
|
-
? "soft_stale_refresh"
|
|
504
|
-
: "allocator",
|
|
487
|
+
cacheStatus: options.background ? "soft_stale_refresh" : "allocator",
|
|
505
488
|
redis,
|
|
506
489
|
poolKey,
|
|
507
490
|
});
|
|
@@ -526,8 +509,7 @@ async function allocateSmartproxyShared(cacheKey, policy, appKey, lifetimeMinute
|
|
|
526
509
|
if (typeof pttl === "number" && pttl <= 0) {
|
|
527
510
|
continue;
|
|
528
511
|
}
|
|
529
|
-
if (Date.now() - startedAt >
|
|
530
|
-
SMARTPROXY_LOCK_POLL_MAX_MS - SMARTPROXY_DEADLINE_MARGIN_MS) {
|
|
512
|
+
if (Date.now() - startedAt > SMARTPROXY_LOCK_POLL_MAX_MS - SMARTPROXY_DEADLINE_MARGIN_MS) {
|
|
531
513
|
break;
|
|
532
514
|
}
|
|
533
515
|
await sleep(Math.min(500, Math.max(50, typeof pttl === "number" ? pttl : 100)));
|
|
@@ -559,7 +541,7 @@ function sleep(ms, signal) {
|
|
|
559
541
|
});
|
|
560
542
|
}
|
|
561
543
|
function smartproxyAllocatorDeadlineMs() {
|
|
562
|
-
return
|
|
544
|
+
return smartproxyAllocatorDeadlineMsForTests ?? SMARTPROXY_ALLOCATOR_DEADLINE_MS;
|
|
563
545
|
}
|
|
564
546
|
function createDeadlineAbortController(deadlineAt) {
|
|
565
547
|
const controller = new AbortController();
|
|
@@ -649,9 +631,7 @@ async function allocateAndStoreSmartproxyPool(cacheKey, policy, appKey, lifetime
|
|
|
649
631
|
}
|
|
650
632
|
}
|
|
651
633
|
const allocatorMs = Math.max(0, Date.now() - allocatorStartedAt);
|
|
652
|
-
const allocatorAttempts = allocation?.attempt ??
|
|
653
|
-
lastFailure?.attempt ??
|
|
654
|
-
SMARTPROXY_ALLOCATOR_MAX_ATTEMPTS;
|
|
634
|
+
const allocatorAttempts = allocation?.attempt ?? lastFailure?.attempt ?? SMARTPROXY_ALLOCATOR_MAX_ATTEMPTS;
|
|
655
635
|
const allocatorBodyClass = lastFailure?.bodyClass ?? allocation?.bodyClass ?? "usable_proxy_endpoints";
|
|
656
636
|
const allocatorStatus = lastFailure ? lastFailure.status : allocation?.status;
|
|
657
637
|
if (!allocation) {
|
|
@@ -804,7 +784,9 @@ function buildSmartproxyAllocatorUrl(policy, appKey, lifetimeMinutes, poolSize)
|
|
|
804
784
|
if (country) {
|
|
805
785
|
params.set("cc", country);
|
|
806
786
|
}
|
|
807
|
-
|
|
787
|
+
// www.smartproxy.org stopped serving the extraction API on 2026-07-21 (the
|
|
788
|
+
// old path 404s into the marketing site); the API lives on the api host.
|
|
789
|
+
return `https://api.smartproxy.org/web_v1/ip/get-ip-v3?${params.toString()}`;
|
|
808
790
|
}
|
|
809
791
|
function parseSmartproxyAllocatorProxies(body) {
|
|
810
792
|
const trimmed = body.trim();
|
|
@@ -813,12 +795,8 @@ function parseSmartproxyAllocatorProxies(body) {
|
|
|
813
795
|
}
|
|
814
796
|
try {
|
|
815
797
|
const parsed = JSON.parse(trimmed);
|
|
816
|
-
const data = parsed && typeof parsed === "object" && "data" in parsed
|
|
817
|
-
|
|
818
|
-
: undefined;
|
|
819
|
-
const list = data && typeof data === "object" && "list" in data
|
|
820
|
-
? data.list
|
|
821
|
-
: undefined;
|
|
798
|
+
const data = parsed && typeof parsed === "object" && "data" in parsed ? parsed.data : undefined;
|
|
799
|
+
const list = data && typeof data === "object" && "list" in data ? data.list : undefined;
|
|
822
800
|
if (Array.isArray(list)) {
|
|
823
801
|
return list
|
|
824
802
|
.map((item) => {
|
|
@@ -826,8 +804,7 @@ function parseSmartproxyAllocatorProxies(body) {
|
|
|
826
804
|
return null;
|
|
827
805
|
}
|
|
828
806
|
const ip = "ip" in item && typeof item.ip === "string" ? item.ip : "";
|
|
829
|
-
const port = "port" in item &&
|
|
830
|
-
(typeof item.port === "string" || typeof item.port === "number")
|
|
807
|
+
const port = "port" in item && (typeof item.port === "string" || typeof item.port === "number")
|
|
831
808
|
? item.port
|
|
832
809
|
: "";
|
|
833
810
|
return ip && port ? `http://${ip}:${port}` : null;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type JsonValue } from "./contract-json";
|
|
2
|
-
import type { SchemaLike } from "./types";
|
|
1
|
+
import { type JsonValue } from "./contract-json.js";
|
|
2
|
+
import type { SchemaLike } from "./types.js";
|
|
3
3
|
export declare function describeSchema(schema: SchemaLike): JsonValue;
|
|
4
4
|
export declare function serializeSmsMatcher(value: Record<string, unknown>): Record<string, unknown>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
2
|
import { z } from "zod";
|
|
3
|
-
import { canonicalJson, compactObject, isRecord, toJsonValue, } from "./contract-json";
|
|
3
|
+
import { canonicalJson, compactObject, isRecord, toJsonValue, } from "./contract-json.js";
|
|
4
4
|
export function describeSchema(schema) {
|
|
5
5
|
if (isZodSchema(schema)) {
|
|
6
6
|
const jsonSchema = zodJsonSchema(schema);
|
|
@@ -9,9 +9,7 @@ export function describeSchema(schema) {
|
|
|
9
9
|
vendor: "zod",
|
|
10
10
|
typeName: getSchemaTypeName(schema),
|
|
11
11
|
jsonSchema,
|
|
12
|
-
jsonSchemaHash: jsonSchema === undefined
|
|
13
|
-
? undefined
|
|
14
|
-
: digest(canonicalJson(jsonSchema)),
|
|
12
|
+
jsonSchemaHash: jsonSchema === undefined ? undefined : digest(canonicalJson(jsonSchema)),
|
|
15
13
|
});
|
|
16
14
|
}
|
|
17
15
|
const standard = isRecord(schema) ? schema["~standard"] : undefined;
|
|
@@ -20,8 +18,7 @@ export function describeSchema(schema) {
|
|
|
20
18
|
kind: "schema",
|
|
21
19
|
standard: "standard-schema-v1",
|
|
22
20
|
vendor: typeof standard.vendor === "string" ? standard.vendor : "unknown",
|
|
23
|
-
version: typeof standard.version === "number" ||
|
|
24
|
-
typeof standard.version === "string"
|
|
21
|
+
version: typeof standard.version === "number" || typeof standard.version === "string"
|
|
25
22
|
? standard.version
|
|
26
23
|
: undefined,
|
|
27
24
|
});
|
package/dist/contract-types.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { JsonValue } from "./contract-json";
|
|
2
|
-
import type { ProviderDefinition } from "./types";
|
|
1
|
+
import type { JsonValue } from "./contract-json.js";
|
|
2
|
+
import type { ProviderDefinition } from "./types.js";
|
|
3
3
|
export declare const PROVIDER_CONTRACT_SCHEMA_VERSION = "2026-06-23";
|
|
4
4
|
export interface ProviderContractSnapshot {
|
|
5
5
|
readonly schemaVersion: typeof PROVIDER_CONTRACT_SCHEMA_VERSION;
|