@apifuse/provider-sdk 2.2.0-beta.55 → 2.2.0-beta.57

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.
@@ -26,6 +26,7 @@ import { getProviderBaseUrl } from "../runtime/provider.js";
26
26
  import { createOcrClientFromEnv } from "../runtime/ocr.js";
27
27
  import { PROXY_AUTH_IP_DENIED_CODE, PROXY_EDGE_AUTH_REJECTED_CODE, PROXY_POOL_EXHAUSTED_CODE, } from "../runtime/proxy-errors.js";
28
28
  import { PROVIDER_TELEMETRY_HEADER, ProxyTelemetryCollector, } from "../runtime/proxy-telemetry.js";
29
+ import { closedEnum, RequestTelemetry, tenantOpaqueKeys, } from "../runtime/request-telemetry.js";
29
30
  import { createUnsupportedResolverClient, } from "../runtime/resolver-shared.js";
30
31
  import { assertRequiredSecretsPresent, listMissingRequiredSecrets, MISSING_SECRET_CODE, } from "../runtime/secrets.js";
31
32
  import { createProviderRuntimeStateFromEnv, createUnsupportedProviderRuntimeState, } from "../runtime/state.js";
@@ -75,6 +76,16 @@ function providerErrorCode(error) {
75
76
  }
76
77
  const AUTH_FLOW_LOCALES = ["en", "ko", "ja"];
77
78
  const retryResponseMeta = new WeakMap();
79
+ const RETRY_LAST_ERROR_CODES = [
80
+ "transport_cancelled",
81
+ "transport_timeout",
82
+ "transport_network_error",
83
+ "upstream_http_error",
84
+ "other",
85
+ ];
86
+ function tenantRetryLastErrorCode(value) {
87
+ return RETRY_LAST_ERROR_CODES.find((candidate) => candidate === value) ?? "other";
88
+ }
78
89
  const STATEFUL_INTERNAL_OPERATIONS_ROUTE = "/__apifuse/stateful/operations";
79
90
  const STATEFUL_FORWARDING_SOURCE_POD_HEADER = "x-apifuse-stateful-source-pod";
80
91
  const DEFAULT_STATEFUL_FORWARDING_MAX_SKEW_MS = 5 * 60_000;
