plato-sandbox-sdk 1.1.1

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 (203) hide show
  1. package/BaseClient.ts +28 -0
  2. package/Client.ts +1849 -0
  3. package/README.md +339 -0
  4. package/api/client/index.ts +1 -0
  5. package/api/client/requests/CreateSandboxRequest.ts +37 -0
  6. package/api/client/requests/CreateSnapshotRequest.ts +11 -0
  7. package/api/client/requests/EvaluateRequest.ts +9 -0
  8. package/api/client/requests/GetEnvironmentStateRequest.ts +11 -0
  9. package/api/client/requests/GetTestCasesRequest.ts +15 -0
  10. package/api/client/requests/LogRequest.ts +19 -0
  11. package/api/client/requests/MakeEnvironmentRequest.ts +27 -0
  12. package/api/client/requests/PostEvaluationResultRequest.ts +14 -0
  13. package/api/client/requests/ResetEnvironmentRequest.ts +11 -0
  14. package/api/client/requests/SetupRootAccessRequest.ts +14 -0
  15. package/api/client/requests/SetupSandboxRequest.ts +29 -0
  16. package/api/client/requests/StartWorkerRequest.ts +28 -0
  17. package/api/client/requests/index.ts +12 -0
  18. package/api/errors/BadRequestError.ts +17 -0
  19. package/api/errors/index.ts +1 -0
  20. package/api/index.ts +3 -0
  21. package/api/types/ActiveSessionResponse.ts +6 -0
  22. package/api/types/BackupEnvironmentResponse.ts +7 -0
  23. package/api/types/CdpUrlResponse.ts +12 -0
  24. package/api/types/CloseEnvironmentResponse.ts +6 -0
  25. package/api/types/CreateSandboxResponse.ts +14 -0
  26. package/api/types/CreateSnapshotResponse.ts +10 -0
  27. package/api/types/DeleteSandboxResponse.ts +6 -0
  28. package/api/types/Environment.ts +7 -0
  29. package/api/types/EnvironmentStateResponse.ts +11 -0
  30. package/api/types/ErrorResponse.ts +6 -0
  31. package/api/types/EvaluateResponse.ts +21 -0
  32. package/api/types/EvaluationResult.ts +9 -0
  33. package/api/types/HeartbeatResponse.ts +6 -0
  34. package/api/types/JobStatusResponse.ts +7 -0
  35. package/api/types/LogResponse.ts +5 -0
  36. package/api/types/MakeEnvironmentResponse.ts +6 -0
  37. package/api/types/OperationEvent.ts +42 -0
  38. package/api/types/PlatoConfig.ts +8 -0
  39. package/api/types/PlatoTask.ts +21 -0
  40. package/api/types/PlatoTaskMetadata.ts +20 -0
  41. package/api/types/PostEvaluationResultResponse.ts +6 -0
  42. package/api/types/ProxyUrlResponse.ts +12 -0
  43. package/api/types/ResetEnvironmentResponse.ts +13 -0
  44. package/api/types/RunningSessionsCountResponse.ts +6 -0
  45. package/api/types/Sandbox.ts +10 -0
  46. package/api/types/ScoringType.ts +7 -0
  47. package/api/types/SetupRootAccessResponse.ts +7 -0
  48. package/api/types/SetupSandboxResponse.ts +6 -0
  49. package/api/types/SimConfigCompute.ts +9 -0
  50. package/api/types/SimConfigDataset.ts +10 -0
  51. package/api/types/SimConfigListener.ts +27 -0
  52. package/api/types/SimConfigMetadata.ts +14 -0
  53. package/api/types/SimConfigService.ts +8 -0
  54. package/api/types/Simulator.ts +10 -0
  55. package/api/types/SimulatorListItem.ts +7 -0
  56. package/api/types/SshInfo.ts +18 -0
  57. package/api/types/StartWorkerResponse.ts +7 -0
  58. package/api/types/TaskMetadata.ts +20 -0
  59. package/api/types/TestCase.ts +40 -0
  60. package/api/types/TestCasesResponse.ts +10 -0
  61. package/api/types/Variable.ts +6 -0
  62. package/api/types/WorkerReadyResponse.ts +9 -0
  63. package/api/types/index.ts +42 -0
  64. package/core/fetcher/APIResponse.ts +23 -0
  65. package/core/fetcher/BinaryResponse.ts +36 -0
  66. package/core/fetcher/EndpointMetadata.ts +13 -0
  67. package/core/fetcher/EndpointSupplier.ts +14 -0
  68. package/core/fetcher/Fetcher.ts +165 -0
  69. package/core/fetcher/Headers.ts +93 -0
  70. package/core/fetcher/HttpResponsePromise.ts +116 -0
  71. package/core/fetcher/RawResponse.ts +61 -0
  72. package/core/fetcher/ResponseWithBody.ts +7 -0
  73. package/core/fetcher/Supplier.ts +11 -0
  74. package/core/fetcher/createRequestUrl.ts +6 -0
  75. package/core/fetcher/getErrorResponseBody.ts +33 -0
  76. package/core/fetcher/getFetchFn.ts +3 -0
  77. package/core/fetcher/getHeader.ts +8 -0
  78. package/core/fetcher/getRequestBody.ts +16 -0
  79. package/core/fetcher/getResponseBody.ts +43 -0
  80. package/core/fetcher/index.ts +11 -0
  81. package/core/fetcher/makeRequest.ts +44 -0
  82. package/core/fetcher/requestWithRetries.ts +73 -0
  83. package/core/fetcher/signals.ts +38 -0
  84. package/core/headers.ts +33 -0
  85. package/core/index.ts +4 -0
  86. package/core/json.ts +27 -0
  87. package/core/runtime/index.ts +1 -0
  88. package/core/runtime/runtime.ts +133 -0
  89. package/core/stream/Stream.ts +155 -0
  90. package/core/stream/index.ts +1 -0
  91. package/core/url/encodePathParam.ts +18 -0
  92. package/core/url/index.ts +3 -0
  93. package/core/url/join.ts +80 -0
  94. package/core/url/qs.ts +74 -0
  95. package/dist/BaseClient.d.ts +25 -0
  96. package/dist/Client.d.ts +376 -0
  97. package/dist/api/client/index.d.ts +2 -0
  98. package/dist/api/client/requests/CreateSandboxRequest.d.ts +35 -0
  99. package/dist/api/client/requests/CreateSnapshotRequest.d.ts +10 -0
  100. package/dist/api/client/requests/EvaluateRequest.d.ts +8 -0
  101. package/dist/api/client/requests/GetEnvironmentStateRequest.d.ts +10 -0
  102. package/dist/api/client/requests/GetTestCasesRequest.d.ts +14 -0
  103. package/dist/api/client/requests/LogRequest.d.ts +18 -0
  104. package/dist/api/client/requests/MakeEnvironmentRequest.d.ts +26 -0
  105. package/dist/api/client/requests/PostEvaluationResultRequest.d.ts +13 -0
  106. package/dist/api/client/requests/ResetEnvironmentRequest.d.ts +10 -0
  107. package/dist/api/client/requests/SetupRootAccessRequest.d.ts +13 -0
  108. package/dist/api/client/requests/SetupSandboxRequest.d.ts +27 -0
  109. package/dist/api/client/requests/StartWorkerRequest.d.ts +26 -0
  110. package/dist/api/client/requests/index.d.ts +13 -0
  111. package/dist/api/errors/BadRequestError.d.ts +7 -0
  112. package/dist/api/errors/index.d.ts +2 -0
  113. package/dist/api/index.d.ts +4 -0
  114. package/dist/api/types/ActiveSessionResponse.d.ts +5 -0
  115. package/dist/api/types/BackupEnvironmentResponse.d.ts +6 -0
  116. package/dist/api/types/CdpUrlResponse.d.ts +10 -0
  117. package/dist/api/types/CloseEnvironmentResponse.d.ts +5 -0
  118. package/dist/api/types/CreateSandboxResponse.d.ts +13 -0
  119. package/dist/api/types/CreateSnapshotResponse.d.ts +9 -0
  120. package/dist/api/types/DeleteSandboxResponse.d.ts +5 -0
  121. package/dist/api/types/Environment.d.ts +6 -0
  122. package/dist/api/types/EnvironmentStateResponse.d.ts +9 -0
  123. package/dist/api/types/ErrorResponse.d.ts +5 -0
  124. package/dist/api/types/EvaluateResponse.d.ts +18 -0
  125. package/dist/api/types/EvaluationResult.d.ts +8 -0
  126. package/dist/api/types/HeartbeatResponse.d.ts +5 -0
  127. package/dist/api/types/JobStatusResponse.d.ts +6 -0
  128. package/dist/api/types/LogResponse.d.ts +4 -0
  129. package/dist/api/types/MakeEnvironmentResponse.d.ts +5 -0
  130. package/dist/api/types/OperationEvent.d.ts +40 -0
  131. package/dist/api/types/PlatoConfig.d.ts +6 -0
  132. package/dist/api/types/PlatoTask.d.ts +19 -0
  133. package/dist/api/types/PlatoTaskMetadata.d.ts +18 -0
  134. package/dist/api/types/PostEvaluationResultResponse.d.ts +5 -0
  135. package/dist/api/types/ProxyUrlResponse.d.ts +10 -0
  136. package/dist/api/types/ResetEnvironmentResponse.d.ts +11 -0
  137. package/dist/api/types/RunningSessionsCountResponse.d.ts +5 -0
  138. package/dist/api/types/Sandbox.d.ts +9 -0
  139. package/dist/api/types/ScoringType.d.ts +6 -0
  140. package/dist/api/types/SetupRootAccessResponse.d.ts +6 -0
  141. package/dist/api/types/SetupSandboxResponse.d.ts +5 -0
  142. package/dist/api/types/SimConfigCompute.d.ts +8 -0
  143. package/dist/api/types/SimConfigDataset.d.ts +8 -0
  144. package/dist/api/types/SimConfigListener.d.ts +25 -0
  145. package/dist/api/types/SimConfigMetadata.d.ts +12 -0
  146. package/dist/api/types/SimConfigService.d.ts +7 -0
  147. package/dist/api/types/Simulator.d.ts +9 -0
  148. package/dist/api/types/SimulatorListItem.d.ts +6 -0
  149. package/dist/api/types/SshInfo.d.ts +17 -0
  150. package/dist/api/types/StartWorkerResponse.d.ts +6 -0
  151. package/dist/api/types/TaskMetadata.d.ts +18 -0
  152. package/dist/api/types/TestCase.d.ts +34 -0
  153. package/dist/api/types/TestCasesResponse.d.ts +8 -0
  154. package/dist/api/types/Variable.d.ts +5 -0
  155. package/dist/api/types/WorkerReadyResponse.d.ts +8 -0
  156. package/dist/api/types/index.d.ts +43 -0
  157. package/dist/core/fetcher/APIResponse.d.ts +21 -0
  158. package/dist/core/fetcher/BinaryResponse.d.ts +21 -0
  159. package/dist/core/fetcher/EndpointMetadata.d.ts +14 -0
  160. package/dist/core/fetcher/EndpointSupplier.d.ts +13 -0
  161. package/dist/core/fetcher/Fetcher.d.ts +43 -0
  162. package/dist/core/fetcher/Headers.d.ts +3 -0
  163. package/dist/core/fetcher/HttpResponsePromise.d.ts +59 -0
  164. package/dist/core/fetcher/RawResponse.d.ts +30 -0
  165. package/dist/core/fetcher/ResponseWithBody.d.ts +5 -0
  166. package/dist/core/fetcher/Supplier.d.ts +5 -0
  167. package/dist/core/fetcher/createRequestUrl.d.ts +2 -0
  168. package/dist/core/fetcher/getErrorResponseBody.d.ts +2 -0
  169. package/dist/core/fetcher/getFetchFn.d.ts +2 -0
  170. package/dist/core/fetcher/getHeader.d.ts +2 -0
  171. package/dist/core/fetcher/getRequestBody.d.ts +8 -0
  172. package/dist/core/fetcher/getResponseBody.d.ts +2 -0
  173. package/dist/core/fetcher/index.d.ts +12 -0
  174. package/dist/core/fetcher/makeRequest.d.ts +2 -0
  175. package/dist/core/fetcher/requestWithRetries.d.ts +2 -0
  176. package/dist/core/fetcher/signals.d.ts +12 -0
  177. package/dist/core/headers.d.ts +3 -0
  178. package/dist/core/index.d.ts +5 -0
  179. package/dist/core/json.d.ts +16 -0
  180. package/dist/core/runtime/index.d.ts +2 -0
  181. package/dist/core/runtime/runtime.d.ts +10 -0
  182. package/dist/core/stream/Stream.d.ts +48 -0
  183. package/dist/core/stream/index.d.ts +2 -0
  184. package/dist/core/url/encodePathParam.d.ts +2 -0
  185. package/dist/core/url/index.d.ts +4 -0
  186. package/dist/core/url/join.d.ts +2 -0
  187. package/dist/core/url/qs.d.ts +7 -0
  188. package/dist/errors/ApiError.d.ts +13 -0
  189. package/dist/errors/ApiTimeoutError.d.ts +4 -0
  190. package/dist/errors/index.d.ts +3 -0
  191. package/dist/helpers/SandboxHelpers.d.ts +127 -0
  192. package/dist/helpers/SandboxMonitor.d.ts +89 -0
  193. package/dist/helpers/index.d.ts +9 -0
  194. package/dist/index.d.ts +6 -0
  195. package/errors/ApiError.ts +53 -0
  196. package/errors/ApiTimeoutError.ts +8 -0
  197. package/errors/index.ts +2 -0
  198. package/helpers/README.md +229 -0
  199. package/helpers/SandboxHelpers.ts +213 -0
  200. package/helpers/SandboxMonitor.ts +252 -0
  201. package/helpers/index.ts +10 -0
  202. package/index.ts +7 -0
  203. package/package.json +54 -0
