@planqk/planqk-service-sdk 2.1.1 → 2.2.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 (173) hide show
  1. package/.gitlab-ci.yml +8 -39
  2. package/README-node.md +16 -12
  3. package/README.md +30 -41
  4. package/dist/sdk/Client.d.ts +10 -4
  5. package/dist/sdk/Client.js +46 -4
  6. package/dist/sdk/api/index.d.ts +2 -3
  7. package/dist/sdk/api/index.js +2 -3
  8. package/dist/sdk/api/resources/index.d.ts +2 -2
  9. package/dist/sdk/api/resources/index.js +2 -2
  10. package/dist/sdk/api/resources/serviceApi/client/Client.d.ts +41 -55
  11. package/dist/sdk/api/resources/serviceApi/client/Client.js +131 -227
  12. package/dist/sdk/api/resources/serviceApi/index.d.ts +2 -2
  13. package/dist/sdk/api/resources/serviceApi/index.js +2 -2
  14. package/dist/sdk/api/resources/serviceApi/types/GetResultResponse.d.ts +13 -3
  15. package/dist/sdk/api/resources/serviceApi/types/index.d.ts +1 -4
  16. package/dist/sdk/api/resources/serviceApi/types/index.js +1 -4
  17. package/dist/sdk/api/types/ServiceExecution.d.ts +12 -2
  18. package/dist/sdk/api/types/ServiceExecution.js +12 -0
  19. package/dist/sdk/api/types/index.d.ts +2 -6
  20. package/dist/sdk/api/types/index.js +2 -6
  21. package/dist/sdk/core/auth/BasicAuth.js +3 -3
  22. package/dist/sdk/core/auth/index.d.ts +2 -2
  23. package/dist/sdk/core/auth/index.js +4 -4
  24. package/dist/sdk/core/base64.d.ts +2 -0
  25. package/dist/sdk/core/base64.js +26 -0
  26. package/dist/sdk/core/fetcher/APIResponse.d.ts +10 -0
  27. package/dist/sdk/core/fetcher/BinaryResponse.d.ts +20 -0
  28. package/dist/sdk/core/fetcher/BinaryResponse.js +17 -0
  29. package/dist/sdk/core/fetcher/Fetcher.d.ts +5 -4
  30. package/dist/sdk/core/fetcher/Fetcher.js +41 -22
  31. package/dist/sdk/core/fetcher/Headers.d.ts +2 -0
  32. package/dist/sdk/core/fetcher/Headers.js +85 -0
  33. package/dist/sdk/core/fetcher/HttpResponsePromise.d.ts +58 -0
  34. package/dist/sdk/core/fetcher/HttpResponsePromise.js +94 -0
  35. package/dist/sdk/core/fetcher/RawResponse.d.ts +29 -0
  36. package/dist/sdk/core/fetcher/RawResponse.js +44 -0
  37. package/dist/sdk/core/fetcher/ResponseWithBody.d.ts +4 -0
  38. package/dist/sdk/core/fetcher/ResponseWithBody.js +6 -0
  39. package/dist/sdk/core/fetcher/createRequestUrl.d.ts +1 -1
  40. package/dist/sdk/core/fetcher/createRequestUrl.js +3 -7
  41. package/dist/sdk/core/fetcher/getErrorResponseBody.d.ts +1 -0
  42. package/dist/sdk/core/fetcher/getErrorResponseBody.js +32 -0
  43. package/dist/sdk/core/fetcher/getFetchFn.d.ts +1 -4
  44. package/dist/sdk/core/fetcher/getFetchFn.js +1 -52
  45. package/dist/sdk/core/fetcher/getRequestBody.js +2 -1
  46. package/dist/sdk/core/fetcher/getResponseBody.js +34 -30
  47. package/dist/sdk/core/fetcher/index.d.ts +9 -5
  48. package/dist/sdk/core/fetcher/index.js +13 -7
  49. package/dist/sdk/core/fetcher/makeRequest.js +3 -3
  50. package/dist/sdk/core/fetcher/requestWithRetries.js +14 -5
  51. package/dist/sdk/core/headers.d.ts +3 -0
  52. package/dist/sdk/core/headers.js +29 -0
  53. package/dist/sdk/core/index.d.ts +5 -3
  54. package/dist/sdk/core/index.js +28 -3
  55. package/dist/sdk/core/json.d.ts +15 -0
  56. package/dist/sdk/core/json.js +24 -0
  57. package/dist/sdk/core/runtime/index.d.ts +1 -1
  58. package/dist/sdk/core/runtime/index.js +2 -2
  59. package/dist/sdk/core/runtime/runtime.d.ts +1 -1
  60. package/dist/sdk/core/runtime/runtime.js +49 -40
  61. package/dist/sdk/core/url/index.d.ts +2 -0
  62. package/dist/sdk/core/url/index.js +7 -0
  63. package/dist/sdk/core/url/join.d.ts +1 -0
  64. package/dist/sdk/core/url/join.js +49 -0
  65. package/dist/sdk/core/url/qs.d.ts +6 -0
  66. package/dist/sdk/core/url/qs.js +67 -0
  67. package/dist/sdk/errors/PlanqkServiceApiError.d.ts +4 -1
  68. package/dist/sdk/errors/PlanqkServiceApiError.js +7 -8
  69. package/dist/sdk/errors/PlanqkServiceApiTimeoutError.d.ts +1 -1
  70. package/dist/sdk/errors/PlanqkServiceApiTimeoutError.js +2 -2
  71. package/dist/sdk/errors/index.d.ts +2 -2
  72. package/dist/sdk/errors/index.js +4 -4
  73. package/dist/sdk/index.d.ts +4 -4
  74. package/dist/sdk/index.js +9 -9
  75. package/fern/fern.config.json +1 -1
  76. package/fern/generators.yml +2 -2
  77. package/fern/openapi/openapi.yml +41 -131
  78. package/notebooks/python-sdk.ipynb +1 -1
  79. package/package.json +2 -3
  80. package/planqk/service/_version.py +1 -1
  81. package/pyproject.toml +1 -1
  82. package/src/index.test.ts +29 -16
  83. package/src/sdk/Client.ts +27 -7
  84. package/src/sdk/api/index.ts +2 -3
  85. package/src/sdk/api/resources/index.ts +2 -2
  86. package/src/sdk/api/resources/serviceApi/client/Client.ts +223 -250
  87. package/src/sdk/api/resources/serviceApi/index.ts +2 -2
  88. package/src/sdk/api/resources/serviceApi/types/GetResultResponse.ts +15 -3
  89. package/src/sdk/api/resources/serviceApi/types/index.ts +1 -4
  90. package/src/sdk/api/types/ServiceExecution.ts +13 -3
  91. package/src/sdk/api/types/index.ts +2 -6
  92. package/src/sdk/core/auth/BasicAuth.ts +3 -3
  93. package/src/sdk/core/auth/index.ts +2 -2
  94. package/src/sdk/core/base64.ts +27 -0
  95. package/src/sdk/core/fetcher/APIResponse.ts +11 -0
  96. package/src/sdk/core/fetcher/BinaryResponse.ts +36 -0
  97. package/src/sdk/core/fetcher/Fetcher.ts +46 -26
  98. package/src/sdk/core/fetcher/Headers.ts +93 -0
  99. package/src/sdk/core/fetcher/HttpResponsePromise.ts +116 -0
  100. package/src/sdk/core/fetcher/RawResponse.ts +61 -0
  101. package/src/sdk/core/fetcher/ResponseWithBody.ts +7 -0
  102. package/src/sdk/core/fetcher/createRequestUrl.ts +4 -8
  103. package/src/sdk/core/fetcher/getErrorResponseBody.ts +32 -0
  104. package/src/sdk/core/fetcher/getFetchFn.ts +2 -24
  105. package/src/sdk/core/fetcher/getRequestBody.ts +3 -1
  106. package/src/sdk/core/fetcher/getResponseBody.ts +38 -27
  107. package/src/sdk/core/fetcher/index.ts +9 -5
  108. package/src/sdk/core/fetcher/makeRequest.ts +2 -2
  109. package/src/sdk/core/fetcher/requestWithRetries.ts +18 -6
  110. package/src/sdk/core/fetcher/signals.ts +1 -1
  111. package/src/sdk/core/headers.ts +35 -0
  112. package/src/sdk/core/index.ts +5 -3
  113. package/src/sdk/core/json.ts +27 -0
  114. package/src/sdk/core/runtime/index.ts +1 -1
  115. package/src/sdk/core/runtime/runtime.ts +60 -53
  116. package/src/sdk/core/url/index.ts +2 -0
  117. package/src/sdk/core/url/join.ts +55 -0
  118. package/src/sdk/core/url/qs.ts +74 -0
  119. package/src/sdk/errors/PlanqkServiceApiError.ts +21 -11
  120. package/src/sdk/errors/PlanqkServiceApiTimeoutError.ts +2 -2
  121. package/src/sdk/errors/index.ts +2 -2
  122. package/src/sdk/index.ts +4 -4
  123. package/dist/sdk/api/errors/BadRequestError.d.ts +0 -7
  124. package/dist/sdk/api/errors/BadRequestError.js +0 -51
  125. package/dist/sdk/api/errors/ForbiddenError.d.ts +0 -7
  126. package/dist/sdk/api/errors/ForbiddenError.js +0 -51
  127. package/dist/sdk/api/errors/InternalServerError.d.ts +0 -7
  128. package/dist/sdk/api/errors/InternalServerError.js +0 -51
  129. package/dist/sdk/api/errors/NotFoundError.d.ts +0 -7
  130. package/dist/sdk/api/errors/NotFoundError.js +0 -51
  131. package/dist/sdk/api/errors/UnauthorizedError.d.ts +0 -7
  132. package/dist/sdk/api/errors/UnauthorizedError.js +0 -51
  133. package/dist/sdk/api/errors/index.d.ts +0 -5
  134. package/dist/sdk/api/errors/index.js +0 -21
  135. package/dist/sdk/api/resources/serviceApi/types/GetResultResponseEmbedded.d.ts +0 -7
  136. package/dist/sdk/api/resources/serviceApi/types/GetResultResponseEmbedded.js +0 -5
  137. package/dist/sdk/api/resources/serviceApi/types/GetResultResponseLinks.d.ts +0 -7
  138. package/dist/sdk/api/resources/serviceApi/types/GetResultResponseLinks.js +0 -5
  139. package/dist/sdk/api/resources/serviceApi/types/HealthCheckResponse.d.ts +0 -7
  140. package/dist/sdk/api/resources/serviceApi/types/HealthCheckResponse.js +0 -5
  141. package/dist/sdk/api/types/InputData.d.ts +0 -4
  142. package/dist/sdk/api/types/InputData.js +0 -5
  143. package/dist/sdk/api/types/InputDataRef.d.ts +0 -8
  144. package/dist/sdk/api/types/InputDataRef.js +0 -5
  145. package/dist/sdk/api/types/InputParams.d.ts +0 -4
  146. package/dist/sdk/api/types/InputParams.js +0 -5
  147. package/dist/sdk/api/types/ServiceExecutionStatus.d.ts +0 -12
  148. package/dist/sdk/api/types/ServiceExecutionStatus.js +0 -14
  149. package/dist/sdk/core/fetcher/stream-wrappers/Node18UniversalStreamWrapper.d.ts +0 -30
  150. package/dist/sdk/core/fetcher/stream-wrappers/Node18UniversalStreamWrapper.js +0 -232
  151. package/dist/sdk/core/fetcher/stream-wrappers/NodePre18StreamWrapper.d.ts +0 -21
  152. package/dist/sdk/core/fetcher/stream-wrappers/NodePre18StreamWrapper.js +0 -91
  153. package/dist/sdk/core/fetcher/stream-wrappers/UndiciStreamWrapper.d.ts +0 -31
  154. package/dist/sdk/core/fetcher/stream-wrappers/UndiciStreamWrapper.js +0 -214
  155. package/dist/sdk/core/fetcher/stream-wrappers/chooseStreamWrapper.d.ts +0 -18
  156. package/dist/sdk/core/fetcher/stream-wrappers/chooseStreamWrapper.js +0 -48
  157. package/src/sdk/api/errors/BadRequestError.ts +0 -16
  158. package/src/sdk/api/errors/ForbiddenError.ts +0 -16
  159. package/src/sdk/api/errors/InternalServerError.ts +0 -16
  160. package/src/sdk/api/errors/NotFoundError.ts +0 -16
  161. package/src/sdk/api/errors/UnauthorizedError.ts +0 -16
  162. package/src/sdk/api/errors/index.ts +0 -5
  163. package/src/sdk/api/resources/serviceApi/types/GetResultResponseEmbedded.ts +0 -9
  164. package/src/sdk/api/resources/serviceApi/types/GetResultResponseLinks.ts +0 -9
  165. package/src/sdk/api/resources/serviceApi/types/HealthCheckResponse.ts +0 -8
  166. package/src/sdk/api/types/InputData.ts +0 -5
  167. package/src/sdk/api/types/InputDataRef.ts +0 -9
  168. package/src/sdk/api/types/InputParams.ts +0 -5
  169. package/src/sdk/api/types/ServiceExecutionStatus.ts +0 -14
  170. package/src/sdk/core/fetcher/stream-wrappers/Node18UniversalStreamWrapper.ts +0 -252
  171. package/src/sdk/core/fetcher/stream-wrappers/NodePre18StreamWrapper.ts +0 -106
  172. package/src/sdk/core/fetcher/stream-wrappers/UndiciStreamWrapper.ts +0 -239
  173. package/src/sdk/core/fetcher/stream-wrappers/chooseStreamWrapper.ts +0 -33
