@apifuse/provider-sdk 2.2.0-beta.41 → 2.2.0-beta.43

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.
@@ -8,7 +8,7 @@ import { basename, dirname, join, relative, resolve, sep } from "node:path";
8
8
  import { pathToFileURL } from "node:url";
9
9
 
10
10
  import * as acorn from "acorn";
11
- import ts from "typescript";
11
+ import type TS from "typescript";
12
12
  import { z } from "zod";
13
13
 
14
14
  import packageJson from "../package.json";
@@ -29,6 +29,19 @@ import { type CheckResult, PROMPT_ASSETS_CHECK_MESSAGE, runChecks } from "./apif
29
29
  import { hasSubstantiveDelimitedTextStructure } from "./submit-check-delimited-text.js";
30
30
  import { hasSubstantiveXmlStructure } from "./submit-check-xml.js";
31
31
 
32
+ const ts: typeof import("typescript") = await loadTypeScript();
33
+
34
+ async function loadTypeScript(): Promise<typeof import("typescript")> {
35
+ try {
36
+ return await import("typescript");
37
+ } catch {
38
+ console.error(
39
+ "apifuse submit-check requires typescript; install it in the workspace running the CLI (bun add -d typescript)",
40
+ );
41
+ process.exit(1);
42
+ }
43
+ }
44
+
32
45
  const TIERS = ["bronze", "silver", "gold", "diamond"] as const;
33
46
  const TIER_VALUES: ReadonlySet<string> = new Set(TIERS);
34
47
  type BountyTier = (typeof TIERS)[number];
@@ -515,7 +528,7 @@ const DYNAMIC_CODE_GLOBAL_OBJECTS: ReadonlySet<string> = new Set([
515
528
  "global",
516
529
  ]);
517
530
 
