@apifuse/provider-sdk 2.2.0-beta.25 → 2.2.0-beta.26

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.
Files changed (62) hide show
  1. package/AUTHORING.md +7 -6
  2. package/CHANGELOG.md +5 -1
  3. package/README.md +3 -3
  4. package/bin/apifuse-check.ts +62 -3
  5. package/bin/apifuse-pack-check.ts +8 -2
  6. package/bin/apifuse-pack-smoke.ts +43 -2
  7. package/bin/apifuse-pack-types.ts +58 -0
  8. package/dist/auth.js +29 -0
  9. package/dist/cli/templates/provider/README.md.tpl +4 -4
  10. package/dist/contract-serialization.d.ts +20 -1
  11. package/dist/contract-serialization.js +583 -8
  12. package/dist/contract.d.ts +2 -0
  13. package/dist/contract.js +9 -5
  14. package/dist/declaration-validation.d.ts +23 -0
  15. package/dist/declaration-validation.js +159 -0
  16. package/dist/define.d.ts +1 -1
  17. package/dist/define.js +13 -2
  18. package/dist/index.d.ts +3 -2
  19. package/dist/index.js +2 -2
  20. package/dist/lint.js +85 -3
  21. package/dist/provider.d.ts +1 -1
  22. package/dist/provider.js +1 -1
  23. package/dist/runtime/resolver-vendors/bindings.d.ts +42 -2
  24. package/dist/runtime/resolver-vendors/bindings.js +31 -6
  25. package/dist/runtime/resolver-vendors/browser.d.ts +3 -7
  26. package/dist/runtime/resolver-vendors/browser.js +7 -22
  27. package/dist/runtime/resolver-vendors/hosts.d.ts +2 -0
  28. package/dist/runtime/resolver-vendors/hosts.js +33 -0
  29. package/dist/runtime/resolver-vendors/twocaptcha.d.ts +23 -0
  30. package/dist/runtime/resolver-vendors/twocaptcha.js +264 -0
  31. package/dist/runtime/resolver-vendors/types.d.ts +44 -3
  32. package/dist/runtime/resolver-vendors/types.js +10 -0
  33. package/dist/runtime/resolver.d.ts +17 -2
  34. package/dist/runtime/resolver.js +237 -15
  35. package/dist/runtime/stealth.d.ts +26 -4
  36. package/dist/runtime/stealth.js +224 -114
  37. package/dist/schema.d.ts +63 -0
  38. package/dist/schema.js +808 -8
  39. package/dist/server/serve.js +8 -0
  40. package/dist/stealth/profiles.js +16 -7
  41. package/dist/types.d.ts +34 -1
  42. package/package.json +2 -2
  43. package/src/auth.ts +40 -0
  44. package/src/cli/templates/provider/README.md.tpl +4 -4
  45. package/src/contract-serialization.ts +857 -8
  46. package/src/contract.ts +16 -5
  47. package/src/declaration-validation.ts +202 -0
  48. package/src/define.ts +23 -2
  49. package/src/index.ts +12 -0
  50. package/src/lint.ts +98 -3
  51. package/src/provider.ts +10 -0
  52. package/src/runtime/resolver-vendors/bindings.ts +40 -15
  53. package/src/runtime/resolver-vendors/browser.ts +9 -31
  54. package/src/runtime/resolver-vendors/hosts.ts +38 -0
  55. package/src/runtime/resolver-vendors/twocaptcha.ts +366 -0
  56. package/src/runtime/resolver-vendors/types.ts +54 -0
  57. package/src/runtime/resolver.ts +304 -24
  58. package/src/runtime/stealth.ts +317 -136
  59. package/src/schema.ts +1060 -9
  60. package/src/server/serve.ts +8 -0
  61. package/src/stealth/profiles.ts +17 -7
  62. package/src/types.ts +36 -3
package/dist/schema.js CHANGED
@@ -41,7 +41,30 @@ export function safeParseSchemaSync(schema, value, fieldPath) {
41
41
  export const APIFUSE_SENSITIVE_META_KEY = "x-apifuse-sensitive";
42
42
  export const APIFUSE_SENSITIVE_KIND_META_KEY = "x-apifuse-sensitive-kind";
43
43
  export const APIFUSE_DESCRIPTION_KEY_META_KEY = "x-apifuse-description-key";
44
+ export const APIFUSE_TEXT_TRUST_META_KEY = "x-apifuse-text-trust";
44
45
  export const APIFUSE_REDACTION_MARKER = "<redacted>";
46
+ /**
47
+ * Auto-trusted output leaves are string-valued `z.literal()` / `z.enum()`,
48
+ * patterns whose every top-level alternative is anchored at both ends and
49
+ * whose bodies use only finite quantifiers, have a maximum match length of 32,
50
+ * and contain only digits and safe punctuation in positive whitespace-free
51
+ * character classes, literals/escapes, and ordinary or non-capturing groups,
52
+ * plus the structurally constrained formats listed here. A brand is trusted
53
+ * only when its underlying schema meets one of those rules. Letter-bearing
54
+ * identifiers, length-only strings, and other formats (including email, URL,
55
+ * base64, and JWT) are not trusted.
56
+ */
57
+ export const AUTO_TRUSTED_ZOD_STRING_FORMATS = [
58
+ "cidrv4",
59
+ "cidrv6",
60
+ "date",
61
+ "datetime",
62
+ "duration",
63
+ "e164",
64
+ "ipv4",
65
+ "ipv6",
66
+ "time",
67
+ ];
45
68
  export function describeKey(schema, key) {
46
69
  const descriptionKey = providerLocaleKey(key);
47
70
  const metadata = schema.meta() ?? {};
@@ -50,19 +73,108 @@ export function describeKey(schema, key) {
50
73
  [APIFUSE_DESCRIPTION_KEY_META_KEY]: descriptionKey,
51
74
  });
52
75
  }