@@ -0,0 +1,32 @@
1
+ import { fromJson } from "../json.js";
2
+ import { getResponseBody } from "./getResponseBody.js";
3
+
4
+ export async function getErrorResponseBody(response: Response): Promise<unknown> {
5
+ let contentType = response.headers.get("Content-Type")?.toLowerCase();
6
+ if (contentType == null || contentType.length === 0) {
7
+ return getResponseBody(response);
8
+ }
9
+
10
+ if (contentType.indexOf(";") !== -1) {
11
+ contentType = contentType.split(";")[0]?.trim() ?? "";
12
+ }
13
+ switch (contentType) {
14
+ case "application/hal+json":
15
+ case "application/json":
16
+ case "application/ld+json":
17
+ case "application/problem+json":
18
+ case "application/vnd.api+json":
19
+ case "text/json":
20
+ const text = await response.text();
21
+ return text.length > 0 ? fromJson(text) : undefined;
22
+ default:
23
+ if (contentType.startsWith("application/vnd.") && contentType.endsWith("+json")) {
24
+ const text = await response.text();
25
+ return text.length > 0 ? fromJson(text) : undefined;
26
+ }
27
+
28
+ // Fallback to plain text if content type is not recognized
29
+ // Even if no body is present, the response will be an empty string
30
+ return await response.text();
31
+ }
32
+ }
@@ -1,25 +1,3 @@
1
- import { RUNTIME } from "../runtime";
2
-
3
- /**
4
- * Returns a fetch function based on the runtime
5
- */
6
- export async function getFetchFn(): Promise<any> {
7
- // In Node.js 18+ environments, use native fetch
8
- if (RUNTIME.type === "node" && RUNTIME.parsedVersion != null && RUNTIME.parsedVersion >= 18) {
9
- return fetch;
10
- }
11
-
12
- // In Node.js 18 or lower environments, the SDK always uses`node-fetch`.
13
- if (RUNTIME.type === "node") {
14
- return (await import("node-fetch")).default as any;
15
- }
16
-
17
- // Otherwise the SDK uses global fetch if available,
18
- // and falls back to node-fetch.
19
- if (typeof fetch == "function") {
20
- return fetch;
21
- }
22
-
23
- // Defaults to node `node-fetch` if global fetch isn't available
24
- return (await import("node-fetch")).default as any;
1
+ export async function getFetchFn(): Promise<typeof fetch> {
2
+ return fetch;
25
3
  }
@@ -1,3 +1,5 @@
1
+ import { toJson } from "../json.js";
2
+
1
3
  export declare namespace GetRequestBody {
2
4
  interface Args {
3
5
  body: unknown;
@@ -7,7 +9,7 @@ export declare namespace GetRequestBody {
7
9
 
8
10
  export async function getRequestBody({ body, type }: GetRequestBody.Args): Promise<BodyInit | undefined> {
9
11
  if (type.includes("json")) {
10
- return JSON.stringify(body);
12
+ return toJson(body);
11
13
  } else {
12
14
  return body as BodyInit;
13
15
  }
@@ -1,32 +1,43 @@
1
- import { chooseStreamWrapper } from "./stream-wrappers/chooseStreamWrapper";
1
+ import { getBinaryResponse } from "./BinaryResponse.js";
2
+ import { isResponseWithBody } from "./ResponseWithBody.js";
3
+ import { fromJson } from "../json.js";
2
4
 
3
5
  export async function getResponseBody(response: Response, responseType?: string): Promise<unknown> {
4
- if (response.body != null && responseType === "blob") {
5
- return await response.blob();
6
- } else if (response.body != null && responseType === "sse") {
7
- return response.body;
8
- } else if (response.body != null && responseType === "streaming") {
9
- return chooseStreamWrapper(response.body);
10
- } else if (response.body != null && responseType === "text") {
11
- return await response.text();
12
- } else {
13
- const text = await response.text();
14
- if (text.length > 0) {
15
- try {
16
- let responseBody = JSON.parse(text);
17
- return responseBody;
18
- } catch (err) {
19
- return {
20
- ok: false,
21
- error: {
22
- reason: "non-json",
23
- statusCode: response.status,
24
- rawBody: text,
25
- },
26
- };
27
- }
28
- } else {
29
- return undefined;
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
+ };
30
40
  }
31
41
  }
42
+ return undefined;
32
43
  }
@@ -1,5 +1,9 @@
1
- export type { APIResponse } from "./APIResponse";
2
- export { fetcher } from "./Fetcher";
3
- export type { Fetcher, FetchFunction } from "./Fetcher";
4
- export { getHeader } from "./getHeader";
5
- export { Supplier } from "./Supplier";
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";
@@ -1,4 +1,4 @@
1
- import { anySignal, getTimeoutSignal } from "./signals";
1
+ import { anySignal, getTimeoutSignal } from "./signals.js";
2
2
 
3
3
  export const makeRequest = async (
4
4
  fetchFn: (url: string, init: RequestInit) => Promise<Response>,
@@ -9,7 +9,7 @@ export const makeRequest = async (
9
9
  timeoutMs?: number,
10
10
  abortSignal?: AbortSignal,
11
11
  withCredentials?: boolean,
12
- duplex?: "half"
12
+ duplex?: "half",
13
13
  ): Promise<Response> => {
14
14
  const signals: AbortSignal[] = [];
15
15
 
@@ -1,17 +1,29 @@
1
- const INITIAL_RETRY_DELAY = 1;
2
- const MAX_RETRY_DELAY = 60;
1
+ const INITIAL_RETRY_DELAY = 1000; // in milliseconds
2
+ const MAX_RETRY_DELAY = 60000; // in milliseconds
3
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
+ }
4
11
 
5
12
  export async function requestWithRetries(
6
13
  requestFn: () => Promise<Response>,
7
- maxRetries: number = DEFAULT_MAX_RETRIES
14
+ maxRetries: number = DEFAULT_MAX_RETRIES,
8
15
  ): Promise<Response> {
9
16
  let response: Response = await requestFn();
10
17
 
11
18
  for (let i = 0; i < maxRetries; ++i) {
12
- if ([408, 409, 429].includes(response.status) || response.status >= 500) {
13
- const delay = Math.min(INITIAL_RETRY_DELAY * Math.pow(2, i), MAX_RETRY_DELAY);
14
- await new Promise((resolve) => setTimeout(resolve, delay));
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));
15
27
  response = await requestFn();
16
28
  } else {
17
29
  break;
@@ -15,7 +15,7 @@ export function getTimeoutSignal(timeoutMs: number): { signal: AbortSignal; abor
15
15
  export function anySignal(...args: AbortSignal[] | [AbortSignal[]]): AbortSignal {
16
16
  // Allowing signals to be passed either as array
17
17
  // of signals or as multiple arguments.
18
- const signals = <AbortSignal[]>(args.length === 1 && Array.isArray(args[0]) ? args[0] : args);
18
+ const signals = (args.length === 1 && Array.isArray(args[0]) ? args[0] : args) as AbortSignal[];
19
19
 
20
20
  const controller = new AbortController();
21
21
 
@@ -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
+ }
@@ -1,3 +1,5 @@
1
- export * from "./fetcher";
2
- export * from "./auth";
3
- export * from "./runtime";
1
+ export * from "./fetcher/index.js";
2
+ export * from "./runtime/index.js";
3
+ export * as url from "./url/index.js";
4
+ export * from "./auth/index.js";
5
+ export * from "./base64.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
+ }
@@ -1 +1 @@
1
- export { RUNTIME } from "./runtime";
1
+ export { RUNTIME } from "./runtime.js";
@@ -8,58 +8,12 @@ interface BunGlobal {
8
8
  version: string;
9
9
  }
10
10
 
11
- declare const Deno: DenoGlobal;
12
- declare const Bun: BunGlobal;
13
-
14
- /**
15
- * A constant that indicates whether the environment the code is running is a Web Browser.
16
- */
17
- const isBrowser = typeof window !== "undefined" && typeof window.document !== "undefined";
18
-
19
- /**
20
- * A constant that indicates whether the environment the code is running is a Web Worker.
21
- */
22
- const isWebWorker =
23
- typeof self === "object" &&
24
- // @ts-ignore
25
- typeof self?.importScripts === "function" &&
26
- (self.constructor?.name === "DedicatedWorkerGlobalScope" ||
27
- self.constructor?.name === "ServiceWorkerGlobalScope" ||
28
- self.constructor?.name === "SharedWorkerGlobalScope");
29
-
30
- /**
31
- * A constant that indicates whether the environment the code is running is Deno.
32
- */
33
- const isDeno =
34
- typeof Deno !== "undefined" && typeof Deno.version !== "undefined" && typeof Deno.version.deno !== "undefined";
35
-
36
- /**
37
- * A constant that indicates whether the environment the code is running is Bun.sh.
38
- */
39
- const isBun = typeof Bun !== "undefined" && typeof Bun.version !== "undefined";
40
-
41
- /**
42
- * A constant that indicates whether the environment the code is running is Node.JS.
43
- */
44
- const isNode =
45
- typeof process !== "undefined" &&
46
- Boolean(process.version) &&
47
- Boolean(process.versions?.node) &&
48
- // Deno spoofs process.versions.node, see https://deno.land/std@0.177.0/node/process.ts?s=versions
49
- !isDeno &&
50
- !isBun;
51
-
52
- /**
53
- * A constant that indicates whether the environment the code is running is in React-Native.
54
- * https://github.com/facebook/react-native/blob/main/packages/react-native/Libraries/Core/setUpNavigator.js
55
- */
56
- const isReactNative = typeof navigator !== "undefined" && navigator?.product === "ReactNative";
57
-
58
- /**
59
- * A constant that indicates whether the environment the code is running is Cloudflare.
60
- * https://developers.cloudflare.com/workers/runtime-apis/web-standards/#navigatoruseragent
61
- */
62
- const isCloudflare = typeof globalThis !== "undefined" && globalThis?.navigator?.userAgent === "Cloudflare-Workers";
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
+ };
63
17
 
64
18
  /**
65
19
  * A constant that indicates which environment and version the SDK is running in.
@@ -67,12 +21,16 @@ const isCloudflare = typeof globalThis !== "undefined" && globalThis?.navigator?
67
21
  export const RUNTIME: Runtime = evaluateRuntime();
68
22
 
69
23
  export interface Runtime {
70
- type: "browser" | "web-worker" | "deno" | "bun" | "node" | "react-native" | "unknown" | "workerd";
24
+ type: "browser" | "web-worker" | "deno" | "bun" | "node" | "react-native" | "unknown" | "workerd" | "edge-runtime";
71
25
  version?: string;
72
26
  parsedVersion?: number;
73
27
  }
74
28
 
75
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";
76
34
  if (isBrowser) {
77
35
  return {
78
36
  type: "browser",
@@ -80,18 +38,49 @@ function evaluateRuntime(): Runtime {
80
38
  };
81
39
  }
82
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";
83
46
  if (isCloudflare) {
84
47
  return {
85
48
  type: "workerd",
86
49
  };
87
50
  }
88
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");
89
72
  if (isWebWorker) {
90
73
  return {
91
74
  type: "web-worker",
92
75
  };
93
76
  }
94
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";
95
84
  if (isDeno) {
96
85
  return {
97
86
  type: "deno",
@@ -99,6 +88,10 @@ function evaluateRuntime(): Runtime {
99
88
  };
100
89
  }
101
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";
102
95
  if (isBun) {
103
96
  return {
104
97
  type: "bun",
@@ -106,6 +99,15 @@ function evaluateRuntime(): Runtime {
106
99
  };
107
100
  }
108
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;
109
111
  if (isNode) {
110
112
  return {
111
113
  type: "node",
@@ -114,6 +116,11 @@ function evaluateRuntime(): Runtime {
114
116
  };
115
117
  }
116
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";
117
124
  if (isReactNative) {
118
125
  return {
119
126
  type: "react-native",
@@ -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
+ }
@@ -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
+ }
@@ -2,20 +2,30 @@
2
2
  * This file was auto-generated by Fern from our API Definition.
3
3
  */
4
4
 
5
+ import * as core from "../core/index.js";
6
+ import { toJson } from "../core/json.js";
7
+
5
8
  export class PlanqkServiceApiError extends Error {
6
- readonly statusCode?: number;
7
- readonly body?: unknown;
9
+ public readonly statusCode?: number;
10
+ public readonly body?: unknown;
11
+ public readonly rawResponse?: core.RawResponse;
8
12
 
9
- constructor({ message, statusCode, body }: { message?: string; statusCode?: number; body?: unknown }) {
13
+ constructor({
14
+ message,
15
+ statusCode,
16
+ body,
17
+ rawResponse,
18
+ }: {
19
+ message?: string;
20
+ statusCode?: number;
21
+ body?: unknown;
22
+ rawResponse?: core.RawResponse;
23
+ }) {
10
24
  super(buildMessage({ message, statusCode, body }));
11
25
  Object.setPrototypeOf(this, PlanqkServiceApiError.prototype);
12
- if (statusCode != null) {
13
- this.statusCode = statusCode;
14
- }
15
-
16
- if (body !== undefined) {
17
- this.body = body;
18
- }
26
+ this.statusCode = statusCode;
27
+ this.body = body;
28
+ this.rawResponse = rawResponse;
19
29
  }
20
30
  }
21
31
 
@@ -38,7 +48,7 @@ function buildMessage({
38
48
  }
39
49
 
40
50
  if (body != null) {
41
- lines.push(`Body: ${JSON.stringify(body, undefined, 2)}`);
51
+ lines.push(`Body: ${toJson(body, undefined, 2)}`);
42
52
  }
43
53
 
44
54
  return lines.join("\n");