@happyvertical/smrt-marketing 0.57.37 → 0.57.39
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 +10 -10
- package/dist/index.js.map +1 -1
- package/dist/manifest.json +22 -4
- package/dist/models/Campaign.d.ts +2 -2
- package/dist/models/Campaign.d.ts.map +1 -1
- package/dist/models/CampaignChannel.d.ts +2 -2
- package/dist/models/CampaignChannel.d.ts.map +1 -1
- package/dist/models/CampaignMetricSnapshot.d.ts +2 -2
- package/dist/models/CampaignMetricSnapshot.d.ts.map +1 -1
- package/dist/smrt-knowledge.json +12 -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, SmrtRecipe, 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.37","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","description":"The customer this campaign is run for, if any.","_meta":{"description":"The customer this campaign is run for, if any.","validate":true,"nullable":true}},"campaignKey":{"type":"text","required":true,"default":"","description":"A short reference of your own for this campaign, kept the same once it is in use.","_meta":{"required":true,"description":"A short reference of your own for this campaign, kept the same once it is in use."}},"name":{"type":"text","required":true,"default":"","description":"What the campaign is called.","_meta":{"required":true,"description":"What the campaign is called."}},"objective":{"type":"text","required":false,"default":"","description":"What the campaign is meant to achieve, such as awareness or new leads.","_meta":{"description":"What the campaign is meant to achieve, such as awareness or new leads."}},"status":{"type":"text","required":false,"default":"draft","description":"Where the campaign stands, from draft through active to completed and archived.","_meta":{"description":"Where the campaign stands, from draft through active to completed and archived."}},"startAt":{"type":"datetime","required":false,"description":"When the campaign starts.","_meta":{"description":"When the campaign starts."}},"endAt":{"type":"datetime","required":false,"description":"When the campaign ends.","_meta":{"description":"When the campaign ends."}},"budgetCents":{"type":"integer","required":false,"default":0,"description":"The total you plan to spend on the campaign, in cents.","_meta":{"description":"The total you plan to spend on the campaign, in cents."}},"currency":{"type":"text","required":false,"default":"USD","description":"The currency every amount on this campaign is in.","_meta":{"description":"The currency every amount on this campaign is in."}},"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","description":"The campaign this channel runs for.","_meta":{"description":"The campaign this channel runs for.","required":true}},"channelKind":{"type":"text","required":true,"default":"","description":"What sort of channel this is, such as an ad group, a social post, a message, content or an event.","_meta":{"required":true,"description":"What sort of channel this is, such as an ad group, a social post, a message, content or an event."}},"channelRef":{"type":"text","required":true,"default":"","description":"The name or reference the channel goes by, so its results can be matched to it.","_meta":{"required":true,"description":"The name or reference the channel goes by, so its results can be matched to it."}},"allocatedBudgetCents":{"type":"integer","required":false,"default":0,"description":"The share of the campaign budget set aside for this channel, in cents.","_meta":{"description":"The share of the campaign budget set aside for this channel, in cents."}},"startAt":{"type":"datetime","required":false,"description":"When this channel starts, if different from the campaign.","_meta":{"description":"When this channel starts, if different from the campaign."}},"endAt":{"type":"datetime","required":false,"description":"When this channel ends, if different from the campaign.","_meta":{"description":"When this channel ends, if different from the campaign."}},"status":{"type":"text","required":false,"default":"planned","description":"Where this channel stands, from planned through active to completed or cancelled.","_meta":{"description":"Where this channel stands, from planned through active to completed or cancelled."}}},"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","description":"The campaign these results belong to.","_meta":{"description":"The campaign these results belong to.","required":true}},"campaignChannelId":{"type":"foreignKey","required":false,"related":"CampaignChannel","description":"The channel these results came from. Empty when they cover the whole campaign.","_meta":{"description":"The channel these results came from. Empty when they cover the whole campaign.","nullable":true}},"periodStart":{"type":"datetime","required":true,"description":"The first day of the period these results cover.","_meta":{"required":true,"description":"The first day of the period these results cover."}},"periodEnd":{"type":"datetime","required":true,"description":"The last day of the period these results cover.","_meta":{"required":true,"description":"The last day of the period these results cover."}},"spendCents":{"type":"integer","required":false,"default":0,"description":"What was spent in the period, in cents.","_meta":{"description":"What was spent in the period, in cents."}},"impressions":{"type":"integer","required":false,"default":0,"description":"How many times the campaign was shown.","_meta":{"description":"How many times the campaign was shown."}},"clicks":{"type":"integer","required":false,"default":0,"description":"How many times someone clicked through.","_meta":{"description":"How many times someone clicked through."}},"conversions":{"type":"integer","required":false,"default":0,"description":"How many people did what the campaign asked, such as buying.","_meta":{"description":"How many people did what the campaign asked, such as buying."}},"leads":{"type":"integer","required":false,"default":0,"description":"How many new leads came in.","_meta":{"description":"How many new leads came in."}},"revenueCents":{"type":"integer","required":false,"description":"The sales brought in during the period, in cents, if known.","_meta":{"nullable":true,"description":"The sales brought in during the period, in cents, if known."}},"source":{"type":"text","required":true,"default":"","description":"Where these results were reported from.","_meta":{"required":true,"description":"Where these results were reported from."}},"dedupeKey":{"type":"text","required":true,"default":"","description":"The reference this result is filed under, so the same report is never counted twice.","_meta":{"required":true,"description":"The reference this result is filed under, so the same report is never counted twice."}}},"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","recipes":[{"id":"marketing.campaigns","className":"MarketingCampaignsRecipe","label":"Campaigns","summary":"Plan a marketing campaign, set its budget and dates, choose where it runs and see what it brought in.","synonyms":["marketing","marketing campaigns","promotions","advertising","ad campaigns","campaign results"],"models":["@happyvertical/smrt-marketing:Campaign","@happyvertical/smrt-marketing:CampaignChannel","@happyvertical/smrt-marketing:CampaignMetricSnapshot"],"nav":[{"label":"Campaigns","model":"@happyvertical/smrt-marketing:Campaign","icon":"tag","description":"Every campaign, with its budget, dates and where it stands.","noun":"campaign"},{"label":"Channels","model":"@happyvertical/smrt-marketing:CampaignChannel","icon":"layers","description":"Where each campaign runs, such as an ad group or a social post, and its share of the budget.","noun":"channel"}],"requires":[],"section":{"id":"grow","label":"Grow","icon":"tag","description":"Bring in new customers and reward the people who help."},"options":{"@happyvertical/smrt-marketing:Campaign":{"fields":{"name":{"order":1},"objective":{"order":2},"status":{"order":3},"startAt":{"label":"Starts","order":4},"endAt":{"label":"Ends","order":5},"budgetCents":{"label":"Budget (cents)","order":6},"currency":{"order":7},"customerId":{"label":"Customer","visibility":"advanced"},"campaignKey":{"label":"Reference","visibility":"advanced"},"tenantId":{"visibility":"hidden"},"metadata":{"visibility":"hidden"}}},"@happyvertical/smrt-marketing:CampaignChannel":{"fields":{"campaignId":{"label":"Campaign","order":1},"channelKind":{"label":"Kind","order":2},"channelRef":{"label":"Name","order":3},"allocatedBudgetCents":{"label":"Budget share (cents)","order":4},"status":{"order":5},"startAt":{"label":"Starts","order":6},"endAt":{"label":"Ends","order":7},"tenantId":{"visibility":"hidden"}}},"@happyvertical/smrt-marketing:CampaignMetricSnapshot":{"fields":{"campaignId":{"label":"Campaign","order":1},"campaignChannelId":{"label":"Channel","order":2},"periodStart":{"label":"From","order":3},"periodEnd":{"label":"To","order":4},"spendCents":{"label":"Spend (cents)","order":5},"impressions":{"order":6},"clicks":{"order":7},"conversions":{"order":8},"leads":{"order":9},"revenueCents":{"label":"Revenue (cents)","order":10},"source":{"order":11},"tenantId":{"visibility":"hidden"},"dedupeKey":{"visibility":"hidden"}}}},"help":{"markdown":"## Overview\\n\\nCampaigns is where you plan a push to bring in customers: a sale, a launch, a\\nseasonal promotion. Each campaign has a budget, start and end dates and a\\nstatus that shows where it stands, from draft through active to completed. A\\ncampaign runs on one or more channels, such as an ad group, a social post, an\\nemail or an event, each with its share of the budget. Results come back from\\nthe channels' reporting, period by period, so you can see what each campaign\\nand channel brought in for what it cost.\\n\\n## Tasks\\n\\n### Plan a campaign\\n\\n1. Open the list of campaigns and choose **New**.\\n2. Type the **{field:Campaign.name}**, for example \\"Spring widget sale\\".\\n3. Say what it is for in **{field:Campaign.objective}**, such as awareness or new leads.\\n4. Set when it **{field:Campaign.startAt}** and when it **{field:Campaign.endAt}**. The end cannot be before the start.\\n5. Enter the **{field:Campaign.budgetCents}** as a whole number of cents, so $500 is 50000, and check the **{field:Campaign.currency}**.\\n6. Save. A new campaign starts as a draft.\\n\\n### See where a campaign stands\\n\\n1. Open the list of campaigns.\\n2. The **{field:Campaign.status}** shows whether each one is still a draft, scheduled, active, paused, completed or archived. It moves forward as the campaign is scheduled, run and wrapped up; you do not set it by hand.\\n3. Open a campaign to change its name, dates or budget while it is still being planned.\\n\\n### Add a channel to a campaign\\n\\n1. Open the list of channels and choose **New**.\\n2. Pick the **{field:CampaignChannel.campaignId}** it belongs to.\\n3. Choose the **{field:CampaignChannel.channelKind}**, such as an ad group, a social post, a message, content or an event.\\n4. Type the **{field:CampaignChannel.channelRef}** the channel goes by, so its results can be matched to it later.\\n5. Enter its **{field:CampaignChannel.allocatedBudgetCents}** as a whole number of cents.\\n6. If the channel runs on different dates from the campaign, set when it **{field:CampaignChannel.startAt}** and **{field:CampaignChannel.endAt}**.\\n7. Save. You can edit a channel later, or remove one that will not run.\\n\\n### Read the results\\n\\nResults arrive from the channels' reporting; nobody types them in. Each one\\ncovers a period for one campaign, or for one channel within it. A result is\\nnever changed once it is in: a correction arrives as a new result for the same\\nperiod.\\n\\n1. Open a campaign and look at its results, listed under the campaign.\\n2. Each result names the **{field:CampaignMetricSnapshot.campaignId}** it belongs to. A result with no **{field:CampaignMetricSnapshot.campaignChannelId}** covers the whole campaign.\\n3. Check the period, **{field:CampaignMetricSnapshot.periodStart}** to **{field:CampaignMetricSnapshot.periodEnd}**.\\n4. Compare the **{field:CampaignMetricSnapshot.spendCents}** with the **{field:CampaignMetricSnapshot.clicks}**, **{field:CampaignMetricSnapshot.leads}** and **{field:CampaignMetricSnapshot.conversions}** it brought in, and the **{field:CampaignMetricSnapshot.revenueCents}** where the channel reports it.\\n5. The **{field:CampaignMetricSnapshot.source}** says which channel's reporting sent the result.\\n","fieldRefs":["Campaign.budgetCents","Campaign.currency","Campaign.endAt","Campaign.name","Campaign.objective","Campaign.startAt","Campaign.status","CampaignChannel.allocatedBudgetCents","CampaignChannel.campaignId","CampaignChannel.channelKind","CampaignChannel.channelRef","CampaignChannel.endAt","CampaignChannel.startAt","CampaignMetricSnapshot.campaignChannelId","CampaignMetricSnapshot.campaignId","CampaignMetricSnapshot.clicks","CampaignMetricSnapshot.conversions","CampaignMetricSnapshot.leads","CampaignMetricSnapshot.periodEnd","CampaignMetricSnapshot.periodStart","CampaignMetricSnapshot.revenueCents","CampaignMetricSnapshot.source","CampaignMetricSnapshot.spendCents"]},"demo":{"mode":"server","reasons":["Needs a server because its package depends on @happyvertical/smrt-tenancy, which do not build for a browser (#3624)."]}}],"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.39","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","description":"The customer this campaign is run for, if any.","_meta":{"description":"The customer this campaign is run for, if any.","validate":true,"nullable":true}},"campaignKey":{"type":"text","required":true,"default":"","description":"A short reference of your own for this campaign, kept the same once it is in use.","_meta":{"required":true,"description":"A short reference of your own for this campaign, kept the same once it is in use."}},"name":{"type":"text","required":true,"default":"","description":"What the campaign is called.","_meta":{"required":true,"description":"What the campaign is called."}},"objective":{"type":"text","required":false,"default":"","description":"What the campaign is meant to achieve, such as awareness or new leads.","_meta":{"description":"What the campaign is meant to achieve, such as awareness or new leads."}},"status":{"type":"text","required":false,"default":"draft","description":"Where the campaign stands, from draft through active to completed and archived.","_meta":{"description":"Where the campaign stands, from draft through active to completed and archived."}},"startAt":{"type":"datetime","required":false,"description":"When the campaign starts.","_meta":{"description":"When the campaign starts."}},"endAt":{"type":"datetime","required":false,"description":"When the campaign ends.","_meta":{"description":"When the campaign ends."}},"budgetCents":{"type":"integer","required":false,"default":0,"description":"The total you plan to spend on the campaign, in cents.","_meta":{"description":"The total you plan to spend on the campaign, in cents."}},"currency":{"type":"text","required":false,"default":"USD","description":"The currency every amount on this campaign is in.","_meta":{"description":"The currency every amount on this campaign is in."}},"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":[{"name":"options","type":"SmrtSaveOptions","optional":true}],"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","description":"The campaign this channel runs for.","_meta":{"description":"The campaign this channel runs for.","required":true}},"channelKind":{"type":"text","required":true,"default":"","description":"What sort of channel this is, such as an ad group, a social post, a message, content or an event.","_meta":{"required":true,"description":"What sort of channel this is, such as an ad group, a social post, a message, content or an event."}},"channelRef":{"type":"text","required":true,"default":"","description":"The name or reference the channel goes by, so its results can be matched to it.","_meta":{"required":true,"description":"The name or reference the channel goes by, so its results can be matched to it."}},"allocatedBudgetCents":{"type":"integer","required":false,"default":0,"description":"The share of the campaign budget set aside for this channel, in cents.","_meta":{"description":"The share of the campaign budget set aside for this channel, in cents."}},"startAt":{"type":"datetime","required":false,"description":"When this channel starts, if different from the campaign.","_meta":{"description":"When this channel starts, if different from the campaign."}},"endAt":{"type":"datetime","required":false,"description":"When this channel ends, if different from the campaign.","_meta":{"description":"When this channel ends, if different from the campaign."}},"status":{"type":"text","required":false,"default":"planned","description":"Where this channel stands, from planned through active to completed or cancelled.","_meta":{"description":"Where this channel stands, from planned through active to completed or cancelled."}}},"methods":{"initialize":{"name":"initialize","async":true,"parameters":[],"returnType":"Promise<this>","isStatic":false,"isPublic":true},"save":{"name":"save","async":true,"parameters":[{"name":"options","type":"SmrtSaveOptions","optional":true}],"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","description":"The campaign these results belong to.","_meta":{"description":"The campaign these results belong to.","required":true}},"campaignChannelId":{"type":"foreignKey","required":false,"related":"CampaignChannel","description":"The channel these results came from. Empty when they cover the whole campaign.","_meta":{"description":"The channel these results came from. Empty when they cover the whole campaign.","nullable":true}},"periodStart":{"type":"datetime","required":true,"description":"The first day of the period these results cover.","_meta":{"required":true,"description":"The first day of the period these results cover."}},"periodEnd":{"type":"datetime","required":true,"description":"The last day of the period these results cover.","_meta":{"required":true,"description":"The last day of the period these results cover."}},"spendCents":{"type":"integer","required":false,"default":0,"description":"What was spent in the period, in cents.","_meta":{"description":"What was spent in the period, in cents."}},"impressions":{"type":"integer","required":false,"default":0,"description":"How many times the campaign was shown.","_meta":{"description":"How many times the campaign was shown."}},"clicks":{"type":"integer","required":false,"default":0,"description":"How many times someone clicked through.","_meta":{"description":"How many times someone clicked through."}},"conversions":{"type":"integer","required":false,"default":0,"description":"How many people did what the campaign asked, such as buying.","_meta":{"description":"How many people did what the campaign asked, such as buying."}},"leads":{"type":"integer","required":false,"default":0,"description":"How many new leads came in.","_meta":{"description":"How many new leads came in."}},"revenueCents":{"type":"integer","required":false,"description":"The sales brought in during the period, in cents, if known.","_meta":{"nullable":true,"description":"The sales brought in during the period, in cents, if known."}},"source":{"type":"text","required":true,"default":"","description":"Where these results were reported from.","_meta":{"required":true,"description":"Where these results were reported from."}},"dedupeKey":{"type":"text","required":true,"default":"","description":"The reference this result is filed under, so the same report is never counted twice.","_meta":{"required":true,"description":"The reference this result is filed under, so the same report is never counted twice."}}},"methods":{"initialize":{"name":"initialize","async":true,"parameters":[],"returnType":"Promise<this>","isStatic":false,"isPublic":true},"save":{"name":"save","async":true,"parameters":[{"name":"options","type":"SmrtSaveOptions","optional":true}],"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","recipes":[{"id":"marketing.campaigns","className":"MarketingCampaignsRecipe","label":"Campaigns","summary":"Plan a marketing campaign, set its budget and dates, choose where it runs and see what it brought in.","synonyms":["marketing","marketing campaigns","promotions","advertising","ad campaigns","campaign results"],"models":["@happyvertical/smrt-marketing:Campaign","@happyvertical/smrt-marketing:CampaignChannel","@happyvertical/smrt-marketing:CampaignMetricSnapshot"],"nav":[{"label":"Campaigns","model":"@happyvertical/smrt-marketing:Campaign","icon":"tag","description":"Every campaign, with its budget, dates and where it stands.","noun":"campaign"},{"label":"Channels","model":"@happyvertical/smrt-marketing:CampaignChannel","icon":"layers","description":"Where each campaign runs, such as an ad group or a social post, and its share of the budget.","noun":"channel"}],"requires":[],"section":{"id":"grow","label":"Grow","icon":"tag","description":"Bring in new customers and reward the people who help."},"options":{"@happyvertical/smrt-marketing:Campaign":{"fields":{"name":{"order":1},"objective":{"order":2},"status":{"order":3},"startAt":{"label":"Starts","order":4},"endAt":{"label":"Ends","order":5},"budgetCents":{"label":"Budget (cents)","order":6},"currency":{"order":7},"customerId":{"label":"Customer","visibility":"advanced"},"campaignKey":{"label":"Reference","visibility":"advanced"},"tenantId":{"visibility":"hidden"},"metadata":{"visibility":"hidden"}}},"@happyvertical/smrt-marketing:CampaignChannel":{"fields":{"campaignId":{"label":"Campaign","order":1},"channelKind":{"label":"Kind","order":2},"channelRef":{"label":"Name","order":3},"allocatedBudgetCents":{"label":"Budget share (cents)","order":4},"status":{"order":5},"startAt":{"label":"Starts","order":6},"endAt":{"label":"Ends","order":7},"tenantId":{"visibility":"hidden"}}},"@happyvertical/smrt-marketing:CampaignMetricSnapshot":{"fields":{"campaignId":{"label":"Campaign","order":1},"campaignChannelId":{"label":"Channel","order":2},"periodStart":{"label":"From","order":3},"periodEnd":{"label":"To","order":4},"spendCents":{"label":"Spend (cents)","order":5},"impressions":{"order":6},"clicks":{"order":7},"conversions":{"order":8},"leads":{"order":9},"revenueCents":{"label":"Revenue (cents)","order":10},"source":{"order":11},"tenantId":{"visibility":"hidden"},"dedupeKey":{"visibility":"hidden"}}}},"help":{"markdown":"## Overview\\n\\nCampaigns is where you plan a push to bring in customers: a sale, a launch, a\\nseasonal promotion. Each campaign has a budget, start and end dates and a\\nstatus that shows where it stands, from draft through active to completed. A\\ncampaign runs on one or more channels, such as an ad group, a social post, an\\nemail or an event, each with its share of the budget. Results come back from\\nthe channels' reporting, period by period, so you can see what each campaign\\nand channel brought in for what it cost.\\n\\n## Tasks\\n\\n### Plan a campaign\\n\\n1. Open the list of campaigns and choose **New**.\\n2. Type the **{field:Campaign.name}**, for example \\"Spring widget sale\\".\\n3. Say what it is for in **{field:Campaign.objective}**, such as awareness or new leads.\\n4. Set when it **{field:Campaign.startAt}** and when it **{field:Campaign.endAt}**. The end cannot be before the start.\\n5. Enter the **{field:Campaign.budgetCents}** as a whole number of cents, so $500 is 50000, and check the **{field:Campaign.currency}**.\\n6. Save. A new campaign starts as a draft.\\n\\n### See where a campaign stands\\n\\n1. Open the list of campaigns.\\n2. The **{field:Campaign.status}** shows whether each one is still a draft, scheduled, active, paused, completed or archived. It moves forward as the campaign is scheduled, run and wrapped up; you do not set it by hand.\\n3. Open a campaign to change its name, dates or budget while it is still being planned.\\n\\n### Add a channel to a campaign\\n\\n1. Open the list of channels and choose **New**.\\n2. Pick the **{field:CampaignChannel.campaignId}** it belongs to.\\n3. Choose the **{field:CampaignChannel.channelKind}**, such as an ad group, a social post, a message, content or an event.\\n4. Type the **{field:CampaignChannel.channelRef}** the channel goes by, so its results can be matched to it later.\\n5. Enter its **{field:CampaignChannel.allocatedBudgetCents}** as a whole number of cents.\\n6. If the channel runs on different dates from the campaign, set when it **{field:CampaignChannel.startAt}** and **{field:CampaignChannel.endAt}**.\\n7. Save. You can edit a channel later, or remove one that will not run.\\n\\n### Read the results\\n\\nResults arrive from the channels' reporting; nobody types them in. Each one\\ncovers a period for one campaign, or for one channel within it. A result is\\nnever changed once it is in: a correction arrives as a new result for the same\\nperiod.\\n\\n1. Open a campaign and look at its results, listed under the campaign.\\n2. Each result names the **{field:CampaignMetricSnapshot.campaignId}** it belongs to. A result with no **{field:CampaignMetricSnapshot.campaignChannelId}** covers the whole campaign.\\n3. Check the period, **{field:CampaignMetricSnapshot.periodStart}** to **{field:CampaignMetricSnapshot.periodEnd}**.\\n4. Compare the **{field:CampaignMetricSnapshot.spendCents}** with the **{field:CampaignMetricSnapshot.clicks}**, **{field:CampaignMetricSnapshot.leads}** and **{field:CampaignMetricSnapshot.conversions}** it brought in, and the **{field:CampaignMetricSnapshot.revenueCents}** where the channel reports it.\\n5. The **{field:CampaignMetricSnapshot.source}** says which channel's reporting sent the result.\\n","fieldRefs":["Campaign.budgetCents","Campaign.currency","Campaign.endAt","Campaign.name","Campaign.objective","Campaign.startAt","Campaign.status","CampaignChannel.allocatedBudgetCents","CampaignChannel.campaignId","CampaignChannel.channelKind","CampaignChannel.channelRef","CampaignChannel.endAt","CampaignChannel.startAt","CampaignMetricSnapshot.campaignChannelId","CampaignMetricSnapshot.campaignId","CampaignMetricSnapshot.clicks","CampaignMetricSnapshot.conversions","CampaignMetricSnapshot.leads","CampaignMetricSnapshot.periodEnd","CampaignMetricSnapshot.periodStart","CampaignMetricSnapshot.revenueCents","CampaignMetricSnapshot.source","CampaignMetricSnapshot.spendCents"]},"demo":{"mode":"server","reasons":["Needs a server because its package depends on @happyvertical/smrt-tenancy, which do not build for a browser (#3624)."]}}],"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 {
|
|
@@ -121,13 +121,13 @@ var Campaign = class extends SmrtObject {
|
|
|
121
121
|
if (this.isPersisted) loadedCampaignStatus.set(this, this.status);
|
|
122
122
|
return this;
|
|
123
123
|
}
|
|
124
|
-
async save() {
|
|
125
|
-
if (this.customerId === null) return this.saveLifecycle();
|
|
124
|
+
async save(options) {
|
|
125
|
+
if (this.customerId === null) return this.saveLifecycle(options);
|
|
126
126
|
const db = this.db;
|
|
127
127
|
if (typeof db.transaction !== "function") throw new Error("Campaign.save requires a database adapter with transaction support.");
|
|
128
|
-
return db.transaction(async (transactionDb) => this.withDatabase(transactionDb, async (bound) => bound.saveLifecycle()));
|
|
128
|
+
return db.transaction(async (transactionDb) => this.withDatabase(transactionDb, async (bound) => bound.saveLifecycle(options)));
|
|
129
129
|
}
|
|
130
|
-
async saveLifecycle() {
|
|
130
|
+
async saveLifecycle(options) {
|
|
131
131
|
this.prepareIdentityForSave();
|
|
132
132
|
if (this.customerId !== null) await assertCustomersBelongToTenant(this.options, this.tenantId, [this.customerId], "Campaign.save", "update");
|
|
133
133
|
const prior = await this.resolvePriorStatus();
|
|
@@ -135,7 +135,7 @@ var Campaign = class extends SmrtObject {
|
|
|
135
135
|
this.assertSchedule();
|
|
136
136
|
let result;
|
|
137
137
|
try {
|
|
138
|
-
const persist = async () => await super.save();
|
|
138
|
+
const persist = async () => await super.save(options);
|
|
139
139
|
const tenantContext = isSystemContext() || isSuperAdminBypass() ? void 0 : getCurrentTenant();
|
|
140
140
|
result = tenantContext ? await withTenant({
|
|
141
141
|
...tenantContext,
|
|
@@ -331,11 +331,11 @@ var CampaignChannel = class extends SmrtObject {
|
|
|
331
331
|
this.endAt = CampaignChannel.coerceDate(this.endAt);
|
|
332
332
|
return this;
|
|
333
333
|
}
|
|
334
|
-
async save() {
|
|
334
|
+
async save(options) {
|
|
335
335
|
if (!CAMPAIGN_CHANNEL_STATUSES.includes(this.status)) throw new Error(`CampaignChannel ${this.channelRef || this.id}: unknown status '${this.status}'.`);
|
|
336
336
|
if (!Number.isInteger(this.allocatedBudgetCents) || this.allocatedBudgetCents < 0) throw new Error("CampaignChannel allocatedBudgetCents must be a non-negative integer.");
|
|
337
337
|
if (this.startAt && this.endAt && this.endAt.getTime() < this.startAt.getTime()) throw new Error("CampaignChannel endAt must be on or after startAt.");
|
|
338
|
-
return await super.save();
|
|
338
|
+
return await super.save(options);
|
|
339
339
|
}
|
|
340
340
|
static coerceDate(value) {
|
|
341
341
|
if (value == null) return null;
|
|
@@ -519,7 +519,7 @@ var CampaignMetricSnapshot = class extends SmrtObject {
|
|
|
519
519
|
if (this.isPersisted) persistedSnapshotState.set(this, this.serializeState());
|
|
520
520
|
return this;
|
|
521
521
|
}
|
|
522
|
-
async save() {
|
|
522
|
+
async save(options) {
|
|
523
523
|
this.assertMetrics();
|
|
524
524
|
await this.assertChannelMatchesCampaign();
|
|
525
525
|
const captured = persistedSnapshotState.get(this);
|
|
@@ -532,7 +532,7 @@ var CampaignMetricSnapshot = class extends SmrtObject {
|
|
|
532
532
|
} catch (error) {
|
|
533
533
|
if (error instanceof Error && error.message.includes("idempotent ingestion")) throw error;
|
|
534
534
|
}
|
|
535
|
-
const result = await super.save();
|
|
535
|
+
const result = await super.save(options);
|
|
536
536
|
persistedSnapshotState.set(this, this.serializeState());
|
|
537
537
|
return result;
|
|
538
538
|
}
|