@mj-biz-apps/marketing-server 0.2.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/__tests__/linkedInTargeting.test.d.ts +2 -0
- package/dist/__tests__/linkedInTargeting.test.d.ts.map +1 -0
- package/dist/__tests__/linkedInTargeting.test.js +65 -0
- package/dist/__tests__/linkedInTargeting.test.js.map +1 -0
- package/dist/agents/BaseMarketingAgent.d.ts.map +1 -1
- package/dist/agents/BaseMarketingAgent.js +22 -1
- package/dist/agents/BaseMarketingAgent.js.map +1 -1
- package/dist/agents/MarketingCreativeAgent.d.ts +16 -0
- package/dist/agents/MarketingCreativeAgent.d.ts.map +1 -0
- package/dist/agents/MarketingCreativeAgent.js +28 -0
- package/dist/agents/MarketingCreativeAgent.js.map +1 -0
- package/dist/agents/MarketingExperimentationAgent.d.ts +53 -0
- package/dist/agents/MarketingExperimentationAgent.d.ts.map +1 -1
- package/dist/agents/MarketingExperimentationAgent.js +241 -15
- package/dist/agents/MarketingExperimentationAgent.js.map +1 -1
- package/dist/agents/MarketingStrategyOnboardingAgent.d.ts.map +1 -1
- package/dist/agents/MarketingStrategyOnboardingAgent.js +38 -4
- package/dist/agents/MarketingStrategyOnboardingAgent.js.map +1 -1
- package/dist/agents/index.d.ts +1 -0
- package/dist/agents/index.d.ts.map +1 -1
- package/dist/agents/index.js +3 -0
- package/dist/agents/index.js.map +1 -1
- package/dist/generated/graphql-schemas/__mj_BizAppsMarketing.d.ts +397 -310
- package/dist/generated/graphql-schemas/__mj_BizAppsMarketing.d.ts.map +1 -1
- package/dist/generated/graphql-schemas/__mj_BizAppsMarketing.js +678 -326
- package/dist/generated/graphql-schemas/__mj_BizAppsMarketing.js.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/programs/ContentPostProgramDriver.d.ts +4 -8
- package/dist/programs/ContentPostProgramDriver.d.ts.map +1 -1
- package/dist/programs/ContentPostProgramDriver.js +16 -46
- package/dist/programs/ContentPostProgramDriver.js.map +1 -1
- package/dist/programs/EmailProgramDriver.d.ts +3 -5
- package/dist/programs/EmailProgramDriver.d.ts.map +1 -1
- package/dist/programs/EmailProgramDriver.js +15 -21
- package/dist/programs/EmailProgramDriver.js.map +1 -1
- package/dist/programs/google/GoogleAdsProgramDriver.d.ts +3 -5
- package/dist/programs/google/GoogleAdsProgramDriver.d.ts.map +1 -1
- package/dist/programs/google/GoogleAdsProgramDriver.js +40 -28
- package/dist/programs/google/GoogleAdsProgramDriver.js.map +1 -1
- package/dist/programs/google/googleBrandAssets.d.ts +5 -0
- package/dist/programs/google/googleBrandAssets.d.ts.map +1 -1
- package/dist/programs/google/googleBrandAssets.js +20 -15
- package/dist/programs/google/googleBrandAssets.js.map +1 -1
- package/dist/programs/index.d.ts +6 -0
- package/dist/programs/index.d.ts.map +1 -1
- package/dist/programs/index.js +5 -0
- package/dist/programs/index.js.map +1 -1
- package/dist/programs/linkedin/LinkedInAdsClient.d.ts +123 -2
- package/dist/programs/linkedin/LinkedInAdsClient.d.ts.map +1 -1
- package/dist/programs/linkedin/LinkedInAdsClient.js +196 -29
- package/dist/programs/linkedin/LinkedInAdsClient.js.map +1 -1
- package/dist/programs/linkedin/LinkedInAdsProgramDriver.d.ts +40 -11
- package/dist/programs/linkedin/LinkedInAdsProgramDriver.d.ts.map +1 -1
- package/dist/programs/linkedin/LinkedInAdsProgramDriver.js +397 -94
- package/dist/programs/linkedin/LinkedInAdsProgramDriver.js.map +1 -1
- package/dist/programs/linkedin/linkedInExecutionContext.d.ts +6 -0
- package/dist/programs/linkedin/linkedInExecutionContext.d.ts.map +1 -1
- package/dist/programs/linkedin/linkedInExecutionContext.js +2 -1
- package/dist/programs/linkedin/linkedInExecutionContext.js.map +1 -1
- package/dist/programs/meta/MetaAdsClient.d.ts +101 -0
- package/dist/programs/meta/MetaAdsClient.d.ts.map +1 -0
- package/dist/programs/meta/MetaAdsClient.js +239 -0
- package/dist/programs/meta/MetaAdsClient.js.map +1 -0
- package/dist/programs/meta/MetaAdsProgramDriver.d.ts +76 -0
- package/dist/programs/meta/MetaAdsProgramDriver.d.ts.map +1 -0
- package/dist/programs/meta/MetaAdsProgramDriver.js +431 -0
- package/dist/programs/meta/MetaAdsProgramDriver.js.map +1 -0
- package/dist/programs/meta/metaAdsExecutionContext.d.ts +39 -0
- package/dist/programs/meta/metaAdsExecutionContext.d.ts.map +1 -0
- package/dist/programs/meta/metaAdsExecutionContext.js +99 -0
- package/dist/programs/meta/metaAdsExecutionContext.js.map +1 -0
- package/package.json +9 -8
package/dist/index.d.ts
CHANGED
|
@@ -6,12 +6,14 @@
|
|
|
6
6
|
* GraphQL resolvers are registered with the MJ class factory.
|
|
7
7
|
*/
|
|
8
8
|
import './generated/generated.js';
|
|
9
|
-
export { LoadAllProgramDrivers, EmailProgramDriver, LoadEmailProgramDriver, ContentPostProgramDriver, LoadContentPostProgramDriver, LinkedInAdsProgramDriver, LoadLinkedInAdsProgramDriver, GoogleAdsProgramDriver, LoadGoogleAdsProgramDriver, LinkedInAdsClient, LinkedInApiError, resolveLinkedInExecutionContext, LINKEDIN_CREDENTIAL_TYPE, GoogleAdsClient, GoogleAdsApiError, resolveGoogleExecutionContext, GOOGLE_CREDENTIAL_TYPE, } from './programs/index.js';
|
|
9
|
+
export { LoadAllProgramDrivers, EmailProgramDriver, LoadEmailProgramDriver, ContentPostProgramDriver, LoadContentPostProgramDriver, LinkedInAdsProgramDriver, LoadLinkedInAdsProgramDriver, GoogleAdsProgramDriver, LoadGoogleAdsProgramDriver, MetaAdsProgramDriver, LoadMetaAdsProgramDriver, LinkedInAdsClient, LinkedInApiError, resolveLinkedInExecutionContext, LINKEDIN_CREDENTIAL_TYPE, GoogleAdsClient, GoogleAdsApiError, resolveGoogleExecutionContext, GOOGLE_CREDENTIAL_TYPE, MetaAdsClient, MetaAdsApiError, resolveMetaExecutionContext, normalizeMetaAdAccountId, META_CREDENTIAL_TYPE, } from './programs/index.js';
|
|
10
|
+
export type { LinkedInExecutionContext, LinkedInExecutionReady, LinkedInContextResolver, GoogleExecutionContext, GoogleExecutionReady, GoogleContextResolver, MetaExecutionContext, MetaExecutionReady, MetaContextResolver } from './programs/index.js';
|
|
10
11
|
export { BaseMarketingAgent, LoadBaseMarketingAgent, LoadAllMarketingAgents, type AuthorizedBrandOption } from './agents/index.js';
|
|
11
12
|
export { MarketingStrategyOnboardingAgent, LoadMarketingStrategyOnboardingAgent } from './agents/index.js';
|
|
12
13
|
export { MarketingExperimentationAgent, LoadMarketingExperimentationAgent } from './agents/index.js';
|
|
13
14
|
export { MarketingOperationsAgent, LoadMarketingOperationsAgent } from './agents/index.js';
|
|
14
15
|
export { MarketingPodcastIngestionAgent, LoadMarketingPodcastIngestionAgent } from './agents/index.js';
|
|
16
|
+
export { MarketingCreativeAgent, LoadMarketingCreativeAgent } from './agents/index.js';
|
|
15
17
|
export { CLASS_REGISTRATIONS } from './generated/class-registrations-manifest.js';
|
|
16
18
|
/**
|
|
17
19
|
* Absolute paths to the resolver files (generated + custom), for use with
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AA2BH,OAAO,0BAA0B,CAAC;AAQlC,OAAO,EACH,qBAAqB,EACrB,kBAAkB,EAAE,sBAAsB,EAC1C,wBAAwB,EAAE,4BAA4B,EACtD,wBAAwB,EAAE,4BAA4B,EACtD,sBAAsB,EAAE,0BAA0B,EAClD,iBAAiB,EAAE,gBAAgB,EAAE,+BAA+B,EAAE,wBAAwB,EAC9F,eAAe,EAAE,iBAAiB,EAAE,6BAA6B,EAAE,sBAAsB,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AA2BH,OAAO,0BAA0B,CAAC;AAQlC,OAAO,EACH,qBAAqB,EACrB,kBAAkB,EAAE,sBAAsB,EAC1C,wBAAwB,EAAE,4BAA4B,EACtD,wBAAwB,EAAE,4BAA4B,EACtD,sBAAsB,EAAE,0BAA0B,EAClD,oBAAoB,EAAE,wBAAwB,EAC9C,iBAAiB,EAAE,gBAAgB,EAAE,+BAA+B,EAAE,wBAAwB,EAC9F,eAAe,EAAE,iBAAiB,EAAE,6BAA6B,EAAE,sBAAsB,EACzF,aAAa,EAAE,eAAe,EAAE,2BAA2B,EAAE,wBAAwB,EAAE,oBAAoB,GAC9G,MAAM,qBAAqB,CAAC;AAC7B,YAAY,EAAE,wBAAwB,EAAE,sBAAsB,EAAE,uBAAuB,EAAE,sBAAsB,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAKzP,OAAO,EAAE,kBAAkB,EAAE,sBAAsB,EAAE,sBAAsB,EAAE,KAAK,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AACnI,OAAO,EAAE,gCAAgC,EAAE,oCAAoC,EAAE,MAAM,mBAAmB,CAAC;AAK3G,OAAO,EAAE,6BAA6B,EAAE,iCAAiC,EAAE,MAAM,mBAAmB,CAAC;AAGrG,OAAO,EAAE,wBAAwB,EAAE,4BAA4B,EAAE,MAAM,mBAAmB,CAAC;AAC3F,OAAO,EAAE,8BAA8B,EAAE,kCAAkC,EAAE,MAAM,mBAAmB,CAAC;AAEvG,OAAO,EAAE,sBAAsB,EAAE,0BAA0B,EAAE,MAAM,mBAAmB,CAAC;AAQvF,OAAO,EAAE,mBAAmB,EAAE,MAAM,6CAA6C,CAAC;AAOlF;;;;;;;;GAQG;AACH,eAAO,MAAM,cAAc,UAG1B,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,0BAA0B,IAAI,IAAI,CAajD"}
|
package/dist/index.js
CHANGED
|
@@ -36,7 +36,7 @@ import './generated/generated.js';
|
|
|
36
36
|
// package root, and a registered-but-unexported class kills its boot with an
|
|
37
37
|
// opaque loader error (same rule as the agents below).
|
|
38
38
|
import { LoadAllProgramDrivers } from './programs/index.js';
|
|
39
|
-
export { LoadAllProgramDrivers, EmailProgramDriver, LoadEmailProgramDriver, ContentPostProgramDriver, LoadContentPostProgramDriver, LinkedInAdsProgramDriver, LoadLinkedInAdsProgramDriver, GoogleAdsProgramDriver, LoadGoogleAdsProgramDriver, LinkedInAdsClient, LinkedInApiError, resolveLinkedInExecutionContext, LINKEDIN_CREDENTIAL_TYPE, GoogleAdsClient, GoogleAdsApiError, resolveGoogleExecutionContext, GOOGLE_CREDENTIAL_TYPE, } from './programs/index.js';
|
|
39
|
+
export { LoadAllProgramDrivers, EmailProgramDriver, LoadEmailProgramDriver, ContentPostProgramDriver, LoadContentPostProgramDriver, LinkedInAdsProgramDriver, LoadLinkedInAdsProgramDriver, GoogleAdsProgramDriver, LoadGoogleAdsProgramDriver, MetaAdsProgramDriver, LoadMetaAdsProgramDriver, LinkedInAdsClient, LinkedInApiError, resolveLinkedInExecutionContext, LINKEDIN_CREDENTIAL_TYPE, GoogleAdsClient, GoogleAdsApiError, resolveGoogleExecutionContext, GOOGLE_CREDENTIAL_TYPE, MetaAdsClient, MetaAdsApiError, resolveMetaExecutionContext, normalizeMetaAdAccountId, META_CREDENTIAL_TYPE, } from './programs/index.js';
|
|
40
40
|
// Agent classes — imported after entities/actions so their @RegisterClass
|
|
41
41
|
// registrations resolve against already-registered bases.
|
|
42
42
|
import { LoadAllMarketingAgents } from './agents/index.js';
|
|
@@ -51,6 +51,8 @@ export { MarketingExperimentationAgent, LoadMarketingExperimentationAgent } from
|
|
|
51
51
|
// a registered-but-unexported class breaks the host's typecheck, not ours.
|
|
52
52
|
export { MarketingOperationsAgent, LoadMarketingOperationsAgent } from './agents/index.js';
|
|
53
53
|
export { MarketingPodcastIngestionAgent, LoadMarketingPodcastIngestionAgent } from './agents/index.js';
|
|
54
|
+
// Every @RegisterClass class is a ROOT export: a host's class-registrations manifest imports them by name (KI-133).
|
|
55
|
+
export { MarketingCreativeAgent, LoadMarketingCreativeAgent } from './agents/index.js';
|
|
54
56
|
// Custom (hand-written) GraphQL resolvers go here as they are added — each
|
|
55
57
|
// needs BOTH a static import (so its @Resolver decorator fires) AND coverage
|
|
56
58
|
// by RESOLVER_PATHS below (so TypeGraphQL builds it into the schema).
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,0EAA0E;AAC1E,8DAA8D;AAC9D,8EAA8E;AAC9E,yEAAyE;AACzE,OAAO,EAAE,qBAAqB,IAAI,qBAAqB,EAAE,MAAM,iCAAiC,CAAC;AACjG,mFAAmF;AACnF,qFAAqF;AACrF,kFAAkF;AAClF,sFAAsF;AACtF,OAAO,EAAE,qBAAqB,IAAI,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAC3F,sFAAsF;AACtF,uFAAuF;AACvF,mFAAmF;AACnF,OAAO,EAAE,+BAA+B,EAAE,MAAM,6CAA6C,CAAC;AAC9F,OAAO,EAAE,oBAAoB,EAAE,MAAM,gCAAgC,CAAC;AACtE,4GAA4G;AAC5G,OAAO,EAAE,qBAAqB,EAAE,MAAM,kCAAkC,CAAC;AACzE,mGAAmG;AACnG,kGAAkG;AAClG,0FAA0F;AAC1F,OAAO,EAAE,aAAa,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAC5E,OAAO,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AACjE,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAEjD,oEAAoE;AACpE,OAAO,0BAA0B,CAAC;AAElC,+EAA+E;AAC/E,kEAAkE;AAClE,2EAA2E;AAC3E,6EAA6E;AAC7E,uDAAuD;AACvD,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EACH,qBAAqB,EACrB,kBAAkB,EAAE,sBAAsB,EAC1C,wBAAwB,EAAE,4BAA4B,EACtD,wBAAwB,EAAE,4BAA4B,EACtD,sBAAsB,EAAE,0BAA0B,EAClD,iBAAiB,EAAE,gBAAgB,EAAE,+BAA+B,EAAE,wBAAwB,EAC9F,eAAe,EAAE,iBAAiB,EAAE,6BAA6B,EAAE,sBAAsB,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type UserInfo } from '@memberjunction/core';
|
|
2
|
-
import { BaseProgramTypeDriver, type DriverValidationIssue, type MetricCollectionWindow, type MetricObservation, type ProgramForDriver, type ProgramTypeParamSpec, type DriverRetirementReason, type RefreshStatusResult } from '@mj-biz-apps/marketing-core';
|
|
2
|
+
import { BaseProgramTypeDriver, type DriverValidationIssue, type MetricCollectionWindow, type MetricObservation, type ProgramForDriver, type ProgramTypeParamSpec, type DriverRetirementReason, type RefreshStatusResult, type RetireStatusResult } from '@mj-biz-apps/marketing-core';
|
|
3
3
|
/**
|
|
4
4
|
* ContentPost driver — the first driver whose measurement is real (PRD v2 §3.2/§3.4).
|
|
5
5
|
*
|
|
@@ -12,8 +12,8 @@ import { BaseProgramTypeDriver, type DriverValidationIssue, type MetricCollectio
|
|
|
12
12
|
* `refreshStatus` maintains both layers of the model:
|
|
13
13
|
* 1. the SPRINT's window totals (all of the brand's content activity in the window —
|
|
14
14
|
* the reliable, always-present numbers), and
|
|
15
|
-
* 2. a per-program **Linked** ProgramObservation for the
|
|
16
|
-
* idempotently (re-polling a
|
|
15
|
+
* 2. a per-program **Linked** ProgramObservation for the sprint, converged
|
|
16
|
+
* idempotently (re-polling a sprint updates the same row — KI-93).
|
|
17
17
|
*
|
|
18
18
|
* The other launch types (Email, Retargeting, Physical Mail) measure external systems
|
|
19
19
|
* and keep the base class's honest no-op until their providers land — their attribution
|
|
@@ -29,16 +29,12 @@ export declare class ContentPostProgramDriver extends BaseProgramTypeDriver {
|
|
|
29
29
|
onLock(_program: ProgramForDriver): Promise<void>;
|
|
30
30
|
collectMetrics(program: ProgramForDriver, window: MetricCollectionWindow): Promise<MetricObservation[] | null>;
|
|
31
31
|
refreshStatus(program: ProgramForDriver, window: MetricCollectionWindow): Promise<RefreshStatusResult>;
|
|
32
|
-
onRetire(_program: ProgramForDriver, _reason: DriverRetirementReason): Promise<
|
|
32
|
+
onRetire(_program: ProgramForDriver, _reason: DriverRetirementReason): Promise<RetireStatusResult>;
|
|
33
33
|
/** Brand-wide CPM totals for the window. */
|
|
34
34
|
private brandSlice;
|
|
35
35
|
/** CPM totals for the window, restricted to content joined to THIS program. */
|
|
36
36
|
private programSlice;
|
|
37
37
|
private slice;
|
|
38
|
-
/** The sprint that CONTAINS the window's start (StartDate <= start < EndDate) — never an overlap test, which double-matches at the seam. */
|
|
39
|
-
private windowSprintId;
|
|
40
|
-
/** Insert-or-update the window's Linked observation so re-polling converges. */
|
|
41
|
-
private convergeObservation;
|
|
42
38
|
}
|
|
43
39
|
export declare function LoadContentPostProgramDriver(): void;
|
|
44
40
|
//# sourceMappingURL=ContentPostProgramDriver.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ContentPostProgramDriver.d.ts","sourceRoot":"","sources":["../../src/programs/ContentPostProgramDriver.ts"],"names":[],"mappings":"AACA,OAAO,EAAgC,KAAK,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AACnF,OAAO,EACH,qBAAqB,EAErB,KAAK,qBAAqB,EAC1B,KAAK,sBAAsB,EAC3B,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EACrB,KAAK,oBAAoB,EACzB,KAAK,sBAAsB,EAC3B,KAAK,mBAAmB,
|
|
1
|
+
{"version":3,"file":"ContentPostProgramDriver.d.ts","sourceRoot":"","sources":["../../src/programs/ContentPostProgramDriver.ts"],"names":[],"mappings":"AACA,OAAO,EAAgC,KAAK,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AACnF,OAAO,EACH,qBAAqB,EAErB,KAAK,qBAAqB,EAC1B,KAAK,sBAAsB,EAC3B,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EACrB,KAAK,oBAAoB,EACzB,KAAK,sBAAsB,EAC3B,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,EAC1B,MAAM,6BAA6B,CAAC;AAerC;;;;;;;;;;;;;;;;;;GAkBG;AACH,qBACa,wBAAyB,SAAQ,qBAAqB;IAInD,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC;IAHzC,SAAgB,QAAQ,iBAAiB;IACzC,SAAgB,UAAU,EAAE,aAAa,CAAC,oBAAoB,CAAC,CAAM;gBAExC,WAAW,CAAC,EAAE,QAAQ;IAItC,gBAAgB,CAAC,QAAQ,EAAE,gBAAgB,GAAG,OAAO,CAAC,qBAAqB,EAAE,CAAC;IAI3F,+EAA+E;IAClE,MAAM,CAAC,QAAQ,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IAEjD,cAAc,CACvB,OAAO,EAAE,gBAAgB,EACzB,MAAM,EAAE,sBAAsB,GAC/B,OAAO,CAAC,iBAAiB,EAAE,GAAG,IAAI,CAAC;IAahB,aAAa,CAC/B,OAAO,EAAE,gBAAgB,EACzB,MAAM,EAAE,sBAAsB,GAC/B,OAAO,CAAC,mBAAmB,CAAC;IA4ClB,QAAQ,CAAC,QAAQ,EAAE,gBAAgB,EAAE,OAAO,EAAE,sBAAsB,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAO/G,4CAA4C;YAC9B,UAAU;IAIxB,+EAA+E;YACjE,YAAY;YAkBZ,KAAK;CAmBtB;AAED,wBAAgB,4BAA4B,SAAK"}
|
|
@@ -10,10 +10,13 @@ var __metadata = (this && this.__metadata) || function (k, v) {
|
|
|
10
10
|
import { EscapeSQLString, RegisterClass } from '@memberjunction/global';
|
|
11
11
|
import { Metadata, RunView, LogStatus } from '@memberjunction/core';
|
|
12
12
|
import { BaseProgramTypeDriver, toMarketingEntityName, } from '@mj-biz-apps/marketing-core';
|
|
13
|
+
import { ConvergeObservation } from '@mj-biz-apps/marketing-actions';
|
|
13
14
|
/** Escapes a value for an ExtraFilter string literal. */
|
|
14
15
|
const esc = (v) => EscapeSQLString(v);
|
|
15
16
|
/** ISO date literal for SQL date comparison. */
|
|
16
17
|
const d = (dt) => dt.toISOString().slice(0, 10);
|
|
18
|
+
/** The content join's SourceRef — also its source family's prefix, which keys its observation row (HA-5). */
|
|
19
|
+
const CONTENT_SOURCE_REF = 'ContentPerformanceMetric via ProgramContent join';
|
|
17
20
|
/**
|
|
18
21
|
* ContentPost driver — the first driver whose measurement is real (PRD v2 §3.2/§3.4).
|
|
19
22
|
*
|
|
@@ -26,8 +29,8 @@ const d = (dt) => dt.toISOString().slice(0, 10);
|
|
|
26
29
|
* `refreshStatus` maintains both layers of the model:
|
|
27
30
|
* 1. the SPRINT's window totals (all of the brand's content activity in the window —
|
|
28
31
|
* the reliable, always-present numbers), and
|
|
29
|
-
* 2. a per-program **Linked** ProgramObservation for the
|
|
30
|
-
* idempotently (re-polling a
|
|
32
|
+
* 2. a per-program **Linked** ProgramObservation for the sprint, converged
|
|
33
|
+
* idempotently (re-polling a sprint updates the same row — KI-93).
|
|
31
34
|
*
|
|
32
35
|
* The other launch types (Email, Retargeting, Physical Mail) measure external systems
|
|
33
36
|
* and keep the base class's honest no-op until their providers land — their attribution
|
|
@@ -54,7 +57,7 @@ let ContentPostProgramDriver = class ContentPostProgramDriver extends BaseProgra
|
|
|
54
57
|
observedMetric: slice.conversions,
|
|
55
58
|
conversionsCount: slice.conversions,
|
|
56
59
|
sampleSize: slice.activity,
|
|
57
|
-
source:
|
|
60
|
+
source: CONTENT_SOURCE_REF,
|
|
58
61
|
attribution: 'Linked',
|
|
59
62
|
}];
|
|
60
63
|
}
|
|
@@ -63,11 +66,15 @@ let ContentPostProgramDriver = class ContentPostProgramDriver extends BaseProgra
|
|
|
63
66
|
if (!user) {
|
|
64
67
|
return { refreshed: false, sprintsUpdated: 0, observationsWritten: 0, note: 'ContentPost: no contextUser supplied.' };
|
|
65
68
|
}
|
|
69
|
+
// The window IS a sprint's (KI-93): its rows are written under that SprintID, never re-derived from dates.
|
|
70
|
+
const sprintId = window.sprintId;
|
|
71
|
+
if (!sprintId) {
|
|
72
|
+
return { refreshed: false, sprintsUpdated: 0, observationsWritten: 0, note: 'ContentPost: refresh needs a sprint window, not a roll-up.' };
|
|
73
|
+
}
|
|
66
74
|
// 1. Window totals for the BRAND — the sprint's reliable numbers.
|
|
67
75
|
const brandSlice = await this.brandSlice(program.brandId, window, user);
|
|
68
|
-
const sprintId = await this.windowSprintId(program.brandId, window, user);
|
|
69
76
|
let sprintsUpdated = 0;
|
|
70
|
-
if (
|
|
77
|
+
if (brandSlice) {
|
|
71
78
|
const md = new Metadata();
|
|
72
79
|
const sprint = await md.GetEntityObject(toMarketingEntityName('Sprints'), user);
|
|
73
80
|
if (await sprint.Load(sprintId)) {
|
|
@@ -78,11 +85,12 @@ let ContentPostProgramDriver = class ContentPostProgramDriver extends BaseProgra
|
|
|
78
85
|
sprintsUpdated = 1;
|
|
79
86
|
}
|
|
80
87
|
}
|
|
81
|
-
// 2. Per-program Linked observation, converged on (ProgramID,
|
|
88
|
+
// 2. Per-program Linked observation, converged on (SprintID, ProgramID, Linked, content family).
|
|
82
89
|
let observationsWritten = 0;
|
|
83
90
|
const progSlice = program.id ? await this.programSlice(program, window) : null;
|
|
84
91
|
if (program.id && progSlice && progSlice.rows > 0) {
|
|
85
|
-
|
|
92
|
+
const saved = await ConvergeObservation({ programId: program.id, sprintId, attribution: 'Linked', sourceRefPrefix: CONTENT_SOURCE_REF }, { window, activityCount: progSlice.activity, conversionsCount: progSlice.conversions, observedMetric: progSlice.conversions, sourceRef: CONTENT_SOURCE_REF }, user);
|
|
93
|
+
observationsWritten = saved ? 1 : 0;
|
|
86
94
|
}
|
|
87
95
|
const note = `ContentPost: window ${d(window.from)}→${d(window.to)} — brand ${brandSlice?.activity ?? 0} activities / ${brandSlice?.conversions ?? 0} conversions; `
|
|
88
96
|
+ (progSlice && progSlice.rows > 0
|
|
@@ -93,6 +101,7 @@ let ContentPostProgramDriver = class ContentPostProgramDriver extends BaseProgra
|
|
|
93
101
|
}
|
|
94
102
|
async onRetire(_program, _reason) {
|
|
95
103
|
// Content keeps existing after a decision; there is no machinery to stand down.
|
|
104
|
+
return { stoodDown: false, note: 'ContentPost: nothing to stand down — the content stays published.' };
|
|
96
105
|
}
|
|
97
106
|
// ------------------------------------------------------------------
|
|
98
107
|
/** Brand-wide CPM totals for the window. */
|
|
@@ -136,45 +145,6 @@ let ContentPostProgramDriver = class ContentPostProgramDriver extends BaseProgra
|
|
|
136
145
|
activity: rows.reduce((n, r) => n + (r.PageViews ?? 0) + (r.EmailClicks ?? 0) + (r.SocialShares ?? 0), 0),
|
|
137
146
|
};
|
|
138
147
|
}
|
|
139
|
-
/** The sprint that CONTAINS the window's start (StartDate <= start < EndDate) — never an overlap test, which double-matches at the seam. */
|
|
140
|
-
async windowSprintId(brandId, w, user) {
|
|
141
|
-
const rv = new RunView();
|
|
142
|
-
const res = await rv.RunView({
|
|
143
|
-
EntityName: toMarketingEntityName('Sprints'),
|
|
144
|
-
ExtraFilter: `BrandID='${esc(brandId)}' AND StartDate <= '${w.from.toISOString()}' AND EndDate > '${w.from.toISOString()}'`,
|
|
145
|
-
Fields: ['ID'], OrderBy: 'StartDate DESC', MaxRows: 1, ResultType: 'simple', BypassCache: true,
|
|
146
|
-
}, user);
|
|
147
|
-
return res.Success ? res.Results?.[0]?.ID ?? null : null;
|
|
148
|
-
}
|
|
149
|
-
/** Insert-or-update the window's Linked observation so re-polling converges. */
|
|
150
|
-
async convergeObservation(programId, sprintId, w, slice, user) {
|
|
151
|
-
const rv = new RunView();
|
|
152
|
-
const existing = await rv.RunView({
|
|
153
|
-
EntityName: toMarketingEntityName('Program Observations'),
|
|
154
|
-
ExtraFilter: `ProgramID='${esc(programId)}' AND AttributionSource='Linked' AND WindowStart='${d(w.from)}' AND WindowEnd='${d(w.to)}'`,
|
|
155
|
-
Fields: ['ID'], MaxRows: 1, ResultType: 'simple', BypassCache: true,
|
|
156
|
-
}, user);
|
|
157
|
-
const md = new Metadata();
|
|
158
|
-
const obs = await md.GetEntityObject(toMarketingEntityName('Program Observations'), user);
|
|
159
|
-
const existingId = existing.Success ? existing.Results?.[0]?.ID : undefined;
|
|
160
|
-
if (existingId) {
|
|
161
|
-
if (!await obs.Load(existingId))
|
|
162
|
-
return 0;
|
|
163
|
-
}
|
|
164
|
-
else {
|
|
165
|
-
obs.NewRecord();
|
|
166
|
-
obs.ProgramID = programId;
|
|
167
|
-
obs.AttributionSource = 'Linked';
|
|
168
|
-
obs.WindowStart = w.from;
|
|
169
|
-
obs.WindowEnd = w.to;
|
|
170
|
-
}
|
|
171
|
-
obs.SprintID = sprintId;
|
|
172
|
-
obs.ConversionsCount = slice.conversions;
|
|
173
|
-
obs.ObservedMetric = slice.conversions;
|
|
174
|
-
obs.ActivityCount = slice.activity;
|
|
175
|
-
obs.SourceRef = 'ContentPerformanceMetric via ProgramContent join';
|
|
176
|
-
return await obs.Save() ? 1 : 0;
|
|
177
|
-
}
|
|
178
148
|
};
|
|
179
149
|
ContentPostProgramDriver = __decorate([
|
|
180
150
|
RegisterClass(BaseProgramTypeDriver, 'ContentPostProgramDriver'),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ContentPostProgramDriver.js","sourceRoot":"","sources":["../../src/programs/ContentPostProgramDriver.ts"],"names":[],"mappings":";;;;;;;;;AAAA,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACxE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,SAAS,EAAiB,MAAM,sBAAsB,CAAC;AACnF,OAAO,EACH,qBAAqB,EACrB,qBAAqB,
|
|
1
|
+
{"version":3,"file":"ContentPostProgramDriver.js","sourceRoot":"","sources":["../../src/programs/ContentPostProgramDriver.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type UserInfo } from '@memberjunction/core';
|
|
2
|
-
import { BaseProgramTypeDriver, type DriverRetirementReason, type DriverValidationIssue, type MetricCollectionWindow, type MetricObservation, type ProgramForDriver, type ProgramTypeParamSpec, type RefreshStatusResult } from '@mj-biz-apps/marketing-core';
|
|
2
|
+
import { BaseProgramTypeDriver, type DriverRetirementReason, type DriverValidationIssue, type MetricCollectionWindow, type MetricObservation, type ProgramForDriver, type ProgramTypeParamSpec, type RefreshStatusResult, type RetireStatusResult } from '@mj-biz-apps/marketing-core';
|
|
3
3
|
/**
|
|
4
4
|
* Email program driver on the BizApps substrate (PRD v3 S2).
|
|
5
5
|
*
|
|
@@ -37,18 +37,16 @@ export declare class EmailProgramDriver extends BaseProgramTypeDriver {
|
|
|
37
37
|
collectMetrics(program: ProgramForDriver, window: MetricCollectionWindow): Promise<MetricObservation[] | null>;
|
|
38
38
|
/**
|
|
39
39
|
* The poller: the sprint's window totals (the trusted numbers) plus this
|
|
40
|
-
* program's Linked observation for the
|
|
40
|
+
* program's Linked observation for the sprint, both converged.
|
|
41
41
|
*/
|
|
42
42
|
refreshStatus(program: ProgramForDriver, window: MetricCollectionWindow): Promise<RefreshStatusResult>;
|
|
43
43
|
/** Sequences keep sending until stopped; the stop lands with the execution providers (S8). */
|
|
44
|
-
onRetire(_program: ProgramForDriver, _reason: DriverRetirementReason): Promise<
|
|
44
|
+
onRetire(_program: ProgramForDriver, _reason: DriverRetirementReason): Promise<RetireStatusResult>;
|
|
45
45
|
/** The brand's source map + the per-request provider (SequenceService pattern — never the process-global default). */
|
|
46
46
|
private context;
|
|
47
47
|
private sourceMapOrNull;
|
|
48
48
|
/** Does the program link onto the CampaignLog entity with a scoped hint? */
|
|
49
49
|
private hasThreadLink;
|
|
50
|
-
/** The sprint that CONTAINS the window's start — never an overlap test (it double-matches at the seam). */
|
|
51
|
-
private windowSprintId;
|
|
52
50
|
/** Only the PRESENCE of SegmentCuts is interpreted; no cut shape has been agreed. */
|
|
53
51
|
private hasDeclaredCuts;
|
|
54
52
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EmailProgramDriver.d.ts","sourceRoot":"","sources":["../../src/programs/EmailProgramDriver.ts"],"names":[],"mappings":"AAAA,OAAO,EAA2D,KAAK,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAE9G,OAAO,EACH,qBAAqB,EAIrB,KAAK,sBAAsB,EAC3B,KAAK,qBAAqB,EAC1B,KAAK,sBAAsB,EAC3B,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EACrB,KAAK,oBAAoB,EACzB,KAAK,mBAAmB,
|
|
1
|
+
{"version":3,"file":"EmailProgramDriver.d.ts","sourceRoot":"","sources":["../../src/programs/EmailProgramDriver.ts"],"names":[],"mappings":"AAAA,OAAO,EAA2D,KAAK,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAE9G,OAAO,EACH,qBAAqB,EAIrB,KAAK,sBAAsB,EAC3B,KAAK,qBAAqB,EAC1B,KAAK,sBAAsB,EAC3B,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EACrB,KAAK,oBAAoB,EACzB,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,EAC1B,MAAM,6BAA6B,CAAC;AAYrC;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBACa,kBAAmB,SAAQ,qBAAqB;IAYtC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC;IAXhD,SAAgB,QAAQ,WAAW;IACnC,SAAgB,UAAU,EAAE,aAAa,CAAC,oBAAoB,CAAC,CAQ7D;gBAEkC,WAAW,CAAC,EAAE,QAAQ;IAI1D;;;;;OAKG;IACU,gBAAgB,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,qBAAqB,EAAE,CAAC;IAiC1F,iHAAiH;IACpG,MAAM,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IAQhD,cAAc,CAAC,OAAO,EAAE,gBAAgB,EAAE,MAAM,EAAE,sBAAsB,GAAG,OAAO,CAAC,iBAAiB,EAAE,GAAG,IAAI,CAAC;IAiB3H;;;OAGG;IACmB,aAAa,CAAC,OAAO,EAAE,gBAAgB,EAAE,MAAM,EAAE,sBAAsB,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAgC5H,8FAA8F;IACjF,QAAQ,CAAC,QAAQ,EAAE,gBAAgB,EAAE,OAAO,EAAE,sBAAsB,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAM/G,sHAAsH;YACxG,OAAO;YAUP,eAAe;IAS7B,4EAA4E;YAC9D,aAAa;IAW3B,qFAAqF;IACrF,OAAO,CAAC,eAAe;CAa1B;AAED,wBAAgB,sBAAsB,SAAK"}
|
|
@@ -115,27 +115,28 @@ let EmailProgramDriver = class EmailProgramDriver extends BaseProgramTypeDriver
|
|
|
115
115
|
}
|
|
116
116
|
/**
|
|
117
117
|
* The poller: the sprint's window totals (the trusted numbers) plus this
|
|
118
|
-
* program's Linked observation for the
|
|
118
|
+
* program's Linked observation for the sprint, both converged.
|
|
119
119
|
*/
|
|
120
120
|
async refreshStatus(program, window) {
|
|
121
121
|
const user = this.contextUser;
|
|
122
122
|
if (!user)
|
|
123
123
|
return { refreshed: false, sprintsUpdated: 0, observationsWritten: 0, note: 'Email: no contextUser supplied.' };
|
|
124
|
+
// The window IS a sprint's (KI-93): its rows are written under that SprintID, never re-derived from dates.
|
|
125
|
+
const sprintId = window.sprintId;
|
|
126
|
+
if (!sprintId)
|
|
127
|
+
return { refreshed: false, sprintsUpdated: 0, observationsWritten: 0, note: 'Email: refresh needs a sprint window, not a roll-up.' };
|
|
124
128
|
const ctx = await this.context(program.brandId, user);
|
|
125
129
|
if (!ctx)
|
|
126
130
|
return { refreshed: false, sprintsUpdated: 0, observationsWritten: 0, note: 'Email: the brand has no valid SourceEntityMap.' };
|
|
127
131
|
const totals = await AggregateWindow({ ...ctx, window });
|
|
128
|
-
const sprintId = await this.windowSprintId(program.brandId, window, user);
|
|
129
132
|
let sprintsUpdated = 0;
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
sprintsUpdated = 1;
|
|
138
|
-
}
|
|
133
|
+
const sprint = await new Metadata().GetEntityObject(toMarketingEntityName('Sprints'), user);
|
|
134
|
+
if (await sprint.Load(sprintId)) {
|
|
135
|
+
sprint.ActivityTotal = totals.activityTotal;
|
|
136
|
+
sprint.ConversionTotal = totals.conversionTotal;
|
|
137
|
+
sprint.TotalsRefreshedAt = new Date();
|
|
138
|
+
if (await sprint.Save())
|
|
139
|
+
sprintsUpdated = 1;
|
|
139
140
|
}
|
|
140
141
|
let slices = [];
|
|
141
142
|
let observationsWritten = 0;
|
|
@@ -150,7 +151,9 @@ let EmailProgramDriver = class EmailProgramDriver extends BaseProgramTypeDriver
|
|
|
150
151
|
return { refreshed: true, sprintsUpdated, observationsWritten, note };
|
|
151
152
|
}
|
|
152
153
|
/** Sequences keep sending until stopped; the stop lands with the execution providers (S8). */
|
|
153
|
-
async onRetire(_program, _reason) {
|
|
154
|
+
async onRetire(_program, _reason) {
|
|
155
|
+
return { stoodDown: false, note: 'Email: nothing stood down on a platform — the sequence is stopped by the execution provider, not by this app.' };
|
|
156
|
+
}
|
|
154
157
|
// ── reads ───────────────────────────────────────────────────────────────
|
|
155
158
|
/** The brand's source map + the per-request provider (SequenceService pattern — never the process-global default). */
|
|
156
159
|
async context(brandId, user) {
|
|
@@ -186,15 +189,6 @@ let EmailProgramDriver = class EmailProgramDriver extends BaseProgramTypeDriver
|
|
|
186
189
|
}, user);
|
|
187
190
|
return res.Success && (res.Results ?? []).some(l => !!l.ScopeHint?.trim());
|
|
188
191
|
}
|
|
189
|
-
/** The sprint that CONTAINS the window's start — never an overlap test (it double-matches at the seam). */
|
|
190
|
-
async windowSprintId(brandId, w, user) {
|
|
191
|
-
const res = await new RunView().RunView({
|
|
192
|
-
EntityName: toMarketingEntityName('Sprints'),
|
|
193
|
-
ExtraFilter: `BrandID='${EscapeSQLString(brandId)}' AND StartDate <= '${w.from.toISOString()}' AND EndDate > '${w.from.toISOString()}'`,
|
|
194
|
-
Fields: ['ID'], OrderBy: 'StartDate DESC', MaxRows: 1, ResultType: 'simple', BypassCache: true,
|
|
195
|
-
}, user);
|
|
196
|
-
return res.Success ? res.Results?.[0]?.ID ?? null : null;
|
|
197
|
-
}
|
|
198
192
|
/** Only the PRESENCE of SegmentCuts is interpreted; no cut shape has been agreed. */
|
|
199
193
|
hasDeclaredCuts(program) {
|
|
200
194
|
const raw = program.segmentCuts?.trim();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EmailProgramDriver.js","sourceRoot":"","sources":["../../src/programs/EmailProgramDriver.ts"],"names":[],"mappings":";;;;;;;;;AAAA,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,OAAO,EAA4C,MAAM,sBAAsB,CAAC;AAC9G,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACxE,OAAO,EACH,qBAAqB,EACrB,kBAAkB,EAClB,qBAAqB,
|
|
1
|
+
{"version":3,"file":"EmailProgramDriver.js","sourceRoot":"","sources":["../../src/programs/EmailProgramDriver.ts"],"names":[],"mappings":"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"}
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
* approval gate (V3-12) BEFORE onLock — by the time this runs, a human approved the spend.
|
|
16
16
|
*/
|
|
17
17
|
import { type UserInfo } from '@memberjunction/core';
|
|
18
|
-
import { BaseProgramTypeDriver, type DriverRetirementReason, type DriverValidationIssue, type MetricCollectionWindow, type MetricObservation, type ProgramForDriver, type ProgramTypeParamSpec, type RefreshStatusResult } from '@mj-biz-apps/marketing-core';
|
|
18
|
+
import { BaseProgramTypeDriver, type DriverRetirementReason, type DriverValidationIssue, type MetricCollectionWindow, type MetricObservation, type ProgramForDriver, type ProgramTypeParamSpec, type RefreshStatusResult, type RetireStatusResult } from '@mj-biz-apps/marketing-core';
|
|
19
19
|
import { type GoogleContextResolver } from './googleAdsExecutionContext.js';
|
|
20
20
|
export declare class GoogleAdsProgramDriver extends BaseProgramTypeDriver {
|
|
21
21
|
private readonly contextUser?;
|
|
@@ -35,14 +35,12 @@ export declare class GoogleAdsProgramDriver extends BaseProgramTypeDriver {
|
|
|
35
35
|
collectMetrics(program: ProgramForDriver, window: MetricCollectionWindow): Promise<MetricObservation[] | null>;
|
|
36
36
|
/**
|
|
37
37
|
* The continuous poll (HA-7): the same platform figures collectMetrics reports at review time,
|
|
38
|
-
* converged every cadence tick as the program's Inferred observation for the sprint
|
|
38
|
+
* converged every cadence tick as the program's Inferred observation for the sprint (KI-93)
|
|
39
39
|
* (keyed by the `google:` source family, HA-5). No connection or no campaign yet ⇒ an honest
|
|
40
40
|
* `refreshed: false`. Sprint totals are the substrate's to refresh, not the platform's.
|
|
41
41
|
*/
|
|
42
42
|
refreshStatus(program: ProgramForDriver, window: MetricCollectionWindow): Promise<RefreshStatusResult>;
|
|
43
|
-
|
|
44
|
-
private sprintIdFor;
|
|
45
|
-
onRetire(program: ProgramForDriver, reason: DriverRetirementReason): Promise<void>;
|
|
43
|
+
onRetire(program: ProgramForDriver, reason: DriverRetirementReason): Promise<RetireStatusResult>;
|
|
46
44
|
private loadRefs;
|
|
47
45
|
private saveRef;
|
|
48
46
|
private updateRefState;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GoogleAdsProgramDriver.d.ts","sourceRoot":"","sources":["../../../src/programs/google/GoogleAdsProgramDriver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,EAAgC,KAAK,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAGnF,OAAO,EACH,qBAAqB,EAOrB,KAAK,sBAAsB,EAC3B,KAAK,qBAAqB,EAC1B,KAAK,sBAAsB,EAC3B,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EACrB,KAAK,oBAAoB,EACzB,KAAK,mBAAmB,
|
|
1
|
+
{"version":3,"file":"GoogleAdsProgramDriver.d.ts","sourceRoot":"","sources":["../../../src/programs/google/GoogleAdsProgramDriver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,EAAgC,KAAK,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAGnF,OAAO,EACH,qBAAqB,EAOrB,KAAK,sBAAsB,EAC3B,KAAK,qBAAqB,EAC1B,KAAK,sBAAsB,EAC3B,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EACrB,KAAK,oBAAoB,EACzB,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,EAG1B,MAAM,6BAA6B,CAAC;AAErC,OAAO,EAGH,KAAK,qBAAqB,EAA0B,MAAM,gCAAgC,CAAC;AAS/F,qBACa,sBAAuB,SAAQ,qBAAqB;IASzD,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC;IAC7B,OAAO,CAAC,QAAQ,CAAC,cAAc;IATnC,SAAgB,QAAQ,gBAAwB;IAChD,yFAAyF;IACzF,SAAgB,UAAU,EAAE,aAAa,CAAC,oBAAoB,CAAC,CAG7D;gBAGmB,WAAW,CAAC,EAAE,QAAQ,EACtB,cAAc,GAAE,qBAAqD;IAK7E,gBAAgB,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,qBAAqB,EAAE,CAAC;IAqB1F;;;;OAIG;IACH,OAAO,CAAC,sBAAsB;IAkBjB,MAAM,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IA8HhD,cAAc,CAAC,OAAO,EAAE,gBAAgB,EAAE,MAAM,EAAE,sBAAsB,GAAG,OAAO,CAAC,iBAAiB,EAAE,GAAG,IAAI,CAAC;IA8B3H;;;;;OAKG;IACmB,aAAa,CAAC,OAAO,EAAE,gBAAgB,EAAE,MAAM,EAAE,sBAAsB,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAoB/G,QAAQ,CAAC,OAAO,EAAE,gBAAgB,EAAE,MAAM,EAAE,sBAAsB,GAAG,OAAO,CAAC,kBAAkB,CAAC;YAuB/F,QAAQ;YAaR,OAAO;YAqBP,cAAc;IAS5B,OAAO,CAAC,SAAS;IAWjB,OAAO,CAAC,SAAS;IAKjB,OAAO,CAAC,aAAa;IAQrB,OAAO,CAAC,WAAW;IAMnB,OAAO,CAAC,WAAW;CAItB;AAED,wBAAgB,0BAA0B,SAAK"}
|
|
@@ -26,9 +26,9 @@ var __metadata = (this && this.__metadata) || function (k, v) {
|
|
|
26
26
|
import { LogStatus, Metadata, RunView } from '@memberjunction/core';
|
|
27
27
|
import { EscapeSQLString, RegisterClass } from '@memberjunction/global';
|
|
28
28
|
import { ConvergeObservation } from '@mj-biz-apps/marketing-actions';
|
|
29
|
-
import { BaseProgramTypeDriver, GOOGLE_ADS_TYPE_NAME, effectiveCreative, parseAdCampaignConfig, platformObjectName, stampUtm,
|
|
30
|
-
import { isGoogleRefused, resolveGoogleExecutionContext, } from './googleAdsExecutionContext.js';
|
|
31
|
-
import { ensureGoogleBrandAssets, isAssetsRefused } from './googleBrandAssets.js';
|
|
29
|
+
import { BaseProgramTypeDriver, GOOGLE_ADS_TYPE_NAME, effectiveCreative, parseAdCampaignConfig, platformObjectName, stampUtm, elapsedReportingRange, } from '@mj-biz-apps/marketing-core';
|
|
30
|
+
import { isGoogleRefused, resolveGoogleExecutionContext, GOOGLE_CREDENTIAL_TYPE } from './googleAdsExecutionContext.js';
|
|
31
|
+
import { ensureGoogleBrandAssets, isAssetsRefused, uploadImageAssetFromUrl } from './googleBrandAssets.js';
|
|
32
32
|
const REFS_ENTITY = 'MJ_BizApps_Marketing: Program Platform Refs';
|
|
33
33
|
/** Budget resources ride the 'Other' kind; StateJSON names the role. */
|
|
34
34
|
const BUDGET_ROLE = 'campaignBudget';
|
|
@@ -42,7 +42,7 @@ let GoogleAdsProgramDriver = class GoogleAdsProgramDriver extends BaseProgramTyp
|
|
|
42
42
|
this.typeName = GOOGLE_ADS_TYPE_NAME;
|
|
43
43
|
/** Mirrors AdCampaignConfig — the parser is the enforcement, this is the declaration. */
|
|
44
44
|
this.paramSpecs = [
|
|
45
|
-
{ name: 'tacticConfigJSON', valueType: 'Scalar', isArray: false, isRequired: true, description: 'The levers as JSON (Program.TacticConfigJSON): audience (targeted | website-retargeting
|
|
45
|
+
{ name: 'tacticConfigJSON', valueType: 'Scalar', isArray: false, isRequired: true, description: 'The levers as JSON (Program.TacticConfigJSON): audience (targeted | website-retargeting), dailyBudgetUsd, landingPageUrl, optional creativeHeadline/creativeBody/audienceWindowDays.' },
|
|
46
46
|
{ name: 'campaignCode', valueType: 'Scalar', isArray: false, isRequired: true, description: 'Program.Code — stamped as utm_campaign and prefixed onto every platform object name.' },
|
|
47
47
|
];
|
|
48
48
|
}
|
|
@@ -177,6 +177,17 @@ let GoogleAdsProgramDriver = class GoogleAdsProgramDriver extends BaseProgramTyp
|
|
|
177
177
|
adNote = `creative declared but no usable brand imagery — ad not created (${provisioned.reason}); the campaign runs ad-less until it is fixed and the program re-locks`;
|
|
178
178
|
}
|
|
179
179
|
else {
|
|
180
|
+
// The program's own landscape image first (the creativeImageUrl lever, KI-117); the brand's is the
|
|
181
|
+
// DEFAULT. Square and logo stay the brand's. An unusable program image degrades to the brand image.
|
|
182
|
+
let marketingImageAsset = provisioned.assets.marketingImageAsset;
|
|
183
|
+
if (creative.imageUrl) {
|
|
184
|
+
try {
|
|
185
|
+
marketingImageAsset = await uploadImageAssetFromUrl(ctx, creative.imageUrl, platformObjectName(code, 'campaign', 'creative image'), 'program creative image');
|
|
186
|
+
}
|
|
187
|
+
catch (e) {
|
|
188
|
+
LogStatus(`GoogleAdsProgramDriver.onLock: ${code} program creative image not used (${e instanceof Error ? e.message : String(e)}) — falling back to the brand image`);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
180
191
|
const adRef = await ctx.client.createResponsiveDisplayAd({
|
|
181
192
|
adGroupResourceName: adGroupRef,
|
|
182
193
|
finalUrl: stampedUrl,
|
|
@@ -184,7 +195,7 @@ let GoogleAdsProgramDriver = class GoogleAdsProgramDriver extends BaseProgramTyp
|
|
|
184
195
|
longHeadline: creative.longHeadline ?? creative.headlines[0],
|
|
185
196
|
descriptions: creative.descriptions,
|
|
186
197
|
businessName: provisioned.assets.businessName,
|
|
187
|
-
marketingImageAsset
|
|
198
|
+
marketingImageAsset,
|
|
188
199
|
squareMarketingImageAsset: provisioned.assets.squareMarketingImageAsset,
|
|
189
200
|
squareLogoImageAsset: provisioned.assets.squareLogoImageAsset ?? null,
|
|
190
201
|
});
|
|
@@ -212,9 +223,15 @@ let GoogleAdsProgramDriver = class GoogleAdsProgramDriver extends BaseProgramTyp
|
|
|
212
223
|
LogStatus(`GoogleAdsProgramDriver.collectMetrics: connection unavailable (${ctx.issues.map(i => i.code).join(', ')}) — no observation.`);
|
|
213
224
|
return null;
|
|
214
225
|
}
|
|
215
|
-
|
|
216
|
-
|
|
226
|
+
// KI-89: ask the platform only for time that has happened (the window stays the observation's key).
|
|
227
|
+
const range = elapsedReportingRange(window, new Date());
|
|
228
|
+
if (!range)
|
|
217
229
|
return null;
|
|
230
|
+
const m = await ctx.client.campaignMetrics(campaigns, range.from, range.to);
|
|
231
|
+
// All-zero is still an observation: the campaign exists, the connection answered, and
|
|
232
|
+
// the platform reported nothing served. Returning null here made 'served nothing'
|
|
233
|
+
// indistinguishable from 'no campaign / no connection' and Refresh Program Status
|
|
234
|
+
// wrote no row at all for a paused or test-account campaign (KI-34, host rehearsal).
|
|
218
235
|
return [{
|
|
219
236
|
segmentLabel: null,
|
|
220
237
|
observedMetric: m.conversions,
|
|
@@ -227,7 +244,7 @@ let GoogleAdsProgramDriver = class GoogleAdsProgramDriver extends BaseProgramTyp
|
|
|
227
244
|
}
|
|
228
245
|
/**
|
|
229
246
|
* The continuous poll (HA-7): the same platform figures collectMetrics reports at review time,
|
|
230
|
-
* converged every cadence tick as the program's Inferred observation for the sprint
|
|
247
|
+
* converged every cadence tick as the program's Inferred observation for the sprint (KI-93)
|
|
231
248
|
* (keyed by the `google:` source family, HA-5). No connection or no campaign yet ⇒ an honest
|
|
232
249
|
* `refreshed: false`. Sprint totals are the substrate's to refresh, not the platform's.
|
|
233
250
|
*/
|
|
@@ -235,38 +252,28 @@ let GoogleAdsProgramDriver = class GoogleAdsProgramDriver extends BaseProgramTyp
|
|
|
235
252
|
const user = this.contextUser;
|
|
236
253
|
if (!user || !program.id)
|
|
237
254
|
return { refreshed: false, sprintsUpdated: 0, observationsWritten: 0, note: `GoogleAdsProgramDriver: no user context.` };
|
|
255
|
+
// The window IS a sprint's (KI-93): the row is written under that SprintID, never re-derived from dates.
|
|
256
|
+
const sprintId = window.sprintId;
|
|
257
|
+
if (!sprintId)
|
|
258
|
+
return { refreshed: false, sprintsUpdated: 0, observationsWritten: 0, note: `GoogleAdsProgramDriver: refresh needs a sprint window, not a roll-up.` };
|
|
238
259
|
const observations = await this.collectMetrics(program, window);
|
|
239
260
|
const top = observations?.find(o => o.segmentLabel === null) ?? null;
|
|
240
261
|
if (!top)
|
|
241
|
-
return { refreshed: false, sprintsUpdated: 0, observationsWritten: 0, note: `GoogleAdsProgramDriver: no campaign
|
|
242
|
-
const
|
|
243
|
-
const saved = await ConvergeObservation({ programId: program.id, attribution: top.attribution ?? 'Inferred', window, sourceRefPrefix: 'google:' }, { sprintId, activityCount: top.sampleSize ?? 0, conversionsCount: top.conversionsCount, observedMetric: top.observedMetric, sourceRef: top.source,
|
|
262
|
+
return { refreshed: false, sprintsUpdated: 0, observationsWritten: 0, note: `GoogleAdsProgramDriver: no campaign ref or the connection is unavailable — nothing to observe.` };
|
|
263
|
+
const saved = await ConvergeObservation({ programId: program.id, sprintId, attribution: top.attribution ?? 'Inferred', sourceRefPrefix: 'google:' }, { window, activityCount: top.sampleSize ?? 0, conversionsCount: top.conversionsCount, observedMetric: top.observedMetric, sourceRef: top.source,
|
|
244
264
|
notes: `platform-reported (Inferred): conversions ${top.conversionsCount}, impressions ${top.sampleSize ?? 0}` }, user);
|
|
245
265
|
const note = `GoogleAdsProgramDriver: ${top.conversionsCount} platform conversion(s) over ${top.sampleSize ?? 0} impressions — ${saved ? 'observation converged' : 'observation NOT saved'}.`;
|
|
246
266
|
LogStatus(`GoogleAdsProgramDriver.refreshStatus: ${note}`);
|
|
247
267
|
return { refreshed: true, sprintsUpdated: 0, observationsWritten: saved ? 1 : 0, note };
|
|
248
268
|
}
|
|
249
|
-
/** The Active sprint the window belongs to, so the observation carries its SprintID (null when none matches). */
|
|
250
|
-
async sprintIdFor(programId, window, user) {
|
|
251
|
-
const res = await new RunView().RunView({
|
|
252
|
-
EntityName: toMarketingEntityName('Sprints'),
|
|
253
|
-
ExtraFilter: `ID IN (SELECT SprintID FROM __mj_BizAppsMarketing.vwSprintPrograms WHERE ProgramID='${EscapeSQLString(programId)}')`,
|
|
254
|
-
Fields: ['ID', 'StartDate', 'EndDate'], ResultType: 'simple', MaxRows: 50,
|
|
255
|
-
}, user);
|
|
256
|
-
if (!res.Success)
|
|
257
|
-
return null;
|
|
258
|
-
const from = window.from.getTime(), to = window.to.getTime();
|
|
259
|
-
const hit = (res.Results ?? []).find(r => new Date(r.StartDate).getTime() <= from && new Date(r.EndDate).getTime() >= to);
|
|
260
|
-
return hit?.ID ?? null;
|
|
261
|
-
}
|
|
262
269
|
async onRetire(program, reason) {
|
|
263
270
|
const user = this.requireUser();
|
|
264
271
|
if (!program.id)
|
|
265
|
-
return;
|
|
272
|
+
return { stoodDown: false, note: 'Google Ads: nothing to stand down — the program has no id.' };
|
|
266
273
|
const refs = await this.loadRefs(program.id, user);
|
|
267
274
|
const campaigns = refs.filter(r => r.ExternalKind === 'Campaign');
|
|
268
275
|
if (campaigns.length === 0)
|
|
269
|
-
return;
|
|
276
|
+
return { stoodDown: false, note: 'Google Ads: nothing to stand down — no campaign was ever launched for this program.' };
|
|
270
277
|
const ctx = await this.resolveContext(program.brandId, user);
|
|
271
278
|
if (isGoogleRefused(ctx)) {
|
|
272
279
|
// The one unacceptable silence: a decided program whose campaign keeps spending.
|
|
@@ -277,13 +284,18 @@ let GoogleAdsProgramDriver = class GoogleAdsProgramDriver extends BaseProgramTyp
|
|
|
277
284
|
await ctx.client.setCampaignStatus(ref.ExternalURN, 'PAUSED');
|
|
278
285
|
await this.updateRefState(ref, { status: 'PAUSED', retiredFor: reason });
|
|
279
286
|
}
|
|
280
|
-
|
|
287
|
+
const note = `Google Ads: ${campaigns.length} campaign(s) paused (${reason}).`;
|
|
288
|
+
LogStatus(`GoogleAdsProgramDriver.onRetire: ${program.name ?? program.id} — ${note}`);
|
|
289
|
+
return { stoodDown: true, note };
|
|
281
290
|
}
|
|
282
291
|
// ── refs (the driver's memory) ──────────────────────────────────────────
|
|
283
292
|
async loadRefs(programId, user) {
|
|
284
293
|
const res = await new RunView().RunView({
|
|
285
294
|
EntityName: REFS_ENTITY,
|
|
286
|
-
|
|
295
|
+
// THIS platform's refs only: refs are scoped by brand connection, and a program also carries refs on
|
|
296
|
+
// other connections (HubSpot attribution writes its campaign ref on the HubSpot connection). Sending that
|
|
297
|
+
// id to Google Ads was a 400 on every poll (KI-105). The HubSpot reader's rule, applied here.
|
|
298
|
+
ExtraFilter: `ProgramID='${EscapeSQLString(programId)}' AND BrandConnectionID IN (SELECT ID FROM __mj_BizAppsMarketing.vwBrandConnections WHERE CredentialType='${EscapeSQLString(GOOGLE_CREDENTIAL_TYPE)}')`,
|
|
287
299
|
ResultType: 'entity_object',
|
|
288
300
|
BypassCache: true,
|
|
289
301
|
}, user);
|