@apifuse/provider-sdk 2.1.0-beta.9 → 2.2.0-beta.2

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 (138) hide show
  1. package/AUTHORING.md +134 -0
  2. package/CHANGELOG.md +61 -0
  3. package/README.md +21 -9
  4. package/SUBMISSION.md +10 -11
  5. package/bin/apifuse-pack-check.ts +22 -0
  6. package/bin/apifuse-submit-check.ts +1747 -388
  7. package/dist/auth-turn/auth-turn.v1.schema.json +89 -0
  8. package/dist/auth-turn/fixtures/invalid/empty-kind.json +4 -0
  9. package/dist/auth-turn/fixtures/invalid/expires-at-not-string.json +5 -0
  10. package/dist/auth-turn/fixtures/invalid/missing-kind.json +3 -0
  11. package/dist/auth-turn/fixtures/invalid/missing-turn-id.json +3 -0
  12. package/dist/auth-turn/fixtures/invalid/timing-unknown-field.json +7 -0
  13. package/dist/auth-turn/fixtures/invalid/turn-id-snake-case.json +4 -0
  14. package/dist/auth-turn/fixtures/invalid/unknown-top-level-field.json +5 -0
  15. package/dist/auth-turn/fixtures/valid/abort.json +8 -0
  16. package/dist/auth-turn/fixtures/valid/challenge.json +17 -0
  17. package/dist/auth-turn/fixtures/valid/complete.json +13 -0
  18. package/dist/auth-turn/fixtures/valid/form.json +14 -0
  19. package/dist/auth-turn/fixtures/valid/message.json +13 -0
  20. package/dist/auth-turn/fixtures/valid/multi_choice.json +15 -0
  21. package/dist/auth-turn/fixtures/valid/pending.json +5 -0
  22. package/dist/auth-turn/fixtures/valid/poll.json +9 -0
  23. package/dist/auth-turn/fixtures/valid/redirect.json +16 -0
  24. package/dist/auth-turn/fixtures/valid/retry.json +8 -0
  25. package/dist/auth-turn/fixtures/valid/unknown-kind.json +7 -0
  26. package/dist/auth-turn/index.d.ts +195 -0
  27. package/dist/auth-turn/index.js +133 -0
  28. package/dist/auth.d.ts +76 -0
  29. package/dist/auth.js +436 -0
  30. package/dist/ceremonies/index.js +7 -31
  31. package/dist/cli/create.js +45 -30
  32. package/dist/cli/templates/provider/.dockerignore.tpl +22 -0
  33. package/dist/cli/templates/provider/.gitignore.tpl +22 -0
  34. package/dist/cli/templates/provider/AGENTS.md.tpl +87 -0
  35. package/dist/cli/templates/provider/CLAUDE.md.tpl +1 -0
  36. package/dist/cli/templates/provider/Dockerfile.tpl +7 -0
  37. package/dist/cli/templates/provider/README.md.tpl +163 -0
  38. package/dist/cli/templates/provider/dev.ts.tpl +5 -0
  39. package/dist/cli/templates/provider/domain/README.md.tpl +3 -0
  40. package/dist/cli/templates/provider/index.test.ts.tpl +13 -0
  41. package/dist/cli/templates/provider/index.ts.tpl +15 -0
  42. package/dist/cli/templates/provider/mappers/README.md.tpl +3 -0
  43. package/dist/cli/templates/provider/meta.ts.tpl +7 -0
  44. package/dist/cli/templates/provider/operations/index.ts.tpl +5 -0
  45. package/dist/cli/templates/provider/operations/ping.ts.tpl +24 -0
  46. package/dist/cli/templates/provider/schemas/ping.ts.tpl +24 -0
  47. package/dist/cli/templates/provider/skills/fixtures-and-recording/SKILL.md.tpl +58 -0
  48. package/dist/cli/templates/provider/skills/health-checks-and-fail-closed/SKILL.md.tpl +65 -0
  49. package/dist/cli/templates/provider/skills/normalization-standards/SKILL.md.tpl +57 -0
  50. package/dist/cli/templates/provider/skills/pagination-and-counts/SKILL.md.tpl +52 -0
  51. package/dist/cli/templates/provider/skills/upstream-contract-verification/SKILL.md.tpl +45 -0
  52. package/dist/cli/templates/provider/skills/upstream-notes/README.md.tpl +13 -0
  53. package/dist/cli/templates/provider/start.ts.tpl +5 -0
  54. package/dist/cli/templates/provider/upstream/README.md.tpl +3 -0
  55. package/dist/contract.js +1 -0
  56. package/dist/define.d.ts +6 -1
  57. package/dist/define.js +140 -70
  58. package/dist/index.d.ts +3 -2
  59. package/dist/index.js +2 -1
  60. package/dist/lint.d.ts +1 -0
  61. package/dist/lint.js +27 -0
  62. package/dist/provider.d.ts +4 -2
  63. package/dist/provider.js +2 -1
  64. package/dist/runtime/auth-flow.js +2 -0
  65. package/dist/runtime/browser.js +203 -0
  66. package/dist/runtime/http.js +46 -336
  67. package/dist/runtime/proxy-retry-policy.d.ts +40 -0
  68. package/dist/runtime/proxy-retry-policy.js +326 -0
  69. package/dist/runtime/stealth.d.ts +5 -2
  70. package/dist/runtime/stealth.js +206 -206
  71. package/dist/server/index.d.ts +4 -0
  72. package/dist/server/index.js +4 -0
  73. package/dist/server/self-test-input-tokens.d.ts +1 -0
  74. package/dist/server/self-test-input-tokens.js +37 -0
  75. package/dist/server/self-test-redaction.d.ts +20 -0
  76. package/dist/server/self-test-redaction.js +70 -0
  77. package/dist/server/self-test-token.d.ts +30 -0
  78. package/dist/server/self-test-token.js +50 -0
  79. package/dist/server/self-test.d.ts +98 -0
  80. package/dist/server/self-test.js +555 -0
  81. package/dist/server/serve.d.ts +6 -0
  82. package/dist/server/serve.js +38 -10
  83. package/dist/server/types.d.ts +1 -0
  84. package/dist/server/types.js +1 -0
  85. package/dist/testing/run.js +5 -1
  86. package/dist/types.d.ts +150 -0
  87. package/package.json +9 -2
  88. package/src/auth-turn/auth-turn.v1.schema.json +89 -0
  89. package/src/auth-turn/fixtures/invalid/empty-kind.json +4 -0
  90. package/src/auth-turn/fixtures/invalid/expires-at-not-string.json +5 -0
  91. package/src/auth-turn/fixtures/invalid/missing-kind.json +3 -0
  92. package/src/auth-turn/fixtures/invalid/missing-turn-id.json +3 -0
  93. package/src/auth-turn/fixtures/invalid/timing-unknown-field.json +7 -0
  94. package/src/auth-turn/fixtures/invalid/turn-id-snake-case.json +4 -0
  95. package/src/auth-turn/fixtures/invalid/unknown-top-level-field.json +5 -0
  96. package/src/auth-turn/fixtures/valid/abort.json +8 -0
  97. package/src/auth-turn/fixtures/valid/challenge.json +17 -0
  98. package/src/auth-turn/fixtures/valid/complete.json +13 -0
  99. package/src/auth-turn/fixtures/valid/form.json +14 -0
  100. package/src/auth-turn/fixtures/valid/message.json +13 -0
  101. package/src/auth-turn/fixtures/valid/multi_choice.json +15 -0
  102. package/src/auth-turn/fixtures/valid/pending.json +5 -0
  103. package/src/auth-turn/fixtures/valid/poll.json +9 -0
  104. package/src/auth-turn/fixtures/valid/redirect.json +16 -0
  105. package/src/auth-turn/fixtures/valid/retry.json +8 -0
  106. package/src/auth-turn/fixtures/valid/unknown-kind.json +7 -0
  107. package/src/auth-turn/index.ts +177 -0
  108. package/src/auth.ts +786 -0
  109. package/src/ceremonies/index.ts +9 -43
  110. package/src/cli/create.ts +60 -97
  111. package/src/cli/templates/provider/AGENTS.md.tpl +87 -0
  112. package/src/cli/templates/provider/CLAUDE.md.tpl +1 -0
  113. package/src/cli/templates/provider/README.md.tpl +7 -4
  114. package/src/cli/templates/provider/skills/fixtures-and-recording/SKILL.md.tpl +58 -0
  115. package/src/cli/templates/provider/skills/health-checks-and-fail-closed/SKILL.md.tpl +65 -0
  116. package/src/cli/templates/provider/skills/normalization-standards/SKILL.md.tpl +57 -0
  117. package/src/cli/templates/provider/skills/pagination-and-counts/SKILL.md.tpl +52 -0
  118. package/src/cli/templates/provider/skills/upstream-contract-verification/SKILL.md.tpl +45 -0
  119. package/src/cli/templates/provider/skills/upstream-notes/README.md.tpl +13 -0
  120. package/src/contract.ts +1 -0
  121. package/src/define.ts +198 -71
  122. package/src/index.ts +16 -0
  123. package/src/lint.ts +33 -0
  124. package/src/provider.ts +27 -0
  125. package/src/runtime/auth-flow.ts +2 -0
  126. package/src/runtime/browser.ts +293 -1
  127. package/src/runtime/http.ts +84 -530
  128. package/src/runtime/proxy-retry-policy.ts +469 -0
  129. package/src/runtime/stealth.ts +269 -353
  130. package/src/server/index.ts +36 -0
  131. package/src/server/self-test-input-tokens.ts +46 -0
  132. package/src/server/self-test-redaction.ts +97 -0
  133. package/src/server/self-test-token.ts +70 -0
  134. package/src/server/self-test.ts +725 -0
  135. package/src/server/serve.ts +75 -6
  136. package/src/server/types.ts +1 -0
  137. package/src/testing/run.ts +9 -1
  138. package/src/types.ts +186 -0
