@contractspec/lib.metering 1.46.2 → 1.48.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/aggregation/index.js.map +1 -1
- package/dist/contracts/index.d.ts +14 -14
- package/dist/entities/index.js.map +1 -1
- package/dist/metering.capability.d.ts +8 -0
- package/dist/metering.capability.d.ts.map +1 -0
- package/dist/metering.capability.js +33 -0
- package/dist/metering.capability.js.map +1 -0
- package/dist/metering.feature.d.ts +4 -4
- package/dist/metering.feature.d.ts.map +1 -1
- package/dist/metering.feature.js +11 -4
- package/dist/metering.feature.js.map +1 -1
- package/package.json +7 -8
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["result: AggregationResult","metricKey","total: number","newSummary: UsageSummary"],"sources":["../../src/aggregation/index.ts"],"sourcesContent":["/**\n * Usage aggregation engine.\n *\n * Provides periodic aggregation of usage records into summaries\n * for efficient billing and reporting queries.\n */\n\n// ============ Types ============\n\nexport type PeriodType = 'HOURLY' | 'DAILY' | 'WEEKLY' | 'MONTHLY' | 'YEARLY';\nexport type AggregationType = 'COUNT' | 'SUM' | 'AVG' | 'MAX' | 'MIN' | 'LAST';\n\nexport interface UsageRecord {\n id: string;\n metricKey: string;\n subjectType: string;\n subjectId: string;\n quantity: number;\n timestamp: Date;\n}\n\nexport interface UsageSummary {\n id: string;\n metricKey: string;\n subjectType: string;\n subjectId: string;\n periodType: PeriodType;\n periodStart: Date;\n periodEnd: Date;\n totalQuantity: number;\n recordCount: number;\n minQuantity?: number;\n maxQuantity?: number;\n avgQuantity?: number;\n}\n\nexport interface MetricDefinition {\n key: string;\n aggregationType: AggregationType;\n}\n\nexport interface UsageStorage {\n /**\n * Get unaggregated records for a period.\n */\n getUnaggregatedRecords(options: {\n metricKey?: string;\n periodStart: Date;\n periodEnd: Date;\n limit?: number;\n }): Promise<UsageRecord[]>;\n\n /**\n * Mark records as aggregated.\n */\n markRecordsAggregated(recordIds: string[], aggregatedAt: Date): Promise<void>;\n\n /**\n * Get or create a summary record.\n */\n upsertSummary(summary: Omit<UsageSummary, 'id'>): Promise<UsageSummary>;\n\n /**\n * Get metric definition.\n */\n getMetric(key: string): Promise<MetricDefinition | null>;\n\n /**\n * List all active metrics.\n */\n listMetrics(): Promise<MetricDefinition[]>;\n}\n\nexport interface AggregationOptions {\n /** Storage implementation */\n storage: UsageStorage;\n /** Batch size for processing records */\n batchSize?: number;\n}\n\nexport interface AggregateParams {\n /** Period type to aggregate */\n periodType: PeriodType;\n /** Period start time */\n periodStart: Date;\n /** Period end time (optional, defaults to period boundary) */\n periodEnd?: Date;\n /** Specific metric to aggregate (optional, aggregates all if not specified) */\n metricKey?: string;\n}\n\nexport interface AggregationResult {\n periodType: PeriodType;\n periodStart: Date;\n periodEnd: Date;\n recordsProcessed: number;\n summariesCreated: number;\n summariesUpdated: number;\n errors: AggregationError[];\n}\n\nexport interface AggregationError {\n metricKey: string;\n subjectType: string;\n subjectId: string;\n error: string;\n}\n\n// ============ Period Helpers ============\n\n/**\n * Get the start of a period for a given date.\n */\nexport function getPeriodStart(date: Date, periodType: PeriodType): Date {\n const d = new Date(date);\n\n switch (periodType) {\n case 'HOURLY':\n d.setMinutes(0, 0, 0);\n return d;\n\n case 'DAILY':\n d.setHours(0, 0, 0, 0);\n return d;\n\n case 'WEEKLY': {\n d.setHours(0, 0, 0, 0);\n const day = d.getDay();\n d.setDate(d.getDate() - day);\n return d;\n }\n\n case 'MONTHLY':\n d.setHours(0, 0, 0, 0);\n d.setDate(1);\n return d;\n\n case 'YEARLY':\n d.setHours(0, 0, 0, 0);\n d.setMonth(0, 1);\n return d;\n }\n}\n\n/**\n * Get the end of a period for a given date.\n */\nexport function getPeriodEnd(date: Date, periodType: PeriodType): Date {\n const start = getPeriodStart(date, periodType);\n\n switch (periodType) {\n case 'HOURLY':\n return new Date(start.getTime() + 60 * 60 * 1000);\n\n case 'DAILY':\n return new Date(start.getTime() + 24 * 60 * 60 * 1000);\n\n case 'WEEKLY':\n return new Date(start.getTime() + 7 * 24 * 60 * 60 * 1000);\n\n case 'MONTHLY': {\n const end = new Date(start);\n end.setMonth(end.getMonth() + 1);\n return end;\n }\n\n case 'YEARLY': {\n const end = new Date(start);\n end.setFullYear(end.getFullYear() + 1);\n return end;\n }\n }\n}\n\n/**\n * Format a period key for grouping.\n */\nexport function formatPeriodKey(date: Date, periodType: PeriodType): string {\n const start = getPeriodStart(date, periodType);\n const year = start.getFullYear();\n const month = String(start.getMonth() + 1).padStart(2, '0');\n const day = String(start.getDate()).padStart(2, '0');\n const hour = String(start.getHours()).padStart(2, '0');\n\n switch (periodType) {\n case 'HOURLY':\n return `${year}-${month}-${day}T${hour}`;\n case 'DAILY':\n return `${year}-${month}-${day}`;\n case 'WEEKLY':\n return `${year}-W${getWeekNumber(start)}`;\n case 'MONTHLY':\n return `${year}-${month}`;\n case 'YEARLY':\n return `${year}`;\n }\n}\n\nfunction getWeekNumber(date: Date): string {\n const d = new Date(\n Date.UTC(date.getFullYear(), date.getMonth(), date.getDate())\n );\n const dayNum = d.getUTCDay() || 7;\n d.setUTCDate(d.getUTCDate() + 4 - dayNum);\n const yearStart = new Date(Date.UTC(d.getUTCFullYear(), 0, 1));\n const weekNum = Math.ceil(\n ((d.getTime() - yearStart.getTime()) / 86400000 + 1) / 7\n );\n return String(weekNum).padStart(2, '0');\n}\n\n// ============ Aggregator ============\n\n/**\n * Usage aggregator.\n *\n * Aggregates usage records into summaries based on period type.\n */\nexport class UsageAggregator {\n private storage: UsageStorage;\n private batchSize: number;\n\n constructor(options: AggregationOptions) {\n this.storage = options.storage;\n this.batchSize = options.batchSize || 1000;\n }\n\n /**\n * Aggregate usage records for a period.\n */\n async aggregate(params: AggregateParams): Promise<AggregationResult> {\n const { periodType, periodStart, metricKey } = params;\n const periodEnd = params.periodEnd || getPeriodEnd(periodStart, periodType);\n\n const result: AggregationResult = {\n periodType,\n periodStart,\n periodEnd,\n recordsProcessed: 0,\n summariesCreated: 0,\n summariesUpdated: 0,\n errors: [],\n };\n\n // Get records to aggregate\n const records = await this.storage.getUnaggregatedRecords({\n metricKey,\n periodStart,\n periodEnd,\n limit: this.batchSize,\n });\n\n if (records.length === 0) {\n return result;\n }\n\n // Group records by metric, subject, and period\n const groups = this.groupRecords(records, periodType);\n\n // Process each group\n for (const [groupKey, groupRecords] of groups.entries()) {\n try {\n await this.aggregateGroup(groupKey, groupRecords, periodType, result);\n } catch (error) {\n const [metricKey, subjectType, subjectId] = groupKey.split('::');\n result.errors.push({\n metricKey: metricKey ?? 'unknown',\n subjectType: subjectType ?? 'unknown',\n subjectId: subjectId ?? 'unknown',\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n // Mark records as aggregated\n const recordIds = records.map((r) => r.id);\n await this.storage.markRecordsAggregated(recordIds, new Date());\n result.recordsProcessed = records.length;\n\n return result;\n }\n\n /**\n * Group records by metric, subject, and period.\n */\n private groupRecords(\n records: UsageRecord[],\n periodType: PeriodType\n ): Map<string, UsageRecord[]> {\n const groups = new Map<string, UsageRecord[]>();\n\n for (const record of records) {\n const periodKey = formatPeriodKey(record.timestamp, periodType);\n const groupKey = `${record.metricKey}::${record.subjectType}::${record.subjectId}::${periodKey}`;\n\n const existing = groups.get(groupKey) || [];\n existing.push(record);\n groups.set(groupKey, existing);\n }\n\n return groups;\n }\n\n /**\n * Aggregate a group of records into a summary.\n */\n private async aggregateGroup(\n groupKey: string,\n records: UsageRecord[],\n periodType: PeriodType,\n result: AggregationResult\n ): Promise<void> {\n const [metricKey, subjectType, subjectId] = groupKey.split('::');\n\n if (!metricKey || !subjectType || !subjectId || records.length === 0) {\n return;\n }\n\n const firstRecord = records[0];\n if (!firstRecord) return;\n const periodStart = getPeriodStart(firstRecord.timestamp, periodType);\n const periodEnd = getPeriodEnd(firstRecord.timestamp, periodType);\n\n // Get metric definition for aggregation type\n const metric = await this.storage.getMetric(metricKey);\n const aggregationType = metric?.aggregationType || 'SUM';\n\n // Calculate aggregated values\n const quantities = records.map((r) => r.quantity);\n const aggregated = this.calculateAggregation(quantities, aggregationType);\n\n // Create or update summary\n await this.storage.upsertSummary({\n metricKey,\n subjectType,\n subjectId,\n periodType,\n periodStart,\n periodEnd,\n totalQuantity: aggregated.total,\n recordCount: records.length,\n minQuantity: aggregated.min,\n maxQuantity: aggregated.max,\n avgQuantity: aggregated.avg,\n });\n\n result.summariesCreated++;\n }\n\n /**\n * Calculate aggregation values.\n */\n private calculateAggregation(\n quantities: number[],\n aggregationType: AggregationType\n ): { total: number; min: number; max: number; avg: number } {\n if (quantities.length === 0) {\n return { total: 0, min: 0, max: 0, avg: 0 };\n }\n\n const min = Math.min(...quantities);\n const max = Math.max(...quantities);\n const sum = quantities.reduce((a, b) => a + b, 0);\n const avg = sum / quantities.length;\n const count = quantities.length;\n\n let total: number;\n switch (aggregationType) {\n case 'COUNT':\n total = count;\n break;\n case 'SUM':\n total = sum;\n break;\n case 'AVG':\n total = avg;\n break;\n case 'MAX':\n total = max;\n break;\n case 'MIN':\n total = min;\n break;\n case 'LAST':\n total = quantities[quantities.length - 1] ?? 0;\n break;\n default:\n total = sum;\n }\n\n return { total, min, max, avg };\n }\n}\n\n// ============ In-Memory Storage ============\n\n/**\n * In-memory usage storage for testing.\n */\nexport class InMemoryUsageStorage implements UsageStorage {\n private records: UsageRecord[] = [];\n private summaries = new Map<string, UsageSummary>();\n private metrics = new Map<string, MetricDefinition>();\n\n addRecord(record: UsageRecord): void {\n this.records.push(record);\n }\n\n addMetric(metric: MetricDefinition): void {\n this.metrics.set(metric.key, metric);\n }\n\n async getUnaggregatedRecords(options: {\n metricKey?: string;\n periodStart: Date;\n periodEnd: Date;\n limit?: number;\n }): Promise<UsageRecord[]> {\n let records = this.records.filter((r) => {\n const inPeriod =\n r.timestamp >= options.periodStart && r.timestamp < options.periodEnd;\n const matchesMetric =\n !options.metricKey || r.metricKey === options.metricKey;\n return inPeriod && matchesMetric;\n });\n\n if (options.limit) {\n records = records.slice(0, options.limit);\n }\n\n return records;\n }\n\n async markRecordsAggregated(recordIds: string[]): Promise<void> {\n this.records = this.records.filter((r) => !recordIds.includes(r.id));\n }\n\n async upsertSummary(\n summary: Omit<UsageSummary, 'id'>\n ): Promise<UsageSummary> {\n const key = `${summary.metricKey}::${summary.subjectType}::${summary.subjectId}::${summary.periodType}::${summary.periodStart.toISOString()}`;\n\n const existing = this.summaries.get(key);\n if (existing) {\n // Update existing summary\n existing.totalQuantity += summary.totalQuantity;\n existing.recordCount += summary.recordCount;\n if (summary.minQuantity !== undefined) {\n existing.minQuantity = Math.min(\n existing.minQuantity ?? Infinity,\n summary.minQuantity\n );\n }\n if (summary.maxQuantity !== undefined) {\n existing.maxQuantity = Math.max(\n existing.maxQuantity ?? -Infinity,\n summary.maxQuantity\n );\n }\n return existing;\n }\n\n // Create new summary\n const newSummary: UsageSummary = {\n id: `summary-${Date.now()}-${Math.random().toString(36).slice(2)}`,\n ...summary,\n };\n this.summaries.set(key, newSummary);\n return newSummary;\n }\n\n async getMetric(key: string): Promise<MetricDefinition | null> {\n return this.metrics.get(key) || null;\n }\n\n async listMetrics(): Promise<MetricDefinition[]> {\n return Array.from(this.metrics.values());\n }\n\n getSummaries(): UsageSummary[] {\n return Array.from(this.summaries.values());\n }\n\n clear(): void {\n this.records = [];\n this.summaries.clear();\n this.metrics.clear();\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["metricKey"],"sources":["../../src/aggregation/index.ts"],"sourcesContent":["/**\n * Usage aggregation engine.\n *\n * Provides periodic aggregation of usage records into summaries\n * for efficient billing and reporting queries.\n */\n\n// ============ Types ============\n\nexport type PeriodType = 'HOURLY' | 'DAILY' | 'WEEKLY' | 'MONTHLY' | 'YEARLY';\nexport type AggregationType = 'COUNT' | 'SUM' | 'AVG' | 'MAX' | 'MIN' | 'LAST';\n\nexport interface UsageRecord {\n id: string;\n metricKey: string;\n subjectType: string;\n subjectId: string;\n quantity: number;\n timestamp: Date;\n}\n\nexport interface UsageSummary {\n id: string;\n metricKey: string;\n subjectType: string;\n subjectId: string;\n periodType: PeriodType;\n periodStart: Date;\n periodEnd: Date;\n totalQuantity: number;\n recordCount: number;\n minQuantity?: number;\n maxQuantity?: number;\n avgQuantity?: number;\n}\n\nexport interface MetricDefinition {\n key: string;\n aggregationType: AggregationType;\n}\n\nexport interface UsageStorage {\n /**\n * Get unaggregated records for a period.\n */\n getUnaggregatedRecords(options: {\n metricKey?: string;\n periodStart: Date;\n periodEnd: Date;\n limit?: number;\n }): Promise<UsageRecord[]>;\n\n /**\n * Mark records as aggregated.\n */\n markRecordsAggregated(recordIds: string[], aggregatedAt: Date): Promise<void>;\n\n /**\n * Get or create a summary record.\n */\n upsertSummary(summary: Omit<UsageSummary, 'id'>): Promise<UsageSummary>;\n\n /**\n * Get metric definition.\n */\n getMetric(key: string): Promise<MetricDefinition | null>;\n\n /**\n * List all active metrics.\n */\n listMetrics(): Promise<MetricDefinition[]>;\n}\n\nexport interface AggregationOptions {\n /** Storage implementation */\n storage: UsageStorage;\n /** Batch size for processing records */\n batchSize?: number;\n}\n\nexport interface AggregateParams {\n /** Period type to aggregate */\n periodType: PeriodType;\n /** Period start time */\n periodStart: Date;\n /** Period end time (optional, defaults to period boundary) */\n periodEnd?: Date;\n /** Specific metric to aggregate (optional, aggregates all if not specified) */\n metricKey?: string;\n}\n\nexport interface AggregationResult {\n periodType: PeriodType;\n periodStart: Date;\n periodEnd: Date;\n recordsProcessed: number;\n summariesCreated: number;\n summariesUpdated: number;\n errors: AggregationError[];\n}\n\nexport interface AggregationError {\n metricKey: string;\n subjectType: string;\n subjectId: string;\n error: string;\n}\n\n// ============ Period Helpers ============\n\n/**\n * Get the start of a period for a given date.\n */\nexport function getPeriodStart(date: Date, periodType: PeriodType): Date {\n const d = new Date(date);\n\n switch (periodType) {\n case 'HOURLY':\n d.setMinutes(0, 0, 0);\n return d;\n\n case 'DAILY':\n d.setHours(0, 0, 0, 0);\n return d;\n\n case 'WEEKLY': {\n d.setHours(0, 0, 0, 0);\n const day = d.getDay();\n d.setDate(d.getDate() - day);\n return d;\n }\n\n case 'MONTHLY':\n d.setHours(0, 0, 0, 0);\n d.setDate(1);\n return d;\n\n case 'YEARLY':\n d.setHours(0, 0, 0, 0);\n d.setMonth(0, 1);\n return d;\n }\n}\n\n/**\n * Get the end of a period for a given date.\n */\nexport function getPeriodEnd(date: Date, periodType: PeriodType): Date {\n const start = getPeriodStart(date, periodType);\n\n switch (periodType) {\n case 'HOURLY':\n return new Date(start.getTime() + 60 * 60 * 1000);\n\n case 'DAILY':\n return new Date(start.getTime() + 24 * 60 * 60 * 1000);\n\n case 'WEEKLY':\n return new Date(start.getTime() + 7 * 24 * 60 * 60 * 1000);\n\n case 'MONTHLY': {\n const end = new Date(start);\n end.setMonth(end.getMonth() + 1);\n return end;\n }\n\n case 'YEARLY': {\n const end = new Date(start);\n end.setFullYear(end.getFullYear() + 1);\n return end;\n }\n }\n}\n\n/**\n * Format a period key for grouping.\n */\nexport function formatPeriodKey(date: Date, periodType: PeriodType): string {\n const start = getPeriodStart(date, periodType);\n const year = start.getFullYear();\n const month = String(start.getMonth() + 1).padStart(2, '0');\n const day = String(start.getDate()).padStart(2, '0');\n const hour = String(start.getHours()).padStart(2, '0');\n\n switch (periodType) {\n case 'HOURLY':\n return `${year}-${month}-${day}T${hour}`;\n case 'DAILY':\n return `${year}-${month}-${day}`;\n case 'WEEKLY':\n return `${year}-W${getWeekNumber(start)}`;\n case 'MONTHLY':\n return `${year}-${month}`;\n case 'YEARLY':\n return `${year}`;\n }\n}\n\nfunction getWeekNumber(date: Date): string {\n const d = new Date(\n Date.UTC(date.getFullYear(), date.getMonth(), date.getDate())\n );\n const dayNum = d.getUTCDay() || 7;\n d.setUTCDate(d.getUTCDate() + 4 - dayNum);\n const yearStart = new Date(Date.UTC(d.getUTCFullYear(), 0, 1));\n const weekNum = Math.ceil(\n ((d.getTime() - yearStart.getTime()) / 86400000 + 1) / 7\n );\n return String(weekNum).padStart(2, '0');\n}\n\n// ============ Aggregator ============\n\n/**\n * Usage aggregator.\n *\n * Aggregates usage records into summaries based on period type.\n */\nexport class UsageAggregator {\n private storage: UsageStorage;\n private batchSize: number;\n\n constructor(options: AggregationOptions) {\n this.storage = options.storage;\n this.batchSize = options.batchSize || 1000;\n }\n\n /**\n * Aggregate usage records for a period.\n */\n async aggregate(params: AggregateParams): Promise<AggregationResult> {\n const { periodType, periodStart, metricKey } = params;\n const periodEnd = params.periodEnd || getPeriodEnd(periodStart, periodType);\n\n const result: AggregationResult = {\n periodType,\n periodStart,\n periodEnd,\n recordsProcessed: 0,\n summariesCreated: 0,\n summariesUpdated: 0,\n errors: [],\n };\n\n // Get records to aggregate\n const records = await this.storage.getUnaggregatedRecords({\n metricKey,\n periodStart,\n periodEnd,\n limit: this.batchSize,\n });\n\n if (records.length === 0) {\n return result;\n }\n\n // Group records by metric, subject, and period\n const groups = this.groupRecords(records, periodType);\n\n // Process each group\n for (const [groupKey, groupRecords] of groups.entries()) {\n try {\n await this.aggregateGroup(groupKey, groupRecords, periodType, result);\n } catch (error) {\n const [metricKey, subjectType, subjectId] = groupKey.split('::');\n result.errors.push({\n metricKey: metricKey ?? 'unknown',\n subjectType: subjectType ?? 'unknown',\n subjectId: subjectId ?? 'unknown',\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n // Mark records as aggregated\n const recordIds = records.map((r) => r.id);\n await this.storage.markRecordsAggregated(recordIds, new Date());\n result.recordsProcessed = records.length;\n\n return result;\n }\n\n /**\n * Group records by metric, subject, and period.\n */\n private groupRecords(\n records: UsageRecord[],\n periodType: PeriodType\n ): Map<string, UsageRecord[]> {\n const groups = new Map<string, UsageRecord[]>();\n\n for (const record of records) {\n const periodKey = formatPeriodKey(record.timestamp, periodType);\n const groupKey = `${record.metricKey}::${record.subjectType}::${record.subjectId}::${periodKey}`;\n\n const existing = groups.get(groupKey) || [];\n existing.push(record);\n groups.set(groupKey, existing);\n }\n\n return groups;\n }\n\n /**\n * Aggregate a group of records into a summary.\n */\n private async aggregateGroup(\n groupKey: string,\n records: UsageRecord[],\n periodType: PeriodType,\n result: AggregationResult\n ): Promise<void> {\n const [metricKey, subjectType, subjectId] = groupKey.split('::');\n\n if (!metricKey || !subjectType || !subjectId || records.length === 0) {\n return;\n }\n\n const firstRecord = records[0];\n if (!firstRecord) return;\n const periodStart = getPeriodStart(firstRecord.timestamp, periodType);\n const periodEnd = getPeriodEnd(firstRecord.timestamp, periodType);\n\n // Get metric definition for aggregation type\n const metric = await this.storage.getMetric(metricKey);\n const aggregationType = metric?.aggregationType || 'SUM';\n\n // Calculate aggregated values\n const quantities = records.map((r) => r.quantity);\n const aggregated = this.calculateAggregation(quantities, aggregationType);\n\n // Create or update summary\n await this.storage.upsertSummary({\n metricKey,\n subjectType,\n subjectId,\n periodType,\n periodStart,\n periodEnd,\n totalQuantity: aggregated.total,\n recordCount: records.length,\n minQuantity: aggregated.min,\n maxQuantity: aggregated.max,\n avgQuantity: aggregated.avg,\n });\n\n result.summariesCreated++;\n }\n\n /**\n * Calculate aggregation values.\n */\n private calculateAggregation(\n quantities: number[],\n aggregationType: AggregationType\n ): { total: number; min: number; max: number; avg: number } {\n if (quantities.length === 0) {\n return { total: 0, min: 0, max: 0, avg: 0 };\n }\n\n const min = Math.min(...quantities);\n const max = Math.max(...quantities);\n const sum = quantities.reduce((a, b) => a + b, 0);\n const avg = sum / quantities.length;\n const count = quantities.length;\n\n let total: number;\n switch (aggregationType) {\n case 'COUNT':\n total = count;\n break;\n case 'SUM':\n total = sum;\n break;\n case 'AVG':\n total = avg;\n break;\n case 'MAX':\n total = max;\n break;\n case 'MIN':\n total = min;\n break;\n case 'LAST':\n total = quantities[quantities.length - 1] ?? 0;\n break;\n default:\n total = sum;\n }\n\n return { total, min, max, avg };\n }\n}\n\n// ============ In-Memory Storage ============\n\n/**\n * In-memory usage storage for testing.\n */\nexport class InMemoryUsageStorage implements UsageStorage {\n private records: UsageRecord[] = [];\n private summaries = new Map<string, UsageSummary>();\n private metrics = new Map<string, MetricDefinition>();\n\n addRecord(record: UsageRecord): void {\n this.records.push(record);\n }\n\n addMetric(metric: MetricDefinition): void {\n this.metrics.set(metric.key, metric);\n }\n\n async getUnaggregatedRecords(options: {\n metricKey?: string;\n periodStart: Date;\n periodEnd: Date;\n limit?: number;\n }): Promise<UsageRecord[]> {\n let records = this.records.filter((r) => {\n const inPeriod =\n r.timestamp >= options.periodStart && r.timestamp < options.periodEnd;\n const matchesMetric =\n !options.metricKey || r.metricKey === options.metricKey;\n return inPeriod && matchesMetric;\n });\n\n if (options.limit) {\n records = records.slice(0, options.limit);\n }\n\n return records;\n }\n\n async markRecordsAggregated(recordIds: string[]): Promise<void> {\n this.records = this.records.filter((r) => !recordIds.includes(r.id));\n }\n\n async upsertSummary(\n summary: Omit<UsageSummary, 'id'>\n ): Promise<UsageSummary> {\n const key = `${summary.metricKey}::${summary.subjectType}::${summary.subjectId}::${summary.periodType}::${summary.periodStart.toISOString()}`;\n\n const existing = this.summaries.get(key);\n if (existing) {\n // Update existing summary\n existing.totalQuantity += summary.totalQuantity;\n existing.recordCount += summary.recordCount;\n if (summary.minQuantity !== undefined) {\n existing.minQuantity = Math.min(\n existing.minQuantity ?? Infinity,\n summary.minQuantity\n );\n }\n if (summary.maxQuantity !== undefined) {\n existing.maxQuantity = Math.max(\n existing.maxQuantity ?? -Infinity,\n summary.maxQuantity\n );\n }\n return existing;\n }\n\n // Create new summary\n const newSummary: UsageSummary = {\n id: `summary-${Date.now()}-${Math.random().toString(36).slice(2)}`,\n ...summary,\n };\n this.summaries.set(key, newSummary);\n return newSummary;\n }\n\n async getMetric(key: string): Promise<MetricDefinition | null> {\n return this.metrics.get(key) || null;\n }\n\n async listMetrics(): Promise<MetricDefinition[]> {\n return Array.from(this.metrics.values());\n }\n\n getSummaries(): UsageSummary[] {\n return Array.from(this.summaries.values());\n }\n\n clear(): void {\n this.records = [];\n this.summaries.clear();\n this.metrics.clear();\n }\n}\n"],"mappings":";;;;AAiHA,SAAgB,eAAe,MAAY,YAA8B;CACvE,MAAM,IAAI,IAAI,KAAK,KAAK;AAExB,SAAQ,YAAR;EACE,KAAK;AACH,KAAE,WAAW,GAAG,GAAG,EAAE;AACrB,UAAO;EAET,KAAK;AACH,KAAE,SAAS,GAAG,GAAG,GAAG,EAAE;AACtB,UAAO;EAET,KAAK,UAAU;AACb,KAAE,SAAS,GAAG,GAAG,GAAG,EAAE;GACtB,MAAM,MAAM,EAAE,QAAQ;AACtB,KAAE,QAAQ,EAAE,SAAS,GAAG,IAAI;AAC5B,UAAO;;EAGT,KAAK;AACH,KAAE,SAAS,GAAG,GAAG,GAAG,EAAE;AACtB,KAAE,QAAQ,EAAE;AACZ,UAAO;EAET,KAAK;AACH,KAAE,SAAS,GAAG,GAAG,GAAG,EAAE;AACtB,KAAE,SAAS,GAAG,EAAE;AAChB,UAAO;;;;;;AAOb,SAAgB,aAAa,MAAY,YAA8B;CACrE,MAAM,QAAQ,eAAe,MAAM,WAAW;AAE9C,SAAQ,YAAR;EACE,KAAK,SACH,QAAO,IAAI,KAAK,MAAM,SAAS,GAAG,OAAU,IAAK;EAEnD,KAAK,QACH,QAAO,IAAI,KAAK,MAAM,SAAS,GAAG,OAAU,KAAK,IAAK;EAExD,KAAK,SACH,QAAO,IAAI,KAAK,MAAM,SAAS,GAAG,QAAc,KAAK,IAAK;EAE5D,KAAK,WAAW;GACd,MAAM,MAAM,IAAI,KAAK,MAAM;AAC3B,OAAI,SAAS,IAAI,UAAU,GAAG,EAAE;AAChC,UAAO;;EAGT,KAAK,UAAU;GACb,MAAM,MAAM,IAAI,KAAK,MAAM;AAC3B,OAAI,YAAY,IAAI,aAAa,GAAG,EAAE;AACtC,UAAO;;;;;;;AAQb,SAAgB,gBAAgB,MAAY,YAAgC;CAC1E,MAAM,QAAQ,eAAe,MAAM,WAAW;CAC9C,MAAM,OAAO,MAAM,aAAa;CAChC,MAAM,QAAQ,OAAO,MAAM,UAAU,GAAG,EAAE,CAAC,SAAS,GAAG,IAAI;CAC3D,MAAM,MAAM,OAAO,MAAM,SAAS,CAAC,CAAC,SAAS,GAAG,IAAI;CACpD,MAAM,OAAO,OAAO,MAAM,UAAU,CAAC,CAAC,SAAS,GAAG,IAAI;AAEtD,SAAQ,YAAR;EACE,KAAK,SACH,QAAO,GAAG,KAAK,GAAG,MAAM,GAAG,IAAI,GAAG;EACpC,KAAK,QACH,QAAO,GAAG,KAAK,GAAG,MAAM,GAAG;EAC7B,KAAK,SACH,QAAO,GAAG,KAAK,IAAI,cAAc,MAAM;EACzC,KAAK,UACH,QAAO,GAAG,KAAK,GAAG;EACpB,KAAK,SACH,QAAO,GAAG;;;AAIhB,SAAS,cAAc,MAAoB;CACzC,MAAM,IAAI,IAAI,KACZ,KAAK,IAAI,KAAK,aAAa,EAAE,KAAK,UAAU,EAAE,KAAK,SAAS,CAAC,CAC9D;CACD,MAAM,SAAS,EAAE,WAAW,IAAI;AAChC,GAAE,WAAW,EAAE,YAAY,GAAG,IAAI,OAAO;CACzC,MAAM,YAAY,IAAI,KAAK,KAAK,IAAI,EAAE,gBAAgB,EAAE,GAAG,EAAE,CAAC;CAC9D,MAAM,UAAU,KAAK,OACjB,EAAE,SAAS,GAAG,UAAU,SAAS,IAAI,QAAW,KAAK,EACxD;AACD,QAAO,OAAO,QAAQ,CAAC,SAAS,GAAG,IAAI;;;;;;;AAUzC,IAAa,kBAAb,MAA6B;CAC3B,AAAQ;CACR,AAAQ;CAER,YAAY,SAA6B;AACvC,OAAK,UAAU,QAAQ;AACvB,OAAK,YAAY,QAAQ,aAAa;;;;;CAMxC,MAAM,UAAU,QAAqD;EACnE,MAAM,EAAE,YAAY,aAAa,cAAc;EAC/C,MAAM,YAAY,OAAO,aAAa,aAAa,aAAa,WAAW;EAE3E,MAAM,SAA4B;GAChC;GACA;GACA;GACA,kBAAkB;GAClB,kBAAkB;GAClB,kBAAkB;GAClB,QAAQ,EAAE;GACX;EAGD,MAAM,UAAU,MAAM,KAAK,QAAQ,uBAAuB;GACxD;GACA;GACA;GACA,OAAO,KAAK;GACb,CAAC;AAEF,MAAI,QAAQ,WAAW,EACrB,QAAO;EAIT,MAAM,SAAS,KAAK,aAAa,SAAS,WAAW;AAGrD,OAAK,MAAM,CAAC,UAAU,iBAAiB,OAAO,SAAS,CACrD,KAAI;AACF,SAAM,KAAK,eAAe,UAAU,cAAc,YAAY,OAAO;WAC9D,OAAO;GACd,MAAM,CAACA,aAAW,aAAa,aAAa,SAAS,MAAM,KAAK;AAChE,UAAO,OAAO,KAAK;IACjB,WAAWA,eAAa;IACxB,aAAa,eAAe;IAC5B,WAAW,aAAa;IACxB,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;IAC9D,CAAC;;EAKN,MAAM,YAAY,QAAQ,KAAK,MAAM,EAAE,GAAG;AAC1C,QAAM,KAAK,QAAQ,sBAAsB,2BAAW,IAAI,MAAM,CAAC;AAC/D,SAAO,mBAAmB,QAAQ;AAElC,SAAO;;;;;CAMT,AAAQ,aACN,SACA,YAC4B;EAC5B,MAAM,yBAAS,IAAI,KAA4B;AAE/C,OAAK,MAAM,UAAU,SAAS;GAC5B,MAAM,YAAY,gBAAgB,OAAO,WAAW,WAAW;GAC/D,MAAM,WAAW,GAAG,OAAO,UAAU,IAAI,OAAO,YAAY,IAAI,OAAO,UAAU,IAAI;GAErF,MAAM,WAAW,OAAO,IAAI,SAAS,IAAI,EAAE;AAC3C,YAAS,KAAK,OAAO;AACrB,UAAO,IAAI,UAAU,SAAS;;AAGhC,SAAO;;;;;CAMT,MAAc,eACZ,UACA,SACA,YACA,QACe;EACf,MAAM,CAAC,WAAW,aAAa,aAAa,SAAS,MAAM,KAAK;AAEhE,MAAI,CAAC,aAAa,CAAC,eAAe,CAAC,aAAa,QAAQ,WAAW,EACjE;EAGF,MAAM,cAAc,QAAQ;AAC5B,MAAI,CAAC,YAAa;EAClB,MAAM,cAAc,eAAe,YAAY,WAAW,WAAW;EACrE,MAAM,YAAY,aAAa,YAAY,WAAW,WAAW;EAIjE,MAAM,mBADS,MAAM,KAAK,QAAQ,UAAU,UAAU,GACtB,mBAAmB;EAGnD,MAAM,aAAa,QAAQ,KAAK,MAAM,EAAE,SAAS;EACjD,MAAM,aAAa,KAAK,qBAAqB,YAAY,gBAAgB;AAGzE,QAAM,KAAK,QAAQ,cAAc;GAC/B;GACA;GACA;GACA;GACA;GACA;GACA,eAAe,WAAW;GAC1B,aAAa,QAAQ;GACrB,aAAa,WAAW;GACxB,aAAa,WAAW;GACxB,aAAa,WAAW;GACzB,CAAC;AAEF,SAAO;;;;;CAMT,AAAQ,qBACN,YACA,iBAC0D;AAC1D,MAAI,WAAW,WAAW,EACxB,QAAO;GAAE,OAAO;GAAG,KAAK;GAAG,KAAK;GAAG,KAAK;GAAG;EAG7C,MAAM,MAAM,KAAK,IAAI,GAAG,WAAW;EACnC,MAAM,MAAM,KAAK,IAAI,GAAG,WAAW;EACnC,MAAM,MAAM,WAAW,QAAQ,GAAG,MAAM,IAAI,GAAG,EAAE;EACjD,MAAM,MAAM,MAAM,WAAW;EAC7B,MAAM,QAAQ,WAAW;EAEzB,IAAI;AACJ,UAAQ,iBAAR;GACE,KAAK;AACH,YAAQ;AACR;GACF,KAAK;AACH,YAAQ;AACR;GACF,KAAK;AACH,YAAQ;AACR;GACF,KAAK;AACH,YAAQ;AACR;GACF,KAAK;AACH,YAAQ;AACR;GACF,KAAK;AACH,YAAQ,WAAW,WAAW,SAAS,MAAM;AAC7C;GACF,QACE,SAAQ;;AAGZ,SAAO;GAAE;GAAO;GAAK;GAAK;GAAK;;;;;;AASnC,IAAa,uBAAb,MAA0D;CACxD,AAAQ,UAAyB,EAAE;CACnC,AAAQ,4BAAY,IAAI,KAA2B;CACnD,AAAQ,0BAAU,IAAI,KAA+B;CAErD,UAAU,QAA2B;AACnC,OAAK,QAAQ,KAAK,OAAO;;CAG3B,UAAU,QAAgC;AACxC,OAAK,QAAQ,IAAI,OAAO,KAAK,OAAO;;CAGtC,MAAM,uBAAuB,SAKF;EACzB,IAAI,UAAU,KAAK,QAAQ,QAAQ,MAAM;GACvC,MAAM,WACJ,EAAE,aAAa,QAAQ,eAAe,EAAE,YAAY,QAAQ;GAC9D,MAAM,gBACJ,CAAC,QAAQ,aAAa,EAAE,cAAc,QAAQ;AAChD,UAAO,YAAY;IACnB;AAEF,MAAI,QAAQ,MACV,WAAU,QAAQ,MAAM,GAAG,QAAQ,MAAM;AAG3C,SAAO;;CAGT,MAAM,sBAAsB,WAAoC;AAC9D,OAAK,UAAU,KAAK,QAAQ,QAAQ,MAAM,CAAC,UAAU,SAAS,EAAE,GAAG,CAAC;;CAGtE,MAAM,cACJ,SACuB;EACvB,MAAM,MAAM,GAAG,QAAQ,UAAU,IAAI,QAAQ,YAAY,IAAI,QAAQ,UAAU,IAAI,QAAQ,WAAW,IAAI,QAAQ,YAAY,aAAa;EAE3I,MAAM,WAAW,KAAK,UAAU,IAAI,IAAI;AACxC,MAAI,UAAU;AAEZ,YAAS,iBAAiB,QAAQ;AAClC,YAAS,eAAe,QAAQ;AAChC,OAAI,QAAQ,gBAAgB,OAC1B,UAAS,cAAc,KAAK,IAC1B,SAAS,eAAe,UACxB,QAAQ,YACT;AAEH,OAAI,QAAQ,gBAAgB,OAC1B,UAAS,cAAc,KAAK,IAC1B,SAAS,eAAe,WACxB,QAAQ,YACT;AAEH,UAAO;;EAIT,MAAM,aAA2B;GAC/B,IAAI,WAAW,KAAK,KAAK,CAAC,GAAG,KAAK,QAAQ,CAAC,SAAS,GAAG,CAAC,MAAM,EAAE;GAChE,GAAG;GACJ;AACD,OAAK,UAAU,IAAI,KAAK,WAAW;AACnC,SAAO;;CAGT,MAAM,UAAU,KAA+C;AAC7D,SAAO,KAAK,QAAQ,IAAI,IAAI,IAAI;;CAGlC,MAAM,cAA2C;AAC/C,SAAO,MAAM,KAAK,KAAK,QAAQ,QAAQ,CAAC;;CAG1C,eAA+B;AAC7B,SAAO,MAAM,KAAK,KAAK,UAAU,QAAQ,CAAC;;CAG5C,QAAc;AACZ,OAAK,UAAU,EAAE;AACjB,OAAK,UAAU,OAAO;AACtB,OAAK,QAAQ,OAAO"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as _contractspec_lib_schema317 from "@contractspec/lib.schema";
|
|
2
|
-
import * as
|
|
2
|
+
import * as _contractspec_lib_contracts18 from "@contractspec/lib.contracts";
|
|
3
3
|
|
|
4
4
|
//#region src/contracts/index.d.ts
|
|
5
5
|
declare const MetricDefinitionModel: _contractspec_lib_schema317.SchemaModel<{
|
|
@@ -201,7 +201,7 @@ declare const UsageThresholdModel: _contractspec_lib_schema317.SchemaModel<{
|
|
|
201
201
|
/**
|
|
202
202
|
* Define a metric.
|
|
203
203
|
*/
|
|
204
|
-
declare const DefineMetricContract:
|
|
204
|
+
declare const DefineMetricContract: _contractspec_lib_contracts18.OperationSpec<_contractspec_lib_schema317.SchemaModel<{
|
|
205
205
|
key: {
|
|
206
206
|
type: _contractspec_lib_schema317.FieldType<string, string>;
|
|
207
207
|
isOptional: false;
|
|
@@ -291,7 +291,7 @@ declare const DefineMetricContract: _contractspec_lib_contracts15.OperationSpec<
|
|
|
291
291
|
/**
|
|
292
292
|
* Update a metric.
|
|
293
293
|
*/
|
|
294
|
-
declare const UpdateMetricContract:
|
|
294
|
+
declare const UpdateMetricContract: _contractspec_lib_contracts18.OperationSpec<_contractspec_lib_schema317.SchemaModel<{
|
|
295
295
|
metricId: {
|
|
296
296
|
type: _contractspec_lib_schema317.FieldType<string, string>;
|
|
297
297
|
isOptional: false;
|
|
@@ -369,7 +369,7 @@ declare const UpdateMetricContract: _contractspec_lib_contracts15.OperationSpec<
|
|
|
369
369
|
/**
|
|
370
370
|
* Delete a metric.
|
|
371
371
|
*/
|
|
372
|
-
declare const DeleteMetricContract:
|
|
372
|
+
declare const DeleteMetricContract: _contractspec_lib_contracts18.OperationSpec<_contractspec_lib_schema317.SchemaModel<{
|
|
373
373
|
metricId: {
|
|
374
374
|
type: _contractspec_lib_schema317.FieldType<string, string>;
|
|
375
375
|
isOptional: false;
|
|
@@ -383,7 +383,7 @@ declare const DeleteMetricContract: _contractspec_lib_contracts15.OperationSpec<
|
|
|
383
383
|
/**
|
|
384
384
|
* Get a metric by key.
|
|
385
385
|
*/
|
|
386
|
-
declare const GetMetricContract:
|
|
386
|
+
declare const GetMetricContract: _contractspec_lib_contracts18.OperationSpec<_contractspec_lib_schema317.SchemaModel<{
|
|
387
387
|
key: {
|
|
388
388
|
type: _contractspec_lib_schema317.FieldType<string, string>;
|
|
389
389
|
isOptional: false;
|
|
@@ -445,7 +445,7 @@ declare const GetMetricContract: _contractspec_lib_contracts15.OperationSpec<_co
|
|
|
445
445
|
/**
|
|
446
446
|
* List metrics.
|
|
447
447
|
*/
|
|
448
|
-
declare const ListMetricsContract:
|
|
448
|
+
declare const ListMetricsContract: _contractspec_lib_contracts18.OperationSpec<_contractspec_lib_schema317.SchemaModel<{
|
|
449
449
|
orgId: {
|
|
450
450
|
type: _contractspec_lib_schema317.FieldType<string, string>;
|
|
451
451
|
isOptional: true;
|
|
@@ -529,7 +529,7 @@ declare const ListMetricsContract: _contractspec_lib_contracts15.OperationSpec<_
|
|
|
529
529
|
/**
|
|
530
530
|
* Record usage.
|
|
531
531
|
*/
|
|
532
|
-
declare const RecordUsageContract:
|
|
532
|
+
declare const RecordUsageContract: _contractspec_lib_contracts18.OperationSpec<_contractspec_lib_schema317.SchemaModel<{
|
|
533
533
|
metricKey: {
|
|
534
534
|
type: _contractspec_lib_schema317.FieldType<string, string>;
|
|
535
535
|
isOptional: false;
|
|
@@ -619,7 +619,7 @@ declare const RecordUsageContract: _contractspec_lib_contracts15.OperationSpec<_
|
|
|
619
619
|
/**
|
|
620
620
|
* Record batch usage.
|
|
621
621
|
*/
|
|
622
|
-
declare const RecordBatchUsageContract:
|
|
622
|
+
declare const RecordBatchUsageContract: _contractspec_lib_contracts18.OperationSpec<_contractspec_lib_schema317.SchemaModel<{
|
|
623
623
|
records: {
|
|
624
624
|
type: _contractspec_lib_schema317.SchemaModel<{
|
|
625
625
|
metricKey: {
|
|
@@ -683,7 +683,7 @@ declare const RecordBatchUsageContract: _contractspec_lib_contracts15.OperationS
|
|
|
683
683
|
/**
|
|
684
684
|
* Get usage records.
|
|
685
685
|
*/
|
|
686
|
-
declare const GetUsageContract:
|
|
686
|
+
declare const GetUsageContract: _contractspec_lib_contracts18.OperationSpec<_contractspec_lib_schema317.SchemaModel<{
|
|
687
687
|
metricKey: {
|
|
688
688
|
type: _contractspec_lib_schema317.FieldType<string, string>;
|
|
689
689
|
isOptional: false;
|
|
@@ -775,7 +775,7 @@ declare const GetUsageContract: _contractspec_lib_contracts15.OperationSpec<_con
|
|
|
775
775
|
/**
|
|
776
776
|
* Get usage summary.
|
|
777
777
|
*/
|
|
778
|
-
declare const GetUsageSummaryContract:
|
|
778
|
+
declare const GetUsageSummaryContract: _contractspec_lib_contracts18.OperationSpec<_contractspec_lib_schema317.SchemaModel<{
|
|
779
779
|
metricKey: {
|
|
780
780
|
type: _contractspec_lib_schema317.FieldType<string, string>;
|
|
781
781
|
isOptional: false;
|
|
@@ -863,7 +863,7 @@ declare const GetUsageSummaryContract: _contractspec_lib_contracts15.OperationSp
|
|
|
863
863
|
/**
|
|
864
864
|
* Create a threshold.
|
|
865
865
|
*/
|
|
866
|
-
declare const CreateThresholdContract:
|
|
866
|
+
declare const CreateThresholdContract: _contractspec_lib_contracts18.OperationSpec<_contractspec_lib_schema317.SchemaModel<{
|
|
867
867
|
metricKey: {
|
|
868
868
|
type: _contractspec_lib_schema317.FieldType<string, string>;
|
|
869
869
|
isOptional: false;
|
|
@@ -957,7 +957,7 @@ declare const CreateThresholdContract: _contractspec_lib_contracts15.OperationSp
|
|
|
957
957
|
/**
|
|
958
958
|
* Update a threshold.
|
|
959
959
|
*/
|
|
960
|
-
declare const UpdateThresholdContract:
|
|
960
|
+
declare const UpdateThresholdContract: _contractspec_lib_contracts18.OperationSpec<_contractspec_lib_schema317.SchemaModel<{
|
|
961
961
|
thresholdId: {
|
|
962
962
|
type: _contractspec_lib_schema317.FieldType<string, string>;
|
|
963
963
|
isOptional: false;
|
|
@@ -1043,7 +1043,7 @@ declare const UpdateThresholdContract: _contractspec_lib_contracts15.OperationSp
|
|
|
1043
1043
|
/**
|
|
1044
1044
|
* Delete a threshold.
|
|
1045
1045
|
*/
|
|
1046
|
-
declare const DeleteThresholdContract:
|
|
1046
|
+
declare const DeleteThresholdContract: _contractspec_lib_contracts18.OperationSpec<_contractspec_lib_schema317.SchemaModel<{
|
|
1047
1047
|
thresholdId: {
|
|
1048
1048
|
type: _contractspec_lib_schema317.FieldType<string, string>;
|
|
1049
1049
|
isOptional: false;
|
|
@@ -1057,7 +1057,7 @@ declare const DeleteThresholdContract: _contractspec_lib_contracts15.OperationSp
|
|
|
1057
1057
|
/**
|
|
1058
1058
|
* List thresholds.
|
|
1059
1059
|
*/
|
|
1060
|
-
declare const ListThresholdsContract:
|
|
1060
|
+
declare const ListThresholdsContract: _contractspec_lib_contracts18.OperationSpec<_contractspec_lib_schema317.SchemaModel<{
|
|
1061
1061
|
metricKey: {
|
|
1062
1062
|
type: _contractspec_lib_schema317.FieldType<string, string>;
|
|
1063
1063
|
isOptional: true;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["meteringSchemaContribution: ModuleSchemaContribution"],"sources":["../../src/entities/index.ts"],"sourcesContent":["import {\n defineEntity,\n defineEntityEnum,\n field,\n index,\n} from '@contractspec/lib.schema';\nimport type { ModuleSchemaContribution } from '@contractspec/lib.schema';\n\n/**\n * Aggregation type enum.\n */\nexport const AggregationTypeEnum = defineEntityEnum({\n name: 'AggregationType',\n values: ['COUNT', 'SUM', 'AVG', 'MAX', 'MIN', 'LAST'] as const,\n schema: 'lssm_metering',\n description: 'How to aggregate metric values.',\n});\n\n/**\n * Reset period enum.\n */\nexport const ResetPeriodEnum = defineEntityEnum({\n name: 'ResetPeriod',\n values: ['NEVER', 'HOURLY', 'DAILY', 'WEEKLY', 'MONTHLY', 'YEARLY'] as const,\n schema: 'lssm_metering',\n description: 'When to reset metric counters.',\n});\n\n/**\n * Period type enum.\n */\nexport const PeriodTypeEnum = defineEntityEnum({\n name: 'PeriodType',\n values: ['HOURLY', 'DAILY', 'WEEKLY', 'MONTHLY', 'YEARLY'] as const,\n schema: 'lssm_metering',\n description: 'Time period for aggregation.',\n});\n\n/**\n * Threshold action enum.\n */\nexport const ThresholdActionEnum = defineEntityEnum({\n name: 'ThresholdAction',\n values: ['NONE', 'ALERT', 'WARN', 'BLOCK', 'DOWNGRADE'] as const,\n schema: 'lssm_metering',\n description: 'Action to take when threshold is exceeded.',\n});\n\n/**\n * MetricDefinition entity - defines a trackable metric.\n */\nexport const MetricDefinitionEntity = defineEntity({\n name: 'MetricDefinition',\n description: 'Definition of a usage metric.',\n schema: 'lssm_metering',\n map: 'metric_definition',\n fields: {\n id: field.id({ description: 'Unique identifier' }),\n key: field.string({\n isUnique: true,\n description: 'Metric key (e.g., api_calls, storage_gb)',\n }),\n name: field.string({ description: 'Human-readable name' }),\n description: field.string({\n isOptional: true,\n description: 'Metric description',\n }),\n\n // Configuration\n unit: field.string({\n description: 'Unit of measurement (calls, bytes, etc.)',\n }),\n aggregationType: field.enum('AggregationType', {\n default: 'SUM',\n description: 'How to aggregate values',\n }),\n resetPeriod: field.enum('ResetPeriod', {\n default: 'MONTHLY',\n description: 'When to reset counters',\n }),\n\n // Precision\n precision: field.int({ default: 2, description: 'Decimal precision' }),\n\n // Scope\n orgId: field.string({\n isOptional: true,\n description: 'Organization scope (null = global metric)',\n }),\n\n // Display\n category: field.string({\n isOptional: true,\n description: 'Category for grouping',\n }),\n displayOrder: field.int({ default: 0, description: 'Order for display' }),\n\n // Metadata\n metadata: field.json({\n isOptional: true,\n description: 'Additional metadata',\n }),\n\n // Status\n isActive: field.boolean({\n default: true,\n description: 'Whether metric is active',\n }),\n\n // Timestamps\n createdAt: field.createdAt(),\n updatedAt: field.updatedAt(),\n\n // Relations\n usageRecords: field.hasMany('UsageRecord'),\n usageSummaries: field.hasMany('UsageSummary'),\n thresholds: field.hasMany('UsageThreshold'),\n },\n indexes: [\n index.on(['orgId', 'key']),\n index.on(['category']),\n index.on(['isActive']),\n ],\n enums: [AggregationTypeEnum, ResetPeriodEnum],\n});\n\n/**\n * UsageRecord entity - individual usage event.\n */\nexport const UsageRecordEntity = defineEntity({\n name: 'UsageRecord',\n description: 'A single usage event.',\n schema: 'lssm_metering',\n map: 'usage_record',\n fields: {\n id: field.id({ description: 'Unique identifier' }),\n\n // Metric reference\n metricKey: field.string({ description: 'Metric being recorded' }),\n metricId: field.string({\n isOptional: true,\n description: 'Metric ID (for FK)',\n }),\n\n // Subject\n subjectType: field.string({\n description: 'Subject type (org, user, project)',\n }),\n subjectId: field.string({ description: 'Subject identifier' }),\n\n // Usage value\n quantity: field.decimal({ description: 'Usage quantity' }),\n\n // Context\n source: field.string({\n isOptional: true,\n description: 'Source of usage (endpoint, feature, etc.)',\n }),\n resourceId: field.string({\n isOptional: true,\n description: 'Related resource ID',\n }),\n resourceType: field.string({\n isOptional: true,\n description: 'Related resource type',\n }),\n\n // Metadata\n metadata: field.json({\n isOptional: true,\n description: 'Additional context',\n }),\n\n // Idempotency\n idempotencyKey: field.string({\n isOptional: true,\n description: 'Idempotency key for deduplication',\n }),\n\n // Timestamps\n timestamp: field.dateTime({ description: 'When usage occurred' }),\n createdAt: field.createdAt(),\n\n // Aggregation status\n aggregated: field.boolean({\n default: false,\n description: 'Whether included in summary',\n }),\n aggregatedAt: field.dateTime({\n isOptional: true,\n description: 'When aggregated',\n }),\n },\n indexes: [\n index.on(['metricKey', 'subjectType', 'subjectId', 'timestamp']),\n index.on(['subjectType', 'subjectId', 'timestamp']),\n index.on(['timestamp']),\n index.on(['aggregated', 'timestamp']),\n index.unique(['idempotencyKey'], { name: 'usage_record_idempotency' }),\n ],\n});\n\n/**\n * UsageSummary entity - pre-aggregated usage.\n */\nexport const UsageSummaryEntity = defineEntity({\n name: 'UsageSummary',\n description: 'Pre-aggregated usage summary.',\n schema: 'lssm_metering',\n map: 'usage_summary',\n fields: {\n id: field.id({ description: 'Unique identifier' }),\n\n // Metric reference\n metricKey: field.string({ description: 'Metric key' }),\n metricId: field.string({\n isOptional: true,\n description: 'Metric ID (for FK)',\n }),\n\n // Subject\n subjectType: field.string({ description: 'Subject type' }),\n subjectId: field.string({ description: 'Subject identifier' }),\n\n // Period\n periodType: field.enum('PeriodType', { description: 'Period type' }),\n periodStart: field.dateTime({ description: 'Period start time' }),\n periodEnd: field.dateTime({ description: 'Period end time' }),\n\n // Aggregated values\n totalQuantity: field.decimal({ description: 'Total/aggregated quantity' }),\n recordCount: field.int({\n default: 0,\n description: 'Number of records aggregated',\n }),\n\n // Statistics (for AVG, MIN, MAX)\n minQuantity: field.decimal({\n isOptional: true,\n description: 'Minimum value',\n }),\n maxQuantity: field.decimal({\n isOptional: true,\n description: 'Maximum value',\n }),\n avgQuantity: field.decimal({\n isOptional: true,\n description: 'Average value',\n }),\n\n // Metadata\n metadata: field.json({\n isOptional: true,\n description: 'Additional metadata',\n }),\n\n // Timestamps\n createdAt: field.createdAt(),\n updatedAt: field.updatedAt(),\n },\n indexes: [\n index.unique(\n ['metricKey', 'subjectType', 'subjectId', 'periodType', 'periodStart'],\n { name: 'usage_summary_unique' }\n ),\n index.on(['subjectType', 'subjectId', 'periodType', 'periodStart']),\n index.on(['metricKey', 'periodType', 'periodStart']),\n ],\n enums: [PeriodTypeEnum],\n});\n\n/**\n * UsageThreshold entity - threshold configuration.\n */\nexport const UsageThresholdEntity = defineEntity({\n name: 'UsageThreshold',\n description: 'Usage threshold configuration.',\n schema: 'lssm_metering',\n map: 'usage_threshold',\n fields: {\n id: field.id({ description: 'Unique identifier' }),\n\n // Metric reference\n metricKey: field.string({ description: 'Metric to monitor' }),\n metricId: field.string({\n isOptional: true,\n description: 'Metric ID (for FK)',\n }),\n\n // Subject (optional - can be global)\n subjectType: field.string({\n isOptional: true,\n description: 'Subject type',\n }),\n subjectId: field.string({\n isOptional: true,\n description: 'Subject identifier',\n }),\n\n // Threshold configuration\n name: field.string({ description: 'Threshold name' }),\n threshold: field.decimal({ description: 'Threshold value' }),\n warnThreshold: field.decimal({\n isOptional: true,\n description: 'Warning threshold (e.g., 80%)',\n }),\n\n // Period\n periodType: field.enum('PeriodType', {\n default: 'MONTHLY',\n description: 'Period to evaluate',\n }),\n\n // Actions\n action: field.enum('ThresholdAction', {\n default: 'ALERT',\n description: 'Action when exceeded',\n }),\n notifyEmails: field.json({\n isOptional: true,\n description: 'Email addresses to notify',\n }),\n notifyWebhook: field.string({\n isOptional: true,\n description: 'Webhook URL to call',\n }),\n\n // Status tracking\n currentValue: field.decimal({\n default: 0,\n description: 'Current usage value',\n }),\n lastCheckedAt: field.dateTime({\n isOptional: true,\n description: 'Last threshold check',\n }),\n lastExceededAt: field.dateTime({\n isOptional: true,\n description: 'Last time threshold was exceeded',\n }),\n\n // Status\n isActive: field.boolean({\n default: true,\n description: 'Whether threshold is active',\n }),\n\n // Metadata\n metadata: field.json({\n isOptional: true,\n description: 'Additional metadata',\n }),\n\n // Timestamps\n createdAt: field.createdAt(),\n updatedAt: field.updatedAt(),\n },\n indexes: [\n index.on(['metricKey']),\n index.on(['subjectType', 'subjectId']),\n index.on(['isActive', 'metricKey']),\n ],\n enums: [ThresholdActionEnum],\n});\n\n/**\n * UsageAlert entity - threshold violation alerts.\n */\nexport const UsageAlertEntity = defineEntity({\n name: 'UsageAlert',\n description: 'Alert generated when threshold is exceeded.',\n schema: 'lssm_metering',\n map: 'usage_alert',\n fields: {\n id: field.id({ description: 'Unique identifier' }),\n\n // Threshold reference\n thresholdId: field.foreignKey({\n description: 'Threshold that triggered alert',\n }),\n\n // Context\n metricKey: field.string({ description: 'Metric key' }),\n subjectType: field.string({\n isOptional: true,\n description: 'Subject type',\n }),\n subjectId: field.string({\n isOptional: true,\n description: 'Subject identifier',\n }),\n\n // Alert details\n alertType: field.string({ description: 'Alert type (warn, exceed, etc.)' }),\n threshold: field.decimal({ description: 'Threshold value' }),\n actualValue: field.decimal({ description: 'Actual usage value' }),\n percentageUsed: field.decimal({\n description: 'Percentage of threshold used',\n }),\n\n // Status\n status: field.string({\n default: '\"pending\"',\n description: 'Alert status (pending, acknowledged, resolved)',\n }),\n acknowledgedBy: field.string({\n isOptional: true,\n description: 'User who acknowledged',\n }),\n acknowledgedAt: field.dateTime({\n isOptional: true,\n description: 'When acknowledged',\n }),\n resolvedAt: field.dateTime({\n isOptional: true,\n description: 'When resolved',\n }),\n\n // Notifications\n notificationsSent: field.json({\n isOptional: true,\n description: 'Notifications sent',\n }),\n\n // Timestamps\n triggeredAt: field.dateTime({ description: 'When alert was triggered' }),\n createdAt: field.createdAt(),\n\n // Relations\n thresholdRelation: field.belongsTo(\n 'UsageThreshold',\n ['thresholdId'],\n ['id'],\n { onDelete: 'Cascade' }\n ),\n },\n indexes: [\n index.on(['thresholdId', 'status']),\n index.on(['metricKey', 'triggeredAt']),\n index.on(['status', 'triggeredAt']),\n ],\n});\n\n/**\n * All metering entities for schema composition.\n */\nexport const meteringEntities = [\n MetricDefinitionEntity,\n UsageRecordEntity,\n UsageSummaryEntity,\n UsageThresholdEntity,\n UsageAlertEntity,\n];\n\n/**\n * Module schema contribution for metering.\n */\nexport const meteringSchemaContribution: ModuleSchemaContribution = {\n moduleId: '@contractspec/lib.metering',\n entities: meteringEntities,\n enums: [\n AggregationTypeEnum,\n ResetPeriodEnum,\n PeriodTypeEnum,\n ThresholdActionEnum,\n ],\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../src/entities/index.ts"],"sourcesContent":["import {\n defineEntity,\n defineEntityEnum,\n field,\n index,\n} from '@contractspec/lib.schema';\nimport type { ModuleSchemaContribution } from '@contractspec/lib.schema';\n\n/**\n * Aggregation type enum.\n */\nexport const AggregationTypeEnum = defineEntityEnum({\n name: 'AggregationType',\n values: ['COUNT', 'SUM', 'AVG', 'MAX', 'MIN', 'LAST'] as const,\n schema: 'lssm_metering',\n description: 'How to aggregate metric values.',\n});\n\n/**\n * Reset period enum.\n */\nexport const ResetPeriodEnum = defineEntityEnum({\n name: 'ResetPeriod',\n values: ['NEVER', 'HOURLY', 'DAILY', 'WEEKLY', 'MONTHLY', 'YEARLY'] as const,\n schema: 'lssm_metering',\n description: 'When to reset metric counters.',\n});\n\n/**\n * Period type enum.\n */\nexport const PeriodTypeEnum = defineEntityEnum({\n name: 'PeriodType',\n values: ['HOURLY', 'DAILY', 'WEEKLY', 'MONTHLY', 'YEARLY'] as const,\n schema: 'lssm_metering',\n description: 'Time period for aggregation.',\n});\n\n/**\n * Threshold action enum.\n */\nexport const ThresholdActionEnum = defineEntityEnum({\n name: 'ThresholdAction',\n values: ['NONE', 'ALERT', 'WARN', 'BLOCK', 'DOWNGRADE'] as const,\n schema: 'lssm_metering',\n description: 'Action to take when threshold is exceeded.',\n});\n\n/**\n * MetricDefinition entity - defines a trackable metric.\n */\nexport const MetricDefinitionEntity = defineEntity({\n name: 'MetricDefinition',\n description: 'Definition of a usage metric.',\n schema: 'lssm_metering',\n map: 'metric_definition',\n fields: {\n id: field.id({ description: 'Unique identifier' }),\n key: field.string({\n isUnique: true,\n description: 'Metric key (e.g., api_calls, storage_gb)',\n }),\n name: field.string({ description: 'Human-readable name' }),\n description: field.string({\n isOptional: true,\n description: 'Metric description',\n }),\n\n // Configuration\n unit: field.string({\n description: 'Unit of measurement (calls, bytes, etc.)',\n }),\n aggregationType: field.enum('AggregationType', {\n default: 'SUM',\n description: 'How to aggregate values',\n }),\n resetPeriod: field.enum('ResetPeriod', {\n default: 'MONTHLY',\n description: 'When to reset counters',\n }),\n\n // Precision\n precision: field.int({ default: 2, description: 'Decimal precision' }),\n\n // Scope\n orgId: field.string({\n isOptional: true,\n description: 'Organization scope (null = global metric)',\n }),\n\n // Display\n category: field.string({\n isOptional: true,\n description: 'Category for grouping',\n }),\n displayOrder: field.int({ default: 0, description: 'Order for display' }),\n\n // Metadata\n metadata: field.json({\n isOptional: true,\n description: 'Additional metadata',\n }),\n\n // Status\n isActive: field.boolean({\n default: true,\n description: 'Whether metric is active',\n }),\n\n // Timestamps\n createdAt: field.createdAt(),\n updatedAt: field.updatedAt(),\n\n // Relations\n usageRecords: field.hasMany('UsageRecord'),\n usageSummaries: field.hasMany('UsageSummary'),\n thresholds: field.hasMany('UsageThreshold'),\n },\n indexes: [\n index.on(['orgId', 'key']),\n index.on(['category']),\n index.on(['isActive']),\n ],\n enums: [AggregationTypeEnum, ResetPeriodEnum],\n});\n\n/**\n * UsageRecord entity - individual usage event.\n */\nexport const UsageRecordEntity = defineEntity({\n name: 'UsageRecord',\n description: 'A single usage event.',\n schema: 'lssm_metering',\n map: 'usage_record',\n fields: {\n id: field.id({ description: 'Unique identifier' }),\n\n // Metric reference\n metricKey: field.string({ description: 'Metric being recorded' }),\n metricId: field.string({\n isOptional: true,\n description: 'Metric ID (for FK)',\n }),\n\n // Subject\n subjectType: field.string({\n description: 'Subject type (org, user, project)',\n }),\n subjectId: field.string({ description: 'Subject identifier' }),\n\n // Usage value\n quantity: field.decimal({ description: 'Usage quantity' }),\n\n // Context\n source: field.string({\n isOptional: true,\n description: 'Source of usage (endpoint, feature, etc.)',\n }),\n resourceId: field.string({\n isOptional: true,\n description: 'Related resource ID',\n }),\n resourceType: field.string({\n isOptional: true,\n description: 'Related resource type',\n }),\n\n // Metadata\n metadata: field.json({\n isOptional: true,\n description: 'Additional context',\n }),\n\n // Idempotency\n idempotencyKey: field.string({\n isOptional: true,\n description: 'Idempotency key for deduplication',\n }),\n\n // Timestamps\n timestamp: field.dateTime({ description: 'When usage occurred' }),\n createdAt: field.createdAt(),\n\n // Aggregation status\n aggregated: field.boolean({\n default: false,\n description: 'Whether included in summary',\n }),\n aggregatedAt: field.dateTime({\n isOptional: true,\n description: 'When aggregated',\n }),\n },\n indexes: [\n index.on(['metricKey', 'subjectType', 'subjectId', 'timestamp']),\n index.on(['subjectType', 'subjectId', 'timestamp']),\n index.on(['timestamp']),\n index.on(['aggregated', 'timestamp']),\n index.unique(['idempotencyKey'], { name: 'usage_record_idempotency' }),\n ],\n});\n\n/**\n * UsageSummary entity - pre-aggregated usage.\n */\nexport const UsageSummaryEntity = defineEntity({\n name: 'UsageSummary',\n description: 'Pre-aggregated usage summary.',\n schema: 'lssm_metering',\n map: 'usage_summary',\n fields: {\n id: field.id({ description: 'Unique identifier' }),\n\n // Metric reference\n metricKey: field.string({ description: 'Metric key' }),\n metricId: field.string({\n isOptional: true,\n description: 'Metric ID (for FK)',\n }),\n\n // Subject\n subjectType: field.string({ description: 'Subject type' }),\n subjectId: field.string({ description: 'Subject identifier' }),\n\n // Period\n periodType: field.enum('PeriodType', { description: 'Period type' }),\n periodStart: field.dateTime({ description: 'Period start time' }),\n periodEnd: field.dateTime({ description: 'Period end time' }),\n\n // Aggregated values\n totalQuantity: field.decimal({ description: 'Total/aggregated quantity' }),\n recordCount: field.int({\n default: 0,\n description: 'Number of records aggregated',\n }),\n\n // Statistics (for AVG, MIN, MAX)\n minQuantity: field.decimal({\n isOptional: true,\n description: 'Minimum value',\n }),\n maxQuantity: field.decimal({\n isOptional: true,\n description: 'Maximum value',\n }),\n avgQuantity: field.decimal({\n isOptional: true,\n description: 'Average value',\n }),\n\n // Metadata\n metadata: field.json({\n isOptional: true,\n description: 'Additional metadata',\n }),\n\n // Timestamps\n createdAt: field.createdAt(),\n updatedAt: field.updatedAt(),\n },\n indexes: [\n index.unique(\n ['metricKey', 'subjectType', 'subjectId', 'periodType', 'periodStart'],\n { name: 'usage_summary_unique' }\n ),\n index.on(['subjectType', 'subjectId', 'periodType', 'periodStart']),\n index.on(['metricKey', 'periodType', 'periodStart']),\n ],\n enums: [PeriodTypeEnum],\n});\n\n/**\n * UsageThreshold entity - threshold configuration.\n */\nexport const UsageThresholdEntity = defineEntity({\n name: 'UsageThreshold',\n description: 'Usage threshold configuration.',\n schema: 'lssm_metering',\n map: 'usage_threshold',\n fields: {\n id: field.id({ description: 'Unique identifier' }),\n\n // Metric reference\n metricKey: field.string({ description: 'Metric to monitor' }),\n metricId: field.string({\n isOptional: true,\n description: 'Metric ID (for FK)',\n }),\n\n // Subject (optional - can be global)\n subjectType: field.string({\n isOptional: true,\n description: 'Subject type',\n }),\n subjectId: field.string({\n isOptional: true,\n description: 'Subject identifier',\n }),\n\n // Threshold configuration\n name: field.string({ description: 'Threshold name' }),\n threshold: field.decimal({ description: 'Threshold value' }),\n warnThreshold: field.decimal({\n isOptional: true,\n description: 'Warning threshold (e.g., 80%)',\n }),\n\n // Period\n periodType: field.enum('PeriodType', {\n default: 'MONTHLY',\n description: 'Period to evaluate',\n }),\n\n // Actions\n action: field.enum('ThresholdAction', {\n default: 'ALERT',\n description: 'Action when exceeded',\n }),\n notifyEmails: field.json({\n isOptional: true,\n description: 'Email addresses to notify',\n }),\n notifyWebhook: field.string({\n isOptional: true,\n description: 'Webhook URL to call',\n }),\n\n // Status tracking\n currentValue: field.decimal({\n default: 0,\n description: 'Current usage value',\n }),\n lastCheckedAt: field.dateTime({\n isOptional: true,\n description: 'Last threshold check',\n }),\n lastExceededAt: field.dateTime({\n isOptional: true,\n description: 'Last time threshold was exceeded',\n }),\n\n // Status\n isActive: field.boolean({\n default: true,\n description: 'Whether threshold is active',\n }),\n\n // Metadata\n metadata: field.json({\n isOptional: true,\n description: 'Additional metadata',\n }),\n\n // Timestamps\n createdAt: field.createdAt(),\n updatedAt: field.updatedAt(),\n },\n indexes: [\n index.on(['metricKey']),\n index.on(['subjectType', 'subjectId']),\n index.on(['isActive', 'metricKey']),\n ],\n enums: [ThresholdActionEnum],\n});\n\n/**\n * UsageAlert entity - threshold violation alerts.\n */\nexport const UsageAlertEntity = defineEntity({\n name: 'UsageAlert',\n description: 'Alert generated when threshold is exceeded.',\n schema: 'lssm_metering',\n map: 'usage_alert',\n fields: {\n id: field.id({ description: 'Unique identifier' }),\n\n // Threshold reference\n thresholdId: field.foreignKey({\n description: 'Threshold that triggered alert',\n }),\n\n // Context\n metricKey: field.string({ description: 'Metric key' }),\n subjectType: field.string({\n isOptional: true,\n description: 'Subject type',\n }),\n subjectId: field.string({\n isOptional: true,\n description: 'Subject identifier',\n }),\n\n // Alert details\n alertType: field.string({ description: 'Alert type (warn, exceed, etc.)' }),\n threshold: field.decimal({ description: 'Threshold value' }),\n actualValue: field.decimal({ description: 'Actual usage value' }),\n percentageUsed: field.decimal({\n description: 'Percentage of threshold used',\n }),\n\n // Status\n status: field.string({\n default: '\"pending\"',\n description: 'Alert status (pending, acknowledged, resolved)',\n }),\n acknowledgedBy: field.string({\n isOptional: true,\n description: 'User who acknowledged',\n }),\n acknowledgedAt: field.dateTime({\n isOptional: true,\n description: 'When acknowledged',\n }),\n resolvedAt: field.dateTime({\n isOptional: true,\n description: 'When resolved',\n }),\n\n // Notifications\n notificationsSent: field.json({\n isOptional: true,\n description: 'Notifications sent',\n }),\n\n // Timestamps\n triggeredAt: field.dateTime({ description: 'When alert was triggered' }),\n createdAt: field.createdAt(),\n\n // Relations\n thresholdRelation: field.belongsTo(\n 'UsageThreshold',\n ['thresholdId'],\n ['id'],\n { onDelete: 'Cascade' }\n ),\n },\n indexes: [\n index.on(['thresholdId', 'status']),\n index.on(['metricKey', 'triggeredAt']),\n index.on(['status', 'triggeredAt']),\n ],\n});\n\n/**\n * All metering entities for schema composition.\n */\nexport const meteringEntities = [\n MetricDefinitionEntity,\n UsageRecordEntity,\n UsageSummaryEntity,\n UsageThresholdEntity,\n UsageAlertEntity,\n];\n\n/**\n * Module schema contribution for metering.\n */\nexport const meteringSchemaContribution: ModuleSchemaContribution = {\n moduleId: '@contractspec/lib.metering',\n entities: meteringEntities,\n enums: [\n AggregationTypeEnum,\n ResetPeriodEnum,\n PeriodTypeEnum,\n ThresholdActionEnum,\n ],\n};\n"],"mappings":";;;;;;AAWA,MAAa,sBAAsB,iBAAiB;CAClD,MAAM;CACN,QAAQ;EAAC;EAAS;EAAO;EAAO;EAAO;EAAO;EAAO;CACrD,QAAQ;CACR,aAAa;CACd,CAAC;;;;AAKF,MAAa,kBAAkB,iBAAiB;CAC9C,MAAM;CACN,QAAQ;EAAC;EAAS;EAAU;EAAS;EAAU;EAAW;EAAS;CACnE,QAAQ;CACR,aAAa;CACd,CAAC;;;;AAKF,MAAa,iBAAiB,iBAAiB;CAC7C,MAAM;CACN,QAAQ;EAAC;EAAU;EAAS;EAAU;EAAW;EAAS;CAC1D,QAAQ;CACR,aAAa;CACd,CAAC;;;;AAKF,MAAa,sBAAsB,iBAAiB;CAClD,MAAM;CACN,QAAQ;EAAC;EAAQ;EAAS;EAAQ;EAAS;EAAY;CACvD,QAAQ;CACR,aAAa;CACd,CAAC;;;;AAKF,MAAa,yBAAyB,aAAa;CACjD,MAAM;CACN,aAAa;CACb,QAAQ;CACR,KAAK;CACL,QAAQ;EACN,IAAI,MAAM,GAAG,EAAE,aAAa,qBAAqB,CAAC;EAClD,KAAK,MAAM,OAAO;GAChB,UAAU;GACV,aAAa;GACd,CAAC;EACF,MAAM,MAAM,OAAO,EAAE,aAAa,uBAAuB,CAAC;EAC1D,aAAa,MAAM,OAAO;GACxB,YAAY;GACZ,aAAa;GACd,CAAC;EAGF,MAAM,MAAM,OAAO,EACjB,aAAa,4CACd,CAAC;EACF,iBAAiB,MAAM,KAAK,mBAAmB;GAC7C,SAAS;GACT,aAAa;GACd,CAAC;EACF,aAAa,MAAM,KAAK,eAAe;GACrC,SAAS;GACT,aAAa;GACd,CAAC;EAGF,WAAW,MAAM,IAAI;GAAE,SAAS;GAAG,aAAa;GAAqB,CAAC;EAGtE,OAAO,MAAM,OAAO;GAClB,YAAY;GACZ,aAAa;GACd,CAAC;EAGF,UAAU,MAAM,OAAO;GACrB,YAAY;GACZ,aAAa;GACd,CAAC;EACF,cAAc,MAAM,IAAI;GAAE,SAAS;GAAG,aAAa;GAAqB,CAAC;EAGzE,UAAU,MAAM,KAAK;GACnB,YAAY;GACZ,aAAa;GACd,CAAC;EAGF,UAAU,MAAM,QAAQ;GACtB,SAAS;GACT,aAAa;GACd,CAAC;EAGF,WAAW,MAAM,WAAW;EAC5B,WAAW,MAAM,WAAW;EAG5B,cAAc,MAAM,QAAQ,cAAc;EAC1C,gBAAgB,MAAM,QAAQ,eAAe;EAC7C,YAAY,MAAM,QAAQ,iBAAiB;EAC5C;CACD,SAAS;EACP,MAAM,GAAG,CAAC,SAAS,MAAM,CAAC;EAC1B,MAAM,GAAG,CAAC,WAAW,CAAC;EACtB,MAAM,GAAG,CAAC,WAAW,CAAC;EACvB;CACD,OAAO,CAAC,qBAAqB,gBAAgB;CAC9C,CAAC;;;;AAKF,MAAa,oBAAoB,aAAa;CAC5C,MAAM;CACN,aAAa;CACb,QAAQ;CACR,KAAK;CACL,QAAQ;EACN,IAAI,MAAM,GAAG,EAAE,aAAa,qBAAqB,CAAC;EAGlD,WAAW,MAAM,OAAO,EAAE,aAAa,yBAAyB,CAAC;EACjE,UAAU,MAAM,OAAO;GACrB,YAAY;GACZ,aAAa;GACd,CAAC;EAGF,aAAa,MAAM,OAAO,EACxB,aAAa,qCACd,CAAC;EACF,WAAW,MAAM,OAAO,EAAE,aAAa,sBAAsB,CAAC;EAG9D,UAAU,MAAM,QAAQ,EAAE,aAAa,kBAAkB,CAAC;EAG1D,QAAQ,MAAM,OAAO;GACnB,YAAY;GACZ,aAAa;GACd,CAAC;EACF,YAAY,MAAM,OAAO;GACvB,YAAY;GACZ,aAAa;GACd,CAAC;EACF,cAAc,MAAM,OAAO;GACzB,YAAY;GACZ,aAAa;GACd,CAAC;EAGF,UAAU,MAAM,KAAK;GACnB,YAAY;GACZ,aAAa;GACd,CAAC;EAGF,gBAAgB,MAAM,OAAO;GAC3B,YAAY;GACZ,aAAa;GACd,CAAC;EAGF,WAAW,MAAM,SAAS,EAAE,aAAa,uBAAuB,CAAC;EACjE,WAAW,MAAM,WAAW;EAG5B,YAAY,MAAM,QAAQ;GACxB,SAAS;GACT,aAAa;GACd,CAAC;EACF,cAAc,MAAM,SAAS;GAC3B,YAAY;GACZ,aAAa;GACd,CAAC;EACH;CACD,SAAS;EACP,MAAM,GAAG;GAAC;GAAa;GAAe;GAAa;GAAY,CAAC;EAChE,MAAM,GAAG;GAAC;GAAe;GAAa;GAAY,CAAC;EACnD,MAAM,GAAG,CAAC,YAAY,CAAC;EACvB,MAAM,GAAG,CAAC,cAAc,YAAY,CAAC;EACrC,MAAM,OAAO,CAAC,iBAAiB,EAAE,EAAE,MAAM,4BAA4B,CAAC;EACvE;CACF,CAAC;;;;AAKF,MAAa,qBAAqB,aAAa;CAC7C,MAAM;CACN,aAAa;CACb,QAAQ;CACR,KAAK;CACL,QAAQ;EACN,IAAI,MAAM,GAAG,EAAE,aAAa,qBAAqB,CAAC;EAGlD,WAAW,MAAM,OAAO,EAAE,aAAa,cAAc,CAAC;EACtD,UAAU,MAAM,OAAO;GACrB,YAAY;GACZ,aAAa;GACd,CAAC;EAGF,aAAa,MAAM,OAAO,EAAE,aAAa,gBAAgB,CAAC;EAC1D,WAAW,MAAM,OAAO,EAAE,aAAa,sBAAsB,CAAC;EAG9D,YAAY,MAAM,KAAK,cAAc,EAAE,aAAa,eAAe,CAAC;EACpE,aAAa,MAAM,SAAS,EAAE,aAAa,qBAAqB,CAAC;EACjE,WAAW,MAAM,SAAS,EAAE,aAAa,mBAAmB,CAAC;EAG7D,eAAe,MAAM,QAAQ,EAAE,aAAa,6BAA6B,CAAC;EAC1E,aAAa,MAAM,IAAI;GACrB,SAAS;GACT,aAAa;GACd,CAAC;EAGF,aAAa,MAAM,QAAQ;GACzB,YAAY;GACZ,aAAa;GACd,CAAC;EACF,aAAa,MAAM,QAAQ;GACzB,YAAY;GACZ,aAAa;GACd,CAAC;EACF,aAAa,MAAM,QAAQ;GACzB,YAAY;GACZ,aAAa;GACd,CAAC;EAGF,UAAU,MAAM,KAAK;GACnB,YAAY;GACZ,aAAa;GACd,CAAC;EAGF,WAAW,MAAM,WAAW;EAC5B,WAAW,MAAM,WAAW;EAC7B;CACD,SAAS;EACP,MAAM,OACJ;GAAC;GAAa;GAAe;GAAa;GAAc;GAAc,EACtE,EAAE,MAAM,wBAAwB,CACjC;EACD,MAAM,GAAG;GAAC;GAAe;GAAa;GAAc;GAAc,CAAC;EACnE,MAAM,GAAG;GAAC;GAAa;GAAc;GAAc,CAAC;EACrD;CACD,OAAO,CAAC,eAAe;CACxB,CAAC;;;;AAKF,MAAa,uBAAuB,aAAa;CAC/C,MAAM;CACN,aAAa;CACb,QAAQ;CACR,KAAK;CACL,QAAQ;EACN,IAAI,MAAM,GAAG,EAAE,aAAa,qBAAqB,CAAC;EAGlD,WAAW,MAAM,OAAO,EAAE,aAAa,qBAAqB,CAAC;EAC7D,UAAU,MAAM,OAAO;GACrB,YAAY;GACZ,aAAa;GACd,CAAC;EAGF,aAAa,MAAM,OAAO;GACxB,YAAY;GACZ,aAAa;GACd,CAAC;EACF,WAAW,MAAM,OAAO;GACtB,YAAY;GACZ,aAAa;GACd,CAAC;EAGF,MAAM,MAAM,OAAO,EAAE,aAAa,kBAAkB,CAAC;EACrD,WAAW,MAAM,QAAQ,EAAE,aAAa,mBAAmB,CAAC;EAC5D,eAAe,MAAM,QAAQ;GAC3B,YAAY;GACZ,aAAa;GACd,CAAC;EAGF,YAAY,MAAM,KAAK,cAAc;GACnC,SAAS;GACT,aAAa;GACd,CAAC;EAGF,QAAQ,MAAM,KAAK,mBAAmB;GACpC,SAAS;GACT,aAAa;GACd,CAAC;EACF,cAAc,MAAM,KAAK;GACvB,YAAY;GACZ,aAAa;GACd,CAAC;EACF,eAAe,MAAM,OAAO;GAC1B,YAAY;GACZ,aAAa;GACd,CAAC;EAGF,cAAc,MAAM,QAAQ;GAC1B,SAAS;GACT,aAAa;GACd,CAAC;EACF,eAAe,MAAM,SAAS;GAC5B,YAAY;GACZ,aAAa;GACd,CAAC;EACF,gBAAgB,MAAM,SAAS;GAC7B,YAAY;GACZ,aAAa;GACd,CAAC;EAGF,UAAU,MAAM,QAAQ;GACtB,SAAS;GACT,aAAa;GACd,CAAC;EAGF,UAAU,MAAM,KAAK;GACnB,YAAY;GACZ,aAAa;GACd,CAAC;EAGF,WAAW,MAAM,WAAW;EAC5B,WAAW,MAAM,WAAW;EAC7B;CACD,SAAS;EACP,MAAM,GAAG,CAAC,YAAY,CAAC;EACvB,MAAM,GAAG,CAAC,eAAe,YAAY,CAAC;EACtC,MAAM,GAAG,CAAC,YAAY,YAAY,CAAC;EACpC;CACD,OAAO,CAAC,oBAAoB;CAC7B,CAAC;;;;AAKF,MAAa,mBAAmB,aAAa;CAC3C,MAAM;CACN,aAAa;CACb,QAAQ;CACR,KAAK;CACL,QAAQ;EACN,IAAI,MAAM,GAAG,EAAE,aAAa,qBAAqB,CAAC;EAGlD,aAAa,MAAM,WAAW,EAC5B,aAAa,kCACd,CAAC;EAGF,WAAW,MAAM,OAAO,EAAE,aAAa,cAAc,CAAC;EACtD,aAAa,MAAM,OAAO;GACxB,YAAY;GACZ,aAAa;GACd,CAAC;EACF,WAAW,MAAM,OAAO;GACtB,YAAY;GACZ,aAAa;GACd,CAAC;EAGF,WAAW,MAAM,OAAO,EAAE,aAAa,mCAAmC,CAAC;EAC3E,WAAW,MAAM,QAAQ,EAAE,aAAa,mBAAmB,CAAC;EAC5D,aAAa,MAAM,QAAQ,EAAE,aAAa,sBAAsB,CAAC;EACjE,gBAAgB,MAAM,QAAQ,EAC5B,aAAa,gCACd,CAAC;EAGF,QAAQ,MAAM,OAAO;GACnB,SAAS;GACT,aAAa;GACd,CAAC;EACF,gBAAgB,MAAM,OAAO;GAC3B,YAAY;GACZ,aAAa;GACd,CAAC;EACF,gBAAgB,MAAM,SAAS;GAC7B,YAAY;GACZ,aAAa;GACd,CAAC;EACF,YAAY,MAAM,SAAS;GACzB,YAAY;GACZ,aAAa;GACd,CAAC;EAGF,mBAAmB,MAAM,KAAK;GAC5B,YAAY;GACZ,aAAa;GACd,CAAC;EAGF,aAAa,MAAM,SAAS,EAAE,aAAa,4BAA4B,CAAC;EACxE,WAAW,MAAM,WAAW;EAG5B,mBAAmB,MAAM,UACvB,kBACA,CAAC,cAAc,EACf,CAAC,KAAK,EACN,EAAE,UAAU,WAAW,CACxB;EACF;CACD,SAAS;EACP,MAAM,GAAG,CAAC,eAAe,SAAS,CAAC;EACnC,MAAM,GAAG,CAAC,aAAa,cAAc,CAAC;EACtC,MAAM,GAAG,CAAC,UAAU,cAAc,CAAC;EACpC;CACF,CAAC;;;;AAKF,MAAa,mBAAmB;CAC9B;CACA;CACA;CACA;CACA;CACD;;;;AAKD,MAAa,6BAAuD;CAClE,UAAU;CACV,UAAU;CACV,OAAO;EACL;EACA;EACA;EACA;EACD;CACF"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import * as _contractspec_lib_contracts15 from "@contractspec/lib.contracts";
|
|
2
|
+
|
|
3
|
+
//#region src/metering.capability.d.ts
|
|
4
|
+
declare const MeteringCapability: _contractspec_lib_contracts15.CapabilitySpec;
|
|
5
|
+
declare const ThresholdsCapability: _contractspec_lib_contracts15.CapabilitySpec;
|
|
6
|
+
//#endregion
|
|
7
|
+
export { MeteringCapability, ThresholdsCapability };
|
|
8
|
+
//# sourceMappingURL=metering.capability.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metering.capability.d.ts","names":[],"sources":["../src/metering.capability.ts"],"sourcesContent":[],"mappings":";;;cAEa,oBAUX,6BAAA,CAV6B;cAYlB,sBAUX,6BAAA,CAV+B"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { StabilityEnum, defineCapability } from "@contractspec/lib.contracts";
|
|
2
|
+
|
|
3
|
+
//#region src/metering.capability.ts
|
|
4
|
+
const MeteringCapability = defineCapability({ meta: {
|
|
5
|
+
key: "metering",
|
|
6
|
+
version: "1.0.0",
|
|
7
|
+
kind: "api",
|
|
8
|
+
stability: StabilityEnum.Experimental,
|
|
9
|
+
description: "Usage metering and tracking",
|
|
10
|
+
owners: ["@platform.finance"],
|
|
11
|
+
tags: [
|
|
12
|
+
"metering",
|
|
13
|
+
"usage",
|
|
14
|
+
"billing"
|
|
15
|
+
]
|
|
16
|
+
} });
|
|
17
|
+
const ThresholdsCapability = defineCapability({ meta: {
|
|
18
|
+
key: "thresholds",
|
|
19
|
+
version: "1.0.0",
|
|
20
|
+
kind: "api",
|
|
21
|
+
stability: StabilityEnum.Experimental,
|
|
22
|
+
description: "Usage threshold alerts and limits",
|
|
23
|
+
owners: ["@platform.finance"],
|
|
24
|
+
tags: [
|
|
25
|
+
"thresholds",
|
|
26
|
+
"limits",
|
|
27
|
+
"metering"
|
|
28
|
+
]
|
|
29
|
+
} });
|
|
30
|
+
|
|
31
|
+
//#endregion
|
|
32
|
+
export { MeteringCapability, ThresholdsCapability };
|
|
33
|
+
//# sourceMappingURL=metering.capability.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metering.capability.js","names":[],"sources":["../src/metering.capability.ts"],"sourcesContent":["import { defineCapability, StabilityEnum } from '@contractspec/lib.contracts';\n\nexport const MeteringCapability = defineCapability({\n meta: {\n key: 'metering',\n version: '1.0.0',\n kind: 'api',\n stability: StabilityEnum.Experimental,\n description: 'Usage metering and tracking',\n owners: ['@platform.finance'],\n tags: ['metering', 'usage', 'billing'],\n },\n});\n\nexport const ThresholdsCapability = defineCapability({\n meta: {\n key: 'thresholds',\n version: '1.0.0',\n kind: 'api',\n stability: StabilityEnum.Experimental,\n description: 'Usage threshold alerts and limits',\n owners: ['@platform.finance'],\n tags: ['thresholds', 'limits', 'metering'],\n },\n});\n"],"mappings":";;;AAEA,MAAa,qBAAqB,iBAAiB,EACjD,MAAM;CACJ,KAAK;CACL,SAAS;CACT,MAAM;CACN,WAAW,cAAc;CACzB,aAAa;CACb,QAAQ,CAAC,oBAAoB;CAC7B,MAAM;EAAC;EAAY;EAAS;EAAU;CACvC,EACF,CAAC;AAEF,MAAa,uBAAuB,iBAAiB,EACnD,MAAM;CACJ,KAAK;CACL,SAAS;CACT,MAAM;CACN,WAAW,cAAc;CACzB,aAAa;CACb,QAAQ,CAAC,oBAAoB;CAC7B,MAAM;EAAC;EAAc;EAAU;EAAW;CAC3C,EACF,CAAC"}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import
|
|
1
|
+
import * as _contractspec_lib_contracts17 from "@contractspec/lib.contracts";
|
|
2
2
|
|
|
3
3
|
//#region src/metering.feature.d.ts
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
* Metering feature module that bundles
|
|
7
|
-
*
|
|
6
|
+
* Metering feature module that bundles usage tracking,
|
|
7
|
+
* metrics definitions, and billing capabilities.
|
|
8
8
|
*/
|
|
9
|
-
declare const MeteringFeature: FeatureModuleSpec;
|
|
9
|
+
declare const MeteringFeature: _contractspec_lib_contracts17.FeatureModuleSpec;
|
|
10
10
|
//#endregion
|
|
11
11
|
export { MeteringFeature };
|
|
12
12
|
//# sourceMappingURL=metering.feature.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"metering.feature.d.ts","names":[],"sources":["../src/metering.feature.ts"],"sourcesContent":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"metering.feature.d.ts","names":[],"sources":["../src/metering.feature.ts"],"sourcesContent":[],"mappings":";;;;;;;AAWA;cAAa,iBAgEX,6BAAA,CAhE0B"}
|
package/dist/metering.feature.js
CHANGED
|
@@ -1,9 +1,16 @@
|
|
|
1
|
+
import { defineFeature } from "@contractspec/lib.contracts";
|
|
2
|
+
|
|
1
3
|
//#region src/metering.feature.ts
|
|
2
4
|
/**
|
|
3
|
-
* Metering
|
|
4
|
-
*
|
|
5
|
+
* Metering Feature Module Specification
|
|
6
|
+
*
|
|
7
|
+
* Defines the feature module for usage metering and threshold management.
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Metering feature module that bundles usage tracking,
|
|
11
|
+
* metrics definitions, and billing capabilities.
|
|
5
12
|
*/
|
|
6
|
-
const MeteringFeature = {
|
|
13
|
+
const MeteringFeature = defineFeature({
|
|
7
14
|
meta: {
|
|
8
15
|
key: "metering",
|
|
9
16
|
version: "1.0.0",
|
|
@@ -120,7 +127,7 @@ const MeteringFeature = {
|
|
|
120
127
|
}],
|
|
121
128
|
requires: []
|
|
122
129
|
}
|
|
123
|
-
};
|
|
130
|
+
});
|
|
124
131
|
|
|
125
132
|
//#endregion
|
|
126
133
|
export { MeteringFeature };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"metering.feature.js","names":[
|
|
1
|
+
{"version":3,"file":"metering.feature.js","names":[],"sources":["../src/metering.feature.ts"],"sourcesContent":["/**\n * Metering Feature Module Specification\n *\n * Defines the feature module for usage metering and threshold management.\n */\nimport { defineFeature } from '@contractspec/lib.contracts';\n\n/**\n * Metering feature module that bundles usage tracking,\n * metrics definitions, and billing capabilities.\n */\nexport const MeteringFeature = defineFeature({\n meta: {\n key: 'metering',\n version: '1.0.0',\n title: 'Usage Metering',\n description: 'Usage metering, metric definitions, and threshold alerting',\n domain: 'platform',\n owners: ['@platform.metering'],\n tags: ['metering', 'usage', 'billing', 'thresholds'],\n stability: 'stable',\n },\n\n // All contract operations included in this feature\n operations: [\n // Metric operations\n { key: 'metric.define', version: '1.0.0' },\n { key: 'metric.update', version: '1.0.0' },\n { key: 'metric.delete', version: '1.0.0' },\n { key: 'metric.get', version: '1.0.0' },\n { key: 'metric.list', version: '1.0.0' },\n\n // Usage operations\n { key: 'usage.record', version: '1.0.0' },\n { key: 'usage.recordBatch', version: '1.0.0' },\n { key: 'usage.get', version: '1.0.0' },\n { key: 'usage.getSummary', version: '1.0.0' },\n\n // Threshold operations\n { key: 'threshold.create', version: '1.0.0' },\n { key: 'threshold.update', version: '1.0.0' },\n { key: 'threshold.delete', version: '1.0.0' },\n { key: 'threshold.list', version: '1.0.0' },\n ],\n\n // Events emitted by this feature\n events: [\n // Metric events\n { key: 'metric.defined', version: '1.0.0' },\n { key: 'metric.updated', version: '1.0.0' },\n\n // Usage events\n { key: 'usage.recorded', version: '1.0.0' },\n { key: 'usage.batch_recorded', version: '1.0.0' },\n { key: 'usage.aggregated', version: '1.0.0' },\n\n // Threshold events\n { key: 'threshold.created', version: '1.0.0' },\n { key: 'threshold.exceeded', version: '1.0.0' },\n { key: 'threshold.approaching', version: '1.0.0' },\n ],\n\n // No presentations for this library feature\n presentations: [],\n opToPresentation: [],\n presentationsTargets: [],\n\n // Capability definitions\n capabilities: {\n provides: [\n { key: 'metering', version: '1.0.0' },\n { key: 'thresholds', version: '1.0.0' },\n ],\n requires: [],\n },\n});\n"],"mappings":";;;;;;;;;;;;AAWA,MAAa,kBAAkB,cAAc;CAC3C,MAAM;EACJ,KAAK;EACL,SAAS;EACT,OAAO;EACP,aAAa;EACb,QAAQ;EACR,QAAQ,CAAC,qBAAqB;EAC9B,MAAM;GAAC;GAAY;GAAS;GAAW;GAAa;EACpD,WAAW;EACZ;CAGD,YAAY;EAEV;GAAE,KAAK;GAAiB,SAAS;GAAS;EAC1C;GAAE,KAAK;GAAiB,SAAS;GAAS;EAC1C;GAAE,KAAK;GAAiB,SAAS;GAAS;EAC1C;GAAE,KAAK;GAAc,SAAS;GAAS;EACvC;GAAE,KAAK;GAAe,SAAS;GAAS;EAGxC;GAAE,KAAK;GAAgB,SAAS;GAAS;EACzC;GAAE,KAAK;GAAqB,SAAS;GAAS;EAC9C;GAAE,KAAK;GAAa,SAAS;GAAS;EACtC;GAAE,KAAK;GAAoB,SAAS;GAAS;EAG7C;GAAE,KAAK;GAAoB,SAAS;GAAS;EAC7C;GAAE,KAAK;GAAoB,SAAS;GAAS;EAC7C;GAAE,KAAK;GAAoB,SAAS;GAAS;EAC7C;GAAE,KAAK;GAAkB,SAAS;GAAS;EAC5C;CAGD,QAAQ;EAEN;GAAE,KAAK;GAAkB,SAAS;GAAS;EAC3C;GAAE,KAAK;GAAkB,SAAS;GAAS;EAG3C;GAAE,KAAK;GAAkB,SAAS;GAAS;EAC3C;GAAE,KAAK;GAAwB,SAAS;GAAS;EACjD;GAAE,KAAK;GAAoB,SAAS;GAAS;EAG7C;GAAE,KAAK;GAAqB,SAAS;GAAS;EAC9C;GAAE,KAAK;GAAsB,SAAS;GAAS;EAC/C;GAAE,KAAK;GAAyB,SAAS;GAAS;EACnD;CAGD,eAAe,EAAE;CACjB,kBAAkB,EAAE;CACpB,sBAAsB,EAAE;CAGxB,cAAc;EACZ,UAAU,CACR;GAAE,KAAK;GAAY,SAAS;GAAS,EACrC;GAAE,KAAK;GAAc,SAAS;GAAS,CACxC;EACD,UAAU,EAAE;EACb;CACF,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@contractspec/lib.metering",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.48.0",
|
|
4
4
|
"description": "Usage metering and billing core module for ContractSpec applications",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"contractspec",
|
|
@@ -10,7 +10,6 @@
|
|
|
10
10
|
"saas",
|
|
11
11
|
"typescript"
|
|
12
12
|
],
|
|
13
|
-
"main": "./dist/index.js",
|
|
14
13
|
"types": "./dist/index.d.ts",
|
|
15
14
|
"type": "module",
|
|
16
15
|
"scripts": {
|
|
@@ -26,13 +25,13 @@
|
|
|
26
25
|
"lint:check": "eslint src"
|
|
27
26
|
},
|
|
28
27
|
"dependencies": {
|
|
29
|
-
"@contractspec/lib.schema": "1.
|
|
30
|
-
"@contractspec/lib.contracts": "1.
|
|
31
|
-
"zod": "^4.
|
|
28
|
+
"@contractspec/lib.schema": "1.48.0",
|
|
29
|
+
"@contractspec/lib.contracts": "1.48.0",
|
|
30
|
+
"zod": "^4.3.5"
|
|
32
31
|
},
|
|
33
32
|
"devDependencies": {
|
|
34
|
-
"@contractspec/tool.typescript": "1.
|
|
35
|
-
"@contractspec/tool.tsdown": "1.
|
|
33
|
+
"@contractspec/tool.typescript": "1.48.0",
|
|
34
|
+
"@contractspec/tool.tsdown": "1.48.0",
|
|
36
35
|
"typescript": "^5.9.3"
|
|
37
36
|
},
|
|
38
37
|
"exports": {
|
|
@@ -43,10 +42,10 @@
|
|
|
43
42
|
"./docs/metering.docblock": "./dist/docs/metering.docblock.js",
|
|
44
43
|
"./entities": "./dist/entities/index.js",
|
|
45
44
|
"./events": "./dist/events.js",
|
|
45
|
+
"./metering.capability": "./dist/metering.capability.js",
|
|
46
46
|
"./metering.feature": "./dist/metering.feature.js",
|
|
47
47
|
"./*": "./*"
|
|
48
48
|
},
|
|
49
|
-
"module": "./dist/index.js",
|
|
50
49
|
"files": [
|
|
51
50
|
"dist",
|
|
52
51
|
"README.md"
|