@happyvertical/smrt-marketing 0.57.4 → 0.57.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/manifest.json +1 -1
- package/dist/smrt-knowledge.json +3 -3
- package/package.json +7 -7
package/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@ import { CAMPAIGN_CHANNEL_KINDS, CAMPAIGN_CHANNEL_STATUSES, CAMPAIGN_STATUSES }
|
|
|
2
2
|
import { ObjectRegistry, SmrtCollection, SmrtObject, ValidationError, crossPackageRef, field, foreignKey, resolveListLimit, smrt } from "@happyvertical/smrt-core";
|
|
3
3
|
import { TenantIsolationError, TenantScoped, getCurrentTenant, isSuperAdminBypass, isSystemContext, tenantId, withTenant } from "@happyvertical/smrt-tenancy";
|
|
4
4
|
//#region src/__smrt-register__.ts
|
|
5
|
-
ObjectRegistry.registerPackageManifest(JSON.parse(`{"version":"1.0.0","timestamp":0,"packageName":"@happyvertical/smrt-marketing","packageVersion":"0.57.4","objects":{"@happyvertical/smrt-marketing:CampaignChannelCollection":{"name":"campaignchannelcollection","className":"CampaignChannelCollection","qualifiedName":"@happyvertical/smrt-marketing:CampaignChannelCollection","collection":"campaignchannels","filePath":"/home/runner/work/smrt/smrt/packages/marketing/src/collections/CampaignChannelCollection.ts","packageName":"@happyvertical/smrt-marketing","fields":{},"methods":{"findByCampaign":{"name":"findByCampaign","async":true,"parameters":[{"name":"campaignId","type":"string","optional":false}],"returnType":"Promise<CampaignChannel[]>","isStatic":false,"isPublic":true},"findByExecutionRef":{"name":"findByExecutionRef","async":true,"parameters":[{"name":"channelKind","type":"string","optional":false},{"name":"channelRef","type":"string","optional":false}],"returnType":"Promise<CampaignChannel[]>","isStatic":false,"isPublic":true}},"decoratorConfig":{"tableName":"campaign_channels","api":{"include":["list","get","create","update","delete"]},"mcp":{"include":["list","get","create","update"]},"cli":{"include":["list","get","create","update","delete"]}},"extends":"SmrtCollection","extendsTypeArg":"CampaignChannel","exportName":"CampaignChannelCollection","collectionExportName":"CampaignChannelCollectionCollection","schema":{"tableName":"campaign_channels","ddl":"CREATE TABLE IF NOT EXISTS \\"campaign_channels\\" (\\n \\"id\\" UUID PRIMARY KEY NOT NULL,\\n \\"slug\\" TEXT NOT NULL,\\n \\"context\\" TEXT NOT NULL DEFAULT '',\\n \\"created_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"updated_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"tenant_id\\" UUID,\\n \\"campaign_id\\" UUID NOT NULL,\\n \\"channel_kind\\" TEXT NOT NULL DEFAULT '',\\n \\"channel_ref\\" TEXT NOT NULL DEFAULT '',\\n \\"allocated_budget_cents\\" INTEGER DEFAULT 0,\\n \\"start_at\\" TIMESTAMP,\\n \\"end_at\\" TIMESTAMP,\\n \\"status\\" TEXT DEFAULT 'planned'\\n);","columns":{"id":{"type":"UUID","primaryKey":true,"referenceKind":"id","notNull":true},"slug":{"type":"TEXT","notNull":true},"context":{"type":"TEXT","notNull":true,"default":""},"created_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"updated_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"tenant_id":{"type":"UUID","referenceKind":"tenantId","notNull":false,"unique":false},"campaign_id":{"type":"UUID","referenceKind":"foreignKey","notNull":true,"unique":false,"foreignKey":{"table":"campaigns","column":"id","onDelete":"CASCADE","onUpdate":"CASCADE"}},"channel_kind":{"type":"TEXT","notNull":true,"unique":false,"default":""},"channel_ref":{"type":"TEXT","notNull":true,"unique":false,"default":""},"allocated_budget_cents":{"type":"INTEGER","notNull":false,"unique":false,"default":0},"start_at":{"type":"TIMESTAMP","notNull":false,"unique":false},"end_at":{"type":"TIMESTAMP","notNull":false,"unique":false},"status":{"type":"TEXT","notNull":false,"unique":false,"default":"planned"}},"indexes":[{"name":"campaign_channels_campaign_id_channel_kind_idx","columns":["campaign_id","channel_kind","channel_ref"],"unique":true},{"name":"campaign_channels_slug_context_idx","columns":["slug","context"]},{"name":"campaign_channels_tenant_id_created_at_idx","columns":["tenant_id","created_at"]}],"version":"cc045525"},"importPath":"@happyvertical/smrt-marketing"},"@happyvertical/smrt-marketing:CampaignCollection":{"name":"campaigncollection","className":"CampaignCollection","qualifiedName":"@happyvertical/smrt-marketing:CampaignCollection","collection":"campaigns","filePath":"/home/runner/work/smrt/smrt/packages/marketing/src/collections/CampaignCollection.ts","packageName":"@happyvertical/smrt-marketing","fields":{},"methods":{"get":{"name":"get","async":true,"parameters":[{"name":"filter","type":"string | SmrtWhereClause<Campaign>","optional":false,"unionBranches":[{"type":"string"},{"type":"SmrtWhereClause<Campaign>"}]},{"name":"options","type":"object","optional":true,"memberTypes":["CollectionCacheConfig | false"]}],"returnType":"Promise<Campaign | null>","isStatic":false,"isPublic":true},"list":{"name":"list","async":true,"parameters":[{"name":"options","type":"SmrtListOptions<Campaign>","optional":true}],"returnType":"Promise<Campaign[] | Record<string, unknown>[]>","isStatic":false,"isPublic":true},"findByCampaignKey":{"name":"findByCampaignKey","async":true,"parameters":[{"name":"campaignKey","type":"string","optional":false},{"name":"tenantId","type":"string | null","optional":true,"unionBranches":[{"type":"string"},{"type":"null"}]}],"returnType":"Promise<Campaign | null>","isStatic":false,"isPublic":true},"findByStatus":{"name":"findByStatus","async":true,"parameters":[{"name":"status","type":"CampaignStatus","optional":false}],"returnType":"Promise<Campaign[]>","isStatic":false,"isPublic":true},"listByCustomer":{"name":"listByCustomer","async":true,"parameters":[{"name":"tenantId","type":"string | null","optional":false,"unionBranches":[{"type":"string"},{"type":"null"}]},{"name":"customerId","type":"string","optional":false},{"name":"options","type":"ListCampaignsByCustomerOptions","optional":true}],"returnType":"Promise<CampaignCustomerPage>","isStatic":false,"isPublic":true},"listReportingByCustomer":{"name":"listReportingByCustomer","async":true,"parameters":[{"name":"tenantId","type":"string | null","optional":false,"unionBranches":[{"type":"string"},{"type":"null"}]},{"name":"customerId","type":"string","optional":false},{"name":"options","type":"ListCampaignReportingByCustomerOptions","optional":true}],"returnType":"Promise<CampaignReportingPage>","isStatic":false,"isPublic":true},"summarizeByCustomers":{"name":"summarizeByCustomers","async":true,"parameters":[{"name":"tenantId","type":"string | null","optional":false,"unionBranches":[{"type":"string"},{"type":"null"}]},{"name":"customerIds","type":"string[]","optional":false}],"returnType":"Promise<CampaignCustomerSummary[]>","isStatic":false,"isPublic":true}},"decoratorConfig":{"tableName":"campaigns","api":{"include":["list","get","create","update"]},"mcp":{"include":["list","get","create","update"]},"cli":{"include":["list","get","create","update"]}},"extends":"SmrtCollection","extendsTypeArg":"Campaign","exportName":"CampaignCollection","collectionExportName":"CampaignCollectionCollection","schema":{"tableName":"campaigns","ddl":"CREATE TABLE IF NOT EXISTS \\"campaigns\\" (\\n \\"id\\" UUID PRIMARY KEY NOT NULL,\\n \\"slug\\" TEXT NOT NULL,\\n \\"context\\" TEXT NOT NULL DEFAULT '',\\n \\"created_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"updated_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"tenant_id\\" UUID,\\n \\"customer_id\\" UUID,\\n \\"campaign_key\\" TEXT NOT NULL DEFAULT '',\\n \\"name\\" TEXT NOT NULL DEFAULT '',\\n \\"objective\\" TEXT DEFAULT '',\\n \\"status\\" TEXT DEFAULT 'draft',\\n \\"start_at\\" TIMESTAMP,\\n \\"end_at\\" TIMESTAMP,\\n \\"budget_cents\\" INTEGER DEFAULT 0,\\n \\"currency\\" TEXT DEFAULT 'USD',\\n \\"metadata\\" TEXT DEFAULT '{}'\\n);","columns":{"id":{"type":"UUID","primaryKey":true,"referenceKind":"id","notNull":true},"slug":{"type":"TEXT","notNull":true},"context":{"type":"TEXT","notNull":true,"default":""},"created_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"updated_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"tenant_id":{"type":"UUID","referenceKind":"tenantId","notNull":false,"unique":false},"customer_id":{"type":"UUID","referenceKind":"crossPackageRef","notNull":false,"unique":false},"campaign_key":{"type":"TEXT","notNull":true,"unique":false,"default":""},"name":{"type":"TEXT","notNull":true,"unique":false,"default":""},"objective":{"type":"TEXT","notNull":false,"unique":false,"default":""},"status":{"type":"TEXT","notNull":false,"unique":false,"default":"draft"},"start_at":{"type":"TIMESTAMP","notNull":false,"unique":false},"end_at":{"type":"TIMESTAMP","notNull":false,"unique":false},"budget_cents":{"type":"INTEGER","notNull":false,"unique":false,"default":0},"currency":{"type":"TEXT","notNull":false,"unique":false,"default":"USD"},"metadata":{"type":"TEXT","notNull":false,"unique":false,"default":"{}"}},"indexes":[{"name":"campaigns_tenant_id_campaign_key_idx","columns":["tenant_id","campaign_key"],"unique":true,"nullsNotDistinct":true},{"name":"campaigns_slug_context_idx","columns":["slug","context"]},{"name":"campaigns_tenant_id_customer_id_start_at_id_idx","columns":["tenant_id","customer_id","start_at","id"]},{"name":"campaigns_tenant_id_created_at_idx","columns":["tenant_id","created_at"]},{"name":"campaigns_customer_id_idx","columns":["customer_id"]}],"version":"d0945102"},"importPath":"@happyvertical/smrt-marketing"},"@happyvertical/smrt-marketing:CampaignMetricSnapshotCollection":{"name":"campaignmetricsnapshotcollection","className":"CampaignMetricSnapshotCollection","qualifiedName":"@happyvertical/smrt-marketing:CampaignMetricSnapshotCollection","collection":"campaignmetricsnapshots","filePath":"/home/runner/work/smrt/smrt/packages/marketing/src/collections/CampaignMetricSnapshotCollection.ts","packageName":"@happyvertical/smrt-marketing","fields":{},"methods":{"findByDedupeKey":{"name":"findByDedupeKey","async":true,"parameters":[{"name":"dedupeKey","type":"string","optional":false}],"returnType":"Promise<CampaignMetricSnapshot | null>","isStatic":false,"isPublic":true},"getOrCreateByDedupeKey":{"name":"getOrCreateByDedupeKey","async":true,"parameters":[{"name":"options","type":"CampaignMetricSnapshotOptions","optional":false}],"returnType":"Promise<object>","isStatic":false,"isPublic":true},"findByCampaign":{"name":"findByCampaign","async":true,"parameters":[{"name":"campaignId","type":"string","optional":false}],"returnType":"Promise<CampaignMetricSnapshot[]>","isStatic":false,"isPublic":true},"findByChannel":{"name":"findByChannel","async":true,"parameters":[{"name":"campaignChannelId","type":"string","optional":false}],"returnType":"Promise<CampaignMetricSnapshot[]>","isStatic":false,"isPublic":true}},"decoratorConfig":{"tableName":"campaign_metric_snapshots","api":{"include":["list","get","create"]},"mcp":{"include":["list","get","create"]},"cli":{"include":["list","get","create"]}},"extends":"SmrtCollection","extendsTypeArg":"CampaignMetricSnapshot","exportName":"CampaignMetricSnapshotCollection","collectionExportName":"CampaignMetricSnapshotCollectionCollection","schema":{"tableName":"campaign_metric_snapshots","ddl":"CREATE TABLE IF NOT EXISTS \\"campaign_metric_snapshots\\" (\\n \\"id\\" UUID PRIMARY KEY NOT NULL,\\n \\"slug\\" TEXT NOT NULL,\\n \\"context\\" TEXT NOT NULL DEFAULT '',\\n \\"created_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"updated_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"tenant_id\\" UUID,\\n \\"campaign_id\\" UUID NOT NULL,\\n \\"campaign_channel_id\\" UUID,\\n \\"period_start\\" TIMESTAMP NOT NULL,\\n \\"period_end\\" TIMESTAMP NOT NULL,\\n \\"spend_cents\\" INTEGER DEFAULT 0,\\n \\"impressions\\" INTEGER DEFAULT 0,\\n \\"clicks\\" INTEGER DEFAULT 0,\\n \\"conversions\\" INTEGER DEFAULT 0,\\n \\"leads\\" INTEGER DEFAULT 0,\\n \\"revenue_cents\\" INTEGER,\\n \\"source\\" TEXT NOT NULL DEFAULT '',\\n \\"dedupe_key\\" TEXT NOT NULL DEFAULT ''\\n);","columns":{"id":{"type":"UUID","primaryKey":true,"referenceKind":"id","notNull":true},"slug":{"type":"TEXT","notNull":true},"context":{"type":"TEXT","notNull":true,"default":""},"created_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"updated_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"tenant_id":{"type":"UUID","referenceKind":"tenantId","notNull":false,"unique":false},"campaign_id":{"type":"UUID","referenceKind":"foreignKey","notNull":true,"unique":false,"foreignKey":{"table":"campaigns","column":"id","onDelete":"NO ACTION","onUpdate":"CASCADE"}},"campaign_channel_id":{"type":"UUID","referenceKind":"foreignKey","notNull":false,"unique":false,"foreignKey":{"table":"campaign_channels","column":"id","onDelete":"NO ACTION","onUpdate":"CASCADE"}},"period_start":{"type":"TIMESTAMP","notNull":true,"unique":false},"period_end":{"type":"TIMESTAMP","notNull":true,"unique":false},"spend_cents":{"type":"INTEGER","notNull":false,"unique":false,"default":0},"impressions":{"type":"INTEGER","notNull":false,"unique":false,"default":0},"clicks":{"type":"INTEGER","notNull":false,"unique":false,"default":0},"conversions":{"type":"INTEGER","notNull":false,"unique":false,"default":0},"leads":{"type":"INTEGER","notNull":false,"unique":false,"default":0},"revenue_cents":{"type":"INTEGER","notNull":false,"unique":false},"source":{"type":"TEXT","notNull":true,"unique":false,"default":""},"dedupe_key":{"type":"TEXT","notNull":true,"unique":false,"default":""}},"indexes":[{"name":"campaign_metric_snapshots_dedupe_key_idx","columns":["dedupe_key"],"unique":true},{"name":"campaign_metric_snapshots_slug_context_idx","columns":["slug","context"]},{"name":"campaign_metric_snapshots_tenant_id_created_at_idx","columns":["tenant_id","created_at"]},{"name":"campaign_metric_snapshots_campaign_id_idx","columns":["campaign_id"]},{"name":"campaign_metric_snapshots_campaign_channel_id_idx","columns":["campaign_channel_id"]}],"version":"1ccd36b3"},"importPath":"@happyvertical/smrt-marketing"},"@happyvertical/smrt-marketing:Campaign":{"name":"campaign","className":"Campaign","qualifiedName":"@happyvertical/smrt-marketing:Campaign","collection":"campaigns","filePath":"/home/runner/work/smrt/smrt/packages/marketing/src/models/Campaign.ts","packageName":"@happyvertical/smrt-marketing","fields":{"tenantId":{"type":"text","required":false,"_meta":{"sqlType":"UUID","nullable":true,"__tenancy":{"isTenantIdField":true,"autoFilter":true,"required":false,"autoPopulate":true,"nullable":true,"mode":"optional","field":"tenantId","allowSuperAdminBypass":false}}},"customerId":{"type":"crossPackageRef","required":false,"related":"@happyvertical/smrt-commerce:Customer","_meta":{"validate":true,"nullable":true}},"campaignKey":{"type":"text","required":true,"default":"","_meta":{"required":true}},"name":{"type":"text","required":true,"default":"","_meta":{"required":true}},"objective":{"type":"text","required":false,"default":""},"status":{"type":"text","required":false,"default":"draft"},"startAt":{"type":"datetime","required":false},"endAt":{"type":"datetime","required":false},"budgetCents":{"type":"integer","required":false,"default":0},"currency":{"type":"text","required":false,"default":"USD"},"metadata":{"type":"text","required":false,"default":"{}"}},"methods":{"initialize":{"name":"initialize","async":true,"parameters":[],"returnType":"Promise<this>","isStatic":false,"isPublic":true},"save":{"name":"save","async":true,"parameters":[],"returnType":"Promise<this>","isStatic":false,"isPublic":true},"transitionTo":{"name":"transitionTo","async":false,"parameters":[{"name":"next","type":"CampaignStatus","optional":false}],"returnType":"this","isStatic":false,"isPublic":true},"getMetadata":{"name":"getMetadata","async":false,"parameters":[],"returnType":"Record<string, unknown>","isStatic":false,"isPublic":true},"setMetadata":{"name":"setMetadata","async":false,"parameters":[{"name":"metadata","type":"Record<string, unknown>","optional":false}],"returnType":"void","isStatic":false,"isPublic":true}},"decoratorConfig":{"tableName":"campaigns","conflictColumns":["tenant_id","campaign_key"],"indexes":[{"name":"campaigns_tenant_id_customer_id_start_at_id_idx","columns":["tenantId","customerId","startAt","id"]}],"api":{"include":["list","get","create","update"]},"mcp":{"include":["list","get","create","update"]},"cli":{"include":["list","get","create","update"]},"tenantScoped":{"mode":"optional"}},"extends":"SmrtObject","exportName":"Campaign","collectionExportName":"CampaignCollection","displayLabelField":"name","validationRules":[{"field":"campaignKey","rule":"required","fieldType":"text"},{"field":"name","rule":"required","fieldType":"text"}],"schema":{"tableName":"campaigns","ddl":"CREATE TABLE IF NOT EXISTS \\"campaigns\\" (\\n \\"id\\" UUID PRIMARY KEY NOT NULL,\\n \\"slug\\" TEXT NOT NULL,\\n \\"context\\" TEXT NOT NULL DEFAULT '',\\n \\"created_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"updated_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"tenant_id\\" UUID,\\n \\"customer_id\\" UUID,\\n \\"campaign_key\\" TEXT NOT NULL DEFAULT '',\\n \\"name\\" TEXT NOT NULL DEFAULT '',\\n \\"objective\\" TEXT DEFAULT '',\\n \\"status\\" TEXT DEFAULT 'draft',\\n \\"start_at\\" TIMESTAMP,\\n \\"end_at\\" TIMESTAMP,\\n \\"budget_cents\\" INTEGER DEFAULT 0,\\n \\"currency\\" TEXT DEFAULT 'USD',\\n \\"metadata\\" TEXT DEFAULT '{}'\\n);","columns":{"id":{"type":"UUID","primaryKey":true,"referenceKind":"id","notNull":true},"slug":{"type":"TEXT","notNull":true},"context":{"type":"TEXT","notNull":true,"default":""},"created_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"updated_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"tenant_id":{"type":"UUID","referenceKind":"tenantId","notNull":false,"unique":false},"customer_id":{"type":"UUID","referenceKind":"crossPackageRef","notNull":false,"unique":false},"campaign_key":{"type":"TEXT","notNull":true,"unique":false,"default":""},"name":{"type":"TEXT","notNull":true,"unique":false,"default":""},"objective":{"type":"TEXT","notNull":false,"unique":false,"default":""},"status":{"type":"TEXT","notNull":false,"unique":false,"default":"draft"},"start_at":{"type":"TIMESTAMP","notNull":false,"unique":false},"end_at":{"type":"TIMESTAMP","notNull":false,"unique":false},"budget_cents":{"type":"INTEGER","notNull":false,"unique":false,"default":0},"currency":{"type":"TEXT","notNull":false,"unique":false,"default":"USD"},"metadata":{"type":"TEXT","notNull":false,"unique":false,"default":"{}"}},"indexes":[{"name":"campaigns_tenant_id_campaign_key_idx","columns":["tenant_id","campaign_key"],"unique":true,"nullsNotDistinct":true},{"name":"campaigns_slug_context_idx","columns":["slug","context"]},{"name":"campaigns_tenant_id_customer_id_start_at_id_idx","columns":["tenant_id","customer_id","start_at","id"]},{"name":"campaigns_tenant_id_created_at_idx","columns":["tenant_id","created_at"]},{"name":"campaigns_customer_id_idx","columns":["customer_id"]}],"version":"d0945102"},"importPath":"@happyvertical/smrt-marketing"},"@happyvertical/smrt-marketing:CampaignChannel":{"name":"campaignchannel","className":"CampaignChannel","qualifiedName":"@happyvertical/smrt-marketing:CampaignChannel","collection":"campaignchannels","filePath":"/home/runner/work/smrt/smrt/packages/marketing/src/models/CampaignChannel.ts","packageName":"@happyvertical/smrt-marketing","fields":{"tenantId":{"type":"text","required":false,"_meta":{"sqlType":"UUID","nullable":true,"__tenancy":{"isTenantIdField":true,"autoFilter":true,"required":false,"autoPopulate":true,"nullable":true,"mode":"optional","field":"tenantId","allowSuperAdminBypass":false}}},"campaignId":{"type":"foreignKey","required":true,"related":"Campaign","_meta":{"required":true}},"channelKind":{"type":"text","required":true,"default":"","_meta":{"required":true}},"channelRef":{"type":"text","required":true,"default":"","_meta":{"required":true}},"allocatedBudgetCents":{"type":"integer","required":false,"default":0},"startAt":{"type":"datetime","required":false},"endAt":{"type":"datetime","required":false},"status":{"type":"text","required":false,"default":"planned"}},"methods":{"initialize":{"name":"initialize","async":true,"parameters":[],"returnType":"Promise<this>","isStatic":false,"isPublic":true},"save":{"name":"save","async":true,"parameters":[],"returnType":"Promise<this>","isStatic":false,"isPublic":true}},"decoratorConfig":{"tableName":"campaign_channels","conflictColumns":["campaign_id","channel_kind","channel_ref"],"api":{"include":["list","get","create","update","delete"]},"mcp":{"include":["list","get","create","update"]},"cli":{"include":["list","get","create","update","delete"]},"tenantScoped":{"mode":"optional"}},"extends":"SmrtObject","exportName":"CampaignChannel","collectionExportName":"CampaignChannelCollection","validationRules":[{"field":"campaignId","rule":"required","fieldType":"foreignKey"},{"field":"channelKind","rule":"required","fieldType":"text"},{"field":"channelRef","rule":"required","fieldType":"text"}],"schema":{"tableName":"campaign_channels","ddl":"CREATE TABLE IF NOT EXISTS \\"campaign_channels\\" (\\n \\"id\\" UUID PRIMARY KEY NOT NULL,\\n \\"slug\\" TEXT NOT NULL,\\n \\"context\\" TEXT NOT NULL DEFAULT '',\\n \\"created_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"updated_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"tenant_id\\" UUID,\\n \\"campaign_id\\" UUID NOT NULL,\\n \\"channel_kind\\" TEXT NOT NULL DEFAULT '',\\n \\"channel_ref\\" TEXT NOT NULL DEFAULT '',\\n \\"allocated_budget_cents\\" INTEGER DEFAULT 0,\\n \\"start_at\\" TIMESTAMP,\\n \\"end_at\\" TIMESTAMP,\\n \\"status\\" TEXT DEFAULT 'planned'\\n);","columns":{"id":{"type":"UUID","primaryKey":true,"referenceKind":"id","notNull":true},"slug":{"type":"TEXT","notNull":true},"context":{"type":"TEXT","notNull":true,"default":""},"created_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"updated_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"tenant_id":{"type":"UUID","referenceKind":"tenantId","notNull":false,"unique":false},"campaign_id":{"type":"UUID","referenceKind":"foreignKey","notNull":true,"unique":false,"foreignKey":{"table":"campaigns","column":"id","onDelete":"CASCADE","onUpdate":"CASCADE"}},"channel_kind":{"type":"TEXT","notNull":true,"unique":false,"default":""},"channel_ref":{"type":"TEXT","notNull":true,"unique":false,"default":""},"allocated_budget_cents":{"type":"INTEGER","notNull":false,"unique":false,"default":0},"start_at":{"type":"TIMESTAMP","notNull":false,"unique":false},"end_at":{"type":"TIMESTAMP","notNull":false,"unique":false},"status":{"type":"TEXT","notNull":false,"unique":false,"default":"planned"}},"indexes":[{"name":"campaign_channels_campaign_id_channel_kind_idx","columns":["campaign_id","channel_kind","channel_ref"],"unique":true},{"name":"campaign_channels_slug_context_idx","columns":["slug","context"]},{"name":"campaign_channels_tenant_id_created_at_idx","columns":["tenant_id","created_at"]}],"version":"cc045525"},"importPath":"@happyvertical/smrt-marketing"},"@happyvertical/smrt-marketing:CampaignMetricSnapshot":{"name":"campaignmetricsnapshot","className":"CampaignMetricSnapshot","qualifiedName":"@happyvertical/smrt-marketing:CampaignMetricSnapshot","collection":"campaignmetricsnapshots","filePath":"/home/runner/work/smrt/smrt/packages/marketing/src/models/CampaignMetricSnapshot.ts","packageName":"@happyvertical/smrt-marketing","fields":{"tenantId":{"type":"text","required":false,"_meta":{"sqlType":"UUID","nullable":true,"__tenancy":{"isTenantIdField":true,"autoFilter":true,"required":false,"autoPopulate":true,"nullable":true,"mode":"optional","field":"tenantId","allowSuperAdminBypass":false}}},"campaignId":{"type":"foreignKey","required":true,"related":"Campaign","_meta":{"required":true}},"campaignChannelId":{"type":"foreignKey","required":false,"related":"CampaignChannel","_meta":{"nullable":true}},"periodStart":{"type":"datetime","required":true,"_meta":{"required":true}},"periodEnd":{"type":"datetime","required":true,"_meta":{"required":true}},"spendCents":{"type":"integer","required":false,"default":0},"impressions":{"type":"integer","required":false,"default":0},"clicks":{"type":"integer","required":false,"default":0},"conversions":{"type":"integer","required":false,"default":0},"leads":{"type":"integer","required":false,"default":0},"revenueCents":{"type":"integer","required":false,"_meta":{"nullable":true}},"source":{"type":"text","required":true,"default":"","_meta":{"required":true}},"dedupeKey":{"type":"text","required":true,"default":"","_meta":{"required":true}}},"methods":{"initialize":{"name":"initialize","async":true,"parameters":[],"returnType":"Promise<this>","isStatic":false,"isPublic":true},"save":{"name":"save","async":true,"parameters":[],"returnType":"Promise<this>","isStatic":false,"isPublic":true},"delete":{"name":"delete","async":true,"parameters":[],"returnType":"Promise<void>","isStatic":false,"isPublic":true}},"decoratorConfig":{"tableName":"campaign_metric_snapshots","conflictColumns":["dedupe_key"],"api":{"include":["list","get","create"]},"mcp":{"include":["list","get","create"]},"cli":{"include":["list","get","create"]},"tenantScoped":{"mode":"optional"}},"extends":"SmrtObject","exportName":"CampaignMetricSnapshot","collectionExportName":"CampaignMetricSnapshotCollection","validationRules":[{"field":"campaignId","rule":"required","fieldType":"foreignKey"},{"field":"periodStart","rule":"required","fieldType":"datetime"},{"field":"periodEnd","rule":"required","fieldType":"datetime"},{"field":"source","rule":"required","fieldType":"text"},{"field":"dedupeKey","rule":"required","fieldType":"text"}],"schema":{"tableName":"campaign_metric_snapshots","ddl":"CREATE TABLE IF NOT EXISTS \\"campaign_metric_snapshots\\" (\\n \\"id\\" UUID PRIMARY KEY NOT NULL,\\n \\"slug\\" TEXT NOT NULL,\\n \\"context\\" TEXT NOT NULL DEFAULT '',\\n \\"created_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"updated_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"tenant_id\\" UUID,\\n \\"campaign_id\\" UUID NOT NULL,\\n \\"campaign_channel_id\\" UUID,\\n \\"period_start\\" TIMESTAMP NOT NULL,\\n \\"period_end\\" TIMESTAMP NOT NULL,\\n \\"spend_cents\\" INTEGER DEFAULT 0,\\n \\"impressions\\" INTEGER DEFAULT 0,\\n \\"clicks\\" INTEGER DEFAULT 0,\\n \\"conversions\\" INTEGER DEFAULT 0,\\n \\"leads\\" INTEGER DEFAULT 0,\\n \\"revenue_cents\\" INTEGER,\\n \\"source\\" TEXT NOT NULL DEFAULT '',\\n \\"dedupe_key\\" TEXT NOT NULL DEFAULT ''\\n);","columns":{"id":{"type":"UUID","primaryKey":true,"referenceKind":"id","notNull":true},"slug":{"type":"TEXT","notNull":true},"context":{"type":"TEXT","notNull":true,"default":""},"created_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"updated_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"tenant_id":{"type":"UUID","referenceKind":"tenantId","notNull":false,"unique":false},"campaign_id":{"type":"UUID","referenceKind":"foreignKey","notNull":true,"unique":false,"foreignKey":{"table":"campaigns","column":"id","onDelete":"NO ACTION","onUpdate":"CASCADE"}},"campaign_channel_id":{"type":"UUID","referenceKind":"foreignKey","notNull":false,"unique":false,"foreignKey":{"table":"campaign_channels","column":"id","onDelete":"NO ACTION","onUpdate":"CASCADE"}},"period_start":{"type":"TIMESTAMP","notNull":true,"unique":false},"period_end":{"type":"TIMESTAMP","notNull":true,"unique":false},"spend_cents":{"type":"INTEGER","notNull":false,"unique":false,"default":0},"impressions":{"type":"INTEGER","notNull":false,"unique":false,"default":0},"clicks":{"type":"INTEGER","notNull":false,"unique":false,"default":0},"conversions":{"type":"INTEGER","notNull":false,"unique":false,"default":0},"leads":{"type":"INTEGER","notNull":false,"unique":false,"default":0},"revenue_cents":{"type":"INTEGER","notNull":false,"unique":false},"source":{"type":"TEXT","notNull":true,"unique":false,"default":""},"dedupe_key":{"type":"TEXT","notNull":true,"unique":false,"default":""}},"indexes":[{"name":"campaign_metric_snapshots_dedupe_key_idx","columns":["dedupe_key"],"unique":true},{"name":"campaign_metric_snapshots_slug_context_idx","columns":["slug","context"]},{"name":"campaign_metric_snapshots_tenant_id_created_at_idx","columns":["tenant_id","created_at"]},{"name":"campaign_metric_snapshots_campaign_id_idx","columns":["campaign_id"]},{"name":"campaign_metric_snapshots_campaign_channel_id_idx","columns":["campaign_channel_id"]}],"version":"1ccd36b3"},"importPath":"@happyvertical/smrt-marketing"}},"moduleType":"smrt","smrtDependencies":["@happyvertical/smrt-commerce","@happyvertical/smrt-core","@happyvertical/smrt-tenancy"],"browser":{"status":"server-only","issues":["#3624"],"via":["@happyvertical/smrt-tenancy"]},"stampsConstructors":true}`));
|
|
5
|
+
ObjectRegistry.registerPackageManifest(JSON.parse(`{"version":"1.0.0","timestamp":0,"packageName":"@happyvertical/smrt-marketing","packageVersion":"0.57.5","objects":{"@happyvertical/smrt-marketing:CampaignChannelCollection":{"name":"campaignchannelcollection","className":"CampaignChannelCollection","qualifiedName":"@happyvertical/smrt-marketing:CampaignChannelCollection","collection":"campaignchannels","filePath":"/home/runner/work/smrt/smrt/packages/marketing/src/collections/CampaignChannelCollection.ts","packageName":"@happyvertical/smrt-marketing","fields":{},"methods":{"findByCampaign":{"name":"findByCampaign","async":true,"parameters":[{"name":"campaignId","type":"string","optional":false}],"returnType":"Promise<CampaignChannel[]>","isStatic":false,"isPublic":true},"findByExecutionRef":{"name":"findByExecutionRef","async":true,"parameters":[{"name":"channelKind","type":"string","optional":false},{"name":"channelRef","type":"string","optional":false}],"returnType":"Promise<CampaignChannel[]>","isStatic":false,"isPublic":true}},"decoratorConfig":{"tableName":"campaign_channels","api":{"include":["list","get","create","update","delete"]},"mcp":{"include":["list","get","create","update"]},"cli":{"include":["list","get","create","update","delete"]}},"extends":"SmrtCollection","extendsTypeArg":"CampaignChannel","exportName":"CampaignChannelCollection","collectionExportName":"CampaignChannelCollectionCollection","schema":{"tableName":"campaign_channels","ddl":"CREATE TABLE IF NOT EXISTS \\"campaign_channels\\" (\\n \\"id\\" UUID PRIMARY KEY NOT NULL,\\n \\"slug\\" TEXT NOT NULL,\\n \\"context\\" TEXT NOT NULL DEFAULT '',\\n \\"created_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"updated_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"tenant_id\\" UUID,\\n \\"campaign_id\\" UUID NOT NULL,\\n \\"channel_kind\\" TEXT NOT NULL DEFAULT '',\\n \\"channel_ref\\" TEXT NOT NULL DEFAULT '',\\n \\"allocated_budget_cents\\" INTEGER DEFAULT 0,\\n \\"start_at\\" TIMESTAMP,\\n \\"end_at\\" TIMESTAMP,\\n \\"status\\" TEXT DEFAULT 'planned'\\n);","columns":{"id":{"type":"UUID","primaryKey":true,"referenceKind":"id","notNull":true},"slug":{"type":"TEXT","notNull":true},"context":{"type":"TEXT","notNull":true,"default":""},"created_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"updated_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"tenant_id":{"type":"UUID","referenceKind":"tenantId","notNull":false,"unique":false},"campaign_id":{"type":"UUID","referenceKind":"foreignKey","notNull":true,"unique":false,"foreignKey":{"table":"campaigns","column":"id","onDelete":"CASCADE","onUpdate":"CASCADE"}},"channel_kind":{"type":"TEXT","notNull":true,"unique":false,"default":""},"channel_ref":{"type":"TEXT","notNull":true,"unique":false,"default":""},"allocated_budget_cents":{"type":"INTEGER","notNull":false,"unique":false,"default":0},"start_at":{"type":"TIMESTAMP","notNull":false,"unique":false},"end_at":{"type":"TIMESTAMP","notNull":false,"unique":false},"status":{"type":"TEXT","notNull":false,"unique":false,"default":"planned"}},"indexes":[{"name":"campaign_channels_campaign_id_channel_kind_idx","columns":["campaign_id","channel_kind","channel_ref"],"unique":true},{"name":"campaign_channels_slug_context_idx","columns":["slug","context"]},{"name":"campaign_channels_tenant_id_created_at_idx","columns":["tenant_id","created_at"]}],"version":"cc045525"},"importPath":"@happyvertical/smrt-marketing"},"@happyvertical/smrt-marketing:CampaignCollection":{"name":"campaigncollection","className":"CampaignCollection","qualifiedName":"@happyvertical/smrt-marketing:CampaignCollection","collection":"campaigns","filePath":"/home/runner/work/smrt/smrt/packages/marketing/src/collections/CampaignCollection.ts","packageName":"@happyvertical/smrt-marketing","fields":{},"methods":{"get":{"name":"get","async":true,"parameters":[{"name":"filter","type":"string | SmrtWhereClause<Campaign>","optional":false,"unionBranches":[{"type":"string"},{"type":"SmrtWhereClause<Campaign>"}]},{"name":"options","type":"object","optional":true,"memberTypes":["CollectionCacheConfig | false"]}],"returnType":"Promise<Campaign | null>","isStatic":false,"isPublic":true},"list":{"name":"list","async":true,"parameters":[{"name":"options","type":"SmrtListOptions<Campaign>","optional":true}],"returnType":"Promise<Campaign[] | Record<string, unknown>[]>","isStatic":false,"isPublic":true},"findByCampaignKey":{"name":"findByCampaignKey","async":true,"parameters":[{"name":"campaignKey","type":"string","optional":false},{"name":"tenantId","type":"string | null","optional":true,"unionBranches":[{"type":"string"},{"type":"null"}]}],"returnType":"Promise<Campaign | null>","isStatic":false,"isPublic":true},"findByStatus":{"name":"findByStatus","async":true,"parameters":[{"name":"status","type":"CampaignStatus","optional":false}],"returnType":"Promise<Campaign[]>","isStatic":false,"isPublic":true},"listByCustomer":{"name":"listByCustomer","async":true,"parameters":[{"name":"tenantId","type":"string | null","optional":false,"unionBranches":[{"type":"string"},{"type":"null"}]},{"name":"customerId","type":"string","optional":false},{"name":"options","type":"ListCampaignsByCustomerOptions","optional":true}],"returnType":"Promise<CampaignCustomerPage>","isStatic":false,"isPublic":true},"listReportingByCustomer":{"name":"listReportingByCustomer","async":true,"parameters":[{"name":"tenantId","type":"string | null","optional":false,"unionBranches":[{"type":"string"},{"type":"null"}]},{"name":"customerId","type":"string","optional":false},{"name":"options","type":"ListCampaignReportingByCustomerOptions","optional":true}],"returnType":"Promise<CampaignReportingPage>","isStatic":false,"isPublic":true},"summarizeByCustomers":{"name":"summarizeByCustomers","async":true,"parameters":[{"name":"tenantId","type":"string | null","optional":false,"unionBranches":[{"type":"string"},{"type":"null"}]},{"name":"customerIds","type":"string[]","optional":false}],"returnType":"Promise<CampaignCustomerSummary[]>","isStatic":false,"isPublic":true}},"decoratorConfig":{"tableName":"campaigns","api":{"include":["list","get","create","update"]},"mcp":{"include":["list","get","create","update"]},"cli":{"include":["list","get","create","update"]}},"extends":"SmrtCollection","extendsTypeArg":"Campaign","exportName":"CampaignCollection","collectionExportName":"CampaignCollectionCollection","schema":{"tableName":"campaigns","ddl":"CREATE TABLE IF NOT EXISTS \\"campaigns\\" (\\n \\"id\\" UUID PRIMARY KEY NOT NULL,\\n \\"slug\\" TEXT NOT NULL,\\n \\"context\\" TEXT NOT NULL DEFAULT '',\\n \\"created_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"updated_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"tenant_id\\" UUID,\\n \\"customer_id\\" UUID,\\n \\"campaign_key\\" TEXT NOT NULL DEFAULT '',\\n \\"name\\" TEXT NOT NULL DEFAULT '',\\n \\"objective\\" TEXT DEFAULT '',\\n \\"status\\" TEXT DEFAULT 'draft',\\n \\"start_at\\" TIMESTAMP,\\n \\"end_at\\" TIMESTAMP,\\n \\"budget_cents\\" INTEGER DEFAULT 0,\\n \\"currency\\" TEXT DEFAULT 'USD',\\n \\"metadata\\" TEXT DEFAULT '{}'\\n);","columns":{"id":{"type":"UUID","primaryKey":true,"referenceKind":"id","notNull":true},"slug":{"type":"TEXT","notNull":true},"context":{"type":"TEXT","notNull":true,"default":""},"created_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"updated_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"tenant_id":{"type":"UUID","referenceKind":"tenantId","notNull":false,"unique":false},"customer_id":{"type":"UUID","referenceKind":"crossPackageRef","notNull":false,"unique":false},"campaign_key":{"type":"TEXT","notNull":true,"unique":false,"default":""},"name":{"type":"TEXT","notNull":true,"unique":false,"default":""},"objective":{"type":"TEXT","notNull":false,"unique":false,"default":""},"status":{"type":"TEXT","notNull":false,"unique":false,"default":"draft"},"start_at":{"type":"TIMESTAMP","notNull":false,"unique":false},"end_at":{"type":"TIMESTAMP","notNull":false,"unique":false},"budget_cents":{"type":"INTEGER","notNull":false,"unique":false,"default":0},"currency":{"type":"TEXT","notNull":false,"unique":false,"default":"USD"},"metadata":{"type":"TEXT","notNull":false,"unique":false,"default":"{}"}},"indexes":[{"name":"campaigns_tenant_id_campaign_key_idx","columns":["tenant_id","campaign_key"],"unique":true,"nullsNotDistinct":true},{"name":"campaigns_slug_context_idx","columns":["slug","context"]},{"name":"campaigns_tenant_id_customer_id_start_at_id_idx","columns":["tenant_id","customer_id","start_at","id"]},{"name":"campaigns_tenant_id_created_at_idx","columns":["tenant_id","created_at"]},{"name":"campaigns_customer_id_idx","columns":["customer_id"]}],"version":"d0945102"},"importPath":"@happyvertical/smrt-marketing"},"@happyvertical/smrt-marketing:CampaignMetricSnapshotCollection":{"name":"campaignmetricsnapshotcollection","className":"CampaignMetricSnapshotCollection","qualifiedName":"@happyvertical/smrt-marketing:CampaignMetricSnapshotCollection","collection":"campaignmetricsnapshots","filePath":"/home/runner/work/smrt/smrt/packages/marketing/src/collections/CampaignMetricSnapshotCollection.ts","packageName":"@happyvertical/smrt-marketing","fields":{},"methods":{"findByDedupeKey":{"name":"findByDedupeKey","async":true,"parameters":[{"name":"dedupeKey","type":"string","optional":false}],"returnType":"Promise<CampaignMetricSnapshot | null>","isStatic":false,"isPublic":true},"getOrCreateByDedupeKey":{"name":"getOrCreateByDedupeKey","async":true,"parameters":[{"name":"options","type":"CampaignMetricSnapshotOptions","optional":false}],"returnType":"Promise<object>","isStatic":false,"isPublic":true},"findByCampaign":{"name":"findByCampaign","async":true,"parameters":[{"name":"campaignId","type":"string","optional":false}],"returnType":"Promise<CampaignMetricSnapshot[]>","isStatic":false,"isPublic":true},"findByChannel":{"name":"findByChannel","async":true,"parameters":[{"name":"campaignChannelId","type":"string","optional":false}],"returnType":"Promise<CampaignMetricSnapshot[]>","isStatic":false,"isPublic":true}},"decoratorConfig":{"tableName":"campaign_metric_snapshots","api":{"include":["list","get","create"]},"mcp":{"include":["list","get","create"]},"cli":{"include":["list","get","create"]}},"extends":"SmrtCollection","extendsTypeArg":"CampaignMetricSnapshot","exportName":"CampaignMetricSnapshotCollection","collectionExportName":"CampaignMetricSnapshotCollectionCollection","schema":{"tableName":"campaign_metric_snapshots","ddl":"CREATE TABLE IF NOT EXISTS \\"campaign_metric_snapshots\\" (\\n \\"id\\" UUID PRIMARY KEY NOT NULL,\\n \\"slug\\" TEXT NOT NULL,\\n \\"context\\" TEXT NOT NULL DEFAULT '',\\n \\"created_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"updated_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"tenant_id\\" UUID,\\n \\"campaign_id\\" UUID NOT NULL,\\n \\"campaign_channel_id\\" UUID,\\n \\"period_start\\" TIMESTAMP NOT NULL,\\n \\"period_end\\" TIMESTAMP NOT NULL,\\n \\"spend_cents\\" INTEGER DEFAULT 0,\\n \\"impressions\\" INTEGER DEFAULT 0,\\n \\"clicks\\" INTEGER DEFAULT 0,\\n \\"conversions\\" INTEGER DEFAULT 0,\\n \\"leads\\" INTEGER DEFAULT 0,\\n \\"revenue_cents\\" INTEGER,\\n \\"source\\" TEXT NOT NULL DEFAULT '',\\n \\"dedupe_key\\" TEXT NOT NULL DEFAULT ''\\n);","columns":{"id":{"type":"UUID","primaryKey":true,"referenceKind":"id","notNull":true},"slug":{"type":"TEXT","notNull":true},"context":{"type":"TEXT","notNull":true,"default":""},"created_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"updated_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"tenant_id":{"type":"UUID","referenceKind":"tenantId","notNull":false,"unique":false},"campaign_id":{"type":"UUID","referenceKind":"foreignKey","notNull":true,"unique":false,"foreignKey":{"table":"campaigns","column":"id","onDelete":"NO ACTION","onUpdate":"CASCADE"}},"campaign_channel_id":{"type":"UUID","referenceKind":"foreignKey","notNull":false,"unique":false,"foreignKey":{"table":"campaign_channels","column":"id","onDelete":"NO ACTION","onUpdate":"CASCADE"}},"period_start":{"type":"TIMESTAMP","notNull":true,"unique":false},"period_end":{"type":"TIMESTAMP","notNull":true,"unique":false},"spend_cents":{"type":"INTEGER","notNull":false,"unique":false,"default":0},"impressions":{"type":"INTEGER","notNull":false,"unique":false,"default":0},"clicks":{"type":"INTEGER","notNull":false,"unique":false,"default":0},"conversions":{"type":"INTEGER","notNull":false,"unique":false,"default":0},"leads":{"type":"INTEGER","notNull":false,"unique":false,"default":0},"revenue_cents":{"type":"INTEGER","notNull":false,"unique":false},"source":{"type":"TEXT","notNull":true,"unique":false,"default":""},"dedupe_key":{"type":"TEXT","notNull":true,"unique":false,"default":""}},"indexes":[{"name":"campaign_metric_snapshots_dedupe_key_idx","columns":["dedupe_key"],"unique":true},{"name":"campaign_metric_snapshots_slug_context_idx","columns":["slug","context"]},{"name":"campaign_metric_snapshots_tenant_id_created_at_idx","columns":["tenant_id","created_at"]},{"name":"campaign_metric_snapshots_campaign_id_idx","columns":["campaign_id"]},{"name":"campaign_metric_snapshots_campaign_channel_id_idx","columns":["campaign_channel_id"]}],"version":"1ccd36b3"},"importPath":"@happyvertical/smrt-marketing"},"@happyvertical/smrt-marketing:Campaign":{"name":"campaign","className":"Campaign","qualifiedName":"@happyvertical/smrt-marketing:Campaign","collection":"campaigns","filePath":"/home/runner/work/smrt/smrt/packages/marketing/src/models/Campaign.ts","packageName":"@happyvertical/smrt-marketing","fields":{"tenantId":{"type":"text","required":false,"_meta":{"sqlType":"UUID","nullable":true,"__tenancy":{"isTenantIdField":true,"autoFilter":true,"required":false,"autoPopulate":true,"nullable":true,"mode":"optional","field":"tenantId","allowSuperAdminBypass":false}}},"customerId":{"type":"crossPackageRef","required":false,"related":"@happyvertical/smrt-commerce:Customer","_meta":{"validate":true,"nullable":true}},"campaignKey":{"type":"text","required":true,"default":"","_meta":{"required":true}},"name":{"type":"text","required":true,"default":"","_meta":{"required":true}},"objective":{"type":"text","required":false,"default":""},"status":{"type":"text","required":false,"default":"draft"},"startAt":{"type":"datetime","required":false},"endAt":{"type":"datetime","required":false},"budgetCents":{"type":"integer","required":false,"default":0},"currency":{"type":"text","required":false,"default":"USD"},"metadata":{"type":"text","required":false,"default":"{}"}},"methods":{"initialize":{"name":"initialize","async":true,"parameters":[],"returnType":"Promise<this>","isStatic":false,"isPublic":true},"save":{"name":"save","async":true,"parameters":[],"returnType":"Promise<this>","isStatic":false,"isPublic":true},"transitionTo":{"name":"transitionTo","async":false,"parameters":[{"name":"next","type":"CampaignStatus","optional":false}],"returnType":"this","isStatic":false,"isPublic":true},"getMetadata":{"name":"getMetadata","async":false,"parameters":[],"returnType":"Record<string, unknown>","isStatic":false,"isPublic":true},"setMetadata":{"name":"setMetadata","async":false,"parameters":[{"name":"metadata","type":"Record<string, unknown>","optional":false}],"returnType":"void","isStatic":false,"isPublic":true}},"decoratorConfig":{"tableName":"campaigns","conflictColumns":["tenant_id","campaign_key"],"indexes":[{"name":"campaigns_tenant_id_customer_id_start_at_id_idx","columns":["tenantId","customerId","startAt","id"]}],"api":{"include":["list","get","create","update"]},"mcp":{"include":["list","get","create","update"]},"cli":{"include":["list","get","create","update"]},"tenantScoped":{"mode":"optional"}},"extends":"SmrtObject","exportName":"Campaign","collectionExportName":"CampaignCollection","displayLabelField":"name","validationRules":[{"field":"campaignKey","rule":"required","fieldType":"text"},{"field":"name","rule":"required","fieldType":"text"}],"schema":{"tableName":"campaigns","ddl":"CREATE TABLE IF NOT EXISTS \\"campaigns\\" (\\n \\"id\\" UUID PRIMARY KEY NOT NULL,\\n \\"slug\\" TEXT NOT NULL,\\n \\"context\\" TEXT NOT NULL DEFAULT '',\\n \\"created_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"updated_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"tenant_id\\" UUID,\\n \\"customer_id\\" UUID,\\n \\"campaign_key\\" TEXT NOT NULL DEFAULT '',\\n \\"name\\" TEXT NOT NULL DEFAULT '',\\n \\"objective\\" TEXT DEFAULT '',\\n \\"status\\" TEXT DEFAULT 'draft',\\n \\"start_at\\" TIMESTAMP,\\n \\"end_at\\" TIMESTAMP,\\n \\"budget_cents\\" INTEGER DEFAULT 0,\\n \\"currency\\" TEXT DEFAULT 'USD',\\n \\"metadata\\" TEXT DEFAULT '{}'\\n);","columns":{"id":{"type":"UUID","primaryKey":true,"referenceKind":"id","notNull":true},"slug":{"type":"TEXT","notNull":true},"context":{"type":"TEXT","notNull":true,"default":""},"created_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"updated_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"tenant_id":{"type":"UUID","referenceKind":"tenantId","notNull":false,"unique":false},"customer_id":{"type":"UUID","referenceKind":"crossPackageRef","notNull":false,"unique":false},"campaign_key":{"type":"TEXT","notNull":true,"unique":false,"default":""},"name":{"type":"TEXT","notNull":true,"unique":false,"default":""},"objective":{"type":"TEXT","notNull":false,"unique":false,"default":""},"status":{"type":"TEXT","notNull":false,"unique":false,"default":"draft"},"start_at":{"type":"TIMESTAMP","notNull":false,"unique":false},"end_at":{"type":"TIMESTAMP","notNull":false,"unique":false},"budget_cents":{"type":"INTEGER","notNull":false,"unique":false,"default":0},"currency":{"type":"TEXT","notNull":false,"unique":false,"default":"USD"},"metadata":{"type":"TEXT","notNull":false,"unique":false,"default":"{}"}},"indexes":[{"name":"campaigns_tenant_id_campaign_key_idx","columns":["tenant_id","campaign_key"],"unique":true,"nullsNotDistinct":true},{"name":"campaigns_slug_context_idx","columns":["slug","context"]},{"name":"campaigns_tenant_id_customer_id_start_at_id_idx","columns":["tenant_id","customer_id","start_at","id"]},{"name":"campaigns_tenant_id_created_at_idx","columns":["tenant_id","created_at"]},{"name":"campaigns_customer_id_idx","columns":["customer_id"]}],"version":"d0945102"},"importPath":"@happyvertical/smrt-marketing"},"@happyvertical/smrt-marketing:CampaignChannel":{"name":"campaignchannel","className":"CampaignChannel","qualifiedName":"@happyvertical/smrt-marketing:CampaignChannel","collection":"campaignchannels","filePath":"/home/runner/work/smrt/smrt/packages/marketing/src/models/CampaignChannel.ts","packageName":"@happyvertical/smrt-marketing","fields":{"tenantId":{"type":"text","required":false,"_meta":{"sqlType":"UUID","nullable":true,"__tenancy":{"isTenantIdField":true,"autoFilter":true,"required":false,"autoPopulate":true,"nullable":true,"mode":"optional","field":"tenantId","allowSuperAdminBypass":false}}},"campaignId":{"type":"foreignKey","required":true,"related":"Campaign","_meta":{"required":true}},"channelKind":{"type":"text","required":true,"default":"","_meta":{"required":true}},"channelRef":{"type":"text","required":true,"default":"","_meta":{"required":true}},"allocatedBudgetCents":{"type":"integer","required":false,"default":0},"startAt":{"type":"datetime","required":false},"endAt":{"type":"datetime","required":false},"status":{"type":"text","required":false,"default":"planned"}},"methods":{"initialize":{"name":"initialize","async":true,"parameters":[],"returnType":"Promise<this>","isStatic":false,"isPublic":true},"save":{"name":"save","async":true,"parameters":[],"returnType":"Promise<this>","isStatic":false,"isPublic":true}},"decoratorConfig":{"tableName":"campaign_channels","conflictColumns":["campaign_id","channel_kind","channel_ref"],"api":{"include":["list","get","create","update","delete"]},"mcp":{"include":["list","get","create","update"]},"cli":{"include":["list","get","create","update","delete"]},"tenantScoped":{"mode":"optional"}},"extends":"SmrtObject","exportName":"CampaignChannel","collectionExportName":"CampaignChannelCollection","validationRules":[{"field":"campaignId","rule":"required","fieldType":"foreignKey"},{"field":"channelKind","rule":"required","fieldType":"text"},{"field":"channelRef","rule":"required","fieldType":"text"}],"schema":{"tableName":"campaign_channels","ddl":"CREATE TABLE IF NOT EXISTS \\"campaign_channels\\" (\\n \\"id\\" UUID PRIMARY KEY NOT NULL,\\n \\"slug\\" TEXT NOT NULL,\\n \\"context\\" TEXT NOT NULL DEFAULT '',\\n \\"created_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"updated_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"tenant_id\\" UUID,\\n \\"campaign_id\\" UUID NOT NULL,\\n \\"channel_kind\\" TEXT NOT NULL DEFAULT '',\\n \\"channel_ref\\" TEXT NOT NULL DEFAULT '',\\n \\"allocated_budget_cents\\" INTEGER DEFAULT 0,\\n \\"start_at\\" TIMESTAMP,\\n \\"end_at\\" TIMESTAMP,\\n \\"status\\" TEXT DEFAULT 'planned'\\n);","columns":{"id":{"type":"UUID","primaryKey":true,"referenceKind":"id","notNull":true},"slug":{"type":"TEXT","notNull":true},"context":{"type":"TEXT","notNull":true,"default":""},"created_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"updated_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"tenant_id":{"type":"UUID","referenceKind":"tenantId","notNull":false,"unique":false},"campaign_id":{"type":"UUID","referenceKind":"foreignKey","notNull":true,"unique":false,"foreignKey":{"table":"campaigns","column":"id","onDelete":"CASCADE","onUpdate":"CASCADE"}},"channel_kind":{"type":"TEXT","notNull":true,"unique":false,"default":""},"channel_ref":{"type":"TEXT","notNull":true,"unique":false,"default":""},"allocated_budget_cents":{"type":"INTEGER","notNull":false,"unique":false,"default":0},"start_at":{"type":"TIMESTAMP","notNull":false,"unique":false},"end_at":{"type":"TIMESTAMP","notNull":false,"unique":false},"status":{"type":"TEXT","notNull":false,"unique":false,"default":"planned"}},"indexes":[{"name":"campaign_channels_campaign_id_channel_kind_idx","columns":["campaign_id","channel_kind","channel_ref"],"unique":true},{"name":"campaign_channels_slug_context_idx","columns":["slug","context"]},{"name":"campaign_channels_tenant_id_created_at_idx","columns":["tenant_id","created_at"]}],"version":"cc045525"},"importPath":"@happyvertical/smrt-marketing"},"@happyvertical/smrt-marketing:CampaignMetricSnapshot":{"name":"campaignmetricsnapshot","className":"CampaignMetricSnapshot","qualifiedName":"@happyvertical/smrt-marketing:CampaignMetricSnapshot","collection":"campaignmetricsnapshots","filePath":"/home/runner/work/smrt/smrt/packages/marketing/src/models/CampaignMetricSnapshot.ts","packageName":"@happyvertical/smrt-marketing","fields":{"tenantId":{"type":"text","required":false,"_meta":{"sqlType":"UUID","nullable":true,"__tenancy":{"isTenantIdField":true,"autoFilter":true,"required":false,"autoPopulate":true,"nullable":true,"mode":"optional","field":"tenantId","allowSuperAdminBypass":false}}},"campaignId":{"type":"foreignKey","required":true,"related":"Campaign","_meta":{"required":true}},"campaignChannelId":{"type":"foreignKey","required":false,"related":"CampaignChannel","_meta":{"nullable":true}},"periodStart":{"type":"datetime","required":true,"_meta":{"required":true}},"periodEnd":{"type":"datetime","required":true,"_meta":{"required":true}},"spendCents":{"type":"integer","required":false,"default":0},"impressions":{"type":"integer","required":false,"default":0},"clicks":{"type":"integer","required":false,"default":0},"conversions":{"type":"integer","required":false,"default":0},"leads":{"type":"integer","required":false,"default":0},"revenueCents":{"type":"integer","required":false,"_meta":{"nullable":true}},"source":{"type":"text","required":true,"default":"","_meta":{"required":true}},"dedupeKey":{"type":"text","required":true,"default":"","_meta":{"required":true}}},"methods":{"initialize":{"name":"initialize","async":true,"parameters":[],"returnType":"Promise<this>","isStatic":false,"isPublic":true},"save":{"name":"save","async":true,"parameters":[],"returnType":"Promise<this>","isStatic":false,"isPublic":true},"delete":{"name":"delete","async":true,"parameters":[],"returnType":"Promise<void>","isStatic":false,"isPublic":true}},"decoratorConfig":{"tableName":"campaign_metric_snapshots","conflictColumns":["dedupe_key"],"api":{"include":["list","get","create"]},"mcp":{"include":["list","get","create"]},"cli":{"include":["list","get","create"]},"tenantScoped":{"mode":"optional"}},"extends":"SmrtObject","exportName":"CampaignMetricSnapshot","collectionExportName":"CampaignMetricSnapshotCollection","validationRules":[{"field":"campaignId","rule":"required","fieldType":"foreignKey"},{"field":"periodStart","rule":"required","fieldType":"datetime"},{"field":"periodEnd","rule":"required","fieldType":"datetime"},{"field":"source","rule":"required","fieldType":"text"},{"field":"dedupeKey","rule":"required","fieldType":"text"}],"schema":{"tableName":"campaign_metric_snapshots","ddl":"CREATE TABLE IF NOT EXISTS \\"campaign_metric_snapshots\\" (\\n \\"id\\" UUID PRIMARY KEY NOT NULL,\\n \\"slug\\" TEXT NOT NULL,\\n \\"context\\" TEXT NOT NULL DEFAULT '',\\n \\"created_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"updated_at\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\n \\"tenant_id\\" UUID,\\n \\"campaign_id\\" UUID NOT NULL,\\n \\"campaign_channel_id\\" UUID,\\n \\"period_start\\" TIMESTAMP NOT NULL,\\n \\"period_end\\" TIMESTAMP NOT NULL,\\n \\"spend_cents\\" INTEGER DEFAULT 0,\\n \\"impressions\\" INTEGER DEFAULT 0,\\n \\"clicks\\" INTEGER DEFAULT 0,\\n \\"conversions\\" INTEGER DEFAULT 0,\\n \\"leads\\" INTEGER DEFAULT 0,\\n \\"revenue_cents\\" INTEGER,\\n \\"source\\" TEXT NOT NULL DEFAULT '',\\n \\"dedupe_key\\" TEXT NOT NULL DEFAULT ''\\n);","columns":{"id":{"type":"UUID","primaryKey":true,"referenceKind":"id","notNull":true},"slug":{"type":"TEXT","notNull":true},"context":{"type":"TEXT","notNull":true,"default":""},"created_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"updated_at":{"type":"TIMESTAMP","notNull":true,"default":"current_timestamp"},"tenant_id":{"type":"UUID","referenceKind":"tenantId","notNull":false,"unique":false},"campaign_id":{"type":"UUID","referenceKind":"foreignKey","notNull":true,"unique":false,"foreignKey":{"table":"campaigns","column":"id","onDelete":"NO ACTION","onUpdate":"CASCADE"}},"campaign_channel_id":{"type":"UUID","referenceKind":"foreignKey","notNull":false,"unique":false,"foreignKey":{"table":"campaign_channels","column":"id","onDelete":"NO ACTION","onUpdate":"CASCADE"}},"period_start":{"type":"TIMESTAMP","notNull":true,"unique":false},"period_end":{"type":"TIMESTAMP","notNull":true,"unique":false},"spend_cents":{"type":"INTEGER","notNull":false,"unique":false,"default":0},"impressions":{"type":"INTEGER","notNull":false,"unique":false,"default":0},"clicks":{"type":"INTEGER","notNull":false,"unique":false,"default":0},"conversions":{"type":"INTEGER","notNull":false,"unique":false,"default":0},"leads":{"type":"INTEGER","notNull":false,"unique":false,"default":0},"revenue_cents":{"type":"INTEGER","notNull":false,"unique":false},"source":{"type":"TEXT","notNull":true,"unique":false,"default":""},"dedupe_key":{"type":"TEXT","notNull":true,"unique":false,"default":""}},"indexes":[{"name":"campaign_metric_snapshots_dedupe_key_idx","columns":["dedupe_key"],"unique":true},{"name":"campaign_metric_snapshots_slug_context_idx","columns":["slug","context"]},{"name":"campaign_metric_snapshots_tenant_id_created_at_idx","columns":["tenant_id","created_at"]},{"name":"campaign_metric_snapshots_campaign_id_idx","columns":["campaign_id"]},{"name":"campaign_metric_snapshots_campaign_channel_id_idx","columns":["campaign_channel_id"]}],"version":"1ccd36b3"},"importPath":"@happyvertical/smrt-marketing"}},"moduleType":"smrt","smrtDependencies":["@happyvertical/smrt-commerce","@happyvertical/smrt-core","@happyvertical/smrt-tenancy"],"browser":{"status":"server-only","issues":["#3624"],"via":["@happyvertical/smrt-tenancy"]},"stampsConstructors":true}`));
|
|
6
6
|
//#endregion
|
|
7
7
|
//#region src/errors.ts
|
|
8
8
|
var CampaignCustomerScopeError = class extends Error {
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["elapsedFraction","tenantContext"],"sources":["../src/__smrt-register__.ts","../src/errors.ts","../src/customer-scope.ts","../src/models/Campaign.ts","../src/models/CampaignChannel.ts","../src/collections/CampaignChannelCollection.ts","../src/services/pacing-calculation.ts","../src/models/CampaignMetricSnapshot.ts","../src/collections/CampaignMetricSnapshotCollection.ts","../src/collections/CampaignCollection.ts","../src/services/BudgetPacingService.ts","../src/services/CampaignLifecycleService.ts","../src/services/MetricIngestionService.ts"],"sourcesContent":["// Generated by @happyvertical/smrt-core smrtPlugin at library build time.\n// The package manifest is inlined so self-registration cannot miss when a\n// downstream bundler relocates this module away from dist/manifest.json\n// (https://github.com/happyvertical/smrt/issues/1506,\n// https://github.com/happyvertical/smrt/issues/1507).\nimport { ObjectRegistry } from '@happyvertical/smrt-core';\n\nObjectRegistry.registerPackageManifest(JSON.parse(\"{\\\"version\\\":\\\"1.0.0\\\",\\\"timestamp\\\":0,\\\"packageName\\\":\\\"@happyvertical/smrt-marketing\\\",\\\"packageVersion\\\":\\\"0.57.4\\\",\\\"objects\\\":{\\\"@happyvertical/smrt-marketing:CampaignChannelCollection\\\":{\\\"name\\\":\\\"campaignchannelcollection\\\",\\\"className\\\":\\\"CampaignChannelCollection\\\",\\\"qualifiedName\\\":\\\"@happyvertical/smrt-marketing:CampaignChannelCollection\\\",\\\"collection\\\":\\\"campaignchannels\\\",\\\"filePath\\\":\\\"/home/runner/work/smrt/smrt/packages/marketing/src/collections/CampaignChannelCollection.ts\\\",\\\"packageName\\\":\\\"@happyvertical/smrt-marketing\\\",\\\"fields\\\":{},\\\"methods\\\":{\\\"findByCampaign\\\":{\\\"name\\\":\\\"findByCampaign\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"campaignId\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<CampaignChannel[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"findByExecutionRef\\\":{\\\"name\\\":\\\"findByExecutionRef\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"channelKind\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false},{\\\"name\\\":\\\"channelRef\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<CampaignChannel[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true}},\\\"decoratorConfig\\\":{\\\"tableName\\\":\\\"campaign_channels\\\",\\\"api\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\",\\\"create\\\",\\\"update\\\",\\\"delete\\\"]},\\\"mcp\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\",\\\"create\\\",\\\"update\\\"]},\\\"cli\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\",\\\"create\\\",\\\"update\\\",\\\"delete\\\"]}},\\\"extends\\\":\\\"SmrtCollection\\\",\\\"extendsTypeArg\\\":\\\"CampaignChannel\\\",\\\"exportName\\\":\\\"CampaignChannelCollection\\\",\\\"collectionExportName\\\":\\\"CampaignChannelCollectionCollection\\\",\\\"schema\\\":{\\\"tableName\\\":\\\"campaign_channels\\\",\\\"ddl\\\":\\\"CREATE TABLE IF NOT EXISTS \\\\\\\"campaign_channels\\\\\\\" (\\\\n \\\\\\\"id\\\\\\\" UUID PRIMARY KEY NOT NULL,\\\\n \\\\\\\"slug\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"context\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"created_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"updated_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"tenant_id\\\\\\\" UUID,\\\\n \\\\\\\"campaign_id\\\\\\\" UUID NOT NULL,\\\\n \\\\\\\"channel_kind\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"channel_ref\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"allocated_budget_cents\\\\\\\" INTEGER DEFAULT 0,\\\\n \\\\\\\"start_at\\\\\\\" TIMESTAMP,\\\\n \\\\\\\"end_at\\\\\\\" TIMESTAMP,\\\\n \\\\\\\"status\\\\\\\" TEXT DEFAULT 'planned'\\\\n);\\\",\\\"columns\\\":{\\\"id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"primaryKey\\\":true,\\\"referenceKind\\\":\\\"id\\\",\\\"notNull\\\":true},\\\"slug\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true},\\\"context\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"\\\"},\\\"created_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"updated_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"tenant_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"tenantId\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"campaign_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"foreignKey\\\",\\\"notNull\\\":true,\\\"unique\\\":false,\\\"foreignKey\\\":{\\\"table\\\":\\\"campaigns\\\",\\\"column\\\":\\\"id\\\",\\\"onDelete\\\":\\\"CASCADE\\\",\\\"onUpdate\\\":\\\"CASCADE\\\"}},\\\"channel_kind\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"channel_ref\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"allocated_budget_cents\\\":{\\\"type\\\":\\\"INTEGER\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":0},\\\"start_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"end_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"status\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"planned\\\"}},\\\"indexes\\\":[{\\\"name\\\":\\\"campaign_channels_campaign_id_channel_kind_idx\\\",\\\"columns\\\":[\\\"campaign_id\\\",\\\"channel_kind\\\",\\\"channel_ref\\\"],\\\"unique\\\":true},{\\\"name\\\":\\\"campaign_channels_slug_context_idx\\\",\\\"columns\\\":[\\\"slug\\\",\\\"context\\\"]},{\\\"name\\\":\\\"campaign_channels_tenant_id_created_at_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"created_at\\\"]}],\\\"version\\\":\\\"cc045525\\\"},\\\"importPath\\\":\\\"@happyvertical/smrt-marketing\\\"},\\\"@happyvertical/smrt-marketing:CampaignCollection\\\":{\\\"name\\\":\\\"campaigncollection\\\",\\\"className\\\":\\\"CampaignCollection\\\",\\\"qualifiedName\\\":\\\"@happyvertical/smrt-marketing:CampaignCollection\\\",\\\"collection\\\":\\\"campaigns\\\",\\\"filePath\\\":\\\"/home/runner/work/smrt/smrt/packages/marketing/src/collections/CampaignCollection.ts\\\",\\\"packageName\\\":\\\"@happyvertical/smrt-marketing\\\",\\\"fields\\\":{},\\\"methods\\\":{\\\"get\\\":{\\\"name\\\":\\\"get\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"filter\\\",\\\"type\\\":\\\"string | SmrtWhereClause<Campaign>\\\",\\\"optional\\\":false,\\\"unionBranches\\\":[{\\\"type\\\":\\\"string\\\"},{\\\"type\\\":\\\"SmrtWhereClause<Campaign>\\\"}]},{\\\"name\\\":\\\"options\\\",\\\"type\\\":\\\"object\\\",\\\"optional\\\":true,\\\"memberTypes\\\":[\\\"CollectionCacheConfig | false\\\"]}],\\\"returnType\\\":\\\"Promise<Campaign | null>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"list\\\":{\\\"name\\\":\\\"list\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"options\\\",\\\"type\\\":\\\"SmrtListOptions<Campaign>\\\",\\\"optional\\\":true}],\\\"returnType\\\":\\\"Promise<Campaign[] | Record<string, unknown>[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"findByCampaignKey\\\":{\\\"name\\\":\\\"findByCampaignKey\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"campaignKey\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false},{\\\"name\\\":\\\"tenantId\\\",\\\"type\\\":\\\"string | null\\\",\\\"optional\\\":true,\\\"unionBranches\\\":[{\\\"type\\\":\\\"string\\\"},{\\\"type\\\":\\\"null\\\"}]}],\\\"returnType\\\":\\\"Promise<Campaign | null>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"findByStatus\\\":{\\\"name\\\":\\\"findByStatus\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"status\\\",\\\"type\\\":\\\"CampaignStatus\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<Campaign[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"listByCustomer\\\":{\\\"name\\\":\\\"listByCustomer\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"tenantId\\\",\\\"type\\\":\\\"string | null\\\",\\\"optional\\\":false,\\\"unionBranches\\\":[{\\\"type\\\":\\\"string\\\"},{\\\"type\\\":\\\"null\\\"}]},{\\\"name\\\":\\\"customerId\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false},{\\\"name\\\":\\\"options\\\",\\\"type\\\":\\\"ListCampaignsByCustomerOptions\\\",\\\"optional\\\":true}],\\\"returnType\\\":\\\"Promise<CampaignCustomerPage>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"listReportingByCustomer\\\":{\\\"name\\\":\\\"listReportingByCustomer\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"tenantId\\\",\\\"type\\\":\\\"string | null\\\",\\\"optional\\\":false,\\\"unionBranches\\\":[{\\\"type\\\":\\\"string\\\"},{\\\"type\\\":\\\"null\\\"}]},{\\\"name\\\":\\\"customerId\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false},{\\\"name\\\":\\\"options\\\",\\\"type\\\":\\\"ListCampaignReportingByCustomerOptions\\\",\\\"optional\\\":true}],\\\"returnType\\\":\\\"Promise<CampaignReportingPage>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"summarizeByCustomers\\\":{\\\"name\\\":\\\"summarizeByCustomers\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"tenantId\\\",\\\"type\\\":\\\"string | null\\\",\\\"optional\\\":false,\\\"unionBranches\\\":[{\\\"type\\\":\\\"string\\\"},{\\\"type\\\":\\\"null\\\"}]},{\\\"name\\\":\\\"customerIds\\\",\\\"type\\\":\\\"string[]\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<CampaignCustomerSummary[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true}},\\\"decoratorConfig\\\":{\\\"tableName\\\":\\\"campaigns\\\",\\\"api\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\",\\\"create\\\",\\\"update\\\"]},\\\"mcp\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\",\\\"create\\\",\\\"update\\\"]},\\\"cli\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\",\\\"create\\\",\\\"update\\\"]}},\\\"extends\\\":\\\"SmrtCollection\\\",\\\"extendsTypeArg\\\":\\\"Campaign\\\",\\\"exportName\\\":\\\"CampaignCollection\\\",\\\"collectionExportName\\\":\\\"CampaignCollectionCollection\\\",\\\"schema\\\":{\\\"tableName\\\":\\\"campaigns\\\",\\\"ddl\\\":\\\"CREATE TABLE IF NOT EXISTS \\\\\\\"campaigns\\\\\\\" (\\\\n \\\\\\\"id\\\\\\\" UUID PRIMARY KEY NOT NULL,\\\\n \\\\\\\"slug\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"context\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"created_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"updated_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"tenant_id\\\\\\\" UUID,\\\\n \\\\\\\"customer_id\\\\\\\" UUID,\\\\n \\\\\\\"campaign_key\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"name\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"objective\\\\\\\" TEXT DEFAULT '',\\\\n \\\\\\\"status\\\\\\\" TEXT DEFAULT 'draft',\\\\n \\\\\\\"start_at\\\\\\\" TIMESTAMP,\\\\n \\\\\\\"end_at\\\\\\\" TIMESTAMP,\\\\n \\\\\\\"budget_cents\\\\\\\" INTEGER DEFAULT 0,\\\\n \\\\\\\"currency\\\\\\\" TEXT DEFAULT 'USD',\\\\n \\\\\\\"metadata\\\\\\\" TEXT DEFAULT '{}'\\\\n);\\\",\\\"columns\\\":{\\\"id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"primaryKey\\\":true,\\\"referenceKind\\\":\\\"id\\\",\\\"notNull\\\":true},\\\"slug\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true},\\\"context\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"\\\"},\\\"created_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"updated_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"tenant_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"tenantId\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"customer_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"crossPackageRef\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"campaign_key\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"name\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"objective\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"status\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"draft\\\"},\\\"start_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"end_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"budget_cents\\\":{\\\"type\\\":\\\"INTEGER\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":0},\\\"currency\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"USD\\\"},\\\"metadata\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"{}\\\"}},\\\"indexes\\\":[{\\\"name\\\":\\\"campaigns_tenant_id_campaign_key_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"campaign_key\\\"],\\\"unique\\\":true,\\\"nullsNotDistinct\\\":true},{\\\"name\\\":\\\"campaigns_slug_context_idx\\\",\\\"columns\\\":[\\\"slug\\\",\\\"context\\\"]},{\\\"name\\\":\\\"campaigns_tenant_id_customer_id_start_at_id_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"customer_id\\\",\\\"start_at\\\",\\\"id\\\"]},{\\\"name\\\":\\\"campaigns_tenant_id_created_at_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"created_at\\\"]},{\\\"name\\\":\\\"campaigns_customer_id_idx\\\",\\\"columns\\\":[\\\"customer_id\\\"]}],\\\"version\\\":\\\"d0945102\\\"},\\\"importPath\\\":\\\"@happyvertical/smrt-marketing\\\"},\\\"@happyvertical/smrt-marketing:CampaignMetricSnapshotCollection\\\":{\\\"name\\\":\\\"campaignmetricsnapshotcollection\\\",\\\"className\\\":\\\"CampaignMetricSnapshotCollection\\\",\\\"qualifiedName\\\":\\\"@happyvertical/smrt-marketing:CampaignMetricSnapshotCollection\\\",\\\"collection\\\":\\\"campaignmetricsnapshots\\\",\\\"filePath\\\":\\\"/home/runner/work/smrt/smrt/packages/marketing/src/collections/CampaignMetricSnapshotCollection.ts\\\",\\\"packageName\\\":\\\"@happyvertical/smrt-marketing\\\",\\\"fields\\\":{},\\\"methods\\\":{\\\"findByDedupeKey\\\":{\\\"name\\\":\\\"findByDedupeKey\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"dedupeKey\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<CampaignMetricSnapshot | null>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"getOrCreateByDedupeKey\\\":{\\\"name\\\":\\\"getOrCreateByDedupeKey\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"options\\\",\\\"type\\\":\\\"CampaignMetricSnapshotOptions\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<object>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"findByCampaign\\\":{\\\"name\\\":\\\"findByCampaign\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"campaignId\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<CampaignMetricSnapshot[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"findByChannel\\\":{\\\"name\\\":\\\"findByChannel\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"campaignChannelId\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<CampaignMetricSnapshot[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true}},\\\"decoratorConfig\\\":{\\\"tableName\\\":\\\"campaign_metric_snapshots\\\",\\\"api\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\",\\\"create\\\"]},\\\"mcp\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\",\\\"create\\\"]},\\\"cli\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\",\\\"create\\\"]}},\\\"extends\\\":\\\"SmrtCollection\\\",\\\"extendsTypeArg\\\":\\\"CampaignMetricSnapshot\\\",\\\"exportName\\\":\\\"CampaignMetricSnapshotCollection\\\",\\\"collectionExportName\\\":\\\"CampaignMetricSnapshotCollectionCollection\\\",\\\"schema\\\":{\\\"tableName\\\":\\\"campaign_metric_snapshots\\\",\\\"ddl\\\":\\\"CREATE TABLE IF NOT EXISTS \\\\\\\"campaign_metric_snapshots\\\\\\\" (\\\\n \\\\\\\"id\\\\\\\" UUID PRIMARY KEY NOT NULL,\\\\n \\\\\\\"slug\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"context\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"created_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"updated_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"tenant_id\\\\\\\" UUID,\\\\n \\\\\\\"campaign_id\\\\\\\" UUID NOT NULL,\\\\n \\\\\\\"campaign_channel_id\\\\\\\" UUID,\\\\n \\\\\\\"period_start\\\\\\\" TIMESTAMP NOT NULL,\\\\n \\\\\\\"period_end\\\\\\\" TIMESTAMP NOT NULL,\\\\n \\\\\\\"spend_cents\\\\\\\" INTEGER DEFAULT 0,\\\\n \\\\\\\"impressions\\\\\\\" INTEGER DEFAULT 0,\\\\n \\\\\\\"clicks\\\\\\\" INTEGER DEFAULT 0,\\\\n \\\\\\\"conversions\\\\\\\" INTEGER DEFAULT 0,\\\\n \\\\\\\"leads\\\\\\\" INTEGER DEFAULT 0,\\\\n \\\\\\\"revenue_cents\\\\\\\" INTEGER,\\\\n \\\\\\\"source\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"dedupe_key\\\\\\\" TEXT NOT NULL DEFAULT ''\\\\n);\\\",\\\"columns\\\":{\\\"id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"primaryKey\\\":true,\\\"referenceKind\\\":\\\"id\\\",\\\"notNull\\\":true},\\\"slug\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true},\\\"context\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"\\\"},\\\"created_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"updated_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"tenant_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"tenantId\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"campaign_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"foreignKey\\\",\\\"notNull\\\":true,\\\"unique\\\":false,\\\"foreignKey\\\":{\\\"table\\\":\\\"campaigns\\\",\\\"column\\\":\\\"id\\\",\\\"onDelete\\\":\\\"NO ACTION\\\",\\\"onUpdate\\\":\\\"CASCADE\\\"}},\\\"campaign_channel_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"foreignKey\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"foreignKey\\\":{\\\"table\\\":\\\"campaign_channels\\\",\\\"column\\\":\\\"id\\\",\\\"onDelete\\\":\\\"NO ACTION\\\",\\\"onUpdate\\\":\\\"CASCADE\\\"}},\\\"period_start\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"unique\\\":false},\\\"period_end\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"unique\\\":false},\\\"spend_cents\\\":{\\\"type\\\":\\\"INTEGER\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":0},\\\"impressions\\\":{\\\"type\\\":\\\"INTEGER\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":0},\\\"clicks\\\":{\\\"type\\\":\\\"INTEGER\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":0},\\\"conversions\\\":{\\\"type\\\":\\\"INTEGER\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":0},\\\"leads\\\":{\\\"type\\\":\\\"INTEGER\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":0},\\\"revenue_cents\\\":{\\\"type\\\":\\\"INTEGER\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"source\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"dedupe_key\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"}},\\\"indexes\\\":[{\\\"name\\\":\\\"campaign_metric_snapshots_dedupe_key_idx\\\",\\\"columns\\\":[\\\"dedupe_key\\\"],\\\"unique\\\":true},{\\\"name\\\":\\\"campaign_metric_snapshots_slug_context_idx\\\",\\\"columns\\\":[\\\"slug\\\",\\\"context\\\"]},{\\\"name\\\":\\\"campaign_metric_snapshots_tenant_id_created_at_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"created_at\\\"]},{\\\"name\\\":\\\"campaign_metric_snapshots_campaign_id_idx\\\",\\\"columns\\\":[\\\"campaign_id\\\"]},{\\\"name\\\":\\\"campaign_metric_snapshots_campaign_channel_id_idx\\\",\\\"columns\\\":[\\\"campaign_channel_id\\\"]}],\\\"version\\\":\\\"1ccd36b3\\\"},\\\"importPath\\\":\\\"@happyvertical/smrt-marketing\\\"},\\\"@happyvertical/smrt-marketing:Campaign\\\":{\\\"name\\\":\\\"campaign\\\",\\\"className\\\":\\\"Campaign\\\",\\\"qualifiedName\\\":\\\"@happyvertical/smrt-marketing:Campaign\\\",\\\"collection\\\":\\\"campaigns\\\",\\\"filePath\\\":\\\"/home/runner/work/smrt/smrt/packages/marketing/src/models/Campaign.ts\\\",\\\"packageName\\\":\\\"@happyvertical/smrt-marketing\\\",\\\"fields\\\":{\\\"tenantId\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"_meta\\\":{\\\"sqlType\\\":\\\"UUID\\\",\\\"nullable\\\":true,\\\"__tenancy\\\":{\\\"isTenantIdField\\\":true,\\\"autoFilter\\\":true,\\\"required\\\":false,\\\"autoPopulate\\\":true,\\\"nullable\\\":true,\\\"mode\\\":\\\"optional\\\",\\\"field\\\":\\\"tenantId\\\",\\\"allowSuperAdminBypass\\\":false}}},\\\"customerId\\\":{\\\"type\\\":\\\"crossPackageRef\\\",\\\"required\\\":false,\\\"related\\\":\\\"@happyvertical/smrt-commerce:Customer\\\",\\\"_meta\\\":{\\\"validate\\\":true,\\\"nullable\\\":true}},\\\"campaignKey\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":true,\\\"default\\\":\\\"\\\",\\\"_meta\\\":{\\\"required\\\":true}},\\\"name\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":true,\\\"default\\\":\\\"\\\",\\\"_meta\\\":{\\\"required\\\":true}},\\\"objective\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"default\\\":\\\"\\\"},\\\"status\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"default\\\":\\\"draft\\\"},\\\"startAt\\\":{\\\"type\\\":\\\"datetime\\\",\\\"required\\\":false},\\\"endAt\\\":{\\\"type\\\":\\\"datetime\\\",\\\"required\\\":false},\\\"budgetCents\\\":{\\\"type\\\":\\\"integer\\\",\\\"required\\\":false,\\\"default\\\":0},\\\"currency\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"default\\\":\\\"USD\\\"},\\\"metadata\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"default\\\":\\\"{}\\\"}},\\\"methods\\\":{\\\"initialize\\\":{\\\"name\\\":\\\"initialize\\\",\\\"async\\\":true,\\\"parameters\\\":[],\\\"returnType\\\":\\\"Promise<this>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"save\\\":{\\\"name\\\":\\\"save\\\",\\\"async\\\":true,\\\"parameters\\\":[],\\\"returnType\\\":\\\"Promise<this>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"transitionTo\\\":{\\\"name\\\":\\\"transitionTo\\\",\\\"async\\\":false,\\\"parameters\\\":[{\\\"name\\\":\\\"next\\\",\\\"type\\\":\\\"CampaignStatus\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"this\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"getMetadata\\\":{\\\"name\\\":\\\"getMetadata\\\",\\\"async\\\":false,\\\"parameters\\\":[],\\\"returnType\\\":\\\"Record<string, unknown>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"setMetadata\\\":{\\\"name\\\":\\\"setMetadata\\\",\\\"async\\\":false,\\\"parameters\\\":[{\\\"name\\\":\\\"metadata\\\",\\\"type\\\":\\\"Record<string, unknown>\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"void\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true}},\\\"decoratorConfig\\\":{\\\"tableName\\\":\\\"campaigns\\\",\\\"conflictColumns\\\":[\\\"tenant_id\\\",\\\"campaign_key\\\"],\\\"indexes\\\":[{\\\"name\\\":\\\"campaigns_tenant_id_customer_id_start_at_id_idx\\\",\\\"columns\\\":[\\\"tenantId\\\",\\\"customerId\\\",\\\"startAt\\\",\\\"id\\\"]}],\\\"api\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\",\\\"create\\\",\\\"update\\\"]},\\\"mcp\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\",\\\"create\\\",\\\"update\\\"]},\\\"cli\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\",\\\"create\\\",\\\"update\\\"]},\\\"tenantScoped\\\":{\\\"mode\\\":\\\"optional\\\"}},\\\"extends\\\":\\\"SmrtObject\\\",\\\"exportName\\\":\\\"Campaign\\\",\\\"collectionExportName\\\":\\\"CampaignCollection\\\",\\\"displayLabelField\\\":\\\"name\\\",\\\"validationRules\\\":[{\\\"field\\\":\\\"campaignKey\\\",\\\"rule\\\":\\\"required\\\",\\\"fieldType\\\":\\\"text\\\"},{\\\"field\\\":\\\"name\\\",\\\"rule\\\":\\\"required\\\",\\\"fieldType\\\":\\\"text\\\"}],\\\"schema\\\":{\\\"tableName\\\":\\\"campaigns\\\",\\\"ddl\\\":\\\"CREATE TABLE IF NOT EXISTS \\\\\\\"campaigns\\\\\\\" (\\\\n \\\\\\\"id\\\\\\\" UUID PRIMARY KEY NOT NULL,\\\\n \\\\\\\"slug\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"context\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"created_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"updated_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"tenant_id\\\\\\\" UUID,\\\\n \\\\\\\"customer_id\\\\\\\" UUID,\\\\n \\\\\\\"campaign_key\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"name\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"objective\\\\\\\" TEXT DEFAULT '',\\\\n \\\\\\\"status\\\\\\\" TEXT DEFAULT 'draft',\\\\n \\\\\\\"start_at\\\\\\\" TIMESTAMP,\\\\n \\\\\\\"end_at\\\\\\\" TIMESTAMP,\\\\n \\\\\\\"budget_cents\\\\\\\" INTEGER DEFAULT 0,\\\\n \\\\\\\"currency\\\\\\\" TEXT DEFAULT 'USD',\\\\n \\\\\\\"metadata\\\\\\\" TEXT DEFAULT '{}'\\\\n);\\\",\\\"columns\\\":{\\\"id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"primaryKey\\\":true,\\\"referenceKind\\\":\\\"id\\\",\\\"notNull\\\":true},\\\"slug\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true},\\\"context\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"\\\"},\\\"created_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"updated_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"tenant_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"tenantId\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"customer_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"crossPackageRef\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"campaign_key\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"name\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"objective\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"status\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"draft\\\"},\\\"start_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"end_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"budget_cents\\\":{\\\"type\\\":\\\"INTEGER\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":0},\\\"currency\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"USD\\\"},\\\"metadata\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"{}\\\"}},\\\"indexes\\\":[{\\\"name\\\":\\\"campaigns_tenant_id_campaign_key_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"campaign_key\\\"],\\\"unique\\\":true,\\\"nullsNotDistinct\\\":true},{\\\"name\\\":\\\"campaigns_slug_context_idx\\\",\\\"columns\\\":[\\\"slug\\\",\\\"context\\\"]},{\\\"name\\\":\\\"campaigns_tenant_id_customer_id_start_at_id_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"customer_id\\\",\\\"start_at\\\",\\\"id\\\"]},{\\\"name\\\":\\\"campaigns_tenant_id_created_at_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"created_at\\\"]},{\\\"name\\\":\\\"campaigns_customer_id_idx\\\",\\\"columns\\\":[\\\"customer_id\\\"]}],\\\"version\\\":\\\"d0945102\\\"},\\\"importPath\\\":\\\"@happyvertical/smrt-marketing\\\"},\\\"@happyvertical/smrt-marketing:CampaignChannel\\\":{\\\"name\\\":\\\"campaignchannel\\\",\\\"className\\\":\\\"CampaignChannel\\\",\\\"qualifiedName\\\":\\\"@happyvertical/smrt-marketing:CampaignChannel\\\",\\\"collection\\\":\\\"campaignchannels\\\",\\\"filePath\\\":\\\"/home/runner/work/smrt/smrt/packages/marketing/src/models/CampaignChannel.ts\\\",\\\"packageName\\\":\\\"@happyvertical/smrt-marketing\\\",\\\"fields\\\":{\\\"tenantId\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"_meta\\\":{\\\"sqlType\\\":\\\"UUID\\\",\\\"nullable\\\":true,\\\"__tenancy\\\":{\\\"isTenantIdField\\\":true,\\\"autoFilter\\\":true,\\\"required\\\":false,\\\"autoPopulate\\\":true,\\\"nullable\\\":true,\\\"mode\\\":\\\"optional\\\",\\\"field\\\":\\\"tenantId\\\",\\\"allowSuperAdminBypass\\\":false}}},\\\"campaignId\\\":{\\\"type\\\":\\\"foreignKey\\\",\\\"required\\\":true,\\\"related\\\":\\\"Campaign\\\",\\\"_meta\\\":{\\\"required\\\":true}},\\\"channelKind\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":true,\\\"default\\\":\\\"\\\",\\\"_meta\\\":{\\\"required\\\":true}},\\\"channelRef\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":true,\\\"default\\\":\\\"\\\",\\\"_meta\\\":{\\\"required\\\":true}},\\\"allocatedBudgetCents\\\":{\\\"type\\\":\\\"integer\\\",\\\"required\\\":false,\\\"default\\\":0},\\\"startAt\\\":{\\\"type\\\":\\\"datetime\\\",\\\"required\\\":false},\\\"endAt\\\":{\\\"type\\\":\\\"datetime\\\",\\\"required\\\":false},\\\"status\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"default\\\":\\\"planned\\\"}},\\\"methods\\\":{\\\"initialize\\\":{\\\"name\\\":\\\"initialize\\\",\\\"async\\\":true,\\\"parameters\\\":[],\\\"returnType\\\":\\\"Promise<this>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"save\\\":{\\\"name\\\":\\\"save\\\",\\\"async\\\":true,\\\"parameters\\\":[],\\\"returnType\\\":\\\"Promise<this>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true}},\\\"decoratorConfig\\\":{\\\"tableName\\\":\\\"campaign_channels\\\",\\\"conflictColumns\\\":[\\\"campaign_id\\\",\\\"channel_kind\\\",\\\"channel_ref\\\"],\\\"api\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\",\\\"create\\\",\\\"update\\\",\\\"delete\\\"]},\\\"mcp\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\",\\\"create\\\",\\\"update\\\"]},\\\"cli\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\",\\\"create\\\",\\\"update\\\",\\\"delete\\\"]},\\\"tenantScoped\\\":{\\\"mode\\\":\\\"optional\\\"}},\\\"extends\\\":\\\"SmrtObject\\\",\\\"exportName\\\":\\\"CampaignChannel\\\",\\\"collectionExportName\\\":\\\"CampaignChannelCollection\\\",\\\"validationRules\\\":[{\\\"field\\\":\\\"campaignId\\\",\\\"rule\\\":\\\"required\\\",\\\"fieldType\\\":\\\"foreignKey\\\"},{\\\"field\\\":\\\"channelKind\\\",\\\"rule\\\":\\\"required\\\",\\\"fieldType\\\":\\\"text\\\"},{\\\"field\\\":\\\"channelRef\\\",\\\"rule\\\":\\\"required\\\",\\\"fieldType\\\":\\\"text\\\"}],\\\"schema\\\":{\\\"tableName\\\":\\\"campaign_channels\\\",\\\"ddl\\\":\\\"CREATE TABLE IF NOT EXISTS \\\\\\\"campaign_channels\\\\\\\" (\\\\n \\\\\\\"id\\\\\\\" UUID PRIMARY KEY NOT NULL,\\\\n \\\\\\\"slug\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"context\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"created_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"updated_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"tenant_id\\\\\\\" UUID,\\\\n \\\\\\\"campaign_id\\\\\\\" UUID NOT NULL,\\\\n \\\\\\\"channel_kind\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"channel_ref\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"allocated_budget_cents\\\\\\\" INTEGER DEFAULT 0,\\\\n \\\\\\\"start_at\\\\\\\" TIMESTAMP,\\\\n \\\\\\\"end_at\\\\\\\" TIMESTAMP,\\\\n \\\\\\\"status\\\\\\\" TEXT DEFAULT 'planned'\\\\n);\\\",\\\"columns\\\":{\\\"id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"primaryKey\\\":true,\\\"referenceKind\\\":\\\"id\\\",\\\"notNull\\\":true},\\\"slug\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true},\\\"context\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"\\\"},\\\"created_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"updated_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"tenant_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"tenantId\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"campaign_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"foreignKey\\\",\\\"notNull\\\":true,\\\"unique\\\":false,\\\"foreignKey\\\":{\\\"table\\\":\\\"campaigns\\\",\\\"column\\\":\\\"id\\\",\\\"onDelete\\\":\\\"CASCADE\\\",\\\"onUpdate\\\":\\\"CASCADE\\\"}},\\\"channel_kind\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"channel_ref\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"allocated_budget_cents\\\":{\\\"type\\\":\\\"INTEGER\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":0},\\\"start_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"end_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"status\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"planned\\\"}},\\\"indexes\\\":[{\\\"name\\\":\\\"campaign_channels_campaign_id_channel_kind_idx\\\",\\\"columns\\\":[\\\"campaign_id\\\",\\\"channel_kind\\\",\\\"channel_ref\\\"],\\\"unique\\\":true},{\\\"name\\\":\\\"campaign_channels_slug_context_idx\\\",\\\"columns\\\":[\\\"slug\\\",\\\"context\\\"]},{\\\"name\\\":\\\"campaign_channels_tenant_id_created_at_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"created_at\\\"]}],\\\"version\\\":\\\"cc045525\\\"},\\\"importPath\\\":\\\"@happyvertical/smrt-marketing\\\"},\\\"@happyvertical/smrt-marketing:CampaignMetricSnapshot\\\":{\\\"name\\\":\\\"campaignmetricsnapshot\\\",\\\"className\\\":\\\"CampaignMetricSnapshot\\\",\\\"qualifiedName\\\":\\\"@happyvertical/smrt-marketing:CampaignMetricSnapshot\\\",\\\"collection\\\":\\\"campaignmetricsnapshots\\\",\\\"filePath\\\":\\\"/home/runner/work/smrt/smrt/packages/marketing/src/models/CampaignMetricSnapshot.ts\\\",\\\"packageName\\\":\\\"@happyvertical/smrt-marketing\\\",\\\"fields\\\":{\\\"tenantId\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"_meta\\\":{\\\"sqlType\\\":\\\"UUID\\\",\\\"nullable\\\":true,\\\"__tenancy\\\":{\\\"isTenantIdField\\\":true,\\\"autoFilter\\\":true,\\\"required\\\":false,\\\"autoPopulate\\\":true,\\\"nullable\\\":true,\\\"mode\\\":\\\"optional\\\",\\\"field\\\":\\\"tenantId\\\",\\\"allowSuperAdminBypass\\\":false}}},\\\"campaignId\\\":{\\\"type\\\":\\\"foreignKey\\\",\\\"required\\\":true,\\\"related\\\":\\\"Campaign\\\",\\\"_meta\\\":{\\\"required\\\":true}},\\\"campaignChannelId\\\":{\\\"type\\\":\\\"foreignKey\\\",\\\"required\\\":false,\\\"related\\\":\\\"CampaignChannel\\\",\\\"_meta\\\":{\\\"nullable\\\":true}},\\\"periodStart\\\":{\\\"type\\\":\\\"datetime\\\",\\\"required\\\":true,\\\"_meta\\\":{\\\"required\\\":true}},\\\"periodEnd\\\":{\\\"type\\\":\\\"datetime\\\",\\\"required\\\":true,\\\"_meta\\\":{\\\"required\\\":true}},\\\"spendCents\\\":{\\\"type\\\":\\\"integer\\\",\\\"required\\\":false,\\\"default\\\":0},\\\"impressions\\\":{\\\"type\\\":\\\"integer\\\",\\\"required\\\":false,\\\"default\\\":0},\\\"clicks\\\":{\\\"type\\\":\\\"integer\\\",\\\"required\\\":false,\\\"default\\\":0},\\\"conversions\\\":{\\\"type\\\":\\\"integer\\\",\\\"required\\\":false,\\\"default\\\":0},\\\"leads\\\":{\\\"type\\\":\\\"integer\\\",\\\"required\\\":false,\\\"default\\\":0},\\\"revenueCents\\\":{\\\"type\\\":\\\"integer\\\",\\\"required\\\":false,\\\"_meta\\\":{\\\"nullable\\\":true}},\\\"source\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":true,\\\"default\\\":\\\"\\\",\\\"_meta\\\":{\\\"required\\\":true}},\\\"dedupeKey\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":true,\\\"default\\\":\\\"\\\",\\\"_meta\\\":{\\\"required\\\":true}}},\\\"methods\\\":{\\\"initialize\\\":{\\\"name\\\":\\\"initialize\\\",\\\"async\\\":true,\\\"parameters\\\":[],\\\"returnType\\\":\\\"Promise<this>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"save\\\":{\\\"name\\\":\\\"save\\\",\\\"async\\\":true,\\\"parameters\\\":[],\\\"returnType\\\":\\\"Promise<this>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"delete\\\":{\\\"name\\\":\\\"delete\\\",\\\"async\\\":true,\\\"parameters\\\":[],\\\"returnType\\\":\\\"Promise<void>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true}},\\\"decoratorConfig\\\":{\\\"tableName\\\":\\\"campaign_metric_snapshots\\\",\\\"conflictColumns\\\":[\\\"dedupe_key\\\"],\\\"api\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\",\\\"create\\\"]},\\\"mcp\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\",\\\"create\\\"]},\\\"cli\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\",\\\"create\\\"]},\\\"tenantScoped\\\":{\\\"mode\\\":\\\"optional\\\"}},\\\"extends\\\":\\\"SmrtObject\\\",\\\"exportName\\\":\\\"CampaignMetricSnapshot\\\",\\\"collectionExportName\\\":\\\"CampaignMetricSnapshotCollection\\\",\\\"validationRules\\\":[{\\\"field\\\":\\\"campaignId\\\",\\\"rule\\\":\\\"required\\\",\\\"fieldType\\\":\\\"foreignKey\\\"},{\\\"field\\\":\\\"periodStart\\\",\\\"rule\\\":\\\"required\\\",\\\"fieldType\\\":\\\"datetime\\\"},{\\\"field\\\":\\\"periodEnd\\\",\\\"rule\\\":\\\"required\\\",\\\"fieldType\\\":\\\"datetime\\\"},{\\\"field\\\":\\\"source\\\",\\\"rule\\\":\\\"required\\\",\\\"fieldType\\\":\\\"text\\\"},{\\\"field\\\":\\\"dedupeKey\\\",\\\"rule\\\":\\\"required\\\",\\\"fieldType\\\":\\\"text\\\"}],\\\"schema\\\":{\\\"tableName\\\":\\\"campaign_metric_snapshots\\\",\\\"ddl\\\":\\\"CREATE TABLE IF NOT EXISTS \\\\\\\"campaign_metric_snapshots\\\\\\\" (\\\\n \\\\\\\"id\\\\\\\" UUID PRIMARY KEY NOT NULL,\\\\n \\\\\\\"slug\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"context\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"created_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"updated_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"tenant_id\\\\\\\" UUID,\\\\n \\\\\\\"campaign_id\\\\\\\" UUID NOT NULL,\\\\n \\\\\\\"campaign_channel_id\\\\\\\" UUID,\\\\n \\\\\\\"period_start\\\\\\\" TIMESTAMP NOT NULL,\\\\n \\\\\\\"period_end\\\\\\\" TIMESTAMP NOT NULL,\\\\n \\\\\\\"spend_cents\\\\\\\" INTEGER DEFAULT 0,\\\\n \\\\\\\"impressions\\\\\\\" INTEGER DEFAULT 0,\\\\n \\\\\\\"clicks\\\\\\\" INTEGER DEFAULT 0,\\\\n \\\\\\\"conversions\\\\\\\" INTEGER DEFAULT 0,\\\\n \\\\\\\"leads\\\\\\\" INTEGER DEFAULT 0,\\\\n \\\\\\\"revenue_cents\\\\\\\" INTEGER,\\\\n \\\\\\\"source\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"dedupe_key\\\\\\\" TEXT NOT NULL DEFAULT ''\\\\n);\\\",\\\"columns\\\":{\\\"id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"primaryKey\\\":true,\\\"referenceKind\\\":\\\"id\\\",\\\"notNull\\\":true},\\\"slug\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true},\\\"context\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"\\\"},\\\"created_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"updated_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"tenant_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"tenantId\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"campaign_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"foreignKey\\\",\\\"notNull\\\":true,\\\"unique\\\":false,\\\"foreignKey\\\":{\\\"table\\\":\\\"campaigns\\\",\\\"column\\\":\\\"id\\\",\\\"onDelete\\\":\\\"NO ACTION\\\",\\\"onUpdate\\\":\\\"CASCADE\\\"}},\\\"campaign_channel_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"foreignKey\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"foreignKey\\\":{\\\"table\\\":\\\"campaign_channels\\\",\\\"column\\\":\\\"id\\\",\\\"onDelete\\\":\\\"NO ACTION\\\",\\\"onUpdate\\\":\\\"CASCADE\\\"}},\\\"period_start\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"unique\\\":false},\\\"period_end\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"unique\\\":false},\\\"spend_cents\\\":{\\\"type\\\":\\\"INTEGER\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":0},\\\"impressions\\\":{\\\"type\\\":\\\"INTEGER\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":0},\\\"clicks\\\":{\\\"type\\\":\\\"INTEGER\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":0},\\\"conversions\\\":{\\\"type\\\":\\\"INTEGER\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":0},\\\"leads\\\":{\\\"type\\\":\\\"INTEGER\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":0},\\\"revenue_cents\\\":{\\\"type\\\":\\\"INTEGER\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"source\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"dedupe_key\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"}},\\\"indexes\\\":[{\\\"name\\\":\\\"campaign_metric_snapshots_dedupe_key_idx\\\",\\\"columns\\\":[\\\"dedupe_key\\\"],\\\"unique\\\":true},{\\\"name\\\":\\\"campaign_metric_snapshots_slug_context_idx\\\",\\\"columns\\\":[\\\"slug\\\",\\\"context\\\"]},{\\\"name\\\":\\\"campaign_metric_snapshots_tenant_id_created_at_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"created_at\\\"]},{\\\"name\\\":\\\"campaign_metric_snapshots_campaign_id_idx\\\",\\\"columns\\\":[\\\"campaign_id\\\"]},{\\\"name\\\":\\\"campaign_metric_snapshots_campaign_channel_id_idx\\\",\\\"columns\\\":[\\\"campaign_channel_id\\\"]}],\\\"version\\\":\\\"1ccd36b3\\\"},\\\"importPath\\\":\\\"@happyvertical/smrt-marketing\\\"}},\\\"moduleType\\\":\\\"smrt\\\",\\\"smrtDependencies\\\":[\\\"@happyvertical/smrt-commerce\\\",\\\"@happyvertical/smrt-core\\\",\\\"@happyvertical/smrt-tenancy\\\"],\\\"browser\\\":{\\\"status\\\":\\\"server-only\\\",\\\"issues\\\":[\\\"#3624\\\"],\\\"via\\\":[\\\"@happyvertical/smrt-tenancy\\\"]},\\\"stampsConstructors\\\":true}\"));\n","/** Fail-closed customer/tenant mismatch without revealing row existence. */\nexport class CampaignCustomerScopeError extends Error {\n readonly code = 'CAMPAIGN_CUSTOMER_SCOPE';\n\n constructor(label: string) {\n super(`${label}: customer scope validation failed.`);\n this.name = 'CampaignCustomerScopeError';\n }\n}\n","import {\n ObjectRegistry,\n type SmrtObject,\n type SmrtObjectOptions,\n} from '@happyvertical/smrt-core';\nimport type { DatabaseInterface } from '@happyvertical/sql';\nimport { CampaignCustomerScopeError } from './errors.js';\n\nconst CUSTOMER_QUALIFIED_NAME = '@happyvertical/smrt-commerce:Customer';\nconst SAFE_SQL_IDENTIFIER = /^[A-Za-z_][A-Za-z0-9_]*$/u;\nconst UUID_RE =\n /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/iu;\n\ntype QueryDatabase = Pick<DatabaseInterface, 'query' | 'url'>;\n\ninterface DatabaseOptions {\n db?: SmrtObjectOptions['db'];\n}\n\nfunction requireDatabase(options: DatabaseOptions): QueryDatabase {\n const db = options.db;\n if (!db || typeof db !== 'object' || !('query' in db)) {\n throw new Error(\n 'Campaign customer queries require an initialized database connection.',\n );\n }\n return db as QueryDatabase;\n}\n\nasync function resolveCustomerTable(options: DatabaseOptions): Promise<string> {\n await ObjectRegistry.ensureManifestLoaded(CUSTOMER_QUALIFIED_NAME);\n const target =\n ObjectRegistry.getClassByQualifiedName(CUSTOMER_QUALIFIED_NAME) ??\n ObjectRegistry.getClass(CUSTOMER_QUALIFIED_NAME);\n if (!target) {\n throw new Error(\n 'Campaign customer queries require @happyvertical/smrt-commerce:Customer to be registered.',\n );\n }\n\n const probe = new target.constructor(options) as SmrtObject;\n const tableName = probe.tableName;\n if (!SAFE_SQL_IDENTIFIER.test(tableName)) {\n throw new Error('Campaign customer table has an invalid identifier.');\n }\n return tableName;\n}\n\n/**\n * Verify a bounded set of canonical commerce Customers in one database read.\n * The generic failure deliberately does not reveal whether an id is missing or\n * belongs to another tenant.\n */\nexport async function assertCustomersBelongToTenant(\n options: DatabaseOptions,\n tenantId: string | null,\n customerIds: readonly string[],\n label: string,\n lock: 'none' | 'share' | 'update' = 'none',\n): Promise<void> {\n if (customerIds.length === 0) return;\n const normalizedCustomerIds = customerIds.map((customerId) => {\n try {\n return normalizeUuid(customerId, 'customerId');\n } catch {\n throw new CampaignCustomerScopeError(label);\n }\n });\n const normalizedTenantId = tenantId?.toLowerCase() ?? null;\n const db = requireDatabase(options);\n const tableName = await resolveCustomerTable(options);\n const placeholders = normalizedCustomerIds.map(() => '?').join(', ');\n const lockClause = postgresLockClause(db, lock);\n const result = await db.query(\n `SELECT id, tenant_id FROM ${tableName} WHERE id IN (${placeholders})${lockClause}`,\n ...normalizedCustomerIds,\n );\n const tenantById = new Map(\n result.rows.map((row) => [\n String(row.id).toLowerCase(),\n row.tenant_id == null ? null : String(row.tenant_id).toLowerCase(),\n ]),\n );\n const valid = normalizedCustomerIds.every(\n (customerId) =>\n tenantById.has(customerId) &&\n tenantById.get(customerId) === normalizedTenantId,\n );\n if (!valid) {\n throw new CampaignCustomerScopeError(label);\n }\n}\n\nfunction postgresLockClause(\n db: QueryDatabase,\n lock: 'none' | 'share' | 'update',\n): string {\n if (lock === 'none' || !/^postgres(?:ql)?:/iu.test(db.url)) return '';\n return lock === 'update' ? ' FOR UPDATE' : ' FOR SHARE';\n}\n\n/** Parse and canonicalize one UUID without echoing the rejected value. */\nexport function normalizeUuid(value: string, label: string): string {\n if (!UUID_RE.test(value)) {\n throw new Error(`${label} must be a canonical UUID.`);\n }\n return value.toLowerCase();\n}\n","/** Campaign identity, budget, schedule, and guarded lifecycle. */\n\nimport {\n crossPackageRef,\n field,\n SmrtObject,\n smrt,\n ValidationError,\n} from '@happyvertical/smrt-core';\nimport {\n getCurrentTenant,\n isSuperAdminBypass,\n isSystemContext,\n TenantIsolationError,\n TenantScoped,\n tenantId,\n withTenant,\n} from '@happyvertical/smrt-tenancy';\nimport {\n assertCustomersBelongToTenant,\n normalizeUuid,\n} from '../customer-scope.js';\nimport { CampaignCustomerScopeError } from '../errors.js';\nimport {\n CAMPAIGN_STATUSES,\n type CampaignOptions,\n type CampaignStatus,\n} from '../types.js';\n\nconst CAMPAIGN_STATUS_TRANSITIONS: Record<CampaignStatus, CampaignStatus[]> = {\n draft: ['scheduled'],\n scheduled: ['active'],\n active: ['paused', 'completed'],\n paused: ['active', 'completed'],\n completed: ['archived'],\n archived: [],\n};\n\nconst loadedCampaignStatus = new WeakMap<Campaign, CampaignStatus>();\n\n@TenantScoped({ mode: 'optional' })\n@smrt({\n tableName: 'campaigns',\n conflictColumns: ['tenant_id', 'campaign_key'],\n indexes: [\n {\n name: 'campaigns_tenant_id_customer_id_start_at_id_idx',\n columns: ['tenantId', 'customerId', 'startAt', 'id'],\n },\n ],\n api: { include: ['list', 'get', 'create', 'update'] },\n mcp: { include: ['list', 'get', 'create', 'update'] },\n cli: { include: ['list', 'get', 'create', 'update'] },\n})\nexport class Campaign extends SmrtObject { static __smrtPackage__ = \"@happyvertical/smrt-marketing\";\n @tenantId({ nullable: true })\n tenantId: string | null = null;\n\n /** Canonical commerce Customer that owns this campaign, when assigned. */\n @crossPackageRef('@happyvertical/smrt-commerce:Customer', {\n nullable: true,\n validate: true,\n })\n customerId: string | null = null;\n\n /** Stable caller-defined key used by CRM/referral systems. */\n @field({ required: true })\n campaignKey: string = '';\n\n @field({ required: true })\n name: string = '';\n\n /** Open objective key such as `awareness` or `demand_generation`. */\n objective: string = '';\n\n status: CampaignStatus = 'draft';\n\n startAt: Date | null = null;\n\n endAt: Date | null = null;\n\n /** Total campaign budget in integer cents. */\n budgetCents: number = 0;\n\n /** ISO 4217 currency for every campaign/channel amount. */\n currency: string = 'USD';\n\n metadata: string = '{}';\n\n constructor(options: CampaignOptions = {}) {\n super(options);\n if (options.tenantId !== undefined) this.tenantId = options.tenantId;\n if (options.customerId !== undefined) this.customerId = options.customerId;\n if (options.campaignKey !== undefined)\n this.campaignKey = options.campaignKey;\n if (options.name !== undefined) this.name = options.name;\n if (options.objective !== undefined) this.objective = options.objective;\n if (options.status !== undefined) this.status = options.status;\n if (options.startAt !== undefined)\n this.startAt = Campaign.coerceDate(options.startAt);\n if (options.endAt !== undefined)\n this.endAt = Campaign.coerceDate(options.endAt);\n if (options.budgetCents !== undefined)\n this.budgetCents = options.budgetCents;\n if (options.currency !== undefined) this.currency = options.currency;\n if (options.metadata !== undefined) this.metadata = options.metadata;\n }\n\n override async initialize(): Promise<this> {\n if (this.id) {\n try {\n this.id = normalizeUuid(this.id, 'id');\n } catch (error) {\n if (this.customerId !== null) {\n throw new CampaignCustomerScopeError('Campaign.initialize');\n }\n throw error;\n }\n }\n await super.initialize();\n this.startAt = Campaign.coerceDate(this.startAt);\n this.endAt = Campaign.coerceDate(this.endAt);\n if (this.isPersisted) loadedCampaignStatus.set(this, this.status);\n return this;\n }\n\n override async save(): Promise<this> {\n if (this.customerId === null) return this.saveLifecycle();\n\n const db = this.db;\n if (typeof db.transaction !== 'function') {\n throw new Error(\n 'Campaign.save requires a database adapter with transaction support.',\n );\n }\n return db.transaction(async (transactionDb) =>\n this.withDatabase(transactionDb, async (bound) => bound.saveLifecycle()),\n );\n }\n\n private async saveLifecycle(): Promise<this> {\n this.prepareIdentityForSave();\n if (this.customerId !== null) {\n await assertCustomersBelongToTenant(\n this.options,\n this.tenantId,\n [this.customerId],\n 'Campaign.save',\n 'update',\n );\n }\n const prior = await this.resolvePriorStatus();\n this.assertStatusTransition(prior);\n this.assertSchedule();\n let result: this;\n try {\n const persist = async () => (await super.save()) as this;\n const tenantContext =\n isSystemContext() || isSuperAdminBypass()\n ? undefined\n : getCurrentTenant();\n result = tenantContext\n ? await withTenant(\n {\n ...tenantContext,\n tenantId: this.tenantId ?? tenantContext.tenantId,\n },\n persist,\n )\n : await persist();\n } catch (error) {\n if (\n error instanceof ValidationError &&\n (error.code === 'VALIDATION_CROSS_PACKAGE_REF_MISSING' ||\n error.code === 'VALIDATION_CROSS_PACKAGE_REF_UNREGISTERED')\n ) {\n throw new CampaignCustomerScopeError('Campaign.save');\n }\n throw error;\n }\n loadedCampaignStatus.set(this, this.status);\n return result;\n }\n\n /** Canonicalize and authorize identity before any status or scope read. */\n private prepareIdentityForSave(): void {\n try {\n if (this.id) this.id = normalizeUuid(this.id, 'id');\n if (this.customerId !== null) {\n this.customerId = normalizeUuid(this.customerId, 'customerId');\n }\n if (this.tenantId !== null) {\n this.tenantId = normalizeUuid(this.tenantId, 'tenantId');\n }\n } catch (error) {\n if (this.customerId !== null) {\n throw new CampaignCustomerScopeError('Campaign.save');\n }\n throw error;\n }\n\n if (isSystemContext() || isSuperAdminBypass()) return;\n const tenantContext = getCurrentTenant();\n if (!tenantContext) return;\n\n let contextTenantId: string;\n try {\n contextTenantId = normalizeUuid(tenantContext.tenantId, 'tenantId');\n } catch (error) {\n if (this.customerId !== null) {\n throw new CampaignCustomerScopeError('Campaign.save');\n }\n throw error;\n }\n if (this.tenantId !== null && this.tenantId !== contextTenantId) {\n throw new TenantIsolationError(\n 'Tenant isolation violation in Campaign.save.',\n { tenantId: contextTenantId, attemptedTenantId: this.tenantId },\n );\n }\n this.tenantId = contextTenantId;\n }\n\n /** Apply one legal transition in memory; callers choose the save boundary. */\n transitionTo(next: CampaignStatus): this {\n if (next === this.status) return this;\n const allowed = CAMPAIGN_STATUS_TRANSITIONS[this.status] ?? [];\n if (!allowed.includes(next)) {\n throw new Error(\n `Campaign ${this.campaignKey || this.id}: cannot transition ` +\n `'${this.status}' → '${next}'.`,\n );\n }\n this.status = next;\n return this;\n }\n\n getMetadata(): Record<string, unknown> {\n if (!this.metadata) return {};\n try {\n const parsed = JSON.parse(this.metadata) as unknown;\n return parsed && typeof parsed === 'object' && !Array.isArray(parsed)\n ? (parsed as Record<string, unknown>)\n : {};\n } catch {\n return {};\n }\n }\n\n setMetadata(metadata: Record<string, unknown>): void {\n this.metadata = JSON.stringify(metadata ?? {});\n }\n\n private assertSchedule(): void {\n if (\n this.startAt &&\n this.endAt &&\n this.endAt.getTime() < this.startAt.getTime()\n ) {\n throw new Error('Campaign endAt must be on or after startAt.');\n }\n if (!Number.isInteger(this.budgetCents) || this.budgetCents < 0) {\n throw new Error('Campaign budgetCents must be a non-negative integer.');\n }\n }\n\n private async resolvePriorStatus(): Promise<CampaignStatus | undefined> {\n if (this.id) {\n let scopedRow: Record<string, unknown> | null = null;\n try {\n scopedRow = await this.db.get(this.tableName, {\n id: this.id,\n tenant_id: this.tenantId,\n });\n } catch {\n // DB not ready / table absent; fall through to the hydrated state.\n }\n if (scopedRow?.status != null) {\n return scopedRow.status as CampaignStatus;\n }\n\n // A caller-supplied ID already owned by another lane must not expose its\n // lifecycle state or be repurposed by an upsert.\n let rowInAnotherLane: Record<string, unknown> | null = null;\n try {\n rowInAnotherLane = await this.db.get(this.tableName, { id: this.id });\n } catch {\n // DB not ready / table absent; fall through to the hydrated state.\n }\n if (rowInAnotherLane) {\n throw new CampaignCustomerScopeError('Campaign.save');\n }\n }\n if (this.campaignKey) {\n try {\n const row = await this.db.get(this.tableName, {\n tenant_id: this.tenantId,\n campaign_key: this.campaignKey,\n });\n if (row && row.status != null) return row.status as CampaignStatus;\n } catch {\n // DB not ready / table absent; fall through to the hydrated state.\n }\n }\n return loadedCampaignStatus.get(this);\n }\n\n private assertStatusTransition(prior: CampaignStatus | undefined): void {\n if (!CAMPAIGN_STATUSES.includes(this.status)) {\n throw new Error(\n `Campaign ${this.campaignKey || this.id}: unknown status '${this.status}'.`,\n );\n }\n if (prior === undefined || prior === this.status) return;\n const allowed = CAMPAIGN_STATUS_TRANSITIONS[prior] ?? [];\n if (!allowed.includes(this.status)) {\n throw new Error(\n `Campaign ${this.campaignKey || this.id}: illegal status transition ` +\n `'${prior}' → '${this.status}'.`,\n );\n }\n }\n\n private static coerceDate(value: unknown): Date | null {\n if (value == null) return null;\n if (value instanceof Date) return value;\n if (typeof value === 'number' || typeof value === 'string') {\n const date = new Date(value);\n return Number.isNaN(date.getTime()) ? null : date;\n }\n return null;\n }\n}\n\nexport default Campaign;\n","/** Generic links from a campaign to cross-package channel execution rows. */\n\nimport { field, foreignKey, SmrtObject, smrt } from '@happyvertical/smrt-core';\nimport { TenantScoped, tenantId } from '@happyvertical/smrt-tenancy';\nimport type {\n CampaignChannelOptions,\n CampaignChannelStatus,\n} from '../types.js';\nimport { CAMPAIGN_CHANNEL_STATUSES } from '../types.js';\nimport { Campaign } from './Campaign.js';\n\n@TenantScoped({ mode: 'optional' })\n@smrt({\n tableName: 'campaign_channels',\n conflictColumns: ['campaign_id', 'channel_kind', 'channel_ref'],\n api: { include: ['list', 'get', 'create', 'update', 'delete'] },\n mcp: { include: ['list', 'get', 'create', 'update'] },\n cli: { include: ['list', 'get', 'create', 'update', 'delete'] },\n})\nexport class CampaignChannel extends SmrtObject { static __smrtPackage__ = \"@happyvertical/smrt-marketing\";\n @tenantId({ nullable: true })\n tenantId: string | null = null;\n\n @foreignKey(Campaign, { required: true })\n campaignId: string = '';\n\n /** Open kind vocabulary; recommended values live in CAMPAIGN_CHANNEL_KINDS. */\n @field({ required: true })\n channelKind: string = '';\n\n /** Opaque identifier in the namespace named by channelKind. */\n @field({ required: true })\n channelRef: string = '';\n\n allocatedBudgetCents: number = 0;\n\n /** Optional execution-specific override of the Campaign start. */\n startAt: Date | null = null;\n\n /** Optional execution-specific override of the Campaign end. */\n endAt: Date | null = null;\n\n status: CampaignChannelStatus = 'planned';\n\n constructor(options: CampaignChannelOptions = {}) {\n super(options);\n if (options.tenantId !== undefined) this.tenantId = options.tenantId;\n if (options.campaignId !== undefined) this.campaignId = options.campaignId;\n if (options.channelKind !== undefined)\n this.channelKind = options.channelKind;\n if (options.channelRef !== undefined) this.channelRef = options.channelRef;\n if (options.allocatedBudgetCents !== undefined)\n this.allocatedBudgetCents = options.allocatedBudgetCents;\n if (options.startAt !== undefined)\n this.startAt = CampaignChannel.coerceDate(options.startAt);\n if (options.endAt !== undefined)\n this.endAt = CampaignChannel.coerceDate(options.endAt);\n if (options.status !== undefined) this.status = options.status;\n }\n\n override async initialize(): Promise<this> {\n await super.initialize();\n this.startAt = CampaignChannel.coerceDate(this.startAt);\n this.endAt = CampaignChannel.coerceDate(this.endAt);\n return this;\n }\n\n override async save(): Promise<this> {\n if (!CAMPAIGN_CHANNEL_STATUSES.includes(this.status)) {\n throw new Error(\n `CampaignChannel ${this.channelRef || this.id}: unknown status '${this.status}'.`,\n );\n }\n if (\n !Number.isInteger(this.allocatedBudgetCents) ||\n this.allocatedBudgetCents < 0\n ) {\n throw new Error(\n 'CampaignChannel allocatedBudgetCents must be a non-negative integer.',\n );\n }\n if (\n this.startAt &&\n this.endAt &&\n this.endAt.getTime() < this.startAt.getTime()\n ) {\n throw new Error('CampaignChannel endAt must be on or after startAt.');\n }\n return (await super.save()) as this;\n }\n\n private static coerceDate(value: unknown): Date | null {\n if (value == null) return null;\n if (value instanceof Date) return value;\n if (typeof value === 'number' || typeof value === 'string') {\n const date = new Date(value);\n return Number.isNaN(date.getTime()) ? null : date;\n }\n return null;\n }\n}\n\nexport default CampaignChannel;\n","import { SmrtCollection } from '@happyvertical/smrt-core';\nimport { CampaignChannel } from '../models/CampaignChannel.js';\n\nexport class CampaignChannelCollection extends SmrtCollection<CampaignChannel> {\n static readonly _itemClass = CampaignChannel;\n\n async findByCampaign(campaignId: string): Promise<CampaignChannel[]> {\n return await this.list({\n where: { campaignId },\n orderBy: 'start_at ASC',\n });\n }\n\n async findByExecutionRef(\n channelKind: string,\n channelRef: string,\n ): Promise<CampaignChannel[]> {\n return await this.list({ where: { channelKind, channelRef } });\n }\n}\n\nexport default CampaignChannelCollection;\n","import type { Campaign } from '../models/Campaign.js';\nimport type { BudgetPacingResult, BudgetPacingStatus } from '../types.js';\n\nexport interface BudgetPacingEvidence {\n spendCents: number;\n snapshotCount: number;\n usedCampaignRollups: boolean;\n}\n\n/** Canonical campaign pacing calculation for grouped and row-level evidence. */\nexport function calculateCampaignPacing(\n campaign: Campaign,\n evidence: BudgetPacingEvidence,\n at = new Date(),\n): BudgetPacingResult {\n return calculatePacing({\n campaign,\n evidence,\n budgetCents: campaign.budgetCents,\n startAt: campaign.startAt,\n endAt: campaign.endAt,\n at,\n });\n}\n\nexport function calculatePacing({\n campaign,\n evidence,\n budgetCents,\n startAt,\n endAt,\n at,\n}: {\n campaign: Campaign;\n evidence: BudgetPacingEvidence;\n budgetCents: number;\n startAt: Date | null;\n endAt: Date | null;\n at: Date;\n}): BudgetPacingResult {\n const elapsed = elapsedFraction(startAt, endAt, at);\n const expectedSpendCents =\n elapsed === null ? null : Math.round(budgetCents * elapsed);\n const varianceCents =\n expectedSpendCents === null\n ? null\n : evidence.spendCents - expectedSpendCents;\n return {\n campaignId: campaign.id ?? '',\n currency: campaign.currency,\n budgetCents,\n spendCents: evidence.spendCents,\n remainingCents: budgetCents - evidence.spendCents,\n expectedSpendCents,\n varianceCents,\n budgetFraction: budgetCents > 0 ? evidence.spendCents / budgetCents : null,\n elapsedFraction: elapsed,\n status: pacingStatus({\n campaign,\n budgetCents,\n spendCents: evidence.spendCents,\n elapsedFraction: elapsed,\n varianceCents,\n startAt,\n at,\n }),\n snapshotCount: evidence.snapshotCount,\n usedCampaignRollups: evidence.usedCampaignRollups,\n };\n}\n\nfunction pacingStatus({\n campaign,\n budgetCents,\n spendCents,\n elapsedFraction,\n varianceCents,\n startAt,\n at,\n}: {\n campaign: Campaign;\n budgetCents: number;\n spendCents: number;\n elapsedFraction: number | null;\n varianceCents: number | null;\n startAt: Date | null;\n at: Date;\n}): BudgetPacingStatus {\n if (budgetCents <= 0) return 'unbudgeted';\n if (spendCents > budgetCents) return 'over_budget';\n if (startAt && at.getTime() < startAt.getTime()) return 'not_started';\n if (\n campaign.status === 'completed' ||\n campaign.status === 'archived' ||\n elapsedFraction === 1\n ) {\n return 'complete';\n }\n if (varianceCents === null) return 'on_track';\n\n // A five-percent budget band avoids noisy status flips from minor timing\n // differences between spend collection and scheduled pacing.\n const toleranceCents = Math.max(1, Math.round(budgetCents * 0.05));\n if (varianceCents > toleranceCents) return 'ahead';\n if (varianceCents < -toleranceCents) return 'behind';\n return 'on_track';\n}\n\nfunction elapsedFraction(\n startAt: Date | null,\n endAt: Date | null,\n at: Date,\n): number | null {\n if (!startAt || !endAt) return null;\n const start = startAt.getTime();\n const end = endAt.getTime();\n if (end <= start) return at.getTime() < start ? 0 : 1;\n return Math.min(1, Math.max(0, (at.getTime() - start) / (end - start)));\n}\n","/** Immutable period performance evidence for a campaign or campaign channel. */\n\nimport { field, foreignKey, SmrtObject, smrt } from '@happyvertical/smrt-core';\nimport { TenantScoped, tenantId } from '@happyvertical/smrt-tenancy';\nimport type { CampaignMetricSnapshotOptions } from '../types.js';\nimport { Campaign } from './Campaign.js';\nimport { CampaignChannel } from './CampaignChannel.js';\n\nconst persistedSnapshotState = new WeakMap<CampaignMetricSnapshot, string>();\n\n@TenantScoped({ mode: 'optional' })\n@smrt({\n tableName: 'campaign_metric_snapshots',\n conflictColumns: ['dedupe_key'],\n api: { include: ['list', 'get', 'create'] },\n mcp: { include: ['list', 'get', 'create'] },\n cli: { include: ['list', 'get', 'create'] },\n})\nexport class CampaignMetricSnapshot extends SmrtObject { static __smrtPackage__ = \"@happyvertical/smrt-marketing\";\n @tenantId({ nullable: true })\n tenantId: string | null = null;\n\n @foreignKey(Campaign, { required: true })\n campaignId: string = '';\n\n /** Null for campaign rollups; set for channel-scoped evidence. */\n @foreignKey(CampaignChannel, { nullable: true })\n campaignChannelId: string | null = null;\n\n @field({ required: true })\n periodStart: Date = new Date();\n\n @field({ required: true })\n periodEnd: Date = new Date();\n\n spendCents: number = 0;\n\n impressions: number = 0;\n\n clicks: number = 0;\n\n conversions: number = 0;\n\n leads: number = 0;\n\n @field({ type: 'integer', nullable: true })\n revenueCents: number | null = null;\n\n /** Ingestion source such as `google_ads`, `meta`, or `rollup_job`. */\n @field({ required: true })\n source: string = '';\n\n @field({ required: true })\n dedupeKey: string = '';\n\n constructor(options: CampaignMetricSnapshotOptions = {}) {\n super(options);\n if (options.tenantId !== undefined) this.tenantId = options.tenantId;\n if (options.campaignId !== undefined) this.campaignId = options.campaignId;\n if (options.campaignChannelId !== undefined)\n this.campaignChannelId = options.campaignChannelId;\n if (options.periodStart !== undefined)\n this.periodStart =\n CampaignMetricSnapshot.coerceDate(options.periodStart) ??\n new Date(Number.NaN);\n if (options.periodEnd !== undefined)\n this.periodEnd =\n CampaignMetricSnapshot.coerceDate(options.periodEnd) ??\n new Date(Number.NaN);\n if (options.spendCents !== undefined) this.spendCents = options.spendCents;\n if (options.impressions !== undefined)\n this.impressions = options.impressions;\n if (options.clicks !== undefined) this.clicks = options.clicks;\n if (options.conversions !== undefined)\n this.conversions = options.conversions;\n if (options.leads !== undefined) this.leads = options.leads;\n if (options.revenueCents !== undefined)\n this.revenueCents = options.revenueCents;\n if (options.source !== undefined) this.source = options.source;\n if (options.dedupeKey !== undefined) this.dedupeKey = options.dedupeKey;\n }\n\n override async initialize(): Promise<this> {\n await super.initialize();\n this.periodStart =\n CampaignMetricSnapshot.coerceDate(this.periodStart) ??\n new Date(Number.NaN);\n this.periodEnd =\n CampaignMetricSnapshot.coerceDate(this.periodEnd) ?? new Date(Number.NaN);\n if (this.isPersisted) {\n persistedSnapshotState.set(this, this.serializeState());\n }\n return this;\n }\n\n override async save(): Promise<this> {\n this.assertMetrics();\n await this.assertChannelMatchesCampaign();\n const captured = persistedSnapshotState.get(this);\n if (captured !== undefined) {\n if (captured !== this.serializeState()) {\n throw new Error(\n `CampaignMetricSnapshot ${this.id ?? '<new>'}: metric snapshots ` +\n 'are immutable evidence; ingest a correcting snapshot instead.',\n );\n }\n } else if (this.id && (await this.isSaved())) {\n throw new Error(\n `CampaignMetricSnapshot ${this.id}: refusing to overwrite an existing ` +\n 'snapshot from a non-hydrated instance; snapshots are immutable evidence.',\n );\n } else if (this.dedupeKey) {\n try {\n const row = await this.db.get(this.tableName, {\n dedupe_key: this.dedupeKey,\n });\n if (row && row.id !== this.id) {\n throw new Error(\n `CampaignMetricSnapshot (dedupeKey '${this.dedupeKey}'): a ` +\n 'snapshot with this dedupe key already exists; use ' +\n 'MetricIngestionService for idempotent ingestion.',\n );\n }\n } catch (error) {\n if (\n error instanceof Error &&\n error.message.includes('idempotent ingestion')\n ) {\n throw error;\n }\n // DB not ready / table absent; there is no persisted row to protect.\n }\n }\n\n const result = (await super.save()) as this;\n persistedSnapshotState.set(this, this.serializeState());\n return result;\n }\n\n override async delete(): Promise<void> {\n throw new Error(\n `CampaignMetricSnapshot ${this.id ?? '<new>'}: metric snapshots are ` +\n 'immutable evidence and cannot be deleted.',\n );\n }\n\n private assertMetrics(): void {\n if (\n Number.isNaN(this.periodStart.getTime()) ||\n Number.isNaN(this.periodEnd.getTime())\n ) {\n throw new Error(\n 'CampaignMetricSnapshot periodStart and periodEnd must be valid dates.',\n );\n }\n if (this.periodEnd.getTime() < this.periodStart.getTime()) {\n throw new Error(\n 'CampaignMetricSnapshot periodEnd must be on or after periodStart.',\n );\n }\n const integerMetrics: Array<[string, number]> = [\n ['spendCents', this.spendCents],\n ['impressions', this.impressions],\n ['clicks', this.clicks],\n ['conversions', this.conversions],\n ['leads', this.leads],\n ];\n for (const [name, value] of integerMetrics) {\n if (!Number.isInteger(value) || value < 0) {\n throw new Error(`${name} must be a non-negative integer.`);\n }\n }\n if (\n this.revenueCents !== null &&\n (!Number.isInteger(this.revenueCents) || this.revenueCents < 0)\n ) {\n throw new Error('revenueCents must be null or a non-negative integer.');\n }\n }\n\n private async assertChannelMatchesCampaign(): Promise<void> {\n if (!this.campaignChannelId) return;\n const channel = (await this.loadRelated(\n 'campaignChannelId',\n )) as CampaignChannel;\n if (channel.campaignId !== this.campaignId) {\n throw new Error(\n `CampaignMetricSnapshot campaignChannelId '${this.campaignChannelId}' ` +\n `does not belong to campaignId '${this.campaignId}'.`,\n );\n }\n }\n\n private serializeState(): string {\n return JSON.stringify({\n tenantId: this.tenantId,\n campaignId: this.campaignId,\n campaignChannelId: this.campaignChannelId,\n periodStart: this.periodStart.toISOString(),\n periodEnd: this.periodEnd.toISOString(),\n spendCents: this.spendCents,\n impressions: this.impressions,\n clicks: this.clicks,\n conversions: this.conversions,\n leads: this.leads,\n revenueCents: this.revenueCents,\n source: this.source,\n dedupeKey: this.dedupeKey,\n });\n }\n\n private static coerceDate(value: unknown): Date | null {\n if (value instanceof Date) {\n return Number.isNaN(value.getTime()) ? null : value;\n }\n if (typeof value === 'number' || typeof value === 'string') {\n const date = new Date(value);\n return Number.isNaN(date.getTime()) ? null : date;\n }\n return null;\n }\n}\n\nexport default CampaignMetricSnapshot;\n","import { SmrtCollection } from '@happyvertical/smrt-core';\nimport { CampaignMetricSnapshot } from '../models/CampaignMetricSnapshot.js';\nimport type { CampaignMetricSnapshotOptions } from '../types.js';\n\nexport class CampaignMetricSnapshotCollection extends SmrtCollection<CampaignMetricSnapshot> {\n static readonly _itemClass = CampaignMetricSnapshot;\n\n async findByDedupeKey(\n dedupeKey: string,\n ): Promise<CampaignMetricSnapshot | null> {\n if (!dedupeKey) return null;\n const rows = await this.list({ where: { dedupeKey }, limit: 1 });\n return rows[0] ?? null;\n }\n\n async getOrCreateByDedupeKey(\n options: CampaignMetricSnapshotOptions,\n ): Promise<{ snapshot: CampaignMetricSnapshot; created: boolean }> {\n const dedupeKey = options.dedupeKey ?? '';\n if (!dedupeKey) {\n throw new Error(\n 'CampaignMetricSnapshotCollection.getOrCreateByDedupeKey requires a dedupeKey.',\n );\n }\n const existing = await this.findByDedupeKey(dedupeKey);\n if (existing) return { snapshot: existing, created: false };\n\n try {\n const snapshot = await this.create({\n ...options,\n // Keep runtime values uncoerced so the model rejects null/invalid\n // periods instead of allowing Date(null) to become the Unix epoch.\n periodStart: options.periodStart as Date | undefined,\n periodEnd: options.periodEnd as Date | undefined,\n _insertOnly: true,\n });\n return { snapshot, created: true };\n } catch (error) {\n // A concurrent ingest may have won the unique dedupe-key insert after\n // our initial read. Re-read the immutable winner instead of allowing a\n // natural-key upsert to replace its evidence in place.\n const concurrent = await this.findByDedupeKey(dedupeKey);\n if (concurrent) return { snapshot: concurrent, created: false };\n throw error;\n }\n }\n\n async findByCampaign(campaignId: string): Promise<CampaignMetricSnapshot[]> {\n return await this.list({\n where: { campaignId },\n orderBy: 'period_start ASC',\n });\n }\n\n async findByChannel(\n campaignChannelId: string,\n ): Promise<CampaignMetricSnapshot[]> {\n return await this.list({\n where: { campaignChannelId },\n orderBy: 'period_start ASC',\n });\n }\n}\n\nexport default CampaignMetricSnapshotCollection;\n","import {\n type CollectionCacheConfig,\n resolveListLimit,\n SmrtCollection,\n type SmrtListOptions,\n type SmrtSelectedRow,\n type SmrtSelectField,\n type SmrtWhereClause,\n} from '@happyvertical/smrt-core';\nimport {\n getCurrentTenant,\n isSuperAdminBypass,\n isSystemContext,\n TenantIsolationError,\n withTenant,\n} from '@happyvertical/smrt-tenancy';\nimport type { DatabaseInterface } from '@happyvertical/sql';\nimport {\n assertCustomersBelongToTenant,\n normalizeUuid,\n} from '../customer-scope.js';\nimport { Campaign } from '../models/Campaign.js';\nimport { calculateCampaignPacing } from '../services/pacing-calculation.js';\nimport type {\n CampaignChannelMixEntry,\n CampaignCustomerCursor,\n CampaignCustomerCursorInput,\n CampaignCustomerPage,\n CampaignCustomerSummary,\n CampaignMetricTotals,\n CampaignReportingPage,\n CampaignStatus,\n ListCampaignReportingByCustomerOptions,\n ListCampaignsByCustomerOptions,\n} from '../types.js';\nimport { CampaignChannelCollection } from './CampaignChannelCollection.js';\nimport { CampaignMetricSnapshotCollection } from './CampaignMetricSnapshotCollection.js';\n\nexport const MAX_CAMPAIGN_CUSTOMER_PAGE_SIZE = 100;\nexport const MAX_CAMPAIGN_CUSTOMER_BATCH_SIZE = 100;\n\nexport class CampaignCollection extends SmrtCollection<Campaign> {\n static readonly _itemClass = Campaign;\n\n override async get(\n filter: string | SmrtWhereClause<Campaign>,\n options: { cache?: CollectionCacheConfig | false } = {},\n ): Promise<Campaign | null> {\n return withCanonicalActiveTenant(() =>\n super.get(normalizeCampaignGetFilter(filter), options),\n );\n }\n\n override async list<\n const Select extends readonly SmrtSelectField<Campaign>[],\n >(\n options: SmrtListOptions<Campaign> & { select: Select; include?: never },\n ): Promise<SmrtSelectedRow<Campaign, Select>[]>;\n override async list(\n options?: Omit<SmrtListOptions<Campaign>, 'select'> & {\n select?: undefined;\n },\n ): Promise<Campaign[]>;\n override async list(\n options: SmrtListOptions<Campaign> = {},\n ): Promise<Campaign[] | Record<string, unknown>[]> {\n return withCanonicalActiveTenant(\n () =>\n super.list(normalizeCampaignListOptions(options) as never) as Promise<\n Campaign[] | Record<string, unknown>[]\n >,\n );\n }\n\n async findByCampaignKey(\n campaignKey: string,\n tenantId?: string | null,\n ): Promise<Campaign | null> {\n if (!campaignKey) return null;\n const where: Record<string, unknown> = { campaignKey };\n if (tenantId !== undefined) where.tenantId = tenantId;\n const rows = await this.list({ where, limit: 1 });\n return rows[0] ?? null;\n }\n\n async findByStatus(status: CampaignStatus): Promise<Campaign[]> {\n return await this.list({\n where: { status },\n orderBy: 'start_at ASC',\n });\n }\n\n /**\n * List one tenant/customer lane newest-first using a stable UUID tiebreaker.\n * Null start times follow all scheduled rows on every supported database.\n */\n async listByCustomer(\n tenantId: string | null,\n customerId: string,\n options: ListCampaignsByCustomerOptions = {},\n ): Promise<CampaignCustomerPage> {\n const normalizedTenantId = normalizeTenantScope(\n tenantId,\n 'CampaignCollection.listByCustomer',\n );\n const normalizedCustomerId = normalizeUuid(customerId, 'customerId');\n const limit = resolveListLimit(options.limit, {\n defaultValue: 50,\n maxValue: Number.MAX_SAFE_INTEGER,\n parameterName: 'campaign customer page limit',\n });\n if (limit > MAX_CAMPAIGN_CUSTOMER_PAGE_SIZE) {\n throw new Error(\n `Campaign customer page limit must not exceed ${MAX_CAMPAIGN_CUSTOMER_PAGE_SIZE}.`,\n );\n }\n if (limit < 1) {\n throw new Error('Campaign customer page limit must be at least 1.');\n }\n const cursor = normalizeCursor(options.after);\n return withCanonicalTenantContext(normalizedTenantId, () =>\n this.inCustomerReadTransaction(async (bound) =>\n bound.listByCustomerInTransaction(\n normalizedTenantId,\n normalizedCustomerId,\n limit,\n cursor,\n 'CampaignCollection.listByCustomer',\n ),\n ),\n );\n }\n\n /**\n * Return one bounded customer page with its complete read-only reporting\n * projection. Channels and immutable evidence are aggregated in two grouped\n * reads, independent of page size; no campaign callback or lazy load runs.\n */\n async listReportingByCustomer(\n tenantId: string | null,\n customerId: string,\n options: ListCampaignReportingByCustomerOptions = {},\n ): Promise<CampaignReportingPage> {\n const normalizedTenantId = normalizeTenantScope(\n tenantId,\n 'CampaignCollection.listReportingByCustomer',\n );\n const normalizedCustomerId = normalizeUuid(customerId, 'customerId');\n const limit = resolveListLimit(options.limit, {\n defaultValue: 50,\n maxValue: Number.MAX_SAFE_INTEGER,\n parameterName: 'campaign reporting page limit',\n });\n if (limit > MAX_CAMPAIGN_CUSTOMER_PAGE_SIZE) {\n throw new Error(\n `Campaign reporting page limit must not exceed ${MAX_CAMPAIGN_CUSTOMER_PAGE_SIZE}.`,\n );\n }\n if (limit < 1) {\n throw new Error('Campaign reporting page limit must be at least 1.');\n }\n const cursor = normalizeCursor(options.after);\n const at = normalizeReportingAt(options.at);\n\n return withCanonicalTenantContext(normalizedTenantId, () =>\n this.inCustomerReadTransaction(async (bound) => {\n const page = await bound.listByCustomerInTransaction(\n normalizedTenantId,\n normalizedCustomerId,\n limit,\n cursor,\n 'CampaignCollection.listReportingByCustomer',\n );\n return bound.projectReportingPage(normalizedTenantId, page, at);\n }),\n );\n }\n\n private async projectReportingPage(\n tenantId: string | null,\n page: CampaignCustomerPage,\n at: Date,\n ): Promise<CampaignReportingPage> {\n const campaignIds = page.items.map((campaign) => {\n if (!campaign.id) {\n throw new Error('Campaign reporting requires persisted Campaign rows.');\n }\n return normalizeUuid(campaign.id, 'campaign id');\n });\n if (campaignIds.length === 0) {\n return { items: [], nextCursor: page.nextCursor };\n }\n\n const channelRows = await this.loadChannelMixRows(tenantId, campaignIds);\n const metricRows = await this.loadMetricRows(tenantId, campaignIds);\n const channelsByCampaign = groupChannelMix(channelRows);\n const metricsByCampaign = groupMetricTotals(metricRows);\n\n return {\n items: page.items.map((campaign) => {\n const campaignId = campaign.id ?? '';\n const channelMix = channelsByCampaign.get(campaignId) ?? [];\n const metrics =\n metricsByCampaign.get(campaignId) ?? emptyMetricTotals();\n return {\n campaign,\n channelCount: channelMix.reduce(\n (sum, entry) =>\n checkedAdd(sum, entry.count, 'Campaign channel count'),\n 0,\n ),\n channelMix,\n metricTotals: metrics.totals,\n pacing: calculateCampaignPacing(\n campaign,\n {\n spendCents: metrics.totals.spendCents,\n snapshotCount: metrics.snapshotCount,\n usedCampaignRollups: metrics.usedCampaignRollups,\n },\n at,\n ),\n };\n }),\n nextCursor: page.nextCursor,\n };\n }\n\n private async loadChannelMixRows(\n tenantId: string | null,\n campaignIds: string[],\n ): Promise<Array<Record<string, unknown>>> {\n const channels = await CampaignChannelCollection.create({\n ...this.options,\n db: this.db,\n defaultListLimit: undefined,\n maxListLimit: undefined,\n });\n const db = requireDatabase(this.options);\n const placeholders = campaignIds.map(() => '?').join(', ');\n const tenantPredicate =\n tenantId === null ? 'tenant_id IS NULL' : 'tenant_id = ?';\n const tenantParams = tenantId === null ? [] : [tenantId];\n const result = await db.query(\n `SELECT campaign_id, channel_kind, COUNT(*) AS channel_count\n FROM ${channels.tableName}\n WHERE ${tenantPredicate} AND campaign_id IN (${placeholders})\n GROUP BY campaign_id, channel_kind\n ORDER BY campaign_id ASC, channel_kind ASC`,\n ...tenantParams,\n ...campaignIds,\n );\n return result.rows;\n }\n\n private async loadMetricRows(\n tenantId: string | null,\n campaignIds: string[],\n ): Promise<Array<Record<string, unknown>>> {\n const snapshots = await CampaignMetricSnapshotCollection.create({\n ...this.options,\n db: this.db,\n defaultListLimit: undefined,\n maxListLimit: undefined,\n });\n const db = requireDatabase(this.options);\n const placeholders = campaignIds.map(() => '?').join(', ');\n const tenantPredicate =\n tenantId === null ? 'tenant_id IS NULL' : 'tenant_id = ?';\n const tenantParams = tenantId === null ? [] : [tenantId];\n const result = await db.query(\n `WITH scoped_snapshots AS (\n SELECT campaign_id,\n campaign_channel_id,\n period_start,\n period_end,\n spend_cents,\n impressions,\n clicks,\n conversions,\n leads,\n revenue_cents\n FROM ${snapshots.tableName}\n WHERE ${tenantPredicate} AND campaign_id IN (${placeholders})\n ), rollup_periods AS (\n SELECT DISTINCT campaign_id, period_start, period_end\n FROM scoped_snapshots\n WHERE campaign_channel_id IS NULL\n ), selected_snapshots AS (\n SELECT s.*\n FROM scoped_snapshots s\n LEFT JOIN rollup_periods r\n ON r.campaign_id = s.campaign_id\n AND r.period_start = s.period_start\n AND r.period_end = s.period_end\n WHERE s.campaign_channel_id IS NULL OR r.campaign_id IS NULL\n )\n SELECT campaign_id,\n COUNT(*) AS snapshot_count,\n MAX(CASE WHEN campaign_channel_id IS NULL THEN 1 ELSE 0 END)\n AS used_campaign_rollups,\n SUM(spend_cents) AS spend_cents,\n SUM(impressions) AS impressions,\n SUM(clicks) AS clicks,\n SUM(conversions) AS conversions,\n SUM(leads) AS leads,\n SUM(COALESCE(revenue_cents, 0)) AS revenue_cents\n FROM selected_snapshots\n GROUP BY campaign_id\n ORDER BY campaign_id ASC`,\n ...tenantParams,\n ...campaignIds,\n );\n return result.rows;\n }\n\n private async listByCustomerInTransaction(\n tenantId: string | null,\n customerId: string,\n limit: number,\n cursor: CampaignCustomerCursor | null,\n operation: string,\n ): Promise<CampaignCustomerPage> {\n await assertCustomersBelongToTenant(\n this.options,\n tenantId,\n [customerId],\n operation,\n 'share',\n );\n const items =\n cursor?.startAt === null\n ? await this.listNullStartLane(tenantId, customerId, limit + 1, cursor)\n : await this.listScheduledLane(tenantId, customerId, limit, cursor);\n const hasMore = items.length > limit;\n const pageItems = hasMore ? items.slice(0, limit) : items;\n return {\n items: pageItems,\n nextCursor: hasMore\n ? cursorFromCampaign(pageItems[pageItems.length - 1])\n : null,\n };\n }\n\n /**\n * Summarize a bounded customer batch with one scope check and one grouped\n * aggregate query. Every requested customer receives a row, including zeros.\n */\n async summarizeByCustomers(\n tenantId: string | null,\n customerIds: string[],\n ): Promise<CampaignCustomerSummary[]> {\n const normalizedTenantId = normalizeTenantScope(\n tenantId,\n 'CampaignCollection.summarizeByCustomers',\n );\n if (!Array.isArray(customerIds)) {\n throw new Error(\n 'Campaign customer summary customerIds must be an array.',\n );\n }\n if (customerIds.length > MAX_CAMPAIGN_CUSTOMER_BATCH_SIZE) {\n throw new Error(\n `Campaign customer summary accepts at most ${MAX_CAMPAIGN_CUSTOMER_BATCH_SIZE} customerIds.`,\n );\n }\n const normalizedCustomerIds = customerIds.map((customerId) =>\n normalizeUuid(customerId, 'customerId'),\n );\n const uniqueIds = [...new Set(normalizedCustomerIds)];\n if (uniqueIds.length === 0) return [];\n\n return withCanonicalTenantContext(normalizedTenantId, () =>\n this.inCustomerReadTransaction(async (bound) =>\n bound.summarizeByCustomersInTransaction(\n normalizedTenantId,\n normalizedCustomerIds,\n uniqueIds,\n ),\n ),\n );\n }\n\n private async summarizeByCustomersInTransaction(\n tenantId: string | null,\n requestedCustomerIds: string[],\n uniqueIds: string[],\n ): Promise<CampaignCustomerSummary[]> {\n await assertCustomersBelongToTenant(\n this.options,\n tenantId,\n uniqueIds,\n 'CampaignCollection.summarizeByCustomers',\n 'share',\n );\n const db = requireDatabase(this.options);\n const placeholders = uniqueIds.map(() => '?').join(', ');\n const tenantPredicate =\n tenantId === null ? 'tenant_id IS NULL' : 'tenant_id = ?';\n const tenantParams = tenantId === null ? [] : [tenantId];\n const result = await db.query(\n `SELECT customer_id,\n COUNT(*) AS total_count,\n SUM(CASE WHEN status = ? THEN 1 ELSE 0 END) AS active_count,\n MAX(start_at) AS latest_start_at\n FROM ${this.tableName}\n WHERE ${tenantPredicate} AND customer_id IN (${placeholders})\n GROUP BY customer_id\n ORDER BY customer_id ASC\n LIMIT ?`,\n 'active',\n ...tenantParams,\n ...uniqueIds,\n uniqueIds.length,\n );\n const byCustomer = new Map(\n result.rows.map((row) => [String(row.customer_id).toLowerCase(), row]),\n );\n return requestedCustomerIds.map((customerId) => {\n const row = byCustomer.get(customerId);\n return {\n customerId,\n totalCount: row\n ? toSafeCount(row.total_count, 'Campaign customer total count')\n : 0,\n activeCount: row\n ? toSafeCount(row.active_count, 'Campaign customer active count')\n : 0,\n latestStartAt: row ? coerceDate(row.latest_start_at) : null,\n };\n });\n }\n\n private async inCustomerReadTransaction<T>(\n operation: (bound: CampaignCollection) => Promise<T>,\n ): Promise<T> {\n const db = this.db as DatabaseInterface;\n if (typeof db.transaction !== 'function') {\n throw new Error(\n 'Campaign customer reads require a database adapter with transaction support.',\n );\n }\n return db.transaction(async (transactionDb) => {\n const bound = await CampaignCollection.create({\n ...this.options,\n db: transactionDb,\n defaultListLimit: undefined,\n maxListLimit: undefined,\n });\n return operation(bound);\n });\n }\n\n private async listScheduledLane(\n tenantId: string | null,\n customerId: string,\n limit: number,\n cursor: CampaignCustomerCursor | null,\n ): Promise<Campaign[]> {\n const base = [{ tenantId }, { customerId }, { 'startAt !=': null }];\n const where = cursor\n ? [\n [...base, { 'startAt <': cursor.startAt }],\n [...base, { startAt: cursor.startAt }, { 'id <': cursor.id }],\n ]\n : { tenantId, customerId, 'startAt !=': null };\n const scheduled = await this.list({\n where,\n orderBy: ['start_at DESC', 'id DESC'],\n limit: limit + 1,\n });\n if (scheduled.length > limit) return scheduled;\n const nullRows = await this.listNullStartLane(\n tenantId,\n customerId,\n limit - scheduled.length + 1,\n null,\n );\n return [...scheduled, ...nullRows];\n }\n\n private async listNullStartLane(\n tenantId: string | null,\n customerId: string,\n limit: number,\n cursor: CampaignCustomerCursor | null,\n ): Promise<Campaign[]> {\n return this.list({\n where: {\n tenantId,\n customerId,\n startAt: null,\n ...(cursor ? { 'id <': cursor.id } : {}),\n },\n orderBy: 'id DESC',\n limit,\n });\n }\n}\n\ninterface QueryDatabase {\n query(\n sql: string,\n ...params: unknown[]\n ): Promise<{ rows: Array<Record<string, unknown>> }>;\n}\n\ninterface GroupedMetricTotals {\n totals: CampaignMetricTotals;\n snapshotCount: number;\n usedCampaignRollups: boolean;\n}\n\nfunction groupChannelMix(\n rows: Array<Record<string, unknown>>,\n): Map<string, CampaignChannelMixEntry[]> {\n const grouped = new Map<string, CampaignChannelMixEntry[]>();\n for (const row of rows) {\n const campaignId = normalizeUuid(String(row.campaign_id), 'campaign id');\n const channelKind = String(row.channel_kind);\n if (!channelKind) throw new Error('Campaign channel kind is empty.');\n const entry = {\n channelKind,\n count: toSafeCount(row.channel_count, 'Campaign channel count'),\n };\n const entries = grouped.get(campaignId) ?? [];\n entries.push(entry);\n grouped.set(campaignId, entries);\n }\n return grouped;\n}\n\nfunction groupMetricTotals(\n rows: Array<Record<string, unknown>>,\n): Map<string, GroupedMetricTotals> {\n return new Map(\n rows.map((row) => {\n const campaignId = normalizeUuid(String(row.campaign_id), 'campaign id');\n return [\n campaignId,\n {\n totals: {\n spendCents: toSafeCount(row.spend_cents, 'Campaign spend total'),\n impressions: toSafeCount(\n row.impressions,\n 'Campaign impression total',\n ),\n clicks: toSafeCount(row.clicks, 'Campaign click total'),\n conversions: toSafeCount(\n row.conversions,\n 'Campaign conversion total',\n ),\n leads: toSafeCount(row.leads, 'Campaign lead total'),\n revenueCents: toSafeCount(\n row.revenue_cents,\n 'Campaign revenue total',\n ),\n },\n snapshotCount: toSafeCount(\n row.snapshot_count,\n 'Campaign snapshot count',\n ),\n usedCampaignRollups: toBooleanFlag(row.used_campaign_rollups),\n },\n ];\n }),\n );\n}\n\nfunction emptyMetricTotals(): GroupedMetricTotals {\n return {\n totals: {\n spendCents: 0,\n impressions: 0,\n clicks: 0,\n conversions: 0,\n leads: 0,\n revenueCents: 0,\n },\n snapshotCount: 0,\n usedCampaignRollups: false,\n };\n}\n\nfunction toBooleanFlag(value: unknown): boolean {\n return value === true || value === 1 || value === '1';\n}\n\nfunction checkedAdd(left: number, right: number, label: string): number {\n const sum = left + right;\n if (!Number.isSafeInteger(sum) || sum < 0) {\n throw new Error(`${label} is outside the safe integer range.`);\n }\n return sum;\n}\n\nfunction requireDatabase(options: { db?: unknown }): QueryDatabase {\n const db = options.db;\n if (!db || typeof db !== 'object' || !('query' in db)) {\n throw new Error(\n 'Campaign reporting and summaries require an initialized database connection.',\n );\n }\n return db as QueryDatabase;\n}\n\nfunction coerceDate(value: unknown): Date | null {\n if (value == null) return null;\n const date =\n value instanceof Date\n ? value\n : new Date(typeof value === 'number' ? value : String(value));\n return Number.isNaN(date.getTime()) ? null : date;\n}\n\nfunction toSafeCount(value: unknown, label: string): number {\n const count = Number(value);\n if (!Number.isSafeInteger(count) || count < 0) {\n throw new Error(`${label} is outside the safe integer range.`);\n }\n return count;\n}\n\nfunction normalizeCursor(\n cursor: CampaignCustomerCursorInput | undefined,\n): CampaignCustomerCursor | null {\n if (!cursor) return null;\n const id = normalizeUuid(cursor.id, 'campaign customer cursor id');\n if (cursor.startAt === null) return { id, startAt: null };\n const startAt = coerceDate(cursor.startAt);\n if (!startAt) throw new Error('campaign customer cursor startAt is invalid.');\n return { id, startAt };\n}\n\nfunction normalizeReportingAt(value: Date | string | number | undefined): Date {\n if (value === undefined) return new Date();\n const at = coerceDate(value);\n if (!at) throw new Error('campaign reporting at is invalid.');\n return at;\n}\n\nfunction cursorFromCampaign(\n campaign: Campaign | undefined,\n): CampaignCustomerCursor | null {\n if (!campaign?.id) return null;\n return { id: campaign.id, startAt: campaign.startAt };\n}\n\nfunction normalizeTenantScope(\n tenantId: string | null,\n label: string,\n): string | null {\n if (tenantId !== null) {\n const normalized = normalizeUuid(tenantId, 'tenantId');\n const tenantContext = getCurrentTenant();\n if (tenantContext && !isSuperAdminBypass()) {\n const contextTenantId = normalizeUuid(tenantContext.tenantId, 'tenantId');\n if (normalized !== contextTenantId) {\n throw new TenantIsolationError(\n `Tenant isolation violation in ${label}.`,\n { tenantId: contextTenantId, attemptedTenantId: normalized },\n );\n }\n }\n return normalized;\n }\n const tenantContext = getCurrentTenant();\n if (tenantContext && !isSuperAdminBypass() && !isSystemContext()) {\n throw new TenantIsolationError(\n `Tenant isolation violation in ${label}: tenant context cannot read global Campaign rows.`,\n { tenantId: tenantContext.tenantId, attemptedTenantId: 'global' },\n );\n }\n return null;\n}\n\nfunction withCanonicalTenantContext<T>(\n tenantId: string | null,\n operation: () => Promise<T>,\n): Promise<T> {\n const tenantContext = getCurrentTenant();\n return tenantId !== null &&\n tenantContext &&\n !isSuperAdminBypass() &&\n !isSystemContext()\n ? withTenant({ ...tenantContext, tenantId }, operation)\n : operation();\n}\n\nfunction withCanonicalActiveTenant<T>(operation: () => Promise<T>): Promise<T> {\n const tenantContext = getCurrentTenant();\n if (!tenantContext || isSuperAdminBypass() || isSystemContext()) {\n return operation();\n }\n const normalizedTenantId = normalizeUuid(tenantContext.tenantId, 'tenantId');\n return normalizedTenantId === tenantContext.tenantId\n ? operation()\n : withTenant({ ...tenantContext, tenantId: normalizedTenantId }, operation);\n}\n\nfunction normalizeCampaignGetFilter(\n filter: string | SmrtWhereClause<Campaign>,\n): string | SmrtWhereClause<Campaign> {\n if (typeof filter !== 'string') return normalizeCampaignUuidWhere(filter);\n try {\n return normalizeUuid(filter, 'campaign id');\n } catch {\n return filter;\n }\n}\n\nfunction normalizeCampaignListOptions(\n options: SmrtListOptions<Campaign>,\n): SmrtListOptions<Campaign> {\n return options.where === undefined\n ? options\n : { ...options, where: normalizeCampaignUuidWhere(options.where) };\n}\n\nfunction normalizeCampaignUuidWhere<T>(where: T): T {\n if (Array.isArray(where)) {\n return where.map((entry) => normalizeCampaignUuidWhere(entry)) as T;\n }\n if (!where || typeof where !== 'object') return where;\n\n const normalized: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(where)) {\n const field = key.trim().split(/\\s+/u)[0];\n const label =\n field === 'id'\n ? 'campaign id'\n : field === 'customerId'\n ? 'customerId'\n : field === 'tenantId'\n ? 'tenantId'\n : null;\n if (!label) {\n normalized[key] = value;\n } else if (Array.isArray(value)) {\n normalized[key] = value.map((uuid) =>\n typeof uuid === 'string' ? normalizeUuid(uuid, label) : uuid,\n );\n } else {\n normalized[key] =\n typeof value === 'string' ? normalizeUuid(value, label) : value;\n }\n }\n return normalized as T;\n}\n\nexport default CampaignCollection;\n","import type { SmrtClassOptions } from '@happyvertical/smrt-core';\nimport {\n CampaignChannelCollection,\n CampaignCollection,\n CampaignMetricSnapshotCollection,\n} from '../collections/index.js';\nimport type { CampaignMetricSnapshot } from '../models/CampaignMetricSnapshot.js';\nimport type { BudgetPacingResult } from '../types.js';\nimport {\n calculateCampaignPacing,\n calculatePacing,\n} from './pacing-calculation.js';\n\n/** Computes spend-to-budget pacing from immutable snapshots; stores nothing. */\nexport class BudgetPacingService {\n constructor(\n private readonly campaigns: CampaignCollection,\n private readonly channels: CampaignChannelCollection,\n private readonly snapshots: CampaignMetricSnapshotCollection,\n ) {}\n\n static async create(\n classOptions: SmrtClassOptions = {},\n ): Promise<BudgetPacingService> {\n return new BudgetPacingService(\n await CampaignCollection.create(classOptions),\n await CampaignChannelCollection.create(classOptions),\n await CampaignMetricSnapshotCollection.create(classOptions),\n );\n }\n\n async getCampaignPacing(\n campaignId: string,\n at = new Date(),\n ): Promise<BudgetPacingResult> {\n const campaign = await this.campaigns.get({ id: campaignId });\n if (!campaign) throw new Error(`Campaign '${campaignId}' was not found.`);\n\n const all = await this.snapshots.findByCampaign(campaignId);\n const rollups = all.filter((snapshot) => !snapshot.campaignChannelId);\n const used = this.selectCampaignEvidence(all);\n return calculateCampaignPacing(\n campaign,\n {\n spendCents: used.reduce(\n (sum, snapshot) => sum + snapshot.spendCents,\n 0,\n ),\n snapshotCount: used.length,\n usedCampaignRollups: rollups.length > 0,\n },\n at,\n );\n }\n\n async getChannelPacing(\n campaignChannelId: string,\n at = new Date(),\n ): Promise<BudgetPacingResult> {\n const channel = await this.channels.get({ id: campaignChannelId });\n if (!channel) {\n throw new Error(`CampaignChannel '${campaignChannelId}' was not found.`);\n }\n const campaign = await this.campaigns.get({ id: channel.campaignId });\n if (!campaign) {\n throw new Error(`Campaign '${channel.campaignId}' was not found.`);\n }\n const snapshots = await this.snapshots.findByChannel(campaignChannelId);\n return {\n ...calculatePacing({\n campaign,\n evidence: {\n spendCents: snapshots.reduce(\n (sum, snapshot) => sum + snapshot.spendCents,\n 0,\n ),\n snapshotCount: snapshots.length,\n usedCampaignRollups: false,\n },\n budgetCents: channel.allocatedBudgetCents,\n startAt: channel.startAt ?? campaign.startAt,\n endAt: channel.endAt ?? campaign.endAt,\n at,\n }),\n campaignChannelId,\n };\n }\n\n /**\n * Prefer a campaign rollup for each exact reporting period, while retaining\n * channel evidence for periods that do not yet have a rollup. This prevents\n * double counting without dropping earlier/later channel-only periods.\n */\n private selectCampaignEvidence(\n snapshots: CampaignMetricSnapshot[],\n ): CampaignMetricSnapshot[] {\n const rollupPeriods = new Set(\n snapshots\n .filter((snapshot) => !snapshot.campaignChannelId)\n .map((snapshot) => this.periodKey(snapshot)),\n );\n return snapshots.filter(\n (snapshot) =>\n !snapshot.campaignChannelId ||\n !rollupPeriods.has(this.periodKey(snapshot)),\n );\n }\n\n private periodKey(snapshot: CampaignMetricSnapshot): string {\n return `${snapshot.periodStart.toISOString()}:${snapshot.periodEnd.toISOString()}`;\n }\n}\n\nexport default BudgetPacingService;\n","import type { SmrtClassOptions } from '@happyvertical/smrt-core';\nimport { CampaignCollection } from '../collections/CampaignCollection.js';\nimport type { Campaign } from '../models/Campaign.js';\nimport type { CampaignStatus } from '../types.js';\n\n/** Single authoritative write path for Campaign lifecycle changes. */\nexport class CampaignLifecycleService {\n constructor(private readonly campaigns: CampaignCollection) {}\n\n static async create(\n classOptions: SmrtClassOptions = {},\n ): Promise<CampaignLifecycleService> {\n return new CampaignLifecycleService(\n await CampaignCollection.create(classOptions),\n );\n }\n\n async transition(\n campaignId: string,\n next: CampaignStatus,\n ): Promise<Campaign> {\n const campaign = await this.campaigns.get({ id: campaignId });\n if (!campaign) throw new Error(`Campaign '${campaignId}' was not found.`);\n campaign.transitionTo(next);\n await campaign.save();\n return campaign;\n }\n\n async schedule(campaignId: string): Promise<Campaign> {\n return await this.transition(campaignId, 'scheduled');\n }\n\n async activate(campaignId: string): Promise<Campaign> {\n return await this.transition(campaignId, 'active');\n }\n\n async pause(campaignId: string): Promise<Campaign> {\n return await this.transition(campaignId, 'paused');\n }\n\n async resume(campaignId: string): Promise<Campaign> {\n return await this.transition(campaignId, 'active');\n }\n\n async complete(campaignId: string): Promise<Campaign> {\n return await this.transition(campaignId, 'completed');\n }\n\n async archive(campaignId: string): Promise<Campaign> {\n return await this.transition(campaignId, 'archived');\n }\n}\n\nexport default CampaignLifecycleService;\n","import type { SmrtClassOptions } from '@happyvertical/smrt-core';\nimport { CampaignMetricSnapshotCollection } from '../collections/CampaignMetricSnapshotCollection.js';\nimport type { CampaignMetricSnapshot } from '../models/CampaignMetricSnapshot.js';\nimport type { CampaignMetricSnapshotOptions } from '../types.js';\n\n/** Idempotent, validation-first ingestion for immutable metric evidence. */\nexport class MetricIngestionService {\n constructor(private readonly snapshots: CampaignMetricSnapshotCollection) {}\n\n static async create(\n classOptions: SmrtClassOptions = {},\n ): Promise<MetricIngestionService> {\n return new MetricIngestionService(\n await CampaignMetricSnapshotCollection.create(classOptions),\n );\n }\n\n async ingest(\n options: CampaignMetricSnapshotOptions,\n ): Promise<{ snapshot: CampaignMetricSnapshot; created: boolean }> {\n if (!options.campaignId) {\n throw new Error('Metric ingestion requires campaignId.');\n }\n if (!options.source?.trim()) {\n throw new Error('Metric ingestion requires source.');\n }\n if (!options.dedupeKey?.trim()) {\n throw new Error('Metric ingestion requires dedupeKey.');\n }\n if (options.periodStart == null || options.periodEnd == null) {\n throw new Error('Metric ingestion requires periodStart and periodEnd.');\n }\n return await this.snapshots.getOrCreateByDedupeKey(options);\n }\n}\n\nexport default MetricIngestionService;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["elapsedFraction","tenantContext"],"sources":["../src/__smrt-register__.ts","../src/errors.ts","../src/customer-scope.ts","../src/models/Campaign.ts","../src/models/CampaignChannel.ts","../src/collections/CampaignChannelCollection.ts","../src/services/pacing-calculation.ts","../src/models/CampaignMetricSnapshot.ts","../src/collections/CampaignMetricSnapshotCollection.ts","../src/collections/CampaignCollection.ts","../src/services/BudgetPacingService.ts","../src/services/CampaignLifecycleService.ts","../src/services/MetricIngestionService.ts"],"sourcesContent":["// Generated by @happyvertical/smrt-core smrtPlugin at library build time.\n// The package manifest is inlined so self-registration cannot miss when a\n// downstream bundler relocates this module away from dist/manifest.json\n// (https://github.com/happyvertical/smrt/issues/1506,\n// https://github.com/happyvertical/smrt/issues/1507).\nimport { ObjectRegistry } from '@happyvertical/smrt-core';\n\nObjectRegistry.registerPackageManifest(JSON.parse(\"{\\\"version\\\":\\\"1.0.0\\\",\\\"timestamp\\\":0,\\\"packageName\\\":\\\"@happyvertical/smrt-marketing\\\",\\\"packageVersion\\\":\\\"0.57.5\\\",\\\"objects\\\":{\\\"@happyvertical/smrt-marketing:CampaignChannelCollection\\\":{\\\"name\\\":\\\"campaignchannelcollection\\\",\\\"className\\\":\\\"CampaignChannelCollection\\\",\\\"qualifiedName\\\":\\\"@happyvertical/smrt-marketing:CampaignChannelCollection\\\",\\\"collection\\\":\\\"campaignchannels\\\",\\\"filePath\\\":\\\"/home/runner/work/smrt/smrt/packages/marketing/src/collections/CampaignChannelCollection.ts\\\",\\\"packageName\\\":\\\"@happyvertical/smrt-marketing\\\",\\\"fields\\\":{},\\\"methods\\\":{\\\"findByCampaign\\\":{\\\"name\\\":\\\"findByCampaign\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"campaignId\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<CampaignChannel[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"findByExecutionRef\\\":{\\\"name\\\":\\\"findByExecutionRef\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"channelKind\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false},{\\\"name\\\":\\\"channelRef\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<CampaignChannel[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true}},\\\"decoratorConfig\\\":{\\\"tableName\\\":\\\"campaign_channels\\\",\\\"api\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\",\\\"create\\\",\\\"update\\\",\\\"delete\\\"]},\\\"mcp\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\",\\\"create\\\",\\\"update\\\"]},\\\"cli\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\",\\\"create\\\",\\\"update\\\",\\\"delete\\\"]}},\\\"extends\\\":\\\"SmrtCollection\\\",\\\"extendsTypeArg\\\":\\\"CampaignChannel\\\",\\\"exportName\\\":\\\"CampaignChannelCollection\\\",\\\"collectionExportName\\\":\\\"CampaignChannelCollectionCollection\\\",\\\"schema\\\":{\\\"tableName\\\":\\\"campaign_channels\\\",\\\"ddl\\\":\\\"CREATE TABLE IF NOT EXISTS \\\\\\\"campaign_channels\\\\\\\" (\\\\n \\\\\\\"id\\\\\\\" UUID PRIMARY KEY NOT NULL,\\\\n \\\\\\\"slug\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"context\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"created_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"updated_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"tenant_id\\\\\\\" UUID,\\\\n \\\\\\\"campaign_id\\\\\\\" UUID NOT NULL,\\\\n \\\\\\\"channel_kind\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"channel_ref\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"allocated_budget_cents\\\\\\\" INTEGER DEFAULT 0,\\\\n \\\\\\\"start_at\\\\\\\" TIMESTAMP,\\\\n \\\\\\\"end_at\\\\\\\" TIMESTAMP,\\\\n \\\\\\\"status\\\\\\\" TEXT DEFAULT 'planned'\\\\n);\\\",\\\"columns\\\":{\\\"id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"primaryKey\\\":true,\\\"referenceKind\\\":\\\"id\\\",\\\"notNull\\\":true},\\\"slug\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true},\\\"context\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"\\\"},\\\"created_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"updated_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"tenant_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"tenantId\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"campaign_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"foreignKey\\\",\\\"notNull\\\":true,\\\"unique\\\":false,\\\"foreignKey\\\":{\\\"table\\\":\\\"campaigns\\\",\\\"column\\\":\\\"id\\\",\\\"onDelete\\\":\\\"CASCADE\\\",\\\"onUpdate\\\":\\\"CASCADE\\\"}},\\\"channel_kind\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"channel_ref\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"allocated_budget_cents\\\":{\\\"type\\\":\\\"INTEGER\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":0},\\\"start_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"end_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"status\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"planned\\\"}},\\\"indexes\\\":[{\\\"name\\\":\\\"campaign_channels_campaign_id_channel_kind_idx\\\",\\\"columns\\\":[\\\"campaign_id\\\",\\\"channel_kind\\\",\\\"channel_ref\\\"],\\\"unique\\\":true},{\\\"name\\\":\\\"campaign_channels_slug_context_idx\\\",\\\"columns\\\":[\\\"slug\\\",\\\"context\\\"]},{\\\"name\\\":\\\"campaign_channels_tenant_id_created_at_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"created_at\\\"]}],\\\"version\\\":\\\"cc045525\\\"},\\\"importPath\\\":\\\"@happyvertical/smrt-marketing\\\"},\\\"@happyvertical/smrt-marketing:CampaignCollection\\\":{\\\"name\\\":\\\"campaigncollection\\\",\\\"className\\\":\\\"CampaignCollection\\\",\\\"qualifiedName\\\":\\\"@happyvertical/smrt-marketing:CampaignCollection\\\",\\\"collection\\\":\\\"campaigns\\\",\\\"filePath\\\":\\\"/home/runner/work/smrt/smrt/packages/marketing/src/collections/CampaignCollection.ts\\\",\\\"packageName\\\":\\\"@happyvertical/smrt-marketing\\\",\\\"fields\\\":{},\\\"methods\\\":{\\\"get\\\":{\\\"name\\\":\\\"get\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"filter\\\",\\\"type\\\":\\\"string | SmrtWhereClause<Campaign>\\\",\\\"optional\\\":false,\\\"unionBranches\\\":[{\\\"type\\\":\\\"string\\\"},{\\\"type\\\":\\\"SmrtWhereClause<Campaign>\\\"}]},{\\\"name\\\":\\\"options\\\",\\\"type\\\":\\\"object\\\",\\\"optional\\\":true,\\\"memberTypes\\\":[\\\"CollectionCacheConfig | false\\\"]}],\\\"returnType\\\":\\\"Promise<Campaign | null>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"list\\\":{\\\"name\\\":\\\"list\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"options\\\",\\\"type\\\":\\\"SmrtListOptions<Campaign>\\\",\\\"optional\\\":true}],\\\"returnType\\\":\\\"Promise<Campaign[] | Record<string, unknown>[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"findByCampaignKey\\\":{\\\"name\\\":\\\"findByCampaignKey\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"campaignKey\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false},{\\\"name\\\":\\\"tenantId\\\",\\\"type\\\":\\\"string | null\\\",\\\"optional\\\":true,\\\"unionBranches\\\":[{\\\"type\\\":\\\"string\\\"},{\\\"type\\\":\\\"null\\\"}]}],\\\"returnType\\\":\\\"Promise<Campaign | null>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"findByStatus\\\":{\\\"name\\\":\\\"findByStatus\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"status\\\",\\\"type\\\":\\\"CampaignStatus\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<Campaign[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"listByCustomer\\\":{\\\"name\\\":\\\"listByCustomer\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"tenantId\\\",\\\"type\\\":\\\"string | null\\\",\\\"optional\\\":false,\\\"unionBranches\\\":[{\\\"type\\\":\\\"string\\\"},{\\\"type\\\":\\\"null\\\"}]},{\\\"name\\\":\\\"customerId\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false},{\\\"name\\\":\\\"options\\\",\\\"type\\\":\\\"ListCampaignsByCustomerOptions\\\",\\\"optional\\\":true}],\\\"returnType\\\":\\\"Promise<CampaignCustomerPage>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"listReportingByCustomer\\\":{\\\"name\\\":\\\"listReportingByCustomer\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"tenantId\\\",\\\"type\\\":\\\"string | null\\\",\\\"optional\\\":false,\\\"unionBranches\\\":[{\\\"type\\\":\\\"string\\\"},{\\\"type\\\":\\\"null\\\"}]},{\\\"name\\\":\\\"customerId\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false},{\\\"name\\\":\\\"options\\\",\\\"type\\\":\\\"ListCampaignReportingByCustomerOptions\\\",\\\"optional\\\":true}],\\\"returnType\\\":\\\"Promise<CampaignReportingPage>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"summarizeByCustomers\\\":{\\\"name\\\":\\\"summarizeByCustomers\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"tenantId\\\",\\\"type\\\":\\\"string | null\\\",\\\"optional\\\":false,\\\"unionBranches\\\":[{\\\"type\\\":\\\"string\\\"},{\\\"type\\\":\\\"null\\\"}]},{\\\"name\\\":\\\"customerIds\\\",\\\"type\\\":\\\"string[]\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<CampaignCustomerSummary[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true}},\\\"decoratorConfig\\\":{\\\"tableName\\\":\\\"campaigns\\\",\\\"api\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\",\\\"create\\\",\\\"update\\\"]},\\\"mcp\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\",\\\"create\\\",\\\"update\\\"]},\\\"cli\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\",\\\"create\\\",\\\"update\\\"]}},\\\"extends\\\":\\\"SmrtCollection\\\",\\\"extendsTypeArg\\\":\\\"Campaign\\\",\\\"exportName\\\":\\\"CampaignCollection\\\",\\\"collectionExportName\\\":\\\"CampaignCollectionCollection\\\",\\\"schema\\\":{\\\"tableName\\\":\\\"campaigns\\\",\\\"ddl\\\":\\\"CREATE TABLE IF NOT EXISTS \\\\\\\"campaigns\\\\\\\" (\\\\n \\\\\\\"id\\\\\\\" UUID PRIMARY KEY NOT NULL,\\\\n \\\\\\\"slug\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"context\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"created_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"updated_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"tenant_id\\\\\\\" UUID,\\\\n \\\\\\\"customer_id\\\\\\\" UUID,\\\\n \\\\\\\"campaign_key\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"name\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"objective\\\\\\\" TEXT DEFAULT '',\\\\n \\\\\\\"status\\\\\\\" TEXT DEFAULT 'draft',\\\\n \\\\\\\"start_at\\\\\\\" TIMESTAMP,\\\\n \\\\\\\"end_at\\\\\\\" TIMESTAMP,\\\\n \\\\\\\"budget_cents\\\\\\\" INTEGER DEFAULT 0,\\\\n \\\\\\\"currency\\\\\\\" TEXT DEFAULT 'USD',\\\\n \\\\\\\"metadata\\\\\\\" TEXT DEFAULT '{}'\\\\n);\\\",\\\"columns\\\":{\\\"id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"primaryKey\\\":true,\\\"referenceKind\\\":\\\"id\\\",\\\"notNull\\\":true},\\\"slug\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true},\\\"context\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"\\\"},\\\"created_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"updated_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"tenant_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"tenantId\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"customer_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"crossPackageRef\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"campaign_key\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"name\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"objective\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"status\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"draft\\\"},\\\"start_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"end_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"budget_cents\\\":{\\\"type\\\":\\\"INTEGER\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":0},\\\"currency\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"USD\\\"},\\\"metadata\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"{}\\\"}},\\\"indexes\\\":[{\\\"name\\\":\\\"campaigns_tenant_id_campaign_key_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"campaign_key\\\"],\\\"unique\\\":true,\\\"nullsNotDistinct\\\":true},{\\\"name\\\":\\\"campaigns_slug_context_idx\\\",\\\"columns\\\":[\\\"slug\\\",\\\"context\\\"]},{\\\"name\\\":\\\"campaigns_tenant_id_customer_id_start_at_id_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"customer_id\\\",\\\"start_at\\\",\\\"id\\\"]},{\\\"name\\\":\\\"campaigns_tenant_id_created_at_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"created_at\\\"]},{\\\"name\\\":\\\"campaigns_customer_id_idx\\\",\\\"columns\\\":[\\\"customer_id\\\"]}],\\\"version\\\":\\\"d0945102\\\"},\\\"importPath\\\":\\\"@happyvertical/smrt-marketing\\\"},\\\"@happyvertical/smrt-marketing:CampaignMetricSnapshotCollection\\\":{\\\"name\\\":\\\"campaignmetricsnapshotcollection\\\",\\\"className\\\":\\\"CampaignMetricSnapshotCollection\\\",\\\"qualifiedName\\\":\\\"@happyvertical/smrt-marketing:CampaignMetricSnapshotCollection\\\",\\\"collection\\\":\\\"campaignmetricsnapshots\\\",\\\"filePath\\\":\\\"/home/runner/work/smrt/smrt/packages/marketing/src/collections/CampaignMetricSnapshotCollection.ts\\\",\\\"packageName\\\":\\\"@happyvertical/smrt-marketing\\\",\\\"fields\\\":{},\\\"methods\\\":{\\\"findByDedupeKey\\\":{\\\"name\\\":\\\"findByDedupeKey\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"dedupeKey\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<CampaignMetricSnapshot | null>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"getOrCreateByDedupeKey\\\":{\\\"name\\\":\\\"getOrCreateByDedupeKey\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"options\\\",\\\"type\\\":\\\"CampaignMetricSnapshotOptions\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<object>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"findByCampaign\\\":{\\\"name\\\":\\\"findByCampaign\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"campaignId\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<CampaignMetricSnapshot[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"findByChannel\\\":{\\\"name\\\":\\\"findByChannel\\\",\\\"async\\\":true,\\\"parameters\\\":[{\\\"name\\\":\\\"campaignChannelId\\\",\\\"type\\\":\\\"string\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"Promise<CampaignMetricSnapshot[]>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true}},\\\"decoratorConfig\\\":{\\\"tableName\\\":\\\"campaign_metric_snapshots\\\",\\\"api\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\",\\\"create\\\"]},\\\"mcp\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\",\\\"create\\\"]},\\\"cli\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\",\\\"create\\\"]}},\\\"extends\\\":\\\"SmrtCollection\\\",\\\"extendsTypeArg\\\":\\\"CampaignMetricSnapshot\\\",\\\"exportName\\\":\\\"CampaignMetricSnapshotCollection\\\",\\\"collectionExportName\\\":\\\"CampaignMetricSnapshotCollectionCollection\\\",\\\"schema\\\":{\\\"tableName\\\":\\\"campaign_metric_snapshots\\\",\\\"ddl\\\":\\\"CREATE TABLE IF NOT EXISTS \\\\\\\"campaign_metric_snapshots\\\\\\\" (\\\\n \\\\\\\"id\\\\\\\" UUID PRIMARY KEY NOT NULL,\\\\n \\\\\\\"slug\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"context\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"created_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"updated_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"tenant_id\\\\\\\" UUID,\\\\n \\\\\\\"campaign_id\\\\\\\" UUID NOT NULL,\\\\n \\\\\\\"campaign_channel_id\\\\\\\" UUID,\\\\n \\\\\\\"period_start\\\\\\\" TIMESTAMP NOT NULL,\\\\n \\\\\\\"period_end\\\\\\\" TIMESTAMP NOT NULL,\\\\n \\\\\\\"spend_cents\\\\\\\" INTEGER DEFAULT 0,\\\\n \\\\\\\"impressions\\\\\\\" INTEGER DEFAULT 0,\\\\n \\\\\\\"clicks\\\\\\\" INTEGER DEFAULT 0,\\\\n \\\\\\\"conversions\\\\\\\" INTEGER DEFAULT 0,\\\\n \\\\\\\"leads\\\\\\\" INTEGER DEFAULT 0,\\\\n \\\\\\\"revenue_cents\\\\\\\" INTEGER,\\\\n \\\\\\\"source\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"dedupe_key\\\\\\\" TEXT NOT NULL DEFAULT ''\\\\n);\\\",\\\"columns\\\":{\\\"id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"primaryKey\\\":true,\\\"referenceKind\\\":\\\"id\\\",\\\"notNull\\\":true},\\\"slug\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true},\\\"context\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"\\\"},\\\"created_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"updated_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"tenant_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"tenantId\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"campaign_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"foreignKey\\\",\\\"notNull\\\":true,\\\"unique\\\":false,\\\"foreignKey\\\":{\\\"table\\\":\\\"campaigns\\\",\\\"column\\\":\\\"id\\\",\\\"onDelete\\\":\\\"NO ACTION\\\",\\\"onUpdate\\\":\\\"CASCADE\\\"}},\\\"campaign_channel_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"foreignKey\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"foreignKey\\\":{\\\"table\\\":\\\"campaign_channels\\\",\\\"column\\\":\\\"id\\\",\\\"onDelete\\\":\\\"NO ACTION\\\",\\\"onUpdate\\\":\\\"CASCADE\\\"}},\\\"period_start\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"unique\\\":false},\\\"period_end\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"unique\\\":false},\\\"spend_cents\\\":{\\\"type\\\":\\\"INTEGER\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":0},\\\"impressions\\\":{\\\"type\\\":\\\"INTEGER\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":0},\\\"clicks\\\":{\\\"type\\\":\\\"INTEGER\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":0},\\\"conversions\\\":{\\\"type\\\":\\\"INTEGER\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":0},\\\"leads\\\":{\\\"type\\\":\\\"INTEGER\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":0},\\\"revenue_cents\\\":{\\\"type\\\":\\\"INTEGER\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"source\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"dedupe_key\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"}},\\\"indexes\\\":[{\\\"name\\\":\\\"campaign_metric_snapshots_dedupe_key_idx\\\",\\\"columns\\\":[\\\"dedupe_key\\\"],\\\"unique\\\":true},{\\\"name\\\":\\\"campaign_metric_snapshots_slug_context_idx\\\",\\\"columns\\\":[\\\"slug\\\",\\\"context\\\"]},{\\\"name\\\":\\\"campaign_metric_snapshots_tenant_id_created_at_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"created_at\\\"]},{\\\"name\\\":\\\"campaign_metric_snapshots_campaign_id_idx\\\",\\\"columns\\\":[\\\"campaign_id\\\"]},{\\\"name\\\":\\\"campaign_metric_snapshots_campaign_channel_id_idx\\\",\\\"columns\\\":[\\\"campaign_channel_id\\\"]}],\\\"version\\\":\\\"1ccd36b3\\\"},\\\"importPath\\\":\\\"@happyvertical/smrt-marketing\\\"},\\\"@happyvertical/smrt-marketing:Campaign\\\":{\\\"name\\\":\\\"campaign\\\",\\\"className\\\":\\\"Campaign\\\",\\\"qualifiedName\\\":\\\"@happyvertical/smrt-marketing:Campaign\\\",\\\"collection\\\":\\\"campaigns\\\",\\\"filePath\\\":\\\"/home/runner/work/smrt/smrt/packages/marketing/src/models/Campaign.ts\\\",\\\"packageName\\\":\\\"@happyvertical/smrt-marketing\\\",\\\"fields\\\":{\\\"tenantId\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"_meta\\\":{\\\"sqlType\\\":\\\"UUID\\\",\\\"nullable\\\":true,\\\"__tenancy\\\":{\\\"isTenantIdField\\\":true,\\\"autoFilter\\\":true,\\\"required\\\":false,\\\"autoPopulate\\\":true,\\\"nullable\\\":true,\\\"mode\\\":\\\"optional\\\",\\\"field\\\":\\\"tenantId\\\",\\\"allowSuperAdminBypass\\\":false}}},\\\"customerId\\\":{\\\"type\\\":\\\"crossPackageRef\\\",\\\"required\\\":false,\\\"related\\\":\\\"@happyvertical/smrt-commerce:Customer\\\",\\\"_meta\\\":{\\\"validate\\\":true,\\\"nullable\\\":true}},\\\"campaignKey\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":true,\\\"default\\\":\\\"\\\",\\\"_meta\\\":{\\\"required\\\":true}},\\\"name\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":true,\\\"default\\\":\\\"\\\",\\\"_meta\\\":{\\\"required\\\":true}},\\\"objective\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"default\\\":\\\"\\\"},\\\"status\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"default\\\":\\\"draft\\\"},\\\"startAt\\\":{\\\"type\\\":\\\"datetime\\\",\\\"required\\\":false},\\\"endAt\\\":{\\\"type\\\":\\\"datetime\\\",\\\"required\\\":false},\\\"budgetCents\\\":{\\\"type\\\":\\\"integer\\\",\\\"required\\\":false,\\\"default\\\":0},\\\"currency\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"default\\\":\\\"USD\\\"},\\\"metadata\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"default\\\":\\\"{}\\\"}},\\\"methods\\\":{\\\"initialize\\\":{\\\"name\\\":\\\"initialize\\\",\\\"async\\\":true,\\\"parameters\\\":[],\\\"returnType\\\":\\\"Promise<this>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"save\\\":{\\\"name\\\":\\\"save\\\",\\\"async\\\":true,\\\"parameters\\\":[],\\\"returnType\\\":\\\"Promise<this>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"transitionTo\\\":{\\\"name\\\":\\\"transitionTo\\\",\\\"async\\\":false,\\\"parameters\\\":[{\\\"name\\\":\\\"next\\\",\\\"type\\\":\\\"CampaignStatus\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"this\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"getMetadata\\\":{\\\"name\\\":\\\"getMetadata\\\",\\\"async\\\":false,\\\"parameters\\\":[],\\\"returnType\\\":\\\"Record<string, unknown>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"setMetadata\\\":{\\\"name\\\":\\\"setMetadata\\\",\\\"async\\\":false,\\\"parameters\\\":[{\\\"name\\\":\\\"metadata\\\",\\\"type\\\":\\\"Record<string, unknown>\\\",\\\"optional\\\":false}],\\\"returnType\\\":\\\"void\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true}},\\\"decoratorConfig\\\":{\\\"tableName\\\":\\\"campaigns\\\",\\\"conflictColumns\\\":[\\\"tenant_id\\\",\\\"campaign_key\\\"],\\\"indexes\\\":[{\\\"name\\\":\\\"campaigns_tenant_id_customer_id_start_at_id_idx\\\",\\\"columns\\\":[\\\"tenantId\\\",\\\"customerId\\\",\\\"startAt\\\",\\\"id\\\"]}],\\\"api\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\",\\\"create\\\",\\\"update\\\"]},\\\"mcp\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\",\\\"create\\\",\\\"update\\\"]},\\\"cli\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\",\\\"create\\\",\\\"update\\\"]},\\\"tenantScoped\\\":{\\\"mode\\\":\\\"optional\\\"}},\\\"extends\\\":\\\"SmrtObject\\\",\\\"exportName\\\":\\\"Campaign\\\",\\\"collectionExportName\\\":\\\"CampaignCollection\\\",\\\"displayLabelField\\\":\\\"name\\\",\\\"validationRules\\\":[{\\\"field\\\":\\\"campaignKey\\\",\\\"rule\\\":\\\"required\\\",\\\"fieldType\\\":\\\"text\\\"},{\\\"field\\\":\\\"name\\\",\\\"rule\\\":\\\"required\\\",\\\"fieldType\\\":\\\"text\\\"}],\\\"schema\\\":{\\\"tableName\\\":\\\"campaigns\\\",\\\"ddl\\\":\\\"CREATE TABLE IF NOT EXISTS \\\\\\\"campaigns\\\\\\\" (\\\\n \\\\\\\"id\\\\\\\" UUID PRIMARY KEY NOT NULL,\\\\n \\\\\\\"slug\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"context\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"created_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"updated_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"tenant_id\\\\\\\" UUID,\\\\n \\\\\\\"customer_id\\\\\\\" UUID,\\\\n \\\\\\\"campaign_key\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"name\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"objective\\\\\\\" TEXT DEFAULT '',\\\\n \\\\\\\"status\\\\\\\" TEXT DEFAULT 'draft',\\\\n \\\\\\\"start_at\\\\\\\" TIMESTAMP,\\\\n \\\\\\\"end_at\\\\\\\" TIMESTAMP,\\\\n \\\\\\\"budget_cents\\\\\\\" INTEGER DEFAULT 0,\\\\n \\\\\\\"currency\\\\\\\" TEXT DEFAULT 'USD',\\\\n \\\\\\\"metadata\\\\\\\" TEXT DEFAULT '{}'\\\\n);\\\",\\\"columns\\\":{\\\"id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"primaryKey\\\":true,\\\"referenceKind\\\":\\\"id\\\",\\\"notNull\\\":true},\\\"slug\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true},\\\"context\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"\\\"},\\\"created_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"updated_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"tenant_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"tenantId\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"customer_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"crossPackageRef\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"campaign_key\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"name\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"objective\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"status\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"draft\\\"},\\\"start_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"end_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"budget_cents\\\":{\\\"type\\\":\\\"INTEGER\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":0},\\\"currency\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"USD\\\"},\\\"metadata\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"{}\\\"}},\\\"indexes\\\":[{\\\"name\\\":\\\"campaigns_tenant_id_campaign_key_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"campaign_key\\\"],\\\"unique\\\":true,\\\"nullsNotDistinct\\\":true},{\\\"name\\\":\\\"campaigns_slug_context_idx\\\",\\\"columns\\\":[\\\"slug\\\",\\\"context\\\"]},{\\\"name\\\":\\\"campaigns_tenant_id_customer_id_start_at_id_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"customer_id\\\",\\\"start_at\\\",\\\"id\\\"]},{\\\"name\\\":\\\"campaigns_tenant_id_created_at_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"created_at\\\"]},{\\\"name\\\":\\\"campaigns_customer_id_idx\\\",\\\"columns\\\":[\\\"customer_id\\\"]}],\\\"version\\\":\\\"d0945102\\\"},\\\"importPath\\\":\\\"@happyvertical/smrt-marketing\\\"},\\\"@happyvertical/smrt-marketing:CampaignChannel\\\":{\\\"name\\\":\\\"campaignchannel\\\",\\\"className\\\":\\\"CampaignChannel\\\",\\\"qualifiedName\\\":\\\"@happyvertical/smrt-marketing:CampaignChannel\\\",\\\"collection\\\":\\\"campaignchannels\\\",\\\"filePath\\\":\\\"/home/runner/work/smrt/smrt/packages/marketing/src/models/CampaignChannel.ts\\\",\\\"packageName\\\":\\\"@happyvertical/smrt-marketing\\\",\\\"fields\\\":{\\\"tenantId\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"_meta\\\":{\\\"sqlType\\\":\\\"UUID\\\",\\\"nullable\\\":true,\\\"__tenancy\\\":{\\\"isTenantIdField\\\":true,\\\"autoFilter\\\":true,\\\"required\\\":false,\\\"autoPopulate\\\":true,\\\"nullable\\\":true,\\\"mode\\\":\\\"optional\\\",\\\"field\\\":\\\"tenantId\\\",\\\"allowSuperAdminBypass\\\":false}}},\\\"campaignId\\\":{\\\"type\\\":\\\"foreignKey\\\",\\\"required\\\":true,\\\"related\\\":\\\"Campaign\\\",\\\"_meta\\\":{\\\"required\\\":true}},\\\"channelKind\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":true,\\\"default\\\":\\\"\\\",\\\"_meta\\\":{\\\"required\\\":true}},\\\"channelRef\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":true,\\\"default\\\":\\\"\\\",\\\"_meta\\\":{\\\"required\\\":true}},\\\"allocatedBudgetCents\\\":{\\\"type\\\":\\\"integer\\\",\\\"required\\\":false,\\\"default\\\":0},\\\"startAt\\\":{\\\"type\\\":\\\"datetime\\\",\\\"required\\\":false},\\\"endAt\\\":{\\\"type\\\":\\\"datetime\\\",\\\"required\\\":false},\\\"status\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"default\\\":\\\"planned\\\"}},\\\"methods\\\":{\\\"initialize\\\":{\\\"name\\\":\\\"initialize\\\",\\\"async\\\":true,\\\"parameters\\\":[],\\\"returnType\\\":\\\"Promise<this>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"save\\\":{\\\"name\\\":\\\"save\\\",\\\"async\\\":true,\\\"parameters\\\":[],\\\"returnType\\\":\\\"Promise<this>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true}},\\\"decoratorConfig\\\":{\\\"tableName\\\":\\\"campaign_channels\\\",\\\"conflictColumns\\\":[\\\"campaign_id\\\",\\\"channel_kind\\\",\\\"channel_ref\\\"],\\\"api\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\",\\\"create\\\",\\\"update\\\",\\\"delete\\\"]},\\\"mcp\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\",\\\"create\\\",\\\"update\\\"]},\\\"cli\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\",\\\"create\\\",\\\"update\\\",\\\"delete\\\"]},\\\"tenantScoped\\\":{\\\"mode\\\":\\\"optional\\\"}},\\\"extends\\\":\\\"SmrtObject\\\",\\\"exportName\\\":\\\"CampaignChannel\\\",\\\"collectionExportName\\\":\\\"CampaignChannelCollection\\\",\\\"validationRules\\\":[{\\\"field\\\":\\\"campaignId\\\",\\\"rule\\\":\\\"required\\\",\\\"fieldType\\\":\\\"foreignKey\\\"},{\\\"field\\\":\\\"channelKind\\\",\\\"rule\\\":\\\"required\\\",\\\"fieldType\\\":\\\"text\\\"},{\\\"field\\\":\\\"channelRef\\\",\\\"rule\\\":\\\"required\\\",\\\"fieldType\\\":\\\"text\\\"}],\\\"schema\\\":{\\\"tableName\\\":\\\"campaign_channels\\\",\\\"ddl\\\":\\\"CREATE TABLE IF NOT EXISTS \\\\\\\"campaign_channels\\\\\\\" (\\\\n \\\\\\\"id\\\\\\\" UUID PRIMARY KEY NOT NULL,\\\\n \\\\\\\"slug\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"context\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"created_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"updated_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"tenant_id\\\\\\\" UUID,\\\\n \\\\\\\"campaign_id\\\\\\\" UUID NOT NULL,\\\\n \\\\\\\"channel_kind\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"channel_ref\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"allocated_budget_cents\\\\\\\" INTEGER DEFAULT 0,\\\\n \\\\\\\"start_at\\\\\\\" TIMESTAMP,\\\\n \\\\\\\"end_at\\\\\\\" TIMESTAMP,\\\\n \\\\\\\"status\\\\\\\" TEXT DEFAULT 'planned'\\\\n);\\\",\\\"columns\\\":{\\\"id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"primaryKey\\\":true,\\\"referenceKind\\\":\\\"id\\\",\\\"notNull\\\":true},\\\"slug\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true},\\\"context\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"\\\"},\\\"created_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"updated_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"tenant_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"tenantId\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"campaign_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"foreignKey\\\",\\\"notNull\\\":true,\\\"unique\\\":false,\\\"foreignKey\\\":{\\\"table\\\":\\\"campaigns\\\",\\\"column\\\":\\\"id\\\",\\\"onDelete\\\":\\\"CASCADE\\\",\\\"onUpdate\\\":\\\"CASCADE\\\"}},\\\"channel_kind\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"channel_ref\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"allocated_budget_cents\\\":{\\\"type\\\":\\\"INTEGER\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":0},\\\"start_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"end_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"status\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":\\\"planned\\\"}},\\\"indexes\\\":[{\\\"name\\\":\\\"campaign_channels_campaign_id_channel_kind_idx\\\",\\\"columns\\\":[\\\"campaign_id\\\",\\\"channel_kind\\\",\\\"channel_ref\\\"],\\\"unique\\\":true},{\\\"name\\\":\\\"campaign_channels_slug_context_idx\\\",\\\"columns\\\":[\\\"slug\\\",\\\"context\\\"]},{\\\"name\\\":\\\"campaign_channels_tenant_id_created_at_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"created_at\\\"]}],\\\"version\\\":\\\"cc045525\\\"},\\\"importPath\\\":\\\"@happyvertical/smrt-marketing\\\"},\\\"@happyvertical/smrt-marketing:CampaignMetricSnapshot\\\":{\\\"name\\\":\\\"campaignmetricsnapshot\\\",\\\"className\\\":\\\"CampaignMetricSnapshot\\\",\\\"qualifiedName\\\":\\\"@happyvertical/smrt-marketing:CampaignMetricSnapshot\\\",\\\"collection\\\":\\\"campaignmetricsnapshots\\\",\\\"filePath\\\":\\\"/home/runner/work/smrt/smrt/packages/marketing/src/models/CampaignMetricSnapshot.ts\\\",\\\"packageName\\\":\\\"@happyvertical/smrt-marketing\\\",\\\"fields\\\":{\\\"tenantId\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":false,\\\"_meta\\\":{\\\"sqlType\\\":\\\"UUID\\\",\\\"nullable\\\":true,\\\"__tenancy\\\":{\\\"isTenantIdField\\\":true,\\\"autoFilter\\\":true,\\\"required\\\":false,\\\"autoPopulate\\\":true,\\\"nullable\\\":true,\\\"mode\\\":\\\"optional\\\",\\\"field\\\":\\\"tenantId\\\",\\\"allowSuperAdminBypass\\\":false}}},\\\"campaignId\\\":{\\\"type\\\":\\\"foreignKey\\\",\\\"required\\\":true,\\\"related\\\":\\\"Campaign\\\",\\\"_meta\\\":{\\\"required\\\":true}},\\\"campaignChannelId\\\":{\\\"type\\\":\\\"foreignKey\\\",\\\"required\\\":false,\\\"related\\\":\\\"CampaignChannel\\\",\\\"_meta\\\":{\\\"nullable\\\":true}},\\\"periodStart\\\":{\\\"type\\\":\\\"datetime\\\",\\\"required\\\":true,\\\"_meta\\\":{\\\"required\\\":true}},\\\"periodEnd\\\":{\\\"type\\\":\\\"datetime\\\",\\\"required\\\":true,\\\"_meta\\\":{\\\"required\\\":true}},\\\"spendCents\\\":{\\\"type\\\":\\\"integer\\\",\\\"required\\\":false,\\\"default\\\":0},\\\"impressions\\\":{\\\"type\\\":\\\"integer\\\",\\\"required\\\":false,\\\"default\\\":0},\\\"clicks\\\":{\\\"type\\\":\\\"integer\\\",\\\"required\\\":false,\\\"default\\\":0},\\\"conversions\\\":{\\\"type\\\":\\\"integer\\\",\\\"required\\\":false,\\\"default\\\":0},\\\"leads\\\":{\\\"type\\\":\\\"integer\\\",\\\"required\\\":false,\\\"default\\\":0},\\\"revenueCents\\\":{\\\"type\\\":\\\"integer\\\",\\\"required\\\":false,\\\"_meta\\\":{\\\"nullable\\\":true}},\\\"source\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":true,\\\"default\\\":\\\"\\\",\\\"_meta\\\":{\\\"required\\\":true}},\\\"dedupeKey\\\":{\\\"type\\\":\\\"text\\\",\\\"required\\\":true,\\\"default\\\":\\\"\\\",\\\"_meta\\\":{\\\"required\\\":true}}},\\\"methods\\\":{\\\"initialize\\\":{\\\"name\\\":\\\"initialize\\\",\\\"async\\\":true,\\\"parameters\\\":[],\\\"returnType\\\":\\\"Promise<this>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"save\\\":{\\\"name\\\":\\\"save\\\",\\\"async\\\":true,\\\"parameters\\\":[],\\\"returnType\\\":\\\"Promise<this>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true},\\\"delete\\\":{\\\"name\\\":\\\"delete\\\",\\\"async\\\":true,\\\"parameters\\\":[],\\\"returnType\\\":\\\"Promise<void>\\\",\\\"isStatic\\\":false,\\\"isPublic\\\":true}},\\\"decoratorConfig\\\":{\\\"tableName\\\":\\\"campaign_metric_snapshots\\\",\\\"conflictColumns\\\":[\\\"dedupe_key\\\"],\\\"api\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\",\\\"create\\\"]},\\\"mcp\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\",\\\"create\\\"]},\\\"cli\\\":{\\\"include\\\":[\\\"list\\\",\\\"get\\\",\\\"create\\\"]},\\\"tenantScoped\\\":{\\\"mode\\\":\\\"optional\\\"}},\\\"extends\\\":\\\"SmrtObject\\\",\\\"exportName\\\":\\\"CampaignMetricSnapshot\\\",\\\"collectionExportName\\\":\\\"CampaignMetricSnapshotCollection\\\",\\\"validationRules\\\":[{\\\"field\\\":\\\"campaignId\\\",\\\"rule\\\":\\\"required\\\",\\\"fieldType\\\":\\\"foreignKey\\\"},{\\\"field\\\":\\\"periodStart\\\",\\\"rule\\\":\\\"required\\\",\\\"fieldType\\\":\\\"datetime\\\"},{\\\"field\\\":\\\"periodEnd\\\",\\\"rule\\\":\\\"required\\\",\\\"fieldType\\\":\\\"datetime\\\"},{\\\"field\\\":\\\"source\\\",\\\"rule\\\":\\\"required\\\",\\\"fieldType\\\":\\\"text\\\"},{\\\"field\\\":\\\"dedupeKey\\\",\\\"rule\\\":\\\"required\\\",\\\"fieldType\\\":\\\"text\\\"}],\\\"schema\\\":{\\\"tableName\\\":\\\"campaign_metric_snapshots\\\",\\\"ddl\\\":\\\"CREATE TABLE IF NOT EXISTS \\\\\\\"campaign_metric_snapshots\\\\\\\" (\\\\n \\\\\\\"id\\\\\\\" UUID PRIMARY KEY NOT NULL,\\\\n \\\\\\\"slug\\\\\\\" TEXT NOT NULL,\\\\n \\\\\\\"context\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"created_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"updated_at\\\\\\\" TIMESTAMP NOT NULL DEFAULT current_timestamp,\\\\n \\\\\\\"tenant_id\\\\\\\" UUID,\\\\n \\\\\\\"campaign_id\\\\\\\" UUID NOT NULL,\\\\n \\\\\\\"campaign_channel_id\\\\\\\" UUID,\\\\n \\\\\\\"period_start\\\\\\\" TIMESTAMP NOT NULL,\\\\n \\\\\\\"period_end\\\\\\\" TIMESTAMP NOT NULL,\\\\n \\\\\\\"spend_cents\\\\\\\" INTEGER DEFAULT 0,\\\\n \\\\\\\"impressions\\\\\\\" INTEGER DEFAULT 0,\\\\n \\\\\\\"clicks\\\\\\\" INTEGER DEFAULT 0,\\\\n \\\\\\\"conversions\\\\\\\" INTEGER DEFAULT 0,\\\\n \\\\\\\"leads\\\\\\\" INTEGER DEFAULT 0,\\\\n \\\\\\\"revenue_cents\\\\\\\" INTEGER,\\\\n \\\\\\\"source\\\\\\\" TEXT NOT NULL DEFAULT '',\\\\n \\\\\\\"dedupe_key\\\\\\\" TEXT NOT NULL DEFAULT ''\\\\n);\\\",\\\"columns\\\":{\\\"id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"primaryKey\\\":true,\\\"referenceKind\\\":\\\"id\\\",\\\"notNull\\\":true},\\\"slug\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true},\\\"context\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"\\\"},\\\"created_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"updated_at\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"default\\\":\\\"current_timestamp\\\"},\\\"tenant_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"tenantId\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"campaign_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"foreignKey\\\",\\\"notNull\\\":true,\\\"unique\\\":false,\\\"foreignKey\\\":{\\\"table\\\":\\\"campaigns\\\",\\\"column\\\":\\\"id\\\",\\\"onDelete\\\":\\\"NO ACTION\\\",\\\"onUpdate\\\":\\\"CASCADE\\\"}},\\\"campaign_channel_id\\\":{\\\"type\\\":\\\"UUID\\\",\\\"referenceKind\\\":\\\"foreignKey\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"foreignKey\\\":{\\\"table\\\":\\\"campaign_channels\\\",\\\"column\\\":\\\"id\\\",\\\"onDelete\\\":\\\"NO ACTION\\\",\\\"onUpdate\\\":\\\"CASCADE\\\"}},\\\"period_start\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"unique\\\":false},\\\"period_end\\\":{\\\"type\\\":\\\"TIMESTAMP\\\",\\\"notNull\\\":true,\\\"unique\\\":false},\\\"spend_cents\\\":{\\\"type\\\":\\\"INTEGER\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":0},\\\"impressions\\\":{\\\"type\\\":\\\"INTEGER\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":0},\\\"clicks\\\":{\\\"type\\\":\\\"INTEGER\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":0},\\\"conversions\\\":{\\\"type\\\":\\\"INTEGER\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":0},\\\"leads\\\":{\\\"type\\\":\\\"INTEGER\\\",\\\"notNull\\\":false,\\\"unique\\\":false,\\\"default\\\":0},\\\"revenue_cents\\\":{\\\"type\\\":\\\"INTEGER\\\",\\\"notNull\\\":false,\\\"unique\\\":false},\\\"source\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"},\\\"dedupe_key\\\":{\\\"type\\\":\\\"TEXT\\\",\\\"notNull\\\":true,\\\"unique\\\":false,\\\"default\\\":\\\"\\\"}},\\\"indexes\\\":[{\\\"name\\\":\\\"campaign_metric_snapshots_dedupe_key_idx\\\",\\\"columns\\\":[\\\"dedupe_key\\\"],\\\"unique\\\":true},{\\\"name\\\":\\\"campaign_metric_snapshots_slug_context_idx\\\",\\\"columns\\\":[\\\"slug\\\",\\\"context\\\"]},{\\\"name\\\":\\\"campaign_metric_snapshots_tenant_id_created_at_idx\\\",\\\"columns\\\":[\\\"tenant_id\\\",\\\"created_at\\\"]},{\\\"name\\\":\\\"campaign_metric_snapshots_campaign_id_idx\\\",\\\"columns\\\":[\\\"campaign_id\\\"]},{\\\"name\\\":\\\"campaign_metric_snapshots_campaign_channel_id_idx\\\",\\\"columns\\\":[\\\"campaign_channel_id\\\"]}],\\\"version\\\":\\\"1ccd36b3\\\"},\\\"importPath\\\":\\\"@happyvertical/smrt-marketing\\\"}},\\\"moduleType\\\":\\\"smrt\\\",\\\"smrtDependencies\\\":[\\\"@happyvertical/smrt-commerce\\\",\\\"@happyvertical/smrt-core\\\",\\\"@happyvertical/smrt-tenancy\\\"],\\\"browser\\\":{\\\"status\\\":\\\"server-only\\\",\\\"issues\\\":[\\\"#3624\\\"],\\\"via\\\":[\\\"@happyvertical/smrt-tenancy\\\"]},\\\"stampsConstructors\\\":true}\"));\n","/** Fail-closed customer/tenant mismatch without revealing row existence. */\nexport class CampaignCustomerScopeError extends Error {\n readonly code = 'CAMPAIGN_CUSTOMER_SCOPE';\n\n constructor(label: string) {\n super(`${label}: customer scope validation failed.`);\n this.name = 'CampaignCustomerScopeError';\n }\n}\n","import {\n ObjectRegistry,\n type SmrtObject,\n type SmrtObjectOptions,\n} from '@happyvertical/smrt-core';\nimport type { DatabaseInterface } from '@happyvertical/sql';\nimport { CampaignCustomerScopeError } from './errors.js';\n\nconst CUSTOMER_QUALIFIED_NAME = '@happyvertical/smrt-commerce:Customer';\nconst SAFE_SQL_IDENTIFIER = /^[A-Za-z_][A-Za-z0-9_]*$/u;\nconst UUID_RE =\n /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/iu;\n\ntype QueryDatabase = Pick<DatabaseInterface, 'query' | 'url'>;\n\ninterface DatabaseOptions {\n db?: SmrtObjectOptions['db'];\n}\n\nfunction requireDatabase(options: DatabaseOptions): QueryDatabase {\n const db = options.db;\n if (!db || typeof db !== 'object' || !('query' in db)) {\n throw new Error(\n 'Campaign customer queries require an initialized database connection.',\n );\n }\n return db as QueryDatabase;\n}\n\nasync function resolveCustomerTable(options: DatabaseOptions): Promise<string> {\n await ObjectRegistry.ensureManifestLoaded(CUSTOMER_QUALIFIED_NAME);\n const target =\n ObjectRegistry.getClassByQualifiedName(CUSTOMER_QUALIFIED_NAME) ??\n ObjectRegistry.getClass(CUSTOMER_QUALIFIED_NAME);\n if (!target) {\n throw new Error(\n 'Campaign customer queries require @happyvertical/smrt-commerce:Customer to be registered.',\n );\n }\n\n const probe = new target.constructor(options) as SmrtObject;\n const tableName = probe.tableName;\n if (!SAFE_SQL_IDENTIFIER.test(tableName)) {\n throw new Error('Campaign customer table has an invalid identifier.');\n }\n return tableName;\n}\n\n/**\n * Verify a bounded set of canonical commerce Customers in one database read.\n * The generic failure deliberately does not reveal whether an id is missing or\n * belongs to another tenant.\n */\nexport async function assertCustomersBelongToTenant(\n options: DatabaseOptions,\n tenantId: string | null,\n customerIds: readonly string[],\n label: string,\n lock: 'none' | 'share' | 'update' = 'none',\n): Promise<void> {\n if (customerIds.length === 0) return;\n const normalizedCustomerIds = customerIds.map((customerId) => {\n try {\n return normalizeUuid(customerId, 'customerId');\n } catch {\n throw new CampaignCustomerScopeError(label);\n }\n });\n const normalizedTenantId = tenantId?.toLowerCase() ?? null;\n const db = requireDatabase(options);\n const tableName = await resolveCustomerTable(options);\n const placeholders = normalizedCustomerIds.map(() => '?').join(', ');\n const lockClause = postgresLockClause(db, lock);\n const result = await db.query(\n `SELECT id, tenant_id FROM ${tableName} WHERE id IN (${placeholders})${lockClause}`,\n ...normalizedCustomerIds,\n );\n const tenantById = new Map(\n result.rows.map((row) => [\n String(row.id).toLowerCase(),\n row.tenant_id == null ? null : String(row.tenant_id).toLowerCase(),\n ]),\n );\n const valid = normalizedCustomerIds.every(\n (customerId) =>\n tenantById.has(customerId) &&\n tenantById.get(customerId) === normalizedTenantId,\n );\n if (!valid) {\n throw new CampaignCustomerScopeError(label);\n }\n}\n\nfunction postgresLockClause(\n db: QueryDatabase,\n lock: 'none' | 'share' | 'update',\n): string {\n if (lock === 'none' || !/^postgres(?:ql)?:/iu.test(db.url)) return '';\n return lock === 'update' ? ' FOR UPDATE' : ' FOR SHARE';\n}\n\n/** Parse and canonicalize one UUID without echoing the rejected value. */\nexport function normalizeUuid(value: string, label: string): string {\n if (!UUID_RE.test(value)) {\n throw new Error(`${label} must be a canonical UUID.`);\n }\n return value.toLowerCase();\n}\n","/** Campaign identity, budget, schedule, and guarded lifecycle. */\n\nimport {\n crossPackageRef,\n field,\n SmrtObject,\n smrt,\n ValidationError,\n} from '@happyvertical/smrt-core';\nimport {\n getCurrentTenant,\n isSuperAdminBypass,\n isSystemContext,\n TenantIsolationError,\n TenantScoped,\n tenantId,\n withTenant,\n} from '@happyvertical/smrt-tenancy';\nimport {\n assertCustomersBelongToTenant,\n normalizeUuid,\n} from '../customer-scope.js';\nimport { CampaignCustomerScopeError } from '../errors.js';\nimport {\n CAMPAIGN_STATUSES,\n type CampaignOptions,\n type CampaignStatus,\n} from '../types.js';\n\nconst CAMPAIGN_STATUS_TRANSITIONS: Record<CampaignStatus, CampaignStatus[]> = {\n draft: ['scheduled'],\n scheduled: ['active'],\n active: ['paused', 'completed'],\n paused: ['active', 'completed'],\n completed: ['archived'],\n archived: [],\n};\n\nconst loadedCampaignStatus = new WeakMap<Campaign, CampaignStatus>();\n\n@TenantScoped({ mode: 'optional' })\n@smrt({\n tableName: 'campaigns',\n conflictColumns: ['tenant_id', 'campaign_key'],\n indexes: [\n {\n name: 'campaigns_tenant_id_customer_id_start_at_id_idx',\n columns: ['tenantId', 'customerId', 'startAt', 'id'],\n },\n ],\n api: { include: ['list', 'get', 'create', 'update'] },\n mcp: { include: ['list', 'get', 'create', 'update'] },\n cli: { include: ['list', 'get', 'create', 'update'] },\n})\nexport class Campaign extends SmrtObject { static __smrtPackage__ = \"@happyvertical/smrt-marketing\";\n @tenantId({ nullable: true })\n tenantId: string | null = null;\n\n /** Canonical commerce Customer that owns this campaign, when assigned. */\n @crossPackageRef('@happyvertical/smrt-commerce:Customer', {\n nullable: true,\n validate: true,\n })\n customerId: string | null = null;\n\n /** Stable caller-defined key used by CRM/referral systems. */\n @field({ required: true })\n campaignKey: string = '';\n\n @field({ required: true })\n name: string = '';\n\n /** Open objective key such as `awareness` or `demand_generation`. */\n objective: string = '';\n\n status: CampaignStatus = 'draft';\n\n startAt: Date | null = null;\n\n endAt: Date | null = null;\n\n /** Total campaign budget in integer cents. */\n budgetCents: number = 0;\n\n /** ISO 4217 currency for every campaign/channel amount. */\n currency: string = 'USD';\n\n metadata: string = '{}';\n\n constructor(options: CampaignOptions = {}) {\n super(options);\n if (options.tenantId !== undefined) this.tenantId = options.tenantId;\n if (options.customerId !== undefined) this.customerId = options.customerId;\n if (options.campaignKey !== undefined)\n this.campaignKey = options.campaignKey;\n if (options.name !== undefined) this.name = options.name;\n if (options.objective !== undefined) this.objective = options.objective;\n if (options.status !== undefined) this.status = options.status;\n if (options.startAt !== undefined)\n this.startAt = Campaign.coerceDate(options.startAt);\n if (options.endAt !== undefined)\n this.endAt = Campaign.coerceDate(options.endAt);\n if (options.budgetCents !== undefined)\n this.budgetCents = options.budgetCents;\n if (options.currency !== undefined) this.currency = options.currency;\n if (options.metadata !== undefined) this.metadata = options.metadata;\n }\n\n override async initialize(): Promise<this> {\n if (this.id) {\n try {\n this.id = normalizeUuid(this.id, 'id');\n } catch (error) {\n if (this.customerId !== null) {\n throw new CampaignCustomerScopeError('Campaign.initialize');\n }\n throw error;\n }\n }\n await super.initialize();\n this.startAt = Campaign.coerceDate(this.startAt);\n this.endAt = Campaign.coerceDate(this.endAt);\n if (this.isPersisted) loadedCampaignStatus.set(this, this.status);\n return this;\n }\n\n override async save(): Promise<this> {\n if (this.customerId === null) return this.saveLifecycle();\n\n const db = this.db;\n if (typeof db.transaction !== 'function') {\n throw new Error(\n 'Campaign.save requires a database adapter with transaction support.',\n );\n }\n return db.transaction(async (transactionDb) =>\n this.withDatabase(transactionDb, async (bound) => bound.saveLifecycle()),\n );\n }\n\n private async saveLifecycle(): Promise<this> {\n this.prepareIdentityForSave();\n if (this.customerId !== null) {\n await assertCustomersBelongToTenant(\n this.options,\n this.tenantId,\n [this.customerId],\n 'Campaign.save',\n 'update',\n );\n }\n const prior = await this.resolvePriorStatus();\n this.assertStatusTransition(prior);\n this.assertSchedule();\n let result: this;\n try {\n const persist = async () => (await super.save()) as this;\n const tenantContext =\n isSystemContext() || isSuperAdminBypass()\n ? undefined\n : getCurrentTenant();\n result = tenantContext\n ? await withTenant(\n {\n ...tenantContext,\n tenantId: this.tenantId ?? tenantContext.tenantId,\n },\n persist,\n )\n : await persist();\n } catch (error) {\n if (\n error instanceof ValidationError &&\n (error.code === 'VALIDATION_CROSS_PACKAGE_REF_MISSING' ||\n error.code === 'VALIDATION_CROSS_PACKAGE_REF_UNREGISTERED')\n ) {\n throw new CampaignCustomerScopeError('Campaign.save');\n }\n throw error;\n }\n loadedCampaignStatus.set(this, this.status);\n return result;\n }\n\n /** Canonicalize and authorize identity before any status or scope read. */\n private prepareIdentityForSave(): void {\n try {\n if (this.id) this.id = normalizeUuid(this.id, 'id');\n if (this.customerId !== null) {\n this.customerId = normalizeUuid(this.customerId, 'customerId');\n }\n if (this.tenantId !== null) {\n this.tenantId = normalizeUuid(this.tenantId, 'tenantId');\n }\n } catch (error) {\n if (this.customerId !== null) {\n throw new CampaignCustomerScopeError('Campaign.save');\n }\n throw error;\n }\n\n if (isSystemContext() || isSuperAdminBypass()) return;\n const tenantContext = getCurrentTenant();\n if (!tenantContext) return;\n\n let contextTenantId: string;\n try {\n contextTenantId = normalizeUuid(tenantContext.tenantId, 'tenantId');\n } catch (error) {\n if (this.customerId !== null) {\n throw new CampaignCustomerScopeError('Campaign.save');\n }\n throw error;\n }\n if (this.tenantId !== null && this.tenantId !== contextTenantId) {\n throw new TenantIsolationError(\n 'Tenant isolation violation in Campaign.save.',\n { tenantId: contextTenantId, attemptedTenantId: this.tenantId },\n );\n }\n this.tenantId = contextTenantId;\n }\n\n /** Apply one legal transition in memory; callers choose the save boundary. */\n transitionTo(next: CampaignStatus): this {\n if (next === this.status) return this;\n const allowed = CAMPAIGN_STATUS_TRANSITIONS[this.status] ?? [];\n if (!allowed.includes(next)) {\n throw new Error(\n `Campaign ${this.campaignKey || this.id}: cannot transition ` +\n `'${this.status}' → '${next}'.`,\n );\n }\n this.status = next;\n return this;\n }\n\n getMetadata(): Record<string, unknown> {\n if (!this.metadata) return {};\n try {\n const parsed = JSON.parse(this.metadata) as unknown;\n return parsed && typeof parsed === 'object' && !Array.isArray(parsed)\n ? (parsed as Record<string, unknown>)\n : {};\n } catch {\n return {};\n }\n }\n\n setMetadata(metadata: Record<string, unknown>): void {\n this.metadata = JSON.stringify(metadata ?? {});\n }\n\n private assertSchedule(): void {\n if (\n this.startAt &&\n this.endAt &&\n this.endAt.getTime() < this.startAt.getTime()\n ) {\n throw new Error('Campaign endAt must be on or after startAt.');\n }\n if (!Number.isInteger(this.budgetCents) || this.budgetCents < 0) {\n throw new Error('Campaign budgetCents must be a non-negative integer.');\n }\n }\n\n private async resolvePriorStatus(): Promise<CampaignStatus | undefined> {\n if (this.id) {\n let scopedRow: Record<string, unknown> | null = null;\n try {\n scopedRow = await this.db.get(this.tableName, {\n id: this.id,\n tenant_id: this.tenantId,\n });\n } catch {\n // DB not ready / table absent; fall through to the hydrated state.\n }\n if (scopedRow?.status != null) {\n return scopedRow.status as CampaignStatus;\n }\n\n // A caller-supplied ID already owned by another lane must not expose its\n // lifecycle state or be repurposed by an upsert.\n let rowInAnotherLane: Record<string, unknown> | null = null;\n try {\n rowInAnotherLane = await this.db.get(this.tableName, { id: this.id });\n } catch {\n // DB not ready / table absent; fall through to the hydrated state.\n }\n if (rowInAnotherLane) {\n throw new CampaignCustomerScopeError('Campaign.save');\n }\n }\n if (this.campaignKey) {\n try {\n const row = await this.db.get(this.tableName, {\n tenant_id: this.tenantId,\n campaign_key: this.campaignKey,\n });\n if (row && row.status != null) return row.status as CampaignStatus;\n } catch {\n // DB not ready / table absent; fall through to the hydrated state.\n }\n }\n return loadedCampaignStatus.get(this);\n }\n\n private assertStatusTransition(prior: CampaignStatus | undefined): void {\n if (!CAMPAIGN_STATUSES.includes(this.status)) {\n throw new Error(\n `Campaign ${this.campaignKey || this.id}: unknown status '${this.status}'.`,\n );\n }\n if (prior === undefined || prior === this.status) return;\n const allowed = CAMPAIGN_STATUS_TRANSITIONS[prior] ?? [];\n if (!allowed.includes(this.status)) {\n throw new Error(\n `Campaign ${this.campaignKey || this.id}: illegal status transition ` +\n `'${prior}' → '${this.status}'.`,\n );\n }\n }\n\n private static coerceDate(value: unknown): Date | null {\n if (value == null) return null;\n if (value instanceof Date) return value;\n if (typeof value === 'number' || typeof value === 'string') {\n const date = new Date(value);\n return Number.isNaN(date.getTime()) ? null : date;\n }\n return null;\n }\n}\n\nexport default Campaign;\n","/** Generic links from a campaign to cross-package channel execution rows. */\n\nimport { field, foreignKey, SmrtObject, smrt } from '@happyvertical/smrt-core';\nimport { TenantScoped, tenantId } from '@happyvertical/smrt-tenancy';\nimport type {\n CampaignChannelOptions,\n CampaignChannelStatus,\n} from '../types.js';\nimport { CAMPAIGN_CHANNEL_STATUSES } from '../types.js';\nimport { Campaign } from './Campaign.js';\n\n@TenantScoped({ mode: 'optional' })\n@smrt({\n tableName: 'campaign_channels',\n conflictColumns: ['campaign_id', 'channel_kind', 'channel_ref'],\n api: { include: ['list', 'get', 'create', 'update', 'delete'] },\n mcp: { include: ['list', 'get', 'create', 'update'] },\n cli: { include: ['list', 'get', 'create', 'update', 'delete'] },\n})\nexport class CampaignChannel extends SmrtObject { static __smrtPackage__ = \"@happyvertical/smrt-marketing\";\n @tenantId({ nullable: true })\n tenantId: string | null = null;\n\n @foreignKey(Campaign, { required: true })\n campaignId: string = '';\n\n /** Open kind vocabulary; recommended values live in CAMPAIGN_CHANNEL_KINDS. */\n @field({ required: true })\n channelKind: string = '';\n\n /** Opaque identifier in the namespace named by channelKind. */\n @field({ required: true })\n channelRef: string = '';\n\n allocatedBudgetCents: number = 0;\n\n /** Optional execution-specific override of the Campaign start. */\n startAt: Date | null = null;\n\n /** Optional execution-specific override of the Campaign end. */\n endAt: Date | null = null;\n\n status: CampaignChannelStatus = 'planned';\n\n constructor(options: CampaignChannelOptions = {}) {\n super(options);\n if (options.tenantId !== undefined) this.tenantId = options.tenantId;\n if (options.campaignId !== undefined) this.campaignId = options.campaignId;\n if (options.channelKind !== undefined)\n this.channelKind = options.channelKind;\n if (options.channelRef !== undefined) this.channelRef = options.channelRef;\n if (options.allocatedBudgetCents !== undefined)\n this.allocatedBudgetCents = options.allocatedBudgetCents;\n if (options.startAt !== undefined)\n this.startAt = CampaignChannel.coerceDate(options.startAt);\n if (options.endAt !== undefined)\n this.endAt = CampaignChannel.coerceDate(options.endAt);\n if (options.status !== undefined) this.status = options.status;\n }\n\n override async initialize(): Promise<this> {\n await super.initialize();\n this.startAt = CampaignChannel.coerceDate(this.startAt);\n this.endAt = CampaignChannel.coerceDate(this.endAt);\n return this;\n }\n\n override async save(): Promise<this> {\n if (!CAMPAIGN_CHANNEL_STATUSES.includes(this.status)) {\n throw new Error(\n `CampaignChannel ${this.channelRef || this.id}: unknown status '${this.status}'.`,\n );\n }\n if (\n !Number.isInteger(this.allocatedBudgetCents) ||\n this.allocatedBudgetCents < 0\n ) {\n throw new Error(\n 'CampaignChannel allocatedBudgetCents must be a non-negative integer.',\n );\n }\n if (\n this.startAt &&\n this.endAt &&\n this.endAt.getTime() < this.startAt.getTime()\n ) {\n throw new Error('CampaignChannel endAt must be on or after startAt.');\n }\n return (await super.save()) as this;\n }\n\n private static coerceDate(value: unknown): Date | null {\n if (value == null) return null;\n if (value instanceof Date) return value;\n if (typeof value === 'number' || typeof value === 'string') {\n const date = new Date(value);\n return Number.isNaN(date.getTime()) ? null : date;\n }\n return null;\n }\n}\n\nexport default CampaignChannel;\n","import { SmrtCollection } from '@happyvertical/smrt-core';\nimport { CampaignChannel } from '../models/CampaignChannel.js';\n\nexport class CampaignChannelCollection extends SmrtCollection<CampaignChannel> {\n static readonly _itemClass = CampaignChannel;\n\n async findByCampaign(campaignId: string): Promise<CampaignChannel[]> {\n return await this.list({\n where: { campaignId },\n orderBy: 'start_at ASC',\n });\n }\n\n async findByExecutionRef(\n channelKind: string,\n channelRef: string,\n ): Promise<CampaignChannel[]> {\n return await this.list({ where: { channelKind, channelRef } });\n }\n}\n\nexport default CampaignChannelCollection;\n","import type { Campaign } from '../models/Campaign.js';\nimport type { BudgetPacingResult, BudgetPacingStatus } from '../types.js';\n\nexport interface BudgetPacingEvidence {\n spendCents: number;\n snapshotCount: number;\n usedCampaignRollups: boolean;\n}\n\n/** Canonical campaign pacing calculation for grouped and row-level evidence. */\nexport function calculateCampaignPacing(\n campaign: Campaign,\n evidence: BudgetPacingEvidence,\n at = new Date(),\n): BudgetPacingResult {\n return calculatePacing({\n campaign,\n evidence,\n budgetCents: campaign.budgetCents,\n startAt: campaign.startAt,\n endAt: campaign.endAt,\n at,\n });\n}\n\nexport function calculatePacing({\n campaign,\n evidence,\n budgetCents,\n startAt,\n endAt,\n at,\n}: {\n campaign: Campaign;\n evidence: BudgetPacingEvidence;\n budgetCents: number;\n startAt: Date | null;\n endAt: Date | null;\n at: Date;\n}): BudgetPacingResult {\n const elapsed = elapsedFraction(startAt, endAt, at);\n const expectedSpendCents =\n elapsed === null ? null : Math.round(budgetCents * elapsed);\n const varianceCents =\n expectedSpendCents === null\n ? null\n : evidence.spendCents - expectedSpendCents;\n return {\n campaignId: campaign.id ?? '',\n currency: campaign.currency,\n budgetCents,\n spendCents: evidence.spendCents,\n remainingCents: budgetCents - evidence.spendCents,\n expectedSpendCents,\n varianceCents,\n budgetFraction: budgetCents > 0 ? evidence.spendCents / budgetCents : null,\n elapsedFraction: elapsed,\n status: pacingStatus({\n campaign,\n budgetCents,\n spendCents: evidence.spendCents,\n elapsedFraction: elapsed,\n varianceCents,\n startAt,\n at,\n }),\n snapshotCount: evidence.snapshotCount,\n usedCampaignRollups: evidence.usedCampaignRollups,\n };\n}\n\nfunction pacingStatus({\n campaign,\n budgetCents,\n spendCents,\n elapsedFraction,\n varianceCents,\n startAt,\n at,\n}: {\n campaign: Campaign;\n budgetCents: number;\n spendCents: number;\n elapsedFraction: number | null;\n varianceCents: number | null;\n startAt: Date | null;\n at: Date;\n}): BudgetPacingStatus {\n if (budgetCents <= 0) return 'unbudgeted';\n if (spendCents > budgetCents) return 'over_budget';\n if (startAt && at.getTime() < startAt.getTime()) return 'not_started';\n if (\n campaign.status === 'completed' ||\n campaign.status === 'archived' ||\n elapsedFraction === 1\n ) {\n return 'complete';\n }\n if (varianceCents === null) return 'on_track';\n\n // A five-percent budget band avoids noisy status flips from minor timing\n // differences between spend collection and scheduled pacing.\n const toleranceCents = Math.max(1, Math.round(budgetCents * 0.05));\n if (varianceCents > toleranceCents) return 'ahead';\n if (varianceCents < -toleranceCents) return 'behind';\n return 'on_track';\n}\n\nfunction elapsedFraction(\n startAt: Date | null,\n endAt: Date | null,\n at: Date,\n): number | null {\n if (!startAt || !endAt) return null;\n const start = startAt.getTime();\n const end = endAt.getTime();\n if (end <= start) return at.getTime() < start ? 0 : 1;\n return Math.min(1, Math.max(0, (at.getTime() - start) / (end - start)));\n}\n","/** Immutable period performance evidence for a campaign or campaign channel. */\n\nimport { field, foreignKey, SmrtObject, smrt } from '@happyvertical/smrt-core';\nimport { TenantScoped, tenantId } from '@happyvertical/smrt-tenancy';\nimport type { CampaignMetricSnapshotOptions } from '../types.js';\nimport { Campaign } from './Campaign.js';\nimport { CampaignChannel } from './CampaignChannel.js';\n\nconst persistedSnapshotState = new WeakMap<CampaignMetricSnapshot, string>();\n\n@TenantScoped({ mode: 'optional' })\n@smrt({\n tableName: 'campaign_metric_snapshots',\n conflictColumns: ['dedupe_key'],\n api: { include: ['list', 'get', 'create'] },\n mcp: { include: ['list', 'get', 'create'] },\n cli: { include: ['list', 'get', 'create'] },\n})\nexport class CampaignMetricSnapshot extends SmrtObject { static __smrtPackage__ = \"@happyvertical/smrt-marketing\";\n @tenantId({ nullable: true })\n tenantId: string | null = null;\n\n @foreignKey(Campaign, { required: true })\n campaignId: string = '';\n\n /** Null for campaign rollups; set for channel-scoped evidence. */\n @foreignKey(CampaignChannel, { nullable: true })\n campaignChannelId: string | null = null;\n\n @field({ required: true })\n periodStart: Date = new Date();\n\n @field({ required: true })\n periodEnd: Date = new Date();\n\n spendCents: number = 0;\n\n impressions: number = 0;\n\n clicks: number = 0;\n\n conversions: number = 0;\n\n leads: number = 0;\n\n @field({ type: 'integer', nullable: true })\n revenueCents: number | null = null;\n\n /** Ingestion source such as `google_ads`, `meta`, or `rollup_job`. */\n @field({ required: true })\n source: string = '';\n\n @field({ required: true })\n dedupeKey: string = '';\n\n constructor(options: CampaignMetricSnapshotOptions = {}) {\n super(options);\n if (options.tenantId !== undefined) this.tenantId = options.tenantId;\n if (options.campaignId !== undefined) this.campaignId = options.campaignId;\n if (options.campaignChannelId !== undefined)\n this.campaignChannelId = options.campaignChannelId;\n if (options.periodStart !== undefined)\n this.periodStart =\n CampaignMetricSnapshot.coerceDate(options.periodStart) ??\n new Date(Number.NaN);\n if (options.periodEnd !== undefined)\n this.periodEnd =\n CampaignMetricSnapshot.coerceDate(options.periodEnd) ??\n new Date(Number.NaN);\n if (options.spendCents !== undefined) this.spendCents = options.spendCents;\n if (options.impressions !== undefined)\n this.impressions = options.impressions;\n if (options.clicks !== undefined) this.clicks = options.clicks;\n if (options.conversions !== undefined)\n this.conversions = options.conversions;\n if (options.leads !== undefined) this.leads = options.leads;\n if (options.revenueCents !== undefined)\n this.revenueCents = options.revenueCents;\n if (options.source !== undefined) this.source = options.source;\n if (options.dedupeKey !== undefined) this.dedupeKey = options.dedupeKey;\n }\n\n override async initialize(): Promise<this> {\n await super.initialize();\n this.periodStart =\n CampaignMetricSnapshot.coerceDate(this.periodStart) ??\n new Date(Number.NaN);\n this.periodEnd =\n CampaignMetricSnapshot.coerceDate(this.periodEnd) ?? new Date(Number.NaN);\n if (this.isPersisted) {\n persistedSnapshotState.set(this, this.serializeState());\n }\n return this;\n }\n\n override async save(): Promise<this> {\n this.assertMetrics();\n await this.assertChannelMatchesCampaign();\n const captured = persistedSnapshotState.get(this);\n if (captured !== undefined) {\n if (captured !== this.serializeState()) {\n throw new Error(\n `CampaignMetricSnapshot ${this.id ?? '<new>'}: metric snapshots ` +\n 'are immutable evidence; ingest a correcting snapshot instead.',\n );\n }\n } else if (this.id && (await this.isSaved())) {\n throw new Error(\n `CampaignMetricSnapshot ${this.id}: refusing to overwrite an existing ` +\n 'snapshot from a non-hydrated instance; snapshots are immutable evidence.',\n );\n } else if (this.dedupeKey) {\n try {\n const row = await this.db.get(this.tableName, {\n dedupe_key: this.dedupeKey,\n });\n if (row && row.id !== this.id) {\n throw new Error(\n `CampaignMetricSnapshot (dedupeKey '${this.dedupeKey}'): a ` +\n 'snapshot with this dedupe key already exists; use ' +\n 'MetricIngestionService for idempotent ingestion.',\n );\n }\n } catch (error) {\n if (\n error instanceof Error &&\n error.message.includes('idempotent ingestion')\n ) {\n throw error;\n }\n // DB not ready / table absent; there is no persisted row to protect.\n }\n }\n\n const result = (await super.save()) as this;\n persistedSnapshotState.set(this, this.serializeState());\n return result;\n }\n\n override async delete(): Promise<void> {\n throw new Error(\n `CampaignMetricSnapshot ${this.id ?? '<new>'}: metric snapshots are ` +\n 'immutable evidence and cannot be deleted.',\n );\n }\n\n private assertMetrics(): void {\n if (\n Number.isNaN(this.periodStart.getTime()) ||\n Number.isNaN(this.periodEnd.getTime())\n ) {\n throw new Error(\n 'CampaignMetricSnapshot periodStart and periodEnd must be valid dates.',\n );\n }\n if (this.periodEnd.getTime() < this.periodStart.getTime()) {\n throw new Error(\n 'CampaignMetricSnapshot periodEnd must be on or after periodStart.',\n );\n }\n const integerMetrics: Array<[string, number]> = [\n ['spendCents', this.spendCents],\n ['impressions', this.impressions],\n ['clicks', this.clicks],\n ['conversions', this.conversions],\n ['leads', this.leads],\n ];\n for (const [name, value] of integerMetrics) {\n if (!Number.isInteger(value) || value < 0) {\n throw new Error(`${name} must be a non-negative integer.`);\n }\n }\n if (\n this.revenueCents !== null &&\n (!Number.isInteger(this.revenueCents) || this.revenueCents < 0)\n ) {\n throw new Error('revenueCents must be null or a non-negative integer.');\n }\n }\n\n private async assertChannelMatchesCampaign(): Promise<void> {\n if (!this.campaignChannelId) return;\n const channel = (await this.loadRelated(\n 'campaignChannelId',\n )) as CampaignChannel;\n if (channel.campaignId !== this.campaignId) {\n throw new Error(\n `CampaignMetricSnapshot campaignChannelId '${this.campaignChannelId}' ` +\n `does not belong to campaignId '${this.campaignId}'.`,\n );\n }\n }\n\n private serializeState(): string {\n return JSON.stringify({\n tenantId: this.tenantId,\n campaignId: this.campaignId,\n campaignChannelId: this.campaignChannelId,\n periodStart: this.periodStart.toISOString(),\n periodEnd: this.periodEnd.toISOString(),\n spendCents: this.spendCents,\n impressions: this.impressions,\n clicks: this.clicks,\n conversions: this.conversions,\n leads: this.leads,\n revenueCents: this.revenueCents,\n source: this.source,\n dedupeKey: this.dedupeKey,\n });\n }\n\n private static coerceDate(value: unknown): Date | null {\n if (value instanceof Date) {\n return Number.isNaN(value.getTime()) ? null : value;\n }\n if (typeof value === 'number' || typeof value === 'string') {\n const date = new Date(value);\n return Number.isNaN(date.getTime()) ? null : date;\n }\n return null;\n }\n}\n\nexport default CampaignMetricSnapshot;\n","import { SmrtCollection } from '@happyvertical/smrt-core';\nimport { CampaignMetricSnapshot } from '../models/CampaignMetricSnapshot.js';\nimport type { CampaignMetricSnapshotOptions } from '../types.js';\n\nexport class CampaignMetricSnapshotCollection extends SmrtCollection<CampaignMetricSnapshot> {\n static readonly _itemClass = CampaignMetricSnapshot;\n\n async findByDedupeKey(\n dedupeKey: string,\n ): Promise<CampaignMetricSnapshot | null> {\n if (!dedupeKey) return null;\n const rows = await this.list({ where: { dedupeKey }, limit: 1 });\n return rows[0] ?? null;\n }\n\n async getOrCreateByDedupeKey(\n options: CampaignMetricSnapshotOptions,\n ): Promise<{ snapshot: CampaignMetricSnapshot; created: boolean }> {\n const dedupeKey = options.dedupeKey ?? '';\n if (!dedupeKey) {\n throw new Error(\n 'CampaignMetricSnapshotCollection.getOrCreateByDedupeKey requires a dedupeKey.',\n );\n }\n const existing = await this.findByDedupeKey(dedupeKey);\n if (existing) return { snapshot: existing, created: false };\n\n try {\n const snapshot = await this.create({\n ...options,\n // Keep runtime values uncoerced so the model rejects null/invalid\n // periods instead of allowing Date(null) to become the Unix epoch.\n periodStart: options.periodStart as Date | undefined,\n periodEnd: options.periodEnd as Date | undefined,\n _insertOnly: true,\n });\n return { snapshot, created: true };\n } catch (error) {\n // A concurrent ingest may have won the unique dedupe-key insert after\n // our initial read. Re-read the immutable winner instead of allowing a\n // natural-key upsert to replace its evidence in place.\n const concurrent = await this.findByDedupeKey(dedupeKey);\n if (concurrent) return { snapshot: concurrent, created: false };\n throw error;\n }\n }\n\n async findByCampaign(campaignId: string): Promise<CampaignMetricSnapshot[]> {\n return await this.list({\n where: { campaignId },\n orderBy: 'period_start ASC',\n });\n }\n\n async findByChannel(\n campaignChannelId: string,\n ): Promise<CampaignMetricSnapshot[]> {\n return await this.list({\n where: { campaignChannelId },\n orderBy: 'period_start ASC',\n });\n }\n}\n\nexport default CampaignMetricSnapshotCollection;\n","import {\n type CollectionCacheConfig,\n resolveListLimit,\n SmrtCollection,\n type SmrtListOptions,\n type SmrtSelectedRow,\n type SmrtSelectField,\n type SmrtWhereClause,\n} from '@happyvertical/smrt-core';\nimport {\n getCurrentTenant,\n isSuperAdminBypass,\n isSystemContext,\n TenantIsolationError,\n withTenant,\n} from '@happyvertical/smrt-tenancy';\nimport type { DatabaseInterface } from '@happyvertical/sql';\nimport {\n assertCustomersBelongToTenant,\n normalizeUuid,\n} from '../customer-scope.js';\nimport { Campaign } from '../models/Campaign.js';\nimport { calculateCampaignPacing } from '../services/pacing-calculation.js';\nimport type {\n CampaignChannelMixEntry,\n CampaignCustomerCursor,\n CampaignCustomerCursorInput,\n CampaignCustomerPage,\n CampaignCustomerSummary,\n CampaignMetricTotals,\n CampaignReportingPage,\n CampaignStatus,\n ListCampaignReportingByCustomerOptions,\n ListCampaignsByCustomerOptions,\n} from '../types.js';\nimport { CampaignChannelCollection } from './CampaignChannelCollection.js';\nimport { CampaignMetricSnapshotCollection } from './CampaignMetricSnapshotCollection.js';\n\nexport const MAX_CAMPAIGN_CUSTOMER_PAGE_SIZE = 100;\nexport const MAX_CAMPAIGN_CUSTOMER_BATCH_SIZE = 100;\n\nexport class CampaignCollection extends SmrtCollection<Campaign> {\n static readonly _itemClass = Campaign;\n\n override async get(\n filter: string | SmrtWhereClause<Campaign>,\n options: { cache?: CollectionCacheConfig | false } = {},\n ): Promise<Campaign | null> {\n return withCanonicalActiveTenant(() =>\n super.get(normalizeCampaignGetFilter(filter), options),\n );\n }\n\n override async list<\n const Select extends readonly SmrtSelectField<Campaign>[],\n >(\n options: SmrtListOptions<Campaign> & { select: Select; include?: never },\n ): Promise<SmrtSelectedRow<Campaign, Select>[]>;\n override async list(\n options?: Omit<SmrtListOptions<Campaign>, 'select'> & {\n select?: undefined;\n },\n ): Promise<Campaign[]>;\n override async list(\n options: SmrtListOptions<Campaign> = {},\n ): Promise<Campaign[] | Record<string, unknown>[]> {\n return withCanonicalActiveTenant(\n () =>\n super.list(normalizeCampaignListOptions(options) as never) as Promise<\n Campaign[] | Record<string, unknown>[]\n >,\n );\n }\n\n async findByCampaignKey(\n campaignKey: string,\n tenantId?: string | null,\n ): Promise<Campaign | null> {\n if (!campaignKey) return null;\n const where: Record<string, unknown> = { campaignKey };\n if (tenantId !== undefined) where.tenantId = tenantId;\n const rows = await this.list({ where, limit: 1 });\n return rows[0] ?? null;\n }\n\n async findByStatus(status: CampaignStatus): Promise<Campaign[]> {\n return await this.list({\n where: { status },\n orderBy: 'start_at ASC',\n });\n }\n\n /**\n * List one tenant/customer lane newest-first using a stable UUID tiebreaker.\n * Null start times follow all scheduled rows on every supported database.\n */\n async listByCustomer(\n tenantId: string | null,\n customerId: string,\n options: ListCampaignsByCustomerOptions = {},\n ): Promise<CampaignCustomerPage> {\n const normalizedTenantId = normalizeTenantScope(\n tenantId,\n 'CampaignCollection.listByCustomer',\n );\n const normalizedCustomerId = normalizeUuid(customerId, 'customerId');\n const limit = resolveListLimit(options.limit, {\n defaultValue: 50,\n maxValue: Number.MAX_SAFE_INTEGER,\n parameterName: 'campaign customer page limit',\n });\n if (limit > MAX_CAMPAIGN_CUSTOMER_PAGE_SIZE) {\n throw new Error(\n `Campaign customer page limit must not exceed ${MAX_CAMPAIGN_CUSTOMER_PAGE_SIZE}.`,\n );\n }\n if (limit < 1) {\n throw new Error('Campaign customer page limit must be at least 1.');\n }\n const cursor = normalizeCursor(options.after);\n return withCanonicalTenantContext(normalizedTenantId, () =>\n this.inCustomerReadTransaction(async (bound) =>\n bound.listByCustomerInTransaction(\n normalizedTenantId,\n normalizedCustomerId,\n limit,\n cursor,\n 'CampaignCollection.listByCustomer',\n ),\n ),\n );\n }\n\n /**\n * Return one bounded customer page with its complete read-only reporting\n * projection. Channels and immutable evidence are aggregated in two grouped\n * reads, independent of page size; no campaign callback or lazy load runs.\n */\n async listReportingByCustomer(\n tenantId: string | null,\n customerId: string,\n options: ListCampaignReportingByCustomerOptions = {},\n ): Promise<CampaignReportingPage> {\n const normalizedTenantId = normalizeTenantScope(\n tenantId,\n 'CampaignCollection.listReportingByCustomer',\n );\n const normalizedCustomerId = normalizeUuid(customerId, 'customerId');\n const limit = resolveListLimit(options.limit, {\n defaultValue: 50,\n maxValue: Number.MAX_SAFE_INTEGER,\n parameterName: 'campaign reporting page limit',\n });\n if (limit > MAX_CAMPAIGN_CUSTOMER_PAGE_SIZE) {\n throw new Error(\n `Campaign reporting page limit must not exceed ${MAX_CAMPAIGN_CUSTOMER_PAGE_SIZE}.`,\n );\n }\n if (limit < 1) {\n throw new Error('Campaign reporting page limit must be at least 1.');\n }\n const cursor = normalizeCursor(options.after);\n const at = normalizeReportingAt(options.at);\n\n return withCanonicalTenantContext(normalizedTenantId, () =>\n this.inCustomerReadTransaction(async (bound) => {\n const page = await bound.listByCustomerInTransaction(\n normalizedTenantId,\n normalizedCustomerId,\n limit,\n cursor,\n 'CampaignCollection.listReportingByCustomer',\n );\n return bound.projectReportingPage(normalizedTenantId, page, at);\n }),\n );\n }\n\n private async projectReportingPage(\n tenantId: string | null,\n page: CampaignCustomerPage,\n at: Date,\n ): Promise<CampaignReportingPage> {\n const campaignIds = page.items.map((campaign) => {\n if (!campaign.id) {\n throw new Error('Campaign reporting requires persisted Campaign rows.');\n }\n return normalizeUuid(campaign.id, 'campaign id');\n });\n if (campaignIds.length === 0) {\n return { items: [], nextCursor: page.nextCursor };\n }\n\n const channelRows = await this.loadChannelMixRows(tenantId, campaignIds);\n const metricRows = await this.loadMetricRows(tenantId, campaignIds);\n const channelsByCampaign = groupChannelMix(channelRows);\n const metricsByCampaign = groupMetricTotals(metricRows);\n\n return {\n items: page.items.map((campaign) => {\n const campaignId = campaign.id ?? '';\n const channelMix = channelsByCampaign.get(campaignId) ?? [];\n const metrics =\n metricsByCampaign.get(campaignId) ?? emptyMetricTotals();\n return {\n campaign,\n channelCount: channelMix.reduce(\n (sum, entry) =>\n checkedAdd(sum, entry.count, 'Campaign channel count'),\n 0,\n ),\n channelMix,\n metricTotals: metrics.totals,\n pacing: calculateCampaignPacing(\n campaign,\n {\n spendCents: metrics.totals.spendCents,\n snapshotCount: metrics.snapshotCount,\n usedCampaignRollups: metrics.usedCampaignRollups,\n },\n at,\n ),\n };\n }),\n nextCursor: page.nextCursor,\n };\n }\n\n private async loadChannelMixRows(\n tenantId: string | null,\n campaignIds: string[],\n ): Promise<Array<Record<string, unknown>>> {\n const channels = await CampaignChannelCollection.create({\n ...this.options,\n db: this.db,\n defaultListLimit: undefined,\n maxListLimit: undefined,\n });\n const db = requireDatabase(this.options);\n const placeholders = campaignIds.map(() => '?').join(', ');\n const tenantPredicate =\n tenantId === null ? 'tenant_id IS NULL' : 'tenant_id = ?';\n const tenantParams = tenantId === null ? [] : [tenantId];\n const result = await db.query(\n `SELECT campaign_id, channel_kind, COUNT(*) AS channel_count\n FROM ${channels.tableName}\n WHERE ${tenantPredicate} AND campaign_id IN (${placeholders})\n GROUP BY campaign_id, channel_kind\n ORDER BY campaign_id ASC, channel_kind ASC`,\n ...tenantParams,\n ...campaignIds,\n );\n return result.rows;\n }\n\n private async loadMetricRows(\n tenantId: string | null,\n campaignIds: string[],\n ): Promise<Array<Record<string, unknown>>> {\n const snapshots = await CampaignMetricSnapshotCollection.create({\n ...this.options,\n db: this.db,\n defaultListLimit: undefined,\n maxListLimit: undefined,\n });\n const db = requireDatabase(this.options);\n const placeholders = campaignIds.map(() => '?').join(', ');\n const tenantPredicate =\n tenantId === null ? 'tenant_id IS NULL' : 'tenant_id = ?';\n const tenantParams = tenantId === null ? [] : [tenantId];\n const result = await db.query(\n `WITH scoped_snapshots AS (\n SELECT campaign_id,\n campaign_channel_id,\n period_start,\n period_end,\n spend_cents,\n impressions,\n clicks,\n conversions,\n leads,\n revenue_cents\n FROM ${snapshots.tableName}\n WHERE ${tenantPredicate} AND campaign_id IN (${placeholders})\n ), rollup_periods AS (\n SELECT DISTINCT campaign_id, period_start, period_end\n FROM scoped_snapshots\n WHERE campaign_channel_id IS NULL\n ), selected_snapshots AS (\n SELECT s.*\n FROM scoped_snapshots s\n LEFT JOIN rollup_periods r\n ON r.campaign_id = s.campaign_id\n AND r.period_start = s.period_start\n AND r.period_end = s.period_end\n WHERE s.campaign_channel_id IS NULL OR r.campaign_id IS NULL\n )\n SELECT campaign_id,\n COUNT(*) AS snapshot_count,\n MAX(CASE WHEN campaign_channel_id IS NULL THEN 1 ELSE 0 END)\n AS used_campaign_rollups,\n SUM(spend_cents) AS spend_cents,\n SUM(impressions) AS impressions,\n SUM(clicks) AS clicks,\n SUM(conversions) AS conversions,\n SUM(leads) AS leads,\n SUM(COALESCE(revenue_cents, 0)) AS revenue_cents\n FROM selected_snapshots\n GROUP BY campaign_id\n ORDER BY campaign_id ASC`,\n ...tenantParams,\n ...campaignIds,\n );\n return result.rows;\n }\n\n private async listByCustomerInTransaction(\n tenantId: string | null,\n customerId: string,\n limit: number,\n cursor: CampaignCustomerCursor | null,\n operation: string,\n ): Promise<CampaignCustomerPage> {\n await assertCustomersBelongToTenant(\n this.options,\n tenantId,\n [customerId],\n operation,\n 'share',\n );\n const items =\n cursor?.startAt === null\n ? await this.listNullStartLane(tenantId, customerId, limit + 1, cursor)\n : await this.listScheduledLane(tenantId, customerId, limit, cursor);\n const hasMore = items.length > limit;\n const pageItems = hasMore ? items.slice(0, limit) : items;\n return {\n items: pageItems,\n nextCursor: hasMore\n ? cursorFromCampaign(pageItems[pageItems.length - 1])\n : null,\n };\n }\n\n /**\n * Summarize a bounded customer batch with one scope check and one grouped\n * aggregate query. Every requested customer receives a row, including zeros.\n */\n async summarizeByCustomers(\n tenantId: string | null,\n customerIds: string[],\n ): Promise<CampaignCustomerSummary[]> {\n const normalizedTenantId = normalizeTenantScope(\n tenantId,\n 'CampaignCollection.summarizeByCustomers',\n );\n if (!Array.isArray(customerIds)) {\n throw new Error(\n 'Campaign customer summary customerIds must be an array.',\n );\n }\n if (customerIds.length > MAX_CAMPAIGN_CUSTOMER_BATCH_SIZE) {\n throw new Error(\n `Campaign customer summary accepts at most ${MAX_CAMPAIGN_CUSTOMER_BATCH_SIZE} customerIds.`,\n );\n }\n const normalizedCustomerIds = customerIds.map((customerId) =>\n normalizeUuid(customerId, 'customerId'),\n );\n const uniqueIds = [...new Set(normalizedCustomerIds)];\n if (uniqueIds.length === 0) return [];\n\n return withCanonicalTenantContext(normalizedTenantId, () =>\n this.inCustomerReadTransaction(async (bound) =>\n bound.summarizeByCustomersInTransaction(\n normalizedTenantId,\n normalizedCustomerIds,\n uniqueIds,\n ),\n ),\n );\n }\n\n private async summarizeByCustomersInTransaction(\n tenantId: string | null,\n requestedCustomerIds: string[],\n uniqueIds: string[],\n ): Promise<CampaignCustomerSummary[]> {\n await assertCustomersBelongToTenant(\n this.options,\n tenantId,\n uniqueIds,\n 'CampaignCollection.summarizeByCustomers',\n 'share',\n );\n const db = requireDatabase(this.options);\n const placeholders = uniqueIds.map(() => '?').join(', ');\n const tenantPredicate =\n tenantId === null ? 'tenant_id IS NULL' : 'tenant_id = ?';\n const tenantParams = tenantId === null ? [] : [tenantId];\n const result = await db.query(\n `SELECT customer_id,\n COUNT(*) AS total_count,\n SUM(CASE WHEN status = ? THEN 1 ELSE 0 END) AS active_count,\n MAX(start_at) AS latest_start_at\n FROM ${this.tableName}\n WHERE ${tenantPredicate} AND customer_id IN (${placeholders})\n GROUP BY customer_id\n ORDER BY customer_id ASC\n LIMIT ?`,\n 'active',\n ...tenantParams,\n ...uniqueIds,\n uniqueIds.length,\n );\n const byCustomer = new Map(\n result.rows.map((row) => [String(row.customer_id).toLowerCase(), row]),\n );\n return requestedCustomerIds.map((customerId) => {\n const row = byCustomer.get(customerId);\n return {\n customerId,\n totalCount: row\n ? toSafeCount(row.total_count, 'Campaign customer total count')\n : 0,\n activeCount: row\n ? toSafeCount(row.active_count, 'Campaign customer active count')\n : 0,\n latestStartAt: row ? coerceDate(row.latest_start_at) : null,\n };\n });\n }\n\n private async inCustomerReadTransaction<T>(\n operation: (bound: CampaignCollection) => Promise<T>,\n ): Promise<T> {\n const db = this.db as DatabaseInterface;\n if (typeof db.transaction !== 'function') {\n throw new Error(\n 'Campaign customer reads require a database adapter with transaction support.',\n );\n }\n return db.transaction(async (transactionDb) => {\n const bound = await CampaignCollection.create({\n ...this.options,\n db: transactionDb,\n defaultListLimit: undefined,\n maxListLimit: undefined,\n });\n return operation(bound);\n });\n }\n\n private async listScheduledLane(\n tenantId: string | null,\n customerId: string,\n limit: number,\n cursor: CampaignCustomerCursor | null,\n ): Promise<Campaign[]> {\n const base = [{ tenantId }, { customerId }, { 'startAt !=': null }];\n const where = cursor\n ? [\n [...base, { 'startAt <': cursor.startAt }],\n [...base, { startAt: cursor.startAt }, { 'id <': cursor.id }],\n ]\n : { tenantId, customerId, 'startAt !=': null };\n const scheduled = await this.list({\n where,\n orderBy: ['start_at DESC', 'id DESC'],\n limit: limit + 1,\n });\n if (scheduled.length > limit) return scheduled;\n const nullRows = await this.listNullStartLane(\n tenantId,\n customerId,\n limit - scheduled.length + 1,\n null,\n );\n return [...scheduled, ...nullRows];\n }\n\n private async listNullStartLane(\n tenantId: string | null,\n customerId: string,\n limit: number,\n cursor: CampaignCustomerCursor | null,\n ): Promise<Campaign[]> {\n return this.list({\n where: {\n tenantId,\n customerId,\n startAt: null,\n ...(cursor ? { 'id <': cursor.id } : {}),\n },\n orderBy: 'id DESC',\n limit,\n });\n }\n}\n\ninterface QueryDatabase {\n query(\n sql: string,\n ...params: unknown[]\n ): Promise<{ rows: Array<Record<string, unknown>> }>;\n}\n\ninterface GroupedMetricTotals {\n totals: CampaignMetricTotals;\n snapshotCount: number;\n usedCampaignRollups: boolean;\n}\n\nfunction groupChannelMix(\n rows: Array<Record<string, unknown>>,\n): Map<string, CampaignChannelMixEntry[]> {\n const grouped = new Map<string, CampaignChannelMixEntry[]>();\n for (const row of rows) {\n const campaignId = normalizeUuid(String(row.campaign_id), 'campaign id');\n const channelKind = String(row.channel_kind);\n if (!channelKind) throw new Error('Campaign channel kind is empty.');\n const entry = {\n channelKind,\n count: toSafeCount(row.channel_count, 'Campaign channel count'),\n };\n const entries = grouped.get(campaignId) ?? [];\n entries.push(entry);\n grouped.set(campaignId, entries);\n }\n return grouped;\n}\n\nfunction groupMetricTotals(\n rows: Array<Record<string, unknown>>,\n): Map<string, GroupedMetricTotals> {\n return new Map(\n rows.map((row) => {\n const campaignId = normalizeUuid(String(row.campaign_id), 'campaign id');\n return [\n campaignId,\n {\n totals: {\n spendCents: toSafeCount(row.spend_cents, 'Campaign spend total'),\n impressions: toSafeCount(\n row.impressions,\n 'Campaign impression total',\n ),\n clicks: toSafeCount(row.clicks, 'Campaign click total'),\n conversions: toSafeCount(\n row.conversions,\n 'Campaign conversion total',\n ),\n leads: toSafeCount(row.leads, 'Campaign lead total'),\n revenueCents: toSafeCount(\n row.revenue_cents,\n 'Campaign revenue total',\n ),\n },\n snapshotCount: toSafeCount(\n row.snapshot_count,\n 'Campaign snapshot count',\n ),\n usedCampaignRollups: toBooleanFlag(row.used_campaign_rollups),\n },\n ];\n }),\n );\n}\n\nfunction emptyMetricTotals(): GroupedMetricTotals {\n return {\n totals: {\n spendCents: 0,\n impressions: 0,\n clicks: 0,\n conversions: 0,\n leads: 0,\n revenueCents: 0,\n },\n snapshotCount: 0,\n usedCampaignRollups: false,\n };\n}\n\nfunction toBooleanFlag(value: unknown): boolean {\n return value === true || value === 1 || value === '1';\n}\n\nfunction checkedAdd(left: number, right: number, label: string): number {\n const sum = left + right;\n if (!Number.isSafeInteger(sum) || sum < 0) {\n throw new Error(`${label} is outside the safe integer range.`);\n }\n return sum;\n}\n\nfunction requireDatabase(options: { db?: unknown }): QueryDatabase {\n const db = options.db;\n if (!db || typeof db !== 'object' || !('query' in db)) {\n throw new Error(\n 'Campaign reporting and summaries require an initialized database connection.',\n );\n }\n return db as QueryDatabase;\n}\n\nfunction coerceDate(value: unknown): Date | null {\n if (value == null) return null;\n const date =\n value instanceof Date\n ? value\n : new Date(typeof value === 'number' ? value : String(value));\n return Number.isNaN(date.getTime()) ? null : date;\n}\n\nfunction toSafeCount(value: unknown, label: string): number {\n const count = Number(value);\n if (!Number.isSafeInteger(count) || count < 0) {\n throw new Error(`${label} is outside the safe integer range.`);\n }\n return count;\n}\n\nfunction normalizeCursor(\n cursor: CampaignCustomerCursorInput | undefined,\n): CampaignCustomerCursor | null {\n if (!cursor) return null;\n const id = normalizeUuid(cursor.id, 'campaign customer cursor id');\n if (cursor.startAt === null) return { id, startAt: null };\n const startAt = coerceDate(cursor.startAt);\n if (!startAt) throw new Error('campaign customer cursor startAt is invalid.');\n return { id, startAt };\n}\n\nfunction normalizeReportingAt(value: Date | string | number | undefined): Date {\n if (value === undefined) return new Date();\n const at = coerceDate(value);\n if (!at) throw new Error('campaign reporting at is invalid.');\n return at;\n}\n\nfunction cursorFromCampaign(\n campaign: Campaign | undefined,\n): CampaignCustomerCursor | null {\n if (!campaign?.id) return null;\n return { id: campaign.id, startAt: campaign.startAt };\n}\n\nfunction normalizeTenantScope(\n tenantId: string | null,\n label: string,\n): string | null {\n if (tenantId !== null) {\n const normalized = normalizeUuid(tenantId, 'tenantId');\n const tenantContext = getCurrentTenant();\n if (tenantContext && !isSuperAdminBypass()) {\n const contextTenantId = normalizeUuid(tenantContext.tenantId, 'tenantId');\n if (normalized !== contextTenantId) {\n throw new TenantIsolationError(\n `Tenant isolation violation in ${label}.`,\n { tenantId: contextTenantId, attemptedTenantId: normalized },\n );\n }\n }\n return normalized;\n }\n const tenantContext = getCurrentTenant();\n if (tenantContext && !isSuperAdminBypass() && !isSystemContext()) {\n throw new TenantIsolationError(\n `Tenant isolation violation in ${label}: tenant context cannot read global Campaign rows.`,\n { tenantId: tenantContext.tenantId, attemptedTenantId: 'global' },\n );\n }\n return null;\n}\n\nfunction withCanonicalTenantContext<T>(\n tenantId: string | null,\n operation: () => Promise<T>,\n): Promise<T> {\n const tenantContext = getCurrentTenant();\n return tenantId !== null &&\n tenantContext &&\n !isSuperAdminBypass() &&\n !isSystemContext()\n ? withTenant({ ...tenantContext, tenantId }, operation)\n : operation();\n}\n\nfunction withCanonicalActiveTenant<T>(operation: () => Promise<T>): Promise<T> {\n const tenantContext = getCurrentTenant();\n if (!tenantContext || isSuperAdminBypass() || isSystemContext()) {\n return operation();\n }\n const normalizedTenantId = normalizeUuid(tenantContext.tenantId, 'tenantId');\n return normalizedTenantId === tenantContext.tenantId\n ? operation()\n : withTenant({ ...tenantContext, tenantId: normalizedTenantId }, operation);\n}\n\nfunction normalizeCampaignGetFilter(\n filter: string | SmrtWhereClause<Campaign>,\n): string | SmrtWhereClause<Campaign> {\n if (typeof filter !== 'string') return normalizeCampaignUuidWhere(filter);\n try {\n return normalizeUuid(filter, 'campaign id');\n } catch {\n return filter;\n }\n}\n\nfunction normalizeCampaignListOptions(\n options: SmrtListOptions<Campaign>,\n): SmrtListOptions<Campaign> {\n return options.where === undefined\n ? options\n : { ...options, where: normalizeCampaignUuidWhere(options.where) };\n}\n\nfunction normalizeCampaignUuidWhere<T>(where: T): T {\n if (Array.isArray(where)) {\n return where.map((entry) => normalizeCampaignUuidWhere(entry)) as T;\n }\n if (!where || typeof where !== 'object') return where;\n\n const normalized: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(where)) {\n const field = key.trim().split(/\\s+/u)[0];\n const label =\n field === 'id'\n ? 'campaign id'\n : field === 'customerId'\n ? 'customerId'\n : field === 'tenantId'\n ? 'tenantId'\n : null;\n if (!label) {\n normalized[key] = value;\n } else if (Array.isArray(value)) {\n normalized[key] = value.map((uuid) =>\n typeof uuid === 'string' ? normalizeUuid(uuid, label) : uuid,\n );\n } else {\n normalized[key] =\n typeof value === 'string' ? normalizeUuid(value, label) : value;\n }\n }\n return normalized as T;\n}\n\nexport default CampaignCollection;\n","import type { SmrtClassOptions } from '@happyvertical/smrt-core';\nimport {\n CampaignChannelCollection,\n CampaignCollection,\n CampaignMetricSnapshotCollection,\n} from '../collections/index.js';\nimport type { CampaignMetricSnapshot } from '../models/CampaignMetricSnapshot.js';\nimport type { BudgetPacingResult } from '../types.js';\nimport {\n calculateCampaignPacing,\n calculatePacing,\n} from './pacing-calculation.js';\n\n/** Computes spend-to-budget pacing from immutable snapshots; stores nothing. */\nexport class BudgetPacingService {\n constructor(\n private readonly campaigns: CampaignCollection,\n private readonly channels: CampaignChannelCollection,\n private readonly snapshots: CampaignMetricSnapshotCollection,\n ) {}\n\n static async create(\n classOptions: SmrtClassOptions = {},\n ): Promise<BudgetPacingService> {\n return new BudgetPacingService(\n await CampaignCollection.create(classOptions),\n await CampaignChannelCollection.create(classOptions),\n await CampaignMetricSnapshotCollection.create(classOptions),\n );\n }\n\n async getCampaignPacing(\n campaignId: string,\n at = new Date(),\n ): Promise<BudgetPacingResult> {\n const campaign = await this.campaigns.get({ id: campaignId });\n if (!campaign) throw new Error(`Campaign '${campaignId}' was not found.`);\n\n const all = await this.snapshots.findByCampaign(campaignId);\n const rollups = all.filter((snapshot) => !snapshot.campaignChannelId);\n const used = this.selectCampaignEvidence(all);\n return calculateCampaignPacing(\n campaign,\n {\n spendCents: used.reduce(\n (sum, snapshot) => sum + snapshot.spendCents,\n 0,\n ),\n snapshotCount: used.length,\n usedCampaignRollups: rollups.length > 0,\n },\n at,\n );\n }\n\n async getChannelPacing(\n campaignChannelId: string,\n at = new Date(),\n ): Promise<BudgetPacingResult> {\n const channel = await this.channels.get({ id: campaignChannelId });\n if (!channel) {\n throw new Error(`CampaignChannel '${campaignChannelId}' was not found.`);\n }\n const campaign = await this.campaigns.get({ id: channel.campaignId });\n if (!campaign) {\n throw new Error(`Campaign '${channel.campaignId}' was not found.`);\n }\n const snapshots = await this.snapshots.findByChannel(campaignChannelId);\n return {\n ...calculatePacing({\n campaign,\n evidence: {\n spendCents: snapshots.reduce(\n (sum, snapshot) => sum + snapshot.spendCents,\n 0,\n ),\n snapshotCount: snapshots.length,\n usedCampaignRollups: false,\n },\n budgetCents: channel.allocatedBudgetCents,\n startAt: channel.startAt ?? campaign.startAt,\n endAt: channel.endAt ?? campaign.endAt,\n at,\n }),\n campaignChannelId,\n };\n }\n\n /**\n * Prefer a campaign rollup for each exact reporting period, while retaining\n * channel evidence for periods that do not yet have a rollup. This prevents\n * double counting without dropping earlier/later channel-only periods.\n */\n private selectCampaignEvidence(\n snapshots: CampaignMetricSnapshot[],\n ): CampaignMetricSnapshot[] {\n const rollupPeriods = new Set(\n snapshots\n .filter((snapshot) => !snapshot.campaignChannelId)\n .map((snapshot) => this.periodKey(snapshot)),\n );\n return snapshots.filter(\n (snapshot) =>\n !snapshot.campaignChannelId ||\n !rollupPeriods.has(this.periodKey(snapshot)),\n );\n }\n\n private periodKey(snapshot: CampaignMetricSnapshot): string {\n return `${snapshot.periodStart.toISOString()}:${snapshot.periodEnd.toISOString()}`;\n }\n}\n\nexport default BudgetPacingService;\n","import type { SmrtClassOptions } from '@happyvertical/smrt-core';\nimport { CampaignCollection } from '../collections/CampaignCollection.js';\nimport type { Campaign } from '../models/Campaign.js';\nimport type { CampaignStatus } from '../types.js';\n\n/** Single authoritative write path for Campaign lifecycle changes. */\nexport class CampaignLifecycleService {\n constructor(private readonly campaigns: CampaignCollection) {}\n\n static async create(\n classOptions: SmrtClassOptions = {},\n ): Promise<CampaignLifecycleService> {\n return new CampaignLifecycleService(\n await CampaignCollection.create(classOptions),\n );\n }\n\n async transition(\n campaignId: string,\n next: CampaignStatus,\n ): Promise<Campaign> {\n const campaign = await this.campaigns.get({ id: campaignId });\n if (!campaign) throw new Error(`Campaign '${campaignId}' was not found.`);\n campaign.transitionTo(next);\n await campaign.save();\n return campaign;\n }\n\n async schedule(campaignId: string): Promise<Campaign> {\n return await this.transition(campaignId, 'scheduled');\n }\n\n async activate(campaignId: string): Promise<Campaign> {\n return await this.transition(campaignId, 'active');\n }\n\n async pause(campaignId: string): Promise<Campaign> {\n return await this.transition(campaignId, 'paused');\n }\n\n async resume(campaignId: string): Promise<Campaign> {\n return await this.transition(campaignId, 'active');\n }\n\n async complete(campaignId: string): Promise<Campaign> {\n return await this.transition(campaignId, 'completed');\n }\n\n async archive(campaignId: string): Promise<Campaign> {\n return await this.transition(campaignId, 'archived');\n }\n}\n\nexport default CampaignLifecycleService;\n","import type { SmrtClassOptions } from '@happyvertical/smrt-core';\nimport { CampaignMetricSnapshotCollection } from '../collections/CampaignMetricSnapshotCollection.js';\nimport type { CampaignMetricSnapshot } from '../models/CampaignMetricSnapshot.js';\nimport type { CampaignMetricSnapshotOptions } from '../types.js';\n\n/** Idempotent, validation-first ingestion for immutable metric evidence. */\nexport class MetricIngestionService {\n constructor(private readonly snapshots: CampaignMetricSnapshotCollection) {}\n\n static async create(\n classOptions: SmrtClassOptions = {},\n ): Promise<MetricIngestionService> {\n return new MetricIngestionService(\n await CampaignMetricSnapshotCollection.create(classOptions),\n );\n }\n\n async ingest(\n options: CampaignMetricSnapshotOptions,\n ): Promise<{ snapshot: CampaignMetricSnapshot; created: boolean }> {\n if (!options.campaignId) {\n throw new Error('Metric ingestion requires campaignId.');\n }\n if (!options.source?.trim()) {\n throw new Error('Metric ingestion requires source.');\n }\n if (!options.dedupeKey?.trim()) {\n throw new Error('Metric ingestion requires dedupeKey.');\n }\n if (options.periodStart == null || options.periodEnd == null) {\n throw new Error('Metric ingestion requires periodStart and periodEnd.');\n }\n return await this.snapshots.getOrCreateByDedupeKey(options);\n }\n}\n\nexport default MetricIngestionService;\n"],"mappings":";;;;AAOA,eAAe,wBAAwB,KAAK,MAAM,wt3BAA85+B,CAAC;;;ACN18+B,IAAM,6BAAN,cAAyC,MAAM;CAC3C,OAAO;CAEhB,YAAY,OAAe;EACzB,MAAM,GAAG,MAAK,oCAAqC;EACnD,KAAK,OAAO;CACd;AACF;;;ACAA,IAAM,0BAA0B;AAChC,IAAM,sBAAsB;AAC5B,IAAM,UACJ;AAQF,SAAS,kBAAgB,SAAyC;CAChE,MAAM,KAAK,QAAQ;CACnB,IAAI,CAAC,MAAM,OAAO,OAAO,YAAY,EAAE,WAAW,KAChD,MAAM,IAAI,MACR,uEACF;CAEF,OAAO;AACT;AAEA,eAAe,qBAAqB,SAA2C;CAC7E,MAAM,eAAe,qBAAqB,uBAAuB;CACjE,MAAM,SACJ,eAAe,wBAAwB,uBAAuB,KAC9D,eAAe,SAAS,uBAAuB;CACjD,IAAI,CAAC,QACH,MAAM,IAAI,MACR,2FACF;CAIF,MAAM,YAAY,IADA,OAAO,YAAY,OACnB,CAAA,CAAM;CACxB,IAAI,CAAC,oBAAoB,KAAK,SAAS,GACrC,MAAM,IAAI,MAAM,oDAAoD;CAEtE,OAAO;AACT;AAOA,eAAsB,8BACpB,SACA,UACA,aACA,OACA,OAAoC,QACrB;CACf,IAAI,YAAY,WAAW,GAAG;CAC9B,MAAM,wBAAwB,YAAY,KAAK,eAAe;EAC5D,IAAI;GACF,OAAO,cAAc,YAAY,YAAY;EAC/C,QAAQ;GACN,MAAM,IAAI,2BAA2B,KAAK;EAC5C;CACF,CAAC;CACD,MAAM,qBAAqB,UAAU,YAAY,KAAK;CACtD,MAAM,KAAK,kBAAgB,OAAO;CAClC,MAAM,YAAY,MAAM,qBAAqB,OAAO;CACpD,MAAM,eAAe,sBAAsB,UAAU,GAAG,CAAA,CAAE,KAAK,IAAI;CACnE,MAAM,aAAa,mBAAmB,IAAI,IAAI;CAC9C,MAAM,SAAS,MAAM,GAAG,MACtB,6BAA6B,UAAS,gBAAiB,aAAY,GAAI,cACvE,GAAG,qBACL;CACA,MAAM,aAAa,IAAI,IACrB,OAAO,KAAK,KAAK,QAAQ,CACvB,OAAO,IAAI,EAAE,CAAA,CAAE,YAAY,GAC3B,IAAI,aAAa,OAAO,OAAO,OAAO,IAAI,SAAS,CAAA,CAAE,YAAY,CACnE,CAAC,CACH;CAMA,IAAI,CALU,sBAAsB,OACjC,eACC,WAAW,IAAI,UAAU,KACzB,WAAW,IAAI,UAAU,MAAM,kBAE9B,GACH,MAAM,IAAI,2BAA2B,KAAK;AAE9C;AAEA,SAAS,mBACP,IACA,MACQ;CACR,IAAI,SAAS,UAAU,CAAC,sBAAsB,KAAK,GAAG,GAAG,GAAG,OAAO;CACnE,OAAO,SAAS,WAAW,gBAAgB;AAC7C;AAGO,SAAS,cAAc,OAAe,OAAuB;CAClE,IAAI,CAAC,QAAQ,KAAK,KAAK,GACrB,MAAM,IAAI,MAAM,GAAG,MAAK,2BAA4B;CAEtD,OAAO,MAAM,YAAY;AAC3B;;;;;;;;;;;;;;;;;;AC9EA,IAAM,8BAAwE;CAC5E,OAAO,CAAC,WAAW;CACnB,WAAW,CAAC,QAAQ;CACpB,QAAQ,CAAC,UAAU,WAAW;CAC9B,QAAQ,CAAC,UAAU,WAAW;CAC9B,WAAW,CAAC,UAAU;CACtB,UAAU,CAAC;AACb;AAEA,IAAM,uCAAuB,IAAI,QAAkC;AAgB5D,IAAM,WAAN,cAAuB,WAAW;CAEvC,WAA0B;CAO1B,aAA4B;CAI5B,cAAsB;CAGtB,OAAe;;CAGf,YAAoB;CAEpB,SAAyB;CAEzB,UAAuB;CAEvB,QAAqB;;CAGrB,cAAsB;;CAGtB,WAAmB;CAEnB,WAAmB;CAEnB,YAAY,UAA2B,CAAC,GAAG;EACzC,MAAM,OAAO;EACb,IAAI,QAAQ,aAAa,KAAA,GAAW,KAAK,WAAW,QAAQ;EAC5D,IAAI,QAAQ,eAAe,KAAA,GAAW,KAAK,aAAa,QAAQ;EAChE,IAAI,QAAQ,gBAAgB,KAAA,GAC1B,KAAK,cAAc,QAAQ;EAC7B,IAAI,QAAQ,SAAS,KAAA,GAAW,KAAK,OAAO,QAAQ;EACpD,IAAI,QAAQ,cAAc,KAAA,GAAW,KAAK,YAAY,QAAQ;EAC9D,IAAI,QAAQ,WAAW,KAAA,GAAW,KAAK,SAAS,QAAQ;EACxD,IAAI,QAAQ,YAAY,KAAA,GACtB,KAAK,UAAU,SAAS,WAAW,QAAQ,OAAO;EACpD,IAAI,QAAQ,UAAU,KAAA,GACpB,KAAK,QAAQ,SAAS,WAAW,QAAQ,KAAK;EAChD,IAAI,QAAQ,gBAAgB,KAAA,GAC1B,KAAK,cAAc,QAAQ;EAC7B,IAAI,QAAQ,aAAa,KAAA,GAAW,KAAK,WAAW,QAAQ;EAC5D,IAAI,QAAQ,aAAa,KAAA,GAAW,KAAK,WAAW,QAAQ;CAC9D;CAEA,MAAe,aAA4B;EACzC,IAAI,KAAK,IACP,IAAI;GACF,KAAK,KAAK,cAAc,KAAK,IAAI,IAAI;EACvC,SAAS,OAAO;GACd,IAAI,KAAK,eAAe,MACtB,MAAM,IAAI,2BAA2B,qBAAqB;GAE5D,MAAM;EACR;EAEF,MAAM,MAAM,WAAW;EACvB,KAAK,UAAU,SAAS,WAAW,KAAK,OAAO;EAC/C,KAAK,QAAQ,SAAS,WAAW,KAAK,KAAK;EAC3C,IAAI,KAAK,aAAa,qBAAqB,IAAI,MAAM,KAAK,MAAM;EAChE,OAAO;CACT;CAEA,MAAe,OAAsB;EACnC,IAAI,KAAK,eAAe,MAAM,OAAO,KAAK,cAAc;EAExD,MAAM,KAAK,KAAK;EAChB,IAAI,OAAO,GAAG,gBAAgB,YAC5B,MAAM,IAAI,MACR,qEACF;EAEF,OAAO,GAAG,YAAY,OAAO,kBAC3B,KAAK,aAAa,eAAe,OAAO,UAAU,MAAM,cAAc,CAAC,CACzE;CACF;CAEA,MAAc,gBAA+B;EAC3C,KAAK,uBAAuB;EAC5B,IAAI,KAAK,eAAe,MACtB,MAAM,8BACJ,KAAK,SACL,KAAK,UACL,CAAC,KAAK,UAAU,GAChB,iBACA,QACF;EAEF,MAAM,QAAQ,MAAM,KAAK,mBAAmB;EAC5C,KAAK,uBAAuB,KAAK;EACjC,KAAK,eAAe;EACpB,IAAI;EACJ,IAAI;GACF,MAAM,UAAU,YAAa,MAAM,MAAM,KAAK;GAC9C,MAAM,gBACJ,gBAAgB,KAAK,mBAAmB,IACpC,KAAA,IACA,iBAAiB;GACvB,SAAS,gBACL,MAAM,WACJ;IACE,GAAG;IACH,UAAU,KAAK,YAAY,cAAc;GAC3C,GACA,OACF,IACA,MAAM,QAAQ;EACpB,SAAS,OAAO;GACd,IACE,iBAAiB,oBAChB,MAAM,SAAS,0CACd,MAAM,SAAS,8CAEjB,MAAM,IAAI,2BAA2B,eAAe;GAEtD,MAAM;EACR;EACA,qBAAqB,IAAI,MAAM,KAAK,MAAM;EAC1C,OAAO;CACT;;CAGQ,yBAA+B;EACrC,IAAI;GACF,IAAI,KAAK,IAAI,KAAK,KAAK,cAAc,KAAK,IAAI,IAAI;GAClD,IAAI,KAAK,eAAe,MACtB,KAAK,aAAa,cAAc,KAAK,YAAY,YAAY;GAE/D,IAAI,KAAK,aAAa,MACpB,KAAK,WAAW,cAAc,KAAK,UAAU,UAAU;EAE3D,SAAS,OAAO;GACd,IAAI,KAAK,eAAe,MACtB,MAAM,IAAI,2BAA2B,eAAe;GAEtD,MAAM;EACR;EAEA,IAAI,gBAAgB,KAAK,mBAAmB,GAAG;EAC/C,MAAM,gBAAgB,iBAAiB;EACvC,IAAI,CAAC,eAAe;EAEpB,IAAI;EACJ,IAAI;GACF,kBAAkB,cAAc,cAAc,UAAU,UAAU;EACpE,SAAS,OAAO;GACd,IAAI,KAAK,eAAe,MACtB,MAAM,IAAI,2BAA2B,eAAe;GAEtD,MAAM;EACR;EACA,IAAI,KAAK,aAAa,QAAQ,KAAK,aAAa,iBAC9C,MAAM,IAAI,qBACR,gDACA;GAAE,UAAU;GAAiB,mBAAmB,KAAK;EAAS,CAChE;EAEF,KAAK,WAAW;CAClB;;CAGA,aAAa,MAA4B;EACvC,IAAI,SAAS,KAAK,QAAQ,OAAO;EAEjC,IAAI,EADY,4BAA4B,KAAK,WAAW,CAAC,EAAA,CAChD,SAAS,IAAI,GACxB,MAAM,IAAI,MACR,YAAY,KAAK,eAAe,KAAK,GAAE,uBACjC,KAAK,OAAM,YAAQ,KAAI,GAC/B;EAEF,KAAK,SAAS;EACd,OAAO;CACT;CAEA,cAAuC;EACrC,IAAI,CAAC,KAAK,UAAU,OAAO,CAAC;EAC5B,IAAI;GACF,MAAM,SAAS,KAAK,MAAM,KAAK,QAAQ;GACvC,OAAO,UAAU,OAAO,WAAW,YAAY,CAAC,MAAM,QAAQ,MAAM,IAC/D,SACD,CAAC;EACP,QAAQ;GACN,OAAO,CAAC;EACV;CACF;CAEA,YAAY,UAAyC;EACnD,KAAK,WAAW,KAAK,UAAU,YAAY,CAAC,CAAC;CAC/C;CAEQ,iBAAuB;EAC7B,IACE,KAAK,WACL,KAAK,SACL,KAAK,MAAM,QAAQ,IAAI,KAAK,QAAQ,QAAQ,GAE5C,MAAM,IAAI,MAAM,6CAA6C;EAE/D,IAAI,CAAC,OAAO,UAAU,KAAK,WAAW,KAAK,KAAK,cAAc,GAC5D,MAAM,IAAI,MAAM,sDAAsD;CAE1E;CAEA,MAAc,qBAA0D;EACtE,IAAI,KAAK,IAAI;GACX,IAAI,YAA4C;GAChD,IAAI;IACF,YAAY,MAAM,KAAK,GAAG,IAAI,KAAK,WAAW;KAC5C,IAAI,KAAK;KACT,WAAW,KAAK;IAClB,CAAC;GACH,QAAQ,CAER;GACA,IAAI,WAAW,UAAU,MACvB,OAAO,UAAU;GAKnB,IAAI,mBAAmD;GACvD,IAAI;IACF,mBAAmB,MAAM,KAAK,GAAG,IAAI,KAAK,WAAW,EAAE,IAAI,KAAK,GAAG,CAAC;GACtE,QAAQ,CAER;GACA,IAAI,kBACF,MAAM,IAAI,2BAA2B,eAAe;EAExD;EACA,IAAI,KAAK,aACP,IAAI;GACF,MAAM,MAAM,MAAM,KAAK,GAAG,IAAI,KAAK,WAAW;IAC5C,WAAW,KAAK;IAChB,cAAc,KAAK;GACrB,CAAC;GACD,IAAI,OAAO,IAAI,UAAU,MAAM,OAAO,IAAI;EAC5C,QAAQ,CAER;EAEF,OAAO,qBAAqB,IAAI,IAAI;CACtC;CAEQ,uBAAuB,OAAyC;EACtE,IAAI,CAAC,kBAAkB,SAAS,KAAK,MAAM,GACzC,MAAM,IAAI,MACR,YAAY,KAAK,eAAe,KAAK,GAAE,oBAAqB,KAAK,OAAM,GACzE;EAEF,IAAI,UAAU,KAAA,KAAa,UAAU,KAAK,QAAQ;EAElD,IAAI,EADY,4BAA4B,UAAU,CAAC,EAAA,CAC1C,SAAS,KAAK,MAAM,GAC/B,MAAM,IAAI,MACR,YAAY,KAAK,eAAe,KAAK,GAAE,+BACjC,MAAK,YAAQ,KAAK,OAAM,GAChC;CAEJ;CAEA,OAAe,WAAW,OAA6B;EACrD,IAAI,SAAS,MAAM,OAAO;EAC1B,IAAI,iBAAiB,MAAM,OAAO;EAClC,IAAI,OAAO,UAAU,YAAY,OAAO,UAAU,UAAU;GAC1D,MAAM,OAAO,IAAI,KAAK,KAAK;GAC3B,OAAO,OAAO,MAAM,KAAK,QAAQ,CAAC,IAAI,OAAO;EAC/C;EACA,OAAO;CACT;AACF;AAtR2C,gBAA9B,UAAqC,mBAAkB,+BAAA;AAElE,kBAAA,CADC,SAAS,EAAE,UAAU,KAAK,CAAC,CAAA,GADjB,SAEX,WAAA,YAAA,CAAA;AAOA,kBAAA,CAJC,gBAAgB,yCAAyC;CACxD,UAAU;CACV,UAAU;AACZ,CAAC,CAAA,GARU,SASX,WAAA,cAAA,CAAA;AAIA,kBAAA,CADC,MAAM,EAAE,UAAU,KAAK,CAAC,CAAA,GAZd,SAaX,WAAA,eAAA,CAAA;AAGA,kBAAA,CADC,MAAM,EAAE,UAAU,KAAK,CAAC,CAAA,GAfd,SAgBX,WAAA,QAAA,CAAA;AAhBW,WAAN,kBAAA,CAdN,aAAa,EAAE,MAAM,WAAW,CAAC,GACjC,KAAK;CACJ,WAAW;CACX,iBAAiB,CAAC,aAAa,cAAc;CAC7C,SAAS,CACP;EACE,MAAM;EACN,SAAS;GAAC;GAAY;GAAc;GAAW;EAAI;CACrD,CACF;CACA,KAAK,EAAE,SAAS;EAAC;EAAQ;EAAO;EAAU;CAAQ,EAAE;CACpD,KAAK,EAAE,SAAS;EAAC;EAAQ;EAAO;EAAU;CAAQ,EAAE;CACpD,KAAK,EAAE,SAAS;EAAC;EAAQ;EAAO;EAAU;CAAQ,EAAE;AACtD,CAAC,CAAA,GACY,QAAA;;;;;;;;;;;;;;;;;;ACnCN,IAAM,kBAAN,cAA8B,WAAW;CAE9C,WAA0B;CAG1B,aAAqB;CAIrB,cAAsB;CAItB,aAAqB;CAErB,uBAA+B;;CAG/B,UAAuB;;CAGvB,QAAqB;CAErB,SAAgC;CAEhC,YAAY,UAAkC,CAAC,GAAG;EAChD,MAAM,OAAO;EACb,IAAI,QAAQ,aAAa,KAAA,GAAW,KAAK,WAAW,QAAQ;EAC5D,IAAI,QAAQ,eAAe,KAAA,GAAW,KAAK,aAAa,QAAQ;EAChE,IAAI,QAAQ,gBAAgB,KAAA,GAC1B,KAAK,cAAc,QAAQ;EAC7B,IAAI,QAAQ,eAAe,KAAA,GAAW,KAAK,aAAa,QAAQ;EAChE,IAAI,QAAQ,yBAAyB,KAAA,GACnC,KAAK,uBAAuB,QAAQ;EACtC,IAAI,QAAQ,YAAY,KAAA,GACtB,KAAK,UAAU,gBAAgB,WAAW,QAAQ,OAAO;EAC3D,IAAI,QAAQ,UAAU,KAAA,GACpB,KAAK,QAAQ,gBAAgB,WAAW,QAAQ,KAAK;EACvD,IAAI,QAAQ,WAAW,KAAA,GAAW,KAAK,SAAS,QAAQ;CAC1D;CAEA,MAAe,aAA4B;EACzC,MAAM,MAAM,WAAW;EACvB,KAAK,UAAU,gBAAgB,WAAW,KAAK,OAAO;EACtD,KAAK,QAAQ,gBAAgB,WAAW,KAAK,KAAK;EAClD,OAAO;CACT;CAEA,MAAe,OAAsB;EACnC,IAAI,CAAC,0BAA0B,SAAS,KAAK,MAAM,GACjD,MAAM,IAAI,MACR,mBAAmB,KAAK,cAAc,KAAK,GAAE,oBAAqB,KAAK,OAAM,GAC/E;EAEF,IACE,CAAC,OAAO,UAAU,KAAK,oBAAoB,KAC3C,KAAK,uBAAuB,GAE5B,MAAM,IAAI,MACR,sEACF;EAEF,IACE,KAAK,WACL,KAAK,SACL,KAAK,MAAM,QAAQ,IAAI,KAAK,QAAQ,QAAQ,GAE5C,MAAM,IAAI,MAAM,oDAAoD;EAEtE,OAAQ,MAAM,MAAM,KAAK;CAC3B;CAEA,OAAe,WAAW,OAA6B;EACrD,IAAI,SAAS,MAAM,OAAO;EAC1B,IAAI,iBAAiB,MAAM,OAAO;EAClC,IAAI,OAAO,UAAU,YAAY,OAAO,UAAU,UAAU;GAC1D,MAAM,OAAO,IAAI,KAAK,KAAK;GAC3B,OAAO,OAAO,MAAM,KAAK,QAAQ,CAAC,IAAI,OAAO;EAC/C;EACA,OAAO;CACT;AACF;AAjFkD,gBAArC,iBAA4C,mBAAkB,+BAAA;AAEzE,kBAAA,CADC,SAAS,EAAE,UAAU,KAAK,CAAC,CAAA,GADjB,gBAEX,WAAA,YAAA,CAAA;AAGA,kBAAA,CADC,WAAW,UAAU,EAAE,UAAU,KAAK,CAAC,CAAA,GAJ7B,gBAKX,WAAA,cAAA,CAAA;AAIA,kBAAA,CADC,MAAM,EAAE,UAAU,KAAK,CAAC,CAAA,GARd,gBASX,WAAA,eAAA,CAAA;AAIA,kBAAA,CADC,MAAM,EAAE,UAAU,KAAK,CAAC,CAAA,GAZd,gBAaX,WAAA,cAAA,CAAA;AAbW,kBAAN,kBAAA,CARN,aAAa,EAAE,MAAM,WAAW,CAAC,GACjC,KAAK;CACJ,WAAW;CACX,iBAAiB;EAAC;EAAe;EAAgB;CAAa;CAC9D,KAAK,EAAE,SAAS;EAAC;EAAQ;EAAO;EAAU;EAAU;CAAQ,EAAE;CAC9D,KAAK,EAAE,SAAS;EAAC;EAAQ;EAAO;EAAU;CAAQ,EAAE;CACpD,KAAK,EAAE,SAAS;EAAC;EAAQ;EAAO;EAAU;EAAU;CAAQ,EAAE;AAChE,CAAC,CAAA,GACY,eAAA;;;AChBN,IAAM,4BAAN,cAAwC,eAAgC;CAC7E,OAAgB,aAAa;CAE7B,MAAM,eAAe,YAAgD;EACnE,OAAO,MAAM,KAAK,KAAK;GACrB,OAAO,EAAE,WAAW;GACpB,SAAS;EACX,CAAC;CACH;CAEA,MAAM,mBACJ,aACA,YAC4B;EAC5B,OAAO,MAAM,KAAK,KAAK,EAAE,OAAO;GAAE;GAAa;EAAW,EAAE,CAAC;CAC/D;AACF;;;ACTO,SAAS,wBACd,UACA,UACA,qBAAK,IAAI,KAAK,GACM;CACpB,OAAO,gBAAgB;EACrB;EACA;EACA,aAAa,SAAS;EACtB,SAAS,SAAS;EAClB,OAAO,SAAS;EAChB;CACF,CAAC;AACH;AAEO,SAAS,gBAAgB,EAC9B,UACA,UACA,aACA,SACA,OACA,MAQqB;CACrB,MAAM,UAAU,gBAAgB,SAAS,OAAO,EAAE;CAClD,MAAM,qBACJ,YAAY,OAAO,OAAO,KAAK,MAAM,cAAc,OAAO;CAC5D,MAAM,gBACJ,uBAAuB,OACnB,OACA,SAAS,aAAa;CAC5B,OAAO;EACL,YAAY,SAAS,MAAM;EAC3B,UAAU,SAAS;EACnB;EACA,YAAY,SAAS;EACrB,gBAAgB,cAAc,SAAS;EACvC;EACA;EACA,gBAAgB,cAAc,IAAI,SAAS,aAAa,cAAc;EACtE,iBAAiB;EACjB,QAAQ,aAAa;GACnB;GACA;GACA,YAAY,SAAS;GACrB,iBAAiB;GACjB;GACA;GACA;EACF,CAAC;EACD,eAAe,SAAS;EACxB,qBAAqB,SAAS;CAChC;AACF;AAEA,SAAS,aAAa,EACpB,UACA,aACA,YACA,iBAAAA,kBACA,eACA,SACA,MASqB;CACrB,IAAI,eAAe,GAAG,OAAO;CAC7B,IAAI,aAAa,aAAa,OAAO;CACrC,IAAI,WAAW,GAAG,QAAQ,IAAI,QAAQ,QAAQ,GAAG,OAAO;CACxD,IACE,SAAS,WAAW,eACpB,SAAS,WAAW,cACpBA,qBAAoB,GAEpB,OAAO;CAET,IAAI,kBAAkB,MAAM,OAAO;CAInC,MAAM,iBAAiB,KAAK,IAAI,GAAG,KAAK,MAAM,cAAc,GAAI,CAAC;CACjE,IAAI,gBAAgB,gBAAgB,OAAO;CAC3C,IAAI,gBAAgB,CAAC,gBAAgB,OAAO;CAC5C,OAAO;AACT;AAEA,SAAS,gBACP,SACA,OACA,IACe;CACf,IAAI,CAAC,WAAW,CAAC,OAAO,OAAO;CAC/B,MAAM,QAAQ,QAAQ,QAAQ;CAC9B,MAAM,MAAM,MAAM,QAAQ;CAC1B,IAAI,OAAO,OAAO,OAAO,GAAG,QAAQ,IAAI,QAAQ,IAAI;CACpD,OAAO,KAAK,IAAI,GAAG,KAAK,IAAI,IAAI,GAAG,QAAQ,IAAI,UAAU,MAAM,MAAM,CAAC;AACxE;;;;;;;;;;;;;;;;;;AC9GA,IAAM,yCAAyB,IAAI,QAAwC;AAUpE,IAAM,yBAAN,cAAqC,WAAW;CAErD,WAA0B;CAG1B,aAAqB;CAIrB,oBAAmC;CAGnC,8BAAoB,IAAI,KAAK;CAG7B,4BAAkB,IAAI,KAAK;CAE3B,aAAqB;CAErB,cAAsB;CAEtB,SAAiB;CAEjB,cAAsB;CAEtB,QAAgB;CAGhB,eAA8B;CAI9B,SAAiB;CAGjB,YAAoB;CAEpB,YAAY,UAAyC,CAAC,GAAG;EACvD,MAAM,OAAO;EACb,IAAI,QAAQ,aAAa,KAAA,GAAW,KAAK,WAAW,QAAQ;EAC5D,IAAI,QAAQ,eAAe,KAAA,GAAW,KAAK,aAAa,QAAQ;EAChE,IAAI,QAAQ,sBAAsB,KAAA,GAChC,KAAK,oBAAoB,QAAQ;EACnC,IAAI,QAAQ,gBAAgB,KAAA,GAC1B,KAAK,cACH,uBAAuB,WAAW,QAAQ,WAAW,qBACrD,IAAI,KAAK,GAAU;EACvB,IAAI,QAAQ,cAAc,KAAA,GACxB,KAAK,YACH,uBAAuB,WAAW,QAAQ,SAAS,qBACnD,IAAI,KAAK,GAAU;EACvB,IAAI,QAAQ,eAAe,KAAA,GAAW,KAAK,aAAa,QAAQ;EAChE,IAAI,QAAQ,gBAAgB,KAAA,GAC1B,KAAK,cAAc,QAAQ;EAC7B,IAAI,QAAQ,WAAW,KAAA,GAAW,KAAK,SAAS,QAAQ;EACxD,IAAI,QAAQ,gBAAgB,KAAA,GAC1B,KAAK,cAAc,QAAQ;EAC7B,IAAI,QAAQ,UAAU,KAAA,GAAW,KAAK,QAAQ,QAAQ;EACtD,IAAI,QAAQ,iBAAiB,KAAA,GAC3B,KAAK,eAAe,QAAQ;EAC9B,IAAI,QAAQ,WAAW,KAAA,GAAW,KAAK,SAAS,QAAQ;EACxD,IAAI,QAAQ,cAAc,KAAA,GAAW,KAAK,YAAY,QAAQ;CAChE;CAEA,MAAe,aAA4B;EACzC,MAAM,MAAM,WAAW;EACvB,KAAK,cACH,uBAAuB,WAAW,KAAK,WAAW,qBAClD,IAAI,KAAK,GAAU;EACrB,KAAK,YACH,uBAAuB,WAAW,KAAK,SAAS,qBAAK,IAAI,KAAK,GAAU;EAC1E,IAAI,KAAK,aACP,uBAAuB,IAAI,MAAM,KAAK,eAAe,CAAC;EAExD,OAAO;CACT;CAEA,MAAe,OAAsB;EACnC,KAAK,cAAc;EACnB,MAAM,KAAK,6BAA6B;EACxC,MAAM,WAAW,uBAAuB,IAAI,IAAI;EAChD,IAAI,aAAa,KAAA;OACX,aAAa,KAAK,eAAe,GACnC,MAAM,IAAI,MACR,0BAA0B,KAAK,MAAM,QAAO,iFAE9C;EAAA,OAEJ,IAAW,KAAK,MAAO,MAAM,KAAK,QAAQ,GACxC,MAAM,IAAI,MACR,0BAA0B,KAAK,GAAE,6GAEnC;OACF,IAAW,KAAK,WACd,IAAI;GACF,MAAM,MAAM,MAAM,KAAK,GAAG,IAAI,KAAK,WAAW,EAC5C,YAAY,KAAK,UACnB,CAAC;GACD,IAAI,OAAO,IAAI,OAAO,KAAK,IACzB,MAAM,IAAI,MACR,sCAAsC,KAAK,UAAS,yGAGtD;EAEJ,SAAS,OAAO;GACd,IACE,iBAAiB,SACjB,MAAM,QAAQ,SAAS,sBAAsB,GAE7C,MAAM;EAGV;EAGF,MAAM,SAAU,MAAM,MAAM,KAAK;EACjC,uBAAuB,IAAI,MAAM,KAAK,eAAe,CAAC;EACtD,OAAO;CACT;CAEA,MAAe,SAAwB;EACrC,MAAM,IAAI,MACR,0BAA0B,KAAK,MAAM,QAAO,iEAE9C;CACF;CAEQ,gBAAsB;EAC5B,IACE,OAAO,MAAM,KAAK,YAAY,QAAQ,CAAC,KACvC,OAAO,MAAM,KAAK,UAAU,QAAQ,CAAC,GAErC,MAAM,IAAI,MACR,uEACF;EAEF,IAAI,KAAK,UAAU,QAAQ,IAAI,KAAK,YAAY,QAAQ,GACtD,MAAM,IAAI,MACR,mEACF;EAEF,MAAM,iBAA0C;GAC9C,CAAC,cAAc,KAAK,UAAU;GAC9B,CAAC,eAAe,KAAK,WAAW;GAChC,CAAC,UAAU,KAAK,MAAM;GACtB,CAAC,eAAe,KAAK,WAAW;GAChC,CAAC,SAAS,KAAK,KAAK;EACtB;EACA,KAAA,MAAW,CAAC,MAAM,UAAU,gBAC1B,IAAI,CAAC,OAAO,UAAU,KAAK,KAAK,QAAQ,GACtC,MAAM,IAAI,MAAM,GAAG,KAAI,iCAAkC;EAG7D,IACE,KAAK,iBAAiB,SACrB,CAAC,OAAO,UAAU,KAAK,YAAY,KAAK,KAAK,eAAe,IAE7D,MAAM,IAAI,MAAM,sDAAsD;CAE1E;CAEA,MAAc,+BAA8C;EAC1D,IAAI,CAAC,KAAK,mBAAmB;EAI7B,KAAI,MAHmB,KAAK,YAC1B,mBACF,EAAA,CACY,eAAe,KAAK,YAC9B,MAAM,IAAI,MACR,6CAA6C,KAAK,kBAAiB,mCAC/B,KAAK,WAAU,GACrD;CAEJ;CAEQ,iBAAyB;EAC/B,OAAO,KAAK,UAAU;GACpB,UAAU,KAAK;GACf,YAAY,KAAK;GACjB,mBAAmB,KAAK;GACxB,aAAa,KAAK,YAAY,YAAY;GAC1C,WAAW,KAAK,UAAU,YAAY;GACtC,YAAY,KAAK;GACjB,aAAa,KAAK;GAClB,QAAQ,KAAK;GACb,aAAa,KAAK;GAClB,OAAO,KAAK;GACZ,cAAc,KAAK;GACnB,QAAQ,KAAK;GACb,WAAW,KAAK;EAClB,CAAC;CACH;CAEA,OAAe,WAAW,OAA6B;EACrD,IAAI,iBAAiB,MACnB,OAAO,OAAO,MAAM,MAAM,QAAQ,CAAC,IAAI,OAAO;EAEhD,IAAI,OAAO,UAAU,YAAY,OAAO,UAAU,UAAU;GAC1D,MAAM,OAAO,IAAI,KAAK,KAAK;GAC3B,OAAO,OAAO,MAAM,KAAK,QAAQ,CAAC,IAAI,OAAO;EAC/C;EACA,OAAO;CACT;AACF;AA3MyD,cAA5C,wBAAmD,mBAAkB,+BAAA;AAEhF,gBAAA,CADC,SAAS,EAAE,UAAU,KAAK,CAAC,CAAA,GADjB,uBAEX,WAAA,YAAA,CAAA;AAGA,gBAAA,CADC,WAAW,UAAU,EAAE,UAAU,KAAK,CAAC,CAAA,GAJ7B,uBAKX,WAAA,cAAA,CAAA;AAIA,gBAAA,CADC,WAAW,iBAAiB,EAAE,UAAU,KAAK,CAAC,CAAA,GARpC,uBASX,WAAA,qBAAA,CAAA;AAGA,gBAAA,CADC,MAAM,EAAE,UAAU,KAAK,CAAC,CAAA,GAXd,uBAYX,WAAA,eAAA,CAAA;AAGA,gBAAA,CADC,MAAM,EAAE,UAAU,KAAK,CAAC,CAAA,GAdd,uBAeX,WAAA,aAAA,CAAA;AAaA,gBAAA,CADC,MAAM;CAAE,MAAM;CAAW,UAAU;AAAK,CAAC,CAAA,GA3B/B,uBA4BX,WAAA,gBAAA,CAAA;AAIA,gBAAA,CADC,MAAM,EAAE,UAAU,KAAK,CAAC,CAAA,GA/Bd,uBAgCX,WAAA,UAAA,CAAA;AAGA,gBAAA,CADC,MAAM,EAAE,UAAU,KAAK,CAAC,CAAA,GAlCd,uBAmCX,WAAA,aAAA,CAAA;AAnCW,yBAAN,gBAAA,CARN,aAAa,EAAE,MAAM,WAAW,CAAC,GACjC,KAAK;CACJ,WAAW;CACX,iBAAiB,CAAC,YAAY;CAC9B,KAAK,EAAE,SAAS;EAAC;EAAQ;EAAO;CAAQ,EAAE;CAC1C,KAAK,EAAE,SAAS;EAAC;EAAQ;EAAO;CAAQ,EAAE;CAC1C,KAAK,EAAE,SAAS;EAAC;EAAQ;EAAO;CAAQ,EAAE;AAC5C,CAAC,CAAA,GACY,sBAAA;;;ACdN,IAAM,mCAAN,cAA+C,eAAuC;CAC3F,OAAgB,aAAa;CAE7B,MAAM,gBACJ,WACwC;EACxC,IAAI,CAAC,WAAW,OAAO;EAEvB,QAAO,MADY,KAAK,KAAK;GAAE,OAAO,EAAE,UAAU;GAAG,OAAO;EAAE,CAAC,EAAA,CACnD,MAAM;CACpB;CAEA,MAAM,uBACJ,SACiE;EACjE,MAAM,YAAY,QAAQ,aAAa;EACvC,IAAI,CAAC,WACH,MAAM,IAAI,MACR,+EACF;EAEF,MAAM,WAAW,MAAM,KAAK,gBAAgB,SAAS;EACrD,IAAI,UAAU,OAAO;GAAE,UAAU;GAAU,SAAS;EAAM;EAE1D,IAAI;GASF,OAAO;IAAE,UAAA,MARc,KAAK,OAAO;KACjC,GAAG;KAGH,aAAa,QAAQ;KACrB,WAAW,QAAQ;KACnB,aAAa;IACf,CAAC;IACkB,SAAS;GAAK;EACnC,SAAS,OAAO;GAId,MAAM,aAAa,MAAM,KAAK,gBAAgB,SAAS;GACvD,IAAI,YAAY,OAAO;IAAE,UAAU;IAAY,SAAS;GAAM;GAC9D,MAAM;EACR;CACF;CAEA,MAAM,eAAe,YAAuD;EAC1E,OAAO,MAAM,KAAK,KAAK;GACrB,OAAO,EAAE,WAAW;GACpB,SAAS;EACX,CAAC;CACH;CAEA,MAAM,cACJ,mBACmC;EACnC,OAAO,MAAM,KAAK,KAAK;GACrB,OAAO,EAAE,kBAAkB;GAC3B,SAAS;EACX,CAAC;CACH;AACF;;;ACxBO,IAAM,kCAAkC;AACxC,IAAM,mCAAmC;AAEzC,IAAM,qBAAN,MAAM,2BAA2B,eAAyB;CAC/D,OAAgB,aAAa;CAE7B,MAAe,IACb,QACA,UAAqD,CAAC,GAC5B;EAC1B,OAAO,gCACL,MAAM,IAAI,2BAA2B,MAAM,GAAG,OAAO,CACvD;CACF;CAYA,MAAe,KACb,UAAqC,CAAC,GACW;EACjD,OAAO,gCAEH,MAAM,KAAK,6BAA6B,OAAO,CAAU,CAG7D;CACF;CAEA,MAAM,kBACJ,aACA,UAC0B;EAC1B,IAAI,CAAC,aAAa,OAAO;EACzB,MAAM,QAAiC,EAAE,YAAY;EACrD,IAAI,aAAa,KAAA,GAAW,MAAM,WAAW;EAE7C,QAAO,MADY,KAAK,KAAK;GAAE;GAAO,OAAO;EAAE,CAAC,EAAA,CACpC,MAAM;CACpB;CAEA,MAAM,aAAa,QAA6C;EAC9D,OAAO,MAAM,KAAK,KAAK;GACrB,OAAO,EAAE,OAAO;GAChB,SAAS;EACX,CAAC;CACH;;;;;CAMA,MAAM,eACJ,UACA,YACA,UAA0C,CAAC,GACZ;EAC/B,MAAM,qBAAqB,qBACzB,UACA,mCACF;EACA,MAAM,uBAAuB,cAAc,YAAY,YAAY;EACnE,MAAM,QAAQ,iBAAiB,QAAQ,OAAO;GAC5C,cAAc;GACd,UAAU,OAAO;GACjB,eAAe;EACjB,CAAC;EACD,IAAI,QAAA,KACF,MAAM,IAAI,MACR,mDACF;EAEF,IAAI,QAAQ,GACV,MAAM,IAAI,MAAM,kDAAkD;EAEpE,MAAM,SAAS,gBAAgB,QAAQ,KAAK;EAC5C,OAAO,2BAA2B,0BAChC,KAAK,0BAA0B,OAAO,UACpC,MAAM,4BACJ,oBACA,sBACA,OACA,QACA,mCACF,CACF,CACF;CACF;;;;;;CAOA,MAAM,wBACJ,UACA,YACA,UAAkD,CAAC,GACnB;EAChC,MAAM,qBAAqB,qBACzB,UACA,4CACF;EACA,MAAM,uBAAuB,cAAc,YAAY,YAAY;EACnE,MAAM,QAAQ,iBAAiB,QAAQ,OAAO;GAC5C,cAAc;GACd,UAAU,OAAO;GACjB,eAAe;EACjB,CAAC;EACD,IAAI,QAAA,KACF,MAAM,IAAI,MACR,oDACF;EAEF,IAAI,QAAQ,GACV,MAAM,IAAI,MAAM,mDAAmD;EAErE,MAAM,SAAS,gBAAgB,QAAQ,KAAK;EAC5C,MAAM,KAAK,qBAAqB,QAAQ,EAAE;EAE1C,OAAO,2BAA2B,0BAChC,KAAK,0BAA0B,OAAO,UAAU;GAC9C,MAAM,OAAO,MAAM,MAAM,4BACvB,oBACA,sBACA,OACA,QACA,4CACF;GACA,OAAO,MAAM,qBAAqB,oBAAoB,MAAM,EAAE;EAChE,CAAC,CACH;CACF;CAEA,MAAc,qBACZ,UACA,MACA,IACgC;EAChC,MAAM,cAAc,KAAK,MAAM,KAAK,aAAa;GAC/C,IAAI,CAAC,SAAS,IACZ,MAAM,IAAI,MAAM,sDAAsD;GAExE,OAAO,cAAc,SAAS,IAAI,aAAa;EACjD,CAAC;EACD,IAAI,YAAY,WAAW,GACzB,OAAO;GAAE,OAAO,CAAC;GAAG,YAAY,KAAK;EAAW;EAGlD,MAAM,cAAc,MAAM,KAAK,mBAAmB,UAAU,WAAW;EACvE,MAAM,aAAa,MAAM,KAAK,eAAe,UAAU,WAAW;EAClE,MAAM,qBAAqB,gBAAgB,WAAW;EACtD,MAAM,oBAAoB,kBAAkB,UAAU;EAEtD,OAAO;GACL,OAAO,KAAK,MAAM,KAAK,aAAa;IAClC,MAAM,aAAa,SAAS,MAAM;IAClC,MAAM,aAAa,mBAAmB,IAAI,UAAU,KAAK,CAAC;IAC1D,MAAM,UACJ,kBAAkB,IAAI,UAAU,KAAK,kBAAkB;IACzD,OAAO;KACL;KACA,cAAc,WAAW,QACtB,KAAK,UACJ,WAAW,KAAK,MAAM,OAAO,wBAAwB,GACvD,CACF;KACA;KACA,cAAc,QAAQ;KACtB,QAAQ,wBACN,UACA;MACE,YAAY,QAAQ,OAAO;MAC3B,eAAe,QAAQ;MACvB,qBAAqB,QAAQ;KAC/B,GACA,EACF;IACF;GACF,CAAC;GACD,YAAY,KAAK;EACnB;CACF;CAEA,MAAc,mBACZ,UACA,aACyC;EACzC,MAAM,WAAW,MAAM,0BAA0B,OAAO;GACtD,GAAG,KAAK;GACR,IAAI,KAAK;GACT,kBAAkB,KAAA;GAClB,cAAc,KAAA;EAChB,CAAC;EACD,MAAM,KAAK,gBAAgB,KAAK,OAAO;EACvC,MAAM,eAAe,YAAY,UAAU,GAAG,CAAA,CAAE,KAAK,IAAI;EACzD,MAAM,kBACJ,aAAa,OAAO,sBAAsB;EAC5C,MAAM,eAAe,aAAa,OAAO,CAAC,IAAI,CAAC,QAAQ;EAUvD,QAAO,MATc,GAAG,MACtB;cACQ,SAAS,UAAS;eACjB,gBAAe,uBAAwB,aAAY;;oDAG5D,GAAG,cACH,GAAG,WACL,EAAA,CACc;CAChB;CAEA,MAAc,eACZ,UACA,aACyC;EACzC,MAAM,YAAY,MAAM,iCAAiC,OAAO;GAC9D,GAAG,KAAK;GACR,IAAI,KAAK;GACT,kBAAkB,KAAA;GAClB,cAAc,KAAA;EAChB,CAAC;EACD,MAAM,KAAK,gBAAgB,KAAK,OAAO;EACvC,MAAM,eAAe,YAAY,UAAU,GAAG,CAAA,CAAE,KAAK,IAAI;EACzD,MAAM,kBACJ,aAAa,OAAO,sBAAsB;EAC5C,MAAM,eAAe,aAAa,OAAO,CAAC,IAAI,CAAC,QAAQ;EA4CvD,QAAO,MA3Cc,GAAG,MACtB;;;;;;;;;;;gBAWU,UAAU,UAAS;iBAClB,gBAAe,uBAAwB,aAAY;;;;;;;;;;;;;;;;;;;;;;;;;;kCA2B9D,GAAG,cACH,GAAG,WACL,EAAA,CACc;CAChB;CAEA,MAAc,4BACZ,UACA,YACA,OACA,QACA,WAC+B;EAC/B,MAAM,8BACJ,KAAK,SACL,UACA,CAAC,UAAU,GACX,WACA,OACF;EACA,MAAM,QACJ,QAAQ,YAAY,OAChB,MAAM,KAAK,kBAAkB,UAAU,YAAY,QAAQ,GAAG,MAAM,IACpE,MAAM,KAAK,kBAAkB,UAAU,YAAY,OAAO,MAAM;EACtE,MAAM,UAAU,MAAM,SAAS;EAC/B,MAAM,YAAY,UAAU,MAAM,MAAM,GAAG,KAAK,IAAI;EACpD,OAAO;GACL,OAAO;GACP,YAAY,UACR,mBAAmB,UAAU,UAAU,SAAS,EAAE,IAClD;EACN;CACF;;;;;CAMA,MAAM,qBACJ,UACA,aACoC;EACpC,MAAM,qBAAqB,qBACzB,UACA,yCACF;EACA,IAAI,CAAC,MAAM,QAAQ,WAAW,GAC5B,MAAM,IAAI,MACR,yDACF;EAEF,IAAI,YAAY,SAAA,KACd,MAAM,IAAI,MACR,4DACF;EAEF,MAAM,wBAAwB,YAAY,KAAK,eAC7C,cAAc,YAAY,YAAY,CACxC;EACA,MAAM,YAAY,CAAC,GAAG,IAAI,IAAI,qBAAqB,CAAC;EACpD,IAAI,UAAU,WAAW,GAAG,OAAO,CAAC;EAEpC,OAAO,2BAA2B,0BAChC,KAAK,0BAA0B,OAAO,UACpC,MAAM,kCACJ,oBACA,uBACA,SACF,CACF,CACF;CACF;CAEA,MAAc,kCACZ,UACA,sBACA,WACoC;EACpC,MAAM,8BACJ,KAAK,SACL,UACA,WACA,2CACA,OACF;EACA,MAAM,KAAK,gBAAgB,KAAK,OAAO;EACvC,MAAM,eAAe,UAAU,UAAU,GAAG,CAAA,CAAE,KAAK,IAAI;EACvD,MAAM,kBACJ,aAAa,OAAO,sBAAsB;EAC5C,MAAM,eAAe,aAAa,OAAO,CAAC,IAAI,CAAC,QAAQ;EACvD,MAAM,SAAS,MAAM,GAAG,MACtB;;;;cAIQ,KAAK,UAAS;eACb,gBAAe,uBAAwB,aAAY;;;iBAI5D,UACA,GAAG,cACH,GAAG,WACH,UAAU,MACZ;EACA,MAAM,aAAa,IAAI,IACrB,OAAO,KAAK,KAAK,QAAQ,CAAC,OAAO,IAAI,WAAW,CAAA,CAAE,YAAY,GAAG,GAAG,CAAC,CACvE;EACA,OAAO,qBAAqB,KAAK,eAAe;GAC9C,MAAM,MAAM,WAAW,IAAI,UAAU;GACrC,OAAO;IACL;IACA,YAAY,MACR,YAAY,IAAI,aAAa,+BAA+B,IAC5D;IACJ,aAAa,MACT,YAAY,IAAI,cAAc,gCAAgC,IAC9D;IACJ,eAAe,MAAM,WAAW,IAAI,eAAe,IAAI;GACzD;EACF,CAAC;CACH;CAEA,MAAc,0BACZ,WACY;EACZ,MAAM,KAAK,KAAK;EAChB,IAAI,OAAO,GAAG,gBAAgB,YAC5B,MAAM,IAAI,MACR,8EACF;EAEF,OAAO,GAAG,YAAY,OAAO,kBAAkB;GAO7C,OAAO,UAAU,MANG,mBAAmB,OAAO;IAC5C,GAAG,KAAK;IACR,IAAI;IACJ,kBAAkB,KAAA;IAClB,cAAc,KAAA;GAChB,CAAC,CACqB;EACxB,CAAC;CACH;CAEA,MAAc,kBACZ,UACA,YACA,OACA,QACqB;EACrB,MAAM,OAAO;GAAC,EAAE,SAAS;GAAG,EAAE,WAAW;GAAG,EAAE,cAAc,KAAK;EAAC;EAClE,MAAM,QAAQ,SACV,CACE,CAAC,GAAG,MAAM,EAAE,aAAa,OAAO,QAAQ,CAAC,GACzC;GAAC,GAAG;GAAM,EAAE,SAAS,OAAO,QAAQ;GAAG,EAAE,QAAQ,OAAO,GAAG;EAAC,CAC9D,IACA;GAAE;GAAU;GAAY,cAAc;EAAK;EAC/C,MAAM,YAAY,MAAM,KAAK,KAAK;GAChC;GACA,SAAS,CAAC,iBAAiB,SAAS;GACpC,OAAO,QAAQ;EACjB,CAAC;EACD,IAAI,UAAU,SAAS,OAAO,OAAO;EACrC,MAAM,WAAW,MAAM,KAAK,kBAC1B,UACA,YACA,QAAQ,UAAU,SAAS,GAC3B,IACF;EACA,OAAO,CAAC,GAAG,WAAW,GAAG,QAAQ;CACnC;CAEA,MAAc,kBACZ,UACA,YACA,OACA,QACqB;EACrB,OAAO,KAAK,KAAK;GACf,OAAO;IACL;IACA;IACA,SAAS;IACT,GAAI,SAAS,EAAE,QAAQ,OAAO,GAAG,IAAI,CAAC;GACxC;GACA,SAAS;GACT;EACF,CAAC;CACH;AACF;AAeA,SAAS,gBACP,MACwC;CACxC,MAAM,0BAAU,IAAI,IAAuC;CAC3D,KAAA,MAAW,OAAO,MAAM;EACtB,MAAM,aAAa,cAAc,OAAO,IAAI,WAAW,GAAG,aAAa;EACvE,MAAM,cAAc,OAAO,IAAI,YAAY;EAC3C,IAAI,CAAC,aAAa,MAAM,IAAI,MAAM,iCAAiC;EACnE,MAAM,QAAQ;GACZ;GACA,OAAO,YAAY,IAAI,eAAe,wBAAwB;EAChE;EACA,MAAM,UAAU,QAAQ,IAAI,UAAU,KAAK,CAAC;EAC5C,QAAQ,KAAK,KAAK;EAClB,QAAQ,IAAI,YAAY,OAAO;CACjC;CACA,OAAO;AACT;AAEA,SAAS,kBACP,MACkC;CAClC,OAAO,IAAI,IACT,KAAK,KAAK,QAAQ;EAEhB,OAAO,CADY,cAAc,OAAO,IAAI,WAAW,GAAG,aAExD,GACA;GACE,QAAQ;IACN,YAAY,YAAY,IAAI,aAAa,sBAAsB;IAC/D,aAAa,YACX,IAAI,aACJ,2BACF;IACA,QAAQ,YAAY,IAAI,QAAQ,sBAAsB;IACtD,aAAa,YACX,IAAI,aACJ,2BACF;IACA,OAAO,YAAY,IAAI,OAAO,qBAAqB;IACnD,cAAc,YACZ,IAAI,eACJ,wBACF;GACF;GACA,eAAe,YACb,IAAI,gBACJ,yBACF;GACA,qBAAqB,cAAc,IAAI,qBAAqB;EAC9D,CACF;CACF,CAAC,CACH;AACF;AAEA,SAAS,oBAAyC;CAChD,OAAO;EACL,QAAQ;GACN,YAAY;GACZ,aAAa;GACb,QAAQ;GACR,aAAa;GACb,OAAO;GACP,cAAc;EAChB;EACA,eAAe;EACf,qBAAqB;CACvB;AACF;AAEA,SAAS,cAAc,OAAyB;CAC9C,OAAO,UAAU,QAAQ,UAAU,KAAK,UAAU;AACpD;AAEA,SAAS,WAAW,MAAc,OAAe,OAAuB;CACtE,MAAM,MAAM,OAAO;CACnB,IAAI,CAAC,OAAO,cAAc,GAAG,KAAK,MAAM,GACtC,MAAM,IAAI,MAAM,GAAG,MAAK,oCAAqC;CAE/D,OAAO;AACT;AAEA,SAAS,gBAAgB,SAA0C;CACjE,MAAM,KAAK,QAAQ;CACnB,IAAI,CAAC,MAAM,OAAO,OAAO,YAAY,EAAE,WAAW,KAChD,MAAM,IAAI,MACR,8EACF;CAEF,OAAO;AACT;AAEA,SAAS,WAAW,OAA6B;CAC/C,IAAI,SAAS,MAAM,OAAO;CAC1B,MAAM,OACJ,iBAAiB,OACb,QACA,IAAI,KAAK,OAAO,UAAU,WAAW,QAAQ,OAAO,KAAK,CAAC;CAChE,OAAO,OAAO,MAAM,KAAK,QAAQ,CAAC,IAAI,OAAO;AAC/C;AAEA,SAAS,YAAY,OAAgB,OAAuB;CAC1D,MAAM,QAAQ,OAAO,KAAK;CAC1B,IAAI,CAAC,OAAO,cAAc,KAAK,KAAK,QAAQ,GAC1C,MAAM,IAAI,MAAM,GAAG,MAAK,oCAAqC;CAE/D,OAAO;AACT;AAEA,SAAS,gBACP,QAC+B;CAC/B,IAAI,CAAC,QAAQ,OAAO;CACpB,MAAM,KAAK,cAAc,OAAO,IAAI,6BAA6B;CACjE,IAAI,OAAO,YAAY,MAAM,OAAO;EAAE;EAAI,SAAS;CAAK;CACxD,MAAM,UAAU,WAAW,OAAO,OAAO;CACzC,IAAI,CAAC,SAAS,MAAM,IAAI,MAAM,8CAA8C;CAC5E,OAAO;EAAE;EAAI;CAAQ;AACvB;AAEA,SAAS,qBAAqB,OAAiD;CAC7E,IAAI,UAAU,KAAA,GAAW,uBAAO,IAAI,KAAK;CACzC,MAAM,KAAK,WAAW,KAAK;CAC3B,IAAI,CAAC,IAAI,MAAM,IAAI,MAAM,mCAAmC;CAC5D,OAAO;AACT;AAEA,SAAS,mBACP,UAC+B;CAC/B,IAAI,CAAC,UAAU,IAAI,OAAO;CAC1B,OAAO;EAAE,IAAI,SAAS;EAAI,SAAS,SAAS;CAAQ;AACtD;AAEA,SAAS,qBACP,UACA,OACe;CACf,IAAI,aAAa,MAAM;EACrB,MAAM,aAAa,cAAc,UAAU,UAAU;EACrD,MAAMC,iBAAgB,iBAAiB;EACvC,IAAIA,kBAAiB,CAAC,mBAAmB,GAAG;GAC1C,MAAM,kBAAkB,cAAcA,eAAc,UAAU,UAAU;GACxE,IAAI,eAAe,iBACjB,MAAM,IAAI,qBACR,iCAAiC,MAAK,IACtC;IAAE,UAAU;IAAiB,mBAAmB;GAAW,CAC7D;EAEJ;EACA,OAAO;CACT;CACA,MAAM,gBAAgB,iBAAiB;CACvC,IAAI,iBAAiB,CAAC,mBAAmB,KAAK,CAAC,gBAAgB,GAC7D,MAAM,IAAI,qBACR,iCAAiC,MAAK,qDACtC;EAAE,UAAU,cAAc;EAAU,mBAAmB;CAAS,CAClE;CAEF,OAAO;AACT;AAEA,SAAS,2BACP,UACA,WACY;CACZ,MAAM,gBAAgB,iBAAiB;CACvC,OAAO,aAAa,QAClB,iBACA,CAAC,mBAAmB,KACpB,CAAC,gBAAgB,IACf,WAAW;EAAE,GAAG;EAAe;CAAS,GAAG,SAAS,IACpD,UAAU;AAChB;AAEA,SAAS,0BAA6B,WAAyC;CAC7E,MAAM,gBAAgB,iBAAiB;CACvC,IAAI,CAAC,iBAAiB,mBAAmB,KAAK,gBAAgB,GAC5D,OAAO,UAAU;CAEnB,MAAM,qBAAqB,cAAc,cAAc,UAAU,UAAU;CAC3E,OAAO,uBAAuB,cAAc,WACxC,UAAU,IACV,WAAW;EAAE,GAAG;EAAe,UAAU;CAAmB,GAAG,SAAS;AAC9E;AAEA,SAAS,2BACP,QACoC;CACpC,IAAI,OAAO,WAAW,UAAU,OAAO,2BAA2B,MAAM;CACxE,IAAI;EACF,OAAO,cAAc,QAAQ,aAAa;CAC5C,QAAQ;EACN,OAAO;CACT;AACF;AAEA,SAAS,6BACP,SAC2B;CAC3B,OAAO,QAAQ,UAAU,KAAA,IACrB,UACA;EAAE,GAAG;EAAS,OAAO,2BAA2B,QAAQ,KAAK;CAAE;AACrE;AAEA,SAAS,2BAA8B,OAAa;CAClD,IAAI,MAAM,QAAQ,KAAK,GACrB,OAAO,MAAM,KAAK,UAAU,2BAA2B,KAAK,CAAC;CAE/D,IAAI,CAAC,SAAS,OAAO,UAAU,UAAU,OAAO;CAEhD,MAAM,aAAsC,CAAC;CAC7C,KAAA,MAAW,CAAC,KAAK,UAAU,OAAO,QAAQ,KAAK,GAAG;EAChD,MAAM,QAAQ,IAAI,KAAK,CAAA,CAAE,MAAM,MAAM,CAAA,CAAE;EACvC,MAAM,QACJ,UAAU,OACN,gBACA,UAAU,eACR,eACA,UAAU,aACR,aACA;EACV,IAAI,CAAC,OACH,WAAW,OAAO;OACpB,IAAW,MAAM,QAAQ,KAAK,GAC5B,WAAW,OAAO,MAAM,KAAK,SAC3B,OAAO,SAAS,WAAW,cAAc,MAAM,KAAK,IAAI,IAC1D;OAEA,WAAW,OACT,OAAO,UAAU,WAAW,cAAc,OAAO,KAAK,IAAI;CAEhE;CACA,OAAO;AACT;;;AC9tBO,IAAM,sBAAN,MAAM,oBAAoB;CAC/B,YACmB,WACA,UACA,WACjB;EAHiB,KAAA,YAAA;EACA,KAAA,WAAA;EACA,KAAA,YAAA;CAChB;CAHgB;CACA;CACA;CAGnB,aAAa,OACX,eAAiC,CAAC,GACJ;EAC9B,OAAO,IAAI,oBACT,MAAM,mBAAmB,OAAO,YAAY,GAC5C,MAAM,0BAA0B,OAAO,YAAY,GACnD,MAAM,iCAAiC,OAAO,YAAY,CAC5D;CACF;CAEA,MAAM,kBACJ,YACA,qBAAK,IAAI,KAAK,GACe;EAC7B,MAAM,WAAW,MAAM,KAAK,UAAU,IAAI,EAAE,IAAI,WAAW,CAAC;EAC5D,IAAI,CAAC,UAAU,MAAM,IAAI,MAAM,aAAa,WAAU,iBAAkB;EAExE,MAAM,MAAM,MAAM,KAAK,UAAU,eAAe,UAAU;EAC1D,MAAM,UAAU,IAAI,QAAQ,aAAa,CAAC,SAAS,iBAAiB;EACpE,MAAM,OAAO,KAAK,uBAAuB,GAAG;EAC5C,OAAO,wBACL,UACA;GACE,YAAY,KAAK,QACd,KAAK,aAAa,MAAM,SAAS,YAClC,CACF;GACA,eAAe,KAAK;GACpB,qBAAqB,QAAQ,SAAS;EACxC,GACA,EACF;CACF;CAEA,MAAM,iBACJ,mBACA,qBAAK,IAAI,KAAK,GACe;EAC7B,MAAM,UAAU,MAAM,KAAK,SAAS,IAAI,EAAE,IAAI,kBAAkB,CAAC;EACjE,IAAI,CAAC,SACH,MAAM,IAAI,MAAM,oBAAoB,kBAAiB,iBAAkB;EAEzE,MAAM,WAAW,MAAM,KAAK,UAAU,IAAI,EAAE,IAAI,QAAQ,WAAW,CAAC;EACpE,IAAI,CAAC,UACH,MAAM,IAAI,MAAM,aAAa,QAAQ,WAAU,iBAAkB;EAEnE,MAAM,YAAY,MAAM,KAAK,UAAU,cAAc,iBAAiB;EACtE,OAAO;GACL,GAAG,gBAAgB;IACjB;IACA,UAAU;KACR,YAAY,UAAU,QACnB,KAAK,aAAa,MAAM,SAAS,YAClC,CACF;KACA,eAAe,UAAU;KACzB,qBAAqB;IACvB;IACA,aAAa,QAAQ;IACrB,SAAS,QAAQ,WAAW,SAAS;IACrC,OAAO,QAAQ,SAAS,SAAS;IACjC;GACF,CAAC;GACD;EACF;CACF;;;;;;CAOQ,uBACN,WAC0B;EAC1B,MAAM,gBAAgB,IAAI,IACxB,UACG,QAAQ,aAAa,CAAC,SAAS,iBAAiB,CAAA,CAChD,KAAK,aAAa,KAAK,UAAU,QAAQ,CAAC,CAC/C;EACA,OAAO,UAAU,QACd,aACC,CAAC,SAAS,qBACV,CAAC,cAAc,IAAI,KAAK,UAAU,QAAQ,CAAC,CAC/C;CACF;CAEQ,UAAU,UAA0C;EAC1D,OAAO,GAAG,SAAS,YAAY,YAAY,EAAC,GAAI,SAAS,UAAU,YAAY;CACjF;AACF;;;ACzGO,IAAM,2BAAN,MAAM,yBAAyB;CACpC,YAA6B,WAA+B;EAA/B,KAAA,YAAA;CAAgC;CAAhC;CAE7B,aAAa,OACX,eAAiC,CAAC,GACC;EACnC,OAAO,IAAI,yBACT,MAAM,mBAAmB,OAAO,YAAY,CAC9C;CACF;CAEA,MAAM,WACJ,YACA,MACmB;EACnB,MAAM,WAAW,MAAM,KAAK,UAAU,IAAI,EAAE,IAAI,WAAW,CAAC;EAC5D,IAAI,CAAC,UAAU,MAAM,IAAI,MAAM,aAAa,WAAU,iBAAkB;EACxE,SAAS,aAAa,IAAI;EAC1B,MAAM,SAAS,KAAK;EACpB,OAAO;CACT;CAEA,MAAM,SAAS,YAAuC;EACpD,OAAO,MAAM,KAAK,WAAW,YAAY,WAAW;CACtD;CAEA,MAAM,SAAS,YAAuC;EACpD,OAAO,MAAM,KAAK,WAAW,YAAY,QAAQ;CACnD;CAEA,MAAM,MAAM,YAAuC;EACjD,OAAO,MAAM,KAAK,WAAW,YAAY,QAAQ;CACnD;CAEA,MAAM,OAAO,YAAuC;EAClD,OAAO,MAAM,KAAK,WAAW,YAAY,QAAQ;CACnD;CAEA,MAAM,SAAS,YAAuC;EACpD,OAAO,MAAM,KAAK,WAAW,YAAY,WAAW;CACtD;CAEA,MAAM,QAAQ,YAAuC;EACnD,OAAO,MAAM,KAAK,WAAW,YAAY,UAAU;CACrD;AACF;;;AC7CO,IAAM,yBAAN,MAAM,uBAAuB;CAClC,YAA6B,WAA6C;EAA7C,KAAA,YAAA;CAA8C;CAA9C;CAE7B,aAAa,OACX,eAAiC,CAAC,GACD;EACjC,OAAO,IAAI,uBACT,MAAM,iCAAiC,OAAO,YAAY,CAC5D;CACF;CAEA,MAAM,OACJ,SACiE;EACjE,IAAI,CAAC,QAAQ,YACX,MAAM,IAAI,MAAM,uCAAuC;EAEzD,IAAI,CAAC,QAAQ,QAAQ,KAAK,GACxB,MAAM,IAAI,MAAM,mCAAmC;EAErD,IAAI,CAAC,QAAQ,WAAW,KAAK,GAC3B,MAAM,IAAI,MAAM,sCAAsC;EAExD,IAAI,QAAQ,eAAe,QAAQ,QAAQ,aAAa,MACtD,MAAM,IAAI,MAAM,sDAAsD;EAExE,OAAO,MAAM,KAAK,UAAU,uBAAuB,OAAO;CAC5D;AACF"}
|
package/dist/manifest.json
CHANGED
package/dist/smrt-knowledge.json
CHANGED
|
@@ -3,12 +3,12 @@
|
|
|
3
3
|
"sensitiveFieldsExcluded": true,
|
|
4
4
|
"generatedAt": "1970-01-01T00:00:00.000Z",
|
|
5
5
|
"packageName": "@happyvertical/smrt-marketing",
|
|
6
|
-
"packageVersion": "0.57.
|
|
6
|
+
"packageVersion": "0.57.5",
|
|
7
7
|
"sourceManifestPath": "dist/manifest.json",
|
|
8
8
|
"agentDocPath": "AGENTS.md",
|
|
9
9
|
"sourceHashes": {
|
|
10
|
-
"manifest": "
|
|
11
|
-
"packageJson": "
|
|
10
|
+
"manifest": "93a8ac232afa602fd897dd0b71aa7310a743fb089e070f77813535626b840624",
|
|
11
|
+
"packageJson": "9ab631e667dba8927c9fa857d4fa17e613287853e8b5f547aa50e20282558184",
|
|
12
12
|
"agents": "3b81365608ec4f1929b51db17194f9c1f74d420b49886277e0f94b42238915d8"
|
|
13
13
|
},
|
|
14
14
|
"exports": [
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@happyvertical/smrt-marketing",
|
|
3
|
-
"version": "0.57.
|
|
3
|
+
"version": "0.57.5",
|
|
4
4
|
"smrtJsdoc": "strict",
|
|
5
5
|
"description": "Cross-channel campaign coordination, immutable performance evidence, budget pacing, and reusable Svelte marketing surfaces for SMRT",
|
|
6
6
|
"type": "module",
|
|
@@ -25,17 +25,17 @@
|
|
|
25
25
|
"./manifest.json": "./dist/manifest.json"
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@happyvertical/smrt-core": "0.57.
|
|
29
|
-
"@happyvertical/smrt-tenancy": "0.57.
|
|
30
|
-
"@happyvertical/smrt-ui": "0.57.
|
|
28
|
+
"@happyvertical/smrt-core": "0.57.5",
|
|
29
|
+
"@happyvertical/smrt-tenancy": "0.57.5",
|
|
30
|
+
"@happyvertical/smrt-ui": "0.57.5"
|
|
31
31
|
},
|
|
32
32
|
"peerDependencies": {
|
|
33
33
|
"svelte": "^5.57.0"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
|
-
"@happyvertical/smrt-commerce": "0.57.
|
|
37
|
-
"@happyvertical/smrt-vitest": "0.57.
|
|
38
|
-
"@happyvertical/sql": "^0.105.
|
|
36
|
+
"@happyvertical/smrt-commerce": "0.57.5",
|
|
37
|
+
"@happyvertical/smrt-vitest": "0.57.5",
|
|
38
|
+
"@happyvertical/sql": "^0.105.2",
|
|
39
39
|
"@sveltejs/package": "^2.5.8",
|
|
40
40
|
"@sveltejs/vite-plugin-svelte": "^7.3.0",
|
|
41
41
|
"@testing-library/svelte": "^5.4.2",
|