package/dist/define.js CHANGED
@@ -1,3 +1,4 @@
1
+ import ms from "ms";
1
2
  import { ProviderError, ValidationError } from "./errors";
2
3
  import { safeParseSchemaSync } from "./schema";
3
4
  import { HEALTH_CHECK_DEGRADED_THRESHOLD_MS_MAX, HEALTH_CHECK_DEGRADED_THRESHOLD_MS_MIN, HEALTH_CHECK_TIMEOUT_MS_MAX, HEALTH_CHECK_TIMEOUT_MS_MIN, OPERATION_TIMEOUT_MS_MAX, OPERATION_TIMEOUT_MS_MIN, STREAM_CHUNK_BYTES_MAX, STREAM_CHUNK_BYTES_MIN, STREAM_HEARTBEAT_MS_MAX, STREAM_HEARTBEAT_MS_MIN, STREAM_IDLE_TIMEOUT_MS_MAX, STREAM_IDLE_TIMEOUT_MS_MIN, STREAM_MAX_DURATION_MS_MAX, STREAM_MAX_DURATION_MS_MIN, } from "./types";
@@ -50,51 +51,23 @@ const VALID_OPERATION_TRANSPORT_KINDS = [
50
51
  ];
51
52
  const SSE_EVENT_NAME_REGEX = /^[A-Za-z][A-Za-z0-9_.-]{0,127}$/;
52
53
  const WEBSOCKET_SUBPROTOCOL_REGEX = /^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$/;
53
- const MS_DURATION_UNITS = new Set([
54
- "years",
55
- "year",
56
- "yrs",
57
- "yr",
58
- "y",
59
- "weeks",
60
- "week",
61
- "w",
62
- "days",
63
- "day",
64
- "d",
65
- "hours",
66
- "hour",
67
- "hrs",
68
- "hr",
69
- "h",
70
- "minutes",
71
- "minute",
72
- "mins",
73
- "min",
74
- "m",
75
- "seconds",
76
- "second",
77
- "secs",
78
- "sec",
79
- "s",
80
- "milliseconds",
81
- "millisecond",
82
- "msecs",
83
- "msec",
84
- "ms",
85
- ]);
86
54
  const MS_DURATION_PATTERN = /^([+-]?(?:\d+(?:\.\d+)?|\.\d+))\s*([a-zA-Z]+)?$/;
87
55
  function isPositiveMsDurationString(value) {
88
56
  if (typeof value !== "string")
89
57
  return false;
90
- const match = value.trim().match(MS_DURATION_PATTERN);
91
- if (!match)
92
- return false;
93
- const amount = Number(match[1]);
94
- if (!Number.isFinite(amount) || amount <= 0)
95
- return false;
96
- const unit = match[2]?.toLowerCase();
97
- return unit === undefined || MS_DURATION_UNITS.has(unit);
58
+ return parsePositiveMsDuration(value) !== undefined;
59
+ }
60
+ function msDurationMs(value) {
61
+ return parsePositiveMsDuration(value) ?? 0;
62
+ }
63
+ function parsePositiveMsDuration(value) {
64
+ const trimmed = value.trim();
65
+ if (!MS_DURATION_PATTERN.test(trimmed))
66
+ return undefined;
67
+ const parsed = ms((trimmed.startsWith("+") ? trimmed.slice(1) : trimmed));
68
+ if (!Number.isFinite(parsed) || parsed <= 0)
69
+ return undefined;
70
+ return parsed;
98
71
  }
99
72
  /** Define one provider operation with schema-driven handler inference. */
