@bagelink/sdk 1.20.52 → 1.20.56

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.
@@ -0,0 +1,48 @@
1
+ import { isSchemaObject } from './types/utils';
2
+ import { formatType, formatVarType, schemaToType } from './utils';
3
+ export function generateTypes(schemas) {
4
+ if (!schemas) {
5
+ return '';
6
+ }
7
+ const schemaEntries = Object.entries(schemas);
8
+ return schemaEntries
9
+ .map(([_typeName, schema]) => {
10
+ const typeName = formatType(_typeName);
11
+ if (!isSchemaObject(schema)) {
12
+ return '';
13
+ }
14
+ if (schema?.enum) {
15
+ return `export type ${typeName} = ${schema.enum.map((item) => `'${item}'`).join(' | ')};\n`;
16
+ }
17
+ if (schema?.type === 'array' && schema.items) {
18
+ return `export type ${typeName} = (${schemaToType(schema.items)})[];\n`;
19
+ }
20
+ if (!schema.properties) {
21
+ // Handle case where schema has additionalProperties: true
22
+ if (schema.additionalProperties === true) {
23
+ return `export type ${typeName} = { [key: string]: any };\n`;
24
+ }
25
+ // #region Debug
26
+ // console.log('No properties found for schema:', typeName)
27
+ // console.log(JSON.stringify({ typeName, schema }, null, 2))
28
+ // #endregion Debug
29
+ return '';
30
+ }
31
+ // Handle empty properties with additionalProperties
32
+ if (Object.keys(schema.properties).length === 0 && schema.additionalProperties === true) {
33
+ return `export type ${typeName} = { [key: string]: any };\n`;
34
+ }
35
+ const properties = Object.entries(schema.properties)
36
+ .map(([key, value]) => {
37
+ // Wrap key in quotes if it contains hyphens or isn't a valid identifier
38
+ const quotedKey = /^[a-z_$][\w$]*$/i.test(key) ? key : `'${key}'`;
39
+ const varType = formatVarType({ varName: quotedKey, schema: value });
40
+ return `\t\t${varType}`;
41
+ })
42
+ .join(';\n ');
43
+ // Add index signature for additionalProperties if true
44
+ const indexSignature = schema.additionalProperties === true ? '\n\t\t[key: string]: any;' : '';
45
+ return `export type ${typeName} = {\n ${properties};${indexSignature}\n };\n`;
46
+ })
47
+ .join('\n');
48
+ }
@@ -0,0 +1,19 @@
1
+ // Typed interfaces for OpenAPI 3.1.0
2
+ // see https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md
3
+ const TYPE_FORMATS = [
4
+ 'uuid',
5
+ 'uri',
6
+ 'date-time',
7
+ 'date',
8
+ 'email',
9
+ 'binary',
10
+ 'password',
11
+ 'phone',
12
+ 'uuid4',
13
+ 'int32',
14
+ 'int64',
15
+ 'float',
16
+ 'double',
17
+ 'byte'
18
+ ];
19
+ export * from './utils';
@@ -0,0 +1,30 @@
1
+ export function getPath(pathsObject, path) {
2
+ return pathsObject ? pathsObject[path] : undefined;
3
+ }
4
+ /**
5
+ * A type guard to check if the given value is a `ReferenceObject`.
6
+ * See https://www.typescriptlang.org/docs/handbook/advanced-types.html#type-guards-and-differentiating-types
7
+ *
8
+ * @param obj The value to check.
9
+ */
10
+ export function isReferenceObject(obj) {
11
+ if (!obj) {
12
+ return false;
13
+ }
14
+ return Object.hasOwn(obj, '$ref');
15
+ }
16
+ /**
17
+ * A type guard to check if the given object is a `SchemaObject`.
18
+ * Useful to distinguish from `ReferenceObject` values that can be used
19
+ * in most places where `SchemaObject` is allowed.
20
+ *
21
+ * See https://www.typescriptlang.org/docs/handbook/advanced-types.html#type-guards-and-differentiating-types
22
+ *
23
+ * @param schema The value to check.
24
+ */
25
+ export function isSchemaObject(schema) {
26
+ return !Object.hasOwn(schema, '$ref');
27
+ }
28
+ export function dereference(property) {
29
+ return property;
30
+ }
@@ -0,0 +1,282 @@
1
+ import { isReferenceObject, isSchemaObject } from './types/utils';
2
+ export function toCamelCase(str) {
3
+ return str
4
+ ?.replaceAll(/[-._\s]+(.)?/g, (_, c) => c?.toUpperCase() || '')
5
+ .replace(/^./, str => str.toLowerCase())
6
+ || str
7
+ || '';
8
+ }
9
+ export function toPascalCase(str) {
10
+ return str
11
+ ?.replaceAll(/[-_\s]+(.)?/g, (_, c) => c?.toUpperCase() || '')
12
+ .replace(/^./, str => str.toUpperCase())
13
+ || str
14
+ || '';
15
+ }
16
+ export function formatType(typeName) {
17
+ typeName = typeName
18
+ .replaceAll('-', '')
19
+ .replaceAll(/post|put$/gi, '')
20
+ .replaceAll(/^body_/gi, '');
21
+ return toPascalCase(typeName);
22
+ }
23
+ function resolveReference(ref) {
24
+ const t = ref.split('/').pop();
25
+ if (!t) {
26
+ return 'any';
27
+ }
28
+ return formatType(t);
29
+ }
30
+ function handleArrayItems(schema) {
31
+ // Handle array items that might be union types
32
+ const itemType = schemaToType(schema.items);
33
+ // Add parentheses around union types to ensure correct syntax
34
+ const needsParentheses = itemType.includes('|') || itemType.includes('&');
35
+ let res = needsParentheses ? `(${itemType})[]` : `${itemType}[]`;
36
+ if (itemType.includes('string | string')) {
37
+ res = res.replace('string | string', 'string');
38
+ }
39
+ if (itemType.includes('string |')) {
40
+ return res.replace('string |', '(string & {}) |');
41
+ }
42
+ if (itemType.includes('| string')) {
43
+ return res.replace('| string', '| (string & {})');
44
+ }
45
+ return res;
46
+ }
47
+ export function schemaToType(schema) {
48
+ if (!schema) {
49
+ return 'any';
50
+ }
51
+ if (isReferenceObject(schema)) {
52
+ if (schema.$ref) {
53
+ return resolveReference(schema.$ref);
54
+ }
55
+ }
56
+ if (!isSchemaObject(schema)) {
57
+ console.warn('Schema is not a SchemaObject:', schema);
58
+ return 'any';
59
+ }
60
+ if (schema.anyOf) {
61
+ let _t = schema.anyOf
62
+ .map(s => schemaToType(s))
63
+ .filter(p => p !== 'any')
64
+ .join(' | ');
65
+ if (_t === '' || _t === 'null') {
66
+ _t = 'any';
67
+ }
68
+ return _t;
69
+ }
70
+ if (schema.oneOf) {
71
+ let _t = schema.oneOf
72
+ .map(s => schemaToType(s))
73
+ .filter(p => p !== 'any')
74
+ .join(' | ');
75
+ if (_t === '' || _t === 'null') {
76
+ _t = 'any';
77
+ }
78
+ return _t;
79
+ }
80
+ if (schema.allOf) {
81
+ return schema.allOf
82
+ .map(s => schemaToType(s))
83
+ .filter(p => p !== 'any')
84
+ .join(' & ');
85
+ }
86
+ // TODO: handle Array.isArray(schema.type) case b4 switch
87
+ switch (schema.type) {
88
+ case 'object': return '{ [key: string]: any }';
89
+ case 'string':
90
+ if (schema.const) {
91
+ return `'${schema.const}'`;
92
+ }
93
+ return 'string';
94
+ case 'integer': return 'number';
95
+ case 'number': return 'number';
96
+ case 'boolean': return 'boolean';
97
+ case 'array': return handleArrayItems(schema);
98
+ case 'undefined': return 'undefined';
99
+ case 'null': return 'null';
100
+ case undefined: return 'any';
101
+ default:
102
+ console.log('Unknown type', schema.type);
103
+ return 'unknown';
104
+ }
105
+ }
106
+ export function isOptional(schema) {
107
+ /// / !schema?.required?.includes(schema.title || '')
108
+ const type = schemaToType(schema);
109
+ const splitType = type.split(/\s+\|\s+/);
110
+ const includesNull = splitType.includes('null');
111
+ const includesUndefined = splitType.includes('undefined');
112
+ return includesNull || includesUndefined || schema?.default !== undefined;
113
+ }
114
+ export function cleanOptionals(str) {
115
+ return str
116
+ .split(' | ')
117
+ .filter(t => t !== 'null' && t !== 'undefined')
118
+ .join(' | ');
119
+ }
120
+ export function formatVarType({ varName, schema, required = false, defaultValue, }) {
121
+ let type = schemaToType(schema);
122
+ type = cleanOptionals(type);
123
+ let defaultStr = '';
124
+ if (defaultValue) {
125
+ if (typeof defaultValue === 'string') {
126
+ defaultStr = ` = '${defaultValue}'`;
127
+ }
128
+ else if (typeof defaultValue === 'object') {
129
+ defaultStr = ` = ${JSON.stringify(defaultValue)}`;
130
+ }
131
+ else {
132
+ defaultStr = ` = ${defaultValue}`;
133
+ }
134
+ }
135
+ let optionalStr = (!required && isOptional(schema)) ? '?' : '';
136
+ if (defaultStr) {
137
+ optionalStr = '';
138
+ }
139
+ return `${varName}${optionalStr}: ${type}${defaultStr}`;
140
+ }
141
+ /**
142
+ * List of JavaScript/TypeScript reserved keywords and common identifiers to avoid
143
+ */
144
+ const RESERVED_KEYWORDS = new Set([
145
+ // JavaScript reserved words
146
+ 'break',
147
+ 'case',
148
+ 'catch',
149
+ 'class',
150
+ 'const',
151
+ 'continue',
152
+ 'debugger',
153
+ 'default',
154
+ 'delete',
155
+ 'do',
156
+ 'else',
157
+ 'enum',
158
+ 'export',
159
+ 'extends',
160
+ 'false',
161
+ 'finally',
162
+ 'for',
163
+ 'function',
164
+ 'if',
165
+ 'import',
166
+ 'in',
167
+ 'instanceof',
168
+ 'new',
169
+ 'null',
170
+ 'return',
171
+ 'super',
172
+ 'switch',
173
+ 'this',
174
+ 'throw',
175
+ 'true',
176
+ 'try',
177
+ 'typeof',
178
+ 'var',
179
+ 'void',
180
+ 'while',
181
+ 'with',
182
+ 'yield',
183
+ // TypeScript reserved words
184
+ 'abstract',
185
+ 'any',
186
+ 'as',
187
+ 'asserts',
188
+ 'bigint',
189
+ 'boolean',
190
+ 'constructor',
191
+ 'declare',
192
+ 'get',
193
+ 'infer',
194
+ 'intrinsic',
195
+ 'is',
196
+ 'keyof',
197
+ 'module',
198
+ 'namespace',
199
+ 'never',
200
+ 'number',
201
+ 'object',
202
+ 'package',
203
+ 'private',
204
+ 'protected',
205
+ 'public',
206
+ 'readonly',
207
+ 'require',
208
+ 'set',
209
+ 'static',
210
+ 'string',
211
+ 'symbol',
212
+ 'type',
213
+ 'undefined',
214
+ 'unique',
215
+ 'unknown',
216
+ // Strict mode reserved words
217
+ 'implements',
218
+ 'interface',
219
+ 'let',
220
+ 'package',
221
+ 'private',
222
+ 'protected',
223
+ 'public',
224
+ 'static',
225
+ // Common global identifiers to avoid
226
+ 'arguments',
227
+ 'eval',
228
+ 'Infinity',
229
+ 'NaN',
230
+ 'undefined',
231
+ 'globalThis',
232
+ 'window',
233
+ 'document',
234
+ 'console',
235
+ 'Object',
236
+ 'Array',
237
+ 'Function',
238
+ 'String',
239
+ 'Number',
240
+ 'Boolean',
241
+ 'Date',
242
+ 'RegExp',
243
+ 'Error',
244
+ 'Promise',
245
+ 'Map',
246
+ 'Set',
247
+ 'WeakMap',
248
+ 'WeakSet',
249
+ 'Symbol',
250
+ 'Proxy',
251
+ 'Reflect'
252
+ ]);
253
+ /**
254
+ * Sanitizes a variable name to ensure it's not a reserved keyword
255
+ * @param varName - The variable name to sanitize
256
+ * @returns A safe variable name
257
+ */
258
+ export function sanitizeVarName(varName) {
259
+ if (!varName) {
260
+ return varName;
261
+ }
262
+ // If it's a reserved keyword, append underscore
263
+ if (RESERVED_KEYWORDS.has(varName.toLowerCase())) {
264
+ return `${varName}_`;
265
+ }
266
+ return varName;
267
+ }
268
+ /**
269
+ * Converts a string to camelCase and ensures it's not a reserved keyword
270
+ * @param str - The string to convert
271
+ * @returns A safe camelCase variable name
272
+ */
273
+ export function toCamelCaseSafe(str) {
274
+ const camelCased = toCamelCase(str);
275
+ return sanitizeVarName(camelCased);
276
+ }
277
+ export function cleanPath(path) {
278
+ return path
279
+ .split('/')
280
+ .filter(p => p && !/\{|\}/.test(p))
281
+ .join('/');
282
+ }
package/src/unwrap.js ADDED
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Unwrap utility for ApiResponse
3
+ *
4
+ * Use this when you need to assign API responses to plain types
5
+ */
6
+ /**
7
+ * Unwrap an ApiResponse to get the plain data
8
+ *
9
+ * @example
10
+ * import { unwrap } from '@bagelink/sdk'
11
+ *
12
+ * const agent = ref<AgentResponse | null>(null)
13
+ * agent.value = unwrap(await api.agents.getByAgentId({ agentId }))
14
+ */
15
+ export function unwrap(response) {
16
+ // If it's already unwrapped, return as-is
17
+ if (!response || typeof response !== 'object') {
18
+ return response;
19
+ }
20
+ // If it's an array (ApiResponse extends Array), return as-is
21
+ if (Array.isArray(response)) {
22
+ return response;
23
+ }
24
+ // If it has $raw, it's an enhanced object - return without metadata
25
+ if ('$raw' in response) {
26
+ const { $raw, $metadata, totalCount, page, perPage, totalPages, rateLimit, rateLimitReset, getHeader, hasPagination, hasNextPage, hasPrevPage, ...data } = response;
27
+ return data;
28
+ }
29
+ return response;
30
+ }
package/src/utils.js ADDED
@@ -0,0 +1,58 @@
1
+ export function formatAPIErrorMessage(err) {
2
+ const error = err;
3
+ // Handle case where error or response is undefined
4
+ if (!error || !error.response) {
5
+ return 'Network error occurred. Please check your connection.';
6
+ }
7
+ const { status, data } = error.response;
8
+ // Handle validation errors (422)
9
+ if (data.detail && Array.isArray(data.detail)) {
10
+ return data.detail
11
+ .map((err) => {
12
+ // Handle nested field paths properly
13
+ const fieldPath = err.loc.slice(1).join('.');
14
+ const field = fieldPath
15
+ .split('.')
16
+ .map(part => part.charAt(0).toUpperCase() + part.slice(1))
17
+ .join(' ');
18
+ const message = err.msg
19
+ // Common validation messages
20
+ .replace(/^(?:field|value|string|none) required$/i, 'is required')
21
+ .replace(/^value is not a valid/i, 'must be a valid')
22
+ .replace(/^ensure this value/i, 'this value must')
23
+ .replace(/^str type expected$/i, 'must be text')
24
+ .replace(/^value could not be parsed to/i, 'must be a')
25
+ .replace(/^ensure this value has at least/i, 'must have at least')
26
+ .replace(/^ensure this value has at most/i, 'must have at most')
27
+ .replace(/^invalid datetime format/i, 'must be a valid date/time')
28
+ .replace(/^value is not a valid email address/i, 'must be a valid email address')
29
+ .replace(/^value is not a valid integer/i, 'must be a whole number')
30
+ .replace(/^value is not a valid float/i, 'must be a valid number');
31
+ return `${field} ${message.toLowerCase()}`;
32
+ })
33
+ .join('\n');
34
+ }
35
+ // Handle specific HTTP status codes
36
+ switch (status) {
37
+ case 401:
38
+ return 'Authentication required. Please log in.';
39
+ case 403:
40
+ return 'You do not have permission to perform this action.';
41
+ case 404:
42
+ return 'The requested resource was not found.';
43
+ case 429:
44
+ return 'Too many requests. Please try again later.';
45
+ case 500:
46
+ return 'An internal server error occurred. Please try again later.';
47
+ }
48
+ // Handle other errors with detail
49
+ if (data.detail && typeof data.detail === 'string') {
50
+ return data.detail;
51
+ }
52
+ // Handle errors with a message field
53
+ if (data.message) {
54
+ return data.message;
55
+ }
56
+ // Generic error fallback
57
+ return `An error occurred (Status ${status}): ${error.message || 'Unknown error'}`;
58
+ }