@burdenoff/be-sdk 2026.805.1 → 2026.815.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/resource-caps/index.ts"],"names":["RESOURCE_CAP_DEFAULTS","workspace","free","paidDefault","scope","workspaceMember","sandbox","vibe","agent","conversation","message","tag","file","group","calendar","scheduledTask","form","apiKey","webhook","ResourceCapExceededError","GraphQLError","detail","resource","currentCount","limit","planName","extensions","code","userMessage","technicalMessage","name","PLAN_QUERY","ResourceCapsModule","client","transport","cacheTtlMs","clientlessTier","billingFailureTier","onFallback","onBillingFailure","warnedClientless","planCache","Map","planResolutionCounter","enforcementCounter","config","createCounter","configure","undefined","hasBillingSource","clear","Boolean","getResourceCap","userId","Error","defaults","plan","resolvePlan","override","overrides","planTier","isFallback","fallbackReason","enforceResourceCap","cap","inc","plan_tier","result","getWorkspaceResourceCap","workspaceId","organizationId","workspaceCacheKey","enforceWorkspaceResourceCap","invalidate","delete","invalidateWorkspace","invalidateAll","cacheKey","key","cached","get","Date","now","fetchedAt","fetchPlan","set","warnClientlessOnce","reason","fallbackPlan","planNode","fetchPlanNode","logger","warn","tier","normaliseTier","sanitizeOverrides","resourceCaps","err","data","userBillingPlan","res","query","raw","fallback","lc","toLowerCase","out","value","Object","entries","Number","isFinite","Math","max","floor","defaultInstance","getResourceCaps","configureResourceCaps","instance","__resetResourceCapsForTests"],"mappings":"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","file":"chunk-RJK4MPDW.js","sourcesContent":["/**\n * Resource Caps Module\n *\n * Enforces per-user / per-workspace resource ceilings to prevent unbounded\n * resource use on a multi-tenant SaaS. Caps come from the user's billing plan\n * (resolved via global-billing-svc) and fall back to static defaults defined\n * here when the plan lookup fails or the resource isn't overridden.\n *\n * Two plan tiers exist by default:\n * - free: tight per-user / per-workspace ceilings\n * - paid (default): ~100x looser; individual paid plans can override via the\n * `Plan.resourceCaps` JSON column in global-billing-svc.\n *\n * @example\n * ```ts\n * import { resourceCaps } from '@burdenoff/be-sdk/resource-caps';\n *\n * const { limit } = await resourceCaps.getResourceCap(userId, 'tag');\n * await resourceCaps.enforceResourceCap(userId, 'tag', currentCount);\n * ```\n */\n\nimport { GraphQLError } from 'graphql';\n\nimport type { BurdenoffGraphQLClient } from '../client/graphql.js';\nimport { createCounter } from '../instrumentation/metrics-collector.js';\nimport { logger } from '../logger/index.js';\n\n// ---------------------------------------------------------------------------\n// Resource registry\n// ---------------------------------------------------------------------------\n\n/**\n * Canonical resource names. Adding a new capped resource? Append it here,\n * extend RESOURCE_CAP_DEFAULTS, and reference it from the relevant svc.\n */\nexport type ResourceName =\n | 'workspace' // per user\n | 'workspaceMember' // per workspace\n | 'sandbox' // per user\n | 'vibe' // per user\n | 'agent' // per workspace\n | 'conversation' // per user/day\n | 'message' // per user/day\n | 'tag' // per workspace\n | 'file' // per user (count only)\n | 'group' // per workspace\n | 'calendar' // per user\n | 'scheduledTask' // per user\n | 'form' // per user\n | 'apiKey' // per user\n | 'webhook'; // per workspace\n\nexport type PlanTier = 'free' | 'paid';\n\nexport interface ResourceCapDefaults {\n free: number;\n paidDefault: number;\n /** Optional scope hint used by callers when wiring guards */\n scope: 'user' | 'workspace' | 'user/day';\n}\n\n/**\n * Static fallback caps. Real values may be overridden per plan in\n * global-billing-svc Plan.resourceCaps JSON.\n */\nexport const RESOURCE_CAP_DEFAULTS: Record<ResourceName, ResourceCapDefaults> = {\n workspace: { free: 3, paidDefault: 50, scope: 'user' },\n workspaceMember: { free: 500, paidDefault: 500, scope: 'workspace' },\n sandbox: { free: 2, paidDefault: 50, scope: 'user' },\n vibe: { free: 10, paidDefault: 500, scope: 'user' },\n agent: { free: 2, paidDefault: 20, scope: 'workspace' },\n conversation: { free: 20, paidDefault: 2000, scope: 'user/day' },\n message: { free: 200, paidDefault: 20000, scope: 'user/day' },\n tag: { free: 50, paidDefault: 5000, scope: 'workspace' },\n file: { free: 100, paidDefault: 10000, scope: 'user' },\n group: { free: 5, paidDefault: 500, scope: 'workspace' },\n calendar: { free: 3, paidDefault: 100, scope: 'user' },\n scheduledTask: { free: 5, paidDefault: 500, scope: 'user' },\n form: { free: 5, paidDefault: 500, scope: 'user' },\n apiKey: { free: 2, paidDefault: 50, scope: 'user' },\n webhook: { free: 2, paidDefault: 100, scope: 'workspace' },\n};\n\n// ---------------------------------------------------------------------------\n// Types & errors\n// ---------------------------------------------------------------------------\n\nexport interface ResourceCap {\n resource: ResourceName;\n limit: number;\n planName: string;\n planTier: PlanTier;\n /** True when the cap came from defaults, not from the billing service */\n isFallback: boolean;\n /** Why the fallback was used, when isFallback is true */\n fallbackReason?: 'clientless' | 'billing_error';\n}\n\n/**\n * Scope for workspace-scoped resource caps. The cap is derived from the plan of\n * the workspace's owning organization, not from whichever actor happens to be\n * making the request, so two members of the same workspace always see the same\n * limit (BOFF-4808).\n */\nexport interface WorkspaceResourceCapScope {\n /** Stable workspace identifier; used as the cache key. */\n workspaceId: string;\n /**\n * Organization that owns the workspace and whose billing plan determines the\n * cap. This is the `organizationId` from global-tenant-svc's Workspace type\n * (or `orgId` from wspace-workspace-svc's Workspace type).\n */\n organizationId: string;\n}\n\n/**\n * Layer-aware transport for the `userBillingPlan` lookup. Given the GraphQL\n * document + variables, returns the response `data` object (or null). Preferred\n * over `client`: the SDK bootstrap wires this to a same-layer (global) or\n * cross-layer (wspace→global) gateway call so billing is reachable from every\n * service without any per-call-site wiring (BOFF-4805).\n */\nexport type BillingPlanTransport = (query: string, variables: Record<string, unknown>) => Promise<unknown>;\n\nexport interface ResourceCapsConfig {\n client?: BurdenoffGraphQLClient;\n /** Preferred billing lookup path; see {@link BillingPlanTransport}. */\n transport?: BillingPlanTransport;\n /** Optional in-memory TTL for plan lookups; defaults to 60s */\n cacheTtlMs?: number;\n /**\n * Plan tier used when the module has no billing source (clientless). This is\n * the misconfiguration path: services should always bootstrap with a billing\n * transport. Defaults to `free` so a clientless service is visibly broken in\n * tests, while still not hard-blocking local unit tests.\n */\n clientlessTier?: PlanTier;\n /**\n * Plan tier used when a billing source is configured but the lookup fails\n * (network error, billing service down, etc.). Defaults to `paid` so a\n * transient billing outage does not silently downgrade paid customers to the\n * tightest free-tier caps (fail-open with alerting; BOFF-4805/4809).\n */\n billingFailureTier?: PlanTier;\n /**\n * Telemetry hook invoked when the module cannot reach billing (no transport /\n * client) and collapses to the clientless fallback. Wired to a metric counter\n * by observability so an unwired/broken integration is visible (BOFF-4809).\n */\n onFallback?: () => void;\n /**\n * Telemetry hook invoked when a billing source is configured but the lookup\n * fails (billing error fallback to the paid default).\n */\n onBillingFailure?: () => void;\n}\n\ninterface CachedPlan {\n planName: string;\n planTier: PlanTier;\n overrides: Partial<Record<ResourceName, number>>;\n fetchedAt: number;\n isFallback: boolean;\n fallbackReason?: 'clientless' | 'billing_error';\n}\n\n/**\n * Thrown when an entity create operation would push the user past the cap.\n * The matching GraphQL error has extensions.code = RESOURCE_CAP_EXCEEDED\n * so clients can detect and route to an upgrade flow.\n */\nexport class ResourceCapExceededError extends GraphQLError {\n constructor(detail: { resource: ResourceName; currentCount: number; limit: number; planName: string }) {\n super(\n `Resource cap exceeded for ${detail.resource}: ${detail.currentCount}/${detail.limit} on plan '${detail.planName}'.`,\n {\n extensions: {\n code: 'RESOURCE_CAP_EXCEEDED',\n userMessage: \"You've reached your plan limit. Upgrade your plan to continue.\",\n technicalMessage: `Resource cap exceeded for ${detail.resource}: ${detail.currentCount}/${detail.limit} on plan '${detail.planName}'.`,\n resource: detail.resource,\n currentCount: detail.currentCount,\n limit: detail.limit,\n planName: detail.planName,\n },\n }\n );\n this.name = 'ResourceCapExceededError';\n }\n}\n\n// ---------------------------------------------------------------------------\n// Module\n// ---------------------------------------------------------------------------\n\nconst PLAN_QUERY = /* GraphQL */ `\n query GetUserPlanForCaps($userId: ID!) {\n userBillingPlan(userId: $userId) {\n planName\n tier\n resourceCaps\n }\n }\n`;\n\ninterface PlanQueryResponse {\n userBillingPlan?: {\n planName?: string | null;\n tier?: string | null;\n resourceCaps?: Record<string, number> | null;\n } | null;\n}\n\ntype PlanNode = NonNullable<PlanQueryResponse['userBillingPlan']>;\n\nexport class ResourceCapsModule {\n private client?: BurdenoffGraphQLClient;\n private transport?: BillingPlanTransport;\n private cacheTtlMs: number;\n private clientlessTier: PlanTier;\n private billingFailureTier: PlanTier;\n private onFallback?: () => void;\n private onBillingFailure?: () => void;\n private warnedClientless = false;\n private readonly planCache = new Map<string, CachedPlan>();\n private readonly planResolutionCounter;\n private readonly enforcementCounter;\n\n constructor(config: ResourceCapsConfig = {}) {\n this.client = config.client;\n this.transport = config.transport;\n this.cacheTtlMs = config.cacheTtlMs ?? 60_000;\n this.clientlessTier = config.clientlessTier ?? 'free';\n this.billingFailureTier = config.billingFailureTier ?? 'paid';\n this.onFallback = config.onFallback;\n this.onBillingFailure = config.onBillingFailure;\n this.planResolutionCounter = createCounter(\n 'resource_caps.plan_resolution_total',\n 'Total number of billing plan resolutions for resource caps'\n );\n this.enforcementCounter = createCounter(\n 'resource_caps.enforcement_total',\n 'Total number of resource cap enforcement checks'\n );\n }\n\n /**\n * (Re)bind runtime dependencies on an already-constructed module. The SDK\n * bootstrap uses this to prime the process-wide singleton with a billing\n * transport even if an early caller already lazily created it clientless\n * (a bare `getResourceCaps(config)` ignores config once the instance exists).\n * Clears the plan cache so stale fallback entries don't linger.\n */\n configure(config: ResourceCapsConfig): void {\n if (config.client !== undefined) this.client = config.client;\n if (config.transport !== undefined) this.transport = config.transport;\n if (config.onFallback !== undefined) this.onFallback = config.onFallback;\n if (config.onBillingFailure !== undefined) this.onBillingFailure = config.onBillingFailure;\n if (typeof config.cacheTtlMs === 'number') this.cacheTtlMs = config.cacheTtlMs;\n if (config.clientlessTier) this.clientlessTier = config.clientlessTier;\n if (config.billingFailureTier) this.billingFailureTier = config.billingFailureTier;\n if (this.hasBillingSource()) this.warnedClientless = false;\n this.planCache.clear();\n }\n\n /** True when the module can actually reach billing (has a transport or client). */\n hasBillingSource(): boolean {\n return Boolean(this.transport || this.client);\n }\n\n /**\n * Resolve the cap for a given resource for the supplied user.\n * Order: plan-override → plan-tier-default → static free default.\n */\n async getResourceCap(userId: string, resource: ResourceName): Promise<ResourceCap> {\n if (!userId) {\n throw new Error('getResourceCap: userId is required');\n }\n const defaults = RESOURCE_CAP_DEFAULTS[resource];\n if (!defaults) {\n throw new Error(`getResourceCap: unknown resource '${resource}'`);\n }\n\n const plan = await this.resolvePlan(userId);\n const override = plan.overrides[resource];\n if (typeof override === 'number' && override >= 0) {\n return {\n resource,\n limit: override,\n planName: plan.planName,\n planTier: plan.planTier,\n isFallback: plan.isFallback,\n fallbackReason: plan.fallbackReason,\n };\n }\n\n const limit = plan.planTier === 'paid' ? defaults.paidDefault : defaults.free;\n return {\n resource,\n limit,\n planName: plan.planName,\n planTier: plan.planTier,\n isFallback: plan.isFallback,\n fallbackReason: plan.fallbackReason,\n };\n }\n\n /**\n * Throws ResourceCapExceededError when currentCount >= limit.\n * Use BEFORE the create transaction to avoid orphan rows.\n */\n async enforceResourceCap(userId: string, resource: ResourceName, currentCount: number): Promise<ResourceCap> {\n const cap = await this.getResourceCap(userId, resource);\n if (currentCount >= cap.limit) {\n this.enforcementCounter.inc({\n resource,\n plan_tier: cap.planTier,\n result: 'denied',\n });\n throw new ResourceCapExceededError({\n resource,\n currentCount,\n limit: cap.limit,\n planName: cap.planName,\n });\n }\n this.enforcementCounter.inc({\n resource,\n plan_tier: cap.planTier,\n result: 'allowed',\n });\n return cap;\n }\n\n /**\n * Resolve a workspace-scoped resource cap from the workspace's owner\n * organization plan, regardless of which actor triggered the action.\n *\n * @example\n * ```ts\n * const { limit } = await caps.getWorkspaceResourceCap(\n * { workspaceId: 'ws-1', organizationId: 'org-1' },\n * 'group'\n * );\n * ```\n */\n async getWorkspaceResourceCap(scope: WorkspaceResourceCapScope, resource: ResourceName): Promise<ResourceCap> {\n const { workspaceId, organizationId } = scope;\n if (!workspaceId) {\n throw new Error('getWorkspaceResourceCap: workspaceId is required');\n }\n if (!organizationId) {\n throw new Error('getWorkspaceResourceCap: organizationId is required');\n }\n const defaults = RESOURCE_CAP_DEFAULTS[resource];\n if (!defaults) {\n throw new Error(`getWorkspaceResourceCap: unknown resource '${resource}'`);\n }\n\n const plan = await this.resolvePlan(organizationId, this.workspaceCacheKey(workspaceId));\n const override = plan.overrides[resource];\n if (typeof override === 'number' && override >= 0) {\n return {\n resource,\n limit: override,\n planName: plan.planName,\n planTier: plan.planTier,\n isFallback: plan.isFallback,\n fallbackReason: plan.fallbackReason,\n };\n }\n\n const limit = plan.planTier === 'paid' ? defaults.paidDefault : defaults.free;\n return {\n resource,\n limit,\n planName: plan.planName,\n planTier: plan.planTier,\n isFallback: plan.isFallback,\n fallbackReason: plan.fallbackReason,\n };\n }\n\n /**\n * Throws ResourceCapExceededError when currentCount >= limit for a\n * workspace-scoped resource. The cap is resolved from the workspace owner's\n * organization plan, so the answer is stable across members.\n */\n async enforceWorkspaceResourceCap(\n scope: WorkspaceResourceCapScope,\n resource: ResourceName,\n currentCount: number\n ): Promise<ResourceCap> {\n const cap = await this.getWorkspaceResourceCap(scope, resource);\n if (currentCount >= cap.limit) {\n this.enforcementCounter.inc({\n resource,\n plan_tier: cap.planTier,\n result: 'denied',\n });\n throw new ResourceCapExceededError({\n resource,\n currentCount,\n limit: cap.limit,\n planName: cap.planName,\n });\n }\n this.enforcementCounter.inc({\n resource,\n plan_tier: cap.planTier,\n result: 'allowed',\n });\n return cap;\n }\n\n /** Invalidate cache for a user (e.g. after plan upgrade) */\n invalidate(userId: string): void {\n this.planCache.delete(userId);\n }\n\n /** Invalidate cache for a workspace (e.g. after workspace plan change) */\n invalidateWorkspace(workspaceId: string): void {\n this.planCache.delete(this.workspaceCacheKey(workspaceId));\n }\n\n /** Clear entire plan cache */\n invalidateAll(): void {\n this.planCache.clear();\n }\n\n // -------------------------------------------------------------------------\n // Internals\n // -------------------------------------------------------------------------\n\n private workspaceCacheKey(workspaceId: string): string {\n return `workspace:${workspaceId}`;\n }\n\n private async resolvePlan(userId: string, cacheKey?: string): Promise<CachedPlan> {\n const key = cacheKey ?? userId;\n const cached = this.planCache.get(key);\n if (cached && Date.now() - cached.fetchedAt < this.cacheTtlMs) {\n return cached;\n }\n\n const plan = await this.fetchPlan(userId);\n this.planCache.set(key, plan);\n return plan;\n }\n\n private async fetchPlan(userId: string): Promise<CachedPlan> {\n // No billing source wired → every cap silently collapses to the configured\n // clientless tier. Warn loudly (once) so an unwired/broken integration\n // can't hide in prod (BOFF-4805/4809).\n if (!this.hasBillingSource()) {\n this.warnClientlessOnce();\n this.planResolutionCounter.inc({ result: 'fallback', reason: 'clientless' });\n return this.fallbackPlan(this.clientlessTier, 'clientless');\n }\n try {\n const planNode = await this.fetchPlanNode(userId);\n if (!planNode) {\n logger.warn('resource-caps: plan lookup returned null; falling back to paid defaults', {\n userId,\n });\n this.onBillingFailure?.();\n this.planResolutionCounter.inc({ result: 'fallback', reason: 'billing_error' });\n return this.fallbackPlan(this.billingFailureTier, 'billing_error');\n }\n const tier = normaliseTier(planNode.tier, this.billingFailureTier);\n const overrides = sanitizeOverrides(planNode.resourceCaps);\n this.planResolutionCounter.inc({ result: 'billing' });\n return {\n planName: planNode.planName ?? (tier === 'paid' ? 'paid' : 'free'),\n planTier: tier,\n overrides,\n fetchedAt: Date.now(),\n isFallback: false,\n };\n } catch (err) {\n logger.warn('resource-caps: plan lookup failed; falling back to paid defaults', {\n err,\n userId,\n });\n this.onBillingFailure?.();\n this.planResolutionCounter.inc({ result: 'fallback', reason: 'billing_error' });\n return this.fallbackPlan(this.billingFailureTier, 'billing_error');\n }\n }\n\n /**\n * Resolve the raw `userBillingPlan` node via the injected transport (preferred)\n * or the legacy direct client. Guarded by {@link hasBillingSource} in the\n * caller, so at least one path is present here.\n */\n private async fetchPlanNode(userId: string): Promise<PlanNode | null> {\n if (this.transport) {\n const data = (await this.transport(PLAN_QUERY, { userId })) as PlanQueryResponse | null | undefined;\n return data?.userBillingPlan ?? null;\n }\n if (this.client) {\n const res = await this.client.query<PlanQueryResponse>(PLAN_QUERY, { userId });\n return res?.userBillingPlan ?? null;\n }\n return null;\n }\n\n private warnClientlessOnce(): void {\n if (this.warnedClientless) return;\n this.warnedClientless = true;\n logger.warn(\n 'resource-caps: running WITHOUT a billing transport/client — every resource cap will use the ' +\n 'free-tier fallback regardless of the customer plan. Ensure initializeBurdenoffSDK() ran with a ' +\n 'layer/gateway configured (BOFF-4805).'\n );\n this.onFallback?.();\n }\n\n private fallbackPlan(tier: PlanTier, reason: 'clientless' | 'billing_error'): CachedPlan {\n return {\n planName: tier === 'paid' ? 'fallback-paid' : 'fallback-free',\n planTier: tier,\n overrides: {},\n fetchedAt: Date.now(),\n isFallback: true,\n fallbackReason: reason,\n };\n }\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction normaliseTier(raw: string | null | undefined, fallback: PlanTier): PlanTier {\n if (!raw) return fallback;\n const lc = raw.toLowerCase();\n if (lc === 'free' || lc === 'paid') return lc;\n // Treat anything non-free as paid (enterprise, business, pro, etc.)\n if (lc === 'enterprise' || lc === 'business' || lc === 'pro' || lc === 'team') {\n return 'paid';\n }\n return fallback;\n}\n\nfunction sanitizeOverrides(raw: Record<string, number> | null | undefined): Partial<Record<ResourceName, number>> {\n if (!raw || typeof raw !== 'object') return {};\n const out: Partial<Record<ResourceName, number>> = {};\n for (const [key, value] of Object.entries(raw)) {\n if (key in RESOURCE_CAP_DEFAULTS && typeof value === 'number' && Number.isFinite(value)) {\n out[key as ResourceName] = Math.max(0, Math.floor(value));\n }\n }\n return out;\n}\n\n// ---------------------------------------------------------------------------\n// Convenience singleton\n// ---------------------------------------------------------------------------\n\nlet defaultInstance: ResourceCapsModule | null = null;\n\n/**\n * Obtain a process-wide singleton. The first call binds the GraphQL client\n * (typically the SDK's internal client). Later calls return the same instance.\n */\nexport function getResourceCaps(config?: ResourceCapsConfig): ResourceCapsModule {\n if (!defaultInstance) {\n defaultInstance = new ResourceCapsModule(config);\n } else if (config) {\n // Previously the config was silently dropped once the singleton existed —\n // the root cause of BOFF-4805 where the billing client could never be bound\n // after a lazy first construction. Apply it instead.\n defaultInstance.configure(config);\n }\n return defaultInstance;\n}\n\n/**\n * Prime/rebind the process-wide singleton with billing connectivity. Call once\n * during SDK bootstrap. Unlike a bare `getResourceCaps(config)` on a fresh\n * process, this is explicit about the intent to (re)wire and is safe to call\n * after the singleton was already lazily created clientless.\n */\nexport function configureResourceCaps(config: ResourceCapsConfig): ResourceCapsModule {\n const instance = getResourceCaps();\n instance.configure(config);\n return instance;\n}\n\n/** Reset the singleton (for tests) */\nexport function __resetResourceCapsForTests(): void {\n defaultInstance = null;\n}\n"]}
1
+ {"version":3,"sources":["../src/resource-caps/index.ts"],"names":["RESOURCE_CAP_DEFAULTS","workspace","free","paidDefault","scope","workspaceMember","sandbox","vibe","agent","conversation","message","tag","file","group","calendar","scheduledTask","form","apiKey","webhook","ResourceCapExceededError","GraphQLError","detail","resource","currentCount","limit","planName","extensions","code","userMessage","technicalMessage","name","PLAN_QUERY","ResourceCapsModule","client","transport","cacheTtlMs","clientlessTier","billingFailureTier","onFallback","onBillingFailure","warnedClientless","planCache","Map","planResolutionCounter","enforcementCounter","config","createCounter","configure","undefined","hasBillingSource","clear","Boolean","getResourceCap","userId","Error","defaults","plan","resolvePlan","override","overrides","planTier","isFallback","fallbackReason","enforceResourceCap","cap","inc","plan_tier","result","getWorkspaceResourceCap","workspaceId","organizationId","workspaceCacheKey","enforceWorkspaceResourceCap","invalidate","delete","invalidateWorkspace","invalidateAll","cacheKey","key","cached","get","Date","now","fetchedAt","fetchPlan","set","warnClientlessOnce","reason","fallbackPlan","planNode","fetchPlanNode","logger","warn","tier","normaliseTier","sanitizeOverrides","resourceCaps","err","data","userBillingPlan","res","query","raw","fallback","lc","toLowerCase","out","value","Object","entries","Number","isFinite","Math","max","floor","defaultInstance","getResourceCaps","configureResourceCaps","instance","__resetResourceCapsForTests"],"mappings":"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","file":"chunk-XWVP4MC6.js","sourcesContent":["/**\n * Resource Caps Module\n *\n * Enforces per-user / per-workspace resource ceilings to prevent unbounded\n * resource use on a multi-tenant SaaS. Caps come from the user's billing plan\n * (resolved via global-billing-svc) and fall back to static defaults defined\n * here when the plan lookup fails or the resource isn't overridden.\n *\n * Two plan tiers exist by default:\n * - free: tight per-user / per-workspace ceilings\n * - paid (default): ~100x looser; individual paid plans can override via the\n * `Plan.resourceCaps` JSON column in global-billing-svc.\n *\n * @example\n * ```ts\n * import { resourceCaps } from '@burdenoff/be-sdk/resource-caps';\n *\n * const { limit } = await resourceCaps.getResourceCap(userId, 'tag');\n * await resourceCaps.enforceResourceCap(userId, 'tag', currentCount);\n * ```\n */\n\nimport { GraphQLError } from 'graphql';\n\nimport type { BurdenoffGraphQLClient } from '../client/graphql.js';\nimport { createCounter } from '../instrumentation/metrics-collector.js';\nimport { logger } from '../logger/index.js';\n\n// ---------------------------------------------------------------------------\n// Resource registry\n// ---------------------------------------------------------------------------\n\n/**\n * Canonical resource names. Adding a new capped resource? Append it here,\n * extend RESOURCE_CAP_DEFAULTS, and reference it from the relevant svc.\n */\nexport type ResourceName =\n | 'workspace' // per user\n | 'workspaceMember' // per workspace\n | 'sandbox' // per user\n | 'vibe' // per user\n | 'agent' // per workspace\n | 'conversation' // per user/day\n | 'message' // per user/day\n | 'tag' // per workspace\n | 'file' // per user (count only)\n | 'group' // per workspace\n | 'calendar' // per user\n | 'scheduledTask' // per user\n | 'form' // per user\n | 'apiKey' // per user\n | 'webhook'; // per workspace\n\nexport type PlanTier = 'free' | 'paid';\n\nexport interface ResourceCapDefaults {\n free: number;\n paidDefault: number;\n /** Optional scope hint used by callers when wiring guards */\n scope: 'user' | 'workspace' | 'user/day';\n}\n\n/**\n * Static fallback caps. Real values may be overridden per plan in\n * global-billing-svc Plan.resourceCaps JSON.\n */\nexport const RESOURCE_CAP_DEFAULTS: Record<ResourceName, ResourceCapDefaults> = {\n workspace: { free: 3, paidDefault: 50, scope: 'user' },\n workspaceMember: { free: 500, paidDefault: 500, scope: 'workspace' },\n sandbox: { free: 2, paidDefault: 50, scope: 'user' },\n vibe: { free: 10, paidDefault: 500, scope: 'user' },\n agent: { free: 2, paidDefault: 20, scope: 'workspace' },\n conversation: { free: 20, paidDefault: 2000, scope: 'user/day' },\n message: { free: 200, paidDefault: 20000, scope: 'user/day' },\n tag: { free: 50, paidDefault: 5000, scope: 'workspace' },\n file: { free: 100, paidDefault: 10000, scope: 'user' },\n group: { free: 5, paidDefault: 500, scope: 'workspace' },\n calendar: { free: 3, paidDefault: 100, scope: 'user' },\n scheduledTask: { free: 5, paidDefault: 500, scope: 'user' },\n form: { free: 5, paidDefault: 500, scope: 'user' },\n apiKey: { free: 2, paidDefault: 50, scope: 'user' },\n webhook: { free: 2, paidDefault: 100, scope: 'workspace' },\n};\n\n// ---------------------------------------------------------------------------\n// Types & errors\n// ---------------------------------------------------------------------------\n\nexport interface ResourceCap {\n resource: ResourceName;\n limit: number;\n planName: string;\n planTier: PlanTier;\n /** True when the cap came from defaults, not from the billing service */\n isFallback: boolean;\n /** Why the fallback was used, when isFallback is true */\n fallbackReason?: 'clientless' | 'billing_error';\n}\n\n/**\n * Scope for workspace-scoped resource caps. The cap is derived from the plan of\n * the workspace's owning organization, not from whichever actor happens to be\n * making the request, so two members of the same workspace always see the same\n * limit (BOFF-4808).\n */\nexport interface WorkspaceResourceCapScope {\n /** Stable workspace identifier; used as the cache key. */\n workspaceId: string;\n /**\n * Organization that owns the workspace and whose billing plan determines the\n * cap. This is the `organizationId` from global-tenant-svc's Workspace type\n * (or `orgId` from wspace-workspace-svc's Workspace type).\n */\n organizationId: string;\n}\n\n/**\n * Layer-aware transport for the `userBillingPlan` lookup. Given the GraphQL\n * document + variables, returns the response `data` object (or null). Preferred\n * over `client`: the SDK bootstrap wires this to a same-layer (global) or\n * cross-layer (wspace→global) gateway call so billing is reachable from every\n * service without any per-call-site wiring (BOFF-4805).\n */\nexport type BillingPlanTransport = (query: string, variables: Record<string, unknown>) => Promise<unknown>;\n\nexport interface ResourceCapsConfig {\n client?: BurdenoffGraphQLClient;\n /** Preferred billing lookup path; see {@link BillingPlanTransport}. */\n transport?: BillingPlanTransport;\n /** Optional in-memory TTL for plan lookups; defaults to 60s */\n cacheTtlMs?: number;\n /**\n * Plan tier used when the module has no billing source (clientless). This is\n * the misconfiguration path: services should always bootstrap with a billing\n * transport. Defaults to `free` so a clientless service is visibly broken in\n * tests, while still not hard-blocking local unit tests.\n */\n clientlessTier?: PlanTier;\n /**\n * Plan tier used when a billing source is configured but the lookup fails\n * (network error, billing service down, etc.). Defaults to `paid` so a\n * transient billing outage does not silently downgrade paid customers to the\n * tightest free-tier caps (fail-open with alerting; BOFF-4805/4809).\n */\n billingFailureTier?: PlanTier;\n /**\n * Telemetry hook invoked when the module cannot reach billing (no transport /\n * client) and collapses to the clientless fallback. Wired to a metric counter\n * by observability so an unwired/broken integration is visible (BOFF-4809).\n */\n onFallback?: () => void;\n /**\n * Telemetry hook invoked when a billing source is configured but the lookup\n * fails (billing error fallback to the paid default).\n */\n onBillingFailure?: () => void;\n}\n\ninterface CachedPlan {\n planName: string;\n planTier: PlanTier;\n overrides: Partial<Record<ResourceName, number>>;\n fetchedAt: number;\n isFallback: boolean;\n fallbackReason?: 'clientless' | 'billing_error';\n}\n\n/**\n * Thrown when an entity create operation would push the user past the cap.\n * The matching GraphQL error has extensions.code = RESOURCE_CAP_EXCEEDED\n * so clients can detect and route to an upgrade flow.\n */\nexport class ResourceCapExceededError extends GraphQLError {\n constructor(detail: { resource: ResourceName; currentCount: number; limit: number; planName: string }) {\n super(\n `Resource cap exceeded for ${detail.resource}: ${detail.currentCount}/${detail.limit} on plan '${detail.planName}'.`,\n {\n extensions: {\n code: 'RESOURCE_CAP_EXCEEDED',\n userMessage: \"You've reached your plan limit. Upgrade your plan to continue.\",\n technicalMessage: `Resource cap exceeded for ${detail.resource}: ${detail.currentCount}/${detail.limit} on plan '${detail.planName}'.`,\n resource: detail.resource,\n currentCount: detail.currentCount,\n limit: detail.limit,\n planName: detail.planName,\n },\n }\n );\n this.name = 'ResourceCapExceededError';\n }\n}\n\n// ---------------------------------------------------------------------------\n// Module\n// ---------------------------------------------------------------------------\n\nconst PLAN_QUERY = /* GraphQL */ `\n query GetUserPlanForCaps($userId: ID!) {\n userBillingPlan(userId: $userId) {\n planName\n tier\n resourceCaps\n }\n }\n`;\n\ninterface PlanQueryResponse {\n userBillingPlan?: {\n planName?: string | null;\n tier?: string | null;\n resourceCaps?: Record<string, number> | null;\n } | null;\n}\n\ntype PlanNode = NonNullable<PlanQueryResponse['userBillingPlan']>;\n\nexport class ResourceCapsModule {\n private client?: BurdenoffGraphQLClient;\n private transport?: BillingPlanTransport;\n private cacheTtlMs: number;\n private clientlessTier: PlanTier;\n private billingFailureTier: PlanTier;\n private onFallback?: () => void;\n private onBillingFailure?: () => void;\n private warnedClientless = false;\n private readonly planCache = new Map<string, CachedPlan>();\n private readonly planResolutionCounter;\n private readonly enforcementCounter;\n\n constructor(config: ResourceCapsConfig = {}) {\n this.client = config.client;\n this.transport = config.transport;\n this.cacheTtlMs = config.cacheTtlMs ?? 60_000;\n this.clientlessTier = config.clientlessTier ?? 'free';\n this.billingFailureTier = config.billingFailureTier ?? 'paid';\n this.onFallback = config.onFallback;\n this.onBillingFailure = config.onBillingFailure;\n this.planResolutionCounter = createCounter(\n 'resource_caps.plan_resolution_total',\n 'Total number of billing plan resolutions for resource caps'\n );\n this.enforcementCounter = createCounter(\n 'resource_caps.enforcement_total',\n 'Total number of resource cap enforcement checks'\n );\n }\n\n /**\n * (Re)bind runtime dependencies on an already-constructed module. The SDK\n * bootstrap uses this to prime the process-wide singleton with a billing\n * transport even if an early caller already lazily created it clientless\n * (a bare `getResourceCaps(config)` ignores config once the instance exists).\n * Clears the plan cache so stale fallback entries don't linger.\n */\n configure(config: ResourceCapsConfig): void {\n if (config.client !== undefined) this.client = config.client;\n if (config.transport !== undefined) this.transport = config.transport;\n if (config.onFallback !== undefined) this.onFallback = config.onFallback;\n if (config.onBillingFailure !== undefined) this.onBillingFailure = config.onBillingFailure;\n if (typeof config.cacheTtlMs === 'number') this.cacheTtlMs = config.cacheTtlMs;\n if (config.clientlessTier) this.clientlessTier = config.clientlessTier;\n if (config.billingFailureTier) this.billingFailureTier = config.billingFailureTier;\n if (this.hasBillingSource()) this.warnedClientless = false;\n this.planCache.clear();\n }\n\n /** True when the module can actually reach billing (has a transport or client). */\n hasBillingSource(): boolean {\n return Boolean(this.transport || this.client);\n }\n\n /**\n * Resolve the cap for a given resource for the supplied user.\n * Order: plan-override → plan-tier-default → static free default.\n */\n async getResourceCap(userId: string, resource: ResourceName): Promise<ResourceCap> {\n if (!userId) {\n throw new Error('getResourceCap: userId is required');\n }\n const defaults = RESOURCE_CAP_DEFAULTS[resource];\n if (!defaults) {\n throw new Error(`getResourceCap: unknown resource '${resource}'`);\n }\n\n const plan = await this.resolvePlan(userId);\n const override = plan.overrides[resource];\n if (typeof override === 'number' && override >= 0) {\n return {\n resource,\n limit: override,\n planName: plan.planName,\n planTier: plan.planTier,\n isFallback: plan.isFallback,\n fallbackReason: plan.fallbackReason,\n };\n }\n\n const limit = plan.planTier === 'paid' ? defaults.paidDefault : defaults.free;\n return {\n resource,\n limit,\n planName: plan.planName,\n planTier: plan.planTier,\n isFallback: plan.isFallback,\n fallbackReason: plan.fallbackReason,\n };\n }\n\n /**\n * Throws ResourceCapExceededError when currentCount >= limit.\n * Use BEFORE the create transaction to avoid orphan rows.\n */\n async enforceResourceCap(userId: string, resource: ResourceName, currentCount: number): Promise<ResourceCap> {\n const cap = await this.getResourceCap(userId, resource);\n if (currentCount >= cap.limit) {\n this.enforcementCounter.inc({\n resource,\n plan_tier: cap.planTier,\n result: 'denied',\n });\n throw new ResourceCapExceededError({\n resource,\n currentCount,\n limit: cap.limit,\n planName: cap.planName,\n });\n }\n this.enforcementCounter.inc({\n resource,\n plan_tier: cap.planTier,\n result: 'allowed',\n });\n return cap;\n }\n\n /**\n * Resolve a workspace-scoped resource cap from the workspace's owner\n * organization plan, regardless of which actor triggered the action.\n *\n * @example\n * ```ts\n * const { limit } = await caps.getWorkspaceResourceCap(\n * { workspaceId: 'ws-1', organizationId: 'org-1' },\n * 'group'\n * );\n * ```\n */\n async getWorkspaceResourceCap(scope: WorkspaceResourceCapScope, resource: ResourceName): Promise<ResourceCap> {\n const { workspaceId, organizationId } = scope;\n if (!workspaceId) {\n throw new Error('getWorkspaceResourceCap: workspaceId is required');\n }\n if (!organizationId) {\n throw new Error('getWorkspaceResourceCap: organizationId is required');\n }\n const defaults = RESOURCE_CAP_DEFAULTS[resource];\n if (!defaults) {\n throw new Error(`getWorkspaceResourceCap: unknown resource '${resource}'`);\n }\n\n const plan = await this.resolvePlan(organizationId, this.workspaceCacheKey(workspaceId));\n const override = plan.overrides[resource];\n if (typeof override === 'number' && override >= 0) {\n return {\n resource,\n limit: override,\n planName: plan.planName,\n planTier: plan.planTier,\n isFallback: plan.isFallback,\n fallbackReason: plan.fallbackReason,\n };\n }\n\n const limit = plan.planTier === 'paid' ? defaults.paidDefault : defaults.free;\n return {\n resource,\n limit,\n planName: plan.planName,\n planTier: plan.planTier,\n isFallback: plan.isFallback,\n fallbackReason: plan.fallbackReason,\n };\n }\n\n /**\n * Throws ResourceCapExceededError when currentCount >= limit for a\n * workspace-scoped resource. The cap is resolved from the workspace owner's\n * organization plan, so the answer is stable across members.\n */\n async enforceWorkspaceResourceCap(\n scope: WorkspaceResourceCapScope,\n resource: ResourceName,\n currentCount: number\n ): Promise<ResourceCap> {\n const cap = await this.getWorkspaceResourceCap(scope, resource);\n if (currentCount >= cap.limit) {\n this.enforcementCounter.inc({\n resource,\n plan_tier: cap.planTier,\n result: 'denied',\n });\n throw new ResourceCapExceededError({\n resource,\n currentCount,\n limit: cap.limit,\n planName: cap.planName,\n });\n }\n this.enforcementCounter.inc({\n resource,\n plan_tier: cap.planTier,\n result: 'allowed',\n });\n return cap;\n }\n\n /** Invalidate cache for a user (e.g. after plan upgrade) */\n invalidate(userId: string): void {\n this.planCache.delete(userId);\n }\n\n /** Invalidate cache for a workspace (e.g. after workspace plan change) */\n invalidateWorkspace(workspaceId: string): void {\n this.planCache.delete(this.workspaceCacheKey(workspaceId));\n }\n\n /** Clear entire plan cache */\n invalidateAll(): void {\n this.planCache.clear();\n }\n\n // -------------------------------------------------------------------------\n // Internals\n // -------------------------------------------------------------------------\n\n private workspaceCacheKey(workspaceId: string): string {\n return `workspace:${workspaceId}`;\n }\n\n private async resolvePlan(userId: string, cacheKey?: string): Promise<CachedPlan> {\n const key = cacheKey ?? userId;\n const cached = this.planCache.get(key);\n if (cached && Date.now() - cached.fetchedAt < this.cacheTtlMs) {\n return cached;\n }\n\n const plan = await this.fetchPlan(userId);\n this.planCache.set(key, plan);\n return plan;\n }\n\n private async fetchPlan(userId: string): Promise<CachedPlan> {\n // No billing source wired → every cap silently collapses to the configured\n // clientless tier. Warn loudly (once) so an unwired/broken integration\n // can't hide in prod (BOFF-4805/4809).\n if (!this.hasBillingSource()) {\n this.warnClientlessOnce();\n this.planResolutionCounter.inc({ result: 'fallback', reason: 'clientless' });\n return this.fallbackPlan(this.clientlessTier, 'clientless');\n }\n try {\n const planNode = await this.fetchPlanNode(userId);\n if (!planNode) {\n logger.warn('resource-caps: plan lookup returned null; falling back to paid defaults', {\n userId,\n });\n this.onBillingFailure?.();\n this.planResolutionCounter.inc({ result: 'fallback', reason: 'billing_error' });\n return this.fallbackPlan(this.billingFailureTier, 'billing_error');\n }\n const tier = normaliseTier(planNode.tier, this.billingFailureTier);\n const overrides = sanitizeOverrides(planNode.resourceCaps);\n this.planResolutionCounter.inc({ result: 'billing' });\n return {\n planName: planNode.planName ?? (tier === 'paid' ? 'paid' : 'free'),\n planTier: tier,\n overrides,\n fetchedAt: Date.now(),\n isFallback: false,\n };\n } catch (err) {\n logger.warn('resource-caps: plan lookup failed; falling back to paid defaults', {\n err,\n userId,\n });\n this.onBillingFailure?.();\n this.planResolutionCounter.inc({ result: 'fallback', reason: 'billing_error' });\n return this.fallbackPlan(this.billingFailureTier, 'billing_error');\n }\n }\n\n /**\n * Resolve the raw `userBillingPlan` node via the injected transport (preferred)\n * or the legacy direct client. Guarded by {@link hasBillingSource} in the\n * caller, so at least one path is present here.\n */\n private async fetchPlanNode(userId: string): Promise<PlanNode | null> {\n if (this.transport) {\n const data = (await this.transport(PLAN_QUERY, { userId })) as PlanQueryResponse | null | undefined;\n return data?.userBillingPlan ?? null;\n }\n if (this.client) {\n const res = await this.client.query<PlanQueryResponse>(PLAN_QUERY, { userId });\n return res?.userBillingPlan ?? null;\n }\n return null;\n }\n\n private warnClientlessOnce(): void {\n if (this.warnedClientless) return;\n this.warnedClientless = true;\n logger.warn(\n 'resource-caps: running WITHOUT a billing transport/client — every resource cap will use the ' +\n 'free-tier fallback regardless of the customer plan. Ensure initializeBurdenoffSDK() ran with a ' +\n 'layer/gateway configured (BOFF-4805).'\n );\n this.onFallback?.();\n }\n\n private fallbackPlan(tier: PlanTier, reason: 'clientless' | 'billing_error'): CachedPlan {\n return {\n planName: tier === 'paid' ? 'fallback-paid' : 'fallback-free',\n planTier: tier,\n overrides: {},\n fetchedAt: Date.now(),\n isFallback: true,\n fallbackReason: reason,\n };\n }\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction normaliseTier(raw: string | null | undefined, fallback: PlanTier): PlanTier {\n if (!raw) return fallback;\n const lc = raw.toLowerCase();\n if (lc === 'free' || lc === 'paid') return lc;\n // Treat anything non-free as paid (enterprise, business, pro, etc.)\n if (lc === 'enterprise' || lc === 'business' || lc === 'pro' || lc === 'team') {\n return 'paid';\n }\n return fallback;\n}\n\nfunction sanitizeOverrides(raw: Record<string, number> | null | undefined): Partial<Record<ResourceName, number>> {\n if (!raw || typeof raw !== 'object') return {};\n const out: Partial<Record<ResourceName, number>> = {};\n for (const [key, value] of Object.entries(raw)) {\n if (key in RESOURCE_CAP_DEFAULTS && typeof value === 'number' && Number.isFinite(value)) {\n out[key as ResourceName] = Math.max(0, Math.floor(value));\n }\n }\n return out;\n}\n\n// ---------------------------------------------------------------------------\n// Convenience singleton\n// ---------------------------------------------------------------------------\n\nlet defaultInstance: ResourceCapsModule | null = null;\n\n/**\n * Obtain a process-wide singleton. The first call binds the GraphQL client\n * (typically the SDK's internal client). Later calls return the same instance.\n */\nexport function getResourceCaps(config?: ResourceCapsConfig): ResourceCapsModule {\n if (!defaultInstance) {\n defaultInstance = new ResourceCapsModule(config);\n } else if (config) {\n // Previously the config was silently dropped once the singleton existed —\n // the root cause of BOFF-4805 where the billing client could never be bound\n // after a lazy first construction. Apply it instead.\n defaultInstance.configure(config);\n }\n return defaultInstance;\n}\n\n/**\n * Prime/rebind the process-wide singleton with billing connectivity. Call once\n * during SDK bootstrap. Unlike a bare `getResourceCaps(config)` on a fresh\n * process, this is explicit about the intent to (re)wire and is safe to call\n * after the singleton was already lazily created clientless.\n */\nexport function configureResourceCaps(config: ResourceCapsConfig): ResourceCapsModule {\n const instance = getResourceCaps();\n instance.configure(config);\n return instance;\n}\n\n/** Reset the singleton (for tests) */\nexport function __resetResourceCapsForTests(): void {\n defaultInstance = null;\n}\n"]}
@@ -1,4 +1,4 @@
1
- import { updateInstrumentationConfig, resetMetricsRegistry, resetInstrumentationConfig, isMetricsRegistryInitialized, isInstrumentationConfigInitialized, isFeatureEnabled, initializeMetricsRegistry, initializeInstrumentationConfig, getMetricsRegistry, getInstrumentationConfig, createUpDownCounter, createHistogram, createGauge, createCounter, buildTracingConfig, buildMetricsConfig, buildInstrumentationConfig, buildGraphQLConfig, buildFeatureFlags, buildDatabaseConfig, MetricsRegistry, ENV_VARS, DEFAULT_TRACING_CONFIG, DEFAULT_METRICS_CONFIG, DEFAULT_LOGGING_CONFIG, DEFAULT_HTTP_CONFIG, DEFAULT_GRAPHQL_CONFIG, DEFAULT_FEATURE_FLAGS, DEFAULT_EVENT_QUEUE_CONFIG, DEFAULT_DATABASE_CONFIG, DEFAULT_CACHE_CONFIG } from './chunk-Q6UAOZFZ.js';
1
+ import { updateInstrumentationConfig, resetMetricsRegistry, resetInstrumentationConfig, isMetricsRegistryInitialized, isInstrumentationConfigInitialized, isFeatureEnabled, initializeMetricsRegistry, initializeInstrumentationConfig, getMetricsRegistry, getInstrumentationConfig, createUpDownCounter, createHistogram, createGauge, createCounter, buildTracingConfig, buildMetricsConfig, buildInstrumentationConfig, buildGraphQLConfig, buildFeatureFlags, buildDatabaseConfig, MetricsRegistry, ENV_VARS, DEFAULT_TRACING_CONFIG, DEFAULT_METRICS_CONFIG, DEFAULT_LOGGING_CONFIG, DEFAULT_HTTP_CONFIG, DEFAULT_GRAPHQL_CONFIG, DEFAULT_FEATURE_FLAGS, DEFAULT_EVENT_QUEUE_CONFIG, DEFAULT_DATABASE_CONFIG, DEFAULT_CACHE_CONFIG } from './chunk-AWPNRV3L.js';
2
2
  import { logger } from './chunk-CBZNP6RF.js';
