@apifuse/provider-sdk 2.2.0-beta.54 → 2.2.0-beta.56
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -0
- package/bin/apifuse-pack-types.ts +121 -0
- package/dist/cli/migrate-operation-declaration.d.ts +5 -1
- package/dist/cli/migrate-operation-declaration.js +645 -46
- package/dist/index.d.ts +2 -1
- package/dist/index.js +1 -0
- package/dist/runtime/proxy-telemetry.d.ts +53 -2
- package/dist/runtime/proxy-telemetry.js +106 -65
- package/dist/runtime/request-telemetry.d.ts +70 -0
- package/dist/runtime/request-telemetry.js +228 -0
- package/dist/server/index.d.ts +3 -1
- package/dist/server/index.js +1 -0
- package/dist/server/serve-implementation.js +58 -20
- package/package.json +1 -1
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-ambiguous-a.ts.txt +3 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-ambiguous-b.ts.txt +3 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-ambiguous-barrel.ts.txt +2 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-ambiguous-index.ts.txt +3 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-computed.ts.txt +6 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-cycle-a.ts.txt +1 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-cycle-b.ts.txt +1 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-cycle-index.ts.txt +3 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-daiso-barrel.ts.txt +7 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-daiso-catalog.ts.txt +19 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-daiso-docs.ts.txt +6 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-daiso-index.ts.txt +3 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-daiso-stores.ts.txt +8 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-indirect-config.ts.txt +5 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-nonstatic.ts.txt +4 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-package-index.ts.txt +3 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-reexport-index.ts.txt +3 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-reexport-leaf.ts.txt +10 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-reexport-one.ts.txt +1 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-reexport-two.ts.txt +1 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-star-package-barrel.ts.txt +2 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-star-package-index.ts.txt +3 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-star-package-leaf.ts.txt +3 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/factory-duplicate-provider.ts.txt +11 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/factory-id-unresolved.ts.txt +7 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/factory-one-to-many.ts.txt +18 -0
- package/src/cli/__tests__/fixtures/migrate-operation-declaration/factory-one-to-one.ts.txt +13 -0
- package/src/cli/migrate-operation-declaration.ts +844 -49
- package/src/index.ts +13 -0
- package/src/runtime/proxy-telemetry.ts +160 -74
- package/src/runtime/request-telemetry.ts +376 -0
- package/src/server/index.ts +14 -0
- package/src/server/serve-implementation.ts +93 -21
|
@@ -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.
|
|
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.
|
|
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.
|
|
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.
|
|
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,
|
|
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
|
|
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
|
-
...(
|
|
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,
|
|
1097
|
-
const
|
|
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
|
-
...(
|
|
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 =
|
|
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
|
-
|
|
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,
|
|
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,
|
|
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
|
-
...(
|
|
1448
|
+
...(cache
|
|
1413
1449
|
? {
|
|
1414
|
-
cached:
|
|
1415
|
-
stale:
|
|
1416
|
-
cache
|
|
1450
|
+
cached: cache.hit,
|
|
1451
|
+
stale: cache.stale,
|
|
1452
|
+
cache,
|
|
1417
1453
|
}
|
|
1418
1454
|
: {}),
|
|
1419
|
-
...(
|
|
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
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { registry } from "./cycle-b";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { registry } from "./cycle-a";
|
package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-daiso-catalog.ts.txt
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { OPERATION_DOCS } from "./docs";
|
|
2
|
+
|
|
3
|
+
export const catalogOperations = {
|
|
4
|
+
"browse-catalog": {
|
|
5
|
+
docs: { ...OPERATION_DOCS.catalog },
|
|
6
|
+
descriptionKey: "operations.browseCatalog.description",
|
|
7
|
+
annotations: { readOnly: true },
|
|
8
|
+
inputExamples: [{ scenario: "Browse the catalog", input: {} }],
|
|
9
|
+
input: InputSchema,
|
|
10
|
+
output: OutputSchema,
|
|
11
|
+
handler,
|
|
12
|
+
},
|
|
13
|
+
"search-products": {
|
|
14
|
+
annotations: { readOnly: true },
|
|
15
|
+
input: InputSchema,
|
|
16
|
+
output: OutputSchema,
|
|
17
|
+
handler,
|
|
18
|
+
},
|
|
19
|
+
};
|
package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-reexport-one.ts.txt
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { registry } from "./barrel-two.js";
|
package/src/cli/__tests__/fixtures/migrate-operation-declaration/discovery-reexport-two.ts.txt
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { registry } from "./leaf";
|
package/src/cli/__tests__/fixtures/migrate-operation-declaration/factory-duplicate-provider.ts.txt
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
function makePingOperation() {
|
|
2
|
+
return defineOperation<ProviderContext>()({
|
|
3
|
+
annotations: { readOnly: true },
|
|
4
|
+
input: InputSchema,
|
|
5
|
+
output: OutputSchema,
|
|
6
|
+
handler,
|
|
7
|
+
});
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export const first = buildProvider({ operations: { ping: makePingOperation() } });
|
|
11
|
+
export default buildProvider({ operations: { ping: makePingOperation() } });
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
function makeSearchOperation(kind: string) {
|
|
2
|
+
return defineOperation<ProviderContext>()({
|
|
3
|
+
annotations: { readOnly: true },
|
|
4
|
+
inputExamples: [{ scenario: "Search items", input: { kind } }],
|
|
5
|
+
input: InputSchema,
|
|
6
|
+
output: OutputSchema,
|
|
7
|
+
handler,
|
|
8
|
+
});
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export default buildProvider({
|
|
12
|
+
operations: {
|
|
13
|
+
"used-goods-search": makeSearchOperation("used"),
|
|
14
|
+
"realty-search-listings": makeSearchOperation("realty"),
|
|
15
|
+
"jobs-search": makeSearchOperation("jobs"),
|
|
16
|
+
"cars-search": makeSearchOperation("cars"),
|
|
17
|
+
},
|
|
18
|
+
});
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
function makeSearchOperation(kind: string) {
|
|
2
|
+
return defineOperation<ProviderContext>()({
|
|
3
|
+
annotations: { readOnly: true },
|
|
4
|
+
inputExamples: [{ scenario: "Search items", input: { kind } }],
|
|
5
|
+
input: InputSchema,
|
|
6
|
+
output: OutputSchema,
|
|
7
|
+
handler,
|
|
8
|
+
});
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export default buildProvider({
|
|
12
|
+
operations: { "search-items": makeSearchOperation("items") },
|
|
13
|
+
});
|