100
73
  export function defineOperation(operation) {
@@ -141,6 +114,11 @@ function validateProviderShape(config) {
141
114
  "mode" in auth &&
142
115
  typeof auth.mode === "string")
143
116
  assertLiteralField(auth.mode, "auth.mode", VALID_AUTH_MODES, String(config.id));
117
+ if (auth && typeof auth === "object" && "exchange" in auth) {
118
+ throw new ProviderError(`Provider "${String(config.id)}" auth.exchange is not part of the Provider SDK auth contract`, {
119
+ fix: "Use the single canonical auth interface: auth.flow. Gateway calls auth.flow.start/continue/poll/abort/refresh only and persists complete turn data.credential as-is, so put login/token/session exchange inside auth.flow.continue.",
120
+ });
121
+ }
144
122
  if (auth &&
145
123
  typeof auth === "object" &&
146
124
  "flow" in auth &&
@@ -555,6 +533,7 @@ function validateOperationTransports(providerId, operations) {
555
533
  }
556
534
  const HEALTH_CHECK_SUITE_FIELDS = new Set([
557
535
  "interval",
536
+ "schedule",
558
537
  "timeoutMs",
559
538
  "degradedThresholdMs",
560
539
  "cases",
@@ -642,26 +621,26 @@ function assertBoundedIntegerMs(value, fieldPath, options) {
642
621
  });
643
622
  }
644
623
  }
645
- function validateProviderHealthMonitor(providerId, healthMonitor) {
624
+ function validateProviderHealthMonitor(providerId, healthMonitor, field = "healthMonitor") {
646
625
  if (healthMonitor === undefined)
647
626
  return;
648
627
  if (!healthMonitor ||
649
628
  typeof healthMonitor !== "object" ||
650
629
  Array.isArray(healthMonitor))
651
- throw new ValidationError(`Provider "${providerId}" has invalid healthMonitor: must be an object.`, {
652
- fix: `Set healthMonitor to { requiredSecrets?: string[]; serviceAccount?: string }`,
630
+ throw new ValidationError(`Provider "${providerId}" has invalid ${field}: must be an object.`, {
631
+ fix: `Set ${field} to { requiredSecrets?: string[]; serviceAccount?: string }`,
653
632
  });
654
633
  const healthMonitorRecord = Object.fromEntries(Object.entries(healthMonitor));
655
- rejectUnknownFields(healthMonitorRecord, PROVIDER_HEALTH_MONITOR_FIELDS, "healthMonitor");
634
+ rejectUnknownFields(healthMonitorRecord, PROVIDER_HEALTH_MONITOR_FIELDS, field);
656
635
  if (healthMonitorRecord.defaultProbeTimeoutMs !== undefined) {
657
- assertBoundedIntegerMs(healthMonitorRecord.defaultProbeTimeoutMs, `Provider "${providerId}" healthMonitor.defaultProbeTimeoutMs`, {
636
+ assertBoundedIntegerMs(healthMonitorRecord.defaultProbeTimeoutMs, `Provider "${providerId}" ${field}.defaultProbeTimeoutMs`, {
658
637
  min: HEALTH_CHECK_TIMEOUT_MS_MIN,
659
638
  max: HEALTH_CHECK_TIMEOUT_MS_MAX,
660
639
  label: "timeout",
661
640
  });
662
641
  }
663
642
  if (healthMonitorRecord.defaultDegradedThresholdMs !== undefined) {
664
- assertBoundedIntegerMs(healthMonitorRecord.defaultDegradedThresholdMs, `Provider "${providerId}" healthMonitor.defaultDegradedThresholdMs`, {
643
+ assertBoundedIntegerMs(healthMonitorRecord.defaultDegradedThresholdMs, `Provider "${providerId}" ${field}.defaultDegradedThresholdMs`, {
665
644
  min: HEALTH_CHECK_DEGRADED_THRESHOLD_MS_MIN,
666
645
  max: HEALTH_CHECK_DEGRADED_THRESHOLD_MS_MAX,
667
646
  label: "degraded threshold",
@@ -670,10 +649,10 @@ function validateProviderHealthMonitor(providerId, healthMonitor) {
670
649
  const requiredSecrets = healthMonitorRecord.requiredSecrets;
671
650
  if (requiredSecrets !== undefined) {
672
651
  if (!Array.isArray(requiredSecrets))
673
- throw new ValidationError(`Provider "${providerId}" has invalid healthMonitor.requiredSecrets: must be string[].`);
652
+ throw new ValidationError(`Provider "${providerId}" has invalid ${field}.requiredSecrets: must be string[].`);
674
653
  for (const [index, secret] of requiredSecrets.entries()) {
675
654
  if (typeof secret !== "string" || secret.length === 0)
676
- throw new ValidationError(`Provider "${providerId}" has invalid healthMonitor.requiredSecrets[${index}]: must be a non-empty string.`);
655
+ throw new ValidationError(`Provider "${providerId}" has invalid ${field}.requiredSecrets[${index}]: must be a non-empty string.`);
677
656
  }
678
657
  }
679
658
  const credentialInputs = healthMonitorRecord.credentialInputs;
@@ -681,17 +660,17 @@ function validateProviderHealthMonitor(providerId, healthMonitor) {
681
660
  if (!credentialInputs ||
682
661
  typeof credentialInputs !== "object" ||
683
662
  Array.isArray(credentialInputs)) {
684
- throw new ValidationError(`Provider "${providerId}" has invalid healthMonitor.credentialInputs: must be an object mapping auth input fields to env var names.`);
663
+ throw new ValidationError(`Provider "${providerId}" has invalid ${field}.credentialInputs: must be an object mapping auth input fields to env var names.`);
685
664
  }
686
- for (const [field, envVar] of Object.entries(credentialInputs)) {
687
- if (field.trim().length === 0) {
688
- throw new ValidationError(`Provider "${providerId}" has invalid healthMonitor.credentialInputs key: must be a non-empty auth input field.`);
665
+ for (const [inputField, envVar] of Object.entries(credentialInputs)) {
666
+ if (inputField.trim().length === 0) {
667
+ throw new ValidationError(`Provider "${providerId}" has invalid ${field}.credentialInputs key: must be a non-empty auth input field.`);
689
668
  }
690
669
  if (typeof envVar !== "string" || envVar.trim().length === 0) {
691
- throw new ValidationError(`Provider "${providerId}" has invalid healthMonitor.credentialInputs.${field}: must be a non-empty env var name.`);
670
+ throw new ValidationError(`Provider "${providerId}" has invalid ${field}.credentialInputs.${inputField}: must be a non-empty env var name.`);
692
671
  }
693
672
  if (Array.isArray(requiredSecrets) && !requiredSecrets.includes(envVar)) {
694
- throw new ValidationError(`Provider "${providerId}" healthMonitor.credentialInputs.${field} references ${envVar}, which must also be listed in healthMonitor.requiredSecrets.`);
673
+ throw new ValidationError(`Provider "${providerId}" ${field}.credentialInputs.${inputField} references ${envVar}, which must also be listed in ${field}.requiredSecrets.`);
695
674
  }
696
675
  }
697
676
  }
@@ -700,26 +679,26 @@ function validateProviderHealthMonitor(providerId, healthMonitor) {
700
679
  if (!probeOverrides ||
701
680
  typeof probeOverrides !== "object" ||
702
681
  Array.isArray(probeOverrides))
703
- throw new ValidationError(`Provider "${providerId}" has invalid healthMonitor.probeOverrides: must be an object keyed by probe id.`);
682
+ throw new ValidationError(`Provider "${providerId}" has invalid ${field}.probeOverrides: must be an object keyed by probe id.`);
704
683
  for (const [probeId, override] of Object.entries(probeOverrides)) {
705
684
  if (probeId.length === 0)
706
- throw new ValidationError(`Provider "${providerId}" has invalid healthMonitor.probeOverrides key: must be a non-empty probe id.`);
685
+ throw new ValidationError(`Provider "${providerId}" has invalid ${field}.probeOverrides key: must be a non-empty probe id.`);
707
686
  if (!override || typeof override !== "object" || Array.isArray(override))
708
- throw new ValidationError(`Provider "${providerId}" has invalid healthMonitor.probeOverrides["${probeId}"]: must be an object.`);
687
+ throw new ValidationError(`Provider "${providerId}" has invalid ${field}.probeOverrides["${probeId}"]: must be an object.`);
709
688
  const overrideRecord = Object.fromEntries(Object.entries(override));
710
- rejectUnknownFields(overrideRecord, PROVIDER_HEALTH_MONITOR_PROBE_OVERRIDE_FIELDS, `healthMonitor.probeOverrides["${probeId}"]`);
689
+ rejectUnknownFields(overrideRecord, PROVIDER_HEALTH_MONITOR_PROBE_OVERRIDE_FIELDS, `${field}.probeOverrides["${probeId}"]`);
711
690
  const interval = overrideRecord.interval;
712
691
  if (interval !== undefined && !isPositiveMsDurationString(interval))
713
- throw new ValidationError(`Provider "${providerId}" has invalid healthMonitor.probeOverrides["${probeId}"].interval: must be a positive ms-style duration string such as 30s, 5m, 8h, or 1 day.`);
692
+ throw new ValidationError(`Provider "${providerId}" has invalid ${field}.probeOverrides["${probeId}"].interval: must be a positive ms-style duration string such as 30s, 5m, 8h, or 1 day.`);
714
693
  if (overrideRecord.timeoutMs !== undefined) {
715
- assertBoundedIntegerMs(overrideRecord.timeoutMs, `Provider "${providerId}" healthMonitor.probeOverrides["${probeId}"].timeoutMs`, {
694
+ assertBoundedIntegerMs(overrideRecord.timeoutMs, `Provider "${providerId}" ${field}.probeOverrides["${probeId}"].timeoutMs`, {
716
695
  min: HEALTH_CHECK_TIMEOUT_MS_MIN,
717
696
  max: HEALTH_CHECK_TIMEOUT_MS_MAX,
718
697
  label: "timeout",
719
698
  });
720
699
  }
721
700
  if (overrideRecord.degradedThresholdMs !== undefined) {
722
- assertBoundedIntegerMs(overrideRecord.degradedThresholdMs, `Provider "${providerId}" healthMonitor.probeOverrides["${probeId}"].degradedThresholdMs`, {
701
+ assertBoundedIntegerMs(overrideRecord.degradedThresholdMs, `Provider "${providerId}" ${field}.probeOverrides["${probeId}"].degradedThresholdMs`, {
723
702
  min: HEALTH_CHECK_DEGRADED_THRESHOLD_MS_MIN,
724
703
  max: HEALTH_CHECK_DEGRADED_THRESHOLD_MS_MAX,
725
704
  label: "degraded threshold",
@@ -730,7 +709,7 @@ function validateProviderHealthMonitor(providerId, healthMonitor) {
730
709
  const serviceAccount = healthMonitorRecord.serviceAccount;
731
710
  if (serviceAccount !== undefined &&
732
711
  (typeof serviceAccount !== "string" || serviceAccount.length === 0))
733
- throw new ValidationError(`Provider "${providerId}" has invalid healthMonitor.serviceAccount: must be a non-empty string.`);
712
+ throw new ValidationError(`Provider "${providerId}" has invalid ${field}.serviceAccount: must be a non-empty string.`);
734
713
  }
735
714
  function validateHealthCheckCase(providerId, operationName, caseValue, caseIndex) {
736
715
  const fieldPath = `operations.${operationName}.healthCheck.cases[${caseIndex}]`;
@@ -776,6 +755,21 @@ function validateHealthCheckSuite(providerId, operationName, suite) {
776
755
  throw new ValidationError(`Provider "${providerId}" ${fieldPath}.interval must be a positive ms-style duration string such as 30s, 5m, 8h, or 1 day.`, {
777
756
  fix: `Set ${fieldPath}.interval to a positive ms-style duration string.`,
778
757
  });
758
+ if (s.schedule !== undefined) {
759
+ if (!s.schedule ||
760
+ typeof s.schedule !== "object" ||
761
+ Array.isArray(s.schedule)) {
762
+ throw new ValidationError(`Provider "${providerId}" ${fieldPath}.schedule must be an object.`);
763
+ }
764
+ if (Reflect.get(s.schedule, "jitter") !== undefined) {
765
+ throw new ValidationError(`Provider "${providerId}" ${fieldPath}.schedule.jitter is not supported for operation healthCheck schedules. Use schedule.randomize instead.`);
766
+ }
767
+ rejectUnknownFields(s.schedule, new Set(["randomize"]), `${fieldPath}.schedule`);
768
+ const randomize = Reflect.get(s.schedule, "randomize");
769
+ if (randomize !== undefined) {
770
+ validateScheduleRandomization(randomize, `Provider "${providerId}" ${fieldPath}.schedule.randomize`, msDurationMs(s.interval));
771
+ }
772
+ }
779
773
  if (s.timeoutMs !== undefined) {
780
774
  assertBoundedIntegerMs(s.timeoutMs, `Provider "${providerId}" ${fieldPath}.timeoutMs`, {
781
775
  min: HEALTH_CHECK_TIMEOUT_MS_MIN,
@@ -837,7 +831,12 @@ const HEALTH_JOURNEY_FIELDS = new Set([
837
831
  "steps",
838
832
  "run",
839
833
  ]);
840
- const HEALTH_JOURNEY_SCHEDULE_FIELDS = new Set(["kind", "interval", "jitter"]);
834
+ const HEALTH_JOURNEY_SCHEDULE_FIELDS = new Set([
835
+ "kind",
836
+ "interval",
837
+ "jitter",
838
+ "randomize",
839
+ ]);
841
840
  const HEALTH_JOURNEY_STEP_FIELDS = new Set([
842
841
  "id",
843
842
  "description",
@@ -953,6 +952,40 @@ function isoDurationMs(value) {
953
952
  const seconds = Number(/(\d+(?:\.\d+)?)S/.exec(value)?.[1] ?? 0);
954
953
  return (days * 86_400_000 + hours * 3_600_000 + minutes * 60_000 + seconds * 1_000);
955
954
  }
955
+ function scheduleRandomizationMs(randomize, fieldPath) {
956
+ const mode = Reflect.get(randomize, "mode");
957
+ switch (mode) {
958
+ case "centered": {
959
+ const maxOffset = Reflect.get(randomize, "maxOffset");
960
+ assertIsoDuration(maxOffset, `${fieldPath}.maxOffset`);
961
+ return isoDurationMs(maxOffset);
962
+ }
963
+ case "delayed": {
964
+ const maxDelay = Reflect.get(randomize, "maxDelay");
965
+ assertIsoDuration(maxDelay, `${fieldPath}.maxDelay`);
966
+ return isoDurationMs(maxDelay);
967
+ }
968
+ default:
969
+ throw new ValidationError(`${fieldPath}.mode must be "centered" or "delayed".`);
970
+ }
971
+ }
972
+ function validateScheduleRandomization(randomize, fieldPath, intervalMs) {
973
+ if (!randomize || typeof randomize !== "object" || Array.isArray(randomize)) {
974
+ throw new ValidationError(`${fieldPath} must be an object.`);
975
+ }
976
+ const mode = Reflect.get(randomize, "mode");
977
+ const allowedFields = mode === "centered"
978
+ ? new Set(["mode", "maxOffset"])
979
+ : new Set(["mode", "maxDelay"]);
980
+ rejectUnknownFields(randomize, allowedFields, fieldPath);
981
+ const offsetMs = scheduleRandomizationMs(randomize, fieldPath);
982
+ if (offsetMs <= 0) {
983
+ throw new ValidationError(`${fieldPath} duration must be positive.`);
984
+ }
985
+ if (offsetMs >= intervalMs) {
986
+ throw new ValidationError(`${fieldPath} duration must be shorter than schedule interval.`);
987
+ }
988
+ }
956
989
  function assertIsoCountry(value, fieldPath) {
957
990
  if (typeof value !== "string" || !ISO_COUNTRY_RE.test(value)) {
958
991
  throw new ValidationError(`${fieldPath} must be an ISO 3166-1 alpha-2 country code for example KR.`);
@@ -962,11 +995,18 @@ function normalizeIntervalDuration(input) {
962
995
  const trimmed = input.trim();
963
996
  const shorthand = /^(\d+)(s|m|h|d)$/i.exec(trimmed);
964
997
  if (shorthand) {
965
- const amount = Number(shorthand[1]);
998
+ const durationMs = msDurationMs(trimmed);
999
+ const unit = shorthand[2]?.toLowerCase();
1000
+ const amount = unit === "s"
1001
+ ? durationMs / 1_000
1002
+ : unit === "m"
1003
+ ? durationMs / 60_000
1004
+ : unit === "h"
1005
+ ? durationMs / 3_600_000
1006
+ : durationMs / 86_400_000;
966
1007
  if (!Number.isInteger(amount) || amount <= 0) {
967
1008
  throw new ValidationError(`Journey schedule interval must be a positive duration.`);
968
1009
  }
969
- const unit = shorthand[2]?.toLowerCase();
970
1010
  if (unit === "s")
971
1011
  return `PT${amount}S`;
972
1012
  if (unit === "m")
@@ -980,15 +1020,27 @@ function normalizeIntervalDuration(input) {
980
1020
  return trimmed;
981
1021
  }
982
1022
  export function every(interval, options = {}) {
1023
+ if (options.jitter !== undefined && options.randomize !== undefined) {
1024
+ throw new ValidationError(`Schedule cannot define both jitter and randomize. Use randomize instead.`);
1025
+ }
983
1026
  const schedule = {
984
1027
  kind: "interval",
985
1028
  interval: normalizeIntervalDuration(interval),
986
1029
  };
1030
+ if (options.randomize !== undefined) {
1031
+ schedule.randomize = options.randomize;
1032
+ }
987
1033
  if (options.jitter !== undefined) {
988
1034
  schedule.jitter = normalizeIntervalDuration(options.jitter);
989
1035
  }
990
1036
  return schedule;
991
1037
  }
1038
+ export function centered(maxOffset) {
1039
+ return { mode: "centered", maxOffset: normalizeIntervalDuration(maxOffset) };
1040
+ }
1041
+ export function delayed(maxDelay) {
1042
+ return { mode: "delayed", maxDelay: normalizeIntervalDuration(maxDelay) };
1043
+ }
992
1044
  function countCapturingGroups(pattern) {
993
1045
  let count = 0;
994
1046
  const source = pattern.source;
@@ -1140,9 +1192,18 @@ function validateHealthJourneySchedule(providerId, journeyId, schedule) {
1140
1192
  rejectUnknownFields(schedule, HEALTH_JOURNEY_SCHEDULE_FIELDS, fieldPath);
1141
1193
  if (Reflect.get(schedule, "kind") !== "interval")
1142
1194
  throw new ValidationError(`Provider "${providerId}" ${fieldPath}.kind must be "interval".`);
1143
- assertIsoDuration(Reflect.get(schedule, "interval"), `Provider "${providerId}" ${fieldPath}.interval`);
1195
+ const interval = Reflect.get(schedule, "interval");
1196
+ assertIsoDuration(interval, `Provider "${providerId}" ${fieldPath}.interval`);
1197
+ const randomize = Reflect.get(schedule, "randomize");
1198
+ if (Reflect.get(schedule, "jitter") !== undefined &&
1199
+ randomize !== undefined) {
1200
+ throw new ValidationError(`Provider "${providerId}" ${fieldPath} cannot define both jitter and randomize.`);
1201
+ }
1144
1202
  if (Reflect.get(schedule, "jitter") !== undefined)
1145
1203
  assertIsoDuration(Reflect.get(schedule, "jitter"), `Provider "${providerId}" ${fieldPath}.jitter`);
1204
+ if (randomize !== undefined) {
1205
+ validateScheduleRandomization(randomize, `Provider "${providerId}" ${fieldPath}.randomize`, isoDurationMs(interval));
1206
+ }
1146
1207
  }
1147
1208
  function validateHealthJourneys(providerId, operations, healthJourneys) {
1148
1209
  const covered = new Set();
@@ -1278,7 +1339,9 @@ export function defineProvider(config) {
1278
1339
  fix: 'Use lowercase alphanumeric with dashes, e.g., "korea-air-quality"',
1279
1340
  });
1280
1341
  if (Object.keys(config.operations).length === 0)
1281
- throw new ProviderError(`Provider "${config.id}" must define at least one operation`, { fix: "Add at least one operation to the operations object" });
1342
+ throw new ProviderError(`Provider "${config.id}" must define at least one operation`, {
1343
+ fix: "Add at least one operation to the operations object",
1344
+ });
1282
1345
  validateOperationIds(config.id, config.operations);
1283
1346
  validateOperationAnnotations(config.id, config.operations);
1284
1347
  validateOperationObservability(config.id, config.operations);
@@ -1287,7 +1350,11 @@ export function defineProvider(config) {
1287
1350
  validateToolRouterMetadata(config.id, config.operations);
1288
1351
  const journeyCoveredOperations = validateHealthJourneys(config.id, config.operations, config.healthJourneys);
1289
1352
  validateOperationHealthChecks(config.id, config.operations, journeyCoveredOperations);
1290
- validateProviderHealthMonitor(config.id, config.healthMonitor);
1353
+ if (config.healthMonitor !== undefined && config.healthProbe !== undefined)
1354
+ throw new ValidationError(`Provider "${config.id}" declares both healthMonitor and healthProbe. They are aliases; declare exactly one.`, {
1355
+ fix: "Keep healthProbe (the new name) and delete the healthMonitor block.",
1356
+ });
1357
+ validateProviderHealthMonitor(config.id, config.healthProbe ?? config.healthMonitor, config.healthProbe !== undefined ? "healthProbe" : "healthMonitor");
1291
1358
  validateOperationFixtures(config.id, config.operations);
1292
1359
  validateProviderProxy(config);
1293
1360
  validateProviderStt(config);
@@ -1314,7 +1381,10 @@ export function defineProvider(config) {
1314
1381
  context: config.context,
1315
1382
  meta: config.meta,
1316
1383
  operations: config.operations,
1317
- healthMonitor: config.healthMonitor,
1384
+ // Transitional healthMonitor → healthProbe alias: mirror whichever field
1385
+ // was declared onto both so old and new consumers keep working.
1386
+ healthMonitor: config.healthMonitor ?? config.healthProbe,
1387
+ healthProbe: config.healthProbe ?? config.healthMonitor,
1318
1388
  healthJourneys: config.healthJourneys,
1319
1389
  };
1320
1390
  }
package/dist/index.d.ts CHANGED
@@ -1,9 +1,10 @@
1
+ export * from "./auth";
1
2
  export * from "./ceremonies";
2
3
  export * from "./choice-token";
3
4
  export type { ApiFuseConfig, BrowserConfig, ProxyConfig, SessionConfig, } from "./config/loader";
4
5
  export { defineConfig, loadApiFuseConfig } from "./config/loader";
5
6
  export { canonicalJson, digestProviderContract, extractProviderContract, type JsonPrimitive, type JsonValue, PROVIDER_CONTRACT_SCHEMA_VERSION, type ProviderContractOperation, type ProviderContractSnapshot, } from "./contract";
6
- export { defineHealthJourney, defineOperation, defineProvider, defineSmsOtpMatcher, defineStreamOperation, every, type ProviderConfig, } from "./define";
7
+ export { centered, delayed, defineHealthJourney, defineOperation, defineProvider, defineSmsOtpMatcher, defineStreamOperation, every, type ProviderConfig, } from "./define";
7
8
  export type { DevServerOptions } from "./dev";
8
9
  export { createDevServer, startDevServer } from "./dev";
9
10
  export * from "./errors";
@@ -33,7 +34,7 @@ export { APIFUSE_DESCRIPTION_KEY_META_KEY, APIFUSE_REDACTION_MARKER, APIFUSE_SEN
33
34
  export { createServerApp, type ServeOptions, serve } from "./server";
34
35
  export { getStealthProfile, listStealthProfiles } from "./stealth/profiles";
35
36
  export * from "./stream";
36
- export type { ApiFuseResponse, AuthConfig, AuthContext, AuthFlowDefinition, AuthFlowInputHandler, AuthFlowStartHandler, AuthMode, AuthTurn, Bcp47Locale, BrowserEngine, BrowserOptions, ConnectionMode, ContextDeclaration, ContextScratchpad, CredentialContext, CredentialDeclaration, E164PhoneNumber, EnvContext, FlowContext, FlowContextStore, HealthCheckAssertionContext, HealthCheckCase, HealthCheckCaseResult, HealthCheckSuite, HealthCheckUnsupported, HealthJourneyDefinition, HealthJourneyEventContext, HealthJourneyGatewayContext, HealthJourneyJournalContext, HealthJourneyManualTriggerPolicy, HealthJourneyRunContext, HealthJourneyRunResult, HealthJourneySchedule, HealthJourneySmsContext, HealthJourneyStep, HttpClient, HttpMethod, HttpResponse, HttpRetryOptions, HttpRetrySummary, HttpStreamResponse, IanaTimeZone, InferSchemaOutput, Iso3166Alpha2CountryCode, Iso4217CurrencyCode, Iso8601Duration, OperationAnnotations, OperationApprovalPolicy, OperationContractMetadata, OperationDefinition, OperationDeprecationMetadata, OperationDocMeta, OperationErrorCode, OperationHandlerResult, OperationInputExample, OperationLifecycle, OperationObservabilityConfig, OperationObservabilitySensitiveConfig, OperationRelationships, OperationRiskClass, OperationSensitivePath, OperationToolRouterMetadata, OperationTransport, OperationTransportKind, ProbeInterval, ProviderAccessConfig, ProviderAccessVisibility, ProviderCache, ProviderCacheGetOrSetOptions, ProviderCacheKeyOptions, ProviderCacheLookupMeta, ProviderCacheResponseMeta, ProviderCacheResult, ProviderChoiceBindingOptions, ProviderChoiceContext, ProviderChoiceIssueOptions, ProviderChoiceParseOptions, ProviderContext, ProviderDefinition, ProviderHealthMonitorConfig, ProviderLocale, ProviderLocaleKey, ProviderLocaleKeyInput, ProviderLogoProfile, ProviderLogoSource, ProviderMeta, ProviderProxyConfig, ProviderProxyMode, ProviderProxyPolicy, ProviderProxyProvider, ProviderProxySessionAffinity, ProviderPublicConnectionMode, ProviderPublicProfile, ProviderReviewed, ProviderRuntimeState, ProviderSecretDeclaration, ProviderStateDurationString, ProviderStateNamespace, ProviderStreamEvent, ProviderSttConfig, ProviderSttMode, ProviderSupportLevel, RequestOptions, Rfc3339Instant, SchemaLike, SmsOrigin, SmsOtpExtractionPattern, SmsOtpMatcherDefinition, SseMessage, StandardSchemaV1, StateCasResult, StateNamespaceOptions, StateValue, StateWriteOptions, StealthClient, StealthFetchOptions, StealthPlatform, StealthProfile, StealthResponse, StealthSession, SttAudioInput, SttContext, SttPromptPolicy, SttSegment, SttTranscribeMode, SttTranscribeRequest, SttTranscript, SttUnsupportedOptionPolicy, SttUsage, SttVerificationCodeOptions, SttWarning, TraceConfig, TraceSpan, VerificationCodeCandidate, VerificationCodeCandidateSource, VerificationCodeExtractionResult, } from "./types";
37
+ export type { ApiFuseResponse, AuthConfig, AuthContext, AuthFlowDefinition, AuthFlowInputHandler, AuthFlowStartHandler, AuthMode, AuthTurn, Bcp47Locale, BrowserEngine, BrowserOptions, BrowserResourceBody, BrowserResourceDecision, BrowserResourceMethod, BrowserResourcePolicy, BrowserResourceRequest, BrowserResourceRoute, ConnectionMode, ContextDeclaration, CookieJar, ContextScratchpad, CredentialContext, CredentialDeclaration, E164PhoneNumber, EnvContext, FlowContext, FlowContextStore, HealthCheckAssertionContext, HealthCheckCase, HealthCheckCaseResult, HealthCheckSuite, HealthCheckUnsupported, HealthJourneyDefinition, HealthJourneyEventContext, HealthJourneyGatewayContext, HealthJourneyJournalContext, HealthJourneyManualTriggerPolicy, HealthJourneyRunContext, HealthJourneyRunResult, HealthJourneySchedule, HealthScheduleRandomization, HealthJourneySmsContext, HealthJourneyStep, HttpClient, HttpMethod, HttpResponse, HttpRetryOptions, HttpRetrySummary, HttpStreamResponse, IanaTimeZone, InferSchemaOutput, Iso3166Alpha2CountryCode, Iso4217CurrencyCode, Iso8601Duration, OperationAnnotations, OperationApprovalPolicy, OperationContractMetadata, OperationDefinition, OperationDeprecationMetadata, OperationDocMeta, OperationErrorCode, OperationHandlerResult, OperationInputExample, OperationLifecycle, OperationObservabilityConfig, OperationObservabilitySensitiveConfig, OperationRelationships, OperationRiskClass, OperationSensitivePath, OperationToolRouterMetadata, OperationTransport, OperationTransportKind, ProbeInterval, ProviderAccessConfig, ProviderAccessVisibility, ProviderCache, ProviderCacheGetOrSetOptions, ProviderCacheKeyOptions, ProviderCacheLookupMeta, ProviderCacheResponseMeta, ProviderCacheResult, ProviderChoiceBindingOptions, ProviderChoiceContext, ProviderChoiceIssueOptions, ProviderChoiceParseOptions, ProviderContext, ProviderDefinition, ProviderHealthMonitorConfig, ProviderHealthProbeConfig, ProviderLocale, ProviderLocaleKey, ProviderLocaleKeyInput, ProviderLogoProfile, ProviderLogoSource, ProviderMeta, ProviderProxyConfig, ProviderProxyMode, ProviderProxyPolicy, ProviderProxyProvider, ProviderProxySessionAffinity, ProviderPublicConnectionMode, ProviderPublicProfile, ProviderReviewed, ProviderRuntimeState, ProviderSecretDeclaration, ProviderStateDurationString, ProviderStateNamespace, ProviderStreamEvent, ProviderSttConfig, ProviderSttMode, ProviderSupportLevel, RequestOptions, Rfc3339Instant, SchemaLike, SmsOrigin, SmsOtpExtractionPattern, SmsOtpMatcherDefinition, SseMessage, StandardSchemaV1, StateCasResult, StateNamespaceOptions, StateValue, StateWriteOptions, StealthClient, StealthFetchOptions, StealthPlatform, StealthProfile, StealthRedirectHop, StealthRedirectRunOptions, StealthRedirectRunResult, StealthResponse, StealthSession, StealthSessionCookies, SttAudioInput, SttContext, SttPromptPolicy, SttSegment, SttTranscribeMode, SttTranscribeRequest, SttTranscript, SttUnsupportedOptionPolicy, SttUsage, SttVerificationCodeOptions, SttWarning, TraceConfig, TraceSpan, VerificationCodeCandidate, VerificationCodeCandidateSource, VerificationCodeExtractionResult, } from "./types";
37
38
  export { DEFAULT_OPERATION_TRANSPORT, HttpRetryAfterPolicy, HttpRetryDelayStrategy, HttpRetryJitter, HttpRetryPreset, HttpRetryUnsafeMethodPolicy, PROBE_INTERVALS, STREAM_CHUNK_BYTES_MAX, STREAM_CHUNK_BYTES_MIN, STREAM_HEARTBEAT_MS_MAX, STREAM_HEARTBEAT_MS_MIN, STREAM_IDLE_TIMEOUT_MS_MAX, STREAM_IDLE_TIMEOUT_MS_MIN, STREAM_MAX_DURATION_MS_MAX, STREAM_MAX_DURATION_MS_MIN, } from "./types";
38
39
  export * from "./utils/date";
39
40
  export * from "./utils/parse";
package/dist/index.js CHANGED
@@ -1,9 +1,10 @@
1
1
  // @apifuse/provider-sdk
2
+ export * from "./auth";
2
3
  export * from "./ceremonies";
3
4
  export * from "./choice-token";
4
5
  export { defineConfig, loadApiFuseConfig } from "./config/loader";
5
6
  export { canonicalJson, digestProviderContract, extractProviderContract, PROVIDER_CONTRACT_SCHEMA_VERSION, } from "./contract";
6
- export { defineHealthJourney, defineOperation, defineProvider, defineSmsOtpMatcher, defineStreamOperation, every, } from "./define";
7
+ export { centered, delayed, defineHealthJourney, defineOperation, defineProvider, defineSmsOtpMatcher, defineStreamOperation, every, } from "./define";
7
8
  export { createDevServer, startDevServer } from "./dev";
8
9
  export * from "./errors";
9
10
  export * from "./i18n";
package/dist/lint.d.ts CHANGED
@@ -8,6 +8,7 @@ type ProviderAuthLike = {
8
8
  abort?: unknown;
9
9
  refresh?: unknown;
10
10
  };
11
+ exchange?: unknown;
11
12
  };
12
13
  type ProviderContractMetaLike = {
13
14
  publicSchemaFieldNames?: "normalized";
package/dist/lint.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { lintPublicSchemaFieldNames } from "./public-schema-field-lint";
2
2
  import { APIFUSE_DESCRIPTION_KEY_META_KEY, APIFUSE_SENSITIVE_META_KEY, } from "./schema";
3
+ const AUTH_OPERATION_ID_PATTERN = /^(?:auth[-_])?(?:login|exchange|continue|refresh|callback)(?:[-_]|$)/i;
3
4
  function lintAllowedHosts(providerId, allowedHosts) {
4
5
  const prefix = providerId ? `Provider "${providerId}"` : "Provider";
5
6
  if (!allowedHosts) {
@@ -49,6 +50,9 @@ function lintReviewed(providerId, reviewed) {
49
50
  },
50
51
  ];
51
52
  }
53
+ function isProviderAuthLike(value) {
54
+ return !!value && typeof value === "object" && !Array.isArray(value);
55
+ }
52
56
  function hasReusableSecretKeys(keys) {
53
57
  if (!keys) {
54
58
  return false;
@@ -99,6 +103,14 @@ function lintAuthModel(provider) {
99
103
  message: `${providerLabel} must define auth.flow.continue for ${authMode} auth mode.`,
100
104
  });
101
105
  }
106
+ if (isProviderAuthLike(provider.auth) && "exchange" in provider.auth) {
107
+ diagnostics.push({
108
+ rule: "auth-exchange-unsupported",
109
+ level: "error",
110
+ field: "auth.exchange",
111
+ message: `${providerLabel} must not define auth.exchange. The Provider SDK has one auth interface: auth.flow. Gateway only calls auth.flow.start/continue/poll/abort/refresh and persists complete turn data.credential as-is; put login/token/session exchange inside auth.flow.continue.`,
112
+ });
113
+ }
102
114
  if (authMode === "credentials" && credentialKeys.length === 0) {
103
115
  diagnostics.push({
104
116
  rule: "credential-keys-required-when-credentials-mode",
@@ -673,6 +685,21 @@ export function lintProvider(provider, options = {}) {
673
685
  ...lintPlaywrightDirectImports(provider),
674
686
  ...lintSelfHostedBrowserPatterns(provider, options),
675
687
  ];
688
+ if (provider.operations) {
689
+ const authMode = provider.auth?.mode;
690
+ if (authMode === "credentials" || authMode === "oauth2") {
691
+ for (const operationKey of Object.keys(provider.operations)) {
692
+ if (AUTH_OPERATION_ID_PATTERN.test(operationKey)) {
693
+ diagnostics.push({
694
+ rule: "auth-operation-unsupported",
695
+ level: "error",
696
+ field: `operations.${operationKey}`,
697
+ message: `Provider "${provider.id ?? "unknown"}" operation "${operationKey}" looks like a login/token/session exchange endpoint. Authenticated providers must expose login through the single auth.flow interface because Gateway persists only auth.flow complete turn data.credential as the connection credential. Move this logic into auth.flow.continue instead of a provider operation.`,
698
+ });
699
+ }
700
+ }
701
+ }
702
+ }
676
703
  if (!provider.operations) {
677
704
  return diagnostics;
678
705
  }
@@ -1,9 +1,11 @@
1
+ export { AuthAbortError, credentialsAuthChallenge, createAuthFlowHelpers, defineCredentialsAuth, } from "./auth";
2
+ export type { CredentialsAuthChallengeDefinition, CredentialsAuthChallengeRequest, CredentialsAuthCompleteResult, CredentialsAuthCredential, CredentialsAuthField, CredentialsAuthFields, CredentialsAuthFieldType, CredentialsAuthInput, CredentialsAuthLoginResult, DefineCredentialsAuthOptions, DefinedCredentialsAuth, } from "./auth";
1
3
  export { createFormCeremony } from "./ceremonies";
2
4
  export { assertFreshProviderChoiceIssuedAt, createProviderChoiceToken, ProviderChoiceTokenError, type ProviderChoiceTokenErrorReason, type ProviderChoiceTokenPayload, parseProviderChoiceToken, } from "./choice-token";
3
- export { defineHealthJourney, defineOperation, defineProvider, defineSmsOtpMatcher, every, } from "./define";
5
+ export { centered, delayed, defineHealthJourney, defineOperation, defineProvider, defineSmsOtpMatcher, every, } from "./define";
4
6
  export { AuthError, ProviderError, SessionExpiredError, TransportError, ValidationError, } from "./errors";
5
7
  export { getProviderLocalePath, providerLocaleKey, qualifyProviderLocaleKey, } from "./i18n";
6
8
  export { type CreateProviderChoiceContextOptions, createProviderChoiceContext, createTestProviderChoiceContext, PROVIDER_RUNTIME_CHOICE_TOKEN_MASTER_SECRET_ENV, } from "./runtime/choice";
7
9
  export { APIFUSE_DESCRIPTION_KEY_META_KEY, APIFUSE_REDACTION_MARKER, APIFUSE_SENSITIVE_KIND_META_KEY, APIFUSE_SENSITIVE_META_KEY, collectSensitivePaths, describeKey, field, fields, isSensitiveSchema, redactPayload, type SensitiveFieldKind, type SensitiveFieldOptions, type SensitivePath, sensitive, z, } from "./schema";
8
- export type { AuthMode, FlowContext, HealthCheckAssertionContext, HealthCheckCase, HealthCheckSuite, HealthCheckUnsupported, HealthJourneyDefinition, HealthJourneyEventContext, HealthJourneyManualTriggerPolicy, HealthJourneyRunContext, HealthJourneyRunResult, HttpRetryOptions, HttpRetrySummary, InferSchemaOutput, OperationApprovalPolicy, OperationContractMetadata, OperationDefinition, OperationDocMeta, OperationErrorCode, OperationInputExample, OperationLifecycle, OperationObservabilityConfig, OperationObservabilitySensitiveConfig, OperationRelationships, OperationRiskClass, OperationSensitivePath, OperationToolRouterMetadata, OperationTransport, ProviderAccessVisibility, ProviderChoiceBindingOptions, ProviderChoiceContext, ProviderChoiceIssueOptions, ProviderChoiceParseOptions, ProviderContext, ProviderDefinition, ProviderLocale, ProviderLocaleKey, ProviderLocaleKeyInput, ProviderLogoProfile, ProviderProxyPolicy, ProviderPublicConnectionMode, ProviderPublicProfile, ProviderRuntimeState, ProviderStateDurationString, ProviderStateNamespace, ProviderSupportLevel, SchemaLike, SmsOtpMatcherDefinition, StandardSchemaV1, StateCasResult, StateNamespaceOptions, StateValue, StateWriteOptions, } from "./types";
10
+ export type { AuthAbortData, AuthAbortRetry, AuthFlowTerminalContext, AuthMode, AuthSafeData, AuthSafeJson, FlowContext, HealthCheckAssertionContext, HealthCheckCase, HealthCheckSuite, HealthCheckUnsupported, HealthJourneyDefinition, HealthJourneyEventContext, HealthJourneyManualTriggerPolicy, HealthJourneyRunContext, HealthJourneyRunResult, HealthScheduleRandomization, HttpRetryOptions, HttpRetrySummary, InferSchemaOutput, OperationApprovalPolicy, OperationContractMetadata, OperationDefinition, OperationDocMeta, OperationErrorCode, OperationInputExample, OperationLifecycle, OperationObservabilityConfig, OperationObservabilitySensitiveConfig, OperationRelationships, OperationRiskClass, OperationSensitivePath, OperationToolRouterMetadata, OperationTransport, ProviderAccessVisibility, ProviderChoiceBindingOptions, ProviderChoiceContext, ProviderChoiceIssueOptions, ProviderChoiceParseOptions, ProviderContext, ProviderDefinition, ProviderLocale, ProviderLocaleKey, ProviderLocaleKeyInput, ProviderLogoProfile, ProviderProxyPolicy, ProviderPublicConnectionMode, ProviderPublicProfile, ProviderRuntimeState, ProviderStateDurationString, ProviderStateNamespace, ProviderSupportLevel, SchemaLike, SmsOtpMatcherDefinition, StandardSchemaV1, StateCasResult, StateNamespaceOptions, StateValue, StateWriteOptions, } from "./types";
9
11
  export { HttpRetryAfterPolicy, HttpRetryDelayStrategy, HttpRetryJitter, HttpRetryPreset, HttpRetryUnsafeMethodPolicy, } from "./types";
package/dist/provider.js CHANGED
@@ -1,6 +1,7 @@
1
+ export { AuthAbortError, credentialsAuthChallenge, createAuthFlowHelpers, defineCredentialsAuth, } from "./auth";
1
2
  export { createFormCeremony } from "./ceremonies";
2
3
  export { assertFreshProviderChoiceIssuedAt, createProviderChoiceToken, ProviderChoiceTokenError, parseProviderChoiceToken, } from "./choice-token";
3
- export { defineHealthJourney, defineOperation, defineProvider, defineSmsOtpMatcher, every, } from "./define";
4
+ export { centered, delayed, defineHealthJourney, defineOperation, defineProvider, defineSmsOtpMatcher, every, } from "./define";
4
5
  export { AuthError, ProviderError, SessionExpiredError, TransportError, ValidationError, } from "./errors";
5
6
  export { getProviderLocalePath, providerLocaleKey, qualifyProviderLocaleKey, } from "./i18n";
6
7
  export { createProviderChoiceContext, createTestProviderChoiceContext, PROVIDER_RUNTIME_CHOICE_TOKEN_MASTER_SECRET_ENV, } from "./runtime/choice";
@@ -1,4 +1,5 @@
1
1
  import { ContextAccessError } from "../errors";
2
+ import { createAuthFlowHelpers } from "../auth";
2
3
  import { createUnsupportedSttClient } from "./stt";
3
4
  function normalizeAllowedKeys(allowedKeys) {
4
5
  return new Set(allowedKeys.filter((key) => key.trim().length > 0));
@@ -40,5 +41,6 @@ export function createFlowContext(options) {
40
41
  env: options.env,
41
42
  context: createScratchpad(options.allowedKeys, options.initialContext),
42
43
  stt: options.stt ?? createUnsupportedSttClient(),
44
+ auth: createAuthFlowHelpers(),
43
45
  };
44
46
  }