Files
wehub-resource-sync 426e9eeabd
Voice Workbench / headless workbench (mocked backends) (push) Has been cancelled
Voice Workbench / real acoustic lane (nightly, provisioned only) (push) Has been cancelled
ci / test (push) Has been cancelled
ci / lint-and-format (push) Has been cancelled
ci / build (push) Has been cancelled
ci / dev-startup (push) Has been cancelled
gitleaks / gitleaks (push) Has been cancelled
Markdown Links / Relative Markdown Links (push) Has been cancelled
Quality (Extended) / Homepage Build (PR smoke) (push) Has been cancelled
Quality (Extended) / Comment-only diff guard (push) Has been cancelled
Quality (Extended) / Format + Type Safety Ratchet (push) Has been cancelled
Quality (Extended) / Develop Gate (secret scan + UI determinism) (push) Has been cancelled
Quality (Extended) / Develop Gate (lint) (push) Has been cancelled
Chat shell gestures / Chat shell gesture + parity e2e (push) Has been cancelled
Cloud Gateway Discord / Test (push) Has been cancelled
Benchmark Bridge Tests / benchmark (bunx @biomejs/biome check packages/lifeops-bench/src, benchmark-lint) (push) Has been cancelled
Benchmark Bridge Tests / benchmark (bunx vitest run --config packages/lifeops-bench/vitest.config.ts --root packages/lifeops-bench --passWithNoTests, benchmark-tests) (push) Has been cancelled
Build Agent Image / build-and-push (push) Has been cancelled
Dev Smoke / bun run dev onboarding chat (push) Has been cancelled
Dev Smoke / Vite HMR dependency-level smoke (push) Has been cancelled
Electrobun Submodule Guard / electrobun gitlink is fetchable (push) Has been cancelled
Publish @elizaos/example-code / check_npm (push) Has been cancelled
Publish @elizaos/example-code / publish_npm (push) Has been cancelled
Publish @elizaos/plugin-elizacloud / verify_version (push) Has been cancelled
Publish @elizaos/plugin-elizacloud / publish_npm (push) Has been cancelled
Sandbox Live Smoke / Sandbox live smoke (push) Has been cancelled
Snap Build & Test / Build Snap (amd64) (push) Has been cancelled
Snap Build & Test / Build Snap (arm64) (push) Has been cancelled
Test Packaging / elizaos CLI global-install smoke (node + bun) (push) Has been cancelled
Cloud Gateway Webhook / Test (push) Has been cancelled
Cloud Tests / lint-and-types (push) Has been cancelled
Cloud Tests / unit-tests (push) Has been cancelled
Cloud Tests / integration-tests (push) Has been cancelled
Cloud Tests / e2e-tests (push) Has been cancelled
CodeQL Advanced / Analyze (javascript-typescript) (push) Has been cancelled
Deploy Apps Worker (Product 2) / Determine environment (push) Has been cancelled
Deploy Apps Worker (Product 2) / Deploy apps worker to apps-control host (${{ needs.determine-env.outputs.environment }}) (push) Has been cancelled
Deploy Eliza Provisioning Worker / Determine environment (push) Has been cancelled
Deploy Eliza Provisioning Worker / Deploy worker to Hetzner host (${{ needs.determine-env.outputs.environment }} @ ${{ needs.determine-env.outputs.deployment_sha }}) (push) Has been cancelled
Dev Smoke / Classify changed paths (push) Has been cancelled
supply-chain / sbom (push) Has been cancelled
supply-chain / vulnerability-scan (push) Has been cancelled
Build, Push & Deploy to Phala Cloud / build-and-push (push) Has been cancelled
Test Packaging / Validate Packaging Configs (push) Has been cancelled
Test Packaging / Build & Test PyPI Package (push) Has been cancelled
Test Packaging / PyPI on Python ${{ matrix.python }} (push) Has been cancelled
Test Packaging / Pack & Test JS Tarballs (push) Has been cancelled
UI Fixture E2E / ui-fixture-e2e (push) Has been cancelled
UI Fixture E2E / fixture-e2e (push) Has been cancelled
UI Story Gate / story-gate (push) Has been cancelled
vault-ci / test (macos-latest) (push) Has been cancelled
vault-ci / test (ubuntu-latest) (push) Has been cancelled
vault-ci / test (windows-latest) (push) Has been cancelled
vault-ci / app-core wiring tests (push) Has been cancelled
verify-patches / verify patches/CHECKSUMS.sha256 (push) Has been cancelled
Voice Benchmark Smoke / voice-emotion fixture smoke (push) Has been cancelled
Voice Benchmark Smoke / voiceagentbench fixture smoke (push) Has been cancelled
Voice Benchmark Smoke / voicebench-quality unit smoke (push) Has been cancelled
Voice Benchmark Smoke / voicebench TypeScript unit (no audio) (push) Has been cancelled
Voice Benchmark Smoke / voice bench smoke summary (push) Has been cancelled
Windows CI / windows ([bun run --cwd packages/app-core test bun run --cwd packages/elizaos test bun run --cwd packages/cloud/shared test], app-and-cli) (push) Has been cancelled
Windows CI / windows ([bun run --cwd packages/scenario-runner test bun run --cwd packages/vault test bun run --cwd packages/security test bun run --cwd plugins/plugin-coding-tools test], framework-packages) (push) Has been cancelled
Windows CI / windows ([bun run --cwd plugins/plugin-elizacloud test bun run --cwd plugins/plugin-discord test bun run --cwd plugins/plugin-anthropic test bun run --cwd plugins/plugin-openai test bun run --cwd plugins/plugin-app-control test bun run --cwd plugins/pl… (push) Has been cancelled
Windows CI / windows ([node packages/scripts/run-turbo.mjs run build --filter=@elizaos/core --filter=@elizaos/shared --filter=@elizaos/agent --concurrency=4 node packages/scripts/run-bash-linux-only.mjs scripts/verify-riscv64-buildpaths.sh node packages/scripts/run… (push) Has been cancelled
Windows CI / windows ([node packages/scripts/run-turbo.mjs run typecheck --filter=@elizaos/core --filter=@elizaos/shared --filter=@elizaos/cloud-shared --concurrency=4 bun run --cwd packages/core test bun run --cwd packages/shared test], core-runtime, 75) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:43:05 +08:00

997 lines
31 KiB
TypeScript

/**
* Shared test helpers for plugin-cloud-apps.
*
* Only the SDK client is mocked: {@link FakeElizaCloudClient} stands in for
* `@elizaos/cloud-sdk`'s `ElizaCloudClient`, and its `listApps` / `getApp`
* methods delegate to per-test functions installed via {@link setListApps} /
* {@link setGetApp}. The actions/provider/formatters under test all run for real.
*/
import { mock } from "bun:test";
import type {
ActivateAppFrontendResponse,
AdCampaignAttributionResponse,
AppBackupSnapshot,
AppDeployStatusResponse,
AppDto,
AppEarningsResponse,
AppMonetizationResponse,
AppResponse,
BuyAppDomainInput,
BuyAppDomainResponse,
CampaignDaypartingResponse,
CampaignPerformanceReportResponse,
CheckAppDomainInput,
CheckAppDomainResponse,
CreateAdSlotInput,
CreateAdSlotResponse,
CreateAppInput,
CreateAppResponse,
CreateBookingInput,
CreateBookingResponse,
CreateCampaignReportShareInput,
CreateCampaignReportShareResponse,
CreateInfluencerProfileInput,
CreateInfluencerProfileResponse,
CreatePressReleaseInput,
CreatePressReleaseResponse,
DeleteAppResponse,
DeployAppFrontendInput,
DeployAppFrontendResponse,
DeployAppInput,
DeployAppResponse,
DuplicateAdCampaignInput,
DuplicateAdCampaignResponse,
ExportAppBackupResponse,
ListAdSlotsResponse,
ListAppDomainsResponse,
ListAppFrontendDeploymentsResponse,
ListAppsResponse,
ListInfluencersResponse,
ListPressReleasesResponse,
PressReleaseDto,
RegenerateAppApiKeyResponse,
SubmitPressReleaseInput,
SubmitPressReleaseResponse,
UpdateAppInput,
UpdateAppMonetizationInput,
UpdateCampaignDaypartingInput,
WithdrawAppEarningsRequest,
WithdrawAppEarningsResponse,
} from "@elizaos/cloud-sdk";
import type { IAgentRuntime, Memory, Task, UUID } from "@elizaos/core";
/** Per-request options the SDK's poll-friendly app getters accept. */
type SdkRequestOptions = { signal?: AbortSignal; timeoutMs?: number };
type ListAppsFn = () => Promise<ListAppsResponse>;
type GetAppFn = (
id: string,
options?: SdkRequestOptions,
) => Promise<AppResponse>;
type CreateAppFn = (input: CreateAppInput) => Promise<CreateAppResponse>;
type CreateAdSlotFn = (
input: CreateAdSlotInput,
) => Promise<CreateAdSlotResponse>;
type ListAdSlotsFn = () => Promise<ListAdSlotsResponse>;
type UpdateAdCampaignDaypartingFn = (
campaignId: string,
input: UpdateCampaignDaypartingInput,
) => Promise<CampaignDaypartingResponse>;
type DuplicateAdCampaignFn = (
campaignId: string,
input?: DuplicateAdCampaignInput,
) => Promise<DuplicateAdCampaignResponse>;
type GetAdCampaignAttributionFn = (
campaignId: string,
) => Promise<AdCampaignAttributionResponse>;
type GetAdCampaignPerformanceReportFn = (
campaignId: string,
) => Promise<CampaignPerformanceReportResponse>;
type CreateAdCampaignReportShareFn = (
campaignId: string,
input?: CreateCampaignReportShareInput,
) => Promise<CreateCampaignReportShareResponse>;
type ListFrontendDeploymentsFn = (
appId: string,
) => Promise<ListAppFrontendDeploymentsResponse>;
type ActivateFrontendFn = (
appId: string,
deploymentId: string,
) => Promise<ActivateAppFrontendResponse>;
type DeployAppFrontendFn = (
id: string,
input: DeployAppFrontendInput,
) => Promise<DeployAppFrontendResponse>;
type CreateBookingFn = (
input: CreateBookingInput,
) => Promise<CreateBookingResponse>;
type CreateInfluencerProfileFn = (
input: CreateInfluencerProfileInput,
) => Promise<CreateInfluencerProfileResponse>;
type ListInfluencersFn = (niche?: string) => Promise<ListInfluencersResponse>;
type CreatePressReleaseFn = (
input: CreatePressReleaseInput,
) => Promise<CreatePressReleaseResponse>;
type ListPressReleasesFn = () => Promise<ListPressReleasesResponse>;
type SubmitPressReleaseFn = (
releaseId: string,
input?: SubmitPressReleaseInput,
) => Promise<SubmitPressReleaseResponse>;
type ExportAppBackupFn = (appId: string) => Promise<ExportAppBackupResponse>;
type DeployAppFn = (
id: string,
input?: DeployAppInput,
) => Promise<DeployAppResponse>;
type GetAppDeployStatusFn = (
id: string,
options?: SdkRequestOptions,
) => Promise<AppDeployStatusResponse>;
type DeleteAppFn = (id: string) => Promise<DeleteAppResponse>;
type UpdateAppFn = (id: string, patch: UpdateAppInput) => Promise<AppResponse>;
type UpdateMonetizationFn = (
id: string,
settings: UpdateAppMonetizationInput,
) => Promise<AppMonetizationResponse>;
type GetAppEarningsFn = (
id: string,
options?: { days?: number },
) => Promise<AppEarningsResponse>;
type WithdrawAppEarningsFn = (
id: string,
request: WithdrawAppEarningsRequest,
) => Promise<WithdrawAppEarningsResponse>;
type RegenerateAppApiKeyFn = (
id: string,
) => Promise<RegenerateAppApiKeyResponse>;
type CheckAppDomainFn = (
id: string,
input: CheckAppDomainInput,
) => Promise<CheckAppDomainResponse>;
type BuyAppDomainFn = (
id: string,
input: BuyAppDomainInput,
) => Promise<BuyAppDomainResponse>;
type ListAppDomainsFn = (id: string) => Promise<ListAppDomainsResponse>;
type CloudAppsTestRuntime = Pick<
IAgentRuntime,
| "agentId"
| "getSetting"
| "getTasks"
| "createTask"
| "updateTask"
| "deleteTask"
>;
interface SdkState {
listApps: ListAppsFn;
getApp: GetAppFn;
createApp: CreateAppFn;
deployApp: DeployAppFn;
createAdSlot: CreateAdSlotFn;
listAdSlots: ListAdSlotsFn;
updateAdCampaignDayparting: UpdateAdCampaignDaypartingFn;
duplicateAdCampaign: DuplicateAdCampaignFn;
getAdCampaignAttribution: GetAdCampaignAttributionFn;
getAdCampaignPerformanceReport: GetAdCampaignPerformanceReportFn;
createAdCampaignReportShare: CreateAdCampaignReportShareFn;
deployAppFrontend: DeployAppFrontendFn;
listAppFrontendDeployments: ListFrontendDeploymentsFn;
activateAppFrontend: ActivateFrontendFn;
createInfluencerProfile: CreateInfluencerProfileFn;
createBooking: CreateBookingFn;
listInfluencers: ListInfluencersFn;
createPressRelease: CreatePressReleaseFn;
listPressReleases: ListPressReleasesFn;
submitPressRelease: SubmitPressReleaseFn;
exportAppBackup: ExportAppBackupFn;
getAppDeployStatus: GetAppDeployStatusFn;
deleteApp: DeleteAppFn;
updateApp: UpdateAppFn;
updateMonetization: UpdateMonetizationFn;
getAppEarnings: GetAppEarningsFn;
withdrawAppEarnings: WithdrawAppEarningsFn;
regenerateAppApiKey: RegenerateAppApiKeyFn;
checkAppDomain: CheckAppDomainFn;
buyAppDomain: BuyAppDomainFn;
listAppDomains: ListAppDomainsFn;
}
function defaultState(): SdkState {
return {
listApps: () => Promise.resolve({ success: true, apps: [] }),
getApp: () =>
Promise.resolve({ success: true, app: undefined as unknown as AppDto }),
createApp: () =>
Promise.resolve({
success: true,
app: undefined as unknown as AppDto,
apiKey: "eliza_app_secret",
}),
deployApp: () =>
Promise.resolve({
success: true,
deploymentId: "dep_1",
status: "BUILDING",
startedAt: "2026-06-29T00:00:00.000Z",
}),
createAdSlot: () =>
Promise.resolve({
success: true,
slot: {
id: "slot_1",
app_id: "app_1",
name: "Slot",
format: "banner",
status: "active",
floor_cpm: "10.0000",
total_impressions: 0,
total_clicks: 0,
total_revenue: "0.000000",
},
adTagToken: "v1.9999999999.deadbeef",
}),
listAdSlots: () => Promise.resolve({ success: true, slots: [] }),
updateAdCampaignDayparting: (_campaignId, input) =>
Promise.resolve({
success: true,
campaignId: "campaign_1",
status: "draft",
dayparting: input.dayparting,
updatedAt: "2026-07-02T00:00:00.000Z",
}),
duplicateAdCampaign: (_campaignId, input) =>
Promise.resolve({
success: true,
campaign: {
id: "campaign_copy",
name: input?.name ?? "Campaign Copy",
platform: "meta",
objective: "traffic",
status: "draft",
budgetType: "daily",
budgetAmount: "100.00",
budgetCurrency: "USD",
creditsAllocated: "0.00",
externalCampaignId: null,
dayparting: null,
sourceCampaignId: "campaign_1",
createdAt: "2026-07-02T00:00:00.000Z",
},
creativesCopied: 1,
}),
getAdCampaignAttribution: (campaignId) =>
Promise.resolve({
success: true,
campaignId,
appId: "app_1",
token: "payloadpart.signaturepart123456789",
pixelEndpoint:
"https://cloud.test/api/v1/advertising/conversions/track?token=payloadpart.signaturepart123456789",
webhookEndpoint:
"https://cloud.test/api/v1/advertising/conversions/track",
install: {
pixelHtml:
'<img src="https://cloud.test/api/v1/advertising/conversions/track?token=payloadpart.signaturepart123456789&eventType=conversion&dedupeKey=ORDER_OR_EVENT_ID" width="1" height="1" style="display:none" alt="" />',
webhook: {
url: "https://cloud.test/api/v1/advertising/conversions/track",
method: "POST",
body: {
token: "payloadpart.signaturepart123456789",
eventType: "purchase",
dedupeKey: "ORDER_OR_EVENT_ID",
},
},
},
}),
getAdCampaignPerformanceReport: (campaignId) =>
Promise.resolve({
success: true,
report: {
generatedAt: "2026-07-02T00:00:00.000Z",
campaign: {
id: campaignId,
name: "Campaign",
platform: "meta",
objective: "traffic",
status: "active",
externalCampaignId: "ext_1",
appId: null,
budgetType: "daily",
budgetAmount: 100,
budgetCurrency: "USD",
creditsAllocated: 110,
creditsSpent: 11,
startDate: null,
endDate: null,
createdAt: "2026-07-01T00:00:00.000Z",
updatedAt: "2026-07-02T00:00:00.000Z",
},
dateRange: null,
summary: {
spend: 10,
impressions: 1000,
clicks: 50,
conversions: 5,
ctr: 5,
cpc: 0.2,
cpm: 10,
conversionRate: 10,
costPerConversion: 2,
budgetUtilization: 10,
conversionValue: 0,
},
provider: {
platform: "meta",
accountId: "acct_1",
externalAccountId: "external_acct",
externalCampaignId: "ext_1",
},
},
}),
createAdCampaignReportShare: (campaignId, input) =>
Promise.resolve({
success: true,
share: {
id: "share_1",
campaignId,
token: "token_1",
publicPath: "/api/v1/advertising/reports/token_1",
publicUrl: "https://elizacloud.ai/api/v1/advertising/reports/token_1",
expiresAt: input?.expiresAt ?? "2026-07-09T00:00:00.000Z",
},
}),
deployAppFrontend: () =>
Promise.resolve({
success: true,
deployment: {
id: "fe_dep_1",
app_id: "app_1",
version: 1,
status: "active",
r2_prefix: "app-frontends/o/app_1/fe_dep_1/",
content_hash: "a".repeat(64),
file_count: 1,
total_bytes: 100,
error: null,
created_at: "2026-06-29T00:00:00.000Z",
activated_at: "2026-06-29T00:00:00.000Z",
},
}),
listAppFrontendDeployments: () =>
Promise.resolve({
success: true,
active_deployment_id: null,
deployments: [],
}),
activateAppFrontend: (_a, id) =>
Promise.resolve({
success: true,
deployment: {
id,
app_id: "app_1",
version: 1,
status: "active",
r2_prefix: "p",
content_hash: null,
file_count: 0,
total_bytes: 0,
error: null,
created_at: "2020-01-01",
activated_at: "2020-01-01",
},
}),
createInfluencerProfile: () =>
Promise.resolve({
success: true,
profile: {
id: "inf_1",
display_name: "Creator",
niche: null,
bio: null,
platforms: [],
status: "active",
},
}),
listInfluencers: () => Promise.resolve({ success: true, profiles: [] }),
createBooking: () =>
Promise.resolve({
success: true,
booking: {
id: "bk_1",
advertiser_org_id: "org",
influencer_profile_id: "inf_1",
amount: "100.00",
status: "offered",
brief: "b",
},
}),
createPressRelease: (input) =>
Promise.resolve({
success: true,
release: {
id: "pr_1",
organization_id: "org",
created_by_user_id: "user",
title: input.title,
summary: input.summary ?? null,
body: input.body,
boilerplate: input.boilerplate ?? null,
status: "draft",
target_audience: input.targetAudience ?? {},
target_regions: input.targetRegions ?? [],
assets: input.assets ?? [],
embargo_at: input.embargoAt ?? null,
submitted_at: null,
distributed_at: null,
failed_reason: null,
idempotency_key: input.idempotencyKey ?? null,
metadata: input.metadata ?? {},
created_at: "2026-07-03T00:00:00.000Z",
updated_at: "2026-07-03T00:00:00.000Z",
} satisfies PressReleaseDto,
}),
listPressReleases: () => Promise.resolve({ success: true, releases: [] }),
submitPressRelease: (releaseId) =>
Promise.resolve({
success: true,
release: {
id: releaseId,
organization_id: "org",
created_by_user_id: "user",
title: "Launch",
summary: null,
body: "Body",
boilerplate: null,
status: "submitted",
target_audience: {},
target_regions: [],
assets: [],
embargo_at: null,
submitted_at: "2026-07-03T00:00:00.000Z",
distributed_at: null,
failed_reason: null,
idempotency_key: null,
metadata: {},
created_at: "2026-07-03T00:00:00.000Z",
updated_at: "2026-07-03T00:00:00.000Z",
} satisfies PressReleaseDto,
}),
exportAppBackup: () =>
Promise.resolve({
success: true,
backup: {
version: 1,
exportedAt: "2020-01-01T00:00:00Z",
app: {
name: "App",
description: null,
app_url: "https://a",
allowed_origins: [],
logo_url: null,
website_url: null,
contact_email: null,
linked_character_ids: [],
},
monetization: {
enabled: false,
inference_markup_percentage: 0,
purchase_share_percentage: 0,
},
} as AppBackupSnapshot,
}),
getAppDeployStatus: () =>
Promise.resolve({
success: true,
deploymentId: "dep_1",
status: "READY",
vercelUrl: null,
error: null,
startedAt: null,
}),
deleteApp: () => Promise.resolve({ success: true, message: "deleted" }),
updateApp: () =>
Promise.resolve({ success: true, app: undefined as unknown as AppDto }),
updateMonetization: () =>
Promise.resolve({ success: true, monetization: null }),
getAppEarnings: () => Promise.resolve({ success: true }),
withdrawAppEarnings: () =>
Promise.resolve({ success: true, message: "withdrawn", newBalance: 0 }),
regenerateAppApiKey: () =>
Promise.resolve({ success: true, apiKey: "eliza_app_rotated" }),
checkAppDomain: (_id, input) =>
Promise.resolve({
success: true,
domain: input.domain,
available: true,
currency: "USD",
years: 1,
price: {
wholesaleUsdCents: 1029,
marginUsdCents: 370,
totalUsdCents: 1399,
marginBps: 3600,
},
renewal: { totalUsdCents: 1399 },
}),
buyAppDomain: (_id, input) =>
Promise.resolve({
success: true,
domain: input.domain,
appDomainId: "ad_1",
zoneId: "zone_1",
status: "pending",
verified: false,
expiresAt: "2027-07-01T00:00:00.000Z",
pendingZoneProvisioning: false,
debited: { totalUsdCents: 1399, currency: "USD" },
}),
listAppDomains: () => Promise.resolve({ success: true, domains: [] }),
};
}
const state: SdkState = defaultState();
const TEST_AGENT_ID = "agent-0000-0000-0000-000000000000" as UUID;
export function setListApps(fn: ListAppsFn): void {
state.listApps = fn;
}
export function setGetApp(fn: GetAppFn): void {
state.getApp = fn;
}
export function setCreateApp(fn: CreateAppFn): void {
state.createApp = fn;
}
export function setDeployApp(fn: DeployAppFn): void {
state.deployApp = fn;
}
export function setCreateAdSlot(fn: CreateAdSlotFn): void {
state.createAdSlot = fn;
}
export function setListAdSlots(fn: ListAdSlotsFn): void {
state.listAdSlots = fn;
}
export function setUpdateAdCampaignDayparting(
fn: UpdateAdCampaignDaypartingFn,
): void {
state.updateAdCampaignDayparting = fn;
}
export function setDuplicateAdCampaign(fn: DuplicateAdCampaignFn): void {
state.duplicateAdCampaign = fn;
}
export function setGetAdCampaignAttribution(
fn: GetAdCampaignAttributionFn,
): void {
state.getAdCampaignAttribution = fn;
}
export function setGetAdCampaignPerformanceReport(
fn: GetAdCampaignPerformanceReportFn,
): void {
state.getAdCampaignPerformanceReport = fn;
}
export function setCreateAdCampaignReportShare(
fn: CreateAdCampaignReportShareFn,
): void {
state.createAdCampaignReportShare = fn;
}
export function setDeployAppFrontend(fn: DeployAppFrontendFn): void {
state.deployAppFrontend = fn;
}
export function setListAppFrontendDeployments(
fn: ListFrontendDeploymentsFn,
): void {
state.listAppFrontendDeployments = fn;
}
export function setActivateAppFrontend(fn: ActivateFrontendFn): void {
state.activateAppFrontend = fn;
}
export function setCreateInfluencerProfile(
fn: CreateInfluencerProfileFn,
): void {
state.createInfluencerProfile = fn;
}
export function setListInfluencers(fn: ListInfluencersFn): void {
state.listInfluencers = fn;
}
export function setCreateBooking(fn: CreateBookingFn): void {
state.createBooking = fn;
}
export function setCreatePressRelease(fn: CreatePressReleaseFn): void {
state.createPressRelease = fn;
}
export function setListPressReleases(fn: ListPressReleasesFn): void {
state.listPressReleases = fn;
}
export function setSubmitPressRelease(fn: SubmitPressReleaseFn): void {
state.submitPressRelease = fn;
}
export function setExportAppBackup(fn: ExportAppBackupFn): void {
state.exportAppBackup = fn;
}
export function setGetAppDeployStatus(fn: GetAppDeployStatusFn): void {
state.getAppDeployStatus = fn;
}
export function setDeleteApp(fn: DeleteAppFn): void {
state.deleteApp = fn;
}
export function setUpdateApp(fn: UpdateAppFn): void {
state.updateApp = fn;
}
export function setUpdateMonetization(fn: UpdateMonetizationFn): void {
state.updateMonetization = fn;
}
export function setGetAppEarnings(fn: GetAppEarningsFn): void {
state.getAppEarnings = fn;
}
export function setWithdrawAppEarnings(fn: WithdrawAppEarningsFn): void {
state.withdrawAppEarnings = fn;
}
export function setRegenerateAppApiKey(fn: RegenerateAppApiKeyFn): void {
state.regenerateAppApiKey = fn;
}
export function setCheckAppDomain(fn: CheckAppDomainFn): void {
state.checkAppDomain = fn;
}
export function setBuyAppDomain(fn: BuyAppDomainFn): void {
state.buyAppDomain = fn;
}
export function setListAppDomains(fn: ListAppDomainsFn): void {
state.listAppDomains = fn;
}
/** Restore default (empty / no-op) behavior between tests. */
export function resetSdk(): void {
Object.assign(state, defaultState());
}
/** Stand-in for `ElizaCloudClient` — the methods the plugin calls. */
export class FakeElizaCloudClient {
listApps(): Promise<ListAppsResponse> {
return state.listApps();
}
getApp(id: string, options?: SdkRequestOptions): Promise<AppResponse> {
return state.getApp(id, options);
}
createApp(input: CreateAppInput): Promise<CreateAppResponse> {
return state.createApp(input);
}
deployApp(id: string, input?: DeployAppInput): Promise<DeployAppResponse> {
return state.deployApp(id, input);
}
createAdSlot(input: CreateAdSlotInput): Promise<CreateAdSlotResponse> {
return state.createAdSlot(input);
}
listAdSlots(): Promise<ListAdSlotsResponse> {
return state.listAdSlots();
}
updateAdCampaignDayparting(
campaignId: string,
input: UpdateCampaignDaypartingInput,
): Promise<CampaignDaypartingResponse> {
return state.updateAdCampaignDayparting(campaignId, input);
}
duplicateAdCampaign(
campaignId: string,
input?: DuplicateAdCampaignInput,
): Promise<DuplicateAdCampaignResponse> {
return state.duplicateAdCampaign(campaignId, input);
}
getAdCampaignAttribution(
campaignId: string,
): Promise<AdCampaignAttributionResponse> {
return state.getAdCampaignAttribution(campaignId);
}
getAdCampaignPerformanceReport(
campaignId: string,
): Promise<CampaignPerformanceReportResponse> {
return state.getAdCampaignPerformanceReport(campaignId);
}
createAdCampaignReportShare(
campaignId: string,
input?: CreateCampaignReportShareInput,
): Promise<CreateCampaignReportShareResponse> {
return state.createAdCampaignReportShare(campaignId, input);
}
deployAppFrontend(
id: string,
input: DeployAppFrontendInput,
): Promise<DeployAppFrontendResponse> {
return state.deployAppFrontend(id, input);
}
listAppFrontendDeployments(
appId: string,
): Promise<ListAppFrontendDeploymentsResponse> {
return state.listAppFrontendDeployments(appId);
}
activateAppFrontend(
appId: string,
deploymentId: string,
): Promise<ActivateAppFrontendResponse> {
return state.activateAppFrontend(appId, deploymentId);
}
createInfluencerProfile(
input: CreateInfluencerProfileInput,
): Promise<CreateInfluencerProfileResponse> {
return state.createInfluencerProfile(input);
}
listInfluencers(niche?: string): Promise<ListInfluencersResponse> {
return state.listInfluencers(niche);
}
createBooking(input: CreateBookingInput): Promise<CreateBookingResponse> {
return state.createBooking(input);
}
createPressRelease(
input: CreatePressReleaseInput,
): Promise<CreatePressReleaseResponse> {
return state.createPressRelease(input);
}
listPressReleases(): Promise<ListPressReleasesResponse> {
return state.listPressReleases();
}
submitPressRelease(
releaseId: string,
input?: SubmitPressReleaseInput,
): Promise<SubmitPressReleaseResponse> {
return state.submitPressRelease(releaseId, input);
}
exportAppBackup(appId: string): Promise<ExportAppBackupResponse> {
return state.exportAppBackup(appId);
}
getAppDeployStatus(
id: string,
options?: SdkRequestOptions,
): Promise<AppDeployStatusResponse> {
return state.getAppDeployStatus(id, options);
}
deleteApp(id: string): Promise<DeleteAppResponse> {
return state.deleteApp(id);
}
updateApp(id: string, patch: UpdateAppInput): Promise<AppResponse> {
return state.updateApp(id, patch);
}
updateMonetization(
id: string,
settings: UpdateAppMonetizationInput,
): Promise<AppMonetizationResponse> {
return state.updateMonetization(id, settings);
}
getAppEarnings(
id: string,
options?: { days?: number },
): Promise<AppEarningsResponse> {
return state.getAppEarnings(id, options);
}
withdrawAppEarnings(
id: string,
request: WithdrawAppEarningsRequest,
): Promise<WithdrawAppEarningsResponse> {
return state.withdrawAppEarnings(id, request);
}
regenerateAppApiKey(id: string): Promise<RegenerateAppApiKeyResponse> {
return state.regenerateAppApiKey(id);
}
checkAppDomain(
id: string,
input: CheckAppDomainInput,
): Promise<CheckAppDomainResponse> {
return state.checkAppDomain(id, input);
}
buyAppDomain(
id: string,
input: BuyAppDomainInput,
): Promise<BuyAppDomainResponse> {
return state.buyAppDomain(id, input);
}
listAppDomains(id: string): Promise<ListAppDomainsResponse> {
return state.listAppDomains(id);
}
}
/** Build a minimal runtime exposing just `getSetting`. */
export function makeRuntime(
settings: Record<string, string | undefined> = {},
): IAgentRuntime {
const tasks: Task[] = [];
let taskCounter = 0;
const runtime: CloudAppsTestRuntime = {
agentId: TEST_AGENT_ID,
getSetting: (key: string) => settings[key] ?? null,
getTasks: (params) =>
Promise.resolve(
tasks.filter((task) => {
const agentMatches = params.agentIds.includes(task.agentId);
const tagMatches =
!params.tags ||
params.tags.every((tag) => task.tags?.includes(tag));
return agentMatches && tagMatches;
}),
),
createTask: (task: Task) => {
const id =
`task-0000-0000-0000-${String(++taskCounter).padStart(12, "0")}` as UUID;
tasks.push({
...task,
id,
agentId: task.agentId ?? TEST_AGENT_ID,
});
return Promise.resolve(id);
},
updateTask: (id: UUID, patch: Partial<Task>) => {
const idx = tasks.findIndex((task) => task.id === id);
if (idx >= 0) tasks[idx] = { ...tasks[idx], ...patch };
return Promise.resolve();
},
deleteTask: (id: UUID) => {
const idx = tasks.findIndex((task) => task.id === id);
if (idx >= 0) tasks.splice(idx, 1);
return Promise.resolve();
},
};
return runtime as IAgentRuntime;
}
/** A runtime with a valid Cloud API key configured. */
export function keyedRuntime(): IAgentRuntime {
return makeRuntime({ ELIZAOS_CLOUD_API_KEY: "eliza_test_key" });
}
/** A runtime with no Cloud API key. */
export function unkeyedRuntime(): IAgentRuntime {
return makeRuntime({});
}
/**
* A keyed runtime backed by a real in-memory `facts` store, so the facts-cache
* code under test exercises its actual create/get/update logic (only the store
* boundary is faked — the dedup + write path runs for real).
*/
export interface MemoryRuntime extends IAgentRuntime {
__facts: Memory[];
}
export function memoryRuntime(
settings: Record<string, string | undefined> = {
ELIZAOS_CLOUD_API_KEY: "eliza_test_key",
},
): MemoryRuntime {
const facts: Memory[] = [];
let counter = 0;
const tasks: Task[] = [];
let taskCounter = 0;
const runtime = {
agentId: TEST_AGENT_ID,
__facts: facts,
getSetting: (key: string) => settings[key] as unknown,
// Same in-memory task store as makeRuntime, so actions that combine the
// two-phase confirm machine WITH facts writes run for real here too.
getTasks: (params: { agentIds: string[]; tags?: string[] }) =>
Promise.resolve(
tasks.filter((task) => {
const agentMatches = params.agentIds.includes(task.agentId);
const tagMatches =
!params.tags ||
params.tags.every((tag) => task.tags?.includes(tag));
return agentMatches && tagMatches;
}),
),
createTask: (task: Task) => {
const id =
`task-0000-0000-0000-${String(++taskCounter).padStart(12, "0")}` as UUID;
tasks.push({ ...task, id, agentId: task.agentId ?? TEST_AGENT_ID });
return Promise.resolve(id);
},
updateTask: (id: UUID, patch: Partial<Task>) => {
const idx = tasks.findIndex((task) => task.id === id);
if (idx >= 0) tasks[idx] = { ...tasks[idx], ...patch };
return Promise.resolve();
},
deleteTask: (id: UUID) => {
const idx = tasks.findIndex((task) => task.id === id);
if (idx >= 0) tasks.splice(idx, 1);
return Promise.resolve();
},
getMemories: (params: { tableName: string }) =>
Promise.resolve(params.tableName === "facts" ? [...facts] : []),
createMemory: (memory: Memory, tableName: string) => {
const id = `mem-${++counter}`;
if (tableName === "facts") facts.push({ ...memory, id } as Memory);
return Promise.resolve(id);
},
updateMemory: (patch: Partial<Memory> & { id: string }) => {
const idx = facts.findIndex(
(m) => (m as { id?: string }).id === patch.id,
);
if (idx >= 0) facts[idx] = { ...facts[idx], ...patch } as Memory;
return Promise.resolve(idx >= 0);
},
deleteMemory: (id: string) => {
const idx = facts.findIndex((m) => (m as { id?: string }).id === id);
if (idx >= 0) facts.splice(idx, 1);
return Promise.resolve();
},
} as unknown as MemoryRuntime;
return runtime;
}
/** Build a message Memory with entity/room ids (for memory-writing actions). */
export function makeRoomMessage(text: string): Memory {
return {
id: "msg-0000-0000-0000-000000000000",
entityId: "entity-0000-0000-0000-000000000000",
roomId: "room-0000-0000-0000-000000000000",
content: { text },
} as unknown as Memory;
}
/** Build a message Memory with the given text. */
export function makeMessage(text: string): Memory {
return {
content: { text },
} as unknown as Memory;
}
/** A callback that records the content it was called with. */
export function captureCallback(): {
fn: (content: { text?: string; actions?: string[] }) => Promise<Memory[]>;
calls: Array<{ text?: string; actions?: string[] }>;
} {
const calls: Array<{ text?: string; actions?: string[] }> = [];
const fn = mock((content: { text?: string; actions?: string[] }) => {
calls.push(content);
return Promise.resolve([] as Memory[]);
});
return { fn, calls };
}
/** Minimal AppDto factory — fills only the fields the read-core reads. */
export function makeApp(overrides: Partial<AppDto> = {}): AppDto {
return {
id: "00000000-0000-0000-0000-000000000001",
name: "Test App",
description: null,
slug: "test-app",
organization_id: "org-1",
created_by_user_id: "user-1",
app_url: "https://test-app.example.com",
allowed_origins: [],
api_key_id: null,
affiliate_code: null,
referral_bonus_credits: null,
total_requests: 0,
total_users: 0,
total_credits_used: null,
logo_url: null,
website_url: null,
contact_email: null,
metadata: {},
deployment_status: "draft",
production_url: null,
last_deployed_at: null,
github_repo: null,
linked_character_ids: null,
monetization_enabled: false,
inference_markup_percentage: null,
purchase_share_percentage: null,
platform_offset_amount: null,
custom_pricing_enabled: null,
total_creator_earnings: null,
total_platform_revenue: null,
discord_automation: null,
telegram_automation: null,
twitter_automation: null,
promotional_assets: null,
email_notifications: null,
response_notifications: null,
is_active: true,
is_approved: true,
review_status: "draft",
review_content_hash: null,
reviewed_at: null,
created_at: "2026-01-01T00:00:00.000Z",
updated_at: "2026-01-01T00:00:00.000Z",
last_used_at: null,
...overrides,
};
}