@frontal-labs/ontology 1.0.1 → 1.0.3

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/dist/index.js CHANGED
@@ -40,1126 +40,8 @@ __export(index_exports, {
40
40
  });
41
41
  module.exports = __toCommonJS(index_exports);
42
42
 
43
- // ../core/dist/index.js
44
- var import_zod = require("zod");
45
-
46
- // ../../node_modules/.bun/@t3-oss+env-core@0.13.11+dcb9db7a51b27bde/node_modules/@t3-oss/env-core/dist/standard.js
47
- function ensureSynchronous(value, message) {
48
- if (value instanceof Promise) throw new Error(message);
49
- }
50
- function parseWithDictionary(dictionary, value) {
51
- const result = {};
52
- const issues = [];
53
- for (const key in dictionary) {
54
- const propResult = dictionary[key]["~standard"].validate(value[key]);
55
- ensureSynchronous(propResult, `Validation must be synchronous, but ${key} returned a Promise.`);
56
- if (propResult.issues) {
57
- issues.push(...propResult.issues.map((issue) => ({
58
- ...issue,
59
- message: issue.message,
60
- path: [key, ...issue.path ?? []]
61
- })));
62
- continue;
63
- }
64
- result[key] = propResult.value;
65
- }
66
- if (issues.length) return { issues };
67
- return { value: result };
68
- }
69
-
70
- // ../../node_modules/.bun/@t3-oss+env-core@0.13.11+dcb9db7a51b27bde/node_modules/@t3-oss/env-core/dist/index.js
71
- function createEnv(opts) {
72
- const runtimeEnv = opts.runtimeEnvStrict ?? opts.runtimeEnv ?? process.env;
73
- if (opts.emptyStringAsUndefined ?? false) {
74
- for (const [key, value] of Object.entries(runtimeEnv)) if (value === "") delete runtimeEnv[key];
75
- }
76
- if (!!opts.skipValidation) {
77
- if (opts.extends) for (const preset of opts.extends) preset.skipValidation = true;
78
- return runtimeEnv;
79
- }
80
- const _client = typeof opts.client === "object" ? opts.client : {};
81
- const _server = typeof opts.server === "object" ? opts.server : {};
82
- const _shared = typeof opts.shared === "object" ? opts.shared : {};
83
- const isServer = opts.isServer ?? (typeof window === "undefined" || "Deno" in window);
84
- const finalSchemaShape = isServer ? {
85
- ..._server,
86
- ..._shared,
87
- ..._client
88
- } : {
89
- ..._client,
90
- ..._shared
91
- };
92
- const parsed = opts.createFinalSchema?.(finalSchemaShape, isServer)?.["~standard"].validate(runtimeEnv) ?? parseWithDictionary(finalSchemaShape, runtimeEnv);
93
- ensureSynchronous(parsed, "Validation must be synchronous");
94
- const onValidationError = opts.onValidationError ?? ((issues) => {
95
- console.error("\u274C Invalid environment variables:", issues);
96
- throw new Error("Invalid environment variables");
97
- });
98
- const onInvalidAccess = opts.onInvalidAccess ?? (() => {
99
- throw new Error("\u274C Attempted to access a server-side environment variable on the client");
100
- });
101
- if (parsed.issues) return onValidationError(parsed.issues);
102
- const isServerAccess = (prop) => {
103
- if (!opts.clientPrefix) return true;
104
- return !prop.startsWith(opts.clientPrefix) && !(prop in _shared);
105
- };
106
- const isValidServerAccess = (prop) => {
107
- return isServer || !isServerAccess(prop);
108
- };
109
- const ignoreProp = (prop) => {
110
- return prop === "__esModule" || prop === "$$typeof";
111
- };
112
- const extendedObj = (opts.extends ?? []).reduce((acc, curr) => {
113
- return Object.assign(acc, curr);
114
- }, {});
115
- const fullObj = Object.assign(extendedObj, parsed.value);
116
- return new Proxy(fullObj, { get(target, prop) {
117
- if (typeof prop !== "string") return void 0;
118
- if (ignoreProp(prop)) return void 0;
119
- if (!isValidServerAccess(prop)) return onInvalidAccess(prop);
120
- return Reflect.get(target, prop);
121
- } });
122
- }
123
-
124
- // ../core/dist/index.js
125
- var import_zod2 = require("zod");
126
- var import_zod3 = require("zod");
127
- var import_zod4 = require("zod");
128
- var DEFAULT_BASE_URL = "https://api.frontal.dev/v1";
129
- var API_KEY_PREFIX = "frt_";
130
- var BACKOFF_STRATEGIES = [
131
- "exponential",
132
- "linear",
133
- "constant"
134
- ];
135
- var DEFAULT_RETRY_ON = [429, 500, 502, 503, 504];
136
- var EXPONENTIAL_BASE = 2;
137
- var JITTER_MAX = 200;
138
- var SDK_VERSION = "1.0.1";
139
- var timestampSchema = import_zod.z.date().transform((date) => new Date(date));
140
- var responseMetaSchema = import_zod.z.object({
141
- requestId: import_zod.z.string().min(1),
142
- timestamp: timestampSchema,
143
- version: import_zod.z.string().optional(),
144
- substrate: import_zod.z.string().optional(),
145
- latency: import_zod.z.object({
146
- total: import_zod.z.number().int().min(0),
147
- substrate: import_zod.z.number().int().min(0).optional()
148
- }).optional()
149
- }).strict();
150
- var paginationMetaSchema = import_zod.z.object({
151
- cursor: import_zod.z.string().min(1),
152
- hasMore: import_zod.z.boolean(),
153
- limit: import_zod.z.number().int().positive().optional(),
154
- total: import_zod.z.number().int().min(0).optional(),
155
- offset: import_zod.z.number().int().min(0).optional()
156
- }).strict();
157
- var errorFieldSchema = import_zod.z.object({
158
- field: import_zod.z.string().describe("Field name"),
159
- code: import_zod.z.string().describe("Error code"),
160
- message: import_zod.z.string().describe("Error message")
161
- }).strict();
162
- var docsUrlSchema = import_zod.z.string().url().refine((url) => /^https?:\/\//.test(url), {
163
- message: "docs must be an http or https URL"
164
- });
165
- var errorResponseSchema = import_zod.z.object({
166
- code: import_zod.z.string().min(1).describe("Error code"),
167
- message: import_zod.z.string().min(1).describe("Error message"),
168
- requestId: import_zod.z.string().min(1).describe("Request ID"),
169
- docs: docsUrlSchema.optional().describe("Documentation URL"),
170
- fields: import_zod.z.array(errorFieldSchema).optional().describe("Array of error fields")
171
- }).strict();
172
- var retryStatusCodeSchema = import_zod.z.number().int().refine((status) => status === 429 || status >= 500 && status <= 599, {
173
- message: "Retry status codes must be 429 or 5xx"
174
- });
175
- var retryConfigSchema = import_zod.z.object({
176
- maxAttempts: import_zod.z.number().int().positive().default(3),
177
- baseDelay: import_zod.z.number().int().positive().default(1e3),
178
- strategy: import_zod.z.enum(BACKOFF_STRATEGIES).default("exponential"),
179
- on: import_zod.z.array(retryStatusCodeSchema).default(DEFAULT_RETRY_ON),
180
- jitter: import_zod.z.boolean().default(true)
181
- }).strict().default({
182
- maxAttempts: 3,
183
- baseDelay: 1e3,
184
- strategy: "exponential",
185
- on: DEFAULT_RETRY_ON,
186
- jitter: true
187
- });
188
- var numericValueSchema = import_zod.z.union([
189
- import_zod.z.number(),
190
- import_zod.z.literal(Number.POSITIVE_INFINITY),
191
- import_zod.z.literal(Number.NEGATIVE_INFINITY)
192
- ]);
193
- var arrayFilterValueSchema = import_zod.z.union([
194
- import_zod.z.array(import_zod.z.string()),
195
- import_zod.z.array(numericValueSchema)
196
- ]);
197
- var scalarFilterValueSchema = import_zod.z.union([
198
- import_zod.z.string(),
199
- numericValueSchema,
200
- import_zod.z.boolean(),
201
- import_zod.z.date(),
202
- import_zod.z.null(),
203
- arrayFilterValueSchema
204
- ]);
205
- var comparableValueSchema = import_zod.z.union([numericValueSchema, import_zod.z.date()]);
206
- var filterOperatorSchema = import_zod.z.object({
207
- eq: scalarFilterValueSchema.optional(),
208
- ne: scalarFilterValueSchema.optional(),
209
- gt: comparableValueSchema.optional(),
210
- gte: comparableValueSchema.optional(),
211
- lt: comparableValueSchema.optional(),
212
- lte: comparableValueSchema.optional(),
213
- in: arrayFilterValueSchema.optional(),
214
- nin: arrayFilterValueSchema.optional(),
215
- contains: import_zod.z.string().optional(),
216
- startsWith: import_zod.z.string().optional(),
217
- endsWith: import_zod.z.string().optional()
218
- }).strict().refine(
219
- (value) => Object.values(value).some((entry) => entry !== void 0),
220
- {
221
- message: "At least one filter operator is required"
222
- }
223
- );
224
- var filterValueSchema = import_zod.z.union([
225
- scalarFilterValueSchema,
226
- filterOperatorSchema
227
- ]);
228
- var filterConditionsSchema = import_zod.z.record(import_zod.z.string(), filterValueSchema);
229
- var pageResultSchema = import_zod.z.object({
230
- data: import_zod.z.array(import_zod.z.unknown()),
231
- meta: responseMetaSchema.optional(),
232
- pagination: paginationMetaSchema
233
- }).strict();
234
- var FrontalError = class extends Error {
235
- code;
236
- requestId;
237
- statusCode;
238
- docs;
239
- rateLimit;
240
- /**
241
- * @param response - The parsed error response from the API.
242
- * @param statusCode - The HTTP status code.
243
- * @param rateLimit - Optional rate-limit headers from the response.
244
- */
245
- constructor(response, statusCode, rateLimit) {
246
- super(response.message);
247
- this.name = "FrontalError";
248
- this.code = response.code;
249
- this.requestId = response.requestId;
250
- this.statusCode = statusCode;
251
- this.docs = response.docs;
252
- this.rateLimit = rateLimit;
253
- Object.setPrototypeOf(this, new.target.prototype);
254
- if (Error.captureStackTrace) {
255
- Error.captureStackTrace(this);
256
- }
257
- }
258
- };
259
- var NotFoundError = class extends FrontalError {
260
- constructor(r, rateLimit) {
261
- super(r, 404, rateLimit);
262
- this.name = "NotFoundError";
263
- }
264
- };
265
- var UnauthorizedError = class extends FrontalError {
266
- constructor(r, rateLimit) {
267
- super(r, 401, rateLimit);
268
- this.name = "UnauthorizedError";
269
- }
270
- };
271
- var ForbiddenError = class extends FrontalError {
272
- constructor(r, rateLimit) {
273
- super(r, 403, rateLimit);
274
- this.name = "ForbiddenError";
275
- }
276
- };
277
- var ValidationError = class extends FrontalError {
278
- /** Per-field validation errors returned by the API. */
279
- fields;
280
- constructor(r, rateLimit) {
281
- super(r, 400, rateLimit);
282
- this.name = "ValidationError";
283
- this.fields = r.fields ?? [];
284
- }
285
- };
286
- var ConflictError = class extends FrontalError {
287
- constructor(r, rateLimit) {
288
- super(r, 409, rateLimit);
289
- this.name = "ConflictError";
290
- }
291
- };
292
- var RateLimitError = class extends FrontalError {
293
- /** Recommended delay in seconds before retrying. */
294
- retryAfter;
295
- constructor(r, retryAfter, rateLimit) {
296
- super(r, 429, rateLimit);
297
- this.name = "RateLimitError";
298
- this.retryAfter = retryAfter;
299
- }
300
- };
301
- var ServiceError = class extends FrontalError {
302
- constructor(r, status, rateLimit) {
303
- super(r, status, rateLimit);
304
- this.name = "ServiceError";
305
- }
306
- };
307
- var NetworkError = class extends Error {
308
- constructor(cause) {
309
- super("Network error \u2014 could not reach Frontal API");
310
- this.cause = cause;
311
- this.name = "NetworkError";
312
- Object.setPrototypeOf(this, new.target.prototype);
313
- if (Error.captureStackTrace) {
314
- Error.captureStackTrace(this, new.target);
315
- }
316
- }
317
- };
318
- function normalizeErrorBody(body) {
319
- const parsed = errorResponseSchema.safeParse(body);
320
- if (parsed.success) return parsed.data;
321
- const fallback = typeof body === "object" && body !== null ? body : {};
322
- const code = typeof fallback.code === "string" && fallback.code.length > 0 ? fallback.code : "UNKNOWN_ERROR";
323
- const hasExplicitCode = typeof fallback.code === "string" && fallback.code.length > 0;
324
- const message = hasExplicitCode && typeof fallback.message === "string" && fallback.message.length > 0 ? fallback.message : "An unknown error occurred";
325
- return {
326
- code,
327
- message,
328
- requestId: typeof fallback.requestId === "string" && fallback.requestId.length > 0 ? fallback.requestId : "unknown",
329
- docs: typeof fallback.docs === "string" ? fallback.docs : void 0,
330
- fields: Array.isArray(fallback.fields) ? fallback.fields : void 0
331
- };
332
- }
333
- function parseFrontalError(body, status, retryAfter, rateLimit) {
334
- const normalized = normalizeErrorBody(body);
335
- switch (status) {
336
- case 400:
337
- return new ValidationError(normalized, rateLimit);
338
- case 401:
339
- return new UnauthorizedError(normalized, rateLimit);
340
- case 403:
341
- return new ForbiddenError(normalized, rateLimit);
342
- case 404:
343
- return new NotFoundError(normalized, rateLimit);
344
- case 409:
345
- return new ConflictError(normalized, rateLimit);
346
- case 429: {
347
- const parsedRetry = retryAfter ? Number.parseInt(retryAfter, 10) : Number.NaN;
348
- return new RateLimitError(
349
- normalized,
350
- Number.isFinite(parsedRetry) ? parsedRetry : 60,
351
- rateLimit
352
- );
353
- }
354
- default:
355
- return new ServiceError(normalized, status, rateLimit);
356
- }
357
- }
358
- var CircuitBreaker = class {
359
- failures = 0;
360
- lastFailureTime = 0;
361
- state = "CLOSED";
362
- config;
363
- constructor(config) {
364
- this.config = config;
365
- }
366
- /** Returns the current circuit state. */
367
- getState() {
368
- return this.state;
369
- }
370
- /** Returns the current consecutive failure count. */
371
- getFailures() {
372
- return this.failures;
373
- }
374
- reset() {
375
- this.failures = 0;
376
- this.state = "CLOSED";
377
- this.config.onClose?.();
378
- }
379
- /**
380
- * Executes an async function through the circuit breaker.
381
- * Throws CircuitBreakerOpenError immediately if the circuit is OPEN
382
- * and the reset timeout has not elapsed. On success in HALF_OPEN state,
383
- * resets the circuit to CLOSED.
384
- *
385
- * @param fn - The async operation to protect.
386
- * @throws {CircuitBreakerOpenError} If the circuit is OPEN.
387
- */
388
- async execute(fn) {
389
- if (this.state === "OPEN") {
390
- if (Date.now() - this.lastFailureTime > this.config.resetTimeoutMs) {
391
- this.state = "HALF_OPEN";
392
- this.config.onHalfOpen?.();
393
- } else {
394
- throw new CircuitBreakerOpenError(
395
- this.config.resetTimeoutMs - (Date.now() - this.lastFailureTime)
396
- );
397
- }
398
- }
399
- try {
400
- const result = await fn();
401
- if (this.state === "HALF_OPEN") {
402
- this.reset();
403
- }
404
- return result;
405
- } catch (error) {
406
- this.failures++;
407
- this.lastFailureTime = Date.now();
408
- if (this.failures >= this.config.failureThreshold) {
409
- this.state = "OPEN";
410
- this.config.onOpen?.();
411
- }
412
- throw error;
413
- }
414
- }
415
- /** Manually forces the circuit into the OPEN state. */
416
- forceOpen() {
417
- this.state = "OPEN";
418
- this.lastFailureTime = Date.now();
419
- }
420
- /** Manually resets the circuit to the CLOSED state. */
421
- forceClose() {
422
- this.reset();
423
- }
424
- };
425
- var CircuitBreakerOpenError = class extends Error {
426
- /** Milliseconds remaining until the circuit transitions to HALF_OPEN. */
427
- retryAfterMs;
428
- constructor(retryAfterMs) {
429
- super(
430
- `Circuit breaker is open \u2014 retry after ${Math.ceil(retryAfterMs / 1e3)}s`
431
- );
432
- this.name = "CircuitBreakerOpenError";
433
- this.retryAfterMs = retryAfterMs;
434
- Object.setPrototypeOf(this, new.target.prototype);
435
- }
436
- };
437
- function computeBaseDelay(attempt, strategy, baseDelay) {
438
- const normalizedAttempt = Math.floor(attempt);
439
- switch (strategy) {
440
- case "linear":
441
- return Math.max(0, baseDelay * (normalizedAttempt + 1));
442
- case "constant":
443
- return baseDelay;
444
- default:
445
- return baseDelay * EXPONENTIAL_BASE ** normalizedAttempt;
446
- }
447
- }
448
- function calculateDelay(attempt, strategyOrConfig, baseDelay, withJitter = false) {
449
- if (typeof strategyOrConfig === "object") {
450
- const strategy = "strategy" in strategyOrConfig ? strategyOrConfig.strategy : strategyOrConfig.backoff;
451
- const delayBase = "baseDelay" in strategyOrConfig ? strategyOrConfig.baseDelay : strategyOrConfig.retryDelay;
452
- const delay2 = computeBaseDelay(attempt, strategy, delayBase);
453
- const shouldJitter = "jitter" in strategyOrConfig ? Boolean(strategyOrConfig.jitter) : true;
454
- if (!shouldJitter) return delay2;
455
- return delay2 + Math.random() * (JITTER_MAX / 2);
456
- }
457
- const delay = computeBaseDelay(
458
- attempt,
459
- strategyOrConfig,
460
- Math.max(0, baseDelay ?? 0)
461
- );
462
- if (!withJitter) return delay;
463
- return delay + Math.random() * (JITTER_MAX / 2);
464
- }
465
- function snakeToCamel(str) {
466
- const prefix = str.match(/^_+/)?.[0] ?? "";
467
- const body = str.slice(prefix.length);
468
- if (!body) return str;
469
- return prefix + body.replace(/_([a-z0-9])/g, (_, c) => c.toUpperCase());
470
- }
471
- function camelToSnake(str) {
472
- return str.replace(/([A-Z]+)([A-Z][a-z])/g, "$1_$2").replace(/([a-z0-9])([A-Z])/g, "$1_$2").toLowerCase();
473
- }
474
- var NEVER_TRANSFORM_KEYS = /* @__PURE__ */ new Set(["$ref", "$schema", "$id"]);
475
- function isStream(obj) {
476
- return typeof obj === "object" && obj !== null && (typeof obj.pipe === "function" || typeof obj.getReader === "function");
477
- }
478
- function deepTransformKeys(obj, transform, skipKeys) {
479
- if (obj === null || obj === void 0) return obj;
480
- if (typeof obj !== "object") return obj;
481
- if (obj instanceof Date || typeof Buffer !== "undefined" && obj instanceof Buffer || obj instanceof RegExp || obj instanceof FormData || obj instanceof File || obj instanceof Blob)
482
- return obj;
483
- if (isStream(obj)) return obj;
484
- if (Array.isArray(obj)) {
485
- return obj.map(
486
- (item) => deepTransformKeys(item, transform, skipKeys)
487
- );
488
- }
489
- const proto = Object.getPrototypeOf(obj);
490
- if (proto !== Object.prototype && proto !== null) return obj;
491
- const result = {};
492
- for (const key of Object.keys(obj)) {
493
- const shouldSkip = skipKeys?.has(key) || NEVER_TRANSFORM_KEYS.has(key);
494
- const newKey = shouldSkip ? key : transform(key);
495
- result[newKey] = deepTransformKeys(
496
- obj[key],
497
- transform,
498
- skipKeys
499
- );
500
- }
501
- return result;
502
- }
503
- function deepCamelToSnake(obj, skipKeys) {
504
- return deepTransformKeys(obj, camelToSnake, skipKeys);
505
- }
506
- function deepSnakeToCamel(obj, skipKeys) {
507
- return deepTransformKeys(obj, snakeToCamel, skipKeys);
508
- }
509
- var HttpClient = class {
510
- constructor(config) {
511
- this.config = config;
512
- if (config.circuitBreaker) {
513
- this.breaker = new CircuitBreaker({
514
- failureThreshold: config.circuitBreaker.failureThreshold,
515
- resetTimeoutMs: config.circuitBreaker.resetTimeoutMs
516
- });
517
- }
518
- }
519
- breaker;
520
- /**
521
- * Sends a GET request.
522
- * @param path - API endpoint path.
523
- * @param params - Optional query parameters.
524
- * @param schema - Optional Zod schema for response validation.
525
- */
526
- async get(path, params, schema) {
527
- return this.request("GET", path, void 0, params, schema);
528
- }
529
- /**
530
- * Sends a POST request with a JSON body.
531
- * @param path - API endpoint path.
532
- * @param body - Request payload (converted to snake_case automatically).
533
- * @param schema - Optional Zod schema for response validation.
534
- */
535
- async post(path, body, schema) {
536
- return this.request("POST", path, body ?? {}, void 0, schema);
537
- }
538
- /**
539
- * Sends a PUT request with a JSON body.
540
- * @param path - API endpoint path.
541
- * @param body - Request payload (converted to snake_case automatically).
542
- * @param schema - Optional Zod schema for response validation.
543
- */
544
- async put(path, body, schema) {
545
- return this.request("PUT", path, body ?? {}, void 0, schema);
546
- }
547
- /**
548
- * Sends a PATCH request with a JSON body.
549
- * @param path - API endpoint path.
550
- * @param body - Request payload (converted to snake_case automatically).
551
- * @param schema - Optional Zod schema for response validation.
552
- */
553
- async patch(path, body, schema) {
554
- return this.request("PATCH", path, body ?? {}, void 0, schema);
555
- }
556
- /**
557
- * Sends a DELETE request.
558
- * @param path - API endpoint path.
559
- * @param params - Optional query parameters.
560
- * @param schema - Optional Zod schema for response validation.
561
- */
562
- async delete(path, params, schema) {
563
- return this.request("DELETE", path, {}, params, schema);
564
- }
565
- /**
566
- * Sends a raw PUT request with a binary/stream body.
567
- * @param path - API endpoint path.
568
- * @param body - Binary buffer or readable stream.
569
- * @param contentType - MIME type of the body.
570
- * @param headers - Additional request headers.
571
- * @returns The parsed JSON response with keys converted to camelCase.
572
- */
573
- async putRaw(path, body, contentType, headers = {}) {
574
- const url = this.buildUrl(path);
575
- const res = await this.fetchWithTimeout(url, {
576
- method: "PUT",
577
- headers: this.buildHeaders({ "Content-Type": contentType, ...headers }),
578
- body
579
- });
580
- if (!res.ok) await this.throwError(res);
581
- if (res.status === 204) return void 0;
582
- const json = await res.json();
583
- return typeof json === "object" && json !== null ? deepSnakeToCamel(json) : json;
584
- }
585
- /**
586
- * Opens a GET SSE stream, yielding parsed server-sent events.
587
- * @param path - API endpoint path.
588
- * @param params - Optional query parameters.
589
- * @yields SSE event objects with `type`, `data`, and optional `id` fields.
590
- */
591
- async *stream(path, params) {
592
- const url = this.buildUrl(path, params);
593
- const res = await this.fetchWithTimeout(url, {
594
- method: "GET",
595
- headers: this.buildHeaders({ Accept: "text/event-stream" })
596
- });
597
- if (!res.ok) await this.throwError(res);
598
- yield* this.parseSSEResponse(res);
599
- }
600
- /**
601
- * Sends a POST request that returns an SSE stream.
602
- * @param path - API endpoint path.
603
- * @param body - Request payload (converted to snake_case automatically).
604
- * @yields SSE event objects with `type`, `data`, and optional `id` fields.
605
- */
606
- async *postStream(path, body) {
607
- const url = this.buildUrl(path);
608
- const res = await this.fetchWithTimeout(url, {
609
- method: "POST",
610
- headers: this.buildHeaders({ Accept: "text/event-stream" }),
611
- body: JSON.stringify(body ?? {})
612
- });
613
- if (!res.ok) await this.throwError(res);
614
- yield* this.parseSSEResponse(res);
615
- }
616
- /**
617
- * Sends a POST request and returns the raw Response object.
618
- * @param path - API endpoint path.
619
- * @param body - Request payload.
620
- * @param headers - Additional request headers.
621
- * @returns The raw fetch Response (caller must handle parsing).
622
- */
623
- async postRaw(path, body, headers = {}) {
624
- const url = this.buildUrl(path);
625
- const res = await this.fetchWithTimeout(url, {
626
- method: "POST",
627
- headers: new Headers(this.buildHeaders(headers)),
628
- body: JSON.stringify(body ?? {})
629
- });
630
- if (!res.ok) await this.throwError(res);
631
- return res;
632
- }
633
- /**
634
- * Sends a POST request with a FormData body (multipart/form-data).
635
- * Automatically removes the Content-Type header so the browser sets the
636
- * correct multipart boundary.
637
- * @param path - API endpoint path.
638
- * @param formData - FormData payload.
639
- * @param headers - Additional request headers.
640
- * @returns The parsed JSON response with keys converted to camelCase.
641
- */
642
- async postFormData(path, formData, headers = {}) {
643
- const url = this.buildUrl(path);
644
- const merged = new Headers(this.buildHeaders(headers));
645
- merged.delete("Content-Type");
646
- const res = await this.fetchWithTimeout(url, {
647
- method: "POST",
648
- headers: merged,
649
- body: formData
650
- });
651
- if (!res.ok) await this.throwError(res);
652
- const json = await res.json();
653
- return deepSnakeToCamel(json);
654
- }
655
- /**
656
- * Sends a raw GET request and returns the Response object directly.
657
- * @param path - API endpoint path.
658
- * @param params - Optional query parameters.
659
- * @param headers - Additional request headers.
660
- * @returns The raw fetch Response (caller must handle parsing).
661
- */
662
- async getRaw(path, params, headers = {}) {
663
- const url = this.buildUrl(path, params);
664
- const res = await this.fetchWithTimeout(url, {
665
- method: "GET",
666
- headers: this.buildHeaders(headers)
667
- });
668
- if (!res.ok) await this.throwError(res);
669
- return res;
670
- }
671
- async *parseSSEResponse(res) {
672
- if (!res.body) return;
673
- const reader = res.body.getReader();
674
- const decoder = new TextDecoder();
675
- let buffer = "";
676
- while (true) {
677
- const { done, value } = await reader.read();
678
- if (done) break;
679
- buffer += decoder.decode(value, { stream: true });
680
- const lines = buffer.split("\n");
681
- buffer = lines.pop() ?? "";
682
- let event = {
683
- type: "message",
684
- data: null
685
- };
686
- for (const rawLine of lines) {
687
- const line = rawLine.trimEnd();
688
- if (line.startsWith("id:")) {
689
- event.id = line.slice(3).trim();
690
- } else if (line.startsWith("event:")) {
691
- event.type = line.slice(6).trim();
692
- } else if (line.startsWith("data:")) {
693
- const payload = line.slice(5).trim();
694
- try {
695
- const parsed = JSON.parse(payload);
696
- event.data = typeof parsed === "object" && parsed !== null ? deepSnakeToCamel(parsed) : parsed;
697
- } catch {
698
- event.data = payload;
699
- }
700
- } else if (line === "") {
701
- if (event.data !== null) yield event;
702
- event = { type: "message", data: null };
703
- }
704
- }
705
- }
706
- }
707
- async request(method, path, body, params, schema, attempt = 0) {
708
- const url = this.buildUrl(path, params);
709
- const requestId = crypto.randomUUID();
710
- const transformedBody = body !== void 0 && body !== null ? deepCamelToSnake(body) : body;
711
- const reqInit = {
712
- method,
713
- headers: this.buildHeaders({ "X-Request-Id": requestId }),
714
- ...method !== "GET" ? { body: JSON.stringify(transformedBody ?? {}) } : { body: void 0 }
715
- };
716
- this.config.logger?.request?.(method, url, reqInit);
717
- const executeRequest = async () => {
718
- try {
719
- return await this.fetchWithTimeout(url, reqInit);
720
- } catch (error) {
721
- this.config.logger?.error?.(error);
722
- throw new NetworkError(error);
723
- }
724
- };
725
- let res;
726
- try {
727
- res = this.breaker ? await this.breaker.execute(executeRequest) : await executeRequest();
728
- } catch (error) {
729
- if (error instanceof CircuitBreakerOpenError) {
730
- throw new Error(
731
- `Circuit breaker is open. Retry after ${Math.ceil(error.retryAfterMs / 1e3)}s.`
732
- );
733
- }
734
- throw error;
735
- }
736
- this.config.logger?.response?.(res);
737
- if (!res.ok) {
738
- const shouldRetry = [429, 500, 502, 503, 504].includes(res.status) && attempt < this.config.maxRetries;
739
- if (shouldRetry) {
740
- const retryAfterValue = res.headers.get("Retry-After");
741
- const retryAfterSeconds = retryAfterValue ? Number.parseInt(retryAfterValue, 10) : Number.NaN;
742
- const delay = Number.isFinite(retryAfterSeconds) ? retryAfterSeconds * 1e3 : calculateDelay(
743
- attempt,
744
- "exponential",
745
- this.config.retryDelay,
746
- true
747
- );
748
- await sleep(delay);
749
- return this.request(method, path, body, params, schema, attempt + 1);
750
- }
751
- await this.throwError(res);
752
- }
753
- if (res.status === 204) return void 0;
754
- const contentType = (res.headers.get("content-type") || "").toLowerCase();
755
- const payload = contentType.includes("application/json") ? await res.json() : await res.text();
756
- const transformedPayload = typeof payload === "object" && payload !== null ? deepSnakeToCamel(payload) : payload;
757
- if (schema) {
758
- try {
759
- const parsed = schema.safeParse(transformedPayload);
760
- if (!parsed.success) {
761
- this.config.logger?.error?.(parsed.error);
762
- throw parsed.error;
763
- }
764
- return parsed.data;
765
- } catch (error) {
766
- if (error instanceof Error && error.message.includes("_zod")) {
767
- return transformedPayload;
768
- }
769
- throw error;
770
- }
771
- }
772
- return transformedPayload;
773
- }
774
- parseRateLimit(res) {
775
- const limit = res.headers.get("X-RateLimit-Limit");
776
- const remaining = res.headers.get("X-RateLimit-Remaining");
777
- const reset = res.headers.get("X-RateLimit-Reset");
778
- if (limit && remaining && reset) {
779
- return {
780
- limit: Number.parseInt(limit, 10),
781
- remaining: Number.parseInt(remaining, 10),
782
- reset: Number.parseInt(reset, 10)
783
- };
784
- }
785
- return void 0;
786
- }
787
- async throwError(res) {
788
- let body;
789
- try {
790
- body = await res.json();
791
- } catch {
792
- body = {};
793
- }
794
- const retryAfter = res.headers.get("Retry-After") ?? void 0;
795
- const rateLimit = this.parseRateLimit(res);
796
- throw parseFrontalError(body, res.status, retryAfter, rateLimit);
797
- }
798
- buildUrl(path, params) {
799
- const base = this.config.baseUrl.replace(/\/$/, "");
800
- let normalizedPath = path.startsWith("/") ? path : `/${path}`;
801
- if (base.endsWith("/v1") && normalizedPath.startsWith("/v1/")) {
802
- if (this.config.debug) {
803
- console.warn(
804
- `[SDK] Double /v1/ prefix detected and normalized. The base URL already includes "/v1" but the route "${normalizedPath}" also starts with "/v1/". Write routes without a leading "/v1".`
805
- );
806
- }
807
- normalizedPath = normalizedPath.slice("/v1".length);
808
- }
809
- const url = `${base}${normalizedPath}`;
810
- const transformedParams = params ? deepCamelToSnake(params) : params;
811
- if (!transformedParams || Object.keys(transformedParams).length === 0) {
812
- return url;
813
- }
814
- const query = Object.entries(transformedParams).filter(([, value]) => value !== void 0 && value !== null).map(
815
- ([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`
816
- ).join("&");
817
- return query ? `${url}?${query}` : url;
818
- }
819
- buildHeaders(extra = {}) {
820
- return {
821
- // The opaque API key (`frt_…`) is the sole public credential. The platform
822
- // edge validates it and exchanges it for a short-lived JWT before reaching
823
- // any service — the SDK never sees or sends a JWT.
824
- Authorization: `Bearer ${this.config.apiKey}`,
825
- "Content-Type": "application/json",
826
- Accept: "application/json",
827
- "User-Agent": "@frontal-labs/core",
828
- "X-Frontal-Core": `typescript@${SDK_VERSION}`,
829
- "X-Frontal-Environment": this.config.environment,
830
- ...this.config.headers,
831
- ...extra
832
- };
833
- }
834
- async fetchWithTimeout(url, init) {
835
- const controller = new AbortController();
836
- const timer = setTimeout(() => controller.abort(), this.config.timeout);
837
- try {
838
- return await (this.config.fetch ?? fetch)(url, {
839
- ...init,
840
- signal: controller.signal
841
- });
842
- } finally {
843
- clearTimeout(timer);
844
- }
845
- }
846
- };
847
- var sleep = async (ms) => new Promise((resolve) => {
848
- setTimeout(resolve, ms);
849
- });
850
- var apiKeySchema = import_zod2.z.string().min(9, "FRONTAL_API_KEY must be at least 9 characters").max(128, "FRONTAL_API_KEY must be at most 128 characters").refine(
851
- (val) => /^frt_[A-Za-z0-9_]+$/.test(val) || /^fr_typed[A-Za-z0-9_]+$/.test(val),
852
- "FRONTAL_API_KEY must start with frt_"
853
- );
854
- var debugSchema = import_zod2.z.union([
855
- import_zod2.z.literal("true"),
856
- import_zod2.z.literal("false"),
857
- import_zod2.z.literal("1"),
858
- import_zod2.z.literal("0")
859
- ]).optional().default("false").transform((val) => val === "true" || val === "1");
860
- var env = createEnv({
861
- server: {
862
- FRONTAL_ENV: import_zod2.z.enum(["development", "test", "production"]).default("development"),
863
- FRONTAL_API_KEY: apiKeySchema.optional(),
864
- FRONTAL_API_URL: import_zod2.z.url("FRONTAL_API_URL must be a valid URL").optional(),
865
- FRONTAL_DEBUG: debugSchema
866
- },
867
- runtimeEnv: {
868
- FRONTAL_ENV: process.env.FRONTAL_ENV,
869
- FRONTAL_API_KEY: process.env.FRONTAL_API_KEY,
870
- FRONTAL_API_URL: process.env.FRONTAL_API_URL,
871
- FRONTAL_DEBUG: process.env.FRONTAL_DEBUG
872
- },
873
- emptyStringAsUndefined: true
874
- });
875
- var unwrapClientError = (error) => {
876
- if (error instanceof NetworkError) {
877
- if (error.cause instanceof Error) {
878
- throw error.cause;
879
- }
880
- throw new Error(String(error.cause));
881
- }
882
- throw error;
883
- };
884
- var FrontalClient = class {
885
- config;
886
- _http;
887
- /**
888
- * @param config - Validated client configuration output from clientConfigSchema.
889
- */
890
- constructor(config) {
891
- Object.defineProperty(this, "config", {
892
- value: config,
893
- writable: false,
894
- enumerable: true
895
- });
896
- const http = new HttpClient(config);
897
- Object.defineProperty(this, "_http", {
898
- value: http,
899
- writable: false,
900
- enumerable: true
901
- });
902
- Object.defineProperty(this, "httpClient", {
903
- get() {
904
- return http;
905
- },
906
- enumerable: true
907
- });
908
- }
909
- /** Public accessor for the underlying HttpClient. */
910
- get httpClient() {
911
- return this._http;
912
- }
913
- /**
914
- * Sends a GET request and optionally validates the response against a schema.
915
- * @param path - API endpoint path.
916
- * @param schema - Optional Zod schema for response validation.
917
- */
918
- async get(path, schema) {
919
- try {
920
- return await this._http.get(path, void 0, schema);
921
- } catch (error) {
922
- throw unwrapClientError(error);
923
- }
924
- }
925
- /**
926
- * Sends a POST request with an optional JSON body and response schema.
927
- * @param path - API endpoint path.
928
- * @param body - Request payload (converted to snake_case automatically).
929
- * @param schema - Optional Zod schema for response validation.
930
- */
931
- async post(path, body, schema) {
932
- try {
933
- return await this._http.post(path, body, schema);
934
- } catch (error) {
935
- throw unwrapClientError(error);
936
- }
937
- }
938
- /**
939
- * Sends a PUT request with an optional JSON body and response schema.
940
- * @param path - API endpoint path.
941
- * @param body - Request payload (converted to snake_case automatically).
942
- * @param schema - Optional Zod schema for response validation.
943
- */
944
- async put(path, body, schema) {
945
- try {
946
- return await this._http.put(path, body, schema);
947
- } catch (error) {
948
- throw unwrapClientError(error);
949
- }
950
- }
951
- /**
952
- * Sends a PATCH request with an optional JSON body and response schema.
953
- * @param path - API endpoint path.
954
- * @param body - Request payload (converted to snake_case automatically).
955
- * @param schema - Optional Zod schema for response validation.
956
- */
957
- async patch(path, body, schema) {
958
- try {
959
- return await this._http.patch(path, body, schema);
960
- } catch (error) {
961
- throw unwrapClientError(error);
962
- }
963
- }
964
- /**
965
- * Sends a DELETE request with optional query parameters and response schema.
966
- * @param path - API endpoint path.
967
- * @param params - Query parameters (converted to snake_case automatically).
968
- * @param schema - Optional Zod schema for response validation.
969
- */
970
- async delete(path, params, schema) {
971
- try {
972
- return await this._http.delete(path, params, schema);
973
- } catch (error) {
974
- throw unwrapClientError(error);
975
- }
976
- }
977
- /**
978
- * Opens a GET SSE stream and yields parsed server-sent events.
979
- * @param path - API endpoint path.
980
- * @param params - Optional query parameters.
981
- * @yields Objects with `type`, `data`, and optional `id` fields from SSE events.
982
- */
983
- async *stream(path, params) {
984
- try {
985
- yield* this._http.stream(path, params);
986
- } catch (error) {
987
- throw unwrapClientError(error);
988
- }
989
- }
990
- /**
991
- * Sends a raw PUT request with a binary/stream body and custom content type.
992
- * @param path - API endpoint path.
993
- * @param body - Binary buffer or readable stream to upload.
994
- * @param contentType - MIME type of the body.
995
- * @param headers - Additional request headers.
996
- * @returns The parsed JSON response (keys converted to camelCase).
997
- */
998
- async putRaw(path, body, contentType, headers = {}) {
999
- try {
1000
- return await this._http.putRaw(path, body, contentType, headers);
1001
- } catch (error) {
1002
- throw unwrapClientError(error);
1003
- }
1004
- }
1005
- };
1006
- var getDefaultClient = () => {
1007
- if (!env.FRONTAL_API_KEY) {
1008
- throw new Error(
1009
- "FRONTAL_API_KEY environment variable is required. Set it in your environment or pass apiKey explicitly to new FrontalClient()."
1010
- );
1011
- }
1012
- return new FrontalClient({
1013
- apiKey: env.FRONTAL_API_KEY,
1014
- baseUrl: env.FRONTAL_API_URL ?? DEFAULT_BASE_URL,
1015
- timeout: 3e4,
1016
- maxRetries: 3,
1017
- retryDelay: 1e3,
1018
- headers: {},
1019
- environment: env.FRONTAL_ENV,
1020
- debug: env.FRONTAL_DEBUG
1021
- });
1022
- };
1023
- var API_KEY_PATTERN = new RegExp(`^${API_KEY_PREFIX}[A-Za-z0-9_-]+$`);
1024
- var loggerFnSchema = import_zod3.z.custom(
1025
- (value) => typeof value === "function",
1026
- "Expected function"
1027
- );
1028
- var headersSchema = import_zod3.z.record(import_zod3.z.string(), import_zod3.z.string()).superRefine((headers, ctx) => {
1029
- for (const key of Object.keys(headers)) {
1030
- if (key.trim().length === 0) {
1031
- ctx.addIssue({
1032
- code: import_zod3.z.ZodIssueCode.custom,
1033
- message: "Header names must be non-empty",
1034
- path: []
1035
- });
1036
- return;
1037
- }
1038
- }
1039
- }).default({});
1040
- var clientConfigSchema = import_zod3.z.object({
1041
- apiKey: import_zod3.z.string().min(9, "apiKey is required").regex(API_KEY_PATTERN, `apiKey must start with "${API_KEY_PREFIX}"`),
1042
- baseUrl: import_zod3.z.string().url().refine(
1043
- (value) => value.startsWith("https://") || value.startsWith("http://"),
1044
- {
1045
- message: "baseUrl must use http or https"
1046
- }
1047
- ).default(DEFAULT_BASE_URL),
1048
- timeout: import_zod3.z.number().int().positive().default(3e4),
1049
- maxRetries: import_zod3.z.number().int().min(0).max(10).default(3),
1050
- retryDelay: import_zod3.z.number().int().positive().default(1e3),
1051
- headers: headersSchema,
1052
- environment: import_zod3.z.string().default("production"),
1053
- debug: import_zod3.z.boolean().default(false),
1054
- fetch: import_zod3.z.custom((value) => typeof value === "function").optional(),
1055
- logger: import_zod3.z.object({
1056
- request: loggerFnSchema.optional(),
1057
- response: loggerFnSchema.optional(),
1058
- error: loggerFnSchema.optional()
1059
- }).optional(),
1060
- circuitBreaker: import_zod3.z.object({
1061
- failureThreshold: import_zod3.z.number().int().positive().default(5),
1062
- resetTimeoutMs: import_zod3.z.number().int().positive().default(3e4)
1063
- }).optional()
1064
- }).strict();
1065
- function asPagePayload(raw) {
1066
- return raw;
1067
- }
1068
- var paginationSchema = import_zod4.z.object({
1069
- cursor: import_zod4.z.string().min(1),
1070
- hasMore: import_zod4.z.boolean(),
1071
- total: import_zod4.z.number().int().min(0).optional(),
1072
- limit: import_zod4.z.number().int().positive().optional(),
1073
- offset: import_zod4.z.number().int().min(0).optional()
1074
- }).strict();
1075
- function buildPageResult(data, pagination, fetchNext, meta) {
1076
- let nextPagePromise = null;
1077
- const page = {
1078
- data,
1079
- meta,
1080
- pagination,
1081
- _fetchNextPage: fetchNext,
1082
- async nextPage() {
1083
- if (!this.pagination.hasMore) return null;
1084
- if (!nextPagePromise) {
1085
- nextPagePromise = (async () => {
1086
- let result = await this._fetchNextPage();
1087
- if (!result && this._fallbackFetchNextPage) {
1088
- result = await this._fallbackFetchNextPage();
1089
- }
1090
- if (result) {
1091
- const mutableResult = result;
1092
- mutableResult._fallbackFetchNextPage = this._fallbackFetchNextPage ?? this._fetchNextPage;
1093
- }
1094
- return result;
1095
- })().finally(() => {
1096
- nextPagePromise = null;
1097
- });
1098
- }
1099
- return nextPagePromise;
1100
- },
1101
- async all() {
1102
- const items = [...this.data];
1103
- let current = this;
1104
- while (current) {
1105
- if (!current.pagination.hasMore) break;
1106
- current = await current.nextPage();
1107
- if (!current) break;
1108
- items.push(...current.data);
1109
- }
1110
- return items;
1111
- },
1112
- [Symbol.asyncIterator]() {
1113
- let current = this;
1114
- let index = 0;
1115
- return {
1116
- async next() {
1117
- while (current) {
1118
- if (index < current.data.length) {
1119
- return { done: false, value: current.data[index++] };
1120
- }
1121
- if (!current.pagination.hasMore) {
1122
- current = null;
1123
- break;
1124
- }
1125
- current = await current.nextPage();
1126
- index = 0;
1127
- }
1128
- return { done: true, value: void 0 };
1129
- }
1130
- };
1131
- }
1132
- };
1133
- return page;
1134
- }
1135
- function createPageResult(dataOrRaw, paginationOrFetchNext, fetchNextOrMeta, meta) {
1136
- if (Array.isArray(dataOrRaw)) {
1137
- const data = dataOrRaw;
1138
- const pagination = paginationOrFetchNext;
1139
- const fetchNextPage2 = fetchNextOrMeta;
1140
- const fetchNext2 = async () => {
1141
- if (!fetchNextPage2) return null;
1142
- return fetchNextPage2.length > 0 ? fetchNextPage2(
1143
- pagination.cursor
1144
- ) : fetchNextPage2();
1145
- };
1146
- return buildPageResult(data, pagination, fetchNext2, meta);
1147
- }
1148
- const raw = dataOrRaw;
1149
- const fetchNextPage = paginationOrFetchNext;
1150
- const fetchNext = async () => {
1151
- if (!fetchNextPage) return null;
1152
- return fetchNextPage.length > 0 ? fetchNextPage(
1153
- raw.pagination.cursor
1154
- ) : fetchNextPage();
1155
- };
1156
- return buildPageResult(
1157
- Array.isArray(raw.data) ? raw.data : [],
1158
- raw.pagination,
1159
- fetchNext,
1160
- raw.meta
1161
- );
1162
- }
43
+ // src/client.ts
44
+ var import_core2 = require("@frontal-labs/core");
1163
45
 
1164
46
  // src/constants.ts
1165
47
  var DEFAULT_ONTOLOGY_BASE_URL = "https://api.frontal.dev/v1";
@@ -1169,6 +51,7 @@ var DEFAULT_MAX_RETRIES = 3;
1169
51
  var DEFAULT_RETRY_DELAY = 1e3;
1170
52
 
1171
53
  // src/sdk.ts
54
+ var import_core = require("@frontal-labs/core");
1172
55
  var OntologySdk = class {
1173
56
  engine;
1174
57
  objects;
@@ -1229,8 +112,8 @@ var SubdomainBase = class {
1229
112
  */
1230
113
  async runs(opts = {}) {
1231
114
  const raw = await this.http.get(`${this.base}/runs`, opts);
1232
- return createPageResult(
1233
- asPagePayload(raw),
115
+ return (0, import_core.createPageResult)(
116
+ (0, import_core.asPagePayload)(raw),
1234
117
  (c) => this.runs({ ...opts, cursor: c })
1235
118
  );
1236
119
  }
@@ -1319,8 +202,8 @@ var ObjectsNamespace = class extends SubdomainBase {
1319
202
  */
1320
203
  async listObjectTypes(opts = {}) {
1321
204
  const raw = await this.http.get("/ontology/objects/object-types", opts);
1322
- return createPageResult(
1323
- asPagePayload(raw),
205
+ return (0, import_core.createPageResult)(
206
+ (0, import_core.asPagePayload)(raw),
1324
207
  (c) => this.listObjectTypes({ ...opts, cursor: c })
1325
208
  );
1326
209
  }
@@ -1352,8 +235,8 @@ var ObjectsNamespace = class extends SubdomainBase {
1352
235
  */
1353
236
  async listObjects(opts = {}) {
1354
237
  const raw = await this.http.get("/ontology/objects/objects", opts);
1355
- return createPageResult(
1356
- asPagePayload(raw),
238
+ return (0, import_core.createPageResult)(
239
+ (0, import_core.asPagePayload)(raw),
1357
240
  (c) => this.listObjects({ ...opts, cursor: c })
1358
241
  );
1359
242
  }
@@ -1393,8 +276,8 @@ var RelationshipsNamespace = class extends SubdomainBase {
1393
276
  "/ontology/relationships/relationship-types",
1394
277
  opts
1395
278
  );
1396
- return createPageResult(
1397
- asPagePayload(raw),
279
+ return (0, import_core.createPageResult)(
280
+ (0, import_core.asPagePayload)(raw),
1398
281
  (c) => this.listTypes({ ...opts, cursor: c })
1399
282
  );
1400
283
  }
@@ -1414,8 +297,8 @@ var RelationshipsNamespace = class extends SubdomainBase {
1414
297
  "/ontology/relationships/relationships",
1415
298
  opts
1416
299
  );
1417
- return createPageResult(
1418
- asPagePayload(raw),
300
+ return (0, import_core.createPageResult)(
301
+ (0, import_core.asPagePayload)(raw),
1419
302
  (c) => this.list({ ...opts, cursor: c })
1420
303
  );
1421
304
  }
@@ -1452,8 +335,8 @@ var SchemasNamespace = class extends SubdomainBase {
1452
335
  */
1453
336
  async list(opts = {}) {
1454
337
  const raw = await this.http.get("/ontology/schemas/schemas", opts);
1455
- return createPageResult(
1456
- asPagePayload(raw),
338
+ return (0, import_core.createPageResult)(
339
+ (0, import_core.asPagePayload)(raw),
1457
340
  (c) => this.list({ ...opts, cursor: c })
1458
341
  );
1459
342
  }
@@ -1531,8 +414,8 @@ var VersionsNamespace = class extends SubdomainBase {
1531
414
  */
1532
415
  async listReleaseBundles(opts = {}) {
1533
416
  const raw = await this.http.get("/ontology/versions/release-bundles", opts);
1534
- return createPageResult(
1535
- asPagePayload(raw),
417
+ return (0, import_core.createPageResult)(
418
+ (0, import_core.asPagePayload)(raw),
1536
419
  (c) => this.listReleaseBundles({ ...opts, cursor: c })
1537
420
  );
1538
421
  }
@@ -1568,8 +451,8 @@ var ValidationNamespace = class extends SubdomainBase {
1568
451
  */
1569
452
  async listRules(opts = {}) {
1570
453
  const raw = await this.http.get("/ontology/validation/rules", opts);
1571
- return createPageResult(
1572
- asPagePayload(raw),
454
+ return (0, import_core.createPageResult)(
455
+ (0, import_core.asPagePayload)(raw),
1573
456
  (c) => this.listRules({ ...opts, cursor: c })
1574
457
  );
1575
458
  }
@@ -1652,8 +535,8 @@ var ReasoningNamespace = class extends SubdomainBase {
1652
535
  */
1653
536
  async listRules(opts = {}) {
1654
537
  const raw = await this.http.get("/ontology/reasoning/rules", opts);
1655
- return createPageResult(
1656
- asPagePayload(raw),
538
+ return (0, import_core.createPageResult)(
539
+ (0, import_core.asPagePayload)(raw),
1657
540
  (c) => this.listRules({ ...opts, cursor: c })
1658
541
  );
1659
542
  }
@@ -1690,8 +573,8 @@ var RolloutsNamespace = class extends SubdomainBase {
1690
573
  */
1691
574
  async list(opts = {}) {
1692
575
  const raw = await this.http.get("/ontology/rollouts/rollouts", opts);
1693
- return createPageResult(
1694
- asPagePayload(raw),
576
+ return (0, import_core.createPageResult)(
577
+ (0, import_core.asPagePayload)(raw),
1695
578
  (c) => this.list({ ...opts, cursor: c })
1696
579
  );
1697
580
  }
@@ -1774,8 +657,8 @@ var RollupsNamespace = class extends SubdomainBase {
1774
657
  */
1775
658
  async list(opts = {}) {
1776
659
  const raw = await this.http.get("/ontology/rollups/rollups", opts);
1777
- return createPageResult(
1778
- asPagePayload(raw),
660
+ return (0, import_core.createPageResult)(
661
+ (0, import_core.asPagePayload)(raw),
1779
662
  (c) => this.list({ ...opts, cursor: c })
1780
663
  );
1781
664
  }
@@ -1903,8 +786,8 @@ var EventsNamespace = class extends SubdomainBase {
1903
786
  */
1904
787
  async list(opts = {}) {
1905
788
  const raw = await this.http.get("/ontology/events/events", opts);
1906
- return createPageResult(
1907
- asPagePayload(raw),
789
+ return (0, import_core.createPageResult)(
790
+ (0, import_core.asPagePayload)(raw),
1908
791
  (c) => this.list({ ...opts, cursor: c })
1909
792
  );
1910
793
  }
@@ -1953,19 +836,20 @@ var EventsNamespace = class extends SubdomainBase {
1953
836
  };
1954
837
 
1955
838
  // src/client.ts
839
+ var import_core3 = require("@frontal-labs/core");
1956
840
  function createOntologyClient(clientOrConfig) {
1957
- if (clientOrConfig instanceof FrontalClient) {
841
+ if (clientOrConfig instanceof import_core2.FrontalClient) {
1958
842
  return new OntologySdk(clientOrConfig.httpClient);
1959
843
  }
1960
- const http = new HttpClient({
844
+ const http = new import_core2.HttpClient({
1961
845
  apiKey: clientOrConfig.apiKey,
1962
- baseUrl: clientOrConfig.baseUrl ?? env.FRONTAL_API_URL ?? DEFAULT_ONTOLOGY_BASE_URL,
846
+ baseUrl: clientOrConfig.baseUrl ?? import_core3.env.FRONTAL_API_URL ?? DEFAULT_ONTOLOGY_BASE_URL,
1963
847
  timeout: clientOrConfig.timeout ?? DEFAULT_TIMEOUT,
1964
848
  maxRetries: clientOrConfig.maxRetries ?? DEFAULT_MAX_RETRIES,
1965
849
  retryDelay: DEFAULT_RETRY_DELAY,
1966
850
  headers: {},
1967
- environment: env.FRONTAL_ENV,
1968
- debug: env.FRONTAL_DEBUG ?? false
851
+ environment: import_core3.env.FRONTAL_ENV,
852
+ debug: import_core3.env.FRONTAL_DEBUG ?? false
1969
853
  });
1970
854
  return new OntologySdk(http);
1971
855
  }
@@ -1973,7 +857,7 @@ var _ontologyCache;
1973
857
  var ontology = new Proxy({}, {
1974
858
  get(_t, prop) {
1975
859
  if (!_ontologyCache) {
1976
- _ontologyCache = createOntologyClient(getDefaultClient());
860
+ _ontologyCache = createOntologyClient((0, import_core2.getDefaultClient)());
1977
861
  }
1978
862
  const inst = _ontologyCache;
1979
863
  const val = inst[prop];
@@ -1982,8 +866,9 @@ var ontology = new Proxy({}, {
1982
866
  });
1983
867
 
1984
868
  // src/schemas.ts
1985
- var import_zod5 = require("zod");
1986
- var FieldTypeSchema = import_zod5.z.enum([
869
+ var import_core4 = require("@frontal-labs/core");
870
+ var import_zod = require("zod");
871
+ var FieldTypeSchema = import_zod.z.enum([
1987
872
  "string",
1988
873
  "integer",
1989
874
  "float",
@@ -1997,126 +882,126 @@ var FieldTypeSchema = import_zod5.z.enum([
1997
882
  "vector",
1998
883
  "text"
1999
884
  ]);
2000
- var RelationshipTypeSchema = import_zod5.z.enum([
885
+ var RelationshipTypeSchema = import_zod.z.enum([
2001
886
  "hasOne",
2002
887
  "hasMany",
2003
888
  "belongsTo",
2004
889
  "manyToMany"
2005
890
  ]);
2006
- var FieldDefinitionSchema = import_zod5.z.object({
891
+ var FieldDefinitionSchema = import_zod.z.object({
2007
892
  type: FieldTypeSchema,
2008
- required: import_zod5.z.boolean().default(false),
2009
- primary: import_zod5.z.boolean().default(false),
2010
- unique: import_zod5.z.boolean().default(false),
2011
- default: import_zod5.z.unknown().optional(),
2012
- substrate: import_zod5.z.string().optional(),
2013
- computed: import_zod5.z.boolean().optional(),
2014
- derivedBy: import_zod5.z.string().optional(),
2015
- cache: import_zod5.z.object({
2016
- ttl: import_zod5.z.string()
893
+ required: import_zod.z.boolean().default(false),
894
+ primary: import_zod.z.boolean().default(false),
895
+ unique: import_zod.z.boolean().default(false),
896
+ default: import_zod.z.unknown().optional(),
897
+ substrate: import_zod.z.string().optional(),
898
+ computed: import_zod.z.boolean().optional(),
899
+ derivedBy: import_zod.z.string().optional(),
900
+ cache: import_zod.z.object({
901
+ ttl: import_zod.z.string()
2017
902
  }).optional(),
2018
- auto: import_zod5.z.boolean().optional(),
2019
- enum: import_zod5.z.array(import_zod5.z.string()).optional(),
2020
- dimensions: import_zod5.z.number().int().optional(),
2021
- items: import_zod5.z.string().optional(),
2022
- description: import_zod5.z.string().optional()
903
+ auto: import_zod.z.boolean().optional(),
904
+ enum: import_zod.z.array(import_zod.z.string()).optional(),
905
+ dimensions: import_zod.z.number().int().optional(),
906
+ items: import_zod.z.string().optional(),
907
+ description: import_zod.z.string().optional()
2023
908
  }).loose();
2024
- var RelationshipDefinitionSchema = import_zod5.z.object({
2025
- name: import_zod5.z.string().optional(),
909
+ var RelationshipDefinitionSchema = import_zod.z.object({
910
+ name: import_zod.z.string().optional(),
2026
911
  type: RelationshipTypeSchema,
2027
- targetEntity: import_zod5.z.string(),
2028
- foreignKey: import_zod5.z.string().optional(),
2029
- substrate: import_zod5.z.string().optional(),
2030
- cascade: import_zod5.z.object({
2031
- delete: import_zod5.z.enum(["hard", "soft", "restrict", "nullify"]),
2032
- update: import_zod5.z.enum(["cascade", "restrict"])
912
+ targetEntity: import_zod.z.string(),
913
+ foreignKey: import_zod.z.string().optional(),
914
+ substrate: import_zod.z.string().optional(),
915
+ cascade: import_zod.z.object({
916
+ delete: import_zod.z.enum(["hard", "soft", "restrict", "nullify"]),
917
+ update: import_zod.z.enum(["cascade", "restrict"])
2033
918
  }).optional(),
2034
- computed: import_zod5.z.record(import_zod5.z.string(), import_zod5.z.unknown()).optional(),
2035
- description: import_zod5.z.string().optional()
919
+ computed: import_zod.z.record(import_zod.z.string(), import_zod.z.unknown()).optional(),
920
+ description: import_zod.z.string().optional()
2036
921
  }).loose();
2037
- var SubstrateRoutingSchema = import_zod5.z.object({
2038
- operational: import_zod5.z.string().optional(),
2039
- analytical: import_zod5.z.string().optional(),
2040
- semantic: import_zod5.z.string().optional(),
2041
- cache: import_zod5.z.string().optional()
922
+ var SubstrateRoutingSchema = import_zod.z.object({
923
+ operational: import_zod.z.string().optional(),
924
+ analytical: import_zod.z.string().optional(),
925
+ semantic: import_zod.z.string().optional(),
926
+ cache: import_zod.z.string().optional()
2042
927
  }).loose();
2043
- var SemanticMetadataSchema = import_zod5.z.object({
2044
- description: import_zod5.z.string().optional(),
2045
- lifecycle: import_zod5.z.array(import_zod5.z.string()).optional(),
2046
- criticalFields: import_zod5.z.array(import_zod5.z.string()).optional(),
2047
- significantEvents: import_zod5.z.array(import_zod5.z.string()).optional(),
2048
- tags: import_zod5.z.array(import_zod5.z.string()).optional()
928
+ var SemanticMetadataSchema = import_zod.z.object({
929
+ description: import_zod.z.string().optional(),
930
+ lifecycle: import_zod.z.array(import_zod.z.string()).optional(),
931
+ criticalFields: import_zod.z.array(import_zod.z.string()).optional(),
932
+ significantEvents: import_zod.z.array(import_zod.z.string()).optional(),
933
+ tags: import_zod.z.array(import_zod.z.string()).optional()
2049
934
  }).loose();
2050
- var IndexDefinitionSchema = import_zod5.z.object({
2051
- name: import_zod5.z.string().optional(),
2052
- fields: import_zod5.z.array(import_zod5.z.string()).min(1),
2053
- substrate: import_zod5.z.string().optional(),
2054
- unique: import_zod5.z.boolean().default(false),
2055
- type: import_zod5.z.enum(["btree", "hash", "gin", "gist", "brin"]).default("btree")
935
+ var IndexDefinitionSchema = import_zod.z.object({
936
+ name: import_zod.z.string().optional(),
937
+ fields: import_zod.z.array(import_zod.z.string()).min(1),
938
+ substrate: import_zod.z.string().optional(),
939
+ unique: import_zod.z.boolean().default(false),
940
+ type: import_zod.z.enum(["btree", "hash", "gin", "gist", "brin"]).default("btree")
2056
941
  }).loose();
2057
- var ModelDefinitionSchema = import_zod5.z.object({
2058
- name: import_zod5.z.string(),
2059
- displayName: import_zod5.z.string().optional(),
2060
- description: import_zod5.z.string().optional(),
2061
- extends: import_zod5.z.string().optional(),
2062
- mixins: import_zod5.z.array(import_zod5.z.string()).optional(),
2063
- fields: import_zod5.z.record(import_zod5.z.string(), FieldDefinitionSchema),
2064
- relationships: import_zod5.z.record(import_zod5.z.string(), RelationshipDefinitionSchema).optional(),
942
+ var ModelDefinitionSchema = import_zod.z.object({
943
+ name: import_zod.z.string(),
944
+ displayName: import_zod.z.string().optional(),
945
+ description: import_zod.z.string().optional(),
946
+ extends: import_zod.z.string().optional(),
947
+ mixins: import_zod.z.array(import_zod.z.string()).optional(),
948
+ fields: import_zod.z.record(import_zod.z.string(), FieldDefinitionSchema),
949
+ relationships: import_zod.z.record(import_zod.z.string(), RelationshipDefinitionSchema).optional(),
2065
950
  substrates: SubstrateRoutingSchema.optional(),
2066
951
  semantics: SemanticMetadataSchema.optional(),
2067
- indexes: import_zod5.z.array(IndexDefinitionSchema).optional(),
2068
- status: import_zod5.z.enum(["draft", "active", "deprecated"]).default("draft")
952
+ indexes: import_zod.z.array(IndexDefinitionSchema).optional(),
953
+ status: import_zod.z.enum(["draft", "active", "deprecated"]).default("draft")
2069
954
  }).strict();
2070
955
  var ModelSchema = ModelDefinitionSchema.extend({
2071
- id: import_zod5.z.string(),
2072
- version: import_zod5.z.number().int(),
2073
- createdAt: timestampSchema,
2074
- updatedAt: timestampSchema,
2075
- entityCount: import_zod5.z.number().int().optional()
956
+ id: import_zod.z.string(),
957
+ version: import_zod.z.number().int(),
958
+ createdAt: import_core4.timestampSchema,
959
+ updatedAt: import_core4.timestampSchema,
960
+ entityCount: import_zod.z.number().int().optional()
2076
961
  }).loose();
2077
- var MigrationPlanSchema = import_zod5.z.object({
2078
- id: import_zod5.z.string(),
2079
- modelId: import_zod5.z.string(),
2080
- fromVersion: import_zod5.z.number().int(),
2081
- toVersion: import_zod5.z.number().int(),
2082
- changes: import_zod5.z.array(
2083
- import_zod5.z.object({
2084
- type: import_zod5.z.enum([
962
+ var MigrationPlanSchema = import_zod.z.object({
963
+ id: import_zod.z.string(),
964
+ modelId: import_zod.z.string(),
965
+ fromVersion: import_zod.z.number().int(),
966
+ toVersion: import_zod.z.number().int(),
967
+ changes: import_zod.z.array(
968
+ import_zod.z.object({
969
+ type: import_zod.z.enum([
2085
970
  "add-field",
2086
971
  "remove-field",
2087
972
  "modify-field",
2088
973
  "add-relationship",
2089
974
  "remove-relationship"
2090
975
  ]),
2091
- description: import_zod5.z.string(),
2092
- impact: import_zod5.z.enum(["breaking", "non-breaking", "data-loss"]),
2093
- sql: import_zod5.z.string().optional()
976
+ description: import_zod.z.string(),
977
+ impact: import_zod.z.enum(["breaking", "non-breaking", "data-loss"]),
978
+ sql: import_zod.z.string().optional()
2094
979
  })
2095
980
  ),
2096
- riskLevel: import_zod5.z.enum(["low", "medium", "high", "critical"]),
2097
- estimatedDowntime: import_zod5.z.string().optional(),
2098
- rolloutStrategy: import_zod5.z.enum([
981
+ riskLevel: import_zod.z.enum(["low", "medium", "high", "critical"]),
982
+ estimatedDowntime: import_zod.z.string().optional(),
983
+ rolloutStrategy: import_zod.z.enum([
2099
984
  "zero-downtime",
2100
985
  "maintenance-window",
2101
986
  "immediate"
2102
987
  ]),
2103
- createdAt: timestampSchema
988
+ createdAt: import_core4.timestampSchema
2104
989
  }).loose();
2105
- var RuleDefinitionSchema = import_zod5.z.object({
2106
- name: import_zod5.z.string(),
2107
- description: import_zod5.z.string().optional(),
2108
- entityTypes: import_zod5.z.array(import_zod5.z.string()).min(1),
2109
- condition: import_zod5.z.string(),
2110
- action: import_zod5.z.enum(["validate", "transform", "notify"]),
2111
- severity: import_zod5.z.enum(["error", "warning", "info"]),
2112
- enabled: import_zod5.z.boolean().default(true)
990
+ var RuleDefinitionSchema = import_zod.z.object({
991
+ name: import_zod.z.string(),
992
+ description: import_zod.z.string().optional(),
993
+ entityTypes: import_zod.z.array(import_zod.z.string()).min(1),
994
+ condition: import_zod.z.string(),
995
+ action: import_zod.z.enum(["validate", "transform", "notify"]),
996
+ severity: import_zod.z.enum(["error", "warning", "info"]),
997
+ enabled: import_zod.z.boolean().default(true)
2113
998
  }).strict();
2114
- var MixinDefinitionSchema = import_zod5.z.object({
2115
- name: import_zod5.z.string(),
2116
- description: import_zod5.z.string().optional(),
2117
- fields: import_zod5.z.record(import_zod5.z.string(), FieldDefinitionSchema),
2118
- relationships: import_zod5.z.record(import_zod5.z.string(), RelationshipDefinitionSchema).optional(),
2119
- appliesTo: import_zod5.z.array(import_zod5.z.string()).optional()
999
+ var MixinDefinitionSchema = import_zod.z.object({
1000
+ name: import_zod.z.string(),
1001
+ description: import_zod.z.string().optional(),
1002
+ fields: import_zod.z.record(import_zod.z.string(), FieldDefinitionSchema),
1003
+ relationships: import_zod.z.record(import_zod.z.string(), RelationshipDefinitionSchema).optional(),
1004
+ appliesTo: import_zod.z.array(import_zod.z.string()).optional()
2120
1005
  }).strict();
2121
1006
  // Annotate the CommonJS export names for ESM import in node:
2122
1007
  0 && (module.exports = {