@@ -0,0 +1,73 @@
1
+ const INITIAL_RETRY_DELAY = 1000; // in milliseconds
2
+ const MAX_RETRY_DELAY = 60000; // in milliseconds
3
+ const DEFAULT_MAX_RETRIES = 2;
4
+ const JITTER_FACTOR = 0.2; // 20% random jitter
5
+
6
+ function addPositiveJitter(delay: number): number {
7
+ // Generate a random value between 0 and +JITTER_FACTOR
8
+ const jitterMultiplier = 1 + Math.random() * JITTER_FACTOR;
9
+ return delay * jitterMultiplier;
10
+ }
11
+
12
+ function addSymmetricJitter(delay: number): number {
13
+ // Generate a random value in a JITTER_FACTOR-sized percentage range around delay
14
+ const jitterMultiplier = 1 + (Math.random() - 0.5) * JITTER_FACTOR;
15
+ return delay * jitterMultiplier;
16
+ }
17
+
18
+ function getRetryDelayFromHeaders(response: Response, retryAttempt: number): number {
19
+ // Check for Retry-After header first (RFC 7231), with no jitter
20
+ const retryAfter = response.headers.get("Retry-After");
21
+ if (retryAfter) {
22
+ // Parse as number of seconds...
23
+ const retryAfterSeconds = parseInt(retryAfter, 10);
24
+ if (!Number.isNaN(retryAfterSeconds) && retryAfterSeconds > 0) {
25
+ return Math.min(retryAfterSeconds * 1000, MAX_RETRY_DELAY);
26
+ }
27
+
28
+ // ...or as an HTTP date; both are valid
29
+ const retryAfterDate = new Date(retryAfter);
30
+ if (!Number.isNaN(retryAfterDate.getTime())) {
31
+ const delay = retryAfterDate.getTime() - Date.now();
32
+ if (delay > 0) {
33
+ return Math.min(Math.max(delay, 0), MAX_RETRY_DELAY);
34
+ }
35
+ }
36
+ }
37
+
38
+ // Then check for industry-standard X-RateLimit-Reset header, with positive jitter
39
+ const rateLimitReset = response.headers.get("X-RateLimit-Reset");
40
+ if (rateLimitReset) {
41
+ const resetTime = parseInt(rateLimitReset, 10);
42
+ if (!Number.isNaN(resetTime)) {
43
+ // Assume Unix timestamp in epoch seconds
44
+ const delay = resetTime * 1000 - Date.now();
45
+ if (delay > 0) {
46
+ return addPositiveJitter(Math.min(delay, MAX_RETRY_DELAY));
47
+ }
48
+ }
49
+ }
50
+
51
+ // Fall back to exponential backoff, with symmetric jitter
52
+ return addSymmetricJitter(Math.min(INITIAL_RETRY_DELAY * 2 ** retryAttempt, MAX_RETRY_DELAY));
53
+ }
54
+
55
+ export async function requestWithRetries(
56
+ requestFn: () => Promise<Response>,
57
+ maxRetries: number = DEFAULT_MAX_RETRIES,
58
+ ): Promise<Response> {
59
+ let response: Response = await requestFn();
60
+
61
+ for (let i = 0; i < maxRetries; ++i) {
62
+ if ([408, 429].includes(response.status) || response.status >= 500) {
63
+ // Get delay with appropriate jitter applied
64
+ const delay = getRetryDelayFromHeaders(response, i);
65
+
66
+ await new Promise((resolve) => setTimeout(resolve, delay));
67
+ response = await requestFn();
68
+ } else {
69
+ break;
70
+ }
71
+ }
72
+ return response!;
73
+ }
@@ -0,0 +1,38 @@
1
+ const TIMEOUT = "timeout";
2
+
3
+ export function getTimeoutSignal(timeoutMs: number): { signal: AbortSignal; abortId: NodeJS.Timeout } {
4
+ const controller = new AbortController();
5
+ const abortId = setTimeout(() => controller.abort(TIMEOUT), timeoutMs);
6
+ return { signal: controller.signal, abortId };
7
+ }
8
+
9
+ /**
10
+ * Returns an abort signal that is getting aborted when
11
+ * at least one of the specified abort signals is aborted.
12
+ *
13
+ * Requires at least node.js 18.
14
+ */
15
+ export function anySignal(...args: AbortSignal[] | [AbortSignal[]]): AbortSignal {
16
+ // Allowing signals to be passed either as array
17
+ // of signals or as multiple arguments.
18
+ const signals = (args.length === 1 && Array.isArray(args[0]) ? args[0] : args) as AbortSignal[];
19
+
20
+ const controller = new AbortController();
21
+
22
+ for (const signal of signals) {
23
+ if (signal.aborted) {
24
+ // Exiting early if one of the signals
25
+ // is already aborted.
26
+ controller.abort((signal as any)?.reason);
27
+ break;
28
+ }
29
+
30
+ // Listening for signals and removing the listeners
31
+ // when at least one symbol is aborted.
32
+ signal.addEventListener("abort", () => controller.abort((signal as any)?.reason), {
33
+ signal: controller.signal,
34
+ });
35
+ }
36
+
37
+ return controller.signal;
38
+ }
@@ -0,0 +1,33 @@
1
+ export function mergeHeaders<THeaderValue>(
2
+ ...headersArray: (Record<string, THeaderValue> | null | undefined)[]
3
+ ): Record<string, string | THeaderValue> {
4
+ const result: Record<string, THeaderValue> = {};
5
+
6
+ for (const [key, value] of headersArray
7
+ .filter((headers) => headers != null)
8
+ .flatMap((headers) => Object.entries(headers))) {
9
+ if (value != null) {
10
+ result[key] = value;
11
+ } else if (key in result) {
12
+ delete result[key];
13
+ }
14
+ }
15
+
16
+ return result;
17
+ }
18
+
19
+ export function mergeOnlyDefinedHeaders<THeaderValue>(
20
+ ...headersArray: (Record<string, THeaderValue> | null | undefined)[]
21
+ ): Record<string, THeaderValue> {
22
+ const result: Record<string, THeaderValue> = {};
23
+
24
+ for (const [key, value] of headersArray
25
+ .filter((headers) => headers != null)
26
+ .flatMap((headers) => Object.entries(headers))) {
27
+ if (value != null) {
28
+ result[key] = value;
29
+ }
30
+ }
31
+
32
+ return result;
33
+ }
package/core/index.ts ADDED
@@ -0,0 +1,4 @@
1
+ export * from "./fetcher/index.js";
2
+ export * from "./runtime/index.js";
3
+ export * from "./stream/index.js";
4
+ export * as url from "./url/index.js";
package/core/json.ts ADDED
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Serialize a value to JSON
3
+ * @param value A JavaScript value, usually an object or array, to be converted.
4
+ * @param replacer A function that transforms the results.
5
+ * @param space Adds indentation, white space, and line break characters to the return-value JSON text to make it easier to read.
6
+ * @returns JSON string
7
+ */
8
+ export const toJson = (
9
+ value: unknown,
10
+ replacer?: (this: unknown, key: string, value: unknown) => unknown,
11
+ space?: string | number,
12
+ ): string => {
13
+ return JSON.stringify(value, replacer, space);
14
+ };
15
+
16
+ /**
17
+ * Parse JSON string to object, array, or other type
18
+ * @param text A valid JSON string.
19
+ * @param reviver A function that transforms the results. This function is called for each member of the object. If a member contains nested objects, the nested objects are transformed before the parent object is.
20
+ * @returns Parsed object, array, or other type
21
+ */
22
+ export function fromJson<T = unknown>(
23
+ text: string,
24
+ reviver?: (this: unknown, key: string, value: unknown) => unknown,
25
+ ): T {
26
+ return JSON.parse(text, reviver);
27
+ }
@@ -0,0 +1 @@
1
+ export { RUNTIME } from "./runtime.js";
@@ -0,0 +1,133 @@
1
+ interface DenoGlobal {
2
+ version: {
3
+ deno: string;
4
+ };
5
+ }
6
+
7
+ interface BunGlobal {
8
+ version: string;
9
+ }
10
+
11
+ declare const Deno: DenoGlobal | undefined;
12
+ declare const Bun: BunGlobal | undefined;
13
+ declare const EdgeRuntime: string | undefined;
14
+ declare const self: typeof globalThis.self & {
15
+ importScripts?: unknown;
16
+ };
17
+
18
+ /**
19
+ * A constant that indicates which environment and version the SDK is running in.
20
+ */
21
+ export const RUNTIME: Runtime = evaluateRuntime();
22
+
23
+ export interface Runtime {
24
+ type: "browser" | "web-worker" | "deno" | "bun" | "node" | "react-native" | "unknown" | "workerd" | "edge-runtime";
25
+ version?: string;
26
+ parsedVersion?: number;
27
+ }
28
+
29
+ function evaluateRuntime(): Runtime {
30
+ /**
31
+ * A constant that indicates whether the environment the code is running is a Web Browser.
32
+ */
33
+ const isBrowser = typeof window !== "undefined" && typeof window.document !== "undefined";
34
+ if (isBrowser) {
35
+ return {
36
+ type: "browser",
37
+ version: window.navigator.userAgent,
38
+ };
39
+ }
40
+
41
+ /**
42
+ * A constant that indicates whether the environment the code is running is Cloudflare.
43
+ * https://developers.cloudflare.com/workers/runtime-apis/web-standards/#navigatoruseragent
44
+ */
45
+ const isCloudflare = typeof globalThis !== "undefined" && globalThis?.navigator?.userAgent === "Cloudflare-Workers";
46
+ if (isCloudflare) {
47
+ return {
48
+ type: "workerd",
49
+ };
50
+ }
51
+
52
+ /**
53
+ * A constant that indicates whether the environment the code is running is Edge Runtime.
54
+ * https://vercel.com/docs/functions/runtimes/edge-runtime#check-if-you're-running-on-the-edge-runtime
55
+ */
56
+ const isEdgeRuntime = typeof EdgeRuntime === "string";
57
+ if (isEdgeRuntime) {
58
+ return {
59
+ type: "edge-runtime",
60
+ };
61
+ }
62
+
63
+ /**
64
+ * A constant that indicates whether the environment the code is running is a Web Worker.
65
+ */
66
+ const isWebWorker =
67
+ typeof self === "object" &&
68
+ typeof self?.importScripts === "function" &&
69
+ (self.constructor?.name === "DedicatedWorkerGlobalScope" ||
70
+ self.constructor?.name === "ServiceWorkerGlobalScope" ||
71
+ self.constructor?.name === "SharedWorkerGlobalScope");
72
+ if (isWebWorker) {
73
+ return {
74
+ type: "web-worker",
75
+ };
76
+ }
77
+
78
+ /**
79
+ * A constant that indicates whether the environment the code is running is Deno.
80
+ * FYI Deno spoofs process.versions.node, see https://deno.land/std@0.177.0/node/process.ts?s=versions
81
+ */
82
+ const isDeno =
83
+ typeof Deno !== "undefined" && typeof Deno.version !== "undefined" && typeof Deno.version.deno !== "undefined";
84
+ if (isDeno) {
85
+ return {
86
+ type: "deno",
87
+ version: Deno.version.deno,
88
+ };
89
+ }
90
+
91
+ /**
92
+ * A constant that indicates whether the environment the code is running is Bun.sh.
93
+ */
94
+ const isBun = typeof Bun !== "undefined" && typeof Bun.version !== "undefined";
95
+ if (isBun) {
96
+ return {
97
+ type: "bun",
98
+ version: Bun.version,
99
+ };
100
+ }
101
+
102
+ /**
103
+ * A constant that indicates whether the environment the code is running is Node.JS.
104
+ */
105
+ const isNode =
106
+ typeof process !== "undefined" &&
107
+ "version" in process &&
108
+ !!process.version &&
109
+ "versions" in process &&
110
+ !!process.versions?.node;
111
+ if (isNode) {
112
+ return {
113
+ type: "node",
114
+ version: process.versions.node,
115
+ parsedVersion: Number(process.versions.node.split(".")[0]),
116
+ };
117
+ }
118
+
119
+ /**
120
+ * A constant that indicates whether the environment the code is running is in React-Native.
121
+ * https://github.com/facebook/react-native/blob/main/packages/react-native/Libraries/Core/setUpNavigator.js
122
+ */
123
+ const isReactNative = typeof navigator !== "undefined" && navigator?.product === "ReactNative";
124
+ if (isReactNative) {
125
+ return {
126
+ type: "react-native",
127
+ };
128
+ }
129
+
130
+ return {
131
+ type: "unknown",
132
+ };
133
+ }
@@ -0,0 +1,155 @@
1
+ import { RUNTIME } from "../runtime/index.js";
2
+
3
+ export declare namespace Stream {
4
+ interface Args {
5
+ /**
6
+ * The HTTP response stream to read from.
7
+ */
8
+
9
+ stream: ReadableStream;
10
+
11
+ /**
12
+ * The event shape to use for parsing the stream data.
13
+ */
14
+ eventShape: JsonEvent | SseEvent;
15
+ /**
16
+ * An abort signal to stop the stream.
17
+ */
18
+ signal?: AbortSignal;
19
+ }
20
+
21
+ interface JsonEvent {
22
+ type: "json";
23
+ messageTerminator: string;
24
+ }
25
+
26
+ interface SseEvent {
27
+ type: "sse";
28
+ streamTerminator?: string;
29
+ }
30
+ }
31
+
32
+ const DATA_PREFIX = "data:";
33
+
34
+ export class Stream<T> implements AsyncIterable<T> {
35
+ private stream: ReadableStream;
36
+
37
+ private parse: (val: unknown) => Promise<T>;
38
+ /**
39
+ * The prefix to use for each message. For example,
40
+ * for SSE, the prefix is "data: ".
41
+ */
42
+ private prefix: string | undefined;
43
+ private messageTerminator: string;
44
+ private streamTerminator: string | undefined;
45
+ private controller: AbortController = new AbortController();
46
+ private decoder: TextDecoder | undefined;
47
+
48
+ constructor({ stream, parse, eventShape, signal }: Stream.Args & { parse: (val: unknown) => Promise<T> }) {
49
+ this.stream = stream;
50
+ this.parse = parse;
51
+ if (eventShape.type === "sse") {
52
+ this.prefix = DATA_PREFIX;
53
+ this.messageTerminator = "\n";
54
+ this.streamTerminator = eventShape.streamTerminator;
55
+ } else {
56
+ this.messageTerminator = eventShape.messageTerminator;
57
+ }
58
+ signal?.addEventListener("abort", () => this.controller.abort());
59
+
60
+ // Initialize shared TextDecoder
61
+ if (typeof TextDecoder !== "undefined") {
62
+ this.decoder = new TextDecoder("utf-8");
63
+ }
64
+ }
65
+
66
+ private async *iterMessages(): AsyncGenerator<T, void> {
67
+ this.controller.signal;
68
+ const stream = readableStreamAsyncIterable<any>(this.stream);
69
+ let buf = "";
70
+ let prefixSeen = false;
71
+ for await (const chunk of stream) {
72
+ buf += this.decodeChunk(chunk);
73
+
74
+ let terminatorIndex: number;
75
+ while ((terminatorIndex = buf.indexOf(this.messageTerminator)) >= 0) {
76
+ let line = buf.slice(0, terminatorIndex);
77
+ buf = buf.slice(terminatorIndex + this.messageTerminator.length);
78
+
79
+ if (!line.trim()) {
80
+ continue;
81
+ }
82
+
83
+ if (!prefixSeen && this.prefix != null) {
84
+ const prefixIndex = line.indexOf(this.prefix);
85
+ if (prefixIndex === -1) {
86
+ continue;
87
+ }
88
+ prefixSeen = true;
89
+ line = line.slice(prefixIndex + this.prefix.length);
90
+ }
91
+
92
+ if (this.streamTerminator != null && line.includes(this.streamTerminator)) {
93
+ return;
94
+ }
95
+ const message = await this.parse(JSON.parse(line));
96
+ yield message;
97
+ prefixSeen = false;
98
+ }
99
+ }
100
+ }
101
+
102
+ async *[Symbol.asyncIterator](): AsyncIterator<T, void, unknown> {
103
+ for await (const message of this.iterMessages()) {
104
+ yield message;
105
+ }
106
+ }
107
+
108
+ private decodeChunk(chunk: any): string {
109
+ let decoded = "";
110
+ // If TextDecoder is available, use the streaming decoder instance
111
+ if (this.decoder != null) {
112
+ decoded += this.decoder.decode(chunk, { stream: true });
113
+ }
114
+ // Buffer is present in Node.js environment
115
+ else if (RUNTIME.type === "node" && typeof chunk !== "undefined") {
116
+ decoded += Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
117
+ }
118
+ return decoded;
119
+ }
120
+ }
121
+
122
+ /**
123
+ * Browser polyfill for ReadableStream
124
+ */
125
+ // biome-ignore lint/suspicious/noExplicitAny: allow explicit any
126
+ export function readableStreamAsyncIterable<T>(stream: any): AsyncIterableIterator<T> {
127
+ if (stream[Symbol.asyncIterator]) {
128
+ return stream;
129
+ }
130
+
131
+ const reader = stream.getReader();
132
+ return {
133
+ async next() {
134
+ try {
135
+ const result = await reader.read();
136
+ if (result?.done) {
137
+ reader.releaseLock();
138
+ } // release lock when stream becomes closed
139
+ return result;
140
+ } catch (e) {
141
+ reader.releaseLock(); // release lock when stream becomes errored
142
+ throw e;
143
+ }
144
+ },
145
+ async return() {
146
+ const cancelPromise = reader.cancel();
147
+ reader.releaseLock();
148
+ await cancelPromise;
149
+ return { done: true, value: undefined };
150
+ },
151
+ [Symbol.asyncIterator]() {
152
+ return this;
153
+ },
154
+ };
155
+ }
@@ -0,0 +1 @@
1
+ export { Stream } from "./Stream.js";
@@ -0,0 +1,18 @@
1
+ export function encodePathParam(param: unknown): string {
2
+ if (param === null) {
3
+ return "null";
4
+ }
5
+ const typeofParam = typeof param;
6
+ switch (typeofParam) {
7
+ case "undefined":
8
+ return "undefined";
9
+ case "string":
10
+ case "number":
11
+ case "boolean":
12
+ break;
13
+ default:
14
+ param = String(param);
15
+ break;
16
+ }
17
+ return encodeURIComponent(param as string | number | boolean);
18
+ }
@@ -0,0 +1,3 @@
1
+ export { encodePathParam } from "./encodePathParam.js";
2
+ export { join } from "./join.js";
3
+ export { toQueryString } from "./qs.js";
@@ -0,0 +1,80 @@
1
+ export function join(base: string, ...segments: string[]): string {
2
+ if (!base) {
3
+ return "";
4
+ }
5
+
6
+ if (segments.length === 0) {
7
+ return base;
8
+ }
9
+
10
+ if (base.includes("://")) {
11
+ let url: URL;
12
+ try {
13
+ url = new URL(base);
14
+ } catch {
15
+ // Fallback to path joining if URL is malformed
16
+ return joinPath(base, ...segments);
17
+ }
18
+
19
+ const lastSegment = segments[segments.length - 1];
20
+ const shouldPreserveTrailingSlash = lastSegment?.endsWith("/");
21
+
22
+ for (const segment of segments) {
23
+ const cleanSegment = trimSlashes(segment);
24
+ if (cleanSegment) {
25
+ url.pathname = joinPathSegments(url.pathname, cleanSegment);
26
+ }
27
+ }
28
+
29
+ if (shouldPreserveTrailingSlash && !url.pathname.endsWith("/")) {
30
+ url.pathname += "/";
31
+ }
32
+
33
+ return url.toString();
34
+ }
35
+
36
+ return joinPath(base, ...segments);
37
+ }
38
+
39
+ function joinPath(base: string, ...segments: string[]): string {
40
+ if (segments.length === 0) {
41
+ return base;
42
+ }
43
+
44
+ let result = base;
45
+
46
+ const lastSegment = segments[segments.length - 1];
47
+ const shouldPreserveTrailingSlash = lastSegment?.endsWith("/");
48
+
49
+ for (const segment of segments) {
50
+ const cleanSegment = trimSlashes(segment);
51
+ if (cleanSegment) {
52
+ result = joinPathSegments(result, cleanSegment);
53
+ }
54
+ }
55
+
56
+ if (shouldPreserveTrailingSlash && !result.endsWith("/")) {
57
+ result += "/";
58
+ }
59
+
60
+ return result;
61
+ }
62
+
63
+ function joinPathSegments(left: string, right: string): string {
64
+ if (left.endsWith("/")) {
65
+ return left + right;
66
+ }
67
+ return `${left}/${right}`;
68
+ }
69
+
70
+ function trimSlashes(str: string): string {
71
+ if (!str) return str;
72
+
73
+ let start = 0;
74
+ let end = str.length;
75
+
76
+ if (str.startsWith("/")) start = 1;
77
+ if (str.endsWith("/")) end = str.length - 1;
78
+
79
+ return start === 0 && end === str.length ? str : str.slice(start, end);
80
+ }
package/core/url/qs.ts ADDED
@@ -0,0 +1,74 @@
1
+ interface QueryStringOptions {
2
+ arrayFormat?: "indices" | "repeat";
3
+ encode?: boolean;
4
+ }
5
+
6
+ const defaultQsOptions: Required<QueryStringOptions> = {
7
+ arrayFormat: "indices",
8
+ encode: true,
9
+ } as const;
10
+
11
+ function encodeValue(value: unknown, shouldEncode: boolean): string {
12
+ if (value === undefined) {
13
+ return "";
14
+ }
15
+ if (value === null) {
16
+ return "";
17
+ }
18
+ const stringValue = String(value);
19
+ return shouldEncode ? encodeURIComponent(stringValue) : stringValue;
20
+ }
21
+
22
+ function stringifyObject(obj: Record<string, unknown>, prefix = "", options: Required<QueryStringOptions>): string[] {
23
+ const parts: string[] = [];
24
+
25
+ for (const [key, value] of Object.entries(obj)) {
26
+ const fullKey = prefix ? `${prefix}[${key}]` : key;
27
+
28
+ if (value === undefined) {
29
+ continue;
30
+ }
31
+
32
+ if (Array.isArray(value)) {
33
+ if (value.length === 0) {
34
+ continue;
35
+ }
36
+ for (let i = 0; i < value.length; i++) {
37
+ const item = value[i];
38
+ if (item === undefined) {
39
+ continue;
40
+ }
41
+ if (typeof item === "object" && !Array.isArray(item) && item !== null) {
42
+ const arrayKey = options.arrayFormat === "indices" ? `${fullKey}[${i}]` : fullKey;
43
+ parts.push(...stringifyObject(item as Record<string, unknown>, arrayKey, options));
44
+ } else {
45
+ const arrayKey = options.arrayFormat === "indices" ? `${fullKey}[${i}]` : fullKey;
46
+ const encodedKey = options.encode ? encodeURIComponent(arrayKey) : arrayKey;
47
+ parts.push(`${encodedKey}=${encodeValue(item, options.encode)}`);
48
+ }
49
+ }
50
+ } else if (typeof value === "object" && value !== null) {
51
+ if (Object.keys(value as Record<string, unknown>).length === 0) {
52
+ continue;
53
+ }
54
+ parts.push(...stringifyObject(value as Record<string, unknown>, fullKey, options));
55
+ } else {
56
+ const encodedKey = options.encode ? encodeURIComponent(fullKey) : fullKey;
57
+ parts.push(`${encodedKey}=${encodeValue(value, options.encode)}`);
58
+ }
59
+ }
60
+
61
+ return parts;
62
+ }
63
+
64
+ export function toQueryString(obj: unknown, options?: QueryStringOptions): string {
65
+ if (obj == null || typeof obj !== "object") {
66
+ return "";
67
+ }
68
+
69
+ const parts = stringifyObject(obj as Record<string, unknown>, "", {
70
+ ...defaultQsOptions,
71
+ ...options,
72
+ });
73
+ return parts.join("&");
74
+ }
@@ -0,0 +1,25 @@
1
+ import type * as core from "./core/index.js";
2
+ export interface BaseClientOptions {
3
+ environment: core.Supplier<string>;
4
+ /** Specify a custom URL to connect the client to. */
5
+ baseUrl?: core.Supplier<string>;
6
+ /** Additional headers to include in requests. */
7
+ headers?: Record<string, string | core.Supplier<string | null | undefined> | null | undefined>;
8
+ /** The default maximum time to wait for a response in seconds. */
9
+ timeoutInSeconds?: number;
10
+ /** The default number of times to retry the request. Defaults to 2. */
11
+ maxRetries?: number;
12
+ }
13
+ export interface BaseRequestOptions {
14
+ /** The maximum time to wait for a response in seconds. */
15
+ timeoutInSeconds?: number;
16
+ /** The number of times to retry the request. Defaults to 2. */
17
+ maxRetries?: number;
18
+ /** A hook to abort the request. */
19
+ abortSignal?: AbortSignal;
20
+ /** Additional query string parameters to include in the request. */
21
+ queryParams?: Record<string, unknown>;
22
+ /** Additional headers to include in the request. */
23
+ headers?: Record<string, string | core.Supplier<string | null | undefined> | null | undefined>;
24
+ }
25
+ //# sourceMappingURL=BaseClient.d.ts.map