From afa907065b6a0a35d1f42687d26aacdd4a86bef0 Mon Sep 17 00:00:00 2001 From: Babayaga Date: Thu, 26 Feb 2026 19:41:09 +0100 Subject: [PATCH] init --- .gitignore | 4 + dist-in/cache.js | 101 + dist-in/commons/cache/MemoryCache.js | 57 + dist-in/commons/cache/index.js | 14 + dist-in/commons/cache/types.js | 2 + dist-in/commons/decorators.js | 195 + dist-in/commons/log-routes-factory.js | 169 + dist-in/commons/logger.js | 67 + dist-in/commons/registry.js | 165 + dist-in/commons/supabase.js | 67 + dist-in/commons/types.js | 2 + dist-in/commons/websocket.js | 228 + dist-in/config/products.js | 115 + dist-in/constants.js | 2 + dist-in/endpoints/admin.js | 179 + dist-in/endpoints/boss.js | 296 + dist-in/endpoints/stream.js | 69 + dist-in/events.js | 27 + dist-in/index.js | 221 + dist-in/integrations/supabase/schemas.js | 1208 ++ dist-in/integrations/supabase/types.js | 41 + dist-in/jobs/boss/AbstractWorker.js | 35 + dist-in/jobs/boss/client.js | 41 + dist-in/jobs/boss/registry.js | 13 + dist-in/jobs/boss/search/SearchWorker.js | 108 + dist-in/jobs/boss/workers.js | 25 + dist-in/lib/analytics-emitter.js | 5 + dist-in/middleware/analytics.js | 114 + dist-in/middleware/auth.js | 118 + dist-in/middleware/autoBan.js | 376 + dist-in/middleware/blocklist.js | 105 + dist-in/middleware/rateLimiter.js | 92 + dist-in/middleware/usageTracking.js | 264 + dist-in/products/AbstractProduct.js | 102 + dist-in/products/EventBus.js | 3 + dist-in/products/analytics/index.js | 122 + dist-in/products/analytics/routes.js | 81 + dist-in/products/enums.js | 20 + dist-in/products/errors.js | 20 + dist-in/products/openai/handlers.js | 84 + dist-in/products/openai/index.js | 32 + dist-in/products/openai/routes.js | 58 + dist-in/products/registry.js | 49 + dist-in/products/serving/routes.js | 307 + dist-in/products/subscriber.js | 36 + dist-in/schemas/index.js | 20 + dist-in/serve-assets.js | 82 + dist-in/zod-setup.js | 5 + openapitools.json | 7 + package-lock.json | 14742 +++++++++++++++++++++ package.json | 139 +- src/__tests__/blocklist.test.ts | 219 + src/__tests__/commons.ts | 1 + src/__tests__/endpoints.test.ts | 120 + src/__tests__/products.test.ts | 163 + src/__tests__/rateLimiter.test.ts | 145 + src/cache.ts | 123 + src/commons/cache/MemoryCache.ts | 67 + src/commons/cache/index.ts | 18 + src/commons/cache/types.ts | 21 + src/commons/decorators.ts | 249 + src/commons/log-routes-factory.ts | 185 + src/commons/logger.ts | 79 + src/commons/registry.ts | 192 + src/commons/supabase.ts | 76 + src/commons/types.ts | 10 + src/commons/websocket.ts | 238 + src/config/blocklist.json | 10 + src/config/products.ts | 137 + src/constants.ts | 1 + src/endpoints/__tests__/admin.test.ts | 32 + src/endpoints/admin.ts | 193 + src/endpoints/boss.ts | 304 + src/endpoints/stream.ts | 87 + src/events.ts | 43 + src/index.ts | 271 + src/integrations/supabase/schemas.ts | 1619 +++ src/integrations/supabase/types.ts | 1767 +++ src/jobs/boss/AbstractWorker.ts | 58 + src/jobs/boss/client.ts | 44 + src/jobs/boss/registry.ts | 25 + src/jobs/boss/search/SearchWorker.ts | 126 + src/jobs/boss/workers.ts | 40 + src/lib/analytics-emitter.ts | 5 + src/middleware/analytics.ts | 171 + src/middleware/auth.ts | 127 + src/middleware/autoBan.ts | 450 + src/middleware/blocklist.ts | 134 + src/middleware/rateLimiter.ts | 106 + src/middleware/usageTracking.ts | 305 + src/products/AbstractProduct.ts | 139 + src/products/EventBus.ts | 3 + src/products/analytics/index.ts | 141 + src/products/analytics/routes.ts | 84 + src/products/enums.ts | 22 + src/products/errors.ts | 29 + src/products/openai/handlers.ts | 99 + src/products/openai/index.ts | 37 + src/products/openai/routes.ts | 58 + src/products/registry.ts | 57 + src/products/serving/routes.ts | 468 + src/products/subscriber.ts | 42 + src/schemas/index.ts | 22 + src/serve-assets.ts | 93 + src/zod-setup.ts | 6 + tsconfig.build.json | 9 + tsconfig.json | 27 + vitest.config.ts | 19 + webpack.config.js | 48 + 109 files changed, 29758 insertions(+), 40 deletions(-) create mode 100644 dist-in/cache.js create mode 100644 dist-in/commons/cache/MemoryCache.js create mode 100644 dist-in/commons/cache/index.js create mode 100644 dist-in/commons/cache/types.js create mode 100644 dist-in/commons/decorators.js create mode 100644 dist-in/commons/log-routes-factory.js create mode 100644 dist-in/commons/logger.js create mode 100644 dist-in/commons/registry.js create mode 100644 dist-in/commons/supabase.js create mode 100644 dist-in/commons/types.js create mode 100644 dist-in/commons/websocket.js create mode 100644 dist-in/config/products.js create mode 100644 dist-in/constants.js create mode 100644 dist-in/endpoints/admin.js create mode 100644 dist-in/endpoints/boss.js create mode 100644 dist-in/endpoints/stream.js create mode 100644 dist-in/events.js create mode 100644 dist-in/index.js create mode 100644 dist-in/integrations/supabase/schemas.js create mode 100644 dist-in/integrations/supabase/types.js create mode 100644 dist-in/jobs/boss/AbstractWorker.js create mode 100644 dist-in/jobs/boss/client.js create mode 100644 dist-in/jobs/boss/registry.js create mode 100644 dist-in/jobs/boss/search/SearchWorker.js create mode 100644 dist-in/jobs/boss/workers.js create mode 100644 dist-in/lib/analytics-emitter.js create mode 100644 dist-in/middleware/analytics.js create mode 100644 dist-in/middleware/auth.js create mode 100644 dist-in/middleware/autoBan.js create mode 100644 dist-in/middleware/blocklist.js create mode 100644 dist-in/middleware/rateLimiter.js create mode 100644 dist-in/middleware/usageTracking.js create mode 100644 dist-in/products/AbstractProduct.js create mode 100644 dist-in/products/EventBus.js create mode 100644 dist-in/products/analytics/index.js create mode 100644 dist-in/products/analytics/routes.js create mode 100644 dist-in/products/enums.js create mode 100644 dist-in/products/errors.js create mode 100644 dist-in/products/openai/handlers.js create mode 100644 dist-in/products/openai/index.js create mode 100644 dist-in/products/openai/routes.js create mode 100644 dist-in/products/registry.js create mode 100644 dist-in/products/serving/routes.js create mode 100644 dist-in/products/subscriber.js create mode 100644 dist-in/schemas/index.js create mode 100644 dist-in/serve-assets.js create mode 100644 dist-in/zod-setup.js create mode 100644 openapitools.json create mode 100644 package-lock.json create mode 100644 src/__tests__/blocklist.test.ts create mode 100644 src/__tests__/commons.ts create mode 100644 src/__tests__/endpoints.test.ts create mode 100644 src/__tests__/products.test.ts create mode 100644 src/__tests__/rateLimiter.test.ts create mode 100644 src/cache.ts create mode 100644 src/commons/cache/MemoryCache.ts create mode 100644 src/commons/cache/index.ts create mode 100644 src/commons/cache/types.ts create mode 100644 src/commons/decorators.ts create mode 100644 src/commons/log-routes-factory.ts create mode 100644 src/commons/logger.ts create mode 100644 src/commons/registry.ts create mode 100644 src/commons/supabase.ts create mode 100644 src/commons/types.ts create mode 100644 src/commons/websocket.ts create mode 100644 src/config/blocklist.json create mode 100644 src/config/products.ts create mode 100644 src/constants.ts create mode 100644 src/endpoints/__tests__/admin.test.ts create mode 100644 src/endpoints/admin.ts create mode 100644 src/endpoints/boss.ts create mode 100644 src/endpoints/stream.ts create mode 100644 src/events.ts create mode 100644 src/index.ts create mode 100644 src/integrations/supabase/schemas.ts create mode 100644 src/integrations/supabase/types.ts create mode 100644 src/jobs/boss/AbstractWorker.ts create mode 100644 src/jobs/boss/client.ts create mode 100644 src/jobs/boss/registry.ts create mode 100644 src/jobs/boss/search/SearchWorker.ts create mode 100644 src/jobs/boss/workers.ts create mode 100644 src/lib/analytics-emitter.ts create mode 100644 src/middleware/analytics.ts create mode 100644 src/middleware/auth.ts create mode 100644 src/middleware/autoBan.ts create mode 100644 src/middleware/blocklist.ts create mode 100644 src/middleware/rateLimiter.ts create mode 100644 src/middleware/usageTracking.ts create mode 100644 src/products/AbstractProduct.ts create mode 100644 src/products/EventBus.ts create mode 100644 src/products/analytics/index.ts create mode 100644 src/products/analytics/routes.ts create mode 100644 src/products/enums.ts create mode 100644 src/products/errors.ts create mode 100644 src/products/openai/handlers.ts create mode 100644 src/products/openai/index.ts create mode 100644 src/products/openai/routes.ts create mode 100644 src/products/registry.ts create mode 100644 src/products/serving/routes.ts create mode 100644 src/products/subscriber.ts create mode 100644 src/schemas/index.ts create mode 100644 src/serve-assets.ts create mode 100644 src/zod-setup.ts create mode 100644 tsconfig.build.json create mode 100644 tsconfig.json create mode 100644 vitest.config.ts create mode 100644 webpack.config.js diff --git a/.gitignore b/.gitignore index cab85ca..5d13ac9 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,7 @@ /coverage *.log .DS_Store +*.env* +scripts +tests + diff --git a/dist-in/cache.js b/dist-in/cache.js new file mode 100644 index 0000000..a4a0700 --- /dev/null +++ b/dist-in/cache.js @@ -0,0 +1,101 @@ +import { getCache } from './commons/cache/index.js'; +import { appEvents } from './events.js'; +import pino from 'pino'; +import path from 'path'; +const logFile = path.join(process.cwd(), 'logs', 'cache.json'); +const fileTransport = pino.transport({ + target: 'pino/file', + options: { destination: logFile, mkdir: true } +}); +const logger = pino({ + level: process.env.PINO_LOG_LEVEL || 'info', + base: { product: 'cache' }, + timestamp: pino.stdTimeFunctions.isoTime, +}, pino.multistream([ + { stream: fileTransport, level: 'info' } +])); +export class AppCache { + static instance; + // Dependencies: key -> [dependencies] + // Defines what each type DEPENDS ON. + // If 'categories' changes, any type that has 'categories' in its dependency list must be invalidated. + static DEPENDENCIES = { + 'posts': ['categories', 'pictures'], // posts depend on categories and pictures + 'pages': ['categories', 'pictures', 'translations'], + 'categories': ['types'], + 'translations': [], // widget/category translations (wt:* keys) + 'feed': ['posts', 'pages', 'categories'], + 'auth': [] // No dependencies, standalone + }; + constructor() { } + static getInstance() { + if (!AppCache.instance) { + AppCache.instance = new AppCache(); + } + return AppCache.instance; + } + async get(type) { + const cache = getCache(); + const val = await cache.get(type); + return val; + } + async set(type, data, ttl) { + const cache = getCache(); + await cache.set(type, data, ttl); + } + /** + * Silent cache invalidation — clears cache for the given type and + * cascades to dependents. Does NOT emit SSE events. + * Use `notify()` in route handlers for explicit SSE. + */ + async invalidate(type) { + const cache = getCache(); + if (type === 'feed') { + await cache.flush('*-feed*'); + await cache.flush('home-feed*'); + } + else if (type === 'translations') { + await cache.flush('wt:*'); + await cache.flush('page-details-*'); + } + else { + await cache.del(type); + } + // Find types that depend on this type + const dependents = Object.keys(AppCache.DEPENDENCIES).filter(key => AppCache.DEPENDENCIES[key].includes(type)); + logger.info({ type, dependents }, 'Cache invalidated'); + if (dependents.length > 0) { + await Promise.all(dependents.map(dep => this.invalidate(dep))); + } + } + /** + * Flush cache entries by pattern. Silent — no SSE. + */ + async flush(pattern) { + const cache = getCache(); + await cache.flush(pattern); + logger.info({ pattern: pattern || 'all' }, 'Cache flushed'); + } + /** + * Emit exactly 1 SSE event to notify clients of a change. + * Call this in route handlers AFTER cache invalidation. + * + * @param type - Entity type (e.g. 'post', 'page', 'category', 'picture') + * @param id - Entity ID (null for list-level / system changes) + * @param action - The mutation that occurred + */ + notify(type, id, action) { + logger.info({ type, id, action }, 'Cache notify'); + appEvents.emitUpdate(type, action, { id }, 'cache'); + } + inspect() { + const cache = getCache(); + return { + info: cache.info(), + dependencies: AppCache.DEPENDENCIES, + entries: cache.entries(), + }; + } +} +export const appCache = AppCache.getInstance(); +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2FjaGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvY2FjaGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLDBCQUEwQixDQUFDO0FBQ3BELE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFFeEMsT0FBTyxJQUFJLE1BQU0sTUFBTSxDQUFDO0FBQ3hCLE9BQU8sSUFBSSxNQUFNLE1BQU0sQ0FBQztBQUV4QixNQUFNLE9BQU8sR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxHQUFHLEVBQUUsRUFBRSxNQUFNLEVBQUUsWUFBWSxDQUFDLENBQUM7QUFFL0QsTUFBTSxhQUFhLEdBQUcsSUFBSSxDQUFDLFNBQVMsQ0FBQztJQUNqQyxNQUFNLEVBQUUsV0FBVztJQUNuQixPQUFPLEVBQUUsRUFBRSxXQUFXLEVBQUUsT0FBTyxFQUFFLEtBQUssRUFBRSxJQUFJLEVBQUU7Q0FDakQsQ0FBQyxDQUFDO0FBRUgsTUFBTSxNQUFNLEdBQUcsSUFBSSxDQUNmO0lBQ0ksS0FBSyxFQUFFLE9BQU8sQ0FBQyxHQUFHLENBQUMsY0FBYyxJQUFJLE1BQU07SUFDM0MsSUFBSSxFQUFFLEVBQUUsT0FBTyxFQUFFLE9BQU8sRUFBRTtJQUMxQixTQUFTLEVBQUUsSUFBSSxDQUFDLGdCQUFnQixDQUFDLE9BQU87Q0FDM0MsRUFDRCxJQUFJLENBQUMsV0FBVyxDQUFDO0lBQ2IsRUFBRSxNQUFNLEVBQUUsYUFBYSxFQUFFLEtBQUssRUFBRSxNQUFNLEVBQUU7Q0FDM0MsQ0FBQyxDQUNMLENBQUM7QUFHRixNQUFNLE9BQU8sUUFBUTtJQUNULE1BQU0sQ0FBQyxRQUFRLENBQVc7SUFFbEMsc0NBQXNDO0lBQ3RDLHFDQUFxQztJQUNyQyxzR0FBc0c7SUFDOUYsTUFBTSxDQUFDLFlBQVksR0FBNkI7UUFDcEQsT0FBTyxFQUFFLENBQUMsWUFBWSxFQUFFLFVBQVUsQ0FBQyxFQUFFLDBD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 \ No newline at end of file diff --git a/dist-in/commons/cache/MemoryCache.js b/dist-in/commons/cache/MemoryCache.js new file mode 100644 index 0000000..e6ba238 --- /dev/null +++ b/dist-in/commons/cache/MemoryCache.js @@ -0,0 +1,57 @@ +import { LRUCache } from 'lru-cache'; +export class MemoryCache { + cache; + constructor() { + const defaultTtl = process.env.CACHE_DEFAULT_TTL ? parseInt(process.env.CACHE_DEFAULT_TTL) : 1000 * 60 * 5; // 5 mins default + this.cache = new LRUCache({ + max: 1000, + ttl: defaultTtl, + updateAgeOnGet: false, + }); + } + async get(key) { + const value = this.cache.get(key); + return value || null; + } + async set(key, value, ttl) { + this.cache.set(key, value, { ttl: ttl ? ttl * 1000 : undefined }); + } + async del(key) { + this.cache.delete(key); + } + async flush(pattern) { + if (pattern) { + // Support simple wildcard patterns (e.g. "home-feed*", "*-feed*") + // Escape special regex chars except *, then replace * with .* + const regexPattern = pattern + .replace(/[.+^${}()|[\]\\]/g, '\\$&') // Escape regex chars + .replace(/\*/g, '.*'); // Convert * to .* + const regex = new RegExp(`^${regexPattern}$`); + for (const key of this.cache.keys()) { + if (typeof key === 'string' && regex.test(key)) { + this.cache.delete(key); + } + } + } + else { + this.cache.clear(); + } + } + keys() { + return [...this.cache.keys()]; + } + info() { + return { + size: this.cache.size, + max: this.cache.max, + provider: 'memory-lru', + }; + } + entries() { + return [...this.cache.keys()].map(key => ({ + key, + remainingTTL: this.cache.getRemainingTTL(key), + })); + } +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiTWVtb3J5Q2FjaGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvY29tbW9ucy9jYWNoZS9NZW1vcnlDYWNoZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0sV0FBVyxDQUFDO0FBR3JDLE1BQU0sT0FBTyxXQUFXO0lBQ1osS0FBSyxDQUF3QjtJQUVyQztRQUNJLE1BQU0sVUFBVSxHQUFHLE9BQU8sQ0FBQyxHQUFHLENBQUMsaUJBQWlCLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLGlCQUFpQixDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksR0FBRyxFQUFFLEdBQUcsQ0FBQyxDQUFDLENBQUMsaUJBQWlCO1FBQzdILElBQUksQ0FBQyxLQUFLLEdBQUcsSUFBSSxRQUFRLENBQUM7WUFDdEIsR0FBRyxFQUFFLElBQUk7WUFDVCxHQUFHLEVBQUUsVUFBVTtZQUNmLGNBQWMsRUFBRSxLQUFLO1NBQ3hCLENBQUMsQ0FBQztJQUNQLENBQUM7SUFFRCxLQUFLLENBQUMsR0FBRyxDQUFJLEdBQVc7UUFDcEIsTUFBTSxLQUFLLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLENBQUM7UUFDbEMsT0FBUSxLQUFXLElBQUksSUFBSSxDQUFDO0lBQ2hDLENBQUM7SUFFRCxLQUFLLENBQUMsR0FBRyxDQUFJLEdBQVcsRUFBRSxLQUFRLEVBQUUsR0FBWTtRQUM1QyxJQUFJLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxHQUFHLEVBQUUsS0FBSyxFQUFFLEVBQUUsR0FBRyxFQUFFLEdBQUcsQ0FBQyxDQUFDLENBQUMsR0FBRyxHQUFHLElBQUksQ0FBQyxDQUFDLENBQUMsU0FBUyxFQUFFLENBQUMsQ0FBQztJQUN0RSxDQUFDO0lBRUQsS0FBSyxDQUFDLEdBQUcsQ0FBQyxHQUFXO1FBQ2pCLElBQUksQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBQzNCLENBQUM7SUFFRCxLQUFLLENBQUMsS0FBSyxDQUFDLE9BQWdCO1FBQ3hCLElBQUksT0FBTyxFQUFFLENBQUM7WUFDVixrRUFBa0U7WUFDbEUsOERBQThEO1lBQzlELE1BQU0sWUFBWSxHQUFHLE9BQU87aUJBQ3ZCLE9BQU8sQ0FBQyxtQkFBbUIsRUFBRSxNQUFNLENBQUMsQ0FBQyxxQkFBcUI7aUJBQzFELE9BQU8sQ0FBQyxLQUFLLEVBQUUsSUFBSSxDQUFDLENBQUMsQ0FBaUIsa0JBQWtCO1lBRTdELE1BQU0sS0FBSyxHQUFHLElBQUksTUFBTSxDQUFDLElBQUksWUFBWSxHQUFHLENBQUMsQ0FBQztZQUU5QyxLQUFLLE1BQU0sR0FBRyxJQUFJLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxFQUFFLEVBQUUsQ0FBQztnQkFDbEMsSUFBSSxPQUFPLEdBQUcsS0FBSyxRQUFRLElBQUksS0FBSyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDO29CQUM3QyxJQUFJLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQztnQkFDM0IsQ0FBQztZQUNMLENBQUM7UUFDTCxDQUFDO2FBQU0sQ0FBQztZQUNKLElBQUksQ0FBQyxLQUFLLENBQUMsS0FBSyxFQUFFLENBQUM7UUFDdkIsQ0FBQztJQUNMLENBQUM7SUFFRCxJQUFJO1FBQ0EsT0FBTyxDQUFDLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLEVBQUUsQ0FBQyxDQUFDO0lBQ2xDLENBQUM7SUFFRCxJQUFJO1FBQ0EsT0FBTztZQUNILElBQUksRUFBRSxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUk7WUFDckIsR0FBRyxFQUFFLElBQUksQ0FBQyxLQUFLLENBQUMsR0FBRztZQUNuQixRQUFRLEVBQUUsWUFBWTtTQUN6QixDQUFDO0lBQ04sQ0FBQztJQUVELE9BQU87UUFDSCxPQUFPLENBQUMsR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksRUFBRSxDQUFDLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsQ0FBQztZQUN0QyxHQUFHO1lBQ0gsWUFBWSxFQUFFLElBQUksQ0FBQyxLQUFLLENBQUMsZUFBZSxDQUFDLEdBQUcsQ0FBQztTQUNoRCxDQUFDLENBQUMsQ0FBQztJQUNSLENBQUM7Q0FDSiJ9 \ No newline at end of file diff --git a/dist-in/commons/cache/index.js b/dist-in/commons/cache/index.js new file mode 100644 index 0000000..7bfd988 --- /dev/null +++ b/dist-in/commons/cache/index.js @@ -0,0 +1,14 @@ +import { MemoryCache } from './MemoryCache.js'; +// Design Pattern: Singleton or Factory +// For now, we export a singleton instance based on ENV or default to Memory +// Future: Read process.env.CACHE_PROVIDER == 'redis' +let instance = null; +export const getCache = () => { + if (!instance) { + instance = new MemoryCache(); + } + return instance; +}; +export * from './types.js'; +export * from './MemoryCache.js'; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvY29tbW9ucy9jYWNoZS9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFDQSxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sa0JBQWtCLENBQUM7QUFFL0MsdUNBQXVDO0FBQ3ZDLDRFQUE0RTtBQUM1RSxxREFBcUQ7QUFFckQsSUFBSSxRQUFRLEdBQXdCLElBQUksQ0FBQztBQUV6QyxNQUFNLENBQUMsTUFBTSxRQUFRLEdBQUcsR0FBaUIsRUFBRTtJQUN2QyxJQUFJLENBQUMsUUFBUSxFQUFFLENBQUM7UUFDWixRQUFRLEdBQUcsSUFBSSxXQUFXLEVBQUUsQ0FBQztJQUNqQyxDQUFDO0lBQ0QsT0FBTyxRQUFRLENBQUM7QUFDcEIsQ0FBQyxDQUFDO0FBRUYsY0FBYyxZQUFZLENBQUM7QUFDM0IsY0FBYyxrQkFBa0IsQ0FBQyJ9 \ No newline at end of file diff --git a/dist-in/commons/cache/types.js b/dist-in/commons/cache/types.js new file mode 100644 index 0000000..a2803aa --- /dev/null +++ b/dist-in/commons/cache/types.js @@ -0,0 +1,2 @@ +export {}; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHlwZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvY29tbW9ucy9jYWNoZS90eXBlcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiIn0= \ No newline at end of file diff --git a/dist-in/commons/decorators.js b/dist-in/commons/decorators.js new file mode 100644 index 0000000..e8623f5 --- /dev/null +++ b/dist-in/commons/decorators.js @@ -0,0 +1,195 @@ +import { trackUsage, updateUsageRecord } from '../middleware/usageTracking.js'; +import { FunctionRegistry, PublicEndpointRegistry, AdminEndpointRegistry } from './registry.js'; +import { logger } from './logger.js'; +/** + * Decorator/Wrapper to mark an endpoint as public + * Registers the route in PublicEndpointRegistry + */ +export function Public(route) { + PublicEndpointRegistry.register(route.path, route.method); + return route; +} +/** + * Decorator/Wrapper to mark an endpoint as admin-only + * Registers the route in AdminEndpointRegistry + */ +export function Admin(route) { + AdminEndpointRegistry.register(route.path, route.method); + return route; +} +/** + * Decorator to mark a method as billable + * Handles usage tracking, context injection, and cancellation + */ +export function Billable(options) { + return function (target, propertyKey, descriptor) { + const originalMethod = descriptor.value; + descriptor.value = async function (...args) { + // 1. Extract context + // Assumes the first argument is BillableContext, or it's part of the first argument object + let context; + if (args.length > 0 && typeof args[0] === 'object') { + // Check if first arg is context + if ('userId' in args[0] && 'jobId' in args[0]) { + context = args[0]; + } + } + if (!context) { + // If no context provided, we can't track usage properly + // For now, we'll log a warning and proceed without tracking + // In strict mode, we might want to throw an error + logger.warn(`[Billable] No context provided for ${options.productId}:${options.actionId}`); + return originalMethod.apply(this, args); + } + // 2. Get config + const config = FunctionRegistry.get(options.productId, options.actionId); + if (!config) { + logger.warn(`[Billable] No config found for ${options.productId}:${options.actionId}`); + return originalMethod.apply(this, args); + } + // 3. Start tracking + const usageId = await trackUsage({ + userId: context.userId, + endpoint: 'function', // Internal function call + method: 'CALL', + product: options.productId, + action: options.actionId, + costUnits: config.costUnits, + cancellable: options.cancellable || false, + jobId: context.jobId, + metadata: context.metadata + }); + const startTime = Date.now(); + let error = null; + let result; + try { + // 4. Execute method + // If cancellable, we should ideally wrap the execution or check signal + if (options.cancellable && context.signal) { + if (context.signal.aborted) { + throw new Error('Operation cancelled'); + } + // Add abort listener + context.signal.addEventListener('abort', () => { + logger.info(`[Billable] Job ${context?.jobId} aborted via signal`); + }); + } + result = await originalMethod.apply(this, args); + return result; + } + catch (err) { + error = err; + throw err; + } + finally { + // 5. End tracking + if (usageId) { + const endTime = Date.now(); + await updateUsageRecord({ + usageId, + responseStatus: error ? 500 : 200, + responseTimeMs: endTime - startTime, + error + }); + } + } + }; + return descriptor; + }; +} +/** + * Class Decorator: Registers the worker queue name + */ +export function Worker(queueName) { + return function (constructor) { + // We can't easily access the instance method 'handler' here without instantiating + // So we assume the class has a 'handler' method or we register the class itself + // For simplicity, let's assume we'll instantiate it later or the registry handles it. + // But wait, pg-boss needs a function. + // Let's store the constructor in the registry, and the registry (or bootstrap) will instantiate and bind. + // Actually, let's just attach the queue name to the class for now, + // and let a separate scanner or manual registration use it. + // OR, we can register a factory. + // Better approach for now: Register the prototype's handler if it exists. + // But 'handler' is on the instance usually. + // Let's just modify the class to have a static 'queueName' property + // and register it. + constructor.queueName = queueName; + }; +} +import { getCache } from './cache/index.js'; +const defaultKeyInfo = (c) => { + const url = new URL(c.req.url); + url.searchParams.sort(); + return `auto-cache:${c.req.method}:${url.pathname}${url.search}`; +}; +export const CachedHandler = (handler, options) => async (c) => { + const opts = options || {}; + const ttl = opts.ttl || 300; + const varyByAuth = opts.varyByAuth || false; + const skipAuth = opts.skipAuth !== undefined ? opts.skipAuth : !varyByAuth; // Default true unless varyByAuth is true + const maxSizeBytes = opts.maxSizeBytes || 1024 * 1024; // 1MB + const keyGen = opts.keyGenerator || defaultKeyInfo; + // 1. Auth Bypass + const authHeader = c.req.header('Authorization'); + if (skipAuth && authHeader) { + // Explicitly mark as skipped due to auth + c.header('X-Cache', 'SKIP'); + return handler(c); + } + const cache = getCache(); + let key = keyGen(c); + // Append Auth to key if requested (User Isolation) + if (varyByAuth && authHeader) { + key += `|auth=${authHeader}`; + } + const bypass = c.req.query('cache') === 'false' || c.req.query('nocache') === 'true'; + // 2. Hit + if (!bypass) { + const cached = await cache.get(key); + if (cached) { + c.header('X-Cache', 'HIT'); + const cachedVal = cached; + if (cachedVal.contentType) + c.header('Content-Type', cachedVal.contentType); + if (varyByAuth) + c.header('Vary', 'Authorization'); + return c.body(cachedVal.data); + } + } + // 3. Miss + const response = await handler(c); + // 4. Save + if (response instanceof Response && response.ok) { + const cloned = response.clone(); + try { + const contentType = response.headers.get('Content-Type') || 'application/json'; + let data; + // Check content length if available + const contentLength = cloned.headers.get('Content-Length'); + if (contentLength && parseInt(contentLength) > maxSizeBytes) { + return response; + } + if (contentType.includes('application/json')) { + const jsonObj = await cloned.json(); + data = JSON.stringify(jsonObj); + } + else { + data = await cloned.text(); + } + // Double check actual size after reading + if (data.length > maxSizeBytes) { + return response; + } + await cache.set(key, { data, contentType }, ttl); + c.header('X-Cache', bypass ? 'BYPASS' : 'MISS'); + if (varyByAuth) + c.header('Vary', 'Authorization'); + } + catch (e) { + logger.error({ err: e }, 'Cache interception failed'); + } + } + return response; +}; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGVjb3JhdG9ycy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9jb21tb25zL2RlY29yYXRvcnMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFVBQVUsRUFBRSxpQkFBaUIsRUFBRSxNQUFNLGdDQUFnQyxDQUFDO0FBQy9FLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxzQkFBc0IsRUFBRSxxQkFBcUIsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUNoRyxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sYUFBYSxDQUFDO0FBRXJDOzs7R0FHRztBQUNILE1BQU0sVUFBVSxNQUFNLENBQTZDLEtBQVE7SUFDdkUsc0JBQXNCLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxJQUFJLEVBQUUsS0FBSyxDQUFDLE1BQU0sQ0FBQyxDQUFDO0lBQzFELE9BQU8sS0FBSyxDQUFDO0FBQ2pCLENBQUM7QUFFRDs7O0dBR0c7QUFDSCxNQUFNLFVBQVUsS0FBSyxDQUE2QyxLQUFRO0lBQ3RFLHFCQUFxQixDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsSUFBSSxFQUFFLEtBQUssQ0FBQyxNQUFNLENBQUMsQ0FBQztJQUN6RCxPQUFPLEtBQUssQ0FBQztBQUNqQixDQUFDO0FBZUQ7OztHQUdHO0FBQ0gsTUFBTSxVQUFVLFFBQVEsQ0FBQyxPQUF3QjtJQUM3QyxPQUFPLFVBQ0gsTUFBVyxFQUNYLFdBQW1CLEVBQ25CLFVBQThCO1FBRTlCLE1BQU0sY0FBYyxHQUFHLFVBQVUsQ0FBQyxLQUFLLENBQUM7UUFFeEMsVUFBVSxDQUFDLEtBQUssR0FBRyxLQUFLLFdBQVcsR0FBRyxJQUFXO1lBQzdDLHFCQUFxQjtZQUNyQiwyRkFBMkY7WUFDM0YsSUFBSSxPQUFvQyxDQUFDO1lBRXpDLElBQUksSUFBSSxDQUFDLE1BQU0sR0FBRyxDQUFDLElBQUksT0FBTyxJQUFJLENBQUMsQ0FBQyxDQUFDLEtBQUssUUFBUSxFQUFFLENBQUM7Z0JBQ2pELGdDQUFn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 \ No newline at end of file diff --git a/dist-in/commons/log-routes-factory.js b/dist-in/commons/log-routes-factory.js new file mode 100644 index 0000000..dcb13b7 --- /dev/null +++ b/dist-in/commons/log-routes-factory.js @@ -0,0 +1,169 @@ +import { createRoute, z } from '@hono/zod-openapi'; +import { streamSSE, stream } from 'hono/streaming'; +import fs from 'fs'; +import readline from 'readline'; +/** + * Creates OpenAPI route definitions for standard log endpoints. + * @param tag The OpenAPI tag for grouping (e.g. 'System', 'Images') + * @param pathPrefix The URL path prefix (e.g. '/api/logs/system') + */ +export const createLogRoutes = (tag, pathPrefix) => { + const getRoute = createRoute({ + method: 'get', + path: pathPrefix, + tags: [tag], + summary: `Get ${tag} logs`, + description: `Download or view ${tag} logs as a JSON array`, + responses: { + 200: { + description: 'Log content', + content: { + 'application/json': { + schema: z.array(z.record(z.string(), z.any())).openapi({ + description: 'Array of log entries' + }) + } + } + }, + 404: { + description: 'Log file not found' + } + } + }); + const streamRoute = createRoute({ + method: 'get', + path: `${pathPrefix}/stream`, + tags: [tag], + summary: `Stream ${tag} logs`, + description: `Stream ${tag} logs via SSE (Server-Sent Events)`, + responses: { + 200: { + description: 'Log stream', + content: { + 'text/event-stream': { schema: z.string() } + } + } + } + }); + return { getRoute, streamRoute }; +}; +/** + * Creates Hono handlers for standard log endpoints. + * @param filePath The absolute path to the log file + */ +export const createLogHandlers = (filePath) => { + const getHandler = async (c) => { + if (!fs.existsSync(filePath)) { + return c.text('Log file not found', 404); + } + c.header('Content-Type', 'application/json'); + return stream(c, async (stream) => { + const fileStream = fs.createReadStream(filePath); + const rl = readline.createInterface({ + input: fileStream, + crlfDelay: Infinity + }); + await stream.write('['); + let first = true; + for await (const line of rl) { + if (!line.trim()) + continue; + if (!first) { + await stream.write(','); + } + try { + // Validate JSON to ensure we don't stream garbage? + // Optional: overhead. Assuming pino writes valid JSON per line. + // Just writing the line directly is faster. + await stream.write(line); + first = false; + } + catch (e) { + // Ignore broken lines + } + } + await stream.write(']'); + }); + }; + const streamHandler = async (c) => { + return streamSSE(c, async (stream) => { + // Send initial connection message + await stream.writeSSE({ + data: JSON.stringify({ type: 'info', message: 'Connected to log stream' }) + }); + if (!fs.existsSync(filePath)) { + await stream.writeSSE({ + data: JSON.stringify({ type: 'error', message: 'Log file not found' }) + }); + // We keep the stream open in case the file is created later + } + let currentSize = 0; + // Check initial size + if (fs.existsSync(filePath)) { + const stat = fs.statSync(filePath); + currentSize = stat.size; + // Optional: Tail current content? + // For simplicity, we start streaming NEW content. + // But let's verify if we should send a bit of context. + // If it's a JSON log, partial lines are bad. + // If it's text, partial lines are bad too. + // Let's just track current size and stream updates. + } + const checkInterval = 250; // Check every 250ms + const interval = setInterval(async () => { + try { + if (!fs.existsSync(filePath)) { + if (currentSize > 0) { + currentSize = 0; // File deleted + await stream.writeSSE({ data: JSON.stringify({ type: 'info', message: 'Log file deleted' }) }); + } + return; + } + const stat = fs.statSync(filePath); + if (stat.size > currentSize) { + const sizeDiff = stat.size - currentSize; + const buffer = Buffer.alloc(sizeDiff); + const fd = fs.openSync(filePath, 'r'); + try { + fs.readSync(fd, buffer, 0, sizeDiff, currentSize); + currentSize = stat.size; + const chunk = buffer.toString('utf-8'); + // If it's line-delimited JSON or text + const lines = chunk.split('\n'); + // Note: the last line might be incomplete if we read exactly to EOF while writing? + // But usually logger writes full lines. + // However, strictly we should handle buffering incomplete lines. + // For this "standard" goal, let's assume atomic writes or simple line splitting. + // To be safer with valid JSON, we could filter empty lines. + for (const line of lines) { + if (!line.trim()) + continue; + await stream.writeSSE({ data: line }); + } + } + finally { + fs.closeSync(fd); + } + } + else if (stat.size < currentSize) { + // Truncated / Rotated + currentSize = stat.size; + await stream.writeSSE({ + data: JSON.stringify({ type: 'info', message: 'Log rotated' }) + }); + } + } + catch (e) { + console.error('Stream error:', e); + } + }, checkInterval); + stream.onAbort(() => { + clearInterval(interval); + }); + // Keep the stream alive + await new Promise(() => { }); + }); + }; + return { getHandler, streamHandler }; +}; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibG9nLXJvdXRlcy1mYWN0b3J5LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2NvbW1vbnMvbG9nLXJvdXRlcy1mYWN0b3J5LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxXQUFXLEVBQUUsQ0FBQyxFQUFFLE1BQU0sbUJBQW1CLENBQUM7QUFFbkQsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUNuRCxPQUFPLEVBQUUsTUFBTSxJQUFJLENBQUM7QUFDcEIsT0FBTyxRQUFRLE1BQU0sVUFBVSxDQUFDO0FBRWhDOzs7O0dBSUc7QUFDSCxNQUFNLENBQUMsTUFBTSxlQUFlLEdBQUcsQ0FBQyxHQUFXLEVBQUUsVUFBa0IsRUFBRSxFQUFFO0lBQy9ELE1BQU0sUUFBUSxHQUFHLFdBQVcsQ0FBQztRQUN6QixNQUFNLEVBQUUsS0FBSztRQUNiLElBQUksRUFBRSxVQUFVO1FBQ2hCLElBQUksRUFBRSxDQUFDLEdBQUcsQ0FBQztRQUNYLE9BQU8sRUFBRSxPQUFPLEdBQUcsT0FBTztRQUMxQixXQUFXLEVBQUUsb0JBQW9CLEdBQUcsdUJBQXVCO1FBQzNELFNBQVMsRUFBRTtZQUNQLEdBQUcsRUFBRTtnQkFDRCxXQUFXLEVBQUUsYUFBYTtnQkFDMUIsT0FBTyxFQUFFO29CQUNMLGtCQUFrQixFQUFFO3dCQUNoQixNQUFNLEVBQUUsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxNQUFNLEVBQUUsRUFBRSxDQUFDLENBQUMsR0FBRyxFQUFFLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQzs0QkFDbkQsV0FBVyxFQUFFLHNCQUFzQjt5QkFDdEMsQ0FBQztxQkFDTDtpQkFDSjthQUNKO1lBQ0QsR0FBRyxFQUFFO2dCQUNELFdBQVcsRUFBRSxvQkFBb0I7YUFDcEM7U0FDSjtLQUNKLENBQUMsQ0FBQztJQUVILE1BQU0sV0FBVyxHQUFHLFdB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 \ No newline at end of file diff --git a/dist-in/commons/logger.js b/dist-in/commons/logger.js new file mode 100644 index 0000000..87047bc --- /dev/null +++ b/dist-in/commons/logger.js @@ -0,0 +1,67 @@ +import pino from 'pino'; +import path from 'path'; +import { mkdirSync } from 'fs'; +// Ensure logs directory exists +try { + mkdirSync(path.join(process.cwd(), 'logs'), { recursive: true }); +} +catch (err) { + // Directory already exists +} +const fileTransport = pino.transport({ + target: 'pino/file', + options: { destination: path.join(process.cwd(), 'app.log') }, +}); +const consoleTransport = pino.transport({ + target: 'pino-pretty', + options: { + colorize: true, + ignore: 'pid,hostname', + destination: 1, + }, +}); +export const logger = pino({ + level: process.env.PINO_LOG_LEVEL || 'info', + formatters: { + level: (label) => { + return { level: label.toUpperCase() }; + }, + }, + timestamp: pino.stdTimeFunctions.isoTime, +}, pino.multistream([ + { stream: fileTransport, level: 'info' }, + { stream: consoleTransport, level: 'info' }, +])); +// Security logger - writes to logs/security.json +const securityFileTransport = pino.transport({ + target: 'pino/file', + options: { + destination: path.join(process.cwd(), 'logs', 'security.json'), + mkdir: true + }, +}); +const securityConsoleTransport = pino.transport({ + target: 'pino-pretty', + options: { + colorize: true, + ignore: 'pid,hostname', + destination: 1, + }, +}); +export const securityLogger = pino({ + level: process.env.PINO_LOG_LEVEL || 'info', + formatters: { + level: (label) => { + return { level: label.toUpperCase() }; + }, + }, + timestamp: pino.stdTimeFunctions.isoTime, + base: { + logger: 'security' + } +}, pino.multistream([ + { stream: securityFileTransport, level: 'info' }, + { stream: securityConsoleTransport, level: 'info' }, +])); +export default logger; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibG9nZ2VyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2NvbW1vbnMvbG9nZ2VyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sSUFBSSxNQUFNLE1BQU0sQ0FBQztBQUN4QixPQUFPLElBQUksTUFBTSxNQUFNLENBQUM7QUFDeEIsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLElBQUksQ0FBQztBQUUvQiwrQkFBK0I7QUFDL0IsSUFBSSxDQUFDO0lBQ0QsU0FBUyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLEdBQUcsRUFBRSxFQUFFLE1BQU0sQ0FBQyxFQUFFLEVBQUUsU0FBUyxFQUFFLElBQUksRUFBRSxDQUFDLENBQUM7QUFDckUsQ0FBQztBQUFDLE9BQU8sR0FBRyxFQUFFLENBQUM7SUFDWCwyQkFBMkI7QUFDL0IsQ0FBQztBQUVELE1BQU0sYUFBYSxHQUFHLElBQUksQ0FBQyxTQUFTLENBQUM7SUFDakMsTUFBTSxFQUFFLFdBQVc7SUFDbkIsT0FBTyxFQUFFLEVBQUUsV0FBVyxFQUFFLElBQUksQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLEdBQUcsRUFBRSxFQUFFLFNBQVMsQ0FBQyxFQUFFO0NBQ2hFLENBQUMsQ0FBQztBQUVILE1BQU0sZ0JBQWdCLEdBQUcsSUFBSSxDQUFDLFNBQVMsQ0FBQztJQUNwQyxNQUFNLEVBQUUsYUFBYTtJQUNyQixPQUFPLEVBQUU7UUFDTCxRQUFRLEVBQUUsSUFBSTtRQUNkLE1BQU0sRUFBRSxjQUFjO1FBQ3RCLFdBQVcsRUFBRSxDQUFDO0tBQ2pCO0NBQ0osQ0FBQyxDQUFDO0FBRUgsTUFBTSxDQUFDLE1BQU0sTUFBTSxHQUFHLElBQUksQ0FDdEI7SUFDSSxLQUFLLEVBQUUsT0FBTyxDQUFDLEdBQUcsQ0FBQyxjQUFjLElBQUksTUFBTTtJQUMzQyxVQUFVLEVBQUU7UUFDUixLQUFLLEVBQUUsQ0FBQyxLQUFLLEVBQUUsRUFBRTtZQUNiLE9BQU8sRUFBRSxLQUFLLEVBQUUsS0FBSyxDQUFDLFdBQVcsRUFBRSxFQUFFLENBQUM7UUFDMUMsQ0FBQztLQUNKO0lBQ0QsU0FBUyxFQUFFLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxPQUFPO0NBQzNDLEVBQ0QsSUFBSSxDQUFDLFdBQVcsQ0FBQztJQUNiLEVBQUUsTUFBTSxFQUFFLGFBQWEsRUFBRSxLQUFLLEVBQUUsTUFBTSxFQUFFO0lBQ3hDLEVBQUUsTUFBTSxFQUFFLGdCQUFnQixFQUFFLEtBQUssRUFBRSxNQUFNLEVBQUU7Q0FDOUMsQ0FBQyxDQUNMLENBQUM7QUFFRixpREFBaUQ7QUFDakQsTUFBTSxxQkFBcUIsR0FBRyxJQUFJLENBQUMsU0FBUyxDQUFDO0lBQ3pDLE1BQU0sRUFBRSxXQUFXO0lBQ25CLE9BQU8sRUFBRTtRQUNMLFdBQVcsRUFBRSxJQUFJLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxHQUFHLEVBQUUsRUFBRSxNQUFNLEVBQUUsZUFBZSxDQUFDO1FBQzlELEtBQUssRUFBRSxJQUFJO0tBQ2Q7Q0FDSixDQUFDLENBQUM7QUFFSCxNQUFNLHdCQUF3QixHQUFHLElBQUksQ0FBQyxTQUFTLENBQUM7SUFDNUMsTUFBTSxFQUFFLGFBQWE7SUFDckIsT0FBTyxFQUFFO1FBQ0wsUUFBUSxFQUFFLElBQUk7UUFDZCxNQUFNLEVBQUUsY0FBYztRQUN0QixXQUFXLEVBQUUsQ0FBQztLQUNqQjtDQUNKLENBQUMsQ0FBQztBQUVILE1BQU0sQ0FBQyxNQUFNLGNBQWMsR0FBRyxJQUFJLENBQzlCO0lBQ0ksS0FBSyxFQUFFLE9BQU8sQ0FBQyxHQUFHLENBQUMsY0FBYyxJQUFJLE1BQU07SUFDM0MsVUFBVSxFQUFFO1FBQ1IsS0FBSyxFQUFFLENBQUMsS0FBSyxFQUFFLEVBQUU7WUFDYixPQUFPLEVBQUUsS0FBSyxFQUFFLEtBQUssQ0FBQyxXQUFXLEVBQUUsRUFBRSxDQUFDO1FBQzFDLENBQUM7S0FDSjtJQUNELFNBQVMsRUFBRSxJQUFJLENBQUMsZ0JBQWdCLENBQUMsT0FBTztJQUN4QyxJQUFJLEVBQUU7UUFDRixNQUFNLEVBQUUsVUFBVTtLQUNyQjtDQUNKLEVBQ0QsSUFBSSxDQUFDLFdBQVcsQ0FBQztJQUNiLEVBQUUsTUFBTSxFQUFFLHFCQUFxQixFQUFFLEtBQUssRUFBRSxNQUFNLEVBQUU7SUFDaEQsRUFBRSxNQUFNLEVBQUUsd0JBQXdCLEVBQUUsS0FBSyxFQUFFLE1BQU0sRUFBRTtDQUN0RCxDQUFDLENBQ0wsQ0FBQztBQUVGLGVBQWUsTUFBTSxDQUFDIn0= \ No newline at end of file diff --git a/dist-in/commons/registry.js b/dist-in/commons/registry.js new file mode 100644 index 0000000..e54953c --- /dev/null +++ b/dist-in/commons/registry.js @@ -0,0 +1,165 @@ +import { PRODUCT_ACTIONS } from '../config/products.js'; +/** + * Central registry for all billable functions + * Manages configuration, costs, and metadata + */ +export class FunctionRegistry { + static registry = new Map(); + static initialized = false; + /** + * Initialize the registry with default configurations + */ + static initialize() { + if (this.initialized) + return; + // Load legacy PRODUCT_ACTIONS + for (const [productId, actions] of Object.entries(PRODUCT_ACTIONS)) { + for (const [actionId, config] of Object.entries(actions)) { + this.register({ + productId, + actionId, + ...config + }); + } + } + this.initialized = true; + } + /** + * Register a new billable function + */ + static register(config) { + const key = this.getKey(config.productId, config.actionId); + this.registry.set(key, config); + } + /** + * Get configuration for a specific function + */ + static get(productId, actionId) { + if (!this.initialized) + this.initialize(); + const key = this.getKey(productId, actionId); + return this.registry.get(key) || null; + } + /** + * Get all registered functions + */ + static getAll() { + if (!this.initialized) + this.initialize(); + return Array.from(this.registry.values()); + } + /** + * Find a configuration by matching route endpoint and method + * (Used for middleware backward compatibility) + */ + static findByRoute(path, method) { + if (!this.initialized) + this.initialize(); + for (const config of this.registry.values()) { + if (this.matchesRoute(path, config.endpoint) && method === config.method) { + return config; + } + } + return null; + } + static getKey(productId, actionId) { + return `${productId}:${actionId}`; + } + static matchesRoute(path, pattern) { + // Convert pattern to regex + // Handle both :param (Express/Hono style) and {param} (OpenAPI style) + // e.g., '/api/competitors/:place_id' or '/api/competitors/{place_id}' -> /^\/api\/competitors\/[^\/]+$/ + const regexPattern = pattern + .replace(/:[^\\/]+/g, '[^/]+') // Replace :param with regex + .replace(/\{[^}]+\}/g, '[^/]+') // Replace {param} with regex + .replace(/\//g, '\\/'); + // Allow optional trailing slash + const regex = new RegExp(`^${regexPattern}\\/?$`); + return regex.test(path); + } +} +/** + * Registry for public endpoints that don't require authentication + */ +export class PublicEndpointRegistry { + static registry = new Set(); + static register(path, method) { + this.registry.add(`${method.toUpperCase()}:${path}`); + } + static getAll() { + return Array.from(this.registry).map(entry => { + // Split only on the FIRST colon (METHOD:PATH) + // Don't split on colons in path parameters like :identifier + const colonIndex = entry.indexOf(':'); + const method = entry.substring(0, colonIndex); + const path = entry.substring(colonIndex + 1); + return { path, method }; + }); + } + static isPublic(path, method) { + const methodUpper = method.toUpperCase(); + for (const registered of this.registry) { + // Split only on the FIRST colon (METHOD:PATH) + // Don't split on colons in path parameters like :identifier + const colonIndex = registered.indexOf(':'); + const regMethod = registered.substring(0, colonIndex); + const regPath = registered.substring(colonIndex + 1); + if (regMethod !== methodUpper) + continue; + // Check if path matches pattern + if (this.matchesRoute(path, regPath)) { + return true; + } + } + // Debug: log when a route is not found as public + // console.log(`[PublicEndpointRegistry] Route not found as public: ${methodUpper} ${path}`); + // console.log(`[PublicEndpointRegistry] Registered routes:`, Array.from(this.registry)); + return false; + } + static matchesRoute(path, pattern) { + // Convert pattern to regex + // Handle both :param (Express/Hono style) and {param} (OpenAPI style) + // e.g., '/api/competitors/:place_id' or '/api/competitors/{place_id}' -> /^\/api\/competitors\/[^\/]+$/ + const regexPattern = pattern + .replace(/:[^\/]+/g, '[^/]+') // Replace :param with regex + .replace(/\{[^}]+\}/g, '[^/]+') // Replace {param} with regex + .replace(/\//g, '\\/'); + // Allow optional trailing slash + const regex = new RegExp(`^${regexPattern}\\/?$`); + return regex.test(path); + } +} +/** + * Registry for admin-only endpoints + */ +export class AdminEndpointRegistry { + static registry = new Set(); + static register(path, method) { + this.registry.add(`${method.toUpperCase()}:${path}`); + } + static isAdmin(path, method) { + const methodUpper = method.toUpperCase(); + for (const registered of this.registry) { + const [regMethod, regPath] = registered.split(':'); + if (regMethod !== methodUpper) + continue; + // Check if path matches pattern + if (this.matchesRoute(path, regPath)) { + return true; + } + } + return false; + } + static matchesRoute(path, pattern) { + // Convert pattern to regex + // Handle both :param (Express/Hono style) and {param} (OpenAPI style) + // e.g., '/api/competitors/:place_id' or '/api/competitors/{place_id}' -> /^\/api\/competitors\/[^\/]+$/ + const regexPattern = pattern + .replace(/:[^\\/]+/g, '[^/]+') // Replace :param with regex + .replace(/\{[^}]+\}/g, '[^/]+') // Replace {param} with regex + .replace(/\//g, '\\/'); + const regex = new RegExp(`^${regexPattern}\\/?$`); + return regex.test(path); + } +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVnaXN0cnkuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvY29tbW9ucy9yZWdpc3RyeS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQXVCLGVBQWUsRUFBRSxNQUFNLHVCQUF1QixDQUFDO0FBTzdFOzs7R0FHRztBQUNILE1BQU0sT0FBTyxnQkFBZ0I7SUFDakIsTUFBTSxDQUFDLFFBQVEsR0FBRyxJQUFJLEdBQUcsRUFBa0MsQ0FBQztJQUM1RCxNQUFNLENBQUMsV0FBVyxHQUFHLEtBQUssQ0FBQztJQUVuQzs7T0FFRztJQUNILE1BQU0sQ0FBQyxVQUFVO1FBQ2IsSUFBSSxJQUFJLENBQUMsV0FBVztZQUFFLE9BQU87UUFFN0IsOEJBQThCO1FBQzlCLEtBQUssTUFBTSxDQUFDLFNBQVMsRUFBRSxPQUFPLENBQUMsSUFBSSxNQUFNLENBQUMsT0FBTyxDQUFDLGVBQWUsQ0FBQyxFQUFFLENBQUM7WUFDakUsS0FBSyxNQUFNLENBQUMsUUFBUSxFQUFFLE1BQU0sQ0FBQyxJQUFJLE1BQU0sQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQztnQkFDdkQsSUFBSSxDQUFDLFFBQVEsQ0FBQztvQkFDVixTQUFTO29CQUNULFFBQVE7b0JBQ1IsR0FBRyxNQUFNO2lCQUNaLENBQUMsQ0FBQztZQUNQLENBQUM7UUFDTCxDQUFDO1FBRUQsSUFBSSxDQUFDLFdBQVcsR0FBRyxJQUFJLENBQUM7SUFDNUIsQ0FBQztJQUVEOztPQUVHO0lBQ0gsTUFBTSxDQUFDLFFBQVEsQ0FBQyxNQUE4QjtRQUMxQyxNQUFNLEdBQUcsR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxTQUFTLEVBQUUsTUFBTSxDQUFDLFFBQVEsQ0FBQyxDQUFDO1FBQzNELElBQUksQ0FBQyxRQUFRLENBQUMsR0FBRyxDQUFDLEdBQUcsRUFBRSxNQUFNLENBQUMsQ0FBQztJQUNuQyxDQUFDO0lBRUQ7O09BRUc7SUFDSCxNQUFNLENBQUMsR0FBRyxDQUFDLFNBQWlCLEVBQUUsUUFBZ0I7UUFDMUMsSUFBSSxDQUFDLElBQUksQ0FBQyxXQUFXO1lBQUUsSUFBSSxDQUFDLFVBQVUsRUFBRSxDQUFDO1FBQ3pDLE1BQU0sR0FBRyxHQUFHLElBQUksQ0FBQyxNQUFNLENBQUMsU0FBUyxFQUFFLFFBQVEsQ0FBQyxDQUFDO1FBQzdDLE9BQU8sSUFBSSxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLElBQUksSUFBSSxDQUFDO0lBQzFDLENBQUM7SUFFRDs7T0FFRztJQUNILE1BQU0sQ0FBQyxNQUFNO1FBQ1QsSUFBSSxDQUFDLElBQUksQ0FBQyxXQUFXO1lBQUUsSUFBSSxDQUFDLFVBQVUsRUFBRSxDQUFDO1FBQ3pDLE9BQU8sS0FBSyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLE1BQU0sRUFBRSxDQUFDLENBQUM7SUFDOUMsQ0FBQztJQUVEOzs7T0FHRztJQUNILE1BQU0sQ0FBQyxXQUFXLENBQUMsSUFBWSxFQUFFLE1BQWM7UUFDM0MsSUFBSSxDQUFDLElBQUksQ0FBQyxXQUFXO1lBQUUsSUFBSSxDQUFDLFVBQVUsRUFBRSxDQUFDO1FBRXpDLEtBQUssTUFBTSxNQUFNLElBQUksSUFBSSxDQUFDLFFBQVEsQ0FBQyxNQUFNLEVBQUUsRUFBRSxDQUFDO1lBQzFDLElBQUksSUFBSSxDQUFDLFlBQVksQ0FBQyxJQUFJLEVBQUUsTUFBTSxDQUFDLFFBQVEsQ0FBQyxJQUFJLE1BQU0sS0FBSyxNQUFNLENBQUMsTUFBTSxFQUFFLENBQUM7Z0JBQ3ZFLE9BQU8sTUFBTSxDQUFDO1lBQ2xCLENBQUM7UUFDTCxDQUFDO1FBQ0QsT0FBTyxJQUFJLENBQUM7SUFDaEIsQ0FBQztJQUVPLE1BQU0sQ0FBQyxNQUFNLENBQUMsU0FBaUIsRUFBRSxRQUFnQjtRQUNyRCxPQUFPLEdBQUcsU0FBUyxJQUFJLFFBQVEsRUFBRSxDQUFDO0lBQ3RDLENBQUM7SUFFTyxNQUFNLENBQUMsWUFBWSxDQUFDLElBQVksRUFBRSxPQUFlO1FBQ3JELDJCQUEyQjtRQUMzQixzRUFBc0U7UUFDdEUsd0dBQXdHO1FBQ3hHLE1BQU0sWUFBWSxHQUFHLE9BQU87YUFDdkIsT0FBTyxDQUFDLFdBQVcsRUFBRSxPQUFPLENBQUMsQ0FBTSw0QkFBNEI7YUFDL0QsT0FBTyxDQUFDLFlBQVksRUFBRSxPQUFPLENBQUMsQ0FBSyw2QkFBNkI7YUFDaEUsT0FBTyxDQUFDLEtBQUssRUFBRSxLQUFLLENBQUMsQ0FBQztRQUUzQixnQ0FBZ0M7UUFDaEMsTUFBTSxLQUFLLEdBQUcsSUFBSSxNQUFNLENBQUMsSUFBSSxZQUFZLE9BQU8sQ0FBQyxDQUFDO1FBQ2xELE9BQU8sS0FBSyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUM1QixDQUFDOztBQUdMOztHQUVHO0FBQ0gsTUFBTSxPQUFPLHNCQUFzQjtJQUN2QixNQUFNLENBQUMsUUFBUSxHQUFHLElBQUksR0FBRyxFQUFVLENBQUM7SUFFNUMsTUFBTSxDQUFDLFFBQVEsQ0FBQyxJQUFZLEVBQUUsTUFBYztRQUN4QyxJQUFJLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FBQyxHQUFHLE1BQU0sQ0FBQyxXQUFXLEVBQUUsSUFBSSxJQUFJLEVBQUUsQ0FBQyxDQUFDO0lBQ3pELENBQUM7SUFFRCxNQUFNLENBQUMsTUFBTTtRQUNULE9BQU8sS0FBSyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxFQUFFO1lBQ3pDLDhDQUE4QztZQUM5Qyw0REFBNEQ7WUFDNUQsTUFBTSxVQUFVLEdBQUcsS0FBSyxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsQ0FBQztZQUN0QyxNQUFNLE1BQU0sR0FBRyxLQUFLLENBQUMsU0FBUyxDQUFDLENBQUMsRUFBRSxVQUFVLENBQUMsQ0FBQztZQUM5QyxNQUFNLElBQUksR0FBRyxLQUFLLENBQUMsU0FBUyxDQUFDLFVBQVUsR0FBRyxDQUFDLENBQUMsQ0FBQztZQUM3QyxPQUFPLEVBQUUsSUFBSSxFQUFFLE1BQU0sRUFBRSxDQUFDO1FBQzVCLENBQUMsQ0FBQyxDQUFDO0lBQ1AsQ0FBQztJQUVELE1BQU0sQ0FBQyxRQUFRLENBQUMsSUFBWSxFQUFFLE1BQWM7UUFDeEMsTUFBTSxXQUFXLEdBQUcsTUFBTSxDQUFDLFdBQVcsRUFBRSxDQUFDO1FBRXpDLEtBQUssTUFBTSxVQUFVLElBQUksSUFBSSxDQUFDLFFBQVEsRUFBRSxDQUFDO1lBQ3JDLDhDQUE4QztZQUM5Qyw0REFBNEQ7WUFDNUQsTUFBTSxVQUFVLEdBQUcsVUFBVSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsQ0FBQztZQUMzQyxNQUFNLFNBQVMsR0FBRyxVQUFVLENBQUMsU0FBUyxDQUFDLENBQUMsRUFBRSxVQUFVLENBQUMsQ0FBQztZQUN0RCxNQUFNLE9BQU8sR0FBRyxVQUFVLENBQUMsU0FBUyxDQUFDLFVBQVUsR0FBRyxDQUFDLENBQUMsQ0FBQztZQUVyRCxJQUFJLFNBQVMsS0FBSyxXQUFXO2dCQUFFLFNBQVM7WUFFeEMsZ0NBQWdDO1lBQ2hDLElBQUksSUFBSSxDQUFDLFlBQVksQ0FBQyxJQUFJLEVBQUUsT0FBTyxDQUFDLEVBQUUsQ0FBQztnQkFDbkMsT0FBTyxJQUFJLENBQUM7WUFDaEIsQ0FBQztRQUNMLENBQUM7UUFDRCxpREFBaUQ7UUFDakQsOEZBQThGO1FBQzlGLDBGQUEwRjtRQUMxRixPQUFPLEtBQUssQ0FBQztJQUNqQixDQUFDO0lBRU8sTUFBTSxDQUFDLFlBQVksQ0FBQyxJQUFZLEVBQUUsT0FBZTtRQUNyRCwyQkFBMkI7UUFDM0Isc0VBQXNFO1FBQ3RFLHdHQUF3RztRQUN4RyxNQUFNLFlBQVksR0FBRyxPQUFPO2FBQ3ZCLE9BQU8sQ0FBQyxVQUFVLEVBQUUsT0FBTyxDQUFDLENBQU0sNEJBQTRCO2FBQzlELE9BQU8sQ0FBQyxZQUFZLEVBQUUsT0FBTyxDQUFDLENBQUssNkJBQTZCO2FBQ2hFLE9BQU8sQ0FBQyxLQUFLLEVBQUUsS0FBSyxDQUFDLENBQUM7UUFFM0IsZ0NBQWdDO1FBQ2hDLE1BQU0sS0FBSyxHQUFHLElBQUksTUFBTSxDQUFDLElBQUksWUFBWSxPQUFPLENBQUMsQ0FBQztRQUNsRCxPQUFPLEtBQUssQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDNUIsQ0FBQzs7QUFHTDs7R0FFRztBQUNILE1BQU0sT0FBTyxxQkFBcUI7SUFDdEIsTUFBTSxDQUFDLFFBQVEsR0FBRyxJQUFJLEdBQUcsRUFBVSxDQUFDO0lBRTVDLE1BQU0sQ0FBQyxRQUFRLENBQUMsSUFBWSxFQUFFLE1BQWM7UUFDeEMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsR0FBRyxNQUFNLENBQUMsV0FBVyxFQUFFLElBQUksSUFBSSxFQUFFLENBQUMsQ0FBQztJQUN6RCxDQUFDO0lBRUQsTUFBTSxDQUFDLE9BQU8sQ0FBQyxJQUFZLEVBQUUsTUFBYztRQUN2QyxNQUFNLFdBQVcsR0FBRyxNQUFNLENBQUMsV0FBVyxFQUFFLENBQUM7UUFFekMsS0FBSyxNQUFNLFVBQVUsSUFBSSxJQUFJLENBQUMsUUFBUSxFQUFFLENBQUM7WUFDckMsTUFBTSxDQUFDLFNBQVMsRUFBRSxPQUFPLENBQUMsR0FBRyxVQUFVLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDO1lBRW5ELElBQUksU0FBUyxLQUFLLFdBQVc7Z0JBQUUsU0FBUztZQUV4QyxnQ0FBZ0M7WUFDaEMsSUFBSSxJQUFJLENBQUMsWUFBWSxDQUFDLElBQUksRUFBRSxPQUFPLENBQUMsRUFBRSxDQUFDO2dCQUNuQyxPQUFPLElBQUksQ0FBQztZQUNoQixDQUFDO1FBQ0wsQ0FBQztRQUNELE9BQU8sS0FBSyxDQUFDO0lBQ2pCLENBQUM7SUFFTyxNQUFNLENBQUMsWUFBWSxDQUFDLElBQVksRUFBRSxPQUFlO1FBQ3JELDJCQUEyQjtRQUMzQixzRUFBc0U7UUFDdEUsd0dBQXdHO1FBQ3hHLE1BQU0sWUFBWSxHQUFHLE9BQU87YUFDdkIsT0FBTyxDQUFDLFdBQVcsRUFBRSxPQUFPLENBQUMsQ0FBTSw0QkFBNEI7YUFDL0QsT0FBTyxDQUFDLFlBQVksRUFBRSxPQUFPLENBQUMsQ0FBSyw2QkFBNkI7YUFDaEUsT0FBTyxDQUFDLEtBQUssRUFBRSxLQUFLLENBQUMsQ0FBQztRQUUzQixNQUFNLEtBQUssR0FBRyxJQUFJLE1BQU0sQ0FBQyxJQUFJLFlBQVksT0FBTyxDQUFDLENBQUM7UUFDbEQsT0FBTyxLQUFLLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQzVCLENBQUMifQ== \ No newline at end of file diff --git a/dist-in/commons/supabase.js b/dist-in/commons/supabase.js new file mode 100644 index 0000000..12e723e --- /dev/null +++ b/dist-in/commons/supabase.js @@ -0,0 +1,67 @@ +import { createClient } from '@supabase/supabase-js'; +import 'dotenv/config'; +const supabaseUrl = process.env.SUPABASE_URL; +const supabaseKey = process.env.SUPABASE_SERVICE_KEY; +import { logger } from './logger.js'; +if (!supabaseUrl || !supabaseKey) { + logger.error({ + hasUrl: !!supabaseUrl, + hasKey: !!supabaseKey, + env: process.env.NODE_ENV + }, 'Missing Supabase environment variables'); + // process.exit(1) // Don't exit in test mode, throw instead + if (process.env.NODE_ENV !== 'test') + process.exit(1); + throw new Error('Missing Supabase environment variables: URL or Key is undefined'); +} +export const supabase = createClient(supabaseUrl, supabaseKey); +// --- Auth Cache (in-process Map for speed) --- +const AUTH_CACHE_TTL = process.env.AUTH_CACHE_TTL ? parseInt(process.env.AUTH_CACHE_TTL) : 1000 * 60 * 1; // Default 1 minute +const authMap = new Map(); +export const getUserCached = async (token) => { + if (!token) + return null; + const now = Date.now(); + const cached = authMap.get(token); + if (cached && (now - cached.timestamp < AUTH_CACHE_TTL)) { + return cached.user; + } + try { + const { data: { user }, error } = await supabase.auth.getUser(token); + if (error || !user) { + authMap.set(token, { user: null, timestamp: now }); + return null; + } + authMap.set(token, { user, timestamp: now }); + return user; + } + catch (err) { + logger.error({ err }, 'Auth Cache Error'); + return null; + } +}; +/** Clear in-process auth cache (call after admin user ops, role changes, etc.) */ +export const flushAuthCache = (userId) => { + if (!userId) { + authMap.clear(); + return; + } + // Remove entries for a specific user + for (const [token, entry] of authMap) { + if (entry.user?.id === userId) + authMap.delete(token); + } +}; +/** + * Test Supabase connection by attempting a simple query + */ +export async function testSupabaseConnection() { + try { + const { error } = await supabase.from('products').select('id').limit(1); + return !error; + } + catch { + return false; + } +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3VwYWJhc2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvY29tbW9ucy9zdXBhYmFzZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsWUFBWSxFQUFRLE1BQU0sdUJBQXVCLENBQUE7QUFDMUQsT0FBTyxlQUFlLENBQUE7QUFFdEIsTUFBTSxXQUFXLEdBQUcsT0FBTyxDQUFDLEdBQUcsQ0FBQyxZQUFZLENBQUE7QUFDNUMsTUFBTSxXQUFXLEdBQUcsT0FBTyxDQUFDLEdBQUcsQ0FBQyxvQkFBb0IsQ0FBQTtBQUVwRCxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sYUFBYSxDQUFBO0FBRXBDLElBQUksQ0FBQyxXQUFXLElBQUksQ0FBQyxXQUFXLEVBQUUsQ0FBQztJQUMvQixNQUFNLENBQUMsS0FBSyxDQUFDO1FBQ1QsTUFBTSxFQUFFLENBQUMsQ0FBQyxXQUFXO1FBQ3JCLE1BQU0sRUFBRSxDQUFDLENBQUMsV0FBVztRQUNyQixHQUFHLEVBQUUsT0FBTyxDQUFDLEdBQUcsQ0FBQyxRQUFRO0tBQzVCLEVBQUUsd0NBQXdDLENBQUMsQ0FBQztJQUM3Qyw0REFBNEQ7SUFDNUQsSUFBSSxPQUFPLENBQUMsR0FBRyxDQUFDLFFBQVEsS0FBSyxNQUFNO1FBQUUsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUNyRCxNQUFNLElBQUksS0FBSyxDQUFDLGlFQUFpRSxDQUFDLENBQUM7QUFDdkYsQ0FBQztBQUVELE1BQU0sQ0FBQyxNQUFNLFFBQVEsR0FBRyxZQUFZLENBQUMsV0FBVyxFQUFFLFdBQVcsQ0FBQyxDQUFBO0FBRTlELGdEQUFnRDtBQUVoRCxNQUFNLGNBQWMsR0FBRyxPQUFPLENBQUMsR0FBRyxDQUFDLGNBQWMsQ0FBQyxDQUFDLENBQUMsUUFBUSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsY0FBYyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksR0FBRyxFQUFFLEdBQUcsQ0FBQyxD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 \ No newline at end of file diff --git a/dist-in/commons/types.js b/dist-in/commons/types.js new file mode 100644 index 0000000..cadce4c --- /dev/null +++ b/dist-in/commons/types.js @@ -0,0 +1,2 @@ +export {}; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHlwZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvY29tbW9ucy90eXBlcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiIn0= \ No newline at end of file diff --git a/dist-in/commons/websocket.js b/dist-in/commons/websocket.js new file mode 100644 index 0000000..a024f7b --- /dev/null +++ b/dist-in/commons/websocket.js @@ -0,0 +1,228 @@ +import { WebSocketServer, WebSocket } from 'ws'; +import fs from 'fs'; +import path from 'path'; +import chokidar from 'chokidar'; +export class WebSocketManager { + static instance; + wss = null; + handlers = new Map(); + writeQueue = Promise.resolve(); + constructor() { + // Register default handlers + this.registerHandler('log', this.handleLog.bind(this)); + this.registerHandler('echo', (ws, payload) => ws.send(JSON.stringify({ type: 'echo', payload }))); + this.registerHandler('ping', (ws, payload) => ws.send(JSON.stringify({ type: 'pong', id: payload.id }))); + } + static getInstance() { + if (!WebSocketManager.instance) { + WebSocketManager.instance = new WebSocketManager(); + } + return WebSocketManager.instance; + } + init(server) { + if (this.wss) { + console.warn('WebSocketServer already initialized'); + return; + } + this.wss = new WebSocketServer({ server, path: '/ws' }); + this.wss.on('connection', (ws) => { + ws.on('message', (message) => { + try { + const data = JSON.parse(message.toString()); + const { command, ...payload } = data; + if (command && this.handlers.has(command)) { + this.handlers.get(command)(ws, payload); + } + else { + console.warn('Unknown command:', command); + } + } + catch (err) { + console.error('Failed to parse message:', err); + } + }); + ws.on('close', () => { + }); + ws.on('error', (err) => { + console.error('WebSocket error:', err); + }); + }); + this.initWatcher(); + } + initWatcher() { + // Watch for changes in canvas-page-new.json + const logDir = path.join(process.cwd(), 'data'); + // Ensure log directory exists + if (!fs.existsSync(logDir)) { + try { + fs.mkdirSync(logDir, { recursive: true }); + } + catch (err) { + console.error('Failed to create log directory for watcher:', err); + } + } + const handleFile = async (filePath) => { + // Ignore output files (logs) to prevent infinite loops (Frontend -> Log -> Watcher -> Frontend -> Loop) + const fileName = path.basename(filePath); + const ext = path.extname(filePath).toLowerCase(); + // Explicitly allow only specific JSON files (layouts) to trigger updates + // Ignore everything else (logs, dumps, etc.) + if (ext === '.json') { + if (fileName !== 'canvas-page-latest-new.json' && fileName !== 'canvas-page-new.json') { + return; + } + } + else if (fileName.startsWith('canvas-html-latest')) { + return; + } + console.log(`[Watcher] File detected: ${filePath}`); + try { + const ext = path.extname(filePath).toLowerCase(); + if (ext === '.json') { + const content = await fs.promises.readFile(filePath, 'utf-8'); + if (!content.trim()) + return; // Ignore empty writes + try { + const layoutData = JSON.parse(content); + console.log('Broadcasting layout-update (json)...'); + this.broadcast({ + type: 'layout-update', + data: layoutData + }); + } + catch (parseErr) { + console.error(`Failed to parse watched JSON file: ${filePath}`, parseErr); + } + } + else if (ext === '.html' || ext === '.md') { + const content = await fs.promises.readFile(filePath, 'base64'); + console.log(`Broadcasting layout-update (${ext})...`); + this.broadcast({ + type: 'layout-update', + data: content + }); + } + } + catch (err) { + console.error(`Failed to process watched file ${filePath}:`, err); + } + }; + chokidar.watch(logDir, { + persistent: true, + ignoreInitial: false, + awaitWriteFinish: { + stabilityThreshold: 100, + pollInterval: 100 + } + }) + .on('add', handleFile) + .on('change', handleFile); + } + registerHandler(command, handler) { + this.handlers.set(command, handler); + } + broadcast(message) { + if (!this.wss) + return; + const data = JSON.stringify(message); + this.wss.clients.forEach((client) => { + if (client.readyState === WebSocket.OPEN) { + client.send(data); + } + }); + } + handleLog(ws, payload) { + // Expected payload: { name: string, options?: { mode?: 'append'|'overwrite', format?: 'json'|'html'|'md' }, message: any, ...others } + const { name, id, options, ...logData } = payload; + if (!name) { + console.warn('Log command missing "name" field'); + return; + } + const mode = options?.mode || 'append'; + const format = options?.format || 'json'; + const logDir = path.join(process.cwd(), 'data'); + const extension = format === 'md' ? 'md' : format === 'html' ? 'html' : 'json'; + const logFile = path.join(logDir, `${name}.${extension}`); + // Ensure log directory exists + if (!fs.existsSync(logDir)) { + try { + fs.mkdirSync(logDir, { recursive: true }); + } + catch (err) { + console.error('Failed to create log directory:', err); + return; + } + } + // Serialize writes using the queue + this.writeQueue = this.writeQueue.then(async () => { + try { + if (format === 'json') { + if (mode === 'overwrite') { + // For overwrite (state capture), write only the message content if available + const content = (logData.message !== undefined) ? logData.message : logData; + const contentToWrite = JSON.stringify(content, null, 2); + await fs.promises.writeFile(logFile, contentToWrite); + } + else { + // For append (logging), read existing, parse, append to array, write back + let records = []; + try { + if (fs.existsSync(logFile)) { + const fileContent = await fs.promises.readFile(logFile, 'utf-8'); + if (fileContent.trim()) { + try { + const parsed = JSON.parse(fileContent); + if (Array.isArray(parsed)) { + records = parsed; + } + else { + records = [parsed]; + } + } + catch (e) { + // Attempt to parse as NDJSON (newline delimited JSON) + records = fileContent.split('\n') + .filter(line => line.trim()) + .map(line => { + try { + return JSON.parse(line); + } + catch { + return null; + } + }) + .filter(item => item !== null); + } + } + } + } + catch (readErr) { + console.warn(`Failed to read log file ${logFile}, starting fresh.`, readErr); + } + const logEntry = { + timestamp: new Date().toISOString(), + ...logData + }; + records.push(logEntry); + await fs.promises.writeFile(logFile, JSON.stringify(records, null, 2)); + } + } + else { + // HTML or MD + const message = logData.message; + const content = typeof message === 'string' ? message : JSON.stringify(message); + if (mode === 'append') { + await fs.promises.appendFile(logFile, content + '\n'); + } + else { + await fs.promises.writeFile(logFile, content); + } + } + } + catch (err) { + console.error(`Failed to write log file ${logFile}:`, err); + } + }); + } +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid2Vic29ja2V0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2NvbW1vbnMvd2Vic29ja2V0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxlQUFlLEVBQUUsU0FBUyxFQUFFLE1BQU0sSUFBSSxDQUFDO0FBRWhELE9BQU8sRUFBRSxNQUFNLElBQUksQ0FBQztBQUNwQixPQUFPLElBQUksTUFBTSxNQUFNLENBQUM7QUFDeEIsT0FBTyxRQUFRLE1BQU0sVUFBVSxDQUFDO0FBSWhDLE1BQU0sT0FBTyxnQkFBZ0I7SUFDakIsTUFBTSxDQUFDLFFBQVEsQ0FBbUI7SUFDbEMsR0FBRyxHQUEyQixJQUFJLENBQUM7SUFDbkMsUUFBUSxHQUFnQyxJQUFJLEdBQUcsRUFBRSxDQUFDO0lBQ2xELFVBQVUsR0FBa0IsT0FBTyxDQUFDLE9BQU8sRUFBRSxDQUFDO0lBRXREO1FBQ0ksNEJBQTRCO1FBQzVCLElBQUksQ0FBQyxlQUFlLENBQUMsS0FBSyxFQUFFLElBQUksQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7UUFDdkQsSUFBSSxDQUFDLGVBQWUsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxFQUFFLEVBQUUsT0FBTyxFQUFFLEVBQUUsQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsRUFBRSxJQUFJLEVBQUUsTUFBTSxFQUFFLE9BQU8sRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQ2xHLElBQUksQ0FBQyxlQUFlLENBQUMsTUFBTSxFQUFFLENBQUMsRUFBRSxFQUFFLE9BQU8sRUFBRSxFQUFFLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLEVBQUUsSUFBSSxFQUFFLE1BQU0sRUFBRSxFQUFFLEVBQUUsT0FBTyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQzdHLENBQUM7SUFFTSxNQUFNLENBQUMs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 \ No newline at end of file diff --git a/dist-in/config/products.js b/dist-in/config/products.js new file mode 100644 index 0000000..3fd363c --- /dev/null +++ b/dist-in/config/products.js @@ -0,0 +1,115 @@ +/** + * Product and Action Mapping Configuration + * Defines all trackable products, their actions, and associated metadata + */ +export const PRODUCT_ACTIONS = { + competitors: { + search: { + endpoint: '/api/competitors', + method: 'GET', + costUnits: 1.0, + cancellable: true, // Search can be cancelled + description: 'Search for competitors in a location', + }, + get_details: { + endpoint: '/api/competitors/:place_id', + method: 'GET', + costUnits: 0.0, + cancellable: false, // Quick lookup, not cancellable + description: 'Get details for a specific competitor', + }, + stream: { + endpoint: '/api/competitors/stream', + method: 'GET', + costUnits: 1.0, // Same cost as regular search + cancellable: true, + description: 'Stream competitors in real-time', + }, + find_email: { + endpoint: '/api/find/email/{place_id}', + method: 'GET', + costUnits: 2.0, // Higher cost due to Puppeteer usage + cancellable: true, // Long-running, can be cancelled + description: 'Find email addresses for a business using Puppeteer', + }, + }, + images: { + upload: { + endpoint: '/api/images', + method: 'POST', + costUnits: 2.0, + cancellable: true, + description: 'Upload an image', + }, + get: { + endpoint: '/api/images/:id', + method: 'GET', + costUnits: 0.05, + cancellable: false, + description: 'Retrieve an image', + }, + update: { + endpoint: '/api/images/:id', + method: 'PUT', + costUnits: 1.5, + cancellable: false, + description: 'Update image metadata', + }, + }, + mock: { + job: { + endpoint: '/api/mock/job', + method: 'POST', + costUnits: 0.0, + cancellable: true, + description: 'Mock job for testing', + }, + }, + // Add more products here as they are developed +}; +/** + * Match a request path and method to a product and action + */ +export function identifyProductAction(path, method) { + for (const [product, actions] of Object.entries(PRODUCT_ACTIONS)) { + for (const [action, config] of Object.entries(actions)) { + if (matchesRoute(path, config.endpoint) && method === config.method) { + return { product, action, config }; + } + } + } + return { product: null, action: null, config: null }; +} +/** + * Check if a path matches a route pattern (supports :param syntax) + */ +function matchesRoute(path, pattern) { + // Convert pattern to regex + // e.g., '/api/competitors/:place_id' or '/api/competitors/{place_id}' -> /^\/api\/competitors\/[^\/]+$/ + const regexPattern = pattern + .replace(/:[^\/]+/g, '[^/]+') // Replace :param with regex + .replace(/\{[^}]+\}/g, '[^/]+') // Replace {param} with regex + .replace(/\//g, '\\/'); // Escape slashes + // Allow optional trailing slash + const regex = new RegExp(`^${regexPattern}\\/?$`); + return regex.test(path); +} +/** + * Get all products + */ +export function getAllProducts() { + return Object.keys(PRODUCT_ACTIONS); +} +/** + * Get all actions for a product + */ +export function getProductActions(product) { + return Object.keys(PRODUCT_ACTIONS[product] || {}); +} +/** + * Get configuration for a specific product action + */ +export function getActionConfig(product, action) { + return PRODUCT_ACTIONS[product]?.[action] || null; +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHJvZHVjdHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvY29uZmlnL3Byb2R1Y3RzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7R0FHRztBQWNILE1BQU0sQ0FBQyxNQUFNLGVBQWUsR0FBa0M7SUFDMUQsV0FBVyxFQUFFO1FBQ1QsTUFBTSxFQUFFO1lBQ0osUUFBUSxFQUFFLGtCQUFrQjtZQUM1QixNQUFNLEVBQUUsS0FBSztZQUNiLFNBQVMsRUFBRSxHQUFHO1lBQ2QsV0FBVyxFQUFFLElBQUksRUFBRywwQkFBMEI7WUFDOUMsV0FBVyxFQUFFLHNDQUFzQztTQUN0RDtRQUNELFdBQVcsRUFBRTtZQUNULFFBQVEsRUFBRSw0QkFBNEI7WUFDdEMsTUFBTSxFQUFFLEtBQUs7WUFDYixTQUFTLEVBQUUsR0FBRztZQUNkLFdBQVcsRUFBRSxLQUFLLEVBQUcsZ0NBQWdDO1lBQ3JELFdBQVcsRUFBRSx1Q0FBdUM7U0FDdkQ7UUFDRCxNQUFNLEVBQUU7WUFDSixRQUFRLEVBQUUseUJBQXlCO1lBQ25DLE1BQU0sRUFBRSxLQUFLO1lBQ2IsU0FBUyxFQUFFLEdBQUcsRUFBRyw4QkFBOEI7WUFDL0MsV0FBVyxFQUFFLElBQUk7WUFDakIsV0FBVyxFQUFFLGlDQUFpQztTQUNqRDtRQUNELFVBQVUsRUFBRTtZQUNSLFFBQVEsRUFBRSw0QkFBNEI7WUFDdEMsTUFBTSxFQUFFLEtBQUs7WUFDYixTQUFTLEVBQUUsR0FBRyxFQUFHLHFDQUFxQztZQUN0RCxXQUFXLEVBQUUsSUFBSSxFQUFHLGlDQUFpQztZQUNyRCxXQUFXLEVBQUUscURBQXFEO1NBQ3JFO0tBQ0o7SUFDRCxNQUFNLEVBQUU7UUFDSixNQUFNLEVBQUU7WUFDSixRQUFRLEVBQUUsYUFBYTtZQUN2QixNQUFNLEVBQUUsTUFBTTtZQUNkLFNBQVMsRUFBRSxHQUFHO1lBQ2QsV0FBVyxFQUFFLElBQUk7WUFDakIsV0FBVyxFQUFFLGlCQUFpQjtTQUNqQztRQUNELEdBQUcs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 \ No newline at end of file diff --git a/dist-in/constants.js b/dist-in/constants.js new file mode 100644 index 0000000..ea2c6d1 --- /dev/null +++ b/dist-in/constants.js @@ -0,0 +1,2 @@ +export const TEST_POST_ID = '8c1d567a-6909-4e43-b432-bd359bb10fc5'; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29uc3RhbnRzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL2NvbnN0YW50cy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxNQUFNLENBQUMsTUFBTSxZQUFZLEdBQUcsc0NBQXNDLENBQUMifQ== \ No newline at end of file diff --git a/dist-in/endpoints/admin.js b/dist-in/endpoints/admin.js new file mode 100644 index 0000000..f8d0834 --- /dev/null +++ b/dist-in/endpoints/admin.js @@ -0,0 +1,179 @@ +import { createRoute, z } from '@hono/zod-openapi'; +import { logger } from '../commons/logger.js'; +import { getBanList, unbanIP, unbanUser, getViolationStats } from '../middleware/autoBan.js'; +export const restartRoute = createRoute({ + method: 'post', + path: '/api/admin/system/restart', + tags: ['Admin'], + summary: 'Restart the server', + description: 'Exits the process with code 0, relying on systemd to restart it.', + responses: { + 200: { + description: 'Restart initiated', + content: { + 'application/json': { + schema: z.object({ + message: z.string(), + pid: z.number() + }) + } + } + } + } +}); +export const restartHandler = async (c) => { + const pid = process.pid; + // Use a slight delay to allow the response to be sent + setTimeout(() => { + logger.info('Exiting process for restart...'); + process.exit(0); + }, 1000); + return c.json({ + message: 'Server is restarting...', + pid + }); +}; +// Ban List Routes +export const getBanListRoute = createRoute({ + method: 'get', + path: '/api/admin/bans', + tags: ['Admin'], + summary: 'Get current ban list', + description: 'Returns all auto-banned IPs, users, and tokens', + responses: { + 200: { + description: 'Ban list retrieved', + content: { + 'application/json': { + schema: z.object({ + bannedIPs: z.array(z.string()), + bannedUserIds: z.array(z.string()), + bannedTokens: z.array(z.string()) + }) + } + } + } + } +}); +export const getBanListHandler = async (c) => { + const banList = getBanList(); + logger.info({ user: c.get('user') }, 'Admin retrieved ban list'); + return c.json(banList); +}; +export const unbanIPRoute = createRoute({ + method: 'post', + path: '/api/admin/bans/unban-ip', + tags: ['Admin'], + summary: 'Unban an IP address', + description: 'Removes an IP from the auto-ban list', + request: { + body: { + content: { + 'application/json': { + schema: z.object({ + ip: z.string() + }) + } + } + } + }, + responses: { + 200: { + description: 'IP unbanned successfully', + content: { + 'application/json': { + schema: z.object({ + success: z.boolean(), + message: z.string() + }) + } + } + } + } +}); +export const unbanIPHandler = async (c) => { + const { ip } = await c.req.json(); + const success = unbanIP(ip); + logger.info({ user: c.get('user'), ip, success }, 'Admin attempted to unban IP'); + return c.json({ + success, + message: success ? `IP ${ip} has been unbanned` : `IP ${ip} was not found in ban list` + }); +}; +export const unbanUserRoute = createRoute({ + method: 'post', + path: '/api/admin/bans/unban-user', + tags: ['Admin'], + summary: 'Unban a user', + description: 'Removes a user from the auto-ban list', + request: { + body: { + content: { + 'application/json': { + schema: z.object({ + userId: z.string() + }) + } + } + } + }, + responses: { + 200: { + description: 'User unbanned successfully', + content: { + 'application/json': { + schema: z.object({ + success: z.boolean(), + message: z.string() + }) + } + } + } + } +}); +export const unbanUserHandler = async (c) => { + const { userId } = await c.req.json(); + const success = unbanUser(userId); + logger.info({ user: c.get('user'), userId, success }, 'Admin attempted to unban user'); + return c.json({ + success, + message: success ? `User ${userId} has been unbanned` : `User ${userId} was not found in ban list` + }); +}; +export const getViolationStatsRoute = createRoute({ + method: 'get', + path: '/api/admin/bans/violations', + tags: ['Admin'], + summary: 'Get violation statistics', + description: 'Returns current violation tracking data', + responses: { + 200: { + description: 'Violation stats retrieved', + content: { + 'application/json': { + schema: z.object({ + totalViolations: z.number(), + violations: z.array(z.object({ + key: z.string(), + count: z.number(), + firstViolation: z.number(), + lastViolation: z.number() + })) + }) + } + } + } + } +}); +export const getViolationStatsHandler = async (c) => { + const stats = getViolationStats(); + return c.json(stats); +}; +export const registerAdminRoutes = (app) => { + app.openapi(restartRoute, restartHandler); + app.openapi(getBanListRoute, getBanListHandler); + app.openapi(unbanIPRoute, unbanIPHandler); + app.openapi(unbanUserRoute, unbanUserHandler); + app.openapi(getViolationStatsRoute, getViolationStatsHandler); +}; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWRtaW4uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvZW5kcG9pbnRzL2FkbWluLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUNBLE9BQU8sRUFBZSxXQUFXLEVBQUUsQ0FBQyxFQUFFLE1BQU0sbUJBQW1CLENBQUE7QUFDL0QsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLHNCQUFzQixDQUFBO0FBQzdDLE9BQU8sRUFBRSxVQUFVLEVBQUUsT0FBTyxFQUFFLFNBQVMsRUFBRSxpQkFBaUIsRUFBRSxNQUFNLDBCQUEwQixDQUFBO0FBRTVGLE1BQU0sQ0FBQyxNQUFNLFlBQVksR0FBRyxXQUFXLENBQUM7SUFDcEMsTUFBTSxFQUFFLE1BQU07SUFDZCxJQUFJLEVBQUUsMkJBQTJCO0lBQ2pDLElBQUksRUFBRSxDQUFDLE9BQU8sQ0FBQztJQUNmLE9BQU8sRUFBRSxvQkFBb0I7SUFDN0IsV0FBVyxFQUFFLGtFQUFrRTtJQUMvRSxTQUFTLEVBQUU7UUFDUCxHQUFHLEVBQUU7WUFDRCxXQUFXLEVBQUUsbUJBQW1CO1lBQ2hDLE9BQU8sRUFBRTtnQkFDTCxrQkFBa0IsRUFBRTtvQkFDaEIsTUFBTSxFQUFFLENBQUMsQ0FBQyxNQUFNLENBQUM7d0JBQ2IsT0FBTyxFQUFFLENBQUMsQ0FBQyxNQUFNLEVBQUU7d0JBQ25CLEdBQUcsRUFBRSxDQUFDLENBQUMsTUFBTSxFQUFFO3FCQUNsQixDQUFDO2lCQUNMO2FBQ0o7U0FDSjtLQUNKO0NBQ0osQ0FBQyxDQUFBO0FBRUYsTUFBTSxDQUFDLE1BQU0sY0FBYyxHQUFHLEtBQUssRUFBRSxDQUFNLEVBQUUsRUFBRTtJQUMzQyxNQUFNLEdBQUcsR0FBRyxPQUFPLENBQUMsR0FBRyxDQUFBO0lBQ3ZCLHNEQUFzRDtJQUN0RCxVQUFVLENBQUMsR0FBRyxFQUFFO1FBQ1osTUFBTSxDQUFDLElBQUksQ0FBQyxnQ0FBZ0MsQ0FBQyxDQUFBO1FBQzdDLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFD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 \ No newline at end of file diff --git a/dist-in/endpoints/boss.js b/dist-in/endpoints/boss.js new file mode 100644 index 0000000..c7fc88a --- /dev/null +++ b/dist-in/endpoints/boss.js @@ -0,0 +1,296 @@ +import { createRoute, z } from '@hono/zod-openapi'; +import { boss } from '../jobs/boss/client.js'; +import { QUEUE_MOCK_JOB } from '../jobs/boss/workers.js'; +const tags = ['PgBoss']; +export const postBossJobRoute = createRoute({ + method: 'post', + path: '/api/boss/job', + tags, + request: { + body: { + content: { + 'application/json': { + schema: z.object({ + delayMs: z.number().default(100), + shouldFail: z.boolean().default(false), + retryLimit: z.number().optional() + }), + }, + }, + }, + }, + responses: { + 200: { + content: { + 'application/json': { + schema: z.object({ + jobId: z.string().nullable(), + message: z.string() + }), + }, + }, + description: 'PgBoss job started', + }, + 500: { + content: { + 'application/json': { + schema: z.object({ error: z.string() }), + }, + }, + description: 'Server error', + }, + }, +}); +export const postBossJobHandler = async (c) => { + if (!boss) { + // Check if there was an initialization error we can report + const { bossInitError } = await import('../jobs/boss/client.js'); + return c.json({ error: `PgBoss not initialized. Init error: ${bossInitError}` }, 500); + } + const { delayMs, shouldFail, retryLimit } = c.req.valid('json'); + const payload = { delayMs, shouldFail }; + const options = retryLimit !== undefined ? { retryLimit } : {}; + try { + const jobId = await boss.send(QUEUE_MOCK_JOB, payload, options); + return c.json({ jobId, message: 'Job submitted to PgBoss' }, 200); + } + catch (error) { + return c.json({ error: error.message }, 500); + } +}; +export const getBossJobRoute = createRoute({ + method: 'get', + path: '/api/boss/job/{id}', + tags, + request: { + params: z.object({ + id: z.string(), + }), + }, + responses: { + 200: { + content: { + 'application/json': { + schema: z.object({ + id: z.string(), + name: z.string(), + data: z.any(), + state: z.string(), + createdOn: z.string().optional(), + startedOn: z.string().optional(), + completedOn: z.string().optional(), + }), + }, + }, + description: 'Job status', + }, + 404: { + content: { + 'application/json': { + schema: z.object({ error: z.string() }), + }, + }, + description: 'Job not found', + }, + 500: { + content: { + 'application/json': { + schema: z.object({ error: z.string() }), + }, + }, + description: 'Server error', + }, + }, +}); +export const getBossJobHandler = async (c) => { + const { id } = c.req.valid('param'); + // Use pg directly to bypass PostgREST schema permissions + const { Client } = await import('pg'); + const client = new Client({ connectionString: process.env.DATABASE_URL, }); + try { + await client.connect(); + const result = await client.query('SELECT * FROM pgboss.job WHERE id = $1', [id]); + const job = result.rows[0]; + if (!job) { + return c.json({ error: 'Job not found' }, 404); + } + return c.json({ + id: job.id, + name: job.name, + data: job.data, + state: job.state, + createdOn: job.createdon, + startedOn: job.startedon, + completedOn: job.completedon, + output: job.output, + }, 200); + } + catch (error) { + console.error('Error in getBossJobHandler:', error); + return c.json({ error: error.message }, 500); + } + finally { + await client.end().catch(() => { }); + } +}; +export const cancelBossJobRoute = createRoute({ + method: 'post', + path: '/api/boss/job/{id}/cancel', + tags, + request: { + params: z.object({ + id: z.string(), + }), + }, + responses: { + 200: { + content: { + 'application/json': { + schema: z.object({ message: z.string() }), + }, + }, + description: 'Job cancelled', + }, + 500: { + content: { + 'application/json': { + schema: z.object({ error: z.string() }), + }, + }, + description: 'Server error', + }, + }, +}); +export const cancelBossJobHandler = async (c) => { + if (!boss) + return c.json({ error: 'PgBoss not initialized' }, 500); + const { id } = c.req.valid('param'); + try { + await boss.cancel(QUEUE_MOCK_JOB, id); + return c.json({ message: 'Job cancelled' }, 200); + } + catch (error) { + return c.json({ error: error.message }, 500); + } +}; +export const resumeBossJobRoute = createRoute({ + method: 'post', + path: '/api/boss/job/{id}/resume', + tags, + request: { + params: z.object({ + id: z.string(), + }), + }, + responses: { + 200: { + content: { + 'application/json': { + schema: z.object({ message: z.string() }), + }, + }, + description: 'Job resumed', + }, + 500: { + content: { + 'application/json': { + schema: z.object({ error: z.string() }), + }, + }, + description: 'Server error', + }, + }, +}); +export const resumeBossJobHandler = async (c) => { + if (!boss) + return c.json({ error: 'PgBoss not initialized' }, 500); + const { id } = c.req.valid('param'); + try { + await boss.resume(QUEUE_MOCK_JOB, id); + return c.json({ message: 'Job resumed' }, 200); + } + catch (error) { + return c.json({ error: error.message }, 500); + } +}; +export const completeBossJobRoute = createRoute({ + method: 'post', + path: '/api/boss/job/{id}/complete', + tags, + request: { + params: z.object({ + id: z.string(), + }), + }, + responses: { + 200: { + content: { + 'application/json': { + schema: z.object({ message: z.string() }), + }, + }, + description: 'Job completed', + }, + 500: { + content: { + 'application/json': { + schema: z.object({ error: z.string() }), + }, + }, + description: 'Server error', + }, + }, +}); +export const completeBossJobHandler = async (c) => { + if (!boss) + return c.json({ error: 'PgBoss not initialized' }, 500); + const { id } = c.req.valid('param'); + try { + await boss.complete(QUEUE_MOCK_JOB, id); + return c.json({ message: 'Job completed' }, 200); + } + catch (error) { + return c.json({ error: error.message }, 500); + } +}; +export const failBossJobRoute = createRoute({ + method: 'post', + path: '/api/boss/job/{id}/fail', + tags, + request: { + params: z.object({ + id: z.string(), + }), + }, + responses: { + 200: { + content: { + 'application/json': { + schema: z.object({ message: z.string() }), + }, + }, + description: 'Job failed', + }, + 500: { + content: { + 'application/json': { + schema: z.object({ error: z.string() }), + }, + }, + description: 'Server error', + }, + }, +}); +export const failBossJobHandler = async (c) => { + if (!boss) + return c.json({ error: 'PgBoss not initialized' }, 500); + const { id } = c.req.valid('param'); + try { + await boss.fail(QUEUE_MOCK_JOB, id); + return c.json({ message: 'Job failed' }, 200); + } + catch (error) { + return c.json({ error: error.message }, 500); + } +}; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYm9zcy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9lbmRwb2ludHMvYm9zcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsV0FBVyxFQUFlLENBQUMsRUFBRSxNQUFNLG1CQUFtQixDQUFDO0FBRWhFLE9BQU8sRUFBRSxJQUFJLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQUM5QyxPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0seUJBQXlCLENBQUM7QUFHekQsTUFBTSxJQUFJLEdBQUcsQ0FBQyxRQUFRLENBQUMsQ0FBQztBQUV4QixNQUFNLENBQUMsTUFBTSxnQkFBZ0IsR0FBRyxXQUFXLENBQUM7SUFDeEMsTUFBTSxFQUFFLE1BQU07SUFDZCxJQUFJLEVBQUUsZUFBZTtJQUNyQixJQUFJO0lBQ0osT0FBTyxFQUFFO1FBQ0wsSUFBSSxFQUFFO1lBQ0YsT0FBTyxFQUFFO2dCQUNMLGtCQUFrQixFQUFFO29CQUNoQixNQUFNLEVBQUUsQ0FBQyxDQUFDLE1BQU0sQ0FBQzt3QkFDYixPQUFPLEVBQUUsQ0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUM7d0JBQ2hDLFVBQVUsRUFBRSxDQUFDLENBQUMsT0FBTyxFQUFFLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQzt3QkFDdEMsVUFBVSxFQUFFLENBQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxRQUFRLEVBQUU7cUJBQ3BDLENBQUM7aUJBQ0w7YUFDSjtTQUNKO0tBQ0o7SUFDRCxTQUFTLEVBQUU7UUFDUCxHQUFHLEVBQUU7WUFDRCxPQUFPLEVBQUU7Z0JBQ0wsa0JBQWtCLEVBQUU7b0JBQ2hCLE1BQU0sRUFBRSxDQUFDLENBQUMsTUFBTSxDQUFDO3dCQUNiLEtBQUssRUFBRSxDQUFDLENBQUMsTUFBTSxFQUFFLENBQUMsUUFBUSxFQUFFO3dCQUM1QixPQUFPLEVBQUUsQ0FBQyxDQUFDLE1BQU0sRUFBRTtxQkFDdEIsQ0FBQztpQkFDTDth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 \ No newline at end of file diff --git a/dist-in/endpoints/stream.js b/dist-in/endpoints/stream.js new file mode 100644 index 0000000..9466878 --- /dev/null +++ b/dist-in/endpoints/stream.js @@ -0,0 +1,69 @@ +import { createRouteBody } from '../products/serving/routes.js'; +import { streamSSE } from 'hono/streaming'; +import { z } from '@hono/zod-openapi'; +import { appEvents } from '../events.js'; +import { logger } from '../commons/logger.js'; +export const getStreamRoute = createRouteBody('get', '/api/stream', ['System'], 'Stream System Events', 'Subscribe to real-time updates for categories, posts, and pages.', undefined, { + 200: { + description: 'Event Stream', + content: { + 'text/event-stream': { + schema: z.string() + } + } + } +}, true // public +); +// Track active connections +const connectedClients = new Set(); +// Single listener for the entire application +const broadcastAppUpdate = async (event) => { + const payload = JSON.stringify(event); + for (const client of connectedClients) { + try { + await client.stream.writeSSE({ + event: event.kind, + data: payload + }); + } + catch (err) { + logger.error({ err, clientId: client.id }, 'Error broadcasting to stream'); + // Client will be removed by the onAbort handler in the stream handler + } + } +}; +// Subscribe once +appEvents.on('app-update', broadcastAppUpdate); +export const streamHandler = async (c) => { + return streamSSE(c, async (stream) => { + const id = crypto.randomUUID(); + const client = { id, stream }; + connectedClients.add(client); + // Send initial connection message + await stream.writeSSE({ + event: 'connected', + data: JSON.stringify({ message: 'Connected to event stream', clientId: id }) + }); + // Keep connection alive & handle cleanup + let interval; + const heartbeatInterval = parseInt(process.env.STREAM_HEARTBEAT_INTERVAL_MS || '30000', 10); + // Send heartbeat to prevent timeouts + interval = setInterval(async () => { + try { + await stream.writeSSE({ event: 'ping', data: '' }); + } + catch (e) { + // connection likely closed + } + }, heartbeatInterval); + // Wait until the stream is aborted + await new Promise((resolve) => { + stream.onAbort(() => { + connectedClients.delete(client); + clearInterval(interval); + resolve(); + }); + }); + }); +}; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3RyZWFtLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2VuZHBvaW50cy9zdHJlYW0udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLCtCQUErQixDQUFDO0FBRWhFLE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUMzQyxPQUFPLEVBQUUsQ0FBQyxFQUFFLE1BQU0sbUJBQW1CLENBQUM7QUFDdEMsT0FBTyxFQUFFLFNBQVMsRUFBWSxNQUFNLGNBQWMsQ0FBQztBQUNuRCxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sc0JBQXNCLENBQUM7QUFFOUMsTUFBTSxDQUFDLE1BQU0sY0FBYyxHQUFHLGVBQWUsQ0FDekMsS0FBSyxFQUNMLGFBQWEsRUFDYixDQUFDLFFBQVEsQ0FBQyxFQUNWLHNCQUFzQixFQUN0QixrRUFBa0UsRUFDbEUsU0FBUyxFQUNUO0lBQ0ksR0FBRyxFQUFFO1FBQ0QsV0FBVyxFQUFFLGNBQWM7UUFDM0IsT0FBTyxFQUFFO1lBQ0wsbUJBQW1CLEVBQUU7Z0JBQ2pCLE1BQU0sRUFBRSxDQUFDLENBQUMsTUFBTSxFQUFFO2FBQ3JCO1NBQ0o7S0FDSjtDQUNKLEVBQ0QsSUFBSSxDQUFDLFNBQVM7Q0FDakIsQ0FBQztBQUVGLDJCQUEyQjtBQUMzQixNQUFNLGdCQUFnQixHQUFHLElBQUksR0FBRyxFQUc1QixDQUFDO0FBRUwsNkNBQTZDO0FBQzdDLE1BQU0sa0JBQWtCLEdBQUcsS0FBSyxFQUFFLEtBQWUsRUFBRSxFQUFFO0lBQ2pELE1BQU0sT0FBTyxHQUFHLElBQUksQ0FBQyxTQUFTLENBQUMsS0FBSyxDQUFDLENBQUM7SUFDdEMsS0FBSyxNQUFNLE1BQU0sSUFBSSxnQkFBZ0IsRUFBRSxDQUFDO1FBQ3BDLElBQUksQ0FBQztZQUNELE1BQU0sTUFBTSxDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUM7Z0JBQ3pCLEtBQUssRUFBRSxLQUFLLENBQUMsSUFBSTtnQkFDakIsSUFBSSxFQUFFLE9BQU87YUFDaEIsQ0FBQyxDQUFDO1FBQ1AsQ0FBQztRQUFDLE9BQU8sR0FBRyxFQUFFLENBQUM7WUFDWCxNQUFNLENBQUMsS0FBSyxDQUFDLEVBQUUsR0FBRyxFQUFFLFFBQVEsRUFBRSxNQUFNLENBQUMsRUFBRSxFQUFFLEVBQUUsOEJBQThCLENBQUMsQ0FBQztZQUMzRSxzRUFBc0U7UUFDMUUsQ0FBQztJQUNMLENBQUM7QUFDTCxDQUFDLENBQUM7QUFFRixpQkFBaUI7QUFDakIsU0FBUyxDQUFDLEVBQUUsQ0FBQyxZQUFZLEVBQUUsa0JBQWtCLENBQUMsQ0FBQztBQUUvQyxNQUFNLENBQUMsTUFBTSxhQUFhLEdBQUcsS0FBSyxFQUFFLENBQVUsRUFBRSxFQUFFO0lBQzlDLE9BQU8sU0FBUyxDQUFDLENBQUMsRUFBRSxLQUFLLEVBQUUsTUFBTSxFQUFFLEVBQUU7UUFDakMsTUFBTSxFQUFFLEdBQUcsTUFBTSxDQUFDLFVBQVUsRUFBRSxDQUFDO1FBQy9CLE1BQU0sTUFBTSxHQUFHLEVBQUUsRUFBRSxFQUFFLE1BQU0sRUFBRSxDQUFDO1FBRTlCLGdCQUFnQixDQUFDLEdBQUcsQ0FBQyxNQUFNLENBQUMsQ0FBQztRQUM3QixrQ0FBa0M7UUFDbEMsTUFBTSxNQUFNLENBQUMsUUFBUSxDQUFDO1lBQ2xCLEtBQUssRUFBRSxXQUFXO1lBQ2xCLElBQUksRUFBRSxJQUFJLENBQUMsU0FBUyxDQUFDLEVBQUUsT0FBTyxFQUFFLDJCQUEyQixFQUFFLFFBQVEsRUFBRSxFQUFFLEVBQUUsQ0FBQztTQUMvRSxDQUFDLENBQUM7UUFFSCx5Q0FBeUM7UUFDekMsSUFBSSxRQUF3QixDQUFDO1FBQzdCLE1BQU0saUJBQWlCLEdBQUcsUUFBUSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsNEJBQTRCLElBQUksT0FBTyxFQUFFLEVBQUUsQ0FBQyxDQUFDO1FBRTVGLHFDQUFxQztRQUNyQyxRQUFRLEdBQUcsV0FBVyxDQUFDLEtBQUssSUFBSSxFQUFFO1lBQzlCLElBQUksQ0FBQztnQkFDRCxNQUFNLE1BQU0sQ0FBQyxRQUFRLENBQUMsRUFBRSxLQUFLLEVBQUUsTUFBTSxFQUFFLElBQUksRUFBRSxFQUFFLEVBQUUsQ0FBQyxDQUFDO1lBQ3ZELENBQUM7WUFBQyxPQUFPLENBQUMsRUFBRSxDQUFDO2dCQUNULDJCQUEyQjtZQUMvQixDQUFDO1FBQ0wsQ0FBQyxFQUFFLGlCQUFpQixDQUFDLENBQUM7UUFFdEIsbUNBQW1DO1FBQ25DLE1BQU0sSUFBSSxPQUFPLENBQU8sQ0FBQyxPQUFPLEVBQUUsRUFBRTtZQUNoQyxNQUFNLENBQUMsT0FBTyxDQUFDLEdBQUcsRUFBRTtnQkFDaEIsZ0JBQWdCLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxDQUFDO2dCQUNoQyxhQUFhLENBQUMsUUFBUSxDQUFDLENBQUM7Z0JBQ3hCLE9BQU8sRUFBRSxDQUFDO1lBQ2QsQ0FBQyxDQUFDLENBQUM7UUFDUCxDQUFDLENBQUMsQ0FBQztJQUNQLENBQUMsQ0FBQyxDQUFDO0FBQ1AsQ0FBQyxDQUFDIn0= \ No newline at end of file diff --git a/dist-in/events.js b/dist-in/events.js new file mode 100644 index 0000000..8e78f82 --- /dev/null +++ b/dist-in/events.js @@ -0,0 +1,27 @@ +import { EventEmitter } from 'events'; +class AppEvents extends EventEmitter { + static instance; + constructor() { + super(); + // this.setMaxListeners(10); // Default is fine now + } + static getInstance() { + if (!AppEvents.instance) { + AppEvents.instance = new AppEvents(); + } + return AppEvents.instance; + } + emitUpdate(type, action, data, kind = 'cache') { + const event = { + kind, + type, + action, + id: data?.id ?? null, + data, + timestamp: Date.now() + }; + this.emit('app-update', event); + } +} +export const appEvents = AppEvents.getInstance(); +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXZlbnRzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL2V2ZW50cy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sUUFBUSxDQUFDO0FBY3RDLE1BQU0sU0FBVSxTQUFRLFlBQVk7SUFDeEIsTUFBTSxDQUFDLFFBQVEsQ0FBWTtJQUVuQztRQUNJLEtBQUssRUFBRSxDQUFDO1FBQ1IsbURBQW1EO0lBQ3ZELENBQUM7SUFFTSxNQUFNLENBQUMsV0FBVztRQUNyQixJQUFJLENBQUMsU0FBUyxDQUFDLFFBQVEsRUFBRSxDQUFDO1lBQ3RCLFNBQVMsQ0FBQyxRQUFRLEdBQUcsSUFBSSxTQUFTLEVBQUUsQ0FBQztRQUN6QyxDQUFDO1FBQ0QsT0FBTyxTQUFTLENBQUMsUUFBUSxDQUFDO0lBQzlCLENBQUM7SUFFTSxVQUFVLENBQUMsSUFBZSxFQUFFLE1BQXNDLEVBQUUsSUFBUyxFQUFFLE9BQXlCLE9BQU87UUFDbEgsTUFBTSxLQUFLLEdBQWE7WUFDcEIsSUFBSTtZQUNKLElBQUk7WUFDSixNQUFNO1lBQ04sRUFBRSxFQUFFLElBQUksRUFBRSxFQUFFLElBQUksSUFBSTtZQUNwQixJQUFJO1lBQ0osU0FBUyxFQUFFLElBQUksQ0FBQyxHQUFHLEVBQUU7U0FDeEIsQ0FBQztRQUNGLElBQUksQ0FBQyxJQUFJLENBQUMsWUFBWSxFQUFFLEtBQUssQ0FBQyxDQUFDO0lBQ25DLENBQUM7Q0FDSjtBQUVELE1BQU0sQ0FBQyxNQUFNLFNBQVMsR0FBRyxTQUFTLENBQUMsV0FBVyxFQUFFLENBQUMifQ== \ No newline at end of file diff --git a/dist-in/index.js b/dist-in/index.js new file mode 100644 index 0000000..80ab9d6 --- /dev/null +++ b/dist-in/index.js @@ -0,0 +1,221 @@ +import { serve } from '@hono/node-server'; +import { OpenAPIHono } from '@hono/zod-openapi'; +import { swaggerUI } from '@hono/swagger-ui'; +import { Scalar } from '@scalar/hono-api-reference'; +import { cors } from 'hono/cors'; +import dotenv from 'dotenv'; +import path from 'path'; +// Load environment variables based on NODE_ENV +const envFile = process.env.NODE_ENV === 'production' ? '.env.production' : '.env'; +dotenv.config({ path: path.resolve(process.cwd(), envFile) }); +import { logger } from './commons/logger.js'; +import { WebSocketManager } from './commons/websocket.js'; +import { optionalAuthMiddleware, adminMiddleware } from './middleware/auth.js'; +import { analyticsMiddleware } from './middleware/analytics.js'; +import { compress } from 'hono/compress'; +import { secureHeaders } from 'hono/secure-headers'; +// Import endpoints +import { registerProductRoutes, startProducts } from './products/registry.js'; +const app = new OpenAPIHono(); +// Middleware +app.use('/*', cors({ + origin: '*', + allowMethods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'], + allowHeaders: ['Content-Type', 'Authorization', 'x-stainless-os', 'x-stainless-lang', 'x-stainless-arch', 'x-stainless-package-version', 'x-stainless-runtime', 'x-stainless-runtime-version', 'x-stainless-helper-method', 'x-stainless-retry-count'], + exposeHeaders: ['Content-Length', 'X-Cache'], + maxAge: 600, + credentials: true, +})); +// Apply blocklist to all API routes (before rate limiting) +//app.use('/api/*', blocklistMiddleware) +// Apply auto-ban middleware (checks ban.json for auto-banned IPs/users) +// app.use('/api/*', autoBanMiddleware) +// Apply Analytics (tracks requests to file) +app.use('*', analyticsMiddleware); +// Apply Authentication & Authorization +app.use('/api/*', optionalAuthMiddleware); +app.use('/api/*', adminMiddleware); +// app.use('/api/*', apiRateLimiter) +// Apply compression to all API routes +// Apply compression to all routes (API + Static Assets) +app.use('*', compress()); +app.use(secureHeaders({ + crossOriginResourcePolicy: false, + crossOriginOpenerPolicy: false, + crossOriginEmbedderPolicy: false, + xFrameOptions: false, + contentSecurityPolicy: { + frameAncestors: ["'self'", "*"] + } +})); +// Register API routes +import { createLogRoutes, createLogHandlers } from './commons/log-routes-factory.js'; +import { registerAssetRoutes } from './serve-assets.js'; +// System Logs +const { getRoute: sysGetLogRoute, streamRoute: sysStreamLogRoute } = createLogRoutes('System', '/api/logs/system'); +const { getHandler: sysGetLogHandler, streamHandler: sysStreamLogHandler } = createLogHandlers(path.join(process.cwd(), 'app.log')); +app.openapi(sysGetLogRoute, sysGetLogHandler); +app.openapi(sysStreamLogRoute, sysStreamLogHandler); +// Register Product Routes +await registerProductRoutes(app); +// Initialize Products +// Products initialized after PgBoss check below +// API Documentation (Development Only) +const isDevelopment = process.env.NODE_ENV !== 'production'; +if (isDevelopment) { + logger.info('Registering API documentation endpoints (development mode)'); + // Swagger UI + app.doc31('/doc', { + openapi: '3.1.0', + info: { + version: '1.0.0', + title: 'Images API', + }, + components: { + securitySchemes: { + bearerAuth: { + type: 'http', + scheme: 'bearer', + bearerFormat: 'JWT', + }, + }, + }, + security: [ + { + bearerAuth: [], + }, + ], + }); + // Swagger UI + app.get('/ui', swaggerUI({ url: '/doc' })); + // Scalar API Reference + app.get('/reference', Scalar({ + spec: { + url: '/doc', + }, + authentication: { + preferredSecurityScheme: 'bearerAuth', + httpBearer: { + token: process.env.SCALAR_AUTH_TOKEN || '', + }, + }, + })); + // Alternative: API Reference at /api/reference + app.get('/api/reference', Scalar({ + spec: { + url: '/doc', + }, + authentication: { + preferredSecurityScheme: 'bearerAuth', + httpBearer: { + token: process.env.SCALAR_AUTH_TOKEN || '', + } + }, + })); +} +else { + logger.info('API documentation endpoints disabled (production mode)'); +} +import { postBossJobRoute, postBossJobHandler, getBossJobRoute, getBossJobHandler, cancelBossJobRoute, cancelBossJobHandler, resumeBossJobRoute, resumeBossJobHandler, completeBossJobRoute, completeBossJobHandler, failBossJobRoute, failBossJobHandler } from './endpoints/boss.js'; +import { startBoss } from './jobs/boss/client.js'; +import { registerMockWorkers } from './jobs/boss/workers.js'; +// Register PgBoss routes +// @ts-ignore - Route type mismatch +app.openapi(postBossJobRoute, postBossJobHandler); +// @ts-ignore - Route type mismatch +app.openapi(getBossJobRoute, getBossJobHandler); +// @ts-ignore - Route type mismatch +app.openapi(cancelBossJobRoute, cancelBossJobHandler); +// @ts-ignore - Route type mismatch +app.openapi(resumeBossJobRoute, resumeBossJobHandler); +// @ts-ignore - Route type mismatch +app.openapi(completeBossJobRoute, completeBossJobHandler); +// @ts-ignore - Route type mismatch +app.openapi(failBossJobRoute, failBossJobHandler); +// Register Streaming Route +import { getStreamRoute, streamHandler } from './endpoints/stream.js'; +app.openapi(getStreamRoute, streamHandler); +// Register Admin Routes +import { registerAdminRoutes } from './endpoints/admin.js'; +import { AdminEndpointRegistry } from './commons/registry.js'; +// Register restart endpoint as admin-only +AdminEndpointRegistry.register('/api/admin/system/restart', 'POST'); +// Register ban management endpoints as admin-only +AdminEndpointRegistry.register('/api/admin/bans', 'GET'); +AdminEndpointRegistry.register('/api/admin/bans/unban-ip', 'POST'); +AdminEndpointRegistry.register('/api/admin/bans/unban-user', 'POST'); +AdminEndpointRegistry.register('/api/admin/bans/violations', 'GET'); +AdminEndpointRegistry.register('/api/analytics', 'GET'); +AdminEndpointRegistry.register('/api/analytics/stream', 'GET'); +AdminEndpointRegistry.register('/api/analytics', 'DELETE'); +registerAdminRoutes(app); +// Register Asset Routes (Static files, SW, SPA fallback) +// IMPORTANT: This MUST be registered AFTER all API routes to prevent the catch-all from intercepting API calls +registerAssetRoutes(app); +// Initialize PgBoss +// Initialize PgBoss and Products +try { + const boss = await startBoss(); + if (boss) { + registerMockWorkers(); + try { + await startProducts(boss); + } + catch (err) { + logger.error({ err }, 'Failed to init products with Boss'); + } + } + else { + // Fallback: Start products without Boss + logger.info('Starting products without PgBoss'); + await startProducts(); + } +} +catch (err) { + logger.error({ err }, 'Failed to init PgBoss'); + // Fallback: Start products without Boss on error + logger.info('Starting products without PgBoss (after error)'); + await startProducts(); +} +const port = parseInt(process.env.PORT || '3333', 10); +logger.info(`Server is running on port ${port}`); +// Only start the server if not in test mode +if (process.env.NODE_ENV !== 'test' && !process.env.VITEST) { + const server = serve({ + fetch: app.fetch, + port + }); + // Initialize WebSocket Server + if (process.env.ENABLE_WEBSOCKETS === 'true') { + WebSocketManager.getInstance().init(server); + } + let isShuttingDown = false; + const gracefulShutdown = (signal) => { + if (isShuttingDown) { + logger.warn('Already shutting down...'); + return; + } + isShuttingDown = true; + // Force exit after a timeout + const timeout = setTimeout(() => { + logger.warn('Shutdown timed out. Forcing exit.'); + process.exit(1); + }, 5000); + server.close(async (err) => { + if (err) { + logger.error({ err }, 'Error closing HTTP server'); + } + else { + console.log('HTTP server closed.'); + } + clearTimeout(timeout); + console.log('Gracefully shut down.'); + process.exit(err ? 1 : 0); + }); + }; + process.on('SIGINT', () => gracefulShutdown('SIGINT')); + process.on('SIGTERM', () => gracefulShutdown('SIGTERM')); + process.on('SIGBREAK', () => gracefulShutdown('SIGBREAK')); // For Windows +} +export { app }; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBRUEsT0FBTyxFQUFFLEtBQUssRUFBRSxNQUFNLG1CQUFtQixDQUFBO0FBQ3pDLE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSxtQkFBbUIsQ0FBQTtBQUMvQyxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0sa0JBQWtCLENBQUE7QUFDNUMsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLDRCQUE0QixDQUFBO0FBQ25ELE9BQU8sRUFBRSxJQUFJLEVBQUUsTUFBTSxXQUFXLENBQUE7QUFDaEMsT0FBTyxNQUFNLE1BQU0sUUFBUSxDQUFBO0FBQzNCLE9BQU8sSUFBSSxNQUFNLE1BQU0sQ0FBQTtBQUV2QiwrQ0FBK0M7QUFDL0MsTUFBTSxPQUFPLEdBQUcsT0FBTyxDQUFDLEdBQUcsQ0FBQyxRQUFRLEtBQUssWUFBWSxDQUFDLENBQUMsQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFBO0FBQ2xGLE1BQU0sQ0FBQyxNQUFNLENBQUMsRUFBRSxJQUFJLEVBQUUsSUFBSSxDQUFDLE9BQU8sQ0FBQyxPQUFPLENBQUMsR0FBRyxFQUFFLEVBQUUsT0FBTyxDQUFDLEVBQUUsQ0FBQyxDQUFBO0FBRTdELE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQTtBQUM1QyxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQUsxRCxPQUFPLEVBQUUsc0JBQXNCLEVBQUUsZUFBZSxFQUFFLE1BQU0sc0JBQXNCLENBQUE7QUFDOUUsT0FBTyxFQUFFLG1CQUFtQixFQUFFLE1BQU0sMkJBQTJCLENBQUE7QUFHL0QsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLGVBQWUsQ0FBQTtBQUN4QyxPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0scUJBQXFCLENBQUE7QUFFbkQsbUJBQW1CO0FBRW5CLE9BQU8sRUFB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 \ No newline at end of file diff --git a/dist-in/integrations/supabase/schemas.js b/dist-in/integrations/supabase/schemas.js new file mode 100644 index 0000000..0036c62 --- /dev/null +++ b/dist-in/integrations/supabase/schemas.js @@ -0,0 +1,1208 @@ +/* + * ========================================== + * | GENERATED BY SUPAZOD | + * ========================================== + */ +import { z } from "zod"; +export const publicAppPermissionSchema = z.union([ + z.literal("pictures.read"), + z.literal("pictures.create"), + z.literal("pictures.update"), + z.literal("pictures.delete"), + z.literal("collections.read"), + z.literal("collections.create"), + z.literal("collections.update"), + z.literal("collections.delete"), + z.literal("comments.read"), + z.literal("comments.create"), + z.literal("comments.update"), + z.literal("comments.delete"), + z.literal("organization.manage"), +]); +export const publicAppRoleSchema = z.union([ + z.literal("owner"), + z.literal("admin"), + z.literal("member"), + z.literal("viewer"), +]); +export const publicCastKindSchema = z.union([ + z.literal("implicit"), + z.literal("explicit"), + z.literal("lossy"), +]); +export const publicCategoryRelationTypeSchema = z.union([ + z.literal("generalization"), + z.literal("material_usage"), + z.literal("domain"), + z.literal("process_step"), + z.literal("standard"), + z.literal("other"), +]); +export const publicCategoryVisibilitySchema = z.union([ + z.literal("public"), + z.literal("unlisted"), + z.literal("private"), +]); +export const publicCollaboratorRoleSchema = z.union([ + z.literal("viewer"), + z.literal("editor"), + z.literal("owner"), +]); +export const publicLayoutVisibilitySchema = z.union([ + z.literal("public"), + z.literal("private"), + z.literal("listed"), + z.literal("custom"), +]); +export const publicTypeKindSchema = z.union([ + z.literal("primitive"), + z.literal("enum"), + z.literal("flags"), + z.literal("structure"), + z.literal("alias"), + z.literal("field"), +]); +export const publicTypeVisibilitySchema = z.union([ + z.literal("public"), + z.literal("private"), + z.literal("custom"), +]); +export const jsonSchema = z.lazy(() => z + .union([ + z.string(), + z.number(), + z.boolean(), + z.record(z.string(), z.union([jsonSchema, z.undefined()])), + z.array(jsonSchema), +]) + .nullable()); +export const publicCategoriesRowSchema = z.object({ + created_at: z.string(), + description: z.string().nullable(), + id: z.string(), + meta: jsonSchema.nullable(), + name: z.string(), + owner_id: z.string().nullable(), + slug: z.string(), + updated_at: z.string(), + visibility: publicCategoryVisibilitySchema, +}); +export const publicCategoriesInsertSchema = z.object({ + created_at: z.string().optional(), + description: z.string().optional().nullable(), + id: z.string().optional(), + meta: jsonSchema.optional().nullable(), + name: z.string(), + owner_id: z.string().optional().nullable(), + slug: z.string(), + updated_at: z.string().optional(), + visibility: publicCategoryVisibilitySchema.optional(), +}); +export const publicCategoriesUpdateSchema = z.object({ + created_at: z.string().optional(), + description: z.string().optional().nullable(), + id: z.string().optional(), + meta: jsonSchema.optional().nullable(), + name: z.string().optional(), + owner_id: z.string().optional().nullable(), + slug: z.string().optional(), + updated_at: z.string().optional(), + visibility: publicCategoryVisibilitySchema.optional(), +}); +export const publicCategoryRelationsRowSchema = z.object({ + child_category_id: z.string(), + created_at: z.string(), + parent_category_id: z.string(), + relation_type: publicCategoryRelationTypeSchema, +}); +export const publicCategoryRelationsInsertSchema = z.object({ + child_category_id: z.string(), + created_at: z.string().optional(), + parent_category_id: z.string(), + relation_type: publicCategoryRelationTypeSchema, +}); +export const publicCategoryRelationsUpdateSchema = z.object({ + child_category_id: z.string().optional(), + created_at: z.string().optional(), + parent_category_id: z.string().optional(), + relation_type: publicCategoryRelationTypeSchema.optional(), +}); +export const publicCategoryRelationsRelationshipsSchema = z.tuple([ + z.object({ + foreignKeyName: z.literal("category_relations_child_category_id_fkey"), + columns: z.tuple([z.literal("child_category_id")]), + isOneToOne: z.literal(false), + referencedRelation: z.literal("categories"), + referencedColumns: z.tuple([z.literal("id")]), + }), + z.object({ + foreignKeyName: z.literal("category_relations_parent_category_id_fkey"), + columns: z.tuple([z.literal("parent_category_id")]), + isOneToOne: z.literal(false), + referencedRelation: z.literal("categories"), + referencedColumns: z.tuple([z.literal("id")]), + }), +]); +export const publicCollectionPicturesRowSchema = z.object({ + added_at: z.string(), + collection_id: z.string(), + id: z.string(), + picture_id: z.string(), +}); +export const publicCollectionPicturesInsertSchema = z.object({ + added_at: z.string().optional(), + collection_id: z.string(), + id: z.string().optional(), + picture_id: z.string(), +}); +export const publicCollectionPicturesUpdateSchema = z.object({ + added_at: z.string().optional(), + collection_id: z.string().optional(), + id: z.string().optional(), + picture_id: z.string().optional(), +}); +export const publicCollectionPicturesRelationshipsSchema = z.tuple([ + z.object({ + foreignKeyName: z.literal("collection_pictures_collection_id_fkey"), + columns: z.tuple([z.literal("collection_id")]), + isOneToOne: z.literal(false), + referencedRelation: z.literal("collections"), + referencedColumns: z.tuple([z.literal("id")]), + }), + z.object({ + foreignKeyName: z.literal("collection_pictures_picture_id_fkey"), + columns: z.tuple([z.literal("picture_id")]), + isOneToOne: z.literal(false), + referencedRelation: z.literal("pictures"), + referencedColumns: z.tuple([z.literal("id")]), + }), +]); +export const publicCollectionPostsRowSchema = z.object({ + collection_id: z.string(), + created_at: z.string(), + id: z.string(), + post_id: z.string(), +}); +export const publicCollectionPostsInsertSchema = z.object({ + collection_id: z.string(), + created_at: z.string().optional(), + id: z.string().optional(), + post_id: z.string(), +}); +export const publicCollectionPostsUpdateSchema = z.object({ + collection_id: z.string().optional(), + created_at: z.string().optional(), + id: z.string().optional(), + post_id: z.string().optional(), +}); +export const publicCollectionPostsRelationshipsSchema = z.tuple([ + z.object({ + foreignKeyName: z.literal("collection_posts_collection_id_fkey"), + columns: z.tuple([z.literal("collection_id")]), + isOneToOne: z.literal(false), + referencedRelation: z.literal("collections"), + referencedColumns: z.tuple([z.literal("id")]), + }), + z.object({ + foreignKeyName: z.literal("collection_posts_post_id_fkey"), + columns: z.tuple([z.literal("post_id")]), + isOneToOne: z.literal(false), + referencedRelation: z.literal("posts"), + referencedColumns: z.tuple([z.literal("id")]), + }), +]); +export const publicCollectionsRowSchema = z.object({ + content: jsonSchema.nullable(), + created_at: z.string(), + description: z.string().nullable(), + id: z.string(), + is_public: z.boolean(), + layout: jsonSchema.nullable(), + name: z.string(), + slug: z.string(), + updated_at: z.string(), + user_id: z.string(), +}); +export const publicCollectionsInsertSchema = z.object({ + content: jsonSchema.optional().nullable(), + created_at: z.string().optional(), + description: z.string().optional().nullable(), + id: z.string().optional(), + is_public: z.boolean().optional(), + layout: jsonSchema.optional().nullable(), + name: z.string(), + slug: z.string(), + updated_at: z.string().optional(), + user_id: z.string(), +}); +export const publicCollectionsUpdateSchema = z.object({ + content: jsonSchema.optional().nullable(), + created_at: z.string().optional(), + description: z.string().optional().nullable(), + id: z.string().optional(), + is_public: z.boolean().optional(), + layout: jsonSchema.optional().nullable(), + name: z.string().optional(), + slug: z.string().optional(), + updated_at: z.string().optional(), + user_id: z.string().optional(), +}); +export const publicCommentLikesRowSchema = z.object({ + comment_id: z.string(), + created_at: z.string(), + id: z.string(), + user_id: z.string(), +}); +export const publicCommentLikesInsertSchema = z.object({ + comment_id: z.string(), + created_at: z.string().optional(), + id: z.string().optional(), + user_id: z.string(), +}); +export const publicCommentLikesUpdateSchema = z.object({ + comment_id: z.string().optional(), + created_at: z.string().optional(), + id: z.string().optional(), + user_id: z.string().optional(), +}); +export const publicCommentsRowSchema = z.object({ + content: z.string(), + created_at: z.string(), + id: z.string(), + likes_count: z.number().nullable(), + parent_comment_id: z.string().nullable(), + picture_id: z.string(), + updated_at: z.string(), + user_id: z.string(), +}); +export const publicCommentsInsertSchema = z.object({ + content: z.string(), + created_at: z.string().optional(), + id: z.string().optional(), + likes_count: z.number().optional().nullable(), + parent_comment_id: z.string().optional().nullable(), + picture_id: z.string(), + updated_at: z.string().optional(), + user_id: z.string(), +}); +export const publicCommentsUpdateSchema = z.object({ + content: z.string().optional(), + created_at: z.string().optional(), + id: z.string().optional(), + likes_count: z.number().optional().nullable(), + parent_comment_id: z.string().optional().nullable(), + picture_id: z.string().optional(), + updated_at: z.string().optional(), + user_id: z.string().optional(), +}); +export const publicCommentsRelationshipsSchema = z.tuple([ + z.object({ + foreignKeyName: z.literal("comments_parent_fk"), + columns: z.tuple([z.literal("parent_comment_id")]), + isOneToOne: z.literal(false), + referencedRelation: z.literal("comments"), + referencedColumns: z.tuple([z.literal("id")]), + }), +]); +export const publicContextDefinitionsRowSchema = z.object({ + created_at: z.string().nullable(), + default_filters: jsonSchema, + default_templates: jsonSchema, + description: z.string().nullable(), + display_name: z.string(), + icon: z.string().nullable(), + id: z.string(), + is_active: z.boolean().nullable(), + name: z.string(), + updated_at: z.string().nullable(), +}); +export const publicContextDefinitionsInsertSchema = z.object({ + created_at: z.string().optional().nullable(), + default_filters: jsonSchema.optional(), + default_templates: jsonSchema.optional(), + description: z.string().optional().nullable(), + display_name: z.string(), + icon: z.string().optional().nullable(), + id: z.string().optional(), + is_active: z.boolean().optional().nullable(), + name: z.string(), + updated_at: z.string().optional().nullable(), +}); +export const publicContextDefinitionsUpdateSchema = z.object({ + created_at: z.string().optional().nullable(), + default_filters: jsonSchema.optional(), + default_templates: jsonSchema.optional(), + description: z.string().optional().nullable(), + display_name: z.string().optional(), + icon: z.string().optional().nullable(), + id: z.string().optional(), + is_active: z.boolean().optional().nullable(), + name: z.string().optional(), + updated_at: z.string().optional().nullable(), +}); +export const publicFilterUsageLogsRowSchema = z.object({ + context: z.string(), + created_at: z.string().nullable(), + error_message: z.string().nullable(), + filters_applied: z.array(z.string()).nullable(), + id: z.string(), + input_length: z.number(), + model: z.string(), + output_length: z.number(), + processing_time_ms: z.number(), + provider: z.string(), + success: z.boolean(), + template_id: z.string().nullable(), + user_id: z.string().nullable(), +}); +export const publicFilterUsageLogsInsertSchema = z.object({ + context: z.string(), + created_at: z.string().optional().nullable(), + error_message: z.string().optional().nullable(), + filters_applied: z.array(z.string()).optional().nullable(), + id: z.string().optional(), + input_length: z.number(), + model: z.string(), + output_length: z.number(), + processing_time_ms: z.number(), + provider: z.string(), + success: z.boolean(), + template_id: z.string().optional().nullable(), + user_id: z.string().optional().nullable(), +}); +export const publicFilterUsageLogsUpdateSchema = z.object({ + context: z.string().optional(), + created_at: z.string().optional().nullable(), + error_message: z.string().optional().nullable(), + filters_applied: z.array(z.string()).optional().nullable(), + id: z.string().optional(), + input_length: z.number().optional(), + model: z.string().optional(), + output_length: z.number().optional(), + processing_time_ms: z.number().optional(), + provider: z.string().optional(), + success: z.boolean().optional(), + template_id: z.string().optional().nullable(), + user_id: z.string().optional().nullable(), +}); +export const publicFilterUsageLogsRelationshipsSchema = z.tuple([ + z.object({ + foreignKeyName: z.literal("filter_usage_logs_template_id_fkey"), + columns: z.tuple([z.literal("template_id")]), + isOneToOne: z.literal(false), + referencedRelation: z.literal("user_templates"), + referencedColumns: z.tuple([z.literal("id")]), + }), +]); +export const publicLayoutsRowSchema = z.object({ + created_at: z.string(), + id: z.string(), + is_predefined: z.boolean().nullable(), + layout_json: jsonSchema, + meta: jsonSchema.nullable(), + name: z.string(), + owner_id: z.string(), + type: z.string().nullable(), + updated_at: z.string(), + visibility: publicLayoutVisibilitySchema, +}); +export const publicLayoutsInsertSchema = z.object({ + created_at: z.string().optional(), + id: z.string().optional(), + is_predefined: z.boolean().optional().nullable(), + layout_json: jsonSchema, + meta: jsonSchema.optional().nullable(), + name: z.string(), + owner_id: z.string(), + type: z.string().optional().nullable(), + updated_at: z.string().optional(), + visibility: publicLayoutVisibilitySchema.optional(), +}); +export const publicLayoutsUpdateSchema = z.object({ + created_at: z.string().optional(), + id: z.string().optional(), + is_predefined: z.boolean().optional().nullable(), + layout_json: jsonSchema.optional(), + meta: jsonSchema.optional().nullable(), + name: z.string().optional(), + owner_id: z.string().optional(), + type: z.string().optional().nullable(), + updated_at: z.string().optional(), + visibility: publicLayoutVisibilitySchema.optional(), +}); +export const publicLikesRowSchema = z.object({ + created_at: z.string(), + id: z.string(), + picture_id: z.string(), + user_id: z.string(), +}); +export const publicLikesInsertSchema = z.object({ + created_at: z.string().optional(), + id: z.string().optional(), + picture_id: z.string(), + user_id: z.string(), +}); +export const publicLikesUpdateSchema = z.object({ + created_at: z.string().optional(), + id: z.string().optional(), + picture_id: z.string().optional(), + user_id: z.string().optional(), +}); +export const publicOrganizationsRowSchema = z.object({ + created_at: z.string(), + id: z.string(), + name: z.string(), + slug: z.string(), + updated_at: z.string(), +}); +export const publicOrganizationsInsertSchema = z.object({ + created_at: z.string().optional(), + id: z.string().optional(), + name: z.string(), + slug: z.string(), + updated_at: z.string().optional(), +}); +export const publicOrganizationsUpdateSchema = z.object({ + created_at: z.string().optional(), + id: z.string().optional(), + name: z.string().optional(), + slug: z.string().optional(), + updated_at: z.string().optional(), +}); +export const publicPageCollaboratorsRowSchema = z.object({ + created_at: z.string(), + id: z.string(), + page_id: z.string(), + role: publicCollaboratorRoleSchema, + user_id: z.string(), +}); +export const publicPageCollaboratorsInsertSchema = z.object({ + created_at: z.string().optional(), + id: z.string().optional(), + page_id: z.string(), + role: publicCollaboratorRoleSchema.optional(), + user_id: z.string(), +}); +export const publicPageCollaboratorsUpdateSchema = z.object({ + created_at: z.string().optional(), + id: z.string().optional(), + page_id: z.string().optional(), + role: publicCollaboratorRoleSchema.optional(), + user_id: z.string().optional(), +}); +export const publicPageCollaboratorsRelationshipsSchema = z.tuple([ + z.object({ + foreignKeyName: z.literal("page_collaborators_page_id_fkey"), + columns: z.tuple([z.literal("page_id")]), + isOneToOne: z.literal(false), + referencedRelation: z.literal("pages"), + referencedColumns: z.tuple([z.literal("id")]), + }), +]); +export const publicPagesRowSchema = z.object({ + content: jsonSchema.nullable(), + created_at: z.string(), + id: z.string(), + is_public: z.boolean(), + meta: jsonSchema.nullable(), + owner: z.string(), + parent: z.string().nullable(), + slug: z.string(), + tags: z.array(z.string()).nullable(), + title: z.string(), + type: z.string().nullable(), + updated_at: z.string(), + visible: z.boolean(), +}); +export const publicPagesInsertSchema = z.object({ + content: jsonSchema.optional().nullable(), + created_at: z.string().optional(), + id: z.string().optional(), + is_public: z.boolean().optional(), + meta: jsonSchema.optional().nullable(), + owner: z.string(), + parent: z.string().optional().nullable(), + slug: z.string(), + tags: z.array(z.string()).optional().nullable(), + title: z.string(), + type: z.string().optional().nullable(), + updated_at: z.string().optional(), + visible: z.boolean().optional(), +}); +export const publicPagesUpdateSchema = z.object({ + content: jsonSchema.optional().nullable(), + created_at: z.string().optional(), + id: z.string().optional(), + is_public: z.boolean().optional(), + meta: jsonSchema.optional().nullable(), + owner: z.string().optional(), + parent: z.string().optional().nullable(), + slug: z.string().optional(), + tags: z.array(z.string()).optional().nullable(), + title: z.string().optional(), + type: z.string().optional().nullable(), + updated_at: z.string().optional(), + visible: z.boolean().optional(), +}); +export const publicPagesRelationshipsSchema = z.tuple([ + z.object({ + foreignKeyName: z.literal("pages_parent_fkey"), + columns: z.tuple([z.literal("parent")]), + isOneToOne: z.literal(false), + referencedRelation: z.literal("pages"), + referencedColumns: z.tuple([z.literal("id")]), + }), +]); +export const publicPicturesRowSchema = z.object({ + created_at: z.string(), + description: z.string().nullable(), + flags: z.array(z.string()).nullable(), + id: z.string(), + image_url: z.string(), + is_selected: z.boolean(), + likes_count: z.number().nullable(), + meta: jsonSchema.nullable(), + organization_id: z.string().nullable(), + parent_id: z.string().nullable(), + position: z.number().nullable(), + post_id: z.string().nullable(), + tags: z.array(z.string()).nullable(), + thumbnail_url: z.string().nullable(), + title: z.string(), + type: z.string().nullable(), + updated_at: z.string(), + user_id: z.string(), + visible: z.boolean(), +}); +export const publicPicturesInsertSchema = z.object({ + created_at: z.string().optional(), + description: z.string().optional().nullable(), + flags: z.array(z.string()).optional().nullable(), + id: z.string().optional(), + image_url: z.string(), + is_selected: z.boolean().optional(), + likes_count: z.number().optional().nullable(), + meta: jsonSchema.optional().nullable(), + organization_id: z.string().optional().nullable(), + parent_id: z.string().optional().nullable(), + position: z.number().optional().nullable(), + post_id: z.string().optional().nullable(), + tags: z.array(z.string()).optional().nullable(), + thumbnail_url: z.string().optional().nullable(), + title: z.string(), + type: z.string().optional().nullable(), + updated_at: z.string().optional(), + user_id: z.string(), + visible: z.boolean().optional(), +}); +export const publicPicturesUpdateSchema = z.object({ + created_at: z.string().optional(), + description: z.string().optional().nullable(), + flags: z.array(z.string()).optional().nullable(), + id: z.string().optional(), + image_url: z.string().optional(), + is_selected: z.boolean().optional(), + likes_count: z.number().optional().nullable(), + meta: jsonSchema.optional().nullable(), + organization_id: z.string().optional().nullable(), + parent_id: z.string().optional().nullable(), + position: z.number().optional().nullable(), + post_id: z.string().optional().nullable(), + tags: z.array(z.string()).optional().nullable(), + thumbnail_url: z.string().optional().nullable(), + title: z.string().optional(), + type: z.string().optional().nullable(), + updated_at: z.string().optional(), + user_id: z.string().optional(), + visible: z.boolean().optional(), +}); +export const publicPicturesRelationshipsSchema = z.tuple([ + z.object({ + foreignKeyName: z.literal("pictures_organization_id_fkey"), + columns: z.tuple([z.literal("organization_id")]), + isOneToOne: z.literal(false), + referencedRelation: z.literal("organizations"), + referencedColumns: z.tuple([z.literal("id")]), + }), + z.object({ + foreignKeyName: z.literal("pictures_parent_id_fkey"), + columns: z.tuple([z.literal("parent_id")]), + isOneToOne: z.literal(false), + referencedRelation: z.literal("pictures"), + referencedColumns: z.tuple([z.literal("id")]), + }), + z.object({ + foreignKeyName: z.literal("pictures_post_id_fkey"), + columns: z.tuple([z.literal("post_id")]), + isOneToOne: z.literal(false), + referencedRelation: z.literal("posts"), + referencedColumns: z.tuple([z.literal("id")]), + }), +]); +export const publicPostsRowSchema = z.object({ + created_at: z.string().nullable(), + description: z.string().nullable(), + id: z.string(), + meta: jsonSchema.nullable(), + settings: jsonSchema.nullable(), + title: z.string(), + updated_at: z.string().nullable(), + user_id: z.string(), +}); +export const publicPostsInsertSchema = z.object({ + created_at: z.string().optional().nullable(), + description: z.string().optional().nullable(), + id: z.string().optional(), + meta: jsonSchema.optional().nullable(), + settings: jsonSchema.optional().nullable(), + title: z.string(), + updated_at: z.string().optional().nullable(), + user_id: z.string(), +}); +export const publicPostsUpdateSchema = z.object({ + created_at: z.string().optional().nullable(), + description: z.string().optional().nullable(), + id: z.string().optional(), + meta: jsonSchema.optional().nullable(), + settings: jsonSchema.optional().nullable(), + title: z.string().optional(), + updated_at: z.string().optional().nullable(), + user_id: z.string().optional(), +}); +export const publicProfilesRowSchema = z.object({ + aimlapi_api_key: z.string().nullable(), + avatar_url: z.string().nullable(), + bio: z.string().nullable(), + bria_api_key: z.string().nullable(), + created_at: z.string(), + display_name: z.string().nullable(), + google_api_key: z.string().nullable(), + huggingface_api_key: z.string().nullable(), + id: z.string(), + openai_api_key: z.string().nullable(), + pages: jsonSchema.nullable(), + replicate_api_key: z.string().nullable(), + settings: jsonSchema.nullable(), + updated_at: z.string(), + user_id: z.string(), + username: z.string().nullable(), +}); +export const publicProfilesInsertSchema = z.object({ + aimlapi_api_key: z.string().optional().nullable(), + avatar_url: z.string().optional().nullable(), + bio: z.string().optional().nullable(), + bria_api_key: z.string().optional().nullable(), + created_at: z.string().optional(), + display_name: z.string().optional().nullable(), + google_api_key: z.string().optional().nullable(), + huggingface_api_key: z.string().optional().nullable(), + id: z.string().optional(), + openai_api_key: z.string().optional().nullable(), + pages: jsonSchema.optional().nullable(), + replicate_api_key: z.string().optional().nullable(), + settings: jsonSchema.optional().nullable(), + updated_at: z.string().optional(), + user_id: z.string(), + username: z.string().optional().nullable(), +}); +export const publicProfilesUpdateSchema = z.object({ + aimlapi_api_key: z.string().optional().nullable(), + avatar_url: z.string().optional().nullable(), + bio: z.string().optional().nullable(), + bria_api_key: z.string().optional().nullable(), + created_at: z.string().optional(), + display_name: z.string().optional().nullable(), + google_api_key: z.string().optional().nullable(), + huggingface_api_key: z.string().optional().nullable(), + id: z.string().optional(), + openai_api_key: z.string().optional().nullable(), + pages: jsonSchema.optional().nullable(), + replicate_api_key: z.string().optional().nullable(), + settings: jsonSchema.optional().nullable(), + updated_at: z.string().optional(), + user_id: z.string().optional(), + username: z.string().optional().nullable(), +}); +export const publicProviderConfigsRowSchema = z.object({ + base_url: z.string(), + created_at: z.string().nullable(), + display_name: z.string(), + id: z.string(), + is_active: z.boolean().nullable(), + models: jsonSchema, + name: z.string(), + rate_limits: jsonSchema.nullable(), + settings: jsonSchema.nullable(), + updated_at: z.string().nullable(), + user_id: z.string().nullable(), +}); +export const publicProviderConfigsInsertSchema = z.object({ + base_url: z.string(), + created_at: z.string().optional().nullable(), + display_name: z.string(), + id: z.string().optional(), + is_active: z.boolean().optional().nullable(), + models: jsonSchema.optional(), + name: z.string(), + rate_limits: jsonSchema.optional().nullable(), + settings: jsonSchema.optional().nullable(), + updated_at: z.string().optional().nullable(), + user_id: z.string().optional().nullable(), +}); +export const publicProviderConfigsUpdateSchema = z.object({ + base_url: z.string().optional(), + created_at: z.string().optional().nullable(), + display_name: z.string().optional(), + id: z.string().optional(), + is_active: z.boolean().optional().nullable(), + models: jsonSchema.optional(), + name: z.string().optional(), + rate_limits: jsonSchema.optional().nullable(), + settings: jsonSchema.optional().nullable(), + updated_at: z.string().optional().nullable(), + user_id: z.string().optional().nullable(), +}); +export const publicRolePermissionsRowSchema = z.object({ + created_at: z.string(), + id: z.string(), + permission: publicAppPermissionSchema, + role: publicAppRoleSchema, +}); +export const publicRolePermissionsInsertSchema = z.object({ + created_at: z.string().optional(), + id: z.string().optional(), + permission: publicAppPermissionSchema, + role: publicAppRoleSchema, +}); +export const publicRolePermissionsUpdateSchema = z.object({ + created_at: z.string().optional(), + id: z.string().optional(), + permission: publicAppPermissionSchema.optional(), + role: publicAppRoleSchema.optional(), +}); +export const publicTypeCastsRowSchema = z.object({ + cast_kind: publicCastKindSchema, + description: z.string().nullable(), + from_type_id: z.string(), + to_type_id: z.string(), +}); +export const publicTypeCastsInsertSchema = z.object({ + cast_kind: publicCastKindSchema, + description: z.string().optional().nullable(), + from_type_id: z.string(), + to_type_id: z.string(), +}); +export const publicTypeCastsUpdateSchema = z.object({ + cast_kind: publicCastKindSchema.optional(), + description: z.string().optional().nullable(), + from_type_id: z.string().optional(), + to_type_id: z.string().optional(), +}); +export const publicTypeCastsRelationshipsSchema = z.tuple([ + z.object({ + foreignKeyName: z.literal("type_casts_from_type_id_fkey"), + columns: z.tuple([z.literal("from_type_id")]), + isOneToOne: z.literal(false), + referencedRelation: z.literal("types"), + referencedColumns: z.tuple([z.literal("id")]), + }), + z.object({ + foreignKeyName: z.literal("type_casts_to_type_id_fkey"), + columns: z.tuple([z.literal("to_type_id")]), + isOneToOne: z.literal(false), + referencedRelation: z.literal("types"), + referencedColumns: z.tuple([z.literal("id")]), + }), +]); +export const publicTypeEnumValuesRowSchema = z.object({ + id: z.string(), + label: z.string(), + order: z.number(), + type_id: z.string(), + value: z.string(), +}); +export const publicTypeEnumValuesInsertSchema = z.object({ + id: z.string().optional(), + label: z.string(), + order: z.number().optional(), + type_id: z.string(), + value: z.string(), +}); +export const publicTypeEnumValuesUpdateSchema = z.object({ + id: z.string().optional(), + label: z.string().optional(), + order: z.number().optional(), + type_id: z.string().optional(), + value: z.string().optional(), +}); +export const publicTypeEnumValuesRelationshipsSchema = z.tuple([ + z.object({ + foreignKeyName: z.literal("type_enum_values_type_id_fkey"), + columns: z.tuple([z.literal("type_id")]), + isOneToOne: z.literal(false), + referencedRelation: z.literal("types"), + referencedColumns: z.tuple([z.literal("id")]), + }), +]); +export const publicTypeFlagValuesRowSchema = z.object({ + bit: z.number(), + id: z.string(), + name: z.string(), + type_id: z.string(), +}); +export const publicTypeFlagValuesInsertSchema = z.object({ + bit: z.number(), + id: z.string().optional(), + name: z.string(), + type_id: z.string(), +}); +export const publicTypeFlagValuesUpdateSchema = z.object({ + bit: z.number().optional(), + id: z.string().optional(), + name: z.string().optional(), + type_id: z.string().optional(), +}); +export const publicTypeFlagValuesRelationshipsSchema = z.tuple([ + z.object({ + foreignKeyName: z.literal("type_flag_values_type_id_fkey"), + columns: z.tuple([z.literal("type_id")]), + isOneToOne: z.literal(false), + referencedRelation: z.literal("types"), + referencedColumns: z.tuple([z.literal("id")]), + }), +]); +export const publicTypeStructureFieldsRowSchema = z.object({ + default_value: jsonSchema.nullable(), + field_name: z.string(), + field_type_id: z.string(), + id: z.string(), + order: z.number(), + required: z.boolean(), + structure_type_id: z.string(), +}); +export const publicTypeStructureFieldsInsertSchema = z.object({ + default_value: jsonSchema.optional().nullable(), + field_name: z.string(), + field_type_id: z.string(), + id: z.string().optional(), + order: z.number().optional(), + required: z.boolean().optional(), + structure_type_id: z.string(), +}); +export const publicTypeStructureFieldsUpdateSchema = z.object({ + default_value: jsonSchema.optional().nullable(), + field_name: z.string().optional(), + field_type_id: z.string().optional(), + id: z.string().optional(), + order: z.number().optional(), + required: z.boolean().optional(), + structure_type_id: z.string().optional(), +}); +export const publicTypeStructureFieldsRelationshipsSchema = z.tuple([ + z.object({ + foreignKeyName: z.literal("type_structure_fields_field_type_id_fkey"), + columns: z.tuple([z.literal("field_type_id")]), + isOneToOne: z.literal(false), + referencedRelation: z.literal("types"), + referencedColumns: z.tuple([z.literal("id")]), + }), + z.object({ + foreignKeyName: z.literal("type_structure_fields_structure_type_id_fkey"), + columns: z.tuple([z.literal("structure_type_id")]), + isOneToOne: z.literal(false), + referencedRelation: z.literal("types"), + referencedColumns: z.tuple([z.literal("id")]), + }), +]); +export const publicTypesRowSchema = z.object({ + created_at: z.string(), + description: z.string().nullable(), + id: z.string(), + json_schema: jsonSchema.nullable(), + kind: publicTypeKindSchema, + meta: jsonSchema.nullable(), + name: z.string(), + owner_id: z.string().nullable(), + parent_type_id: z.string().nullable(), + settings: jsonSchema.nullable(), + updated_at: z.string(), + visibility: publicTypeVisibilitySchema, +}); +export const publicTypesInsertSchema = z.object({ + created_at: z.string().optional(), + description: z.string().optional().nullable(), + id: z.string().optional(), + json_schema: jsonSchema.optional().nullable(), + kind: publicTypeKindSchema, + meta: jsonSchema.optional().nullable(), + name: z.string(), + owner_id: z.string().optional().nullable(), + parent_type_id: z.string().optional().nullable(), + settings: jsonSchema.optional().nullable(), + updated_at: z.string().optional(), + visibility: publicTypeVisibilitySchema.optional(), +}); +export const publicTypesUpdateSchema = z.object({ + created_at: z.string().optional(), + description: z.string().optional().nullable(), + id: z.string().optional(), + json_schema: jsonSchema.optional().nullable(), + kind: publicTypeKindSchema.optional(), + meta: jsonSchema.optional().nullable(), + name: z.string().optional(), + owner_id: z.string().optional().nullable(), + parent_type_id: z.string().optional().nullable(), + settings: jsonSchema.optional().nullable(), + updated_at: z.string().optional(), + visibility: publicTypeVisibilitySchema.optional(), +}); +export const publicTypesRelationshipsSchema = z.tuple([ + z.object({ + foreignKeyName: z.literal("types_parent_type_id_fkey"), + columns: z.tuple([z.literal("parent_type_id")]), + isOneToOne: z.literal(false), + referencedRelation: z.literal("types"), + referencedColumns: z.tuple([z.literal("id")]), + }), +]); +export const publicUserFilterConfigsRowSchema = z.object({ + context: z.string(), + created_at: z.string().nullable(), + custom_filters: jsonSchema.nullable(), + default_templates: z.array(z.string()).nullable(), + id: z.string(), + is_default: z.boolean().nullable(), + model: z.string(), + provider: z.string(), + updated_at: z.string().nullable(), + user_id: z.string().nullable(), + variables: jsonSchema.nullable(), +}); +export const publicUserFilterConfigsInsertSchema = z.object({ + context: z.string(), + created_at: z.string().optional().nullable(), + custom_filters: jsonSchema.optional().nullable(), + default_templates: z.array(z.string()).optional().nullable(), + id: z.string().optional(), + is_default: z.boolean().optional().nullable(), + model: z.string().optional(), + provider: z.string().optional(), + updated_at: z.string().optional().nullable(), + user_id: z.string().optional().nullable(), + variables: jsonSchema.optional().nullable(), +}); +export const publicUserFilterConfigsUpdateSchema = z.object({ + context: z.string().optional(), + created_at: z.string().optional().nullable(), + custom_filters: jsonSchema.optional().nullable(), + default_templates: z.array(z.string()).optional().nullable(), + id: z.string().optional(), + is_default: z.boolean().optional().nullable(), + model: z.string().optional(), + provider: z.string().optional(), + updated_at: z.string().optional().nullable(), + user_id: z.string().optional().nullable(), + variables: jsonSchema.optional().nullable(), +}); +export const publicUserOrganizationsRowSchema = z.object({ + created_at: z.string(), + id: z.string(), + organization_id: z.string(), + role: z.string(), + updated_at: z.string(), + user_id: z.string(), +}); +export const publicUserOrganizationsInsertSchema = z.object({ + created_at: z.string().optional(), + id: z.string().optional(), + organization_id: z.string(), + role: z.string().optional(), + updated_at: z.string().optional(), + user_id: z.string(), +}); +export const publicUserOrganizationsUpdateSchema = z.object({ + created_at: z.string().optional(), + id: z.string().optional(), + organization_id: z.string().optional(), + role: z.string().optional(), + updated_at: z.string().optional(), + user_id: z.string().optional(), +}); +export const publicUserOrganizationsRelationshipsSchema = z.tuple([ + z.object({ + foreignKeyName: z.literal("user_organizations_organization_id_fkey"), + columns: z.tuple([z.literal("organization_id")]), + isOneToOne: z.literal(false), + referencedRelation: z.literal("organizations"), + referencedColumns: z.tuple([z.literal("id")]), + }), +]); +export const publicUserRolesRowSchema = z.object({ + created_at: z.string(), + id: z.string(), + organization_id: z.string().nullable(), + role: publicAppRoleSchema, + updated_at: z.string(), + user_id: z.string(), +}); +export const publicUserRolesInsertSchema = z.object({ + created_at: z.string().optional(), + id: z.string().optional(), + organization_id: z.string().optional().nullable(), + role: publicAppRoleSchema, + updated_at: z.string().optional(), + user_id: z.string(), +}); +export const publicUserRolesUpdateSchema = z.object({ + created_at: z.string().optional(), + id: z.string().optional(), + organization_id: z.string().optional().nullable(), + role: publicAppRoleSchema.optional(), + updated_at: z.string().optional(), + user_id: z.string().optional(), +}); +export const publicUserRolesRelationshipsSchema = z.tuple([ + z.object({ + foreignKeyName: z.literal("user_roles_user_id_fkey"), + columns: z.tuple([z.literal("user_id")]), + isOneToOne: z.literal(false), + referencedRelation: z.literal("profiles"), + referencedColumns: z.tuple([z.literal("user_id")]), + }), +]); +export const publicUserSecretsRowSchema = z.object({ + aimlapi_api_key: z.string().nullable(), + bria_api_key: z.string().nullable(), + created_at: z.string(), + google_api_key: z.string().nullable(), + huggingface_api_key: z.string().nullable(), + is_admin: z.boolean().nullable(), + openai_api_key: z.string().nullable(), + replicate_api_key: z.string().nullable(), + settings: jsonSchema.nullable(), + updated_at: z.string(), + user_id: z.string(), +}); +export const publicUserSecretsInsertSchema = z.object({ + aimlapi_api_key: z.string().optional().nullable(), + bria_api_key: z.string().optional().nullable(), + created_at: z.string().optional(), + google_api_key: z.string().optional().nullable(), + huggingface_api_key: z.string().optional().nullable(), + is_admin: z.boolean().optional().nullable(), + openai_api_key: z.string().optional().nullable(), + replicate_api_key: z.string().optional().nullable(), + settings: jsonSchema.optional().nullable(), + updated_at: z.string().optional(), + user_id: z.string(), +}); +export const publicUserSecretsUpdateSchema = z.object({ + aimlapi_api_key: z.string().optional().nullable(), + bria_api_key: z.string().optional().nullable(), + created_at: z.string().optional(), + google_api_key: z.string().optional().nullable(), + huggingface_api_key: z.string().optional().nullable(), + is_admin: z.boolean().optional().nullable(), + openai_api_key: z.string().optional().nullable(), + replicate_api_key: z.string().optional().nullable(), + settings: jsonSchema.optional().nullable(), + updated_at: z.string().optional(), + user_id: z.string().optional(), +}); +export const publicUserTemplatesRowSchema = z.object({ + context: z.string(), + created_at: z.string().nullable(), + description: z.string().nullable(), + filters: z.array(z.string()).nullable(), + format: z.string().nullable(), + id: z.string(), + is_public: z.boolean().nullable(), + model: z.string(), + name: z.string(), + prompt: z.string(), + provider: z.string(), + updated_at: z.string().nullable(), + usage_count: z.number().nullable(), + user_id: z.string().nullable(), +}); +export const publicUserTemplatesInsertSchema = z.object({ + context: z.string(), + created_at: z.string().optional().nullable(), + description: z.string().optional().nullable(), + filters: z.array(z.string()).optional().nullable(), + format: z.string().optional().nullable(), + id: z.string().optional(), + is_public: z.boolean().optional().nullable(), + model: z.string().optional(), + name: z.string(), + prompt: z.string(), + provider: z.string().optional(), + updated_at: z.string().optional().nullable(), + usage_count: z.number().optional().nullable(), + user_id: z.string().optional().nullable(), +}); +export const publicUserTemplatesUpdateSchema = z.object({ + context: z.string().optional(), + created_at: z.string().optional().nullable(), + description: z.string().optional().nullable(), + filters: z.array(z.string()).optional().nullable(), + format: z.string().optional().nullable(), + id: z.string().optional(), + is_public: z.boolean().optional().nullable(), + model: z.string().optional(), + name: z.string().optional(), + prompt: z.string().optional(), + provider: z.string().optional(), + updated_at: z.string().optional().nullable(), + usage_count: z.number().optional().nullable(), + user_id: z.string().optional().nullable(), +}); +export const publicWizardSessionsRowSchema = z.object({ + created_at: z.string(), + generated_image_url: z.string().nullable(), + id: z.string(), + input_images: z.array(z.string()).nullable(), + prompt: z.string(), + status: z.string(), + updated_at: z.string(), + user_id: z.string(), +}); +export const publicWizardSessionsInsertSchema = z.object({ + created_at: z.string().optional(), + generated_image_url: z.string().optional().nullable(), + id: z.string().optional(), + input_images: z.array(z.string()).optional().nullable(), + prompt: z.string().optional(), + status: z.string().optional(), + updated_at: z.string().optional(), + user_id: z.string(), +}); +export const publicWizardSessionsUpdateSchema = z.object({ + created_at: z.string().optional(), + generated_image_url: z.string().optional().nullable(), + id: z.string().optional(), + input_images: z.array(z.string()).optional().nullable(), + prompt: z.string().optional(), + status: z.string().optional(), + updated_at: z.string().optional(), + user_id: z.string().optional(), +}); +export const publicAuthorizeArgsSchema = z.object({ + _role: publicAppRoleSchema, + _user_id: z.string(), +}); +export const publicAuthorizeReturnsSchema = z.boolean(); +export const publicHasPermissionArgsSchema = z.object({ + _permission: publicAppPermissionSchema, + _user_id: z.string(), +}); +export const publicHasPermissionReturnsSchema = z.boolean(); +export const publicIsPageCollaboratorArgsSchema = z.object({ + _page_id: z.string(), +}); +export const publicIsPageCollaboratorReturnsSchema = z.boolean(); +export const publicIsPageOwnerArgsSchema = z.object({ + _page_id: z.string(), +}); +export const publicIsPageOwnerReturnsSchema = z.boolean(); +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2NoZW1hcy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9pbnRlZ3JhdGlvbnMvc3VwYWJhc2Uvc2NoZW1hcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7OztHQUlHO0FBRUgsT0FBTyxFQUFFLENBQUMsRUFBRSxNQUFNLEtBQUssQ0FBQztBQUV4QixNQUFNLENBQUMsTUFBTSx5QkFBeUIsR0FBRyxDQUFDLENBQUMsS0FBSyxDQUFDO0lBQy9DLENBQUMsQ0FBQyxPQUFPLENBQUMsZUFBZSxDQUFDO0lBQzFCLENBQUMsQ0FBQyxPQUFPLENBQUMsaUJBQWlCLENBQUM7SUFDNUIsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxpQkFBaUIsQ0FBQztJQUM1QixDQUFDLENBQUMsT0FBTyxDQUFDLGlCQUFpQixDQUFDO0lBQzVCLENBQUMsQ0FBQyxPQUFPLENBQUMsa0JBQWtCLENBQUM7SUFDN0IsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxvQkFBb0IsQ0FBQztJQUMvQixDQUFDLENBQUMsT0FBTyxDQUFDLG9CQUFvQixDQUFDO0lBQy9CLENBQUMsQ0FBQyxPQUFPLENBQUMsb0JBQW9CLENBQUM7SUFDL0IsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxlQUFlLENBQUM7SUFDMUIsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxpQkFBaUIsQ0FBQztJQUM1QixDQUFDLENBQUMsT0FBTyxDQUFDLGlCQUFpQixDQUFDO0lBQzVCLENBQUMsQ0FBQyxPQUFPLENBQUMsaUJBQWlCLENBQUM7SUFDNUIsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxxQkFBcUIsQ0FBQztDQUNqQyxDQUFDLENBQUM7QUFFSCxNQUFNLENBQUMsTUFBTSxtQkFBbUIsR0FBRyxDQUFDLENBQUMsS0FBSyxDQUFDO0lBQ3pDLENBQUMsQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDO0lBQ2xCLENBQUMsQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDO0lBQ2xCLENBQUMsQ0FBQyxPQUFPLENBQUMsUUFBUSxD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QUksRUFBRSxVQUFVLENBQUMsUUFBUSxFQUFFO0lBQzNCLEtBQUssRUFBRSxDQUFDLENBQUMsTUFBTSxFQUFFO0lBQ2pCLE1BQU0sRUFBRSxDQUFDLENBQUMsTUFBTSxFQUFFLENBQUMsUUFBUSxFQUFFO0lBQzdCLElBQUksRUFBRSxDQUFDLENBQUMsTUFBTSxFQUFFO0lBQ2hCLElBQUksRUFBRSxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxDQUFDLFFBQVEsRUFBRTtJQUNwQyxLQUFLLEVBQUUsQ0FBQyxDQUFDLE1BQU0sRUFBRTtJQUNqQixJQUFJLEVBQUUsQ0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDLFFBQVEsRUFBRTtJQUMzQixVQUFVLEVBQUUsQ0FBQyxDQUFDLE1BQU0sRUFBRTtJQUN0QixPQUFPLEVBQUUsQ0FBQyxDQUFDLE9BQU8sRUFBRTtDQUNyQixDQUFDLENBQUM7QUFFSCxNQUFNLENBQUMsTUFBTSx1QkFBdUIsR0FBRyxDQUFDLENBQUMsTUFBTSxDQUFDO0lBQzlDLE9BQU8sRUFBRSxVQUFVLENBQUMsUUFBUSxFQUFFLENBQUMsUUFBUSxFQUFFO0lBQ3pDLFVBQVUsRUFBRSxDQUFDLENBQUMsTUFBTSxFQUFFLENBQUMsUUFBUSxFQUFFO0lBQ2pDLEVBQUUsRUFBRSxDQUFDLENBQUMsTUFBTSxFQUFFLENBQUMsUUFBUSxFQUFFO0lBQ3pCLFNBQVMsRUFBRSxDQUFDLENBQUMsT0FBTyxFQUFFLENBQUMsUUFBUSxFQUFFO0lBQ2pDLElBQUksRUFBRSxVQUFVLENBQUMsUUFBUSxFQUFFLENBQUMsUUFBUSxFQUFFO0lBQ3RDLEtBQUssRUFBRSxDQUFDLENBQUMsTUFBTSxFQUFFO0lBQ2pCLE1BQU0sRUFBRSxDQUFDLENBQUMsTUFBTSxFQUFFLENBQUMsUUFBUSxFQUFFLENBQUMsUUFBUSxFQUFFO0lBQ3hDLElBQUksRUFBRSxDQUFDLENBQUMsTUFBTSxFQUFFO0lBQ2hCLElBQUksRUFBRSxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxDQUFDLFFBQVEsRUFBRSxDQUFDLFFBQVEsRUFBRTtJQUMvQyxLQUFLLEVBQUUsQ0FBQyxDQUFDLE1BQU0sRUFBRTtJQUNqQixJQUFJLEVBQUUsQ0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDLFFBQVEsRUFBRSxDQUFDLFFBQVEsRUFBRTtJQUN0QyxVQUFVLEVBQUUsQ0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDLFFBQVEsRUFBRTtJQUNqQyxPQUFPLEVBQUUsQ0FBQyxDQUFDLE9BQU8sRUFBRSxDQUFDLFFBQVEsRUFBRTtDQUNoQyxDQUFDLENBQUM7QUFFSCxNQUFNLENBQUMsTUFBTSx1QkFBdUIsR0FBRyxDQUFDLENBQUMsTUFBTSxDQUFDO0lBQzlDLE9BQU8sRUFBRSxVQUFVLENBQUMsUUFBUSxFQUFFLENBQUMsUUFBUSxFQUFFO0lBQ3pDLFVBQVUsRUFBRSxDQUFDLENBQUMsTUFBTSxFQUFFLENBQUMsUUFBUSxFQUFFO0lBQ2pDLEVBQUUsRUFBRSxDQUFDLENBQUMsTUFBTSxFQUFFLENBQUMsUUFBUSxFQUFFO0lBQ3pCLFNBQVMsRUFBRSxDQUFDLENBQUMsT0FBTyxFQUFFLENBQUMsUUFBUSxFQUFFO0lBQ2pDLElBQUksRUFBRSxVQUFVLENBQUMsUUFBUSxFQUFFLENBQUMsUUFBUSxFQUFFO0lBQ3RDLEtBQUssRUFBRSxDQUFDLENBQUMsTUFBTSxFQUFFLENBQUMsUUFBUSxFQUFFO0lBQzVCLE1BQU0sRUFBRSxDQUFDLENBQUMsTUFBTSxFQUFFLENBQUMsUUFBUSxFQUFFLENBQUMsUUFBUSxFQUFFO0lBQ3hDLElBQUksRUFBRSxDQUFDLENBQUMsTUFBTSxFQUFFLENBQUMsUUFBUSxFQUFFO0lBQzNCLElBQUksRUFBRSxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxDQUFDLFFBQVEsRUFBRSxDQUFDLFFBQVEsRUFBRTtJQUMvQyxLQUFLLEVBQUUsQ0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDLFFBQVEsRUFBRTtJQUM1QixJQUFJLEVBQUUsQ0FBQyxDQUFD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RUFBRSxDQUFDLENBQUMsTUFBTSxFQUFFO0NBQ3BCLENBQUMsQ0FBQztBQUVILE1BQU0sQ0FBQyxNQUFNLHVCQUF1QixHQUFHLENBQUMsQ0FBQyxNQUFNLENBQUM7SUFDOUMsVUFBVSxFQUFFLENBQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxRQUFRLEVBQUUsQ0FBQyxRQUFRLEVBQUU7SUFDNUMsV0FBVyxFQUFFLENBQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxRQUFRLEVBQUUsQ0FBQyxRQUFRLEVBQUU7SUFDN0MsRUFBRSxFQUFFLENBQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxRQUFRLEVBQUU7SUFDekIsSUFBSSxFQUFFLFVBQVUsQ0FBQyxRQUFRLEVBQUUsQ0FBQyxRQUFRLEVBQUU7SUFDdEMsUUFBUSxFQUFFLFVBQVUsQ0FBQyxRQUFRLEVBQUUsQ0FBQyxRQUFRLEVBQUU7SUFDMUMsS0FBSyxFQUFFLENBQUMsQ0FBQyxNQUFNLEVBQUU7SUFDakIsVUFBVSxFQUFFLENBQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxRQUFRLEVBQUUsQ0FBQyxRQUFRLEVBQUU7SUFDNUMsT0FBTyxFQUFFLENBQUMsQ0FBQyxNQUFNLEVBQUU7Q0FDcEIsQ0FBQyxDQUFDO0FBRUgsTUFBTSxDQUFDLE1BQU0sdUJBQXVCLEdBQUcsQ0FBQyxDQUFDLE1BQU0sQ0FBQztJQUM5QyxVQUFVLEVBQUUsQ0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDLFFBQVEsRUFBRSxDQUFDLFFBQVEsRUFBRTtJQUM1QyxXQUFXLEVBQUUsQ0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDLFFBQVEsRUFBRSxDQUFDLFFBQVEsRUFBRTtJQUM3QyxFQUFFLEVBQUUsQ0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDLFFBQVEsRUFBRTtJQUN6QixJQUFJLEVBQUUsVUFBVSxDQUFDLFFBQVEsRUFBRSxDQUFDLFFBQVEsRUFBRTtJQUN0QyxRQUFRLEVBQUUsVUFBVSxDQUFDLFFBQVEsRUFBRSxDQUFDLFFBQVEsRUFBRTtJQUMxQyxLQUFLLEVBQUUsQ0FBQyxDQUFDLE1BQU0s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QUFNLEVBQUUsQ0FBQyxRQUFRLEVBQUU7SUFDNUIsSUFBSSxFQUFFLENBQUMsQ0FBQyxNQUFNLEVBQUU7SUFDaEIsTUFBTSxFQUFFLENBQUMsQ0FBQyxNQUFNLEVBQUU7SUFDbEIsUUFBUSxFQUFFLENBQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxRQUFRLEVBQUU7SUFDL0IsVUFBVSxFQUFFLENBQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxRQUFRLEVBQUUsQ0FBQyxRQUFRLEVBQUU7SUFDNUMsV0FBVyxFQUFFLENBQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxRQUFRLEVBQUUsQ0FBQyxRQUFRLEVBQUU7SUFDN0MsT0FBTyxFQUFFLENBQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxRQUFRLEVBQUUsQ0FBQyxRQUFRLEVBQUU7Q0FDMUMsQ0FBQyxDQUFDO0FBRUgsTUFBTSxDQUFDLE1BQU0sK0JBQStCLEdBQUcsQ0FBQyxDQUFDLE1BQU0sQ0FBQztJQUN0RCxPQUFPLEVBQUUsQ0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDLFFBQVEsRUFBRTtJQUM5QixVQUFVLEVBQUUsQ0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDLFFBQVEsRUFBRSxDQUFDLFFBQVEsRUFBRTtJQUM1QyxXQUFXLEVBQUUsQ0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDLFFBQVEsRUFBRSxDQUFDLFFBQVEsRUFBRTtJQUM3QyxPQUFPLEVBQUUsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsTUFBTSxFQUFFLENBQUMsQ0FBQyxRQUFRLEVBQUUsQ0FBQyxRQUFRLEVBQUU7SUFDbEQsTUFBTSxFQUFFLENBQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxRQUFRLEVBQUUsQ0FBQyxRQUFRLEVBQUU7SUFDeEMsRUFBRSxFQUFFLENBQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxRQUFRLEVBQUU7SUFDekIsU0FBUyxFQUFFLENBQUMsQ0FBQyxPQUFPLEVBQUUsQ0FBQyxRQUFRLEVBQUUsQ0FBQyxRQUFRLEVBQUU7SUFDNUMsS0FBSyxFQUFFLENBQUMsQ0FBQyxNQUFN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 \ No newline at end of file diff --git a/dist-in/integrations/supabase/types.js b/dist-in/integrations/supabase/types.js new file mode 100644 index 0000000..7d380fa --- /dev/null +++ b/dist-in/integrations/supabase/types.js @@ -0,0 +1,41 @@ +export const Constants = { + graphql_public: { + Enums: {}, + }, + public: { + Enums: { + app_permission: [ + "pictures.read", + "pictures.create", + "pictures.update", + "pictures.delete", + "collections.read", + "collections.create", + "collections.update", + "collections.delete", + "comments.read", + "comments.create", + "comments.update", + "comments.delete", + "organization.manage", + ], + app_role: ["owner", "admin", "member", "viewer"], + cast_kind: ["implicit", "explicit", "lossy"], + category_relation_type: [ + "generalization", + "material_usage", + "domain", + "process_step", + "standard", + "other", + ], + category_visibility: ["public", "unlisted", "private"], + collaborator_role: ["viewer", "editor", "owner"], + layout_visibility: ["public", "private", "listed", "custom"], + translation_status: ["draft", "machine", "reviewed", "published"], + type_kind: ["primitive", "enum", "flags", "structure", "alias", "field"], + type_visibility: ["public", "private", "custom"], + }, + }, +}; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHlwZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvaW50ZWdyYXRpb25zL3N1cGFiYXNlL3R5cGVzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQStyREEsTUFBTSxDQUFDLE1BQU0sU0FBUyxHQUFHO0lBQ3ZCLGNBQWMsRUFBRTtRQUNkLEtBQUssRUFBRSxFQUFFO0tBQ1Y7SUFDRCxNQUFNLEVBQUU7UUFDTixLQUFLLEVBQUU7WUFDTCxjQUFjLEVBQUU7Z0JBQ2QsZUFBZTtnQkFDZixpQkFBaUI7Z0JBQ2pCLGlCQUFpQjtnQkFDakIsaUJBQWlCO2dCQUNqQixrQkFBa0I7Z0JBQ2xCLG9CQUFvQjtnQkFDcEIsb0JBQW9CO2dCQUNwQixvQkFBb0I7Z0JBQ3BCLGVBQWU7Z0JBQ2YsaUJBQWlCO2dCQUNqQixpQkFBaUI7Z0JBQ2pCLGlCQUFpQjtnQkFDakIscUJBQXFCO2FBQ3RCO1lBQ0QsUUFBUSxFQUFFLENBQUMsT0FBTyxFQUFFLE9BQU8sRUFBRSxRQUFRLEVBQUUsUUFBUSxDQUFDO1lBQ2hELFNBQVMsRUFBRSxDQUFDLFVBQVUsRUFBRSxVQUFVLEVBQUUsT0FBTyxDQUFDO1lBQzVDLHNCQUFzQixFQUFFO2dCQUN0QixnQkFBZ0I7Z0JBQ2hCLGdCQUFnQjtnQkFDaEIsUUFBUTtnQkFDUixjQUFjO2dCQUNkLFVBQVU7Z0JBQ1YsT0FBTzthQUNSO1lBQ0QsbUJBQW1CLEVBQUUsQ0FBQyxRQUFRLEVBQUUsVUFBVSxFQUFFLFNBQVMsQ0FBQztZQUN0RCxpQkFBaUIsRUFBRSxDQUFDLFFBQVEsRUFBRSxRQUFRLEVBQUUsT0FBTyxDQUFDO1lBQ2hELGlCQUFpQixFQUFFLENBQUMsUUFBUSxFQUFFLFNBQVMsRUFBRSxRQUFRLEVBQUUsUUFBUSxDQUFDO1lBQzVELGtCQUFrQixFQUFFLENBQUMsT0FBTyxFQUFFLFNBQVMsRUFBRSxVQUFVLEVBQUUsV0FBVyxDQUFDO1lBQ2pFLFNBQVMsRUFBRSxDQUFDLFdBQVcsRUFBRSxNQUFNLEVBQUUsT0FBTyxFQUFFLFdBQVcsRUFBRSxPQUFPLEVBQUUsT0FBTyxDQUFDO1lBQ3hFLGVBQWUsRUFBRSxDQUFDLFFBQVEsRUFBRSxTQUFTLEVBQUUsUUFBUSxDQUFDO1NBQ2pEO0tBQ0Y7Q0FDTyxDQUFBIn0= \ No newline at end of file diff --git a/dist-in/jobs/boss/AbstractWorker.js b/dist-in/jobs/boss/AbstractWorker.js new file mode 100644 index 0000000..17b867f --- /dev/null +++ b/dist-in/jobs/boss/AbstractWorker.js @@ -0,0 +1,35 @@ +import { logger } from '../../commons/logger.js'; +export class AbstractWorker { + queueOptions; // pg-boss QueueOptions + emitter; + // Main entry point for pg-boss + async handler(jobOrJobs) { + const job = Array.isArray(jobOrJobs) ? jobOrJobs[0] : jobOrJobs; + // Safety check + if (!job) { + logger.error(`[${this.queueName}] Received null or empty job`); + return; + } + const jobId = job.id; + const usageId = job.data?.usageId; + logger.info(`[${this.queueName}] Starting job ${jobId}`); + try { + // 2. Execute Business Logic + const result = await this.process(job); + // 3. Calculate Cost + const cost = this.calculateCost(job, result); + if (this.emitter) { + this.emitter.emit('job:complete', { + jobId, + result + }); + } + return result; + } + catch (error) { + logger.error({ err: error }, `[${this.queueName}] Job failed`); + throw error; // Let pg-boss handle retry/failure + } + } +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQWJzdHJhY3RXb3JrZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvam9icy9ib3NzL0Fic3RyYWN0V29ya2VyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUVBLE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUlqRCxNQUFNLE9BQWdCLGNBQWM7SUFFdkIsWUFBWSxDQUFPLENBQUMsdUJBQXVCO0lBQzFDLE9BQU8sQ0FBZ0I7SUFRakMsK0JBQStCO0lBQ3hCLEtBQUssQ0FBQyxPQUFPLENBQUMsU0FBb0M7UUFFckQsTUFBTSxHQUFHLEdBQUcsS0FBSyxDQUFDLE9BQU8sQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUM7UUFFaEUsZUFBZTtRQUNmLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQztZQUNQLE1BQU0sQ0FBQyxLQUFLLENBQUMsSUFBSSxJQUFJLENBQUMsU0FBUyw4QkFBOEIsQ0FBQyxDQUFDO1lBQy9ELE9BQU87UUFDWCxDQUFDO1FBRUQsTUFBTSxLQUFLLEdBQUcsR0FBRyxDQUFDLEVBQUUsQ0FBQztRQUNyQixNQUFNLE9BQU8sR0FBSSxHQUFHLENBQUMsSUFBWSxFQUFFLE9BQU8sQ0FBQztRQUUzQyxNQUFNLENBQUMsSUFBSSxDQUFDLElBQUksSUFBSSxDQUFDLFNBQVMsa0JBQWtCLEtBQUssRUFBRSxDQUFDLENBQUM7UUFFekQsSUFBSSxDQUFDO1lBQ0QsNEJBQTRCO1lBQzVCLE1BQU0sTUFBTSxHQUFHLE1BQU0sSUFBSSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsQ0FBQztZQUV2QyxvQkFBb0I7WUFDcEIsTUFBTSxJQUFJLEdBQUcsSUFBSSxDQUFDLGFBQWEsQ0FBQyxHQUFHLEVBQUUsTUFBTSxDQUFDLENBQUM7WUFFN0MsSUFBSSxJQUFJLENBQUMsT0FBTyxFQUFFLENBQUM7Z0JBQ2YsSUFBSSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsY0FBYyxFQUFFO29CQUM5QixLQUFLO29CQUNMLE1BQU07aUJBQ1QsQ0FBQyxDQUFDO1lBQ1AsQ0FBQztZQUdELE9BQU8sTUFBTSxDQUFDO1FBRWxCLENBQUM7UUFBQyxPQUFPLEtBQVUsRUFBRSxDQUFDO1lBRWxCLE1BQU0sQ0FBQyxLQUFLLENBQUMsRUFBRSxHQUFHLEVBQUUsS0FBSyxFQUFFLEVBQUUsSUFBSSxJQUFJLENBQUMsU0FBUyxjQUFjLENBQUMsQ0FBQztZQUUvRCxNQUFNLEtBQUssQ0FBQyxDQUFDLG1DQUFtQztRQUNwRCxDQUFDO0lBQ0wsQ0FBQztDQUNKIn0= \ No newline at end of file diff --git a/dist-in/jobs/boss/client.js b/dist-in/jobs/boss/client.js new file mode 100644 index 0000000..7f47412 --- /dev/null +++ b/dist-in/jobs/boss/client.js @@ -0,0 +1,41 @@ +import { PgBoss } from 'pg-boss'; +import { logger } from '../../commons/logger.js'; +const connectionString = process.env.DATABASE_URL; +if (!connectionString) { + logger.warn('DATABASE_URL not found, PgBoss will not be initialized'); +} +export const boss = connectionString ? new PgBoss({ + connectionString, + __test__enableSpies: true +}) : null; +export let bossInitError = null; +export async function startBoss() { + if (!boss) + return; + boss.on('error', (error) => logger.error({ error }, 'PgBoss error')); + try { + await boss.start(); + logger.info('PgBoss started'); + return boss; + } + catch (error) { + bossInitError = error; + logger.error({ error }, 'Failed to start PgBoss'); + const fs = await import('fs'); + fs.writeFileSync('debug_pgboss_error.txt', JSON.stringify(error, Object.getOwnPropertyNames(error))); + } +} +export async function stopBoss() { + if (!boss) { + console.info('PgBoss not initialized, skipping stop.'); + return; + } + try { + await boss.stop({ timeout: 5000 }); // 5s timeout + console.info('PgBoss stopped'); + } + catch (error) { + console.error({ error }, 'Failed to stop PgBoss'); + } +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xpZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2pvYnMvYm9zcy9jbGllbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLFNBQVMsQ0FBQztBQUNqQyxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0seUJBQXlCLENBQUM7QUFFakQsTUFBTSxnQkFBZ0IsR0FBRyxPQUFPLENBQUMsR0FBRyxDQUFDLFlBQVksQ0FBQztBQUVsRCxJQUFJLENBQUMsZ0JBQWdCLEVBQUUsQ0FBQztJQUNwQixNQUFNLENBQUMsSUFBSSxDQUFDLHdEQUF3RCxDQUFDLENBQUM7QUFDMUUsQ0FBQztBQUVELE1BQU0sQ0FBQyxNQUFNLElBQUksR0FBRyxnQkFBZ0IsQ0FBQyxDQUFDLENBQUMsSUFBSSxNQUFNLENBQUM7SUFDOUMsZ0JBQWdCO0lBQ2hCLG1CQUFtQixFQUFFLElBQUk7Q0FDckIsQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUM7QUFDakIsTUFBTSxDQUFDLElBQUksYUFBYSxHQUFpQixJQUFJLENBQUM7QUFFOUMsTUFBTSxDQUFDLEtBQUssVUFBVSxTQUFTO0lBQzNCLElBQUksQ0FBQyxJQUFJO1FBQUUsT0FBTztJQUVsQixJQUFJLENBQUMsRUFBRSxDQUFDLE9BQU8sRUFBRSxDQUFDLEtBQVksRUFBRSxFQUFFLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxFQUFFLEtBQUssRUFBRSxFQUFFLGNBQWMsQ0FBQyxDQUFDLENBQUM7SUFFNUUsSUFBSSxDQUFDO1FBQ0QsTUFBTSxJQUFJLENBQUMsS0FBSyxFQUFFLENBQUM7UUFDbkIsTUFBTSxDQUFDLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDO1FBQzlCLE9BQU8sSUFBSSxDQUFDO0lBQ2hCLENBQUM7SUFBQyxPQUFPLEtBQVUsRUFBRSxDQUFDO1FBQ2xCLGFBQWEsR0FBRyxLQUFLLENBQUM7UUFDdEIsTUFBTSxDQUFDLEtBQUssQ0FBQyxFQUFFLEtBQUssRUFBRSxFQUFFLHdCQUF3QixDQUFDLENBQUM7UUFDbEQsTUFBTSxFQUFFLEdBQUcsTUFBTSxNQUFNLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDOUIsRUFBRSxDQUFDLGFBQWEsQ0FBQyx3QkFBd0IsRUFBRSxJQUFJLENBQUMsU0FBUyxDQUFDLEtBQUssRUFBRSxNQUFNLENBQUMsbUJBQW1CLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ3pHLENBQUM7QUFDTCxDQUFDO0FBRUQsTUFBTSxDQUFDLEtBQUssVUFBVSxRQUFRO0lBQzFCLElBQUksQ0FBQyxJQUFJLEVBQUUsQ0FBQztRQUNSLE9BQU8sQ0FBQyxJQUFJLENBQUMsd0NBQXdDLENBQUMsQ0FBQTtRQUN0RCxPQUFNO0lBQ1YsQ0FBQztJQUNELElBQUksQ0FBQztRQUNELE1BQU0sSUFBSSxDQUFDLElBQUksQ0FBQyxFQUFFLE9BQU8sRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFDLENBQUMsYUFBYTtRQUNqRCxPQUFPLENBQUMsSUFBSSxDQUFDLGdCQUFnQixDQUFDLENBQUM7SUFDbkMsQ0FBQztJQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7UUFDYixPQUFPLENBQUMsS0FBSyxDQUFDLEVBQUUsS0FBSyxFQUFFLEVBQUUsdUJBQXVCLENBQUMsQ0FBQztJQUN0RCxDQUFDO0FBQ0wsQ0FBQyJ9 \ No newline at end of file diff --git a/dist-in/jobs/boss/registry.js b/dist-in/jobs/boss/registry.js new file mode 100644 index 0000000..b91b12a --- /dev/null +++ b/dist-in/jobs/boss/registry.js @@ -0,0 +1,13 @@ +export class WorkerRegistry { + static workers = new Map(); + static register(queueName, handler, options) { + this.workers.set(queueName, { queueName, handler, options }); + } + static get(queueName) { + return this.workers.get(queueName); + } + static getAll() { + return Array.from(this.workers.values()); + } +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVnaXN0cnkuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvam9icy9ib3NzL3JlZ2lzdHJ5LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQVVBLE1BQU0sT0FBTyxjQUFjO0lBQ2YsTUFBTSxDQUFDLE9BQU8sR0FBOEIsSUFBSSxHQUFHLEVBQUUsQ0FBQztJQUU5RCxNQUFNLENBQUMsUUFBUSxDQUFDLFNBQWlCLEVBQUUsT0FBc0IsRUFBRSxPQUFhO1FBQ3BFLElBQUksQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLFNBQVMsRUFBRSxFQUFFLFNBQVMsRUFBRSxPQUFPLEVBQUUsT0FBTyxFQUFFLENBQUMsQ0FBQztJQUNqRSxDQUFDO0lBRUQsTUFBTSxDQUFDLEdBQUcsQ0FBQyxTQUFpQjtRQUN4QixPQUFPLElBQUksQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLFNBQVMsQ0FBQyxDQUFDO0lBQ3ZDLENBQUM7SUFFRCxNQUFNLENBQUMsTUFBTTtRQUNULE9BQU8sS0FBSyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLE1BQU0sRUFBRSxDQUFDLENBQUM7SUFDN0MsQ0FBQyJ9 \ No newline at end of file diff --git a/dist-in/jobs/boss/search/SearchWorker.js b/dist-in/jobs/boss/search/SearchWorker.js new file mode 100644 index 0000000..860f345 --- /dev/null +++ b/dist-in/jobs/boss/search/SearchWorker.js @@ -0,0 +1,108 @@ +var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { + var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; + if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); + else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; + return c > 3 && r && Object.defineProperty(target, key, r), r; +}; +import { AbstractWorker } from '../AbstractWorker.js'; +import { googleMaps, ResolveFlags } from '@polymech/search'; +import { supabase } from '../../../commons/supabase.js'; +import { logger } from '../../../commons/logger.js'; +import { Worker } from '../../../commons/decorators.js'; +let SearchWorker = class SearchWorker extends AbstractWorker { + queueName = 'search-worker'; + calculateCost(job, result) { + // Example: 1 credit per search + 0.1 per result + return 1 + (result?.length || 0) * 0.1; + } + async process(job) { + const { query, location, filters, userId } = job.data; + // Call existing logic (refactored from endpoints/competitors/index.ts) + const results = await googleMaps({ + query, + searchFrom: location, + resolve: [ResolveFlags.PHOTOS], + filterCity: filters?.filterCity, + filterContinent: filters?.filterContinent, + filterType: filters?.filterType, + concurrency: filters?.concurrency || 5 + }); + // Flatten results + const flatResults = results ? results.flat(Infinity) : []; + // Map and Upsert Locations + const locationsToUpsert = flatResults + .filter((r) => r.place_id) + .map((r) => ({ + place_id: r.place_id, + title: r.title, + description: r.description, + address: r.address, + gps_coordinates: r.gps_coordinates, + phone: r.phone, + website: r.website, + operating_hours: r.operating_hours, + thumbnail: r.thumbnail, + types: r.types, + raw_data: r, + continent: r.geo?.continent, + country: r.geo?.countryName, + city: r.geo?.city, + updated_at: new Date().toISOString(), // Update timestamp + user_id: userId + })); + // Fetch existing locations to preserve meta (emails) + const placeIds = locationsToUpsert.map(l => l.place_id); + if (placeIds.length > 0) { + const { data: existingLocations } = await supabase + .from('locations') + .select('place_id, meta') + .in('place_id', placeIds); + if (existingLocations) { + const metaMap = new Map(existingLocations.map(l => [l.place_id, l.meta])); + locationsToUpsert.forEach(l => { + const existingMeta = metaMap.get(l.place_id); + if (existingMeta) { + // Merge existing meta into raw_data for the client + l.raw_data.meta = { + ...(l.raw_data.meta || {}), + ...existingMeta + }; + } + }); + } + } + if (locationsToUpsert.length > 0) { + const { error: upsertError } = await supabase + .from('locations') + .upsert(locationsToUpsert, { onConflict: 'place_id' }); + if (upsertError) { + logger.error(upsertError, 'Error upserting locations'); + throw upsertError; + } + } + // Store Search (for caching) + // Re-create hash logic from handler + const { createHash } = await import('crypto'); + const inputParams = { query, location }; + const normalizedInput = JSON.stringify(inputParams, Object.keys(inputParams).sort()); + const inputHash = createHash('sha256').update(normalizedInput).digest('hex'); + const { error: searchStoreError } = await supabase + .from('searches') + .upsert({ + input_hash: inputHash, + input_params: inputParams, + result_place_ids: placeIds, + created_at: new Date().toISOString() + }, { onConflict: 'input_hash' }); + if (searchStoreError) { + logger.error(searchStoreError, `Error storing search ${searchStoreError.message}`); + // Don't fail the job just because caching failed + } + return { count: locationsToUpsert.length, placeIds }; + } +}; +SearchWorker = __decorate([ + Worker('search-worker') +], SearchWorker); +export { SearchWorker }; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiU2VhcmNoV29ya2VyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL2pvYnMvYm9zcy9zZWFyY2gvU2VhcmNoV29ya2VyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7OztBQUNBLE9BQU8sRUFBRSxjQUFjLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQztBQUN0RCxPQUFPLEVBQUUsVUFBVSxFQUFFLFlBQVksRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBQzVELE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBTSw4QkFBOEIsQ0FBQztBQUN4RCxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sNEJBQTRCLENBQUM7QUFDcEQsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLGdDQUFnQyxDQUFDO0FBZ0JqRCxJQUFNLFlBQVksR0FBbEIsTUFBTSxZQUFhLFNBQVEsY0FBNkI7SUFDbEQsU0FBUyxHQUFHLGVBQWUsQ0FBQztJQUVyQyxhQUFhLENBQUMsR0FBdUIsRUFBRSxNQUFXO1FBQzlDLGdEQUFnRDtRQUNoRCxPQUFPLENBQUMsR0FBRyxDQUFDLE1BQU0sRUFBRSxNQUFNLElBQUksQ0FBQyxDQUFDLEdBQUcsR0FBRyxDQUFDO0lBQzNDLENBQUM7SUFFUyxLQUFLLENBQUMsT0FBTyxDQUFDLEdBQXVCO1FBQzNDLE1BQU0sRUFBRSxLQUFLLEVBQUUsUUFBUSxFQUFFLE9BQU8sRUFBRSxNQUFNLEVBQUUsR0FBRyxHQUFHLENBQUMsSUFBSSxDQUFDO1FBRXRELHVFQUF1RTtRQUN2RSxNQUFNLE9BQU8sR0FBRyxNQUFNLFVBQVUsQ0FBQztZQUM3QixLQUFLO1lBQ0wsVUFBVSxFQUFFLFFBQVE7WUFDcEIsT0FBTyxFQUFFLENBQUMsWUFBWSxDQUFDLE1BQU0sQ0FBQztZQUM5QixVQUFVLEVBQUUsT0FBTyxFQUFFLFVBQVU7WUFDL0IsZUFBZSxFQUFFLE9BQU8sRUFBRSxlQUFlO1lBQ3pDLFVBQVUsRUFBRSxPQUFPLEVBQUUsVUFBVTtZQUMvQixX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 \ No newline at end of file diff --git a/dist-in/jobs/boss/workers.js b/dist-in/jobs/boss/workers.js new file mode 100644 index 0000000..32f6700 --- /dev/null +++ b/dist-in/jobs/boss/workers.js @@ -0,0 +1,25 @@ +import { boss } from './client.js'; +import { logger } from '@/commons/logger.js'; +export const QUEUE_MOCK_JOB = 'mock-job'; +export async function registerMockWorkers() { + if (!boss) + return; + // Product workers are now registered by the products themselves in AbstractProduct.start() + await boss.createQueue(QUEUE_MOCK_JOB); + await boss.work(QUEUE_MOCK_JOB, async (jobs) => { + // PgBoss might pass an array of jobs or a single job depending on config/version + const job = Array.isArray(jobs) ? jobs[0] : jobs; + const data = job.data || {}; + const { delayMs = 100, shouldFail = false } = data; + const jobId = job.id; + logger.info({ jobId, data }, 'Processing PgBoss mock job'); + await new Promise(resolve => setTimeout(resolve, delayMs)); + if (shouldFail) { + throw new Error('Simulated PgBoss job failure'); + } + logger.info({ jobId }, 'PgBoss mock job completed'); + return { success: true }; + }); + logger.info('PgBoss workers registered'); +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid29ya2Vycy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9qb2JzL2Jvc3Mvd29ya2Vycy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsSUFBSSxFQUFFLE1BQU0sYUFBYSxDQUFDO0FBRW5DLE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQUU3QyxNQUFNLENBQUMsTUFBTSxjQUFjLEdBQUcsVUFBVSxDQUFDO0FBUXpDLE1BQU0sQ0FBQyxLQUFLLFVBQVUsbUJBQW1CO0lBQ3JDLElBQUksQ0FBQyxJQUFJO1FBQUUsT0FBTztJQUVsQiwyRkFBMkY7SUFFM0YsTUFBTSxJQUFJLENBQUMsV0FBVyxDQUFDLGNBQWMsQ0FBQyxDQUFDO0lBQ3ZDLE1BQU0sSUFBSSxDQUFDLElBQUksQ0FBYyxjQUFjLEVBQUUsS0FBSyxFQUFFLElBQVMsRUFBRSxFQUFFO1FBQzdELGlGQUFpRjtRQUNqRixNQUFNLEdBQUcsR0FBRyxLQUFLLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQztRQUVqRCxNQUFNLElBQUksR0FBRyxHQUFHLENBQUMsSUFBSSxJQUFJLEVBQUUsQ0FBQztRQUM1QixNQUFNLEVBQUUsT0FBTyxHQUFHLEdBQUcsRUFBRSxVQUFVLEdBQUcsS0FBSyxFQUFFLEdBQUcsSUFBSSxDQUFDO1FBQ25ELE1BQU0sS0FBSyxHQUFHLEdBQUcsQ0FBQyxFQUFFLENBQUM7UUFFckIsTUFBTSxDQUFDLElBQUksQ0FBQyxFQUFFLEtBQUssRUFBRSxJQUFJLEVBQUUsRUFBRSw0QkFBNEIsQ0FBQyxDQUFDO1FBRTNELE1BQU0sSUFBSSxPQUFPLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQyxVQUFVLENBQUMsT0FBTyxFQUFFLE9BQU8sQ0FBQyxDQUFDLENBQUM7UUFFM0QsSUFBSSxVQUFVLEVBQUUsQ0FBQztZQUNiLE1BQU0sSUFBSSxLQUFLLENBQUMsOEJBQThCLENBQUMsQ0FBQztRQUNwRCxDQUFDO1FBRUQsTUFBTSxDQUFDLElBQUksQ0FBQyxFQUFFLEtBQUssRUFBRSxFQUFFLDJCQUEyQixDQUFDLENBQUM7UUFDcEQsT0FBTyxFQUFFLE9BQU8sRUFBRSxJQUFJLEVBQUUsQ0FBQztJQUM3QixDQUFDLENBQUMsQ0FBQztJQUVILE1BQU0sQ0FBQyxJQUFJLENBQUMsMkJBQTJCLENBQUMsQ0FBQztBQUM3QyxDQUFDIn0= \ No newline at end of file diff --git a/dist-in/lib/analytics-emitter.js b/dist-in/lib/analytics-emitter.js new file mode 100644 index 0000000..83276e6 --- /dev/null +++ b/dist-in/lib/analytics-emitter.js @@ -0,0 +1,5 @@ +import { EventEmitter } from 'events'; +class AnalyticsEmitter extends EventEmitter { +} +export const analyticsEmitter = new AnalyticsEmitter(); +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYW5hbHl0aWNzLWVtaXR0ZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvbGliL2FuYWx5dGljcy1lbWl0dGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxRQUFRLENBQUM7QUFFdEMsTUFBTSxnQkFBaUIsU0FBUSxZQUFZO0NBQUk7QUFFL0MsTUFBTSxDQUFDLE1BQU0sZ0JBQWdCLEdBQUcsSUFBSSxnQkFBZ0IsRUFBRSxDQUFDIn0= \ No newline at end of file diff --git a/dist-in/middleware/analytics.js b/dist-in/middleware/analytics.js new file mode 100644 index 0000000..90bea8b --- /dev/null +++ b/dist-in/middleware/analytics.js @@ -0,0 +1,114 @@ +import fs from 'fs'; +import path from 'path'; +import { analyticsEmitter } from '../lib/analytics-emitter.js'; +// import { isBotRequest, isAIRequest } from '../products/serving/bots.js'; +const ANALYTICS_FILE = path.resolve(process.cwd(), 'logs/analytics.jsonl'); +// Extensions to ignore +const IGNORED_EXTENSIONS = new Set([ + '.js', '.css', '.png', '.jpg', '.jpeg', '.gif', '.ico', '.svg', '.woff', '.woff2', '.ttf', '.eot', '.map' +]); +export const REVERSE_DEFAULT = { continent: 'unknown', countryName: 'unknown', city: 'unknown' }; +const GEO_CACHE_FILE = path.resolve(process.cwd(), 'cache/geoip.json'); +// Simple in-memory cache to reduce disk I/O, initialized on first use +let geoCache = null; +const loadGeoCache = () => { + if (geoCache) + return geoCache; + try { + if (fs.existsSync(GEO_CACHE_FILE)) { + const data = fs.readFileSync(GEO_CACHE_FILE, 'utf-8'); + geoCache = JSON.parse(data); + } + else { + geoCache = {}; + } + } + catch (e) { + console.error('Error loading geo cache', e); + geoCache = {}; + } + return geoCache; +}; +const saveGeoCache = (ip, data) => { + if (!geoCache) + geoCache = {}; + geoCache[ip] = data; + // Ensure directory exists + const dir = path.dirname(GEO_CACHE_FILE); + if (!fs.existsSync(dir)) { + fs.mkdirSync(dir, { recursive: true }); + } + // Write to file (async to not block) + fs.promises.writeFile(GEO_CACHE_FILE, JSON.stringify(geoCache, null, 2)).catch(err => { + console.error('Error saving geo cache', err); + }); +}; +export const reverse = async (ip, opts) => { + return REVERSE_DEFAULT; + /* + const cache = loadGeoCache(); + if (cache && cache[ip]) { + return cache[ip]; + } + + const config = CONFIG_DEFAULT() as any + try { + const q = `https://api-bdc.net/data/ip-geolocation?ip=${ip}&localityLanguage=en&key=${config.bigdata.key}` + const ret = await axios.get(q) || { data: REVERSE_DEFAULT } + const data = ret.data || REVERSE_DEFAULT + saveGeoCache(ip, data); + return data; + } catch (e: any) { + logger.error('Error reverse geocoding', e.message) + return REVERSE_DEFAULT + } + */ +}; +export async function analyticsMiddleware(c, next) { + await next(); // Execute the request first (non-blocking for the response?) + // Wait, "await next()" blocks the middleware until the downstream handlers finish. + // If we want to capture the status code, we need to wait. + // The user asked for "non blocking analytics middleware". + // Usually this means the *write* operation shouldn't block the response. + // So we can do the logging logic *after* `await next()`, but ensuring the file write is not awaited or is fire-and-forget. + try { + const url = new URL(c.req.url); + const pathname = url.pathname; + const extension = path.extname(pathname).toLowerCase(); + // Filter static assets + if (IGNORED_EXTENSIONS.has(extension)) { + return; + } + // Additional check for common static paths if they don't have extensions + if (pathname.startsWith('/assets/') || pathname.startsWith('/static/')) { + return; + } + const ip = c.req.header('x-forwarded-for') || c.req.header('cf-connecting-ip') || '92.176.215.140'; + const geo = REVERSE_DEFAULT; // || ip !== 'unknown' ? await reverse(ip, CONFIG_DEFAULT()) : REVERSE_DEFAULT + const userAgent = c.req.header('user-agent'); + const entry = { + timestamp: new Date().toISOString(), + method: c.req.method, + path: pathname, + status: c.res.status, + ip, + userAgent, + // isBot: isBotRequest(userAgent), + // isAI: isAIRequest(userAgent), + referer: c.req.header('referer'), + userId: c.get('userId'), + geo + }; + const line = JSON.stringify(entry) + '\n'; + // Emit event for real-time streaming + analyticsEmitter.emit('log', entry); + // Fire and forget write + fs.promises.appendFile(ANALYTICS_FILE, line).catch(err => { + console.error('Failed to write to analytics file:', err); + }); + } + catch (err) { + console.error('Error in analytics middleware:', err); + } +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYW5hbHl0aWNzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL21pZGRsZXdhcmUvYW5hbHl0aWNzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUNBLE9BQU8sRUFBRSxNQUFNLElBQUksQ0FBQztBQUNwQixPQUFPLElBQUksTUFBTSxNQUFNLENBQUM7QUFFeEIsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sNkJBQTZCLENBQUM7QUFFL0QsMkVBQTJFO0FBRTNFLE1BQU0sY0FBYyxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLEdBQUcsRUFBRSxFQUFFLHNCQUFzQixDQUFDLENBQUM7QUFFM0UsdUJBQXVCO0FBQ3ZCLE1BQU0sa0JBQWtCLEdBQUcsSUFBSSxHQUFHLENBQUM7SUFDL0IsS0FBSyxFQUFFLE1BQU0sRUFBRSxNQUFNLEVBQUUsTUFBTSxFQUFFLE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSxFQUFFLE1BQU0sRUFBRSxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0sRUFBRSxNQUFNLEVBQUUsTUFBTTtDQUM1RyxDQUFDLENBQUM7QUFDSCxNQUFNLENBQUMsTUFBTSxlQUFlLEdBQUcsRUFBRSxTQUFTLEVBQUUsU0FBUyxFQUFFLFdBQVcsRUFBRSxTQUFTLEVBQUUsSUFBSSxFQUFFLFNBQVMsRUFBRSxDQUFBO0FBOENoRyxNQUFNLGNBQWMsR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxHQUFHLEVBQUUsRUFBRSxrQkFBa0IsQ0FBQyxDQUFDO0FBRXZFLHNFQUFzRTtBQUN0RSxJQUFJLFFBQVEsR0FBK0IsSUFBSSxDQUFDO0FBRWhELE1BQU0sWUFBWSxHQUFHLEdBQUcsRUFBRTtJQUN0QixJQUFJLFFBQVE7UUFBRSxPQUFPLFFBQVEsQ0FBQztJQUM5QixJQUFJLENBQUM7UUFDRCxJQUFJLEVBQUUsQ0FBQyxVQUFVLENBQUMsY0FBYyxDQUFDLEVBQUUsQ0FBQztZQUNoQyxNQUFNLElBQUks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 \ No newline at end of file diff --git a/dist-in/middleware/auth.js b/dist-in/middleware/auth.js new file mode 100644 index 0000000..f9ac628 --- /dev/null +++ b/dist-in/middleware/auth.js @@ -0,0 +1,118 @@ +import { securityLogger as logger } from '../commons/logger.js'; +import { PublicEndpointRegistry, AdminEndpointRegistry } from '../commons/registry.js'; +import { getUserCached, supabase } from '../commons/supabase.js'; +/** + * Strict authentication middleware – requires a valid Bearer token. + */ +export async function authMiddleware(c, next) { + const authHeader = c.req.header('authorization'); + if (!authHeader?.startsWith('Bearer ')) { + return c.json({ error: 'Unauthorized - Missing or invalid authorization header' }, 401); + } + const token = authHeader.substring(7); + try { + const user = await getUserCached(token); + if (!user) { + return c.json({ error: 'Invalid or expired token' }, 401); + } + c.set('userId', user.id); + c.set('user', user); + c.set('userEmail', user.email); + await next(); + } + catch (err) { + logger.error({ err }, 'Auth middleware error'); + return c.json({ error: 'Authentication failed' }, 401); + } +} +/** + * Optional authentication middleware. + * - Public endpoint: GET /api/products (no auth required). + * - Otherwise respects REQUIRE_AUTH flag, but skips auth in test/dev environments. + */ +export async function optionalAuthMiddleware(c, next) { + const path = c.req.path; + const method = c.req.method; + // Public endpoint – allow unauthenticated access + const isPublicEndpoint = PublicEndpointRegistry.isPublic(path, method); + const isProductsEndpoint = method === 'GET' && path === '/api/products'; + if (isProductsEndpoint || isPublicEndpoint) { + return await next(); + } + const requireAuth = process.env.REQUIRE_AUTH === 'true'; + const isTestEnv = false; // process.env.NODE_ENV === 'test' || process.env.NODE_ENV === 'development'; + const authHeader = c.req.header('authorization'); + // If no auth header, or it's not a Bearer token... + let token; + if (authHeader && authHeader.startsWith('Bearer ')) { + token = authHeader.substring(7); + } + else { + // Check for token in query param (for SSE) + const queryToken = c.req.query('token'); + if (queryToken) { + token = queryToken; + } + } + if (!token) { + // ...and we are in test env or auth not required, just continue. + if (!requireAuth) { + return await next(); + } + // ...otherwise reject + return c.json({ error: 'Unauthorized' }, 401); + } + try { + const user = await getUserCached(token); + if (!user) { + logger.warn('[Auth] Token verification failed'); + if (isTestEnv) { + return await next(); + } + return c.json({ error: 'Unauthorized' }, 401); + } + c.set('userId', user.id); + c.set('user', user); + c.set('userEmail', user.email); + await next(); + } + catch (err) { + logger.error({ err }, '[Auth] Optional auth middleware error - REJECTING'); + return c.json({ error: 'Authentication failed' }, 401); + } +} +/** + * Admin‑only middleware – requires authentication and admin role. + * Checks AdminEndpointRegistry to see if the route requires admin access. + */ +export async function adminMiddleware(c, next) { + const path = c.req.path; + const method = c.req.method; + // Check if this is an admin endpoint + if (!AdminEndpointRegistry.isAdmin(path, method)) { + return await next(); + } + // If it is an admin endpoint, enforce auth and role + const userId = c.get('userId'); + if (!userId) { + return c.json({ error: 'Unauthorized - Authentication required' }, 401); + } + try { + const { data: profile, error } = await supabase + .from('user_roles') + .select('role') + .eq('user_id', userId) + .single(); + // @todo : fix db - type | multiple - currently single string + if (error || !profile || profile.role !== 'admin') { + return c.json({ error: 'Forbidden - Admin access required' }, 403); + } + c.set('isAdmin', true); + await next(); + } + catch (err) { + logger.error({ err }, 'Admin middleware error'); + return c.json({ error: 'Authorization check failed' }, 500); + } +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXV0aC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9taWRkbGV3YXJlL2F1dGgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQ0EsT0FBTyxFQUFFLGNBQWMsSUFBSSxNQUFNLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQztBQUNoRSxPQUFPLEVBQUUsc0JBQXNCLEVBQUUscUJBQXFCLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQUN2RixPQUFPLEVBQUUsYUFBYSxFQUFFLFFBQVEsRUFBRSxNQUFNLHdCQUF3QixDQUFDO0FBR2pFOztHQUVHO0FBQ0gsTUFBTSxDQUFDLEtBQUssVUFBVSxjQUFjLENBQUMsQ0FBVSxFQUFFLElBQVU7SUFDdkQsTUFBTSxVQUFVLEdBQUcsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxNQUFNLENBQUMsZUFBZSxDQUFDLENBQUM7SUFDakQsSUFBSSxDQUFDLFVBQVUsRUFBRSxVQUFVLENBQUMsU0FBUyxDQUFDLEVBQUUsQ0FBQztRQUNyQyxPQUFPLENBQUMsQ0FBQyxJQUFJLENBQUMsRUFBRSxLQUFLLEVBQUUsd0RBQXdELEVBQUUsRUFBRSxHQUFHLENBQUMsQ0FBQztJQUM1RixDQUFDO0lBQ0QsTUFBTSxLQUFLLEdBQUcsVUFBVSxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUN0QyxJQUFJLENBQUM7UUFDRCxNQUFNLElBQUksR0FBRyxNQUFNLGFBQWEsQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUN4QyxJQUFJLENBQUMsSUFBSSxFQUFFLENBQUM7WUFDUixPQUFPLENBQUMsQ0FBQyxJQUFJLENBQUMsRUFBRSxLQUFLLEVBQUUsMEJBQTBCLEVBQUUsRUFBRSxHQUFHLENBQUMsQ0FBQztRQUM5RCxDQUFDO1FBQ0QsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxRQUFRLEVBQUUsSUFBSSxDQUFDLEVBQUUsQ0FBQyxDQUFDO1FBQ3pCLENBQUMsQ0FBQyxHQUFHLENBQUMsTUFBTSxFQUFFLElBQUksQ0FBQyxDQUFDO1FB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 \ No newline at end of file diff --git a/dist-in/middleware/autoBan.js b/dist-in/middleware/autoBan.js new file mode 100644 index 0000000..0000ca4 --- /dev/null +++ b/dist-in/middleware/autoBan.js @@ -0,0 +1,376 @@ +import { readFileSync, writeFileSync } from 'fs'; +import { join } from 'path'; +import { logger, securityLogger } from '../commons/logger.js'; +// Configuration +const BAN_THRESHOLD = parseInt(process.env.AUTO_BAN_THRESHOLD || '5', 10); // Number of violations before ban +const VIOLATION_WINDOW_MS = parseInt(process.env.AUTO_BAN_WINDOW_MS || '10000', 10); // 1 minute default +const VIOLATION_CLEANUP_INTERVAL = 10000; // Clean up old violations every minute +console.log('Auto-ban configured with:', { + threshold: BAN_THRESHOLD, + window: VIOLATION_WINDOW_MS / 60000, + cleanupInterval: VIOLATION_CLEANUP_INTERVAL / 60000 +}); +// In-memory violation tracking +const violations = new Map(); +let banList = { + bannedIPs: [], + bannedUserIds: [], + bannedTokens: [], +}; +/** + * Load ban list from JSON file + */ +export function loadBanList() { + try { + const banListPath = join(process.cwd(), 'config', 'ban.json'); + const data = readFileSync(banListPath, 'utf-8'); + banList = JSON.parse(data); + return banList; + } + catch (error) { + logger.error({ error }, 'Failed to load ban list'); + return banList; + } +} +/** + * Save ban list to JSON file + */ +function saveBanList() { + try { + const banListPath = join(process.cwd(), 'config', 'ban.json'); + writeFileSync(banListPath, JSON.stringify(banList, null, 4), 'utf-8'); + logger.info('Ban list saved'); + } + catch (error) { + logger.error({ error }, 'Failed to save ban list'); + } +} +/** + * Get current ban list + */ +export function getBanList() { + return banList; +} +/** + * Check if an IP is banned + */ +export function isIPBanned(ip) { + return banList.bannedIPs.includes(ip); +} +/** + * Check if a user ID is banned + */ +export function isUserBanned(userId) { + return banList.bannedUserIds.includes(userId); +} +/** + * Check if an auth token is banned + */ +export function isTokenBanned(token) { + return banList.bannedTokens.includes(token); +} +/** + * Extract IP address from request + */ +export function getClientIP(c) { + // Check forwarded headers first (for proxies) + const forwarded = c.req.header('x-forwarded-for'); + if (forwarded) { + return forwarded.split(',')[0].trim(); + } + const realIp = c.req.header('x-real-ip'); + if (realIp) { + return realIp; + } + // Fallback to connection IP (works for localhost) + // In Node.js/Hono, we can try to get the remote address + try { + // @ts-ignore - accessing internal request object + const remoteAddress = c.req.raw?.socket?.remoteAddress || c.env?.ip; + if (remoteAddress) { + return remoteAddress; + } + } + catch (e) { + // Ignore errors + } + // Last resort: use localhost identifier + return '127.0.0.1'; +} +/** + * Extract user ID from authorization header + */ +function getUserId(c) { + const authHeader = c.req.header('authorization'); + if (!authHeader) + return null; + return authHeader; +} +/** + * Record a rate limit violation + */ +export function recordViolation(key) { + const now = Date.now(); + const existing = violations.get(key); + if (existing) { + // Check if violation is within the window + if (now - existing.firstViolation <= VIOLATION_WINDOW_MS) { + existing.count++; + existing.lastViolation = now; + violations.set(key, existing); + // Check if threshold exceeded + if (existing.count >= BAN_THRESHOLD) { + banEntity(key); + } + } + else { + // Reset violation count if outside window + violations.set(key, { + count: 1, + firstViolation: now, + lastViolation: now, + }); + } + } + else { + // First violation + violations.set(key, { + count: 1, + firstViolation: now, + lastViolation: now, + }); + } + logger.debug({ key, violations: violations.get(key) }, 'Violation recorded'); +} +/** + * Ban an entity (IP, user, or token) + */ +function banEntity(key) { + const [type, value] = key.split(':', 2); + const violationRecord = violations.get(key); + let added = false; + if (type === 'ip' && !banList.bannedIPs.includes(value)) { + banList.bannedIPs.push(value); + added = true; + // Log to security.json + securityLogger.warn({ + event: 'auto_ban', + type: 'ip', + ip: value, + violations: violationRecord?.count, + firstViolation: violationRecord?.firstViolation, + lastViolation: violationRecord?.lastViolation + }, 'IP auto-banned for excessive requests'); + // Also log to console + logger.info({ ip: value, violations: violationRecord?.count }, '🚫 IP auto-banned for excessive requests'); + } + else if (type === 'user' && !banList.bannedUserIds.includes(value)) { + banList.bannedUserIds.push(value); + added = true; + // Log to security.json + securityLogger.warn({ + event: 'auto_ban', + type: 'user', + userId: value, + violations: violationRecord?.count, + firstViolation: violationRecord?.firstViolation, + lastViolation: violationRecord?.lastViolation + }, 'User auto-banned for excessive requests'); + // Also log to console + logger.info({ userId: value, violations: violationRecord?.count }, '🚫 User auto-banned for excessive requests'); + } + else if (type === 'token' && !banList.bannedTokens.includes(value)) { + banList.bannedTokens.push(value); + added = true; + // Log to security.json + securityLogger.warn({ + event: 'auto_ban', + type: 'token', + token: value.substring(0, 20) + '...', + violations: violationRecord?.count, + firstViolation: violationRecord?.firstViolation, + lastViolation: violationRecord?.lastViolation + }, 'Token auto-banned for excessive requests'); + // Also log to console + logger.info({ token: value.substring(0, 20) + '...', violations: violationRecord?.count }, '🚫 Token auto-banned for excessive requests'); + } + if (added) { + saveBanList(); + // Clear violation record after ban + violations.delete(key); + } +} +/** + * Clean up old violation records + */ +function cleanupViolations() { + const now = Date.now(); + let cleaned = 0; + for (const [key, record] of violations.entries()) { + if (now - record.lastViolation > VIOLATION_WINDOW_MS) { + violations.delete(key); + cleaned++; + } + } + if (cleaned > 0) { + logger.debug({ cleaned }, 'Cleaned up old violation records'); + } +} +/** + * Auto-ban middleware + * Checks if request is from a banned entity + */ +// Simple in-memory rate limiting +const requestCounts = new Map(); +const RATE_LIMIT_MAX = parseInt(process.env.RATE_LIMIT_MAX || '20', 10); +const RATE_LIMIT_WINDOW_MS = parseInt(process.env.RATE_LIMIT_WINDOW_MS || '1000', 10); +export async function autoBanMiddleware(c, next) { + const ip = getClientIP(c); + const path = c.req.path; + const method = c.req.method; + // Skip ban/rate-limit checks for local requests (dev & e2e tests) + if (ip === '127.0.0.1' || ip === 'localhost' || ip === '::1' || ip === '::ffff:127.0.0.1') { + return next(); + } + const authHeader = c.req.header('authorization'); + const userId = getUserId(c); + // Generate key for rate limiting + let key; + if (authHeader) { + key = `user:${authHeader}`; + } + else { + key = `ip:${ip}`; + } + // Check if IP is banned + if (isIPBanned(ip)) { + /* + securityLogger.info({ + event: 'blocked_request', + type: 'ip', + ip, + path, + method + }, 'Blocked request from banned IP') + */ + // logger.info({ ip, path }, '🚫 Blocked request from banned IP') + return c.json({ + error: 'Forbidden', + message: 'Your IP address has been banned for excessive requests', + }, 403); + } + // Check if auth token is banned + if (authHeader && isTokenBanned(authHeader)) { + securityLogger.info({ + event: 'blocked_request', + type: 'token', + token: authHeader.substring(0, 20) + '...', + path, + method + }, 'Blocked request from banned token'); + logger.info({ token: authHeader.substring(0, 20) + '...', path }, '🚫 Blocked request from banned token'); + return c.json({ + error: 'Forbidden', + message: 'Your access token has been banned for excessive requests', + }, 403); + } + // Check if user ID is banned + if (userId && isUserBanned(userId)) { + securityLogger.info({ + event: 'blocked_request', + type: 'user', + userId, + path, + method + }, 'Blocked request from banned user'); + logger.info({ userId, path }, '🚫 Blocked request from banned user'); + return c.json({ + error: 'Forbidden', + message: 'Your account has been banned for excessive requests', + }, 403); + } + // Built-in rate limiting (since hono-rate-limiter isn't working) + const now = Date.now(); + const record = requestCounts.get(key); + if (record) { + if (now < record.resetTime) { + // Within the window + record.count++; + if (record.count > RATE_LIMIT_MAX) { + // Rate limit exceeded! + console.log(`⚠️ Rate limit exceeded for ${key} (${record.count}/${RATE_LIMIT_MAX})`); + recordViolation(key); + return c.json({ + error: 'Too many requests', + message: `Rate limit exceeded. Maximum ${RATE_LIMIT_MAX} requests per ${RATE_LIMIT_WINDOW_MS}ms`, + }, 429); + } + } + else { + // Window expired, reset + record.count = 1; + record.resetTime = now + RATE_LIMIT_WINDOW_MS; + } + } + else { + // First request + requestCounts.set(key, { + count: 1, + resetTime: now + RATE_LIMIT_WINDOW_MS + }); + } + await next(); +} +/** + * Manually unban an IP + */ +export function unbanIP(ip) { + const index = banList.bannedIPs.indexOf(ip); + if (index > -1) { + banList.bannedIPs.splice(index, 1); + saveBanList(); + securityLogger.info({ + event: 'unban', + type: 'ip', + ip + }, 'IP unbanned'); + logger.info({ ip }, 'IP unbanned'); + return true; + } + return false; +} +/** + * Manually unban a user + */ +export function unbanUser(userId) { + const index = banList.bannedUserIds.indexOf(userId); + if (index > -1) { + banList.bannedUserIds.splice(index, 1); + saveBanList(); + securityLogger.info({ + event: 'unban', + type: 'user', + userId + }, 'User unbanned'); + logger.info({ userId }, 'User unbanned'); + return true; + } + return false; +} +/** + * Get current violation stats + */ +export function getViolationStats() { + return { + totalViolations: violations.size, + violations: Array.from(violations.entries()).map(([key, record]) => ({ + key, + ...record, + })), + }; +} +// Load ban list on module initialization +loadBanList(); +// Start cleanup interval +setInterval(cleanupViolations, VIOLATION_CLEANUP_INTERVAL); +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXV0b0Jhbi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9taWRkbGV3YXJlL2F1dG9CYW4udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQ0EsT0FBTyxFQUFFLFlBQVksRUFBRSxhQUFhLEVBQUUsTUFBTSxJQUFJLENBQUE7QUFDaEQsT0FBTyxFQUFFLElBQUksRUFBRSxNQUFNLE1BQU0sQ0FBQTtBQUMzQixPQUFPLEVBQUUsTUFBTSxFQUFFLGNBQWMsRUFBRSxNQUFNLHNCQUFzQixDQUFBO0FBYzdELGdCQUFnQjtBQUNoQixNQUFNLGFBQWEsR0FBRyxRQUFRLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxrQkFBa0IsSUFBSSxHQUFHLEVBQUUsRUFBRSxDQUFDLENBQUEsQ0FBQyxrQ0FBa0M7QUFDNUcsTUFBTSxtQkFBbUIsR0FBRyxRQUFRLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxrQkFBa0IsSUFBSSxPQUFPLEVBQUUsRUFBRSxDQUFDLENBQUEsQ0FBQyxtQkFBbUI7QUFDdkcsTUFBTSwwQkFBMEIsR0FBRyxLQUFLLENBQUEsQ0FBQyx1Q0FBdUM7QUFFaEYsT0FBTyxDQUFDLEdBQUcsQ0FBQywyQkFBMkIsRUFBRTtJQUNyQyxTQUFTLEVBQUUsYUFBYTtJQUN4QixNQUFNLEVBQUUsbUJBQW1CLEdBQUcsS0FBSztJQUNuQyxlQUFlLEVBQUUsMEJBQTBCLEdBQUcsS0FBSztDQUN0RCxDQUFDLENBQUE7QUFFRiwrQkFBK0I7QUFDL0IsTUFBTSxVQUFVLEdBQUcsSUFBSSxHQUFHLEVBQTJCLENBQUE7QUFFckQsSUFBSSxPQUFPLEdBQVk7SUFDbkIsU0FBUyxFQUFFLEVBQUU7SUFDYixhQUFhLEVBQUUsRUFBRTtJQUNqQixZQUFZLEVBQUUsRUFBRTtDQUNuQixDQUFBO0FBRUQ7O0dBRUc7QUFDSCxNQUFNLFVBQVUsV0FBVztJQUN2QixJQUFJLENBQUM7UUFDRCxNQUFNLFdBQVcsR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDLEdB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 \ No newline at end of file diff --git a/dist-in/middleware/blocklist.js b/dist-in/middleware/blocklist.js new file mode 100644 index 0000000..c7c2eb9 --- /dev/null +++ b/dist-in/middleware/blocklist.js @@ -0,0 +1,105 @@ +import { readFileSync } from 'fs'; +import { join, dirname } from 'path'; +import { fileURLToPath } from 'url'; +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); +let blocklist = { + blockedIPs: [], + blockedUserIds: [], + blockedTokens: [], +}; +/** + * Load blocklist from JSON file + */ +export function loadBlocklist() { + try { + const blocklistPath = join(process.cwd(), 'config', 'blocklist.json'); + const data = readFileSync(blocklistPath, 'utf-8'); + blocklist = JSON.parse(data); + return blocklist; + } + catch (error) { + console.error('Failed to load blocklist:', error); + return blocklist; + } +} +/** + * Get current blocklist + */ +export function getBlocklist() { + return blocklist; +} +/** + * Check if an IP is blocked + */ +export function isIPBlocked(ip) { + return blocklist.blockedIPs.includes(ip); +} +/** + * Check if a user ID is blocked + */ +export function isUserBlocked(userId) { + return blocklist.blockedUserIds.includes(userId); +} +/** + * Check if an auth token is blocked + */ +export function isTokenBlocked(token) { + return blocklist.blockedTokens.includes(token); +} +/** + * Extract IP address from request + */ +function getClientIP(c) { + const forwarded = c.req.header('x-forwarded-for'); + if (forwarded) { + return forwarded.split(',')[0].trim(); + } + return c.req.header('x-real-ip') || 'unknown'; +} +/** + * Extract user ID from authorization header + * This is a simple implementation - adjust based on your auth strategy + */ +function getUserId(c) { + const authHeader = c.req.header('authorization'); + if (!authHeader) + return null; + // Simple extraction - in production, you'd decode JWT or validate token + // For now, we'll use the auth header as-is for blocklist checking + return authHeader; +} +/** + * Blocklist middleware + * Blocks requests from blacklisted IPs, users, or tokens + */ +export async function blocklistMiddleware(c, next) { + const ip = getClientIP(c); + const authHeader = c.req.header('authorization'); + const userId = getUserId(c); + // Check if IP is blocked + if (isIPBlocked(ip)) { + return c.json({ + error: 'Forbidden', + message: 'Your IP address has been blocked', + }, 403); + } + // Check if auth token is blocked + if (authHeader && isTokenBlocked(authHeader)) { + return c.json({ + error: 'Forbidden', + message: 'Your access token has been blocked', + }, 403); + } + // Check if user ID is blocked + if (userId && isUserBlocked(userId)) { + return c.json({ + error: 'Forbidden', + message: 'Your account has been blocked', + }, 403); + } + await next(); +} +// Load blocklist on module initialization +loadBlocklist(); +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYmxvY2tsaXN0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL21pZGRsZXdhcmUvYmxvY2tsaXN0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUNBLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxJQUFJLENBQUE7QUFDakMsT0FBTyxFQUFFLElBQUksRUFBRSxPQUFPLEVBQUUsTUFBTSxNQUFNLENBQUE7QUFDcEMsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLEtBQUssQ0FBQTtBQUVuQyxNQUFNLFVBQVUsR0FBRyxhQUFhLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQTtBQUNqRCxNQUFNLFNBQVMsR0FBRyxPQUFPLENBQUMsVUFBVSxDQUFDLENBQUE7QUFRckMsSUFBSSxTQUFTLEdBQWM7SUFDdkIsVUFBVSxFQUFFLEVBQUU7SUFDZCxjQUFjLEVBQUUsRUFBRTtJQUNsQixhQUFhLEVBQUUsRUFBRTtDQUNwQixDQUFBO0FBRUQ7O0dBRUc7QUFDSCxNQUFNLFVBQVUsYUFBYTtJQUN6QixJQUFJLENBQUM7UUFDRCxNQUFNLGFBQWEsR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDLEdBQUcsRUFBRSxFQUFFLFFBQVEsRUFBRSxnQkFBZ0IsQ0FBQyxDQUFBO1FBQ3JFLE1BQU0sSUFBSSxHQUFHLFlBQVksQ0FBQyxhQUFhLEVBQUUsT0FBTyxDQUFDLENBQUE7UUFDakQsU0FBUyxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLENBQUE7UUFDNUIsT0FBTyxTQUFTLENBQUE7SUFDcEIsQ0FBQztJQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7UUFDYixPQUFPLENBQUMsS0FBSyxDQUFDLDJCQUEyQixFQUFFLEtBQUssQ0FBQyxDQUFBO1FBQ2pELE9BQU8sU0FBUyxDQUFBO0lBQ3BCLENBQUM7QUFDTCxDQUFDO0FBRUQ7O0dBRUc7QUFDSCxNQUFNLFVBQVUsWUFBWTtJQUN4QixPQUFPLFNBQVMsQ0FBQTtBQUNwQixDQUFDO0FBRUQ7O0dBRUc7QUFDSCxNQUFNLFVBQVUsV0FBVyxDQUFDLEVBQVU7SUFDbEMsT0FBTyxTQUFTLENBQUMsVUFBVSxDQUFDLFFBQVEsQ0FBQyxFQUFFLENBQUMsQ0FBQTtBQUM1QyxDQUFDO0FBRUQ7O0dBRUc7QUFDSCxNQUFNLFVBQVUsYUFBYSxDQUFDLE1BQWM7SUFDeEMsT0FBTyxTQUFTLENBQUMsY0FBYyxDQUFDLFFBQVEsQ0FBQyxNQUFNLENBQUMsQ0FBQTtBQUNwRCxDQUFDO0FBRUQ7O0dBRUc7QUFDSCxNQUFNLFVBQVUsY0FBYyxDQUFDLEtBQWE7SUFDeEMsT0FBTyxTQUFTLENBQUMsYUFBYSxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsQ0FBQTtBQUNsRCxDQUFDO0FBRUQ7O0dBRUc7QUFDSCxTQUFTLFdBQVcsQ0FBQyxDQUFVO0lBQzNCLE1BQU0sU0FBUyxHQUFHLENBQUMsQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFDLGlCQUFpQixDQUFDLENBQUE7SUFDakQsSUFBSSxTQUFTLEVBQUUsQ0FBQztRQUNaLE9BQU8sU0FBUyxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLEVBQUUsQ0FBQTtJQUN6QyxDQUFDO0lBQ0QsT0FBTyxDQUFDLENBQUMsR0FBRyxDQUFDLE1BQU0sQ0FBQyxXQUFXLENBQUMsSUFBSSxTQUFTLENBQUE7QUFDakQsQ0FBQztBQUVEOzs7R0FHRztBQUNILFNBQVMsU0FBUyxDQUFDLENBQVU7SUFDekIsTUFBTSxVQUFVLEdBQUcsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxNQUFNLENBQUMsZUFBZSxDQUFDLENBQUE7SUFDaEQsSUFBSSxDQUFDLFVBQVU7UUFBRSxPQUFPLElBQUksQ0FBQTtJQUU1Qix3RUFBd0U7SUFDeEUsa0VBQWtFO0lBQ2xFLE9BQU8sVUFBVSxDQUFBO0FBQ3JCLENBQUM7QUFFRDs7O0dBR0c7QUFDSCxNQUFNLENBQUMsS0FBSyxVQUFVLG1CQUFtQixDQUFDLENBQVUsRUFBRSxJQUFVO0lBQzVELE1BQU0sRUFBRSxHQUFHLFdBQVcsQ0FBQyxDQUFDLENBQUMsQ0FBQTtJQUN6QixNQUFNLFVBQVUsR0FBRyxDQUFDLENBQUMsR0FBRyxDQUFDLE1BQU0sQ0FBQyxlQUFlLENBQUMsQ0FBQTtJQUNoRCxNQUFNLE1BQU0sR0FBRyxTQUFTLENBQUMsQ0FBQyxDQUFDLENBQUE7SUFFM0IseUJBQXlCO0lBQ3pCLElBQUksV0FBVyxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUM7UUFDbEIsT0FBTyxDQUFDLENBQUMsSUFBSSxDQUNUO1lBQ0ksS0FBSyxFQUFFLFdBQVc7WUFDbEIsT0FBTyxFQUFFLGtDQUFrQztTQUM5QyxFQUNELEdBQUcsQ0FDTixDQUFBO0lBQ0wsQ0FBQztJQUVELGlDQUFpQztJQUNqQyxJQUFJLFVBQVUsSUFBSSxjQUFjLENBQUMsVUFBVSxDQUFDLEVBQUUsQ0FBQztRQUMzQyxPQUFPLENBQUMsQ0FBQyxJQUFJLENBQ1Q7WUFDSSxLQUFLLEVBQUUsV0FBVztZQUNsQixPQUFPLEVBQUUsb0NBQW9DO1NBQ2hELEVBQ0QsR0FBRyxDQUNOLENBQUE7SUFDTCxDQUFDO0lBRUQsOEJBQThCO0lBQzlCLElBQUksTUFBTSxJQUFJLGFBQWEsQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDO1FBQ2xDLE9BQU8sQ0FBQyxDQUFDLElBQUksQ0FDVDtZQUNJLEtBQUssRUFBRSxXQUFXO1lBQ2xCLE9BQU8sRUFBRSwrQkFBK0I7U0FDM0MsRUFDRCxHQUFHLENBQ04sQ0FBQTtJQUNMLENBQUM7SUFFRCxNQUFNLElBQUksRUFBRSxDQUFBO0FBQ2hCLENBQUM7QUFFRCwwQ0FBMEM7QUFDMUMsYUFBYSxFQUFFLENBQUEifQ== \ No newline at end of file diff --git a/dist-in/middleware/rateLimiter.js b/dist-in/middleware/rateLimiter.js new file mode 100644 index 0000000..adc6e1e --- /dev/null +++ b/dist-in/middleware/rateLimiter.js @@ -0,0 +1,92 @@ +import { rateLimiter } from 'hono-rate-limiter'; +import { recordViolation } from './autoBan.js'; +// Rate limit configuration from environment variables +const RATE_LIMIT_MAX = parseInt(process.env.RATE_LIMIT_MAX || '1', 10); +const RATE_LIMIT_WINDOW_MS = parseInt(process.env.RATE_LIMIT_WINDOW_MS || '50', 10); +console.log('🔒 Rate Limiter Configuration:'); +console.log(` Max: ${RATE_LIMIT_MAX} requests per ${RATE_LIMIT_WINDOW_MS}ms`); +console.log(` Auto-ban threshold: ${process.env.AUTO_BAN_THRESHOLD || 10} violations`); +/** + * Rate limiter middleware configuration + * Limits requests per user/IP address + */ +export const apiRateLimiter = rateLimiter({ + windowMs: RATE_LIMIT_WINDOW_MS, // Time window in milliseconds + limit: RATE_LIMIT_MAX, // Max requests per window + standardHeaders: 'draft-6', // Return rate limit info in headers + keyGenerator: (c) => { + // Try to get user ID from auth header, fallback to IP + const authHeader = c.req.header('authorization'); + if (authHeader) { + // Extract user ID from JWT or auth token if available + // For now, use the auth header as key + return `user:${authHeader}`; + } + // Fallback to IP address + const forwarded = c.req.header('x-forwarded-for'); + const ip = forwarded ? forwarded.split(',')[0] : c.req.header('x-real-ip') || 'unknown'; + return `ip:${ip}`; + }, + handler: (c) => { + // Record violation for auto-ban tracking + const authHeader = c.req.header('authorization'); + let key; + if (authHeader) { + key = `user:${authHeader}`; + } + else { + const forwarded = c.req.header('x-forwarded-for'); + const ip = forwarded ? forwarded.split(',')[0] : c.req.header('x-real-ip') || 'unknown'; + key = `ip:${ip}`; + } + console.log(`⚠️ Rate limit exceeded for ${key}`); + recordViolation(key); + return c.json({ + error: 'Too many requests', + message: `Rate limit exceeded. Maximum ${RATE_LIMIT_MAX} requests per ${RATE_LIMIT_WINDOW_MS}ms`, + }, 429); + }, +}); +/** + * Custom rate limiter for specific endpoints with different limits + */ +export function createCustomRateLimiter(limit, windowMs) { + return rateLimiter({ + windowMs, + limit, + standardHeaders: 'draft-6', + keyGenerator: (c) => { + const authHeader = c.req.header('authorization'); + if (authHeader) { + return `user:${authHeader}`; + } + const forwarded = c.req.header('x-forwarded-for'); + const ip = forwarded ? forwarded.split(',')[0] : c.req.header('x-real-ip') || 'unknown'; + return `ip:${ip}`; + }, + handler: (c) => { + // Record violation for auto-ban tracking + const authHeader = c.req.header('authorization'); + let key; + if (authHeader) { + key = `user:${authHeader}`; + } + else { + const forwarded = c.req.header('x-forwarded-for'); + const ip = forwarded ? forwarded.split(',')[0] : c.req.header('x-real-ip') || 'unknown'; + key = `ip:${ip}`; + } + recordViolation(key); + return c.json({ + error: 'Too many requests', + message: `Rate limit exceeded. Maximum ${limit} requests per ${windowMs}ms`, + }, 429); + }, + }); +} +// Export configuration for testing +export const rateLimitConfig = { + max: RATE_LIMIT_MAX, + windowMs: RATE_LIMIT_WINDOW_MS, +}; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmF0ZUxpbWl0ZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvbWlkZGxld2FyZS9yYXRlTGltaXRlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFDQSxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sbUJBQW1CLENBQUE7QUFDL0MsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLGNBQWMsQ0FBQTtBQUU5QyxzREFBc0Q7QUFDdEQsTUFBTSxjQUFjLEdBQUcsUUFBUSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsY0FBYyxJQUFJLEdBQUcsRUFBRSxFQUFFLENBQUMsQ0FBQTtBQUN0RSxNQUFNLG9CQUFvQixHQUFHLFFBQVEsQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLG9CQUFvQixJQUFJLElBQUksRUFBRSxFQUFFLENBQUMsQ0FBQTtBQUVuRixPQUFPLENBQUMsR0FBRyxDQUFDLGdDQUFnQyxDQUFDLENBQUE7QUFDN0MsT0FBTyxDQUFDLEdBQUcsQ0FBQyxXQUFXLGNBQWMsaUJBQWlCLG9CQUFvQixJQUFJLENBQUMsQ0FBQTtBQUMvRSxPQUFPLENBQUMsR0FBRyxDQUFDLDBCQUEwQixPQUFPLENBQUMsR0FBRyxDQUFDLGtCQUFrQixJQUFJLEVBQUUsYUFBYSxDQUFDLENBQUE7QUFHeEY7OztHQUdHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sY0FBYyxHQUFHLFdBQVcsQ0FBQztJQUN0QyxRQUFRLEVBQUUsb0JBQW9CLEVBQUUsOEJBQThCO0lBQzlELEtBQUssRUFBRSxjQUFjLEVBQUUsMEJBQTBCO0lBQ2pELGVBQWUsRUFBRSxTQUFTLEVBQUUsb0NBQW9DO0lBQ2hFLFlBQVksRUFBRSxDQUFDLENBQVUsRUFBRSxFQUFFO1FBQ3pCLHNEQUFzRDtRQUN0RCxNQUFNLFVBQVUsR0FBRyxDQUFDLENBQUMsR0FBRyxDQUFDLE1BQU0sQ0FBQyxlQUFlLENBQUMsQ0FBQTtRQUNoRCxJQUFJLFVBQVUsRUFBRSxDQUFDO1lBQ2Isc0RBQXNEO1lB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 \ No newline at end of file diff --git a/dist-in/middleware/usageTracking.js b/dist-in/middleware/usageTracking.js new file mode 100644 index 0000000..3d61f24 --- /dev/null +++ b/dist-in/middleware/usageTracking.js @@ -0,0 +1,264 @@ +import { supabase } from '../commons/supabase.js'; +import { logger } from '../commons/logger.js'; +import { FunctionRegistry } from '../commons/registry.js'; +/** + * Middleware to track API usage for billing and monitoring + * Tracks request start and updates with completion status + */ +export async function usageTrackingMiddleware(c, next) { + const startTime = Date.now(); + // Extract user ID from context (set by auth middleware) + const userId = c.get('userId'); + // Skip tracking for unauthenticated requests + if (!userId) { + logger.trace('[UsageTracking] Skipping - No userId'); + await next(); + return; + } + // Determine product and action + const path = c.req.path; + const method = c.req.method; + // Use Registry to find config + const config = FunctionRegistry.findByRoute(path, method); + const product = config?.productId; + const action = config?.actionId; + logger.trace(`[UsageTracking] Identified: product=${product}, action=${action}`); + // Skip if not a tracked endpoint + if (!product || !action || !config) { + logger.info('[UsageTracking] Skipping - Not a tracked endpoint'); + await next(); + return; + } + // Generate a job ID for this request + const jobId = `${product}_${action}_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`; + // Create initial usage record with 'processing' status + let usageId = null; + try { + const { data, error } = await supabase + .from('api_usage') + .insert({ + user_id: userId, + endpoint: path, + method, + product, + action, + status: 'processing', + job_id: jobId, + cancellable: config.cancellable || false, + cost_units: config.costUnits, + metadata: { + query: c.req.query(), + userAgent: c.req.header('user-agent'), + ip: c.req.header('x-forwarded-for') || c.req.header('x-real-ip'), + }, + }) + .select('id') + .single(); + if (error) { + logger.error({ err: error }, '[UsageTracking] Error creating usage record'); + } + else if (data) { + logger.trace(`[UsageTracking] Created usage record: ${data.id}`); + usageId = data.id; + // Store usage ID in context for potential use in handlers + c.set('usageId', usageId); + c.set('jobId', jobId); + } + else { + logger.trace('[UsageTracking] No data returned from insert'); + } + } + catch (err) { + logger.error({ err }, 'Failed to create usage record'); + } + // Execute the request + let requestError = null; + try { + await next(); + } + catch (err) { + requestError = err; + throw err; // Re-throw to let error handler deal with it + } + finally { + // Update usage record with completion status + const endTime = Date.now(); + const responseTime = endTime - startTime; + if (usageId) { + // Check if handler requested to skip status update (e.g. for background jobs) + const skipUpdate = c.get('skipUsageStatusUpdate'); + if (!skipUpdate) { + updateUsageRecord({ + usageId, + responseStatus: c.res.status, + responseTimeMs: responseTime, + error: requestError, + }).catch(err => { + logger.error({ err }, 'Failed to update usage record'); + }); + } + } + } +} +/** + * Update usage record with completion status + */ +export async function updateUsageRecord(data) { + const status = data.error + ? 'failed' + : (data.responseStatus >= 200 && data.responseStatus < 300) + ? 'completed' + : 'failed'; + const updateData = { + status, + response_status: data.responseStatus, + response_time_ms: data.responseTimeMs, + }; + if (data.error) { + updateData.error_message = data.error.message; + } + const { error } = await supabase + .from('api_usage') + .update(updateData) + .eq('id', data.usageId); + if (error) { + logger.error({ err: error }, 'Error updating usage record'); + } +} +/** + * Helper function to manually track usage (for non-middleware scenarios) + */ +export async function trackUsage(data) { + try { + const { data: record, error } = await supabase + .from('api_usage') + .insert({ + user_id: data.userId, + endpoint: data.endpoint, + method: data.method, + product: data.product, + action: data.action, + status: data.responseStatus ? 'completed' : 'processing', + job_id: data.jobId, + cancellable: data.cancellable, + response_status: data.responseStatus, + response_time_ms: data.responseTimeMs, + cost_units: data.costUnits, + metadata: data.metadata, + api_key_id: data.apiKeyId, + }) + .select('id') + .single(); + if (error) { + logger.error({ err: error }, 'Error tracking usage'); + return null; + } + return record?.id || null; + } + catch (err) { + logger.error({ err }, 'Failed to track usage'); + return null; + } +} +/** + * Cancel a job by job ID + */ +export async function cancelJob(userId, jobId) { + try { + const { data, error } = await supabase + .from('api_usage') + .update({ + status: 'cancelled', + }) + .eq('user_id', userId) + .eq('job_id', jobId) + .eq('cancellable', true) + .in('status', ['pending', 'processing']) + .select('id'); + if (error) { + logger.error({ err: error }, 'Error cancelling job'); + return false; + } + return !!data && data.length > 0; + } + catch (err) { + logger.error({ err }, 'Failed to cancel job'); + return false; + } +} +/** + * Get active (cancellable) jobs for a user + */ +export async function getActiveJobs(userId) { + try { + const { data, error } = await supabase + .from('api_usage') + .select('id, job_id, product, action, status, created_at, metadata') + .eq('user_id', userId) + .eq('cancellable', true) + .in('status', ['pending', 'processing']) + .order('created_at', { ascending: false }); + if (error) { + logger.error({ err: error }, 'Error fetching active jobs'); + return []; + } + return data || []; + } + catch (err) { + logger.error({ err }, 'Failed to fetch active jobs'); + return []; + } +} +/** + * Pause a job by job ID + */ +export async function pauseJob(userId, jobId) { + try { + const { data, error } = await supabase + .from('api_usage') + .update({ + status: 'paused', + }) + .eq('user_id', userId) + .eq('job_id', jobId) + .eq('cancellable', true) + .eq('status', 'processing') // Only processing jobs can be paused + .select('id'); + if (error) { + logger.error({ err: error }, 'Error pausing job'); + return false; + } + return !!data && data.length > 0; + } + catch (err) { + logger.error({ err }, 'Failed to pause job'); + return false; + } +} +/** + * Resume a paused job by job ID + */ +export async function resumeJob(userId, jobId) { + try { + const { data, error } = await supabase + .from('api_usage') + .update({ + status: 'processing', + }) + .eq('user_id', userId) + .eq('job_id', jobId) + .eq('cancellable', true) + .eq('status', 'paused') // Only paused jobs can be resumed + .select('id'); + if (error) { + logger.error({ err: error }, 'Error resuming job'); + return false; + } + return !!data && data.length > 0; + } + catch (err) { + logger.error({ err }, 'Failed to resume job'); + return false; + } +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXNhZ2VUcmFja2luZy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9taWRkbGV3YXJlL3VzYWdlVHJhY2tpbmcudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQ0EsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLHdCQUF3QixDQUFDO0FBQ2xELE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQztBQUM5QyxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQWlCMUQ7OztHQUdHO0FBQ0gsTUFBTSxDQUFDLEtBQUssVUFBVSx1QkFBdUIsQ0FBQyxDQUFVLEVBQUUsSUFBVTtJQUNoRSxNQUFNLFNBQVMsR0FBRyxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUM7SUFFN0Isd0RBQXdEO0lBQ3hELE1BQU0sTUFBTSxHQUFHLENBQUMsQ0FBQyxHQUFHLENBQUMsUUFBUSxDQUFDLENBQUM7SUFDL0IsNkNBQTZDO0lBQzdDLElBQUksQ0FBQyxNQUFNLEVBQUUsQ0FBQztRQUNWLE1BQU0sQ0FBQyxLQUFLLENBQUMsc0NBQXNDLENBQUMsQ0FBQztRQUNyRCxNQUFNLElBQUksRUFBRSxDQUFDO1FBQ2IsT0FBTztJQUNYLENBQUM7SUFFRCwrQkFBK0I7SUFDL0IsTUFBTSxJQUFJLEdBQUcsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUM7SUFDeEIsTUFBTSxNQUFNLEdBQUcsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxNQUFNLENBQUM7SUFFNUIsOEJBQThCO0lBQzlCLE1BQU0sTUFBTSxHQUFHLGdCQUFnQixDQUFDLFdBQVcsQ0FBQyxJQUFJLEVBQUUsTUFBTSxDQUFDLENBQUM7SUFDMUQsTUFBTSxPQUFPLEdBQUcsTUFBTSxFQUFFLFNBQVMsQ0FBQztJQUNsQyxNQUFNLE1BQU0sR0FBRyxNQUFNLEVBQUUsUUFBUSxDQUFDO0lBRWhDLE1BQU0sQ0FBQyxLQUFLLENBQUMsdUNBQXVDLE9BQU8sWUFBWSxNQUFNLEVB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 \ No newline at end of file diff --git a/dist-in/products/AbstractProduct.js b/dist-in/products/AbstractProduct.js new file mode 100644 index 0000000..5b7cfca --- /dev/null +++ b/dist-in/products/AbstractProduct.js @@ -0,0 +1,102 @@ +import EventEmitter from 'events'; +import { createHash } from 'crypto'; +import { streamSSE } from 'hono/streaming'; +import { ProductErrorCode } from './enums.js'; +import { ProductError } from './errors.js'; +import { logger } from '../commons/logger.js'; +export class AbstractProduct extends EventEmitter { + async start(boss) { + try { + await this.onStart(boss); + } + catch (error) { + throw new ProductError(ProductErrorCode.START_FAILED, { + message: `Failed to start product ${this.id}: ${error.message}`, + originalError: error + }); + } + } + async onStart(boss) { + // Optional hook for subclasses + } + async stop() { + try { + await this.onStop(); + } + catch (error) { + throw new ProductError(ProductErrorCode.STOP_FAILED, { + message: `Failed to stop product ${this.id}: ${error.message}`, + originalError: error + }); + } + } + async onStop() { + // Optional hook + } + async pause() { + // No-op for now as we removed pgboss + } + async resume() { + // No-op for now as we removed pgboss + } + async handleStream(c, options) { + const { data, userId, forceRefresh, fetcher, cacheChecker } = options; + const inputHash = this.generateHash(data); + return streamSSE(c, async (stream) => { + try { + await stream.writeSSE({ + event: 'progress', + data: JSON.stringify({ stage: 'starting', percent: 0 }) + }); + if (!forceRefresh && cacheChecker) { + await stream.writeSSE({ + event: 'progress', + data: JSON.stringify({ stage: 'checking_cache', percent: 10 }) + }); + const cached = await cacheChecker(inputHash); + if (cached) { + for (let i = 0; i < cached.length; i++) { + await stream.writeSSE({ + event: 'result', + data: JSON.stringify(cached[i]) + }); + } + await stream.writeSSE({ + event: 'complete', + data: JSON.stringify({ total: cached.length, cached: true }) + }); + return; + } + } + await stream.writeSSE({ + event: 'progress', + data: JSON.stringify({ stage: 'fetching_from_api', percent: 20 }) + }); + const results = await fetcher(data, userId); + for (let i = 0; i < results.length; i++) { + await stream.writeSSE({ + event: 'result', + data: JSON.stringify(results[i]) + }); + } + await stream.writeSSE({ + event: 'complete', + data: JSON.stringify({ total: results.length, cached: false }) + }); + } + catch (error) { + logger.error(error, `[${this.id}] Stream error`); + await stream.writeSSE({ + event: 'error', + data: JSON.stringify({ error: error.message || 'Internal Server Error' }) + }); + } + }); + } + // Helper for hashing + generateHash(params) { + const normalizedInput = JSON.stringify(params, Object.keys(params).sort()); + return createHash('sha256').update(normalizedInput).digest('hex'); + } +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQWJzdHJhY3RQcm9kdWN0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3Byb2R1Y3RzL0Fic3RyYWN0UHJvZHVjdC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLFlBQVksTUFBTSxRQUFRLENBQUM7QUFDbEMsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLFFBQVEsQ0FBQztBQUNwQyxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFFM0MsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sWUFBWSxDQUFDO0FBQzlDLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFDM0MsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBZ0I5QyxNQUFNLE9BQWdCLGVBQWdDLFNBQVEsWUFBWTtJQU90RSxLQUFLLENBQUMsS0FBSyxDQUFDLElBQVU7UUFDbEIsSUFBSSxDQUFDO1lBQ0QsTUFBTSxJQUFJLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDO1FBQzdCLENBQUM7UUFBQyxPQUFPLEtBQVUsRUFBRSxDQUFDO1lBQ2xCLE1BQU0sSUFBSSxZQUFZLENBQUMsZ0JBQWdCLENBQUMsWUFBWSxFQUFFO2dCQUNsRCxPQUFPLEVBQUUsMkJBQTJCLElBQUksQ0FBQyxFQUFFLEtBQUssS0FBSyxDQUFDLE9BQU8sRUFBRTtnQkFDL0QsYUFBYSxFQUFFLEtBQUs7YUFDdkIsQ0FBQyxDQUFDO1FBQ1AsQ0FBQztJQUNMLENBQUM7SUFFUyxLQUFLLENBQUMsT0FBTyxDQUFDLElBQVU7UUFDOUIsK0JBQStCO0lBQ25DLENBQUM7SUFFRCxLQUFLLENBQUMsSUFBSTtRQUNOLElBQUksQ0FBQztZQUNELE1BQU0sSUFBSSxDQUFDLE1BQU0sRUFBRSxDQUFDO1FBQ3hCLENBQUM7UUFBQyxPQUFPLEtBQVUsRUFBRSxDQUFDO1lBQ2xCLE1BQU0sSUFBSSxZQUFZLENBQUMsZ0JBQWdCLENB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 \ No newline at end of file diff --git a/dist-in/products/EventBus.js b/dist-in/products/EventBus.js new file mode 100644 index 0000000..22c5ee9 --- /dev/null +++ b/dist-in/products/EventBus.js @@ -0,0 +1,3 @@ +import EventEmitter from 'events'; +export const EventBus = new EventEmitter(); +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiRXZlbnRCdXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvcHJvZHVjdHMvRXZlbnRCdXMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxZQUFZLE1BQU0sUUFBUSxDQUFDO0FBRWxDLE1BQU0sQ0FBQyxNQUFNLFFBQVEsR0FBRyxJQUFJLFlBQVksRUFBRSxDQUFDIn0= \ No newline at end of file diff --git a/dist-in/products/analytics/index.js b/dist-in/products/analytics/index.js new file mode 100644 index 0000000..de6d68b --- /dev/null +++ b/dist-in/products/analytics/index.js @@ -0,0 +1,122 @@ +import { streamSSE } from 'hono/streaming'; +import { AbstractProduct } from '../AbstractProduct.js'; +import { getAnalyticsRoute, getAnalyticsStreamRoute, deleteAnalyticsRoute } from './routes.js'; +import { analyticsEmitter } from '../../lib/analytics-emitter.js'; +import fs from 'fs'; +import path from 'path'; +import readline from 'readline'; +const ANALYTICS_FILE = path.resolve(process.cwd(), 'logs/analytics.jsonl'); +export class AnalyticsProduct extends AbstractProduct { + id = 'analytics'; + jobOptions = {}; + actions = {}; // Optional: Add actions if needed for jobs + workers = []; + routes = []; + hash = () => 'analytics-hash'; + meta = () => ({}); + constructor() { + super(); + this.initializeRoutes(); + } + initializeRoutes() { + this.routes.push({ + definition: getAnalyticsRoute, + handler: this.handleGetAnalytics.bind(this) + }); + this.routes.push({ + definition: getAnalyticsStreamRoute, + handler: this.handleGetAnalyticsStream.bind(this) + }); + this.routes.push({ + definition: deleteAnalyticsRoute, + handler: this.handleDeleteAnalytics.bind(this) + }); + } + // ... existing handlers + async handleDeleteAnalytics(c) { + try { + if (fs.existsSync(ANALYTICS_FILE)) { + // Truncate file + await fs.promises.truncate(ANALYTICS_FILE, 0); + } + return c.json({ success: true }); + } + catch (err) { + console.error('Error clearing analytics:', err); + return c.json({ error: 'Internal Server Error' }, 500); + } + } + async handleGetAnalyticsStream(c) { + return streamSSE(c, async (stream) => { + const listener = async (entry) => { + await stream.writeSSE({ + data: JSON.stringify(entry), + event: 'log', + }); + }; + analyticsEmitter.on('log', listener); + // Keep connection alive or handle disconnect + // Hono's streamSSE handles closing the stream when the connection drops, + // but we need to remove the listener to avoid leaks. + stream.onAbort(() => { + analyticsEmitter.off('log', listener); + }); + // Wait forever (or until client disconnects) + while (true) { + await new Promise(resolve => setTimeout(resolve, 1000)); + } + }); + } + async handleGetAnalytics(c) { + try { + const limit = parseInt(c.req.query('limit') || '100', 10); + const startDateStr = c.req.query('startDate'); + const endDateStr = c.req.query('endDate'); + const startDate = startDateStr ? new Date(startDateStr).getTime() : 0; + const endDate = endDateStr ? new Date(endDateStr).getTime() : Date.now(); + if (!fs.existsSync(ANALYTICS_FILE)) { + return c.json([]); + } + // Efficiently read last N lines would be better, but for "filtered" queries we generally need to scan. + // If file is huge, this is slow. + // However, typical usage for "analytics middleware... for now" implies simple logging. + // We will stream the file from the beginning (or end if we could) and collect matching entries. + // To respect 'limit' effectively with date filters, we ideally want the *latest* entries. + // So reading from end or collecting all and sorting/slicing is needed. + // Collecting all in memory is dangerous for large files. + // But implementing reverse line reading is complex without a library. + // Compromise: Read all, parse, filter, take last N. + // Optimization: If no date filter, reasonable to assume we want latest. + const logs = []; + const fileStream = fs.createReadStream(ANALYTICS_FILE); + const rl = readline.createInterface({ + input: fileStream, + crlfDelay: Infinity + }); + for await (const line of rl) { + if (!line.trim()) + continue; + try { + const entry = JSON.parse(line); + const timestamp = new Date(entry.timestamp).getTime(); + if (timestamp >= startDate && timestamp <= endDate) { + logs.push(entry); + } + } + catch (e) { + // Ignore bad lines + } + } + // Sort by timestamp desc + logs.sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime()); + // Limit + const result = logs.slice(0, limit); + return c.json(result); + } + catch (err) { + console.error('Error reading analytics:', err); + return c.json({ error: 'Internal Server Error' }, 500); + } + } +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvcHJvZHVjdHMvYW5hbHl0aWNzL2luZGV4LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUNBLE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUMzQyxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sdUJBQXVCLENBQUM7QUFDeEQsT0FBTyxFQUFFLGlCQUFpQixFQUFFLHVCQUF1QixFQUFFLG9CQUFvQixFQUFFLE1BQU0sYUFBYSxDQUFDO0FBQy9GLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLGdDQUFnQyxDQUFDO0FBRWxFLE9BQU8sRUFBRSxNQUFNLElBQUksQ0FBQztBQUNwQixPQUFPLElBQUksTUFBTSxNQUFNLENBQUM7QUFDeEIsT0FBTyxRQUFRLE1BQU0sVUFBVSxDQUFDO0FBRWhDLE1BQU0sY0FBYyxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLEdBQUcsRUFBRSxFQUFFLHNCQUFzQixDQUFDLENBQUM7QUFFM0UsTUFBTSxPQUFPLGdCQUFpQixTQUFRLGVBQW9CO0lBQ3RELEVBQUUsR0FBRyxXQUFXLENBQUM7SUFDakIsVUFBVSxHQUFHLEVBQUUsQ0FBQztJQUNoQixPQUFPLEdBQUcsRUFBRSxDQUFDLENBQUMsMkNBQTJDO0lBQ3pELE9BQU8sR0FBVSxFQUFFLENBQUM7SUFDcEIsTUFBTSxHQUFVLEVBQUUsQ0FBQztJQUNuQixJQUFJLEdBQUcsR0FBRyxFQUFFLENBQUMsZ0JBQWdCLENBQUM7SUFDOUIsSUFBSSxHQUFHLEdBQUcsRUFBRSxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUM7SUFFbEI7UUFDSSxLQUFLLEVBQUUsQ0FBQztRQUNSLElBQUksQ0FBQyxnQkFBZ0IsRUFBRSxDQUFDO0lBQzVCLENBQUM7SUFFRCxnQkFBZ0I7UUFDWixJQUFJLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQztZQUNiLFVBQVUsRUFBRSxp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 \ No newline at end of file diff --git a/dist-in/products/analytics/routes.js b/dist-in/products/analytics/routes.js new file mode 100644 index 0000000..1fd7480 --- /dev/null +++ b/dist-in/products/analytics/routes.js @@ -0,0 +1,81 @@ +import { createRoute, z } from '@hono/zod-openapi'; +export const getAnalyticsRoute = createRoute({ + method: 'get', + path: '/api/analytics', + tags: ['Analytics'], + summary: 'Get Analytics Data', + description: 'Retrieve analytics data from the log file, optionally filtered by date.', + security: [{ bearerAuth: [] }], + request: { + query: z.object({ + limit: z.string().optional().default('100').openapi({ description: 'Number of entries to return (default 100)' }), + startDate: z.string().optional().openapi({ description: 'Filter entries after this date (ISO string)' }), + endDate: z.string().optional().openapi({ description: 'Filter entries before this date (ISO string)' }), + }), + }, + responses: { + 200: { + description: 'Analytics Data', + content: { + 'application/json': { + schema: z.array(z.object({ + timestamp: z.string(), + method: z.string(), + path: z.string(), + status: z.number(), + ip: z.string(), + userAgent: z.string().optional(), + referer: z.string().optional(), + userId: z.string().optional() + })), + }, + }, + }, + 401: { + description: 'Unauthorized', + }, + }, +}); +export const getAnalyticsStreamRoute = createRoute({ + method: 'get', + path: '/api/analytics/stream', + tags: ['Analytics'], + summary: 'Stream Analytics Data', + description: 'Stream real-time analytics data via Server-Sent Events (SSE).', + security: [{ bearerAuth: [] }], + responses: { + 200: { + description: 'Analytics Event Stream', + content: { + 'text/event-stream': { + schema: z.string(), + }, + }, + }, + 401: { + description: 'Unauthorized', + }, + }, +}); +export const deleteAnalyticsRoute = createRoute({ + method: 'delete', + path: '/api/analytics', + tags: ['Analytics'], + summary: 'Clear Analytics Data', + description: 'Clear all analytics data from the log file.', + security: [{ bearerAuth: [] }], + responses: { + 200: { + description: 'Analytics Data Cleared', + content: { + 'application/json': { + schema: z.object({ success: z.boolean() }), + }, + }, + }, + 401: { + description: 'Unauthorized', + }, + }, +}); +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm91dGVzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3Byb2R1Y3RzL2FuYWx5dGljcy9yb3V0ZXMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFdBQVcsRUFBRSxDQUFDLEVBQUUsTUFBTSxtQkFBbUIsQ0FBQztBQUVuRCxNQUFNLENBQUMsTUFBTSxpQkFBaUIsR0FBRyxXQUFXLENBQUM7SUFDekMsTUFBTSxFQUFFLEtBQUs7SUFDYixJQUFJLEVBQUUsZ0JBQWdCO0lBQ3RCLElBQUksRUFBRSxDQUFDLFdBQVcsQ0FBQztJQUNuQixPQUFPLEVBQUUsb0JBQW9CO0lBQzdCLFdBQVcsRUFBRSx5RUFBeUU7SUFDdEYsUUFBUSxFQUFFLENBQUMsRUFBRSxVQUFVLEVBQUUsRUFBRSxFQUFFLENBQUM7SUFDOUIsT0FBTyxFQUFFO1FBQ0wsS0FBSyxFQUFFLENBQUMsQ0FBQyxNQUFNLENBQUM7WUFDWixLQUFLLEVBQUUsQ0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDLFFBQVEsRUFBRSxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsQ0FBQyxPQUFPLENBQUMsRUFBRSxXQUFXLEVBQUUsMkNBQTJDLEVBQUUsQ0FBQztZQUNqSCxTQUFTLEVBQUUsQ0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDLFFBQVEsRUFBRSxDQUFDLE9BQU8sQ0FBQyxFQUFFLFdBQVcsRUFBRSw2Q0FBNkMsRUFBRSxDQUFDO1lBQ3hHLE9BQU8sRUFBRSxDQUFDLENBQUMsTUFBTSxFQUFFLENBQUMsUUFBUSxFQUFFLENBQUMsT0FBTyxDQUFDLEVBQUUsV0FBVyxFQUFFLDhDQUE4QyxFQUFFLENBQUM7U0FDMUcsQ0FBQztLQUNMO0lBQ0QsU0FBUyxFQUFFO1FBQ1AsR0FBRyxFQUFFO1lBQ0QsV0FBVyxFQUFFLGdCQUFnQjtZQUM3QixPQUFPLEVBQUU7Z0JBQ0wsa0JBQWtCLEVBQUU7b0JBQ2hCLE1BQU0sRUFBRSxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUM7d0JBQ3JCLFNBQVMsRUFBRSxDQUFDLENBQUMsTUFBTSxFQUFFO3dCQUNyQixNQUFNLEVBQUUsQ0FBQyxDQUFDLE1BQU0sRUFBRTt3QkFDbEIsSUFBSSxFQUFFLENBQUMsQ0FBQyxNQUFNLEVBQUU7d0JBQ2hCLE1BQU0sRUFBRSxDQUFDLENBQUMsTUFBTSxFQUFFO3dCQUNsQixFQUFFLEVBQUUsQ0FBQyxDQUFDLE1BQU0sRUFBRTt3QkFDZCxTQUFTLEVBQUUsQ0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDLFFBQVEsRUFBRTt3QkFDaEMsT0FBTyxFQUFFLENBQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxRQUFRLEVBQUU7d0JBQzlCLE1BQU0sRUFBRSxDQUFDLENBQUMsTUFBTSxFQUFFLENBQUMsUUFBUSxFQUFFO3FCQUNoQyxDQUFDLENBQUM7aUJBQ047YUFDSjtTQUNKO1FBQ0QsR0FBRyxFQUFFO1lBQ0QsV0FBVyxFQUFFLGNBQWM7U0FDOUI7S0FDSjtDQUNKLENBQUMsQ0FBQztBQUVILE1BQU0sQ0FBQyxNQUFNLHVCQUF1QixHQUFHLFdBQVcsQ0FBQztJQUMvQyxNQUFNLEVBQUUsS0FBSztJQUNiLElBQUksRUFBRSx1QkFBdUI7SUFDN0IsSUFBSSxFQUFFLENBQUMsV0FBVyxDQUFDO0lBQ25CLE9BQU8sRUFBRSx1QkFBdUI7SUFDaEMsV0FBVyxFQUFFLCtEQUErRDtJQUM1RSxRQUFRLEVBQUUsQ0FBQyxFQUFFLFVBQVUsRUFBRSxFQUFFLEVBQUUsQ0FBQztJQUM5QixTQUFTLEVBQUU7UUFDUCxHQUFHLEVBQUU7WUFDRCxXQUFXLEVBQUUsd0JBQXdCO1lBQ3JDLE9BQU8sRUFBRTtnQkFDTCxtQkFBbUIsRUFBRTtvQkFDakIsTUFBTSxFQUFFLENBQUMsQ0FBQyxNQUFNLEVBQUU7aUJBQ3JCO2FBQ0o7U0FDSjtRQUNELEdBQUcsRUFBRTtZQUNELFdBQVcsRUFBRSxjQUFjO1NBQzlCO0tBQ0o7Q0FFSixDQUFDLENBQUM7QUFFSCxNQUFNLENBQUMsTUFBTSxvQkFBb0IsR0FBRyxXQUFXLENBQUM7SUFDNUMsTUFBTSxFQUFFLFFBQVE7SUFDaEIsSUFBSSxFQUFFLGdCQUFnQjtJQUN0QixJQUFJLEVBQUUsQ0FBQyxXQUFXLENBQUM7SUFDbkIsT0FBTyxFQUFFLHNCQUFzQjtJQUMvQixXQUFXLEVBQUUsNkNBQTZDO0lBQzFELFFBQVEsRUFBRSxDQUFDLEVBQUUsVUFBVSxFQUFFLEVBQUUsRUFBRSxDQUFDO0lBQzlCLFNBQVMsRUFBRTtRQUNQLEdBQUcsRUFBRTtZQUNELFdBQVcsRUFBRSx3QkFBd0I7WUFDckMsT0FBTyxFQUFFO2dCQUNMLGtCQUFrQixFQUFFO29CQUNoQixNQUFNLEVBQUUsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxFQUFFLE9BQU8sRUFBRSxDQUFDLENBQUMsT0FBTyxFQUFFLEVBQUUsQ0FBQztpQkFDN0M7YUFDSjtTQUNKO1FBQ0QsR0FBRyxFQUFFO1lBQ0QsV0FBVyxFQUFFLGNBQWM7U0FDOUI7S0FDSjtDQUNKLENBQUMsQ0FBQyJ9 \ No newline at end of file diff --git a/dist-in/products/enums.js b/dist-in/products/enums.js new file mode 100644 index 0000000..6013f8a --- /dev/null +++ b/dist-in/products/enums.js @@ -0,0 +1,20 @@ +export var ProductErrorCode; +(function (ProductErrorCode) { + // Lifecycle Errors + ProductErrorCode["START_FAILED"] = "PRODUCT_START_FAILED"; + ProductErrorCode["STOP_FAILED"] = "PRODUCT_STOP_FAILED"; + ProductErrorCode["PAUSE_FAILED"] = "PRODUCT_PAUSE_FAILED"; + ProductErrorCode["RESUME_FAILED"] = "PRODUCT_RESUME_FAILED"; + // Worker Errors + ProductErrorCode["WORKER_REGISTRATION_FAILED"] = "WORKER_REGISTRATION_FAILED"; + ProductErrorCode["WORKER_NOT_FOUND"] = "WORKER_NOT_FOUND"; + // Job Errors + ProductErrorCode["JOB_SUBMISSION_FAILED"] = "JOB_SUBMISSION_FAILED"; + ProductErrorCode["JOB_TIMEOUT"] = "JOB_TIMEOUT"; + // Configuration Errors + ProductErrorCode["INVALID_CONFIG"] = "INVALID_CONFIG"; + ProductErrorCode["MISSING_DEPENDENCY"] = "MISSING_DEPENDENCY"; + // Generic + ProductErrorCode["UNKNOWN_ERROR"] = "UNKNOWN_ERROR"; +})(ProductErrorCode || (ProductErrorCode = {})); +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZW51bXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvcHJvZHVjdHMvZW51bXMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsTUFBTSxDQUFOLElBQVksZ0JBcUJYO0FBckJELFdBQVksZ0JBQWdCO0lBQ3hCLG1CQUFtQjtJQUNuQix5REFBcUMsQ0FBQTtJQUNyQyx1REFBbUMsQ0FBQTtJQUNuQyx5REFBcUMsQ0FBQTtJQUNyQywyREFBdUMsQ0FBQTtJQUV2QyxnQkFBZ0I7SUFDaEIsNkVBQXlELENBQUE7SUFDekQseURBQXFDLENBQUE7SUFFckMsYUFBYTtJQUNiLG1FQUErQyxDQUFBO0lBQy9DLCtDQUEyQixDQUFBO0lBRTNCLHVCQUF1QjtJQUN2QixxREFBaUMsQ0FBQTtJQUNqQyw2REFBeUMsQ0FBQTtJQUV6QyxVQUFVO0lBQ1YsbURBQStCLENBQUE7QUFDbkMsQ0FBQyxFQXJCVyxnQkFBZ0IsS0FBaEIsZ0JBQWdCLFFBcUIzQiJ9 \ No newline at end of file diff --git a/dist-in/products/errors.js b/dist-in/products/errors.js new file mode 100644 index 0000000..612dd1b --- /dev/null +++ b/dist-in/products/errors.js @@ -0,0 +1,20 @@ +export class ProductError extends Error { + code; + payload; + constructor(code, payload) { + const message = typeof payload === 'string' ? payload : payload.message; + super(message); + this.code = code; + this.payload = typeof payload === 'string' ? { message: payload } : payload; + // Restore prototype chain + Object.setPrototypeOf(this, new.target.prototype); + } + toJSON() { + return { + code: this.code, + message: this.message, + payload: this.payload + }; + } +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXJyb3JzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3Byb2R1Y3RzL2Vycm9ycy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFPQSxNQUFNLE9BQU8sWUFBYSxTQUFRLEtBQUs7SUFDbkIsSUFBSSxDQUFtQjtJQUN2QixPQUFPLENBQXNCO0lBRTdDLFlBQVksSUFBc0IsRUFBRSxPQUFxQztRQUNyRSxNQUFNLE9BQU8sR0FBRyxPQUFPLE9BQU8sS0FBSyxRQUFRLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQztRQUN4RSxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDZixJQUFJLENBQUMsSUFBSSxHQUFHLElBQUksQ0FBQztRQUNqQixJQUFJLENBQUMsT0FBTyxHQUFHLE9BQU8sT0FBTyxLQUFLLFFBQVEsQ0FBQyxDQUFDLENBQUMsRUFBRSxPQUFPLEVBQUUsT0FBTyxFQUFFLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQztRQUU1RSwwQkFBMEI7UUFDMUIsTUFBTSxDQUFDLGNBQWMsQ0FBQyxJQUFJLEVBQUUsR0FBRyxDQUFDLE1BQU0sQ0FBQyxTQUFTLENBQUMsQ0FBQztJQUN0RCxDQUFDO0lBRUQsTUFBTTtRQUNGLE9BQU87WUFDSCxJQUFJLEVBQUUsSUFBSSxDQUFDLElBQUk7WUFDZixPQUFPLEVBQUUsSUFBSSxDQUFDLE9BQU87WUFDckIsT0FBTyxFQUFFLElBQUksQ0FBQyxPQUFPO1NBQ3hCLENBQUM7SUFDTixDQUFDO0NBQ0oifQ== \ No newline at end of file diff --git a/dist-in/products/openai/handlers.js b/dist-in/products/openai/handlers.js new file mode 100644 index 0000000..b7bea5c --- /dev/null +++ b/dist-in/products/openai/handlers.js @@ -0,0 +1,84 @@ +import { logger } from '../../commons/logger.js'; +import { createClient } from '@supabase/supabase-js'; +// Helper to get Supabase credentials (copied from auth middleware logic) +const getSupabaseCredentials = () => { + const url = process.env.SUPABASE_URL; + const key = process.env.SUPABASE_SERVICE_KEY; + if (!url || !key) { + throw new Error('Supabase credentials missing via process.env'); + } + return { url, key }; +}; +export async function handleChatCompletions(c) { + const userId = c.get('userId'); + if (!userId) { + return c.json({ error: 'Unauthorized' }, 401); + } + try { + // 1. Fetch User API Key + const { url, key } = getSupabaseCredentials(); + const supabase = createClient(url, key); + const { data: userSecrets, error: secretsError } = await supabase + .from('user_secrets') + .select('settings') + .eq('user_id', userId) + .maybeSingle(); + if (secretsError) { + logger.error({ err: secretsError, userId }, 'Failed to fetch user secrets'); + return c.json({ error: 'Internal Server Error' }, 500); + } + // Add debug logging + logger.debug({ userId, hasSecrets: !!userSecrets, settings: userSecrets?.settings }, 'Checking for OpenAI API key'); + const apiKey = userSecrets?.settings?.api_keys?.openai_api_key; + if (!apiKey) { + logger.warn({ userId }, 'Missing OpenAI API key in user_secrets'); + return c.json({ error: 'OpenAI API key not found. Please add it to your profile settings.' }, 400); + } + // 2. Prepare Request to OpenAI + const body = await c.req.json(); + // Log request (sanitize sensitive data) + logger.info({ userId, model: body.model }, 'Proxying OpenAI request'); + const headers = { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${apiKey}`, + }; + // 3. Make Request to OpenAI + const response = await fetch('https://api.openai.com/v1/chat/completions', { + method: 'POST', + headers, + body: JSON.stringify(body), + }); + // 4. Handle Response + if (!response.ok) { + const errorText = await response.text(); + logger.error({ status: response.status, errorText, userId }, 'OpenAI API error'); + // Try to parse error as JSON to return proper error object + try { + const errorJson = JSON.parse(errorText); + return c.json(errorJson, response.status); + } + catch (e) { + return c.text(errorText, response.status); + } + } + // 5. Stream Response if requested + if (body.stream) { + // Need to handle streaming response properly in Hono/Node + // We can return the body stream directly + return new Response(response.body, { + headers: { + 'Content-Type': 'text/event-stream', + 'Cache-Control': 'no-cache', + 'Connection': 'keep-alive', + } + }); + } + const data = await response.json(); + return c.json(data); + } + catch (err) { + logger.error({ err, userId }, 'OpenAI Proxy handler failed'); + return c.json({ error: 'Internal Server Error' }, 500); + } +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaGFuZGxlcnMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvcHJvZHVjdHMvb3BlbmFpL2hhbmRsZXJzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUNBLE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUNqRCxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sdUJBQXVCLENBQUM7QUFFckQseUVBQXlFO0FBQ3pFLE1BQU0sc0JBQXNCLEdBQUcsR0FBRyxFQUFFO0lBQ2hDLE1BQU0sR0FBRyxHQUFHLE9BQU8sQ0FBQyxHQUFHLENBQUMsWUFBWSxDQUFDO0lBQ3JDLE1BQU0sR0FBRyxHQUFHLE9BQU8sQ0FBQyxHQUFHLENBQUMsb0JBQW9CLENBQUM7SUFDN0MsSUFBSSxDQUFDLEdBQUcsSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFDO1FBQ2YsTUFBTSxJQUFJLEtBQUssQ0FBQyw4Q0FBOEMsQ0FBQyxDQUFDO0lBQ3BFLENBQUM7SUFDRCxPQUFPLEVBQUUsR0FBRyxFQUFFLEdBQUcsRUFBRSxDQUFDO0FBQ3hCLENBQUMsQ0FBQztBQUVGLE1BQU0sQ0FBQyxLQUFLLFVBQVUscUJBQXFCLENBQUMsQ0FBVTtJQUNsRCxNQUFNLE1BQU0sR0FBRyxDQUFDLENBQUMsR0FBRyxDQUFDLFFBQVEsQ0FBQyxDQUFDO0lBQy9CLElBQUksQ0FBQyxNQUFNLEVBQUUsQ0FBQztRQUNWLE9BQU8sQ0FBQyxDQUFDLElBQUksQ0FBQyxFQUFFLEtBQUssRUFBRSxjQUFjLEVBQUUsRUFBRSxHQUFHLENBQUMsQ0FBQztJQUNsRCxDQUFDO0lBRUQsSUFBSSxDQUFDO1FBQ0Qsd0JBQXdCO1FBQ3hCLE1BQU0sRUFBRSxHQUFHLEVBQUUsR0FBRyxFQUFFLEdBQUcsc0JBQXNCLEVBQUUsQ0FBQztRQUM5QyxNQUFNLFFBQVEsR0FBRyxZQUFZLENBQUMsR0FBRyxFQUFFLEdBQUcsQ0FBQyxDQUFDO1FBRXhDLE1BQU0sRUFBRSxJQUFJLEVBQUUsV0FBVyxFQUFFLEtBQUssRUFBRSxZQUFZLEVBQUUsR0FBRyxNQUFNLFFBQVE7YUFDNUQsSUFBSSxDQUFDLGNBQWMsQ0FBQzthQUNwQixNQUFNLENBQUMsVUFBVSxDQUFDO2FBQ2xCLEVBQUUsQ0FBQyxTQUFTLEVBQUUsTUFBTSxDQUFDO2FBQ3JCLFdBQVcsRUFBRSxDQUFDO1FBRW5CLElBQUksWUFBWSxFQUFFLENBQUM7WUFDZixNQUFNLENBQUMsS0FBSyxDQUFDLEVBQUUsR0FBRyxFQUFFLFlBQVksRUFBRSxNQUFNLEVBQUUsRUFBRSw4QkFBOEIsQ0FBQyxDQUFDO1lBQzVFLE9BQU8sQ0FBQyxDQUFDLElBQUksQ0FBQyxFQUFFLEtBQUssRUFBRSx1QkFBdUIsRUFBRSxFQUFFLEdBQUcsQ0FBQyxDQUFDO1FBQzNELENBQUM7UUFFRCxvQkFBb0I7UUFDcEIsTUFBTSxDQUFDLEtBQUssQ0FBQyxFQUFFLE1BQU0sRUFBRSxVQUFVLEVBQUUsQ0FBQyxDQUFDLFdBQVcsRUFBRSxRQUFRLEVBQUUsV0FBVyxFQUFFLFFBQVEsRUFBRSxFQUFFLDZCQUE2QixDQUFDLENBQUM7UUFFcEgsTUFBTSxNQUFNLEdBQUksV0FBVyxFQUFFLFFBQWdCLEVBQUUsUUFBUSxFQUFFLGNBQWMsQ0FBQztRQUV4RSxJQUFJLENBQUMsTUFBTSxFQUFFLENBQUM7WUFDVixNQUFNLENBQUMsSUFBSSxDQUFDLEVBQUUsTUFBTSxFQUFFLEVBQUUsd0NBQXdDLENBQUMsQ0FBQztZQUNsRSxPQUFPLENBQUMsQ0FBQyxJQUFJLENBQUMsRUFBRSxLQUFLLEVBQUUsbUVBQW1FLEVBQUUsRUFBRSxHQUFHLENBQUMsQ0FBQztRQUN2RyxDQUFDO1FBRUQsK0JBQStCO1FBQy9CLE1BQU0sSUFBSSxHQUFHLE1BQU0sQ0FBQyxDQUFDLEdBQUcsQ0FBQyxJQUFJLEVBQUUsQ0FBQztRQUVoQyx3Q0FBd0M7UUFDeEMsTUFBTSxDQUFDLElBQUksQ0FBQyxFQUFFLE1BQU0sRUFBRSxLQUFLLEVBQUUsSUFBSSxDQUFDLEtBQUssRUFBRSxFQUFFLHlCQUF5QixDQUFDLENBQUM7UUFFdEUsTUFBTSxPQUFPLEdBQTJCO1lBQ3BDLGNBQWMsRUFBRSxrQkFBa0I7WUFDbEMsZUFBZSxFQUFFLFVBQVUsTUFBTSxFQUFFO1NBQ3RDLENBQUM7UUFFRiw0QkFBNEI7UUFDNUIsTUFBTSxRQUFRLEdBQUcsTUFBTSxLQUFLLENBQUMsNENBQTRDLEVBQUU7WUFDdkUsTUFBTSxFQUFFLE1BQU07WUFDZCxPQUFPO1lBQ1AsSUFBSSxFQUFFLElBQUksQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDO1NBQzdCLENBQUMsQ0FBQztRQUVILHFCQUFxQjtRQUNyQixJQUFJLENBQUMsUUFBUSxDQUFDLEVBQUUsRUFBRSxDQUFDO1lBQ2YsTUFBTSxTQUFTLEdBQUcsTUFBTSxRQUFRLENBQUMsSUFBSSxFQUFFLENBQUM7WUFDeEMsTUFBTSxDQUFDLEtBQUssQ0FBQyxFQUFFLE1BQU0sRUFBRSxRQUFRLENBQUMsTUFBTSxFQUFFLFNBQVMsRUFBRSxNQUFNLEVBQUUsRUFBRSxrQkFBa0IsQ0FBQyxDQUFDO1lBQ2pGLDJEQUEyRDtZQUMzRCxJQUFJLENBQUM7Z0JBQ0QsTUFBTSxTQUFTLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxTQUFTLENBQUMsQ0FBQztnQkFDeEMsT0FBTyxDQUFDLENBQUMsSUFBSSxDQUFDLFNBQVMsRUFBRSxRQUFRLENBQUMsTUFBYSxDQUFDLENBQUM7WUFDckQsQ0FBQztZQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUM7Z0JBQ1QsT0FBTyxDQUFDLENBQUMsSUFBSSxDQUFDLFNBQVMsRUFBRSxRQUFRLENBQUMsTUFBYSxDQUFDLENBQUM7WUFDckQsQ0FBQztRQUNMLENBQUM7UUFFRCxrQ0FBa0M7UUFDbEMsSUFBSSxJQUFJLENBQUMsTUFBTSxFQUFFLENBQUM7WUFDZCwwREFBMEQ7WUFDMUQseUNBQXlDO1lBRXpDLE9BQU8sSUFBSSxRQUFRLENBQUMsUUFBUSxDQUFDLElBQUksRUFBRTtnQkFDL0IsT0FBTyxFQUFFO29CQUNMLGNBQWMsRUFBRSxtQkFBbUI7b0JBQ25DLGVBQWUsRUFBRSxVQUFVO29CQUMzQixZQUFZLEVBQUUsWUFBWTtpQkFDN0I7YUFDSixDQUFDLENBQUM7UUFDUCxDQUFDO1FBRUQsTUFBTSxJQUFJLEdBQUcsTUFBTSxRQUFRLENBQUMsSUFBSSxFQUFFLENBQUM7UUFDbkMsT0FBTyxDQUFDLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO0lBRXhCLENBQUM7SUFBQyxPQUFPLEdBQVEsRUFBRSxDQUFDO1FBQ2hCLE1BQU0sQ0FBQyxLQUFLLENBQUMsRUFBRSxHQUFHLEVBQUUsTUFBTSxFQUFFLEVBQUUsNkJBQTZCLENBQUMsQ0FBQztRQUM3RCxPQUFPLENBQUMsQ0FBQyxJQUFJLENBQUMsRUFBRSxLQUFLLEVBQUUsdUJBQXVCLEVBQUUsRUFBRSxHQUFHLENBQUMsQ0FBQztJQUMzRCxDQUFDO0FBQ0wsQ0FBQyJ9 \ No newline at end of file diff --git a/dist-in/products/openai/index.js b/dist-in/products/openai/index.js new file mode 100644 index 0000000..a6c3068 --- /dev/null +++ b/dist-in/products/openai/index.js @@ -0,0 +1,32 @@ +import { AbstractProduct } from '../AbstractProduct.js'; +import { postChatCompletionsRoute } from './routes.js'; +import { handleChatCompletions } from './handlers.js'; +export class OpenAIProduct extends AbstractProduct { + id = 'openai'; + jobOptions = {}; + actions = {}; + workers = []; + routes = []; + constructor() { + super(); + this.initializeRoutes(); + } + initializeRoutes() { + // Register the chat completion route + // We use CachedHandler here just to wrap it properly, but we probably don't want to actually cache LLM responses aggressively + // unless we implement specific caching logic. For now, let's use the handler directly or create a simple wrapper if needed. + // Actually, AbstractProduct expects { definition, handler } objects. + // And `registry.ts` does: app.openapi(route.definition, route.handler); + this.routes.push({ + definition: postChatCompletionsRoute, + handler: handleChatCompletions + }); + } + hash(data) { + return 'openai-hash'; + } + meta(userId) { + return { userId }; + } +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvcHJvZHVjdHMvb3BlbmFpL2luZGV4LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSx1QkFBdUIsQ0FBQztBQUN4RCxPQUFPLEVBQUUsd0JBQXdCLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFDdkQsT0FBTyxFQUFFLHFCQUFxQixFQUFFLE1BQU0sZUFBZSxDQUFDO0FBRXRELE1BQU0sT0FBTyxhQUFjLFNBQVEsZUFBb0I7SUFDbkQsRUFBRSxHQUFHLFFBQVEsQ0FBQztJQUNkLFVBQVUsR0FBRyxFQUFFLENBQUM7SUFDaEIsT0FBTyxHQUFHLEVBQUUsQ0FBQztJQUNiLE9BQU8sR0FBRyxFQUFFLENBQUM7SUFDYixNQUFNLEdBQVUsRUFBRSxDQUFDO0lBRW5CO1FBQ0ksS0FBSyxFQUFFLENBQUM7UUFDUixJQUFJLENBQUMsZ0JBQWdCLEVBQUUsQ0FBQztJQUM1QixDQUFDO0lBRUQsZ0JBQWdCO1FBQ1oscUNBQXFDO1FBQ3JDLDhIQUE4SDtRQUM5SCw0SEFBNEg7UUFDNUgscUVBQXFFO1FBQ3JFLHdFQUF3RTtRQUV4RSxJQUFJLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQztZQUNiLFVBQVUsRUFBRSx3QkFBd0I7WUFDcEMsT0FBTyxFQUFFLHFCQUFxQjtTQUNqQyxDQUFDLENBQUM7SUFDUCxDQUFDO0lBRUQsSUFBSSxDQUFDLElBQVM7UUFDVixPQUFPLGFBQWEsQ0FBQztJQUN6QixDQUFDO0lBRUQsSUFBSSxDQUFDLE1BQWM7UUFDZixPQUFPLEVBQUUsTUFBTSxFQUFFLENBQUM7SUFDdEIsQ0FBQztDQUNKIn0= \ No newline at end of file diff --git a/dist-in/products/openai/routes.js b/dist-in/products/openai/routes.js new file mode 100644 index 0000000..ee4a071 --- /dev/null +++ b/dist-in/products/openai/routes.js @@ -0,0 +1,58 @@ +import { createRoute, z } from '@hono/zod-openapi'; +export const postChatCompletionsRoute = createRoute({ + method: 'post', + path: '/api/openai/v1/chat/completions', + tags: ['OpenAI'], + summary: 'Chat Completions Proxy', + description: 'Proxies chat completion requests to OpenAI, injecting user API key.', + request: { + body: { + content: { + 'application/json': { + schema: z.object({ + model: z.string(), + messages: z.array(z.object({ + role: z.string(), + content: z.any() // string or array (for multimodal) + })), + stream: z.boolean().optional(), + temperature: z.number().optional(), + top_p: z.number().optional(), + n: z.number().optional(), + presence_penalty: z.number().optional(), + frequency_penalty: z.number().optional(), + logit_bias: z.record(z.string(), z.number()).optional(), + user: z.string().optional(), + max_tokens: z.number().optional(), + response_format: z.any().optional(), + tools: z.array(z.any()).optional(), + tool_choice: z.any().optional(), + }).passthrough() // Allow other OpenAI params + } + } + } + }, + responses: { + 200: { + description: 'Chat completion response', + content: { + 'application/json': { + schema: z.any() + }, + 'text/event-stream': { + schema: z.string() + } + } + }, + 400: { + description: 'Bad Request' + }, + 401: { + description: 'Unauthorized' + }, + 500: { + description: 'Internal Server Error' + } + } +}); +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm91dGVzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3Byb2R1Y3RzL29wZW5haS9yb3V0ZXMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFdBQVcsRUFBRSxDQUFDLEVBQUUsTUFBTSxtQkFBbUIsQ0FBQztBQUVuRCxNQUFNLENBQUMsTUFBTSx3QkFBd0IsR0FBRyxXQUFXLENBQUM7SUFDaEQsTUFBTSxFQUFFLE1BQU07SUFDZCxJQUFJLEVBQUUsaUNBQWlDO0lBQ3ZDLElBQUksRUFBRSxDQUFDLFFBQVEsQ0FBQztJQUNoQixPQUFPLEVBQUUsd0JBQXdCO0lBQ2pDLFdBQVcsRUFBRSxxRUFBcUU7SUFDbEYsT0FBTyxFQUFFO1FBQ0wsSUFBSSxFQUFFO1lBQ0YsT0FBTyxFQUFFO2dCQUNMLGtCQUFrQixFQUFFO29CQUNoQixNQUFNLEVBQUUsQ0FBQyxDQUFDLE1BQU0sQ0FBQzt3QkFDYixLQUFLLEVBQUUsQ0FBQyxDQUFDLE1BQU0sRUFBRTt3QkFDakIsUUFBUSxFQUFFLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQzs0QkFDdkIsSUFBSSxFQUFFLENBQUMsQ0FBQyxNQUFNLEVBQUU7NEJBQ2hCLE9BQU8sRUFBRSxDQUFDLENBQUMsR0FBRyxFQUFFLENBQUMsbUNBQW1DO3lCQUN2RCxDQUFDLENBQUM7d0JBQ0gsTUFBTSxFQUFFLENBQUMsQ0FBQyxPQUFPLEVBQUUsQ0FBQyxRQUFRLEVBQUU7d0JBQzlCLFdBQVcsRUFBRSxDQUFDLENBQUMsTUFBTSxFQUFFLENBQUMsUUFBUSxFQUFFO3dCQUNsQyxLQUFLLEVBQUUsQ0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDLFFBQVEsRUFBRTt3QkFDNUIsQ0FBQyxFQUFFLENBQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxRQUFRLEVBQUU7d0JBQ3hCLGdCQUFnQixFQUFFLENBQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxRQUFRLEVBQUU7d0JBQ3ZDLGlCQUFpQixFQUFFLENBQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxRQUFRLEVBQUU7d0JBQ3hDLFVBQVUsRUFBRSxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxNQUFNLEVBQUUsRUFBRSxDQUFDLENBQUMsTUFBTSxFQUFFLENBQUMsQ0FBQyxRQUFRLEVBQUU7d0JBQ3ZELElBQUksRUFBRSxDQUFDLENBQUMsTUFBTSxFQUFFLENBQUMsUUFBUSxFQUFFO3dCQUMzQixVQUFVLEVBQUUsQ0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDLFFBQVEsRUFBRTt3QkFDakMsZUFBZSxFQUFFLENBQUMsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxRQUFRLEVBQUU7d0JBQ25DLEtBQUssRUFBRSxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxDQUFDLFFBQVEsRUFBRTt3QkFDbEMsV0FBVyxFQUFFLENBQUMsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxRQUFRLEVBQUU7cUJBQ2xDLENBQUMsQ0FBQyxXQUFXLEVBQUUsQ0FBQyw0QkFBNEI7aUJBQ2hEO2FBQ0o7U0FDSjtLQUNKO0lBQ0QsU0FBUyxFQUFFO1FBQ1AsR0FBRyxFQUFFO1lBQ0QsV0FBVyxFQUFFLDBCQUEwQjtZQUN2QyxPQUFPLEVBQUU7Z0JBQ0wsa0JBQWtCLEVBQUU7b0JBQ2hCLE1BQU0sRUFBRSxDQUFDLENBQUMsR0FBRyxFQUFFO2lCQUNsQjtnQkFDRCxtQkFBbUIsRUFBRTtvQkFDakIsTUFBTSxFQUFFLENBQUMsQ0FBQyxNQUFNLEVBQUU7aUJBQ3JCO2FBQ0o7U0FDSjtRQUNELEdBQUcsRUFBRTtZQUNELFdBQVcsRUFBRSxhQUFhO1NBQzdCO1FBQ0QsR0FBRyxFQUFFO1lBQ0QsV0FBVyxFQUFFLGNBQWM7U0FDOUI7UUFDRCxHQUFHLEVBQUU7WUFDRCxXQUFXLEVBQUUsdUJBQXVCO1NBQ3ZDO0tBQ0o7Q0FDSixDQUFDLENBQUMifQ== \ No newline at end of file diff --git a/dist-in/products/registry.js b/dist-in/products/registry.js new file mode 100644 index 0000000..03a98c6 --- /dev/null +++ b/dist-in/products/registry.js @@ -0,0 +1,49 @@ +import './subscriber.js'; +import { OpenAIProduct } from './openai/index.js'; +import { AnalyticsProduct } from './analytics/index.js'; +// import './subscriber.js'; +let instances = []; +export const ALL_PRODUCTS = instances; +export const registerProductRoutes = async (app) => { + console.log('Registering product routes'); + // Instantiate all products + instances = [ + new OpenAIProduct(), + new AnalyticsProduct(), + ]; + instances.forEach(product => { + console.log(`Registering routes for product ${product.id}`); + product.routes.forEach((route) => { + // @ts-ignore + app.openapi(route.definition, route.handler); + }); + }); +}; +export const getAllWorkers = () => { + return instances.flatMap(p => p.workers || []); +}; +export const startProducts = async (boss) => { + for (const product of instances) { + try { + // Create a timeout promise + const timeoutPromise = new Promise((_, reject) => { + const id = setTimeout(() => { + clearTimeout(id); + // @ts-ignore + reject(new Error(`Product ${product?.id || 'unknown'} startup timed out`)); + }, 20000); // 5 seconds timeout + }); + // Race the product start against the timeout + await Promise.race([ + product.start(boss), + timeoutPromise + ]); + } + catch (err) { + // @ts-ignore + console.error(`Failed to start product ${product.id}`, err); + // Continue with other products even if one fails + } + } +}; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVnaXN0cnkuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvcHJvZHVjdHMvcmVnaXN0cnkudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQ0EsT0FBTyxpQkFBaUIsQ0FBQztBQUV6QixPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0sbUJBQW1CLENBQUM7QUFDbEQsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sc0JBQXNCLENBQUM7QUFFeEQsNEJBQTRCO0FBRTVCLElBQUksU0FBUyxHQUFVLEVBQUUsQ0FBQztBQUMxQixNQUFNLENBQUMsTUFBTSxZQUFZLEdBQUcsU0FBUyxDQUFDO0FBRXRDLE1BQU0sQ0FBQyxNQUFNLHFCQUFxQixHQUFHLEtBQUssRUFBRSxHQUFRLEVBQUUsRUFBRTtJQUNwRCxPQUFPLENBQUMsR0FBRyxDQUFDLDRCQUE0QixDQUFDLENBQUM7SUFDMUMsMkJBQTJCO0lBQzNCLFNBQVMsR0FBRztRQUNSLElBQUksYUFBYSxFQUFFO1FBQ25CLElBQUksZ0JBQWdCLEVBQUU7S0FDekIsQ0FBQztJQUVGLFNBQVMsQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLEVBQUU7UUFDeEIsT0FBTyxDQUFDLEdBQUcsQ0FBQyxrQ0FBa0MsT0FBTyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUM7UUFDNUQsT0FBTyxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsQ0FBQyxLQUFVLEVBQUUsRUFBRTtZQUNsQyxhQUFhO1lBQ2IsR0FBRyxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsVUFBVSxFQUFFLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUNqRCxDQUFDLENBQUMsQ0FBQztJQUNQLENBQUMsQ0FBQyxDQUFDO0FBQ1AsQ0FBQyxDQUFDO0FBRUYsTUFBTSxDQUFDLE1BQU0sYUFBYSxHQUFHLEdBQUcsRUFBRTtJQUM5QixPQUFPLFNBQVMsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsT0FBTyxJQUFJLEVBQUUsQ0FBQyxDQUFDO0FBQ25ELENBQUMsQ0FBQztBQUVGLE1BQU0sQ0FBQyxNQUFNLGFBQWEsR0FBRyxLQUFLLEVBQUUsSUFBVSxFQUFFLEVBQUU7SUFDOUMsS0FBSyxNQUFNLE9BQU8sSUFBSSxTQUFTLEVBQUUsQ0FBQztRQUM5QixJQUFJLENBQUM7WUFDRCwyQkFBMkI7WUFDM0IsTUFBTSxjQUFjLEdBQUcsSUFBSSxPQUFPLENBQUMsQ0FBQyxDQUFDLEVBQUUsTUFBTSxFQUFFLEVBQUU7Z0JBQzdDLE1BQU0sRUFBRSxHQUFHLFVBQVUsQ0FBQyxHQUFHLEVBQUU7b0JBQ3ZCLFlBQVksQ0FBQyxFQUFFLENBQUMsQ0FBQztvQkFDakIsYUFBYTtvQkFDYixNQUFNLENBQUMsSUFBSSxLQUFLLENBQUMsV0FBVyxPQUFPLEVBQUUsRUFBRSxJQUFJLFNBQVMsb0JBQW9CLENBQUMsQ0FBQyxDQUFDO2dCQUMvRSxDQUFDLEVBQUUsS0FBSyxDQUFDLENBQUMsQ0FBQyxvQkFBb0I7WUFDbkMsQ0FBQyxDQUFDLENBQUM7WUFFSCw2Q0FBNkM7WUFDN0MsTUFBTSxPQUFPLENBQUMsSUFBSSxDQUFDO2dCQUNmLE9BQU8sQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDO2dCQUNuQixjQUFjO2FBQ2pCLENBQUMsQ0FBQztRQUVQLENBQUM7UUFBQyxPQUFPLEdBQUcsRUFBRSxDQUFDO1lBQ1gsYUFBYTtZQUNiLE9BQU8sQ0FBQyxLQUFLLENBQUMsMkJBQTJCLE9BQU8sQ0FBQyxFQUFFLEVBQUUsRUFBRSxHQUFHLENBQUMsQ0FBQztZQUM1RCxpREFBaUQ7UUFDckQsQ0FBQztJQUNMLENBQUM7QUFDTCxDQUFDLENBQUMifQ== \ No newline at end of file diff --git a/dist-in/products/serving/routes.js b/dist-in/products/serving/routes.js new file mode 100644 index 0000000..2de68bf --- /dev/null +++ b/dist-in/products/serving/routes.js @@ -0,0 +1,307 @@ +import { createRoute, z } from '@hono/zod-openapi'; +import { Admin, Public } from '../../commons/decorators.js'; +/** + * Factory function to create a service route with optional decorators + */ +function createServiceRoute(options) { + const { public: isPublic, admin: isAdmin, ...routeDef } = options; + let route = createRoute(routeDef); + if (isPublic) { + route = Public(route); + } + if (isAdmin) { + route = Admin(route); + } + return route; +} +export function createRouteBody(method, path, tags, summary, description, request, responses, publicRoute = true, adminRoute = false) { + return createServiceRoute({ + method: method, + path, + tags, + summary, + description, + request, + responses, + public: publicRoute, + admin: adminRoute + }); +} +export const getFeedRoute = createRouteBody('get', '/feed.xml', ['Serving'], 'Get RSS Feed', 'Returns the latest posts as an RSS 2.0 feed.', undefined, { + 200: { + description: 'RSS Feed', + content: { + 'application/xml': { + schema: z.string() + } + } + } +}); +export const getMerchantFeedRoute = createRouteBody('get', '/products.xml', ['Serving'], 'Get Merchant Feed', 'Returns the latest products as a Google Merchant XML feed.', undefined, { + 200: { + description: 'XML Feed', + content: { + 'application/xml': { + schema: z.string() + } + } + } +}); +export const getLLMTextRoute = createRouteBody('get', '/llms.txt', ['Serving'], 'Get LLM Summary', 'Returns a Markdown summary of content for AI agents.', undefined, { + 200: { + description: 'Markdown Text', + content: { + 'text/plain': { + schema: z.string() + } + } + } +}); +export const getPostMetaRoute = createRouteBody('get', '/post/:id', ['Serving'], 'Get Post with Metadata', 'Serves the React app HTML with injected Open Graph metadata for the specific post.', { + params: z.object({ + id: z.string() + }) +}, { + 200: { + description: 'HTML Page', + content: { + 'text/html': { + schema: z.string() + } + } + }, + 404: { + description: 'Post not found (Serves default HTML)', + } +}); +export const getHomeRoute = createRouteBody('get', '/', ['Serving'], 'Get Home Page', 'Serves the home page with injected feed data.', undefined, { + 200: { + description: 'HTML Page', + content: { + 'text/html': { + schema: z.string() + } + } + } +}); +export const getApiPostDetailsRoute = createRouteBody('get', '/api/posts/:id', ['Posts'], 'Get Post Details', 'Get Post Details', { + params: z.object({ + id: z.string() + }), + query: z.object({ + sizes: z.string().optional().openapi({ description: 'Responsive sizes' }), + formats: z.string().optional().openapi({ description: 'Responsive formats' }) + }) +}, { + 200: { + description: 'Post Details', + content: { + 'application/json': { + schema: z.any() + } + } + }, + 404: { + description: 'Post not found' + } +}, true); +export const postFlushCacheRoute = createRouteBody('post', '/api/flush-cache', ['Posts'], 'Flush Cache', 'Flushes the server-side content cache and the disk-based image cache.', undefined, { + 200: { + description: 'Cache Flushed', + content: { + 'application/json': { + schema: z.object({ + success: z.boolean(), + message: z.string() + }) + } + } + }, + 500: { + description: 'Internal Server Error' + } +}, false, // not public +true // admin +); +export const invalidateCacheRoute = createRouteBody('post', '/api/cache/invalidate', ['System'], 'Invalidate Cache by Path', 'Invalidates cache keys matching the provided paths.', { + body: { + content: { + 'application/json': { + schema: z.object({ + paths: z.array(z.string()).optional().openapi({ + description: 'List of URL paths to invalidate (e.g. /api/user-page/123/slug)' + }), + types: z.array(z.string()).optional().openapi({ + description: 'List of cache types to invalidate (e.g. posts, pages)' + }) + }) + } + } + } +}, { + 200: { + description: 'Cache Invalidated', + content: { + 'application/json': { + schema: z.object({ + success: z.boolean(), + count: z.number() + }) + } + } + } +}, false, // not public +false // not admin-only (allow authed users to invalidate their own content ideally, for now just authed) +); +export const getCacheInspectRoute = createRouteBody('get', '/api/cache/inspect', ['System'], 'Inspect Cache', 'Returns current cache state: keys, TTLs, dependency graph, and overall stats.', undefined, { + 200: { + description: 'Cache state', + content: { + 'application/json': { + schema: z.object({ + info: z.object({ + size: z.number(), + max: z.number(), + provider: z.string() + }), + dependencies: z.record(z.string(), z.array(z.string())), + entries: z.array(z.object({ + key: z.string(), + remainingTTL: z.number() + })) + }) + } + } + } +}, true, // not public +false // admin only +); +export const getProfilesRoute = createRouteBody('get', '/api/profiles', ['Users'], 'Get Batch Profiles', 'Get Batch Profiles', { + query: z.object({ + ids: z.string().optional().openapi({ + description: 'Comma-separated list of user IDs' + }), + q: z.string().optional().openapi({ + description: 'Search query' + }) + }) +}, { + 200: { + description: 'Profiles Map', + content: { + 'application/json': { + schema: z.record(z.string(), z.any()) + } + } + } +}, true // public +); +export const getApiMediaItemsRoute = createRouteBody('get', '/api/media-items', ['Media'], 'Get Media Items by IDs', 'Fetches multiple media items by their IDs using server-side cache for optimal performance.', { + query: z.object({ + ids: z.string().openapi({ + description: 'Comma-separated list of picture IDs' + }), + maintainOrder: z.enum(['true', 'false']).optional().openapi({ + description: 'Maintain the order of IDs in the response' + }), + sizes: z.string().optional().openapi({ + description: 'Comma-separated list of widths for responsive images' + }), + formats: z.string().optional().openapi({ + description: 'Comma-separated list of formats for responsive images' + }) + }) +}, { + 200: { + description: 'Array of Media Items', + content: { + 'application/json': { + schema: z.array(z.any()) + } + } + } +}, true // public +); +export const getEmbedRoute = createRouteBody('get', '/embed/:id', ['Serving'], 'Get Embed Page', 'Serves the embed page with injected post data.', { + params: z.object({ + id: z.string() + }) +}, { + 200: { + description: 'HTML Page', + content: { + 'text/html': { + schema: z.string() + } + } + }, + 404: { + description: 'Post not found', + } +}); +export const getSiteInfoRoute = createRouteBody('get', '/api/serving/site-info', ['Serving'], 'Get Site Information', 'Extracts metadata (Open Graph, JSON-LD, etc.) from a given URL.', { + query: z.object({ + url: z.string().openapi({ + description: 'The URL to extract information from', + example: 'https://example.com' + }) + }) +}, { + 200: { + description: 'Site Information', + content: { + 'application/json': { + schema: z.object({ + title: z.string().optional(), + description: z.string().optional(), + url: z.string().optional(), + siteName: z.string().optional(), + favicon: z.string().optional(), + og: z.record(z.string(), z.string().optional()).optional(), + images: z.array(z.object({ + src: z.string(), + width: z.number().optional(), + height: z.number().optional(), + alt: z.string().optional() + })).optional(), + structuredData: z.array(z.any()).optional(), + social: z.array(z.object({ + source: z.string(), + url: z.string() + })).optional() + }) + } + } + }, + 400: { + description: 'Invalid URL' + }, + 500: { + description: 'Failed to extract information' + } +}, true // public? Site info scraper is usually public +); +export const getSitemapRoute = createRouteBody('get', '/sitemap-en.xml', ['Serving'], 'Get Sitemap', 'Returns the sitemap XML for internal pages.', undefined, { + 200: { + description: 'Sitemap XML', + content: { + 'application/xml': { + schema: z.string() + } + } + } +}); +export const getSystemInfoRoute = createRouteBody('get', '/api/system-info', ['System'], 'Get System Info', 'Returns public client environment variables and app configuration.', undefined, { + 200: { + description: 'System Info', + content: { + 'application/json': { + schema: z.object({ + env: z.record(z.string(), z.any()) + }) + } + } + } +}, true // public +); +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm91dGVzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3Byb2R1Y3RzL3NlcnZpbmcvcm91dGVzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxXQUFXLEVBQUUsQ0FBQyxFQUFFLE1BQU0sbUJBQW1CLENBQUM7QUFDbkQsT0FBTyxFQUFFLEtBQUssRUFBRSxNQUFNLEVBQUUsTUFBTSw2QkFBNkIsQ0FBQztBQU81RDs7R0FFRztBQUNILFNBQVMsa0JBQWtCLENBQUMsT0FBNEI7SUFDcEQsTUFBTSxFQUFFLE1BQU0sRUFBRSxRQUFRLEVBQUUsS0FBSyxFQUFFLE9BQU8sRUFBRSxHQUFHLFFBQVEsRUFBRSxHQUFHLE9BQU8sQ0FBQztJQUNsRSxJQUFJLEtBQUssR0FBRyxXQUFXLENBQUMsUUFBUSxDQUFDLENBQUM7SUFFbEMsSUFBSSxRQUFRLEVBQUUsQ0FBQztRQUNYLEtBQUssR0FBRyxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUM7SUFDMUIsQ0FBQztJQUVELElBQUksT0FBTyxFQUFFLENBQUM7UUFDVixLQUFLLEdBQUcsS0FBSyxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQ3pCLENBQUM7SUFFRCxPQUFPLEtBQUssQ0FBQztBQUNqQixDQUFDO0FBRUQsTUFBTSxVQUFVLGVBQWUsQ0FDM0IsTUFBYyxFQUNkLElBQVksRUFDWixJQUFjLEVBQ2QsT0FBZSxFQUNmLFdBQW1CLEVBQ25CLE9BQVksRUFDWixTQUFjLEVBQ2QsY0FBdUIsSUFBSSxFQUMzQixhQUFzQixLQUFLO0lBQzNCLE9BQU8sa0JBQWtCLENBQUM7UUFDdEIsTUFBTSxFQUFFLE1BQWE7UUFDckIsSUFBSTtRQUNKLElBQUk7UUFDSixPQUFPO1FBQ1AsV0FBVztRQUNYLE9BQU87UUFDUCxTQUFTO1FBQ1QsTUFBTSxFQUFFLFdBQVc7UUFDbkIsS0FBSyxFQUFFLFVBQVU7S0FDcEIsQ0FBQyxDQUFBO0FBQ04sQ0FBQztBQUVELE1BQU0sQ0FBQyxN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 \ No newline at end of file diff --git a/dist-in/products/subscriber.js b/dist-in/products/subscriber.js new file mode 100644 index 0000000..21b88eb --- /dev/null +++ b/dist-in/products/subscriber.js @@ -0,0 +1,36 @@ +import { ALL_PRODUCTS } from './registry.js'; +import { EventBus } from './EventBus.js'; +const findProductByQueue = (queue) => { + return ALL_PRODUCTS.find(p => p.workers?.some((w) => { + try { + const worker = new w(); + return worker.queueName === queue; + } + catch (e) { + return false; + } + })); +}; +EventBus.on('job:create', (event) => { + const product = findProductByQueue(event.queue); + if (!product) + return; + // Apply default job options from product if available + if (product.jobOptions) { + event.options = { ...product.jobOptions, ...event.options }; + } + const singletonKey = product.hash(event.data); + if (singletonKey) { + event.options.singletonKey = singletonKey; + // Default to 5 minutes if not specified + if (!event.options.singletonSeconds) { + event.options.singletonSeconds = 300; + } + } + const { userId } = event.data; + if (userId) { + const metadata = product.meta(userId); + event.data = { ...event.data, ...metadata }; + } +}); +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3Vic2NyaWJlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9wcm9kdWN0cy9zdWJzY3JpYmVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDN0MsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUV6QyxNQUFNLGtCQUFrQixHQUFHLENBQUMsS0FBYSxFQUFFLEVBQUU7SUFDekMsT0FBTyxZQUFZLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQ3pCLENBQUMsQ0FBQyxPQUFPLEVBQUUsSUFBSSxDQUFDLENBQUMsQ0FBTSxFQUFFLEVBQUU7UUFDdkIsSUFBSSxDQUFDO1lBQ0QsTUFBTSxNQUFNLEdBQUcsSUFBSyxDQUFTLEVBQUUsQ0FBQztZQUNoQyxPQUFPLE1BQU0sQ0FBQyxTQUFTLEtBQUssS0FBSyxDQUFDO1FBQ3RDLENBQUM7UUFBQyxPQUFPLENBQUMsRUFBRSxDQUFDO1lBQ1QsT0FBTyxLQUFLLENBQUM7UUFDakIsQ0FBQztJQUNMLENBQUMsQ0FBQyxDQUNMLENBQUM7QUFDTixDQUFDLENBQUM7QUFFRixRQUFRLENBQUMsRUFBRSxDQUFDLFlBQVksRUFBRSxDQUFDLEtBQVUsRUFBRSxFQUFFO0lBQ3JDLE1BQU0sT0FBTyxHQUFHLGtCQUFrQixDQUFDLEtBQUssQ0FBQyxLQUFLLENBQUMsQ0FBQztJQUVoRCxJQUFJLENBQUMsT0FBTztRQUFFLE9BQU87SUFFckIsc0RBQXNEO0lBQ3RELElBQUksT0FBTyxDQUFDLFVBQVUsRUFBRSxDQUFDO1FBQ3JCLEtBQUssQ0FBQyxPQUFPLEdBQUcsRUFBRSxHQUFHLE9BQU8sQ0FBQyxVQUFVLEVBQUUsR0FBRyxLQUFLLENBQUMsT0FBTyxFQUFFLENBQUM7SUFDaEUsQ0FBQztJQUVELE1BQU0sWUFBWSxHQUFHLE9BQU8sQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQzlDLElBQUksWUFBWSxFQUFFLENBQUM7UUFDZixLQUFLLENBQUMsT0FBTyxDQUFDLFlBQVksR0FBRyxZQUFZLENBQUM7UUFDMUMsd0NBQXdDO1FBQ3hDLElBQUksQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLGdCQUFnQixFQUFFLENBQUM7WUFDbEMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxnQkFBZ0IsR0FBRyxHQUFHLENBQUM7UUFDekMsQ0FBQztJQUNMLENBQUM7SUFFRCxNQUFNLEVBQUUsTUFBTSxFQUFFLEdBQUcsS0FBSyxDQUFDLElBQUksQ0FBQztJQUM5QixJQUFJLE1BQU0sRUFBRSxDQUFDO1FBQ1QsTUFBTSxRQUFRLEdBQUcsT0FBTyxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQztRQUN0QyxLQUFLLENBQUMsSUFBSSxHQUFHLEVBQUUsR0FBRyxLQUFLLENBQUMsSUFBSSxFQUFFLEdBQUcsUUFBUSxFQUFFLENBQUM7SUFDaEQsQ0FBQztBQUVMLENBQUMsQ0FBQyxDQUFDIn0= \ No newline at end of file diff --git a/dist-in/schemas/index.js b/dist-in/schemas/index.js new file mode 100644 index 0000000..a950e4c --- /dev/null +++ b/dist-in/schemas/index.js @@ -0,0 +1,20 @@ +import { z } from '@hono/zod-openapi'; +export const ErrorSchema = z.object({ + error: z.string(), +}); +export const ImageSchema = z.object({ + idx: z.number().openapi({ example: 0 }), + id: z.number().openapi({ example: 6 }), + name: z.string().openapi({ example: 'images' }), + slug: z.string().openapi({ example: 'images' }), + description: z.string().openapi({ example: 'fcghdfgh' }), + price: z.string().openapi({ example: '10.00' }), + variants: z.string().openapi({ example: '[]' }), + created_at: z.string().openapi({ example: '2025-11-22 10:46:09.77718+00' }), + updated_at: z.string().openapi({ example: '2025-11-22 10:46:09.77718+00' }), +}); +export const ImageResponseSchema = z.object({ + message: z.string().openapi({ example: 'Success' }), + data: z.array(ImageSchema).optional(), +}); +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvc2NoZW1hcy9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsQ0FBQyxFQUFFLE1BQU0sbUJBQW1CLENBQUE7QUFFckMsTUFBTSxDQUFDLE1BQU0sV0FBVyxHQUFHLENBQUMsQ0FBQyxNQUFNLENBQUM7SUFDaEMsS0FBSyxFQUFFLENBQUMsQ0FBQyxNQUFNLEVBQUU7Q0FDcEIsQ0FBQyxDQUFBO0FBQ0YsTUFBTSxDQUFDLE1BQU0sV0FBVyxHQUFHLENBQUMsQ0FBQyxNQUFNLENBQUM7SUFDaEMsR0FBRyxFQUFFLENBQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxPQUFPLENBQUMsRUFBRSxPQUFPLEVBQUUsQ0FBQyxFQUFFLENBQUM7SUFDdkMsRUFBRSxFQUFFLENBQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxPQUFPLENBQUMsRUFBRSxPQUFPLEVBQUUsQ0FBQyxFQUFFLENBQUM7SUFDdEMsSUFBSSxFQUFFLENBQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxPQUFPLENBQUMsRUFBRSxPQUFPLEVBQUUsUUFBUSxFQUFFLENBQUM7SUFDL0MsSUFBSSxFQUFFLENBQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxPQUFPLENBQUMsRUFBRSxPQUFPLEVBQUUsUUFBUSxFQUFFLENBQUM7SUFDL0MsV0FBVyxFQUFFLENBQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxPQUFPLENBQUMsRUFBRSxPQUFPLEVBQUUsVUFBVSxFQUFFLENBQUM7SUFDeEQsS0FBSyxFQUFFLENBQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxPQUFPLENBQUMsRUFBRSxPQUFPLEVBQUUsT0FBTyxFQUFFLENBQUM7SUFDL0MsUUFBUSxFQUFFLENBQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxPQUFPLENBQUMsRUFBRSxPQUFPLEVBQUUsSUFBSSxFQUFFLENBQUM7SUFDL0MsVUFBVSxFQUFFLENBQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxPQUFPLENBQUMsRUFBRSxPQUFPLEVBQUUsOEJBQThCLEVBQUUsQ0FBQztJQUMzRSxVQUFVLEVBQUUsQ0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDLE9BQU8sQ0FBQyxFQUFFLE9BQU8sRUFBRSw4QkFBOEIsRUFBRSxDQUFDO0NBQzlFLENBQUMsQ0FBQTtBQUVGLE1BQU0sQ0FBQyxNQUFNLG1CQUFtQixHQUFHLENBQUMsQ0FBQyxNQUFNLENBQUM7SUFDeEMsT0FBTyxFQUFFLENBQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxPQUFPLENBQUMsRUFBRSxPQUFPLEVBQUUsU0FBUyxFQUFFLENBQUM7SUFDbkQsSUFBSSxFQUFFLENBQUMsQ0FBQyxLQUFLLENBQUMsV0FBVyxDQUFDLENBQUMsUUFBUSxFQUFFO0NBQ3hDLENBQUMsQ0FBQSJ9 \ No newline at end of file diff --git a/dist-in/serve-assets.js b/dist-in/serve-assets.js new file mode 100644 index 0000000..8f19353 --- /dev/null +++ b/dist-in/serve-assets.js @@ -0,0 +1,82 @@ +import { serveStatic } from '@hono/node-server/serve-static'; +import path from 'path'; +export const registerAssetRoutes = (app) => { + // Serve manifest.webmanifest from dist root + app.get('/manifest.webmanifest', serveStatic({ + root: process.env.CLIENT_DIST_PATH || '../dist', + path: 'manifest.webmanifest' + })); + // Serve service worker — must never be cached so browser always checks for updates + app.get('/sw.js', async (c, next) => { + await next(); + c.res.headers.set('Cache-Control', 'no-cache'); + }); + app.get('/sw.js', serveStatic({ + root: process.env.CLIENT_DIST_PATH || '../dist', + path: 'sw.js' + })); + // Serve registerSW.js — must always be fresh + app.get('/registerSW.js', async (c, next) => { + await next(); + c.res.headers.set('Cache-Control', 'no-cache'); + }); + app.get('/registerSW.js', serveStatic({ + root: process.env.CLIENT_DIST_PATH || '../dist', + path: 'registerSW.js' + })); + // Serve workbox assets if they are at root + app.get('/workbox-*.js', serveStatic({ + root: process.env.CLIENT_DIST_PATH || '../dist', + rewriteRequestPath: (path) => path // Serve matching file + })); + // Serve workbox assets if they are at root + app.get('/widgets/*', serveStatic({ + root: process.env.CLIENT_DIST_PATH || '../dist/widgets', + rewriteRequestPath: (path) => path // Serve matching file + })); + // Serve root static assets (images, icons, robots.txt, etc) — short cache since not hash-busted + app.use('/:file{.+\\.(png|ico|jpg|jpeg|svg|txt|xml)$}', async (c, next) => { + await next(); + if (c.res.ok) { + c.res.headers.set('Cache-Control', 'public, max-age=3600, must-revalidate'); + } + }); + app.get('/:file{.+\\.(png|ico|jpg|jpeg|svg|txt|xml)$}', serveStatic({ + root: process.env.CLIENT_DIST_PATH || '../dist', + })); + // Serve static assets from dist + app.use('/assets/*', async (c, next) => { + await next(); + if (c.res.ok && c.res.status === 200) { + c.res.headers.set('Cache-Control', 'public, max-age=31536000, immutable'); + } + }); + app.use('/assets/*', serveStatic({ + root: process.env.CLIENT_DIST_PATH || '../dist', + onNotFound: (path, c) => { + return undefined; + } + })); + // Serve embed assets + app.use('/embed_assets/*', serveStatic({ + root: process.env.CLIENT_DIST_PATH ? path.join(process.env.CLIENT_DIST_PATH, 'client/embed') : '../dist/client/embed', + onNotFound: (path, c) => { + return undefined; + }, + rewriteRequestPath: (path) => path.replace(/^\/embed_assets/, ''), + })); + // Serve filebrowser assets + app.use('/filebrowser_assets/*', serveStatic({ + root: process.env.CLIENT_DIST_PATH ? path.join(process.env.CLIENT_DIST_PATH, 'client/filebrowser') : '../dist/client/filebrowser', + onNotFound: (path, c) => { + return undefined; + }, + rewriteRequestPath: (path) => path.replace(/^\/filebrowser_assets/, ''), + })); + // Fallback to index.html for SPA + app.get('*', serveStatic({ + root: process.env.CLIENT_DIST_PATH || '../dist', + path: 'index.html' + })); +}; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VydmUtYXNzZXRzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL3NlcnZlLWFzc2V0cy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFFQSxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sZ0NBQWdDLENBQUE7QUFDNUQsT0FBTyxJQUFJLE1BQU0sTUFBTSxDQUFBO0FBRXZCLE1BQU0sQ0FBQyxNQUFNLG1CQUFtQixHQUFHLENBQUMsR0FBZ0IsRUFBRSxFQUFFO0lBQ3BELDRDQUE0QztJQUM1QyxHQUFHLENBQUMsR0FBRyxDQUFDLHVCQUF1QixFQUFFLFdBQVcsQ0FBQztRQUN6QyxJQUFJLEVBQUUsT0FBTyxDQUFDLEdBQUcsQ0FBQyxnQkFBZ0IsSUFBSSxTQUFTO1FBQy9DLElBQUksRUFBRSxzQkFBc0I7S0FDL0IsQ0FBQyxDQUFDLENBQUM7SUFFSixtRkFBbUY7SUFDbkYsR0FBRyxDQUFDLEdBQUcsQ0FBQyxRQUFRLEVBQUUsS0FBSyxFQUFFLENBQUMsRUFBRSxJQUFJLEVBQUUsRUFBRTtRQUNoQyxNQUFNLElBQUksRUFBRSxDQUFDO1FBQ2IsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLGVBQWUsRUFBRSxVQUFVLENBQUMsQ0FBQztJQUNuRCxDQUFDLENBQUMsQ0FBQztJQUNILEdBQUcsQ0FBQyxHQUFHLENBQUMsUUFBUSxFQUFFLFdBQVcsQ0FBQztRQUMxQixJQUFJLEVBQUUsT0FBTyxDQUFDLEdBQUcsQ0FBQyxnQkFBZ0IsSUFBSSxTQUFTO1FBQy9DLElBQUksRUFBRSxPQUFPO0tBQ2hCLENBQUMsQ0FBQyxDQUFDO0lBRUosNkNBQTZDO0lBQzdDLEdBQUcsQ0FBQyxHQUFHLENBQUMsZ0JBQWdCLEVBQUUsS0FBSyxFQUFFLENBQUMsRUFBRSxJQUFJLEVBQUUsRUFBRTtRQUN4QyxNQUFNLElBQUksRUFBRSxDQUFDO1FBQ2IsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLGVBQWUs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 \ No newline at end of file diff --git a/dist-in/zod-setup.js b/dist-in/zod-setup.js new file mode 100644 index 0000000..22f2b5c --- /dev/null +++ b/dist-in/zod-setup.js @@ -0,0 +1,5 @@ +import { z } from 'zod'; +import { extendZodWithOpenApi } from '@hono/zod-openapi'; +extendZodWithOpenApi(z); +export { z }; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiem9kLXNldHVwLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL3pvZC1zZXR1cC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsQ0FBQyxFQUFFLE1BQU0sS0FBSyxDQUFDO0FBQ3hCLE9BQU8sRUFBRSxvQkFBb0IsRUFBRSxNQUFNLG1CQUFtQixDQUFDO0FBRXpELG9CQUFvQixDQUFDLENBQUMsQ0FBQyxDQUFDO0FBRXhCLE9BQU8sRUFBRSxDQUFDLEVBQUUsQ0FBQyJ9 \ No newline at end of file diff --git a/openapitools.json b/openapitools.json new file mode 100644 index 0000000..dae2553 --- /dev/null +++ b/openapitools.json @@ -0,0 +1,7 @@ +{ + "$schema": "./node_modules/@openapitools/openapi-generator-cli/config.schema.json", + "spaces": 2, + "generator-cli": { + "version": "7.19.0" + } +} diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..16dd26a --- /dev/null +++ b/package-lock.json @@ -0,0 +1,14742 @@ +{ + "name": "server", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "server", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "@hono/node-ws": "^1.2.0", + "@hono/swagger-ui": "^0.5.2", + "@hono/zod-openapi": "^1.1.5", + "@polymech/acl": "file:../polymech-mono/packages/acl", + "@polymech/commons": "file:../polymech-mono/packages/commons", + "@polymech/core": "file:../polymech-mono/packages/core", + "@polymech/fs": "file:../polymech-mono/packages/fs", + "@polymech/i18n": "file:../polymech-mono/packages/i18n", + "@polymech/media": "file:../polymech-mono/packages/media", + "@polymech/registry": "file:../polymech-mono/packages/registry", + "@polymech/search": "file:../polymech-mono/packages/search", + "@scalar/hono-api-reference": "^0.9.25", + "@ssut/tiktok-api": "^1.5.2", + "@supabase/supabase-js": "^2.87.1", + "@types/pdfmake": "^0.2.12", + "@types/sharp": "^0.31.1", + "@types/ws": "^8.18.1", + "cheerio": "^1.1.2", + "chokidar": "^5.0.0", + "deepl-node": "^1.24.0", + "dotenv": "^17.2.3", + "exifreader": "^4.33.1", + "feed": "^5.1.0", + "glob": "^13.0.3", + "hono-rate-limiter": "^0.4.2", + "i": "^0.3.7", + "ignore": "^7.0.5", + "isbot": "^5.1.34", + "juice": "^11.1.1", + "lru-cache": "^11.2.4", + "marked": "^17.0.1", + "mime": "^4.1.0", + "npm": "^11.7.0", + "pdfmake": "^0.2.20", + "pg-boss": "^12.5.2", + "pino": "^10.1.0", + "quicktype-core": "^23.2.6", + "sharp": "^0.34.5", + "stripe": "^20.3.1", + "swagger-typescript-codegen": "^3.2.4", + "vite-node": "^5.3.0", + "ws": "^8.19.0", + "zod": "^4.3.6" + }, + "devDependencies": { + "@hey-api/client-fetch": "^0.13.1", + "@hey-api/openapi-ts": "^0.92.3", + "@hono/node-server": "^1.19.6", + "@types/node": "^24.10.1", + "@types/pg": "^8.15.6", + "@vitest/ui": "^4.0.18", + "hono": "^4.10.6", + "nexe": "^1.1.6", + "pino-pretty": "^13.1.2", + "supazod": "^4.5.0", + "tsx": "^4.20.6", + "typescript": "^5.9.3", + "vite-tsconfig-paths": "^5.1.4", + "vitest": "^4.0.18", + "webpack": "^5.97.1", + "webpack-cli": "^6.0.1" + } + }, + "../../polymech-mono/packages/acl": { + "extraneous": true + }, + "../../polymech-mono/packages/commons": { + "extraneous": true + }, + "../../polymech-mono/packages/core": { + "extraneous": true + }, + "../../polymech-mono/packages/fs": { + "extraneous": true + }, + "../../polymech-mono/packages/i18n": { + "extraneous": true + }, + "../../polymech-mono/packages/media": { + "extraneous": true + }, + "../../polymech-mono/packages/registry": { + "extraneous": true + }, + "../../polymech-mono/packages/search": { + "extraneous": true + }, + "../polymech-mono/packages/acl": { + "name": "@polymech/acl", + "version": "0.2.0", + "license": "MIT", + "dependencies": { + "ignore": "^7.0.5", + "mime": "^4.1.0", + "pino": "^9.6.0" + }, + "bin": { + "pm-acl": "dist-in/main.js" + }, + "devDependencies": { + "@repo/typescript-config": "file:../typescript-config", + "@types/node": "22.10.2", + "@vitest/coverage-v8": "^2.1.8", + "@vitest/ui": "2.1.9", + "eslint": "^9.39.2", + "typescript": "^5.7.2", + "typescript-eslint": "^8.56.0", + "vitest": "^2.1.8" + } + }, + "../polymech-mono/packages/commons": { + "name": "@polymech/commons", + "version": "0.2.6", + "license": "BSD", + "dependencies": { + "@polymech/core": "file:../core", + "@polymech/fs": "file:../fs", + "@repo/typescript-config": "file:../typescript-config", + "@schemastore/package": "^0.0.10", + "ansi-regex": "^6.2.2", + "env-var": "^7.5.0", + "glob": "^10.4.5", + "js-yaml": "^4.1.0", + "jsonpath-plus": "^10.3.0", + "normalize-url": "^8.0.1", + "p-map": "^7.0.3", + "p-throttle": "^4.1.1", + "regedit": "^5.1.4", + "tslog": "^3.3.3", + "tsup": "^2.0.3", + "yargs": "^17.7.2", + "zod": "^3.24.3", + "zod-to-json-schema": "^3.24.5", + "zod-to-ts": "^1.2.0" + }, + "bin": { + "pm-cli": "dist/main.js" + }, + "devDependencies": { + "@types/node": "^22.12.0", + "typescript": "^5.7.3" + } + }, + "../polymech-mono/packages/core": { + "name": "@polymech/core", + "version": "0.2.6", + "license": "BSD", + "dependencies": { + "tslog": "^3.3.3", + "type-fest": "^4.37.0", + "zod": "^3.24.1" + }, + "devDependencies": { + "@repo/typescript-config": "../typescript-config", + "@types/node": "^22.12.0", + "typescript": "^5.7.3" + } + }, + "../polymech-mono/packages/fs": { + "name": "@polymech/fs", + "version": "0.13.41", + "license": "BSD-3-Clause", + "dependencies": { + "@polymech/core": "file:../core", + "@repo/typescript-config": "file:../typescript-config", + "denodeify": "^1.2.1", + "glob": "^10.4.1", + "mime": "^2.0.3", + "minimatch": "^10.0.1", + "mkdirp": "^3.0.1", + "q": "^1.4.1", + "rimraf": "^6.0.1", + "write-file-atomic": "^6.0.0", + "yargs": "^17.7.2" + }, + "devDependencies": { + "@types/denodeify": "^1.2.31", + "@types/mime": "^2.0.0", + "@types/node": "^22.10.2", + "fs-extra": "^4.0.2", + "globals": "^15.14.0", + "ts-node": "^10.9.1", + "typescript": "^5.7.2" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "../polymech-mono/packages/i18n": { + "name": "@polymech/i18n", + "version": "0.3.0", + "license": "BSD-3-Clause", + "dependencies": { + "@polymech/cache": "file:../cache", + "@polymech/commons": "file:../commons", + "@polymech/core": "file:../core", + "@polymech/fs": "file:../fs", + "@polymech/log": "file:../log", + "@types/html-minifier-terser": "^7.0.2", + "@types/node": "^22.12.0", + "axios": "^1.7.9", + "cacache": "^19.0.1", + "convert-units": "^2.3.4", + "cryptr": "^6.0.3", + "deepl-node": "^1.8.0", + "env-var": "^7.1.1", + "html-minifier-terser": "^7.2.0", + "json-to-pretty-yaml": "^1.2.2", + "jsonpath-plus": "^8.1.0", + "keyv": "^4.5.4", + "keyv-file": "^0.3.1", + "link-dev": "^1.0.4", + "p-map": "^7.0.3", + "p-throttle": "^4.1.1", + "querystring": "^0.2.1", + "smol-toml": "^1.3.1", + "ssri": "^10.0.1", + "tslog": "^3.3.3", + "typescript": "^5.7.3", + "xlsx": "^0.18.5", + "yaml": "^2.4.1", + "yargs": "^17.7.2", + "zod": "^3.24.1" + }, + "bin": { + "pm-i18n": "dist/main.js" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "../polymech-mono/packages/media": { + "name": "@polymech/media", + "version": "0.3.0", + "license": "BSD-3-Clause", + "dependencies": { + "@polymech/cache": "file:../cache", + "@polymech/commons": "file:../commons", + "@polymech/core": "file:../core", + "@polymech/fs": "file:../fs", + "@polymech/log": "file:../log", + "@types/fluent-ffmpeg": "^2.1.27", + "@types/node": "^24.0.10", + "bluebird": "^3.7.2", + "download": "^8.0.0", + "electron": "^37.2.6", + "fast-glob": "^3.3.2", + "fluent-ffmpeg": "^2.1.3", + "glob": "^11.0.0", + "js-beautify": "^1.14.6", + "lucide-react": "^0.539.0", + "mupdf": "^1.3.3", + "novita-sdk": "^1.0.37", + "p-map": "^7.0.3", + "regedit": "^5.1.4", + "replicate": "^1.0.1", + "sharp": "^0.34.3", + "tslog": "^4.9.3", + "typescript": "^5.8.3", + "webpack": "^5.101.1", + "webpack-cli": "^6.0.1", + "webpack-visualizer-plugin2": "^2.0.0", + "yargs": "^18.0.0", + "zod": "^3.25.74" + }, + "bin": { + "pm-media": "dist-in/main.js" + }, + "devDependencies": { + "@types/glob": "^8.1.0", + "@types/showdown": "^2.0.6", + "nexe": "^5.0.0-beta.4", + "pkg": "^5.8.1", + "vitest": "^3.1.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "../polymech-mono/packages/registry": { + "name": "@polymech/registry", + "version": "0.1.0", + "license": "BSD-3-Clause", + "dependencies": { + "@keyv/sqlite": "^4.0.6", + "@polymech/commons": "file:../commons", + "@polymech/core": "file:../core", + "@polymech/fs": "file:../fs", + "@polymech/log": "file:../log", + "@types/node": "^24.10.1", + "env-var": "^7.0.1", + "keyv": "^5.5.4", + "keyv-file": "^5.3.3", + "p-map": "^4.0.0", + "tslog": "^4.10.2", + "typescript": "^4.9.5", + "yargs": "^18.0.0" + }, + "bin": { + "polymech-registry": "main.js" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "../polymech-mono/packages/search": { + "name": "@polymech/search", + "version": "0.2.0", + "license": "BSD-3-Clause", + "dependencies": { + "@keyv/sqlite": "^4.0.1", + "@plastichub/osr-registry": "file:../registry", + "@polymech/cache": "file:../cache", + "@polymech/commons": "file:../commons", + "@polymech/core": "file:../core", + "@polymech/fs": "file:../fs", + "@polymech/log": "file:../log", + "@polymech/registry": "file:../registry", + "@types/cacache": "^15.0.1", + "@types/node": "^22.10.2", + "axios": "^1.3.4", + "bluebird": "^3.7.2", + "cacache": "^17.1.4", + "cheerio": "^1.0.0-rc.12", + "convert-units": "^2.3.4", + "csv-generate": "^4.3.1", + "env-var": "^7.0.1", + "html-to-text": "^9.0.5", + "jsonpath-plus": "^9.0.0", + "langchain": "^0.1.18", + "md5": "^2.3.0", + "node-html-parser": "^6.1.12", + "node-xlsx": "^0.23.0", + "p-limit": "^7.2.0", + "p-map": "^4.0.0", + "publish": "^0.6.0", + "puppeteer": "^24.35.0", + "puppeteer-extra": "^3.3.6", + "puppeteer-extra-plugin-stealth": "^2.11.2", + "serpapi": "^1.1.1", + "tslog": "^4.10.2", + "typescript": "^5.6.3", + "yargs": "^17.7.2", + "zod": "^3.24.3", + "zod-to-json-schema": "^3.24.5", + "zod-to-ts": "^1.2.0" + }, + "bin": { + "polymech-search": "dist-in/main.js" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@asteasolutions/zod-to-openapi": { + "version": "8.4.1", + "resolved": "https://registry.npmjs.org/@asteasolutions/zod-to-openapi/-/zod-to-openapi-8.4.1.tgz", + "integrity": "sha512-WmJUsFINbnWxGvHSd16aOjgKf+5GsfdxruO2YDLcgplsidakCauik1lhlk83YDH06265Yd1XtUyF24o09uygpw==", + "license": "MIT", + "dependencies": { + "openapi3-ts": "^4.1.2" + }, + "peerDependencies": { + "zod": "^4.0.0" + } + }, + "node_modules/@discoveryjs/json-ext": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.6.3.tgz", + "integrity": "sha512-4B4OijXeVNOPZlYA2oEwWOTkzyltLao+xbotHQeqN++Rv27Y6s818+n2Qkp8q+Fxhn0t/5lA5X1Mxktud8eayQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.17.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.8.1.tgz", + "integrity": "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz", + "integrity": "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.3.tgz", + "integrity": "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.3.tgz", + "integrity": "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.3.tgz", + "integrity": "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz", + "integrity": "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.3.tgz", + "integrity": "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz", + "integrity": "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz", + "integrity": "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.3.tgz", + "integrity": "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz", + "integrity": "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.3.tgz", + "integrity": "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.3.tgz", + "integrity": "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.3.tgz", + "integrity": "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==", + "cpu": [ + "mips64el" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.3.tgz", + "integrity": "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz", + "integrity": "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz", + "integrity": "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.3.tgz", + "integrity": "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.3.tgz", + "integrity": "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.3.tgz", + "integrity": "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.3.tgz", + "integrity": "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.3.tgz", + "integrity": "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.3.tgz", + "integrity": "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.3.tgz", + "integrity": "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.3.tgz", + "integrity": "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.3.tgz", + "integrity": "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.3.tgz", + "integrity": "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@foliojs-fork/fontkit": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/@foliojs-fork/fontkit/-/fontkit-1.9.2.tgz", + "integrity": "sha512-IfB5EiIb+GZk+77TRB86AHroVaqfq8JRFlUbz0WEwsInyCG0epX2tCPOy+UfaWPju30DeVoUAXfzWXmhn753KA==", + "license": "MIT", + "dependencies": { + "@foliojs-fork/restructure": "^2.0.2", + "brotli": "^1.2.0", + "clone": "^1.0.4", + "deep-equal": "^1.0.0", + "dfa": "^1.2.0", + "tiny-inflate": "^1.0.2", + "unicode-properties": "^1.2.2", + "unicode-trie": "^2.0.0" + } + }, + "node_modules/@foliojs-fork/linebreak": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@foliojs-fork/linebreak/-/linebreak-1.1.2.tgz", + "integrity": "sha512-ZPohpxxbuKNE0l/5iBJnOAfUaMACwvUIKCvqtWGKIMv1lPYoNjYXRfhi9FeeV9McBkBLxsMFWTVVhHJA8cyzvg==", + "license": "MIT", + "dependencies": { + "base64-js": "1.3.1", + "unicode-trie": "^2.0.0" + } + }, + "node_modules/@foliojs-fork/linebreak/node_modules/base64-js": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz", + "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==", + "license": "MIT" + }, + "node_modules/@foliojs-fork/pdfkit": { + "version": "0.15.3", + "resolved": "https://registry.npmjs.org/@foliojs-fork/pdfkit/-/pdfkit-0.15.3.tgz", + "integrity": "sha512-Obc0Wmy3bm7BINFVvPhcl2rnSSK61DQrlHU8aXnAqDk9LCjWdUOPwhgD8Ywz5VtuFjRxmVOM/kQ/XLIBjDvltw==", + "license": "MIT", + "dependencies": { + "@foliojs-fork/fontkit": "^1.9.2", + "@foliojs-fork/linebreak": "^1.1.1", + "crypto-js": "^4.2.0", + "jpeg-exif": "^1.1.4", + "png-js": "^1.0.0" + } + }, + "node_modules/@foliojs-fork/restructure": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@foliojs-fork/restructure/-/restructure-2.0.2.tgz", + "integrity": "sha512-59SgoZ3EXbkfSX7b63tsou/SDGzwUEK6MuB5sKqgVK1/XE0fxmpsOb9DQI8LXW3KfGnAjImCGhhEb7uPPAUVNA==", + "license": "MIT" + }, + "node_modules/@glideapps/ts-necessities": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/@glideapps/ts-necessities/-/ts-necessities-2.2.3.tgz", + "integrity": "sha512-gXi0awOZLHk3TbW55GZLCPP6O+y/b5X1pBXKBVckFONSwF1z1E5ND2BGJsghQFah+pW7pkkyFb2VhUQI2qhL5w==", + "license": "MIT" + }, + "node_modules/@hey-api/client-fetch": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/@hey-api/client-fetch/-/client-fetch-0.13.1.tgz", + "integrity": "sha512-29jBRYNdxVGlx5oewFgOrkulZckpIpBIRHth3uHFn1PrL2ucMy52FvWOY3U3dVx2go1Z3kUmMi6lr07iOpUqqA==", + "deprecated": "Starting with v0.73.0, this package is bundled directly inside @hey-api/openapi-ts.", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/hey-api" + }, + "peerDependencies": { + "@hey-api/openapi-ts": "< 2" + } + }, + "node_modules/@hey-api/codegen-core": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/@hey-api/codegen-core/-/codegen-core-0.7.0.tgz", + "integrity": "sha512-HglL4B4QwpzocE+c8qDU6XK8zMf8W8Pcv0RpFDYxHuYALWLTnpDUuEsglC7NQ4vC1maoXsBpMbmwpco0N4QviA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@hey-api/types": "0.1.3", + "ansi-colors": "4.1.3", + "c12": "3.3.3", + "color-support": "1.1.3" + }, + "engines": { + "node": ">=20.19.0" + }, + "funding": { + "url": "https://github.com/sponsors/hey-api" + }, + "peerDependencies": { + "typescript": ">=5.5.3" + } + }, + "node_modules/@hey-api/json-schema-ref-parser": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@hey-api/json-schema-ref-parser/-/json-schema-ref-parser-1.3.0.tgz", + "integrity": "sha512-3tQJ8N2egHXZjQWUeceoWrl88APWjo7gRrQ/L4HWJKnh6HowczCv7yNNFeSusPoWGV6HGdoFiCvq6UsLkrwKhg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jsdevtools/ono": "7.1.3", + "@types/json-schema": "7.0.15", + "js-yaml": "4.1.1" + }, + "engines": { + "node": ">=20.19.0" + }, + "funding": { + "url": "https://github.com/sponsors/hey-api" + } + }, + "node_modules/@hey-api/openapi-ts": { + "version": "0.92.4", + "resolved": "https://registry.npmjs.org/@hey-api/openapi-ts/-/openapi-ts-0.92.4.tgz", + "integrity": "sha512-RA3wnL7Odr5xczuS3xpvnPClgJ/K8jivK3hvD8J0m5GBuvJFkZ1A1xp+6Ve1G0BV8p4LwxwgN1Qhb+4BFsLfMg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@hey-api/codegen-core": "0.7.0", + "@hey-api/json-schema-ref-parser": "1.3.0", + "@hey-api/shared": "0.2.0", + "@hey-api/types": "0.1.3", + "ansi-colors": "4.1.3", + "color-support": "1.1.3", + "commander": "14.0.3" + }, + "bin": { + "openapi-ts": "bin/run.js" + }, + "engines": { + "node": ">=20.19.0" + }, + "funding": { + "url": "https://github.com/sponsors/hey-api" + }, + "peerDependencies": { + "typescript": ">=5.5.3" + } + }, + "node_modules/@hey-api/shared": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@hey-api/shared/-/shared-0.2.0.tgz", + "integrity": "sha512-t7C+65ES12OqAE5k6DB/y5nDuTjydtqdxf/Qe4zflVn2AzGs7hO/7KjXvGXZYnpNVF7QISAcj0LEObASU9I53Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@hey-api/codegen-core": "0.7.0", + "@hey-api/json-schema-ref-parser": "1.3.0", + "@hey-api/types": "0.1.3", + "ansi-colors": "4.1.3", + "cross-spawn": "7.0.6", + "open": "11.0.0", + "semver": "7.7.3" + }, + "engines": { + "node": ">=20.19.0" + }, + "funding": { + "url": "https://github.com/sponsors/hey-api" + }, + "peerDependencies": { + "typescript": ">=5.5.3" + } + }, + "node_modules/@hey-api/types": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@hey-api/types/-/types-0.1.3.tgz", + "integrity": "sha512-mZaiPOWH761yD4GjDQvtjS2ZYLu5o5pI1TVSvV/u7cmbybv51/FVtinFBeaE1kFQCKZ8OQpn2ezjLBJrKsGATw==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "typescript": ">=5.5.3" + } + }, + "node_modules/@hono/node-server": { + "version": "1.19.9", + "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.9.tgz", + "integrity": "sha512-vHL6w3ecZsky+8P5MD+eFfaGTyCeOHUIFYMGpQGbrBTSmNNoxv0if69rEZ5giu36weC5saFuznL411gRX7bJDw==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=18.14.1" + }, + "peerDependencies": { + "hono": "^4" + } + }, + "node_modules/@hono/node-ws": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@hono/node-ws/-/node-ws-1.3.0.tgz", + "integrity": "sha512-ju25YbbvLuXdqBCmLZLqnNYu1nbHIQjoyUqA8ApZOeL1k4skuiTcw5SW77/5SUYo2Xi2NVBJoVlfQurnKEp03Q==", + "license": "MIT", + "dependencies": { + "ws": "^8.17.0" + }, + "engines": { + "node": ">=18.14.1" + }, + "peerDependencies": { + "@hono/node-server": "^1.19.2", + "hono": "^4.6.0" + } + }, + "node_modules/@hono/swagger-ui": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/@hono/swagger-ui/-/swagger-ui-0.5.3.tgz", + "integrity": "sha512-Hn90DOOJ62ICJQplQvCDVpi9Jcn6EhtRaiffyJIS53wA5RmRLtMCDQGVc0bor8vQD7JIwpkweWjs+3cycp+IvA==", + "license": "MIT", + "peerDependencies": { + "hono": ">=4.0.0" + } + }, + "node_modules/@hono/zod-openapi": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@hono/zod-openapi/-/zod-openapi-1.2.2.tgz", + "integrity": "sha512-va6vsL23wCJ1d0Vd+vGL1XOt+wPwItxirYafuhlW9iC2MstYr2FvsI7mctb45eBTjZfkqB/3LYDJEppPjOEiHw==", + "license": "MIT", + "dependencies": { + "@asteasolutions/zod-to-openapi": "^8.4.1", + "@hono/zod-validator": "^0.7.6", + "openapi3-ts": "^4.5.0" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "hono": ">=4.3.6", + "zod": "^4.0.0" + } + }, + "node_modules/@hono/zod-validator": { + "version": "0.7.6", + "resolved": "https://registry.npmjs.org/@hono/zod-validator/-/zod-validator-0.7.6.tgz", + "integrity": "sha512-Io1B6d011Gj1KknV4rXYz4le5+5EubcWEU/speUjuw9XMMIaP3n78yXLhjd2A3PXaXaUwEAluOiAyLqhBEJgsw==", + "license": "MIT", + "peerDependencies": { + "hono": ">=3.9.0", + "zod": "^3.25.0 || ^4.0.0" + } + }, + "node_modules/@img/colour": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.0.0.tgz", + "integrity": "sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@img/sharp-darwin-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.5.tgz", + "integrity": "sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-arm64": "1.2.4" + } + }, + "node_modules/@img/sharp-darwin-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.5.tgz", + "integrity": "sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-x64": "1.2.4" + } + }, + "node_modules/@img/sharp-libvips-darwin-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.4.tgz", + "integrity": "sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-darwin-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.4.tgz", + "integrity": "sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.4.tgz", + "integrity": "sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==", + "cpu": [ + "arm" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.4.tgz", + "integrity": "sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-ppc64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.4.tgz", + "integrity": "sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==", + "cpu": [ + "ppc64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-riscv64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.2.4.tgz", + "integrity": "sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==", + "cpu": [ + "riscv64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-s390x": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.4.tgz", + "integrity": "sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==", + "cpu": [ + "s390x" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.4.tgz", + "integrity": "sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.4.tgz", + "integrity": "sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.4.tgz", + "integrity": "sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-linux-arm": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.5.tgz", + "integrity": "sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==", + "cpu": [ + "arm" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.5.tgz", + "integrity": "sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm64": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-ppc64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.5.tgz", + "integrity": "sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==", + "cpu": [ + "ppc64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-ppc64": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-riscv64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.34.5.tgz", + "integrity": "sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==", + "cpu": [ + "riscv64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-riscv64": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-s390x": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.5.tgz", + "integrity": "sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==", + "cpu": [ + "s390x" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-s390x": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.5.tgz", + "integrity": "sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-x64": "1.2.4" + } + }, + "node_modules/@img/sharp-linuxmusl-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.5.tgz", + "integrity": "sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-arm64": "1.2.4" + } + }, + "node_modules/@img/sharp-linuxmusl-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.5.tgz", + "integrity": "sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-x64": "1.2.4" + } + }, + "node_modules/@img/sharp-wasm32": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.5.tgz", + "integrity": "sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==", + "cpu": [ + "wasm32" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", + "optional": true, + "dependencies": { + "@emnapi/runtime": "^1.7.0" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.5.tgz", + "integrity": "sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-ia32": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.5.tgz", + "integrity": "sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==", + "cpu": [ + "ia32" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.5.tgz", + "integrity": "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@inquirer/external-editor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-1.0.3.tgz", + "integrity": "sha512-RWbSrDiYmO4LbejWY7ttpxczuwQyZLBUyygsA9Nsv95hpzUWwnNTVQmAq3xuh7vNwCp07UTmE5i11XAEExx4RA==", + "dev": true, + "license": "MIT", + "dependencies": { + "chardet": "^2.1.1", + "iconv-lite": "^0.7.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/external-editor/node_modules/iconv-lite": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz", + "integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "license": "MIT" + }, + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.11", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.11.tgz", + "integrity": "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@jsdevtools/ono": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/@jsdevtools/ono/-/ono-7.1.3.tgz", + "integrity": "sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@oclif/core": { + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/@oclif/core/-/core-4.8.1.tgz", + "integrity": "sha512-07mq0vKCWNsB85ZHeBMlTAiO0KLFqHyAeRK3bD2K8CI1tX3tiwkWw1lZQZkiw8MUBrhxdROhMkYMY4Q0l7JHqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-escapes": "^4.3.2", + "ansis": "^3.17.0", + "clean-stack": "^3.0.1", + "cli-spinners": "^2.9.2", + "debug": "^4.4.3", + "ejs": "^3.1.10", + "get-package-type": "^0.1.0", + "indent-string": "^4.0.0", + "is-wsl": "^2.2.0", + "lilconfig": "^3.1.3", + "minimatch": "^10.2.1", + "semver": "^7.7.3", + "string-width": "^4.2.3", + "supports-color": "^8", + "tinyglobby": "^0.2.14", + "widest-line": "^3.1.0", + "wordwrap": "^1.0.0", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@one-ini/wasm": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@one-ini/wasm/-/wasm-0.1.1.tgz", + "integrity": "sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw==", + "license": "MIT" + }, + "node_modules/@pinojs/redact": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@pinojs/redact/-/redact-0.4.0.tgz", + "integrity": "sha512-k2ENnmBugE/rzQfEcdWHcCY+/FM3VLzH9cYEsbdsoqrvzAKRhUZeRNhAZvB8OitQJ1TBed3yqWtdjzS6wJKBwg==", + "license": "MIT" + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@polka/url": { + "version": "1.0.0-next.29", + "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.29.tgz", + "integrity": "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==", + "dev": true, + "license": "MIT" + }, + "node_modules/@polymech/acl": { + "resolved": "../polymech-mono/packages/acl", + "link": true + }, + "node_modules/@polymech/commons": { + "resolved": "../polymech-mono/packages/commons", + "link": true + }, + "node_modules/@polymech/core": { + "resolved": "../polymech-mono/packages/core", + "link": true + }, + "node_modules/@polymech/fs": { + "resolved": "../polymech-mono/packages/fs", + "link": true + }, + "node_modules/@polymech/i18n": { + "resolved": "../polymech-mono/packages/i18n", + "link": true + }, + "node_modules/@polymech/media": { + "resolved": "../polymech-mono/packages/media", + "link": true + }, + "node_modules/@polymech/registry": { + "resolved": "../polymech-mono/packages/registry", + "link": true + }, + "node_modules/@polymech/search": { + "resolved": "../polymech-mono/packages/search", + "link": true + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.59.0.tgz", + "integrity": "sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.59.0.tgz", + "integrity": "sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.59.0.tgz", + "integrity": "sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.59.0.tgz", + "integrity": "sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.59.0.tgz", + "integrity": "sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.59.0.tgz", + "integrity": "sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.59.0.tgz", + "integrity": "sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.59.0.tgz", + "integrity": "sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.59.0.tgz", + "integrity": "sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.59.0.tgz", + "integrity": "sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.59.0.tgz", + "integrity": "sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.59.0.tgz", + "integrity": "sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.59.0.tgz", + "integrity": "sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.59.0.tgz", + "integrity": "sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.59.0.tgz", + "integrity": "sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.59.0.tgz", + "integrity": "sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.59.0.tgz", + "integrity": "sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.59.0.tgz", + "integrity": "sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.59.0.tgz", + "integrity": "sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.59.0.tgz", + "integrity": "sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.59.0.tgz", + "integrity": "sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.59.0.tgz", + "integrity": "sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.59.0.tgz", + "integrity": "sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.59.0.tgz", + "integrity": "sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.59.0.tgz", + "integrity": "sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@scalar/core": { + "version": "0.3.42", + "resolved": "https://registry.npmjs.org/@scalar/core/-/core-0.3.42.tgz", + "integrity": "sha512-RbyooMuG4oQEOhiA/tC+++bkIK1zeYGNxrTzSAgTrTzVlbFKPzw72fs4gX9/eHDo7qVc9FsymIW6qVpWbySzNg==", + "license": "MIT", + "dependencies": { + "@scalar/types": "0.6.7" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@scalar/helpers": { + "version": "0.2.16", + "resolved": "https://registry.npmjs.org/@scalar/helpers/-/helpers-0.2.16.tgz", + "integrity": "sha512-JlDUKdmwAHdcFUdTngNtx/uhLKTBACXlgvri7iKb6Jx6ImRIBgHwxZNAqlil1L047+QBrKh97lnezNpzNQAffQ==", + "license": "MIT", + "engines": { + "node": ">=20" + } + }, + "node_modules/@scalar/hono-api-reference": { + "version": "0.9.45", + "resolved": "https://registry.npmjs.org/@scalar/hono-api-reference/-/hono-api-reference-0.9.45.tgz", + "integrity": "sha512-RH275yhbKlON6N1KgJUCiLIixw0Bd77Dp/6IuYQ6UhIboyq6c4EuSegRLJrb3XpP57+MNKuetYvAljDp8alHpQ==", + "license": "MIT", + "dependencies": { + "@scalar/core": "0.3.42" + }, + "engines": { + "node": ">=20" + }, + "peerDependencies": { + "hono": "^4.11.5" + } + }, + "node_modules/@scalar/types": { + "version": "0.6.7", + "resolved": "https://registry.npmjs.org/@scalar/types/-/types-0.6.7.tgz", + "integrity": "sha512-ihHaoPF9qQR05pV3mfE7yBlHQdm5CoJVE0HiJFH6xSrzLfk2yJ6XdD3OzyRCqyxkZ38bj2RIZMS6LJsGy4p66g==", + "license": "MIT", + "dependencies": { + "@scalar/helpers": "0.2.16", + "nanoid": "^5.1.6", + "type-fest": "^5.3.1", + "zod": "^4.3.5" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@sindresorhus/is": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", + "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/@ssut/tiktok-api": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@ssut/tiktok-api/-/tiktok-api-1.5.2.tgz", + "integrity": "sha512-5bCLxuoeiEig/XkQyJ8Xqewsj38Gc1daIyJJfSSvUmeobG8hPYcmF5ugCIOW9T99LguElPKwo2uLBzVrqKf1RA==", + "license": "ISC", + "dependencies": { + "debug": "^4.4.3" + }, + "peerDependencies": { + "async-retry": "^1.0.0", + "axios": "^1.0.0", + "https-proxy-agent": "^7.0.0" + } + }, + "node_modules/@standard-schema/spec": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", + "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@supabase/auth-js": { + "version": "2.98.0", + "resolved": "https://registry.npmjs.org/@supabase/auth-js/-/auth-js-2.98.0.tgz", + "integrity": "sha512-GBH361T0peHU91AQNzOlIrjUZw9TZbB9YDRiyFgk/3Kvr3/Z1NWUZ2athWTfHhwNNi8IrW00foyFxQD9IO/Trg==", + "license": "MIT", + "dependencies": { + "tslib": "2.8.1" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@supabase/functions-js": { + "version": "2.98.0", + "resolved": "https://registry.npmjs.org/@supabase/functions-js/-/functions-js-2.98.0.tgz", + "integrity": "sha512-N/xEyiNU5Org+d+PNCpv+TWniAXRzxIURxDYsS/m2I/sfAB/HcM9aM2Dmf5edj5oWb9GxID1OBaZ8NMmPXL+Lg==", + "license": "MIT", + "dependencies": { + "tslib": "2.8.1" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@supabase/postgrest-js": { + "version": "2.98.0", + "resolved": "https://registry.npmjs.org/@supabase/postgrest-js/-/postgrest-js-2.98.0.tgz", + "integrity": "sha512-v6e9WeZuJijzUut8HyXu6gMqWFepIbaeaMIm1uKzei4yLg9bC9OtEW9O14LE/9ezqNbSAnSLO5GtOLFdm7Bpkg==", + "license": "MIT", + "dependencies": { + "tslib": "2.8.1" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@supabase/realtime-js": { + "version": "2.98.0", + "resolved": "https://registry.npmjs.org/@supabase/realtime-js/-/realtime-js-2.98.0.tgz", + "integrity": "sha512-rOWt28uGyFipWOSd+n0WVMr9kUXiWaa7J4hvyLCIHjRFqWm1z9CaaKAoYyfYMC1Exn3WT8WePCgiVhlAtWC2yw==", + "license": "MIT", + "dependencies": { + "@types/phoenix": "^1.6.6", + "@types/ws": "^8.18.1", + "tslib": "2.8.1", + "ws": "^8.18.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@supabase/storage-js": { + "version": "2.98.0", + "resolved": "https://registry.npmjs.org/@supabase/storage-js/-/storage-js-2.98.0.tgz", + "integrity": "sha512-tzr2mG+v7ILSAZSfZMSL9OPyIH4z1ikgQ8EcQTKfMRz4EwmlFt3UnJaGzSOxyvF5b+fc9So7qdSUWTqGgeLokQ==", + "license": "MIT", + "dependencies": { + "iceberg-js": "^0.8.1", + "tslib": "2.8.1" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@supabase/supabase-js": { + "version": "2.98.0", + "resolved": "https://registry.npmjs.org/@supabase/supabase-js/-/supabase-js-2.98.0.tgz", + "integrity": "sha512-Ohc97CtInLwZyiSASz7tT9/Abm/vqnIbO9REp+PivVUII8UZsuI3bngRQnYgJdFoOIwvaEII1fX1qy8x0CyNiw==", + "license": "MIT", + "dependencies": { + "@supabase/auth-js": "2.98.0", + "@supabase/functions-js": "2.98.0", + "@supabase/postgrest-js": "2.98.0", + "@supabase/realtime-js": "2.98.0", + "@supabase/storage-js": "2.98.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@szmarczak/http-timer": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", + "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", + "license": "MIT", + "dependencies": { + "defer-to-connect": "^1.0.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@types/chai": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", + "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/deep-eql": "*", + "assertion-error": "^2.0.1" + } + }, + "node_modules/@types/deep-eql": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", + "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/eslint": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz", + "integrity": "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "node_modules/@types/eslint-scope": { + "version": "3.7.7", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", + "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "license": "MIT" + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "24.10.14", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.14.tgz", + "integrity": "sha512-OowOUbD1lBCOFIPOZ8xnMIhgqA4sCutMiYOmPHL1PTLt5+y1XA+g2+yC9OOyz8p+deMZqPZLxfMjYIfrKsPeFg==", + "license": "MIT", + "dependencies": { + "undici-types": "~7.16.0" + } + }, + "node_modules/@types/pdfkit": { + "version": "0.17.5", + "resolved": "https://registry.npmjs.org/@types/pdfkit/-/pdfkit-0.17.5.tgz", + "integrity": "sha512-T3ZHnvF91HsEco5ClhBCOuBwobZfPcI2jaiSHybkkKYq4KhVIIurod94JVKvDIG0JXT6o3KiERC0X0//m8dyrg==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/pdfmake": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/@types/pdfmake/-/pdfmake-0.2.13.tgz", + "integrity": "sha512-QzOwk3dMTZOwVbDZNHGIQcpwBgprp1y1vzRBmR+p+vMtCZo00G1CN+YhNebkygtmaGjdzvyXJVOHMEuTbvhJ8A==", + "license": "MIT", + "dependencies": { + "@types/node": "*", + "@types/pdfkit": "*" + } + }, + "node_modules/@types/pg": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/@types/pg/-/pg-8.16.0.tgz", + "integrity": "sha512-RmhMd/wD+CF8Dfo+cVIy3RR5cl8CyfXQ0tGgW6XBL8L4LM/UTEbNXYRbLwU6w+CgrKBNbrQWt4FUtTfaU5jSYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "pg-protocol": "*", + "pg-types": "^2.2.0" + } + }, + "node_modules/@types/phoenix": { + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/@types/phoenix/-/phoenix-1.6.7.tgz", + "integrity": "sha512-oN9ive//QSBkf19rfDv45M7eZPi0eEXylht2OLEXicu5b4KoQ1OzXIw+xDSGWxSxe1JmepRR/ZH283vsu518/Q==", + "license": "MIT" + }, + "node_modules/@types/sharp": { + "version": "0.31.1", + "resolved": "https://registry.npmjs.org/@types/sharp/-/sharp-0.31.1.tgz", + "integrity": "sha512-5nWwamN9ZFHXaYEincMSuza8nNfOof8nmO+mcI+Agx1uMUk4/pQnNIcix+9rLPXzKrm1pS34+6WRDbDV0Jn7ag==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/ws": { + "version": "8.18.1", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz", + "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@typescript/vfs": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/@typescript/vfs/-/vfs-1.6.4.tgz", + "integrity": "sha512-PJFXFS4ZJKiJ9Qiuix6Dz/OwEIqHD7Dme1UwZhTK11vR+5dqW2ACbdndWQexBzCx+CPuMe5WBYQWCsFyGlQLlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.4.3" + }, + "peerDependencies": { + "typescript": "*" + } + }, + "node_modules/@vitest/expect": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.0.18.tgz", + "integrity": "sha512-8sCWUyckXXYvx4opfzVY03EOiYVxyNrHS5QxX3DAIi5dpJAAkyJezHCP77VMX4HKA2LDT/Jpfo8i2r5BE3GnQQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@standard-schema/spec": "^1.0.0", + "@types/chai": "^5.2.2", + "@vitest/spy": "4.0.18", + "@vitest/utils": "4.0.18", + "chai": "^6.2.1", + "tinyrainbow": "^3.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/mocker": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.0.18.tgz", + "integrity": "sha512-HhVd0MDnzzsgevnOWCBj5Otnzobjy5wLBe4EdeeFGv8luMsGcYqDuFRMcttKWZA5vVO8RFjexVovXvAM4JoJDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "4.0.18", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.21" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^6.0.0 || ^7.0.0-0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "node_modules/@vitest/pretty-format": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.0.18.tgz", + "integrity": "sha512-P24GK3GulZWC5tz87ux0m8OADrQIUVDPIjjj65vBXYG17ZeU3qD7r+MNZ1RNv4l8CGU2vtTRqixrOi9fYk/yKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^3.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.0.18.tgz", + "integrity": "sha512-rpk9y12PGa22Jg6g5M3UVVnTS7+zycIGk9ZNGN+m6tZHKQb7jrP7/77WfZy13Y/EUDd52NDsLRQhYKtv7XfPQw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/utils": "4.0.18", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/snapshot": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.0.18.tgz", + "integrity": "sha512-PCiV0rcl7jKQjbgYqjtakly6T1uwv/5BQ9SwBLekVg/EaYeQFPiXcgrC2Y7vDMA8dM1SUEAEV82kgSQIlXNMvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "4.0.18", + "magic-string": "^0.30.21", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/spy": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.0.18.tgz", + "integrity": "sha512-cbQt3PTSD7P2OARdVW3qWER5EGq7PHlvE+QfzSC0lbwO+xnt7+XH06ZzFjFRgzUX//JmpxrCu92VdwvEPlWSNw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/ui": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/ui/-/ui-4.0.18.tgz", + "integrity": "sha512-CGJ25bc8fRi8Lod/3GHSvXRKi7nBo3kxh0ApW4yCjmrWmRmlT53B5E08XRSZRliygG0aVNxLrBEqPYdz/KcCtQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@vitest/utils": "4.0.18", + "fflate": "^0.8.2", + "flatted": "^3.3.3", + "pathe": "^2.0.3", + "sirv": "^3.0.2", + "tinyglobby": "^0.2.15", + "tinyrainbow": "^3.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "vitest": "4.0.18" + } + }, + "node_modules/@vitest/utils": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.0.18.tgz", + "integrity": "sha512-msMRKLMVLWygpK3u2Hybgi4MNjcYJvwTb0Ru09+fOyCXIgT5raYP041DRRdiJiI3k/2U6SEbAETB3YtBrUkCFA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "4.0.18", + "tinyrainbow": "^3.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@webassemblyjs/ast": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz", + "integrity": "sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/helper-numbers": "1.13.2", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2" + } + }, + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.13.2.tgz", + "integrity": "sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.13.2.tgz", + "integrity": "sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.14.1.tgz", + "integrity": "sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-numbers": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.13.2.tgz", + "integrity": "sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/floating-point-hex-parser": "1.13.2", + "@webassemblyjs/helper-api-error": "1.13.2", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.13.2.tgz", + "integrity": "sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.14.1.tgz", + "integrity": "sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/wasm-gen": "1.14.1" + } + }, + "node_modules/@webassemblyjs/ieee754": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.13.2.tgz", + "integrity": "sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "node_modules/@webassemblyjs/leb128": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.13.2.tgz", + "integrity": "sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/utf8": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.13.2.tgz", + "integrity": "sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@webassemblyjs/wasm-edit": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.14.1.tgz", + "integrity": "sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/helper-wasm-section": "1.14.1", + "@webassemblyjs/wasm-gen": "1.14.1", + "@webassemblyjs/wasm-opt": "1.14.1", + "@webassemblyjs/wasm-parser": "1.14.1", + "@webassemblyjs/wast-printer": "1.14.1" + } + }, + "node_modules/@webassemblyjs/wasm-gen": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.14.1.tgz", + "integrity": "sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/ieee754": "1.13.2", + "@webassemblyjs/leb128": "1.13.2", + "@webassemblyjs/utf8": "1.13.2" + } + }, + "node_modules/@webassemblyjs/wasm-opt": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.14.1.tgz", + "integrity": "sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/wasm-gen": "1.14.1", + "@webassemblyjs/wasm-parser": "1.14.1" + } + }, + "node_modules/@webassemblyjs/wasm-parser": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.14.1.tgz", + "integrity": "sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-api-error": "1.13.2", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/ieee754": "1.13.2", + "@webassemblyjs/leb128": "1.13.2", + "@webassemblyjs/utf8": "1.13.2" + } + }, + "node_modules/@webassemblyjs/wast-printer": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.14.1.tgz", + "integrity": "sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webpack-cli/configtest": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-3.0.1.tgz", + "integrity": "sha512-u8d0pJ5YFgneF/GuvEiDA61Tf1VDomHHYMjv/wc9XzYj7nopltpG96nXN5dJRstxZhcNpV1g+nT6CydO7pHbjA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.12.0" + }, + "peerDependencies": { + "webpack": "^5.82.0", + "webpack-cli": "6.x.x" + } + }, + "node_modules/@webpack-cli/info": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-3.0.1.tgz", + "integrity": "sha512-coEmDzc2u/ffMvuW9aCjoRzNSPDl/XLuhPdlFRpT9tZHmJ/039az33CE7uH+8s0uL1j5ZNtfdv0HkfaKRBGJsQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.12.0" + }, + "peerDependencies": { + "webpack": "^5.82.0", + "webpack-cli": "6.x.x" + } + }, + "node_modules/@webpack-cli/serve": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-3.0.1.tgz", + "integrity": "sha512-sbgw03xQaCLiT6gcY/6u3qBDn01CWw/nbaXl3gTdTFuJJ75Gffv3E3DBpgvY2fkkrdS1fpjaXNOmJlnbtKauKg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.12.0" + }, + "peerDependencies": { + "webpack": "^5.82.0", + "webpack-cli": "6.x.x" + }, + "peerDependenciesMeta": { + "webpack-dev-server": { + "optional": true + } + } + }, + "node_modules/@xmldom/xmldom": { + "version": "0.9.8", + "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.9.8.tgz", + "integrity": "sha512-p96FSY54r+WJ50FIOsCOjyj/wavs8921hG5+kVMmZgKcvIKxMXHTrjNJvRgWa/zuX3B6t2lijLNFaOyuxUH+2A==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14.6" + } + }, + "node_modules/@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/abbrev": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-2.0.0.tgz", + "integrity": "sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==", + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "license": "MIT", + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, + "node_modules/acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-node": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/acorn-node/-/acorn-node-1.8.2.tgz", + "integrity": "sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "acorn": "^7.0.0", + "acorn-walk": "^7.0.0", + "xtend": "^4.0.2" + } + }, + "node_modules/acorn-walk": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", + "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/adm-zip": { + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.16.tgz", + "integrity": "sha512-TGw5yVi4saajsSEgz25grObGHEUaDrniwvA2qwSC060KfqGPdglhvPMA2lPIoxs3PQIItj2iag35fONcQqgUaQ==", + "license": "MIT", + "engines": { + "node": ">=12.0" + } + }, + "node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/ajv": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", + "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ajv-formats/node_modules/ajv": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", + "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT" + }, + "node_modules/ansi-align": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", + "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", + "license": "ISC", + "dependencies": { + "string-width": "^4.1.0" + } + }, + "node_modules/ansi-colors": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-escapes/node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/ansis": { + "version": "3.17.0", + "resolved": "https://registry.npmjs.org/ansis/-/ansis-3.17.0.tgz", + "integrity": "sha512-0qWUglt9JEqLFr3w1I1pbrChn1grhaiAR2ocX1PP/flRmxgtwTzPFFFnfIlD6aMOLQZgSuCRlidD70lvx8yhzg==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/anymatch/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/asn1": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", + "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": "~2.1.0" + } + }, + "node_modules/asn1.js": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz", + "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/asn1.js/node_modules/bn.js": { + "version": "4.12.3", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.3.tgz", + "integrity": "sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==", + "dev": true, + "license": "MIT" + }, + "node_modules/assert": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/assert/-/assert-1.5.1.tgz", + "integrity": "sha512-zzw1uCAgLbsKwBfFc8CX78DDg+xZeBksSO3vwVIDDN5i94eOrPsSSyiVhmsSABFDM/OcpE2aagCat9dnWQLG1A==", + "dev": true, + "license": "MIT", + "dependencies": { + "object.assign": "^4.1.4", + "util": "^0.10.4" + } + }, + "node_modules/assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/async": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "integrity": "sha512-nSVgobk4rv61R9PUSDtYt7mPVB2olxNR5RWJcAsH676/ef11bUZwvu7+RGYrYauVdDPcO519v68wRhXQtxsV9w==", + "dev": true, + "license": "MIT" + }, + "node_modules/async-retry": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/async-retry/-/async-retry-1.3.3.tgz", + "integrity": "sha512-wfr/jstw9xNi/0teMHrRW7dsz3Lt5ARhYNZ2ewpadnhaIp5mbALhOAP+EAdsC7t4Z6wqsDVv9+W6gm1Dk9mEyw==", + "license": "MIT", + "peer": true, + "dependencies": { + "retry": "0.13.1" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" + }, + "node_modules/atomic-sleep": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz", + "integrity": "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==", + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "*" + } + }, + "node_modules/aws4": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.13.2.tgz", + "integrity": "sha512-lHe62zvbTB5eEABUVi/AwVh0ZKY9rMMDhmm+eeyuuUQbQ3+J+fONVQOZyj+DdrvD4BY33uYniyRJ4UJIaSKAfw==", + "dev": true, + "license": "MIT" + }, + "node_modules/axios": { + "version": "1.13.5", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.5.tgz", + "integrity": "sha512-cz4ur7Vb0xS4/KUN0tPWe44eqxrIu31me+fbang3ijiNscE129POzipJJA6zniq2C/Z6sJCjMimjS8Lc/GAs8Q==", + "license": "MIT", + "peer": true, + "dependencies": { + "follow-redirects": "^1.15.11", + "form-data": "^4.0.5", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/baseline-browser-mapping": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.0.tgz", + "integrity": "sha512-lIyg0szRfYbiy67j9KN8IyeD7q7hcmqnJ1ddWmNt19ItGpNN64mnllmxUNFIOdOm6by97jlL6wfpTTJrmnjWAA==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "tweetnacl": "^0.14.3" + } + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/bl": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.3.tgz", + "integrity": "sha512-pvcNpa0UU69UT341rO6AYy4FVAIkUHuZXRIWbq+zHnsVcRzDDjIAhGuuYoi0d//cwIwtt4pkpKycWEfjdV+vww==", + "dev": true, + "license": "MIT", + "dependencies": { + "readable-stream": "^2.3.5", + "safe-buffer": "^5.1.1" + } + }, + "node_modules/bn.js": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.3.tgz", + "integrity": "sha512-EAcmnPkxpntVL+DS7bO1zhcZNvCkxqtkd0ZY53h06GNQ3DEkkGZ/gKgmDv6DdZQGj9BgfSPKtJJ7Dp1GPP8f7w==", + "dev": true, + "license": "MIT" + }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "license": "ISC" + }, + "node_modules/boxen": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-4.2.0.tgz", + "integrity": "sha512-eB4uT9RGzg2odpER62bBwSLvUeGC+WbRjjyyFhGsKnc8wp/m0+hQsMUvUe3H2V0D5vw0nBdO1hCJoZo5mKeuIQ==", + "license": "MIT", + "dependencies": { + "ansi-align": "^3.0.0", + "camelcase": "^5.3.1", + "chalk": "^3.0.0", + "cli-boxes": "^2.2.0", + "string-width": "^4.1.0", + "term-size": "^2.1.0", + "type-fest": "^0.8.1", + "widest-line": "^3.1.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/boxen/node_modules/chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/boxen/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/boxen/node_modules/type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=8" + } + }, + "node_modules/brace-expansion": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.3.tgz", + "integrity": "sha512-fy6KJm2RawA5RcHkLa1z/ScpBeA762UF9KmZQxwIbDtRJrgLzM10depAiEQ+CXYcoiqW1/m96OAAoke2nE9EeA==", + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==", + "dev": true, + "license": "MIT" + }, + "node_modules/brotli": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/brotli/-/brotli-1.3.3.tgz", + "integrity": "sha512-oTKjJdShmDuGW94SyyaoQvAjf30dZaHnjJ8uAF+u2/vGJkJbJPJAT1gDiOJP5v1Zb6f9KEyW/1HpuaWIXtGHPg==", + "license": "MIT", + "dependencies": { + "base64-js": "^1.1.2" + } + }, + "node_modules/browser-or-node": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/browser-or-node/-/browser-or-node-3.0.0.tgz", + "integrity": "sha512-iczIdVJzGEYhP5DqQxYM9Hh7Ztpqqi+CXZpSmX8ALFs9ecXkQIeqRyM6TfxEfMVpwhl3dSuDvxdzzo9sUOIVBQ==", + "license": "MIT" + }, + "node_modules/browser-pack": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/browser-pack/-/browser-pack-6.1.0.tgz", + "integrity": "sha512-erYug8XoqzU3IfcU8fUgyHqyOXqIE4tUTTQ+7mqUjQlvnXkOO6OlT9c/ZoJVHYoAaqGxr09CN53G7XIsO4KtWA==", + "dev": true, + "license": "MIT", + "dependencies": { + "combine-source-map": "~0.8.0", + "defined": "^1.0.0", + "JSONStream": "^1.0.3", + "safe-buffer": "^5.1.1", + "through2": "^2.0.0", + "umd": "^3.0.0" + }, + "bin": { + "browser-pack": "bin/cmd.js" + } + }, + "node_modules/browser-resolve": { + "version": "1.11.3", + "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-1.11.3.tgz", + "integrity": "sha512-exDi1BYWB/6raKHmDTCicQfTkqwN5fioMFV4j8BsfMU4R2DK/QfZfK7kOVkmWCNANf0snkBzqGqAJBao9gZMdQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve": "1.1.7" + } + }, + "node_modules/browser-resolve/node_modules/resolve": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", + "integrity": "sha512-9znBF0vBcaSN3W2j7wKvdERPwqTxSpCq+if5C0WoTCyV9n24rua28jeuQ2pL/HOf+yUe/Mef+H/5p60K0Id3bg==", + "dev": true, + "license": "MIT" + }, + "node_modules/browserify": { + "version": "13.3.0", + "resolved": "https://registry.npmjs.org/browserify/-/browserify-13.3.0.tgz", + "integrity": "sha512-RC51w//pULmKo3XmyC5Ax0FgQ3OZQk6he1SHbgsH63hSpa1RR0cGFU4s1AJY4exLesSZjJI00PynhjwWryi2bg==", + "dev": true, + "license": "MIT", + "dependencies": { + "assert": "^1.4.0", + "browser-pack": "^6.0.1", + "browser-resolve": "^1.11.0", + "browserify-zlib": "~0.1.2", + "buffer": "^4.1.0", + "cached-path-relative": "^1.0.0", + "concat-stream": "~1.5.1", + "console-browserify": "^1.1.0", + "constants-browserify": "~1.0.0", + "crypto-browserify": "^3.0.0", + "defined": "^1.0.0", + "deps-sort": "^2.0.0", + "domain-browser": "~1.1.0", + "duplexer2": "~0.1.2", + "events": "~1.1.0", + "glob": "^7.1.0", + "has": "^1.0.0", + "htmlescape": "^1.1.0", + "https-browserify": "~0.0.0", + "inherits": "~2.0.1", + "insert-module-globals": "^7.0.0", + "JSONStream": "^1.0.3", + "labeled-stream-splicer": "^2.0.0", + "module-deps": "^4.0.8", + "os-browserify": "~0.1.1", + "parents": "^1.0.1", + "path-browserify": "~0.0.0", + "process": "~0.11.0", + "punycode": "^1.3.2", + "querystring-es3": "~0.2.0", + "read-only-stream": "^2.0.0", + "readable-stream": "^2.0.2", + "resolve": "^1.1.4", + "shasum": "^1.0.0", + "shell-quote": "^1.6.1", + "stream-browserify": "^2.0.0", + "stream-http": "^2.0.0", + "string_decoder": "~0.10.0", + "subarg": "^1.0.0", + "syntax-error": "^1.1.1", + "through2": "^2.0.0", + "timers-browserify": "^1.0.1", + "tty-browserify": "~0.0.0", + "url": "~0.11.0", + "util": "~0.10.1", + "vm-browserify": "~0.0.1", + "xtend": "^4.0.0" + }, + "bin": { + "browserify": "bin/cmd.js" + } + }, + "node_modules/browserify-aes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/browserify-cipher": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", + "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "browserify-aes": "^1.0.4", + "browserify-des": "^1.0.0", + "evp_bytestokey": "^1.0.0" + } + }, + "node_modules/browserify-des": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", + "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "cipher-base": "^1.0.1", + "des.js": "^1.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/browserify-rsa": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.1.tgz", + "integrity": "sha512-YBjSAiTqM04ZVei6sXighu679a3SqWORA3qZTEqZImnlkDIFtKc6pNutpjyZ8RJTjQtuYfeetkxM11GwoYXMIQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "bn.js": "^5.2.1", + "randombytes": "^2.1.0", + "safe-buffer": "^5.2.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/browserify-sign": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.5.tgz", + "integrity": "sha512-C2AUdAJg6rlM2W5QMp2Q4KGQMVBwR1lIimTsUnutJ8bMpW5B52pGpR2gEnNBNwijumDo5FojQ0L9JrXA8m4YEw==", + "dev": true, + "license": "ISC", + "dependencies": { + "bn.js": "^5.2.2", + "browserify-rsa": "^4.1.1", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "elliptic": "^6.6.1", + "inherits": "^2.0.4", + "parse-asn1": "^5.1.9", + "readable-stream": "^2.3.8", + "safe-buffer": "^5.2.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/browserify-zlib": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.1.4.tgz", + "integrity": "sha512-19OEpq7vWgsH6WkvkBJQDFvJS1uPcbFOQ4v9CU839dO+ZZXUZO6XpE6hNCqvlIIj+4fZvRiJ6DsAQ382GwiyTQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "pako": "~0.2.0" + } + }, + "node_modules/browserify/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/browserify/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/browserify/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/browserify/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/browserslist": { + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", + "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "peer": true, + "dependencies": { + "baseline-browser-mapping": "^2.9.0", + "caniuse-lite": "^1.0.30001759", + "electron-to-chromium": "^1.5.263", + "node-releases": "^2.0.27", + "update-browserslist-db": "^1.2.0" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/buffer": { + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", + "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", + "dev": true, + "license": "MIT", + "dependencies": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4", + "isarray": "^1.0.0" + } + }, + "node_modules/buffer-alloc": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz", + "integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-alloc-unsafe": "^1.1.0", + "buffer-fill": "^1.0.0" + } + }, + "node_modules/buffer-alloc-unsafe": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz", + "integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==", + "dev": true, + "license": "MIT" + }, + "node_modules/buffer-fill": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz", + "integrity": "sha512-T7zexNBwiiaCOGDg9xNX9PBmjrubblRkENuptryuI64URkXDFum9il/JGL8Lm8wYfAXpredVXXZz7eMHilimiQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/buffer-xor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/builtin-status-codes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", + "integrity": "sha512-HpGFw18DgFWlncDfjTa2rcQ4W88O1mC8e8yZ2AvQY5KDaktSTwo+KRf6nHK6FRI5FyRyb/5T6+TSxfP7QyGsmQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/bundle-name": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz", + "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "run-applescript": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/c12": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/c12/-/c12-3.3.3.tgz", + "integrity": "sha512-750hTRvgBy5kcMNPdh95Qo+XUBeGo8C7nsKSmedDmaQI+E0r82DwHeM6vBewDe4rGFbnxoa4V9pw+sPh5+Iz8Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "chokidar": "^5.0.0", + "confbox": "^0.2.2", + "defu": "^6.1.4", + "dotenv": "^17.2.3", + "exsolve": "^1.0.8", + "giget": "^2.0.0", + "jiti": "^2.6.1", + "ohash": "^2.0.11", + "pathe": "^2.0.3", + "perfect-debounce": "^2.0.0", + "pkg-types": "^2.3.0", + "rc9": "^2.1.2" + }, + "peerDependencies": { + "magicast": "*" + }, + "peerDependenciesMeta": { + "magicast": { + "optional": true + } + } + }, + "node_modules/cac": { + "version": "6.7.14", + "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", + "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cacheable-request": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz", + "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==", + "license": "MIT", + "dependencies": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^3.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^4.1.0", + "responselike": "^1.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cacheable-request/node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "license": "MIT", + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cacheable-request/node_modules/lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cached-path-relative": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/cached-path-relative/-/cached-path-relative-1.1.0.tgz", + "integrity": "sha512-WF0LihfemtesFcJgO7xfOoOcnWzY/QHR4qeDqV44jPU3HTI54+LnfXK3SA27AVVGCdZFgjjFFaqUA9Jx7dMJZA==", + "dev": true, + "license": "MIT" + }, + "node_modules/call-bind": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", + "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.0", + "es-define-property": "^1.0.0", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001774", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001774.tgz", + "integrity": "sha512-DDdwPGz99nmIEv216hKSgLD+D4ikHQHjBC/seF98N9CPqRX4M5mSxT9eTV6oyisnJcuzxtZy4n17yKKQYmYQOA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/case": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/case/-/case-1.6.3.tgz", + "integrity": "sha512-mzDSXIPaFwVDvZAHqZ9VlbyF4yyXRuX6IvB06WvPYkqJVO24kX1PPhv9bfpKNFZyxYFmmgo03HUiD8iklmJYRQ==", + "dev": true, + "license": "(MIT OR GPL-3.0-or-later)", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/chai": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz", + "integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chalk/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/chardet": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-2.1.1.tgz", + "integrity": "sha512-PsezH1rqdV9VvyNhxxOW32/d75r01NY7TQCmOqomRo15ZSOKbpTFVsfjghxo6JloQUCGnH4k1LGu0R4yCLlWQQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/cheerio": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.2.0.tgz", + "integrity": "sha512-WDrybc/gKFpTYQutKIK6UvfcuxijIZfMfXaYm8NMsPQxSYvf+13fXUJ4rztGGbJcBQ/GF55gvrZ0Bc0bj/mqvg==", + "license": "MIT", + "dependencies": { + "cheerio-select": "^2.1.0", + "dom-serializer": "^2.0.0", + "domhandler": "^5.0.3", + "domutils": "^3.2.2", + "encoding-sniffer": "^0.2.1", + "htmlparser2": "^10.1.0", + "parse5": "^7.3.0", + "parse5-htmlparser2-tree-adapter": "^7.1.0", + "parse5-parser-stream": "^7.1.2", + "undici": "^7.19.0", + "whatwg-mimetype": "^4.0.0" + }, + "engines": { + "node": ">=20.18.1" + }, + "funding": { + "url": "https://github.com/cheeriojs/cheerio?sponsor=1" + } + }, + "node_modules/cheerio-select": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz", + "integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==", + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0", + "css-select": "^5.1.0", + "css-what": "^6.1.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/chokidar": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz", + "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", + "license": "MIT", + "dependencies": { + "readdirp": "^5.0.0" + }, + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/chrome-trace-event": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", + "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0" + } + }, + "node_modules/ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", + "license": "MIT" + }, + "node_modules/cipher-base": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.7.tgz", + "integrity": "sha512-Mz9QMT5fJe7bKI7MH31UilT5cEK5EHHRCccw/YRFsRY47AuNgaV6HY3rscp0/I4Q+tTW/5zoqpSeRRI54TkDWA==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.4", + "safe-buffer": "^5.2.1", + "to-buffer": "^1.2.2" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/citty": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/citty/-/citty-0.1.6.tgz", + "integrity": "sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "consola": "^3.2.3" + } + }, + "node_modules/clean-stack": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-3.0.1.tgz", + "integrity": "sha512-lR9wNiMRcVQjSB3a7xXGLuz4cr4wJuuXlaAEbRutGowQTmlp7R72/DOgN21e8jdwblMWl9UOJMJXarX94pzKdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "escape-string-regexp": "4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cli/-/cli-1.0.1.tgz", + "integrity": "sha512-41U72MB56TfUMGndAKK8vJ78eooOD4Z5NOL4xEfjc0c23s+6EYKXlXsmACBVclLP1yOfWCgEganVzddVrSNoTg==", + "license": "MIT", + "dependencies": { + "exit": "0.1.2", + "glob": "^7.1.1" + }, + "engines": { + "node": ">=0.2.5" + } + }, + "node_modules/cli-boxes": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz", + "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==", + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "restore-cursor": "^3.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-spinners": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", + "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-width": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", + "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 10" + } + }, + "node_modules/cli/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "license": "MIT" + }, + "node_modules/cli/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/cli/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/cli/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/cliui": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", + "integrity": "sha512-0yayqDxWQbqk3ojkYqUKqaAQ6AfNKeKWRNA8kR0WXzAsdHpP4BIaOmMAG87JGuO6qcobyW4GjxHd9PmhEd+T9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wrap-ansi": "^2.0.0" + } + }, + "node_modules/cliui/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/cliui/node_modules/is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "number-is-nan": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/cliui/node_modules/string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw==", + "dev": true, + "license": "MIT", + "dependencies": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/cliui/node_modules/strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/cliui/node_modules/wrap-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "integrity": "sha512-vAaEaDM946gbNpH5pLVNR+vX2ht6n0Bt3GXwVB1AuAqZosOvHNF3P7wDnh8KLkSqgUh0uh77le7Owgoz+Z9XBw==", + "dev": true, + "license": "MIT", + "dependencies": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", + "license": "MIT", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/clone-response": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz", + "integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==", + "license": "MIT", + "dependencies": { + "mimic-response": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha512-RpAVKQA5T63xEj6/giIbUEtZwJ4UFIc3ZtvEkiaUERylqe8xb5IvqcgOurZLahv93CLKfxcw5YI+DZcUBRyLXA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/collection-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/collection-utils/-/collection-utils-1.0.1.tgz", + "integrity": "sha512-LA2YTIlR7biSpXkKYwwuzGjwL5rjWEZVOSnvdUc7gObvWe4WkjxOpfrdhoP7Hs09YWDVfg0Mal9BpAqLfVEzQg==", + "license": "Apache-2.0" + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" + }, + "node_modules/color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "dev": true, + "license": "ISC", + "bin": { + "color-support": "bin.js" + } + }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/combine-source-map": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/combine-source-map/-/combine-source-map-0.8.0.tgz", + "integrity": "sha512-UlxQ9Vw0b/Bt/KYwCFqdEwsQ1eL8d1gibiFb7lxQJFdvTgc2hIZi6ugsg+kyhzhPV+QEpUiEIwInIAIrgoEkrg==", + "dev": true, + "license": "MIT", + "dependencies": { + "convert-source-map": "~1.1.0", + "inline-source-map": "~0.6.0", + "lodash.memoize": "~3.0.3", + "source-map": "~0.5.3" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commander": { + "version": "14.0.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.3.tgz", + "integrity": "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "license": "MIT" + }, + "node_modules/concat-stream": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.5.2.tgz", + "integrity": "sha512-H6xsIBfQ94aESBG8jGHXQ7i5AEpy5ZeVaLDOisDICiTCKpqEfr34/KmTrspKQNoLKNu9gTkovlpQcUi630AKiQ==", + "dev": true, + "engines": [ + "node >= 0.8" + ], + "license": "MIT", + "dependencies": { + "inherits": "~2.0.1", + "readable-stream": "~2.0.0", + "typedarray": "~0.0.5" + } + }, + "node_modules/concat-stream/node_modules/process-nextick-args": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", + "integrity": "sha512-yN0WQmuCX63LP/TMvAg31nvT6m4vDqJEiiv2CAZqWOGNWutc9DfDk1NPYYmKUFmaVM2UwDowH4u5AHWYP/jxKw==", + "dev": true, + "license": "MIT" + }, + "node_modules/concat-stream/node_modules/readable-stream": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz", + "integrity": "sha512-TXcFfb63BQe1+ySzsHZI/5v1aJPCShfqvWJ64ayNImXMsN1Cd0YGk/wm8KB7/OeessgPc9QvS9Zou8QTkFzsLw==", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "~1.0.0", + "process-nextick-args": "~1.0.6", + "string_decoder": "~0.10.x", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/confbox": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.4.tgz", + "integrity": "sha512-ysOGlgTFbN2/Y6Cg3Iye8YKulHw+R2fNXHrgSmXISQdMnomY6eNDprVdW9R5xBguEqI954+S6709UyiO7B+6OQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/config-chain": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz", + "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==", + "license": "MIT", + "dependencies": { + "ini": "^1.3.4", + "proto-list": "~1.2.1" + } + }, + "node_modules/configstore": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz", + "integrity": "sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==", + "license": "BSD-2-Clause", + "dependencies": { + "dot-prop": "^5.2.0", + "graceful-fs": "^4.1.2", + "make-dir": "^3.0.0", + "unique-string": "^2.0.0", + "write-file-atomic": "^3.0.0", + "xdg-basedir": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/consola": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/consola/-/consola-3.4.2.tgz", + "integrity": "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.18.0 || >=16.10.0" + } + }, + "node_modules/console-browserify": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz", + "integrity": "sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==", + "dev": true + }, + "node_modules/constants-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", + "integrity": "sha512-xFxOwqIzR/e1k1gLiWEophSCMqXcwVHIH7akf7b/vxcUeGunlj3hvZaaqxwHsTgn+IndtkQJgSztIDWeumWJDQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/convert-source-map": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.1.3.tgz", + "integrity": "sha512-Y8L5rp6jo+g9VEPgvqNfEopjTR4OTYct8lXlS8iVQdmnjDvbdbzYe9rjtFCB9egC86JoNCU61WRY+ScjkZpnIg==", + "dev": true, + "license": "MIT" + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "license": "MIT" + }, + "node_modules/create-ecdh": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz", + "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==", + "dev": true, + "license": "MIT", + "dependencies": { + "bn.js": "^4.1.0", + "elliptic": "^6.5.3" + } + }, + "node_modules/create-ecdh/node_modules/bn.js": { + "version": "4.12.3", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.3.tgz", + "integrity": "sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==", + "dev": true, + "license": "MIT" + }, + "node_modules/create-hash": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, + "node_modules/create-hmac": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "node_modules/cron-parser": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/cron-parser/-/cron-parser-5.5.0.tgz", + "integrity": "sha512-oML4lKUXxizYswqmxuOCpgFS8BNUJpIu6k/2HVHyaL8Ynnf3wdf9tkns0yRdJLSIjkJ+b0DXHMZEHGpMwjnPww==", + "license": "MIT", + "dependencies": { + "luxon": "^3.7.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/cross-fetch": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.1.0.tgz", + "integrity": "sha512-uKm5PU+MHTootlWEY+mZ4vvXoCn4fLQxT9dSc1sXVMSFkINTJVN8cAQROpwcKm8bJ/c7rgZVIBWzH5T78sNZZw==", + "license": "MIT", + "dependencies": { + "node-fetch": "^2.7.0" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/crypto-browserify": { + "version": "3.12.1", + "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.1.tgz", + "integrity": "sha512-r4ESw/IlusD17lgQi1O20Fa3qNnsckR126TdUuBgAu7GBYSIPvdNyONd3Zrxh0xCwA4+6w/TDArBPsMvhur+KQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "browserify-cipher": "^1.0.1", + "browserify-sign": "^4.2.3", + "create-ecdh": "^4.0.4", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "diffie-hellman": "^5.0.3", + "hash-base": "~3.0.4", + "inherits": "^2.0.4", + "pbkdf2": "^3.1.2", + "public-encrypt": "^4.0.3", + "randombytes": "^2.1.0", + "randomfill": "^1.0.4" + }, + "engines": { + "node": ">= 0.10" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/crypto-js": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz", + "integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==", + "license": "MIT" + }, + "node_modules/crypto-random-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", + "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/css-select": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.2.2.tgz", + "integrity": "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==", + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.1.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-what": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.2.2.tgz", + "integrity": "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==", + "license": "BSD-2-Clause", + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/dash-ast": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/dash-ast/-/dash-ast-1.0.0.tgz", + "integrity": "sha512-Vy4dx7gquTeMcQR/hDkYLGUnwVil6vk4FOOct+djUnHOUWt+zJPJAaRIXaAFkPXtJjvlY7o3rfRu0/3hpnwoUA==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", + "dev": true, + "license": "MIT", + "dependencies": { + "assert-plus": "^1.0.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/date-now": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz", + "integrity": "sha512-AsElvov3LoNB7tf5k37H2jYSB+ZZPMT5sG2QjJCcdlV5chIv6htBUBUui2IKRjgtKAKtCBN7Zbwa+MtwLjSeNw==" + }, + "node_modules/dateformat": { + "version": "4.6.3", + "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-4.6.3.tgz", + "integrity": "sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/decompress-response": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", + "integrity": "sha512-BzRPQuY1ip+qDonAOz42gRm/pg9F768C+npV/4JOsxRC2sq+Rlk+Q4ZCAsOhnIaMrgarILY+RMUIvMmmX1qAEA==", + "license": "MIT", + "dependencies": { + "mimic-response": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/deep-equal": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.2.tgz", + "integrity": "sha512-5tdhKF6DbU7iIzrIOa1AOUt39ZRm13cmL1cGEh//aqR8x9+tNfbywRf0n5FD/18OKMdo7DNEtrX2t22ZAkI+eg==", + "license": "MIT", + "dependencies": { + "is-arguments": "^1.1.1", + "is-date-object": "^1.0.5", + "is-regex": "^1.1.4", + "object-is": "^1.1.5", + "object-keys": "^1.1.1", + "regexp.prototype.flags": "^1.5.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "license": "MIT", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/deepl-node": { + "version": "1.24.0", + "resolved": "https://registry.npmjs.org/deepl-node/-/deepl-node-1.24.0.tgz", + "integrity": "sha512-vZ9jUpzJRvFamgVOfm1LDy3YYJ7k8FhxtAX9whR92EFshLIP9JlYS0HFwXL5yYsfqzXdb/wssGRSWvR48t7nSg==", + "license": "MIT", + "dependencies": { + "@types/node": ">=12.0", + "adm-zip": "^0.5.16", + "axios": "^1.7.4", + "form-data": "^3.0.0", + "loglevel": ">=1.6.2", + "uuid": "^8.3.2" + }, + "engines": { + "node": ">=12.0" + } + }, + "node_modules/deepl-node/node_modules/form-data": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.4.tgz", + "integrity": "sha512-f0cRzm6dkyVYV3nPoooP8XlccPQukegwhAnpoLcXy+X+A8KfpGOoXwDr9FLZd3wzgLaBGQBE3lY93Zm/i1JvIQ==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.35" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/default-browser": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.5.0.tgz", + "integrity": "sha512-H9LMLr5zwIbSxrmvikGuI/5KGhZ8E2zH3stkMgM5LpOWDutGM2JZaj460Udnf1a+946zc7YBgrqEWwbk7zHvGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "bundle-name": "^4.1.0", + "default-browser-id": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-browser-id": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.1.tgz", + "integrity": "sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/defaults": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", + "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "clone": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/defer-to-connect": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz", + "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==", + "license": "MIT" + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-lazy-prop": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", + "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "license": "MIT", + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/defined": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.1.tgz", + "integrity": "sha512-hsBd2qSVCRE+5PmNdHt1uzyrFu5d3RwmFDKzyNZMFq/EwDNJF7Ee5+D5oEKF0hU6LhtoUF1macFvOe4AskQC1Q==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/defu": { + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.4.tgz", + "integrity": "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==", + "dev": true, + "license": "MIT" + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/deps-sort": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/deps-sort/-/deps-sort-2.0.1.tgz", + "integrity": "sha512-1orqXQr5po+3KI6kQb9A4jnXT1PBwggGl2d7Sq2xsnOeI9GPcE/tGcF9UiSZtZBM7MukY4cAh7MemS6tZYipfw==", + "dev": true, + "license": "MIT", + "dependencies": { + "JSONStream": "^1.0.3", + "shasum-object": "^1.0.0", + "subarg": "^1.0.0", + "through2": "^2.0.0" + }, + "bin": { + "deps-sort": "bin/cmd.js" + } + }, + "node_modules/des.js": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.1.0.tgz", + "integrity": "sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/destr": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/destr/-/destr-2.0.5.tgz", + "integrity": "sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==", + "dev": true, + "license": "MIT" + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/detective": { + "version": "4.7.1", + "resolved": "https://registry.npmjs.org/detective/-/detective-4.7.1.tgz", + "integrity": "sha512-H6PmeeUcZloWtdt4DAkFyzFL94arpHr3NOwwmVILFiy+9Qd4JTxxXrzfyGk/lmct2qVGBwTSwSXagqu2BxmWig==", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^5.2.1", + "defined": "^1.0.0" + } + }, + "node_modules/detective/node_modules/acorn": { + "version": "5.7.4", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.4.tgz", + "integrity": "sha512-1D++VG7BhrtvQpNbBzovKNc1FLGGEE/oGe7b9xJm/RFHMBeUaUGpluV9RLjZa47YFdPcDAenEYuq9pQPcMdLJg==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/dfa": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/dfa/-/dfa-1.2.0.tgz", + "integrity": "sha512-ED3jP8saaweFTjeGX8HQPjeC1YYyZs98jGNZx6IiBvxW7JG5v492kamAQB3m2wop07CvU/RQmzcKr6bgcC5D/Q==", + "license": "MIT" + }, + "node_modules/diffie-hellman": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", + "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", + "dev": true, + "license": "MIT", + "dependencies": { + "bn.js": "^4.1.0", + "miller-rabin": "^4.0.0", + "randombytes": "^2.0.0" + } + }, + "node_modules/diffie-hellman/node_modules/bn.js": { + "version": "4.12.3", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.3.tgz", + "integrity": "sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==", + "dev": true, + "license": "MIT" + }, + "node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "license": "MIT", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/domain-browser": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.1.7.tgz", + "integrity": "sha512-fJ5MoHxe69h3E4/lJtFRhcWwLb04bhIBSfvCEMS1YDH+/9yEZTqBHTSTgch8nCP5tE5k2gdQEjodUqJzy7qJ9Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4", + "npm": ">=1.2" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "BSD-2-Clause" + }, + "node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "license": "BSD-2-Clause", + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz", + "integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==", + "license": "BSD-2-Clause", + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/dot-prop": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", + "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", + "license": "MIT", + "dependencies": { + "is-obj": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/dotenv": { + "version": "17.3.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.3.1.tgz", + "integrity": "sha512-IO8C/dzEb6O3F9/twg6ZLXz164a2fhTnEWb95H23Dm4OuN+92NmEAlTrupP9VW6Jm3sO26tQlqyvyi4CsnY9GA==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/duplexer2": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", + "integrity": "sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "readable-stream": "^2.0.2" + } + }, + "node_modules/duplexer3": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.5.tgz", + "integrity": "sha512-1A8za6ws41LQgv9HrE/66jyC5yuSjQ3L/KOpFtoBilsAK2iA2wuS5rTt1OCzIvtS2V7nVmedsUU+DGRcjBmOYA==", + "license": "BSD-3-Clause" + }, + "node_modules/duplexify": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", + "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", + "dev": true, + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.0.0", + "stream-shift": "^1.0.0" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "license": "MIT" + }, + "node_modules/ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", + "dev": true, + "license": "MIT", + "dependencies": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "node_modules/editorconfig": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-1.0.4.tgz", + "integrity": "sha512-L9Qe08KWTlqYMVvMcTIvMAdl1cDUubzRNYL+WfA4bLDMHe4nemKkpmYzkznE1FwLKu0EEmy6obgQKzMJrg4x9Q==", + "license": "MIT", + "dependencies": { + "@one-ini/wasm": "0.1.1", + "commander": "^10.0.0", + "minimatch": "9.0.1", + "semver": "^7.5.3" + }, + "bin": { + "editorconfig": "bin/editorconfig" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/editorconfig/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "license": "MIT" + }, + "node_modules/editorconfig/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/editorconfig/node_modules/commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "license": "MIT", + "engines": { + "node": ">=14" + } + }, + "node_modules/editorconfig/node_modules/minimatch": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.1.tgz", + "integrity": "sha512-0jWhJpD/MdhPXwPuiRkCbfYfSKp2qnn2eOc279qI7f+osl/l+prKSrvhg157zSYvx/1nmgn2NqdT6k2Z7zSH9w==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/ejs": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz", + "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "jake": "^10.8.5" + }, + "bin": { + "ejs": "bin/cli.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.302", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.302.tgz", + "integrity": "sha512-sM6HAN2LyK82IyPBpznDRqlTQAtuSaO+ShzFiWTvoMJLHyZ+Y39r8VMfHzwbU8MVBzQ4Wdn85+wlZl2TLGIlwg==", + "dev": true, + "license": "ISC" + }, + "node_modules/elliptic": { + "version": "6.6.1", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.6.1.tgz", + "integrity": "sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/elliptic/node_modules/bn.js": { + "version": "4.12.3", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.3.tgz", + "integrity": "sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==", + "dev": true, + "license": "MIT" + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/encoding-sniffer": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/encoding-sniffer/-/encoding-sniffer-0.2.1.tgz", + "integrity": "sha512-5gvq20T6vfpekVtqrYQsSCFZ1wEg5+wW0/QaZMWkFr6BqD3NfKs0rLCx4rrVlSWJeZb5NBJgVLswK/w2MWU+Gw==", + "license": "MIT", + "dependencies": { + "iconv-lite": "^0.6.3", + "whatwg-encoding": "^3.1.1" + }, + "funding": { + "url": "https://github.com/fb55/encoding-sniffer?sponsor=1" + } + }, + "node_modules/end-of-stream": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", + "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", + "license": "MIT", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/enhanced-resolve": { + "version": "5.19.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.19.0.tgz", + "integrity": "sha512-phv3E1Xl4tQOShqSte26C7Fl84EwUdZsyOuSSk9qtAGyyQs2s3jJzComh+Abf4g187lUUAvH+H26omrqia2aGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.3.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/envinfo": { + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.21.0.tgz", + "integrity": "sha512-Lw7I8Zp5YKHFCXL7+Dz95g4CcbMEpgvqZNNq3AmlT5XAV6CgAAk6gyAMqn2zjw08K9BHfcNuKrMiCPLByGafow==", + "dev": true, + "license": "MIT", + "bin": { + "envinfo": "dist/cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/error-ex": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", + "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-module-lexer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.0.0.tgz", + "integrity": "sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==", + "license": "MIT" + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/esbuild": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.3.tgz", + "integrity": "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==", + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.3", + "@esbuild/android-arm": "0.27.3", + "@esbuild/android-arm64": "0.27.3", + "@esbuild/android-x64": "0.27.3", + "@esbuild/darwin-arm64": "0.27.3", + "@esbuild/darwin-x64": "0.27.3", + "@esbuild/freebsd-arm64": "0.27.3", + "@esbuild/freebsd-x64": "0.27.3", + "@esbuild/linux-arm": "0.27.3", + "@esbuild/linux-arm64": "0.27.3", + "@esbuild/linux-ia32": "0.27.3", + "@esbuild/linux-loong64": "0.27.3", + "@esbuild/linux-mips64el": "0.27.3", + "@esbuild/linux-ppc64": "0.27.3", + "@esbuild/linux-riscv64": "0.27.3", + "@esbuild/linux-s390x": "0.27.3", + "@esbuild/linux-x64": "0.27.3", + "@esbuild/netbsd-arm64": "0.27.3", + "@esbuild/netbsd-x64": "0.27.3", + "@esbuild/openbsd-arm64": "0.27.3", + "@esbuild/openbsd-x64": "0.27.3", + "@esbuild/openharmony-arm64": "0.27.3", + "@esbuild/sunos-x64": "0.27.3", + "@esbuild/win32-arm64": "0.27.3", + "@esbuild/win32-ia32": "0.27.3", + "@esbuild/win32-x64": "0.27.3" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-goat": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-2.1.1.tgz", + "integrity": "sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/esm": { + "version": "3.2.25", + "resolved": "https://registry.npmjs.org/esm/-/esm-3.2.25.tgz", + "integrity": "sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/events": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", + "integrity": "sha512-kEcvvCBByWXGnZy6JUlgAp2gBIUjfCAV6P6TgT1/aaQKcmuAEC4OZTV1I4EWQLz2gxZw76atuVyvHhTxvi0Flw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4.x" + } + }, + "node_modules/evp_bytestokey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", + "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, + "node_modules/exifreader": { + "version": "4.36.2", + "resolved": "https://registry.npmjs.org/exifreader/-/exifreader-4.36.2.tgz", + "integrity": "sha512-Rpboqge86aBhRVJeW70BZHIkFNCi6rVlidzKuDyRxsreS/SbT983wFk/88+ddJu7zSrOae5fuiyXO7X91qq88Q==", + "hasInstallScript": true, + "license": "MPL-2.0", + "optionalDependencies": { + "@xmldom/xmldom": "^0.9.4" + } + }, + "node_modules/exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/expect-type": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.3.0.tgz", + "integrity": "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/exsolve": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.0.8.tgz", + "integrity": "sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==", + "dev": true, + "license": "MIT" + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true, + "license": "MIT" + }, + "node_modules/extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==", + "dev": true, + "engines": [ + "node >=0.6.0" + ], + "license": "MIT" + }, + "node_modules/fast-copy": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/fast-copy/-/fast-copy-4.0.2.tgz", + "integrity": "sha512-ybA6PDXIXOXivLJK/z9e+Otk7ve13I4ckBvGO5I2RRmBU1gMHLVDJYEuJYhGwez7YNlYji2M2DvVU+a9mSFDlw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-safe-stringify": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", + "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", + "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/fastest-levenshtein": { + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", + "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4.9.1" + } + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/feed": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/feed/-/feed-5.2.0.tgz", + "integrity": "sha512-hgH6CCb+7+0c8PBlakI2KubG6R+Rb1MhpNcdvqUXZTBwBHf32piwY255diAkAmkGZ6AWlywOU88AkOgP9q8Rdw==", + "license": "MIT", + "dependencies": { + "xml-js": "^1.6.11" + }, + "engines": { + "node": ">=20", + "pnpm": ">=10" + } + }, + "node_modules/fflate": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.2.tgz", + "integrity": "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==", + "dev": true, + "license": "MIT" + }, + "node_modules/figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^1.0.5" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/figures/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/filelist": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.6.tgz", + "integrity": "sha512-5giy2PkLYY1cP39p17Ech+2xlpTRL9HLspOfEgm0L6CwBXBTgsK5ou0JtzYuepxkaQ/tvhCFIJ5uXo0OrM2DxA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "minimatch": "^5.0.1" + } + }, + "node_modules/filelist/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/filelist/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/filelist/node_modules/minimatch": { + "version": "5.1.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.9.tgz", + "integrity": "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "license": "BSD-3-Clause", + "bin": { + "flat": "cli.js" + } + }, + "node_modules/flatted": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "dev": true, + "license": "ISC" + }, + "node_modules/follow-redirects": { + "version": "1.15.11", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", + "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/for-each": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", + "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/foreground-child/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "*" + } + }, + "node_modules/form-data": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", + "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", + "dev": true, + "license": "MIT" + }, + "node_modules/fs-extra": { + "version": "11.3.3", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.3.tgz", + "integrity": "sha512-VWSRii4t0AFm6ixFFmLLx1t7wS1gh+ckoa84aOeapGum0h+EZd1EhEumSB+ZdDLnEPuucsVB9oB7cxJHap6Afg==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "license": "ISC" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-assigned-identifiers": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/get-assigned-identifiers/-/get-assigned-identifiers-1.2.0.tgz", + "integrity": "sha512-mBBwmeGTrxEMO4pMaaf/uUEFHnYtwr8FTe8Y/mer4rcV/bye0qGm6pw1bGZFGStxC5O76c5ZAVBGnqHmOaJpdQ==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/get-caller-file": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", + "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", + "dev": true, + "license": "ISC" + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "license": "MIT", + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/get-tsconfig": { + "version": "4.13.6", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.6.tgz", + "integrity": "sha512-shZT/QMiSHc/YBLxxOkMtgSid5HFoauqCE3/exfsEcwg1WkeqjG+V40yBbBrsD+jW2HDXcs28xOfcbm2jI8Ddw==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", + "dev": true, + "license": "MIT", + "dependencies": { + "assert-plus": "^1.0.0" + } + }, + "node_modules/giget": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/giget/-/giget-2.0.0.tgz", + "integrity": "sha512-L5bGsVkxJbJgdnwyuheIunkGatUF/zssUoxxjACCseZYAVbaqdh9Tsmmlkl8vYan09H7sbvKt4pS8GqKLBrEzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "citty": "^0.1.6", + "consola": "^3.4.0", + "defu": "^6.1.4", + "node-fetch-native": "^1.6.6", + "nypm": "^0.6.0", + "pathe": "^2.0.3" + }, + "bin": { + "giget": "dist/cli.mjs" + } + }, + "node_modules/glob": { + "version": "13.0.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz", + "integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==", + "license": "BlueOak-1.0.0", + "dependencies": { + "minimatch": "^10.2.2", + "minipass": "^7.1.3", + "path-scurry": "^2.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/global-dirs": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-2.1.0.tgz", + "integrity": "sha512-MG6kdOUh/xBnyo9cJFeIKkLEc1AyFq42QTU4XiX51i2NEdxLxLWXIjEjmqKeSuKR7pAZjTqUVoT2b2huxVLgYQ==", + "license": "MIT", + "dependencies": { + "ini": "1.3.7" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/global-dirs/node_modules/ini": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.7.tgz", + "integrity": "sha512-iKpRpXP+CrP2jyrxvg1kMUpXDyRUFDWurxbnVT1vQPx+Wz9uCYsMIqYuSBLV+PAaZG/d7kRLKRFc9oDMsH+mFQ==", + "license": "ISC" + }, + "node_modules/globrex": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz", + "integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==", + "dev": true, + "license": "MIT" + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/got": { + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", + "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==", + "license": "MIT", + "dependencies": { + "@sindresorhus/is": "^0.14.0", + "@szmarczak/http-timer": "^1.1.2", + "cacheable-request": "^6.0.0", + "decompress-response": "^3.3.0", + "duplexer3": "^0.1.4", + "get-stream": "^4.1.0", + "lowercase-keys": "^1.0.1", + "mimic-response": "^1.0.1", + "p-cancelable": "^1.0.0", + "to-readable-stream": "^1.0.0", + "url-parse-lax": "^3.0.0" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "license": "ISC" + }, + "node_modules/gunzip-maybe": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/gunzip-maybe/-/gunzip-maybe-1.4.2.tgz", + "integrity": "sha512-4haO1M4mLO91PW57BMsDFf75UmwoRX0GkdD+Faw+Lr+r/OZrOCS0pIBwOL1xCKQqnQzbNFGgK2V2CpBUPeFNTw==", + "dev": true, + "license": "MIT", + "dependencies": { + "browserify-zlib": "^0.1.4", + "is-deflate": "^1.0.0", + "is-gzip": "^1.0.0", + "peek-stream": "^1.1.0", + "pumpify": "^1.3.3", + "through2": "^2.0.3" + }, + "bin": { + "gunzip-maybe": "bin.js" + } + }, + "node_modules/har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=4" + } + }, + "node_modules/har-validator": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", + "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", + "deprecated": "this library is no longer supported", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.3", + "har-schema": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/has": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.4.tgz", + "integrity": "sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-yarn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz", + "integrity": "sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/hash-base": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.5.tgz", + "integrity": "sha512-vXm0l45VbcHEVlTCzs8M+s0VeYsB2lnlAaThoLKGXr3bE/VWDOelNUnycUPEhKEaXARL2TEFjBOyUiM6+55KBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.4", + "safe-buffer": "^5.2.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/help-me": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/help-me/-/help-me-5.0.0.tgz", + "integrity": "sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg==", + "dev": true, + "license": "MIT" + }, + "node_modules/hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/hono": { + "version": "4.12.3", + "resolved": "https://registry.npmjs.org/hono/-/hono-4.12.3.tgz", + "integrity": "sha512-SFsVSjp8sj5UumXOOFlkZOG6XS9SJDKw0TbwFeV+AJ8xlST8kxK5Z/5EYa111UY8732lK2S/xB653ceuaoGwpg==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=16.9.0" + } + }, + "node_modules/hono-rate-limiter": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/hono-rate-limiter/-/hono-rate-limiter-0.4.2.tgz", + "integrity": "sha512-AAtFqgADyrmbDijcRTT/HJfwqfvhalya2Zo+MgfdrMPas3zSMD8SU03cv+ZsYwRU1swv7zgVt0shwN059yzhjw==", + "license": "MIT", + "peerDependencies": { + "hono": "^4.1.1" + } + }, + "node_modules/hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true, + "license": "ISC" + }, + "node_modules/htmlescape": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/htmlescape/-/htmlescape-1.1.1.tgz", + "integrity": "sha512-eVcrzgbR4tim7c7soKQKtxa/kQM4TzjnlU83rcZ9bHU6t31ehfV7SktN6McWgwPWg+JYMA/O3qpGxBvFq1z2Jg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/htmlparser2": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-10.1.0.tgz", + "integrity": "sha512-VTZkM9GWRAtEpveh7MSF6SjjrpNVNNVJfFup7xTY3UpFtm67foy9HDVXneLtFVt4pMz5kZtgNcvCniNFb1hlEQ==", + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "MIT", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.2.2", + "entities": "^7.0.1" + } + }, + "node_modules/htmlparser2/node_modules/entities": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-7.0.1.tgz", + "integrity": "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/http-cache-semantics": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz", + "integrity": "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==", + "license": "BSD-2-Clause" + }, + "node_modules/http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + }, + "engines": { + "node": ">=0.8", + "npm": ">=1.3.7" + } + }, + "node_modules/https-browserify": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-0.0.1.tgz", + "integrity": "sha512-EjDQFbgJr1vDD/175UJeSX3ncQ3+RUnCL5NkthQGHvF4VNHlzTy8ifJfTqz47qiPRqaFH58+CbuG3x51WuB1XQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "license": "MIT", + "peer": true, + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/i": { + "version": "0.3.7", + "resolved": "https://registry.npmjs.org/i/-/i-0.3.7.tgz", + "integrity": "sha512-FYz4wlXgkQwIPqhzC5TdNMLSE5+GS1IIDJZY/1ZiEPCT2S3COUVZeT5OW4BmW4r5LHLQuOosSwsvnroG9GR59Q==", + "engines": { + "node": ">=0.4" + } + }, + "node_modules/iceberg-js": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/iceberg-js/-/iceberg-js-0.8.1.tgz", + "integrity": "sha512-1dhVQZXhcHje7798IVM+xoo/1ZdVfzOMIc8/rgVSijRK38EDqOJoGula9N/8ZI5RD8QTxNQtK/Gozpr+qUqRRA==", + "license": "MIT", + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-lazy": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", + "integrity": "sha512-m7ZEHgtw69qOGw+jwxXkHlrlIPdTGkyh66zXZ1ajZbxkDBNjSY/LGbmjc7h0s2ELsUDTAhFr55TrPSSqJGPG0A==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/import-local": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz", + "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==", + "dev": true, + "license": "MIT", + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/indexof": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", + "integrity": "sha512-i0G7hLJ1z0DE8dsqJa2rycj9dBmNKgXBvotXtZYXakU9oivfB9Uj2ZBC27qqef2U58/ZLwalxa1X/RDCdkHtVg==", + "dev": true + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "license": "ISC" + }, + "node_modules/inline-source-map": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/inline-source-map/-/inline-source-map-0.6.3.tgz", + "integrity": "sha512-1aVsPEsJWMJq/pdMU61CDlm1URcW702MTB4w9/zUjMus6H/Py8o7g68Pr9D4I6QluWGt/KdmswuRhaA05xVR1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "source-map": "~0.5.3" + } + }, + "node_modules/inquirer": { + "version": "8.2.7", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.7.tgz", + "integrity": "sha512-UjOaSel/iddGZJ5xP/Eixh6dY1XghiBw4XK13rCCIJcJfyhhoul/7KhLLUGtebEj6GDYM6Vnx/mVsjx2L/mFIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/external-editor": "^1.0.0", + "ansi-escapes": "^4.2.1", + "chalk": "^4.1.1", + "cli-cursor": "^3.1.0", + "cli-width": "^3.0.0", + "figures": "^3.0.0", + "lodash": "^4.17.21", + "mute-stream": "0.0.8", + "ora": "^5.4.1", + "run-async": "^2.4.0", + "rxjs": "^7.5.5", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "through": "^2.3.6", + "wrap-ansi": "^6.0.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/inquirer/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/insert-module-globals": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/insert-module-globals/-/insert-module-globals-7.2.1.tgz", + "integrity": "sha512-ufS5Qq9RZN+Bu899eA9QCAYThY+gGW7oRkmb0vC93Vlyu/CFGcH0OYPEjVkDXA5FEbTt1+VWzdoOD3Ny9N+8tg==", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn-node": "^1.5.2", + "combine-source-map": "^0.8.0", + "concat-stream": "^1.6.1", + "is-buffer": "^1.1.0", + "JSONStream": "^1.0.3", + "path-is-absolute": "^1.0.1", + "process": "~0.11.0", + "through2": "^2.0.0", + "undeclared-identifiers": "^1.1.2", + "xtend": "^4.0.0" + }, + "bin": { + "insert-module-globals": "bin/cmd.js" + } + }, + "node_modules/insert-module-globals/node_modules/concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "dev": true, + "engines": [ + "node >= 0.8" + ], + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "node_modules/insert-module-globals/node_modules/typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/interpret": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-3.1.1.tgz", + "integrity": "sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/invert-kv": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", + "integrity": "sha512-xgs2NH9AE66ucSq4cNG1nhSFghr5l6tdL15Pk+jl46bmmBapgoaY/AacXyaDznAqmGL99TiLSQgO/XazFSKYeQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-arguments": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.2.0.tgz", + "integrity": "sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-ci": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", + "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", + "license": "MIT", + "dependencies": { + "ci-info": "^2.0.0" + }, + "bin": { + "is-ci": "bin.js" + } + }, + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz", + "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-deflate": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-deflate/-/is-deflate-1.0.0.tgz", + "integrity": "sha512-YDoFpuZWu1VRXlsnlYMzKyVRITXj7Ej/V9gXQ2/pAe7X1J7M/RNOqaIYi6qUn+B7nGyB9pDXrv02dsB58d2ZAQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-docker": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", + "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", + "dev": true, + "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-gzip": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-gzip/-/is-gzip-1.0.0.tgz", + "integrity": "sha512-rcfALRIb1YewtnksfRIHGcIY93QnK8BIQ/2c9yDYcG/Y6+vRoJuTWBmmSEbyLLYtXm7q35pHOHbZFQBaLrhlWQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-in-ssh": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-in-ssh/-/is-in-ssh-1.0.0.tgz", + "integrity": "sha512-jYa6Q9rH90kR1vKB6NM7qqd1mge3Fx4Dhw5TVlK1MUBqhEOuCagrEHMevNuCcbECmXZ0ThXkRm+Ymr51HwEPAw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-inside-container": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", + "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-docker": "^3.0.0" + }, + "bin": { + "is-inside-container": "cli.js" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-installed-globally": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.3.2.tgz", + "integrity": "sha512-wZ8x1js7Ia0kecP/CHM/3ABkAmujX7WPvQk6uu3Fly/Mk44pySulQpnHG46OMjHGXApINnV4QhY3SWnECO2z5g==", + "license": "MIT", + "dependencies": { + "global-dirs": "^2.0.1", + "is-path-inside": "^3.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-interactive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-npm": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-4.0.0.tgz", + "integrity": "sha512-96ECIfh9xtDDlPylNPXhzjsykHsMJZ18ASpaWzQyBr4YRTcVjUvzaHayDAES2oU/3KpljhHUjtSRNiDwi0F0ig==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-observable": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-observable/-/is-observable-2.1.0.tgz", + "integrity": "sha512-DailKdLb0WU+xX8K5w7VsJhapwHLZ9jjmazqCJq4X12CTgqq73TKnbRcnSLuXYPOoLQgV5IrD7ePiX/h1vnkBw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "license": "MIT", + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-regex": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", + "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", + "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", + "license": "MIT" + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-url": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/is-url/-/is-url-1.2.4.tgz", + "integrity": "sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==", + "license": "MIT" + }, + "node_modules/is-utf8": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", + "integrity": "sha512-rMYPYvCzsXywIsldgLaSoPlw5PfoB/ssr7hY4pLfcodrA5M/eArza1a9VmTiNIBNMjOGr1Ow9mTyU2o69U6U9Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-wsl/node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "dev": true, + "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-yarn-global": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.3.0.tgz", + "integrity": "sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==", + "license": "MIT" + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/isbot": { + "version": "5.1.35", + "resolved": "https://registry.npmjs.org/isbot/-/isbot-5.1.35.tgz", + "integrity": "sha512-waFfC72ZNfwLLuJ2iLaoVaqcNo+CAaLR7xCpAn0Y5WfGzkNHv7ZN39Vbi1y+kb+Zs46XHOX3tZNExroFUPX+Kg==", + "license": "Unlicense", + "engines": { + "node": ">=18" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "license": "ISC" + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==", + "dev": true, + "license": "MIT" + }, + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/jake": { + "version": "10.9.4", + "resolved": "https://registry.npmjs.org/jake/-/jake-10.9.4.tgz", + "integrity": "sha512-wpHYzhxiVQL+IV05BLE2Xn34zW1S223hvjtqk0+gsPrwd/8JNLXJgZZM/iPFsYc1xyphF+6M6EvdE5E9MBGkDA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "async": "^3.2.6", + "filelist": "^1.0.4", + "picocolors": "^1.1.1" + }, + "bin": { + "jake": "bin/cli.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jake/node_modules/async": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", + "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", + "dev": true, + "license": "MIT" + }, + "node_modules/jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/jiti": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", + "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", + "devOptional": true, + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/joycon": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/joycon/-/joycon-3.1.1.tgz", + "integrity": "sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/jpeg-exif": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/jpeg-exif/-/jpeg-exif-1.1.4.tgz", + "integrity": "sha512-a+bKEcCjtuW5WTdgeXFzswSrdqi0jk4XlEtZlx5A94wCoBpFjfFTbo/Tra5SpNCl/YFZPvcV1dJc+TAYeg6ROQ==", + "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", + "license": "MIT" + }, + "node_modules/js-base64": { + "version": "3.7.8", + "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-3.7.8.tgz", + "integrity": "sha512-hNngCeKxIUQiEUN3GPJOkz4wF/YvdUdbNL9hsBcMQTkKzboD7T/q3OYOuuPZLUE6dBxSGpwhk5mwuDud7JVAow==", + "license": "BSD-3-Clause" + }, + "node_modules/js-beautify": { + "version": "1.15.4", + "resolved": "https://registry.npmjs.org/js-beautify/-/js-beautify-1.15.4.tgz", + "integrity": "sha512-9/KXeZUKKJwqCXUdBxFJ3vPh467OCckSBmYDwSK/EtV090K+iMJ7zx2S3HLVDIWFQdqMIsZWbnaGiba18aWhaA==", + "license": "MIT", + "dependencies": { + "config-chain": "^1.1.13", + "editorconfig": "^1.0.4", + "glob": "^10.4.2", + "js-cookie": "^3.0.5", + "nopt": "^7.2.1" + }, + "bin": { + "css-beautify": "js/bin/css-beautify.js", + "html-beautify": "js/bin/html-beautify.js", + "js-beautify": "js/bin/js-beautify.js" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/js-beautify/node_modules/glob": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", + "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/js-beautify/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "license": "ISC" + }, + "node_modules/js-beautify/node_modules/minimatch": { + "version": "9.0.8", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.8.tgz", + "integrity": "sha512-reYkDYtj/b19TeqbNZCV4q9t+Yxylf/rYBsLb42SXJatTv4/ylq5lEiAmhA/IToxO7NI2UzNMghHoHuaqDkAjw==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^5.0.2" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/js-beautify/node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/js-cookie": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-3.0.5.tgz", + "integrity": "sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==", + "license": "MIT", + "engines": { + "node": ">=14" + } + }, + "node_modules/js-yaml": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", + "dev": true, + "license": "MIT" + }, + "node_modules/jshint": { + "version": "2.13.6", + "resolved": "https://registry.npmjs.org/jshint/-/jshint-2.13.6.tgz", + "integrity": "sha512-IVdB4G0NTTeQZrBoM8C5JFVLjV2KtZ9APgybDA1MK73xb09qFs0jCXyQLnCOp1cSZZZbvhq/6mfXHUTaDkffuQ==", + "license": "MIT", + "dependencies": { + "cli": "~1.0.0", + "console-browserify": "1.1.x", + "exit": "0.1.x", + "htmlparser2": "3.8.x", + "lodash": "~4.17.21", + "minimatch": "~3.0.2", + "strip-json-comments": "1.0.x" + }, + "bin": { + "jshint": "bin/jshint" + } + }, + "node_modules/jshint/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "license": "MIT" + }, + "node_modules/jshint/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/jshint/node_modules/console-browserify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz", + "integrity": "sha512-duS7VP5pvfsNLDvL1O4VOEbw37AI3A4ZUQYemvDlnpGrNu9tprR7BYWpDYwC0Xia0Zxz5ZupdiIrUp0GH1aXfg==", + "dependencies": { + "date-now": "^0.1.4" + } + }, + "node_modules/jshint/node_modules/dom-serializer": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz", + "integrity": "sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==", + "license": "MIT", + "dependencies": { + "domelementtype": "^2.0.1", + "entities": "^2.0.0" + } + }, + "node_modules/jshint/node_modules/dom-serializer/node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "BSD-2-Clause" + }, + "node_modules/jshint/node_modules/dom-serializer/node_modules/entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "license": "BSD-2-Clause", + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/jshint/node_modules/domelementtype": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", + "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==", + "license": "BSD-2-Clause" + }, + "node_modules/jshint/node_modules/domhandler": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.3.0.tgz", + "integrity": "sha512-q9bUwjfp7Eif8jWxxxPSykdRZAb6GkguBGSgvvCrhI9wB71W2K/Kvv4E61CF/mcCfnVJDeDWx/Vb/uAqbDj6UQ==", + "dependencies": { + "domelementtype": "1" + } + }, + "node_modules/jshint/node_modules/domutils": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz", + "integrity": "sha512-gSu5Oi/I+3wDENBsOWBiRK1eoGxcywYSqg3rR960/+EfY0CF4EX1VPkgHOZ3WiS/Jg2DtliF6BhWcHlfpYUcGw==", + "dependencies": { + "dom-serializer": "0", + "domelementtype": "1" + } + }, + "node_modules/jshint/node_modules/entities": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-1.0.0.tgz", + "integrity": "sha512-LbLqfXgJMmy81t+7c14mnulFHJ170cM6E+0vMXR9k/ZiZwgX8i5pNgjTCX3SO4VeUsFLV+8InixoretwU+MjBQ==", + "license": "BSD-like" + }, + "node_modules/jshint/node_modules/htmlparser2": { + "version": "3.8.3", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.8.3.tgz", + "integrity": "sha512-hBxEg3CYXe+rPIua8ETe7tmG3XDn9B0edOE/e9wH2nLczxzgdu0m0aNHY+5wFZiviLWLdANPJTssa92dMcXQ5Q==", + "license": "MIT", + "dependencies": { + "domelementtype": "1", + "domhandler": "2.3", + "domutils": "1.5", + "entities": "1.0", + "readable-stream": "1.1" + } + }, + "node_modules/jshint/node_modules/isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", + "license": "MIT" + }, + "node_modules/jshint/node_modules/minimatch": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.8.tgz", + "integrity": "sha512-6FsRAQsxQ61mw+qP1ZzbL9Bc78x2p5OqNgNpnoAFLTrX8n5Kxph0CsnhmKKNXTWjXqU5L0pGPR7hYk+XWZr60Q==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/jshint/node_modules/readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==", + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "node_modules/jshint/node_modules/strip-json-comments": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-1.0.4.tgz", + "integrity": "sha512-AOPG8EBc5wAikaG1/7uFCNFJwnKOuQwFTpYBdTW6OvWHeZBQBrAA/amefHGrEiOnCPcLFZK6FUPtWVKpQVIRgg==", + "license": "MIT", + "bin": { + "strip-json-comments": "cli.js" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/json-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", + "integrity": "sha512-CuUqjv0FUZIdXkHPI8MezCnFCdaTAacej1TZYulLoAg1h/PhwkdXFN4V/gzY4g+fMBCOV2xF+rp7t2XD2ns/NQ==", + "license": "MIT" + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", + "dev": true, + "license": "(AFL-2.1 OR BSD-3-Clause)" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-0.0.1.tgz", + "integrity": "sha512-nKtD/Qxm7tWdZqJoldEC7fF0S41v0mWbeaXG3637stOWfyGxTgWTYE2wtfKmjzpvxv2MA2xzxsXOIiwUpkX6Qw==", + "dev": true, + "license": "MIT", + "dependencies": { + "jsonify": "~0.0.0" + } + }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", + "dev": true, + "license": "ISC" + }, + "node_modules/jsonfile": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", + "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsonify": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.1.tgz", + "integrity": "sha512-2/Ki0GcmuqSrgFyelQq9M05y7PS0mEwuIzrf3f1fPqkVDVRvZrPZtVSMHxdgo8Aq0sxAOb/cr2aqqA3LeWHVPg==", + "dev": true, + "license": "Public Domain", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/jsonparse": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", + "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", + "dev": true, + "engines": [ + "node >= 0.2.0" + ], + "license": "MIT" + }, + "node_modules/JSONStream": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", + "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", + "dev": true, + "license": "(MIT OR Apache-2.0)", + "dependencies": { + "jsonparse": "^1.2.0", + "through": ">=2.2.7 <3" + }, + "bin": { + "JSONStream": "bin.js" + }, + "engines": { + "node": "*" + } + }, + "node_modules/jsprim": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", + "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", + "dev": true, + "license": "MIT", + "dependencies": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.4.0", + "verror": "1.10.0" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/juice": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/juice/-/juice-11.1.1.tgz", + "integrity": "sha512-4SBfZqKcc6DrIS+5b/WiGoWaZsdUPBH+e6SbRlNjJpaIRtfoBhYReAtobIEW6mcLeFFDXLBJMuZwkJLkBJjs2w==", + "license": "MIT", + "dependencies": { + "cheerio": "1.0.0", + "commander": "^12.1.0", + "entities": "^7.0.0", + "mensch": "^0.3.4", + "slick": "^1.12.2", + "web-resource-inliner": "^8.0.0" + }, + "bin": { + "juice": "bin/juice" + }, + "engines": { + "node": ">=18.17" + } + }, + "node_modules/juice/node_modules/cheerio": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0.tgz", + "integrity": "sha512-quS9HgjQpdaXOvsZz82Oz7uxtXiy6UIsIQcpBj7HRw2M63Skasm9qlDocAM7jNuaxdhpPU7c4kJN+gA5MCu4ww==", + "license": "MIT", + "dependencies": { + "cheerio-select": "^2.1.0", + "dom-serializer": "^2.0.0", + "domhandler": "^5.0.3", + "domutils": "^3.1.0", + "encoding-sniffer": "^0.2.0", + "htmlparser2": "^9.1.0", + "parse5": "^7.1.2", + "parse5-htmlparser2-tree-adapter": "^7.0.0", + "parse5-parser-stream": "^7.1.2", + "undici": "^6.19.5", + "whatwg-mimetype": "^4.0.0" + }, + "engines": { + "node": ">=18.17" + }, + "funding": { + "url": "https://github.com/cheeriojs/cheerio?sponsor=1" + } + }, + "node_modules/juice/node_modules/commander": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", + "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/juice/node_modules/entities": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-7.0.1.tgz", + "integrity": "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/juice/node_modules/htmlparser2": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-9.1.0.tgz", + "integrity": "sha512-5zfg6mHUoaer/97TxnGpxmbR7zJtPwIYFMZ/H5ucTlPZhKvtum05yiPK3Mgai3a0DyVxv7qYqoweaEd2nrYQzQ==", + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "MIT", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.1.0", + "entities": "^4.5.0" + } + }, + "node_modules/juice/node_modules/htmlparser2/node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/juice/node_modules/undici": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-6.23.0.tgz", + "integrity": "sha512-VfQPToRA5FZs/qJxLIinmU59u0r7LXqoJkCzinq3ckNJp3vKEh7jTWN589YQ5+aoAC/TGRLyJLCPKcLQbM8r9g==", + "license": "MIT", + "engines": { + "node": ">=18.17" + } + }, + "node_modules/keyv": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", + "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==", + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.0" + } + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/labeled-stream-splicer": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/labeled-stream-splicer/-/labeled-stream-splicer-2.0.2.tgz", + "integrity": "sha512-Ca4LSXFFZUjPScRaqOcFxneA0VpKZr4MMYCljyQr4LIewTLb3Y0IUTIsnBBsVubIeEfxeSZpSjSsRM8APEQaAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.1", + "stream-splicer": "^2.0.0" + } + }, + "node_modules/latest-version": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz", + "integrity": "sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==", + "license": "MIT", + "dependencies": { + "package-json": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lcid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", + "integrity": "sha512-YiGkH6EnGrDGqLMITnGjXtGmNtjoXw9SVUzcaos8RBi7Ps0VBylkq+vOcY9QE5poLasPCR849ucFUkl0UzUyOw==", + "dev": true, + "license": "MIT", + "dependencies": { + "invert-kv": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/lilconfig": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", + "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, + "node_modules/load-json-file": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "integrity": "sha512-cy7ZdNRXdablkXYNI049pthVeXFurRyb9+hA/dZzerZ0pGTx42z+y+ssxBaVV2l70t1muq5IdKhn4UtcoGUY9A==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "strip-bom": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/loader-runner": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.1.tgz", + "integrity": "sha512-IWqP2SCPhyVFTBtRcgMHdzlf9ul25NwaFx4wCEH/KjAXuuHY4yNjvPXsBokp8jCB936PyWRaPKUNh8NvylLp2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.11.5" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lodash": { + "version": "4.17.23", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz", + "integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==", + "license": "MIT" + }, + "node_modules/lodash.assign": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz", + "integrity": "sha512-hFuH8TY+Yji7Eja3mGiuAxBqLagejScbG8GbG0j6o9vzn0YL14My+ktnqtZgFTosKymC9/44wP6s7xyuLfnClw==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.memoize": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-3.0.4.tgz", + "integrity": "sha512-eDn9kqrAmVUC1wmZvlQ6Uhde44n+tXpqPrN8olQJbttgh0oKclk+SF54P47VEGE9CEiMeRwAP8BaM7UHvBkz2A==", + "dev": true, + "license": "MIT" + }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/loglevel": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.9.2.tgz", + "integrity": "sha512-HgMmCqIJSAKqo68l0rS2AanEWfkxaZ5wNiEFb5ggm08lDs9Xl2KxBlX3PTcaD2chBM1gXAYf491/M2Rv8Jwayg==", + "license": "MIT", + "engines": { + "node": ">= 0.6.0" + }, + "funding": { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/loglevel" + } + }, + "node_modules/lowercase-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", + "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/lru-cache": { + "version": "11.2.6", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.6.tgz", + "integrity": "sha512-ESL2CrkS/2wTPfuend7Zhkzo2u0daGJ/A2VucJOgQ/C48S/zB8MMeMHSGKYpXhIjbPxfuezITkaBH1wqv00DDQ==", + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/luxon": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.7.2.tgz", + "integrity": "sha512-vtEhXh/gNjI9Yg1u4jX/0YVPMvxzHuGgCm6tC5kZyb08yjGWGnqAjGJvcXbqQR2P3MyMEFnRbpcdFS6PBcLqew==", + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "license": "MIT", + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/marked": { + "version": "17.0.3", + "resolved": "https://registry.npmjs.org/marked/-/marked-17.0.3.tgz", + "integrity": "sha512-jt1v2ObpyOKR8p4XaUJVk3YWRJ5n+i4+rjQopxvV32rSndTJXvIzuUdWWIy/1pFQMkQmvTXawzDNqOH/CUmx6A==", + "license": "MIT", + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/md5.js": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "dev": true, + "license": "MIT", + "dependencies": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/mensch": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/mensch/-/mensch-0.3.4.tgz", + "integrity": "sha512-IAeFvcOnV9V0Yk+bFhYR07O3yNina9ANIN5MoXBKYJ/RLYPurd2d0yw14MDhpr9/momp0WofT1bPUh3hkzdi/g==", + "license": "MIT" + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true, + "license": "MIT" + }, + "node_modules/miller-rabin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", + "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "bn.js": "^4.0.0", + "brorand": "^1.0.1" + }, + "bin": { + "miller-rabin": "bin/miller-rabin" + } + }, + "node_modules/miller-rabin/node_modules/bn.js": { + "version": "4.12.3", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.3.tgz", + "integrity": "sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==", + "dev": true, + "license": "MIT" + }, + "node_modules/mime": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-4.1.0.tgz", + "integrity": "sha512-X5ju04+cAzsojXKes0B/S4tcYtFAJ6tTMuSPBEn9CPGlrWr8Fiw7qYeLT0XyH80HSoAoqWCaz+MWKh22P7G1cw==", + "funding": [ + "https://github.com/sponsors/broofa" + ], + "license": "MIT", + "bin": { + "mime": "bin/cli.js" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "dev": true, + "license": "ISC" + }, + "node_modules/minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==", + "dev": true, + "license": "MIT" + }, + "node_modules/minimatch": { + "version": "10.2.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", + "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/module-deps": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/module-deps/-/module-deps-4.1.1.tgz", + "integrity": "sha512-ze1e77tkYtlJI90RmlJJvTOGe91OAbtNQj34tg26GWlvdDc0dzmlxujTnh85S8feiTB3eBkKAOCD/v5p9v6wHg==", + "dev": true, + "license": "MIT", + "dependencies": { + "browser-resolve": "^1.7.0", + "cached-path-relative": "^1.0.0", + "concat-stream": "~1.5.0", + "defined": "^1.0.0", + "detective": "^4.0.0", + "duplexer2": "^0.1.2", + "inherits": "^2.0.1", + "JSONStream": "^1.0.3", + "parents": "^1.0.0", + "readable-stream": "^2.0.2", + "resolve": "^1.1.3", + "stream-combiner2": "^1.1.1", + "subarg": "^1.0.0", + "through2": "^2.0.0", + "xtend": "^4.0.0" + }, + "bin": { + "module-deps": "bin/cmd.js" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mrmime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz", + "integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/mustache": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/mustache/-/mustache-3.2.1.tgz", + "integrity": "sha512-RERvMFdLpaFfSRIEe632yDm5nsd0SDKn8hGmcUwswnyiE5mtdZLDybtHAz6hjJhawokF0hXvGLtx9mrQfm6FkA==", + "license": "MIT", + "bin": { + "mustache": "bin/mustache" + }, + "engines": { + "npm": ">=1.4.0" + } + }, + "node_modules/mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", + "dev": true, + "license": "ISC" + }, + "node_modules/nanoid": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.1.6.tgz", + "integrity": "sha512-c7+7RQ+dMB5dPwwCp4ee1/iV/q2P6aK1mTZcfr1BTuVlyW9hJYiMPybJCcnBlQtuSmTIWNeazm/zqNoZSSElBg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.js" + }, + "engines": { + "node": "^18 || >=20" + } + }, + "node_modules/ncp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ncp/-/ncp-2.0.0.tgz", + "integrity": "sha512-zIdGUrPRFTUELUvr3Gmc7KZ2Sw/h1PiVM0Af/oHB6zgnV1ikqSfRk+TOufi79aHYCW3NiOXmr1BP5nWbzojLaA==", + "dev": true, + "license": "MIT", + "bin": { + "ncp": "bin/ncp" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true, + "license": "MIT" + }, + "node_modules/nexe": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/nexe/-/nexe-1.1.6.tgz", + "integrity": "sha512-9sIAnLFTeImJNkeKleRuwKQSlkZjoX5uPmeGvAPXp4AwqiNteEIRIMYRquLlv3rQ2GpkFqRHGjnyVm2v8Huzew==", + "dev": true, + "license": "MIT", + "dependencies": { + "async": "^1.5.2", + "browserify": "^13.0.0", + "colors": "^1.1.2", + "glob": "^7.0.0", + "gunzip-maybe": "^1.3.1", + "insert-module-globals": "^7.0.1", + "mkdirp": "^0.5.1", + "module-deps": "^4.0.5", + "ncp": "^2.0.0", + "progress": "^1.1.8", + "request": "^2.67.0", + "tar-stream": "^1.3.1", + "yargs": "^4.2.0" + }, + "bin": { + "nexe": "bin/nexe" + } + }, + "node_modules/nexe/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/nexe/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/nexe/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/nexe/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-fetch-native": { + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/node-fetch-native/-/node-fetch-native-1.6.7.tgz", + "integrity": "sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-releases": { + "version": "2.0.27", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz", + "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/non-error": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/non-error/-/non-error-0.1.0.tgz", + "integrity": "sha512-TMB1uHiGsHRGv1uYclfhivcnf0/PdFp2pNqRxXjncaAsjYMoisaQJI+SSZCqRq+VliwRTC8tsMQfmrWjDMhkPQ==", + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/nopt": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-7.2.1.tgz", + "integrity": "sha512-taM24ViiimT/XntxbPyJQzCG+p4EKOpgD3mxFwW38mGjVUrfERQOeY4EDHjdnptttfHuHQXFx+lTP08Q+mLa/w==", + "license": "ISC", + "dependencies": { + "abbrev": "^2.0.0" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "node_modules/normalize-package-data/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-url": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.1.tgz", + "integrity": "sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/npm": { + "version": "11.11.0", + "resolved": "https://registry.npmjs.org/npm/-/npm-11.11.0.tgz", + "integrity": "sha512-82gRxKrh/eY5UnNorkTFcdBQAGpgjWehkfGVqAGlJjejEtJZGGJUqjo3mbBTNbc5BTnPKGVtGPBZGhElujX5cw==", + "bundleDependencies": [ + "@isaacs/string-locale-compare", + "@npmcli/arborist", + "@npmcli/config", + "@npmcli/fs", + "@npmcli/map-workspaces", + "@npmcli/metavuln-calculator", + "@npmcli/package-json", + "@npmcli/promise-spawn", + "@npmcli/redact", + "@npmcli/run-script", + "@sigstore/tuf", + "abbrev", + "archy", + "cacache", + "chalk", + "ci-info", + "fastest-levenshtein", + "fs-minipass", + "glob", + "graceful-fs", + "hosted-git-info", + "ini", + "init-package-json", + "is-cidr", + "json-parse-even-better-errors", + "libnpmaccess", + "libnpmdiff", + "libnpmexec", + "libnpmfund", + "libnpmorg", + "libnpmpack", + "libnpmpublish", + "libnpmsearch", + "libnpmteam", + "libnpmversion", + "make-fetch-happen", + "minimatch", + "minipass", + "minipass-pipeline", + "ms", + "node-gyp", + "nopt", + "npm-audit-report", + "npm-install-checks", + "npm-package-arg", + "npm-pick-manifest", + "npm-profile", + "npm-registry-fetch", + "npm-user-validate", + "p-map", + "pacote", + "parse-conflict-json", + "proc-log", + "qrcode-terminal", + "read", + "semver", + "spdx-expression-parse", + "ssri", + "supports-color", + "tar", + "text-table", + "tiny-relative-date", + "treeverse", + "validate-npm-package-name", + "which" + ], + "license": "Artistic-2.0", + "workspaces": [ + "docs", + "smoke-tests", + "mock-globals", + "mock-registry", + "workspaces/*" + ], + "dependencies": { + "@isaacs/string-locale-compare": "^1.1.0", + "@npmcli/arborist": "^9.4.0", + "@npmcli/config": "^10.7.1", + "@npmcli/fs": "^5.0.0", + "@npmcli/map-workspaces": "^5.0.3", + "@npmcli/metavuln-calculator": "^9.0.3", + "@npmcli/package-json": "^7.0.5", + "@npmcli/promise-spawn": "^9.0.1", + "@npmcli/redact": "^4.0.0", + "@npmcli/run-script": "^10.0.3", + "@sigstore/tuf": "^4.0.1", + "abbrev": "^4.0.0", + "archy": "~1.0.0", + "cacache": "^20.0.3", + "chalk": "^5.6.2", + "ci-info": "^4.4.0", + "fastest-levenshtein": "^1.0.16", + "fs-minipass": "^3.0.3", + "glob": "^13.0.6", + "graceful-fs": "^4.2.11", + "hosted-git-info": "^9.0.2", + "ini": "^6.0.0", + "init-package-json": "^8.2.5", + "is-cidr": "^6.0.3", + "json-parse-even-better-errors": "^5.0.0", + "libnpmaccess": "^10.0.3", + "libnpmdiff": "^8.1.3", + "libnpmexec": "^10.2.3", + "libnpmfund": "^7.0.17", + "libnpmorg": "^8.0.1", + "libnpmpack": "^9.1.3", + "libnpmpublish": "^11.1.3", + "libnpmsearch": "^9.0.1", + "libnpmteam": "^8.0.2", + "libnpmversion": "^8.0.3", + "make-fetch-happen": "^15.0.4", + "minimatch": "^10.2.2", + "minipass": "^7.1.3", + "minipass-pipeline": "^1.2.4", + "ms": "^2.1.2", + "node-gyp": "^12.2.0", + "nopt": "^9.0.0", + "npm-audit-report": "^7.0.0", + "npm-install-checks": "^8.0.0", + "npm-package-arg": "^13.0.2", + "npm-pick-manifest": "^11.0.3", + "npm-profile": "^12.0.1", + "npm-registry-fetch": "^19.1.1", + "npm-user-validate": "^4.0.0", + "p-map": "^7.0.4", + "pacote": "^21.4.0", + "parse-conflict-json": "^5.0.1", + "proc-log": "^6.1.0", + "qrcode-terminal": "^0.12.0", + "read": "^5.0.1", + "semver": "^7.7.4", + "spdx-expression-parse": "^4.0.0", + "ssri": "^13.0.1", + "supports-color": "^10.2.2", + "tar": "^7.5.9", + "text-table": "~0.2.0", + "tiny-relative-date": "^2.0.2", + "treeverse": "^3.0.0", + "validate-npm-package-name": "^7.0.2", + "which": "^6.0.1" + }, + "bin": { + "npm": "bin/npm-cli.js", + "npx": "bin/npx-cli.js" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/@gar/promise-retry": { + "version": "1.0.2", + "inBundle": true, + "license": "MIT", + "dependencies": { + "retry": "^0.13.1" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/@gar/promise-retry/node_modules/retry": { + "version": "0.13.1", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/npm/node_modules/@isaacs/fs-minipass": { + "version": "4.0.1", + "inBundle": true, + "license": "ISC", + "dependencies": { + "minipass": "^7.0.4" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/npm/node_modules/@isaacs/string-locale-compare": { + "version": "1.1.0", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/@npmcli/agent": { + "version": "4.0.0", + "inBundle": true, + "license": "ISC", + "dependencies": { + "agent-base": "^7.1.0", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.1", + "lru-cache": "^11.2.1", + "socks-proxy-agent": "^8.0.3" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/@npmcli/arborist": { + "version": "9.4.0", + "inBundle": true, + "license": "ISC", + "dependencies": { + "@isaacs/string-locale-compare": "^1.1.0", + "@npmcli/fs": "^5.0.0", + "@npmcli/installed-package-contents": "^4.0.0", + "@npmcli/map-workspaces": "^5.0.0", + "@npmcli/metavuln-calculator": "^9.0.2", + "@npmcli/name-from-folder": "^4.0.0", + "@npmcli/node-gyp": "^5.0.0", + "@npmcli/package-json": "^7.0.0", + "@npmcli/query": "^5.0.0", + "@npmcli/redact": "^4.0.0", + "@npmcli/run-script": "^10.0.0", + "bin-links": "^6.0.0", + "cacache": "^20.0.1", + "common-ancestor-path": "^2.0.0", + "hosted-git-info": "^9.0.0", + "json-stringify-nice": "^1.1.4", + "lru-cache": "^11.2.1", + "minimatch": "^10.0.3", + "nopt": "^9.0.0", + "npm-install-checks": "^8.0.0", + "npm-package-arg": "^13.0.0", + "npm-pick-manifest": "^11.0.1", + "npm-registry-fetch": "^19.0.0", + "pacote": "^21.0.2", + "parse-conflict-json": "^5.0.1", + "proc-log": "^6.0.0", + "proggy": "^4.0.0", + "promise-all-reject-late": "^1.0.0", + "promise-call-limit": "^3.0.1", + "semver": "^7.3.7", + "ssri": "^13.0.0", + "treeverse": "^3.0.0", + "walk-up-path": "^4.0.0" + }, + "bin": { + "arborist": "bin/index.js" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/@npmcli/config": { + "version": "10.7.1", + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/map-workspaces": "^5.0.0", + "@npmcli/package-json": "^7.0.0", + "ci-info": "^4.0.0", + "ini": "^6.0.0", + "nopt": "^9.0.0", + "proc-log": "^6.0.0", + "semver": "^7.3.5", + "walk-up-path": "^4.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/@npmcli/fs": { + "version": "5.0.0", + "inBundle": true, + "license": "ISC", + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/@npmcli/git": { + "version": "7.0.2", + "inBundle": true, + "license": "ISC", + "dependencies": { + "@gar/promise-retry": "^1.0.0", + "@npmcli/promise-spawn": "^9.0.0", + "ini": "^6.0.0", + "lru-cache": "^11.2.1", + "npm-pick-manifest": "^11.0.1", + "proc-log": "^6.0.0", + "semver": "^7.3.5", + "which": "^6.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/@npmcli/installed-package-contents": { + "version": "4.0.0", + "inBundle": true, + "license": "ISC", + "dependencies": { + "npm-bundled": "^5.0.0", + "npm-normalize-package-bin": "^5.0.0" + }, + "bin": { + "installed-package-contents": "bin/index.js" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/@npmcli/map-workspaces": { + "version": "5.0.3", + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/name-from-folder": "^4.0.0", + "@npmcli/package-json": "^7.0.0", + "glob": "^13.0.0", + "minimatch": "^10.0.3" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/@npmcli/metavuln-calculator": { + "version": "9.0.3", + "inBundle": true, + "license": "ISC", + "dependencies": { + "cacache": "^20.0.0", + "json-parse-even-better-errors": "^5.0.0", + "pacote": "^21.0.0", + "proc-log": "^6.0.0", + "semver": "^7.3.5" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/@npmcli/name-from-folder": { + "version": "4.0.0", + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/@npmcli/node-gyp": { + "version": "5.0.0", + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/@npmcli/package-json": { + "version": "7.0.5", + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/git": "^7.0.0", + "glob": "^13.0.0", + "hosted-git-info": "^9.0.0", + "json-parse-even-better-errors": "^5.0.0", + "proc-log": "^6.0.0", + "semver": "^7.5.3", + "spdx-expression-parse": "^4.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/@npmcli/promise-spawn": { + "version": "9.0.1", + "inBundle": true, + "license": "ISC", + "dependencies": { + "which": "^6.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/@npmcli/query": { + "version": "5.0.0", + "inBundle": true, + "license": "ISC", + "dependencies": { + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/@npmcli/redact": { + "version": "4.0.0", + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/@npmcli/run-script": { + "version": "10.0.3", + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/node-gyp": "^5.0.0", + "@npmcli/package-json": "^7.0.0", + "@npmcli/promise-spawn": "^9.0.0", + "node-gyp": "^12.1.0", + "proc-log": "^6.0.0", + "which": "^6.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/@sigstore/bundle": { + "version": "4.0.0", + "inBundle": true, + "license": "Apache-2.0", + "dependencies": { + "@sigstore/protobuf-specs": "^0.5.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/@sigstore/core": { + "version": "3.1.0", + "inBundle": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/@sigstore/protobuf-specs": { + "version": "0.5.0", + "inBundle": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/@sigstore/sign": { + "version": "4.1.0", + "inBundle": true, + "license": "Apache-2.0", + "dependencies": { + "@sigstore/bundle": "^4.0.0", + "@sigstore/core": "^3.1.0", + "@sigstore/protobuf-specs": "^0.5.0", + "make-fetch-happen": "^15.0.3", + "proc-log": "^6.1.0", + "promise-retry": "^2.0.1" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/@sigstore/tuf": { + "version": "4.0.1", + "inBundle": true, + "license": "Apache-2.0", + "dependencies": { + "@sigstore/protobuf-specs": "^0.5.0", + "tuf-js": "^4.1.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/@sigstore/verify": { + "version": "3.1.0", + "inBundle": true, + "license": "Apache-2.0", + "dependencies": { + "@sigstore/bundle": "^4.0.0", + "@sigstore/core": "^3.1.0", + "@sigstore/protobuf-specs": "^0.5.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/@tufjs/canonical-json": { + "version": "2.0.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/@tufjs/models": { + "version": "4.1.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "@tufjs/canonical-json": "2.0.0", + "minimatch": "^10.1.1" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/abbrev": { + "version": "4.0.0", + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/agent-base": { + "version": "7.1.4", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/npm/node_modules/aproba": { + "version": "2.1.0", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/archy": { + "version": "1.0.0", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/balanced-match": { + "version": "4.0.4", + "inBundle": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/npm/node_modules/bin-links": { + "version": "6.0.0", + "inBundle": true, + "license": "ISC", + "dependencies": { + "cmd-shim": "^8.0.0", + "npm-normalize-package-bin": "^5.0.0", + "proc-log": "^6.0.0", + "read-cmd-shim": "^6.0.0", + "write-file-atomic": "^7.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/binary-extensions": { + "version": "3.1.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=18.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm/node_modules/brace-expansion": { + "version": "5.0.3", + "inBundle": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/npm/node_modules/cacache": { + "version": "20.0.3", + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/fs": "^5.0.0", + "fs-minipass": "^3.0.0", + "glob": "^13.0.0", + "lru-cache": "^11.1.0", + "minipass": "^7.0.3", + "minipass-collect": "^2.0.1", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "p-map": "^7.0.2", + "ssri": "^13.0.0", + "unique-filename": "^5.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/chalk": { + "version": "5.6.2", + "inBundle": true, + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/npm/node_modules/chownr": { + "version": "3.0.0", + "inBundle": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/npm/node_modules/ci-info": { + "version": "4.4.0", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/cidr-regex": { + "version": "5.0.3", + "inBundle": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=20" + } + }, + "node_modules/npm/node_modules/cmd-shim": { + "version": "8.0.0", + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/common-ancestor-path": { + "version": "2.0.0", + "inBundle": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">= 18" + } + }, + "node_modules/npm/node_modules/cssesc": { + "version": "3.0.0", + "inBundle": true, + "license": "MIT", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npm/node_modules/debug": { + "version": "4.4.3", + "inBundle": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/npm/node_modules/diff": { + "version": "8.0.3", + "inBundle": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/npm/node_modules/env-paths": { + "version": "2.2.1", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/npm/node_modules/err-code": { + "version": "2.0.3", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/exponential-backoff": { + "version": "3.1.3", + "inBundle": true, + "license": "Apache-2.0" + }, + "node_modules/npm/node_modules/fastest-levenshtein": { + "version": "1.0.16", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 4.9.1" + } + }, + "node_modules/npm/node_modules/fs-minipass": { + "version": "3.0.3", + "inBundle": true, + "license": "ISC", + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/glob": { + "version": "13.0.6", + "inBundle": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "minimatch": "^10.2.2", + "minipass": "^7.1.3", + "path-scurry": "^2.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm/node_modules/graceful-fs": { + "version": "4.2.11", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/hosted-git-info": { + "version": "9.0.2", + "inBundle": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^11.1.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/http-cache-semantics": { + "version": "4.2.0", + "inBundle": true, + "license": "BSD-2-Clause" + }, + "node_modules/npm/node_modules/http-proxy-agent": { + "version": "7.0.2", + "inBundle": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/npm/node_modules/https-proxy-agent": { + "version": "7.0.6", + "inBundle": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/npm/node_modules/iconv-lite": { + "version": "0.7.2", + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/npm/node_modules/ignore-walk": { + "version": "8.0.0", + "inBundle": true, + "license": "ISC", + "dependencies": { + "minimatch": "^10.0.3" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/imurmurhash": { + "version": "0.1.4", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/npm/node_modules/ini": { + "version": "6.0.0", + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/init-package-json": { + "version": "8.2.5", + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/package-json": "^7.0.0", + "npm-package-arg": "^13.0.0", + "promzard": "^3.0.1", + "read": "^5.0.1", + "semver": "^7.7.2", + "validate-npm-package-name": "^7.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/ip-address": { + "version": "10.1.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/npm/node_modules/is-cidr": { + "version": "6.0.3", + "inBundle": true, + "license": "BSD-2-Clause", + "dependencies": { + "cidr-regex": "^5.0.1" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/npm/node_modules/isexe": { + "version": "4.0.0", + "inBundle": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=20" + } + }, + "node_modules/npm/node_modules/json-parse-even-better-errors": { + "version": "5.0.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/json-stringify-nice": { + "version": "1.1.4", + "inBundle": true, + "license": "ISC", + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm/node_modules/jsonparse": { + "version": "1.3.1", + "engines": [ + "node >= 0.2.0" + ], + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/just-diff": { + "version": "6.0.2", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/just-diff-apply": { + "version": "5.5.0", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/libnpmaccess": { + "version": "10.0.3", + "inBundle": true, + "license": "ISC", + "dependencies": { + "npm-package-arg": "^13.0.0", + "npm-registry-fetch": "^19.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/libnpmdiff": { + "version": "8.1.3", + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/arborist": "^9.4.0", + "@npmcli/installed-package-contents": "^4.0.0", + "binary-extensions": "^3.0.0", + "diff": "^8.0.2", + "minimatch": "^10.0.3", + "npm-package-arg": "^13.0.0", + "pacote": "^21.0.2", + "tar": "^7.5.1" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/libnpmexec": { + "version": "10.2.3", + "inBundle": true, + "license": "ISC", + "dependencies": { + "@gar/promise-retry": "^1.0.0", + "@npmcli/arborist": "^9.4.0", + "@npmcli/package-json": "^7.0.0", + "@npmcli/run-script": "^10.0.0", + "ci-info": "^4.0.0", + "npm-package-arg": "^13.0.0", + "pacote": "^21.0.2", + "proc-log": "^6.0.0", + "read": "^5.0.1", + "semver": "^7.3.7", + "signal-exit": "^4.1.0", + "walk-up-path": "^4.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/libnpmfund": { + "version": "7.0.17", + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/arborist": "^9.4.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/libnpmorg": { + "version": "8.0.1", + "inBundle": true, + "license": "ISC", + "dependencies": { + "aproba": "^2.0.0", + "npm-registry-fetch": "^19.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/libnpmpack": { + "version": "9.1.3", + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/arborist": "^9.4.0", + "@npmcli/run-script": "^10.0.0", + "npm-package-arg": "^13.0.0", + "pacote": "^21.0.2" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/libnpmpublish": { + "version": "11.1.3", + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/package-json": "^7.0.0", + "ci-info": "^4.0.0", + "npm-package-arg": "^13.0.0", + "npm-registry-fetch": "^19.0.0", + "proc-log": "^6.0.0", + "semver": "^7.3.7", + "sigstore": "^4.0.0", + "ssri": "^13.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/libnpmsearch": { + "version": "9.0.1", + "inBundle": true, + "license": "ISC", + "dependencies": { + "npm-registry-fetch": "^19.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/libnpmteam": { + "version": "8.0.2", + "inBundle": true, + "license": "ISC", + "dependencies": { + "aproba": "^2.0.0", + "npm-registry-fetch": "^19.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/libnpmversion": { + "version": "8.0.3", + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/git": "^7.0.0", + "@npmcli/run-script": "^10.0.0", + "json-parse-even-better-errors": "^5.0.0", + "proc-log": "^6.0.0", + "semver": "^7.3.7" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/lru-cache": { + "version": "11.2.6", + "inBundle": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/npm/node_modules/make-fetch-happen": { + "version": "15.0.4", + "inBundle": true, + "license": "ISC", + "dependencies": { + "@gar/promise-retry": "^1.0.0", + "@npmcli/agent": "^4.0.0", + "cacache": "^20.0.1", + "http-cache-semantics": "^4.1.1", + "minipass": "^7.0.2", + "minipass-fetch": "^5.0.0", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^1.0.0", + "proc-log": "^6.0.0", + "ssri": "^13.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/minimatch": { + "version": "10.2.2", + "inBundle": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm/node_modules/minipass": { + "version": "7.1.3", + "inBundle": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/npm/node_modules/minipass-collect": { + "version": "2.0.1", + "inBundle": true, + "license": "ISC", + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/npm/node_modules/minipass-fetch": { + "version": "5.0.2", + "inBundle": true, + "license": "MIT", + "dependencies": { + "minipass": "^7.0.3", + "minipass-sized": "^2.0.0", + "minizlib": "^3.0.1" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + }, + "optionalDependencies": { + "iconv-lite": "^0.7.2" + } + }, + "node_modules/npm/node_modules/minipass-flush": { + "version": "1.0.5", + "inBundle": true, + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/npm/node_modules/minipass-flush/node_modules/minipass": { + "version": "3.3.6", + "inBundle": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/minipass-flush/node_modules/yallist": { + "version": "4.0.0", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/minipass-pipeline": { + "version": "1.2.4", + "inBundle": true, + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/minipass-pipeline/node_modules/minipass": { + "version": "3.3.6", + "inBundle": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/minipass-pipeline/node_modules/yallist": { + "version": "4.0.0", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/minipass-sized": { + "version": "2.0.0", + "inBundle": true, + "license": "ISC", + "dependencies": { + "minipass": "^7.1.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/minizlib": { + "version": "3.1.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "minipass": "^7.1.2" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/npm/node_modules/ms": { + "version": "2.1.3", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/mute-stream": { + "version": "3.0.0", + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/negotiator": { + "version": "1.0.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/npm/node_modules/node-gyp": { + "version": "12.2.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "env-paths": "^2.2.0", + "exponential-backoff": "^3.1.1", + "graceful-fs": "^4.2.6", + "make-fetch-happen": "^15.0.0", + "nopt": "^9.0.0", + "proc-log": "^6.0.0", + "semver": "^7.3.5", + "tar": "^7.5.4", + "tinyglobby": "^0.2.12", + "which": "^6.0.0" + }, + "bin": { + "node-gyp": "bin/node-gyp.js" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/nopt": { + "version": "9.0.0", + "inBundle": true, + "license": "ISC", + "dependencies": { + "abbrev": "^4.0.0" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/npm-audit-report": { + "version": "7.0.0", + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/npm-bundled": { + "version": "5.0.0", + "inBundle": true, + "license": "ISC", + "dependencies": { + "npm-normalize-package-bin": "^5.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/npm-install-checks": { + "version": "8.0.0", + "inBundle": true, + "license": "BSD-2-Clause", + "dependencies": { + "semver": "^7.1.1" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/npm-normalize-package-bin": { + "version": "5.0.0", + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/npm-package-arg": { + "version": "13.0.2", + "inBundle": true, + "license": "ISC", + "dependencies": { + "hosted-git-info": "^9.0.0", + "proc-log": "^6.0.0", + "semver": "^7.3.5", + "validate-npm-package-name": "^7.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/npm-packlist": { + "version": "10.0.4", + "inBundle": true, + "license": "ISC", + "dependencies": { + "ignore-walk": "^8.0.0", + "proc-log": "^6.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/npm-pick-manifest": { + "version": "11.0.3", + "inBundle": true, + "license": "ISC", + "dependencies": { + "npm-install-checks": "^8.0.0", + "npm-normalize-package-bin": "^5.0.0", + "npm-package-arg": "^13.0.0", + "semver": "^7.3.5" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/npm-profile": { + "version": "12.0.1", + "inBundle": true, + "license": "ISC", + "dependencies": { + "npm-registry-fetch": "^19.0.0", + "proc-log": "^6.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/npm-registry-fetch": { + "version": "19.1.1", + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/redact": "^4.0.0", + "jsonparse": "^1.3.1", + "make-fetch-happen": "^15.0.0", + "minipass": "^7.0.2", + "minipass-fetch": "^5.0.0", + "minizlib": "^3.0.1", + "npm-package-arg": "^13.0.0", + "proc-log": "^6.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/npm-user-validate": { + "version": "4.0.0", + "inBundle": true, + "license": "BSD-2-Clause", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/p-map": { + "version": "7.0.4", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm/node_modules/pacote": { + "version": "21.4.0", + "inBundle": true, + "license": "ISC", + "dependencies": { + "@gar/promise-retry": "^1.0.0", + "@npmcli/git": "^7.0.0", + "@npmcli/installed-package-contents": "^4.0.0", + "@npmcli/package-json": "^7.0.0", + "@npmcli/promise-spawn": "^9.0.0", + "@npmcli/run-script": "^10.0.0", + "cacache": "^20.0.0", + "fs-minipass": "^3.0.0", + "minipass": "^7.0.2", + "npm-package-arg": "^13.0.0", + "npm-packlist": "^10.0.1", + "npm-pick-manifest": "^11.0.1", + "npm-registry-fetch": "^19.0.0", + "proc-log": "^6.0.0", + "sigstore": "^4.0.0", + "ssri": "^13.0.0", + "tar": "^7.4.3" + }, + "bin": { + "pacote": "bin/index.js" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/parse-conflict-json": { + "version": "5.0.1", + "inBundle": true, + "license": "ISC", + "dependencies": { + "json-parse-even-better-errors": "^5.0.0", + "just-diff": "^6.0.0", + "just-diff-apply": "^5.2.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/path-scurry": { + "version": "2.0.2", + "inBundle": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm/node_modules/postcss-selector-parser": { + "version": "7.1.1", + "inBundle": true, + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npm/node_modules/proc-log": { + "version": "6.1.0", + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/proggy": { + "version": "4.0.0", + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/promise-all-reject-late": { + "version": "1.0.1", + "inBundle": true, + "license": "ISC", + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm/node_modules/promise-call-limit": { + "version": "3.0.2", + "inBundle": true, + "license": "ISC", + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm/node_modules/promise-retry": { + "version": "2.0.1", + "inBundle": true, + "license": "MIT", + "dependencies": { + "err-code": "^2.0.2", + "retry": "^0.12.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm/node_modules/promzard": { + "version": "3.0.1", + "inBundle": true, + "license": "ISC", + "dependencies": { + "read": "^5.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/qrcode-terminal": { + "version": "0.12.0", + "inBundle": true, + "bin": { + "qrcode-terminal": "bin/qrcode-terminal.js" + } + }, + "node_modules/npm/node_modules/read": { + "version": "5.0.1", + "inBundle": true, + "license": "ISC", + "dependencies": { + "mute-stream": "^3.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/read-cmd-shim": { + "version": "6.0.0", + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/retry": { + "version": "0.12.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/npm/node_modules/safer-buffer": { + "version": "2.1.2", + "inBundle": true, + "license": "MIT", + "optional": true + }, + "node_modules/npm/node_modules/semver": { + "version": "7.7.4", + "inBundle": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm/node_modules/signal-exit": { + "version": "4.1.0", + "inBundle": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm/node_modules/sigstore": { + "version": "4.1.0", + "inBundle": true, + "license": "Apache-2.0", + "dependencies": { + "@sigstore/bundle": "^4.0.0", + "@sigstore/core": "^3.1.0", + "@sigstore/protobuf-specs": "^0.5.0", + "@sigstore/sign": "^4.1.0", + "@sigstore/tuf": "^4.0.1", + "@sigstore/verify": "^3.1.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/smart-buffer": { + "version": "4.2.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/npm/node_modules/socks": { + "version": "2.8.7", + "inBundle": true, + "license": "MIT", + "dependencies": { + "ip-address": "^10.0.1", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/npm/node_modules/socks-proxy-agent": { + "version": "8.0.5", + "inBundle": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "^4.3.4", + "socks": "^2.8.3" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/npm/node_modules/spdx-exceptions": { + "version": "2.5.0", + "inBundle": true, + "license": "CC-BY-3.0" + }, + "node_modules/npm/node_modules/spdx-expression-parse": { + "version": "4.0.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/npm/node_modules/spdx-license-ids": { + "version": "3.0.23", + "inBundle": true, + "license": "CC0-1.0" + }, + "node_modules/npm/node_modules/ssri": { + "version": "13.0.1", + "inBundle": true, + "license": "ISC", + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/supports-color": { + "version": "10.2.2", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/npm/node_modules/tar": { + "version": "7.5.9", + "inBundle": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/fs-minipass": "^4.0.0", + "chownr": "^3.0.0", + "minipass": "^7.1.2", + "minizlib": "^3.1.0", + "yallist": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/npm/node_modules/text-table": { + "version": "0.2.0", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/tiny-relative-date": { + "version": "2.0.2", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/tinyglobby": { + "version": "0.2.15", + "inBundle": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/npm/node_modules/tinyglobby/node_modules/fdir": { + "version": "6.5.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/npm/node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.3", + "inBundle": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/npm/node_modules/treeverse": { + "version": "3.0.0", + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/tuf-js": { + "version": "4.1.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "@tufjs/models": "4.1.0", + "debug": "^4.4.3", + "make-fetch-happen": "^15.0.1" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/unique-filename": { + "version": "5.0.0", + "inBundle": true, + "license": "ISC", + "dependencies": { + "unique-slug": "^6.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/unique-slug": { + "version": "6.0.0", + "inBundle": true, + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/util-deprecate": { + "version": "1.0.2", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/validate-npm-package-name": { + "version": "7.0.2", + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/walk-up-path": { + "version": "4.0.0", + "inBundle": true, + "license": "ISC", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/npm/node_modules/which": { + "version": "6.0.1", + "inBundle": true, + "license": "ISC", + "dependencies": { + "isexe": "^4.0.0" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/write-file-atomic": { + "version": "7.0.0", + "inBundle": true, + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/yallist": { + "version": "5.0.0", + "inBundle": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/nypm": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/nypm/-/nypm-0.6.5.tgz", + "integrity": "sha512-K6AJy1GMVyfyMXRVB88700BJqNUkByijGJM8kEHpLdcAt+vSQAVfkWWHYzuRXHSY6xA2sNc5RjTj0p9rE2izVQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "citty": "^0.2.0", + "pathe": "^2.0.3", + "tinyexec": "^1.0.2" + }, + "bin": { + "nypm": "dist/cli.mjs" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/nypm/node_modules/citty": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/citty/-/citty-0.2.1.tgz", + "integrity": "sha512-kEV95lFBhQgtogAPlQfJJ0WGVSokvLr/UEoFPiKKOXF7pl98HfUVUD0ejsuTCld/9xH9vogSywZ5KqHzXrZpqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "*" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-is": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.6.tgz", + "integrity": "sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz", + "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0", + "has-symbols": "^1.1.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/observable-fns": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/observable-fns/-/observable-fns-0.6.1.tgz", + "integrity": "sha512-9gRK4+sRWzeN6AOewNBTLXir7Zl/i3GB6Yl26gK4flxz8BXVpD3kt8amREmWNb0mxYOGDotvE5a4N+PtGGKdkg==", + "dev": true, + "license": "MIT" + }, + "node_modules/obug": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.1.tgz", + "integrity": "sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==", + "funding": [ + "https://github.com/sponsors/sxzz", + "https://opencollective.com/debug" + ], + "license": "MIT" + }, + "node_modules/ohash": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/ohash/-/ohash-2.0.11.tgz", + "integrity": "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/on-exit-leak-free": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/on-exit-leak-free/-/on-exit-leak-free-2.1.2.tgz", + "integrity": "sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/open": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/open/-/open-11.0.0.tgz", + "integrity": "sha512-smsWv2LzFjP03xmvFoJ331ss6h+jixfA4UUV/Bsiyuu4YJPfN+FIQGOIiv4w9/+MoHkfkJ22UIaQWRVFRfH6Vw==", + "dev": true, + "license": "MIT", + "dependencies": { + "default-browser": "^5.4.0", + "define-lazy-prop": "^3.0.0", + "is-in-ssh": "^1.0.0", + "is-inside-container": "^1.0.0", + "powershell-utils": "^0.1.0", + "wsl-utils": "^0.3.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/openapi3-ts": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/openapi3-ts/-/openapi3-ts-4.5.0.tgz", + "integrity": "sha512-jaL+HgTq2Gj5jRcfdutgRGLosCy/hT8sQf6VOy+P+g36cZOjI1iukdPnijC+4CmeRzg/jEllJUboEic2FhxhtQ==", + "license": "MIT", + "dependencies": { + "yaml": "^2.8.0" + } + }, + "node_modules/ora": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora/node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/ora/node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/ora/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/ora/node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/os-browserify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.1.2.tgz", + "integrity": "sha512-aZicJZccvxWOZ0Bja2eAch2L8RIJWBuRYmM8Gwl/JjNtRltH0Itcz4eH/ESyuIWfse8cc93ZCf0XrzhXK2HEDA==", + "dev": true, + "license": "MIT" + }, + "node_modules/os-locale": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", + "integrity": "sha512-PRT7ZORmwu2MEFt4/fv3Q+mEfN4zetKxufQrkShY2oGvUms9r8otu5HfdyIFHkYXjO7laNsoVGmM2MANfuTA8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "lcid": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/p-cancelable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", + "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/package-json": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/package-json/-/package-json-6.5.0.tgz", + "integrity": "sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ==", + "license": "MIT", + "dependencies": { + "got": "^9.6.0", + "registry-auth-token": "^4.0.0", + "registry-url": "^5.0.0", + "semver": "^6.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "license": "BlueOak-1.0.0" + }, + "node_modules/package-json/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/pako": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz", + "integrity": "sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==", + "license": "MIT" + }, + "node_modules/parents": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parents/-/parents-1.0.1.tgz", + "integrity": "sha512-mXKF3xkoUt5td2DoxpLmtOmZvko9VfFpwRwkKDHSNvgmpLAeBo18YDhcPbBzJq+QLCHMbGOfzia2cX4U+0v9Mg==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-platform": "~0.11.15" + } + }, + "node_modules/parse-asn1": { + "version": "5.1.9", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.9.tgz", + "integrity": "sha512-fIYNuZ/HastSb80baGOuPRo1O9cf4baWw5WsAp7dBuUzeTD/BoaG8sVTdlPFksBE2lF21dN+A1AnrpIjSWqHHg==", + "dev": true, + "license": "ISC", + "dependencies": { + "asn1.js": "^4.10.1", + "browserify-aes": "^1.2.0", + "evp_bytestokey": "^1.0.3", + "pbkdf2": "^3.1.5", + "safe-buffer": "^5.2.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha512-QR/GGaKCkhwk1ePQNYDRKYZ3mwU9ypsKhB0XyFnLQdomyEqk3e8wpW3V5Jp88zbxK4n5ST1nqo+g9juTpownhQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "error-ex": "^1.2.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/parse5": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", + "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==", + "license": "MIT", + "dependencies": { + "entities": "^6.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parse5-htmlparser2-tree-adapter": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.1.0.tgz", + "integrity": "sha512-ruw5xyKs6lrpo9x9rCZqZZnIUntICjQAd0Wsmp396Ul9lN/h+ifgVV1x1gZHi8euej6wTfpqX8j+BFQxF0NS/g==", + "license": "MIT", + "dependencies": { + "domhandler": "^5.0.3", + "parse5": "^7.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parse5-parser-stream": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5-parser-stream/-/parse5-parser-stream-7.1.2.tgz", + "integrity": "sha512-JyeQc9iwFLn5TbvvqACIF/VXG6abODeB3Fwmv/TGdLk2LfbWkaySGY72at4+Ty7EkPZj854u4CrICqNk2qIbow==", + "license": "MIT", + "dependencies": { + "parse5": "^7.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parse5/node_modules/entities": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", + "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/path-browserify": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.1.tgz", + "integrity": "sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true, + "license": "MIT" + }, + "node_modules/path-platform": { + "version": "0.11.15", + "resolved": "https://registry.npmjs.org/path-platform/-/path-platform-0.11.15.tgz", + "integrity": "sha512-Y30dB6rab1A/nfEKsZxmr01nUotHX0c/ZiIAsCTatEe1CmS5Pm5He7fZ195bPT7RdquoaL8lLxFCMQi/bS7IJg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/path-scurry": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz", + "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==", + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-type": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", + "integrity": "sha512-S4eENJz1pkiQn9Znv33Q+deTOKmbl+jj1Fl+qiP/vYezj+S8x+J3Uo0ISrx/QoEvIlOaDWJhPaRd1flJ9HXZqg==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.1.2", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "license": "MIT" + }, + "node_modules/pbkdf2": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.5.tgz", + "integrity": "sha512-Q3CG/cYvCO1ye4QKkuH7EXxs3VC/rI1/trd+qX2+PolbaKG0H+bgcZzrTt96mMyRtejk+JMCiLUn3y29W8qmFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "ripemd160": "^2.0.3", + "safe-buffer": "^5.2.1", + "sha.js": "^2.4.12", + "to-buffer": "^1.2.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/pdfmake": { + "version": "0.2.23", + "resolved": "https://registry.npmjs.org/pdfmake/-/pdfmake-0.2.23.tgz", + "integrity": "sha512-A/IksoKb/ikOZH1edSDJ/2zBbqJKDghD4+fXn3rT7quvCJDlsZMs3NmIB3eajLMMFU9Bd3bZPVvlUMXhvFI+bQ==", + "license": "MIT", + "dependencies": { + "@foliojs-fork/linebreak": "^1.1.2", + "@foliojs-fork/pdfkit": "^0.15.3", + "iconv-lite": "^0.7.1", + "xmldoc": "^2.0.3" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/pdfmake/node_modules/iconv-lite": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz", + "integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/peek-stream": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/peek-stream/-/peek-stream-1.1.3.tgz", + "integrity": "sha512-FhJ+YbOSBb9/rIl2ZeE/QHEsWn7PqNYt8ARAY3kIgNGOk13g9FGyIY6JIl/xB/3TFRVoTv5as0l11weORrTekA==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "duplexify": "^3.5.0", + "through2": "^2.0.3" + } + }, + "node_modules/perfect-debounce": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-2.1.0.tgz", + "integrity": "sha512-LjgdTytVFXeUgtHZr9WYViYSM/g8MkcTPYDlPa3cDqMirHjKiSZPYd6DoL7pK8AJQr+uWkQvCjHNdiMqsrJs+g==", + "dev": true, + "license": "MIT" + }, + "node_modules/performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", + "dev": true, + "license": "MIT" + }, + "node_modules/pg": { + "version": "8.19.0", + "resolved": "https://registry.npmjs.org/pg/-/pg-8.19.0.tgz", + "integrity": "sha512-QIcLGi508BAHkQ3pJNptsFz5WQMlpGbuBGBaIaXsWK8mel2kQ/rThYI+DbgjUvZrIr7MiuEuc9LcChJoEZK1xQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "pg-connection-string": "^2.11.0", + "pg-pool": "^3.12.0", + "pg-protocol": "^1.12.0", + "pg-types": "2.2.0", + "pgpass": "1.0.5" + }, + "engines": { + "node": ">= 16.0.0" + }, + "optionalDependencies": { + "pg-cloudflare": "^1.3.0" + }, + "peerDependencies": { + "pg-native": ">=3.0.1" + }, + "peerDependenciesMeta": { + "pg-native": { + "optional": true + } + } + }, + "node_modules/pg-boss": { + "version": "12.13.0", + "resolved": "https://registry.npmjs.org/pg-boss/-/pg-boss-12.13.0.tgz", + "integrity": "sha512-xaMIXAEyYR4+OjCid7y4574b7fYeY59j//TWD1x6yMFsn9EV7TiRUtIKYRqXV68rJ12Guduvz3eTjBMRje+iUw==", + "license": "MIT", + "dependencies": { + "cron-parser": "^5.5.0", + "pg": "^8.18.0", + "serialize-error": "^13.0.1" + }, + "bin": { + "pg-boss": "dist/cli.js" + }, + "engines": { + "node": ">=22.12.0" + } + }, + "node_modules/pg-cloudflare": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.3.0.tgz", + "integrity": "sha512-6lswVVSztmHiRtD6I8hw4qP/nDm1EJbKMRhf3HCYaqud7frGysPv7FYJ5noZQdhQtN2xJnimfMtvQq21pdbzyQ==", + "license": "MIT", + "optional": true + }, + "node_modules/pg-connection-string": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.11.0.tgz", + "integrity": "sha512-kecgoJwhOpxYU21rZjULrmrBJ698U2RxXofKVzOn5UDj61BPj/qMb7diYUR1nLScCDbrztQFl1TaQZT0t1EtzQ==", + "license": "MIT" + }, + "node_modules/pg-int8": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", + "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==", + "license": "ISC", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/pg-pool": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.12.0.tgz", + "integrity": "sha512-eIJ0DES8BLaziFHW7VgJEBPi5hg3Nyng5iKpYtj3wbcAUV9A1wLgWiY7ajf/f/oO1wfxt83phXPY8Emztg7ITg==", + "license": "MIT", + "peerDependencies": { + "pg": ">=8.0" + } + }, + "node_modules/pg-protocol": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.12.0.tgz", + "integrity": "sha512-uOANXNRACNdElMXJ0tPz6RBM0XQ61nONGAwlt8da5zs/iUOOCLBQOHSXnrC6fMsvtjxbOJrZZl5IScGv+7mpbg==", + "license": "MIT" + }, + "node_modules/pg-types": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", + "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", + "license": "MIT", + "dependencies": { + "pg-int8": "1.0.1", + "postgres-array": "~2.0.0", + "postgres-bytea": "~1.0.0", + "postgres-date": "~1.0.4", + "postgres-interval": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pgpass": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz", + "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==", + "license": "MIT", + "dependencies": { + "split2": "^4.1.0" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "pinkie": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pino": { + "version": "10.3.1", + "resolved": "https://registry.npmjs.org/pino/-/pino-10.3.1.tgz", + "integrity": "sha512-r34yH/GlQpKZbU1BvFFqOjhISRo1MNx1tWYsYvmj6KIRHSPMT2+yHOEb1SG6NMvRoHRF0a07kCOox/9yakl1vg==", + "license": "MIT", + "dependencies": { + "@pinojs/redact": "^0.4.0", + "atomic-sleep": "^1.0.0", + "on-exit-leak-free": "^2.1.0", + "pino-abstract-transport": "^3.0.0", + "pino-std-serializers": "^7.0.0", + "process-warning": "^5.0.0", + "quick-format-unescaped": "^4.0.3", + "real-require": "^0.2.0", + "safe-stable-stringify": "^2.3.1", + "sonic-boom": "^4.0.1", + "thread-stream": "^4.0.0" + }, + "bin": { + "pino": "bin.js" + } + }, + "node_modules/pino-abstract-transport": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-3.0.0.tgz", + "integrity": "sha512-wlfUczU+n7Hy/Ha5j9a/gZNy7We5+cXp8YL+X+PG8S0KXxw7n/JXA3c46Y0zQznIJ83URJiwy7Lh56WLokNuxg==", + "license": "MIT", + "dependencies": { + "split2": "^4.0.0" + } + }, + "node_modules/pino-pretty": { + "version": "13.1.3", + "resolved": "https://registry.npmjs.org/pino-pretty/-/pino-pretty-13.1.3.tgz", + "integrity": "sha512-ttXRkkOz6WWC95KeY9+xxWL6AtImwbyMHrL1mSwqwW9u+vLp/WIElvHvCSDg0xO/Dzrggz1zv3rN5ovTRVowKg==", + "dev": true, + "license": "MIT", + "dependencies": { + "colorette": "^2.0.7", + "dateformat": "^4.6.3", + "fast-copy": "^4.0.0", + "fast-safe-stringify": "^2.1.1", + "help-me": "^5.0.0", + "joycon": "^3.1.1", + "minimist": "^1.2.6", + "on-exit-leak-free": "^2.1.0", + "pino-abstract-transport": "^3.0.0", + "pump": "^3.0.0", + "secure-json-parse": "^4.0.0", + "sonic-boom": "^4.0.1", + "strip-json-comments": "^5.0.2" + }, + "bin": { + "pino-pretty": "bin.js" + } + }, + "node_modules/pino-std-serializers": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-7.1.0.tgz", + "integrity": "sha512-BndPH67/JxGExRgiX1dX0w1FvZck5Wa4aal9198SrRhZjH3GxKQUKIBnYJTdj2HDN3UQAS06HlfcSbQj2OHmaw==", + "license": "MIT" + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-types": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.3.0.tgz", + "integrity": "sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==", + "dev": true, + "license": "MIT", + "dependencies": { + "confbox": "^0.2.2", + "exsolve": "^1.0.7", + "pathe": "^2.0.3" + } + }, + "node_modules/pluralize": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", + "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/png-js": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/png-js/-/png-js-1.0.0.tgz", + "integrity": "sha512-k+YsbhpA9e+EFfKjTCH3VW6aoKlyNYI6NYdTfDL4CIvFnvsuO84ttonmZE7rc+v23SLTH8XX+5w/Ak9v0xGY4g==" + }, + "node_modules/possible-typed-array-names": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", + "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/postcss": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss/node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/postgres-array": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", + "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/postgres-bytea": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.1.tgz", + "integrity": "sha512-5+5HqXnsZPE65IJZSMkZtURARZelel2oXUEO8rH83VS/hxH5vv1uHquPg5wZs8yMAfdv971IU+kcPUczi7NVBQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-date": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", + "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-interval": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", + "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", + "license": "MIT", + "dependencies": { + "xtend": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/powershell-utils": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/powershell-utils/-/powershell-utils-0.1.0.tgz", + "integrity": "sha512-dM0jVuXJPsDN6DvRpea484tCUaMiXWjuCn++HGTqUWzGDjv5tZkEZldAJ/UMlqRYGFrD/etByo4/xOuC/snX2A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/prepend-http": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", + "integrity": "sha512-ravE6m9Atw9Z/jjttRUZ+clIXogdghyZAuWJ3qEzjT+jI/dL1ifAqhZeC5VHzQp1MSt1+jxKkFNemj/iO7tVUA==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/prettier": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz", + "integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "license": "MIT", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true, + "license": "MIT" + }, + "node_modules/process-warning": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-5.0.0.tgz", + "integrity": "sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "MIT" + }, + "node_modules/progress": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/progress/-/progress-1.1.8.tgz", + "integrity": "sha512-UdA8mJ4weIkUBO224tIarHzuHs4HuYiJvsuGT7j/SPQiUJVjYvNDBIPa0hAorduOfjGohB/qHWRa/lrrWX/mXw==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/proto-list": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", + "integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==", + "license": "ISC" + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "license": "MIT" + }, + "node_modules/psl": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.15.0.tgz", + "integrity": "sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "punycode": "^2.3.1" + }, + "funding": { + "url": "https://github.com/sponsors/lupomontero" + } + }, + "node_modules/psl/node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/public-encrypt": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", + "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "bn.js": "^4.1.0", + "browserify-rsa": "^4.0.0", + "create-hash": "^1.1.0", + "parse-asn1": "^5.0.0", + "randombytes": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/public-encrypt/node_modules/bn.js": { + "version": "4.12.3", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.3.tgz", + "integrity": "sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==", + "dev": true, + "license": "MIT" + }, + "node_modules/pump": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.3.tgz", + "integrity": "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==", + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/pumpify": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", + "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "duplexify": "^3.6.0", + "inherits": "^2.0.3", + "pump": "^2.0.0" + } + }, + "node_modules/pumpify/node_modules/pump": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", + "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", + "dev": true, + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/pupa": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/pupa/-/pupa-2.1.1.tgz", + "integrity": "sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A==", + "license": "MIT", + "dependencies": { + "escape-goat": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/qs": { + "version": "6.5.5", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.5.tgz", + "integrity": "sha512-mzR4sElr1bfCaPJe7m8ilJ6ZXdDaGoObcYR0ZHSsktM/Lt21MVHj5De30GQH2eiZ1qGRTO7LCAzQsUeXTNexWQ==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/querystring-es3": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", + "integrity": "sha512-773xhDQnZBMFobEiztv8LIl70ch5MSF/jUQVlhwFyBILqq96anmoctVIYz+ZRp0qbCKATTn6ev02M3r7Ga5vqA==", + "dev": true, + "engines": { + "node": ">=0.4.x" + } + }, + "node_modules/quick-format-unescaped": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz", + "integrity": "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==", + "license": "MIT" + }, + "node_modules/quicktype-core": { + "version": "23.2.6", + "resolved": "https://registry.npmjs.org/quicktype-core/-/quicktype-core-23.2.6.tgz", + "integrity": "sha512-asfeSv7BKBNVb9WiYhFRBvBZHcRutPRBwJMxW0pefluK4kkKu4lv0IvZBwFKvw2XygLcL1Rl90zxWDHYgkwCmA==", + "license": "Apache-2.0", + "dependencies": { + "@glideapps/ts-necessities": "2.2.3", + "browser-or-node": "^3.0.0", + "collection-utils": "^1.0.1", + "cross-fetch": "^4.0.0", + "is-url": "^1.2.4", + "js-base64": "^3.7.7", + "lodash": "^4.17.21", + "pako": "^1.0.6", + "pluralize": "^8.0.0", + "readable-stream": "4.5.2", + "unicode-properties": "^1.4.1", + "urijs": "^1.19.1", + "wordwrap": "^1.0.0", + "yaml": "^2.4.1" + } + }, + "node_modules/quicktype-core/node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/quicktype-core/node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "license": "MIT", + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/quicktype-core/node_modules/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "license": "(MIT AND Zlib)" + }, + "node_modules/quicktype-core/node_modules/readable-stream": { + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.5.2.tgz", + "integrity": "sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g==", + "license": "MIT", + "dependencies": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/quicktype-core/node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/randomfill": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", + "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", + "dev": true, + "license": "MIT", + "dependencies": { + "randombytes": "^2.0.5", + "safe-buffer": "^5.1.0" + } + }, + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/rc/node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/rc9": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/rc9/-/rc9-2.1.2.tgz", + "integrity": "sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg==", + "dev": true, + "license": "MIT", + "dependencies": { + "defu": "^6.1.4", + "destr": "^2.0.3" + } + }, + "node_modules/read-only-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-only-stream/-/read-only-stream-2.0.0.tgz", + "integrity": "sha512-3ALe0bjBVZtkdWKIcThYpQCLbBMd/+Tbh2CDSrAIDO3UsZ4Xs+tnyjv2MjCOMMgBG+AsUOeuP1cgtY1INISc8w==", + "dev": true, + "license": "MIT", + "dependencies": { + "readable-stream": "^2.0.2" + } + }, + "node_modules/read-pkg": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", + "integrity": "sha512-7BGwRHqt4s/uVbuyoeejRn4YmFnYZiFl4AuaeXHlgZf3sONF0SOGlxs2Pw8g6hCKupo08RafIO5YXFNOKTfwsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "load-json-file": "^1.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/read-pkg-up": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", + "integrity": "sha512-WD9MTlNtI55IwYUS27iHh9tK3YoIVhxis8yKhLpTqWtml739uXc9NWTpxoHkfZf3+DkCCsXox94/VWZniuZm6A==", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^1.0.0", + "read-pkg": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/read-pkg-up/node_modules/find-up": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha512-jvElSjyuo4EMQGoTwo1uJU5pQMwTW5lS1x05zzfJuTIyLR3zwO27LYrxNg+dlvKpGOuGy/MzBdXh80g0ve5+HA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-exists": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/read-pkg-up/node_modules/path-exists": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha512-yTltuKuhtNeFJKa1PiRzfLAU5182q1y4Eb4XCJ3PBqyzEDkAZRzBrKKBct682ls9reBVHf9udYLN5Nd+K1B9BQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "pinkie-promise": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/readable-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true, + "license": "MIT" + }, + "node_modules/readable-stream/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/readdirp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz", + "integrity": "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==", + "license": "MIT", + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/real-require": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/real-require/-/real-require-0.2.0.tgz", + "integrity": "sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==", + "license": "MIT", + "engines": { + "node": ">= 12.13.0" + } + }, + "node_modules/rechoir": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz", + "integrity": "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve": "^1.20.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", + "integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "set-function-name": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/registry-auth-token": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.2.tgz", + "integrity": "sha512-PC5ZysNb42zpFME6D/XlIgtNGdTl8bBOCw90xQLVMpzuuubJKYDWFAEuUNc+Cn8Z8724tg2SDhDRrkVEsqfDMg==", + "license": "MIT", + "dependencies": { + "rc": "1.2.8" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/registry-url": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-5.1.0.tgz", + "integrity": "sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==", + "license": "MIT", + "dependencies": { + "rc": "^1.2.8" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/request": { + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", + "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/request/node_modules/form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 0.12" + } + }, + "node_modules/request/node_modules/uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "dev": true, + "license": "MIT", + "bin": { + "uuid": "bin/uuid" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-main-filename": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", + "integrity": "sha512-IqSUtOVP4ksd1C/ej5zeEh/BIP2ajqpn8c5x+q99gvcIG/Qf0cud5raVnE/Dwd0ua9TXYDoDc0RE5hBSdz22Ug==", + "dev": true, + "license": "ISC" + }, + "node_modules/resolve": { + "version": "1.22.11", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", + "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "devOptional": true, + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/responselike": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", + "integrity": "sha512-/Fpe5guzJk1gPqdJLJR5u7eG/gNY4nImjbRDaVWVMRhne55TCmj2i9Q+54PBRfatRC8v/rIiv9BN0pMd9OV5EQ==", + "license": "MIT", + "dependencies": { + "lowercase-keys": "^1.0.0" + } + }, + "node_modules/restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/ripemd160": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.3.tgz", + "integrity": "sha512-5Di9UC0+8h1L6ZD2d7awM7E/T4uA1fJRlx6zk/NvdCCVEoAnFqvHmCuNeIKoCeIixBX/q8uM+6ycDvF8woqosA==", + "dev": true, + "license": "MIT", + "dependencies": { + "hash-base": "^3.1.2", + "inherits": "^2.0.4" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/ripemd160/node_modules/hash-base": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.2.tgz", + "integrity": "sha512-Bb33KbowVTIj5s7Ked1OsqHUeCpz//tPwR+E2zJgJKo9Z5XolZ9b6bdUgjmYlwnWhoOQKoTd1TYToZGn5mAYOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.4", + "readable-stream": "^2.3.8", + "safe-buffer": "^5.2.1", + "to-buffer": "^1.2.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/rollup": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.59.0.tgz", + "integrity": "sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==", + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.59.0", + "@rollup/rollup-android-arm64": "4.59.0", + "@rollup/rollup-darwin-arm64": "4.59.0", + "@rollup/rollup-darwin-x64": "4.59.0", + "@rollup/rollup-freebsd-arm64": "4.59.0", + "@rollup/rollup-freebsd-x64": "4.59.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.59.0", + "@rollup/rollup-linux-arm-musleabihf": "4.59.0", + "@rollup/rollup-linux-arm64-gnu": "4.59.0", + "@rollup/rollup-linux-arm64-musl": "4.59.0", + "@rollup/rollup-linux-loong64-gnu": "4.59.0", + "@rollup/rollup-linux-loong64-musl": "4.59.0", + "@rollup/rollup-linux-ppc64-gnu": "4.59.0", + "@rollup/rollup-linux-ppc64-musl": "4.59.0", + "@rollup/rollup-linux-riscv64-gnu": "4.59.0", + "@rollup/rollup-linux-riscv64-musl": "4.59.0", + "@rollup/rollup-linux-s390x-gnu": "4.59.0", + "@rollup/rollup-linux-x64-gnu": "4.59.0", + "@rollup/rollup-linux-x64-musl": "4.59.0", + "@rollup/rollup-openbsd-x64": "4.59.0", + "@rollup/rollup-openharmony-arm64": "4.59.0", + "@rollup/rollup-win32-arm64-msvc": "4.59.0", + "@rollup/rollup-win32-ia32-msvc": "4.59.0", + "@rollup/rollup-win32-x64-gnu": "4.59.0", + "@rollup/rollup-win32-x64-msvc": "4.59.0", + "fsevents": "~2.3.2" + } + }, + "node_modules/run-applescript": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.1.0.tgz", + "integrity": "sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/run-async": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", + "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/rxjs": { + "version": "7.8.2", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", + "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safe-stable-stringify": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", + "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, + "node_modules/sax": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.4.tgz", + "integrity": "sha512-1n3r/tGXO6b6VXMdFT54SHzT9ytu9yr7TaELowdYpMqY/Ao7EnlQGmAQ1+RatX7Tkkdm6hONI2owqNx2aZj5Sw==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=11.0.0" + } + }, + "node_modules/schema-utils": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.3.tgz", + "integrity": "sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/schema-utils/node_modules/ajv": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", + "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/schema-utils/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/schema-utils/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT" + }, + "node_modules/secure-json-parse": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/secure-json-parse/-/secure-json-parse-4.1.0.tgz", + "integrity": "sha512-l4KnYfEyqYJxDwlNVyRfO2E4NTHfMKAWdUuA8J0yve2Dz/E/PdBepY03RvyJpssIpRFwJoCD55wA+mEDs6ByWA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver-diff": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-3.1.1.tgz", + "integrity": "sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==", + "license": "MIT", + "dependencies": { + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/semver-diff/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/serialize-error": { + "version": "13.0.1", + "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-13.0.1.tgz", + "integrity": "sha512-bBZaRwLH9PN5HbLCjPId4dP5bNGEtumcErgOX952IsvOhVPrm3/AeK1y0UHA/QaPG701eg0yEnOKsCOC6X/kaA==", + "license": "MIT", + "dependencies": { + "non-error": "^0.1.0", + "type-fest": "^5.4.1" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/serialize-javascript": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "dev": true, + "license": "ISC" + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-function-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/sha.js": { + "version": "2.4.12", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.12.tgz", + "integrity": "sha512-8LzC5+bvI45BjpfXU8V5fdU2mfeKiQe1D1gIMn7XUlF3OTUrpdJpPPH4EMAnF0DsHHdSZqCdSss5qCmJKuiO3w==", + "dev": true, + "license": "(MIT AND BSD-3-Clause)", + "dependencies": { + "inherits": "^2.0.4", + "safe-buffer": "^5.2.1", + "to-buffer": "^1.2.0" + }, + "bin": { + "sha.js": "bin.js" + }, + "engines": { + "node": ">= 0.10" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "license": "MIT", + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/sharp": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.5.tgz", + "integrity": "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==", + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@img/colour": "^1.0.0", + "detect-libc": "^2.1.2", + "semver": "^7.7.3" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-darwin-arm64": "0.34.5", + "@img/sharp-darwin-x64": "0.34.5", + "@img/sharp-libvips-darwin-arm64": "1.2.4", + "@img/sharp-libvips-darwin-x64": "1.2.4", + "@img/sharp-libvips-linux-arm": "1.2.4", + "@img/sharp-libvips-linux-arm64": "1.2.4", + "@img/sharp-libvips-linux-ppc64": "1.2.4", + "@img/sharp-libvips-linux-riscv64": "1.2.4", + "@img/sharp-libvips-linux-s390x": "1.2.4", + "@img/sharp-libvips-linux-x64": "1.2.4", + "@img/sharp-libvips-linuxmusl-arm64": "1.2.4", + "@img/sharp-libvips-linuxmusl-x64": "1.2.4", + "@img/sharp-linux-arm": "0.34.5", + "@img/sharp-linux-arm64": "0.34.5", + "@img/sharp-linux-ppc64": "0.34.5", + "@img/sharp-linux-riscv64": "0.34.5", + "@img/sharp-linux-s390x": "0.34.5", + "@img/sharp-linux-x64": "0.34.5", + "@img/sharp-linuxmusl-arm64": "0.34.5", + "@img/sharp-linuxmusl-x64": "0.34.5", + "@img/sharp-wasm32": "0.34.5", + "@img/sharp-win32-arm64": "0.34.5", + "@img/sharp-win32-ia32": "0.34.5", + "@img/sharp-win32-x64": "0.34.5" + } + }, + "node_modules/shasum": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/shasum/-/shasum-1.0.2.tgz", + "integrity": "sha512-UTzHm/+AzKfO9RgPgRpDIuMSNie1ubXRaljjlhFMNGYoG7z+rm9AHLPMf70R7887xboDH9Q+5YQbWKObFHEAtw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-stable-stringify": "~0.0.0", + "sha.js": "~2.4.4" + } + }, + "node_modules/shasum-object": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/shasum-object/-/shasum-object-1.0.1.tgz", + "integrity": "sha512-SsC+1tW7XKQ/94D4k1JhLmjDFpVGET/Nf54jVDtbavbALf8Zhp0Td9zTlxScjMW6nbEIrpADtPWfLk9iCXzHDQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "fast-safe-stringify": "^2.0.7" + }, + "bin": { + "shasum-object": "bin.js" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/shell-quote": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.3.tgz", + "integrity": "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/siginfo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "dev": true, + "license": "ISC" + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "license": "ISC" + }, + "node_modules/simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/sirv": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/sirv/-/sirv-3.0.2.tgz", + "integrity": "sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@polka/url": "^1.0.0-next.24", + "mrmime": "^2.0.0", + "totalist": "^3.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/slash": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz", + "integrity": "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/slick": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/slick/-/slick-1.12.2.tgz", + "integrity": "sha512-4qdtOGcBjral6YIBCWJ0ljFSKNLz9KkhbWtuGvUyRowl1kxfuE1x/Z/aJcaiilpb3do9bl5K7/1h9XC5wWpY/A==", + "license": "MIT (http://mootools.net/license.txt)", + "engines": { + "node": "*" + } + }, + "node_modules/sonic-boom": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-4.2.1.tgz", + "integrity": "sha512-w6AxtubXa2wTXAUsZMMWERrsIRAdrK0Sc+FUytWvYAhBJLyuI4llrMIC1DtlNSdI99EI86KZum2MMq3EAZlF9Q==", + "license": "MIT", + "dependencies": { + "atomic-sleep": "^1.0.0" + } + }, + "node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/source-map-support/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "devOptional": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/spdx-correct": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", + "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", + "dev": true, + "license": "CC-BY-3.0" + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.23", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.23.tgz", + "integrity": "sha512-CWLcCCH7VLu13TgOH+r8p1O/Znwhqv/dbb6lqWy67G+pT1kHmeD/+V36AVb/vq8QMIQwVShJ6Ssl5FPh0fuSdw==", + "dev": true, + "license": "CC0-1.0" + }, + "node_modules/split2": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", + "license": "ISC", + "engines": { + "node": ">= 10.x" + } + }, + "node_modules/sshpk": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.18.0.tgz", + "integrity": "sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + }, + "bin": { + "sshpk-conv": "bin/sshpk-conv", + "sshpk-sign": "bin/sshpk-sign", + "sshpk-verify": "bin/sshpk-verify" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/stackback": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", + "dev": true, + "license": "MIT" + }, + "node_modules/std-env": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz", + "integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==", + "dev": true, + "license": "MIT" + }, + "node_modules/stream-browserify": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz", + "integrity": "sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "~2.0.1", + "readable-stream": "^2.0.2" + } + }, + "node_modules/stream-combiner2": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/stream-combiner2/-/stream-combiner2-1.1.1.tgz", + "integrity": "sha512-3PnJbYgS56AeWgtKF5jtJRT6uFJe56Z0Hc5Ngg/6sI6rIt8iiMBTa9cvdyFfpMQjaVHr8dusbNeFGIIonxOvKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "duplexer2": "~0.1.0", + "readable-stream": "^2.0.2" + } + }, + "node_modules/stream-http": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.8.3.tgz", + "integrity": "sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "builtin-status-codes": "^3.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.3.6", + "to-arraybuffer": "^1.0.0", + "xtend": "^4.0.0" + } + }, + "node_modules/stream-shift": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.3.tgz", + "integrity": "sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/stream-splicer": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/stream-splicer/-/stream-splicer-2.0.1.tgz", + "integrity": "sha512-Xizh4/NPuYSyAXyT7g8IvdJ9HJpxIGL9PjyhtywCZvvP0OPIdqyrr4dMikeuvY8xahpdKEBlBTySe583totajg==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.2" + } + }, + "node_modules/string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", + "license": "MIT" + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "integrity": "sha512-kwrX1y7czp1E69n2ajbG65mIo9dqvJ+8aBQXOGVxqwvNbsXdFM6Lq37dLAY3mknUwru8CfcCbfOLL/gMo+fi3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-utf8": "^0.2.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strip-json-comments": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-5.0.3.tgz", + "integrity": "sha512-1tB5mhVo7U+ETBKNf92xT4hrQa3pm0MZ0PQvuDnWgAAGHDsfp4lPSpiS6psrSiet87wyGPh9ft6wmhOMQ0hDiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/stripe": { + "version": "20.4.0", + "resolved": "https://registry.npmjs.org/stripe/-/stripe-20.4.0.tgz", + "integrity": "sha512-F/aN1IQ9vHmlyLNi3DkiIbyzQb6gyBG0uYFd/VrEVQSc9BLtlgknPUx0EvzZdBMRLFuRaPFIFd7Mxwtg7Pbwzw==", + "license": "MIT", + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "@types/node": ">=16" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/subarg": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/subarg/-/subarg-1.0.0.tgz", + "integrity": "sha512-RIrIdRY0X1xojthNcVtgT9sjpOGagEUKpZdgBUi054OEPFo282yg+zE+t1Rj3+RqKq2xStL7uUHhY+AjbC4BXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.1.0" + } + }, + "node_modules/supazod": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/supazod/-/supazod-4.5.0.tgz", + "integrity": "sha512-dauwTgAtHsglzikstwagcNH75YFucuSyNVIqCYe2+0sYP6e+UFgLULWorNj3T0VZNLsaiZ0Ve0wKTWx46SKLaQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "case": "1.6.3", + "commander": "^12.0.0", + "prettier": "3.2.5", + "slash": "^5.1.0", + "ts-to-zod": "4.0.0", + "typescript": "5.3.3", + "zod": "^4.1.11" + }, + "bin": { + "supazod": "dist/cli.js" + } + }, + "node_modules/supazod/node_modules/commander": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", + "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/supazod/node_modules/typescript": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", + "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/swagger-typescript-codegen": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/swagger-typescript-codegen/-/swagger-typescript-codegen-3.2.4.tgz", + "integrity": "sha512-IEBRPd/Su5AggaHXtGsxJ3gyJU7k4QDb3UN5HziRMNK7ykZnJcwpvh55HOZpH5RBL2XW1DHJuNZs7P+2PUaUHw==", + "license": "Apache-2.0", + "dependencies": { + "commander": "^2.19.0", + "js-beautify": "^1.8.9", + "jshint": "^2.9.7", + "lodash": "^4.17.19", + "mustache": "^3.0.1", + "update-notifier": "^4.1.0" + }, + "bin": { + "swagger2ts": "bin/swagger2ts.js" + } + }, + "node_modules/swagger-typescript-codegen/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "license": "MIT" + }, + "node_modules/syntax-error": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/syntax-error/-/syntax-error-1.4.0.tgz", + "integrity": "sha512-YPPlu67mdnHGTup2A8ff7BC2Pjq0e0Yp/IyTFN03zWO0RcK07uLcbi7C2KpGR2FvWbaB0+bfE27a+sBKebSo7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn-node": "^1.2.0" + } + }, + "node_modules/tagged-tag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/tagged-tag/-/tagged-tag-1.0.0.tgz", + "integrity": "sha512-yEFYrVhod+hdNyx7g5Bnkkb0G6si8HJurOoOEgC8B/O0uXLHlaey/65KRv6cuWBNhBgHKAROVpc7QyYqE5gFng==", + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/tapable": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz", + "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/tar-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.2.tgz", + "integrity": "sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A==", + "dev": true, + "license": "MIT", + "dependencies": { + "bl": "^1.0.0", + "buffer-alloc": "^1.2.0", + "end-of-stream": "^1.0.0", + "fs-constants": "^1.0.0", + "readable-stream": "^2.3.0", + "to-buffer": "^1.1.1", + "xtend": "^4.0.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/term-size": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/term-size/-/term-size-2.2.1.tgz", + "integrity": "sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==", + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/terser": { + "version": "5.46.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.46.0.tgz", + "integrity": "sha512-jTwoImyr/QbOWFFso3YoU3ik0jBBDJ6JTOQiy/J2YxVJdZCc+5u7skhNwiOR3FQIygFqVUPHl7qbbxtjW2K3Qg==", + "devOptional": true, + "license": "BSD-2-Clause", + "peer": true, + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.15.0", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser-webpack-plugin": { + "version": "5.3.16", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.16.tgz", + "integrity": "sha512-h9oBFCWrq78NyWWVcSwZarJkZ01c2AyGrzs1crmHZO3QUg9D61Wu4NPjBy69n7JqylFF5y+CsUZYmYEIZ3mR+Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.25", + "jest-worker": "^27.4.5", + "schema-utils": "^4.3.0", + "serialize-javascript": "^6.0.2", + "terser": "^5.31.1" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "uglify-js": { + "optional": true + } + } + }, + "node_modules/terser/node_modules/acorn": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", + "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", + "devOptional": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/terser/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/thread-stream": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/thread-stream/-/thread-stream-4.0.0.tgz", + "integrity": "sha512-4iMVL6HAINXWf1ZKZjIPcz5wYaOdPhtO8ATvZ+Xqp3BTdaqtAwQkNmKORqcIo5YkQqGXq5cwfswDwMqqQNrpJA==", + "license": "MIT", + "dependencies": { + "real-require": "^0.2.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/threads": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/threads/-/threads-1.7.0.tgz", + "integrity": "sha512-Mx5NBSHX3sQYR6iI9VYbgHKBLisyB+xROCBGjjWm1O9wb9vfLxdaGtmT/KCjUqMsSNW6nERzCW3T6H43LqjDZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.1.0", + "debug": "^4.2.0", + "is-observable": "^2.1.0", + "observable-fns": "^0.6.1" + }, + "funding": { + "url": "https://github.com/andywer/threads.js?sponsor=1" + }, + "optionalDependencies": { + "tiny-worker": ">= 2" + } + }, + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", + "dev": true, + "license": "MIT" + }, + "node_modules/through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "node_modules/timers-browserify": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-1.4.2.tgz", + "integrity": "sha512-PIxwAupJZiYU4JmVZYwXp9FKsHMXb5h0ZEFyuXTAn8WLHOlcij+FEcbrvDsom1o5dr1YggEtFbECvGCW2sT53Q==", + "dev": true, + "dependencies": { + "process": "~0.11.0" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/tiny-inflate": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-inflate/-/tiny-inflate-1.0.3.tgz", + "integrity": "sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==", + "license": "MIT" + }, + "node_modules/tiny-worker": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tiny-worker/-/tiny-worker-2.3.0.tgz", + "integrity": "sha512-pJ70wq5EAqTAEl9IkGzA+fN0836rycEuz2Cn6yeZ6FRzlVS5IDOkFHpIoEsksPRQV34GDqXm65+OlnZqUSyK2g==", + "dev": true, + "license": "BSD-3-Clause", + "optional": true, + "dependencies": { + "esm": "^3.2.25" + } + }, + "node_modules/tinybench": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", + "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyexec": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.2.tgz", + "integrity": "sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyrainbow": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.0.3.tgz", + "integrity": "sha512-PSkbLUoxOFRzJYjjxHJt9xro7D+iilgMX/C9lawzVuYiIdcihh9DXmVibBe8lmcFrRi/VzlPjBxbN7rH24q8/Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/to-arraybuffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz", + "integrity": "sha512-okFlQcoGTi4LQBG/PgSYblw9VOyptsz2KJZqc6qtgGdes8VktzUQkj4BI2blit072iS8VODNcMA+tvnS9dnuMA==", + "dev": true, + "license": "MIT" + }, + "node_modules/to-buffer": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.2.2.tgz", + "integrity": "sha512-db0E3UJjcFhpDhAF4tLo03oli3pwl3dbnzXOUIlRKrp+ldk/VUxzpWYZENsw2SZiuBjHAk7DfB0VU7NKdpb6sw==", + "dev": true, + "license": "MIT", + "dependencies": { + "isarray": "^2.0.5", + "safe-buffer": "^5.2.1", + "typed-array-buffer": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/to-buffer/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true, + "license": "MIT" + }, + "node_modules/to-readable-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz", + "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/totalist": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", + "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/tough-cookie/node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "license": "MIT" + }, + "node_modules/ts-to-zod": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/ts-to-zod/-/ts-to-zod-4.0.0.tgz", + "integrity": "sha512-Ri8lPNxJlB/tbkEN8G/apaCM+Fg1vFB+l1TyC9q8YYRqOUvUOIGDgfrUKrKSlNXp63gtD6RJ8DI+eOe8lJYELA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@oclif/core": ">=3.26.0", + "@typescript/vfs": "^1.5.0", + "case": "^1.6.3", + "chokidar": "^3.5.1", + "fs-extra": "^11.1.1", + "inquirer": "^8.2.0", + "lodash": "^4.17.21", + "ora": "^5.4.0", + "prettier": "3.0.3", + "rxjs": "^7.4.0", + "slash": "^3.0.0", + "threads": "^1.7.0", + "tslib": "^2.3.1", + "tsutils": "^3.21.0", + "typescript": "^5.2.2", + "zod": "^4.1.5" + }, + "bin": { + "ts-to-zod": "bin/run" + } + }, + "node_modules/ts-to-zod/node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/ts-to-zod/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/ts-to-zod/node_modules/prettier": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.0.3.tgz", + "integrity": "sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/ts-to-zod/node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/ts-to-zod/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/tsconfck": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/tsconfck/-/tsconfck-3.1.6.tgz", + "integrity": "sha512-ks6Vjr/jEw0P1gmOVwutM3B7fWxoWBL2KRDb1JfqGVawBmO5UsvmWOQFGHBPl5yxYz4eERr19E6L7NMv+Fej4w==", + "dev": true, + "license": "MIT", + "bin": { + "tsconfck": "bin/tsconfck.js" + }, + "engines": { + "node": "^18 || >=20" + }, + "peerDependencies": { + "typescript": "^5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^1.8.1" + }, + "engines": { + "node": ">= 6" + }, + "peerDependencies": { + "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" + } + }, + "node_modules/tsutils/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true, + "license": "0BSD" + }, + "node_modules/tsx": { + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz", + "integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==", + "devOptional": true, + "license": "MIT", + "peer": true, + "dependencies": { + "esbuild": "~0.27.0", + "get-tsconfig": "^4.7.5" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, + "node_modules/tty-browserify": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.1.tgz", + "integrity": "sha512-C3TaO7K81YvjCgQH9Q1S3R3P3BtN3RIM8n+OvX4il1K1zgE8ZhI0op7kClgkxtutIE8hQrcrHBXvIheqKUUCxw==", + "dev": true, + "license": "MIT" + }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", + "dev": true, + "license": "Unlicense" + }, + "node_modules/type-fest": { + "version": "5.4.4", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-5.4.4.tgz", + "integrity": "sha512-JnTrzGu+zPV3aXIUhnyWJj4z/wigMsdYajGLIYakqyOW1nPllzXEJee0QQbHj+CTIQtXGlAjuK0UY+2xTyjVAw==", + "license": "(MIT OR CC0-1.0)", + "dependencies": { + "tagged-tag": "^1.0.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typed-array-buffer": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", + "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typedarray": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.7.tgz", + "integrity": "sha512-ueeb9YybpjhivjbHP2LdFDAjbS948fGEPj+ACAMs4xCMmh72OCOMQWBQKlaN4ZNQ04yfLSDLSx1tGRIoWimObQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "license": "MIT", + "dependencies": { + "is-typedarray": "^1.0.0" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/umd": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/umd/-/umd-3.0.3.tgz", + "integrity": "sha512-4IcGSufhFshvLNcMCV80UnQVlZ5pMOC8mvNPForqwA4+lzYQuetTESLDQkeLmihq8bRcnpbQa48Wb8Lh16/xow==", + "dev": true, + "license": "MIT", + "bin": { + "umd": "bin/cli.js" + } + }, + "node_modules/undeclared-identifiers": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/undeclared-identifiers/-/undeclared-identifiers-1.1.3.tgz", + "integrity": "sha512-pJOW4nxjlmfwKApE4zvxLScM/njmwj/DiUBv7EabwE4O8kRUy+HIwxQtZLBPll/jx1LJyBcqNfB3/cpv9EZwOw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "acorn-node": "^1.3.0", + "dash-ast": "^1.0.0", + "get-assigned-identifiers": "^1.2.0", + "simple-concat": "^1.0.0", + "xtend": "^4.0.1" + }, + "bin": { + "undeclared-identifiers": "bin.js" + } + }, + "node_modules/undici": { + "version": "7.22.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-7.22.0.tgz", + "integrity": "sha512-RqslV2Us5BrllB+JeiZnK4peryVTndy9Dnqq62S3yYRRTj0tFQCwEniUy2167skdGOy3vqRzEvl1Dm4sV2ReDg==", + "license": "MIT", + "engines": { + "node": ">=20.18.1" + } + }, + "node_modules/undici-types": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", + "license": "MIT" + }, + "node_modules/unicode-properties": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/unicode-properties/-/unicode-properties-1.4.1.tgz", + "integrity": "sha512-CLjCCLQ6UuMxWnbIylkisbRj31qxHPAurvena/0iwSVbQ2G1VY5/HjV0IRabOEbDHlzZlRdCrD4NhB0JtU40Pg==", + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.0", + "unicode-trie": "^2.0.0" + } + }, + "node_modules/unicode-trie": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-trie/-/unicode-trie-2.0.0.tgz", + "integrity": "sha512-x7bc76x0bm4prf1VLg79uhAzKw8DVboClSN5VxJuQ+LKDOVEW9CdH+VY7SP+vX7xCYQqzzgQpFqz15zeLvAtZQ==", + "license": "MIT", + "dependencies": { + "pako": "^0.2.5", + "tiny-inflate": "^1.0.0" + } + }, + "node_modules/unique-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", + "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", + "license": "MIT", + "dependencies": { + "crypto-random-string": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/update-notifier": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-4.1.3.tgz", + "integrity": "sha512-Yld6Z0RyCYGB6ckIjffGOSOmHXj1gMeE7aROz4MG+XMkmixBX4jUngrGXNYz7wPKBmtoD4MnBa2Anu7RSKht/A==", + "license": "BSD-2-Clause", + "dependencies": { + "boxen": "^4.2.0", + "chalk": "^3.0.0", + "configstore": "^5.0.1", + "has-yarn": "^2.1.0", + "import-lazy": "^2.1.0", + "is-ci": "^2.0.0", + "is-installed-globally": "^0.3.1", + "is-npm": "^4.0.0", + "is-yarn-global": "^0.3.0", + "latest-version": "^5.0.0", + "pupa": "^2.0.1", + "semver-diff": "^3.1.1", + "xdg-basedir": "^4.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/yeoman/update-notifier?sponsor=1" + } + }, + "node_modules/update-notifier/node_modules/chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/update-notifier/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/uri-js/node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/urijs": { + "version": "1.19.11", + "resolved": "https://registry.npmjs.org/urijs/-/urijs-1.19.11.tgz", + "integrity": "sha512-HXgFDgDommxn5/bIv0cnQZsPhHDA90NPHD6+c/v21U5+Sx5hoP8+dP9IZXBU1gIfvdRfhG8cel9QNPeionfcCQ==", + "license": "MIT" + }, + "node_modules/url": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/url/-/url-0.11.4.tgz", + "integrity": "sha512-oCwdVC7mTuWiPyjLUz/COz5TLk6wgp0RCsN+wHZ2Ekneac9w8uuV0njcbbie2ME+Vs+d6duwmYuR3HgQXs1fOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "punycode": "^1.4.1", + "qs": "^6.12.3" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/url-parse-lax": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", + "integrity": "sha512-NjFKA0DidqPa5ciFcSrXnAltTtzz84ogy+NebPvfEgAck0+TNg4UJ4IN+fB7zRZfbgUf0syOo9MDxFkDSMuFaQ==", + "license": "MIT", + "dependencies": { + "prepend-http": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/url/node_modules/qs": { + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.0.tgz", + "integrity": "sha512-mAZTtNCeetKMH+pSjrb76NAM8V9a05I9aBZOHztWy/UqcJdQYNsf59vrRKWnojAT9Y+GbIvoTBC++CPHqpDBhQ==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/util": { + "version": "0.10.4", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.4.tgz", + "integrity": "sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "2.0.3" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true, + "license": "MIT" + }, + "node_modules/util/node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", + "dev": true, + "license": "ISC" + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/valid-data-url": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/valid-data-url/-/valid-data-url-3.0.1.tgz", + "integrity": "sha512-jOWVmzVceKlVVdwjNSenT4PbGghU0SBIizAev8ofZVgivk/TVHXSbNL8LP6M3spZvkR9/QolkyJavGSX5Cs0UA==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", + "dev": true, + "engines": [ + "node >=0.6.0" + ], + "license": "MIT", + "dependencies": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "node_modules/verror/node_modules/core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/vite": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz", + "integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==", + "license": "MIT", + "dependencies": { + "esbuild": "^0.27.0", + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.15" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "lightningcss": "^1.21.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vite-node": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-5.3.0.tgz", + "integrity": "sha512-8f20COPYJujc3OKPX6OuyBy3ZIv2det4eRRU4GY1y2MjbeGSUmPjedxg1b72KnTagCofwvZ65ThzjxDW2AtQFQ==", + "license": "MIT", + "dependencies": { + "cac": "^6.7.14", + "es-module-lexer": "^2.0.0", + "obug": "^2.1.1", + "pathe": "^2.0.3", + "vite": "^7.3.1" + }, + "bin": { + "vite-node": "dist/cli.mjs" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://opencollective.com/antfu" + } + }, + "node_modules/vite-tsconfig-paths": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/vite-tsconfig-paths/-/vite-tsconfig-paths-5.1.4.tgz", + "integrity": "sha512-cYj0LRuLV2c2sMqhqhGpaO3LretdtMn/BVX4cPLanIZuwwrkVl+lK84E/miEXkCHWXuq65rhNN4rXsBcOB3S4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.1.1", + "globrex": "^0.1.2", + "tsconfck": "^3.0.3" + }, + "peerDependencies": { + "vite": "*" + }, + "peerDependenciesMeta": { + "vite": { + "optional": true + } + } + }, + "node_modules/vitest": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.0.18.tgz", + "integrity": "sha512-hOQuK7h0FGKgBAas7v0mSAsnvrIgAvWmRFjmzpJ7SwFHH3g1k2u37JtYwOwmEKhK6ZO3v9ggDBBm0La1LCK4uQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@vitest/expect": "4.0.18", + "@vitest/mocker": "4.0.18", + "@vitest/pretty-format": "4.0.18", + "@vitest/runner": "4.0.18", + "@vitest/snapshot": "4.0.18", + "@vitest/spy": "4.0.18", + "@vitest/utils": "4.0.18", + "es-module-lexer": "^1.7.0", + "expect-type": "^1.2.2", + "magic-string": "^0.30.21", + "obug": "^2.1.1", + "pathe": "^2.0.3", + "picomatch": "^4.0.3", + "std-env": "^3.10.0", + "tinybench": "^2.9.0", + "tinyexec": "^1.0.2", + "tinyglobby": "^0.2.15", + "tinyrainbow": "^3.0.3", + "vite": "^6.0.0 || ^7.0.0", + "why-is-node-running": "^2.3.0" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@opentelemetry/api": "^1.9.0", + "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", + "@vitest/browser-playwright": "4.0.18", + "@vitest/browser-preview": "4.0.18", + "@vitest/browser-webdriverio": "4.0.18", + "@vitest/ui": "4.0.18", + "happy-dom": "*", + "jsdom": "*" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@opentelemetry/api": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser-playwright": { + "optional": true + }, + "@vitest/browser-preview": { + "optional": true + }, + "@vitest/browser-webdriverio": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + } + } + }, + "node_modules/vitest/node_modules/es-module-lexer": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", + "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", + "dev": true, + "license": "MIT" + }, + "node_modules/vm-browserify": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-0.0.4.tgz", + "integrity": "sha512-NyZNR3WDah+NPkjh/YmhuWSsT4a0mF0BJYgUmvrJ70zxjTXh5Y2Asobxlh0Nfs0PCFB5FVpRJft7NozAWFMwLQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "indexof": "0.0.1" + } + }, + "node_modules/watchpack": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.5.1.tgz", + "integrity": "sha512-Zn5uXdcFNIA1+1Ei5McRd+iRzfhENPCe7LeABkJtNulSxjma+l7ltNx55BWZkRlwRnpOgHqxnjyaDgJnNXnqzg==", + "dev": true, + "license": "MIT", + "dependencies": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", + "dev": true, + "license": "MIT", + "dependencies": { + "defaults": "^1.0.3" + } + }, + "node_modules/web-resource-inliner": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/web-resource-inliner/-/web-resource-inliner-8.0.0.tgz", + "integrity": "sha512-Ezr98sqXW/+OCGoUEXuOKVR+oVFlSdn1tIySEEJdiSAw4IjrW8hQkwARSSBJTSB5Us5dnytDgL0ZDliAYBhaNA==", + "license": "MIT", + "dependencies": { + "ansi-colors": "^4.1.1", + "escape-goat": "^3.0.0", + "htmlparser2": "^9.1.0", + "mime": "^2.4.6", + "valid-data-url": "^3.0.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/web-resource-inliner/node_modules/escape-goat": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-3.0.0.tgz", + "integrity": "sha512-w3PwNZJwRxlp47QGzhuEBldEqVHHhh8/tIPcl6ecf2Bou99cdAt0knihBV0Ecc7CGxYduXVBDheH1K2oADRlvw==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/web-resource-inliner/node_modules/htmlparser2": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-9.1.0.tgz", + "integrity": "sha512-5zfg6mHUoaer/97TxnGpxmbR7zJtPwIYFMZ/H5ucTlPZhKvtum05yiPK3Mgai3a0DyVxv7qYqoweaEd2nrYQzQ==", + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "MIT", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.1.0", + "entities": "^4.5.0" + } + }, + "node_modules/web-resource-inliner/node_modules/mime": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "license": "BSD-2-Clause" + }, + "node_modules/webpack": { + "version": "5.105.3", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.105.3.tgz", + "integrity": "sha512-LLBBA4oLmT7sZdHiYE/PeVuifOxYyE2uL/V+9VQP7YSYdJU7bSf7H8bZRRxW8kEPMkmVjnrXmoR3oejIdX0xbg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@types/eslint-scope": "^3.7.7", + "@types/estree": "^1.0.8", + "@types/json-schema": "^7.0.15", + "@webassemblyjs/ast": "^1.14.1", + "@webassemblyjs/wasm-edit": "^1.14.1", + "@webassemblyjs/wasm-parser": "^1.14.1", + "acorn": "^8.16.0", + "acorn-import-phases": "^1.0.3", + "browserslist": "^4.28.1", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.19.0", + "es-module-lexer": "^2.0.0", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.11", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.3.1", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^4.3.3", + "tapable": "^2.3.0", + "terser-webpack-plugin": "^5.3.16", + "watchpack": "^2.5.1", + "webpack-sources": "^3.3.4" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-cli": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-6.0.1.tgz", + "integrity": "sha512-MfwFQ6SfwinsUVi0rNJm7rHZ31GyTcpVE5pgVA3hwFRb7COD4TzjUUwhGWKfO50+xdc2MQPuEBBJoqIMGt3JDw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@discoveryjs/json-ext": "^0.6.1", + "@webpack-cli/configtest": "^3.0.1", + "@webpack-cli/info": "^3.0.1", + "@webpack-cli/serve": "^3.0.1", + "colorette": "^2.0.14", + "commander": "^12.1.0", + "cross-spawn": "^7.0.3", + "envinfo": "^7.14.0", + "fastest-levenshtein": "^1.0.12", + "import-local": "^3.0.2", + "interpret": "^3.1.1", + "rechoir": "^0.8.0", + "webpack-merge": "^6.0.1" + }, + "bin": { + "webpack-cli": "bin/cli.js" + }, + "engines": { + "node": ">=18.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.82.0" + }, + "peerDependenciesMeta": { + "webpack-bundle-analyzer": { + "optional": true + }, + "webpack-dev-server": { + "optional": true + } + } + }, + "node_modules/webpack-cli/node_modules/commander": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", + "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/webpack-merge": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-6.0.1.tgz", + "integrity": "sha512-hXXvrjtx2PLYx4qruKl+kyRSLc52V+cCvMxRjmKwoA+CBbbF5GfIBtR6kCvl0fYGqTUPKB+1ktVmTHqMOzgCBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "clone-deep": "^4.0.1", + "flat": "^5.0.2", + "wildcard": "^2.0.1" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/webpack-sources": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.3.4.tgz", + "integrity": "sha512-7tP1PdV4vF+lYPnkMR0jMY5/la2ub5Fc/8VQrrU+lXkiM6C4TjVfGw7iKfyhnTQOsD+6Q/iKw0eFciziRgD58Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webpack/node_modules/acorn": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", + "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", + "dev": true, + "license": "MIT", + "peer": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/webpack/node_modules/acorn-import-phases": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/acorn-import-phases/-/acorn-import-phases-1.0.4.tgz", + "integrity": "sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.13.0" + }, + "peerDependencies": { + "acorn": "^8.14.0" + } + }, + "node_modules/webpack/node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/whatwg-encoding": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", + "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==", + "deprecated": "Use @exodus/bytes instead for a more spec-conformant and faster implementation", + "license": "MIT", + "dependencies": { + "iconv-lite": "0.6.3" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/whatwg-mimetype": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", + "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz", + "integrity": "sha512-F6+WgncZi/mJDrammbTuHe1q0R5hOXv/mBaiNA2TCNT/LTHusX0V+CJnj9XT8ki5ln2UZyyddDgHfCzyrOH7MQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/which-typed-array": { + "version": "1.1.20", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.20.tgz", + "integrity": "sha512-LYfpUkmqwl0h9A2HL09Mms427Q1RZWuOHsukfVcKRq9q95iQxdw0ix1JQrqbcDR9PH1QDwf5Qo8OZb5lksZ8Xg==", + "dev": true, + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "for-each": "^0.3.5", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/why-is-node-running": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", + "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", + "dev": true, + "license": "MIT", + "dependencies": { + "siginfo": "^2.0.0", + "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/widest-line": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", + "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==", + "license": "MIT", + "dependencies": { + "string-width": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wildcard": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", + "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/window-size": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.2.0.tgz", + "integrity": "sha512-UD7d8HFA2+PZsbKyaOCEy8gMh1oDtHgJh1LfgjQ4zVXmYjAT/kvz3PueITKuqDiIXQe7yzpPnxX3lNc+AhQMyw==", + "dev": true, + "license": "MIT", + "bin": { + "window-size": "cli.js" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", + "license": "MIT" + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "license": "ISC" + }, + "node_modules/write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, + "node_modules/ws": { + "version": "8.19.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.19.0.tgz", + "integrity": "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/wsl-utils": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/wsl-utils/-/wsl-utils-0.3.1.tgz", + "integrity": "sha512-g/eziiSUNBSsdDJtCLB8bdYEUMj4jR7AGeUo96p/3dTafgjHhpF4RiCFPiRILwjQoDXx5MqkBr4fwWtR3Ky4Wg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-wsl": "^3.1.0", + "powershell-utils": "^0.1.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/wsl-utils/node_modules/is-wsl": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.1.tgz", + "integrity": "sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-inside-container": "^1.0.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/xdg-basedir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", + "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/xml-js": { + "version": "1.6.11", + "resolved": "https://registry.npmjs.org/xml-js/-/xml-js-1.6.11.tgz", + "integrity": "sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g==", + "license": "MIT", + "dependencies": { + "sax": "^1.2.4" + }, + "bin": { + "xml-js": "bin/cli.js" + } + }, + "node_modules/xmldoc": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/xmldoc/-/xmldoc-2.0.3.tgz", + "integrity": "sha512-6gRk4NY/Jvg67xn7OzJuxLRsGgiXBaPUQplVJ/9l99uIugxh4FTOewYz5ic8WScj7Xx/2WvhENiQKwkK9RpE4w==", + "license": "MIT", + "dependencies": { + "sax": "^1.4.3" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "license": "MIT", + "engines": { + "node": ">=0.4" + } + }, + "node_modules/y18n": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.2.tgz", + "integrity": "sha512-uGZHXkHnhF0XeeAPgnKfPv1bgKAYyVvmNL1xlKsPYZPaIHxGti2hHqvOCQv71XMsLxu1QjergkqogUnms5D3YQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/yaml": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.2.tgz", + "integrity": "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==", + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" + } + }, + "node_modules/yargs": { + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-4.8.1.tgz", + "integrity": "sha512-LqodLrnIDM3IFT+Hf/5sxBnEGECrfdC1uIbgZeJmESCSo4HoCAaKEus8MylXHAkdacGc0ye+Qa+dpkuom8uVYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^3.2.0", + "decamelize": "^1.1.1", + "get-caller-file": "^1.0.1", + "lodash.assign": "^4.0.3", + "os-locale": "^1.4.0", + "read-pkg-up": "^1.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^1.0.1", + "which-module": "^1.0.0", + "window-size": "^0.2.0", + "y18n": "^3.2.1", + "yargs-parser": "^2.4.1" + } + }, + "node_modules/yargs-parser": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-2.4.1.tgz", + "integrity": "sha512-9pIKIJhnI5tonzG6OnCFlz/yln8xHYcGl+pn3xR0Vzff0vzN1PbNRaelgfgRUwZ3s4i3jvxT9WhmUGL4whnasA==", + "dev": true, + "license": "ISC", + "dependencies": { + "camelcase": "^3.0.0", + "lodash.assign": "^4.0.6" + } + }, + "node_modules/yargs-parser/node_modules/camelcase": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", + "integrity": "sha512-4nhGqUkc4BqbBBB4Q6zLuD7lzzrHYrjKGeYaEji/3tFR5VdJu9v+LilhGIVe8wxEJPPOeWo7eg8dwY13TZ1BNg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/yargs/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/yargs/node_modules/is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "number-is-nan": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/yargs/node_modules/string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw==", + "dev": true, + "license": "MIT", + "dependencies": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/yargs/node_modules/strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/zod": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.3.6.tgz", + "integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==", + "license": "MIT", + "peer": true, + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + } + } +} diff --git a/package.json b/package.json index e67de54..5f03eaa 100644 --- a/package.json +++ b/package.json @@ -1,45 +1,104 @@ { - "name": "@plastichub/template", + "name": "server", + "version": "1.0.0", "description": "", - "version": "0.3.1", - "main": "main.js", - "typings": "index.d.ts", - "publishConfig": { - "access": "public" + "type": "module", + "scripts": { + "dev-o": "tsx watch src/index.ts", + "dev": "sh ./scripts/dev.sh", + "start": "node dist/main_node.cjs", + "build": "tsc -p tsconfig.build.json", + "build:webpack": "npm run build && webpack --config webpack.config.js", + "build:exe": "npm run build:webpack && node scripts/nexe.js", + "generate:config": "npx vite-node scripts/generate-app-config.ts", + "seed": "tsx src/seed.ts", + "migrate": "cd .. && npx supabase db push", + "test": "vitest --run", + "test:feed": "vitest run src/products/serving/__tests__/feed.e2e.test.ts", + "test:ui": "vitest --run --ui", + "test:coverage": "vitest --run --coverage", + "test:usage": "vitest run usage", + "test:emails": "vitest run email_real", + "test:pgboss": "vitest run pgboss", + "test:pgboss-e2e": "vitest run pgboss-e2e", + "test:product:locations": "vitest run src/products/locations/__tests__/e2e.test.ts", + "test:product:images": "vitest run src/products/images/__tests__/e2e.test.ts", + "test:images": "vitest run src/products/images/__tests__/e2e.test.ts", + "test:video": "vitest run src/products/videos/__tests__/e2e.test.ts", + "test:video:probe": "vitest run src/products/videos/__tests__/upload.test.ts", + "test:serve": "vitest run src/products/serving/__tests__/e2e.test.ts", + "supabase:types": "npx supabase gen types typescript --linked > ./src/integrations/supabase/types.ts", + "semgrep": "sh ./scripts/semgrep.sh", + "scalar:token": "tsx scripts/get-scalar-token.js", + "test:bots": "vitest run src/products/serving/__tests__/e2e.test.ts -t \"should serve HTML to bots\"", + "swagger:get": "tsx scripts/swagger-get.js", + "swagger:gen": "tsx scripts/swagger-gen-client.js", + "supabase:schemas": "supazod -i src/integrations/supabase/types.ts -o src/integrations/supabase/schemas.ts --inline-types -s public" }, - "bin": { - "osr-bin": "main.js" + "keywords": [], + "author": "", + "license": "ISC", + "devDependencies": { + "@hey-api/client-fetch": "^0.13.1", + "@hey-api/openapi-ts": "^0.92.3", + "@hono/node-server": "^1.19.6", + "@types/node": "^24.10.1", + "@types/pg": "^8.15.6", + "@vitest/ui": "^4.0.18", + "hono": "^4.10.6", + "nexe": "^1.1.6", + "pino-pretty": "^13.1.2", + "supazod": "^4.5.0", + "tsx": "^4.20.6", + "typescript": "^5.9.3", + "vite-tsconfig-paths": "^5.1.4", + "vitest": "^4.0.18", + "webpack": "^5.97.1", + "webpack-cli": "^6.0.1" }, "dependencies": { - "@types/node": "^14.17.5", - "@types/yargs": "^17.0.2", - "chalk": "^2.4.1", - "convert-units": "^2.3.4", - "env-var": "^7.0.1", - "typescript": "^4.3.5", - "yargs": "^14.2.3", - "yargs-parser": "^15.0.3" - }, - "scripts": { - "test": "tsc; mocha --full-trace mocha \"spec/**/*.spec.js\"", - "test-with-coverage": "istanbul cover node_modules/.bin/_mocha -- 'spec/**/*.spec.js'", - "lint": "tslint --project=./tsconfig.json", - "build": "tsc -p .", - "dev": "tsc -p . --declaration -w", - "typings": "tsc --declaration", - "docs": "npx typedoc src/index.ts", - "dev-test-watch": "mocha-typescript-watch" - }, - "homepage": "https://git.osr-plastic.org/plastichub/lib-content", - "repository": { - "type": "git", - "url": "https://git.osr-plastic.org/plastichub/lib-content.git" - }, - "engines": { - "node": ">= 14.0.0" - }, - "license": "BSD-3-Clause", - "keywords": [ - "typescript" - ] -} + "@hono/node-ws": "^1.2.0", + "@hono/swagger-ui": "^0.5.2", + "@hono/zod-openapi": "^1.1.5", + "@polymech/acl": "file:../polymech-mono/packages/acl", + "@polymech/commons": "file:../polymech-mono/packages/commons", + "@polymech/core": "file:../polymech-mono/packages/core", + "@polymech/fs": "file:../polymech-mono/packages/fs", + "@polymech/i18n": "file:../polymech-mono/packages/i18n", + "@polymech/media": "file:../polymech-mono/packages/media", + "@polymech/registry": "file:../polymech-mono/packages/registry", + "@polymech/search": "file:../polymech-mono/packages/search", + "@scalar/hono-api-reference": "^0.9.25", + "@ssut/tiktok-api": "^1.5.2", + "@supabase/supabase-js": "^2.87.1", + "@types/pdfmake": "^0.2.12", + "@types/sharp": "^0.31.1", + "@types/ws": "^8.18.1", + "cheerio": "^1.1.2", + "chokidar": "^5.0.0", + "deepl-node": "^1.24.0", + "dotenv": "^17.2.3", + "exifreader": "^4.33.1", + "feed": "^5.1.0", + "glob": "^13.0.3", + "hono-rate-limiter": "^0.4.2", + "i": "^0.3.7", + "ignore": "^7.0.5", + "isbot": "^5.1.34", + "juice": "^11.1.1", + "lru-cache": "^11.2.4", + "marked": "^17.0.1", + "mime": "^4.1.0", + "npm": "^11.7.0", + "pdfmake": "^0.2.20", + "pg-boss": "^12.5.2", + "pino": "^10.1.0", + "quicktype-core": "^23.2.6", + "sharp": "^0.34.5", + "stripe": "^20.3.1", + "swagger-typescript-codegen": "^3.2.4", + "vite-node": "^5.3.0", + "ws": "^8.19.0", + "zod": "^4.3.6" + } +} \ No newline at end of file diff --git a/src/__tests__/blocklist.test.ts b/src/__tests__/blocklist.test.ts new file mode 100644 index 0000000..c169287 --- /dev/null +++ b/src/__tests__/blocklist.test.ts @@ -0,0 +1,219 @@ +import { describe, it, expect, beforeAll } from 'vitest' +import { app } from '../index.js' +import { + loadBlocklist, + getBlocklist, + isIPBlocked, + isUserBlocked, + isTokenBlocked +} from '../middleware/blocklist.js' + +describe('Blocklist Middleware', () => { + beforeAll(() => { + // Ensure blocklist is loaded + loadBlocklist() + }) + + describe('Blocklist Loading', () => { + it('should load blocklist from JSON file', () => { + const blocklist = getBlocklist() + + expect(blocklist).toBeDefined() + expect(blocklist).toHaveProperty('blockedIPs') + expect(blocklist).toHaveProperty('blockedUserIds') + expect(blocklist).toHaveProperty('blockedTokens') + }) + + it('should have blocked IPs in the list', () => { + const blocklist = getBlocklist() + + expect(Array.isArray(blocklist.blockedIPs)).toBe(true) + expect(blocklist.blockedIPs.length).toBeGreaterThan(0) + }) + + it('should have blocked user IDs in the list', () => { + const blocklist = getBlocklist() + + expect(Array.isArray(blocklist.blockedUserIds)).toBe(true) + expect(blocklist.blockedUserIds.length).toBeGreaterThan(0) + }) + + it('should have blocked tokens in the list', () => { + const blocklist = getBlocklist() + + expect(Array.isArray(blocklist.blockedTokens)).toBe(true) + expect(blocklist.blockedTokens.length).toBeGreaterThan(0) + }) + }) + + describe('IP Blocking', () => { + it('should block requests from blocked IP addresses', async () => { + const response = await app.request('/api/products', { + headers: { + 'x-forwarded-for': '192.168.1.100' // Blocked IP from blocklist.json + } + }) + + expect(response.status).toBe(403) + + const data = await response.json() + expect(data).toHaveProperty('error') + expect(data.error).toBe('Forbidden') + expect(data.message).toContain('IP address has been blocked') + }, 10000) + + it('should allow requests from non-blocked IP addresses', async () => { + const response = await app.request('/api/subscriptions', { + headers: { + 'x-forwarded-for': '192.168.1.1' // Non-blocked IP + } + }) + + expect(response.status).toBe(200) + }) + + it('should check IP blocking correctly', () => { + expect(isIPBlocked('192.168.1.100')).toBe(true) + expect(isIPBlocked('10.0.0.50')).toBe(true) + expect(isIPBlocked('192.168.1.1')).toBe(false) + }) + }) + + describe('User ID Blocking', () => { + it('should block requests from blocked user IDs', async () => { + const response = await app.request('/api/products', { + headers: { + 'authorization': 'user_banned_123', // Blocked user from blocklist.json + 'x-forwarded-for': '192.168.1.1' + } + }) + + expect(response.status).toBe(403) + + const data = await response.json() + expect(data).toHaveProperty('error') + expect(data.error).toBe('Forbidden') + expect(data.message).toContain('account has been blocked') + }, 10000) + + it('should allow requests from non-blocked users', async () => { + const response = await app.request('/api/subscriptions', { + headers: { + 'authorization': 'user_valid_789', + 'x-forwarded-for': '192.168.1.1' + } + }) + + expect(response.status).toBe(200) + }) + + it('should check user blocking correctly', () => { + expect(isUserBlocked('user_banned_123')).toBe(true) + expect(isUserBlocked('user_spam_456')).toBe(true) + expect(isUserBlocked('user_valid_789')).toBe(false) + }) + }) + + describe('Token Blocking', () => { + it('should block requests with blocked tokens', async () => { + const response = await app.request('/api/products', { + headers: { + 'authorization': 'Bearer malicious_token_xyz', // Blocked token + 'x-forwarded-for': '192.168.1.1' + } + }) + + expect(response.status).toBe(403) + + const data = await response.json() + expect(data).toHaveProperty('error') + expect(data.error).toBe('Forbidden') + expect(data.message).toContain('access token has been blocked') + }, 10000) + + it('should allow requests with valid tokens', async () => { + const response = await app.request('/api/subscriptions', { + headers: { + 'authorization': 'Bearer valid_token_abc', + 'x-forwarded-for': '192.168.1.1' + } + }) + + expect(response.status).toBe(200) + }) + + it('should check token blocking correctly', () => { + expect(isTokenBlocked('Bearer malicious_token_xyz')).toBe(true) + expect(isTokenBlocked('Bearer valid_token_abc')).toBe(false) + }) + }) + + describe('Multiple Blocking Criteria', () => { + it('should block if IP is blocked even with valid token', async () => { + const response = await app.request('/api/products', { + headers: { + 'authorization': 'Bearer valid_token_abc', + 'x-forwarded-for': '192.168.1.100' // Blocked IP + } + }) + + expect(response.status).toBe(403) + expect((await response.json()).message).toContain('IP address') + }, 10000) + + it('should block if token is blocked even from valid IP', async () => { + const response = await app.request('/api/products', { + headers: { + 'authorization': 'Bearer malicious_token_xyz', // Blocked token + 'x-forwarded-for': '192.168.1.1' // Valid IP + } + }) + + expect(response.status).toBe(403) + expect((await response.json()).message).toContain('access token') + }, 10000) + }) + + describe('Non-API Routes', () => { + it('should not apply blocklist to non-API routes', async () => { + // Root route should not be blocked even from blocked IP + const response = await app.request('/', { + headers: { + 'x-forwarded-for': '192.168.1.100' // Blocked IP + } + }) + + // This might still be blocked if we apply blocklist globally + // But based on our middleware setup, only /api/* is protected + expect(response.status).toBe(200) + }) + }) + + describe('Error Response Structure', () => { + it('should return consistent error structure for blocked requests', async () => { + const response = await app.request('/api/products', { + headers: { + 'x-forwarded-for': '192.168.1.100' + } + }) + + expect(response.status).toBe(403) + + const data = await response.json() + expect(data).toHaveProperty('error') + expect(data).toHaveProperty('message') + expect(typeof data.error).toBe('string') + expect(typeof data.message).toBe('string') + }, 10000) + }) + + describe('Blocklist Reload', () => { + it('should be able to reload blocklist', () => { + const initialBlocklist = getBlocklist() + const reloadedBlocklist = loadBlocklist() + + expect(reloadedBlocklist).toBeDefined() + expect(reloadedBlocklist.blockedIPs).toEqual(initialBlocklist.blockedIPs) + }) + }) +}) diff --git a/src/__tests__/commons.ts b/src/__tests__/commons.ts new file mode 100644 index 0000000..6b1dc8f --- /dev/null +++ b/src/__tests__/commons.ts @@ -0,0 +1 @@ +export const TEST_LOCATION_PLACE_ID = 'ChIJ_burz4DrpBIR7Tb0r_IWzQI' \ No newline at end of file diff --git a/src/__tests__/endpoints.test.ts b/src/__tests__/endpoints.test.ts new file mode 100644 index 0000000..fad9fff --- /dev/null +++ b/src/__tests__/endpoints.test.ts @@ -0,0 +1,120 @@ +import { describe, it, expect } from 'vitest' +import { app } from '../index' + +// Helper to generate unique IP for each test to avoid rate limiting +let ipCounter = 0 +function getUniqueIP() { + return `10.0.${Math.floor(ipCounter / 255)}.${ipCounter++ % 255}` +} + +describe('API Endpoints', () => { + describe('GET /', () => { + it('should return welcome message', async () => { + const res = await app.request('/') + expect(res.status).toBe(200) + + const text = await res.text() + expect(text).toBe('Hello Hono + Supabase + Swagger!') + }) + }) + + describe('GET /api/products', () => { + it('should return products array', async () => { + const res = await app.request('/api/products', { + headers: { 'x-forwarded-for': getUniqueIP() } + }) + expect(res.status).toBe(200) + + const data = await res.json() + expect(Array.isArray(data)).toBe(true) + }, 10000) + + it('should have correct content-type header', async () => { + const res = await app.request('/api/products', { + headers: { 'x-forwarded-for': getUniqueIP() } + }) + expect(res.headers.get('content-type')).toContain('application/json') + }, 10000) + }) + + describe('GET /api/subscriptions', () => { + it('should return subscriptions array', async () => { + const res = await app.request('/api/subscriptions', { + headers: { 'x-forwarded-for': getUniqueIP() } + }) + expect(res.status).toBe(200) + + const data = await res.json() + expect(Array.isArray(data)).toBe(true) + expect(data.length).toBeGreaterThan(0) + }) + + it('should return valid subscription objects', async () => { + const res = await app.request('/api/subscriptions', { + headers: { 'x-forwarded-for': getUniqueIP() } + }) + const data = await res.json() + + expect(data[0]).toHaveProperty('id') + expect(data[0]).toHaveProperty('name') + expect(data[0]).toHaveProperty('price') + expect(typeof data[0].price).toBe('number') + }) + }) + + describe('GET /api/admin/stats', () => { + it('should return stats object', async () => { + const res = await app.request('/api/admin/stats', { + headers: { 'x-forwarded-for': getUniqueIP() } + }) + expect(res.status).toBe(200) + + const data = await res.json() + expect(data).toHaveProperty('users') + expect(data).toHaveProperty('revenue') + }) + + it('should return numeric values for stats', async () => { + const res = await app.request('/api/admin/stats', { + headers: { 'x-forwarded-for': getUniqueIP() } + }) + const data = await res.json() + + expect(typeof data.users).toBe('number') + expect(typeof data.revenue).toBe('number') + expect(data.users).toBeGreaterThanOrEqual(0) + expect(data.revenue).toBeGreaterThanOrEqual(0) + }) + }) + + describe('OpenAPI Documentation', () => { + it('should serve OpenAPI spec at /doc', async () => { + const res = await app.request('/doc') + expect(res.status).toBe(200) + + const spec = await res.json() + expect(spec).toHaveProperty('openapi') + expect(spec).toHaveProperty('info') + expect(spec.info.title).toBe('SaaS API') + }) + + it('should serve Swagger UI at /ui', async () => { + const res = await app.request('/ui') + expect(res.status).toBe(200) + }) + + it('should serve Scalar reference at /reference', async () => { + const res = await app.request('/reference') + expect(res.status).toBe(200) + }) + }) + + describe('CORS', () => { + it('should have CORS headers enabled', async () => { + const res = await app.request('/api/products', { + headers: { 'x-forwarded-for': getUniqueIP() } + }) + expect(res.headers.get('access-control-allow-origin')).toBeDefined() + }, 10000) + }) +}) diff --git a/src/__tests__/products.test.ts b/src/__tests__/products.test.ts new file mode 100644 index 0000000..f75cd14 --- /dev/null +++ b/src/__tests__/products.test.ts @@ -0,0 +1,163 @@ +import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; +import { identifyProductAction, getActionConfig, getAllProducts, getProductActions } from '../config/products'; + +describe('Product Configuration', () => { + describe('identifyProductAction', () => { + it('should identify competitors search action', () => { + const result = identifyProductAction('/api/competitors', 'GET'); + + expect(result.product).toBe('competitors'); + expect(result.action).toBe('search'); + expect(result.config).toBeDefined(); + expect(result.config?.costUnits).toBe(1.0); + expect(result.config?.cancellable).toBe(true); + }); + + it('should identify competitors get_details action with parameter', () => { + const result = identifyProductAction('/api/competitors/ChIJd8BlQ2BZwokRAFUEcm_qrcA', 'GET'); + + expect(result.product).toBe('competitors'); + expect(result.action).toBe('get_details'); + expect(result.config).toBeDefined(); + expect(result.config?.costUnits).toBe(0.0); + expect(result.config?.cancellable).toBe(false); + }); + + it('should identify images upload action', () => { + const result = identifyProductAction('/api/images', 'POST'); + + expect(result.product).toBe('images'); + expect(result.action).toBe('upload'); + expect(result.config).toBeDefined(); + expect(result.config?.costUnits).toBe(2.0); + expect(result.config?.cancellable).toBe(true); + }); + + it('should identify images get action with parameter', () => { + const result = identifyProductAction('/api/images/abc123', 'GET'); + + expect(result.product).toBe('images'); + expect(result.action).toBe('get'); + expect(result.config?.costUnits).toBe(0.05); + }); + + it('should return null for untracked endpoints', () => { + const result = identifyProductAction('/api/unknown', 'GET'); + + expect(result.product).toBeNull(); + expect(result.action).toBeNull(); + expect(result.config).toBeNull(); + }); + + it('should return null for wrong method', () => { + const result = identifyProductAction('/api/competitors', 'POST'); + + expect(result.product).toBeNull(); + expect(result.action).toBeNull(); + }); + + it('should handle multiple path parameters', () => { + const result = identifyProductAction('/api/images/abc123/xyz789', 'GET'); + + // Should not match since pattern is /api/images/:id + expect(result.product).toBeNull(); + }); + }); + + describe('getActionConfig', () => { + it('should get config for valid product and action', () => { + const config = getActionConfig('competitors', 'search'); + + expect(config).toBeDefined(); + expect(config?.endpoint).toBe('/api/competitors'); + expect(config?.method).toBe('GET'); + expect(config?.costUnits).toBe(1.0); + }); + + it('should return null for invalid product', () => { + const config = getActionConfig('invalid', 'search'); + + expect(config).toBeNull(); + }); + + it('should return null for invalid action', () => { + const config = getActionConfig('competitors', 'invalid'); + + expect(config).toBeNull(); + }); + }); + + describe('getAllProducts', () => { + it('should return all product names', () => { + const products = getAllProducts(); + + expect(Array.isArray(products)).toBe(true); + expect(products).toContain('competitors'); + expect(products).toContain('images'); + expect(products.length).toBeGreaterThan(0); + }); + }); + + describe('getProductActions', () => { + it('should return all actions for competitors product', () => { + const actions = getProductActions('competitors'); + + expect(Array.isArray(actions)).toBe(true); + expect(actions).toContain('search'); + expect(actions).toContain('get_details'); + }); + + it('should return all actions for images product', () => { + const actions = getProductActions('images'); + + expect(Array.isArray(actions)).toBe(true); + expect(actions).toContain('upload'); + expect(actions).toContain('get'); + expect(actions).toContain('update'); + }); + + it('should return empty array for invalid product', () => { + const actions = getProductActions('invalid'); + + expect(Array.isArray(actions)).toBe(true); + expect(actions.length).toBe(0); + }); + }); + + describe('Cost Units', () => { + it('should have consistent cost units across products', () => { + const competitorsSearch = getActionConfig('competitors', 'search'); + const competitorsDetails = getActionConfig('competitors', 'get_details'); + const imagesUpload = getActionConfig('images', 'upload'); + const imagesGet = getActionConfig('images', 'get'); + + // Search/upload should be more expensive than get + expect(competitorsSearch?.costUnits).toBeGreaterThan(competitorsDetails?.costUnits || 0); + expect(imagesUpload?.costUnits).toBeGreaterThan(imagesGet?.costUnits || 0); + + // All cost units should be non-negative + expect(competitorsSearch?.costUnits).toBeGreaterThan(0); + expect(competitorsDetails?.costUnits).toBeGreaterThanOrEqual(0); + expect(imagesUpload?.costUnits).toBeGreaterThan(0); + expect(imagesGet?.costUnits).toBeGreaterThan(0); + }); + }); + + describe('Cancellable Actions', () => { + it('should mark long-running actions as cancellable', () => { + const competitorsSearch = getActionConfig('competitors', 'search'); + const imagesUpload = getActionConfig('images', 'upload'); + + expect(competitorsSearch?.cancellable).toBe(true); + expect(imagesUpload?.cancellable).toBe(true); + }); + + it('should mark quick actions as non-cancellable', () => { + const competitorsDetails = getActionConfig('competitors', 'get_details'); + const imagesGet = getActionConfig('images', 'get'); + + expect(competitorsDetails?.cancellable).toBe(false); + expect(imagesGet?.cancellable).toBe(false); + }); + }); +}); diff --git a/src/__tests__/rateLimiter.test.ts b/src/__tests__/rateLimiter.test.ts new file mode 100644 index 0000000..09c5a8e --- /dev/null +++ b/src/__tests__/rateLimiter.test.ts @@ -0,0 +1,145 @@ +import { describe, it, expect } from 'vitest' +import { app } from '../index' + +describe('Rate Limiting', () => { + // Helper to make multiple requests sequentially + async function makeSequentialRequests(path: string, count: number, ip?: string) { + const responses = [] + for (let i = 0; i < count; i++) { + const headers: Record = {} + if (ip) { + headers['x-forwarded-for'] = ip + } + const response = await app.request(path, { headers }) + responses.push(response) + } + return responses + } + + // Helper to make multiple requests concurrently + async function makeRequests(path: string, count: number, ip?: string) { + const requests = [] + for (let i = 0; i < count; i++) { + const headers: Record = {} + if (ip) { + headers['x-forwarded-for'] = ip + } + requests.push(app.request(path, { headers })) + } + return Promise.all(requests) + } + + describe('API Rate Limiting', () => { + it('should allow requests within rate limit', async () => { + // Make 2 requests sequentially (limit is 2 per 100ms) + const responses = await makeSequentialRequests('/api/subscriptions', 2, '192.168.2.1') + + // Both requests should succeed + expect(responses[0].status).toBe(200) + expect(responses[1].status).toBe(200) + }) + + it('should block requests exceeding rate limit', async () => { + // Make 3 requests quickly from same IP + const responses = await makeSequentialRequests('/api/subscriptions', 3, '192.168.2.2') + + // First 2 should succeed + expect(responses[0].status).toBe(200) + expect(responses[1].status).toBe(200) + + // Third should be rate limited + expect(responses[2].status).toBe(429) + + const errorData = await responses[2].json() + expect(errorData).toHaveProperty('error') + expect(errorData.error).toBe('Too many requests') + }) + + it('should include rate limit headers', async () => { + const response = await app.request('/api/products', { + headers: { 'x-forwarded-for': '192.168.2.3' } + }) + + // Check for rate limit headers + const headers = response.headers + expect(headers.get('ratelimit-limit')).toBeDefined() + expect(headers.get('ratelimit-remaining')).toBeDefined() + }, 10000) + + it('should track different IPs separately', async () => { + // Make 2 requests from IP 1 + const ip1Responses = await makeRequests('/api/subscriptions', 2, '192.168.2.4') + + // Make 2 requests from IP 2 + const ip2Responses = await makeRequests('/api/subscriptions', 2, '192.168.2.5') + + // All should succeed as they're from different IPs + expect(ip1Responses[0].status).toBe(200) + expect(ip1Responses[1].status).toBe(200) + expect(ip2Responses[0].status).toBe(200) + expect(ip2Responses[1].status).toBe(200) + }) + + it('should track authenticated users separately from IP', async () => { + // Request with auth header + const authResponse = await app.request('/api/subscriptions', { + headers: { + 'authorization': 'Bearer user123', + 'x-forwarded-for': '192.168.2.6' + } + }) + + // Request from same IP but no auth + const noAuthResponse = await app.request('/api/subscriptions', { + headers: { + 'x-forwarded-for': '192.168.2.6' + } + }) + + // Both should succeed as they're tracked separately + expect(authResponse.status).toBe(200) + expect(noAuthResponse.status).toBe(200) + }) + + it('should reset rate limit after time window', async () => { + // Make 2 requests (hit the limit) + const firstBatch = await makeSequentialRequests('/api/subscriptions', 2, '192.168.2.7') + expect(firstBatch[0].status).toBe(200) + expect(firstBatch[1].status).toBe(200) + + // Wait for the time window to pass (100ms + buffer) + await new Promise(resolve => setTimeout(resolve, 150)) + + // Should be able to make requests again + const response = await app.request('/api/subscriptions', { + headers: { 'x-forwarded-for': '192.168.2.7' } + }) + expect(response.status).toBe(200) + }, 15000) + + it('should not rate limit non-API routes', async () => { + // Root route should not be rate limited + const responses = await makeRequests('/', 5, '192.168.2.8') + + // All should succeed + responses.forEach(response => { + expect(response.status).toBe(200) + }) + }) + }) + + describe('Rate Limit Error Response', () => { + it('should return proper error structure when rate limited', async () => { + // Exceed rate limit + const responses = await makeSequentialRequests('/api/subscriptions', 3, '192.168.2.9') + + const errorResponse = responses[2] + expect(errorResponse.status).toBe(429) + + const errorData = await errorResponse.json() + expect(errorData).toHaveProperty('error') + expect(errorData).toHaveProperty('message') + expect(errorData.message).toContain('Rate limit exceeded') + }) + }) +}) diff --git a/src/cache.ts b/src/cache.ts new file mode 100644 index 0000000..b49e155 --- /dev/null +++ b/src/cache.ts @@ -0,0 +1,123 @@ +import { getCache } from './commons/cache/index.js'; +import { appEvents } from './events.js'; +import { CacheEntryInfo, CacheInfo } from './commons/cache/types.js'; +import pino from 'pino'; +import path from 'path'; + +const logFile = path.join(process.cwd(), 'logs', 'cache.json'); + +const fileTransport = pino.transport({ + target: 'pino/file', + options: { destination: logFile, mkdir: true } +}); + +const logger = pino( + { + level: process.env.PINO_LOG_LEVEL || 'info', + base: { product: 'cache' }, + timestamp: pino.stdTimeFunctions.isoTime, + }, + pino.multistream([ + { stream: fileTransport, level: 'info' } + ]) +); + + +export class AppCache { + private static instance: AppCache; + + // Dependencies: key -> [dependencies] + // Defines what each type DEPENDS ON. + // If 'categories' changes, any type that has 'categories' in its dependency list must be invalidated. + private static DEPENDENCIES: Record = { + 'posts': ['categories', 'pictures'], // posts depend on categories and pictures + 'pages': ['categories', 'pictures', 'translations'], + 'categories': ['types'], + 'translations': [], // widget/category translations (wt:* keys) + 'feed': ['posts', 'pages', 'categories'], + 'auth': [] // No dependencies, standalone + }; + + private constructor() { } + + public static getInstance(): AppCache { + if (!AppCache.instance) { + AppCache.instance = new AppCache(); + } + return AppCache.instance; + } + + public async get(type: string): Promise { + const cache = getCache(); + const val = await cache.get(type); + return val; + } + + public async set(type: string, data: T, ttl?: number): Promise { + const cache = getCache(); + await cache.set(type, data, ttl); + } + + /** + * Silent cache invalidation — clears cache for the given type and + * cascades to dependents. Does NOT emit SSE events. + * Use `notify()` in route handlers for explicit SSE. + */ + public async invalidate(type: string): Promise { + const cache = getCache(); + + if (type === 'feed') { + await cache.flush('*-feed*'); + await cache.flush('home-feed*'); + } else if (type === 'translations') { + await cache.flush('wt:*'); + await cache.flush('page-details-*'); + } else { + await cache.del(type); + } + + // Find types that depend on this type + const dependents = Object.keys(AppCache.DEPENDENCIES).filter(key => + AppCache.DEPENDENCIES[key].includes(type) + ); + + logger.info({ type, dependents }, 'Cache invalidated'); + + if (dependents.length > 0) { + await Promise.all(dependents.map(dep => this.invalidate(dep))); + } + } + + /** + * Flush cache entries by pattern. Silent — no SSE. + */ + public async flush(pattern?: string): Promise { + const cache = getCache(); + await cache.flush(pattern); + logger.info({ pattern: pattern || 'all' }, 'Cache flushed'); + } + + /** + * Emit exactly 1 SSE event to notify clients of a change. + * Call this in route handlers AFTER cache invalidation. + * + * @param type - Entity type (e.g. 'post', 'page', 'category', 'picture') + * @param id - Entity ID (null for list-level / system changes) + * @param action - The mutation that occurred + */ + public notify(type: string, id: string | null, action: 'create' | 'update' | 'delete'): void { + logger.info({ type, id, action }, 'Cache notify'); + appEvents.emitUpdate(type, action, { id }, 'cache'); + } + + public inspect(): { info: CacheInfo; dependencies: Record; entries: CacheEntryInfo[] } { + const cache = getCache(); + return { + info: cache.info(), + dependencies: AppCache.DEPENDENCIES, + entries: cache.entries(), + }; + } +} + +export const appCache = AppCache.getInstance(); diff --git a/src/commons/cache/MemoryCache.ts b/src/commons/cache/MemoryCache.ts new file mode 100644 index 0000000..4ba04ab --- /dev/null +++ b/src/commons/cache/MemoryCache.ts @@ -0,0 +1,67 @@ +import { LRUCache } from 'lru-cache'; +import { CacheAdapter } from './types.js'; + +export class MemoryCache implements CacheAdapter { + private cache: LRUCache; + + constructor() { + const defaultTtl = process.env.CACHE_DEFAULT_TTL ? parseInt(process.env.CACHE_DEFAULT_TTL) : 1000 * 60 * 5; // 5 mins default + this.cache = new LRUCache({ + max: 1000, + ttl: defaultTtl, + updateAgeOnGet: false, + }); + } + + async get(key: string): Promise { + const value = this.cache.get(key); + return (value as T) || null; + } + + async set(key: string, value: T, ttl?: number): Promise { + this.cache.set(key, value, { ttl: ttl ? ttl * 1000 : undefined }); + } + + async del(key: string): Promise { + this.cache.delete(key); + } + + async flush(pattern?: string): Promise { + if (pattern) { + // Support simple wildcard patterns (e.g. "home-feed*", "*-feed*") + // Escape special regex chars except *, then replace * with .* + const regexPattern = pattern + .replace(/[.+^${}()|[\]\\]/g, '\\$&') // Escape regex chars + .replace(/\*/g, '.*'); // Convert * to .* + + const regex = new RegExp(`^${regexPattern}$`); + + for (const key of this.cache.keys()) { + if (typeof key === 'string' && regex.test(key)) { + this.cache.delete(key); + } + } + } else { + this.cache.clear(); + } + } + + keys(): string[] { + return [...this.cache.keys()]; + } + + info() { + return { + size: this.cache.size, + max: this.cache.max, + provider: 'memory-lru', + }; + } + + entries() { + return [...this.cache.keys()].map(key => ({ + key, + remainingTTL: this.cache.getRemainingTTL(key), + })); + } +} diff --git a/src/commons/cache/index.ts b/src/commons/cache/index.ts new file mode 100644 index 0000000..dded8c0 --- /dev/null +++ b/src/commons/cache/index.ts @@ -0,0 +1,18 @@ +import { CacheAdapter } from './types.js'; +import { MemoryCache } from './MemoryCache.js'; + +// Design Pattern: Singleton or Factory +// For now, we export a singleton instance based on ENV or default to Memory +// Future: Read process.env.CACHE_PROVIDER == 'redis' + +let instance: CacheAdapter | null = null; + +export const getCache = (): CacheAdapter => { + if (!instance) { + instance = new MemoryCache(); + } + return instance; +}; + +export * from './types.js'; +export * from './MemoryCache.js'; diff --git a/src/commons/cache/types.ts b/src/commons/cache/types.ts new file mode 100644 index 0000000..3d6e007 --- /dev/null +++ b/src/commons/cache/types.ts @@ -0,0 +1,21 @@ +export interface CacheEntryInfo { + key: string; + remainingTTL: number; // ms remaining, 0 = no TTL / infinite + sizeEstimate?: number; // rough byte estimate if available +} + +export interface CacheInfo { + size: number; + max: number; + provider: string; +} + +export interface CacheAdapter { + get(key: string): Promise; + set(key: string, value: T, ttl?: number): Promise; + del(key: string): Promise; + flush(pattern?: string): Promise; + keys(): string[]; + info(): CacheInfo; + entries(): CacheEntryInfo[]; +} diff --git a/src/commons/decorators.ts b/src/commons/decorators.ts new file mode 100644 index 0000000..8bdf437 --- /dev/null +++ b/src/commons/decorators.ts @@ -0,0 +1,249 @@ +import { trackUsage, updateUsageRecord } from '../middleware/usageTracking.js'; +import { FunctionRegistry, PublicEndpointRegistry, AdminEndpointRegistry } from './registry.js'; +import { logger } from './logger.js'; + +/** + * Decorator/Wrapper to mark an endpoint as public + * Registers the route in PublicEndpointRegistry + */ +export function Public(route: T): T { + PublicEndpointRegistry.register(route.path, route.method); + return route; +} + +/** + * Decorator/Wrapper to mark an endpoint as admin-only + * Registers the route in AdminEndpointRegistry + */ +export function Admin(route: T): T { + AdminEndpointRegistry.register(route.path, route.method); + return route; +} + +export interface BillableContext { + userId: string; + jobId: string; + signal?: AbortSignal; + metadata?: Record; +} + +export interface BillableOptions { + productId: string; + actionId: string; + cancellable?: boolean; +} + +/** + * Decorator to mark a method as billable + * Handles usage tracking, context injection, and cancellation + */ +export function Billable(options: BillableOptions) { + return function ( + target: any, + propertyKey: string, + descriptor: PropertyDescriptor + ) { + const originalMethod = descriptor.value; + + descriptor.value = async function (...args: any[]) { + // 1. Extract context + // Assumes the first argument is BillableContext, or it's part of the first argument object + let context: BillableContext | undefined; + + if (args.length > 0 && typeof args[0] === 'object') { + // Check if first arg is context + if ('userId' in args[0] && 'jobId' in args[0]) { + context = args[0] as BillableContext; + } + } + + if (!context) { + // If no context provided, we can't track usage properly + // For now, we'll log a warning and proceed without tracking + // In strict mode, we might want to throw an error + logger.warn(`[Billable] No context provided for ${options.productId}:${options.actionId}`); + return originalMethod.apply(this, args); + } + + // 2. Get config + const config = FunctionRegistry.get(options.productId, options.actionId); + if (!config) { + logger.warn(`[Billable] No config found for ${options.productId}:${options.actionId}`); + return originalMethod.apply(this, args); + } + + // 3. Start tracking + const usageId = await trackUsage({ + userId: context.userId, + endpoint: 'function', // Internal function call + method: 'CALL', + product: options.productId, + action: options.actionId, + costUnits: config.costUnits, + cancellable: options.cancellable || false, + jobId: context.jobId, + metadata: context.metadata + }); + + const startTime = Date.now(); + let error: Error | null = null; + let result: any; + + try { + // 4. Execute method + // If cancellable, we should ideally wrap the execution or check signal + if (options.cancellable && context.signal) { + if (context.signal.aborted) { + throw new Error('Operation cancelled'); + } + + // Add abort listener + context.signal.addEventListener('abort', () => { + logger.info(`[Billable] Job ${context?.jobId} aborted via signal`); + }); + } + + result = await originalMethod.apply(this, args); + return result; + } catch (err) { + error = err as Error; + throw err; + } finally { + // 5. End tracking + if (usageId) { + const endTime = Date.now(); + await updateUsageRecord({ + usageId, + responseStatus: error ? 500 : 200, + responseTimeMs: endTime - startTime, + error + }); + } + } + }; + + return descriptor; + }; +} + + +/** + * Class Decorator: Registers the worker queue name + */ +export function Worker(queueName: string) { + return function (constructor: T) { + // We can't easily access the instance method 'handler' here without instantiating + // So we assume the class has a 'handler' method or we register the class itself + // For simplicity, let's assume we'll instantiate it later or the registry handles it. + // But wait, pg-boss needs a function. + // Let's store the constructor in the registry, and the registry (or bootstrap) will instantiate and bind. + + // Actually, let's just attach the queue name to the class for now, + // and let a separate scanner or manual registration use it. + // OR, we can register a factory. + + // Better approach for now: Register the prototype's handler if it exists. + // But 'handler' is on the instance usually. + + // Let's just modify the class to have a static 'queueName' property + // and register it. + (constructor as any).queueName = queueName; + }; +} + +import { Context } from 'hono'; +import { getCache } from './cache/index.js'; + +type KeyGenerator = (c: Context) => string; + +const defaultKeyInfo = (c: Context) => { + const url = new URL(c.req.url); + url.searchParams.sort(); + return `auto-cache:${c.req.method}:${url.pathname}${url.search}`; +}; + +export const CachedHandler = ( + handler: (c: Context) => Promise, + options?: { + ttl?: number, + keyGenerator?: KeyGenerator, + skipAuth?: boolean, // Default true + varyByAuth?: boolean, // If true, includes auth token in key and disables skipAuth default + maxSizeBytes?: number // Default: 1MB + } +) => async (c: Context) => { + const opts = options || {}; + const ttl = opts.ttl || 300; + const varyByAuth = opts.varyByAuth || false; + const skipAuth = opts.skipAuth !== undefined ? opts.skipAuth : !varyByAuth; // Default true unless varyByAuth is true + const maxSizeBytes = opts.maxSizeBytes || 1024 * 1024; // 1MB + const keyGen = opts.keyGenerator || defaultKeyInfo; + + // 1. Auth Bypass + const authHeader = c.req.header('Authorization'); + if (skipAuth && authHeader) { + // Explicitly mark as skipped due to auth + c.header('X-Cache', 'SKIP'); + return handler(c); + } + + const cache = getCache(); + let key = keyGen(c); + + // Append Auth to key if requested (User Isolation) + if (varyByAuth && authHeader) { + key += `|auth=${authHeader}`; + } + const bypass = c.req.query('cache') === 'false' || c.req.query('nocache') === 'true'; + + // 2. Hit + if (!bypass) { + const cached = await cache.get(key); + if (cached) { + c.header('X-Cache', 'HIT'); + const cachedVal = cached as any; + if (cachedVal.contentType) c.header('Content-Type', cachedVal.contentType); + if (varyByAuth) c.header('Vary', 'Authorization'); + return c.body(cachedVal.data); + } + } + + // 3. Miss + const response = await handler(c); + + // 4. Save + if (response instanceof Response && response.ok) { + const cloned = response.clone(); + try { + const contentType = response.headers.get('Content-Type') || 'application/json'; + let data: any; + + // Check content length if available + const contentLength = cloned.headers.get('Content-Length'); + if (contentLength && parseInt(contentLength) > maxSizeBytes) { + return response; + } + + if (contentType.includes('application/json')) { + const jsonObj = await cloned.json(); + data = JSON.stringify(jsonObj); + } else { + data = await cloned.text(); + } + + // Double check actual size after reading + if (data.length > maxSizeBytes) { + return response; + } + + await cache.set(key, { data, contentType }, ttl); + c.header('X-Cache', bypass ? 'BYPASS' : 'MISS'); + if (varyByAuth) c.header('Vary', 'Authorization'); + } catch (e) { + logger.error({ err: e }, 'Cache interception failed'); + } + } + + return response; +} + diff --git a/src/commons/log-routes-factory.ts b/src/commons/log-routes-factory.ts new file mode 100644 index 0000000..e68b1d6 --- /dev/null +++ b/src/commons/log-routes-factory.ts @@ -0,0 +1,185 @@ +import { createRoute, z } from '@hono/zod-openapi'; +import { Context } from 'hono'; +import { streamSSE, stream } from 'hono/streaming'; +import fs from 'fs'; +import readline from 'readline'; + +/** + * Creates OpenAPI route definitions for standard log endpoints. + * @param tag The OpenAPI tag for grouping (e.g. 'System', 'Images') + * @param pathPrefix The URL path prefix (e.g. '/api/logs/system') + */ +export const createLogRoutes = (tag: string, pathPrefix: string) => { + const getRoute = createRoute({ + method: 'get', + path: pathPrefix, + tags: [tag], + summary: `Get ${tag} logs`, + description: `Download or view ${tag} logs as a JSON array`, + responses: { + 200: { + description: 'Log content', + content: { + 'application/json': { + schema: z.array(z.record(z.string(), z.any())).openapi({ + description: 'Array of log entries' + }) + } + } + }, + 404: { + description: 'Log file not found' + } + } + }); + + const streamRoute = createRoute({ + method: 'get', + path: `${pathPrefix}/stream`, + tags: [tag], + summary: `Stream ${tag} logs`, + description: `Stream ${tag} logs via SSE (Server-Sent Events)`, + responses: { + 200: { + description: 'Log stream', + content: { + 'text/event-stream': { schema: z.string() } + } + } + } + }); + + return { getRoute, streamRoute }; +}; + +/** + * Creates Hono handlers for standard log endpoints. + * @param filePath The absolute path to the log file + */ +export const createLogHandlers = (filePath: string) => { + const getHandler = async (c: Context) => { + if (!fs.existsSync(filePath)) { + return c.text('Log file not found', 404); + } + + c.header('Content-Type', 'application/json'); + + return stream(c, async (stream) => { + const fileStream = fs.createReadStream(filePath); + const rl = readline.createInterface({ + input: fileStream, + crlfDelay: Infinity + }); + + await stream.write('['); + let first = true; + + for await (const line of rl) { + if (!line.trim()) continue; + if (!first) { + await stream.write(','); + } + try { + // Validate JSON to ensure we don't stream garbage? + // Optional: overhead. Assuming pino writes valid JSON per line. + // Just writing the line directly is faster. + await stream.write(line); + first = false; + } catch (e) { + // Ignore broken lines + } + } + + await stream.write(']'); + }); + }; + + const streamHandler = async (c: Context) => { + return streamSSE(c, async (stream) => { + // Send initial connection message + await stream.writeSSE({ + data: JSON.stringify({ type: 'info', message: 'Connected to log stream' }) + }); + + if (!fs.existsSync(filePath)) { + await stream.writeSSE({ + data: JSON.stringify({ type: 'error', message: 'Log file not found' }) + }); + // We keep the stream open in case the file is created later + } + + let currentSize = 0; + // Check initial size + if (fs.existsSync(filePath)) { + const stat = fs.statSync(filePath); + currentSize = stat.size; + + // Optional: Tail current content? + // For simplicity, we start streaming NEW content. + // But let's verify if we should send a bit of context. + // If it's a JSON log, partial lines are bad. + // If it's text, partial lines are bad too. + // Let's just track current size and stream updates. + } + + const checkInterval = 250; // Check every 250ms + + const interval = setInterval(async () => { + try { + if (!fs.existsSync(filePath)) { + if (currentSize > 0) { + currentSize = 0; // File deleted + await stream.writeSSE({ data: JSON.stringify({ type: 'info', message: 'Log file deleted' }) }); + } + return; + } + + const stat = fs.statSync(filePath); + + if (stat.size > currentSize) { + const sizeDiff = stat.size - currentSize; + const buffer = Buffer.alloc(sizeDiff); + const fd = fs.openSync(filePath, 'r'); + try { + fs.readSync(fd, buffer, 0, sizeDiff, currentSize); + currentSize = stat.size; + + const chunk = buffer.toString('utf-8'); + // If it's line-delimited JSON or text + const lines = chunk.split('\n'); + // Note: the last line might be incomplete if we read exactly to EOF while writing? + // But usually logger writes full lines. + // However, strictly we should handle buffering incomplete lines. + // For this "standard" goal, let's assume atomic writes or simple line splitting. + + // To be safer with valid JSON, we could filter empty lines. + for (const line of lines) { + if (!line.trim()) continue; + await stream.writeSSE({ data: line }); + } + } finally { + fs.closeSync(fd); + } + } else if (stat.size < currentSize) { + // Truncated / Rotated + currentSize = stat.size; + await stream.writeSSE({ + data: JSON.stringify({ type: 'info', message: 'Log rotated' }) + }); + } + } catch (e) { + console.error('Stream error:', e); + } + }, checkInterval); + + stream.onAbort(() => { + clearInterval(interval); + }); + + // Keep the stream alive + await new Promise(() => { }); + }); + }; + + return { getHandler, streamHandler }; +}; diff --git a/src/commons/logger.ts b/src/commons/logger.ts new file mode 100644 index 0000000..9fa12e8 --- /dev/null +++ b/src/commons/logger.ts @@ -0,0 +1,79 @@ +import pino from 'pino'; +import path from 'path'; +import { mkdirSync } from 'fs'; + +// Ensure logs directory exists +try { + mkdirSync(path.join(process.cwd(), 'logs'), { recursive: true }); +} catch (err) { + // Directory already exists +} + +const fileTransport = pino.transport({ + target: 'pino/file', + options: { destination: path.join(process.cwd(), 'app.log') }, +}); + +const consoleTransport = pino.transport({ + target: 'pino-pretty', + options: { + colorize: true, + ignore: 'pid,hostname', + destination: 1, + }, +}); + +export const logger = pino( + { + level: process.env.PINO_LOG_LEVEL || 'info', + formatters: { + level: (label) => { + return { level: label.toUpperCase() }; + }, + }, + timestamp: pino.stdTimeFunctions.isoTime, + }, + pino.multistream([ + { stream: fileTransport, level: 'info' }, + { stream: consoleTransport, level: 'info' }, + ]) +); + +// Security logger - writes to logs/security.json +const securityFileTransport = pino.transport({ + target: 'pino/file', + options: { + destination: path.join(process.cwd(), 'logs', 'security.json'), + mkdir: true + }, +}); + +const securityConsoleTransport = pino.transport({ + target: 'pino-pretty', + options: { + colorize: true, + ignore: 'pid,hostname', + destination: 1, + }, +}); + +export const securityLogger = pino( + { + level: process.env.PINO_LOG_LEVEL || 'info', + formatters: { + level: (label) => { + return { level: label.toUpperCase() }; + }, + }, + timestamp: pino.stdTimeFunctions.isoTime, + base: { + logger: 'security' + } + }, + pino.multistream([ + { stream: securityFileTransport, level: 'info' }, + { stream: securityConsoleTransport, level: 'info' }, + ]) +); + +export default logger; diff --git a/src/commons/registry.ts b/src/commons/registry.ts new file mode 100644 index 0000000..ddd1770 --- /dev/null +++ b/src/commons/registry.ts @@ -0,0 +1,192 @@ +import { ProductActionConfig, PRODUCT_ACTIONS } from '../config/products.js'; + +export interface BillableFunctionConfig extends ProductActionConfig { + productId: string; + actionId: string; +} + +/** + * Central registry for all billable functions + * Manages configuration, costs, and metadata + */ +export class FunctionRegistry { + private static registry = new Map(); + private static initialized = false; + + /** + * Initialize the registry with default configurations + */ + static initialize() { + if (this.initialized) return; + + // Load legacy PRODUCT_ACTIONS + for (const [productId, actions] of Object.entries(PRODUCT_ACTIONS)) { + for (const [actionId, config] of Object.entries(actions)) { + this.register({ + productId, + actionId, + ...config + }); + } + } + + this.initialized = true; + } + + /** + * Register a new billable function + */ + static register(config: BillableFunctionConfig) { + const key = this.getKey(config.productId, config.actionId); + this.registry.set(key, config); + } + + /** + * Get configuration for a specific function + */ + static get(productId: string, actionId: string): BillableFunctionConfig | null { + if (!this.initialized) this.initialize(); + const key = this.getKey(productId, actionId); + return this.registry.get(key) || null; + } + + /** + * Get all registered functions + */ + static getAll(): BillableFunctionConfig[] { + if (!this.initialized) this.initialize(); + return Array.from(this.registry.values()); + } + + /** + * Find a configuration by matching route endpoint and method + * (Used for middleware backward compatibility) + */ + static findByRoute(path: string, method: string): BillableFunctionConfig | null { + if (!this.initialized) this.initialize(); + + for (const config of this.registry.values()) { + if (this.matchesRoute(path, config.endpoint) && method === config.method) { + return config; + } + } + return null; + } + + private static getKey(productId: string, actionId: string): string { + return `${productId}:${actionId}`; + } + + private static matchesRoute(path: string, pattern: string): boolean { + // Convert pattern to regex + // Handle both :param (Express/Hono style) and {param} (OpenAPI style) + // e.g., '/api/competitors/:place_id' or '/api/competitors/{place_id}' -> /^\/api\/competitors\/[^\/]+$/ + const regexPattern = pattern + .replace(/:[^\\/]+/g, '[^/]+') // Replace :param with regex + .replace(/\{[^}]+\}/g, '[^/]+') // Replace {param} with regex + .replace(/\//g, '\\/'); + + // Allow optional trailing slash + const regex = new RegExp(`^${regexPattern}\\/?$`); + return regex.test(path); + } +} + +/** + * Registry for public endpoints that don't require authentication + */ +export class PublicEndpointRegistry { + private static registry = new Set(); + + static register(path: string, method: string) { + this.registry.add(`${method.toUpperCase()}:${path}`); + } + + static getAll(): Array<{ path: string; method: string }> { + return Array.from(this.registry).map(entry => { + // Split only on the FIRST colon (METHOD:PATH) + // Don't split on colons in path parameters like :identifier + const colonIndex = entry.indexOf(':'); + const method = entry.substring(0, colonIndex); + const path = entry.substring(colonIndex + 1); + return { path, method }; + }); + } + + static isPublic(path: string, method: string): boolean { + const methodUpper = method.toUpperCase(); + + for (const registered of this.registry) { + // Split only on the FIRST colon (METHOD:PATH) + // Don't split on colons in path parameters like :identifier + const colonIndex = registered.indexOf(':'); + const regMethod = registered.substring(0, colonIndex); + const regPath = registered.substring(colonIndex + 1); + + if (regMethod !== methodUpper) continue; + + // Check if path matches pattern + if (this.matchesRoute(path, regPath)) { + return true; + } + } + // Debug: log when a route is not found as public + // console.log(`[PublicEndpointRegistry] Route not found as public: ${methodUpper} ${path}`); + // console.log(`[PublicEndpointRegistry] Registered routes:`, Array.from(this.registry)); + return false; + } + + private static matchesRoute(path: string, pattern: string): boolean { + // Convert pattern to regex + // Handle both :param (Express/Hono style) and {param} (OpenAPI style) + // e.g., '/api/competitors/:place_id' or '/api/competitors/{place_id}' -> /^\/api\/competitors\/[^\/]+$/ + const regexPattern = pattern + .replace(/:[^\/]+/g, '[^/]+') // Replace :param with regex + .replace(/\{[^}]+\}/g, '[^/]+') // Replace {param} with regex + .replace(/\//g, '\\/'); + + // Allow optional trailing slash + const regex = new RegExp(`^${regexPattern}\\/?$`); + return regex.test(path); + } +} + +/** + * Registry for admin-only endpoints + */ +export class AdminEndpointRegistry { + private static registry = new Set(); + + static register(path: string, method: string) { + this.registry.add(`${method.toUpperCase()}:${path}`); + } + + static isAdmin(path: string, method: string): boolean { + const methodUpper = method.toUpperCase(); + + for (const registered of this.registry) { + const [regMethod, regPath] = registered.split(':'); + + if (regMethod !== methodUpper) continue; + + // Check if path matches pattern + if (this.matchesRoute(path, regPath)) { + return true; + } + } + return false; + } + + private static matchesRoute(path: string, pattern: string): boolean { + // Convert pattern to regex + // Handle both :param (Express/Hono style) and {param} (OpenAPI style) + // e.g., '/api/competitors/:place_id' or '/api/competitors/{place_id}' -> /^\/api\/competitors\/[^\/]+$/ + const regexPattern = pattern + .replace(/:[^\\/]+/g, '[^/]+') // Replace :param with regex + .replace(/\{[^}]+\}/g, '[^/]+') // Replace {param} with regex + .replace(/\//g, '\\/'); + + const regex = new RegExp(`^${regexPattern}\\/?$`); + return regex.test(path); + } +} diff --git a/src/commons/supabase.ts b/src/commons/supabase.ts new file mode 100644 index 0000000..82e0b16 --- /dev/null +++ b/src/commons/supabase.ts @@ -0,0 +1,76 @@ +import { createClient, User } from '@supabase/supabase-js' +import 'dotenv/config' + +const supabaseUrl = process.env.SUPABASE_URL +const supabaseKey = process.env.SUPABASE_SERVICE_KEY + +import { logger } from './logger.js' + +if (!supabaseUrl || !supabaseKey) { + logger.error({ + hasUrl: !!supabaseUrl, + hasKey: !!supabaseKey, + env: process.env.NODE_ENV + }, 'Missing Supabase environment variables'); + // process.exit(1) // Don't exit in test mode, throw instead + if (process.env.NODE_ENV !== 'test') process.exit(1); + throw new Error('Missing Supabase environment variables: URL or Key is undefined'); +} + +export const supabase = createClient(supabaseUrl, supabaseKey) + +// --- Auth Cache (in-process Map for speed) --- + +const AUTH_CACHE_TTL = process.env.AUTH_CACHE_TTL ? parseInt(process.env.AUTH_CACHE_TTL) : 1000 * 60 * 1; // Default 1 minute + +type AuthCacheEntry = { user: User | null; timestamp: number }; +const authMap = new Map(); + +export const getUserCached = async (token: string): Promise => { + if (!token) return null; + + const now = Date.now(); + const cached = authMap.get(token); + if (cached && (now - cached.timestamp < AUTH_CACHE_TTL)) { + return cached.user; + } + + try { + const { data: { user }, error } = await supabase.auth.getUser(token); + + if (error || !user) { + authMap.set(token, { user: null, timestamp: now }); + return null; + } + + authMap.set(token, { user, timestamp: now }); + return user; + } catch (err) { + logger.error({ err }, 'Auth Cache Error'); + return null; + } +}; + +/** Clear in-process auth cache (call after admin user ops, role changes, etc.) */ +export const flushAuthCache = (userId?: string) => { + if (!userId) { + authMap.clear(); + return; + } + // Remove entries for a specific user + for (const [token, entry] of authMap) { + if (entry.user?.id === userId) authMap.delete(token); + } +}; + +/** + * Test Supabase connection by attempting a simple query + */ +export async function testSupabaseConnection(): Promise { + try { + const { error } = await supabase.from('products').select('id').limit(1) + return !error + } catch { + return false + } +} diff --git a/src/commons/types.ts b/src/commons/types.ts new file mode 100644 index 0000000..ee7a403 --- /dev/null +++ b/src/commons/types.ts @@ -0,0 +1,10 @@ +import { Env } from 'hono' + +export interface HonoEnv extends Env { + Variables: { + jobId?: string; + userId?: string; + usageId?: string; + skipUsageStatusUpdate?: boolean; + } +} diff --git a/src/commons/websocket.ts b/src/commons/websocket.ts new file mode 100644 index 0000000..342f1c5 --- /dev/null +++ b/src/commons/websocket.ts @@ -0,0 +1,238 @@ +import { WebSocketServer, WebSocket } from 'ws'; +import { Server } from 'http'; +import fs from 'fs'; +import path from 'path'; +import chokidar from 'chokidar'; + +type MessageHandler = (ws: WebSocket, payload: any) => void; + +export class WebSocketManager { + private static instance: WebSocketManager; + private wss: WebSocketServer | null = null; + private handlers: Map = new Map(); + private writeQueue: Promise = Promise.resolve(); + + private constructor() { + // Register default handlers + this.registerHandler('log', this.handleLog.bind(this)); + this.registerHandler('echo', (ws, payload) => ws.send(JSON.stringify({ type: 'echo', payload }))); + this.registerHandler('ping', (ws, payload) => ws.send(JSON.stringify({ type: 'pong', id: payload.id }))); + } + + public static getInstance(): WebSocketManager { + if (!WebSocketManager.instance) { + WebSocketManager.instance = new WebSocketManager(); + } + return WebSocketManager.instance; + } + + public init(server: Server) { + if (this.wss) { + console.warn('WebSocketServer already initialized'); + return; + } + + this.wss = new WebSocketServer({ server, path: '/ws' }); + + this.wss.on('connection', (ws: WebSocket) => { + ws.on('message', (message: string) => { + try { + const data = JSON.parse(message.toString()); + const { command, ...payload } = data; + + if (command && this.handlers.has(command)) { + this.handlers.get(command)!(ws, payload); + } else { + console.warn('Unknown command:', command); + } + } catch (err) { + console.error('Failed to parse message:', err); + } + }); + + ws.on('close', () => { + + }); + + ws.on('error', (err) => { + console.error('WebSocket error:', err); + }); + }); + + this.initWatcher(); + } + + private initWatcher() { + // Watch for changes in canvas-page-new.json + const logDir = path.join(process.cwd(), 'data'); + // Ensure log directory exists + if (!fs.existsSync(logDir)) { + try { + fs.mkdirSync(logDir, { recursive: true }); + } catch (err) { + console.error('Failed to create log directory for watcher:', err); + } + } + + const handleFile = async (filePath: string) => { + // Ignore output files (logs) to prevent infinite loops (Frontend -> Log -> Watcher -> Frontend -> Loop) + const fileName = path.basename(filePath); + const ext = path.extname(filePath).toLowerCase(); + + // Explicitly allow only specific JSON files (layouts) to trigger updates + // Ignore everything else (logs, dumps, etc.) + if (ext === '.json') { + if (fileName !== 'canvas-page-latest-new.json' && fileName !== 'canvas-page-new.json') { + return; + } + } else if (fileName.startsWith('canvas-html-latest')) { + return; + } + + console.log(`[Watcher] File detected: ${filePath}`); + try { + const ext = path.extname(filePath).toLowerCase(); + + if (ext === '.json') { + const content = await fs.promises.readFile(filePath, 'utf-8'); + if (!content.trim()) return; // Ignore empty writes + + try { + const layoutData = JSON.parse(content); + console.log('Broadcasting layout-update (json)...'); + this.broadcast({ + type: 'layout-update', + data: layoutData + }); + } catch (parseErr) { + console.error(`Failed to parse watched JSON file: ${filePath}`, parseErr); + } + } else if (ext === '.html' || ext === '.md') { + const content = await fs.promises.readFile(filePath, 'base64'); + console.log(`Broadcasting layout-update (${ext})...`); + this.broadcast({ + type: 'layout-update', + data: content + }); + } + } catch (err) { + console.error(`Failed to process watched file ${filePath}:`, err); + } + }; + + chokidar.watch(logDir, { + persistent: true, + ignoreInitial: false, + awaitWriteFinish: { + stabilityThreshold: 100, + pollInterval: 100 + } + }) + .on('add', handleFile) + .on('change', handleFile); + } + + public registerHandler(command: string, handler: MessageHandler) { + this.handlers.set(command, handler); + } + + public broadcast(message: any) { + if (!this.wss) return; + const data = JSON.stringify(message); + this.wss.clients.forEach((client) => { + if (client.readyState === WebSocket.OPEN) { + client.send(data); + } + }); + } + + private handleLog(ws: WebSocket, payload: any) { + // Expected payload: { name: string, options?: { mode?: 'append'|'overwrite', format?: 'json'|'html'|'md' }, message: any, ...others } + const { name, id, options, ...logData } = payload; + + if (!name) { + console.warn('Log command missing "name" field'); + return; + } + + const mode = options?.mode || 'append'; + const format = options?.format || 'json'; + + const logDir = path.join(process.cwd(), 'data'); + const extension = format === 'md' ? 'md' : format === 'html' ? 'html' : 'json'; + const logFile = path.join(logDir, `${name}.${extension}`); + + // Ensure log directory exists + if (!fs.existsSync(logDir)) { + try { + fs.mkdirSync(logDir, { recursive: true }); + } catch (err) { + console.error('Failed to create log directory:', err); + return; + } + } + + // Serialize writes using the queue + this.writeQueue = this.writeQueue.then(async () => { + try { + if (format === 'json') { + if (mode === 'overwrite') { + // For overwrite (state capture), write only the message content if available + const content = (logData.message !== undefined) ? logData.message : logData; + const contentToWrite = JSON.stringify(content, null, 2); + await fs.promises.writeFile(logFile, contentToWrite); + } else { + // For append (logging), read existing, parse, append to array, write back + let records: any[] = []; + + try { + if (fs.existsSync(logFile)) { + const fileContent = await fs.promises.readFile(logFile, 'utf-8'); + if (fileContent.trim()) { + try { + const parsed = JSON.parse(fileContent); + if (Array.isArray(parsed)) { + records = parsed; + } else { + records = [parsed]; + } + } catch (e) { + // Attempt to parse as NDJSON (newline delimited JSON) + records = fileContent.split('\n') + .filter(line => line.trim()) + .map(line => { + try { return JSON.parse(line); } catch { return null; } + }) + .filter(item => item !== null); + } + } + } + } catch (readErr) { + console.warn(`Failed to read log file ${logFile}, starting fresh.`, readErr); + } + + const logEntry = { + timestamp: new Date().toISOString(), + ...logData + }; + records.push(logEntry); + + await fs.promises.writeFile(logFile, JSON.stringify(records, null, 2)); + } + } else { + // HTML or MD + const message = logData.message; + const content = typeof message === 'string' ? message : JSON.stringify(message); + + if (mode === 'append') { + await fs.promises.appendFile(logFile, content + '\n'); + } else { + await fs.promises.writeFile(logFile, content); + } + } + } catch (err) { + console.error(`Failed to write log file ${logFile}:`, err); + } + }); + } +} diff --git a/src/config/blocklist.json b/src/config/blocklist.json new file mode 100644 index 0000000..a3b975a --- /dev/null +++ b/src/config/blocklist.json @@ -0,0 +1,10 @@ +{ + "blockedIPs": [], + "blockedUserIds": [ + "user_banned_123", + "user_spam_456" + ], + "blockedTokens": [ + "Bearer malicious_token_xyz" + ] +} \ No newline at end of file diff --git a/src/config/products.ts b/src/config/products.ts new file mode 100644 index 0000000..d4b75c7 --- /dev/null +++ b/src/config/products.ts @@ -0,0 +1,137 @@ +/** + * Product and Action Mapping Configuration + * Defines all trackable products, their actions, and associated metadata + */ + +export interface ProductActionConfig { + endpoint: string; + method: string; + costUnits: number; + cancellable?: boolean; // Whether this action can be cancelled + description?: string; +} + +export interface ProductConfig { + [action: string]: ProductActionConfig; +} + +export const PRODUCT_ACTIONS: Record = { + competitors: { + search: { + endpoint: '/api/competitors', + method: 'GET', + costUnits: 1.0, + cancellable: true, // Search can be cancelled + description: 'Search for competitors in a location', + }, + get_details: { + endpoint: '/api/competitors/:place_id', + method: 'GET', + costUnits: 0.0, + cancellable: false, // Quick lookup, not cancellable + description: 'Get details for a specific competitor', + }, + stream: { + endpoint: '/api/competitors/stream', + method: 'GET', + costUnits: 1.0, // Same cost as regular search + cancellable: true, + description: 'Stream competitors in real-time', + }, + find_email: { + endpoint: '/api/find/email/{place_id}', + method: 'GET', + costUnits: 2.0, // Higher cost due to Puppeteer usage + cancellable: true, // Long-running, can be cancelled + description: 'Find email addresses for a business using Puppeteer', + }, + }, + images: { + upload: { + endpoint: '/api/images', + method: 'POST', + costUnits: 2.0, + cancellable: true, + description: 'Upload an image', + }, + get: { + endpoint: '/api/images/:id', + method: 'GET', + costUnits: 0.05, + cancellable: false, + description: 'Retrieve an image', + }, + update: { + endpoint: '/api/images/:id', + method: 'PUT', + costUnits: 1.5, + cancellable: false, + description: 'Update image metadata', + }, + }, + mock: { + job: { + endpoint: '/api/mock/job', + method: 'POST', + costUnits: 0.0, + cancellable: true, + description: 'Mock job for testing', + }, + }, + // Add more products here as they are developed +} as const; + +/** + * Match a request path and method to a product and action + */ +export function identifyProductAction(path: string, method: string): { + product: string | null; + action: string | null; + config: ProductActionConfig | null; +} { + for (const [product, actions] of Object.entries(PRODUCT_ACTIONS)) { + for (const [action, config] of Object.entries(actions)) { + if (matchesRoute(path, config.endpoint) && method === config.method) { + return { product, action, config }; + } + } + } + return { product: null, action: null, config: null }; +} + +/** + * Check if a path matches a route pattern (supports :param syntax) + */ +function matchesRoute(path: string, pattern: string): boolean { + // Convert pattern to regex + // e.g., '/api/competitors/:place_id' or '/api/competitors/{place_id}' -> /^\/api\/competitors\/[^\/]+$/ + const regexPattern = pattern + .replace(/:[^\/]+/g, '[^/]+') // Replace :param with regex + .replace(/\{[^}]+\}/g, '[^/]+') // Replace {param} with regex + .replace(/\//g, '\\/'); // Escape slashes + + // Allow optional trailing slash + const regex = new RegExp(`^${regexPattern}\\/?$`); + return regex.test(path); +} + +/** + * Get all products + */ +export function getAllProducts(): string[] { + return Object.keys(PRODUCT_ACTIONS); +} + +/** + * Get all actions for a product + */ +export function getProductActions(product: string): string[] { + return Object.keys(PRODUCT_ACTIONS[product] || {}); +} + +/** + * Get configuration for a specific product action + */ +export function getActionConfig(product: string, action: string): ProductActionConfig | null { + return PRODUCT_ACTIONS[product]?.[action] || null; +} diff --git a/src/constants.ts b/src/constants.ts new file mode 100644 index 0000000..054ff0d --- /dev/null +++ b/src/constants.ts @@ -0,0 +1 @@ +export const TEST_POST_ID = '8c1d567a-6909-4e43-b432-bd359bb10fc5'; diff --git a/src/endpoints/__tests__/admin.test.ts b/src/endpoints/__tests__/admin.test.ts new file mode 100644 index 0000000..ea34205 --- /dev/null +++ b/src/endpoints/__tests__/admin.test.ts @@ -0,0 +1,32 @@ + +import { vi, describe, it, expect, beforeEach, afterEach } from 'vitest' +import { app } from '../../index.js' // Adjust path if needed +import { AdminEndpointRegistry } from '../../commons/registry.js' + +describe('Admin Restart Endpoint', () => { + beforeEach(() => { + // Mock process.exit to prevent killing the test runner + vi.spyOn(process, 'exit').mockImplementation((code) => { + // console.log(`Mock process.exit(${code}) called`) + return undefined as never + }) + }) + + afterEach(() => { + vi.restoreAllMocks() + }) + + it('should be registered as an admin endpoint', () => { + expect(AdminEndpointRegistry.isAdmin('/api/admin/system/restart', 'POST')).toBe(true) + }) + + it('should return 401 if unauthenticated', async () => { + const res = await app.request('/api/admin/system/restart', { method: 'POST' }) + expect(res.status).toBe(401) + const body = await res.json() + expect(body).toEqual({ error: 'Unauthorized - Authentication required' }) + }) + + // Mocking a full admin user flow is complex without mocking Supabase, + // but verifying 401 proves that the middleware is intercepting the request. +}) diff --git a/src/endpoints/admin.ts b/src/endpoints/admin.ts new file mode 100644 index 0000000..bf1df4b --- /dev/null +++ b/src/endpoints/admin.ts @@ -0,0 +1,193 @@ + +import { OpenAPIHono, createRoute, z } from '@hono/zod-openapi' +import { logger } from '../commons/logger.js' +import { getBanList, unbanIP, unbanUser, getViolationStats } from '../middleware/autoBan.js' + +export const restartRoute = createRoute({ + method: 'post', + path: '/api/admin/system/restart', + tags: ['Admin'], + summary: 'Restart the server', + description: 'Exits the process with code 0, relying on systemd to restart it.', + responses: { + 200: { + description: 'Restart initiated', + content: { + 'application/json': { + schema: z.object({ + message: z.string(), + pid: z.number() + }) + } + } + } + } +}) + +export const restartHandler = async (c: any) => { + const pid = process.pid + // Use a slight delay to allow the response to be sent + setTimeout(() => { + logger.info('Exiting process for restart...') + process.exit(0) + }, 1000) + + return c.json({ + message: 'Server is restarting...', + pid + }) +} + +// Ban List Routes +export const getBanListRoute = createRoute({ + method: 'get', + path: '/api/admin/bans', + tags: ['Admin'], + summary: 'Get current ban list', + description: 'Returns all auto-banned IPs, users, and tokens', + responses: { + 200: { + description: 'Ban list retrieved', + content: { + 'application/json': { + schema: z.object({ + bannedIPs: z.array(z.string()), + bannedUserIds: z.array(z.string()), + bannedTokens: z.array(z.string()) + }) + } + } + } + } +}) + +export const getBanListHandler = async (c: any) => { + const banList = getBanList() + logger.info({ user: c.get('user') }, 'Admin retrieved ban list') + return c.json(banList) +} + +export const unbanIPRoute = createRoute({ + method: 'post', + path: '/api/admin/bans/unban-ip', + tags: ['Admin'], + summary: 'Unban an IP address', + description: 'Removes an IP from the auto-ban list', + request: { + body: { + content: { + 'application/json': { + schema: z.object({ + ip: z.string() + }) + } + } + } + }, + responses: { + 200: { + description: 'IP unbanned successfully', + content: { + 'application/json': { + schema: z.object({ + success: z.boolean(), + message: z.string() + }) + } + } + } + } +}) + +export const unbanIPHandler = async (c: any) => { + const { ip } = await c.req.json() + const success = unbanIP(ip) + logger.info({ user: c.get('user'), ip, success }, 'Admin attempted to unban IP') + + return c.json({ + success, + message: success ? `IP ${ip} has been unbanned` : `IP ${ip} was not found in ban list` + }) +} + +export const unbanUserRoute = createRoute({ + method: 'post', + path: '/api/admin/bans/unban-user', + tags: ['Admin'], + summary: 'Unban a user', + description: 'Removes a user from the auto-ban list', + request: { + body: { + content: { + 'application/json': { + schema: z.object({ + userId: z.string() + }) + } + } + } + }, + responses: { + 200: { + description: 'User unbanned successfully', + content: { + 'application/json': { + schema: z.object({ + success: z.boolean(), + message: z.string() + }) + } + } + } + } +}) + +export const unbanUserHandler = async (c: any) => { + const { userId } = await c.req.json() + const success = unbanUser(userId) + logger.info({ user: c.get('user'), userId, success }, 'Admin attempted to unban user') + + return c.json({ + success, + message: success ? `User ${userId} has been unbanned` : `User ${userId} was not found in ban list` + }) +} + +export const getViolationStatsRoute = createRoute({ + method: 'get', + path: '/api/admin/bans/violations', + tags: ['Admin'], + summary: 'Get violation statistics', + description: 'Returns current violation tracking data', + responses: { + 200: { + description: 'Violation stats retrieved', + content: { + 'application/json': { + schema: z.object({ + totalViolations: z.number(), + violations: z.array(z.object({ + key: z.string(), + count: z.number(), + firstViolation: z.number(), + lastViolation: z.number() + })) + }) + } + } + } + } +}) + +export const getViolationStatsHandler = async (c: any) => { + const stats = getViolationStats() + return c.json(stats) +} + +export const registerAdminRoutes = (app: OpenAPIHono) => { + app.openapi(restartRoute, restartHandler) + app.openapi(getBanListRoute, getBanListHandler) + app.openapi(unbanIPRoute, unbanIPHandler) + app.openapi(unbanUserRoute, unbanUserHandler) + app.openapi(getViolationStatsRoute, getViolationStatsHandler) +} diff --git a/src/endpoints/boss.ts b/src/endpoints/boss.ts new file mode 100644 index 0000000..fee5cac --- /dev/null +++ b/src/endpoints/boss.ts @@ -0,0 +1,304 @@ +import { createRoute, OpenAPIHono, z } from '@hono/zod-openapi'; +import { RouteHandler } from '@hono/zod-openapi'; +import { boss } from '../jobs/boss/client.js'; +import { QUEUE_MOCK_JOB } from '../jobs/boss/workers.js'; +import { HonoEnv } from '../commons/types.js'; + +const tags = ['PgBoss']; + +export const postBossJobRoute = createRoute({ + method: 'post', + path: '/api/boss/job', + tags, + request: { + body: { + content: { + 'application/json': { + schema: z.object({ + delayMs: z.number().default(100), + shouldFail: z.boolean().default(false), + retryLimit: z.number().optional() + }), + }, + }, + }, + }, + responses: { + 200: { + content: { + 'application/json': { + schema: z.object({ + jobId: z.string().nullable(), + message: z.string() + }), + }, + }, + description: 'PgBoss job started', + }, + 500: { + content: { + 'application/json': { + schema: z.object({ error: z.string() }), + }, + }, + description: 'Server error', + }, + }, +}); + +export const postBossJobHandler: RouteHandler = async (c) => { + if (!boss) { + // Check if there was an initialization error we can report + const { bossInitError } = await import('../jobs/boss/client.js'); + return c.json({ error: `PgBoss not initialized. Init error: ${bossInitError}` }, 500); + } + + const { delayMs, shouldFail, retryLimit } = c.req.valid('json'); + const payload = { delayMs, shouldFail }; + const options = retryLimit !== undefined ? { retryLimit } : {}; + try { + const jobId = await boss.send(QUEUE_MOCK_JOB, payload, options); + return c.json({ jobId, message: 'Job submitted to PgBoss' }, 200); + } catch (error: any) { + return c.json({ error: error.message }, 500); + } +}; + +export const getBossJobRoute = createRoute({ + method: 'get', + path: '/api/boss/job/{id}', + tags, + request: { + params: z.object({ + id: z.string(), + }), + }, + responses: { + 200: { + content: { + 'application/json': { + schema: z.object({ + id: z.string(), + name: z.string(), + data: z.any(), + state: z.string(), + createdOn: z.string().optional(), + startedOn: z.string().optional(), + completedOn: z.string().optional(), + }), + }, + }, + description: 'Job status', + }, + 404: { + content: { + 'application/json': { + schema: z.object({ error: z.string() }), + }, + }, + description: 'Job not found', + }, + 500: { + content: { + 'application/json': { + schema: z.object({ error: z.string() }), + }, + }, + description: 'Server error', + }, + }, +}); + +export const getBossJobHandler: RouteHandler = async (c) => { + const { id } = c.req.valid('param'); + + // Use pg directly to bypass PostgREST schema permissions + const { Client } = await import('pg'); + const client = new Client({ connectionString: process.env.DATABASE_URL, }); + + try { + await client.connect(); + const result = await client.query('SELECT * FROM pgboss.job WHERE id = $1', [id]); + const job = result.rows[0]; + + if (!job) { + return c.json({ error: 'Job not found' }, 404); + } + + return c.json({ + id: job.id, + name: job.name, + data: job.data, + state: job.state, + createdOn: job.createdon, + startedOn: job.startedon, + completedOn: job.completedon, + output: job.output, + }, 200); + } catch (error: any) { + console.error('Error in getBossJobHandler:', error); + return c.json({ error: error.message }, 500); + } finally { + await client.end().catch(() => { }); + } +}; + +export const cancelBossJobRoute = createRoute({ + method: 'post', + path: '/api/boss/job/{id}/cancel', + tags, + request: { + params: z.object({ + id: z.string(), + }), + }, + responses: { + 200: { + content: { + 'application/json': { + schema: z.object({ message: z.string() }), + }, + }, + description: 'Job cancelled', + }, + 500: { + content: { + 'application/json': { + schema: z.object({ error: z.string() }), + }, + }, + description: 'Server error', + }, + }, +}); + +export const cancelBossJobHandler: RouteHandler = async (c) => { + if (!boss) return c.json({ error: 'PgBoss not initialized' }, 500); + const { id } = c.req.valid('param'); + try { + await boss.cancel(QUEUE_MOCK_JOB, id); + return c.json({ message: 'Job cancelled' }, 200); + } catch (error: any) { + return c.json({ error: error.message }, 500); + } +}; + +export const resumeBossJobRoute = createRoute({ + method: 'post', + path: '/api/boss/job/{id}/resume', + tags, + request: { + params: z.object({ + id: z.string(), + }), + }, + responses: { + 200: { + content: { + 'application/json': { + schema: z.object({ message: z.string() }), + }, + }, + description: 'Job resumed', + }, + 500: { + content: { + 'application/json': { + schema: z.object({ error: z.string() }), + }, + }, + description: 'Server error', + }, + }, +}); + +export const resumeBossJobHandler: RouteHandler = async (c) => { + if (!boss) return c.json({ error: 'PgBoss not initialized' }, 500); + const { id } = c.req.valid('param'); + try { + await boss.resume(QUEUE_MOCK_JOB, id); + return c.json({ message: 'Job resumed' }, 200); + } catch (error: any) { + return c.json({ error: error.message }, 500); + } +}; + +export const completeBossJobRoute = createRoute({ + method: 'post', + path: '/api/boss/job/{id}/complete', + tags, + request: { + params: z.object({ + id: z.string(), + }), + }, + responses: { + 200: { + content: { + 'application/json': { + schema: z.object({ message: z.string() }), + }, + }, + description: 'Job completed', + }, + 500: { + content: { + 'application/json': { + schema: z.object({ error: z.string() }), + }, + }, + description: 'Server error', + }, + }, +}); + +export const completeBossJobHandler: RouteHandler = async (c) => { + if (!boss) return c.json({ error: 'PgBoss not initialized' }, 500); + const { id } = c.req.valid('param'); + try { + await boss.complete(QUEUE_MOCK_JOB, id); + return c.json({ message: 'Job completed' }, 200); + } catch (error: any) { + return c.json({ error: error.message }, 500); + } +}; + +export const failBossJobRoute = createRoute({ + method: 'post', + path: '/api/boss/job/{id}/fail', + tags, + request: { + params: z.object({ + id: z.string(), + }), + }, + responses: { + 200: { + content: { + 'application/json': { + schema: z.object({ message: z.string() }), + }, + }, + description: 'Job failed', + }, + 500: { + content: { + 'application/json': { + schema: z.object({ error: z.string() }), + }, + }, + description: 'Server error', + }, + }, +}); + +export const failBossJobHandler: RouteHandler = async (c) => { + if (!boss) return c.json({ error: 'PgBoss not initialized' }, 500); + const { id } = c.req.valid('param'); + try { + await boss.fail(QUEUE_MOCK_JOB, id); + return c.json({ message: 'Job failed' }, 200); + } catch (error: any) { + return c.json({ error: error.message }, 500); + } +}; diff --git a/src/endpoints/stream.ts b/src/endpoints/stream.ts new file mode 100644 index 0000000..f4990c8 --- /dev/null +++ b/src/endpoints/stream.ts @@ -0,0 +1,87 @@ +import { createRouteBody } from '../products/serving/routes.js'; +import { Context } from 'hono'; +import { streamSSE } from 'hono/streaming'; +import { z } from '@hono/zod-openapi'; +import { appEvents, AppEvent } from '../events.js'; +import { logger } from '../commons/logger.js'; + +export const getStreamRoute = createRouteBody( + 'get', + '/api/stream', + ['System'], + 'Stream System Events', + 'Subscribe to real-time updates for categories, posts, and pages.', + undefined, + { + 200: { + description: 'Event Stream', + content: { + 'text/event-stream': { + schema: z.string() + } + } + } + }, + true // public +); + +// Track active connections +const connectedClients = new Set<{ + id: string; + stream: any; // Hono SSEStreamingApi +}>(); + +// Single listener for the entire application +const broadcastAppUpdate = async (event: AppEvent) => { + const payload = JSON.stringify(event); + for (const client of connectedClients) { + try { + await client.stream.writeSSE({ + event: event.kind, + data: payload + }); + } catch (err) { + logger.error({ err, clientId: client.id }, 'Error broadcasting to stream'); + // Client will be removed by the onAbort handler in the stream handler + } + } +}; + +// Subscribe once +appEvents.on('app-update', broadcastAppUpdate); + +export const streamHandler = async (c: Context) => { + return streamSSE(c, async (stream) => { + const id = crypto.randomUUID(); + const client = { id, stream }; + + connectedClients.add(client); + // Send initial connection message + await stream.writeSSE({ + event: 'connected', + data: JSON.stringify({ message: 'Connected to event stream', clientId: id }) + }); + + // Keep connection alive & handle cleanup + let interval: NodeJS.Timeout; + const heartbeatInterval = parseInt(process.env.STREAM_HEARTBEAT_INTERVAL_MS || '30000', 10); + + // Send heartbeat to prevent timeouts + interval = setInterval(async () => { + try { + await stream.writeSSE({ event: 'ping', data: '' }); + } catch (e) { + // connection likely closed + } + }, heartbeatInterval); + + // Wait until the stream is aborted + await new Promise((resolve) => { + stream.onAbort(() => { + connectedClients.delete(client); + clearInterval(interval); + resolve(); + }); + }); + }); +}; diff --git a/src/events.ts b/src/events.ts new file mode 100644 index 0000000..0493c8b --- /dev/null +++ b/src/events.ts @@ -0,0 +1,43 @@ +import { EventEmitter } from 'events'; + + +export type EventType = 'category' | 'post' | 'page' | 'system' | string; + +export interface AppEvent { + type: EventType; + kind: 'cache' | 'system' | 'chat' | 'other'; + action: 'create' | 'update' | 'delete'; + id?: string | null; // Entity ID for per-item invalidation + data: any; + timestamp: number; +} + +class AppEvents extends EventEmitter { + private static instance: AppEvents; + + private constructor() { + super(); + // this.setMaxListeners(10); // Default is fine now + } + + public static getInstance(): AppEvents { + if (!AppEvents.instance) { + AppEvents.instance = new AppEvents(); + } + return AppEvents.instance; + } + + public emitUpdate(type: EventType, action: 'create' | 'update' | 'delete', data: any, kind: AppEvent['kind'] = 'cache') { + const event: AppEvent = { + kind, + type, + action, + id: data?.id ?? null, + data, + timestamp: Date.now() + }; + this.emit('app-update', event); + } +} + +export const appEvents = AppEvents.getInstance(); diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..7028841 --- /dev/null +++ b/src/index.ts @@ -0,0 +1,271 @@ + +import { z } from './zod-setup.js' +import { serve } from '@hono/node-server' +import { OpenAPIHono } from '@hono/zod-openapi' +import { swaggerUI } from '@hono/swagger-ui' +import { Scalar } from '@scalar/hono-api-reference' +import { cors } from 'hono/cors' +import dotenv from 'dotenv' +import path from 'path' + +// Load environment variables based on NODE_ENV +const envFile = process.env.NODE_ENV === 'production' ? '.env.production' : '.env' +dotenv.config({ path: path.resolve(process.cwd(), envFile) }) + +import { logger } from './commons/logger.js' +import { WebSocketManager } from './commons/websocket.js'; + +// Import middleware +import { blocklistMiddleware } from './middleware/blocklist.js' +import { autoBanMiddleware } from './middleware/autoBan.js' +import { optionalAuthMiddleware, adminMiddleware } from './middleware/auth.js' +import { analyticsMiddleware } from './middleware/analytics.js' +import { apiRateLimiter } from './middleware/rateLimiter.js' + +import { compress } from 'hono/compress' +import { secureHeaders } from 'hono/secure-headers' + +// Import endpoints + +import { registerProductRoutes, startProducts } from './products/registry.js' + +const app = new OpenAPIHono() +// Middleware +app.use('/*', cors({ + origin: '*', + allowMethods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'], + allowHeaders: ['Content-Type', 'Authorization', 'x-stainless-os', 'x-stainless-lang', 'x-stainless-arch', 'x-stainless-package-version', 'x-stainless-runtime', 'x-stainless-runtime-version', 'x-stainless-helper-method', 'x-stainless-retry-count'], + exposeHeaders: ['Content-Length', 'X-Cache'], + maxAge: 600, + credentials: true, +})) + +// Apply blocklist to all API routes (before rate limiting) +//app.use('/api/*', blocklistMiddleware) +// Apply auto-ban middleware (checks ban.json for auto-banned IPs/users) +// app.use('/api/*', autoBanMiddleware) +// Apply Analytics (tracks requests to file) +app.use('*', analyticsMiddleware) + +// Apply Authentication & Authorization +app.use('/api/*', optionalAuthMiddleware) +app.use('/api/*', adminMiddleware) +// app.use('/api/*', apiRateLimiter) + +// Apply compression to all API routes +// Apply compression to all routes (API + Static Assets) +app.use('*', compress()) +app.use(secureHeaders({ + crossOriginResourcePolicy: false, + crossOriginOpenerPolicy: false, + crossOriginEmbedderPolicy: false, + xFrameOptions: false, + contentSecurityPolicy: { + frameAncestors: ["'self'", "*"] + } +})) + + +// Register API routes +import { createLogRoutes, createLogHandlers } from './commons/log-routes-factory.js' +import { registerAssetRoutes } from './serve-assets.js' + +// System Logs +const { getRoute: sysGetLogRoute, streamRoute: sysStreamLogRoute } = createLogRoutes('System', '/api/logs/system'); +const { getHandler: sysGetLogHandler, streamHandler: sysStreamLogHandler } = createLogHandlers(path.join(process.cwd(), 'app.log')); + +app.openapi(sysGetLogRoute, sysGetLogHandler); +app.openapi(sysStreamLogRoute, sysStreamLogHandler); + +// Register Product Routes + +await registerProductRoutes(app) +// Initialize Products +// Products initialized after PgBoss check below + + +// API Documentation (Development Only) +const isDevelopment = process.env.NODE_ENV !== 'production'; + +if (isDevelopment) { + logger.info('Registering API documentation endpoints (development mode)'); + + // Swagger UI + app.doc31('/doc', { + openapi: '3.1.0', + info: { + version: '1.0.0', + title: 'Images API', + }, + components: { + securitySchemes: { + bearerAuth: { + type: 'http', + scheme: 'bearer', + bearerFormat: 'JWT', + }, + }, + }, + security: [ + { + bearerAuth: [], + }, + ], + } as any); + + // Swagger UI + app.get('/ui', swaggerUI({ url: '/doc' })); + + // Scalar API Reference + app.get('/reference', Scalar({ + spec: { + url: '/doc', + }, + authentication: { + preferredSecurityScheme: 'bearerAuth', + httpBearer: { + token: process.env.SCALAR_AUTH_TOKEN || '', + }, + }, + } as any)); + + // Alternative: API Reference at /api/reference + app.get('/api/reference', Scalar({ + spec: { + url: '/doc', + }, + authentication: { + preferredSecurityScheme: 'bearerAuth', + httpBearer: { + token: process.env.SCALAR_AUTH_TOKEN || '', + } + }, + } as any)); +} else { + logger.info('API documentation endpoints disabled (production mode)'); +} + +import { + postBossJobRoute, postBossJobHandler, + getBossJobRoute, getBossJobHandler, + cancelBossJobRoute, cancelBossJobHandler, + resumeBossJobRoute, resumeBossJobHandler, + completeBossJobRoute, completeBossJobHandler, + failBossJobRoute, failBossJobHandler +} from './endpoints/boss.js' + +import { startBoss } from './jobs/boss/client.js' +import { registerMockWorkers } from './jobs/boss/workers.js' + + +// Register PgBoss routes +// @ts-ignore - Route type mismatch +app.openapi(postBossJobRoute, postBossJobHandler) +// @ts-ignore - Route type mismatch +app.openapi(getBossJobRoute, getBossJobHandler) +// @ts-ignore - Route type mismatch +app.openapi(cancelBossJobRoute, cancelBossJobHandler) +// @ts-ignore - Route type mismatch +app.openapi(resumeBossJobRoute, resumeBossJobHandler) +// @ts-ignore - Route type mismatch +app.openapi(completeBossJobRoute, completeBossJobHandler) +// @ts-ignore - Route type mismatch +app.openapi(failBossJobRoute, failBossJobHandler) + +// Register Streaming Route +import { getStreamRoute, streamHandler } from './endpoints/stream.js' +app.openapi(getStreamRoute, streamHandler) + +// Register Admin Routes +import { registerAdminRoutes } from './endpoints/admin.js' +import { AdminEndpointRegistry } from './commons/registry.js' + +// Register restart endpoint as admin-only +AdminEndpointRegistry.register('/api/admin/system/restart', 'POST') +// Register ban management endpoints as admin-only +AdminEndpointRegistry.register('/api/admin/bans', 'GET') +AdminEndpointRegistry.register('/api/admin/bans/unban-ip', 'POST') +AdminEndpointRegistry.register('/api/admin/bans/unban-user', 'POST') +AdminEndpointRegistry.register('/api/admin/bans/violations', 'GET') +AdminEndpointRegistry.register('/api/analytics', 'GET') +AdminEndpointRegistry.register('/api/analytics/stream', 'GET') +AdminEndpointRegistry.register('/api/analytics', 'DELETE') + + +registerAdminRoutes(app) + +// Register Asset Routes (Static files, SW, SPA fallback) +// IMPORTANT: This MUST be registered AFTER all API routes to prevent the catch-all from intercepting API calls +registerAssetRoutes(app); + + +// Initialize PgBoss +// Initialize PgBoss and Products +try { + const boss = await startBoss(); + if (boss) { + registerMockWorkers(); + try { + await startProducts(boss); + } catch (err) { + logger.error({ err }, 'Failed to init products with Boss'); + } + } else { + // Fallback: Start products without Boss + logger.info('Starting products without PgBoss'); + await startProducts(); + } +} catch (err) { + logger.error({ err }, 'Failed to init PgBoss'); + // Fallback: Start products without Boss on error + logger.info('Starting products without PgBoss (after error)'); + await startProducts(); +} + +const port = parseInt(process.env.PORT || '3333', 10) +logger.info(`Server is running on port ${port}`) +// Only start the server if not in test mode +if (process.env.NODE_ENV !== 'test' && !process.env.VITEST) { + const server = serve({ + fetch: app.fetch, + port + }) + + // Initialize WebSocket Server + if (process.env.ENABLE_WEBSOCKETS === 'true') { + WebSocketManager.getInstance().init(server as any); + } + + let isShuttingDown = false; + const gracefulShutdown = (signal: string) => { + if (isShuttingDown) { + logger.warn('Already shutting down...'); + return; + } + isShuttingDown = true; + + // Force exit after a timeout + const timeout = setTimeout(() => { + logger.warn('Shutdown timed out. Forcing exit.'); + process.exit(1); + }, 5000); + + server.close(async (err) => { + if (err) { + logger.error({ err }, 'Error closing HTTP server'); + } else { + console.log('HTTP server closed.'); + } + + clearTimeout(timeout); + console.log('Gracefully shut down.'); + process.exit(err ? 1 : 0); + }); + }; + + process.on('SIGINT', () => gracefulShutdown('SIGINT')); + process.on('SIGTERM', () => gracefulShutdown('SIGTERM')); + process.on('SIGBREAK', () => gracefulShutdown('SIGBREAK')); // For Windows +} + +export { app } diff --git a/src/integrations/supabase/schemas.ts b/src/integrations/supabase/schemas.ts new file mode 100644 index 0000000..1e3ddb8 --- /dev/null +++ b/src/integrations/supabase/schemas.ts @@ -0,0 +1,1619 @@ +/* + * ========================================== + * | GENERATED BY SUPAZOD | + * ========================================== + */ + +import { z } from "zod"; + +export const publicAppPermissionSchema = z.union([ + z.literal("pictures.read"), + z.literal("pictures.create"), + z.literal("pictures.update"), + z.literal("pictures.delete"), + z.literal("collections.read"), + z.literal("collections.create"), + z.literal("collections.update"), + z.literal("collections.delete"), + z.literal("comments.read"), + z.literal("comments.create"), + z.literal("comments.update"), + z.literal("comments.delete"), + z.literal("organization.manage"), +]); + +export const publicAppRoleSchema = z.union([ + z.literal("owner"), + z.literal("admin"), + z.literal("member"), + z.literal("viewer"), +]); + +export const publicCastKindSchema = z.union([ + z.literal("implicit"), + z.literal("explicit"), + z.literal("lossy"), +]); + +export const publicCategoryRelationTypeSchema = z.union([ + z.literal("generalization"), + z.literal("material_usage"), + z.literal("domain"), + z.literal("process_step"), + z.literal("standard"), + z.literal("other"), +]); + +export const publicCategoryVisibilitySchema = z.union([ + z.literal("public"), + z.literal("unlisted"), + z.literal("private"), +]); + +export const publicCollaboratorRoleSchema = z.union([ + z.literal("viewer"), + z.literal("editor"), + z.literal("owner"), +]); + +export const publicLayoutVisibilitySchema = z.union([ + z.literal("public"), + z.literal("private"), + z.literal("listed"), + z.literal("custom"), +]); + +export const publicTypeKindSchema = z.union([ + z.literal("primitive"), + z.literal("enum"), + z.literal("flags"), + z.literal("structure"), + z.literal("alias"), + z.literal("field"), +]); + +export const publicTypeVisibilitySchema = z.union([ + z.literal("public"), + z.literal("private"), + z.literal("custom"), +]); + +export const jsonSchema: z.ZodType = z.lazy(() => + z + .union([ + z.string(), + z.number(), + z.boolean(), + z.record(z.string(), z.union([jsonSchema, z.undefined()])), + z.array(jsonSchema), + ]) + .nullable(), +); + +export const publicCategoriesRowSchema = z.object({ + created_at: z.string(), + description: z.string().nullable(), + id: z.string(), + meta: jsonSchema.nullable(), + name: z.string(), + owner_id: z.string().nullable(), + slug: z.string(), + updated_at: z.string(), + visibility: publicCategoryVisibilitySchema, +}); + +export const publicCategoriesInsertSchema = z.object({ + created_at: z.string().optional(), + description: z.string().optional().nullable(), + id: z.string().optional(), + meta: jsonSchema.optional().nullable(), + name: z.string(), + owner_id: z.string().optional().nullable(), + slug: z.string(), + updated_at: z.string().optional(), + visibility: publicCategoryVisibilitySchema.optional(), +}); + +export const publicCategoriesUpdateSchema = z.object({ + created_at: z.string().optional(), + description: z.string().optional().nullable(), + id: z.string().optional(), + meta: jsonSchema.optional().nullable(), + name: z.string().optional(), + owner_id: z.string().optional().nullable(), + slug: z.string().optional(), + updated_at: z.string().optional(), + visibility: publicCategoryVisibilitySchema.optional(), +}); + +export const publicCategoryRelationsRowSchema = z.object({ + child_category_id: z.string(), + created_at: z.string(), + parent_category_id: z.string(), + relation_type: publicCategoryRelationTypeSchema, +}); + +export const publicCategoryRelationsInsertSchema = z.object({ + child_category_id: z.string(), + created_at: z.string().optional(), + parent_category_id: z.string(), + relation_type: publicCategoryRelationTypeSchema, +}); + +export const publicCategoryRelationsUpdateSchema = z.object({ + child_category_id: z.string().optional(), + created_at: z.string().optional(), + parent_category_id: z.string().optional(), + relation_type: publicCategoryRelationTypeSchema.optional(), +}); + +export const publicCategoryRelationsRelationshipsSchema = z.tuple([ + z.object({ + foreignKeyName: z.literal("category_relations_child_category_id_fkey"), + columns: z.tuple([z.literal("child_category_id")]), + isOneToOne: z.literal(false), + referencedRelation: z.literal("categories"), + referencedColumns: z.tuple([z.literal("id")]), + }), + z.object({ + foreignKeyName: z.literal("category_relations_parent_category_id_fkey"), + columns: z.tuple([z.literal("parent_category_id")]), + isOneToOne: z.literal(false), + referencedRelation: z.literal("categories"), + referencedColumns: z.tuple([z.literal("id")]), + }), +]); + +export const publicCollectionPicturesRowSchema = z.object({ + added_at: z.string(), + collection_id: z.string(), + id: z.string(), + picture_id: z.string(), +}); + +export const publicCollectionPicturesInsertSchema = z.object({ + added_at: z.string().optional(), + collection_id: z.string(), + id: z.string().optional(), + picture_id: z.string(), +}); + +export const publicCollectionPicturesUpdateSchema = z.object({ + added_at: z.string().optional(), + collection_id: z.string().optional(), + id: z.string().optional(), + picture_id: z.string().optional(), +}); + +export const publicCollectionPicturesRelationshipsSchema = z.tuple([ + z.object({ + foreignKeyName: z.literal("collection_pictures_collection_id_fkey"), + columns: z.tuple([z.literal("collection_id")]), + isOneToOne: z.literal(false), + referencedRelation: z.literal("collections"), + referencedColumns: z.tuple([z.literal("id")]), + }), + z.object({ + foreignKeyName: z.literal("collection_pictures_picture_id_fkey"), + columns: z.tuple([z.literal("picture_id")]), + isOneToOne: z.literal(false), + referencedRelation: z.literal("pictures"), + referencedColumns: z.tuple([z.literal("id")]), + }), +]); + +export const publicCollectionPostsRowSchema = z.object({ + collection_id: z.string(), + created_at: z.string(), + id: z.string(), + post_id: z.string(), +}); + +export const publicCollectionPostsInsertSchema = z.object({ + collection_id: z.string(), + created_at: z.string().optional(), + id: z.string().optional(), + post_id: z.string(), +}); + +export const publicCollectionPostsUpdateSchema = z.object({ + collection_id: z.string().optional(), + created_at: z.string().optional(), + id: z.string().optional(), + post_id: z.string().optional(), +}); + +export const publicCollectionPostsRelationshipsSchema = z.tuple([ + z.object({ + foreignKeyName: z.literal("collection_posts_collection_id_fkey"), + columns: z.tuple([z.literal("collection_id")]), + isOneToOne: z.literal(false), + referencedRelation: z.literal("collections"), + referencedColumns: z.tuple([z.literal("id")]), + }), + z.object({ + foreignKeyName: z.literal("collection_posts_post_id_fkey"), + columns: z.tuple([z.literal("post_id")]), + isOneToOne: z.literal(false), + referencedRelation: z.literal("posts"), + referencedColumns: z.tuple([z.literal("id")]), + }), +]); + +export const publicCollectionsRowSchema = z.object({ + content: jsonSchema.nullable(), + created_at: z.string(), + description: z.string().nullable(), + id: z.string(), + is_public: z.boolean(), + layout: jsonSchema.nullable(), + name: z.string(), + slug: z.string(), + updated_at: z.string(), + user_id: z.string(), +}); + +export const publicCollectionsInsertSchema = z.object({ + content: jsonSchema.optional().nullable(), + created_at: z.string().optional(), + description: z.string().optional().nullable(), + id: z.string().optional(), + is_public: z.boolean().optional(), + layout: jsonSchema.optional().nullable(), + name: z.string(), + slug: z.string(), + updated_at: z.string().optional(), + user_id: z.string(), +}); + +export const publicCollectionsUpdateSchema = z.object({ + content: jsonSchema.optional().nullable(), + created_at: z.string().optional(), + description: z.string().optional().nullable(), + id: z.string().optional(), + is_public: z.boolean().optional(), + layout: jsonSchema.optional().nullable(), + name: z.string().optional(), + slug: z.string().optional(), + updated_at: z.string().optional(), + user_id: z.string().optional(), +}); + +export const publicCommentLikesRowSchema = z.object({ + comment_id: z.string(), + created_at: z.string(), + id: z.string(), + user_id: z.string(), +}); + +export const publicCommentLikesInsertSchema = z.object({ + comment_id: z.string(), + created_at: z.string().optional(), + id: z.string().optional(), + user_id: z.string(), +}); + +export const publicCommentLikesUpdateSchema = z.object({ + comment_id: z.string().optional(), + created_at: z.string().optional(), + id: z.string().optional(), + user_id: z.string().optional(), +}); + +export const publicCommentsRowSchema = z.object({ + content: z.string(), + created_at: z.string(), + id: z.string(), + likes_count: z.number().nullable(), + parent_comment_id: z.string().nullable(), + picture_id: z.string(), + updated_at: z.string(), + user_id: z.string(), +}); + +export const publicCommentsInsertSchema = z.object({ + content: z.string(), + created_at: z.string().optional(), + id: z.string().optional(), + likes_count: z.number().optional().nullable(), + parent_comment_id: z.string().optional().nullable(), + picture_id: z.string(), + updated_at: z.string().optional(), + user_id: z.string(), +}); + +export const publicCommentsUpdateSchema = z.object({ + content: z.string().optional(), + created_at: z.string().optional(), + id: z.string().optional(), + likes_count: z.number().optional().nullable(), + parent_comment_id: z.string().optional().nullable(), + picture_id: z.string().optional(), + updated_at: z.string().optional(), + user_id: z.string().optional(), +}); + +export const publicCommentsRelationshipsSchema = z.tuple([ + z.object({ + foreignKeyName: z.literal("comments_parent_fk"), + columns: z.tuple([z.literal("parent_comment_id")]), + isOneToOne: z.literal(false), + referencedRelation: z.literal("comments"), + referencedColumns: z.tuple([z.literal("id")]), + }), +]); + +export const publicContextDefinitionsRowSchema = z.object({ + created_at: z.string().nullable(), + default_filters: jsonSchema, + default_templates: jsonSchema, + description: z.string().nullable(), + display_name: z.string(), + icon: z.string().nullable(), + id: z.string(), + is_active: z.boolean().nullable(), + name: z.string(), + updated_at: z.string().nullable(), +}); + +export const publicContextDefinitionsInsertSchema = z.object({ + created_at: z.string().optional().nullable(), + default_filters: jsonSchema.optional(), + default_templates: jsonSchema.optional(), + description: z.string().optional().nullable(), + display_name: z.string(), + icon: z.string().optional().nullable(), + id: z.string().optional(), + is_active: z.boolean().optional().nullable(), + name: z.string(), + updated_at: z.string().optional().nullable(), +}); + +export const publicContextDefinitionsUpdateSchema = z.object({ + created_at: z.string().optional().nullable(), + default_filters: jsonSchema.optional(), + default_templates: jsonSchema.optional(), + description: z.string().optional().nullable(), + display_name: z.string().optional(), + icon: z.string().optional().nullable(), + id: z.string().optional(), + is_active: z.boolean().optional().nullable(), + name: z.string().optional(), + updated_at: z.string().optional().nullable(), +}); + +export const publicFilterUsageLogsRowSchema = z.object({ + context: z.string(), + created_at: z.string().nullable(), + error_message: z.string().nullable(), + filters_applied: z.array(z.string()).nullable(), + id: z.string(), + input_length: z.number(), + model: z.string(), + output_length: z.number(), + processing_time_ms: z.number(), + provider: z.string(), + success: z.boolean(), + template_id: z.string().nullable(), + user_id: z.string().nullable(), +}); + +export const publicFilterUsageLogsInsertSchema = z.object({ + context: z.string(), + created_at: z.string().optional().nullable(), + error_message: z.string().optional().nullable(), + filters_applied: z.array(z.string()).optional().nullable(), + id: z.string().optional(), + input_length: z.number(), + model: z.string(), + output_length: z.number(), + processing_time_ms: z.number(), + provider: z.string(), + success: z.boolean(), + template_id: z.string().optional().nullable(), + user_id: z.string().optional().nullable(), +}); + +export const publicFilterUsageLogsUpdateSchema = z.object({ + context: z.string().optional(), + created_at: z.string().optional().nullable(), + error_message: z.string().optional().nullable(), + filters_applied: z.array(z.string()).optional().nullable(), + id: z.string().optional(), + input_length: z.number().optional(), + model: z.string().optional(), + output_length: z.number().optional(), + processing_time_ms: z.number().optional(), + provider: z.string().optional(), + success: z.boolean().optional(), + template_id: z.string().optional().nullable(), + user_id: z.string().optional().nullable(), +}); + +export const publicFilterUsageLogsRelationshipsSchema = z.tuple([ + z.object({ + foreignKeyName: z.literal("filter_usage_logs_template_id_fkey"), + columns: z.tuple([z.literal("template_id")]), + isOneToOne: z.literal(false), + referencedRelation: z.literal("user_templates"), + referencedColumns: z.tuple([z.literal("id")]), + }), +]); + +export const publicLayoutsRowSchema = z.object({ + created_at: z.string(), + id: z.string(), + is_predefined: z.boolean().nullable(), + layout_json: jsonSchema, + meta: jsonSchema.nullable(), + name: z.string(), + owner_id: z.string(), + type: z.string().nullable(), + updated_at: z.string(), + visibility: publicLayoutVisibilitySchema, +}); + +export const publicLayoutsInsertSchema = z.object({ + created_at: z.string().optional(), + id: z.string().optional(), + is_predefined: z.boolean().optional().nullable(), + layout_json: jsonSchema, + meta: jsonSchema.optional().nullable(), + name: z.string(), + owner_id: z.string(), + type: z.string().optional().nullable(), + updated_at: z.string().optional(), + visibility: publicLayoutVisibilitySchema.optional(), +}); + +export const publicLayoutsUpdateSchema = z.object({ + created_at: z.string().optional(), + id: z.string().optional(), + is_predefined: z.boolean().optional().nullable(), + layout_json: jsonSchema.optional(), + meta: jsonSchema.optional().nullable(), + name: z.string().optional(), + owner_id: z.string().optional(), + type: z.string().optional().nullable(), + updated_at: z.string().optional(), + visibility: publicLayoutVisibilitySchema.optional(), +}); + +export const publicLikesRowSchema = z.object({ + created_at: z.string(), + id: z.string(), + picture_id: z.string(), + user_id: z.string(), +}); + +export const publicLikesInsertSchema = z.object({ + created_at: z.string().optional(), + id: z.string().optional(), + picture_id: z.string(), + user_id: z.string(), +}); + +export const publicLikesUpdateSchema = z.object({ + created_at: z.string().optional(), + id: z.string().optional(), + picture_id: z.string().optional(), + user_id: z.string().optional(), +}); + +export const publicOrganizationsRowSchema = z.object({ + created_at: z.string(), + id: z.string(), + name: z.string(), + slug: z.string(), + updated_at: z.string(), +}); + +export const publicOrganizationsInsertSchema = z.object({ + created_at: z.string().optional(), + id: z.string().optional(), + name: z.string(), + slug: z.string(), + updated_at: z.string().optional(), +}); + +export const publicOrganizationsUpdateSchema = z.object({ + created_at: z.string().optional(), + id: z.string().optional(), + name: z.string().optional(), + slug: z.string().optional(), + updated_at: z.string().optional(), +}); + +export const publicPageCollaboratorsRowSchema = z.object({ + created_at: z.string(), + id: z.string(), + page_id: z.string(), + role: publicCollaboratorRoleSchema, + user_id: z.string(), +}); + +export const publicPageCollaboratorsInsertSchema = z.object({ + created_at: z.string().optional(), + id: z.string().optional(), + page_id: z.string(), + role: publicCollaboratorRoleSchema.optional(), + user_id: z.string(), +}); + +export const publicPageCollaboratorsUpdateSchema = z.object({ + created_at: z.string().optional(), + id: z.string().optional(), + page_id: z.string().optional(), + role: publicCollaboratorRoleSchema.optional(), + user_id: z.string().optional(), +}); + +export const publicPageCollaboratorsRelationshipsSchema = z.tuple([ + z.object({ + foreignKeyName: z.literal("page_collaborators_page_id_fkey"), + columns: z.tuple([z.literal("page_id")]), + isOneToOne: z.literal(false), + referencedRelation: z.literal("pages"), + referencedColumns: z.tuple([z.literal("id")]), + }), +]); + +export const publicPagesRowSchema = z.object({ + content: jsonSchema.nullable(), + created_at: z.string(), + id: z.string(), + is_public: z.boolean(), + meta: jsonSchema.nullable(), + owner: z.string(), + parent: z.string().nullable(), + slug: z.string(), + tags: z.array(z.string()).nullable(), + title: z.string(), + type: z.string().nullable(), + updated_at: z.string(), + visible: z.boolean(), +}); + +export const publicPagesInsertSchema = z.object({ + content: jsonSchema.optional().nullable(), + created_at: z.string().optional(), + id: z.string().optional(), + is_public: z.boolean().optional(), + meta: jsonSchema.optional().nullable(), + owner: z.string(), + parent: z.string().optional().nullable(), + slug: z.string(), + tags: z.array(z.string()).optional().nullable(), + title: z.string(), + type: z.string().optional().nullable(), + updated_at: z.string().optional(), + visible: z.boolean().optional(), +}); + +export const publicPagesUpdateSchema = z.object({ + content: jsonSchema.optional().nullable(), + created_at: z.string().optional(), + id: z.string().optional(), + is_public: z.boolean().optional(), + meta: jsonSchema.optional().nullable(), + owner: z.string().optional(), + parent: z.string().optional().nullable(), + slug: z.string().optional(), + tags: z.array(z.string()).optional().nullable(), + title: z.string().optional(), + type: z.string().optional().nullable(), + updated_at: z.string().optional(), + visible: z.boolean().optional(), +}); + +export const publicPagesRelationshipsSchema = z.tuple([ + z.object({ + foreignKeyName: z.literal("pages_parent_fkey"), + columns: z.tuple([z.literal("parent")]), + isOneToOne: z.literal(false), + referencedRelation: z.literal("pages"), + referencedColumns: z.tuple([z.literal("id")]), + }), +]); + +export const publicPicturesRowSchema = z.object({ + created_at: z.string(), + description: z.string().nullable(), + flags: z.array(z.string()).nullable(), + id: z.string(), + image_url: z.string(), + is_selected: z.boolean(), + likes_count: z.number().nullable(), + meta: jsonSchema.nullable(), + organization_id: z.string().nullable(), + parent_id: z.string().nullable(), + position: z.number().nullable(), + post_id: z.string().nullable(), + tags: z.array(z.string()).nullable(), + thumbnail_url: z.string().nullable(), + title: z.string(), + type: z.string().nullable(), + updated_at: z.string(), + user_id: z.string(), + visible: z.boolean(), +}); + +export const publicPicturesInsertSchema = z.object({ + created_at: z.string().optional(), + description: z.string().optional().nullable(), + flags: z.array(z.string()).optional().nullable(), + id: z.string().optional(), + image_url: z.string(), + is_selected: z.boolean().optional(), + likes_count: z.number().optional().nullable(), + meta: jsonSchema.optional().nullable(), + organization_id: z.string().optional().nullable(), + parent_id: z.string().optional().nullable(), + position: z.number().optional().nullable(), + post_id: z.string().optional().nullable(), + tags: z.array(z.string()).optional().nullable(), + thumbnail_url: z.string().optional().nullable(), + title: z.string(), + type: z.string().optional().nullable(), + updated_at: z.string().optional(), + user_id: z.string(), + visible: z.boolean().optional(), +}); + +export const publicPicturesUpdateSchema = z.object({ + created_at: z.string().optional(), + description: z.string().optional().nullable(), + flags: z.array(z.string()).optional().nullable(), + id: z.string().optional(), + image_url: z.string().optional(), + is_selected: z.boolean().optional(), + likes_count: z.number().optional().nullable(), + meta: jsonSchema.optional().nullable(), + organization_id: z.string().optional().nullable(), + parent_id: z.string().optional().nullable(), + position: z.number().optional().nullable(), + post_id: z.string().optional().nullable(), + tags: z.array(z.string()).optional().nullable(), + thumbnail_url: z.string().optional().nullable(), + title: z.string().optional(), + type: z.string().optional().nullable(), + updated_at: z.string().optional(), + user_id: z.string().optional(), + visible: z.boolean().optional(), +}); + +export const publicPicturesRelationshipsSchema = z.tuple([ + z.object({ + foreignKeyName: z.literal("pictures_organization_id_fkey"), + columns: z.tuple([z.literal("organization_id")]), + isOneToOne: z.literal(false), + referencedRelation: z.literal("organizations"), + referencedColumns: z.tuple([z.literal("id")]), + }), + z.object({ + foreignKeyName: z.literal("pictures_parent_id_fkey"), + columns: z.tuple([z.literal("parent_id")]), + isOneToOne: z.literal(false), + referencedRelation: z.literal("pictures"), + referencedColumns: z.tuple([z.literal("id")]), + }), + z.object({ + foreignKeyName: z.literal("pictures_post_id_fkey"), + columns: z.tuple([z.literal("post_id")]), + isOneToOne: z.literal(false), + referencedRelation: z.literal("posts"), + referencedColumns: z.tuple([z.literal("id")]), + }), +]); + +export const publicPostsRowSchema = z.object({ + created_at: z.string().nullable(), + description: z.string().nullable(), + id: z.string(), + meta: jsonSchema.nullable(), + settings: jsonSchema.nullable(), + title: z.string(), + updated_at: z.string().nullable(), + user_id: z.string(), +}); + +export const publicPostsInsertSchema = z.object({ + created_at: z.string().optional().nullable(), + description: z.string().optional().nullable(), + id: z.string().optional(), + meta: jsonSchema.optional().nullable(), + settings: jsonSchema.optional().nullable(), + title: z.string(), + updated_at: z.string().optional().nullable(), + user_id: z.string(), +}); + +export const publicPostsUpdateSchema = z.object({ + created_at: z.string().optional().nullable(), + description: z.string().optional().nullable(), + id: z.string().optional(), + meta: jsonSchema.optional().nullable(), + settings: jsonSchema.optional().nullable(), + title: z.string().optional(), + updated_at: z.string().optional().nullable(), + user_id: z.string().optional(), +}); + +export const publicProfilesRowSchema = z.object({ + aimlapi_api_key: z.string().nullable(), + avatar_url: z.string().nullable(), + bio: z.string().nullable(), + bria_api_key: z.string().nullable(), + created_at: z.string(), + display_name: z.string().nullable(), + google_api_key: z.string().nullable(), + huggingface_api_key: z.string().nullable(), + id: z.string(), + openai_api_key: z.string().nullable(), + pages: jsonSchema.nullable(), + replicate_api_key: z.string().nullable(), + settings: jsonSchema.nullable(), + updated_at: z.string(), + user_id: z.string(), + username: z.string().nullable(), +}); + +export const publicProfilesInsertSchema = z.object({ + aimlapi_api_key: z.string().optional().nullable(), + avatar_url: z.string().optional().nullable(), + bio: z.string().optional().nullable(), + bria_api_key: z.string().optional().nullable(), + created_at: z.string().optional(), + display_name: z.string().optional().nullable(), + google_api_key: z.string().optional().nullable(), + huggingface_api_key: z.string().optional().nullable(), + id: z.string().optional(), + openai_api_key: z.string().optional().nullable(), + pages: jsonSchema.optional().nullable(), + replicate_api_key: z.string().optional().nullable(), + settings: jsonSchema.optional().nullable(), + updated_at: z.string().optional(), + user_id: z.string(), + username: z.string().optional().nullable(), +}); + +export const publicProfilesUpdateSchema = z.object({ + aimlapi_api_key: z.string().optional().nullable(), + avatar_url: z.string().optional().nullable(), + bio: z.string().optional().nullable(), + bria_api_key: z.string().optional().nullable(), + created_at: z.string().optional(), + display_name: z.string().optional().nullable(), + google_api_key: z.string().optional().nullable(), + huggingface_api_key: z.string().optional().nullable(), + id: z.string().optional(), + openai_api_key: z.string().optional().nullable(), + pages: jsonSchema.optional().nullable(), + replicate_api_key: z.string().optional().nullable(), + settings: jsonSchema.optional().nullable(), + updated_at: z.string().optional(), + user_id: z.string().optional(), + username: z.string().optional().nullable(), +}); + +export const publicProviderConfigsRowSchema = z.object({ + base_url: z.string(), + created_at: z.string().nullable(), + display_name: z.string(), + id: z.string(), + is_active: z.boolean().nullable(), + models: jsonSchema, + name: z.string(), + rate_limits: jsonSchema.nullable(), + settings: jsonSchema.nullable(), + updated_at: z.string().nullable(), + user_id: z.string().nullable(), +}); + +export const publicProviderConfigsInsertSchema = z.object({ + base_url: z.string(), + created_at: z.string().optional().nullable(), + display_name: z.string(), + id: z.string().optional(), + is_active: z.boolean().optional().nullable(), + models: jsonSchema.optional(), + name: z.string(), + rate_limits: jsonSchema.optional().nullable(), + settings: jsonSchema.optional().nullable(), + updated_at: z.string().optional().nullable(), + user_id: z.string().optional().nullable(), +}); + +export const publicProviderConfigsUpdateSchema = z.object({ + base_url: z.string().optional(), + created_at: z.string().optional().nullable(), + display_name: z.string().optional(), + id: z.string().optional(), + is_active: z.boolean().optional().nullable(), + models: jsonSchema.optional(), + name: z.string().optional(), + rate_limits: jsonSchema.optional().nullable(), + settings: jsonSchema.optional().nullable(), + updated_at: z.string().optional().nullable(), + user_id: z.string().optional().nullable(), +}); + +export const publicRolePermissionsRowSchema = z.object({ + created_at: z.string(), + id: z.string(), + permission: publicAppPermissionSchema, + role: publicAppRoleSchema, +}); + +export const publicRolePermissionsInsertSchema = z.object({ + created_at: z.string().optional(), + id: z.string().optional(), + permission: publicAppPermissionSchema, + role: publicAppRoleSchema, +}); + +export const publicRolePermissionsUpdateSchema = z.object({ + created_at: z.string().optional(), + id: z.string().optional(), + permission: publicAppPermissionSchema.optional(), + role: publicAppRoleSchema.optional(), +}); + +export const publicTypeCastsRowSchema = z.object({ + cast_kind: publicCastKindSchema, + description: z.string().nullable(), + from_type_id: z.string(), + to_type_id: z.string(), +}); + +export const publicTypeCastsInsertSchema = z.object({ + cast_kind: publicCastKindSchema, + description: z.string().optional().nullable(), + from_type_id: z.string(), + to_type_id: z.string(), +}); + +export const publicTypeCastsUpdateSchema = z.object({ + cast_kind: publicCastKindSchema.optional(), + description: z.string().optional().nullable(), + from_type_id: z.string().optional(), + to_type_id: z.string().optional(), +}); + +export const publicTypeCastsRelationshipsSchema = z.tuple([ + z.object({ + foreignKeyName: z.literal("type_casts_from_type_id_fkey"), + columns: z.tuple([z.literal("from_type_id")]), + isOneToOne: z.literal(false), + referencedRelation: z.literal("types"), + referencedColumns: z.tuple([z.literal("id")]), + }), + z.object({ + foreignKeyName: z.literal("type_casts_to_type_id_fkey"), + columns: z.tuple([z.literal("to_type_id")]), + isOneToOne: z.literal(false), + referencedRelation: z.literal("types"), + referencedColumns: z.tuple([z.literal("id")]), + }), +]); + +export const publicTypeEnumValuesRowSchema = z.object({ + id: z.string(), + label: z.string(), + order: z.number(), + type_id: z.string(), + value: z.string(), +}); + +export const publicTypeEnumValuesInsertSchema = z.object({ + id: z.string().optional(), + label: z.string(), + order: z.number().optional(), + type_id: z.string(), + value: z.string(), +}); + +export const publicTypeEnumValuesUpdateSchema = z.object({ + id: z.string().optional(), + label: z.string().optional(), + order: z.number().optional(), + type_id: z.string().optional(), + value: z.string().optional(), +}); + +export const publicTypeEnumValuesRelationshipsSchema = z.tuple([ + z.object({ + foreignKeyName: z.literal("type_enum_values_type_id_fkey"), + columns: z.tuple([z.literal("type_id")]), + isOneToOne: z.literal(false), + referencedRelation: z.literal("types"), + referencedColumns: z.tuple([z.literal("id")]), + }), +]); + +export const publicTypeFlagValuesRowSchema = z.object({ + bit: z.number(), + id: z.string(), + name: z.string(), + type_id: z.string(), +}); + +export const publicTypeFlagValuesInsertSchema = z.object({ + bit: z.number(), + id: z.string().optional(), + name: z.string(), + type_id: z.string(), +}); + +export const publicTypeFlagValuesUpdateSchema = z.object({ + bit: z.number().optional(), + id: z.string().optional(), + name: z.string().optional(), + type_id: z.string().optional(), +}); + +export const publicTypeFlagValuesRelationshipsSchema = z.tuple([ + z.object({ + foreignKeyName: z.literal("type_flag_values_type_id_fkey"), + columns: z.tuple([z.literal("type_id")]), + isOneToOne: z.literal(false), + referencedRelation: z.literal("types"), + referencedColumns: z.tuple([z.literal("id")]), + }), +]); + +export const publicTypeStructureFieldsRowSchema = z.object({ + default_value: jsonSchema.nullable(), + field_name: z.string(), + field_type_id: z.string(), + id: z.string(), + order: z.number(), + required: z.boolean(), + structure_type_id: z.string(), +}); + +export const publicTypeStructureFieldsInsertSchema = z.object({ + default_value: jsonSchema.optional().nullable(), + field_name: z.string(), + field_type_id: z.string(), + id: z.string().optional(), + order: z.number().optional(), + required: z.boolean().optional(), + structure_type_id: z.string(), +}); + +export const publicTypeStructureFieldsUpdateSchema = z.object({ + default_value: jsonSchema.optional().nullable(), + field_name: z.string().optional(), + field_type_id: z.string().optional(), + id: z.string().optional(), + order: z.number().optional(), + required: z.boolean().optional(), + structure_type_id: z.string().optional(), +}); + +export const publicTypeStructureFieldsRelationshipsSchema = z.tuple([ + z.object({ + foreignKeyName: z.literal("type_structure_fields_field_type_id_fkey"), + columns: z.tuple([z.literal("field_type_id")]), + isOneToOne: z.literal(false), + referencedRelation: z.literal("types"), + referencedColumns: z.tuple([z.literal("id")]), + }), + z.object({ + foreignKeyName: z.literal("type_structure_fields_structure_type_id_fkey"), + columns: z.tuple([z.literal("structure_type_id")]), + isOneToOne: z.literal(false), + referencedRelation: z.literal("types"), + referencedColumns: z.tuple([z.literal("id")]), + }), +]); + +export const publicTypesRowSchema = z.object({ + created_at: z.string(), + description: z.string().nullable(), + id: z.string(), + json_schema: jsonSchema.nullable(), + kind: publicTypeKindSchema, + meta: jsonSchema.nullable(), + name: z.string(), + owner_id: z.string().nullable(), + parent_type_id: z.string().nullable(), + settings: jsonSchema.nullable(), + updated_at: z.string(), + visibility: publicTypeVisibilitySchema, +}); + +export const publicTypesInsertSchema = z.object({ + created_at: z.string().optional(), + description: z.string().optional().nullable(), + id: z.string().optional(), + json_schema: jsonSchema.optional().nullable(), + kind: publicTypeKindSchema, + meta: jsonSchema.optional().nullable(), + name: z.string(), + owner_id: z.string().optional().nullable(), + parent_type_id: z.string().optional().nullable(), + settings: jsonSchema.optional().nullable(), + updated_at: z.string().optional(), + visibility: publicTypeVisibilitySchema.optional(), +}); + +export const publicTypesUpdateSchema = z.object({ + created_at: z.string().optional(), + description: z.string().optional().nullable(), + id: z.string().optional(), + json_schema: jsonSchema.optional().nullable(), + kind: publicTypeKindSchema.optional(), + meta: jsonSchema.optional().nullable(), + name: z.string().optional(), + owner_id: z.string().optional().nullable(), + parent_type_id: z.string().optional().nullable(), + settings: jsonSchema.optional().nullable(), + updated_at: z.string().optional(), + visibility: publicTypeVisibilitySchema.optional(), +}); + +export const publicTypesRelationshipsSchema = z.tuple([ + z.object({ + foreignKeyName: z.literal("types_parent_type_id_fkey"), + columns: z.tuple([z.literal("parent_type_id")]), + isOneToOne: z.literal(false), + referencedRelation: z.literal("types"), + referencedColumns: z.tuple([z.literal("id")]), + }), +]); + +export const publicUserFilterConfigsRowSchema = z.object({ + context: z.string(), + created_at: z.string().nullable(), + custom_filters: jsonSchema.nullable(), + default_templates: z.array(z.string()).nullable(), + id: z.string(), + is_default: z.boolean().nullable(), + model: z.string(), + provider: z.string(), + updated_at: z.string().nullable(), + user_id: z.string().nullable(), + variables: jsonSchema.nullable(), +}); + +export const publicUserFilterConfigsInsertSchema = z.object({ + context: z.string(), + created_at: z.string().optional().nullable(), + custom_filters: jsonSchema.optional().nullable(), + default_templates: z.array(z.string()).optional().nullable(), + id: z.string().optional(), + is_default: z.boolean().optional().nullable(), + model: z.string().optional(), + provider: z.string().optional(), + updated_at: z.string().optional().nullable(), + user_id: z.string().optional().nullable(), + variables: jsonSchema.optional().nullable(), +}); + +export const publicUserFilterConfigsUpdateSchema = z.object({ + context: z.string().optional(), + created_at: z.string().optional().nullable(), + custom_filters: jsonSchema.optional().nullable(), + default_templates: z.array(z.string()).optional().nullable(), + id: z.string().optional(), + is_default: z.boolean().optional().nullable(), + model: z.string().optional(), + provider: z.string().optional(), + updated_at: z.string().optional().nullable(), + user_id: z.string().optional().nullable(), + variables: jsonSchema.optional().nullable(), +}); + +export const publicUserOrganizationsRowSchema = z.object({ + created_at: z.string(), + id: z.string(), + organization_id: z.string(), + role: z.string(), + updated_at: z.string(), + user_id: z.string(), +}); + +export const publicUserOrganizationsInsertSchema = z.object({ + created_at: z.string().optional(), + id: z.string().optional(), + organization_id: z.string(), + role: z.string().optional(), + updated_at: z.string().optional(), + user_id: z.string(), +}); + +export const publicUserOrganizationsUpdateSchema = z.object({ + created_at: z.string().optional(), + id: z.string().optional(), + organization_id: z.string().optional(), + role: z.string().optional(), + updated_at: z.string().optional(), + user_id: z.string().optional(), +}); + +export const publicUserOrganizationsRelationshipsSchema = z.tuple([ + z.object({ + foreignKeyName: z.literal("user_organizations_organization_id_fkey"), + columns: z.tuple([z.literal("organization_id")]), + isOneToOne: z.literal(false), + referencedRelation: z.literal("organizations"), + referencedColumns: z.tuple([z.literal("id")]), + }), +]); + +export const publicUserRolesRowSchema = z.object({ + created_at: z.string(), + id: z.string(), + organization_id: z.string().nullable(), + role: publicAppRoleSchema, + updated_at: z.string(), + user_id: z.string(), +}); + +export const publicUserRolesInsertSchema = z.object({ + created_at: z.string().optional(), + id: z.string().optional(), + organization_id: z.string().optional().nullable(), + role: publicAppRoleSchema, + updated_at: z.string().optional(), + user_id: z.string(), +}); + +export const publicUserRolesUpdateSchema = z.object({ + created_at: z.string().optional(), + id: z.string().optional(), + organization_id: z.string().optional().nullable(), + role: publicAppRoleSchema.optional(), + updated_at: z.string().optional(), + user_id: z.string().optional(), +}); + +export const publicUserRolesRelationshipsSchema = z.tuple([ + z.object({ + foreignKeyName: z.literal("user_roles_user_id_fkey"), + columns: z.tuple([z.literal("user_id")]), + isOneToOne: z.literal(false), + referencedRelation: z.literal("profiles"), + referencedColumns: z.tuple([z.literal("user_id")]), + }), +]); + +export const publicUserSecretsRowSchema = z.object({ + aimlapi_api_key: z.string().nullable(), + bria_api_key: z.string().nullable(), + created_at: z.string(), + google_api_key: z.string().nullable(), + huggingface_api_key: z.string().nullable(), + is_admin: z.boolean().nullable(), + openai_api_key: z.string().nullable(), + replicate_api_key: z.string().nullable(), + settings: jsonSchema.nullable(), + updated_at: z.string(), + user_id: z.string(), +}); + +export const publicUserSecretsInsertSchema = z.object({ + aimlapi_api_key: z.string().optional().nullable(), + bria_api_key: z.string().optional().nullable(), + created_at: z.string().optional(), + google_api_key: z.string().optional().nullable(), + huggingface_api_key: z.string().optional().nullable(), + is_admin: z.boolean().optional().nullable(), + openai_api_key: z.string().optional().nullable(), + replicate_api_key: z.string().optional().nullable(), + settings: jsonSchema.optional().nullable(), + updated_at: z.string().optional(), + user_id: z.string(), +}); + +export const publicUserSecretsUpdateSchema = z.object({ + aimlapi_api_key: z.string().optional().nullable(), + bria_api_key: z.string().optional().nullable(), + created_at: z.string().optional(), + google_api_key: z.string().optional().nullable(), + huggingface_api_key: z.string().optional().nullable(), + is_admin: z.boolean().optional().nullable(), + openai_api_key: z.string().optional().nullable(), + replicate_api_key: z.string().optional().nullable(), + settings: jsonSchema.optional().nullable(), + updated_at: z.string().optional(), + user_id: z.string().optional(), +}); + +export const publicUserTemplatesRowSchema = z.object({ + context: z.string(), + created_at: z.string().nullable(), + description: z.string().nullable(), + filters: z.array(z.string()).nullable(), + format: z.string().nullable(), + id: z.string(), + is_public: z.boolean().nullable(), + model: z.string(), + name: z.string(), + prompt: z.string(), + provider: z.string(), + updated_at: z.string().nullable(), + usage_count: z.number().nullable(), + user_id: z.string().nullable(), +}); + +export const publicUserTemplatesInsertSchema = z.object({ + context: z.string(), + created_at: z.string().optional().nullable(), + description: z.string().optional().nullable(), + filters: z.array(z.string()).optional().nullable(), + format: z.string().optional().nullable(), + id: z.string().optional(), + is_public: z.boolean().optional().nullable(), + model: z.string().optional(), + name: z.string(), + prompt: z.string(), + provider: z.string().optional(), + updated_at: z.string().optional().nullable(), + usage_count: z.number().optional().nullable(), + user_id: z.string().optional().nullable(), +}); + +export const publicUserTemplatesUpdateSchema = z.object({ + context: z.string().optional(), + created_at: z.string().optional().nullable(), + description: z.string().optional().nullable(), + filters: z.array(z.string()).optional().nullable(), + format: z.string().optional().nullable(), + id: z.string().optional(), + is_public: z.boolean().optional().nullable(), + model: z.string().optional(), + name: z.string().optional(), + prompt: z.string().optional(), + provider: z.string().optional(), + updated_at: z.string().optional().nullable(), + usage_count: z.number().optional().nullable(), + user_id: z.string().optional().nullable(), +}); + +export const publicWizardSessionsRowSchema = z.object({ + created_at: z.string(), + generated_image_url: z.string().nullable(), + id: z.string(), + input_images: z.array(z.string()).nullable(), + prompt: z.string(), + status: z.string(), + updated_at: z.string(), + user_id: z.string(), +}); + +export const publicWizardSessionsInsertSchema = z.object({ + created_at: z.string().optional(), + generated_image_url: z.string().optional().nullable(), + id: z.string().optional(), + input_images: z.array(z.string()).optional().nullable(), + prompt: z.string().optional(), + status: z.string().optional(), + updated_at: z.string().optional(), + user_id: z.string(), +}); + +export const publicWizardSessionsUpdateSchema = z.object({ + created_at: z.string().optional(), + generated_image_url: z.string().optional().nullable(), + id: z.string().optional(), + input_images: z.array(z.string()).optional().nullable(), + prompt: z.string().optional(), + status: z.string().optional(), + updated_at: z.string().optional(), + user_id: z.string().optional(), +}); + +export const publicAuthorizeArgsSchema = z.object({ + _role: publicAppRoleSchema, + _user_id: z.string(), +}); + +export const publicAuthorizeReturnsSchema = z.boolean(); + +export const publicHasPermissionArgsSchema = z.object({ + _permission: publicAppPermissionSchema, + _user_id: z.string(), +}); + +export const publicHasPermissionReturnsSchema = z.boolean(); + +export const publicIsPageCollaboratorArgsSchema = z.object({ + _page_id: z.string(), +}); + +export const publicIsPageCollaboratorReturnsSchema = z.boolean(); + +export const publicIsPageOwnerArgsSchema = z.object({ + _page_id: z.string(), +}); + +export const publicIsPageOwnerReturnsSchema = z.boolean(); + +export type PublicAppPermission = z.infer; +export type PublicAppRole = z.infer; +export type PublicCastKind = z.infer; +export type PublicCategoryRelationType = z.infer< + typeof publicCategoryRelationTypeSchema +>; +export type PublicCategoryVisibility = z.infer< + typeof publicCategoryVisibilitySchema +>; +export type PublicCollaboratorRole = z.infer< + typeof publicCollaboratorRoleSchema +>; +export type PublicLayoutVisibility = z.infer< + typeof publicLayoutVisibilitySchema +>; +export type PublicTypeKind = z.infer; +export type PublicTypeVisibility = z.infer; +export type Json = z.infer; +export type PublicCategoriesRow = z.infer; +export type PublicCategoriesInsert = z.infer< + typeof publicCategoriesInsertSchema +>; +export type PublicCategoriesUpdate = z.infer< + typeof publicCategoriesUpdateSchema +>; +export type PublicCategoryRelationsRow = z.infer< + typeof publicCategoryRelationsRowSchema +>; +export type PublicCategoryRelationsInsert = z.infer< + typeof publicCategoryRelationsInsertSchema +>; +export type PublicCategoryRelationsUpdate = z.infer< + typeof publicCategoryRelationsUpdateSchema +>; +export type PublicCategoryRelationsRelationships = z.infer< + typeof publicCategoryRelationsRelationshipsSchema +>; +export type PublicCollectionPicturesRow = z.infer< + typeof publicCollectionPicturesRowSchema +>; +export type PublicCollectionPicturesInsert = z.infer< + typeof publicCollectionPicturesInsertSchema +>; +export type PublicCollectionPicturesUpdate = z.infer< + typeof publicCollectionPicturesUpdateSchema +>; +export type PublicCollectionPicturesRelationships = z.infer< + typeof publicCollectionPicturesRelationshipsSchema +>; +export type PublicCollectionPostsRow = z.infer< + typeof publicCollectionPostsRowSchema +>; +export type PublicCollectionPostsInsert = z.infer< + typeof publicCollectionPostsInsertSchema +>; +export type PublicCollectionPostsUpdate = z.infer< + typeof publicCollectionPostsUpdateSchema +>; +export type PublicCollectionPostsRelationships = z.infer< + typeof publicCollectionPostsRelationshipsSchema +>; +export type PublicCollectionsRow = z.infer; +export type PublicCollectionsInsert = z.infer< + typeof publicCollectionsInsertSchema +>; +export type PublicCollectionsUpdate = z.infer< + typeof publicCollectionsUpdateSchema +>; +export type PublicCommentLikesRow = z.infer; +export type PublicCommentLikesInsert = z.infer< + typeof publicCommentLikesInsertSchema +>; +export type PublicCommentLikesUpdate = z.infer< + typeof publicCommentLikesUpdateSchema +>; +export type PublicCommentsRow = z.infer; +export type PublicCommentsInsert = z.infer; +export type PublicCommentsUpdate = z.infer; +export type PublicCommentsRelationships = z.infer< + typeof publicCommentsRelationshipsSchema +>; +export type PublicContextDefinitionsRow = z.infer< + typeof publicContextDefinitionsRowSchema +>; +export type PublicContextDefinitionsInsert = z.infer< + typeof publicContextDefinitionsInsertSchema +>; +export type PublicContextDefinitionsUpdate = z.infer< + typeof publicContextDefinitionsUpdateSchema +>; +export type PublicFilterUsageLogsRow = z.infer< + typeof publicFilterUsageLogsRowSchema +>; +export type PublicFilterUsageLogsInsert = z.infer< + typeof publicFilterUsageLogsInsertSchema +>; +export type PublicFilterUsageLogsUpdate = z.infer< + typeof publicFilterUsageLogsUpdateSchema +>; +export type PublicFilterUsageLogsRelationships = z.infer< + typeof publicFilterUsageLogsRelationshipsSchema +>; +export type PublicLayoutsRow = z.infer; +export type PublicLayoutsInsert = z.infer; +export type PublicLayoutsUpdate = z.infer; +export type PublicLikesRow = z.infer; +export type PublicLikesInsert = z.infer; +export type PublicLikesUpdate = z.infer; +export type PublicOrganizationsRow = z.infer< + typeof publicOrganizationsRowSchema +>; +export type PublicOrganizationsInsert = z.infer< + typeof publicOrganizationsInsertSchema +>; +export type PublicOrganizationsUpdate = z.infer< + typeof publicOrganizationsUpdateSchema +>; +export type PublicPageCollaboratorsRow = z.infer< + typeof publicPageCollaboratorsRowSchema +>; +export type PublicPageCollaboratorsInsert = z.infer< + typeof publicPageCollaboratorsInsertSchema +>; +export type PublicPageCollaboratorsUpdate = z.infer< + typeof publicPageCollaboratorsUpdateSchema +>; +export type PublicPageCollaboratorsRelationships = z.infer< + typeof publicPageCollaboratorsRelationshipsSchema +>; +export type PublicPagesRow = z.infer; +export type PublicPagesInsert = z.infer; +export type PublicPagesUpdate = z.infer; +export type PublicPagesRelationships = z.infer< + typeof publicPagesRelationshipsSchema +>; +export type PublicPicturesRow = z.infer; +export type PublicPicturesInsert = z.infer; +export type PublicPicturesUpdate = z.infer; +export type PublicPicturesRelationships = z.infer< + typeof publicPicturesRelationshipsSchema +>; +export type PublicPostsRow = z.infer; +export type PublicPostsInsert = z.infer; +export type PublicPostsUpdate = z.infer; +export type PublicProfilesRow = z.infer; +export type PublicProfilesInsert = z.infer; +export type PublicProfilesUpdate = z.infer; +export type PublicProviderConfigsRow = z.infer< + typeof publicProviderConfigsRowSchema +>; +export type PublicProviderConfigsInsert = z.infer< + typeof publicProviderConfigsInsertSchema +>; +export type PublicProviderConfigsUpdate = z.infer< + typeof publicProviderConfigsUpdateSchema +>; +export type PublicRolePermissionsRow = z.infer< + typeof publicRolePermissionsRowSchema +>; +export type PublicRolePermissionsInsert = z.infer< + typeof publicRolePermissionsInsertSchema +>; +export type PublicRolePermissionsUpdate = z.infer< + typeof publicRolePermissionsUpdateSchema +>; +export type PublicTypeCastsRow = z.infer; +export type PublicTypeCastsInsert = z.infer; +export type PublicTypeCastsUpdate = z.infer; +export type PublicTypeCastsRelationships = z.infer< + typeof publicTypeCastsRelationshipsSchema +>; +export type PublicTypeEnumValuesRow = z.infer< + typeof publicTypeEnumValuesRowSchema +>; +export type PublicTypeEnumValuesInsert = z.infer< + typeof publicTypeEnumValuesInsertSchema +>; +export type PublicTypeEnumValuesUpdate = z.infer< + typeof publicTypeEnumValuesUpdateSchema +>; +export type PublicTypeEnumValuesRelationships = z.infer< + typeof publicTypeEnumValuesRelationshipsSchema +>; +export type PublicTypeFlagValuesRow = z.infer< + typeof publicTypeFlagValuesRowSchema +>; +export type PublicTypeFlagValuesInsert = z.infer< + typeof publicTypeFlagValuesInsertSchema +>; +export type PublicTypeFlagValuesUpdate = z.infer< + typeof publicTypeFlagValuesUpdateSchema +>; +export type PublicTypeFlagValuesRelationships = z.infer< + typeof publicTypeFlagValuesRelationshipsSchema +>; +export type PublicTypeStructureFieldsRow = z.infer< + typeof publicTypeStructureFieldsRowSchema +>; +export type PublicTypeStructureFieldsInsert = z.infer< + typeof publicTypeStructureFieldsInsertSchema +>; +export type PublicTypeStructureFieldsUpdate = z.infer< + typeof publicTypeStructureFieldsUpdateSchema +>; +export type PublicTypeStructureFieldsRelationships = z.infer< + typeof publicTypeStructureFieldsRelationshipsSchema +>; +export type PublicTypesRow = z.infer; +export type PublicTypesInsert = z.infer; +export type PublicTypesUpdate = z.infer; +export type PublicTypesRelationships = z.infer< + typeof publicTypesRelationshipsSchema +>; +export type PublicUserFilterConfigsRow = z.infer< + typeof publicUserFilterConfigsRowSchema +>; +export type PublicUserFilterConfigsInsert = z.infer< + typeof publicUserFilterConfigsInsertSchema +>; +export type PublicUserFilterConfigsUpdate = z.infer< + typeof publicUserFilterConfigsUpdateSchema +>; +export type PublicUserOrganizationsRow = z.infer< + typeof publicUserOrganizationsRowSchema +>; +export type PublicUserOrganizationsInsert = z.infer< + typeof publicUserOrganizationsInsertSchema +>; +export type PublicUserOrganizationsUpdate = z.infer< + typeof publicUserOrganizationsUpdateSchema +>; +export type PublicUserOrganizationsRelationships = z.infer< + typeof publicUserOrganizationsRelationshipsSchema +>; +export type PublicUserRolesRow = z.infer; +export type PublicUserRolesInsert = z.infer; +export type PublicUserRolesUpdate = z.infer; +export type PublicUserRolesRelationships = z.infer< + typeof publicUserRolesRelationshipsSchema +>; +export type PublicUserSecretsRow = z.infer; +export type PublicUserSecretsInsert = z.infer< + typeof publicUserSecretsInsertSchema +>; +export type PublicUserSecretsUpdate = z.infer< + typeof publicUserSecretsUpdateSchema +>; +export type PublicUserTemplatesRow = z.infer< + typeof publicUserTemplatesRowSchema +>; +export type PublicUserTemplatesInsert = z.infer< + typeof publicUserTemplatesInsertSchema +>; +export type PublicUserTemplatesUpdate = z.infer< + typeof publicUserTemplatesUpdateSchema +>; +export type PublicWizardSessionsRow = z.infer< + typeof publicWizardSessionsRowSchema +>; +export type PublicWizardSessionsInsert = z.infer< + typeof publicWizardSessionsInsertSchema +>; +export type PublicWizardSessionsUpdate = z.infer< + typeof publicWizardSessionsUpdateSchema +>; +export type PublicAuthorizeArgs = z.infer; +export type PublicAuthorizeReturns = z.infer< + typeof publicAuthorizeReturnsSchema +>; +export type PublicHasPermissionArgs = z.infer< + typeof publicHasPermissionArgsSchema +>; +export type PublicHasPermissionReturns = z.infer< + typeof publicHasPermissionReturnsSchema +>; +export type PublicIsPageCollaboratorArgs = z.infer< + typeof publicIsPageCollaboratorArgsSchema +>; +export type PublicIsPageCollaboratorReturns = z.infer< + typeof publicIsPageCollaboratorReturnsSchema +>; +export type PublicIsPageOwnerArgs = z.infer; +export type PublicIsPageOwnerReturns = z.infer< + typeof publicIsPageOwnerReturnsSchema +>; diff --git a/src/integrations/supabase/types.ts b/src/integrations/supabase/types.ts new file mode 100644 index 0000000..6fd2697 --- /dev/null +++ b/src/integrations/supabase/types.ts @@ -0,0 +1,1767 @@ +export type Json = + | string + | number + | boolean + | null + | { [key: string]: Json | undefined } + | Json[] + +export type Database = { + // Allows to automatically instantiate createClient with right options + // instead of createClient(URL, KEY) + __InternalSupabase: { + PostgrestVersion: "13.0.5" + } + graphql_public: { + Tables: { + [_ in never]: never + } + Views: { + [_ in never]: never + } + Functions: { + graphql: { + Args: { + extensions?: Json + operationName?: string + query?: string + variables?: Json + } + Returns: Json + } + } + Enums: { + [_ in never]: never + } + CompositeTypes: { + [_ in never]: never + } + } + public: { + Tables: { + categories: { + Row: { + created_at: string + description: string | null + id: string + meta: Json | null + name: string + owner_id: string | null + slug: string + updated_at: string + visibility: Database["public"]["Enums"]["category_visibility"] + } + Insert: { + created_at?: string + description?: string | null + id?: string + meta?: Json | null + name: string + owner_id?: string | null + slug: string + updated_at?: string + visibility?: Database["public"]["Enums"]["category_visibility"] + } + Update: { + created_at?: string + description?: string | null + id?: string + meta?: Json | null + name?: string + owner_id?: string | null + slug?: string + updated_at?: string + visibility?: Database["public"]["Enums"]["category_visibility"] + } + Relationships: [] + } + category_relations: { + Row: { + child_category_id: string + created_at: string + parent_category_id: string + relation_type: Database["public"]["Enums"]["category_relation_type"] + } + Insert: { + child_category_id: string + created_at?: string + parent_category_id: string + relation_type: Database["public"]["Enums"]["category_relation_type"] + } + Update: { + child_category_id?: string + created_at?: string + parent_category_id?: string + relation_type?: Database["public"]["Enums"]["category_relation_type"] + } + Relationships: [ + { + foreignKeyName: "category_relations_child_category_id_fkey" + columns: ["child_category_id"] + isOneToOne: false + referencedRelation: "categories" + referencedColumns: ["id"] + }, + { + foreignKeyName: "category_relations_parent_category_id_fkey" + columns: ["parent_category_id"] + isOneToOne: false + referencedRelation: "categories" + referencedColumns: ["id"] + }, + ] + } + collection_pictures: { + Row: { + added_at: string + collection_id: string + id: string + picture_id: string + } + Insert: { + added_at?: string + collection_id: string + id?: string + picture_id: string + } + Update: { + added_at?: string + collection_id?: string + id?: string + picture_id?: string + } + Relationships: [ + { + foreignKeyName: "collection_pictures_collection_id_fkey" + columns: ["collection_id"] + isOneToOne: false + referencedRelation: "collections" + referencedColumns: ["id"] + }, + { + foreignKeyName: "collection_pictures_picture_id_fkey" + columns: ["picture_id"] + isOneToOne: false + referencedRelation: "pictures" + referencedColumns: ["id"] + }, + ] + } + collection_posts: { + Row: { + collection_id: string + created_at: string + id: string + post_id: string + } + Insert: { + collection_id: string + created_at?: string + id?: string + post_id: string + } + Update: { + collection_id?: string + created_at?: string + id?: string + post_id?: string + } + Relationships: [ + { + foreignKeyName: "collection_posts_collection_id_fkey" + columns: ["collection_id"] + isOneToOne: false + referencedRelation: "collections" + referencedColumns: ["id"] + }, + { + foreignKeyName: "collection_posts_post_id_fkey" + columns: ["post_id"] + isOneToOne: false + referencedRelation: "posts" + referencedColumns: ["id"] + }, + ] + } + collections: { + Row: { + content: Json | null + created_at: string + description: string | null + id: string + is_public: boolean + layout: Json | null + name: string + slug: string + updated_at: string + user_id: string + } + Insert: { + content?: Json | null + created_at?: string + description?: string | null + id?: string + is_public?: boolean + layout?: Json | null + name: string + slug: string + updated_at?: string + user_id: string + } + Update: { + content?: Json | null + created_at?: string + description?: string | null + id?: string + is_public?: boolean + layout?: Json | null + name?: string + slug?: string + updated_at?: string + user_id?: string + } + Relationships: [] + } + comment_likes: { + Row: { + comment_id: string + created_at: string + id: string + user_id: string + } + Insert: { + comment_id: string + created_at?: string + id?: string + user_id: string + } + Update: { + comment_id?: string + created_at?: string + id?: string + user_id?: string + } + Relationships: [] + } + comments: { + Row: { + content: string + created_at: string + id: string + likes_count: number | null + parent_comment_id: string | null + picture_id: string + updated_at: string + user_id: string + } + Insert: { + content: string + created_at?: string + id?: string + likes_count?: number | null + parent_comment_id?: string | null + picture_id: string + updated_at?: string + user_id: string + } + Update: { + content?: string + created_at?: string + id?: string + likes_count?: number | null + parent_comment_id?: string | null + picture_id?: string + updated_at?: string + user_id?: string + } + Relationships: [ + { + foreignKeyName: "comments_parent_fk" + columns: ["parent_comment_id"] + isOneToOne: false + referencedRelation: "comments" + referencedColumns: ["id"] + }, + ] + } + context_definitions: { + Row: { + created_at: string | null + default_filters: Json + default_templates: Json + description: string | null + display_name: string + icon: string | null + id: string + is_active: boolean | null + name: string + updated_at: string | null + } + Insert: { + created_at?: string | null + default_filters?: Json + default_templates?: Json + description?: string | null + display_name: string + icon?: string | null + id?: string + is_active?: boolean | null + name: string + updated_at?: string | null + } + Update: { + created_at?: string | null + default_filters?: Json + default_templates?: Json + description?: string | null + display_name?: string + icon?: string | null + id?: string + is_active?: boolean | null + name?: string + updated_at?: string | null + } + Relationships: [] + } + filter_usage_logs: { + Row: { + context: string + created_at: string | null + error_message: string | null + filters_applied: string[] | null + id: string + input_length: number + model: string + output_length: number + processing_time_ms: number + provider: string + success: boolean + template_id: string | null + user_id: string | null + } + Insert: { + context: string + created_at?: string | null + error_message?: string | null + filters_applied?: string[] | null + id?: string + input_length: number + model: string + output_length: number + processing_time_ms: number + provider: string + success: boolean + template_id?: string | null + user_id?: string | null + } + Update: { + context?: string + created_at?: string | null + error_message?: string | null + filters_applied?: string[] | null + id?: string + input_length?: number + model?: string + output_length?: number + processing_time_ms?: number + provider?: string + success?: boolean + template_id?: string | null + user_id?: string | null + } + Relationships: [ + { + foreignKeyName: "filter_usage_logs_template_id_fkey" + columns: ["template_id"] + isOneToOne: false + referencedRelation: "user_templates" + referencedColumns: ["id"] + }, + ] + } + i18n_glossaries: { + Row: { + creation_time: string | null + entry_count: number | null + glossary_id: string + hash: string | null + local_created_at: string | null + local_updated_at: string | null + name: string + ready: boolean | null + source_lang: string + target_lang: string + } + Insert: { + creation_time?: string | null + entry_count?: number | null + glossary_id: string + hash?: string | null + local_created_at?: string | null + local_updated_at?: string | null + name: string + ready?: boolean | null + source_lang: string + target_lang: string + } + Update: { + creation_time?: string | null + entry_count?: number | null + glossary_id?: string + hash?: string | null + local_created_at?: string | null + local_updated_at?: string | null + name?: string + ready?: boolean | null + source_lang?: string + target_lang?: string + } + Relationships: [] + } + i18n_glossary_terms: { + Row: { + created_at: string | null + id: string + source_lang: string + target_lang: string + term: string + translation: string + updated_at: string | null + } + Insert: { + created_at?: string | null + id?: string + source_lang: string + target_lang: string + term: string + translation: string + updated_at?: string | null + } + Update: { + created_at?: string | null + id?: string + source_lang?: string + target_lang?: string + term?: string + translation?: string + updated_at?: string | null + } + Relationships: [] + } + i18n_translations: { + Row: { + created_at: string | null + dst_lang: string + dst_text: string + id: string + meta: Json | null + src_lang: string + src_text: string + updated_at: string | null + } + Insert: { + created_at?: string | null + dst_lang: string + dst_text: string + id?: string + meta?: Json | null + src_lang: string + src_text: string + updated_at?: string | null + } + Update: { + created_at?: string | null + dst_lang?: string + dst_text?: string + id?: string + meta?: Json | null + src_lang?: string + src_text?: string + updated_at?: string | null + } + Relationships: [] + } + layouts: { + Row: { + created_at: string + id: string + is_predefined: boolean | null + layout_json: Json + meta: Json | null + name: string + owner_id: string + type: string | null + updated_at: string + visibility: Database["public"]["Enums"]["layout_visibility"] + } + Insert: { + created_at?: string + id?: string + is_predefined?: boolean | null + layout_json: Json + meta?: Json | null + name: string + owner_id: string + type?: string | null + updated_at?: string + visibility?: Database["public"]["Enums"]["layout_visibility"] + } + Update: { + created_at?: string + id?: string + is_predefined?: boolean | null + layout_json?: Json + meta?: Json | null + name?: string + owner_id?: string + type?: string | null + updated_at?: string + visibility?: Database["public"]["Enums"]["layout_visibility"] + } + Relationships: [] + } + likes: { + Row: { + created_at: string + id: string + picture_id: string + user_id: string + } + Insert: { + created_at?: string + id?: string + picture_id: string + user_id: string + } + Update: { + created_at?: string + id?: string + picture_id?: string + user_id?: string + } + Relationships: [] + } + organizations: { + Row: { + created_at: string + id: string + name: string + slug: string + updated_at: string + } + Insert: { + created_at?: string + id?: string + name: string + slug: string + updated_at?: string + } + Update: { + created_at?: string + id?: string + name?: string + slug?: string + updated_at?: string + } + Relationships: [] + } + page_collaborators: { + Row: { + created_at: string + id: string + page_id: string + role: Database["public"]["Enums"]["collaborator_role"] + user_id: string + } + Insert: { + created_at?: string + id?: string + page_id: string + role?: Database["public"]["Enums"]["collaborator_role"] + user_id: string + } + Update: { + created_at?: string + id?: string + page_id?: string + role?: Database["public"]["Enums"]["collaborator_role"] + user_id?: string + } + Relationships: [ + { + foreignKeyName: "page_collaborators_page_id_fkey" + columns: ["page_id"] + isOneToOne: false + referencedRelation: "pages" + referencedColumns: ["id"] + }, + ] + } + pages: { + Row: { + content: Json | null + created_at: string + id: string + is_public: boolean + meta: Json | null + owner: string + parent: string | null + slug: string + tags: string[] | null + title: string + type: string | null + updated_at: string + visible: boolean + } + Insert: { + content?: Json | null + created_at?: string + id?: string + is_public?: boolean + meta?: Json | null + owner: string + parent?: string | null + slug: string + tags?: string[] | null + title: string + type?: string | null + updated_at?: string + visible?: boolean + } + Update: { + content?: Json | null + created_at?: string + id?: string + is_public?: boolean + meta?: Json | null + owner?: string + parent?: string | null + slug?: string + tags?: string[] | null + title?: string + type?: string | null + updated_at?: string + visible?: boolean + } + Relationships: [ + { + foreignKeyName: "pages_parent_fkey" + columns: ["parent"] + isOneToOne: false + referencedRelation: "pages" + referencedColumns: ["id"] + }, + ] + } + pictures: { + Row: { + created_at: string + description: string | null + flags: string[] | null + id: string + image_url: string + is_selected: boolean + likes_count: number | null + meta: Json | null + organization_id: string | null + parent_id: string | null + position: number | null + post_id: string | null + tags: string[] | null + thumbnail_url: string | null + title: string + type: string | null + updated_at: string + user_id: string + visible: boolean + } + Insert: { + created_at?: string + description?: string | null + flags?: string[] | null + id?: string + image_url: string + is_selected?: boolean + likes_count?: number | null + meta?: Json | null + organization_id?: string | null + parent_id?: string | null + position?: number | null + post_id?: string | null + tags?: string[] | null + thumbnail_url?: string | null + title: string + type?: string | null + updated_at?: string + user_id: string + visible?: boolean + } + Update: { + created_at?: string + description?: string | null + flags?: string[] | null + id?: string + image_url?: string + is_selected?: boolean + likes_count?: number | null + meta?: Json | null + organization_id?: string | null + parent_id?: string | null + position?: number | null + post_id?: string | null + tags?: string[] | null + thumbnail_url?: string | null + title?: string + type?: string | null + updated_at?: string + user_id?: string + visible?: boolean + } + Relationships: [ + { + foreignKeyName: "pictures_organization_id_fkey" + columns: ["organization_id"] + isOneToOne: false + referencedRelation: "organizations" + referencedColumns: ["id"] + }, + { + foreignKeyName: "pictures_parent_id_fkey" + columns: ["parent_id"] + isOneToOne: false + referencedRelation: "pictures" + referencedColumns: ["id"] + }, + { + foreignKeyName: "pictures_post_id_fkey" + columns: ["post_id"] + isOneToOne: false + referencedRelation: "posts" + referencedColumns: ["id"] + }, + ] + } + posts: { + Row: { + created_at: string | null + description: string | null + id: string + meta: Json | null + settings: Json | null + title: string + updated_at: string | null + user_id: string + } + Insert: { + created_at?: string | null + description?: string | null + id?: string + meta?: Json | null + settings?: Json | null + title: string + updated_at?: string | null + user_id: string + } + Update: { + created_at?: string | null + description?: string | null + id?: string + meta?: Json | null + settings?: Json | null + title?: string + updated_at?: string | null + user_id?: string + } + Relationships: [] + } + profiles: { + Row: { + aimlapi_api_key: string | null + avatar_url: string | null + bio: string | null + bria_api_key: string | null + created_at: string + display_name: string | null + google_api_key: string | null + huggingface_api_key: string | null + id: string + openai_api_key: string | null + pages: Json | null + replicate_api_key: string | null + settings: Json | null + updated_at: string + user_id: string + username: string | null + } + Insert: { + aimlapi_api_key?: string | null + avatar_url?: string | null + bio?: string | null + bria_api_key?: string | null + created_at?: string + display_name?: string | null + google_api_key?: string | null + huggingface_api_key?: string | null + id?: string + openai_api_key?: string | null + pages?: Json | null + replicate_api_key?: string | null + settings?: Json | null + updated_at?: string + user_id: string + username?: string | null + } + Update: { + aimlapi_api_key?: string | null + avatar_url?: string | null + bio?: string | null + bria_api_key?: string | null + created_at?: string + display_name?: string | null + google_api_key?: string | null + huggingface_api_key?: string | null + id?: string + openai_api_key?: string | null + pages?: Json | null + replicate_api_key?: string | null + settings?: Json | null + updated_at?: string + user_id?: string + username?: string | null + } + Relationships: [] + } + provider_configs: { + Row: { + base_url: string + created_at: string | null + display_name: string + id: string + is_active: boolean | null + models: Json + name: string + rate_limits: Json | null + settings: Json | null + updated_at: string | null + user_id: string | null + } + Insert: { + base_url: string + created_at?: string | null + display_name: string + id?: string + is_active?: boolean | null + models?: Json + name: string + rate_limits?: Json | null + settings?: Json | null + updated_at?: string | null + user_id?: string | null + } + Update: { + base_url?: string + created_at?: string | null + display_name?: string + id?: string + is_active?: boolean | null + models?: Json + name?: string + rate_limits?: Json | null + settings?: Json | null + updated_at?: string | null + user_id?: string | null + } + Relationships: [] + } + resource_acl: { + Row: { + created_at: string | null + group_name: string | null + id: string + log: Json | null + meta: Json | null + path: string | null + permissions: string[] + resource_id: string + resource_owner_id: string | null + resource_type: string + updated_at: string | null + user_id: string | null + } + Insert: { + created_at?: string | null + group_name?: string | null + id?: string + log?: Json | null + meta?: Json | null + path?: string | null + permissions?: string[] + resource_id: string + resource_owner_id?: string | null + resource_type: string + updated_at?: string | null + user_id?: string | null + } + Update: { + created_at?: string | null + group_name?: string | null + id?: string + log?: Json | null + meta?: Json | null + path?: string | null + permissions?: string[] + resource_id?: string + resource_owner_id?: string | null + resource_type?: string + updated_at?: string | null + user_id?: string | null + } + Relationships: [] + } + role_permissions: { + Row: { + created_at: string + id: string + permission: Database["public"]["Enums"]["app_permission"] + role: Database["public"]["Enums"]["app_role"] + } + Insert: { + created_at?: string + id?: string + permission: Database["public"]["Enums"]["app_permission"] + role: Database["public"]["Enums"]["app_role"] + } + Update: { + created_at?: string + id?: string + permission?: Database["public"]["Enums"]["app_permission"] + role?: Database["public"]["Enums"]["app_role"] + } + Relationships: [] + } + transactions: { + Row: { + buyer_email: string | null + buyer_ip: unknown + buyer_name: string | null + buyer_profile: Json + created_at: string + currency: string + external_checkout_id: string | null + external_order_id: string | null + id: string + metadata: Json + note: string | null + payment_provider: string | null + product_info: Json + shipping_info: Json + status: string + total_amount: number + updated_at: string + user_id: string + vendor_info: Json + } + Insert: { + buyer_email?: string | null + buyer_ip?: unknown + buyer_name?: string | null + buyer_profile?: Json + created_at?: string + currency?: string + external_checkout_id?: string | null + external_order_id?: string | null + id?: string + metadata?: Json + note?: string | null + payment_provider?: string | null + product_info?: Json + shipping_info?: Json + status?: string + total_amount?: number + updated_at?: string + user_id: string + vendor_info?: Json + } + Update: { + buyer_email?: string | null + buyer_ip?: unknown + buyer_name?: string | null + buyer_profile?: Json + created_at?: string + currency?: string + external_checkout_id?: string | null + external_order_id?: string | null + id?: string + metadata?: Json + note?: string | null + payment_provider?: string | null + product_info?: Json + shipping_info?: Json + status?: string + total_amount?: number + updated_at?: string + user_id?: string + vendor_info?: Json + } + Relationships: [] + } + type_casts: { + Row: { + cast_kind: Database["public"]["Enums"]["cast_kind"] + description: string | null + from_type_id: string + to_type_id: string + } + Insert: { + cast_kind: Database["public"]["Enums"]["cast_kind"] + description?: string | null + from_type_id: string + to_type_id: string + } + Update: { + cast_kind?: Database["public"]["Enums"]["cast_kind"] + description?: string | null + from_type_id?: string + to_type_id?: string + } + Relationships: [ + { + foreignKeyName: "type_casts_from_type_id_fkey" + columns: ["from_type_id"] + isOneToOne: false + referencedRelation: "types" + referencedColumns: ["id"] + }, + { + foreignKeyName: "type_casts_to_type_id_fkey" + columns: ["to_type_id"] + isOneToOne: false + referencedRelation: "types" + referencedColumns: ["id"] + }, + ] + } + type_enum_values: { + Row: { + id: string + label: string + order: number + type_id: string + value: string + } + Insert: { + id?: string + label: string + order?: number + type_id: string + value: string + } + Update: { + id?: string + label?: string + order?: number + type_id?: string + value?: string + } + Relationships: [ + { + foreignKeyName: "type_enum_values_type_id_fkey" + columns: ["type_id"] + isOneToOne: false + referencedRelation: "types" + referencedColumns: ["id"] + }, + ] + } + type_flag_values: { + Row: { + bit: number + id: string + name: string + type_id: string + } + Insert: { + bit: number + id?: string + name: string + type_id: string + } + Update: { + bit?: number + id?: string + name?: string + type_id?: string + } + Relationships: [ + { + foreignKeyName: "type_flag_values_type_id_fkey" + columns: ["type_id"] + isOneToOne: false + referencedRelation: "types" + referencedColumns: ["id"] + }, + ] + } + type_structure_fields: { + Row: { + default_value: Json | null + field_name: string + field_type_id: string + id: string + order: number + required: boolean + structure_type_id: string + } + Insert: { + default_value?: Json | null + field_name: string + field_type_id: string + id?: string + order?: number + required?: boolean + structure_type_id: string + } + Update: { + default_value?: Json | null + field_name?: string + field_type_id?: string + id?: string + order?: number + required?: boolean + structure_type_id?: string + } + Relationships: [ + { + foreignKeyName: "type_structure_fields_field_type_id_fkey" + columns: ["field_type_id"] + isOneToOne: false + referencedRelation: "types" + referencedColumns: ["id"] + }, + { + foreignKeyName: "type_structure_fields_structure_type_id_fkey" + columns: ["structure_type_id"] + isOneToOne: false + referencedRelation: "types" + referencedColumns: ["id"] + }, + ] + } + types: { + Row: { + created_at: string + description: string | null + id: string + json_schema: Json | null + kind: Database["public"]["Enums"]["type_kind"] + meta: Json | null + name: string + owner_id: string | null + parent_type_id: string | null + settings: Json | null + updated_at: string + visibility: Database["public"]["Enums"]["type_visibility"] + } + Insert: { + created_at?: string + description?: string | null + id?: string + json_schema?: Json | null + kind: Database["public"]["Enums"]["type_kind"] + meta?: Json | null + name: string + owner_id?: string | null + parent_type_id?: string | null + settings?: Json | null + updated_at?: string + visibility?: Database["public"]["Enums"]["type_visibility"] + } + Update: { + created_at?: string + description?: string | null + id?: string + json_schema?: Json | null + kind?: Database["public"]["Enums"]["type_kind"] + meta?: Json | null + name?: string + owner_id?: string | null + parent_type_id?: string | null + settings?: Json | null + updated_at?: string + visibility?: Database["public"]["Enums"]["type_visibility"] + } + Relationships: [ + { + foreignKeyName: "types_parent_type_id_fkey" + columns: ["parent_type_id"] + isOneToOne: false + referencedRelation: "types" + referencedColumns: ["id"] + }, + ] + } + user_filter_configs: { + Row: { + context: string + created_at: string | null + custom_filters: Json | null + default_templates: string[] | null + id: string + is_default: boolean | null + model: string + provider: string + updated_at: string | null + user_id: string | null + variables: Json | null + } + Insert: { + context: string + created_at?: string | null + custom_filters?: Json | null + default_templates?: string[] | null + id?: string + is_default?: boolean | null + model?: string + provider?: string + updated_at?: string | null + user_id?: string | null + variables?: Json | null + } + Update: { + context?: string + created_at?: string | null + custom_filters?: Json | null + default_templates?: string[] | null + id?: string + is_default?: boolean | null + model?: string + provider?: string + updated_at?: string | null + user_id?: string | null + variables?: Json | null + } + Relationships: [] + } + user_organizations: { + Row: { + created_at: string + id: string + organization_id: string + role: string + updated_at: string + user_id: string + } + Insert: { + created_at?: string + id?: string + organization_id: string + role?: string + updated_at?: string + user_id: string + } + Update: { + created_at?: string + id?: string + organization_id?: string + role?: string + updated_at?: string + user_id?: string + } + Relationships: [ + { + foreignKeyName: "user_organizations_organization_id_fkey" + columns: ["organization_id"] + isOneToOne: false + referencedRelation: "organizations" + referencedColumns: ["id"] + }, + ] + } + user_roles: { + Row: { + created_at: string + id: string + organization_id: string | null + role: Database["public"]["Enums"]["app_role"] + updated_at: string + user_id: string + } + Insert: { + created_at?: string + id?: string + organization_id?: string | null + role: Database["public"]["Enums"]["app_role"] + updated_at?: string + user_id: string + } + Update: { + created_at?: string + id?: string + organization_id?: string | null + role?: Database["public"]["Enums"]["app_role"] + updated_at?: string + user_id?: string + } + Relationships: [ + { + foreignKeyName: "user_roles_user_id_fkey" + columns: ["user_id"] + isOneToOne: false + referencedRelation: "profiles" + referencedColumns: ["user_id"] + }, + ] + } + user_secrets: { + Row: { + aimlapi_api_key: string | null + bria_api_key: string | null + created_at: string + google_api_key: string | null + huggingface_api_key: string | null + is_admin: boolean | null + openai_api_key: string | null + replicate_api_key: string | null + settings: Json | null + updated_at: string + user_id: string + } + Insert: { + aimlapi_api_key?: string | null + bria_api_key?: string | null + created_at?: string + google_api_key?: string | null + huggingface_api_key?: string | null + is_admin?: boolean | null + openai_api_key?: string | null + replicate_api_key?: string | null + settings?: Json | null + updated_at?: string + user_id: string + } + Update: { + aimlapi_api_key?: string | null + bria_api_key?: string | null + created_at?: string + google_api_key?: string | null + huggingface_api_key?: string | null + is_admin?: boolean | null + openai_api_key?: string | null + replicate_api_key?: string | null + settings?: Json | null + updated_at?: string + user_id?: string + } + Relationships: [] + } + user_templates: { + Row: { + context: string + created_at: string | null + description: string | null + filters: string[] | null + format: string | null + id: string + is_public: boolean | null + model: string + name: string + prompt: string + provider: string + updated_at: string | null + usage_count: number | null + user_id: string | null + } + Insert: { + context: string + created_at?: string | null + description?: string | null + filters?: string[] | null + format?: string | null + id?: string + is_public?: boolean | null + model?: string + name: string + prompt: string + provider?: string + updated_at?: string | null + usage_count?: number | null + user_id?: string | null + } + Update: { + context?: string + created_at?: string | null + description?: string | null + filters?: string[] | null + format?: string | null + id?: string + is_public?: boolean | null + model?: string + name?: string + prompt?: string + provider?: string + updated_at?: string | null + usage_count?: number | null + user_id?: string | null + } + Relationships: [] + } + widget_translations: { + Row: { + created_at: string | null + entity_id: string | null + entity_type: string | null + id: string + meta: Json | null + prop_path: string | null + source_lang: string + source_text: string | null + source_version: number | null + status: Database["public"]["Enums"]["translation_status"] | null + target_lang: string + translated_text: string | null + updated_at: string | null + widget_id: string | null + } + Insert: { + created_at?: string | null + entity_id?: string | null + entity_type?: string | null + id?: string + meta?: Json | null + prop_path?: string | null + source_lang: string + source_text?: string | null + source_version?: number | null + status?: Database["public"]["Enums"]["translation_status"] | null + target_lang: string + translated_text?: string | null + updated_at?: string | null + widget_id?: string | null + } + Update: { + created_at?: string | null + entity_id?: string | null + entity_type?: string | null + id?: string + meta?: Json | null + prop_path?: string | null + source_lang?: string + source_text?: string | null + source_version?: number | null + status?: Database["public"]["Enums"]["translation_status"] | null + target_lang?: string + translated_text?: string | null + updated_at?: string | null + widget_id?: string | null + } + Relationships: [] + } + wizard_sessions: { + Row: { + created_at: string + generated_image_url: string | null + id: string + input_images: string[] | null + prompt: string + status: string + updated_at: string + user_id: string + } + Insert: { + created_at?: string + generated_image_url?: string | null + id?: string + input_images?: string[] | null + prompt?: string + status?: string + updated_at?: string + user_id: string + } + Update: { + created_at?: string + generated_image_url?: string | null + id?: string + input_images?: string[] | null + prompt?: string + status?: string + updated_at?: string + user_id?: string + } + Relationships: [] + } + } + Views: { + [_ in never]: never + } + Functions: { + authorize: { + Args: { + _role: Database["public"]["Enums"]["app_role"] + _user_id: string + } + Returns: boolean + } + has_permission: { + Args: { + _permission: Database["public"]["Enums"]["app_permission"] + _user_id: string + } + Returns: boolean + } + is_page_collaborator: { Args: { _page_id: string }; Returns: boolean } + is_page_owner: { Args: { _page_id: string }; Returns: boolean } + pages_search_text: { + Args: { rec: Database["public"]["Tables"]["pages"]["Row"] } + Returns: unknown + } + pictures_search_text: { + Args: { rec: Database["public"]["Tables"]["pictures"]["Row"] } + Returns: unknown + } + posts_search_text: { + Args: { rec: Database["public"]["Tables"]["posts"]["Row"] } + Returns: unknown + } + search_pages: { + Args: { result_limit?: number; search_query: string } + Returns: { + created_at: string + id: string + meta: Json + owner: string + rank: number + slug: string + tags: string[] + title: string + type: string + updated_at: string + }[] + } + search_pictures: { + Args: { result_limit?: number; search_query: string } + Returns: { + created_at: string + description: string + id: string + image_url: string + rank: number + tags: string[] + thumbnail_url: string + title: string + type: string + user_id: string + }[] + } + search_posts: { + Args: { result_limit?: number; search_query: string } + Returns: { + created_at: string + description: string + id: string + rank: number + title: string + type: string + user_id: string + }[] + } + } + Enums: { + app_permission: + | "pictures.read" + | "pictures.create" + | "pictures.update" + | "pictures.delete" + | "collections.read" + | "collections.create" + | "collections.update" + | "collections.delete" + | "comments.read" + | "comments.create" + | "comments.update" + | "comments.delete" + | "organization.manage" + app_role: "owner" | "admin" | "member" | "viewer" + cast_kind: "implicit" | "explicit" | "lossy" + category_relation_type: + | "generalization" + | "material_usage" + | "domain" + | "process_step" + | "standard" + | "other" + category_visibility: "public" | "unlisted" | "private" + collaborator_role: "viewer" | "editor" | "owner" + layout_visibility: "public" | "private" | "listed" | "custom" + translation_status: "draft" | "machine" | "reviewed" | "published" + type_kind: + | "primitive" + | "enum" + | "flags" + | "structure" + | "alias" + | "field" + type_visibility: "public" | "private" | "custom" + } + CompositeTypes: { + [_ in never]: never + } + } +} + +type DatabaseWithoutInternals = Omit + +type DefaultSchema = DatabaseWithoutInternals[Extract] + +export type Tables< + DefaultSchemaTableNameOrOptions extends + | keyof (DefaultSchema["Tables"] & DefaultSchema["Views"]) + | { schema: keyof DatabaseWithoutInternals }, + TableName extends DefaultSchemaTableNameOrOptions extends { + schema: keyof DatabaseWithoutInternals + } + ? keyof (DatabaseWithoutInternals[DefaultSchemaTableNameOrOptions["schema"]]["Tables"] & + DatabaseWithoutInternals[DefaultSchemaTableNameOrOptions["schema"]]["Views"]) + : never = never, +> = DefaultSchemaTableNameOrOptions extends { + schema: keyof DatabaseWithoutInternals +} + ? (DatabaseWithoutInternals[DefaultSchemaTableNameOrOptions["schema"]]["Tables"] & + DatabaseWithoutInternals[DefaultSchemaTableNameOrOptions["schema"]]["Views"])[TableName] extends { + Row: infer R + } + ? R + : never + : DefaultSchemaTableNameOrOptions extends keyof (DefaultSchema["Tables"] & + DefaultSchema["Views"]) + ? (DefaultSchema["Tables"] & + DefaultSchema["Views"])[DefaultSchemaTableNameOrOptions] extends { + Row: infer R + } + ? R + : never + : never + +export type TablesInsert< + DefaultSchemaTableNameOrOptions extends + | keyof DefaultSchema["Tables"] + | { schema: keyof DatabaseWithoutInternals }, + TableName extends DefaultSchemaTableNameOrOptions extends { + schema: keyof DatabaseWithoutInternals + } + ? keyof DatabaseWithoutInternals[DefaultSchemaTableNameOrOptions["schema"]]["Tables"] + : never = never, +> = DefaultSchemaTableNameOrOptions extends { + schema: keyof DatabaseWithoutInternals +} + ? DatabaseWithoutInternals[DefaultSchemaTableNameOrOptions["schema"]]["Tables"][TableName] extends { + Insert: infer I + } + ? I + : never + : DefaultSchemaTableNameOrOptions extends keyof DefaultSchema["Tables"] + ? DefaultSchema["Tables"][DefaultSchemaTableNameOrOptions] extends { + Insert: infer I + } + ? I + : never + : never + +export type TablesUpdate< + DefaultSchemaTableNameOrOptions extends + | keyof DefaultSchema["Tables"] + | { schema: keyof DatabaseWithoutInternals }, + TableName extends DefaultSchemaTableNameOrOptions extends { + schema: keyof DatabaseWithoutInternals + } + ? keyof DatabaseWithoutInternals[DefaultSchemaTableNameOrOptions["schema"]]["Tables"] + : never = never, +> = DefaultSchemaTableNameOrOptions extends { + schema: keyof DatabaseWithoutInternals +} + ? DatabaseWithoutInternals[DefaultSchemaTableNameOrOptions["schema"]]["Tables"][TableName] extends { + Update: infer U + } + ? U + : never + : DefaultSchemaTableNameOrOptions extends keyof DefaultSchema["Tables"] + ? DefaultSchema["Tables"][DefaultSchemaTableNameOrOptions] extends { + Update: infer U + } + ? U + : never + : never + +export type Enums< + DefaultSchemaEnumNameOrOptions extends + | keyof DefaultSchema["Enums"] + | { schema: keyof DatabaseWithoutInternals }, + EnumName extends DefaultSchemaEnumNameOrOptions extends { + schema: keyof DatabaseWithoutInternals + } + ? keyof DatabaseWithoutInternals[DefaultSchemaEnumNameOrOptions["schema"]]["Enums"] + : never = never, +> = DefaultSchemaEnumNameOrOptions extends { + schema: keyof DatabaseWithoutInternals +} + ? DatabaseWithoutInternals[DefaultSchemaEnumNameOrOptions["schema"]]["Enums"][EnumName] + : DefaultSchemaEnumNameOrOptions extends keyof DefaultSchema["Enums"] + ? DefaultSchema["Enums"][DefaultSchemaEnumNameOrOptions] + : never + +export type CompositeTypes< + PublicCompositeTypeNameOrOptions extends + | keyof DefaultSchema["CompositeTypes"] + | { schema: keyof DatabaseWithoutInternals }, + CompositeTypeName extends PublicCompositeTypeNameOrOptions extends { + schema: keyof DatabaseWithoutInternals + } + ? keyof DatabaseWithoutInternals[PublicCompositeTypeNameOrOptions["schema"]]["CompositeTypes"] + : never = never, +> = PublicCompositeTypeNameOrOptions extends { + schema: keyof DatabaseWithoutInternals +} + ? DatabaseWithoutInternals[PublicCompositeTypeNameOrOptions["schema"]]["CompositeTypes"][CompositeTypeName] + : PublicCompositeTypeNameOrOptions extends keyof DefaultSchema["CompositeTypes"] + ? DefaultSchema["CompositeTypes"][PublicCompositeTypeNameOrOptions] + : never + +export const Constants = { + graphql_public: { + Enums: {}, + }, + public: { + Enums: { + app_permission: [ + "pictures.read", + "pictures.create", + "pictures.update", + "pictures.delete", + "collections.read", + "collections.create", + "collections.update", + "collections.delete", + "comments.read", + "comments.create", + "comments.update", + "comments.delete", + "organization.manage", + ], + app_role: ["owner", "admin", "member", "viewer"], + cast_kind: ["implicit", "explicit", "lossy"], + category_relation_type: [ + "generalization", + "material_usage", + "domain", + "process_step", + "standard", + "other", + ], + category_visibility: ["public", "unlisted", "private"], + collaborator_role: ["viewer", "editor", "owner"], + layout_visibility: ["public", "private", "listed", "custom"], + translation_status: ["draft", "machine", "reviewed", "published"], + type_kind: ["primitive", "enum", "flags", "structure", "alias", "field"], + type_visibility: ["public", "private", "custom"], + }, + }, +} as const diff --git a/src/jobs/boss/AbstractWorker.ts b/src/jobs/boss/AbstractWorker.ts new file mode 100644 index 0000000..1280c7a --- /dev/null +++ b/src/jobs/boss/AbstractWorker.ts @@ -0,0 +1,58 @@ +import { Job } from 'pg-boss'; +import { supabase } from '../../commons/supabase.js'; +import { logger } from '../../commons/logger.js'; +import EventEmitter from 'events'; + + +export abstract class AbstractWorker { + abstract readonly queueName: string; + readonly queueOptions?: any; // pg-boss QueueOptions + protected emitter?: EventEmitter; + + // Cost calculation can be static or dynamic based on results + abstract calculateCost(job: Job, result?: any): number; + + // The core business logic + protected abstract process(job: Job): Promise; + + // Main entry point for pg-boss + public async handler(jobOrJobs: Job | Job[]) { + + const job = Array.isArray(jobOrJobs) ? jobOrJobs[0] : jobOrJobs; + + // Safety check + if (!job) { + logger.error(`[${this.queueName}] Received null or empty job`); + return; + } + + const jobId = job.id; + const usageId = (job.data as any)?.usageId; + + logger.info(`[${this.queueName}] Starting job ${jobId}`); + + try { + // 2. Execute Business Logic + const result = await this.process(job); + + // 3. Calculate Cost + const cost = this.calculateCost(job, result); + + if (this.emitter) { + this.emitter.emit('job:complete', { + jobId, + result + }); + } + + + return result; + + } catch (error: any) { + + logger.error({ err: error }, `[${this.queueName}] Job failed`); + + throw error; // Let pg-boss handle retry/failure + } + } +} diff --git a/src/jobs/boss/client.ts b/src/jobs/boss/client.ts new file mode 100644 index 0000000..1fc3330 --- /dev/null +++ b/src/jobs/boss/client.ts @@ -0,0 +1,44 @@ +import { PgBoss } from 'pg-boss'; +import { logger } from '../../commons/logger.js'; + +const connectionString = process.env.DATABASE_URL; + +if (!connectionString) { + logger.warn('DATABASE_URL not found, PgBoss will not be initialized'); +} + +export const boss = connectionString ? new PgBoss({ + connectionString, + __test__enableSpies: true +} as any) : null; +export let bossInitError: Error | null = null; + +export async function startBoss() { + if (!boss) return; + + boss.on('error', (error: Error) => logger.error({ error }, 'PgBoss error')); + + try { + await boss.start(); + logger.info('PgBoss started'); + return boss; + } catch (error: any) { + bossInitError = error; + logger.error({ error }, 'Failed to start PgBoss'); + const fs = await import('fs'); + fs.writeFileSync('debug_pgboss_error.txt', JSON.stringify(error, Object.getOwnPropertyNames(error))); + } +} + +export async function stopBoss() { + if (!boss) { + console.info('PgBoss not initialized, skipping stop.') + return + } + try { + await boss.stop({ timeout: 5000 }); // 5s timeout + console.info('PgBoss stopped'); + } catch (error) { + console.error({ error }, 'Failed to stop PgBoss'); + } +} \ No newline at end of file diff --git a/src/jobs/boss/registry.ts b/src/jobs/boss/registry.ts new file mode 100644 index 0000000..e90a531 --- /dev/null +++ b/src/jobs/boss/registry.ts @@ -0,0 +1,25 @@ +import { Job } from 'pg-boss'; + +type WorkerHandler = (job: Job) => Promise; + +interface WorkerConfig { + queueName: string; + handler: WorkerHandler; + options?: any; +} + +export class WorkerRegistry { + private static workers: Map = new Map(); + + static register(queueName: string, handler: WorkerHandler, options?: any) { + this.workers.set(queueName, { queueName, handler, options }); + } + + static get(queueName: string): WorkerConfig | undefined { + return this.workers.get(queueName); + } + + static getAll(): WorkerConfig[] { + return Array.from(this.workers.values()); + } +} diff --git a/src/jobs/boss/search/SearchWorker.ts b/src/jobs/boss/search/SearchWorker.ts new file mode 100644 index 0000000..20d8ce3 --- /dev/null +++ b/src/jobs/boss/search/SearchWorker.ts @@ -0,0 +1,126 @@ +import { Job } from 'pg-boss'; +import { AbstractWorker } from '../AbstractWorker.js'; +import { googleMaps, ResolveFlags } from '@polymech/search'; +import { supabase } from '../../../commons/supabase.js'; +import { logger } from '../../../commons/logger.js'; +import { Worker } from '../../../commons/decorators.js'; + +export interface SearchJobData { + query: string; + location: string; + filters?: { + filterCity?: string; + filterContinent?: string; + filterType?: string; + concurrency?: number; + }; + userId: string; + usageId?: string; +} + +@Worker('search-worker') +export class SearchWorker extends AbstractWorker { + readonly queueName = 'search-worker'; + + calculateCost(job: Job, result: any): number { + // Example: 1 credit per search + 0.1 per result + return 1 + (result?.length || 0) * 0.1; + } + + protected async process(job: Job) { + const { query, location, filters, userId } = job.data; + + // Call existing logic (refactored from endpoints/competitors/index.ts) + const results = await googleMaps({ + query, + searchFrom: location, + resolve: [ResolveFlags.PHOTOS], + filterCity: filters?.filterCity, + filterContinent: filters?.filterContinent, + filterType: filters?.filterType, + concurrency: filters?.concurrency || 5 + }); + + // Flatten results + const flatResults = results ? results.flat(Infinity) : []; + + // Map and Upsert Locations + const locationsToUpsert = flatResults + .filter((r: any) => r.place_id) + .map((r: any) => ({ + place_id: r.place_id, + title: r.title, + description: r.description, + address: r.address, + gps_coordinates: r.gps_coordinates, + phone: r.phone, + website: r.website, + operating_hours: r.operating_hours, + thumbnail: r.thumbnail, + types: r.types, + raw_data: r, + continent: r.geo?.continent, + country: r.geo?.countryName, + city: r.geo?.city, + updated_at: new Date().toISOString(), // Update timestamp + user_id: userId + })); + + // Fetch existing locations to preserve meta (emails) + const placeIds = locationsToUpsert.map(l => l.place_id); + if (placeIds.length > 0) { + const { data: existingLocations } = await supabase + .from('locations') + .select('place_id, meta') + .in('place_id', placeIds); + + if (existingLocations) { + const metaMap = new Map(existingLocations.map(l => [l.place_id, l.meta])); + locationsToUpsert.forEach(l => { + const existingMeta = metaMap.get(l.place_id); + if (existingMeta) { + // Merge existing meta into raw_data for the client + l.raw_data.meta = { + ...(l.raw_data.meta || {}), + ...existingMeta + }; + } + }); + } + } + + if (locationsToUpsert.length > 0) { + const { error: upsertError } = await supabase + .from('locations') + .upsert(locationsToUpsert, { onConflict: 'place_id' }); + + if (upsertError) { + logger.error(upsertError, 'Error upserting locations'); + throw upsertError; + } + } + + // Store Search (for caching) + // Re-create hash logic from handler + const { createHash } = await import('crypto'); + const inputParams = { query, location }; + const normalizedInput = JSON.stringify(inputParams, Object.keys(inputParams).sort()); + const inputHash = createHash('sha256').update(normalizedInput).digest('hex'); + + const { error: searchStoreError } = await supabase + .from('searches') + .upsert({ + input_hash: inputHash, + input_params: inputParams, + result_place_ids: placeIds, + created_at: new Date().toISOString() + }, { onConflict: 'input_hash' }); + + if (searchStoreError) { + logger.error(searchStoreError, `Error storing search ${searchStoreError.message}`); + // Don't fail the job just because caching failed + } + + return { count: locationsToUpsert.length, placeIds }; + } +} diff --git a/src/jobs/boss/workers.ts b/src/jobs/boss/workers.ts new file mode 100644 index 0000000..9463e93 --- /dev/null +++ b/src/jobs/boss/workers.ts @@ -0,0 +1,40 @@ +import { boss } from './client.js'; +import { getAllWorkers } from '@/products/registry.js'; +import { logger } from '@/commons/logger.js'; + +export const QUEUE_MOCK_JOB = 'mock-job'; + +interface MockJobData { + subtasks: number; + delayMs: number; + shouldFail: boolean; +} + +export async function registerMockWorkers() { + if (!boss) return; + + // Product workers are now registered by the products themselves in AbstractProduct.start() + + await boss.createQueue(QUEUE_MOCK_JOB); + await boss.work(QUEUE_MOCK_JOB, async (jobs: any) => { + // PgBoss might pass an array of jobs or a single job depending on config/version + const job = Array.isArray(jobs) ? jobs[0] : jobs; + + const data = job.data || {}; + const { delayMs = 100, shouldFail = false } = data; + const jobId = job.id; + + logger.info({ jobId, data }, 'Processing PgBoss mock job'); + + await new Promise(resolve => setTimeout(resolve, delayMs)); + + if (shouldFail) { + throw new Error('Simulated PgBoss job failure'); + } + + logger.info({ jobId }, 'PgBoss mock job completed'); + return { success: true }; + }); + + logger.info('PgBoss workers registered'); +} diff --git a/src/lib/analytics-emitter.ts b/src/lib/analytics-emitter.ts new file mode 100644 index 0000000..332871f --- /dev/null +++ b/src/lib/analytics-emitter.ts @@ -0,0 +1,5 @@ +import { EventEmitter } from 'events'; + +class AnalyticsEmitter extends EventEmitter { } + +export const analyticsEmitter = new AnalyticsEmitter(); diff --git a/src/middleware/analytics.ts b/src/middleware/analytics.ts new file mode 100644 index 0000000..c91dff9 --- /dev/null +++ b/src/middleware/analytics.ts @@ -0,0 +1,171 @@ +import { Context, Next } from 'hono'; +import fs from 'fs'; +import path from 'path'; +import axios from 'axios' +import { analyticsEmitter } from '../lib/analytics-emitter.js'; + +// import { isBotRequest, isAIRequest } from '../products/serving/bots.js'; + +const ANALYTICS_FILE = path.resolve(process.cwd(), 'logs/analytics.jsonl'); + +// Extensions to ignore +const IGNORED_EXTENSIONS = new Set([ + '.js', '.css', '.png', '.jpg', '.jpeg', '.gif', '.ico', '.svg', '.woff', '.woff2', '.ttf', '.eot', '.map' +]); +export const REVERSE_DEFAULT = { continent: 'unknown', countryName: 'unknown', city: 'unknown' } + +export interface Geo { + latitude: number + lookupSource: string + longitude: number + localityLanguageRequested: string + continent: string + continentCode: string + countryName: string + countryCode: string + principalSubdivision: string + principalSubdivisionCode: string + city: string + locality: string + postcode: string + plusCode: string + localityInfo: LocalityInfo +} + +export interface LocalityInfo { + administrative: Administrative[] + informative: Informative[] +} + +export interface Administrative { + name: string + description: string + isoName?: string + order: number + adminLevel: number + isoCode?: string + wikidataId: string + geonameId: number +} + +export interface Informative { + name: string + description?: string + isoName?: string + order: number + isoCode?: string + wikidataId?: string + geonameId?: number +} + +const GEO_CACHE_FILE = path.resolve(process.cwd(), 'cache/geoip.json'); + +// Simple in-memory cache to reduce disk I/O, initialized on first use +let geoCache: Record | null = null; + +const loadGeoCache = () => { + if (geoCache) return geoCache; + try { + if (fs.existsSync(GEO_CACHE_FILE)) { + const data = fs.readFileSync(GEO_CACHE_FILE, 'utf-8'); + geoCache = JSON.parse(data); + } else { + geoCache = {}; + } + } catch (e) { + console.error('Error loading geo cache', e); + geoCache = {}; + } + return geoCache; +}; + +const saveGeoCache = (ip: string, data: any) => { + if (!geoCache) geoCache = {}; + geoCache[ip] = data; + + // Ensure directory exists + const dir = path.dirname(GEO_CACHE_FILE); + if (!fs.existsSync(dir)) { + fs.mkdirSync(dir, { recursive: true }); + } + + // Write to file (async to not block) + fs.promises.writeFile(GEO_CACHE_FILE, JSON.stringify(geoCache, null, 2)).catch(err => { + console.error('Error saving geo cache', err); + }); +}; + +export const reverse = async (ip: string, opts: any) => { + return REVERSE_DEFAULT; + /* + const cache = loadGeoCache(); + if (cache && cache[ip]) { + return cache[ip]; + } + + const config = CONFIG_DEFAULT() as any + try { + const q = `https://api-bdc.net/data/ip-geolocation?ip=${ip}&localityLanguage=en&key=${config.bigdata.key}` + const ret = await axios.get(q) || { data: REVERSE_DEFAULT } + const data = ret.data || REVERSE_DEFAULT + saveGeoCache(ip, data); + return data; + } catch (e: any) { + logger.error('Error reverse geocoding', e.message) + return REVERSE_DEFAULT + } + */ +} + +export async function analyticsMiddleware(c: Context, next: Next) { + await next(); // Execute the request first (non-blocking for the response?) + // Wait, "await next()" blocks the middleware until the downstream handlers finish. + // If we want to capture the status code, we need to wait. + // The user asked for "non blocking analytics middleware". + // Usually this means the *write* operation shouldn't block the response. + // So we can do the logging logic *after* `await next()`, but ensuring the file write is not awaited or is fire-and-forget. + + try { + const url = new URL(c.req.url); + const pathname = url.pathname; + const extension = path.extname(pathname).toLowerCase(); + + // Filter static assets + if (IGNORED_EXTENSIONS.has(extension)) { + return; + } + + // Additional check for common static paths if they don't have extensions + if (pathname.startsWith('/assets/') || pathname.startsWith('/static/')) { + return; + } + + const ip = c.req.header('x-forwarded-for') || c.req.header('cf-connecting-ip') || '92.176.215.140' + const geo = REVERSE_DEFAULT; // || ip !== 'unknown' ? await reverse(ip, CONFIG_DEFAULT()) : REVERSE_DEFAULT + const userAgent = c.req.header('user-agent'); + const entry: any = { + timestamp: new Date().toISOString(), + method: c.req.method, + path: pathname, + status: c.res.status, + ip, + userAgent, + // isBot: isBotRequest(userAgent), + // isAI: isAIRequest(userAgent), + referer: c.req.header('referer'), + userId: c.get('userId'), + geo + }; + + const line = JSON.stringify(entry) + '\n'; + // Emit event for real-time streaming + analyticsEmitter.emit('log', entry); + // Fire and forget write + fs.promises.appendFile(ANALYTICS_FILE, line).catch(err => { + console.error('Failed to write to analytics file:', err); + }); + + } catch (err) { + console.error('Error in analytics middleware:', err); + } +} diff --git a/src/middleware/auth.ts b/src/middleware/auth.ts new file mode 100644 index 0000000..0c3f7b2 --- /dev/null +++ b/src/middleware/auth.ts @@ -0,0 +1,127 @@ +import { Context, Next } from 'hono'; +import { securityLogger as logger } from '../commons/logger.js'; +import { PublicEndpointRegistry, AdminEndpointRegistry } from '../commons/registry.js'; +import { getUserCached, supabase } from '../commons/supabase.js'; + + +/** + * Strict authentication middleware – requires a valid Bearer token. + */ +export async function authMiddleware(c: Context, next: Next) { + const authHeader = c.req.header('authorization'); + if (!authHeader?.startsWith('Bearer ')) { + return c.json({ error: 'Unauthorized - Missing or invalid authorization header' }, 401); + } + const token = authHeader.substring(7); + try { + const user = await getUserCached(token); + if (!user) { + return c.json({ error: 'Invalid or expired token' }, 401); + } + c.set('userId', user.id); + c.set('user', user); + c.set('userEmail', user.email); + await next(); + } catch (err) { + logger.error({ err }, 'Auth middleware error'); + return c.json({ error: 'Authentication failed' }, 401); + } +} + +/** + * Optional authentication middleware. + * - Public endpoint: GET /api/products (no auth required). + * - Otherwise respects REQUIRE_AUTH flag, but skips auth in test/dev environments. + */ +export async function optionalAuthMiddleware(c: Context, next: Next) { + const path = c.req.path; + const method = c.req.method; + + // Public endpoint – allow unauthenticated access + const isPublicEndpoint = PublicEndpointRegistry.isPublic(path, method); + const isProductsEndpoint = method === 'GET' && path === '/api/products'; + if (isProductsEndpoint || isPublicEndpoint) { + return await next(); + } + + const requireAuth = process.env.REQUIRE_AUTH === 'true'; + const isTestEnv = false; // process.env.NODE_ENV === 'test' || process.env.NODE_ENV === 'development'; + const authHeader = c.req.header('authorization'); + + // If no auth header, or it's not a Bearer token... + let token: string | undefined; + + if (authHeader && authHeader.startsWith('Bearer ')) { + token = authHeader.substring(7); + } else { + // Check for token in query param (for SSE) + const queryToken = c.req.query('token'); + if (queryToken) { + token = queryToken; + } + } + + if (!token) { + // ...and we are in test env or auth not required, just continue. + if (!requireAuth) { + return await next(); + } + // ...otherwise reject + return c.json({ error: 'Unauthorized' }, 401); + } + + try { + const user = await getUserCached(token); + if (!user) { + logger.warn('[Auth] Token verification failed'); + if (isTestEnv) { + return await next(); + } + return c.json({ error: 'Unauthorized' }, 401); + } + c.set('userId', user.id); + c.set('user', user); + c.set('userEmail', user.email); + await next(); + } catch (err) { + logger.error({ err }, '[Auth] Optional auth middleware error - REJECTING'); + return c.json({ error: 'Authentication failed' }, 401); + } +} + +/** + * Admin‑only middleware – requires authentication and admin role. + * Checks AdminEndpointRegistry to see if the route requires admin access. + */ +export async function adminMiddleware(c: Context, next: Next) { + const path = c.req.path; + const method = c.req.method; + + // Check if this is an admin endpoint + if (!AdminEndpointRegistry.isAdmin(path, method)) { + return await next(); + } + + // If it is an admin endpoint, enforce auth and role + const userId = c.get('userId'); + if (!userId) { + return c.json({ error: 'Unauthorized - Authentication required' }, 401); + } + try { + const { data: profile, error } = await supabase + .from('user_roles') + .select('role') + .eq('user_id', userId) + .single(); + // @todo : fix db - type | multiple - currently single string + if (error || !profile || profile.role !== 'admin') { + return c.json({ error: 'Forbidden - Admin access required' }, 403); + } + c.set('isAdmin', true); + await next(); + } catch (err) { + logger.error({ err }, 'Admin middleware error'); + return c.json({ error: 'Authorization check failed' }, 500); + } +} + diff --git a/src/middleware/autoBan.ts b/src/middleware/autoBan.ts new file mode 100644 index 0000000..def5d86 --- /dev/null +++ b/src/middleware/autoBan.ts @@ -0,0 +1,450 @@ +import { Context, Next } from 'hono' +import { readFileSync, writeFileSync } from 'fs' +import { join } from 'path' +import { logger, securityLogger } from '../commons/logger.js' + +interface BanList { + bannedIPs: string[] + bannedUserIds: string[] + bannedTokens: string[] +} + +interface ViolationRecord { + count: number + firstViolation: number + lastViolation: number +} + +// Configuration +const BAN_THRESHOLD = parseInt(process.env.AUTO_BAN_THRESHOLD || '5', 10) // Number of violations before ban +const VIOLATION_WINDOW_MS = parseInt(process.env.AUTO_BAN_WINDOW_MS || '10000', 10) // 1 minute default +const VIOLATION_CLEANUP_INTERVAL = 10000 // Clean up old violations every minute + +console.log('Auto-ban configured with:', { + threshold: BAN_THRESHOLD, + window: VIOLATION_WINDOW_MS / 60000, + cleanupInterval: VIOLATION_CLEANUP_INTERVAL / 60000 +}) + +// In-memory violation tracking +const violations = new Map() + +let banList: BanList = { + bannedIPs: [], + bannedUserIds: [], + bannedTokens: [], +} + +/** + * Load ban list from JSON file + */ +export function loadBanList(): BanList { + try { + const banListPath = join(process.cwd(), 'config', 'ban.json') + const data = readFileSync(banListPath, 'utf-8') + banList = JSON.parse(data) + return banList + } catch (error) { + logger.error({ error }, 'Failed to load ban list') + return banList + } +} + +/** + * Save ban list to JSON file + */ +function saveBanList(): void { + try { + const banListPath = join(process.cwd(), 'config', 'ban.json') + writeFileSync(banListPath, JSON.stringify(banList, null, 4), 'utf-8') + logger.info('Ban list saved') + } catch (error) { + logger.error({ error }, 'Failed to save ban list') + } +} + +/** + * Get current ban list + */ +export function getBanList(): BanList { + return banList +} + +/** + * Check if an IP is banned + */ +export function isIPBanned(ip: string): boolean { + return banList.bannedIPs.includes(ip) +} + +/** + * Check if a user ID is banned + */ +export function isUserBanned(userId: string): boolean { + return banList.bannedUserIds.includes(userId) +} + +/** + * Check if an auth token is banned + */ +export function isTokenBanned(token: string): boolean { + return banList.bannedTokens.includes(token) +} + +/** + * Extract IP address from request + */ +export function getClientIP(c: Context): string { + // Check forwarded headers first (for proxies) + const forwarded = c.req.header('x-forwarded-for') + if (forwarded) { + return forwarded.split(',')[0].trim() + } + + const realIp = c.req.header('x-real-ip') + if (realIp) { + return realIp + } + + // Fallback to connection IP (works for localhost) + // In Node.js/Hono, we can try to get the remote address + try { + // @ts-ignore - accessing internal request object + const remoteAddress = c.req.raw?.socket?.remoteAddress || c.env?.ip + if (remoteAddress) { + return remoteAddress + } + } catch (e) { + // Ignore errors + } + + // Last resort: use localhost identifier + return '127.0.0.1' +} + +/** + * Extract user ID from authorization header + */ +function getUserId(c: Context): string | null { + const authHeader = c.req.header('authorization') + if (!authHeader) return null + return authHeader +} + +/** + * Record a rate limit violation + */ +export function recordViolation(key: string): void { + const now = Date.now() + const existing = violations.get(key) + + if (existing) { + // Check if violation is within the window + if (now - existing.firstViolation <= VIOLATION_WINDOW_MS) { + existing.count++ + existing.lastViolation = now + violations.set(key, existing) + + // Check if threshold exceeded + if (existing.count >= BAN_THRESHOLD) { + banEntity(key) + } + } else { + // Reset violation count if outside window + violations.set(key, { + count: 1, + firstViolation: now, + lastViolation: now, + }) + } + } else { + // First violation + violations.set(key, { + count: 1, + firstViolation: now, + lastViolation: now, + }) + } + + logger.debug({ key, violations: violations.get(key) }, 'Violation recorded') +} + +/** + * Ban an entity (IP, user, or token) + */ +function banEntity(key: string): void { + const [type, value] = key.split(':', 2) + const violationRecord = violations.get(key) + + let added = false + if (type === 'ip' && !banList.bannedIPs.includes(value)) { + banList.bannedIPs.push(value) + added = true + + // Log to security.json + securityLogger.warn({ + event: 'auto_ban', + type: 'ip', + ip: value, + violations: violationRecord?.count, + firstViolation: violationRecord?.firstViolation, + lastViolation: violationRecord?.lastViolation + }, 'IP auto-banned for excessive requests') + + // Also log to console + logger.info({ ip: value, violations: violationRecord?.count }, '🚫 IP auto-banned for excessive requests') + + } else if (type === 'user' && !banList.bannedUserIds.includes(value)) { + banList.bannedUserIds.push(value) + added = true + + // Log to security.json + securityLogger.warn({ + event: 'auto_ban', + type: 'user', + userId: value, + violations: violationRecord?.count, + firstViolation: violationRecord?.firstViolation, + lastViolation: violationRecord?.lastViolation + }, 'User auto-banned for excessive requests') + + // Also log to console + logger.info({ userId: value, violations: violationRecord?.count }, '🚫 User auto-banned for excessive requests') + + } else if (type === 'token' && !banList.bannedTokens.includes(value)) { + banList.bannedTokens.push(value) + added = true + + // Log to security.json + securityLogger.warn({ + event: 'auto_ban', + type: 'token', + token: value.substring(0, 20) + '...', + violations: violationRecord?.count, + firstViolation: violationRecord?.firstViolation, + lastViolation: violationRecord?.lastViolation + }, 'Token auto-banned for excessive requests') + + // Also log to console + logger.info({ token: value.substring(0, 20) + '...', violations: violationRecord?.count }, '🚫 Token auto-banned for excessive requests') + } + + if (added) { + saveBanList() + // Clear violation record after ban + violations.delete(key) + } +} + +/** + * Clean up old violation records + */ +function cleanupViolations(): void { + const now = Date.now() + let cleaned = 0 + + for (const [key, record] of violations.entries()) { + if (now - record.lastViolation > VIOLATION_WINDOW_MS) { + violations.delete(key) + cleaned++ + } + } + + if (cleaned > 0) { + logger.debug({ cleaned }, 'Cleaned up old violation records') + } +} + +/** + * Auto-ban middleware + * Checks if request is from a banned entity + */ + +// Simple in-memory rate limiting +const requestCounts = new Map() +const RATE_LIMIT_MAX = parseInt(process.env.RATE_LIMIT_MAX || '20', 10) +const RATE_LIMIT_WINDOW_MS = parseInt(process.env.RATE_LIMIT_WINDOW_MS || '1000', 10) + +export async function autoBanMiddleware(c: Context, next: Next) { + const ip = getClientIP(c) + const path = c.req.path + const method = c.req.method + + // Skip ban/rate-limit checks for local requests (dev & e2e tests) + if (ip === '127.0.0.1' || ip === 'localhost' || ip === '::1' || ip === '::ffff:127.0.0.1') { + return next() + } + + const authHeader = c.req.header('authorization') + const userId = getUserId(c) + + // Generate key for rate limiting + let key: string + if (authHeader) { + key = `user:${authHeader}` + } else { + key = `ip:${ip}` + } + + // Check if IP is banned + if (isIPBanned(ip)) { + /* + securityLogger.info({ + event: 'blocked_request', + type: 'ip', + ip, + path, + method + }, 'Blocked request from banned IP') + */ + + // logger.info({ ip, path }, '🚫 Blocked request from banned IP') + + return c.json( + { + error: 'Forbidden', + message: 'Your IP address has been banned for excessive requests', + }, + 403 + ) + } + + // Check if auth token is banned + if (authHeader && isTokenBanned(authHeader)) { + securityLogger.info({ + event: 'blocked_request', + type: 'token', + token: authHeader.substring(0, 20) + '...', + path, + method + }, 'Blocked request from banned token') + + logger.info({ token: authHeader.substring(0, 20) + '...', path }, '🚫 Blocked request from banned token') + + return c.json( + { + error: 'Forbidden', + message: 'Your access token has been banned for excessive requests', + }, + 403 + ) + } + + // Check if user ID is banned + if (userId && isUserBanned(userId)) { + securityLogger.info({ + event: 'blocked_request', + type: 'user', + userId, + path, + method + }, 'Blocked request from banned user') + + logger.info({ userId, path }, '🚫 Blocked request from banned user') + + return c.json( + { + error: 'Forbidden', + message: 'Your account has been banned for excessive requests', + }, + 403 + ) + } + + // Built-in rate limiting (since hono-rate-limiter isn't working) + const now = Date.now() + const record = requestCounts.get(key) + + if (record) { + if (now < record.resetTime) { + // Within the window + record.count++ + + if (record.count > RATE_LIMIT_MAX) { + // Rate limit exceeded! + console.log(`⚠️ Rate limit exceeded for ${key} (${record.count}/${RATE_LIMIT_MAX})`) + recordViolation(key) + + return c.json( + { + error: 'Too many requests', + message: `Rate limit exceeded. Maximum ${RATE_LIMIT_MAX} requests per ${RATE_LIMIT_WINDOW_MS}ms`, + }, + 429 + ) + } + } else { + // Window expired, reset + record.count = 1 + record.resetTime = now + RATE_LIMIT_WINDOW_MS + } + } else { + // First request + requestCounts.set(key, { + count: 1, + resetTime: now + RATE_LIMIT_WINDOW_MS + }) + } + await next() +} + +/** + * Manually unban an IP + */ +export function unbanIP(ip: string): boolean { + const index = banList.bannedIPs.indexOf(ip) + if (index > -1) { + banList.bannedIPs.splice(index, 1) + saveBanList() + + securityLogger.info({ + event: 'unban', + type: 'ip', + ip + }, 'IP unbanned') + + logger.info({ ip }, 'IP unbanned') + return true + } + return false +} + +/** + * Manually unban a user + */ +export function unbanUser(userId: string): boolean { + const index = banList.bannedUserIds.indexOf(userId) + if (index > -1) { + banList.bannedUserIds.splice(index, 1) + saveBanList() + + securityLogger.info({ + event: 'unban', + type: 'user', + userId + }, 'User unbanned') + + logger.info({ userId }, 'User unbanned') + return true + } + return false +} + +/** + * Get current violation stats + */ +export function getViolationStats() { + return { + totalViolations: violations.size, + violations: Array.from(violations.entries()).map(([key, record]) => ({ + key, + ...record, + })), + } +} + +// Load ban list on module initialization +loadBanList() + +// Start cleanup interval +setInterval(cleanupViolations, VIOLATION_CLEANUP_INTERVAL) diff --git a/src/middleware/blocklist.ts b/src/middleware/blocklist.ts new file mode 100644 index 0000000..b9aecac --- /dev/null +++ b/src/middleware/blocklist.ts @@ -0,0 +1,134 @@ +import { Context, Next } from 'hono' +import { readFileSync } from 'fs' +import { join, dirname } from 'path' +import { fileURLToPath } from 'url' + +const __filename = fileURLToPath(import.meta.url) +const __dirname = dirname(__filename) + +interface Blocklist { + blockedIPs: string[] + blockedUserIds: string[] + blockedTokens: string[] +} + +let blocklist: Blocklist = { + blockedIPs: [], + blockedUserIds: [], + blockedTokens: [], +} + +/** + * Load blocklist from JSON file + */ +export function loadBlocklist(): Blocklist { + try { + const blocklistPath = join(process.cwd(), 'config', 'blocklist.json') + const data = readFileSync(blocklistPath, 'utf-8') + blocklist = JSON.parse(data) + return blocklist + } catch (error) { + console.error('Failed to load blocklist:', error) + return blocklist + } +} + +/** + * Get current blocklist + */ +export function getBlocklist(): Blocklist { + return blocklist +} + +/** + * Check if an IP is blocked + */ +export function isIPBlocked(ip: string): boolean { + return blocklist.blockedIPs.includes(ip) +} + +/** + * Check if a user ID is blocked + */ +export function isUserBlocked(userId: string): boolean { + return blocklist.blockedUserIds.includes(userId) +} + +/** + * Check if an auth token is blocked + */ +export function isTokenBlocked(token: string): boolean { + return blocklist.blockedTokens.includes(token) +} + +/** + * Extract IP address from request + */ +function getClientIP(c: Context): string { + const forwarded = c.req.header('x-forwarded-for') + if (forwarded) { + return forwarded.split(',')[0].trim() + } + return c.req.header('x-real-ip') || 'unknown' +} + +/** + * Extract user ID from authorization header + * This is a simple implementation - adjust based on your auth strategy + */ +function getUserId(c: Context): string | null { + const authHeader = c.req.header('authorization') + if (!authHeader) return null + + // Simple extraction - in production, you'd decode JWT or validate token + // For now, we'll use the auth header as-is for blocklist checking + return authHeader +} + +/** + * Blocklist middleware + * Blocks requests from blacklisted IPs, users, or tokens + */ +export async function blocklistMiddleware(c: Context, next: Next) { + const ip = getClientIP(c) + const authHeader = c.req.header('authorization') + const userId = getUserId(c) + + // Check if IP is blocked + if (isIPBlocked(ip)) { + return c.json( + { + error: 'Forbidden', + message: 'Your IP address has been blocked', + }, + 403 + ) + } + + // Check if auth token is blocked + if (authHeader && isTokenBlocked(authHeader)) { + return c.json( + { + error: 'Forbidden', + message: 'Your access token has been blocked', + }, + 403 + ) + } + + // Check if user ID is blocked + if (userId && isUserBlocked(userId)) { + return c.json( + { + error: 'Forbidden', + message: 'Your account has been blocked', + }, + 403 + ) + } + + await next() +} + +// Load blocklist on module initialization +loadBlocklist() diff --git a/src/middleware/rateLimiter.ts b/src/middleware/rateLimiter.ts new file mode 100644 index 0000000..2ae64ed --- /dev/null +++ b/src/middleware/rateLimiter.ts @@ -0,0 +1,106 @@ +import { Context, Next } from 'hono' +import { rateLimiter } from 'hono-rate-limiter' +import { recordViolation } from './autoBan.js' + +// Rate limit configuration from environment variables +const RATE_LIMIT_MAX = parseInt(process.env.RATE_LIMIT_MAX || '1', 10) +const RATE_LIMIT_WINDOW_MS = parseInt(process.env.RATE_LIMIT_WINDOW_MS || '50', 10) + +console.log('🔒 Rate Limiter Configuration:') +console.log(` Max: ${RATE_LIMIT_MAX} requests per ${RATE_LIMIT_WINDOW_MS}ms`) +console.log(` Auto-ban threshold: ${process.env.AUTO_BAN_THRESHOLD || 10} violations`) + + +/** + * Rate limiter middleware configuration + * Limits requests per user/IP address + */ +export const apiRateLimiter = rateLimiter({ + windowMs: RATE_LIMIT_WINDOW_MS, // Time window in milliseconds + limit: RATE_LIMIT_MAX, // Max requests per window + standardHeaders: 'draft-6', // Return rate limit info in headers + keyGenerator: (c: Context) => { + // Try to get user ID from auth header, fallback to IP + const authHeader = c.req.header('authorization') + if (authHeader) { + // Extract user ID from JWT or auth token if available + // For now, use the auth header as key + return `user:${authHeader}` + } + + // Fallback to IP address + const forwarded = c.req.header('x-forwarded-for') + const ip = forwarded ? forwarded.split(',')[0] : c.req.header('x-real-ip') || 'unknown' + return `ip:${ip}` + }, + handler: (c: Context) => { + // Record violation for auto-ban tracking + const authHeader = c.req.header('authorization') + let key: string + if (authHeader) { + key = `user:${authHeader}` + } else { + const forwarded = c.req.header('x-forwarded-for') + const ip = forwarded ? forwarded.split(',')[0] : c.req.header('x-real-ip') || 'unknown' + key = `ip:${ip}` + } + + console.log(`⚠️ Rate limit exceeded for ${key}`) + recordViolation(key) + + return c.json( + { + error: 'Too many requests', + message: `Rate limit exceeded. Maximum ${RATE_LIMIT_MAX} requests per ${RATE_LIMIT_WINDOW_MS}ms`, + }, + 429 + ) + }, +}) + +/** + * Custom rate limiter for specific endpoints with different limits + */ +export function createCustomRateLimiter(limit: number, windowMs: number) { + return rateLimiter({ + windowMs, + limit, + standardHeaders: 'draft-6', + keyGenerator: (c: Context) => { + const authHeader = c.req.header('authorization') + if (authHeader) { + return `user:${authHeader}` + } + const forwarded = c.req.header('x-forwarded-for') + const ip = forwarded ? forwarded.split(',')[0] : c.req.header('x-real-ip') || 'unknown' + return `ip:${ip}` + }, + handler: (c: Context) => { + // Record violation for auto-ban tracking + const authHeader = c.req.header('authorization') + let key: string + if (authHeader) { + key = `user:${authHeader}` + } else { + const forwarded = c.req.header('x-forwarded-for') + const ip = forwarded ? forwarded.split(',')[0] : c.req.header('x-real-ip') || 'unknown' + key = `ip:${ip}` + } + recordViolation(key) + + return c.json( + { + error: 'Too many requests', + message: `Rate limit exceeded. Maximum ${limit} requests per ${windowMs}ms`, + }, + 429 + ) + }, + }) +} + +// Export configuration for testing +export const rateLimitConfig = { + max: RATE_LIMIT_MAX, + windowMs: RATE_LIMIT_WINDOW_MS, +} diff --git a/src/middleware/usageTracking.ts b/src/middleware/usageTracking.ts new file mode 100644 index 0000000..2ebc4d2 --- /dev/null +++ b/src/middleware/usageTracking.ts @@ -0,0 +1,305 @@ +import { Context, Next } from 'hono'; +import { supabase } from '../commons/supabase.js'; +import { logger } from '../commons/logger.js'; +import { FunctionRegistry } from '../commons/registry.js'; + +export interface UsageData { + userId: string; + endpoint: string; + method: string; + product: string; + action: string; + responseStatus?: number; + responseTimeMs?: number; + costUnits: number; + cancellable: boolean; + metadata?: Record; + apiKeyId?: string; + jobId?: string; +} + +/** + * Middleware to track API usage for billing and monitoring + * Tracks request start and updates with completion status + */ +export async function usageTrackingMiddleware(c: Context, next: Next) { + const startTime = Date.now(); + + // Extract user ID from context (set by auth middleware) + const userId = c.get('userId'); + // Skip tracking for unauthenticated requests + if (!userId) { + logger.trace('[UsageTracking] Skipping - No userId'); + await next(); + return; + } + + // Determine product and action + const path = c.req.path; + const method = c.req.method; + + // Use Registry to find config + const config = FunctionRegistry.findByRoute(path, method); + const product = config?.productId; + const action = config?.actionId; + + logger.trace(`[UsageTracking] Identified: product=${product}, action=${action}`); + + // Skip if not a tracked endpoint + if (!product || !action || !config) { + logger.info('[UsageTracking] Skipping - Not a tracked endpoint'); + await next(); + return; + } + + // Generate a job ID for this request + const jobId = `${product}_${action}_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`; + + // Create initial usage record with 'processing' status + let usageId: string | null = null; + try { + const { data, error } = await supabase + .from('api_usage') + .insert({ + user_id: userId, + endpoint: path, + method, + product, + action, + status: 'processing', + job_id: jobId, + cancellable: config.cancellable || false, + cost_units: config.costUnits, + metadata: { + query: c.req.query(), + userAgent: c.req.header('user-agent'), + ip: c.req.header('x-forwarded-for') || c.req.header('x-real-ip'), + }, + }) + .select('id') + .single(); + + if (error) { + logger.error({ err: error }, '[UsageTracking] Error creating usage record'); + } else if (data) { + logger.trace(`[UsageTracking] Created usage record: ${data.id}`); + usageId = data.id; + // Store usage ID in context for potential use in handlers + c.set('usageId', usageId); + c.set('jobId', jobId); + } else { + logger.trace('[UsageTracking] No data returned from insert'); + } + } catch (err) { + logger.error({ err }, 'Failed to create usage record'); + } + + // Execute the request + let requestError: Error | null = null; + try { + await next(); + } catch (err) { + requestError = err as Error; + throw err; // Re-throw to let error handler deal with it + } finally { + // Update usage record with completion status + const endTime = Date.now(); + const responseTime = endTime - startTime; + + if (usageId) { + // Check if handler requested to skip status update (e.g. for background jobs) + const skipUpdate = c.get('skipUsageStatusUpdate'); + + if (!skipUpdate) { + updateUsageRecord({ + usageId, + responseStatus: c.res.status, + responseTimeMs: responseTime, + error: requestError, + }).catch(err => { + logger.error({ err }, 'Failed to update usage record'); + }); + } + } + } +} + +/** + * Update usage record with completion status + */ +export async function updateUsageRecord(data: { + usageId: string; + responseStatus: number; + responseTimeMs: number; + error?: Error | null; +}) { + const status = data.error + ? 'failed' + : (data.responseStatus >= 200 && data.responseStatus < 300) + ? 'completed' + : 'failed'; + + const updateData: any = { + status, + response_status: data.responseStatus, + response_time_ms: data.responseTimeMs, + }; + + if (data.error) { + updateData.error_message = data.error.message; + } + + const { error } = await supabase + .from('api_usage') + .update(updateData) + .eq('id', data.usageId); + + if (error) { + logger.error({ err: error }, 'Error updating usage record'); + } +} + +/** + * Helper function to manually track usage (for non-middleware scenarios) + */ +export async function trackUsage(data: UsageData): Promise { + try { + const { data: record, error } = await supabase + .from('api_usage') + .insert({ + user_id: data.userId, + endpoint: data.endpoint, + method: data.method, + product: data.product, + action: data.action, + status: data.responseStatus ? 'completed' : 'processing', + job_id: data.jobId, + cancellable: data.cancellable, + response_status: data.responseStatus, + response_time_ms: data.responseTimeMs, + cost_units: data.costUnits, + metadata: data.metadata, + api_key_id: data.apiKeyId, + }) + .select('id') + .single(); + + if (error) { + logger.error({ err: error }, 'Error tracking usage'); + return null; + } + + return record?.id || null; + } catch (err) { + logger.error({ err }, 'Failed to track usage'); + return null; + } +} +/** + * Cancel a job by job ID + */ +export async function cancelJob(userId: string, jobId: string): Promise { + try { + const { data, error } = await supabase + .from('api_usage') + .update({ + status: 'cancelled', + }) + .eq('user_id', userId) + .eq('job_id', jobId) + .eq('cancellable', true) + .in('status', ['pending', 'processing']) + .select('id'); + + if (error) { + logger.error({ err: error }, 'Error cancelling job'); + return false; + } + + return !!data && data.length > 0; + } catch (err) { + logger.error({ err }, 'Failed to cancel job'); + return false; + } +} + +/** + * Get active (cancellable) jobs for a user + */ +export async function getActiveJobs(userId: string) { + try { + const { data, error } = await supabase + .from('api_usage') + .select('id, job_id, product, action, status, created_at, metadata') + .eq('user_id', userId) + .eq('cancellable', true) + .in('status', ['pending', 'processing']) + .order('created_at', { ascending: false }); + + if (error) { + logger.error({ err: error }, 'Error fetching active jobs'); + return []; + } + + return data || []; + } catch (err) { + logger.error({ err }, 'Failed to fetch active jobs'); + return []; + } +} + +/** + * Pause a job by job ID + */ +export async function pauseJob(userId: string, jobId: string): Promise { + try { + const { data, error } = await supabase + .from('api_usage') + .update({ + status: 'paused', + }) + .eq('user_id', userId) + .eq('job_id', jobId) + .eq('cancellable', true) + .eq('status', 'processing') // Only processing jobs can be paused + .select('id'); + + if (error) { + logger.error({ err: error }, 'Error pausing job'); + return false; + } + + return !!data && data.length > 0; + } catch (err) { + logger.error({ err }, 'Failed to pause job'); + return false; + } +} + +/** + * Resume a paused job by job ID + */ +export async function resumeJob(userId: string, jobId: string): Promise { + try { + const { data, error } = await supabase + .from('api_usage') + .update({ + status: 'processing', + }) + .eq('user_id', userId) + .eq('job_id', jobId) + .eq('cancellable', true) + .eq('status', 'paused') // Only paused jobs can be resumed + .select('id'); + + if (error) { + logger.error({ err: error }, 'Error resuming job'); + return false; + } + + return !!data && data.length > 0; + } catch (err) { + logger.error({ err }, 'Failed to resume job'); + return false; + } +} diff --git a/src/products/AbstractProduct.ts b/src/products/AbstractProduct.ts new file mode 100644 index 0000000..322b4b5 --- /dev/null +++ b/src/products/AbstractProduct.ts @@ -0,0 +1,139 @@ +import EventEmitter from 'events'; +import { createHash } from 'crypto'; +import { streamSSE } from 'hono/streaming'; +import { EventBus } from './EventBus.js'; +import { ProductErrorCode } from './enums.js'; +import { ProductError } from './errors.js'; +import { logger } from '../commons/logger.js'; + +export interface JobCreationEvent { + queue: string; + data: any; + options: any; +} + +export interface StreamOptions { + data: TData; + userId: string; + forceRefresh?: boolean; + fetcher: (data: TData, userId: string) => Promise; + cacheChecker?: (hash: string) => Promise; +} + +export abstract class AbstractProduct extends EventEmitter { + abstract readonly id: string; + abstract readonly jobOptions: any; + abstract readonly actions: Record; + abstract readonly workers: any[]; + abstract readonly routes: any[]; + + async start(boss?: any) { + try { + await this.onStart(boss); + } catch (error: any) { + throw new ProductError(ProductErrorCode.START_FAILED, { + message: `Failed to start product ${this.id}: ${error.message}`, + originalError: error + }); + } + } + + protected async onStart(boss?: any) { + // Optional hook for subclasses + } + + async stop() { + try { + await this.onStop(); + } catch (error: any) { + throw new ProductError(ProductErrorCode.STOP_FAILED, { + message: `Failed to stop product ${this.id}: ${error.message}`, + originalError: error + }); + } + } + + protected async onStop() { + // Optional hook + } + + async pause() { + // No-op for now as we removed pgboss + } + + async resume() { + // No-op for now as we removed pgboss + } + + protected async handleStream(c: any, options: StreamOptions) { + const { data, userId, forceRefresh, fetcher, cacheChecker } = options; + + const inputHash = this.generateHash(data); + + return streamSSE(c, async (stream) => { + try { + await stream.writeSSE({ + event: 'progress', + data: JSON.stringify({ stage: 'starting', percent: 0 }) + }); + + if (!forceRefresh && cacheChecker) { + await stream.writeSSE({ + event: 'progress', + data: JSON.stringify({ stage: 'checking_cache', percent: 10 }) + }); + + const cached = await cacheChecker(inputHash); + if (cached) { + for (let i = 0; i < cached.length; i++) { + await stream.writeSSE({ + event: 'result', + data: JSON.stringify(cached[i]) + }); + } + await stream.writeSSE({ + event: 'complete', + data: JSON.stringify({ total: cached.length, cached: true }) + }); + return; + } + } + + await stream.writeSSE({ + event: 'progress', + data: JSON.stringify({ stage: 'fetching_from_api', percent: 20 }) + }); + + const results = await fetcher(data, userId); + + for (let i = 0; i < results.length; i++) { + await stream.writeSSE({ + event: 'result', + data: JSON.stringify(results[i]) + }); + } + + await stream.writeSSE({ + event: 'complete', + data: JSON.stringify({ total: results.length, cached: false }) + }); + + } catch (error: any) { + logger.error(error, `[${this.id}] Stream error`); + await stream.writeSSE({ + event: 'error', + data: JSON.stringify({ error: error.message || 'Internal Server Error' }) + }); + } + }); + } + + // Helper for hashing + protected generateHash(params: any) { + const normalizedInput = JSON.stringify(params, Object.keys(params).sort()); + return createHash('sha256').update(normalizedInput).digest('hex'); + } + + abstract hash(data: TJobData): string; + abstract meta(userId: string): any; +} diff --git a/src/products/EventBus.ts b/src/products/EventBus.ts new file mode 100644 index 0000000..b532e43 --- /dev/null +++ b/src/products/EventBus.ts @@ -0,0 +1,3 @@ +import EventEmitter from 'events'; + +export const EventBus = new EventEmitter(); diff --git a/src/products/analytics/index.ts b/src/products/analytics/index.ts new file mode 100644 index 0000000..5cc3d4c --- /dev/null +++ b/src/products/analytics/index.ts @@ -0,0 +1,141 @@ +import { Context } from 'hono'; +import { streamSSE } from 'hono/streaming'; +import { AbstractProduct } from '../AbstractProduct.js'; +import { getAnalyticsRoute, getAnalyticsStreamRoute, deleteAnalyticsRoute } from './routes.js'; +import { analyticsEmitter } from '../../lib/analytics-emitter.js'; +import { CONFIG_DEFAULT } from '@polymech/commons'; +import fs from 'fs'; +import path from 'path'; +import readline from 'readline'; + +const ANALYTICS_FILE = path.resolve(process.cwd(), 'logs/analytics.jsonl'); + +export class AnalyticsProduct extends AbstractProduct { + id = 'analytics'; + jobOptions = {}; + actions = {}; // Optional: Add actions if needed for jobs + workers: any[] = []; + routes: any[] = []; + hash = () => 'analytics-hash'; + meta = () => ({}); + + constructor() { + super(); + this.initializeRoutes(); + } + + initializeRoutes() { + this.routes.push({ + definition: getAnalyticsRoute, + handler: this.handleGetAnalytics.bind(this) + }); + this.routes.push({ + definition: getAnalyticsStreamRoute, + handler: this.handleGetAnalyticsStream.bind(this) + }); + this.routes.push({ + definition: deleteAnalyticsRoute, + handler: this.handleDeleteAnalytics.bind(this) + }); + } + + // ... existing handlers + + async handleDeleteAnalytics(c: Context) { + try { + if (fs.existsSync(ANALYTICS_FILE)) { + // Truncate file + await fs.promises.truncate(ANALYTICS_FILE, 0); + } + return c.json({ success: true }); + } catch (err: any) { + console.error('Error clearing analytics:', err); + return c.json({ error: 'Internal Server Error' }, 500); + } + } + + async handleGetAnalyticsStream(c: Context) { + return streamSSE(c, async (stream) => { + const listener = async (entry: any) => { + await stream.writeSSE({ + data: JSON.stringify(entry), + event: 'log', + }); + }; + + analyticsEmitter.on('log', listener); + + // Keep connection alive or handle disconnect + // Hono's streamSSE handles closing the stream when the connection drops, + // but we need to remove the listener to avoid leaks. + stream.onAbort(() => { + analyticsEmitter.off('log', listener); + }); + + // Wait forever (or until client disconnects) + while (true) { + await new Promise(resolve => setTimeout(resolve, 1000)); + } + }); + } + + async handleGetAnalytics(c: Context) { + try { + const limit = parseInt(c.req.query('limit') || '100', 10); + const startDateStr = c.req.query('startDate'); + const endDateStr = c.req.query('endDate'); + + const startDate = startDateStr ? new Date(startDateStr).getTime() : 0; + const endDate = endDateStr ? new Date(endDateStr).getTime() : Date.now(); + + if (!fs.existsSync(ANALYTICS_FILE)) { + return c.json([]); + } + + // Efficiently read last N lines would be better, but for "filtered" queries we generally need to scan. + // If file is huge, this is slow. + // However, typical usage for "analytics middleware... for now" implies simple logging. + // We will stream the file from the beginning (or end if we could) and collect matching entries. + // To respect 'limit' effectively with date filters, we ideally want the *latest* entries. + // So reading from end or collecting all and sorting/slicing is needed. + // Collecting all in memory is dangerous for large files. + // But implementing reverse line reading is complex without a library. + // Compromise: Read all, parse, filter, take last N. + // Optimization: If no date filter, reasonable to assume we want latest. + + const logs: any[] = []; + + const fileStream = fs.createReadStream(ANALYTICS_FILE); + const rl = readline.createInterface({ + input: fileStream, + crlfDelay: Infinity + }); + + for await (const line of rl) { + if (!line.trim()) continue; + try { + const entry = JSON.parse(line); + const timestamp = new Date(entry.timestamp).getTime(); + + if (timestamp >= startDate && timestamp <= endDate) { + logs.push(entry); + } + } catch (e) { + // Ignore bad lines + } + } + + // Sort by timestamp desc + logs.sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime()); + + // Limit + const result = logs.slice(0, limit); + + return c.json(result); + + } catch (err: any) { + console.error('Error reading analytics:', err); + return c.json({ error: 'Internal Server Error' }, 500); + } + } +} diff --git a/src/products/analytics/routes.ts b/src/products/analytics/routes.ts new file mode 100644 index 0000000..3dcf611 --- /dev/null +++ b/src/products/analytics/routes.ts @@ -0,0 +1,84 @@ +import { createRoute, z } from '@hono/zod-openapi'; + +export const getAnalyticsRoute = createRoute({ + method: 'get', + path: '/api/analytics', + tags: ['Analytics'], + summary: 'Get Analytics Data', + description: 'Retrieve analytics data from the log file, optionally filtered by date.', + security: [{ bearerAuth: [] }], + request: { + query: z.object({ + limit: z.string().optional().default('100').openapi({ description: 'Number of entries to return (default 100)' }), + startDate: z.string().optional().openapi({ description: 'Filter entries after this date (ISO string)' }), + endDate: z.string().optional().openapi({ description: 'Filter entries before this date (ISO string)' }), + }), + }, + responses: { + 200: { + description: 'Analytics Data', + content: { + 'application/json': { + schema: z.array(z.object({ + timestamp: z.string(), + method: z.string(), + path: z.string(), + status: z.number(), + ip: z.string(), + userAgent: z.string().optional(), + referer: z.string().optional(), + userId: z.string().optional() + })), + }, + }, + }, + 401: { + description: 'Unauthorized', + }, + }, +}); + +export const getAnalyticsStreamRoute = createRoute({ + method: 'get', + path: '/api/analytics/stream', + tags: ['Analytics'], + summary: 'Stream Analytics Data', + description: 'Stream real-time analytics data via Server-Sent Events (SSE).', + security: [{ bearerAuth: [] }], + responses: { + 200: { + description: 'Analytics Event Stream', + content: { + 'text/event-stream': { + schema: z.string(), + }, + }, + }, + 401: { + description: 'Unauthorized', + }, + }, + +}); + +export const deleteAnalyticsRoute = createRoute({ + method: 'delete', + path: '/api/analytics', + tags: ['Analytics'], + summary: 'Clear Analytics Data', + description: 'Clear all analytics data from the log file.', + security: [{ bearerAuth: [] }], + responses: { + 200: { + description: 'Analytics Data Cleared', + content: { + 'application/json': { + schema: z.object({ success: z.boolean() }), + }, + }, + }, + 401: { + description: 'Unauthorized', + }, + }, +}); diff --git a/src/products/enums.ts b/src/products/enums.ts new file mode 100644 index 0000000..fe66ec2 --- /dev/null +++ b/src/products/enums.ts @@ -0,0 +1,22 @@ +export enum ProductErrorCode { + // Lifecycle Errors + START_FAILED = 'PRODUCT_START_FAILED', + STOP_FAILED = 'PRODUCT_STOP_FAILED', + PAUSE_FAILED = 'PRODUCT_PAUSE_FAILED', + RESUME_FAILED = 'PRODUCT_RESUME_FAILED', + + // Worker Errors + WORKER_REGISTRATION_FAILED = 'WORKER_REGISTRATION_FAILED', + WORKER_NOT_FOUND = 'WORKER_NOT_FOUND', + + // Job Errors + JOB_SUBMISSION_FAILED = 'JOB_SUBMISSION_FAILED', + JOB_TIMEOUT = 'JOB_TIMEOUT', + + // Configuration Errors + INVALID_CONFIG = 'INVALID_CONFIG', + MISSING_DEPENDENCY = 'MISSING_DEPENDENCY', + + // Generic + UNKNOWN_ERROR = 'UNKNOWN_ERROR' +} diff --git a/src/products/errors.ts b/src/products/errors.ts new file mode 100644 index 0000000..a9f5644 --- /dev/null +++ b/src/products/errors.ts @@ -0,0 +1,29 @@ +import { ProductErrorCode } from './enums.js'; + +export interface ProductErrorPayload { + message: string; + [key: string]: any; +} + +export class ProductError extends Error { + public readonly code: ProductErrorCode; + public readonly payload: ProductErrorPayload; + + constructor(code: ProductErrorCode, payload: ProductErrorPayload | string) { + const message = typeof payload === 'string' ? payload : payload.message; + super(message); + this.code = code; + this.payload = typeof payload === 'string' ? { message: payload } : payload; + + // Restore prototype chain + Object.setPrototypeOf(this, new.target.prototype); + } + + toJSON() { + return { + code: this.code, + message: this.message, + payload: this.payload + }; + } +} diff --git a/src/products/openai/handlers.ts b/src/products/openai/handlers.ts new file mode 100644 index 0000000..642cef2 --- /dev/null +++ b/src/products/openai/handlers.ts @@ -0,0 +1,99 @@ +import { Context } from 'hono'; +import { logger } from '../../commons/logger.js'; +import { createClient } from '@supabase/supabase-js'; + +// Helper to get Supabase credentials (copied from auth middleware logic) +const getSupabaseCredentials = () => { + const url = process.env.SUPABASE_URL; + const key = process.env.SUPABASE_SERVICE_KEY; + if (!url || !key) { + throw new Error('Supabase credentials missing via process.env'); + } + return { url, key }; +}; + +export async function handleChatCompletions(c: Context) { + const userId = c.get('userId'); + if (!userId) { + return c.json({ error: 'Unauthorized' }, 401); + } + + try { + // 1. Fetch User API Key + const { url, key } = getSupabaseCredentials(); + const supabase = createClient(url, key); + + const { data: userSecrets, error: secretsError } = await supabase + .from('user_secrets') + .select('settings') + .eq('user_id', userId) + .maybeSingle(); + + if (secretsError) { + logger.error({ err: secretsError, userId }, 'Failed to fetch user secrets'); + return c.json({ error: 'Internal Server Error' }, 500); + } + + // Add debug logging + logger.debug({ userId, hasSecrets: !!userSecrets, settings: userSecrets?.settings }, 'Checking for OpenAI API key'); + + const apiKey = (userSecrets?.settings as any)?.api_keys?.openai_api_key; + + if (!apiKey) { + logger.warn({ userId }, 'Missing OpenAI API key in user_secrets'); + return c.json({ error: 'OpenAI API key not found. Please add it to your profile settings.' }, 400); + } + + // 2. Prepare Request to OpenAI + const body = await c.req.json(); + + // Log request (sanitize sensitive data) + logger.info({ userId, model: body.model }, 'Proxying OpenAI request'); + + const headers: Record = { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${apiKey}`, + }; + + // 3. Make Request to OpenAI + const response = await fetch('https://api.openai.com/v1/chat/completions', { + method: 'POST', + headers, + body: JSON.stringify(body), + }); + + // 4. Handle Response + if (!response.ok) { + const errorText = await response.text(); + logger.error({ status: response.status, errorText, userId }, 'OpenAI API error'); + // Try to parse error as JSON to return proper error object + try { + const errorJson = JSON.parse(errorText); + return c.json(errorJson, response.status as any); + } catch (e) { + return c.text(errorText, response.status as any); + } + } + + // 5. Stream Response if requested + if (body.stream) { + // Need to handle streaming response properly in Hono/Node + // We can return the body stream directly + + return new Response(response.body, { + headers: { + 'Content-Type': 'text/event-stream', + 'Cache-Control': 'no-cache', + 'Connection': 'keep-alive', + } + }); + } + + const data = await response.json(); + return c.json(data); + + } catch (err: any) { + logger.error({ err, userId }, 'OpenAI Proxy handler failed'); + return c.json({ error: 'Internal Server Error' }, 500); + } +} diff --git a/src/products/openai/index.ts b/src/products/openai/index.ts new file mode 100644 index 0000000..cd317c3 --- /dev/null +++ b/src/products/openai/index.ts @@ -0,0 +1,37 @@ +import { AbstractProduct } from '../AbstractProduct.js'; +import { postChatCompletionsRoute } from './routes.js'; +import { handleChatCompletions } from './handlers.js'; + +export class OpenAIProduct extends AbstractProduct { + id = 'openai'; + jobOptions = {}; + actions = {}; + workers = []; + routes: any[] = []; + + constructor() { + super(); + this.initializeRoutes(); + } + + initializeRoutes() { + // Register the chat completion route + // We use CachedHandler here just to wrap it properly, but we probably don't want to actually cache LLM responses aggressively + // unless we implement specific caching logic. For now, let's use the handler directly or create a simple wrapper if needed. + // Actually, AbstractProduct expects { definition, handler } objects. + // And `registry.ts` does: app.openapi(route.definition, route.handler); + + this.routes.push({ + definition: postChatCompletionsRoute, + handler: handleChatCompletions + }); + } + + hash(data: any): string { + return 'openai-hash'; + } + + meta(userId: string): any { + return { userId }; + } +} diff --git a/src/products/openai/routes.ts b/src/products/openai/routes.ts new file mode 100644 index 0000000..6b4f546 --- /dev/null +++ b/src/products/openai/routes.ts @@ -0,0 +1,58 @@ +import { createRoute, z } from '@hono/zod-openapi'; + +export const postChatCompletionsRoute = createRoute({ + method: 'post', + path: '/api/openai/v1/chat/completions', + tags: ['OpenAI'], + summary: 'Chat Completions Proxy', + description: 'Proxies chat completion requests to OpenAI, injecting user API key.', + request: { + body: { + content: { + 'application/json': { + schema: z.object({ + model: z.string(), + messages: z.array(z.object({ + role: z.string(), + content: z.any() // string or array (for multimodal) + })), + stream: z.boolean().optional(), + temperature: z.number().optional(), + top_p: z.number().optional(), + n: z.number().optional(), + presence_penalty: z.number().optional(), + frequency_penalty: z.number().optional(), + logit_bias: z.record(z.string(), z.number()).optional(), + user: z.string().optional(), + max_tokens: z.number().optional(), + response_format: z.any().optional(), + tools: z.array(z.any()).optional(), + tool_choice: z.any().optional(), + }).passthrough() // Allow other OpenAI params + } + } + } + }, + responses: { + 200: { + description: 'Chat completion response', + content: { + 'application/json': { + schema: z.any() + }, + 'text/event-stream': { + schema: z.string() + } + } + }, + 400: { + description: 'Bad Request' + }, + 401: { + description: 'Unauthorized' + }, + 500: { + description: 'Internal Server Error' + } + } +}); diff --git a/src/products/registry.ts b/src/products/registry.ts new file mode 100644 index 0000000..7c03c63 --- /dev/null +++ b/src/products/registry.ts @@ -0,0 +1,57 @@ + +import './subscriber.js'; + +import { OpenAIProduct } from './openai/index.js'; +import { AnalyticsProduct } from './analytics/index.js'; + +// import './subscriber.js'; + +let instances: any[] = []; +export const ALL_PRODUCTS = instances; + +export const registerProductRoutes = async (app: any) => { + console.log('Registering product routes'); + // Instantiate all products + instances = [ + new OpenAIProduct(), + new AnalyticsProduct(), + ]; + + instances.forEach(product => { + console.log(`Registering routes for product ${product.id}`); + product.routes.forEach((route: any) => { + // @ts-ignore + app.openapi(route.definition, route.handler); + }); + }); +}; + +export const getAllWorkers = () => { + return instances.flatMap(p => p.workers || []); +}; + +export const startProducts = async (boss?: any) => { + for (const product of instances) { + try { + // Create a timeout promise + const timeoutPromise = new Promise((_, reject) => { + const id = setTimeout(() => { + clearTimeout(id); + // @ts-ignore + reject(new Error(`Product ${product?.id || 'unknown'} startup timed out`)); + }, 20000); // 5 seconds timeout + }); + + // Race the product start against the timeout + await Promise.race([ + product.start(boss), + timeoutPromise + ]); + + } catch (err) { + // @ts-ignore + console.error(`Failed to start product ${product.id}`, err); + // Continue with other products even if one fails + } + } +}; diff --git a/src/products/serving/routes.ts b/src/products/serving/routes.ts new file mode 100644 index 0000000..6c3193f --- /dev/null +++ b/src/products/serving/routes.ts @@ -0,0 +1,468 @@ +import { createRoute, z } from '@hono/zod-openapi'; +import { Admin, Public } from '../../commons/decorators.js'; + +type ServiceRouteOptions = Parameters[0] & { + public?: boolean; + admin?: boolean; +}; + +/** + * Factory function to create a service route with optional decorators + */ +function createServiceRoute(options: ServiceRouteOptions) { + const { public: isPublic, admin: isAdmin, ...routeDef } = options; + let route = createRoute(routeDef); + + if (isPublic) { + route = Public(route); + } + + if (isAdmin) { + route = Admin(route); + } + + return route; +} + +export function createRouteBody( + method: string, + path: string, + tags: string[], + summary: string, + description: string, + request: any, + responses: any, + publicRoute: boolean = true, + adminRoute: boolean = false) { + return createServiceRoute({ + method: method as any, + path, + tags, + summary, + description, + request, + responses, + public: publicRoute, + admin: adminRoute + }) +} + +export const getFeedRoute = createRouteBody( + 'get', + '/feed.xml', + ['Serving'], + 'Get RSS Feed', + 'Returns the latest posts as an RSS 2.0 feed.', + undefined, + { + 200: { + description: 'RSS Feed', + content: { + 'application/xml': { + schema: z.string() + } + } + } + } +); + +export const getMerchantFeedRoute = createRouteBody( + 'get', + '/products.xml', + ['Serving'], + 'Get Merchant Feed', + 'Returns the latest products as a Google Merchant XML feed.', + undefined, + { + 200: { + description: 'XML Feed', + content: { + 'application/xml': { + schema: z.string() + } + } + } + } +); + +export const getLLMTextRoute = createRouteBody( + 'get', + '/llms.txt', + ['Serving'], + 'Get LLM Summary', + 'Returns a Markdown summary of content for AI agents.', + undefined, + { + 200: { + description: 'Markdown Text', + content: { + 'text/plain': { + schema: z.string() + } + } + } + } +); + +export const getPostMetaRoute = createRouteBody( + 'get', + '/post/:id', + ['Serving'], + 'Get Post with Metadata', + 'Serves the React app HTML with injected Open Graph metadata for the specific post.', + { + params: z.object({ + id: z.string() + }) + }, + { + 200: { + description: 'HTML Page', + content: { + 'text/html': { + schema: z.string() + } + } + }, + 404: { + description: 'Post not found (Serves default HTML)', + } + } +); + + +export const getHomeRoute = createRouteBody( + 'get', + '/', + ['Serving'], + 'Get Home Page', + 'Serves the home page with injected feed data.', + undefined, + { + 200: { + description: 'HTML Page', + content: { + 'text/html': { + schema: z.string() + } + } + } + } +); + +export const getApiPostDetailsRoute = createRouteBody( + 'get', + '/api/posts/:id', + ['Posts'], + 'Get Post Details', + 'Get Post Details', + { + params: z.object({ + id: z.string() + }), + query: z.object({ + sizes: z.string().optional().openapi({ description: 'Responsive sizes' }), + formats: z.string().optional().openapi({ description: 'Responsive formats' }) + }) + }, + { + 200: { + description: 'Post Details', + content: { + 'application/json': { + schema: z.any() + } + } + }, + 404: { + description: 'Post not found' + } + }, + true +); + + + + + + +export const postFlushCacheRoute = createRouteBody( + 'post', + '/api/flush-cache', + ['Posts'], + 'Flush Cache', + 'Flushes the server-side content cache and the disk-based image cache.', + undefined, + { + 200: { + description: 'Cache Flushed', + content: { + 'application/json': { + schema: z.object({ + success: z.boolean(), + message: z.string() + }) + } + } + }, + 500: { + description: 'Internal Server Error' + } + }, + false, // not public + true // admin +); + +export const invalidateCacheRoute = createRouteBody( + 'post', + '/api/cache/invalidate', + ['System'], + 'Invalidate Cache by Path', + 'Invalidates cache keys matching the provided paths.', + { + body: { + content: { + 'application/json': { + schema: z.object({ + paths: z.array(z.string()).optional().openapi({ + description: 'List of URL paths to invalidate (e.g. /api/user-page/123/slug)' + }), + types: z.array(z.string()).optional().openapi({ + description: 'List of cache types to invalidate (e.g. posts, pages)' + }) + }) + } + } + } + }, + { + 200: { + description: 'Cache Invalidated', + content: { + 'application/json': { + schema: z.object({ + success: z.boolean(), + count: z.number() + }) + } + } + } + }, + false, // not public + false // not admin-only (allow authed users to invalidate their own content ideally, for now just authed) +); + +export const getCacheInspectRoute = createRouteBody( + 'get', + '/api/cache/inspect', + ['System'], + 'Inspect Cache', + 'Returns current cache state: keys, TTLs, dependency graph, and overall stats.', + undefined, + { + 200: { + description: 'Cache state', + content: { + 'application/json': { + schema: z.object({ + info: z.object({ + size: z.number(), + max: z.number(), + provider: z.string() + }), + dependencies: z.record(z.string(), z.array(z.string())), + entries: z.array(z.object({ + key: z.string(), + remainingTTL: z.number() + })) + }) + } + } + } + }, + true, // not public + false // admin only +); + +export const getProfilesRoute = createRouteBody( + 'get', + '/api/profiles', + ['Users'], + 'Get Batch Profiles', + 'Get Batch Profiles', + { + query: z.object({ + ids: z.string().optional().openapi({ + description: 'Comma-separated list of user IDs' + }), + q: z.string().optional().openapi({ + description: 'Search query' + }) + }) + }, + { + 200: { + description: 'Profiles Map', + content: { + 'application/json': { + schema: z.record(z.string(), z.any()) + } + } + } + }, + true // public +); + +export const getApiMediaItemsRoute = createRouteBody( + 'get', + '/api/media-items', + ['Media'], + 'Get Media Items by IDs', + 'Fetches multiple media items by their IDs using server-side cache for optimal performance.', + { + query: z.object({ + ids: z.string().openapi({ + description: 'Comma-separated list of picture IDs' + }), + maintainOrder: z.enum(['true', 'false']).optional().openapi({ + description: 'Maintain the order of IDs in the response' + }), + sizes: z.string().optional().openapi({ + description: 'Comma-separated list of widths for responsive images' + }), + formats: z.string().optional().openapi({ + description: 'Comma-separated list of formats for responsive images' + }) + }) + }, + { + 200: { + description: 'Array of Media Items', + content: { + 'application/json': { + schema: z.array(z.any()) + } + } + } + }, + true // public +); + + +export const getEmbedRoute = createRouteBody( + 'get', + '/embed/:id', + ['Serving'], + 'Get Embed Page', + 'Serves the embed page with injected post data.', + { + params: z.object({ + id: z.string() + }) + }, + { + 200: { + description: 'HTML Page', + content: { + 'text/html': { + schema: z.string() + } + } + }, + 404: { + description: 'Post not found', + } + } +); + +export const getSiteInfoRoute = createRouteBody( + 'get', + '/api/serving/site-info', + ['Serving'], + 'Get Site Information', + 'Extracts metadata (Open Graph, JSON-LD, etc.) from a given URL.', + { + query: z.object({ + url: z.string().openapi({ + description: 'The URL to extract information from', + example: 'https://example.com' + }) + }) + }, + { + 200: { + description: 'Site Information', + content: { + 'application/json': { + schema: z.object({ + title: z.string().optional(), + description: z.string().optional(), + url: z.string().optional(), + siteName: z.string().optional(), + favicon: z.string().optional(), + og: z.record(z.string(), z.string().optional()).optional(), + images: z.array(z.object({ + src: z.string(), + width: z.number().optional(), + height: z.number().optional(), + alt: z.string().optional() + })).optional(), + structuredData: z.array(z.any()).optional(), + social: z.array(z.object({ + source: z.string(), + url: z.string() + })).optional() + }) + } + } + }, + 400: { + description: 'Invalid URL' + }, + 500: { + description: 'Failed to extract information' + } + }, + true // public? Site info scraper is usually public +); + +export const getSitemapRoute = createRouteBody( + 'get', + '/sitemap-en.xml', + ['Serving'], + 'Get Sitemap', + 'Returns the sitemap XML for internal pages.', + undefined, + { + 200: { + description: 'Sitemap XML', + content: { + 'application/xml': { + schema: z.string() + } + } + } + } +); + +export const getSystemInfoRoute = createRouteBody( + 'get', + '/api/system-info', + ['System'], + 'Get System Info', + 'Returns public client environment variables and app configuration.', + undefined, + { + 200: { + description: 'System Info', + content: { + 'application/json': { + schema: z.object({ + env: z.record(z.string(), z.any()) + }) + } + } + } + }, + true // public +); \ No newline at end of file diff --git a/src/products/subscriber.ts b/src/products/subscriber.ts new file mode 100644 index 0000000..c803e58 --- /dev/null +++ b/src/products/subscriber.ts @@ -0,0 +1,42 @@ +import { ALL_PRODUCTS } from './registry.js'; +import { EventBus } from './EventBus.js'; + +const findProductByQueue = (queue: string) => { + return ALL_PRODUCTS.find(p => + p.workers?.some((w: any) => { + try { + const worker = new (w as any)(); + return worker.queueName === queue; + } catch (e) { + return false; + } + }) + ); +}; + +EventBus.on('job:create', (event: any) => { + const product = findProductByQueue(event.queue); + + if (!product) return; + + // Apply default job options from product if available + if (product.jobOptions) { + event.options = { ...product.jobOptions, ...event.options }; + } + + const singletonKey = product.hash(event.data); + if (singletonKey) { + event.options.singletonKey = singletonKey; + // Default to 5 minutes if not specified + if (!event.options.singletonSeconds) { + event.options.singletonSeconds = 300; + } + } + + const { userId } = event.data; + if (userId) { + const metadata = product.meta(userId); + event.data = { ...event.data, ...metadata }; + } + +}); diff --git a/src/schemas/index.ts b/src/schemas/index.ts new file mode 100644 index 0000000..7f7c4bc --- /dev/null +++ b/src/schemas/index.ts @@ -0,0 +1,22 @@ +import { z } from '@hono/zod-openapi' + +export const ErrorSchema = z.object({ + error: z.string(), +}) +export const ImageSchema = z.object({ + idx: z.number().openapi({ example: 0 }), + id: z.number().openapi({ example: 6 }), + name: z.string().openapi({ example: 'images' }), + slug: z.string().openapi({ example: 'images' }), + description: z.string().openapi({ example: 'fcghdfgh' }), + price: z.string().openapi({ example: '10.00' }), + variants: z.string().openapi({ example: '[]' }), + created_at: z.string().openapi({ example: '2025-11-22 10:46:09.77718+00' }), + updated_at: z.string().openapi({ example: '2025-11-22 10:46:09.77718+00' }), +}) + +export const ImageResponseSchema = z.object({ + message: z.string().openapi({ example: 'Success' }), + data: z.array(ImageSchema).optional(), +}) + diff --git a/src/serve-assets.ts b/src/serve-assets.ts new file mode 100644 index 0000000..f0eed1e --- /dev/null +++ b/src/serve-assets.ts @@ -0,0 +1,93 @@ + +import { OpenAPIHono } from '@hono/zod-openapi' +import { serveStatic } from '@hono/node-server/serve-static' +import path from 'path' + +export const registerAssetRoutes = (app: OpenAPIHono) => { + // Serve manifest.webmanifest from dist root + app.get('/manifest.webmanifest', serveStatic({ + root: process.env.CLIENT_DIST_PATH || '../dist', + path: 'manifest.webmanifest' + })); + + // Serve service worker — must never be cached so browser always checks for updates + app.get('/sw.js', async (c, next) => { + await next(); + c.res.headers.set('Cache-Control', 'no-cache'); + }); + app.get('/sw.js', serveStatic({ + root: process.env.CLIENT_DIST_PATH || '../dist', + path: 'sw.js' + })); + + // Serve registerSW.js — must always be fresh + app.get('/registerSW.js', async (c, next) => { + await next(); + c.res.headers.set('Cache-Control', 'no-cache'); + }); + app.get('/registerSW.js', serveStatic({ + root: process.env.CLIENT_DIST_PATH || '../dist', + path: 'registerSW.js' + })); + + // Serve workbox assets if they are at root + app.get('/workbox-*.js', serveStatic({ + root: process.env.CLIENT_DIST_PATH || '../dist', + rewriteRequestPath: (path) => path // Serve matching file + })); + + // Serve workbox assets if they are at root + app.get('/widgets/*', serveStatic({ + root: process.env.CLIENT_DIST_PATH || '../dist/widgets', + rewriteRequestPath: (path) => path // Serve matching file + })); + + // Serve root static assets (images, icons, robots.txt, etc) — short cache since not hash-busted + app.use('/:file{.+\\.(png|ico|jpg|jpeg|svg|txt|xml)$}', async (c, next) => { + await next(); + if (c.res.ok) { + c.res.headers.set('Cache-Control', 'public, max-age=3600, must-revalidate'); + } + }); + app.get('/:file{.+\\.(png|ico|jpg|jpeg|svg|txt|xml)$}', serveStatic({ + root: process.env.CLIENT_DIST_PATH || '../dist', + })); + + // Serve static assets from dist + app.use('/assets/*', async (c, next) => { + await next(); + if (c.res.ok && c.res.status === 200) { + c.res.headers.set('Cache-Control', 'public, max-age=31536000, immutable'); + } + }); + app.use('/assets/*', serveStatic({ + root: process.env.CLIENT_DIST_PATH || '../dist', + onNotFound: (path, c) => { + return undefined; + } + })); + + // Serve embed assets + app.use('/embed_assets/*', serveStatic({ + root: process.env.CLIENT_DIST_PATH ? path.join(process.env.CLIENT_DIST_PATH, 'client/embed') : '../dist/client/embed', + onNotFound: (path, c) => { + return undefined; + }, + rewriteRequestPath: (path) => path.replace(/^\/embed_assets/, ''), + })); + + // Serve filebrowser assets + app.use('/filebrowser_assets/*', serveStatic({ + root: process.env.CLIENT_DIST_PATH ? path.join(process.env.CLIENT_DIST_PATH, 'client/filebrowser') : '../dist/client/filebrowser', + onNotFound: (path, c) => { + return undefined; + }, + rewriteRequestPath: (path) => path.replace(/^\/filebrowser_assets/, ''), + })); + + // Fallback to index.html for SPA + app.get('*', serveStatic({ + root: process.env.CLIENT_DIST_PATH || '../dist', + path: 'index.html' + })); +} diff --git a/src/zod-setup.ts b/src/zod-setup.ts new file mode 100644 index 0000000..cf0610e --- /dev/null +++ b/src/zod-setup.ts @@ -0,0 +1,6 @@ +import { z } from 'zod'; +import { extendZodWithOpenApi } from '@hono/zod-openapi'; + +extendZodWithOpenApi(z); + +export { z }; diff --git a/tsconfig.build.json b/tsconfig.build.json new file mode 100644 index 0000000..90c85ff --- /dev/null +++ b/tsconfig.build.json @@ -0,0 +1,9 @@ +{ + "extends": "./tsconfig.json", + "exclude": [ + "node_modules", + "src/**/__tests__", + "**/*.test.ts", + "**/*.spec.ts" + ] +} \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..9a828af --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,27 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "NodeNext", + "moduleResolution": "NodeNext", + "outDir": "./dist-in", + "rootDir": "./src", + "baseUrl": ".", + "paths": { + "@/*": [ + "src/*" + ] + }, + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "inlineSourceMap": true, + "experimentalDecorators": true + }, + "include": [ + "src/**/*" + ], + "exclude": [ + "node_modules" + ] +} \ No newline at end of file diff --git a/vitest.config.ts b/vitest.config.ts new file mode 100644 index 0000000..2fc2f04 --- /dev/null +++ b/vitest.config.ts @@ -0,0 +1,19 @@ +import { defineConfig } from 'vitest/config' +import tsconfigPaths from 'vite-tsconfig-paths' + +export default defineConfig({ + plugins: [tsconfigPaths()], + test: { + globals: true, + environment: 'node', + coverage: { + provider: 'v8', + reporter: ['text', 'json', 'html'], + exclude: [ + 'node_modules/', + 'src/seed.ts', + '**/*.test.ts', + ], + }, + }, +}) diff --git a/webpack.config.js b/webpack.config.js new file mode 100644 index 0000000..5708d18 --- /dev/null +++ b/webpack.config.js @@ -0,0 +1,48 @@ +import path from 'path'; +import { fileURLToPath } from 'url'; +import webpack from 'webpack'; + +const __dirname = fileURLToPath(new URL('.', import.meta.url)); + +export default { + devtool: false, + plugins: [ + new webpack.BannerPlugin({ banner: "#!/usr/bin/env node", raw: true }) + ], + entry: './dist-in/index.js', + target: 'node', + mode: 'production', + module: { + rules: [ + { + test: /\.m?js$/, + resolve: { + fullySpecified: false + } + } + ] + }, + optimization: { + minimize: false + }, + resolve: { + extensions: ['.js', '.mjs', '.ts'], + extensionAlias: { + '.js': ['.js', '.ts'] + }, + alias: { + '@': path.resolve(__dirname, 'dist-in') + } + }, + output: { + filename: 'main_node.cjs', + path: path.resolve(__dirname, 'dist') + }, + externals: { + 'sharp': 'commonjs sharp', + 'pino': 'commonjs pino', + 'thread-stream': 'commonjs thread-stream', + 'fluent-ffmpeg': 'commonjs fluent-ffmpeg', + 'pdfmake': 'commonjs pdfmake' + } +} \ No newline at end of file