@planqk/planqk-api-sdk 1.0.0

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 (222) hide show
  1. package/.devcontainer/devcontainer.json +32 -0
  2. package/.devcontainer/post-create.sh +7 -0
  3. package/.env.template +2 -0
  4. package/.gitlab-ci.yml +71 -0
  5. package/.python-version +1 -0
  6. package/.releaserc.json +45 -0
  7. package/LICENSE +201 -0
  8. package/README-node.md +18 -0
  9. package/README-python.md +21 -0
  10. package/README.md +56 -0
  11. package/dist/Client.d.ts +32 -0
  12. package/dist/Client.js +60 -0
  13. package/dist/api/errors/BadRequestError.d.ts +8 -0
  14. package/dist/api/errors/BadRequestError.js +52 -0
  15. package/dist/api/errors/ForbiddenError.d.ts +8 -0
  16. package/dist/api/errors/ForbiddenError.js +52 -0
  17. package/dist/api/errors/InternalServerError.d.ts +8 -0
  18. package/dist/api/errors/InternalServerError.js +52 -0
  19. package/dist/api/errors/NotFoundError.d.ts +8 -0
  20. package/dist/api/errors/NotFoundError.js +52 -0
  21. package/dist/api/errors/UnauthorizedError.d.ts +8 -0
  22. package/dist/api/errors/UnauthorizedError.js +52 -0
  23. package/dist/api/errors/index.d.ts +5 -0
  24. package/dist/api/errors/index.js +21 -0
  25. package/dist/api/index.d.ts +3 -0
  26. package/dist/api/index.js +19 -0
  27. package/dist/api/resources/dataPools/client/Client.d.ts +177 -0
  28. package/dist/api/resources/dataPools/client/Client.js +676 -0
  29. package/dist/api/resources/dataPools/client/index.d.ts +2 -0
  30. package/dist/api/resources/dataPools/client/index.js +17 -0
  31. package/dist/api/resources/dataPools/client/requests/AddDataPoolFileRequest.d.ts +14 -0
  32. package/dist/api/resources/dataPools/client/requests/AddDataPoolFileRequest.js +5 -0
  33. package/dist/api/resources/dataPools/client/requests/CreateDataPoolRequest.d.ts +10 -0
  34. package/dist/api/resources/dataPools/client/requests/CreateDataPoolRequest.js +5 -0
  35. package/dist/api/resources/dataPools/client/requests/UpdateDataPoolRequest.d.ts +12 -0
  36. package/dist/api/resources/dataPools/client/requests/UpdateDataPoolRequest.js +5 -0
  37. package/dist/api/resources/dataPools/client/requests/index.d.ts +3 -0
  38. package/dist/api/resources/dataPools/client/requests/index.js +2 -0
  39. package/dist/api/resources/dataPools/index.d.ts +1 -0
  40. package/dist/api/resources/dataPools/index.js +17 -0
  41. package/dist/api/resources/index.d.ts +2 -0
  42. package/dist/api/resources/index.js +41 -0
  43. package/dist/api/types/DataPoolDto.d.ts +23 -0
  44. package/dist/api/types/DataPoolDto.js +14 -0
  45. package/dist/api/types/DataPoolFileDto.d.ts +12 -0
  46. package/dist/api/types/DataPoolFileDto.js +5 -0
  47. package/dist/api/types/OauthScope.d.ts +9 -0
  48. package/dist/api/types/OauthScope.js +9 -0
  49. package/dist/api/types/index.d.ts +3 -0
  50. package/dist/api/types/index.js +19 -0
  51. package/dist/core/fetcher/APIResponse.d.ts +20 -0
  52. package/dist/core/fetcher/APIResponse.js +2 -0
  53. package/dist/core/fetcher/BinaryResponse.d.ts +20 -0
  54. package/dist/core/fetcher/BinaryResponse.js +17 -0
  55. package/dist/core/fetcher/Fetcher.d.ts +40 -0
  56. package/dist/core/fetcher/Fetcher.js +105 -0
  57. package/dist/core/fetcher/Headers.d.ts +2 -0
  58. package/dist/core/fetcher/Headers.js +85 -0
  59. package/dist/core/fetcher/HttpResponsePromise.d.ts +58 -0
  60. package/dist/core/fetcher/HttpResponsePromise.js +94 -0
  61. package/dist/core/fetcher/RawResponse.d.ts +29 -0
  62. package/dist/core/fetcher/RawResponse.js +44 -0
  63. package/dist/core/fetcher/ResponseWithBody.d.ts +4 -0
  64. package/dist/core/fetcher/ResponseWithBody.js +6 -0
  65. package/dist/core/fetcher/Supplier.d.ts +4 -0
  66. package/dist/core/fetcher/Supplier.js +13 -0
  67. package/dist/core/fetcher/createRequestUrl.d.ts +1 -0
  68. package/dist/core/fetcher/createRequestUrl.js +8 -0
  69. package/dist/core/fetcher/getErrorResponseBody.d.ts +1 -0
  70. package/dist/core/fetcher/getErrorResponseBody.js +32 -0
  71. package/dist/core/fetcher/getFetchFn.d.ts +1 -0
  72. package/dist/core/fetcher/getFetchFn.js +6 -0
  73. package/dist/core/fetcher/getHeader.d.ts +1 -0
  74. package/dist/core/fetcher/getHeader.js +11 -0
  75. package/dist/core/fetcher/getRequestBody.d.ts +7 -0
  76. package/dist/core/fetcher/getRequestBody.js +12 -0
  77. package/dist/core/fetcher/getResponseBody.d.ts +1 -0
  78. package/dist/core/fetcher/getResponseBody.js +44 -0
  79. package/dist/core/fetcher/index.d.ts +9 -0
  80. package/dist/core/fetcher/index.js +15 -0
  81. package/dist/core/fetcher/makeRequest.d.ts +1 -0
  82. package/dist/core/fetcher/makeRequest.js +33 -0
  83. package/dist/core/fetcher/requestWithRetries.d.ts +1 -0
  84. package/dist/core/fetcher/requestWithRetries.js +29 -0
  85. package/dist/core/fetcher/signals.d.ts +11 -0
  86. package/dist/core/fetcher/signals.js +36 -0
  87. package/dist/core/file.d.ts +1 -0
  88. package/dist/core/file.js +2 -0
  89. package/dist/core/form-data-utils/FormDataWrapper.d.ts +16 -0
  90. package/dist/core/form-data-utils/FormDataWrapper.js +166 -0
  91. package/dist/core/form-data-utils/encodeAsFormParameter.d.ts +1 -0
  92. package/dist/core/form-data-utils/encodeAsFormParameter.js +12 -0
  93. package/dist/core/form-data-utils/index.d.ts +2 -0
  94. package/dist/core/form-data-utils/index.js +20 -0
  95. package/dist/core/headers.d.ts +3 -0
  96. package/dist/core/headers.js +29 -0
  97. package/dist/core/index.d.ts +5 -0
  98. package/dist/core/index.js +44 -0
  99. package/dist/core/json.d.ts +15 -0
  100. package/dist/core/json.js +24 -0
  101. package/dist/core/runtime/index.d.ts +1 -0
  102. package/dist/core/runtime/index.js +5 -0
  103. package/dist/core/runtime/runtime.d.ts +9 -0
  104. package/dist/core/runtime/runtime.js +101 -0
  105. package/dist/core/url/index.d.ts +2 -0
  106. package/dist/core/url/index.js +7 -0
  107. package/dist/core/url/join.d.ts +1 -0
  108. package/dist/core/url/join.js +49 -0
  109. package/dist/core/url/qs.d.ts +6 -0
  110. package/dist/core/url/qs.js +67 -0
  111. package/dist/environments.d.ts +7 -0
  112. package/dist/environments.js +9 -0
  113. package/dist/errors/PlanqkApiError.d.ts +15 -0
  114. package/dist/errors/PlanqkApiError.js +33 -0
  115. package/dist/errors/PlanqkApiTimeoutError.d.ts +6 -0
  116. package/dist/errors/PlanqkApiTimeoutError.js +13 -0
  117. package/dist/errors/index.d.ts +2 -0
  118. package/dist/errors/index.js +7 -0
  119. package/dist/index.d.ts +4 -0
  120. package/dist/index.js +44 -0
  121. package/eslint.config.mjs +11 -0
  122. package/fern/fern.config.json +4 -0
  123. package/fern/generators.yml +25 -0
  124. package/fern/openapi/openapi.json +610 -0
  125. package/notebooks/python-sdk.ipynb +218 -0
  126. package/package.json +48 -0
  127. package/planqk/__init__.py +0 -0
  128. package/planqk/api/__init__.py +1 -0
  129. package/planqk/api/_version.py +1 -0
  130. package/planqk/api/client.py +19 -0
  131. package/planqk/api/credentials.py +103 -0
  132. package/planqk/api/sdk/__init__.py +25 -0
  133. package/planqk/api/sdk/client.py +153 -0
  134. package/planqk/api/sdk/core/__init__.py +52 -0
  135. package/planqk/api/sdk/core/api_error.py +23 -0
  136. package/planqk/api/sdk/core/client_wrapper.py +76 -0
  137. package/planqk/api/sdk/core/datetime_utils.py +28 -0
  138. package/planqk/api/sdk/core/file.py +67 -0
  139. package/planqk/api/sdk/core/force_multipart.py +16 -0
  140. package/planqk/api/sdk/core/http_client.py +543 -0
  141. package/planqk/api/sdk/core/http_response.py +55 -0
  142. package/planqk/api/sdk/core/jsonable_encoder.py +100 -0
  143. package/planqk/api/sdk/core/pydantic_utilities.py +255 -0
  144. package/planqk/api/sdk/core/query_encoder.py +58 -0
  145. package/planqk/api/sdk/core/remove_none_from_dict.py +11 -0
  146. package/planqk/api/sdk/core/request_options.py +35 -0
  147. package/planqk/api/sdk/core/serialization.py +276 -0
  148. package/planqk/api/sdk/data_pools/__init__.py +4 -0
  149. package/planqk/api/sdk/data_pools/client.py +700 -0
  150. package/planqk/api/sdk/data_pools/raw_client.py +1650 -0
  151. package/planqk/api/sdk/environment.py +7 -0
  152. package/planqk/api/sdk/errors/__init__.py +11 -0
  153. package/planqk/api/sdk/errors/bad_request_error.py +10 -0
  154. package/planqk/api/sdk/errors/forbidden_error.py +10 -0
  155. package/planqk/api/sdk/errors/internal_server_error.py +10 -0
  156. package/planqk/api/sdk/errors/not_found_error.py +10 -0
  157. package/planqk/api/sdk/errors/unauthorized_error.py +10 -0
  158. package/planqk/api/sdk/types/__init__.py +10 -0
  159. package/planqk/api/sdk/types/data_pool_dto.py +33 -0
  160. package/planqk/api/sdk/types/data_pool_dto_current_user_permission.py +5 -0
  161. package/planqk/api/sdk/types/data_pool_file_dto.py +27 -0
  162. package/planqk/api/sdk/types/oauth_scope.py +5 -0
  163. package/pyproject.toml +51 -0
  164. package/scripts/update-version.sh +6 -0
  165. package/src/Client.ts +53 -0
  166. package/src/api/errors/BadRequestError.ts +18 -0
  167. package/src/api/errors/ForbiddenError.ts +18 -0
  168. package/src/api/errors/InternalServerError.ts +18 -0
  169. package/src/api/errors/NotFoundError.ts +18 -0
  170. package/src/api/errors/UnauthorizedError.ts +18 -0
  171. package/src/api/errors/index.ts +5 -0
  172. package/src/api/index.ts +3 -0
  173. package/src/api/resources/dataPools/client/Client.ts +825 -0
  174. package/src/api/resources/dataPools/client/index.ts +2 -0
  175. package/src/api/resources/dataPools/client/requests/AddDataPoolFileRequest.ts +17 -0
  176. package/src/api/resources/dataPools/client/requests/CreateDataPoolRequest.ts +11 -0
  177. package/src/api/resources/dataPools/client/requests/UpdateDataPoolRequest.ts +13 -0
  178. package/src/api/resources/dataPools/client/requests/index.ts +3 -0
  179. package/src/api/resources/dataPools/index.ts +1 -0
  180. package/src/api/resources/index.ts +2 -0
  181. package/src/api/types/DataPoolDto.ts +25 -0
  182. package/src/api/types/DataPoolFileDto.ts +13 -0
  183. package/src/api/types/OauthScope.ts +10 -0
  184. package/src/api/types/index.ts +3 -0
  185. package/src/core/fetcher/APIResponse.ts +23 -0
  186. package/src/core/fetcher/BinaryResponse.ts +36 -0
  187. package/src/core/fetcher/Fetcher.ts +163 -0
  188. package/src/core/fetcher/Headers.ts +93 -0
  189. package/src/core/fetcher/HttpResponsePromise.ts +116 -0
  190. package/src/core/fetcher/RawResponse.ts +61 -0
  191. package/src/core/fetcher/ResponseWithBody.ts +7 -0
  192. package/src/core/fetcher/Supplier.ts +11 -0
  193. package/src/core/fetcher/createRequestUrl.ts +6 -0
  194. package/src/core/fetcher/getErrorResponseBody.ts +32 -0
  195. package/src/core/fetcher/getFetchFn.ts +3 -0
  196. package/src/core/fetcher/getHeader.ts +8 -0
  197. package/src/core/fetcher/getRequestBody.ts +16 -0
  198. package/src/core/fetcher/getResponseBody.ts +43 -0
  199. package/src/core/fetcher/index.ts +9 -0
  200. package/src/core/fetcher/makeRequest.ts +44 -0
  201. package/src/core/fetcher/requestWithRetries.ts +33 -0
  202. package/src/core/fetcher/signals.ts +38 -0
  203. package/src/core/file.ts +11 -0
  204. package/src/core/form-data-utils/FormDataWrapper.ts +176 -0
  205. package/src/core/form-data-utils/encodeAsFormParameter.ts +12 -0
  206. package/src/core/form-data-utils/index.ts +2 -0
  207. package/src/core/headers.ts +35 -0
  208. package/src/core/index.ts +5 -0
  209. package/src/core/json.ts +27 -0
  210. package/src/core/runtime/index.ts +1 -0
  211. package/src/core/runtime/runtime.ts +133 -0
  212. package/src/core/url/index.ts +2 -0
  213. package/src/core/url/join.ts +55 -0
  214. package/src/core/url/qs.ts +74 -0
  215. package/src/environments.ts +9 -0
  216. package/src/errors/PlanqkApiError.ts +55 -0
  217. package/src/errors/PlanqkApiTimeoutError.ts +10 -0
  218. package/src/errors/index.ts +2 -0
  219. package/src/index.test.ts +17 -0
  220. package/src/index.ts +4 -0
  221. package/tsconfig.json +18 -0
  222. package/uv.lock +1102 -0
