@open-loyalty/mcp-server 1.0.3 → 1.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +180 -177
- package/dist/auth/provider.js +2 -14
- package/dist/auth/storage.js +22 -0
- package/dist/client/http.d.ts +5 -0
- package/dist/client/http.js +62 -3
- package/dist/config.d.ts +6 -5
- package/dist/config.js +15 -11
- package/dist/http.js +170 -65
- package/dist/instructions.d.ts +5 -0
- package/dist/instructions.js +420 -0
- package/dist/prompts/fan-engagement-setup.d.ts +107 -0
- package/dist/prompts/fan-engagement-setup.js +492 -0
- package/dist/server.d.ts +1 -1
- package/dist/server.js +68 -278
- package/dist/tools/achievement/handlers.d.ts +117 -0
- package/dist/tools/achievement/handlers.js +161 -0
- package/dist/tools/achievement/index.d.ts +479 -0
- package/dist/tools/achievement/index.js +74 -0
- package/dist/tools/achievement/schemas.d.ts +433 -0
- package/dist/tools/achievement/schemas.js +142 -0
- package/dist/tools/achievement.d.ts +155 -121
- package/dist/tools/achievement.js +82 -39
- package/dist/tools/admin.d.ts +18 -6
- package/dist/tools/admin.js +24 -12
- package/dist/tools/analytics.d.ts +29 -11
- package/dist/tools/analytics.js +58 -48
- package/dist/tools/apikey.d.ts +10 -3
- package/dist/tools/apikey.js +13 -6
- package/dist/tools/audit.d.ts +6 -2
- package/dist/tools/audit.js +8 -4
- package/dist/tools/badge.d.ts +14 -6
- package/dist/tools/badge.js +36 -27
- package/dist/tools/campaign/handlers.d.ts +42 -0
- package/dist/tools/campaign/handlers.js +223 -0
- package/dist/tools/campaign/index.d.ts +783 -0
- package/dist/tools/campaign/index.js +112 -0
- package/dist/tools/campaign/member-handlers.d.ts +60 -0
- package/dist/tools/campaign/member-handlers.js +159 -0
- package/dist/tools/campaign/schemas.d.ts +704 -0
- package/dist/tools/campaign/schemas.js +259 -0
- package/dist/tools/campaign/types.d.ts +161 -0
- package/dist/tools/campaign/types.js +2 -0
- package/dist/tools/campaign.d.ts +41 -16
- package/dist/tools/campaign.js +38 -25
- package/dist/tools/custom-event.d.ts +315 -0
- package/dist/tools/custom-event.js +270 -0
- package/dist/tools/export.d.ts +12 -4
- package/dist/tools/export.js +25 -20
- package/dist/tools/import.d.ts +9 -3
- package/dist/tools/import.js +33 -21
- package/dist/tools/index.d.ts +3 -11
- package/dist/tools/index.js +17 -475
- package/dist/tools/member/handlers.d.ts +111 -0
- package/dist/tools/member/handlers.js +206 -0
- package/dist/tools/member/index.d.ts +169 -0
- package/dist/tools/member/index.js +92 -0
- package/dist/tools/member/schemas.d.ts +89 -0
- package/dist/tools/member/schemas.js +65 -0
- package/dist/tools/member.d.ts +21 -0
- package/dist/tools/member.js +56 -62
- package/dist/tools/points.d.ts +19 -6
- package/dist/tools/points.js +51 -49
- package/dist/tools/referral/handlers.d.ts +47 -0
- package/dist/tools/referral/handlers.js +115 -0
- package/dist/tools/referral/index.d.ts +44 -0
- package/dist/tools/referral/index.js +44 -0
- package/dist/tools/referral/schemas.d.ts +34 -0
- package/dist/tools/referral/schemas.js +52 -0
- package/dist/tools/reward/handlers.d.ts +110 -0
- package/dist/tools/reward/handlers.js +289 -0
- package/dist/tools/reward/index.d.ts +177 -0
- package/dist/tools/reward/index.js +90 -0
- package/dist/tools/reward/schemas.d.ts +116 -0
- package/dist/tools/reward/schemas.js +91 -0
- package/dist/tools/reward.d.ts +18 -0
- package/dist/tools/reward.js +56 -66
- package/dist/tools/role.d.ts +26 -7
- package/dist/tools/role.js +25 -12
- package/dist/tools/segment/handlers.d.ts +87 -0
- package/dist/tools/segment/handlers.js +174 -0
- package/dist/tools/segment/index.d.ts +395 -0
- package/dist/tools/segment/index.js +87 -0
- package/dist/tools/segment/schemas.d.ts +337 -0
- package/dist/tools/segment/schemas.js +79 -0
- package/dist/tools/segment.d.ts +29 -10
- package/dist/tools/segment.js +84 -50
- package/dist/tools/store.d.ts +12 -4
- package/dist/tools/store.js +16 -8
- package/dist/tools/tierset.d.ts +19 -7
- package/dist/tools/tierset.js +44 -35
- package/dist/tools/transaction.d.ts +16 -8
- package/dist/tools/transaction.js +25 -21
- package/dist/tools/wallet-type.d.ts +7 -3
- package/dist/tools/wallet-type.js +14 -12
- package/dist/tools/webhook.d.ts +23 -10
- package/dist/tools/webhook.js +135 -33
- package/dist/types/schemas/achievement.d.ts +12 -309
- package/dist/types/schemas/achievement.js +0 -13
- package/dist/types/schemas/admin.d.ts +10 -97
- package/dist/types/schemas/admin.js +0 -38
- package/dist/types/schemas/badge.d.ts +0 -37
- package/dist/types/schemas/badge.js +0 -11
- package/dist/types/schemas/campaign.d.ts +64 -832
- package/dist/types/schemas/campaign.js +2 -25
- package/dist/types/schemas/common.d.ts +5 -0
- package/dist/types/schemas/common.js +5 -0
- package/dist/types/schemas/export.d.ts +0 -17
- package/dist/types/schemas/export.js +0 -7
- package/dist/types/schemas/member.d.ts +37 -176
- package/dist/types/schemas/member.js +0 -27
- package/dist/types/schemas/points.d.ts +0 -63
- package/dist/types/schemas/points.js +0 -22
- package/dist/types/schemas/reward.d.ts +71 -68
- package/dist/types/schemas/reward.js +8 -28
- package/dist/types/schemas/role.d.ts +0 -100
- package/dist/types/schemas/role.js +0 -29
- package/dist/types/schemas/segment.d.ts +0 -58
- package/dist/types/schemas/segment.js +0 -17
- package/dist/types/schemas/tierset.d.ts +0 -176
- package/dist/types/schemas/tierset.js +0 -27
- package/dist/types/schemas/transaction.d.ts +23 -254
- package/dist/types/schemas/transaction.js +0 -7
- package/dist/types/schemas/wallet-type.d.ts +8 -8
- package/dist/types/schemas/wallet-type.js +1 -1
- package/dist/types/schemas/webhook.d.ts +0 -58
- package/dist/types/schemas/webhook.js +0 -12
- package/dist/utils/errors.js +30 -3
- package/dist/utils/payload.d.ts +12 -0
- package/dist/utils/payload.js +14 -0
- package/dist/workflows/app-login-streak.d.ts +39 -0
- package/dist/workflows/app-login-streak.js +298 -0
- package/dist/workflows/early-arrival.d.ts +33 -0
- package/dist/workflows/early-arrival.js +148 -0
- package/dist/workflows/index.d.ts +101 -0
- package/dist/workflows/index.js +208 -0
- package/dist/workflows/match-attendance.d.ts +45 -0
- package/dist/workflows/match-attendance.js +308 -0
- package/dist/workflows/sportsbar-visit.d.ts +41 -0
- package/dist/workflows/sportsbar-visit.js +284 -0
- package/dist/workflows/vod-watching.d.ts +43 -0
- package/dist/workflows/vod-watching.js +326 -0
- package/package.json +10 -2
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Early Arrival Workflow
|
|
3
|
+
*
|
|
4
|
+
* Creates a campaign to reward fans who arrive early to matches.
|
|
5
|
+
* Uses a custom event with minutes_before attribute for conditional rewards.
|
|
6
|
+
*/
|
|
7
|
+
import { campaignCreate } from "../tools/campaign/handlers.js";
|
|
8
|
+
import { formatOLDate, DEFAULTS } from "../prompts/fan-engagement-setup.js";
|
|
9
|
+
// ============================================================================
|
|
10
|
+
// Workflow Implementation
|
|
11
|
+
// ============================================================================
|
|
12
|
+
/**
|
|
13
|
+
* Execute the early arrival workflow
|
|
14
|
+
*/
|
|
15
|
+
export async function executeEarlyArrivalWorkflow(config = {}) {
|
|
16
|
+
const result = {
|
|
17
|
+
success: false,
|
|
18
|
+
errors: [],
|
|
19
|
+
summary: "",
|
|
20
|
+
};
|
|
21
|
+
// Merge with defaults
|
|
22
|
+
const cfg = {
|
|
23
|
+
minutesBefore: config.minutesBefore ?? DEFAULTS.earlyArrival.minutesBefore,
|
|
24
|
+
coinsPerArrival: config.coinsPerArrival ?? DEFAULTS.earlyArrival.coinsPerArrival,
|
|
25
|
+
limitPerMatch: config.limitPerMatch ?? DEFAULTS.earlyArrival.limitPerMatch,
|
|
26
|
+
seasonStart: config.seasonStart ?? DEFAULTS.seasonDates.start,
|
|
27
|
+
seasonEnd: config.seasonEnd ?? DEFAULTS.seasonDates.end,
|
|
28
|
+
};
|
|
29
|
+
try {
|
|
30
|
+
// Create the early arrival campaign with condition
|
|
31
|
+
const campaignResult = await createEarlyArrivalCampaign(cfg);
|
|
32
|
+
if (campaignResult.error) {
|
|
33
|
+
result.errors.push(campaignResult.error);
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
result.campaignId = campaignResult.campaignId;
|
|
37
|
+
result.success = true;
|
|
38
|
+
}
|
|
39
|
+
// Build summary
|
|
40
|
+
result.summary = buildSummary(cfg, result);
|
|
41
|
+
}
|
|
42
|
+
catch (error) {
|
|
43
|
+
result.errors.push(`Workflow error: ${error instanceof Error ? error.message : String(error)}`);
|
|
44
|
+
}
|
|
45
|
+
return result;
|
|
46
|
+
}
|
|
47
|
+
// ============================================================================
|
|
48
|
+
// Helper Functions
|
|
49
|
+
// ============================================================================
|
|
50
|
+
async function createEarlyArrivalCampaign(cfg) {
|
|
51
|
+
try {
|
|
52
|
+
/**
|
|
53
|
+
* The early_arrival custom event expects:
|
|
54
|
+
* {
|
|
55
|
+
* "event": "early_arrival",
|
|
56
|
+
* "attributes": {
|
|
57
|
+
* "minutes_before": 75 // how many minutes before kickoff they arrived
|
|
58
|
+
* }
|
|
59
|
+
* }
|
|
60
|
+
*
|
|
61
|
+
* The campaign condition checks if minutes_before >= threshold
|
|
62
|
+
*/
|
|
63
|
+
const response = await campaignCreate({
|
|
64
|
+
type: "direct",
|
|
65
|
+
trigger: "custom_event",
|
|
66
|
+
event: "early_arrival",
|
|
67
|
+
translations: {
|
|
68
|
+
en: {
|
|
69
|
+
name: "Early Arrival Bonus",
|
|
70
|
+
description: `Earn ${cfg.coinsPerArrival} bonus coins for arriving at least ${cfg.minutesBefore} minutes before kickoff`,
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
activity: {
|
|
74
|
+
startsAt: formatOLDate(cfg.seasonStart),
|
|
75
|
+
endsAt: formatOLDate(cfg.seasonEnd),
|
|
76
|
+
},
|
|
77
|
+
rules: [
|
|
78
|
+
{
|
|
79
|
+
name: "Award coins for early arrival",
|
|
80
|
+
effects: [
|
|
81
|
+
{
|
|
82
|
+
effect: "give_points",
|
|
83
|
+
pointsRule: { fixedValue: cfg.coinsPerArrival },
|
|
84
|
+
},
|
|
85
|
+
],
|
|
86
|
+
conditions: [
|
|
87
|
+
{
|
|
88
|
+
operator: "gte",
|
|
89
|
+
attribute: "event.minutes_before",
|
|
90
|
+
data: { value: cfg.minutesBefore },
|
|
91
|
+
},
|
|
92
|
+
],
|
|
93
|
+
},
|
|
94
|
+
],
|
|
95
|
+
limits: {
|
|
96
|
+
executionsPerMember: {
|
|
97
|
+
value: cfg.limitPerMatch,
|
|
98
|
+
interval: { type: "days", value: 1 },
|
|
99
|
+
},
|
|
100
|
+
},
|
|
101
|
+
active: true,
|
|
102
|
+
});
|
|
103
|
+
return { campaignId: response.campaignId };
|
|
104
|
+
}
|
|
105
|
+
catch (error) {
|
|
106
|
+
return {
|
|
107
|
+
error: `Failed to create early arrival campaign: ${error instanceof Error ? error.message : String(error)}`,
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
function buildSummary(cfg, result) {
|
|
112
|
+
const lines = [];
|
|
113
|
+
if (result.success && result.campaignId) {
|
|
114
|
+
lines.push(`Early arrival campaign created successfully!`);
|
|
115
|
+
lines.push(`\nReward: ${cfg.coinsPerArrival} coins`);
|
|
116
|
+
lines.push(`Requirement: Arrive at least ${cfg.minutesBefore} minutes before kickoff`);
|
|
117
|
+
lines.push(`Limit: ${cfg.limitPerMatch} bonus per match day`);
|
|
118
|
+
lines.push(`\nSeason: ${cfg.seasonStart} to ${cfg.seasonEnd}`);
|
|
119
|
+
lines.push(`\nCustom event to trigger reward:`);
|
|
120
|
+
lines.push(` Event: early_arrival`);
|
|
121
|
+
lines.push(` Required attribute: minutes_before (number)`);
|
|
122
|
+
lines.push(`\nExample event payload:`);
|
|
123
|
+
lines.push(`{`);
|
|
124
|
+
lines.push(` "event": "early_arrival",`);
|
|
125
|
+
lines.push(` "attributes": {`);
|
|
126
|
+
lines.push(` "minutes_before": 75`);
|
|
127
|
+
lines.push(` }`);
|
|
128
|
+
lines.push(`}`);
|
|
129
|
+
}
|
|
130
|
+
else {
|
|
131
|
+
lines.push(`Early arrival campaign setup failed.`);
|
|
132
|
+
}
|
|
133
|
+
if (result.errors.length > 0) {
|
|
134
|
+
lines.push(`\nErrors:`);
|
|
135
|
+
for (const error of result.errors) {
|
|
136
|
+
lines.push(`- ${error}`);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
return lines.join("\n");
|
|
140
|
+
}
|
|
141
|
+
// ============================================================================
|
|
142
|
+
// Exports
|
|
143
|
+
// ============================================================================
|
|
144
|
+
export const earlyArrivalWorkflow = {
|
|
145
|
+
id: "early-arrival",
|
|
146
|
+
name: "Early Arrival Campaign",
|
|
147
|
+
execute: executeEarlyArrivalWorkflow,
|
|
148
|
+
};
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fan Engagement Workflows
|
|
3
|
+
*
|
|
4
|
+
* Orchestrated workflows for setting up complete fan engagement campaigns.
|
|
5
|
+
* These combine multiple Open Loyalty tools into guided, step-by-step flows.
|
|
6
|
+
*/
|
|
7
|
+
import { matchAttendanceWorkflow, executeMatchAttendanceWorkflow, type MatchAttendanceConfig, type MatchAttendanceResult } from "./match-attendance.js";
|
|
8
|
+
import { earlyArrivalWorkflow, executeEarlyArrivalWorkflow, type EarlyArrivalConfig, type EarlyArrivalResult } from "./early-arrival.js";
|
|
9
|
+
import { sportsbarVisitWorkflow, executeSportsbarVisitWorkflow, type SportsbarVisitConfig, type SportsbarVisitResult } from "./sportsbar-visit.js";
|
|
10
|
+
import { vodWatchingWorkflow, executeVodWatchingWorkflow, type VodWatchingConfig, type VodWatchingResult } from "./vod-watching.js";
|
|
11
|
+
import { appLoginStreakWorkflow, executeAppLoginStreakWorkflow, type AppLoginStreakConfig, type AppLoginStreakResult } from "./app-login-streak.js";
|
|
12
|
+
export { matchAttendanceWorkflow, executeMatchAttendanceWorkflow, type MatchAttendanceConfig, type MatchAttendanceResult, };
|
|
13
|
+
export { earlyArrivalWorkflow, executeEarlyArrivalWorkflow, type EarlyArrivalConfig, type EarlyArrivalResult, };
|
|
14
|
+
export { sportsbarVisitWorkflow, executeSportsbarVisitWorkflow, type SportsbarVisitConfig, type SportsbarVisitResult, };
|
|
15
|
+
export { vodWatchingWorkflow, executeVodWatchingWorkflow, type VodWatchingConfig, type VodWatchingResult, };
|
|
16
|
+
export { appLoginStreakWorkflow, executeAppLoginStreakWorkflow, type AppLoginStreakConfig, type AppLoginStreakResult, };
|
|
17
|
+
export { DEFAULTS, ALL_WORKFLOWS, findMatchingWorkflow, getWorkflowById, parseCommaSeparated, parseMilestones, formatOLDate, AGENT_PROMPTS, type WorkflowDefinition, type WorkflowQuestion, type WorkflowStep, } from "../prompts/fan-engagement-setup.js";
|
|
18
|
+
export interface FanEngagementConfig {
|
|
19
|
+
/** Match attendance configuration */
|
|
20
|
+
matchAttendance?: Partial<MatchAttendanceConfig>;
|
|
21
|
+
/** Early arrival configuration */
|
|
22
|
+
earlyArrival?: Partial<EarlyArrivalConfig>;
|
|
23
|
+
/** Sports bar visit configuration */
|
|
24
|
+
sportsbarVisit?: Partial<SportsbarVisitConfig>;
|
|
25
|
+
/** VOD watching configuration */
|
|
26
|
+
vodWatching?: Partial<VodWatchingConfig>;
|
|
27
|
+
/** App login streak configuration */
|
|
28
|
+
appLoginStreak?: Partial<AppLoginStreakConfig>;
|
|
29
|
+
/** Which workflows to execute (default: all) */
|
|
30
|
+
enabledWorkflows?: ("match-attendance" | "early-arrival" | "sportsbar-visit" | "vod-watching" | "app-login-streak")[];
|
|
31
|
+
}
|
|
32
|
+
export interface FanEngagementResult {
|
|
33
|
+
success: boolean;
|
|
34
|
+
results: {
|
|
35
|
+
matchAttendance?: MatchAttendanceResult;
|
|
36
|
+
earlyArrival?: EarlyArrivalResult;
|
|
37
|
+
sportsbarVisit?: SportsbarVisitResult;
|
|
38
|
+
vodWatching?: VodWatchingResult;
|
|
39
|
+
appLoginStreak?: AppLoginStreakResult;
|
|
40
|
+
};
|
|
41
|
+
summary: string;
|
|
42
|
+
totalCampaigns: number;
|
|
43
|
+
totalAchievements: number;
|
|
44
|
+
errors: string[];
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Execute all fan engagement workflows
|
|
48
|
+
*
|
|
49
|
+
* This is the master workflow that orchestrates all individual workflows
|
|
50
|
+
* based on the provided configuration.
|
|
51
|
+
*/
|
|
52
|
+
export declare function executeAllFanEngagementWorkflows(config?: FanEngagementConfig): Promise<FanEngagementResult>;
|
|
53
|
+
export declare const allWorkflows: readonly [{
|
|
54
|
+
id: string;
|
|
55
|
+
name: string;
|
|
56
|
+
execute: typeof executeMatchAttendanceWorkflow;
|
|
57
|
+
}, {
|
|
58
|
+
id: string;
|
|
59
|
+
name: string;
|
|
60
|
+
execute: typeof executeEarlyArrivalWorkflow;
|
|
61
|
+
}, {
|
|
62
|
+
id: string;
|
|
63
|
+
name: string;
|
|
64
|
+
execute: typeof executeSportsbarVisitWorkflow;
|
|
65
|
+
}, {
|
|
66
|
+
id: string;
|
|
67
|
+
name: string;
|
|
68
|
+
execute: typeof executeVodWatchingWorkflow;
|
|
69
|
+
}, {
|
|
70
|
+
id: string;
|
|
71
|
+
name: string;
|
|
72
|
+
execute: typeof executeAppLoginStreakWorkflow;
|
|
73
|
+
}];
|
|
74
|
+
/**
|
|
75
|
+
* Get workflow by ID
|
|
76
|
+
*/
|
|
77
|
+
export declare function getWorkflow(id: string): {
|
|
78
|
+
id: string;
|
|
79
|
+
name: string;
|
|
80
|
+
execute: typeof executeAppLoginStreakWorkflow;
|
|
81
|
+
} | {
|
|
82
|
+
id: string;
|
|
83
|
+
name: string;
|
|
84
|
+
execute: typeof executeEarlyArrivalWorkflow;
|
|
85
|
+
} | {
|
|
86
|
+
id: string;
|
|
87
|
+
name: string;
|
|
88
|
+
execute: typeof executeMatchAttendanceWorkflow;
|
|
89
|
+
} | {
|
|
90
|
+
id: string;
|
|
91
|
+
name: string;
|
|
92
|
+
execute: typeof executeSportsbarVisitWorkflow;
|
|
93
|
+
} | {
|
|
94
|
+
id: string;
|
|
95
|
+
name: string;
|
|
96
|
+
execute: typeof executeVodWatchingWorkflow;
|
|
97
|
+
} | undefined;
|
|
98
|
+
/**
|
|
99
|
+
* Execute a workflow by ID with given config
|
|
100
|
+
*/
|
|
101
|
+
export declare function executeWorkflowById(id: string, config?: Record<string, unknown>): Promise<unknown>;
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fan Engagement Workflows
|
|
3
|
+
*
|
|
4
|
+
* Orchestrated workflows for setting up complete fan engagement campaigns.
|
|
5
|
+
* These combine multiple Open Loyalty tools into guided, step-by-step flows.
|
|
6
|
+
*/
|
|
7
|
+
// Import execute functions for internal use
|
|
8
|
+
import { matchAttendanceWorkflow, executeMatchAttendanceWorkflow, } from "./match-attendance.js";
|
|
9
|
+
import { earlyArrivalWorkflow, executeEarlyArrivalWorkflow, } from "./early-arrival.js";
|
|
10
|
+
import { sportsbarVisitWorkflow, executeSportsbarVisitWorkflow, } from "./sportsbar-visit.js";
|
|
11
|
+
import { vodWatchingWorkflow, executeVodWatchingWorkflow, } from "./vod-watching.js";
|
|
12
|
+
import { appLoginStreakWorkflow, executeAppLoginStreakWorkflow, } from "./app-login-streak.js";
|
|
13
|
+
// Re-export all workflow components
|
|
14
|
+
export { matchAttendanceWorkflow, executeMatchAttendanceWorkflow, };
|
|
15
|
+
export { earlyArrivalWorkflow, executeEarlyArrivalWorkflow, };
|
|
16
|
+
export { sportsbarVisitWorkflow, executeSportsbarVisitWorkflow, };
|
|
17
|
+
export { vodWatchingWorkflow, executeVodWatchingWorkflow, };
|
|
18
|
+
export { appLoginStreakWorkflow, executeAppLoginStreakWorkflow, };
|
|
19
|
+
// Re-export prompt utilities
|
|
20
|
+
export { DEFAULTS, ALL_WORKFLOWS, findMatchingWorkflow, getWorkflowById, parseCommaSeparated, parseMilestones, formatOLDate, AGENT_PROMPTS, } from "../prompts/fan-engagement-setup.js";
|
|
21
|
+
// ============================================================================
|
|
22
|
+
// Master Workflow
|
|
23
|
+
// ============================================================================
|
|
24
|
+
/**
|
|
25
|
+
* Execute all fan engagement workflows
|
|
26
|
+
*
|
|
27
|
+
* This is the master workflow that orchestrates all individual workflows
|
|
28
|
+
* based on the provided configuration.
|
|
29
|
+
*/
|
|
30
|
+
export async function executeAllFanEngagementWorkflows(config = {}) {
|
|
31
|
+
const enabledWorkflows = config.enabledWorkflows || [
|
|
32
|
+
"match-attendance",
|
|
33
|
+
"early-arrival",
|
|
34
|
+
"sportsbar-visit",
|
|
35
|
+
"vod-watching",
|
|
36
|
+
"app-login-streak",
|
|
37
|
+
];
|
|
38
|
+
const result = {
|
|
39
|
+
success: false,
|
|
40
|
+
results: {},
|
|
41
|
+
summary: "",
|
|
42
|
+
totalCampaigns: 0,
|
|
43
|
+
totalAchievements: 0,
|
|
44
|
+
errors: [],
|
|
45
|
+
};
|
|
46
|
+
try {
|
|
47
|
+
// Execute each enabled workflow
|
|
48
|
+
for (const workflowId of enabledWorkflows) {
|
|
49
|
+
switch (workflowId) {
|
|
50
|
+
case "match-attendance": {
|
|
51
|
+
const maResult = await executeMatchAttendanceWorkflow(config.matchAttendance);
|
|
52
|
+
result.results.matchAttendance = maResult;
|
|
53
|
+
if (maResult.baseCampaignId)
|
|
54
|
+
result.totalCampaigns++;
|
|
55
|
+
result.totalCampaigns += maResult.achievements.filter((a) => a.bonusCampaignId).length;
|
|
56
|
+
result.totalAchievements += maResult.achievements.length;
|
|
57
|
+
result.errors.push(...maResult.errors);
|
|
58
|
+
break;
|
|
59
|
+
}
|
|
60
|
+
case "early-arrival": {
|
|
61
|
+
const eaResult = await executeEarlyArrivalWorkflow(config.earlyArrival);
|
|
62
|
+
result.results.earlyArrival = eaResult;
|
|
63
|
+
if (eaResult.campaignId)
|
|
64
|
+
result.totalCampaigns++;
|
|
65
|
+
result.errors.push(...eaResult.errors);
|
|
66
|
+
break;
|
|
67
|
+
}
|
|
68
|
+
case "sportsbar-visit": {
|
|
69
|
+
const sbResult = await executeSportsbarVisitWorkflow(config.sportsbarVisit);
|
|
70
|
+
result.results.sportsbarVisit = sbResult;
|
|
71
|
+
if (sbResult.visitCampaignId)
|
|
72
|
+
result.totalCampaigns++;
|
|
73
|
+
if (sbResult.bonusCampaignId)
|
|
74
|
+
result.totalCampaigns++;
|
|
75
|
+
if (sbResult.achievementId)
|
|
76
|
+
result.totalAchievements++;
|
|
77
|
+
result.errors.push(...sbResult.errors);
|
|
78
|
+
break;
|
|
79
|
+
}
|
|
80
|
+
case "vod-watching": {
|
|
81
|
+
const vodResult = await executeVodWatchingWorkflow(config.vodWatching);
|
|
82
|
+
result.results.vodWatching = vodResult;
|
|
83
|
+
if (vodResult.watchCampaignId)
|
|
84
|
+
result.totalCampaigns++;
|
|
85
|
+
if (vodResult.bonusCampaignId)
|
|
86
|
+
result.totalCampaigns++;
|
|
87
|
+
if (vodResult.achievementId)
|
|
88
|
+
result.totalAchievements++;
|
|
89
|
+
result.errors.push(...vodResult.errors);
|
|
90
|
+
break;
|
|
91
|
+
}
|
|
92
|
+
case "app-login-streak": {
|
|
93
|
+
const loginResult = await executeAppLoginStreakWorkflow(config.appLoginStreak);
|
|
94
|
+
result.results.appLoginStreak = loginResult;
|
|
95
|
+
if (loginResult.loginCampaignId)
|
|
96
|
+
result.totalCampaigns++;
|
|
97
|
+
if (loginResult.streakBonusCampaignId)
|
|
98
|
+
result.totalCampaigns++;
|
|
99
|
+
if (loginResult.streakAchievementId)
|
|
100
|
+
result.totalAchievements++;
|
|
101
|
+
result.errors.push(...loginResult.errors);
|
|
102
|
+
break;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
// Determine overall success
|
|
107
|
+
result.success = result.errors.length === 0 && result.totalCampaigns > 0;
|
|
108
|
+
// Build summary
|
|
109
|
+
result.summary = buildMasterSummary(result);
|
|
110
|
+
}
|
|
111
|
+
catch (error) {
|
|
112
|
+
result.errors.push(`Master workflow error: ${error instanceof Error ? error.message : String(error)}`);
|
|
113
|
+
}
|
|
114
|
+
return result;
|
|
115
|
+
}
|
|
116
|
+
// ============================================================================
|
|
117
|
+
// Helper Functions
|
|
118
|
+
// ============================================================================
|
|
119
|
+
function buildMasterSummary(result) {
|
|
120
|
+
const lines = [];
|
|
121
|
+
lines.push(`Fan Engagement Program Setup Complete!`);
|
|
122
|
+
lines.push(`========================================`);
|
|
123
|
+
lines.push(`\nCreated: ${result.totalCampaigns} campaigns, ${result.totalAchievements} achievements`);
|
|
124
|
+
// Match Attendance
|
|
125
|
+
if (result.results.matchAttendance) {
|
|
126
|
+
const ma = result.results.matchAttendance;
|
|
127
|
+
if (ma.baseCampaignId) {
|
|
128
|
+
lines.push(`\nMatch Attendance:`);
|
|
129
|
+
lines.push(` - Base campaign: ${ma.baseCampaignId}`);
|
|
130
|
+
if (ma.achievements.length > 0) {
|
|
131
|
+
lines.push(` - Achievements: ${ma.achievements.map((a) => a.milestone).join(", ")} matches`);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
// Early Arrival
|
|
136
|
+
if (result.results.earlyArrival?.campaignId) {
|
|
137
|
+
lines.push(`\nEarly Arrival:`);
|
|
138
|
+
lines.push(` - Campaign: ${result.results.earlyArrival.campaignId}`);
|
|
139
|
+
}
|
|
140
|
+
// Sports Bar
|
|
141
|
+
if (result.results.sportsbarVisit?.visitCampaignId) {
|
|
142
|
+
lines.push(`\nSports Bar Visits:`);
|
|
143
|
+
lines.push(` - Visit campaign: ${result.results.sportsbarVisit.visitCampaignId}`);
|
|
144
|
+
if (result.results.sportsbarVisit.achievementId) {
|
|
145
|
+
lines.push(` - Achievement: ${result.results.sportsbarVisit.achievementId}`);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
// VOD Watching
|
|
149
|
+
if (result.results.vodWatching?.watchCampaignId) {
|
|
150
|
+
lines.push(`\nVOD Watching:`);
|
|
151
|
+
lines.push(` - Watch campaign: ${result.results.vodWatching.watchCampaignId}`);
|
|
152
|
+
if (result.results.vodWatching.achievementId) {
|
|
153
|
+
lines.push(` - Achievement: ${result.results.vodWatching.achievementId}`);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
// App Login
|
|
157
|
+
if (result.results.appLoginStreak?.loginCampaignId) {
|
|
158
|
+
lines.push(`\nApp Login Streak:`);
|
|
159
|
+
lines.push(` - Login campaign: ${result.results.appLoginStreak.loginCampaignId}`);
|
|
160
|
+
if (result.results.appLoginStreak.streakAchievementId) {
|
|
161
|
+
lines.push(` - Streak achievement: ${result.results.appLoginStreak.streakAchievementId}`);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
// Custom events reference
|
|
165
|
+
lines.push(`\nCustom Events Reference:`);
|
|
166
|
+
lines.push(` - match_attendance: Triggered when fan scans at stadium entry`);
|
|
167
|
+
lines.push(` - early_arrival: Triggered when fan arrives early (needs minutes_before attribute)`);
|
|
168
|
+
lines.push(` - sportsbar_visit: Triggered when fan visits the sports bar`);
|
|
169
|
+
lines.push(` - vod_watch: Triggered when fan watches video (needs minutes_watched attribute)`);
|
|
170
|
+
lines.push(` - app_login: Triggered on daily app login`);
|
|
171
|
+
// Errors
|
|
172
|
+
if (result.errors.length > 0) {
|
|
173
|
+
lines.push(`\nWarnings/Errors (${result.errors.length}):`);
|
|
174
|
+
for (const error of result.errors.slice(0, 5)) {
|
|
175
|
+
lines.push(` - ${error}`);
|
|
176
|
+
}
|
|
177
|
+
if (result.errors.length > 5) {
|
|
178
|
+
lines.push(` ... and ${result.errors.length - 5} more`);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
return lines.join("\n");
|
|
182
|
+
}
|
|
183
|
+
// ============================================================================
|
|
184
|
+
// All Workflows Registry
|
|
185
|
+
// ============================================================================
|
|
186
|
+
export const allWorkflows = [
|
|
187
|
+
matchAttendanceWorkflow,
|
|
188
|
+
earlyArrivalWorkflow,
|
|
189
|
+
sportsbarVisitWorkflow,
|
|
190
|
+
vodWatchingWorkflow,
|
|
191
|
+
appLoginStreakWorkflow,
|
|
192
|
+
];
|
|
193
|
+
/**
|
|
194
|
+
* Get workflow by ID
|
|
195
|
+
*/
|
|
196
|
+
export function getWorkflow(id) {
|
|
197
|
+
return allWorkflows.find((w) => w.id === id);
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Execute a workflow by ID with given config
|
|
201
|
+
*/
|
|
202
|
+
export async function executeWorkflowById(id, config) {
|
|
203
|
+
const workflow = getWorkflow(id);
|
|
204
|
+
if (!workflow) {
|
|
205
|
+
throw new Error(`Workflow not found: ${id}`);
|
|
206
|
+
}
|
|
207
|
+
return workflow.execute(config);
|
|
208
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Match Attendance Workflow
|
|
3
|
+
*
|
|
4
|
+
* Creates a complete match attendance reward program including:
|
|
5
|
+
* - Base campaign for per-match coin rewards
|
|
6
|
+
* - Achievements for attendance milestones (6, 12 matches, etc.)
|
|
7
|
+
* - Bonus campaigns triggered by achievement completion
|
|
8
|
+
*/
|
|
9
|
+
export interface MatchAttendanceConfig {
|
|
10
|
+
/** Coins awarded per match attendance */
|
|
11
|
+
coinsPerMatch: number;
|
|
12
|
+
/** Attendance milestones for achievements (e.g., [6, 12] or [6, 12, "80%"]) */
|
|
13
|
+
milestones: (number | string)[];
|
|
14
|
+
/** Badge names for each milestone */
|
|
15
|
+
badgeNames: string[];
|
|
16
|
+
/** Bonus coins for each milestone */
|
|
17
|
+
milestoneBonuses: number[];
|
|
18
|
+
/** Maximum attendances counted per day (anti-fraud) */
|
|
19
|
+
limitPerDay: number;
|
|
20
|
+
/** Season start date (ISO format) */
|
|
21
|
+
seasonStart: string;
|
|
22
|
+
/** Season end date (ISO format) */
|
|
23
|
+
seasonEnd: string;
|
|
24
|
+
}
|
|
25
|
+
export interface MatchAttendanceResult {
|
|
26
|
+
success: boolean;
|
|
27
|
+
baseCampaignId?: string;
|
|
28
|
+
achievements: Array<{
|
|
29
|
+
achievementId: string;
|
|
30
|
+
milestone: number | string;
|
|
31
|
+
badgeName: string;
|
|
32
|
+
bonusCampaignId?: string;
|
|
33
|
+
}>;
|
|
34
|
+
errors: string[];
|
|
35
|
+
summary: string;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Execute the match attendance workflow
|
|
39
|
+
*/
|
|
40
|
+
export declare function executeMatchAttendanceWorkflow(config?: Partial<MatchAttendanceConfig>): Promise<MatchAttendanceResult>;
|
|
41
|
+
export declare const matchAttendanceWorkflow: {
|
|
42
|
+
id: string;
|
|
43
|
+
name: string;
|
|
44
|
+
execute: typeof executeMatchAttendanceWorkflow;
|
|
45
|
+
};
|