@@ -409,7 +420,7 @@ function createProviderContext(provider, request, operationId, options, state =
409
420
  const proxyClientOptions = {
410
421
  upstream: { proxy: provider.proxy },
411
422
  affinityKey: resolveProviderProxyAffinityKey(provider, request, operationId),
412
- telemetry: scope.proxyTelemetry,
423
+ telemetry: scope.telemetry.proxy,
413
424
  engineCredentials: engineProxyCredentials,
414
425
  };
415
426
  const resolverIdentityScope = resolveProviderResolverIdentityScope(provider, proxyClientOptions.affinityKey, request.requestId);
@@ -417,7 +428,7 @@ function createProviderContext(provider, request, operationId, options, state =
417
428
  const stealthClientOptions = {
418
429
  upstream: proxyClientOptions.upstream,
419
430
  affinityKey: proxyClientOptions.affinityKey,
420
- telemetry: scope.proxyTelemetry,
431
+ telemetry: scope.telemetry.proxy,
421
432
  engineCredentials: engineProxyCredentials,
422
433
  ...(signal ? { signal } : {}),
423
434
  ...(provider.stealth ? { stealth: provider.stealth } : {}),
@@ -564,14 +575,14 @@ function createAuthFlowContext(provider, request, options, state, scope, signal)
564
575
  const proxyClientOptions = {
565
576
  upstream: { proxy: provider.proxy },
566
577
  affinityKey: resolveAuthFlowProxyAffinityKey(provider, request),
567
- telemetry: scope.proxyTelemetry,
578
+ telemetry: scope.telemetry.proxy,
568
579
  engineCredentials: engineProxyCredentials,
569
580
  };
570
581
  const resolverIdentityScope = resolveProviderResolverIdentityScope(provider, proxyClientOptions.affinityKey, request.requestId);
571
582
  const stealthClientOptions = {
572
583
  upstream: proxyClientOptions.upstream,
573
584
  affinityKey: proxyClientOptions.affinityKey,
574
- telemetry: scope.proxyTelemetry,
585
+ telemetry: scope.telemetry.proxy,
575
586
  engineCredentials: engineProxyCredentials,
576
587
  ...(signal ? { signal } : {}),
577
588
  ...(provider.stealth ? { stealth: provider.stealth } : {}),
@@ -1014,7 +1025,7 @@ function providerErrorCauseChain(error) {
1014
1025
  }
1015
1026
  return frames.length > 0 ? frames : undefined;
1016
1027
  }
1017
- function logProviderError(logger, provider, kind, route, requestId, error, status, cost, declaredErrorCode, proxyTelemetry, observabilityDetails, correlation = {}) {
1028
+ function logProviderError(logger, provider, kind, route, requestId, error, status, cost, declaredErrorCode, telemetry, observabilityDetails, correlation = {}) {
1018
1029
  const providerCode = isProviderError(error) ? providerErrorCode(error) : undefined;
1019
1030
  const code = isProviderError(error)
1020
1031
  ? (providerCode ?? "provider_error")
@@ -1033,7 +1044,7 @@ function logProviderError(logger, provider, kind, route, requestId, error, statu
1033
1044
  typeof providerCode === "string" &&
1034
1045
  !SDK_OWNED_PROVIDER_ERROR_CODES.has(providerCode) &&
1035
1046
  declaredErrorCode === undefined;
1036
- const proxy = proxyTelemetry?.toLogPayload();
1047
+ const telemetryPayload = telemetry?.toLogPayload();
1037
1048
  const emit = typeof logger === "function" ? logger : defaultProviderServerLogger;
1038
1049
  // The logger is caller-supplied and may mutate the event synchronously.
1039
1050
  // Give it an independent snapshot so those mutations cannot corrupt the
@@ -1058,7 +1069,7 @@ function logProviderError(logger, provider, kind, route, requestId, error, statu
1058
1069
  : {}),
1059
1070
  status,
1060
1071
  ...cost,
1061
- ...(proxy ? { proxy } : {}),
1072
+ ...(telemetryPayload ?? {}),
1062
1073
  code,
1063
1074
  errorClass,
1064
1075
  message,
@@ -1093,8 +1104,8 @@ function logProviderCleanupError(logger, provider, kind, operationId, requestId,
1093
1104
  message,
1094
1105
  });
1095
1106
  }
1096
- function logProviderSuccess(logger, provider, kind, route, requestId, status, cost, proxyTelemetry, correlation = {}) {
1097
- const proxy = proxyTelemetry?.toLogPayload();
1107
+ function logProviderSuccess(logger, provider, kind, route, requestId, status, cost, telemetry, correlation = {}) {
1108
+ const telemetryPayload = telemetry?.toLogPayload();
1098
1109
  const emit = typeof logger === "function" ? logger : defaultProviderServerLogger;
1099
1110
  emit({
1100
1111
  level: "info",
@@ -1113,7 +1124,7 @@ function logProviderSuccess(logger, provider, kind, route, requestId, status, co
1113
1124
  : {}),
1114
1125
  status,
1115
1126
  ...cost,
1116
- ...(proxy ? { proxy } : {}),
1127
+ ...(telemetryPayload ?? {}),
1117
1128
  });
1118
1129
  }
1119
1130
  const STREAM_CLEANUP_TIMEOUT_MS = 100;
@@ -1165,7 +1176,6 @@ function requestTraceId(headers, requestId) {
1165
1176
  function createRequestScope(input) {
1166
1177
  const requestCost = startRequestCost();
1167
1178
  const traceConfig = resolveTraceConfigFromEnv();
1168
- const proxyTelemetry = new ProxyTelemetryCollector();
1169
1179
  const details = {
1170
1180
  route: input.route,
1171
1181
  requestId: input.requestId,
@@ -1188,6 +1198,9 @@ function createRequestScope(input) {
1188
1198
  ...(initialTraceId ? { traceId: initialTraceId } : {}),
1189
1199
  })
1190
1200
  : createTraceContext();
1201
+ const proxyCollector = new ProxyTelemetryCollector();
1202
+ const telemetry = new RequestTelemetry(trace);
1203
+ telemetry.register(proxyCollector);
1191
1204
  let rootRunner = (fn) => fn();
1192
1205
  let resolveRoot;
1193
1206
  const rootTerminal = new Promise((resolve) => {
@@ -1233,7 +1246,7 @@ function createRequestScope(input) {
1233
1246
  await Promise.all(streamCleanups.map(runCleanupEntry));
1234
1247
  };
1235
1248
  const headerSnapshot = (error) => {
1236
- const providerTelemetryHeader = proxyTelemetry.toHeaderValue();
1249
+ const providerTelemetryHeader = telemetry.toHeaderValue();
1237
1250
  const declaredErrorCode = error === undefined ? undefined : input.declaredErrorCode?.(error);
1238
1251
  const errorObservability = error === undefined ? undefined : errorObservabilityDetails(error, declaredErrorCode);
1239
1252
  return {
@@ -1261,7 +1274,7 @@ function createRequestScope(input) {
1261
1274
  };
1262
1275
  const scope = {
1263
1276
  trace,
1264
- proxyTelemetry,
1277
+ telemetry,
1265
1278
  enrich(enrichment) {
1266
1279
  if (terminalOutcome)
1267
1280
  return;
@@ -1334,10 +1347,10 @@ function createRequestScope(input) {
1334
1347
  const cost = finishRequestCost(requestCost);
1335
1348
  try {
1336
1349
  if (error === undefined) {
1337
- logProviderSuccess(input.logger, input.provider, input.kind, details.route, details.requestId, status, cost, proxyTelemetry, details.correlation);
1350
+ logProviderSuccess(input.logger, input.provider, input.kind, details.route, details.requestId, status, cost, telemetry, details.correlation);
1338
1351
  }
1339
1352
  else {
1340
- logProviderError(input.logger, input.provider, input.kind, details.route, details.requestId, error, status, cost, declaredErrorCode, proxyTelemetry, finishedResult.errorObservability, details.correlation);
1353
+ logProviderError(input.logger, input.provider, input.kind, details.route, details.requestId, error, status, cost, declaredErrorCode, telemetry, finishedResult.errorObservability, details.correlation);
1341
1354
  }
1342
1355
  }
1343
1356
  catch {
@@ -1407,18 +1420,43 @@ function toJsonSuccessResponse(result, ctx) {
1407
1420
  }
1408
1421
  const cacheMeta = ctx && "cache" in ctx ? ctx.cache.responseMeta() : undefined;
1409
1422
  const retryMeta = ctx ? retryResponseMeta.get(ctx) : undefined;
1423
+ const cache = cacheMeta
1424
+ ? {
1425
+ hit: cacheMeta.hit,
1426
+ stale: cacheMeta.stale,
1427
+ // TODO(owner): keep or remove implementation-shaped cache keys from tenant meta.
1428
+ keys: tenantOpaqueKeys(cacheMeta.keys),
1429
+ ...(cacheMeta.source ? { source: closedEnum(cacheMeta.source) } : {}),
1430
+ }
1431
+ : undefined;
1432
+ const retry = retryMeta
1433
+ ? {
1434
+ attempts: retryMeta.attempts,
1435
+ retries: retryMeta.retries,
1436
+ ...(retryMeta.preset ? { preset: closedEnum(retryMeta.preset) } : {}),
1437
+ transport: closedEnum(retryMeta.transport),
1438
+ ...(retryMeta.lastErrorCode
1439
+ ? {
1440
+ lastErrorCode: closedEnum(tenantRetryLastErrorCode(retryMeta.lastErrorCode)),
1441
+ }
1442
+ : {}),
1443
+ ...(retryMeta.lastStatus ? { lastStatus: retryMeta.lastStatus } : {}),
1444
+ }
1445
+ : undefined;
1410
1446
  const meta = cacheMeta || retryMeta
1411
1447
  ? {
1412
- ...(cacheMeta
1448
+ ...(cache
1413
1449
  ? {
1414
- cached: cacheMeta.hit,
1415
- stale: cacheMeta.stale,
1416
- cache: cacheMeta,
1450
+ cached: cache.hit,
1451
+ stale: cache.stale,
1452
+ cache,
1417
1453
  }
1418
1454
  : {}),
1419
- ...(retryMeta ? { retry: retryMeta } : {}),
1455
+ ...(retry ? { retry } : {}),
1420
1456
  }
1421
1457
  : undefined;
1458
+ const _neutralMeta = meta;
1459
+ void _neutralMeta;
1422
1460
  return {
1423
1461
  data: result,
1424
1462
  ...(meta ? { meta } : {}),
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "2.2.0-beta.55",
2
+ "version": "2.2.0-beta.57",
3
3
  "name": "@apifuse/provider-sdk",
4
4
  "private": false,
5
5
  "type": "module",
@@ -0,0 +1,3 @@
1
+ import { makeRegistry } from "./operations/registry";
2
+
3
+ export default buildProvider({ operations: makeRegistry({ publicOnly: true }) });
@@ -0,0 +1,6 @@
1
+ export const firstOperation = defineOperation<ProviderContext>()({
2
+ annotations: { readOnly: true },
3
+ input: FirstInputSchema,
4
+ output: FirstOutputSchema,
5
+ handler: firstHandler,
6
+ });
@@ -0,0 +1,6 @@
1
+ export const secondOperation = defineOperation<ProviderContext>()({
2
+ annotations: { readOnly: true },
3
+ input: SecondInputSchema,
4
+ output: SecondOutputSchema,
5
+ handler: secondHandler,
6
+ });
@@ -0,0 +1,14 @@
1
+ import { makeRegistry } from "./operations/registry";
2
+
3
+ const literalOperation = defineOperation<ProviderContext>()({
4
+ annotations: { readOnly: true },
5
+ input: LiteralInputSchema,
6
+ output: LiteralOutputSchema,
7
+ handler: literalHandler,
8
+ });
9
+
10
+ export const literalProvider = buildProvider({
11
+ operations: { literal: literalOperation },
12
+ });
13
+
14
+ export default buildProvider({ operations: makeRegistry({ publicOnly: true }) });
@@ -0,0 +1,3 @@
1
+ export function makeRegistry(_options: { publicOnly: boolean }) {
2
+ return {};
3
+ }
@@ -141,6 +141,8 @@ type RepositoryMigrationContext = {
141
141
  readonly operationSites?: ReadonlyMap<number, string>;
142
142
  readonly excludedBindings?: ReadonlySet<string>;
143
143
  readonly staticObjectResolver?: StaticObjectResolver;
144
+ readonly runtimeComposedInitializers?: ReadonlySet<number>;
145
+ readonly recordDiscoveredSites?: (count: number) => void;
144
146
  };
145
147
 
146
148
  type OperationSite = {
@@ -194,7 +196,9 @@ function migrateOperationDeclarationInternal(
194
196
  options.operationIds,
195
197
  context.operationSites,
196
198
  context.excludedBindings,
199
+ context.runtimeComposedInitializers,
197
200
  );
201
+ context.recordDiscoveredSites?.(discovery.discoveredCount);
198
202
  if (discovery.refusals.length > 0) {
199
203
  return { status: "refused", refusals: discovery.refusals };
200
204
  }
@@ -1047,18 +1051,27 @@ function discoverOperationSites(
1047
1051
  operationIds: ReadonlyMap<string, string> | undefined,
1048
1052
  operationSites: ReadonlyMap<number, string> | undefined,
1049
1053
  excludedBindings: ReadonlySet<string> | undefined,
1054
+ runtimeComposedInitializers: ReadonlySet<number> | undefined,
1050
1055
  ): {
1051
1056
  readonly sites: OperationSite[];
1057
+ readonly discoveredCount: number;
1052
1058
  readonly refusals: OperationDeclarationRefusal[];
1053
1059
  } {
1054
1060
  const sitesByStart = new Map<number, OperationSite>();
1061
+ const discoveredStarts = new Set<number>();
1055
1062
  const localIds = new Map(operationIds ?? []);
1056
1063
  const localExcludedBindings = new Set(excludedBindings ?? []);
1057
1064
  const refusals: OperationDeclarationRefusal[] = [];
1058
1065
  const operationFactories = collectSimpleOperationFactories(source);
1059
1066
  const factoryCallIds = new Map<string, Set<string>>();
1060
1067
 
1061
- for (const map of collectOperationsMaps(source, constObjects, fileName, refusals)) {
1068
+ for (const map of collectOperationsMaps(
1069
+ source,
1070
+ constObjects,
1071
+ fileName,
1072
+ refusals,
1073
+ runtimeComposedInitializers,
1074
+ )) {
1062
1075
  for (const property of map.properties) {
1063
1076
  if (ts.isSpreadAssignment(property)) continue;
1064
1077
  const key = staticPropertyName(property.name);
@@ -1145,12 +1158,15 @@ function discoverOperationSites(
1145
1158
  if (ts.isCallExpression(node) && isOperationHelperCall(node)) {
1146
1159
  const argument = operationArgument(node);
1147
1160
  const bindingName = enclosingBindingName(node);
1161
+ const unwrappedArgument = unwrapExpression(argument);
1162
+ if (unwrappedArgument !== undefined && ts.isObjectLiteralExpression(unwrappedArgument)) {
1163
+ discoveredStarts.add(unwrappedArgument.getStart(source));
1164
+ }
1148
1165
  if (bindingName !== undefined && localExcludedBindings.has(bindingName)) return;
1149
1166
  const operationKey =
1150
1167
  (bindingName === undefined ? undefined : localIds.get(bindingName)) ??
1151
1168
  bindingName ??
1152
1169
  "<anonymous>";
1153
- const unwrappedArgument = unwrapExpression(argument);
1154
1170
  if (unwrappedArgument === undefined || !ts.isObjectLiteralExpression(unwrappedArgument)) {
1155
1171
  refusals.push(
1156
1172
  refusal(
@@ -1181,10 +1197,12 @@ function discoverOperationSites(
1181
1197
  ts.forEachChild(node, visit);
1182
1198
  };
1183
1199
  visit(source);
1200
+ for (const start of sitesByStart.keys()) discoveredStarts.add(start);
1184
1201
  return {
1185
1202
  sites: [...sitesByStart.values()].sort(
1186
1203
  (left, right) => left.object.getStart(source) - right.object.getStart(source),
1187
1204
  ),
1205
+ discoveredCount: discoveredStarts.size,
1188
1206
  refusals,
1189
1207
  };
1190
1208
  }
@@ -1223,6 +1241,7 @@ function collectOperationsMaps(
1223
1241
  constObjects: ReadonlyMap<string, TS.ObjectLiteralExpression>,
1224
1242
  fileName: string,
1225
1243
  refusals: OperationDeclarationRefusal[],
1244
+ runtimeComposedInitializers?: ReadonlySet<number>,
1226
1245
  ): TS.ObjectLiteralExpression[] {
1227
1246
  const maps = new Map<number, TS.ObjectLiteralExpression>();
1228
1247
  const inspect = (expression: TS.Expression, label: string): void => {
@@ -1238,6 +1257,7 @@ function collectOperationsMaps(
1238
1257
  return;
1239
1258
  }
1240
1259
  if (ts.isCallExpression(unwrapped)) {
1260
+ if (runtimeComposedInitializers?.has(expression.getStart(source)) === true) return;
1241
1261
  refusals.push(
1242
1262
  refusal(
1243
1263
  fileName,
@@ -1893,6 +1913,7 @@ export type OperationDeclarationRepositoryResult =
1893
1913
  readonly providerRoot: string;
1894
1914
  readonly changedFiles: readonly string[];
1895
1915
  readonly operationCount: number;
1916
+ readonly notes: readonly OperationDeclarationNote[];
1896
1917
  readonly sidecar?: string;
1897
1918
  readonly localeTodoCount: number;
1898
1919
  }
@@ -1902,10 +1923,17 @@ export type OperationDeclarationRepositoryResult =
1902
1923
  readonly refusals: readonly OperationDeclarationRefusal[];
1903
1924
  /** Operations that were independently migratable before repository-atomic refusal. */
1904
1925
  readonly operationCount: number;
1926
+ readonly notes: readonly OperationDeclarationNote[];
1905
1927
  readonly changedFiles: readonly string[];
1906
1928
  readonly localeTodoCount: number;
1907
1929
  };
1908
1930
 
1931
+ export type OperationDeclarationNote = {
1932
+ readonly code: "runtime_composed_registry";
1933
+ readonly path: string;
1934
+ readonly initializer: string;
1935
+ };
1936
+
1909
1937
  /** Run the file transform repository-wide, committing writes only if every file is provable. */
1910
1938
  export function migrateOperationDeclarationRepository(
1911
1939
  providerRootInput: string,
@@ -1920,6 +1948,7 @@ export function migrateOperationDeclarationRepository(
1920
1948
  const todos: LocaleTodo[] = [];
1921
1949
  const refusals: OperationDeclarationRefusal[] = [...repositoryIndex.refusals];
1922
1950
  let operationCount = 0;
1951
+ let repositoryDiscoveredCount = 0;
1923
1952
 
1924
1953
  for (const sourcePath of sourceFiles) {
1925
1954
  const relativePath = slash(relative(providerRoot, sourcePath));
@@ -1934,6 +1963,10 @@ export function migrateOperationDeclarationRepository(
1934
1963
  operationSites: repositoryIndex.operationSites.get(sourcePath),
1935
1964
  excludedBindings: repositoryIndex.excludedBindings.get(sourcePath),
1936
1965
  staticObjectResolver: repositoryIndex.staticObjectResolverFor(sourcePath),
1966
+ runtimeComposedInitializers: repositoryIndex.runtimeComposedInitializers.get(sourcePath),
1967
+ recordDiscoveredSites: (count) => {
1968
+ repositoryDiscoveredCount += count;
1969
+ },
1937
1970
  },
1938
1971
  );
1939
1972
  if (result.status === "refused") {
@@ -1947,7 +1980,21 @@ export function migrateOperationDeclarationRepository(
1947
1980
  todos.push(...result.localeTodos);
1948
1981
  }
1949
1982
  }
1950
- if (repositoryIndex.declarations.length > 0 && repositoryIndex.discoveredCount === 0) {
1983
+ const notes: OperationDeclarationNote[] =
1984
+ repositoryDiscoveredCount === 0
1985
+ ? []
1986
+ : repositoryIndex.declarations.flatMap((declaration) =>
1987
+ declaration.runtimeInitializer === undefined
1988
+ ? []
1989
+ : [
1990
+ {
1991
+ code: "runtime_composed_registry" as const,
1992
+ path: slash(relative(providerRoot, declaration.path)),
1993
+ initializer: declaration.runtimeInitializer,
1994
+ },
1995
+ ],
1996
+ );
1997
+ if (repositoryIndex.declarations.length > 0 && repositoryDiscoveredCount === 0) {
1951
1998
  for (const declaration of repositoryIndex.declarations) {
1952
1999
  refusals.push(
1953
2000
  refusal(
@@ -1970,6 +2017,7 @@ export function migrateOperationDeclarationRepository(
1970
2017
  providerRoot,
1971
2018
  refusals,
1972
2019
  operationCount,
2020
+ notes,
1973
2021
  changedFiles,
1974
2022
  localeTodoCount: todos.length,
1975
2023
  };
@@ -1984,6 +2032,7 @@ export function migrateOperationDeclarationRepository(
1984
2032
  providerRoot,
1985
2033
  changedFiles: [],
1986
2034
  operationCount,
2035
+ notes,
1987
2036
  localeTodoCount: 0,
1988
2037
  };
1989
2038
  }
@@ -2000,6 +2049,7 @@ export function migrateOperationDeclarationRepository(
2000
2049
  providerRoot,
2001
2050
  changedFiles,
2002
2051
  operationCount,
2052
+ notes,
2003
2053
  sidecar,
2004
2054
  localeTodoCount: todos.length,
2005
2055
  };
@@ -2180,15 +2230,16 @@ type ProviderOperationsDeclaration = {
2180
2230
  readonly path: string;
2181
2231
  readonly construct: string;
2182
2232
  readonly initializer: TS.Expression;
2233
+ readonly runtimeInitializer?: string;
2183
2234
  };
2184
2235
 
2185
2236
  type RepositoryOperationIndex = {
2186
2237
  readonly operationIds: Map<string, Map<string, string>>;
2187
2238
  readonly operationSites: Map<string, Map<number, string>>;
2188
2239
  readonly excludedBindings: Map<string, Set<string>>;
2240
+ readonly runtimeComposedInitializers: Map<string, Set<number>>;
2189
2241
  readonly refusals: OperationDeclarationRefusal[];
2190
2242
  readonly declarations: ProviderOperationsDeclaration[];
2191
- readonly discoveredCount: number;
2192
2243
  readonly staticObjectResolverFor: (path: string) => StaticObjectResolver;
2193
2244
  };
2194
2245
 
@@ -2205,12 +2256,12 @@ function buildRepositoryOperationIndex(
2205
2256
  const operationIds = buildOperationIdIndex(sourceFiles);
2206
2257
  const operationSites = new Map<string, Map<number, string>>();
2207
2258
  const excludedBindings = new Map<string, Set<string>>();
2259
+ const runtimeComposedInitializers = new Map<string, Set<number>>();
2208
2260
  const refusals: OperationDeclarationRefusal[] = [];
2209
2261
  const declarations: ProviderOperationsDeclaration[] = [];
2210
2262
  const indexedProviderProperties = new Set<string>();
2211
2263
  const factoryIds = new Map<string, { path: string; name: string; ids: Set<string> }>();
2212
2264
  const bindingCandidates = new Map<string, { path: string; name: string; ids: Set<string> }>();
2213
- let discoveredCount = 0;
2214
2265
 
2215
2266
  const relativePath = (path: string): string => slash(relative(providerRoot, path));
2216
2267
  const resolutionRefusal = (path: string, operationKey: string, detail: string): void => {
@@ -2489,7 +2540,6 @@ function buildRepositoryOperationIndex(
2489
2540
  }
2490
2541
  sites.set(start, operationId);
2491
2542
  operationSites.set(path, sites);
2492
- discoveredCount += 1;
2493
2543
  };
2494
2544
 
2495
2545
  const classifyEntry = (entry: RegistryEntry): void => {
@@ -2543,7 +2593,6 @@ function buildRepositoryOperationIndex(
2543
2593
  };
2544
2594
  factory.ids.add(entry.operationId);
2545
2595
  factoryIds.set(key, factory);
2546
- discoveredCount += 1;
2547
2596
  return;
2548
2597
  }
2549
2598
  resolutionRefusal(
@@ -2562,10 +2611,26 @@ function buildRepositoryOperationIndex(
2562
2611
  const key = `${path}\0${node.getStart(source)}`;
2563
2612
  if (indexedProviderProperties.has(key)) return;
2564
2613
  indexedProviderProperties.add(key);
2565
- declarations.push({ path, construct, initializer: node.initializer });
2614
+ const resolvedInitializer = resolveLocatedExpression(
2615
+ { path, source, expression: node.initializer },
2616
+ new Set(),
2617
+ );
2618
+ let runtimeInitializer: string | undefined;
2619
+ if (resolvedInitializer.status === "resolved") {
2620
+ const resolvedExpression = unwrapExpression(resolvedInitializer.value.expression);
2621
+ if (resolvedExpression !== undefined && ts.isCallExpression(resolvedExpression)) {
2622
+ runtimeInitializer = resolvedExpression.getText(resolvedInitializer.value.source);
2623
+ const initializers = runtimeComposedInitializers.get(path) ?? new Set<number>();
2624
+ initializers.add(node.initializer.getStart(source));
2625
+ runtimeComposedInitializers.set(path, initializers);
2626
+ }
2627
+ }
2628
+ declarations.push({ path, construct, initializer: node.initializer, runtimeInitializer });
2566
2629
  const flattened = flattenRegistry({ path, source, expression: node.initializer }, new Set());
2567
2630
  if ("detail" in flattened) {
2568
- resolutionRefusal(path, "<operations>", flattened.detail);
2631
+ if (runtimeInitializer === undefined) {
2632
+ resolutionRefusal(path, "<operations>", flattened.detail);
2633
+ }
2569
2634
  } else {
2570
2635
  for (const entry of flattened.entries.values()) classifyEntry(entry);
2571
2636
  }
@@ -2691,9 +2756,9 @@ function buildRepositoryOperationIndex(
2691
2756
  operationIds,
2692
2757
  operationSites,
2693
2758
  excludedBindings,
2759
+ runtimeComposedInitializers,
2694
2760
  refusals,
2695
2761
  declarations,
2696
- discoveredCount,
2697
2762
  staticObjectResolverFor: (currentPath) => (expression, source) =>
2698
2763
  resolveStaticObject(expression, sources.has(source.fileName) ? source.fileName : currentPath),
2699
2764
  };
package/src/index.ts CHANGED
@@ -181,10 +181,23 @@ export {
181
181
  export type { PrevalidateResult } from "./runtime/prevalidate.js";
182
182
  export { getProviderBaseUrl } from "./runtime/provider.js";
183
183
  export type {
184
+ ProxyTelemetryHeaderPayload,
185
+ ProxyHash,
184
186
  ProxyTelemetryLogPayload,
185
187
  ProxyTelemetryResolvedPayload,
186
188
  ProxyTelemetryUnresolvedPayload,
187
189
  } from "./runtime/proxy-telemetry.js";
190
+ export {
191
+ RequestTelemetry,
192
+ closedEnum,
193
+ type ClosedEnum,
194
+ type GatewayIngestible,
195
+ type RequestTelemetryLogPayload,
196
+ type SpanIndex,
197
+ type TelemetryContributor,
198
+ type TelemetryKey,
199
+ type TenantNeutral,
200
+ } from "./runtime/request-telemetry.js";
188
201
  export {
189
202
  APIFUSE__CDP_POOL__URL,
190
203
  APIFUSE__RESOLVER__2CAPTCHA__API_KEY,