@holaboss/app-sdk 0.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.
- package/LICENSE +21 -0
- package/README.md +94 -0
- package/dist/app-BpcA69HT.d.cts +32 -0
- package/dist/app-BpcA69HT.d.cts.map +1 -0
- package/dist/app-CPM9G9Ak.d.ts +32 -0
- package/dist/app-CPM9G9Ak.d.ts.map +1 -0
- package/dist/app-DvahQ8xx.js +147 -0
- package/dist/app-DvahQ8xx.js.map +1 -0
- package/dist/app-mQJKUJHj.cjs +156 -0
- package/dist/approveMarketplaceSubmission-BmtuKiRw.d.ts +3328 -0
- package/dist/approveMarketplaceSubmission-BmtuKiRw.d.ts.map +1 -0
- package/dist/approveMarketplaceSubmission-Cno-7U1J.d.cts +3328 -0
- package/dist/approveMarketplaceSubmission-Cno-7U1J.d.cts.map +1 -0
- package/dist/clients/app.cjs +7 -0
- package/dist/clients/app.d.cts +2 -0
- package/dist/clients/app.d.ts +2 -0
- package/dist/clients/app.js +2 -0
- package/dist/core.cjs +29 -0
- package/dist/core.d.cts +3 -0
- package/dist/core.d.ts +3 -0
- package/dist/core.js +3 -0
- package/dist/index.cjs +218 -0
- package/dist/index.d.cts +4 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +7 -0
- package/dist/react-DN2Q1phB.cjs +1229 -0
- package/dist/react-VeTZ8VzJ.js +764 -0
- package/dist/react-VeTZ8VzJ.js.map +1 -0
- package/dist/react.cjs +214 -0
- package/dist/react.d.cts +3 -0
- package/dist/react.d.ts +3 -0
- package/dist/react.js +4 -0
- package/dist/uninstallMarketplaceSkill-CXtlpmlt.cjs +654 -0
- package/dist/uninstallMarketplaceSkill-CYAiu4cU.js +531 -0
- package/dist/uninstallMarketplaceSkill-CYAiu4cU.js.map +1 -0
- package/dist/uninstallMarketplaceSkillSchema-Bay4cbpz.cjs +1711 -0
- package/dist/uninstallMarketplaceSkillSchema-BbGKwqP0.d.ts +1090 -0
- package/dist/uninstallMarketplaceSkillSchema-BbGKwqP0.d.ts.map +1 -0
- package/dist/uninstallMarketplaceSkillSchema-BfOp0667.d.cts +1090 -0
- package/dist/uninstallMarketplaceSkillSchema-BfOp0667.d.cts.map +1 -0
- package/dist/uninstallMarketplaceSkillSchema-Dz2r1ms-.js +1048 -0
- package/dist/uninstallMarketplaceSkillSchema-Dz2r1ms-.js.map +1 -0
- package/dist/zod.cjs +113 -0
- package/dist/zod.d.cts +2 -0
- package/dist/zod.d.ts +2 -0
- package/dist/zod.js +2 -0
- package/package.json +120 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Holaboss
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# @holaboss/app-sdk
|
|
2
|
+
|
|
3
|
+
Generated TypeScript client for the Holaboss product API. Consumed by the Holaboss web app and the open-source [holaOS](https://github.com/holaboss-ai/holaOS) desktop.
|
|
4
|
+
|
|
5
|
+
This package is a thin, type-safe wrapper over the Holaboss REST API (the Hono server that fronts the Python services). It is generated from the server's OpenAPI surface using [Kubb](https://kubb.dev/), so the types, functions, and React Query hooks stay in sync with the live contract.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install @holaboss/app-sdk
|
|
11
|
+
# or
|
|
12
|
+
bun add @holaboss/app-sdk
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
React hooks are optional; if you use them, install the peer:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install @tanstack/react-query
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Subpath exports
|
|
22
|
+
|
|
23
|
+
| Subpath | For | Contains |
|
|
24
|
+
|---|---|---|
|
|
25
|
+
| `@holaboss/app-sdk/core` | Non-React consumers, main/preload code in Electron, Node scripts | Generated fetch functions + `createAppClient` |
|
|
26
|
+
| `@holaboss/app-sdk/react` | React UIs | Generated TanStack Query hooks |
|
|
27
|
+
| `@holaboss/app-sdk/zod` | Client-side runtime validation | Generated Zod schemas |
|
|
28
|
+
| `@holaboss/app-sdk/clients/app` | Advanced: configure the underlying fetch client | Low-level `createClient` + request/response types |
|
|
29
|
+
| `@holaboss/app-sdk` | Convenience re-export of `core + react + zod` | Everything |
|
|
30
|
+
|
|
31
|
+
## Usage
|
|
32
|
+
|
|
33
|
+
### Create a configured client
|
|
34
|
+
|
|
35
|
+
```ts
|
|
36
|
+
import { createAppClient } from "@holaboss/app-sdk/core";
|
|
37
|
+
|
|
38
|
+
export const appClient = createAppClient({
|
|
39
|
+
baseURL: "https://api.holaboss.ai/api/marketplace",
|
|
40
|
+
credentials: "include",
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
export const appClientOptions = { client: appClient } as const;
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Call a generated function (non-React)
|
|
47
|
+
|
|
48
|
+
```ts
|
|
49
|
+
import { listMarketplaceTemplates } from "@holaboss/app-sdk/core";
|
|
50
|
+
|
|
51
|
+
const templates = await listMarketplaceTemplates({
|
|
52
|
+
client: appClient,
|
|
53
|
+
});
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Use a generated React Query hook
|
|
57
|
+
|
|
58
|
+
```tsx
|
|
59
|
+
import { useListMarketplaceTemplates } from "@holaboss/app-sdk/react";
|
|
60
|
+
|
|
61
|
+
function TemplatesList() {
|
|
62
|
+
const { data } = useListMarketplaceTemplates({
|
|
63
|
+
client: appClientOptions,
|
|
64
|
+
});
|
|
65
|
+
return <ul>{data?.map((t) => <li key={t.id}>{t.name}</li>)}</ul>;
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Stability & versioning
|
|
70
|
+
|
|
71
|
+
This package follows [Semantic Versioning](https://semver.org/).
|
|
72
|
+
|
|
73
|
+
- **patch** (`0.x.y`) — internal changes to generated code with no observable API change
|
|
74
|
+
- **minor** (`0.x.0`) — additive changes: new endpoints, new optional request/response fields
|
|
75
|
+
- **major** — breaking changes: removed endpoints, removed fields, required field additions, request/response shape changes
|
|
76
|
+
|
|
77
|
+
While on `0.x`, breaking changes are allowed on minor bumps per standard semver-for-0.x conventions, but we will call them out in release notes and bump conservatively.
|
|
78
|
+
|
|
79
|
+
**Consumers should pin an exact version** (no `^` ranges) until this package reaches `1.0.0`.
|
|
80
|
+
|
|
81
|
+
## Regenerating
|
|
82
|
+
|
|
83
|
+
Code is generated from the Holaboss Hono server's OpenAPI spec at `/api/marketplace/openapi.json`. To regenerate with the server running locally:
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
bun install
|
|
87
|
+
KUBB_APP_OPENAPI_URL=http://127.0.0.1:4000/api/marketplace/openapi.json bun run codegen
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
The `src/generated/` tree is committed. Do not run codegen as part of the release pipeline — regeneration is a deliberate human action, reviewed in a PR, followed by a version bump.
|
|
91
|
+
|
|
92
|
+
## License
|
|
93
|
+
|
|
94
|
+
MIT
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
//#region src/clients/base.d.ts
|
|
2
|
+
type HeaderValue = null | string | undefined;
|
|
3
|
+
type RequestHeaders = Headers | Record<string, HeaderValue> | [string, HeaderValue][];
|
|
4
|
+
type QueryParamValue = boolean | null | number | string | undefined | Array<boolean | null | number | string | undefined>;
|
|
5
|
+
type RequestConfig<TData = unknown> = {
|
|
6
|
+
baseURL?: string;
|
|
7
|
+
credentials?: RequestCredentials;
|
|
8
|
+
data?: TData;
|
|
9
|
+
headers?: RequestHeaders;
|
|
10
|
+
method: "DELETE" | "GET" | "PATCH" | "POST" | "PUT";
|
|
11
|
+
params?: Record<string, QueryParamValue>;
|
|
12
|
+
responseType?: "arraybuffer" | "blob" | "json" | "text";
|
|
13
|
+
signal?: AbortSignal;
|
|
14
|
+
url?: string;
|
|
15
|
+
};
|
|
16
|
+
type ResponseConfig<TData = unknown> = {
|
|
17
|
+
data: TData;
|
|
18
|
+
headers: Headers;
|
|
19
|
+
status: number;
|
|
20
|
+
statusText: string;
|
|
21
|
+
};
|
|
22
|
+
type ResponseErrorConfig<TError = unknown> = Error & {
|
|
23
|
+
data?: TError;
|
|
24
|
+
headers?: Headers;
|
|
25
|
+
status: number;
|
|
26
|
+
statusText: string;
|
|
27
|
+
};
|
|
28
|
+
declare function baseClient<TData, TError = unknown, TVariables = unknown>(config: RequestConfig<TVariables>): Promise<ResponseConfig<TData>>;
|
|
29
|
+
declare function createClient(defaults: Pick<RequestConfig, "baseURL" | "credentials" | "headers">): <TData, TError = unknown, TVariables = unknown>(config: RequestConfig<TVariables>) => Promise<ResponseConfig<TData>>;
|
|
30
|
+
//#endregion
|
|
31
|
+
export { createClient as a, baseClient as i, ResponseConfig as n, ResponseErrorConfig as r, RequestConfig as t };
|
|
32
|
+
//# sourceMappingURL=app-BpcA69HT.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app-BpcA69HT.d.cts","names":[],"sources":["../src/clients/base.ts"],"mappings":";KAAY,WAAA;AAAA,KAEA,cAAA,GACR,OAAA,GACA,MAAA,SAAe,WAAA,aACN,WAAA;AAAA,KAED,eAAA,kDAMR,KAAA;AAAA,KAEQ,aAAA;EACV,OAAA;EACA,WAAA,GAAc,kBAAA;EACd,IAAA,GAAO,KAAA;EACP,OAAA,GAAU,cAAA;EACV,MAAA;EACA,MAAA,GAAS,MAAA,SAAe,eAAA;EACxB,YAAA;EACA,MAAA,GAAS,WAAA;EACT,GAAA;AAAA;AAAA,KAGU,cAAA;EACV,IAAA,EAAM,KAAA;EACN,OAAA,EAAS,OAAA;EACT,MAAA;EACA,UAAA;AAAA;AAAA,KAGU,mBAAA,qBAAwC,KAAA;EAClD,IAAA,GAAO,MAAA;EACP,OAAA,GAAU,OAAA;EACV,MAAA;EACA,UAAA;AAAA;AAAA,iBAyMa,UAAA,+CAAA,CACb,MAAA,EAAQ,aAAA,CAAc,UAAA,IACrB,OAAA,CAAQ,cAAA,CAAe,KAAA;AAAA,iBAkDV,YAAA,CACd,QAAA,EAAU,IAAA,CAAK,aAAA,2FAGb,MAAA,EAAQ,aAAA,CAAc,UAAA,MAAW,OAAA,CAAA,cAAA,CAAA,KAAA"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
//#region src/clients/base.d.ts
|
|
2
|
+
type HeaderValue = null | string | undefined;
|
|
3
|
+
type RequestHeaders = Headers | Record<string, HeaderValue> | [string, HeaderValue][];
|
|
4
|
+
type QueryParamValue = boolean | null | number | string | undefined | Array<boolean | null | number | string | undefined>;
|
|
5
|
+
type RequestConfig<TData = unknown> = {
|
|
6
|
+
baseURL?: string;
|
|
7
|
+
credentials?: RequestCredentials;
|
|
8
|
+
data?: TData;
|
|
9
|
+
headers?: RequestHeaders;
|
|
10
|
+
method: "DELETE" | "GET" | "PATCH" | "POST" | "PUT";
|
|
11
|
+
params?: Record<string, QueryParamValue>;
|
|
12
|
+
responseType?: "arraybuffer" | "blob" | "json" | "text";
|
|
13
|
+
signal?: AbortSignal;
|
|
14
|
+
url?: string;
|
|
15
|
+
};
|
|
16
|
+
type ResponseConfig<TData = unknown> = {
|
|
17
|
+
data: TData;
|
|
18
|
+
headers: Headers;
|
|
19
|
+
status: number;
|
|
20
|
+
statusText: string;
|
|
21
|
+
};
|
|
22
|
+
type ResponseErrorConfig<TError = unknown> = Error & {
|
|
23
|
+
data?: TError;
|
|
24
|
+
headers?: Headers;
|
|
25
|
+
status: number;
|
|
26
|
+
statusText: string;
|
|
27
|
+
};
|
|
28
|
+
declare function baseClient<TData, TError = unknown, TVariables = unknown>(config: RequestConfig<TVariables>): Promise<ResponseConfig<TData>>;
|
|
29
|
+
declare function createClient(defaults: Pick<RequestConfig, "baseURL" | "credentials" | "headers">): <TData, TError = unknown, TVariables = unknown>(config: RequestConfig<TVariables>) => Promise<ResponseConfig<TData>>;
|
|
30
|
+
//#endregion
|
|
31
|
+
export { createClient as a, baseClient as i, ResponseConfig as n, ResponseErrorConfig as r, RequestConfig as t };
|
|
32
|
+
//# sourceMappingURL=app-CPM9G9Ak.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app-CPM9G9Ak.d.ts","names":[],"sources":["../src/clients/base.ts"],"mappings":";KAAY,WAAA;AAAA,KAEA,cAAA,GACR,OAAA,GACA,MAAA,SAAe,WAAA,aACN,WAAA;AAAA,KAED,eAAA,kDAMR,KAAA;AAAA,KAEQ,aAAA;EACV,OAAA;EACA,WAAA,GAAc,kBAAA;EACd,IAAA,GAAO,KAAA;EACP,OAAA,GAAU,cAAA;EACV,MAAA;EACA,MAAA,GAAS,MAAA,SAAe,eAAA;EACxB,YAAA;EACA,MAAA,GAAS,WAAA;EACT,GAAA;AAAA;AAAA,KAGU,cAAA;EACV,IAAA,EAAM,KAAA;EACN,OAAA,EAAS,OAAA;EACT,MAAA;EACA,UAAA;AAAA;AAAA,KAGU,mBAAA,qBAAwC,KAAA;EAClD,IAAA,GAAO,MAAA;EACP,OAAA,GAAU,OAAA;EACV,MAAA;EACA,UAAA;AAAA;AAAA,iBAyMa,UAAA,+CAAA,CACb,MAAA,EAAQ,aAAA,CAAc,UAAA,IACrB,OAAA,CAAQ,cAAA,CAAe,KAAA;AAAA,iBAkDV,YAAA,CACd,QAAA,EAAU,IAAA,CAAK,aAAA,2FAGb,MAAA,EAAQ,aAAA,CAAc,UAAA,MAAW,OAAA,CAAA,cAAA,CAAA,KAAA"}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
//#region src/clients/base.ts
|
|
2
|
+
var UpstreamInvalidResponseError = class extends Error {
|
|
3
|
+
url;
|
|
4
|
+
status;
|
|
5
|
+
contentType;
|
|
6
|
+
bodySnippet;
|
|
7
|
+
constructor(params) {
|
|
8
|
+
const snippet = params.bodySnippet.slice(0, 200);
|
|
9
|
+
super(`Upstream returned ${params.status} with non-JSON body (content-type="${params.contentType || "<none>"}", length=${params.bodySnippet.length}) from ${params.url}. This usually means the request hit a catchall handler or a misrouted reverse proxy. Body: ${JSON.stringify(snippet)}`);
|
|
10
|
+
this.name = "UpstreamInvalidResponseError";
|
|
11
|
+
this.url = params.url;
|
|
12
|
+
this.status = params.status;
|
|
13
|
+
this.contentType = params.contentType;
|
|
14
|
+
this.bodySnippet = snippet;
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
function toHeaders(headers) {
|
|
18
|
+
const normalized = new Headers();
|
|
19
|
+
if (!headers) return normalized;
|
|
20
|
+
if (headers instanceof Headers) {
|
|
21
|
+
for (const [key, value] of headers.entries()) normalized.set(key, value);
|
|
22
|
+
return normalized;
|
|
23
|
+
}
|
|
24
|
+
if (Array.isArray(headers)) {
|
|
25
|
+
for (const [key, value] of headers) if (value != null) normalized.set(key, value);
|
|
26
|
+
return normalized;
|
|
27
|
+
}
|
|
28
|
+
for (const [key, value] of Object.entries(headers)) if (value != null) normalized.set(key, value);
|
|
29
|
+
return normalized;
|
|
30
|
+
}
|
|
31
|
+
function appendQueryParam(searchParams, key, value) {
|
|
32
|
+
if (value == null) return;
|
|
33
|
+
searchParams.append(key, String(value));
|
|
34
|
+
}
|
|
35
|
+
function buildUrl({ baseURL, params, url }) {
|
|
36
|
+
if (!url) throw new Error("Request URL is required.");
|
|
37
|
+
const hasAbsoluteUrl = /^https?:\/\//u.test(url);
|
|
38
|
+
if (!(baseURL || hasAbsoluteUrl)) throw new Error(`Relative URL "${url}" requires a baseURL.`);
|
|
39
|
+
let resolved;
|
|
40
|
+
if (hasAbsoluteUrl) resolved = new URL(url);
|
|
41
|
+
else {
|
|
42
|
+
const trimmedBase = (baseURL ?? "").replace(/\/+$/u, "");
|
|
43
|
+
const normalizedPath = url.startsWith("/") ? url : `/${url}`;
|
|
44
|
+
resolved = new URL(`${trimmedBase}${normalizedPath}`);
|
|
45
|
+
}
|
|
46
|
+
for (const [key, rawValue] of Object.entries(params ?? {})) {
|
|
47
|
+
if (Array.isArray(rawValue)) {
|
|
48
|
+
for (const value of rawValue) appendQueryParam(resolved.searchParams, key, value);
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
appendQueryParam(resolved.searchParams, key, rawValue);
|
|
52
|
+
}
|
|
53
|
+
return resolved;
|
|
54
|
+
}
|
|
55
|
+
function isJsonBody(value) {
|
|
56
|
+
return typeof value === "object" && value !== null && !(value instanceof ArrayBuffer) && !(value instanceof Blob) && !(value instanceof FormData) && !(value instanceof URLSearchParams);
|
|
57
|
+
}
|
|
58
|
+
async function parseSuccessBody(response, responseType, requestUrl) {
|
|
59
|
+
if (response.status === 204) return;
|
|
60
|
+
if (responseType === "arraybuffer") return await response.arrayBuffer();
|
|
61
|
+
if (responseType === "blob") return await response.blob();
|
|
62
|
+
if (responseType === "text") return await response.text();
|
|
63
|
+
const contentType = response.headers.get("content-type") ?? "";
|
|
64
|
+
if (!contentType.includes("application/json")) {
|
|
65
|
+
const snippet = await response.text();
|
|
66
|
+
throw new UpstreamInvalidResponseError({
|
|
67
|
+
url: requestUrl,
|
|
68
|
+
status: response.status,
|
|
69
|
+
contentType,
|
|
70
|
+
bodySnippet: snippet
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
const raw = await response.text();
|
|
74
|
+
if (raw.length === 0) throw new UpstreamInvalidResponseError({
|
|
75
|
+
url: requestUrl,
|
|
76
|
+
status: response.status,
|
|
77
|
+
contentType,
|
|
78
|
+
bodySnippet: ""
|
|
79
|
+
});
|
|
80
|
+
try {
|
|
81
|
+
return JSON.parse(raw);
|
|
82
|
+
} catch (_parseError) {
|
|
83
|
+
throw new UpstreamInvalidResponseError({
|
|
84
|
+
url: requestUrl,
|
|
85
|
+
status: response.status,
|
|
86
|
+
contentType,
|
|
87
|
+
bodySnippet: raw
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
async function parseErrorBody(response) {
|
|
92
|
+
try {
|
|
93
|
+
if ((response.headers.get("content-type") ?? "").includes("application/json")) {
|
|
94
|
+
const raw = await response.text();
|
|
95
|
+
return raw.length === 0 ? void 0 : JSON.parse(raw);
|
|
96
|
+
}
|
|
97
|
+
return await response.text();
|
|
98
|
+
} catch {
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
async function baseClient(config) {
|
|
103
|
+
const requestUrl = buildUrl(config);
|
|
104
|
+
const headers = toHeaders(config.headers);
|
|
105
|
+
const init = {
|
|
106
|
+
credentials: config.credentials,
|
|
107
|
+
headers,
|
|
108
|
+
method: config.method,
|
|
109
|
+
signal: config.signal
|
|
110
|
+
};
|
|
111
|
+
if (config.data !== void 0 && config.method !== "GET") if (isJsonBody(config.data)) {
|
|
112
|
+
if (!headers.has("content-type")) headers.set("content-type", "application/json");
|
|
113
|
+
init.body = JSON.stringify(config.data);
|
|
114
|
+
} else init.body = config.data;
|
|
115
|
+
const response = await fetch(requestUrl, init);
|
|
116
|
+
if (!response.ok) {
|
|
117
|
+
const errorData = await parseErrorBody(response);
|
|
118
|
+
const error = /* @__PURE__ */ new Error(`Request failed with status ${response.status} ${response.statusText}`);
|
|
119
|
+
error.status = response.status;
|
|
120
|
+
error.statusText = response.statusText;
|
|
121
|
+
error.headers = response.headers;
|
|
122
|
+
error.data = errorData;
|
|
123
|
+
throw error;
|
|
124
|
+
}
|
|
125
|
+
return {
|
|
126
|
+
data: await parseSuccessBody(response, config.responseType, requestUrl.toString()),
|
|
127
|
+
headers: response.headers,
|
|
128
|
+
status: response.status,
|
|
129
|
+
statusText: response.statusText
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
function createClient(defaults) {
|
|
133
|
+
return (config) => {
|
|
134
|
+
const headers = toHeaders(defaults.headers);
|
|
135
|
+
for (const [key, value] of toHeaders(config.headers).entries()) headers.set(key, value);
|
|
136
|
+
return baseClient({
|
|
137
|
+
...config,
|
|
138
|
+
baseURL: config.baseURL ?? defaults.baseURL,
|
|
139
|
+
credentials: config.credentials ?? defaults.credentials,
|
|
140
|
+
headers
|
|
141
|
+
});
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
//#endregion
|
|
145
|
+
export { createClient as n, baseClient as t };
|
|
146
|
+
|
|
147
|
+
//# sourceMappingURL=app-DvahQ8xx.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app-DvahQ8xx.js","names":[],"sources":["../src/clients/base.ts"],"sourcesContent":["export type HeaderValue = null | string | undefined;\n\nexport type RequestHeaders =\n | Headers\n | Record<string, HeaderValue>\n | [string, HeaderValue][];\n\nexport type QueryParamValue =\n | boolean\n | null\n | number\n | string\n | undefined\n | Array<boolean | null | number | string | undefined>;\n\nexport type RequestConfig<TData = unknown> = {\n baseURL?: string;\n credentials?: RequestCredentials;\n data?: TData;\n headers?: RequestHeaders;\n method: \"DELETE\" | \"GET\" | \"PATCH\" | \"POST\" | \"PUT\";\n params?: Record<string, QueryParamValue>;\n responseType?: \"arraybuffer\" | \"blob\" | \"json\" | \"text\";\n signal?: AbortSignal;\n url?: string;\n};\n\nexport type ResponseConfig<TData = unknown> = {\n data: TData;\n headers: Headers;\n status: number;\n statusText: string;\n};\n\nexport type ResponseErrorConfig<TError = unknown> = Error & {\n data?: TError;\n headers?: Headers;\n status: number;\n statusText: string;\n};\n\nexport class UpstreamInvalidResponseError extends Error {\n readonly url: string;\n readonly status: number;\n readonly contentType: string;\n readonly bodySnippet: string;\n\n constructor(params: {\n url: string;\n status: number;\n contentType: string;\n bodySnippet: string;\n }) {\n const snippet = params.bodySnippet.slice(0, 200);\n super(\n `Upstream returned ${params.status} with non-JSON body ` +\n `(content-type=\"${params.contentType || \"<none>\"}\", length=${params.bodySnippet.length}) ` +\n `from ${params.url}. This usually means the request hit a catchall handler or a ` +\n `misrouted reverse proxy. Body: ${JSON.stringify(snippet)}`\n );\n this.name = \"UpstreamInvalidResponseError\";\n this.url = params.url;\n this.status = params.status;\n this.contentType = params.contentType;\n this.bodySnippet = snippet;\n }\n}\n\nfunction toHeaders(headers?: RequestHeaders): Headers {\n const normalized = new Headers();\n\n if (!headers) {\n return normalized;\n }\n\n if (headers instanceof Headers) {\n for (const [key, value] of headers.entries()) {\n normalized.set(key, value);\n }\n return normalized;\n }\n\n if (Array.isArray(headers)) {\n for (const [key, value] of headers) {\n if (value != null) {\n normalized.set(key, value);\n }\n }\n return normalized;\n }\n\n for (const [key, value] of Object.entries(headers)) {\n if (value != null) {\n normalized.set(key, value);\n }\n }\n\n return normalized;\n}\n\nfunction appendQueryParam(\n searchParams: URLSearchParams,\n key: string,\n value: Exclude<QueryParamValue, QueryParamValue[]>\n) {\n if (value == null) {\n return;\n }\n\n searchParams.append(key, String(value));\n}\n\nexport function buildUrl({\n baseURL,\n params,\n url,\n}: Pick<RequestConfig, \"baseURL\" | \"params\" | \"url\">): URL {\n if (!url) {\n throw new Error(\"Request URL is required.\");\n }\n\n const hasAbsoluteUrl = /^https?:\\/\\//u.test(url);\n if (!(baseURL || hasAbsoluteUrl)) {\n throw new Error(`Relative URL \"${url}\" requires a baseURL.`);\n }\n\n // Concatenate baseURL and url manually so any path segment on the baseURL\n // (e.g. `/api/marketplace`) is preserved. `new URL(\"/templates\", base)`\n // would treat the leading slash as path-absolute and discard the\n // baseURL's existing path component.\n let resolved: URL;\n if (hasAbsoluteUrl) {\n resolved = new URL(url);\n } else {\n const trimmedBase = (baseURL ?? \"\").replace(/\\/+$/u, \"\");\n const normalizedPath = url.startsWith(\"/\") ? url : `/${url}`;\n resolved = new URL(`${trimmedBase}${normalizedPath}`);\n }\n\n for (const [key, rawValue] of Object.entries(params ?? {})) {\n if (Array.isArray(rawValue)) {\n for (const value of rawValue) {\n appendQueryParam(resolved.searchParams, key, value);\n }\n continue;\n }\n\n appendQueryParam(resolved.searchParams, key, rawValue);\n }\n\n return resolved;\n}\n\nfunction isJsonBody(\n value: unknown\n): value is Record<string, unknown> | unknown[] {\n return (\n typeof value === \"object\" &&\n value !== null &&\n !(value instanceof ArrayBuffer) &&\n !(value instanceof Blob) &&\n !(value instanceof FormData) &&\n !(value instanceof URLSearchParams)\n );\n}\n\nasync function parseSuccessBody<TData>(\n response: Response,\n responseType: RequestConfig[\"responseType\"] | undefined,\n requestUrl: string\n): Promise<TData> {\n if (response.status === 204) {\n return undefined as TData;\n }\n\n if (responseType === \"arraybuffer\") {\n return (await response.arrayBuffer()) as TData;\n }\n\n if (responseType === \"blob\") {\n return (await response.blob()) as TData;\n }\n\n if (responseType === \"text\") {\n return (await response.text()) as TData;\n }\n\n // Default path: caller expects JSON. Treat anything else (empty body, text,\n // HTML from a reverse-proxy catchall, etc.) as a hard failure so routing\n // mistakes surface with a clear error instead of bleeding into downstream\n // Zod \"expected object, received string\" errors.\n const contentType = response.headers.get(\"content-type\") ?? \"\";\n if (!contentType.includes(\"application/json\")) {\n const snippet = await response.text();\n throw new UpstreamInvalidResponseError({\n url: requestUrl,\n status: response.status,\n contentType,\n bodySnippet: snippet,\n });\n }\n\n const raw = await response.text();\n if (raw.length === 0) {\n throw new UpstreamInvalidResponseError({\n url: requestUrl,\n status: response.status,\n contentType,\n bodySnippet: \"\",\n });\n }\n\n try {\n return JSON.parse(raw) as TData;\n } catch (_parseError) {\n throw new UpstreamInvalidResponseError({\n url: requestUrl,\n status: response.status,\n contentType,\n bodySnippet: raw,\n });\n }\n}\n\nasync function parseErrorBody(response: Response): Promise<unknown> {\n // Best-effort on error paths: try JSON when advertised, otherwise text,\n // and never throw — we always want the caller to see the HTTP failure.\n try {\n const contentType = response.headers.get(\"content-type\") ?? \"\";\n if (contentType.includes(\"application/json\")) {\n const raw = await response.text();\n return raw.length === 0 ? undefined : JSON.parse(raw);\n }\n return await response.text();\n } catch {\n return;\n }\n}\n\nasync function baseClient<TData, TError = unknown, TVariables = unknown>(\n config: RequestConfig<TVariables>\n): Promise<ResponseConfig<TData>> {\n const requestUrl = buildUrl(config);\n const headers = toHeaders(config.headers);\n\n const init: RequestInit = {\n credentials: config.credentials,\n headers,\n method: config.method,\n signal: config.signal,\n };\n\n if (config.data !== undefined && config.method !== \"GET\") {\n if (isJsonBody(config.data)) {\n if (!headers.has(\"content-type\")) {\n headers.set(\"content-type\", \"application/json\");\n }\n init.body = JSON.stringify(config.data);\n } else {\n init.body = config.data as BodyInit;\n }\n }\n\n const response = await fetch(requestUrl, init);\n\n if (!response.ok) {\n const errorData = await parseErrorBody(response);\n const error = new Error(\n `Request failed with status ${response.status} ${response.statusText}`\n ) as ResponseErrorConfig<TError>;\n error.status = response.status;\n error.statusText = response.statusText;\n error.headers = response.headers;\n error.data = errorData as TError;\n throw error;\n }\n\n const data = await parseSuccessBody<TData>(\n response,\n config.responseType,\n requestUrl.toString()\n );\n\n return {\n data,\n headers: response.headers,\n status: response.status,\n statusText: response.statusText,\n };\n}\n\nexport function createClient(\n defaults: Pick<RequestConfig, \"baseURL\" | \"credentials\" | \"headers\">\n) {\n return <TData, TError = unknown, TVariables = unknown>(\n config: RequestConfig<TVariables>\n ) => {\n const headers = toHeaders(defaults.headers);\n for (const [key, value] of toHeaders(config.headers).entries()) {\n headers.set(key, value);\n }\n\n return baseClient<TData, TError, TVariables>({\n ...config,\n baseURL: config.baseURL ?? defaults.baseURL,\n credentials: config.credentials ?? defaults.credentials,\n headers,\n });\n };\n}\n\nexport default baseClient;\n"],"mappings":"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"}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
//#region src/clients/base.ts
|
|
2
|
+
var UpstreamInvalidResponseError = class extends Error {
|
|
3
|
+
url;
|
|
4
|
+
status;
|
|
5
|
+
contentType;
|
|
6
|
+
bodySnippet;
|
|
7
|
+
constructor(params) {
|
|
8
|
+
const snippet = params.bodySnippet.slice(0, 200);
|
|
9
|
+
super(`Upstream returned ${params.status} with non-JSON body (content-type="${params.contentType || "<none>"}", length=${params.bodySnippet.length}) from ${params.url}. This usually means the request hit a catchall handler or a misrouted reverse proxy. Body: ${JSON.stringify(snippet)}`);
|
|
10
|
+
this.name = "UpstreamInvalidResponseError";
|
|
11
|
+
this.url = params.url;
|
|
12
|
+
this.status = params.status;
|
|
13
|
+
this.contentType = params.contentType;
|
|
14
|
+
this.bodySnippet = snippet;
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
function toHeaders(headers) {
|
|
18
|
+
const normalized = new Headers();
|
|
19
|
+
if (!headers) return normalized;
|
|
20
|
+
if (headers instanceof Headers) {
|
|
21
|
+
for (const [key, value] of headers.entries()) normalized.set(key, value);
|
|
22
|
+
return normalized;
|
|
23
|
+
}
|
|
24
|
+
if (Array.isArray(headers)) {
|
|
25
|
+
for (const [key, value] of headers) if (value != null) normalized.set(key, value);
|
|
26
|
+
return normalized;
|
|
27
|
+
}
|
|
28
|
+
for (const [key, value] of Object.entries(headers)) if (value != null) normalized.set(key, value);
|
|
29
|
+
return normalized;
|
|
30
|
+
}
|
|
31
|
+
function appendQueryParam(searchParams, key, value) {
|
|
32
|
+
if (value == null) return;
|
|
33
|
+
searchParams.append(key, String(value));
|
|
34
|
+
}
|
|
35
|
+
function buildUrl({ baseURL, params, url }) {
|
|
36
|
+
if (!url) throw new Error("Request URL is required.");
|
|
37
|
+
const hasAbsoluteUrl = /^https?:\/\//u.test(url);
|
|
38
|
+
if (!(baseURL || hasAbsoluteUrl)) throw new Error(`Relative URL "${url}" requires a baseURL.`);
|
|
39
|
+
let resolved;
|
|
40
|
+
if (hasAbsoluteUrl) resolved = new URL(url);
|
|
41
|
+
else {
|
|
42
|
+
const trimmedBase = (baseURL ?? "").replace(/\/+$/u, "");
|
|
43
|
+
const normalizedPath = url.startsWith("/") ? url : `/${url}`;
|
|
44
|
+
resolved = new URL(`${trimmedBase}${normalizedPath}`);
|
|
45
|
+
}
|
|
46
|
+
for (const [key, rawValue] of Object.entries(params ?? {})) {
|
|
47
|
+
if (Array.isArray(rawValue)) {
|
|
48
|
+
for (const value of rawValue) appendQueryParam(resolved.searchParams, key, value);
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
appendQueryParam(resolved.searchParams, key, rawValue);
|
|
52
|
+
}
|
|
53
|
+
return resolved;
|
|
54
|
+
}
|
|
55
|
+
function isJsonBody(value) {
|
|
56
|
+
return typeof value === "object" && value !== null && !(value instanceof ArrayBuffer) && !(value instanceof Blob) && !(value instanceof FormData) && !(value instanceof URLSearchParams);
|
|
57
|
+
}
|
|
58
|
+
async function parseSuccessBody(response, responseType, requestUrl) {
|
|
59
|
+
if (response.status === 204) return;
|
|
60
|
+
if (responseType === "arraybuffer") return await response.arrayBuffer();
|
|
61
|
+
if (responseType === "blob") return await response.blob();
|
|
62
|
+
if (responseType === "text") return await response.text();
|
|
63
|
+
const contentType = response.headers.get("content-type") ?? "";
|
|
64
|
+
if (!contentType.includes("application/json")) {
|
|
65
|
+
const snippet = await response.text();
|
|
66
|
+
throw new UpstreamInvalidResponseError({
|
|
67
|
+
url: requestUrl,
|
|
68
|
+
status: response.status,
|
|
69
|
+
contentType,
|
|
70
|
+
bodySnippet: snippet
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
const raw = await response.text();
|
|
74
|
+
if (raw.length === 0) throw new UpstreamInvalidResponseError({
|
|
75
|
+
url: requestUrl,
|
|
76
|
+
status: response.status,
|
|
77
|
+
contentType,
|
|
78
|
+
bodySnippet: ""
|
|
79
|
+
});
|
|
80
|
+
try {
|
|
81
|
+
return JSON.parse(raw);
|
|
82
|
+
} catch (_parseError) {
|
|
83
|
+
throw new UpstreamInvalidResponseError({
|
|
84
|
+
url: requestUrl,
|
|
85
|
+
status: response.status,
|
|
86
|
+
contentType,
|
|
87
|
+
bodySnippet: raw
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
async function parseErrorBody(response) {
|
|
92
|
+
try {
|
|
93
|
+
if ((response.headers.get("content-type") ?? "").includes("application/json")) {
|
|
94
|
+
const raw = await response.text();
|
|
95
|
+
return raw.length === 0 ? void 0 : JSON.parse(raw);
|
|
96
|
+
}
|
|
97
|
+
return await response.text();
|
|
98
|
+
} catch {
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
async function baseClient(config) {
|
|
103
|
+
const requestUrl = buildUrl(config);
|
|
104
|
+
const headers = toHeaders(config.headers);
|
|
105
|
+
const init = {
|
|
106
|
+
credentials: config.credentials,
|
|
107
|
+
headers,
|
|
108
|
+
method: config.method,
|
|
109
|
+
signal: config.signal
|
|
110
|
+
};
|
|
111
|
+
if (config.data !== void 0 && config.method !== "GET") if (isJsonBody(config.data)) {
|
|
112
|
+
if (!headers.has("content-type")) headers.set("content-type", "application/json");
|
|
113
|
+
init.body = JSON.stringify(config.data);
|
|
114
|
+
} else init.body = config.data;
|
|
115
|
+
const response = await fetch(requestUrl, init);
|
|
116
|
+
if (!response.ok) {
|
|
117
|
+
const errorData = await parseErrorBody(response);
|
|
118
|
+
const error = /* @__PURE__ */ new Error(`Request failed with status ${response.status} ${response.statusText}`);
|
|
119
|
+
error.status = response.status;
|
|
120
|
+
error.statusText = response.statusText;
|
|
121
|
+
error.headers = response.headers;
|
|
122
|
+
error.data = errorData;
|
|
123
|
+
throw error;
|
|
124
|
+
}
|
|
125
|
+
return {
|
|
126
|
+
data: await parseSuccessBody(response, config.responseType, requestUrl.toString()),
|
|
127
|
+
headers: response.headers,
|
|
128
|
+
status: response.status,
|
|
129
|
+
statusText: response.statusText
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
function createClient(defaults) {
|
|
133
|
+
return (config) => {
|
|
134
|
+
const headers = toHeaders(defaults.headers);
|
|
135
|
+
for (const [key, value] of toHeaders(config.headers).entries()) headers.set(key, value);
|
|
136
|
+
return baseClient({
|
|
137
|
+
...config,
|
|
138
|
+
baseURL: config.baseURL ?? defaults.baseURL,
|
|
139
|
+
credentials: config.credentials ?? defaults.credentials,
|
|
140
|
+
headers
|
|
141
|
+
});
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
//#endregion
|
|
145
|
+
Object.defineProperty(exports, "baseClient", {
|
|
146
|
+
enumerable: true,
|
|
147
|
+
get: function() {
|
|
148
|
+
return baseClient;
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
Object.defineProperty(exports, "createClient", {
|
|
152
|
+
enumerable: true,
|
|
153
|
+
get: function() {
|
|
154
|
+
return createClient;
|
|
155
|
+
}
|
|
156
|
+
});
|