3
3
  import { __export, __name } from './chunk-XE4OXN2W.js';
4
4
  import { createRequire } from 'module';
@@ -1620,5 +1620,5 @@ function setupInstrumentation(serviceName, options) {
1620
1620
  __name(setupInstrumentation, "setupInstrumentation");
1621
1621
 
1622
1622
  export { Instrument, Log, Metric, STANDARD_METRICS, SpanKind, SpanStatus, Trace, Tracer, createApolloInlineTracePlugin, createGraphQLInstrumentationPlugin, createPrometheusPlugin, extractOperationInfo, extractTraceContext, getGraphQLOperationFromContext, getGraphQLSpanFromContext, getLogger, getTraceContext, getTracer, initializeInstrumentation, initializeTracer, injectTraceContext, instrumentResolver, instrumentResolverMap, instrumentation_exports, instrumented, isApolloInlineTraceAvailable, isInstrumentationInitialized, isPrometheusAvailable, isTracerInitialized, resetInstrumentation, setActiveTelemetryLogger, setupInstrumentation, startSpan, traced, withSpan };
1623
- //# sourceMappingURL=chunk-WW6P2S6L.js.map
1624
- //# sourceMappingURL=chunk-WW6P2S6L.js.map
1623
+ //# sourceMappingURL=chunk-Z3O32BW6.js.map
1624
+ //# sourceMappingURL=chunk-Z3O32BW6.js.map