@customyai/customy-sdk 0.1.0 → 0.3.2
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/CHANGELOG.md +43 -0
- package/LICENSE +21 -0
- package/README.md +2 -0
- package/dist/chunk-25MIDL7U.mjs +198 -0
- package/dist/chunk-YYMC3WOQ.cjs +206 -0
- package/dist/{index.js → index.cjs} +27 -206
- package/dist/{index.d.mts → index.d.cts} +3 -74
- package/dist/index.d.ts +3 -74
- package/dist/index.mjs +5 -176
- package/dist/portfolio-Bk9cn8h4.d.cts +79 -0
- package/dist/portfolio-Bk9cn8h4.d.ts +79 -0
- package/dist/server.cjs +454 -0
- package/dist/server.d.cts +165 -0
- package/dist/server.d.ts +165 -0
- package/dist/server.mjs +452 -0
- package/package.json +72 -27
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# @customyai/customy-sdk
|
|
2
|
+
|
|
3
|
+
## 0.3.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Dependencias actualizadas:
|
|
8
|
+
- @customyai/customy-access@0.8.2
|
|
9
|
+
- @customyai/sdk@0.1.1
|
|
10
|
+
|
|
11
|
+
## 0.3.1
|
|
12
|
+
|
|
13
|
+
### Patch Changes
|
|
14
|
+
|
|
15
|
+
- Dependencias actualizadas:
|
|
16
|
+
- @customyai/customy-access@0.8.1
|
|
17
|
+
|
|
18
|
+
## 0.3.0
|
|
19
|
+
|
|
20
|
+
### Minor Changes
|
|
21
|
+
|
|
22
|
+
- En desuso: usa `@customyai/sdk`. `./server` toma ahora el discovery y los tokens de máquina de `@customyai/sdk` (y `@customyai/core`) y avisa una vez por proceso (`DeprecationWarning` `CUSTOMY_SDK_DEPRECATED`; `console.warn` fuera de Node); `createCustomy`, `token`, `product`, `send`, `links`, `data` y `billing` conservan su forma y sus mensajes de error (`CUSTOMY_DISCOVERY_FAILED: <estado>`, `CUSTOMY_MACHINE_TOKEN_FAILED: <estado> <motivo>`, con el error de `@customyai/core` en `cause`). `CustomyClient` y los clientes de cartera (`createCustomySdk`) no tienen equivalente en los paquetes nuevos y siguen igual, con el mismo aviso.
|
|
23
|
+
|
|
24
|
+
### Patch Changes
|
|
25
|
+
|
|
26
|
+
- `customy.send` recoge lo nuevo de `@customyai/send-sdk` para push: contenido rico, programación, cancelar/retirar, categorías, ajustes y preferencias por persona. Solo añade.
|
|
27
|
+
- `customy.send` (en `@customyai/customy-sdk/server`) incluye las notificaciones de Customy Send: enviar con clave de idempotencia, dispositivos y credenciales de push nativo, bandeja e in-app. Solo añade: nada existente cambia.
|
|
28
|
+
- Dependencias actualizadas:
|
|
29
|
+
- @customyai/customy-access@0.8.0
|
|
30
|
+
- @customyai/links-sdk@0.3.0
|
|
31
|
+
- @customyai/sdk@0.1.0
|
|
32
|
+
- @customyai/send-sdk@1.3.0
|
|
33
|
+
|
|
34
|
+
## 0.2.0
|
|
35
|
+
|
|
36
|
+
- `./server`: `createCustomy({ issuer, clientId, clientSecret })` discovers the
|
|
37
|
+
platform, keeps one machine token per audience and returns ready clients for
|
|
38
|
+
Send, Links, Data and Billing, plus a generic `product(key)`.
|
|
39
|
+
|
|
40
|
+
## 0.1.0
|
|
41
|
+
|
|
42
|
+
- Initial portfolio umbrella SDK with isolated clients for every Customy product
|
|
43
|
+
and platform service.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Customy
|
|
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
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# @customyai/customy-sdk
|
|
2
2
|
|
|
3
|
+
> **Deprecated.** Use [`@customyai/sdk`](../sdk): `createCustomy({ issuer, clientId, clientSecret })` and `product(key)` keep their shape, and each product comes from its own package (`@customyai/send`, `@customyai/links`, `@customyai/data`, `@customyai/billing`, `@customyai/access`). This package stays for one major cycle as an adapter: `./server` takes discovery and machine tokens from `@customyai/sdk`; `CustomyClient` and the portfolio clients are unchanged. It warns once per process.
|
|
4
|
+
|
|
3
5
|
Umbrella SDK for the Customy portfolio. It exposes one isolated client per
|
|
4
6
|
product and platform service while keeping the base URL of each boundary
|
|
5
7
|
explicit. It never guesses staging or production URLs.
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
// src/deprecation.ts
|
|
2
|
+
var SEEN = /* @__PURE__ */ Symbol.for("customy.sdk.deprecations");
|
|
3
|
+
function warnDeprecated(name, message) {
|
|
4
|
+
const registry = globalThis;
|
|
5
|
+
const seen = registry[SEEN] ??= /* @__PURE__ */ new Set();
|
|
6
|
+
if (seen.has(name)) return;
|
|
7
|
+
seen.add(name);
|
|
8
|
+
const text = `${name} is deprecated: ${message}`;
|
|
9
|
+
const proc = globalThis.process;
|
|
10
|
+
if (typeof proc?.emitWarning === "function") proc.emitWarning(text, { type: "DeprecationWarning", code: "CUSTOMY_SDK_DEPRECATED" });
|
|
11
|
+
else if (typeof console !== "undefined" && typeof console.warn === "function") console.warn(text);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// src/portfolio.ts
|
|
15
|
+
var CUSTOMY_PRODUCT_KEYS = [
|
|
16
|
+
"agent",
|
|
17
|
+
"ads",
|
|
18
|
+
"analytics",
|
|
19
|
+
"atlas",
|
|
20
|
+
"bookings",
|
|
21
|
+
"campaigns",
|
|
22
|
+
"commerce",
|
|
23
|
+
"content",
|
|
24
|
+
"crm",
|
|
25
|
+
"data",
|
|
26
|
+
"design",
|
|
27
|
+
"domains",
|
|
28
|
+
"engagement",
|
|
29
|
+
"flows",
|
|
30
|
+
"forms",
|
|
31
|
+
"links",
|
|
32
|
+
"mission-control",
|
|
33
|
+
"pages",
|
|
34
|
+
"payments",
|
|
35
|
+
"send",
|
|
36
|
+
"sitesight",
|
|
37
|
+
"support",
|
|
38
|
+
"tables",
|
|
39
|
+
"tasks",
|
|
40
|
+
"voice",
|
|
41
|
+
"whatsapp",
|
|
42
|
+
"work"
|
|
43
|
+
];
|
|
44
|
+
var CUSTOMY_PLATFORM_SERVICE_KEYS = [
|
|
45
|
+
"access",
|
|
46
|
+
"audit",
|
|
47
|
+
"billing",
|
|
48
|
+
"events",
|
|
49
|
+
"integrations",
|
|
50
|
+
"realtime",
|
|
51
|
+
"scheduler",
|
|
52
|
+
"storage"
|
|
53
|
+
];
|
|
54
|
+
var CustomySdkError = class extends Error {
|
|
55
|
+
constructor(product, status, code, body) {
|
|
56
|
+
super(`Customy ${product} SDK request failed (${status}): ${code}`);
|
|
57
|
+
this.product = product;
|
|
58
|
+
this.status = status;
|
|
59
|
+
this.code = code;
|
|
60
|
+
this.body = body;
|
|
61
|
+
this.name = "CustomySdkError";
|
|
62
|
+
}
|
|
63
|
+
product;
|
|
64
|
+
status;
|
|
65
|
+
code;
|
|
66
|
+
body;
|
|
67
|
+
};
|
|
68
|
+
function normalizeBaseUrl(value, product, allowLoopbackHttp = false) {
|
|
69
|
+
if (!value) throw new CustomySdkError(product, 0, "SDK_BASE_URL_REQUIRED");
|
|
70
|
+
let url;
|
|
71
|
+
try {
|
|
72
|
+
url = new URL(value);
|
|
73
|
+
} catch {
|
|
74
|
+
throw new CustomySdkError(product, 0, "SDK_BASE_URL_INVALID");
|
|
75
|
+
}
|
|
76
|
+
const internalHttp = url.protocol === "http:" && /^customy-[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/.test(url.hostname) && (!url.port || /^[0-9]{1,5}$/.test(url.port));
|
|
77
|
+
const loopbackHttp = allowLoopbackHttp && url.protocol === "http:" && (url.hostname === "127.0.0.1" || url.hostname === "[::1]") && (!url.port || /^[0-9]{1,5}$/.test(url.port));
|
|
78
|
+
if (!internalHttp && !loopbackHttp && url.protocol !== "https:" || url.username || url.password || url.search || url.hash)
|
|
79
|
+
throw new CustomySdkError(product, 0, "SDK_BASE_URL_INVALID");
|
|
80
|
+
return url.toString().replace(/\/$/, "");
|
|
81
|
+
}
|
|
82
|
+
function buildUrl(baseUrl, path, query, product) {
|
|
83
|
+
if (!path.startsWith("/") || path.startsWith("//") || path.includes("..")) throw new CustomySdkError(product, 0, "SDK_PATH_INVALID");
|
|
84
|
+
const url = new URL(path, `${baseUrl}/`);
|
|
85
|
+
for (const [key, value] of Object.entries(query ?? {})) {
|
|
86
|
+
if (value === void 0 || value === null) continue;
|
|
87
|
+
if (Array.isArray(value)) for (const item of value) url.searchParams.append(key, String(item));
|
|
88
|
+
else url.searchParams.set(key, String(value));
|
|
89
|
+
}
|
|
90
|
+
return url;
|
|
91
|
+
}
|
|
92
|
+
async function readBody(response, maxBytes) {
|
|
93
|
+
if (response.status === 204) return null;
|
|
94
|
+
let text;
|
|
95
|
+
try {
|
|
96
|
+
text = await response.text();
|
|
97
|
+
} catch {
|
|
98
|
+
throw new Error("SDK_RESPONSE_READ_FAILED");
|
|
99
|
+
}
|
|
100
|
+
if (new TextEncoder().encode(text).byteLength > maxBytes) throw new Error("SDK_RESPONSE_TOO_LARGE");
|
|
101
|
+
if (!text) return null;
|
|
102
|
+
try {
|
|
103
|
+
return JSON.parse(text);
|
|
104
|
+
} catch {
|
|
105
|
+
return text;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
var CustomyProductClient = class {
|
|
109
|
+
product;
|
|
110
|
+
configuredBaseUrl;
|
|
111
|
+
config;
|
|
112
|
+
fetchImpl;
|
|
113
|
+
constructor(product, config) {
|
|
114
|
+
this.product = product;
|
|
115
|
+
this.config = config;
|
|
116
|
+
this.configuredBaseUrl = config.baseUrls?.[product] ?? config.baseUrl;
|
|
117
|
+
this.fetchImpl = config.fetch ?? globalThis.fetch;
|
|
118
|
+
if (!this.fetchImpl) throw new CustomySdkError(product, 0, "SDK_FETCH_REQUIRED");
|
|
119
|
+
}
|
|
120
|
+
get baseUrl() {
|
|
121
|
+
return normalizeBaseUrl(this.configuredBaseUrl, this.product, Boolean(this.config.fetch));
|
|
122
|
+
}
|
|
123
|
+
async request(method, path, options = {}) {
|
|
124
|
+
const url = buildUrl(this.baseUrl, path, options.query, this.product);
|
|
125
|
+
const controller = new AbortController();
|
|
126
|
+
const signal = options.signal ? AbortSignal.any([options.signal, controller.signal]) : controller.signal;
|
|
127
|
+
const timeout = setTimeout(() => controller.abort(), options.timeoutMs ?? this.config.timeoutMs ?? 3e4);
|
|
128
|
+
const headers = { accept: "application/json", ...this.config.headers, ...options.headers };
|
|
129
|
+
if (options.body !== void 0) headers["content-type"] ??= "application/json";
|
|
130
|
+
if (this.config.apiKey || this.config.bearerToken) headers.authorization ??= `Bearer ${this.config.bearerToken ?? this.config.apiKey}`;
|
|
131
|
+
if (this.config.internalKey) headers["x-internal-key"] ??= this.config.internalKey;
|
|
132
|
+
try {
|
|
133
|
+
if (this.config.accessToken && !headers.authorization) {
|
|
134
|
+
try {
|
|
135
|
+
headers.authorization = `Bearer ${await this.config.accessToken()}`;
|
|
136
|
+
} catch {
|
|
137
|
+
throw new CustomySdkError(this.product, 401, "SDK_ACCESS_TOKEN_UNAVAILABLE");
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
const response = await this.fetchImpl(url, { method, headers, body: options.body === void 0 ? void 0 : JSON.stringify(options.body), cache: "no-store", credentials: "omit", redirect: "error", signal });
|
|
141
|
+
let body;
|
|
142
|
+
try {
|
|
143
|
+
body = await readBody(response, options.maxBytes ?? 4 * 1024 * 1024);
|
|
144
|
+
} catch (error) {
|
|
145
|
+
if (error instanceof Error && error.message === "SDK_RESPONSE_TOO_LARGE") throw new CustomySdkError(this.product, 413, "SDK_RESPONSE_TOO_LARGE");
|
|
146
|
+
if (error instanceof Error && error.message === "SDK_RESPONSE_READ_FAILED") throw new CustomySdkError(this.product, 503, "SDK_RESPONSE_READ_FAILED");
|
|
147
|
+
throw new CustomySdkError(this.product, 502, "SDK_RESPONSE_INVALID");
|
|
148
|
+
}
|
|
149
|
+
if (!response.ok) {
|
|
150
|
+
const code = body && typeof body === "object" && "code" in body && typeof body.code === "string" ? body.code : `HTTP_${response.status}`;
|
|
151
|
+
throw new CustomySdkError(this.product, response.status, code, body);
|
|
152
|
+
}
|
|
153
|
+
return body;
|
|
154
|
+
} catch (error) {
|
|
155
|
+
if (error instanceof CustomySdkError) throw error;
|
|
156
|
+
if (error instanceof DOMException && error.name === "AbortError") throw new CustomySdkError(this.product, 408, "SDK_TIMEOUT");
|
|
157
|
+
throw new CustomySdkError(this.product, 503, "SDK_UNAVAILABLE");
|
|
158
|
+
} finally {
|
|
159
|
+
clearTimeout(timeout);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
get(path, options) {
|
|
163
|
+
return this.request("GET", path, options);
|
|
164
|
+
}
|
|
165
|
+
post(path, body, options) {
|
|
166
|
+
return this.request("POST", path, { ...options, body });
|
|
167
|
+
}
|
|
168
|
+
put(path, body, options) {
|
|
169
|
+
return this.request("PUT", path, { ...options, body });
|
|
170
|
+
}
|
|
171
|
+
patch(path, body, options) {
|
|
172
|
+
return this.request("PATCH", path, { ...options, body });
|
|
173
|
+
}
|
|
174
|
+
delete(path, options) {
|
|
175
|
+
return this.request("DELETE", path, options);
|
|
176
|
+
}
|
|
177
|
+
};
|
|
178
|
+
var CustomyPortfolioSdk = class {
|
|
179
|
+
clients;
|
|
180
|
+
products;
|
|
181
|
+
platform;
|
|
182
|
+
constructor(config) {
|
|
183
|
+
warnDeprecated("@customyai/customy-sdk", "use @customyai/sdk (createCustomy and product(key)).");
|
|
184
|
+
const keys = [...CUSTOMY_PRODUCT_KEYS, ...CUSTOMY_PLATFORM_SERVICE_KEYS];
|
|
185
|
+
this.clients = Object.fromEntries(keys.map((key) => [key, new CustomyProductClient(key, config)]));
|
|
186
|
+
this.products = Object.fromEntries(CUSTOMY_PRODUCT_KEYS.map((key) => [key, this.clients[key]]));
|
|
187
|
+
this.platform = Object.fromEntries(CUSTOMY_PLATFORM_SERVICE_KEYS.map((key) => [key, this.clients[key]]));
|
|
188
|
+
}
|
|
189
|
+
product(key) {
|
|
190
|
+
return this.products[key];
|
|
191
|
+
}
|
|
192
|
+
service(key) {
|
|
193
|
+
return this.platform[key];
|
|
194
|
+
}
|
|
195
|
+
};
|
|
196
|
+
var createCustomySdk = (config) => new CustomyPortfolioSdk(config);
|
|
197
|
+
|
|
198
|
+
export { CUSTOMY_PLATFORM_SERVICE_KEYS, CUSTOMY_PRODUCT_KEYS, CustomyPortfolioSdk, CustomyProductClient, CustomySdkError, createCustomySdk, warnDeprecated };
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// src/deprecation.ts
|
|
4
|
+
var SEEN = /* @__PURE__ */ Symbol.for("customy.sdk.deprecations");
|
|
5
|
+
function warnDeprecated(name, message) {
|
|
6
|
+
const registry = globalThis;
|
|
7
|
+
const seen = registry[SEEN] ??= /* @__PURE__ */ new Set();
|
|
8
|
+
if (seen.has(name)) return;
|
|
9
|
+
seen.add(name);
|
|
10
|
+
const text = `${name} is deprecated: ${message}`;
|
|
11
|
+
const proc = globalThis.process;
|
|
12
|
+
if (typeof proc?.emitWarning === "function") proc.emitWarning(text, { type: "DeprecationWarning", code: "CUSTOMY_SDK_DEPRECATED" });
|
|
13
|
+
else if (typeof console !== "undefined" && typeof console.warn === "function") console.warn(text);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// src/portfolio.ts
|
|
17
|
+
var CUSTOMY_PRODUCT_KEYS = [
|
|
18
|
+
"agent",
|
|
19
|
+
"ads",
|
|
20
|
+
"analytics",
|
|
21
|
+
"atlas",
|
|
22
|
+
"bookings",
|
|
23
|
+
"campaigns",
|
|
24
|
+
"commerce",
|
|
25
|
+
"content",
|
|
26
|
+
"crm",
|
|
27
|
+
"data",
|
|
28
|
+
"design",
|
|
29
|
+
"domains",
|
|
30
|
+
"engagement",
|
|
31
|
+
"flows",
|
|
32
|
+
"forms",
|
|
33
|
+
"links",
|
|
34
|
+
"mission-control",
|
|
35
|
+
"pages",
|
|
36
|
+
"payments",
|
|
37
|
+
"send",
|
|
38
|
+
"sitesight",
|
|
39
|
+
"support",
|
|
40
|
+
"tables",
|
|
41
|
+
"tasks",
|
|
42
|
+
"voice",
|
|
43
|
+
"whatsapp",
|
|
44
|
+
"work"
|
|
45
|
+
];
|
|
46
|
+
var CUSTOMY_PLATFORM_SERVICE_KEYS = [
|
|
47
|
+
"access",
|
|
48
|
+
"audit",
|
|
49
|
+
"billing",
|
|
50
|
+
"events",
|
|
51
|
+
"integrations",
|
|
52
|
+
"realtime",
|
|
53
|
+
"scheduler",
|
|
54
|
+
"storage"
|
|
55
|
+
];
|
|
56
|
+
var CustomySdkError = class extends Error {
|
|
57
|
+
constructor(product, status, code, body) {
|
|
58
|
+
super(`Customy ${product} SDK request failed (${status}): ${code}`);
|
|
59
|
+
this.product = product;
|
|
60
|
+
this.status = status;
|
|
61
|
+
this.code = code;
|
|
62
|
+
this.body = body;
|
|
63
|
+
this.name = "CustomySdkError";
|
|
64
|
+
}
|
|
65
|
+
product;
|
|
66
|
+
status;
|
|
67
|
+
code;
|
|
68
|
+
body;
|
|
69
|
+
};
|
|
70
|
+
function normalizeBaseUrl(value, product, allowLoopbackHttp = false) {
|
|
71
|
+
if (!value) throw new CustomySdkError(product, 0, "SDK_BASE_URL_REQUIRED");
|
|
72
|
+
let url;
|
|
73
|
+
try {
|
|
74
|
+
url = new URL(value);
|
|
75
|
+
} catch {
|
|
76
|
+
throw new CustomySdkError(product, 0, "SDK_BASE_URL_INVALID");
|
|
77
|
+
}
|
|
78
|
+
const internalHttp = url.protocol === "http:" && /^customy-[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/.test(url.hostname) && (!url.port || /^[0-9]{1,5}$/.test(url.port));
|
|
79
|
+
const loopbackHttp = allowLoopbackHttp && url.protocol === "http:" && (url.hostname === "127.0.0.1" || url.hostname === "[::1]") && (!url.port || /^[0-9]{1,5}$/.test(url.port));
|
|
80
|
+
if (!internalHttp && !loopbackHttp && url.protocol !== "https:" || url.username || url.password || url.search || url.hash)
|
|
81
|
+
throw new CustomySdkError(product, 0, "SDK_BASE_URL_INVALID");
|
|
82
|
+
return url.toString().replace(/\/$/, "");
|
|
83
|
+
}
|
|
84
|
+
function buildUrl(baseUrl, path, query, product) {
|
|
85
|
+
if (!path.startsWith("/") || path.startsWith("//") || path.includes("..")) throw new CustomySdkError(product, 0, "SDK_PATH_INVALID");
|
|
86
|
+
const url = new URL(path, `${baseUrl}/`);
|
|
87
|
+
for (const [key, value] of Object.entries(query ?? {})) {
|
|
88
|
+
if (value === void 0 || value === null) continue;
|
|
89
|
+
if (Array.isArray(value)) for (const item of value) url.searchParams.append(key, String(item));
|
|
90
|
+
else url.searchParams.set(key, String(value));
|
|
91
|
+
}
|
|
92
|
+
return url;
|
|
93
|
+
}
|
|
94
|
+
async function readBody(response, maxBytes) {
|
|
95
|
+
if (response.status === 204) return null;
|
|
96
|
+
let text;
|
|
97
|
+
try {
|
|
98
|
+
text = await response.text();
|
|
99
|
+
} catch {
|
|
100
|
+
throw new Error("SDK_RESPONSE_READ_FAILED");
|
|
101
|
+
}
|
|
102
|
+
if (new TextEncoder().encode(text).byteLength > maxBytes) throw new Error("SDK_RESPONSE_TOO_LARGE");
|
|
103
|
+
if (!text) return null;
|
|
104
|
+
try {
|
|
105
|
+
return JSON.parse(text);
|
|
106
|
+
} catch {
|
|
107
|
+
return text;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
var CustomyProductClient = class {
|
|
111
|
+
product;
|
|
112
|
+
configuredBaseUrl;
|
|
113
|
+
config;
|
|
114
|
+
fetchImpl;
|
|
115
|
+
constructor(product, config) {
|
|
116
|
+
this.product = product;
|
|
117
|
+
this.config = config;
|
|
118
|
+
this.configuredBaseUrl = config.baseUrls?.[product] ?? config.baseUrl;
|
|
119
|
+
this.fetchImpl = config.fetch ?? globalThis.fetch;
|
|
120
|
+
if (!this.fetchImpl) throw new CustomySdkError(product, 0, "SDK_FETCH_REQUIRED");
|
|
121
|
+
}
|
|
122
|
+
get baseUrl() {
|
|
123
|
+
return normalizeBaseUrl(this.configuredBaseUrl, this.product, Boolean(this.config.fetch));
|
|
124
|
+
}
|
|
125
|
+
async request(method, path, options = {}) {
|
|
126
|
+
const url = buildUrl(this.baseUrl, path, options.query, this.product);
|
|
127
|
+
const controller = new AbortController();
|
|
128
|
+
const signal = options.signal ? AbortSignal.any([options.signal, controller.signal]) : controller.signal;
|
|
129
|
+
const timeout = setTimeout(() => controller.abort(), options.timeoutMs ?? this.config.timeoutMs ?? 3e4);
|
|
130
|
+
const headers = { accept: "application/json", ...this.config.headers, ...options.headers };
|
|
131
|
+
if (options.body !== void 0) headers["content-type"] ??= "application/json";
|
|
132
|
+
if (this.config.apiKey || this.config.bearerToken) headers.authorization ??= `Bearer ${this.config.bearerToken ?? this.config.apiKey}`;
|
|
133
|
+
if (this.config.internalKey) headers["x-internal-key"] ??= this.config.internalKey;
|
|
134
|
+
try {
|
|
135
|
+
if (this.config.accessToken && !headers.authorization) {
|
|
136
|
+
try {
|
|
137
|
+
headers.authorization = `Bearer ${await this.config.accessToken()}`;
|
|
138
|
+
} catch {
|
|
139
|
+
throw new CustomySdkError(this.product, 401, "SDK_ACCESS_TOKEN_UNAVAILABLE");
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
const response = await this.fetchImpl(url, { method, headers, body: options.body === void 0 ? void 0 : JSON.stringify(options.body), cache: "no-store", credentials: "omit", redirect: "error", signal });
|
|
143
|
+
let body;
|
|
144
|
+
try {
|
|
145
|
+
body = await readBody(response, options.maxBytes ?? 4 * 1024 * 1024);
|
|
146
|
+
} catch (error) {
|
|
147
|
+
if (error instanceof Error && error.message === "SDK_RESPONSE_TOO_LARGE") throw new CustomySdkError(this.product, 413, "SDK_RESPONSE_TOO_LARGE");
|
|
148
|
+
if (error instanceof Error && error.message === "SDK_RESPONSE_READ_FAILED") throw new CustomySdkError(this.product, 503, "SDK_RESPONSE_READ_FAILED");
|
|
149
|
+
throw new CustomySdkError(this.product, 502, "SDK_RESPONSE_INVALID");
|
|
150
|
+
}
|
|
151
|
+
if (!response.ok) {
|
|
152
|
+
const code = body && typeof body === "object" && "code" in body && typeof body.code === "string" ? body.code : `HTTP_${response.status}`;
|
|
153
|
+
throw new CustomySdkError(this.product, response.status, code, body);
|
|
154
|
+
}
|
|
155
|
+
return body;
|
|
156
|
+
} catch (error) {
|
|
157
|
+
if (error instanceof CustomySdkError) throw error;
|
|
158
|
+
if (error instanceof DOMException && error.name === "AbortError") throw new CustomySdkError(this.product, 408, "SDK_TIMEOUT");
|
|
159
|
+
throw new CustomySdkError(this.product, 503, "SDK_UNAVAILABLE");
|
|
160
|
+
} finally {
|
|
161
|
+
clearTimeout(timeout);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
get(path, options) {
|
|
165
|
+
return this.request("GET", path, options);
|
|
166
|
+
}
|
|
167
|
+
post(path, body, options) {
|
|
168
|
+
return this.request("POST", path, { ...options, body });
|
|
169
|
+
}
|
|
170
|
+
put(path, body, options) {
|
|
171
|
+
return this.request("PUT", path, { ...options, body });
|
|
172
|
+
}
|
|
173
|
+
patch(path, body, options) {
|
|
174
|
+
return this.request("PATCH", path, { ...options, body });
|
|
175
|
+
}
|
|
176
|
+
delete(path, options) {
|
|
177
|
+
return this.request("DELETE", path, options);
|
|
178
|
+
}
|
|
179
|
+
};
|
|
180
|
+
var CustomyPortfolioSdk = class {
|
|
181
|
+
clients;
|
|
182
|
+
products;
|
|
183
|
+
platform;
|
|
184
|
+
constructor(config) {
|
|
185
|
+
warnDeprecated("@customyai/customy-sdk", "use @customyai/sdk (createCustomy and product(key)).");
|
|
186
|
+
const keys = [...CUSTOMY_PRODUCT_KEYS, ...CUSTOMY_PLATFORM_SERVICE_KEYS];
|
|
187
|
+
this.clients = Object.fromEntries(keys.map((key) => [key, new CustomyProductClient(key, config)]));
|
|
188
|
+
this.products = Object.fromEntries(CUSTOMY_PRODUCT_KEYS.map((key) => [key, this.clients[key]]));
|
|
189
|
+
this.platform = Object.fromEntries(CUSTOMY_PLATFORM_SERVICE_KEYS.map((key) => [key, this.clients[key]]));
|
|
190
|
+
}
|
|
191
|
+
product(key) {
|
|
192
|
+
return this.products[key];
|
|
193
|
+
}
|
|
194
|
+
service(key) {
|
|
195
|
+
return this.platform[key];
|
|
196
|
+
}
|
|
197
|
+
};
|
|
198
|
+
var createCustomySdk = (config) => new CustomyPortfolioSdk(config);
|
|
199
|
+
|
|
200
|
+
exports.CUSTOMY_PLATFORM_SERVICE_KEYS = CUSTOMY_PLATFORM_SERVICE_KEYS;
|
|
201
|
+
exports.CUSTOMY_PRODUCT_KEYS = CUSTOMY_PRODUCT_KEYS;
|
|
202
|
+
exports.CustomyPortfolioSdk = CustomyPortfolioSdk;
|
|
203
|
+
exports.CustomyProductClient = CustomyProductClient;
|
|
204
|
+
exports.CustomySdkError = CustomySdkError;
|
|
205
|
+
exports.createCustomySdk = createCustomySdk;
|
|
206
|
+
exports.warnDeprecated = warnDeprecated;
|