518
- function unwrapLocalExpression(expression: ts.Expression): ts.Expression {
531
+ function unwrapLocalExpression(expression: TS.Expression): TS.Expression {
519
532
  let current = expression;
520
533
  while (
521
534
  ts.isParenthesizedExpression(current) ||
@@ -532,18 +545,18 @@ function unwrapLocalExpression(expression: ts.Expression): ts.Expression {
532
545
  }
533
546
 
534
547
  type LocalBinding = {
535
- declaration: ts.Identifier;
536
- initializer?: ts.Expression;
548
+ declaration: TS.Identifier;
549
+ initializer?: TS.Expression;
537
550
  destructuredProperty?: string;
538
551
  mutable: boolean;
539
552
  reassigned: boolean;
540
553
  };
541
554
 
542
555
  type LocalBindings = {
543
- scopes: Map<ts.Node, Map<string, LocalBinding[]>>;
556
+ scopes: Map<TS.Node, Map<string, LocalBinding[]>>;
544
557
  };
545
558
 
546
- function isLexicalScope(node: ts.Node): boolean {
559
+ function isLexicalScope(node: TS.Node): boolean {
547
560
  return (
548
561
  ts.isSourceFile(node) ||
549
562
  ts.isFunctionLike(node) ||
@@ -557,8 +570,8 @@ function isLexicalScope(node: ts.Node): boolean {
557
570
  );
558
571
  }
559
572
 
560
- function enclosingScope(node: ts.Node, functionScoped: boolean): ts.Node {
561
- let current: ts.Node | undefined = node.parent;
573
+ function enclosingScope(node: TS.Node, functionScoped: boolean): TS.Node {
574
+ let current: TS.Node | undefined = node.parent;
562
575
  while (current !== undefined) {
563
576
  if (
564
577
  ts.isSourceFile(current) ||
@@ -571,11 +584,11 @@ function enclosingScope(node: ts.Node, functionScoped: boolean): ts.Node {
571
584
  return node.getSourceFile();
572
585
  }
573
586
 
574
- function collectLocalBindings(sourceFile: ts.SourceFile): LocalBindings {
587
+ function collectLocalBindings(sourceFile: TS.SourceFile): LocalBindings {
575
588
  const bindings: LocalBindings = { scopes: new Map() };
576
589
  const addBinding = (
577
- scope: ts.Node,
578
- name: ts.Identifier,
590
+ scope: TS.Node,
591
+ name: TS.Identifier,
579
592
  binding: Omit<LocalBinding, "declaration" | "reassigned">,
580
593
  ): void => {
581
594
  let scopeBindings = bindings.scopes.get(scope);
@@ -592,8 +605,8 @@ function collectLocalBindings(sourceFile: ts.SourceFile): LocalBindings {
592
605
  }
593
606
  };
594
607
  const addBindingName = (
595
- bindingName: ts.BindingName,
596
- scope: ts.Node,
608
+ bindingName: TS.BindingName,
609
+ scope: TS.Node,
597
610
  binding: Omit<LocalBinding, "declaration" | "reassigned">,
598
611
  ): void => {
599
612
  if (ts.isIdentifier(bindingName)) {
@@ -619,7 +632,7 @@ function collectLocalBindings(sourceFile: ts.SourceFile): LocalBindings {
619
632
  addBindingName(element.name, scope, { mutable: binding.mutable });
620
633
  }
621
634
  };
622
- const visit = (node: ts.Node): void => {
635
+ const visit = (node: TS.Node): void => {
623
636
  if (ts.isVariableDeclaration(node)) {
624
637
  const declarationList = ts.isVariableDeclarationList(node.parent) ? node.parent : undefined;
625
638
  const isConstBinding =
@@ -649,12 +662,12 @@ function collectLocalBindings(sourceFile: ts.SourceFile): LocalBindings {
649
662
  };
650
663
  visit(sourceFile);
651
664
 
652
- const markReassigned = (identifier: ts.Identifier): void => {
665
+ const markReassigned = (identifier: TS.Identifier): void => {
653
666
  for (const binding of lookupLocalBindings(identifier, bindings) ?? []) {
654
667
  binding.reassigned = true;
655
668
  }
656
669
  };
657
- const markAssignmentTarget = (node: ts.Node): void => {
670
+ const markAssignmentTarget = (node: TS.Node): void => {
658
671
  const target = ts.isExpression(node) ? unwrapLocalExpression(node) : node;
659
672
  if (ts.isIdentifier(target)) {
660
673
  markReassigned(target);
@@ -678,7 +691,7 @@ function collectLocalBindings(sourceFile: ts.SourceFile): LocalBindings {
678
691
  }
679
692
  }
680
693
  };
681
- const visitAssignments = (node: ts.Node): void => {
694
+ const visitAssignments = (node: TS.Node): void => {
682
695
  if (
683
696
  ts.isBinaryExpression(node) &&
684
697
  node.operatorToken.kind >= ts.SyntaxKind.FirstAssignment &&
@@ -704,10 +717,10 @@ function collectLocalBindings(sourceFile: ts.SourceFile): LocalBindings {
704
717
  }
705
718
 
706
719
  function lookupLocalBindings(
707
- reference: ts.Identifier,
720
+ reference: TS.Identifier,
708
721
  bindings: LocalBindings,
709
722
  ): readonly LocalBinding[] | undefined {
710
- let current: ts.Node | undefined = reference;
723
+ let current: TS.Node | undefined = reference;
711
724
  while (current !== undefined) {
712
725
  const localBindings = bindings.scopes.get(current)?.get(reference.text);
713
726
  if (localBindings !== undefined && localBindings.length > 0) {
@@ -718,7 +731,7 @@ function lookupLocalBindings(
718
731
  return undefined;
719
732
  }
720
733
 
721
- function propertyNameText(name: ts.PropertyName | ts.BindingName): string | undefined {
734
+ function propertyNameText(name: TS.PropertyName | TS.BindingName): string | undefined {
722
735
  if (
723
736
  ts.isIdentifier(name) ||
724
737
  ts.isStringLiteral(name) ||
@@ -736,7 +749,7 @@ function propertyNameText(name: ts.PropertyName | ts.BindingName): string | unde
736
749
  return undefined;
737
750
  }
738
751
 
739
- function isUnshadowedGlobalObject(reference: ts.Expression, bindings: LocalBindings): boolean {
752
+ function isUnshadowedGlobalObject(reference: TS.Expression, bindings: LocalBindings): boolean {
740
753
  const receiver = unwrapLocalExpression(reference);
741
754
  return (
742
755
  ts.isIdentifier(receiver) &&
@@ -746,13 +759,13 @@ function isUnshadowedGlobalObject(reference: ts.Expression, bindings: LocalBindi
746
759
  }
747
760
 
748
761
  function isGlobalMemberSink(
749
- expression: ts.Expression,
762
+ expression: TS.Expression,
750
763
  sinkNames: ReadonlySet<string>,
751
764
  bindings: LocalBindings,
752
765
  ): boolean {
753
766
  const callee = unwrapLocalExpression(expression);
754
767
  let sinkName: string | undefined;
755
- let receiver: ts.Expression | undefined;
768
+ let receiver: TS.Expression | undefined;
756
769
  if (ts.isPropertyAccessExpression(callee)) {
757
770
  sinkName = callee.name.text;
758
771
  receiver = callee.expression;
@@ -773,7 +786,7 @@ function isGlobalMemberSink(
773
786
  }
774
787
 
775
788
  function isGlobalSinkReference(
776
- expression: ts.Expression,
789
+ expression: TS.Expression,
777
790
  sinkNames: ReadonlySet<string>,
778
791
  bindings: LocalBindings,
779
792
  resolving: ReadonlySet<LocalBinding>,
@@ -789,7 +802,7 @@ function isGlobalSinkReference(
789
802
  }
790
803
 
791
804
  function isGlobalSinkIdentifier(
792
- reference: ts.Identifier,
805
+ reference: TS.Identifier,
793
806
  sinkNames: ReadonlySet<string>,
794
807
  bindings: LocalBindings,
795
808
  resolving: ReadonlySet<LocalBinding>,
@@ -821,7 +834,7 @@ function isGlobalSinkIdentifier(
821
834
  }
822
835
 
823
836
  function isGlobalSinkCallee(
824
- expression: ts.Expression,
837
+ expression: TS.Expression,
825
838
  sinkNames: ReadonlySet<string>,
826
839
  bindings: LocalBindings,
827
840
  ): boolean {
@@ -836,7 +849,7 @@ function isGlobalSinkCallee(
836
849
  }
837
850
 
838
851
  function resolveConstStringIdentifier(
839
- reference: ts.Identifier,
852
+ reference: TS.Identifier,
840
853
  bindings: LocalBindings,
841
854
  resolving: ReadonlySet<LocalBinding> = new Set(),
842
855
  ): string | undefined {
@@ -889,7 +902,7 @@ function findGlobalSinkCalls(
889
902
  ts.ScriptKind.TS,
890
903
  );
891
904
  const bindings = collectLocalBindings(sourceFile);
892
- const visit = (node: ts.Node): void => {
905
+ const visit = (node: TS.Node): void => {
893
906
  if (findings.length >= MAX_SOURCE_FINDING_EVIDENCE) {
894
907
  return;
895
908
  }
@@ -1688,13 +1701,13 @@ function spreadIdentifierResolvesToFactory(
1688
1701
  return false;
1689
1702
  }
1690
1703
 
1691
- function isDefineProviderCall(node: ts.CallExpression): boolean {
1704
+ function isDefineProviderCall(node: TS.CallExpression): boolean {
1692
1705
  return ts.isIdentifier(node.expression) && node.expression.text === "defineProvider";
1693
1706
  }
1694
1707
 
1695
1708
  function resolveDefineProviderImplementationCall(
1696
- candidate: ts.CallExpression,
1697
- ): ts.CallExpression | undefined {
1709
+ candidate: TS.CallExpression,
1710
+ ): TS.CallExpression | undefined {
1698
1711
  let root = candidate;
1699
1712
  while (ts.isCallExpression(root.expression)) {
1700
1713
  root = root.expression;
@@ -1702,9 +1715,9 @@ function resolveDefineProviderImplementationCall(
1702
1715
  return isDefineProviderCall(root) ? candidate : undefined;
1703
1716
  }
1704
1717
 
1705
- function findProviderImplementationCall(sourceFile: ts.SourceFile): ts.CallExpression | undefined {
1718
+ function findProviderImplementationCall(sourceFile: TS.SourceFile): TS.CallExpression | undefined {
1706
1719
  const defaultExports = sourceFile.statements.filter(
1707
- (statement): statement is ts.ExportAssignment =>
1720
+ (statement): statement is TS.ExportAssignment =>
1708
1721
  ts.isExportAssignment(statement) && !statement.isExportEquals,
1709
1722
  );
1710
1723
 
@@ -1770,8 +1783,8 @@ function findProviderImplementationCall(sourceFile: ts.SourceFile): ts.CallExpre
1770
1783
 
1771
1784
  // Structural fixtures without a recognizable default export retain the
1772
1785
  // previous fallback to the first defineProvider call in source order.
1773
- let firstCall: ts.CallExpression | undefined;
1774
- const visit = (node: ts.Node): void => {
1786
+ let firstCall: TS.CallExpression | undefined;
1787
+ const visit = (node: TS.Node): void => {
1775
1788
  if (firstCall !== undefined) {
1776
1789
  return;
1777
1790
  }
@@ -1788,7 +1801,7 @@ function findProviderImplementationCall(sourceFile: ts.SourceFile): ts.CallExpre
1788
1801
  return firstCall;
1789
1802
  }
1790
1803
 
1791
- function unwrapImplementationExpression(expression: ts.Expression): ts.Expression {
1804
+ function unwrapImplementationExpression(expression: TS.Expression): TS.Expression {
1792
1805
  let current = expression;
1793
1806
  while (
1794
1807
  ts.isSatisfiesExpression(current) ||
@@ -1802,8 +1815,8 @@ function unwrapImplementationExpression(expression: ts.Expression): ts.Expressio
1802
1815
  }
1803
1816
 
1804
1817
  function isOperationsProperty(
1805
- property: ts.ObjectLiteralElementLike,
1806
- ): property is ts.PropertyAssignment | ts.ShorthandPropertyAssignment {
1818
+ property: TS.ObjectLiteralElementLike,
1819
+ ): property is TS.PropertyAssignment | TS.ShorthandPropertyAssignment {
1807
1820
  if (ts.isShorthandPropertyAssignment(property)) {
1808
1821
  return property.name.text === "operations";
1809
1822
  }
@@ -1817,8 +1830,8 @@ function isOperationsProperty(
1817
1830
  }
1818
1831
 
1819
1832
  function isOperationsAccessorOrMethod(
1820
- property: ts.ObjectLiteralElementLike,
1821
- ): property is ts.GetAccessorDeclaration | ts.SetAccessorDeclaration | ts.MethodDeclaration {
1833
+ property: TS.ObjectLiteralElementLike,
1834
+ ): property is TS.GetAccessorDeclaration | TS.SetAccessorDeclaration | TS.MethodDeclaration {
1822
1835
  if (
1823
1836
  !ts.isGetAccessorDeclaration(property) &&
1824
1837
  !ts.isSetAccessorDeclaration(property) &&
@@ -1832,7 +1845,7 @@ function isOperationsAccessorOrMethod(
1832
1845
  );
1833
1846
  }
1834
1847
 
1835
- function isSourceEnumerableStaticObjectLiteral(expression: ts.Expression): boolean {
1848
+ function isSourceEnumerableStaticObjectLiteral(expression: TS.Expression): boolean {
1836
1849
  const unwrapped = unwrapImplementationExpression(expression);
1837
1850
  if (!ts.isObjectLiteralExpression(unwrapped)) {
1838
1851
  return false;
@@ -1849,8 +1862,8 @@ function isSourceEnumerableStaticObjectLiteral(expression: ts.Expression): boole
1849
1862
  }
1850
1863
 
1851
1864
  function findComputedImplementationProperty(
1852
- objectLiteral: ts.ObjectLiteralExpression,
1853
- ): ts.ObjectLiteralElementLike | undefined {
1865
+ objectLiteral: TS.ObjectLiteralExpression,
1866
+ ): TS.ObjectLiteralElementLike | undefined {
1854
1867
  for (const property of objectLiteral.properties) {
1855
1868
  if (property.name !== undefined && ts.isComputedPropertyName(property.name)) {
1856
1869
  return property;
@@ -1869,20 +1882,20 @@ function findComputedImplementationProperty(
1869
1882
  }
1870
1883
 
1871
1884
  function findEffectiveOperationsProperty(
1872
- objectLiteral: ts.ObjectLiteralExpression,
1885
+ objectLiteral: TS.ObjectLiteralExpression,
1873
1886
  ):
1874
- | ts.PropertyAssignment
1875
- | ts.ShorthandPropertyAssignment
1876
- | ts.GetAccessorDeclaration
1877
- | ts.SetAccessorDeclaration
1878
- | ts.MethodDeclaration
1887
+ | TS.PropertyAssignment
1888
+ | TS.ShorthandPropertyAssignment
1889
+ | TS.GetAccessorDeclaration
1890
+ | TS.SetAccessorDeclaration
1891
+ | TS.MethodDeclaration
1879
1892
  | undefined {
1880
1893
  let effective:
1881
- | ts.PropertyAssignment
1882
- | ts.ShorthandPropertyAssignment
1883
- | ts.GetAccessorDeclaration
1884
- | ts.SetAccessorDeclaration
1885
- | ts.MethodDeclaration
1894
+ | TS.PropertyAssignment
1895
+ | TS.ShorthandPropertyAssignment
1896
+ | TS.GetAccessorDeclaration
1897
+ | TS.SetAccessorDeclaration
1898
+ | TS.MethodDeclaration
1886
1899
  | undefined;
1887
1900
  for (const property of objectLiteral.properties) {
1888
1901
  if (isOperationsProperty(property) || isOperationsAccessorOrMethod(property)) {
@@ -1994,7 +2007,7 @@ function scoreFlatOperationComposition(providerRoot: string): SubmitCheck {
1994
2007
  // exposes all of its property names to this source-only gate. Identifiers,
1995
2008
  // calls, and other expressions are opaque and therefore fail closed.
1996
2009
  const opaqueSpread = implementationArg.properties.find(
1997
- (property): property is ts.SpreadAssignment =>
2010
+ (property): property is TS.SpreadAssignment =>
1998
2011
  ts.isSpreadAssignment(property) &&
1999
2012
  !isSourceEnumerableStaticObjectLiteral(property.expression),
2000
2013
  );
@@ -2210,9 +2223,9 @@ function scoreCredentialUsage(providerRoot: string, provider: ProviderDefinition
2210
2223
  );
2211
2224
  }
2212
2225
 
2213
- function isDirectCredentialReference(expression: ts.Expression): boolean {
2226
+ function isDirectCredentialReference(expression: TS.Expression): boolean {
2214
2227
  const reference = unwrapLocalExpression(expression);
2215
- let receiver: ts.Expression | undefined;
2228
+ let receiver: TS.Expression | undefined;
2216
2229
  let memberName: string | undefined;
2217
2230
  if (ts.isPropertyAccessExpression(reference)) {
2218
2231
  receiver = reference.expression;
@@ -2237,7 +2250,7 @@ function isDirectCredentialReference(expression: ts.Expression): boolean {
2237
2250
  }
2238
2251
 
2239
2252
  function isCredentialReference(
2240
- expression: ts.Expression,
2253
+ expression: TS.Expression,
2241
2254
  bindings: LocalBindings,
2242
2255
  resolving: ReadonlySet<LocalBinding> = new Set(),
2243
2256
  ): boolean {
@@ -2284,7 +2297,7 @@ function findCredentialReferences(providerRoot: string): SourceFinding[] {
2284
2297
  ts.ScriptKind.TS,
2285
2298
  );
2286
2299
  const bindings = collectLocalBindings(sourceFile);
2287
- const visit = (node: ts.Node): void => {
2300
+ const visit = (node: TS.Node): void => {
2288
2301
  if (findings.length >= MAX_SOURCE_FINDING_EVIDENCE) {
2289
2302
  return;
2290
2303
  }
@@ -3332,12 +3345,12 @@ function findZObjectLiterals(source: string): ZObjectLiteral[] {
3332
3345
  }
3333
3346
 
3334
3347
  function zObjectAppearsPublicOutput(
3335
- sourceFile: ts.SourceFile,
3348
+ sourceFile: TS.SourceFile,
3336
3349
  zObject: ZObjectLiteral,
3337
3350
  relPath: string,
3338
3351
  ): boolean {
3339
- let zObjectCall: ts.CallExpression | undefined;
3340
- const findCall = (node: ts.Node): void => {
3352
+ let zObjectCall: TS.CallExpression | undefined;
3353
+ const findCall = (node: TS.Node): void => {
3341
3354
  if (
3342
3355
  zObjectCall === undefined &&
3343
3356
  ts.isCallExpression(node) &&
@@ -3353,7 +3366,7 @@ function zObjectAppearsPublicOutput(
3353
3366
  return true;
3354
3367
  }
3355
3368
 
3356
- let expression: ts.Expression = zObjectCall;
3369
+ let expression: TS.Expression = zObjectCall;
3357
3370
  while (
3358
3371
  ts.isParenthesizedExpression(expression.parent) ||
3359
3372
  ts.isAsExpression(expression.parent) ||
@@ -3411,8 +3424,8 @@ const PARSE_LIKE_SCHEMA_METHODS: ReadonlySet<string> = new Set([
3411
3424
  ]);
3412
3425
 
3413
3426
  function isExportedVariableBinding(
3414
- sourceFile: ts.SourceFile,
3415
- declaration: ts.VariableDeclaration,
3427
+ sourceFile: TS.SourceFile,
3428
+ declaration: TS.VariableDeclaration,
3416
3429
  ): boolean {
3417
3430
  const declarationStatement = declaration.parent.parent;
3418
3431
  if (
@@ -3428,7 +3441,7 @@ function isExportedVariableBinding(
3428
3441
  }
3429
3442
  const name = declaration.name.text;
3430
3443
  let exported = false;
3431
- const visit = (node: ts.Node): void => {
3444
+ const visit = (node: TS.Node): void => {
3432
3445
  if (exported) {
3433
3446
  return;
3434
3447
  }
@@ -3457,13 +3470,13 @@ function isExportedVariableBinding(
3457
3470
  return exported;
3458
3471
  }
3459
3472
 
3460
- function isPublicOutputPropertyName(name: ts.PropertyName): boolean {
3473
+ function isPublicOutputPropertyName(name: TS.PropertyName): boolean {
3461
3474
  const text = propertyNameText(name);
3462
3475
  return text === "output" || text === "response";
3463
3476
  }
3464
3477
 
3465
- function findEnclosingVariableDeclaration(node: ts.Node): ts.VariableDeclaration | undefined {
3466
- let current: ts.Node | undefined = node;
3478
+ function findEnclosingVariableDeclaration(node: TS.Node): TS.VariableDeclaration | undefined {
3479
+ let current: TS.Node | undefined = node;
3467
3480
  while (current !== undefined && !ts.isSourceFile(current)) {
3468
3481
  if (ts.isVariableDeclaration(current)) {
3469
3482
  return current;
@@ -3474,9 +3487,9 @@ function findEnclosingVariableDeclaration(node: ts.Node): ts.VariableDeclaration
3474
3487
  }
3475
3488
 
3476
3489
  function localSchemaBindingReachability(
3477
- sourceFile: ts.SourceFile,
3490
+ sourceFile: TS.SourceFile,
3478
3491
  name: string,
3479
- declaration: ts.VariableDeclaration,
3492
+ declaration: TS.VariableDeclaration,
3480
3493
  resolving: ReadonlySet<string>,
3481
3494
  ): SchemaReachability {
3482
3495
  if (resolving.has(name)) {
@@ -3485,7 +3498,7 @@ function localSchemaBindingReachability(
3485
3498
  const nextResolving = new Set(resolving);
3486
3499
  nextResolving.add(name);
3487
3500
  let result: SchemaReachability = "internal";
3488
- const visit = (node: ts.Node): void => {
3501
+ const visit = (node: TS.Node): void => {
3489
3502
  if (result === "public") {
3490
3503
  return;
3491
3504
  }
@@ -3550,7 +3563,7 @@ function localSchemaBindingReachability(
3550
3563
  return result;
3551
3564
  }
3552
3565
 
3553
- function isParseLikeSchemaReceiver(identifier: ts.Identifier): boolean {
3566
+ function isParseLikeSchemaReceiver(identifier: TS.Identifier): boolean {
3554
3567
  const access = identifier.parent;
3555
3568
  let methodName: string | undefined;
3556
3569
  if (ts.isPropertyAccessExpression(access) && access.expression === identifier) {
@@ -3574,7 +3587,7 @@ function isParseLikeSchemaReceiver(identifier: ts.Identifier): boolean {
3574
3587
 
3575
3588
  function vendorKeyFindingsForObject(
3576
3589
  source: string,
3577
- sourceFile: ts.SourceFile,
3590
+ sourceFile: TS.SourceFile,
3578
3591
  zObject: ZObjectLiteral,
3579
3592
  bindings: LocalBindings,
3580
3593
  ): Array<{ key: string; line: number }> {
@@ -3640,7 +3653,7 @@ function isAllowedPublicOutputKeyName(name: string): boolean {
3640
3653
 
3641
3654
  function collectTopLevelObjectKeys(
3642
3655
  source: string,
3643
- sourceFile: ts.SourceFile,
3656
+ sourceFile: TS.SourceFile,
3644
3657
  objectStart: number,
3645
3658
  objectEnd: number,
3646
3659
  bindings: LocalBindings,
@@ -3702,11 +3715,11 @@ function collectTopLevelObjectKeys(
3702
3715
  }
3703
3716
 
3704
3717
  function computedPropertyExpressionAtOffset(
3705
- sourceFile: ts.SourceFile,
3718
+ sourceFile: TS.SourceFile,
3706
3719
  offset: number,
3707
- ): ts.Expression | undefined {
3708
- let expression: ts.Expression | undefined;
3709
- const visit = (node: ts.Node): void => {
3720
+ ): TS.Expression | undefined {
3721
+ let expression: TS.Expression | undefined;
3722
+ const visit = (node: TS.Node): void => {
3710
3723
  if (expression !== undefined || offset < node.getFullStart() || offset >= node.getEnd()) {
3711
3724
  return;
3712
3725
  }
@@ -3770,7 +3783,7 @@ function findVendorTimestampLeakFindings(providerRoot: string): SourceFinding[]
3770
3783
  }
3771
3784
  }
3772
3785
 
3773
- const visitAliases = (node: ts.Node): void => {
3786
+ const visitAliases = (node: TS.Node): void => {
3774
3787
  if (findings.length >= MAX_SOURCE_FINDING_EVIDENCE) {
3775
3788
  return;
3776
3789
  }
@@ -3808,7 +3821,7 @@ function findVendorTimestampLeakFindings(providerRoot: string): SourceFinding[]
3808
3821
  return findings;
3809
3822
  }
3810
3823
 
3811
- function isIdentifierValueUse(identifier: ts.Identifier): boolean {
3824
+ function isIdentifierValueUse(identifier: TS.Identifier): boolean {
3812
3825
  const parent = identifier.parent;
3813
3826
  return !(
3814
3827
  (ts.isPropertyAssignment(parent) && parent.name === identifier) ||
@@ -3830,8 +3843,8 @@ function isIdentifierValueUse(identifier: ts.Identifier): boolean {
3830
3843
  );
3831
3844
  }
3832
3845
 
3833
- function propertyNameForValueExpression(expression: ts.Expression): string | undefined {
3834
- let current: ts.Expression = expression;
3846
+ function propertyNameForValueExpression(expression: TS.Expression): string | undefined {
3847
+ let current: TS.Expression = expression;
3835
3848
  while (
3836
3849
  ts.isParenthesizedExpression(current.parent) ||
3837
3850
  ts.isAsExpression(current.parent) ||
@@ -4113,14 +4126,14 @@ function computeMaskedSource(
4113
4126
  if (chars[index] !== "\n" && chars[index] !== "\r") chars[index] = " ";
4114
4127
  }
4115
4128
  };
4116
- const commentRanges = new Map<string, ts.CommentRange>();
4117
- const addCommentRanges = (ranges: readonly ts.CommentRange[] | undefined): void => {
4129
+ const commentRanges = new Map<string, TS.CommentRange>();
4130
+ const addCommentRanges = (ranges: readonly TS.CommentRange[] | undefined): void => {
4118
4131
  for (const range of ranges ?? []) {
4119
4132
  commentRanges.set(`${range.pos}:${range.end}`, range);
4120
4133
  }
4121
4134
  };
4122
4135
 
4123
- const visit = (node: ts.Node): void => {
4136
+ const visit = (node: TS.Node): void => {
4124
4137
  addCommentRanges(ts.getLeadingCommentRanges(source, node.getFullStart()));
4125
4138
  addCommentRanges(ts.getTrailingCommentRanges(source, node.getEnd()));
4126
4139
 
@@ -32,7 +32,7 @@ export const COMMAND_MANIFEST = {
32
32
  },
33
33
  "migrate-shape": {
34
34
  name: "migrate-shape",
35
- summary: "Migrate a provider index.ts from the single-phase defineProvider shape to the two-phase declaration builder.",
35
+ summary: "Migrate a provider to the phase-separated SDK: two-phase defineProvider in index.ts and curried defineOperation across sources.",
36
36
  usage: "apifuse migrate-shape [path] [--check] [--json]",
37
37
  examples: ["apifuse migrate-shape .", "apifuse migrate-shape . --check"],
38
38
  modulePath: "./apifuse-migrate-shape",
@@ -1,7 +1,7 @@
1
1
  export declare const PROVIDER_NAME_REGEX: RegExp;
2
2
  export declare const CATEGORY_OPTIONS: readonly ["developer-tools", "finance", "commerce", "productivity", "marketing", "data", "communication", "other"];
3
3
  export declare const AUTH_MODE_OPTIONS: readonly ["none", "platform-managed", "credentials", "oauth2"];
4
- export declare const RUNTIME_OPTIONS: readonly ["standard", "browser"];
4
+ export declare const RUNTIME_OPTIONS: readonly ["standard", "shared", "browser"];
5
5
  export declare const PRESET_OPTIONS: readonly ["standalone", "monorepo"];
6
6
  export type CreateCategory = (typeof CATEGORY_OPTIONS)[number];
7
7
  export type CreateAuthMode = (typeof AUTH_MODE_OPTIONS)[number];
@@ -19,7 +19,7 @@ export const CATEGORY_OPTIONS = [
19
19
  "other",
20
20
  ];
21
21
  export const AUTH_MODE_OPTIONS = ["none", "platform-managed", "credentials", "oauth2"];
22
- export const RUNTIME_OPTIONS = ["standard", "browser"];
22
+ export const RUNTIME_OPTIONS = ["standard", "shared", "browser"];
23
23
  export const PRESET_OPTIONS = ["standalone", "monorepo"];
24
24
  const CREATE_CONFIG_SCHEMA = z.object({
25
25
  authMode: z.enum(AUTH_MODE_OPTIONS).optional(),
@@ -46,7 +46,7 @@ Options:
46
46
  --display-name <name>
47
47
  --category <category>
48
48
  --auth-mode <mode>
49
- --runtime <standard|browser>
49
+ --runtime <standard|shared|browser>
50
50
  --yes
51
51
  --dry-run
52
52
  --json
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Operation authoring-shape migration.
3
+ *
4
+ * `defineOperation` / `defineStreamOperation` changed alongside the provider
5
+ * builder in 2.2.0-beta.37: the identity helper became a curried,
6
+ * context-typed factory.
7
+ *
8
+ * before: defineOperation({ ...config })
9
+ * after: defineOperation<ProviderContext>()({ ...config })
10
+ *
11
+ * The old call still type-checks against an older pin, but under the new SDK
12
+ * it returns the INNER FACTORY FUNCTION with the config swallowed as an
13
+ * ignored argument, so every operation in the map becomes a function and the
14
+ * provider fails `finalizeProvider` with a misleading "declares neither
15
+ * healthCheck nor healthCheckUnsupported" error. Measured fleet blast radius
16
+ * (2026-08-29): 53 of 84 repositories, 450 legacy call sites.
17
+ *
18
+ * Same contract as the provider-shape transform: rewrite only what is fully
19
+ * understood, report a reasoned skip otherwise, never emit a partial file.
20
+ */
21
+ export type OperationShapeMigration = {
22
+ readonly status: "migrated";
23
+ readonly code: string;
24
+ /** Number of call sites rewritten in this file. */
25
+ readonly rewrites: number;
26
+ /** True when a `ProviderContext` type import was added. */
27
+ readonly importAdded: boolean;
28
+ } | {
29
+ readonly status: "unchanged";
30
+ readonly code: string;
31
+ } | {
32
+ readonly status: "skipped";
33
+ readonly reason: string;
34
+ };
35
+ /**
36
+ * Migrate legacy `defineOperation(config)` calls in one source file to the
37
+ * curried `defineOperation<ProviderContext>()(config)` form.
38
+ *
39
+ * @param contextImportSpecifier module specifier the `ProviderContext` type
40
+ * import should come from when one has to be added — `"../index"` for
41
+ * operation modules, `"./index"` is never needed because index.ts declares
42
+ * the alias itself. Callers pass the correct relative path per file.
43
+ */
44
+ export declare function migrateOperationShape(sourceText: string, fileName: string, contextImportSpecifier: string): OperationShapeMigration;