@apifuse/provider-sdk 2.1.0-beta.6 → 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.
Files changed (128) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/dist/ceremonies/index.d.ts +41 -0
  3. package/dist/ceremonies/index.js +490 -0
  4. package/dist/choice-token.d.ts +24 -0
  5. package/dist/choice-token.js +74 -0
  6. package/dist/cli/commands.d.ts +10 -0
  7. package/dist/cli/commands.js +80 -0
  8. package/dist/cli/create.d.ts +47 -0
  9. package/dist/cli/create.js +762 -0
  10. package/dist/config/loader.d.ts +107 -0
  11. package/dist/config/loader.js +935 -0
  12. package/dist/contract-json.d.ts +9 -0
  13. package/dist/contract-json.js +51 -0
  14. package/dist/contract-serialization.d.ts +4 -0
  15. package/dist/contract-serialization.js +78 -0
  16. package/dist/contract-types.d.ts +49 -0
  17. package/dist/contract-types.js +1 -0
  18. package/dist/contract.d.ts +6 -0
  19. package/dist/contract.js +155 -0
  20. package/dist/define.d.ts +97 -0
  21. package/dist/define.js +1320 -0
  22. package/dist/dev.d.ts +9 -0
  23. package/dist/dev.js +15 -0
  24. package/dist/errors.d.ts +59 -0
  25. package/dist/errors.js +97 -0
  26. package/dist/i18n/catalog.d.ts +29 -0
  27. package/dist/i18n/catalog.js +159 -0
  28. package/dist/i18n/index.d.ts +2 -0
  29. package/dist/i18n/index.js +2 -0
  30. package/dist/i18n/keys.d.ts +10 -0
  31. package/dist/i18n/keys.js +34 -0
  32. package/dist/index.d.ts +41 -0
  33. package/dist/index.js +37 -0
  34. package/dist/lint.d.ts +73 -0
  35. package/dist/lint.js +702 -0
  36. package/dist/observability.d.ts +5 -0
  37. package/dist/observability.js +39 -0
  38. package/dist/provider.d.ts +9 -0
  39. package/dist/provider.js +8 -0
  40. package/dist/public-schema-field-lint.d.ts +2 -0
  41. package/dist/public-schema-field-lint.js +158 -0
  42. package/dist/recipes/gov-api.d.ts +19 -0
  43. package/dist/recipes/gov-api.js +72 -0
  44. package/dist/recipes/rest-api.d.ts +21 -0
  45. package/dist/recipes/rest-api.js +115 -0
  46. package/dist/runtime/auth-flow.d.ts +14 -0
  47. package/dist/runtime/auth-flow.js +44 -0
  48. package/dist/runtime/browser.d.ts +25 -0
  49. package/dist/runtime/browser.js +1034 -0
  50. package/dist/runtime/cache.d.ts +10 -0
  51. package/dist/runtime/cache.js +372 -0
  52. package/dist/runtime/choice.d.ts +15 -0
  53. package/dist/runtime/choice.js +435 -0
  54. package/dist/runtime/credential.d.ts +8 -0
  55. package/dist/runtime/credential.js +61 -0
  56. package/dist/runtime/env.d.ts +2 -0
  57. package/dist/runtime/env.js +10 -0
  58. package/dist/runtime/executor.d.ts +16 -0
  59. package/dist/runtime/executor.js +51 -0
  60. package/dist/runtime/http.d.ts +8 -0
  61. package/dist/runtime/http.js +706 -0
  62. package/dist/runtime/insights.d.ts +9 -0
  63. package/dist/runtime/insights.js +324 -0
  64. package/dist/runtime/instrumentation.d.ts +8 -0
  65. package/dist/runtime/instrumentation.js +269 -0
  66. package/dist/runtime/key-derivation.d.ts +24 -0
  67. package/dist/runtime/key-derivation.js +73 -0
  68. package/dist/runtime/keyring.d.ts +25 -0
  69. package/dist/runtime/keyring.js +93 -0
  70. package/dist/runtime/namespace.d.ts +9 -0
  71. package/dist/runtime/namespace.js +19 -0
  72. package/dist/runtime/otlp.d.ts +39 -0
  73. package/dist/runtime/otlp.js +103 -0
  74. package/dist/runtime/perf.d.ts +12 -0
  75. package/dist/runtime/perf.js +52 -0
  76. package/dist/runtime/prevalidate.d.ts +12 -0
  77. package/dist/runtime/prevalidate.js +173 -0
  78. package/dist/runtime/provider.d.ts +2 -0
  79. package/dist/runtime/provider.js +11 -0
  80. package/dist/runtime/proxy-errors.d.ts +21 -0
  81. package/dist/runtime/proxy-errors.js +83 -0
  82. package/dist/runtime/proxy-telemetry.d.ts +8 -0
  83. package/dist/runtime/proxy-telemetry.js +174 -0
  84. package/dist/runtime/redis.d.ts +17 -0
  85. package/dist/runtime/redis.js +82 -0
  86. package/dist/runtime/request-options.d.ts +3 -0
  87. package/dist/runtime/request-options.js +42 -0
  88. package/dist/runtime/state.d.ts +17 -0
  89. package/dist/runtime/state.js +344 -0
  90. package/dist/runtime/stealth.d.ts +18 -0
  91. package/dist/runtime/stealth.js +827 -0
  92. package/dist/runtime/stt.d.ts +22 -0
  93. package/dist/runtime/stt.js +480 -0
  94. package/dist/runtime/trace.d.ts +26 -0
  95. package/dist/runtime/trace.js +142 -0
  96. package/dist/runtime/waterfall.d.ts +12 -0
  97. package/dist/runtime/waterfall.js +147 -0
  98. package/dist/schema.d.ts +74 -0
  99. package/dist/schema.js +243 -0
  100. package/dist/serve.d.ts +1 -0
  101. package/dist/serve.js +1 -0
  102. package/dist/server/index.d.ts +3 -0
  103. package/dist/server/index.js +2 -0
  104. package/dist/server/serve.d.ts +64 -0
  105. package/dist/server/serve.js +1110 -0
  106. package/dist/server/types.d.ts +136 -0
  107. package/dist/server/types.js +86 -0
  108. package/dist/stealth/profiles.d.ts +4 -0
  109. package/dist/stealth/profiles.js +259 -0
  110. package/dist/stream.d.ts +44 -0
  111. package/dist/stream.js +151 -0
  112. package/dist/testing/helpers.d.ts +23 -0
  113. package/dist/testing/helpers.js +95 -0
  114. package/dist/testing/index.d.ts +2 -0
  115. package/dist/testing/index.js +2 -0
  116. package/dist/testing/run.d.ts +34 -0
  117. package/dist/testing/run.js +303 -0
  118. package/dist/types.d.ts +1324 -0
  119. package/dist/types.js +61 -0
  120. package/dist/utils/date.d.ts +6 -0
  121. package/dist/utils/date.js +101 -0
  122. package/dist/utils/parse.d.ts +16 -0
  123. package/dist/utils/parse.js +51 -0
  124. package/dist/utils/text.d.ts +4 -0
  125. package/dist/utils/text.js +14 -0
  126. package/dist/utils/transform.d.ts +8 -0
  127. package/dist/utils/transform.js +48 -0
  128. package/package.json +109 -107