76
+ /** Attach output text-trust authoring metadata without changing validation. */
77
+ export function textTrust(schema, trust) {
78
+ const metadata = schema.meta() ?? {};
79
+ return schema.meta({
80
+ ...metadata,
81
+ [APIFUSE_TEXT_TRUST_META_KEY]: { v: 1, trust },
82
+ });
83
+ }
53
84
  const describeKeyMethod = function (key) {
54
85
  return describeKey(this, key);
55
86
  };
56
- function installDescribeKeyOnPrototype(prototype) {
87
+ const textTrustMethod = function (trust) {
88
+ return textTrust(this, trust);
89
+ };
90
+ const staticOutputFallbacks = new WeakMap();
91
+ let suppressDynamicOutputFallbacks = 0;
92
+ function trackOutputFallback(schema, fallback) {
93
+ if (!(schema instanceof z.ZodType))
94
+ return;
95
+ const def = schema._zod.def;
96
+ if (typeof fallback !== "function") {
97
+ staticOutputFallbacks.set(def, { value: fallback });
98
+ return;
99
+ }
100
+ if (def.type === "default") {
101
+ const descriptor = Object.getOwnPropertyDescriptor(def, "defaultValue");
102
+ if (!descriptor?.get)
103
+ return;
104
+ const originalGetter = descriptor.get;
105
+ Object.defineProperty(def, "defaultValue", {
106
+ ...descriptor,
107
+ get() {
108
+ if (suppressDynamicOutputFallbacks > 0)
109
+ return null;
110
+ return Reflect.apply(originalGetter, this, []);
111
+ },
112
+ });
113
+ return;
114
+ }
115
+ if (def.type === "catch") {
116
+ const catchValue = Reflect.get(def, "catchValue");
117
+ if (typeof catchValue !== "function")
118
+ return;
119
+ Reflect.set(def, "catchValue", function (...args) {
120
+ if (suppressDynamicOutputFallbacks > 0)
121
+ return null;
122
+ return Reflect.apply(catchValue, this, args);
123
+ });
124
+ }
125
+ }
126
+ const trackedFallbackPrototypes = new WeakSet();
127
+ function installOutputFallbackTrackingOnPrototype(prototype) {
128
+ if (!prototype || typeof prototype !== "object" || trackedFallbackPrototypes.has(prototype)) {
129
+ return;
130
+ }
131
+ trackedFallbackPrototypes.add(prototype);
132
+ Reflect.apply(z.ZodType.init, z.ZodType, [Object.create(prototype), { type: "custom" }]);
133
+ for (const methodName of ["default", "catch"]) {
134
+ const descriptor = Object.getOwnPropertyDescriptor(prototype, methodName);
135
+ if (!descriptor?.configurable || !descriptor.get)
136
+ continue;
137
+ const originalGetter = descriptor.get;
138
+ Object.defineProperty(prototype, methodName, {
139
+ ...descriptor,
140
+ get() {
141
+ const originalMethod = Reflect.apply(originalGetter, this, []);
142
+ if (typeof originalMethod !== "function")
143
+ return originalMethod;
144
+ const trackedMethod = function (fallback) {
145
+ const result = Reflect.apply(originalMethod, this, [fallback]);
146
+ trackOutputFallback(result, fallback);
147
+ return result;
148
+ };
149
+ Object.defineProperty(this, methodName, {
150
+ configurable: true,
151
+ enumerable: true,
152
+ value: trackedMethod,
153
+ writable: true,
154
+ });
155
+ return trackedMethod;
156
+ },
157
+ });
158
+ }
159
+ }
160
+ function installSchemaMetadataMethodsOnPrototype(prototype) {
57
161
  const target = prototype;
58
- if (!target || typeof target.describeKey === "function") {
162
+ if (!target)
59
163
  return;
164
+ if (typeof target.describeKey !== "function") {
165
+ Object.defineProperty(target, "describeKey", {
166
+ configurable: true,
167
+ value: describeKeyMethod,
168
+ writable: true,
169
+ });
170
+ }
171
+ if (typeof target.textTrust !== "function") {
172
+ Object.defineProperty(target, "textTrust", {
173
+ configurable: true,
174
+ value: textTrustMethod,
175
+ writable: true,
176
+ });
60
177
  }
61
- Object.defineProperty(target, "describeKey", {
62
- configurable: true,
63
- value: describeKeyMethod,
64
- writable: true,
65
- });
66
178
  }
67
179
  for (const [name, value] of Object.entries(z)) {
68
180
  if (!name.startsWith("Zod") || name.endsWith("Error")) {
@@ -71,7 +183,8 @@ for (const [name, value] of Object.entries(z)) {
71
183
  if (typeof value !== "function") {
72
184
  continue;
73
185
  }
74
- installDescribeKeyOnPrototype(value.prototype);
186
+ installSchemaMetadataMethodsOnPrototype(value.prototype);
187
+ installOutputFallbackTrackingOnPrototype(value.prototype);
75
188
  }
76
189
  const RESERVED_SENSITIVE_KEYS = new Set([
77
190
  "authorization",
@@ -124,6 +237,693 @@ export const fields = {
124
237
  secret: (options) => sensitiveString("secret", "Provider secret material.", options),
125
238
  token: (options) => sensitiveString("token", "Provider access or refresh token.", options),
126
239
  };
240
+ export class OutputTextTrustSchemaError extends TypeError {
241
+ code = "invalid_output_text_trust_schema";
242
+ constructor(value) {
243
+ const receivedType = value === null ? "null" : Array.isArray(value) ? "array" : typeof value;
244
+ super(`Output text-trust collection requires a Zod schema; received ${receivedType}.`);
245
+ this.name = "OutputTextTrustSchemaError";
246
+ }
247
+ }
248
+ export class OutputTextTrustCollectionError extends Error {
249
+ schemaPath;
250
+ classification = "untrusted";
251
+ code = "output_text_trust_collection_failed";
252
+ constructor(schemaPath, cause) {
253
+ super(`Output text-trust collection failed at schema path ${schemaPath}.`);
254
+ this.schemaPath = schemaPath;
255
+ this.name = "OutputTextTrustCollectionError";
256
+ this.cause = cause;
257
+ }
258
+ }
259
+ /**
260
+ * Collect every textual leaf in a Zod output schema as a deterministic
261
+ * schema-path-to-classification object. The path grammar is rooted at `$`:
262
+ * object keys are `["key"]`, arrays and record values are `[*]`, tuple slots
263
+ * are `[n]`, union/intersection alternatives are `<union:n>` / `<intersection:n>`,
264
+ * record keys are `<record-key>`, and one bounded cycle expansion is marked
265
+ * `<recursive>`.
266
+ */
267
+ export function collectOutputTextTrust(schema) {
268
+ const { leaves } = collectOutputTextLeaves(requireOutputTextTrustSchema(schema));
269
+ return Object.fromEntries(leaves
270
+ .map(({ path, classification }) => [path, classification])
271
+ .sort(([left], [right]) => left.localeCompare(right)));
272
+ }
273
+ /** Report textual output paths that lack a valid explicit or auto-derived classification. */
274
+ export function findUnclassifiedOutputTextPaths(schema) {
275
+ const { debtPaths, leaves } = collectOutputTextLeaves(requireOutputTextTrustSchema(schema));
276
+ for (const { classified, path } of leaves) {
277
+ if (!classified)
278
+ debtPaths.add(path);
279
+ }
280
+ return [...debtPaths].sort((left, right) => left.localeCompare(right));
281
+ }
282
+ /** @internal Used by contract JSON Schema projection. */
283
+ export function resolveOutputTextTrust(schema, inheritedUntrusted = false) {
284
+ const resolved = resolveOutputTextTrustProjection(schema);
285
+ return resolved?.[inheritedUntrusted ? "inherited" : "local"];
286
+ }
287
+ /** @internal Resolve both projection states from one stable schema traversal. */
288
+ export function resolveOutputTextTrustProjection(schema) {
289
+ const resolved = resolveOutputTextLeafPair(asInternalZodSchema(schema), [], true);
290
+ return resolved
291
+ ? {
292
+ inherited: resolved.inherited.classification,
293
+ local: resolved.local.classification,
294
+ }
295
+ : undefined;
296
+ }
297
+ /** @internal Whether this node can bypass or mutate descendant validation guarantees. */
298
+ export function invalidatesDescendantOutputTextAutoTrust(schema) {
299
+ return invalidatesOutputTextAutoTrust(asInternalZodSchema(schema)._zod.def);
300
+ }
301
+ /** @internal Run output projection without evaluating dynamic fallback callbacks. */
302
+ export function suppressDynamicOutputFallbacksDuring(project) {
303
+ suppressDynamicOutputFallbacks += 1;
304
+ try {
305
+ return project();
306
+ }
307
+ finally {
308
+ suppressDynamicOutputFallbacks -= 1;
309
+ }
310
+ }
311
+ /** @internal Whether this mutator has a static fallback that cannot contain text. */
312
+ export function mutatorReturnIsProvablyNonText(schema) {
313
+ const def = asInternalZodSchema(schema)._zod.def;
314
+ if (def.type !== "default" && def.type !== "catch")
315
+ return false;
316
+ const fallback = staticOutputFallbacks.get(def);
317
+ return fallback !== undefined && outputFallbackValueIsProvablyNonText(fallback.value);
318
+ }
319
+ /** @internal Whether this mutator has a static array fallback. */
320
+ export function mutatorUsesStaticArrayFallback(schema) {
321
+ const def = asInternalZodSchema(schema)._zod.def;
322
+ if (def.type !== "default" && def.type !== "catch")
323
+ return false;
324
+ const fallback = staticOutputFallbacks.get(def);
325
+ return fallback !== undefined && Array.isArray(fallback.value);
326
+ }
327
+ /** @internal Whether this default or catch was authored with a callback. */
328
+ export function hasDynamicOutputFallback(schema) {
329
+ const def = asInternalZodSchema(schema)._zod.def;
330
+ return (def.type === "default" || def.type === "catch") && !staticOutputFallbacks.has(def);
331
+ }
332
+ /** @internal Used by contract JSON Schema projection. */
333
+ export function inheritsUntrustedOutputTextTrust(schema) {
334
+ let current = asInternalZodSchema(schema);
335
+ while (true) {
336
+ if (readTextTrustDeclaration(current) === "untrusted")
337
+ return true;
338
+ const inner = flattenedOutputSchema(current._zod.def);
339
+ if (!inner)
340
+ return false;
341
+ current = inner;
342
+ }
343
+ }
344
+ function outputFallbackValueIsProvablyNonText(value) {
345
+ return (value === null ||
346
+ typeof value === "boolean" ||
347
+ typeof value === "number" ||
348
+ (Array.isArray(value) && value.every(outputFallbackValueIsProvablyNonText)));
349
+ }
350
+ function collectOutputTextLeaves(schema) {
351
+ const leaves = [];
352
+ const debtPaths = new Set();
353
+ const emittedPaths = new Set();
354
+ walkOutputSchema(schema, "$", leaves, debtPaths, emittedPaths, new Set(), false, false, true);
355
+ return { leaves, debtPaths };
356
+ }
357
+ function walkOutputSchema(schema, path, out, debtPaths, emittedPaths, activeSchemas, expandingCycle, inheritedUntrusted, autoTrustAllowed) {
358
+ try {
359
+ walkOutputSchemaUnchecked(schema, path, out, debtPaths, emittedPaths, activeSchemas, expandingCycle, inheritedUntrusted, autoTrustAllowed);
360
+ }
361
+ catch (error) {
362
+ if (error instanceof OutputTextTrustCollectionError)
363
+ throw error;
364
+ throw new OutputTextTrustCollectionError(path, error);
365
+ }
366
+ }
367
+ function walkOutputSchemaUnchecked(schema, path, out, debtPaths, emittedPaths, activeSchemas, expandingCycle, inheritedUntrusted, autoTrustAllowed) {
368
+ const alreadyActive = activeSchemas.has(schema);
369
+ if (alreadyActive) {
370
+ if (!expandingCycle) {
371
+ walkOutputSchema(schema, `${path}<recursive>`, out, debtPaths, emittedPaths, new Set(), true, inheritedUntrusted, autoTrustAllowed);
372
+ }
373
+ return;
374
+ }
375
+ const leaf = resolveOutputTextLeaf(schema, [], autoTrustAllowed, inheritedUntrusted);
376
+ if (leaf) {
377
+ if (!emittedPaths.has(path)) {
378
+ emittedPaths.add(path);
379
+ out.push({ path, ...leaf });
380
+ }
381
+ return;
382
+ }
383
+ const def = schema._zod.def;
384
+ const declaration = readTextTrustDeclaration(schema);
385
+ if (declaration === "trusted" || declaration === "invalid")
386
+ debtPaths.add(path);
387
+ const descendantUntrusted = inheritedUntrusted || declaration === "untrusted";
388
+ const descendantAutoTrustAllowed = autoTrustAllowed && !invalidatesOutputTextAutoTrust(def);
389
+ if (invalidatesOutputTextAutoTrust(def) &&
390
+ !mutatorReturnIsProvablyNonText(schema) &&
391
+ !mutatorCanUseCollectedTextItems(schema) &&
392
+ !emittedPaths.has(path)) {
393
+ emittedPaths.add(path);
394
+ out.push({
395
+ classification: "untrusted",
396
+ classified: descendantUntrusted,
397
+ path,
398
+ });
399
+ }
400
+ if (!alreadyActive)
401
+ activeSchemas.add(schema);
402
+ try {
403
+ switch (def.type) {
404
+ case "object": {
405
+ for (const [key, child] of Object.entries(def.shape).sort(([left], [right]) => left.localeCompare(right))) {
406
+ walkOutputSchema(asInternalZodSchema(child), `${path}[${JSON.stringify(key)}]`, out, debtPaths, emittedPaths, activeSchemas, expandingCycle, descendantUntrusted, descendantAutoTrustAllowed);
407
+ }
408
+ if (def.catchall) {
409
+ if (asInternalZodSchema(def.catchall)._zod.def.type !== "never") {
410
+ const catchallKeyPath = `${path}<catchall-key>`;
411
+ if (!emittedPaths.has(catchallKeyPath)) {
412
+ emittedPaths.add(catchallKeyPath);
413
+ out.push({
414
+ classification: "untrusted",
415
+ classified: descendantUntrusted,
416
+ path: catchallKeyPath,
417
+ });
418
+ }
419
+ }
420
+ walkOutputSchema(asInternalZodSchema(def.catchall), `${path}[*]`, out, debtPaths, emittedPaths, activeSchemas, expandingCycle, descendantUntrusted, descendantAutoTrustAllowed);
421
+ }
422
+ break;
423
+ }
424
+ case "array":
425
+ walkOutputSchema(asInternalZodSchema(def.element), `${path}[*]`, out, debtPaths, emittedPaths, activeSchemas, expandingCycle, descendantUntrusted, descendantAutoTrustAllowed);
426
+ break;
427
+ case "tuple": {
428
+ def.items.forEach((child, index) => {
429
+ walkOutputSchema(asInternalZodSchema(child), `${path}[${index}]`, out, debtPaths, emittedPaths, activeSchemas, expandingCycle, descendantUntrusted, descendantAutoTrustAllowed);
430
+ });
431
+ if (def.rest) {
432
+ walkOutputSchema(asInternalZodSchema(def.rest), `${path}[*]`, out, debtPaths, emittedPaths, activeSchemas, expandingCycle, descendantUntrusted, descendantAutoTrustAllowed);
433
+ }
434
+ break;
435
+ }
436
+ case "record":
437
+ walkOutputSchema(asInternalZodSchema(def.keyType), `${path}<record-key>`, out, debtPaths, emittedPaths, activeSchemas, expandingCycle, descendantUntrusted, descendantAutoTrustAllowed);
438
+ walkOutputSchema(asInternalZodSchema(def.valueType), `${path}[*]`, out, debtPaths, emittedPaths, activeSchemas, expandingCycle, descendantUntrusted, descendantAutoTrustAllowed);
439
+ break;
440
+ case "union":
441
+ def.options.forEach((child, index) => {
442
+ walkOutputSchema(asInternalZodSchema(child), `${path}<union:${index}>`, out, debtPaths, emittedPaths, activeSchemas, expandingCycle, descendantUntrusted, descendantAutoTrustAllowed);
443
+ });
444
+ break;
445
+ case "intersection":
446
+ for (const [index, side] of [def.left, def.right].entries()) {
447
+ walkOutputSchema(asInternalZodSchema(side), `${path}<intersection:${index}>`, out, debtPaths, emittedPaths, activeSchemas, expandingCycle, descendantUntrusted, descendantAutoTrustAllowed);
448
+ }
449
+ break;
450
+ case "optional":
451
+ case "nullable":
452
+ case "default":
453
+ case "prefault":
454
+ case "catch":
455
+ case "readonly":
456
+ case "nonoptional":
457
+ case "promise":
458
+ walkOutputSchema(asInternalZodSchema(def.innerType), path, out, debtPaths, emittedPaths, activeSchemas, expandingCycle, descendantUntrusted, descendantAutoTrustAllowed);
459
+ break;
460
+ case "pipe":
461
+ walkOutputSchema(asInternalZodSchema(def.out), path, out, debtPaths, emittedPaths, activeSchemas, expandingCycle, descendantUntrusted, descendantAutoTrustAllowed);
462
+ break;
463
+ case "lazy":
464
+ walkOutputSchema(asInternalZodSchema(def.getter()), path, out, debtPaths, emittedPaths, activeSchemas, expandingCycle, descendantUntrusted, descendantAutoTrustAllowed);
465
+ break;
466
+ case "string":
467
+ case "template_literal":
468
+ case "literal":
469
+ case "enum":
470
+ case "number":
471
+ case "bigint":
472
+ case "boolean":
473
+ case "date":
474
+ case "symbol":
475
+ case "undefined":
476
+ case "null":
477
+ case "any":
478
+ case "unknown":
479
+ case "never":
480
+ case "void":
481
+ case "map":
482
+ case "set":
483
+ case "function":
484
+ case "custom":
485
+ case "transform":
486
+ case "nan":
487
+ case "success":
488
+ case "file":
489
+ break;
490
+ default:
491
+ assertNeverZodDef(def);
492
+ }
493
+ }
494
+ finally {
495
+ if (!alreadyActive)
496
+ activeSchemas.delete(schema);
497
+ }
498
+ }
499
+ function mutatorCanUseCollectedTextItems(schema) {
500
+ if (!mutatorUsesStaticArrayFallback(schema))
501
+ return false;
502
+ const inner = flattenedOutputSchema(schema._zod.def);
503
+ if (inner?._zod.def.type !== "array")
504
+ return false;
505
+ return collectOutputTextLeaves(asInternalZodSchema(inner._zod.def.element)).leaves.length > 0;
506
+ }
507
+ function resolveOutputTextLeaf(schema, outerDeclarations, autoTrustAllowed, inheritedUntrusted) {
508
+ const resolved = resolveOutputTextLeafPair(schema, outerDeclarations, autoTrustAllowed);
509
+ return resolved?.[inheritedUntrusted ? "inherited" : "local"];
510
+ }
511
+ function resolveOutputTextLeafPair(schema, outerDeclarations, autoTrustAllowed) {
512
+ const declarations = [...outerDeclarations, readTextTrustDeclaration(schema)];
513
+ const def = schema._zod.def;
514
+ if (!isOutputTextLeafDef(def)) {
515
+ const inner = flattenedOutputSchema(def);
516
+ return inner
517
+ ? resolveOutputTextLeafPair(inner, declarations, autoTrustAllowed && !invalidatesOutputTextAutoTrust(def))
518
+ : undefined;
519
+ }
520
+ const autoTrusted = autoTrustAllowed && !invalidatesOutputTextAutoTrust(def) && isAutoTrustedOutputTextLeaf(schema);
521
+ const explicitTrustAllowed = autoTrustAllowed && !invalidatesOutputTextAutoTrust(def);
522
+ return {
523
+ inherited: classifyOutputTextLeaf(declarations, autoTrusted, explicitTrustAllowed, true),
524
+ local: classifyOutputTextLeaf(declarations, autoTrusted, explicitTrustAllowed, false),
525
+ };
526
+ }
527
+ function classifyOutputTextLeaf(declarations, autoTrusted, explicitTrustAllowed, inheritedUntrusted) {
528
+ if (declarations.includes("invalid")) {
529
+ return { classification: "untrusted", classified: false };
530
+ }
531
+ if (declarations.includes("untrusted")) {
532
+ return { classification: "untrusted", classified: true };
533
+ }
534
+ if (declarations.includes("trusted")) {
535
+ return {
536
+ classification: explicitTrustAllowed ? "trusted" : "untrusted",
537
+ classified: explicitTrustAllowed,
538
+ };
539
+ }
540
+ if (inheritedUntrusted) {
541
+ return { classification: "untrusted", classified: true };
542
+ }
543
+ return autoTrusted
544
+ ? { classification: "trusted", classified: true }
545
+ : { classification: "untrusted", classified: false };
546
+ }
547
+ function flattenedOutputSchema(def) {
548
+ switch (def.type) {
549
+ case "optional":
550
+ case "nullable":
551
+ case "default":
552
+ case "prefault":
553
+ case "catch":
554
+ case "readonly":
555
+ case "nonoptional":
556
+ case "promise":
557
+ return asInternalZodSchema(def.innerType);
558
+ case "pipe":
559
+ return asInternalZodSchema(def.out);
560
+ case "lazy":
561
+ return asInternalZodSchema(def.getter());
562
+ case "string":
563
+ case "template_literal":
564
+ case "literal":
565
+ case "enum":
566
+ case "number":
567
+ case "bigint":
568
+ case "boolean":
569
+ case "date":
570
+ case "symbol":
571
+ case "undefined":
572
+ case "null":
573
+ case "any":
574
+ case "unknown":
575
+ case "never":
576
+ case "void":
577
+ case "object":
578
+ case "array":
579
+ case "tuple":
580
+ case "record":
581
+ case "union":
582
+ case "intersection":
583
+ case "map":
584
+ case "set":
585
+ case "function":
586
+ case "custom":
587
+ case "transform":
588
+ case "nan":
589
+ case "success":
590
+ case "file":
591
+ return undefined;
592
+ default:
593
+ return assertNeverZodDef(def);
594
+ }
595
+ }
596
+ function isOutputTextLeafDef(def) {
597
+ switch (def.type) {
598
+ case "string":
599
+ case "template_literal":
600
+ return true;
601
+ case "literal":
602
+ return def.values.some((value) => typeof value === "string");
603
+ case "enum":
604
+ return Object.values(def.entries).some((value) => typeof value === "string");
605
+ case "any":
606
+ case "unknown":
607
+ case "custom":
608
+ case "transform":
609
+ return true;
610
+ default:
611
+ return false;
612
+ }
613
+ }
614
+ function isAutoTrustedOutputTextLeaf(schema) {
615
+ const def = schema._zod.def;
616
+ if (hasUnsafeOutputCheck(def))
617
+ return false;
618
+ if (def.type === "literal" || def.type === "enum")
619
+ return isOutputTextLeafDef(def);
620
+ if (def.type !== "string" && def.type !== "template_literal")
621
+ return false;
622
+ const { bag, pattern } = schema._zod;
623
+ if (hasSdkOwnedStringFormatValidator(schema)) {
624
+ return true;
625
+ }
626
+ if (pattern instanceof RegExp && isRestrictiveAnchoredPattern(pattern))
627
+ return true;
628
+ const patterns = bag.patterns;
629
+ return (patterns instanceof Set &&
630
+ patterns.size > 0 &&
631
+ [...patterns].every((candidate) => candidate instanceof RegExp && isRestrictiveAnchoredPattern(candidate)));
632
+ }
633
+ function hasUnsafeOutputCheck(def) {
634
+ const checks = Reflect.get(def, "checks");
635
+ return (Array.isArray(checks) &&
636
+ checks.some((check) => {
637
+ if (!check || typeof check !== "object")
638
+ return false;
639
+ const internals = Reflect.get(check, "_zod");
640
+ if (!internals || typeof internals !== "object")
641
+ return false;
642
+ const checkDef = Reflect.get(internals, "def");
643
+ if (!checkDef || typeof checkDef !== "object")
644
+ return false;
645
+ const kind = Reflect.get(checkDef, "check");
646
+ return kind === "overwrite" || kind === "custom";
647
+ }));
648
+ }
649
+ function invalidatesOutputTextAutoTrust(def) {
650
+ return (def.type === "default" ||
651
+ def.type === "catch" ||
652
+ def.type === "transform" ||
653
+ hasUnsafeOutputCheck(def));
654
+ }
655
+ const SDK_OWNED_STRING_FORMAT_VALIDATORS = [
656
+ z.cidrv4(),
657
+ z.cidrv6(),
658
+ z.iso.date(),
659
+ z.iso.datetime(),
660
+ z.iso.duration(),
661
+ z.e164(),
662
+ z.ipv4(),
663
+ z.ipv6(),
664
+ z.iso.time(),
665
+ ].map((validator) => {
666
+ const pattern = Reflect.get(validator._zod.def, "pattern");
667
+ if (!(pattern instanceof RegExp)) {
668
+ throw new TypeError("SDK-owned Zod string format validator is missing its pattern.");
669
+ }
670
+ return {
671
+ constructor: validator.constructor,
672
+ patternFlags: pattern.flags,
673
+ patternSource: pattern.source,
674
+ };
675
+ });
676
+ function hasSdkOwnedStringFormatValidator(schema) {
677
+ const candidates = [schema];
678
+ const checks = Reflect.get(schema._zod.def, "checks");
679
+ if (Array.isArray(checks))
680
+ candidates.push(...checks);
681
+ return candidates.some((candidate) => {
682
+ if (!candidate || typeof candidate !== "object")
683
+ return false;
684
+ const internals = Reflect.get(candidate, "_zod");
685
+ if (!internals || typeof internals !== "object")
686
+ return false;
687
+ const def = Reflect.get(internals, "def");
688
+ if (!def || typeof def !== "object" || Reflect.has(def, "fn"))
689
+ return false;
690
+ const pattern = Reflect.get(def, "pattern");
691
+ if (!(pattern instanceof RegExp))
692
+ return false;
693
+ return SDK_OWNED_STRING_FORMAT_VALIDATORS.some((owned) => Reflect.get(candidate, "constructor") === owned.constructor &&
694
+ pattern.source === owned.patternSource &&
695
+ pattern.flags === owned.patternFlags);
696
+ });
697
+ }
698
+ function isRestrictiveAnchoredPattern(pattern) {
699
+ if (pattern.multiline)
700
+ return false;
701
+ const alternatives = splitTopLevelRegexAlternatives(pattern.source);
702
+ if (alternatives.length === 0)
703
+ return false;
704
+ let maximumLength = 0;
705
+ for (const alternative of alternatives) {
706
+ if (!alternative.startsWith("^") || !alternative.endsWith("$"))
707
+ return false;
708
+ const analysis = analyzeProvablyRestrictedRegexBody(alternative.slice(1, -1));
709
+ if (!analysis)
710
+ return false;
711
+ maximumLength = Math.max(maximumLength, analysis.maximumLength);
712
+ }
713
+ return maximumLength <= MAXIMUM_AUTO_TRUSTED_REGEX_LENGTH;
714
+ }
715
+ function splitTopLevelRegexAlternatives(source) {
716
+ const alternatives = [];
717
+ let start = 0;
718
+ let escaped = false;
719
+ let inCharacterClass = false;
720
+ let groupDepth = 0;
721
+ for (let index = 0; index < source.length; index += 1) {
722
+ const character = source[index];
723
+ if (escaped) {
724
+ escaped = false;
725
+ continue;
726
+ }
727
+ if (character === "\\") {
728
+ escaped = true;
729
+ continue;
730
+ }
731
+ if (character === "[") {
732
+ inCharacterClass = true;
733
+ continue;
734
+ }
735
+ if (character === "]") {
736
+ inCharacterClass = false;
737
+ continue;
738
+ }
739
+ if (inCharacterClass)
740
+ continue;
741
+ if (character === "(") {
742
+ groupDepth += 1;
743
+ continue;
744
+ }
745
+ if (character === ")") {
746
+ groupDepth -= 1;
747
+ continue;
748
+ }
749
+ if (character === "|" && groupDepth === 0) {
750
+ alternatives.push(source.slice(start, index));
751
+ start = index + 1;
752
+ }
753
+ }
754
+ alternatives.push(source.slice(start));
755
+ return alternatives;
756
+ }
757
+ const MAXIMUM_AUTO_TRUSTED_REGEX_LENGTH = 32;
758
+ function analyzeProvablyRestrictedRegexBody(source) {
759
+ let index = 0;
760
+ const parseAlternatives = () => {
761
+ let maximumLength = 0;
762
+ while (true) {
763
+ const sequence = parseSequence();
764
+ if (!sequence)
765
+ return undefined;
766
+ maximumLength = Math.max(maximumLength, sequence.maximumLength);
767
+ if (source[index] !== "|")
768
+ break;
769
+ index += 1;
770
+ }
771
+ return { maximumLength };
772
+ };
773
+ const parseSequence = () => {
774
+ let maximumLength = 0;
775
+ while (index < source.length && source[index] !== "|" && source[index] !== ")") {
776
+ const atom = parseAtom();
777
+ if (!atom)
778
+ return undefined;
779
+ let maximumRepetitions = 1;
780
+ if (source[index] === "?") {
781
+ index += 1;
782
+ }
783
+ else if (source[index] === "{") {
784
+ const match = /^\{(\d+)(?:,(\d+))?\}/.exec(source.slice(index));
785
+ if (!match)
786
+ return undefined;
787
+ const minimum = Number(match[1]);
788
+ maximumRepetitions = match[2] === undefined ? minimum : Number(match[2]);
789
+ if (!Number.isSafeInteger(minimum) ||
790
+ !Number.isSafeInteger(maximumRepetitions) ||
791
+ maximumRepetitions < minimum)
792
+ return undefined;
793
+ index += match[0].length;
794
+ }
795
+ if (source[index] === "?")
796
+ index += 1;
797
+ maximumLength = addRestrictedRegexLengths(maximumLength, multiplyRestrictedRegexLength(atom.maximumLength, maximumRepetitions));
798
+ }
799
+ return { maximumLength };
800
+ };
801
+ const parseAtom = () => {
802
+ if (source[index] === "(") {
803
+ index += 1;
804
+ if (source[index] === "?") {
805
+ if (source.slice(index, index + 2) !== "?:")
806
+ return undefined;
807
+ index += 2;
808
+ }
809
+ const group = parseAlternatives();
810
+ if (!group || source[index] !== ")")
811
+ return undefined;
812
+ index += 1;
813
+ return group;
814
+ }
815
+ if (source[index] === "[") {
816
+ const characterClass = analyzeSafeRegexCharacterClass(source.slice(index));
817
+ if (!characterClass)
818
+ return undefined;
819
+ index += characterClass.consumedLength;
820
+ return characterClass;
821
+ }
822
+ const atomLength = safeRegexAtomLength(source.slice(index));
823
+ if (atomLength === 0)
824
+ return undefined;
825
+ index += atomLength;
826
+ return { maximumLength: 1 };
827
+ };
828
+ const analysis = parseAlternatives();
829
+ return analysis && index === source.length ? analysis : undefined;
830
+ }
831
+ function analyzeSafeRegexCharacterClass(source) {
832
+ if (!source.startsWith("[") || source[1] === "^")
833
+ return undefined;
834
+ for (let index = 1; index < source.length; index += 1) {
835
+ const character = source[index];
836
+ if (character === "]") {
837
+ return { consumedLength: index + 1, maximumLength: 1 };
838
+ }
839
+ const atomLength = safeRegexAtomLength(source.slice(index));
840
+ if (atomLength === 0)
841
+ return undefined;
842
+ const rangeSeparator = index + atomLength;
843
+ if (source[rangeSeparator] === "-" && source[rangeSeparator + 1] !== "]") {
844
+ const endIndex = rangeSeparator + 1;
845
+ const endLength = safeRegexAtomLength(source.slice(endIndex));
846
+ if (endLength === 0 || !isSafeRegexCharacterRange(source, index, endIndex))
847
+ return undefined;
848
+ index = endIndex + endLength - 1;
849
+ continue;
850
+ }
851
+ index += atomLength - 1;
852
+ }
853
+ return undefined;
854
+ }
855
+ function addRestrictedRegexLengths(left, right) {
856
+ return left > MAXIMUM_AUTO_TRUSTED_REGEX_LENGTH - right
857
+ ? MAXIMUM_AUTO_TRUSTED_REGEX_LENGTH + 1
858
+ : left + right;
859
+ }
860
+ function multiplyRestrictedRegexLength(length, repetitions) {
861
+ if (length === 0 || repetitions === 0)
862
+ return 0;
863
+ return repetitions > Math.floor(MAXIMUM_AUTO_TRUSTED_REGEX_LENGTH / length)
864
+ ? MAXIMUM_AUTO_TRUSTED_REGEX_LENGTH + 1
865
+ : length * repetitions;
866
+ }
867
+ function safeRegexAtomLength(source) {
868
+ const character = source[0];
869
+ if (character === undefined)
870
+ return 0;
871
+ if (/^[0-9]$/.test(character))
872
+ return 1;
873
+ if (character === "-")
874
+ return 1;
875
+ if (character !== "\\")
876
+ return 0;
877
+ const escaped = source[1];
878
+ if (escaped === "d")
879
+ return 2;
880
+ return escaped !== undefined && SAFE_REGEX_ESCAPED_PUNCTUATION.includes(escaped) ? 2 : 0;
881
+ }
882
+ function isSafeRegexCharacterRange(source, startIndex, endIndex) {
883
+ const start = regexCharacterClassLiteralCodePoint(source, startIndex);
884
+ const end = regexCharacterClassLiteralCodePoint(source, endIndex);
885
+ if (start === undefined || end === undefined || start > end)
886
+ return false;
887
+ const minimum = "0".codePointAt(0);
888
+ const maximum = "9".codePointAt(0);
889
+ return minimum !== undefined && maximum !== undefined && start >= minimum && end <= maximum;
890
+ }
891
+ function regexCharacterClassLiteralCodePoint(source, index) {
892
+ const character = source[index];
893
+ if (character !== "\\")
894
+ return character?.codePointAt(0);
895
+ const escaped = source[index + 1];
896
+ if (escaped === undefined || escaped === "d" || escaped === "w")
897
+ return undefined;
898
+ return escaped.codePointAt(0);
899
+ }
900
+ const SAFE_REGEX_ESCAPED_PUNCTUATION = "\\.-^$*+?()[]{}|";
901
+ function requireOutputTextTrustSchema(schema) {
902
+ if (!(schema instanceof z.ZodType))
903
+ throw new OutputTextTrustSchemaError(schema);
904
+ return asInternalZodSchema(schema);
905
+ }
906
+ function asInternalZodSchema(schema) {
907
+ // Zod's child-definition fields use the base type and erase the concrete
908
+ // union member. This is the only cast boundary; all callers immediately
909
+ // narrow the returned discriminated definition by `def.type`.
910
+ return schema;
911
+ }
912
+ function assertNeverZodDef(def) {
913
+ throw new Error(`Unsupported Zod definition: ${String(def.type)}`);
914
+ }
915
+ function readTextTrustDeclaration(schema) {
916
+ const metadata = readZodMetadata(schema);
917
+ if (!metadata || !Reflect.has(metadata, APIFUSE_TEXT_TRUST_META_KEY))
918
+ return "absent";
919
+ const value = Reflect.get(metadata, APIFUSE_TEXT_TRUST_META_KEY);
920
+ if (!value || typeof value !== "object")
921
+ return "invalid";
922
+ if (Reflect.get(value, "v") !== 1)
923
+ return "invalid";
924
+ const trust = Reflect.get(value, "trust");
925
+ return trust === "trusted" || trust === "untrusted" ? trust : "invalid";
926
+ }
127
927
  export function isSensitiveSchema(schema) {
128
928
  const metadata = readZodMetadata(schema);
129
929
  return metadata !== undefined && Reflect.get(metadata, APIFUSE_SENSITIVE_META_KEY) === true;