@@ -0,0 +1,8 @@
1
+ export function getHeader(headers: Record<string, any>, header: string): string | undefined {
2
+ for (const [headerKey, headerValue] of Object.entries(headers)) {
3
+ if (headerKey.toLowerCase() === header.toLowerCase()) {
4
+ return headerValue;
5
+ }
6
+ }
7
+ return undefined;
8
+ }
@@ -0,0 +1,16 @@
1
+ import { toJson } from "../json.js";
2
+
3
+ export declare namespace GetRequestBody {
4
+ interface Args {
5
+ body: unknown;
6
+ type: "json" | "file" | "bytes" | "other";
7
+ }
8
+ }
9
+
10
+ export async function getRequestBody({ body, type }: GetRequestBody.Args): Promise<BodyInit | undefined> {
11
+ if (type.includes("json")) {
12
+ return toJson(body);
13
+ } else {
14
+ return body as BodyInit;
15
+ }
16
+ }
@@ -0,0 +1,43 @@
1
+ import { getBinaryResponse } from "./BinaryResponse.js";
2
+ import { isResponseWithBody } from "./ResponseWithBody.js";
3
+ import { fromJson } from "../json.js";
4
+
5
+ export async function getResponseBody(response: Response, responseType?: string): Promise<unknown> {
6
+ if (!isResponseWithBody(response)) {
7
+ return undefined;
8
+ }
9
+ switch (responseType) {
10
+ case "binary-response":
11
+ return getBinaryResponse(response);
12
+ case "blob":
13
+ return await response.blob();
14
+ case "arrayBuffer":
15
+ return await response.arrayBuffer();
16
+ case "sse":
17
+ return response.body;
18
+ case "streaming":
19
+ return response.body;
20
+
21
+ case "text":
22
+ return await response.text();
23
+ }
24
+
25
+ // if responseType is "json" or not specified, try to parse as JSON
26
+ const text = await response.text();
27
+ if (text.length > 0) {
28
+ try {
29
+ let responseBody = fromJson(text);
30
+ return responseBody;
31
+ } catch (err) {
32
+ return {
33
+ ok: false,
34
+ error: {
35
+ reason: "non-json",
36
+ statusCode: response.status,
37
+ rawBody: text,
38
+ },
39
+ };
40
+ }
41
+ }
42
+ return undefined;
43
+ }
@@ -0,0 +1,9 @@
1
+ export type { APIResponse } from "./APIResponse.js";
2
+ export { fetcher } from "./Fetcher.js";
3
+ export type { Fetcher, FetchFunction } from "./Fetcher.js";
4
+ export { getHeader } from "./getHeader.js";
5
+ export { Supplier } from "./Supplier.js";
6
+ export { abortRawResponse, toRawResponse, unknownRawResponse } from "./RawResponse.js";
7
+ export type { RawResponse, WithRawResponse } from "./RawResponse.js";
8
+ export { HttpResponsePromise } from "./HttpResponsePromise.js";
9
+ export { BinaryResponse } from "./BinaryResponse.js";
@@ -0,0 +1,44 @@
1
+ import { anySignal, getTimeoutSignal } from "./signals.js";
2
+
3
+ export const makeRequest = async (
4
+ fetchFn: (url: string, init: RequestInit) => Promise<Response>,
5
+ url: string,
6
+ method: string,
7
+ headers: Record<string, string>,
8
+ requestBody: BodyInit | undefined,
9
+ timeoutMs?: number,
10
+ abortSignal?: AbortSignal,
11
+ withCredentials?: boolean,
12
+ duplex?: "half",
13
+ ): Promise<Response> => {
14
+ const signals: AbortSignal[] = [];
15
+
16
+ // Add timeout signal
17
+ let timeoutAbortId: NodeJS.Timeout | undefined = undefined;
18
+ if (timeoutMs != null) {
19
+ const { signal, abortId } = getTimeoutSignal(timeoutMs);
20
+ timeoutAbortId = abortId;
21
+ signals.push(signal);
22
+ }
23
+
24
+ // Add arbitrary signal
25
+ if (abortSignal != null) {
26
+ signals.push(abortSignal);
27
+ }
28
+ let newSignals = anySignal(signals);
29
+ const response = await fetchFn(url, {
30
+ method: method,
31
+ headers,
32
+ body: requestBody,
33
+ signal: newSignals,
34
+ credentials: withCredentials ? "include" : undefined,
35
+ // @ts-ignore
36
+ duplex,
37
+ });
38
+
39
+ if (timeoutAbortId != null) {
40
+ clearTimeout(timeoutAbortId);
41
+ }
42
+
43
+ return response;
44
+ };
@@ -0,0 +1,33 @@
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 addJitter(delay: number): number {
7
+ // Generate a random value between -JITTER_FACTOR and +JITTER_FACTOR
8
+ const jitterMultiplier = 1 + (Math.random() * 2 - 1) * JITTER_FACTOR;
9
+ return delay * jitterMultiplier;
10
+ }
11
+
12
+ export async function requestWithRetries(
13
+ requestFn: () => Promise<Response>,
14
+ maxRetries: number = DEFAULT_MAX_RETRIES,
15
+ ): Promise<Response> {
16
+ let response: Response = await requestFn();
17
+
18
+ for (let i = 0; i < maxRetries; ++i) {
19
+ if ([408, 429].includes(response.status) || response.status >= 500) {
20
+ // Calculate base delay using exponential backoff (in milliseconds)
21
+ const baseDelay = Math.min(INITIAL_RETRY_DELAY * Math.pow(2, i), MAX_RETRY_DELAY);
22
+
23
+ // Add jitter to the delay
24
+ const delayWithJitter = addJitter(baseDelay);
25
+
26
+ await new Promise((resolve) => setTimeout(resolve, delayWithJitter));
27
+ response = await requestFn();
28
+ } else {
29
+ break;
30
+ }
31
+ }
32
+ return response!;
33
+ }
@@ -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,11 @@
1
+ export type FileLike =
2
+ | ArrayBuffer
3
+ | Uint8Array
4
+ | import("buffer").Buffer
5
+ | import("buffer").Blob
6
+ | import("buffer").File
7
+ | import("stream").Readable
8
+ | import("stream/web").ReadableStream
9
+ | globalThis.Blob
10
+ | globalThis.File
11
+ | ReadableStream;
@@ -0,0 +1,176 @@
1
+ import { toJson } from "../../core/json.js";
2
+ import { RUNTIME } from "../runtime/index.js";
3
+
4
+ type NamedValue = {
5
+ name: string;
6
+ } & unknown;
7
+
8
+ type PathedValue = {
9
+ path: string | { toString(): string };
10
+ } & unknown;
11
+
12
+ type StreamLike = {
13
+ read?: () => unknown;
14
+ pipe?: (dest: unknown) => unknown;
15
+ } & unknown;
16
+
17
+ function isNamedValue(value: unknown): value is NamedValue {
18
+ return typeof value === "object" && value != null && "name" in value;
19
+ }
20
+
21
+ function isPathedValue(value: unknown): value is PathedValue {
22
+ return typeof value === "object" && value != null && "path" in value;
23
+ }
24
+
25
+ function isStreamLike(value: unknown): value is StreamLike {
26
+ return typeof value === "object" && value != null && ("read" in value || "pipe" in value);
27
+ }
28
+
29
+ function isReadableStream(value: unknown): value is ReadableStream {
30
+ return typeof value === "object" && value != null && "getReader" in value;
31
+ }
32
+
33
+ function isBuffer(value: unknown): value is Buffer {
34
+ return typeof Buffer !== "undefined" && Buffer.isBuffer && Buffer.isBuffer(value);
35
+ }
36
+
37
+ function isArrayBufferView(value: unknown): value is ArrayBufferView {
38
+ return ArrayBuffer.isView(value);
39
+ }
40
+
41
+ interface FormDataRequest<Body> {
42
+ body: Body;
43
+ headers: Record<string, string>;
44
+ duplex?: "half";
45
+ }
46
+
47
+ function getLastPathSegment(pathStr: string): string {
48
+ const lastForwardSlash = pathStr.lastIndexOf("/");
49
+ const lastBackSlash = pathStr.lastIndexOf("\\");
50
+ const lastSlashIndex = Math.max(lastForwardSlash, lastBackSlash);
51
+ return lastSlashIndex >= 0 ? pathStr.substring(lastSlashIndex + 1) : pathStr;
52
+ }
53
+
54
+ async function streamToBuffer(stream: unknown): Promise<Buffer> {
55
+ if (RUNTIME.type === "node") {
56
+ const { Readable } = await import("stream");
57
+
58
+ if (stream instanceof Readable) {
59
+ const chunks: Buffer[] = [];
60
+ for await (const chunk of stream) {
61
+ chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
62
+ }
63
+ return Buffer.concat(chunks);
64
+ }
65
+ }
66
+
67
+ if (isReadableStream(stream)) {
68
+ const reader = stream.getReader();
69
+ const chunks: Uint8Array[] = [];
70
+
71
+ try {
72
+ while (true) {
73
+ const { done, value } = await reader.read();
74
+ if (done) break;
75
+ chunks.push(value);
76
+ }
77
+ } finally {
78
+ reader.releaseLock();
79
+ }
80
+
81
+ const totalLength = chunks.reduce((sum, chunk) => sum + chunk.length, 0);
82
+ const result = new Uint8Array(totalLength);
83
+ let offset = 0;
84
+ for (const chunk of chunks) {
85
+ result.set(chunk, offset);
86
+ offset += chunk.length;
87
+ }
88
+
89
+ return Buffer.from(result);
90
+ }
91
+
92
+ throw new Error(
93
+ "Unsupported stream type: " + typeof stream + ". Expected Node.js Readable stream or Web ReadableStream.",
94
+ );
95
+ }
96
+
97
+ export async function newFormData(): Promise<FormDataWrapper> {
98
+ return new FormDataWrapper();
99
+ }
100
+
101
+ export class FormDataWrapper {
102
+ private fd: FormData = new FormData();
103
+
104
+ public async setup(): Promise<void> {
105
+ // noop
106
+ }
107
+
108
+ public append(key: string, value: unknown): void {
109
+ this.fd.append(key, String(value));
110
+ }
111
+
112
+ private getFileName(value: unknown, filename?: string): string | undefined {
113
+ if (filename != null) {
114
+ return filename;
115
+ }
116
+ if (isNamedValue(value)) {
117
+ return value.name;
118
+ }
119
+ if (isPathedValue(value) && value.path) {
120
+ return getLastPathSegment(value.path.toString());
121
+ }
122
+ return undefined;
123
+ }
124
+
125
+ private async convertToBlob(value: unknown): Promise<Blob> {
126
+ if (isStreamLike(value) || isReadableStream(value)) {
127
+ const buffer = await streamToBuffer(value);
128
+ return new Blob([buffer]);
129
+ }
130
+
131
+ if (value instanceof Blob) {
132
+ return value;
133
+ }
134
+
135
+ if (isBuffer(value)) {
136
+ return new Blob([value]);
137
+ }
138
+
139
+ if (value instanceof ArrayBuffer) {
140
+ return new Blob([value]);
141
+ }
142
+
143
+ if (isArrayBufferView(value)) {
144
+ return new Blob([value]);
145
+ }
146
+
147
+ if (typeof value === "string") {
148
+ return new Blob([value]);
149
+ }
150
+
151
+ if (typeof value === "object" && value !== null) {
152
+ return new Blob([toJson(value)], { type: "application/json" });
153
+ }
154
+
155
+ return new Blob([String(value)]);
156
+ }
157
+
158
+ public async appendFile(key: string, value: unknown, fileName?: string): Promise<void> {
159
+ fileName = this.getFileName(value, fileName);
160
+ const blob = await this.convertToBlob(value);
161
+
162
+ if (fileName) {
163
+ this.fd.append(key, blob, fileName);
164
+ } else {
165
+ this.fd.append(key, blob);
166
+ }
167
+ }
168
+
169
+ public getRequest(): FormDataRequest<FormData> {
170
+ return {
171
+ body: this.fd,
172
+ headers: {},
173
+ duplex: "half" as const,
174
+ };
175
+ }
176
+ }
@@ -0,0 +1,12 @@
1
+ import { toQueryString } from "../url/qs.js";
2
+
3
+ export function encodeAsFormParameter(value: unknown): Record<string, string> {
4
+ const stringified = toQueryString(value, { encode: false });
5
+
6
+ const keyValuePairs = stringified.split("&").map((pair) => {
7
+ const [key, value] = pair.split("=");
8
+ return [key, value] as const;
9
+ });
10
+
11
+ return Object.fromEntries(keyValuePairs);
12
+ }
@@ -0,0 +1,2 @@
1
+ export { encodeAsFormParameter } from "./encodeAsFormParameter.js";
2
+ export * from "./FormDataWrapper.js";
@@ -0,0 +1,35 @@
1
+ import * as core from "./index.js";
2
+
3
+ export function mergeHeaders(
4
+ ...headersArray: (Record<string, string | core.Supplier<string | undefined> | undefined> | undefined)[]
5
+ ): Record<string, string | core.Supplier<string | undefined>> {
6
+ const result: Record<string, string | core.Supplier<string | undefined>> = {};
7
+
8
+ for (const [key, value] of headersArray
9
+ .filter((headers) => headers != null)
10
+ .flatMap((headers) => Object.entries(headers))) {
11
+ if (value != null) {
12
+ result[key] = value;
13
+ } else if (key in result) {
14
+ delete result[key];
15
+ }
16
+ }
17
+
18
+ return result;
19
+ }
20
+
21
+ export function mergeOnlyDefinedHeaders(
22
+ ...headersArray: (Record<string, string | core.Supplier<string | undefined> | undefined> | undefined)[]
23
+ ): Record<string, string | core.Supplier<string | undefined>> {
24
+ const result: Record<string, string | core.Supplier<string | undefined>> = {};
25
+
26
+ for (const [key, value] of headersArray
27
+ .filter((headers) => headers != null)
28
+ .flatMap((headers) => Object.entries(headers))) {
29
+ if (value != null) {
30
+ result[key] = value;
31
+ }
32
+ }
33
+
34
+ return result;
35
+ }
@@ -0,0 +1,5 @@
1
+ export * from "./fetcher/index.js";
2
+ export * from "./runtime/index.js";
3
+ export * as url from "./url/index.js";
4
+ export * from "./form-data-utils/index.js";
5
+ export * from "./file.js";
@@ -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,2 @@
1
+ export { join } from "./join.js";
2
+ export { toQueryString } from "./qs.js";
@@ -0,0 +1,55 @@
1
+ export function join(base: string, ...segments: string[]): string {
2
+ if (!base) {
3
+ return "";
4
+ }
5
+
6
+ if (base.includes("://")) {
7
+ let url: URL;
8
+ try {
9
+ url = new URL(base);
10
+ } catch {
11
+ // Fallback to path joining if URL is malformed
12
+ return joinPath(base, ...segments);
13
+ }
14
+
15
+ for (const segment of segments) {
16
+ const cleanSegment = trimSlashes(segment);
17
+ if (cleanSegment) {
18
+ url.pathname = joinPathSegments(url.pathname, cleanSegment);
19
+ }
20
+ }
21
+
22
+ return url.toString();
23
+ }
24
+
25
+ return joinPath(base, ...segments);
26
+ }
27
+
28
+ function joinPath(base: string, ...segments: string[]): string {
29
+ let result = base;
30
+
31
+ for (const segment of segments) {
32
+ const cleanSegment = trimSlashes(segment);
33
+ if (cleanSegment) {
34
+ result = joinPathSegments(result, cleanSegment);
35
+ }
36
+ }
37
+
38
+ return result;
39
+ }
40
+
41
+ function joinPathSegments(left: string, right: string): string {
42
+ if (left.endsWith("/")) {
43
+ return left + right;
44
+ }
45
+ return left + "/" + right;
46
+ }
47
+
48
+ function trimSlashes(str: string): string {
49
+ if (!str) return str;
50
+
51
+ let start = str.startsWith("/") ? 1 : 0;
52
+ let end = str.endsWith("/") ? str.length - 1 : str.length;
53
+
54
+ return str.slice(start, end);
55
+ }