UNPKG

@simpleapps-com/augur-api

Version:

TypeScript client library for Augur microservices API endpoints

165 lines 6.86 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.flexibleProductFields = exports.flexibleUserFields = exports.makeFlexible = exports.flexibleMetadataFields = exports.flexibleNested = exports.flexibleObject = exports.flexibleProfileData = exports.flexibleDate = exports.flexibleBoolean = exports.flexibleStringOrNumber = exports.flexibleCollection = exports.flexibleArrayOrObject = void 0; const zod_1 = require("zod"); /** * Flexible Schema Utilities for Handling Inconsistent API Outputs * * During microservice API refactoring, many endpoints return inconsistent formats. * These utilities provide standardized patterns for handling common inconsistencies. */ /** * Creates a schema that accepts both array and object formats * Common pattern: server sometimes returns [] and sometimes {} */ const flexibleArrayOrObject = (itemSchema) => zod_1.z.union([ zod_1.z.array(itemSchema), // Preferred format zod_1.z.record(zod_1.z.unknown()), // Legacy/inconsistent format zod_1.z.record(zod_1.z.never()).optional(), // Empty object fallback ]); exports.flexibleArrayOrObject = flexibleArrayOrObject; /** * Creates a schema that accepts both array and record formats for collections * Handles cases where APIs return either array of items or object with key-value pairs */ const flexibleCollection = (itemSchema) => zod_1.z.union([ zod_1.z.array(itemSchema), // Standard array format zod_1.z.record(itemSchema), // Object with typed values zod_1.z.array(zod_1.z.unknown()), // Fallback array with unknown items zod_1.z.record(zod_1.z.unknown()), // Fallback object with unknown values ]); exports.flexibleCollection = flexibleCollection; /** * Creates a schema for fields that might be string, number, or null * Common during API migrations when data types are being standardized */ const flexibleStringOrNumber = () => zod_1.z.union([zod_1.z.string(), zod_1.z.number(), zod_1.z.null(), zod_1.z.undefined()]).transform(val => { if (val === null || val === undefined) return null; return String(val); }); exports.flexibleStringOrNumber = flexibleStringOrNumber; /** * Creates a schema for boolean fields that might come as string, number, or boolean * Handles legacy APIs that return "1"/"0", true/false, or "true"/"false" */ const flexibleBoolean = () => zod_1.z.union([zod_1.z.boolean(), zod_1.z.string(), zod_1.z.number(), zod_1.z.null(), zod_1.z.undefined()]).transform(val => { if (typeof val === 'boolean') return val; if (typeof val === 'string') return val.toLowerCase() === 'true' || val === '1'; if (typeof val === 'number') return val === 1; return false; }); exports.flexibleBoolean = flexibleBoolean; /** * Creates a schema for date fields that might be string, Date, or null * Handles various date format inconsistencies */ const flexibleDate = () => zod_1.z.union([zod_1.z.string(), zod_1.z.date(), zod_1.z.null(), zod_1.z.undefined()]).transform(val => { if (val === null || val === undefined) return null; if (val instanceof Date) return val.toISOString(); return String(val); }); exports.flexibleDate = flexibleDate; /** * Creates a flexible schema for profile/metadata fields that vary between endpoints * This is the pattern we found with profileValues - sometimes array, sometimes object */ const flexibleProfileData = () => zod_1.z .union([ zod_1.z.record(zod_1.z.union([zod_1.z.string(), zod_1.z.array(zod_1.z.string())])), // Object format with string or array values zod_1.z.array(zod_1.z.unknown()), // Array format (common case) zod_1.z.null(), // No profile data zod_1.z.undefined(), // Field missing ]) .optional(); exports.flexibleProfileData = flexibleProfileData; /** * Creates a flexible schema that gracefully handles unexpected extra fields * Uses passthrough to allow additional properties during API evolution */ const flexibleObject = (shape) => zod_1.z.object(shape).passthrough(); exports.flexibleObject = flexibleObject; /** * Creates a schema that handles nested data that might be normalized or denormalized * Common when APIs are being refactored from flat to nested structures */ const flexibleNested = (simpleSchema, complexSchema) => zod_1.z.union([ simpleSchema, // Simple/flat format complexSchema, // Complex/nested format ]); exports.flexibleNested = flexibleNested; /** * Pre-built schema for common metadata fields that are inconsistent during refactoring * Handles count normalization and bidirectional sync between total and totalResults */ exports.flexibleMetadataFields = zod_1.z .object({ count: zod_1.z.number().optional().default(0), total: zod_1.z.number().optional().default(0), totalResults: zod_1.z.number().optional().default(0), }) .transform(data => { // Apply the same normalization logic as BaseResponseSchema const count = data.count || 0; // Bidirectional sync between total and totalResults let total = data.total; let totalResults = data.totalResults || 0; // If total is 0 and totalResults > 0, set total to totalResults if (total === 0 && totalResults > 0) { total = totalResults; } // If totalResults is 0 and total > 0, set totalResults to total else if (totalResults === 0 && total > 0) { totalResults = total; } return { count, total, totalResults, }; }); /** * Utility for wrapping existing schemas to be more flexible during API refactoring * Adds .catch() to provide fallback values instead of throwing validation errors */ const makeFlexible = (schema, fallbackValue) => schema.catch(fallbackValue); exports.makeFlexible = makeFlexible; /** * Common patterns for user-related data that varies across services */ exports.flexibleUserFields = { profileValues: (0, exports.flexibleProfileData)(), customFields: (0, exports.flexibleArrayOrObject)(zod_1.z.unknown()), permissions: (0, exports.flexibleCollection)(zod_1.z.string()), groups: (0, exports.flexibleArrayOrObject)(zod_1.z .object({ id: zod_1.z.number(), title: zod_1.z.string(), }) .passthrough()), }; /** * Common patterns for product/item data that varies across services */ exports.flexibleProductFields = { attributes: (0, exports.flexibleCollection)(zod_1.z .object({ attributeId: zod_1.z.string(), value: zod_1.z.string(), }) .passthrough()), categories: (0, exports.flexibleArrayOrObject)(zod_1.z .object({ categoryUid: zod_1.z.number(), categoryDesc: zod_1.z.string(), }) .passthrough()), metadata: (0, exports.flexibleProfileData)(), customData: (0, exports.flexibleArrayOrObject)(zod_1.z.unknown()), }; //# sourceMappingURL=flexible-schemas.js.map