@@ -0,0 +1,83 @@
1
+ import { TransportError } from "../errors";
2
+ export const PROXY_AUTH_IP_DENIED_CODE = "PROXY_AUTH_IP_DENIED";
3
+ export const PROXY_AUTH_IP_DENIED_MESSAGE = "Proxy source IP is not authorized. Add the runtime egress IP to the proxy provider allowlist.";
4
+ export const PROXY_EDGE_AUTH_REJECTED_CODE = "PROXY_EDGE_AUTH_REJECTED";
5
+ export const PROXY_EDGE_AUTH_REJECTED_MESSAGE = "Proxy provider rejected a candidate endpoint during authentication. The SDK will retry or refresh the proxy pool when safe.";
6
+ export const PROXY_POOL_STALE_CODE = "PROXY_POOL_STALE";
7
+ export const PROXY_EDGE_TLS_REJECTED_CODE = "PROXY_EDGE_TLS_REJECTED";
8
+ export const PROXY_POOL_EXHAUSTED_CODE = "PROXY_POOL_EXHAUSTED";
9
+ export const PROXY_POOL_EXHAUSTED_MESSAGE = "Proxy provider pool was exhausted. The SDK refreshed the proxy allocation, but all candidate endpoints failed.";
10
+ const PROXY_POOL_STALE_STATUS_CODES = new Set([509, 512]);
11
+ const PROXY_EDGE_TLS_REJECTED_STATUS_CODES = new Set([495]);
12
+ const PROXY_AUTH_IP_DENIED_PATTERN = /\b(?:source|egress|client)\s+ip\b.{0,120}\b(?:deny|denied|unauthori[sz]ed|not\s+authori[sz]ed|white\s*list|allow\s*list)\b|\b(?:white\s*list|allow\s*list)\b.{0,120}\b(?:source|egress|client)\s+ip\b/i;
13
+ const PROXY_EDGE_AUTH_REJECTED_PATTERN = /\bauth\s+ip\s+err\b|\bproxy\b.{0,120}\bauth(?:entication)?\b.{0,120}\b(?:reject(?:ed)?|fail(?:ed)?|invalid|den(?:y|ied)|unauthori[sz]ed)\b|\bauth(?:entication)?\b.{0,120}\b(?:reject(?:ed)?|fail(?:ed)?|invalid|den(?:y|ied)|unauthori[sz]ed)\b.{0,120}\bproxy\b/i;
14
+ const PROXY_POOL_STALE_MESSAGE_PATTERN = /\bproxy\b.{0,120}\b(?:pool|lease|expired|unavailable|exhausted|non[\s-]?200\s+code:\s*(?:509|512))\b|\bnon[\s-]?200\s+code:\s*(?:509|512)\b.{0,120}\bproxy\b|\bsmartproxy\b.{0,120}\b(?:509|512)\b/i;
15
+ const PROXY_EDGE_TLS_REJECTED_MESSAGE_PATTERN = /\b(?:smartproxy|proxy)\b.{0,160}\b(?:495|ssl|tls|cert(?:ificate)?|handshake|edge|connect|non[\s-]?200)\b|\b(?:495|ssl|tls|cert(?:ificate)?|handshake|edge|connect|non[\s-]?200)\b.{0,160}\b(?:smartproxy|proxy)\b/i;
16
+ export function isProxyAuthIpDeniedMessage(message) {
17
+ return PROXY_AUTH_IP_DENIED_PATTERN.test(message);
18
+ }
19
+ export function createProxyAuthIpDeniedError(cause) {
20
+ return new TransportError(PROXY_AUTH_IP_DENIED_MESSAGE, {
21
+ code: PROXY_AUTH_IP_DENIED_CODE,
22
+ cause,
23
+ });
24
+ }
25
+ export function isProxyEdgeAuthRejectedMessage(message) {
26
+ return PROXY_EDGE_AUTH_REJECTED_PATTERN.test(message);
27
+ }
28
+ export function createProxyEdgeAuthRejectedError(cause) {
29
+ return new TransportError(PROXY_EDGE_AUTH_REJECTED_MESSAGE, {
30
+ code: PROXY_EDGE_AUTH_REJECTED_CODE,
31
+ cause,
32
+ });
33
+ }
34
+ export function isProxyPoolStaleStatus(status) {
35
+ return PROXY_POOL_STALE_STATUS_CODES.has(status);
36
+ }
37
+ export function isProxyEdgeTlsRejectedResponse(status, evidence) {
38
+ return (PROXY_EDGE_TLS_REJECTED_STATUS_CODES.has(status) &&
39
+ PROXY_EDGE_TLS_REJECTED_MESSAGE_PATTERN.test(evidence));
40
+ }
41
+ export function isProxyPoolStaleMessage(message) {
42
+ return PROXY_POOL_STALE_MESSAGE_PATTERN.test(message);
43
+ }
44
+ export function isProxyPoolRefreshableError(error) {
45
+ if (error instanceof TransportError &&
46
+ error.code === PROXY_AUTH_IP_DENIED_CODE) {
47
+ return false;
48
+ }
49
+ if (error instanceof TransportError &&
50
+ (error.code === PROXY_POOL_STALE_CODE ||
51
+ error.code === PROXY_EDGE_AUTH_REJECTED_CODE ||
52
+ error.code === PROXY_EDGE_TLS_REJECTED_CODE)) {
53
+ return true;
54
+ }
55
+ const cause = error instanceof Error ? error.cause : undefined;
56
+ const message = [
57
+ error instanceof Error ? error.message : String(error),
58
+ cause instanceof Error ? cause.message : "",
59
+ ].join(" ");
60
+ return (PROXY_POOL_STALE_MESSAGE_PATTERN.test(message) ||
61
+ PROXY_EDGE_AUTH_REJECTED_PATTERN.test(message));
62
+ }
63
+ export const isProxyPoolStaleError = isProxyPoolRefreshableError;
64
+ export function createProxyPoolStaleError(status, cause) {
65
+ return new TransportError(`Proxy provider pool failed with status ${status}`, {
66
+ code: PROXY_POOL_STALE_CODE,
67
+ status,
68
+ cause,
69
+ });
70
+ }
71
+ export function createProxyEdgeTlsRejectedError(status, cause) {
72
+ return new TransportError(`Proxy edge TLS request was rejected with status ${status}`, {
73
+ code: PROXY_EDGE_TLS_REJECTED_CODE,
74
+ status,
75
+ cause,
76
+ });
77
+ }
78
+ export function createProxyPoolExhaustedError(cause) {
79
+ return new TransportError(PROXY_POOL_EXHAUSTED_MESSAGE, {
80
+ code: PROXY_POOL_EXHAUSTED_CODE,
81
+ cause,
82
+ });
83
+ }
@@ -0,0 +1,8 @@
1
+ import type { ProxyAttemptTelemetryEvent, ProxyResolutionTelemetryEvent, ProxyTelemetrySink } from "../config/loader";
2
+ export declare const PROVIDER_TELEMETRY_HEADER = "X-ApiFuse-Provider-Telemetry";
3
+ export declare class ProxyTelemetryCollector implements ProxyTelemetrySink {
4
+ #private;
5
+ recordProxyResolution(event: ProxyResolutionTelemetryEvent): void;
6
+ recordProxyAttempt(event: ProxyAttemptTelemetryEvent): void;
7
+ toHeaderValue(): string | undefined;
8
+ }
@@ -0,0 +1,174 @@
1
+ export const PROVIDER_TELEMETRY_HEADER = "X-ApiFuse-Provider-Telemetry";
2
+ const MAX_HEADER_BYTES = 4_096;
3
+ const MAX_PROXY_ATTEMPT_SAMPLES = 24;
4
+ const CACHE_STATUS_SEVERITY = {
5
+ disabled: 0,
6
+ memory_hit: 1,
7
+ redis_hit: 2,
8
+ soft_stale_refresh: 3,
9
+ redis_corrupt: 4,
10
+ redis_error: 5,
11
+ lock_wait: 6,
12
+ allocator: 7,
13
+ };
14
+ function sumOptional(left, right) {
15
+ const total = (left ?? 0) + (right ?? 0);
16
+ return total > 0 ? total : undefined;
17
+ }
18
+ function maxOptional(left, right) {
19
+ const values = [left, right].filter((value) => typeof value === "number");
20
+ return values.length > 0 ? Math.max(...values) : undefined;
21
+ }
22
+ function worseStatus(left, right) {
23
+ return CACHE_STATUS_SEVERITY[right] > CACHE_STATUS_SEVERITY[left]
24
+ ? right
25
+ : left;
26
+ }
27
+ function encodeBase64Url(value) {
28
+ return Buffer.from(value, "utf8").toString("base64url");
29
+ }
30
+ export class ProxyTelemetryCollector {
31
+ #events = [];
32
+ #attempts = [];
33
+ recordProxyResolution(event) {
34
+ this.#events.push({
35
+ provider: "smartproxy",
36
+ cacheStatus: event.cacheStatus,
37
+ cacheHit: event.cacheHit,
38
+ resolutionMs: Math.max(0, Math.floor(event.resolutionMs)),
39
+ allocatorMs: event.allocatorMs === undefined
40
+ ? undefined
41
+ : Math.max(0, Math.floor(event.allocatorMs)),
42
+ allocatorStatus: event.allocatorStatus === undefined
43
+ ? undefined
44
+ : Math.max(0, Math.floor(event.allocatorStatus)),
45
+ allocatorBodyClass: event.allocatorBodyClass,
46
+ allocatorAttempts: event.allocatorAttempts === undefined
47
+ ? undefined
48
+ : Math.max(1, Math.floor(event.allocatorAttempts)),
49
+ lockWaitMs: event.lockWaitMs === undefined
50
+ ? undefined
51
+ : Math.max(0, Math.floor(event.lockWaitMs)),
52
+ redisReadMs: event.redisReadMs === undefined
53
+ ? undefined
54
+ : Math.max(0, Math.floor(event.redisReadMs)),
55
+ redisWriteMs: event.redisWriteMs === undefined
56
+ ? undefined
57
+ : Math.max(0, Math.floor(event.redisWriteMs)),
58
+ poolAgeMs: event.poolAgeMs === undefined
59
+ ? undefined
60
+ : Math.max(0, Math.floor(event.poolAgeMs)),
61
+ poolExpiresInMs: event.poolExpiresInMs === undefined
62
+ ? undefined
63
+ : Math.max(0, Math.floor(event.poolExpiresInMs)),
64
+ attempts: Math.max(1, Math.floor(event.attempts || 1)),
65
+ refreshes: event.refreshes === undefined
66
+ ? undefined
67
+ : Math.max(0, Math.floor(event.refreshes)),
68
+ });
69
+ }
70
+ recordProxyAttempt(event) {
71
+ if (this.#attempts.length >= MAX_PROXY_ATTEMPT_SAMPLES)
72
+ return;
73
+ this.#attempts.push({
74
+ provider: "smartproxy",
75
+ attempt: Math.max(1, Math.floor(event.attempt || 1)),
76
+ ...(event.poolIndex === undefined
77
+ ? {}
78
+ : { poolIndex: Math.max(0, Math.floor(event.poolIndex)) }),
79
+ ...(event.proxyHash ? { proxyHash: event.proxyHash.slice(0, 16) } : {}),
80
+ outcome: event.outcome === "ok" ? "ok" : "error",
81
+ ...(event.errorCode ? { errorCode: event.errorCode.slice(0, 80) } : {}),
82
+ ...(event.status === undefined
83
+ ? {}
84
+ : { status: Math.max(0, Math.floor(event.status)) }),
85
+ ...(event.durationMs === undefined
86
+ ? {}
87
+ : { durationMs: Math.max(0, Math.floor(event.durationMs)) }),
88
+ });
89
+ }
90
+ toHeaderValue() {
91
+ const [first, ...rest] = this.#events;
92
+ if (!first)
93
+ return undefined;
94
+ const aggregate = rest.reduce((acc, event) => ({
95
+ provider: "smartproxy",
96
+ cacheStatus: worseStatus(acc.cacheStatus, event.cacheStatus),
97
+ cacheHit: acc.cacheHit && event.cacheHit,
98
+ resolutionMs: acc.resolutionMs + event.resolutionMs,
99
+ allocatorMs: sumOptional(acc.allocatorMs, event.allocatorMs),
100
+ allocatorStatus: event.allocatorStatus ?? acc.allocatorStatus,
101
+ allocatorBodyClass: event.allocatorBodyClass ?? acc.allocatorBodyClass,
102
+ allocatorAttempts: sumOptional(acc.allocatorAttempts, event.allocatorAttempts),
103
+ lockWaitMs: sumOptional(acc.lockWaitMs, event.lockWaitMs),
104
+ redisReadMs: sumOptional(acc.redisReadMs, event.redisReadMs),
105
+ redisWriteMs: sumOptional(acc.redisWriteMs, event.redisWriteMs),
106
+ poolAgeMs: maxOptional(acc.poolAgeMs, event.poolAgeMs),
107
+ poolExpiresInMs: maxOptional(acc.poolExpiresInMs, event.poolExpiresInMs),
108
+ attempts: acc.attempts + event.attempts,
109
+ refreshes: sumOptional(acc.refreshes, event.refreshes),
110
+ }), first);
111
+ const payload = {
112
+ v: 1,
113
+ proxy: {
114
+ provider: "smartproxy",
115
+ cacheStatus: aggregate.cacheStatus,
116
+ cacheHit: aggregate.cacheHit,
117
+ resolutionMs: aggregate.resolutionMs,
118
+ ...(aggregate.allocatorMs !== undefined
119
+ ? { allocatorMs: aggregate.allocatorMs }
120
+ : {}),
121
+ ...(aggregate.allocatorStatus !== undefined
122
+ ? { allocatorStatus: aggregate.allocatorStatus }
123
+ : {}),
124
+ ...(aggregate.allocatorBodyClass !== undefined
125
+ ? { allocatorBodyClass: aggregate.allocatorBodyClass }
126
+ : {}),
127
+ ...(aggregate.allocatorAttempts !== undefined
128
+ ? { allocatorAttempts: aggregate.allocatorAttempts }
129
+ : {}),
130
+ ...(aggregate.lockWaitMs !== undefined
131
+ ? { lockWaitMs: aggregate.lockWaitMs }
132
+ : {}),
133
+ ...(aggregate.redisReadMs !== undefined
134
+ ? { redisReadMs: aggregate.redisReadMs }
135
+ : {}),
136
+ ...(aggregate.redisWriteMs !== undefined
137
+ ? { redisWriteMs: aggregate.redisWriteMs }
138
+ : {}),
139
+ ...(aggregate.poolAgeMs !== undefined
140
+ ? { poolAgeMs: aggregate.poolAgeMs }
141
+ : {}),
142
+ ...(aggregate.poolExpiresInMs !== undefined
143
+ ? { poolExpiresInMs: aggregate.poolExpiresInMs }
144
+ : {}),
145
+ attempts: aggregate.attempts,
146
+ ...(aggregate.refreshes !== undefined
147
+ ? { refreshes: aggregate.refreshes }
148
+ : {}),
149
+ ...(this.#attempts.length > 0
150
+ ? {
151
+ attemptSamples: this.#attempts.map((attempt, index) => ({
152
+ n: index + 1,
153
+ a: attempt.attempt,
154
+ ...(attempt.poolIndex === undefined
155
+ ? {}
156
+ : { i: attempt.poolIndex }),
157
+ ...(attempt.proxyHash ? { h: attempt.proxyHash } : {}),
158
+ o: attempt.outcome,
159
+ ...(attempt.errorCode ? { c: attempt.errorCode } : {}),
160
+ ...(attempt.status === undefined ? {} : { s: attempt.status }),
161
+ ...(attempt.durationMs === undefined
162
+ ? {}
163
+ : { d: attempt.durationMs }),
164
+ })),
165
+ }
166
+ : {}),
167
+ },
168
+ };
169
+ const encoded = encodeBase64Url(JSON.stringify(payload));
170
+ if (encoded.length > MAX_HEADER_BYTES)
171
+ return undefined;
172
+ return encoded;
173
+ }
174
+ }
@@ -0,0 +1,17 @@
1
+ import Redis from "ioredis";
2
+ export type ProviderRedisClient = Redis;
3
+ export type ProviderRedisClientOptions = {
4
+ readonly redisUrl: string;
5
+ readonly timeoutMs: number;
6
+ readonly onError: () => void;
7
+ };
8
+ type RedisTimeoutOptions<T> = {
9
+ readonly timeoutMs: number;
10
+ readonly onTimeout: () => T;
11
+ readonly onError?: (error: unknown) => T;
12
+ };
13
+ export declare function createProviderRedisClient(options: ProviderRedisClientOptions): ProviderRedisClient;
14
+ export declare function withRedisTimeout<T>(operation: () => Promise<T>, options: RedisTimeoutOptions<T>): Promise<T>;
15
+ export declare function redisStatus(redis: ProviderRedisClient): string;
16
+ export declare function ensureRedisReady(redis: ProviderRedisClient, timeoutMs: number): Promise<boolean>;
17
+ export {};
@@ -0,0 +1,82 @@
1
+ import Redis from "ioredis";
2
+ export function createProviderRedisClient(options) {
3
+ const redis = new Redis(options.redisUrl, {
4
+ connectTimeout: options.timeoutMs,
5
+ enableOfflineQueue: false,
6
+ lazyConnect: true,
7
+ maxRetriesPerRequest: 0,
8
+ retryStrategy: () => null,
9
+ });
10
+ redis.on("error", options.onError);
11
+ return redis;
12
+ }
13
+ export async function withRedisTimeout(operation, options) {
14
+ let timeoutId;
15
+ try {
16
+ const timeout = new Promise((resolve, reject) => {
17
+ timeoutId = setTimeout(() => {
18
+ try {
19
+ resolve(options.onTimeout());
20
+ }
21
+ catch (error) {
22
+ reject(error);
23
+ }
24
+ }, options.timeoutMs);
25
+ });
26
+ const operationResult = options.onError
27
+ ? operation().catch(options.onError)
28
+ : operation();
29
+ return await Promise.race([operationResult, timeout]);
30
+ }
31
+ finally {
32
+ if (timeoutId)
33
+ clearTimeout(timeoutId);
34
+ }
35
+ }
36
+ export function redisStatus(redis) {
37
+ return redis.status;
38
+ }
39
+ async function waitForRedisReady(redis, timeoutMs) {
40
+ let timeoutId;
41
+ let settled = false;
42
+ return await new Promise((resolve) => {
43
+ const cleanup = () => {
44
+ if (timeoutId)
45
+ clearTimeout(timeoutId);
46
+ redis.off("ready", onReady);
47
+ redis.off("close", onUnavailable);
48
+ redis.off("end", onUnavailable);
49
+ redis.off("error", onUnavailable);
50
+ };
51
+ const finish = (ready) => {
52
+ if (settled)
53
+ return;
54
+ settled = true;
55
+ cleanup();
56
+ resolve(ready);
57
+ };
58
+ const onReady = () => finish(true);
59
+ const onUnavailable = () => finish(false);
60
+ timeoutId = setTimeout(() => finish(redisStatus(redis) === "ready"), timeoutMs);
61
+ redis.once("ready", onReady);
62
+ redis.once("close", onUnavailable);
63
+ redis.once("end", onUnavailable);
64
+ redis.once("error", onUnavailable);
65
+ });
66
+ }
67
+ export async function ensureRedisReady(redis, timeoutMs) {
68
+ if (redisStatus(redis) === "ready")
69
+ return true;
70
+ if (redisStatus(redis) === "wait" || redisStatus(redis) === "end") {
71
+ const connected = await withRedisTimeout(async () => {
72
+ await redis.connect();
73
+ return true;
74
+ }, {
75
+ timeoutMs,
76
+ onTimeout: () => false,
77
+ onError: () => false,
78
+ });
79
+ return connected && redisStatus(redis) === "ready";
80
+ }
81
+ return await waitForRedisReady(redis, timeoutMs);
82
+ }
@@ -0,0 +1,3 @@
1
+ import type { RequestParams } from "../types";
2
+ export declare function appendQueryParams(url: string, params?: RequestParams): string;
3
+ export declare function normalizeHttpRequestBody(body: unknown): string | Buffer | undefined;
@@ -0,0 +1,42 @@
1
+ function isParamArray(value) {
2
+ return Array.isArray(value);
3
+ }
4
+ function appendQueryValue(searchParams, key, value) {
5
+ if (value === null || value === undefined) {
6
+ return;
7
+ }
8
+ searchParams.append(key, String(value));
9
+ }
10
+ export function appendQueryParams(url, params) {
11
+ if (!params || Object.keys(params).length === 0) {
12
+ return url;
13
+ }
14
+ const parsed = new URL(url);
15
+ for (const [key, value] of Object.entries(params)) {
16
+ if (isParamArray(value)) {
17
+ for (const item of value)
18
+ appendQueryValue(parsed.searchParams, key, item);
19
+ continue;
20
+ }
21
+ appendQueryValue(parsed.searchParams, key, value);
22
+ }
23
+ return parsed.toString();
24
+ }
25
+ export function normalizeHttpRequestBody(body) {
26
+ if (body === undefined) {
27
+ return undefined;
28
+ }
29
+ if (typeof body === "string" || Buffer.isBuffer(body)) {
30
+ return body;
31
+ }
32
+ if (body instanceof URLSearchParams) {
33
+ return body.toString();
34
+ }
35
+ if (body instanceof ArrayBuffer) {
36
+ return Buffer.from(body);
37
+ }
38
+ if (ArrayBuffer.isView(body)) {
39
+ return Buffer.from(body.buffer, body.byteOffset, body.byteLength);
40
+ }
41
+ return JSON.stringify(body);
42
+ }
@@ -0,0 +1,17 @@
1
+ import { ProviderError } from "../errors";
2
+ import type { ProviderRuntimeState } from "../types";
3
+ type RedisProviderRuntimeStateOptions = {
4
+ readonly redisUrl: string;
5
+ readonly providerId?: string;
6
+ };
7
+ export declare class UnsupportedProviderStateError extends ProviderError {
8
+ constructor(message?: string);
9
+ }
10
+ export declare function createRedisProviderRuntimeState(options: RedisProviderRuntimeStateOptions): ProviderRuntimeState;
11
+ export declare function createProviderRuntimeStateFromEnv(options?: {
12
+ readonly providerId?: string;
13
+ readonly allowMemoryFallback?: boolean;
14
+ }): ProviderRuntimeState;
15
+ export declare function createMemoryProviderRuntimeState(): ProviderRuntimeState;
16
+ export declare function createUnsupportedProviderRuntimeState(): ProviderRuntimeState;
17
+ export {};