@apifuse/provider-sdk 2.1.0-beta.5 → 2.1.0-beta.8
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 +16 -0
- package/README.md +2 -2
- package/SUBMISSION.md +2 -1
- package/bin/apifuse-check.ts +60 -6
- package/bin/apifuse-dev.ts +48 -5
- package/bin/apifuse-perf.ts +50 -11
- package/bin/apifuse-record.ts +35 -11
- package/bin/apifuse-submit-check.ts +1425 -3
- package/dist/ceremonies/index.d.ts +41 -0
- package/dist/ceremonies/index.js +490 -0
- package/dist/choice-token.d.ts +24 -0
- package/dist/choice-token.js +74 -0
- package/dist/cli/commands.d.ts +10 -0
- package/dist/cli/commands.js +80 -0
- package/dist/cli/create.d.ts +47 -0
- package/dist/cli/create.js +762 -0
- package/dist/config/loader.d.ts +107 -0
- package/dist/config/loader.js +935 -0
- package/dist/contract-json.d.ts +9 -0
- package/dist/contract-json.js +51 -0
- package/dist/contract-serialization.d.ts +4 -0
- package/dist/contract-serialization.js +78 -0
- package/dist/contract-types.d.ts +49 -0
- package/dist/contract-types.js +1 -0
- package/dist/contract.d.ts +6 -0
- package/dist/contract.js +155 -0
- package/dist/define.d.ts +97 -0
- package/dist/define.js +1320 -0
- package/dist/dev.d.ts +9 -0
- package/dist/dev.js +15 -0
- package/dist/errors.d.ts +59 -0
- package/dist/errors.js +97 -0
- package/dist/i18n/catalog.d.ts +29 -0
- package/dist/i18n/catalog.js +159 -0
- package/dist/i18n/index.d.ts +2 -0
- package/dist/i18n/index.js +2 -0
- package/dist/i18n/keys.d.ts +10 -0
- package/dist/i18n/keys.js +34 -0
- package/dist/index.d.ts +41 -0
- package/dist/index.js +37 -0
- package/dist/lint.d.ts +73 -0
- package/dist/lint.js +702 -0
- package/dist/observability.d.ts +5 -0
- package/dist/observability.js +39 -0
- package/dist/provider.d.ts +9 -0
- package/dist/provider.js +8 -0
- package/dist/public-schema-field-lint.d.ts +2 -0
- package/dist/public-schema-field-lint.js +158 -0
- package/dist/recipes/gov-api.d.ts +19 -0
- package/dist/recipes/gov-api.js +72 -0
- package/dist/recipes/rest-api.d.ts +21 -0
- package/dist/recipes/rest-api.js +115 -0
- package/dist/runtime/auth-flow.d.ts +14 -0
- package/dist/runtime/auth-flow.js +44 -0
- package/dist/runtime/browser.d.ts +25 -0
- package/dist/runtime/browser.js +1034 -0
- package/dist/runtime/cache.d.ts +10 -0
- package/dist/runtime/cache.js +372 -0
- package/dist/runtime/choice.d.ts +15 -0
- package/dist/runtime/choice.js +435 -0
- package/dist/runtime/credential.d.ts +8 -0
- package/dist/runtime/credential.js +61 -0
- package/dist/runtime/env.d.ts +2 -0
- package/dist/runtime/env.js +10 -0
- package/dist/runtime/executor.d.ts +16 -0
- package/dist/runtime/executor.js +51 -0
- package/dist/runtime/http.d.ts +8 -0
- package/dist/runtime/http.js +706 -0
- package/dist/runtime/insights.d.ts +9 -0
- package/dist/runtime/insights.js +324 -0
- package/dist/runtime/instrumentation.d.ts +8 -0
- package/dist/runtime/instrumentation.js +269 -0
- package/dist/runtime/key-derivation.d.ts +24 -0
- package/dist/runtime/key-derivation.js +73 -0
- package/dist/runtime/keyring.d.ts +25 -0
- package/dist/runtime/keyring.js +93 -0
- package/dist/runtime/namespace.d.ts +9 -0
- package/dist/runtime/namespace.js +19 -0
- package/dist/runtime/otlp.d.ts +39 -0
- package/dist/runtime/otlp.js +103 -0
- package/dist/runtime/perf.d.ts +12 -0
- package/dist/runtime/perf.js +52 -0
- package/dist/runtime/prevalidate.d.ts +12 -0
- package/dist/runtime/prevalidate.js +173 -0
- package/dist/runtime/provider.d.ts +2 -0
- package/dist/runtime/provider.js +11 -0
- package/dist/runtime/proxy-errors.d.ts +21 -0
- package/dist/runtime/proxy-errors.js +83 -0
- package/dist/runtime/proxy-telemetry.d.ts +8 -0
- package/dist/runtime/proxy-telemetry.js +174 -0
- package/dist/runtime/redis.d.ts +17 -0
- package/dist/runtime/redis.js +82 -0
- package/dist/runtime/request-options.d.ts +3 -0
- package/dist/runtime/request-options.js +42 -0
- package/dist/runtime/state.d.ts +17 -0
- package/dist/runtime/state.js +344 -0
- package/dist/runtime/stealth.d.ts +18 -0
- package/dist/runtime/stealth.js +827 -0
- package/dist/runtime/stt.d.ts +22 -0
- package/dist/runtime/stt.js +480 -0
- package/dist/runtime/trace.d.ts +26 -0
- package/dist/runtime/trace.js +142 -0
- package/dist/runtime/waterfall.d.ts +12 -0
- package/dist/runtime/waterfall.js +147 -0
- package/dist/schema.d.ts +74 -0
- package/dist/schema.js +243 -0
- package/dist/serve.d.ts +1 -0
- package/dist/serve.js +1 -0
- package/dist/server/index.d.ts +3 -0
- package/dist/server/index.js +2 -0
- package/dist/server/serve.d.ts +64 -0
- package/dist/server/serve.js +1110 -0
- package/dist/server/types.d.ts +136 -0
- package/dist/server/types.js +86 -0
- package/dist/stealth/profiles.d.ts +4 -0
- package/dist/stealth/profiles.js +259 -0
- package/dist/stream.d.ts +44 -0
- package/dist/stream.js +151 -0
- package/dist/testing/helpers.d.ts +23 -0
- package/dist/testing/helpers.js +95 -0
- package/dist/testing/index.d.ts +2 -0
- package/dist/testing/index.js +2 -0
- package/dist/testing/run.d.ts +34 -0
- package/dist/testing/run.js +303 -0
- package/dist/types.d.ts +1324 -0
- package/dist/types.js +61 -0
- package/dist/utils/date.d.ts +6 -0
- package/dist/utils/date.js +101 -0
- package/dist/utils/parse.d.ts +16 -0
- package/dist/utils/parse.js +51 -0
- package/dist/utils/text.d.ts +4 -0
- package/dist/utils/text.js +14 -0
- package/dist/utils/transform.d.ts +8 -0
- package/dist/utils/transform.js +48 -0
- package/package.json +42 -25
- package/src/ceremonies/index.ts +8 -2
- package/src/choice-token.ts +1 -0
- package/src/cli/commands.ts +8 -5
- package/src/cli/create.ts +28 -0
- package/src/cli/templates/provider/operations/ping.ts.tpl +3 -2
- package/src/cli/templates/provider/schemas/ping.ts.tpl +8 -0
- package/src/config/loader.ts +19 -1
- package/src/contract-json.ts +75 -0
- package/src/contract-serialization.ts +89 -0
- package/src/contract-types.ts +52 -0
- package/src/contract.ts +215 -0
- package/src/define.ts +37 -2
- package/src/errors.ts +15 -0
- package/src/i18n/catalog.ts +156 -0
- package/src/index.ts +22 -1
- package/src/lint.ts +256 -37
- package/src/provider.ts +45 -2
- package/src/runtime/browser.ts +685 -30
- package/src/runtime/cache.ts +35 -89
- package/src/runtime/choice.ts +760 -0
- package/src/runtime/executor.ts +19 -2
- package/src/runtime/redis.ts +116 -0
- package/src/runtime/state.ts +487 -0
- package/src/runtime/stealth.ts +8 -1
- package/src/server/serve.ts +361 -46
- package/src/server/types.ts +2 -0
- package/src/testing/run.ts +16 -3
- package/src/types.ts +209 -6
package/src/runtime/cache.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
2
|
|
|
3
|
-
import
|
|
4
|
-
|
|
3
|
+
import { providerCacheRedisUrlFromEnv } from "../config/loader";
|
|
5
4
|
import type {
|
|
6
5
|
ProviderCache,
|
|
7
6
|
ProviderCacheGetOrSetOptions,
|
|
@@ -10,6 +9,12 @@ import type {
|
|
|
10
9
|
ProviderCacheResponseMeta,
|
|
11
10
|
ProviderCacheResult,
|
|
12
11
|
} from "../types";
|
|
12
|
+
import {
|
|
13
|
+
createProviderRedisClient,
|
|
14
|
+
ensureRedisReady,
|
|
15
|
+
type ProviderRedisClient,
|
|
16
|
+
withRedisTimeout,
|
|
17
|
+
} from "./redis";
|
|
13
18
|
|
|
14
19
|
type CacheSource = ProviderCacheLookupMeta["source"];
|
|
15
20
|
|
|
@@ -26,7 +31,7 @@ type MemoryEntry = CacheEnvelope & {
|
|
|
26
31
|
};
|
|
27
32
|
|
|
28
33
|
type SharedCacheBackend = {
|
|
29
|
-
redis?:
|
|
34
|
+
redis?: ProviderRedisClient;
|
|
30
35
|
memory: Map<string, MemoryEntry>;
|
|
31
36
|
inflight: Map<string, Promise<ProviderCacheResult<unknown>>>;
|
|
32
37
|
};
|
|
@@ -57,14 +62,6 @@ const SECRET_FIELD_NAMES = new Set([
|
|
|
57
62
|
|
|
58
63
|
const sharedBackends = new Map<string, SharedCacheBackend>();
|
|
59
64
|
|
|
60
|
-
function redisUrlFromEnv(): string | undefined {
|
|
61
|
-
return (
|
|
62
|
-
process.env.APIFUSE__PROVIDER__CACHE_REDIS_URL?.trim() ||
|
|
63
|
-
process.env.APIFUSE__REDIS__URL?.trim() ||
|
|
64
|
-
undefined
|
|
65
|
-
);
|
|
66
|
-
}
|
|
67
|
-
|
|
68
65
|
function backendKey(redisUrl: string | undefined): string {
|
|
69
66
|
return redisUrl ?? "memory";
|
|
70
67
|
}
|
|
@@ -80,15 +77,12 @@ function getSharedBackend(redisUrl: string | undefined): SharedCacheBackend {
|
|
|
80
77
|
};
|
|
81
78
|
|
|
82
79
|
if (redisUrl) {
|
|
83
|
-
const redis =
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
});
|
|
90
|
-
redis.on("error", () => {
|
|
91
|
-
// Fail-open: cache connectivity must never fail provider execution.
|
|
80
|
+
const redis = createProviderRedisClient({
|
|
81
|
+
redisUrl,
|
|
82
|
+
timeoutMs: DEFAULT_REDIS_TIMEOUT_MS,
|
|
83
|
+
onError: () => {
|
|
84
|
+
// Fail-open: cache connectivity must never fail provider execution.
|
|
85
|
+
},
|
|
92
86
|
});
|
|
93
87
|
backend.redis = redis;
|
|
94
88
|
}
|
|
@@ -202,77 +196,20 @@ function sourceSummary(
|
|
|
202
196
|
return "mixed";
|
|
203
197
|
}
|
|
204
198
|
|
|
205
|
-
async function
|
|
199
|
+
async function withRedisFallback<T>(
|
|
206
200
|
operation: () => Promise<T>,
|
|
207
201
|
): Promise<T | undefined> {
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
() => resolve(undefined),
|
|
213
|
-
DEFAULT_REDIS_TIMEOUT_MS,
|
|
214
|
-
);
|
|
215
|
-
});
|
|
216
|
-
return await Promise.race([operation().catch(() => undefined), timeout]);
|
|
217
|
-
} finally {
|
|
218
|
-
if (timeoutId) clearTimeout(timeoutId);
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
function redisStatus(redis: Redis): string {
|
|
223
|
-
return redis.status;
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
async function waitForRedisReady(redis: Redis): Promise<boolean> {
|
|
227
|
-
let timeoutId: ReturnType<typeof setTimeout> | undefined;
|
|
228
|
-
let settled = false;
|
|
229
|
-
|
|
230
|
-
return await new Promise<boolean>((resolve) => {
|
|
231
|
-
const cleanup = () => {
|
|
232
|
-
if (timeoutId) clearTimeout(timeoutId);
|
|
233
|
-
redis.off("ready", onReady);
|
|
234
|
-
redis.off("close", onUnavailable);
|
|
235
|
-
redis.off("end", onUnavailable);
|
|
236
|
-
redis.off("error", onUnavailable);
|
|
237
|
-
};
|
|
238
|
-
const finish = (ready: boolean) => {
|
|
239
|
-
if (settled) return;
|
|
240
|
-
settled = true;
|
|
241
|
-
cleanup();
|
|
242
|
-
resolve(ready);
|
|
243
|
-
};
|
|
244
|
-
const onReady = () => finish(true);
|
|
245
|
-
const onUnavailable = () => finish(false);
|
|
246
|
-
|
|
247
|
-
timeoutId = setTimeout(
|
|
248
|
-
() => finish(redisStatus(redis) === "ready"),
|
|
249
|
-
DEFAULT_REDIS_TIMEOUT_MS,
|
|
250
|
-
);
|
|
251
|
-
redis.once("ready", onReady);
|
|
252
|
-
redis.once("close", onUnavailable);
|
|
253
|
-
redis.once("end", onUnavailable);
|
|
254
|
-
redis.once("error", onUnavailable);
|
|
202
|
+
return await withRedisTimeout(operation, {
|
|
203
|
+
timeoutMs: DEFAULT_REDIS_TIMEOUT_MS,
|
|
204
|
+
onTimeout: () => undefined,
|
|
205
|
+
onError: () => undefined,
|
|
255
206
|
});
|
|
256
207
|
}
|
|
257
208
|
|
|
258
|
-
async function ensureRedisReady(redis: Redis): Promise<boolean> {
|
|
259
|
-
if (redisStatus(redis) === "ready") return true;
|
|
260
|
-
|
|
261
|
-
if (redisStatus(redis) === "wait" || redisStatus(redis) === "end") {
|
|
262
|
-
const connected = await withRedisTimeout(async () => {
|
|
263
|
-
await redis.connect();
|
|
264
|
-
return true;
|
|
265
|
-
});
|
|
266
|
-
return connected === true && redisStatus(redis) === "ready";
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
return await waitForRedisReady(redis);
|
|
270
|
-
}
|
|
271
|
-
|
|
272
209
|
export function createProviderCache(
|
|
273
210
|
options: ProviderCacheOptions,
|
|
274
211
|
): ProviderCache {
|
|
275
|
-
const redisUrl = options.redisUrl ??
|
|
212
|
+
const redisUrl = options.redisUrl ?? providerCacheRedisUrlFromEnv();
|
|
276
213
|
const backend = getSharedBackend(redisUrl);
|
|
277
214
|
const memoryMaxEntries = Math.max(
|
|
278
215
|
1,
|
|
@@ -333,9 +270,11 @@ export function createProviderCache(
|
|
|
333
270
|
result: ProviderCacheResult<T>;
|
|
334
271
|
} | null> {
|
|
335
272
|
const redis = backend.redis;
|
|
336
|
-
if (!redis || !(await ensureRedisReady(redis)))
|
|
273
|
+
if (!redis || !(await ensureRedisReady(redis, DEFAULT_REDIS_TIMEOUT_MS))) {
|
|
274
|
+
return null;
|
|
275
|
+
}
|
|
337
276
|
|
|
338
|
-
const raw = await
|
|
277
|
+
const raw = await withRedisFallback(async () => {
|
|
339
278
|
return await redis.get(key);
|
|
340
279
|
});
|
|
341
280
|
if (typeof raw !== "string" && raw !== null) return null;
|
|
@@ -410,8 +349,10 @@ export function createProviderCache(
|
|
|
410
349
|
rememberEnvelope(key, envelope, currentTime);
|
|
411
350
|
|
|
412
351
|
const redis = backend.redis;
|
|
413
|
-
if (!redis || !(await ensureRedisReady(redis)))
|
|
414
|
-
|
|
352
|
+
if (!redis || !(await ensureRedisReady(redis, DEFAULT_REDIS_TIMEOUT_MS))) {
|
|
353
|
+
return;
|
|
354
|
+
}
|
|
355
|
+
await withRedisFallback(() =>
|
|
415
356
|
redis.set(key, JSON.stringify(envelope), "PX", staleTtlMs),
|
|
416
357
|
);
|
|
417
358
|
}
|
|
@@ -464,8 +405,13 @@ export function createProviderCache(
|
|
|
464
405
|
async delete(key: string): Promise<void> {
|
|
465
406
|
backend.memory.delete(key);
|
|
466
407
|
const redis = backend.redis;
|
|
467
|
-
if (
|
|
468
|
-
|
|
408
|
+
if (
|
|
409
|
+
!redis ||
|
|
410
|
+
!(await ensureRedisReady(redis, DEFAULT_REDIS_TIMEOUT_MS))
|
|
411
|
+
) {
|
|
412
|
+
return;
|
|
413
|
+
}
|
|
414
|
+
await withRedisFallback(() => redis.del(key));
|
|
469
415
|
},
|
|
470
416
|
|
|
471
417
|
async getOrSet<T = unknown>(
|