adapty 0.8.2 → 0.8.3-beta.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/commands/asa/ad-groups/create.js +1 -1
- package/dist/commands/asa/ad-groups/update.js +1 -1
- package/dist/commands/asa/ads/create.js +1 -1
- package/dist/commands/asa/ads/update.js +1 -1
- package/dist/commands/asa/automations/create.js +1 -1
- package/dist/commands/asa/automations/run.js +1 -1
- package/dist/commands/asa/automations/update.js +1 -1
- package/dist/commands/asa/campaigns/bulk-create.js +1 -1
- package/dist/commands/asa/campaigns/create.js +1 -1
- package/dist/commands/asa/campaigns/update.js +1 -1
- package/dist/commands/asa/keywords/add.js +1 -1
- package/dist/commands/asa/keywords/update.js +1 -1
- package/dist/commands/asa/negative-keywords/add.js +1 -1
- package/dist/commands/asa/product-pages/sync.js +1 -1
- package/dist/commands/flows/publish.d.ts +15 -0
- package/dist/commands/flows/publish.js +34 -0
- package/dist/commands/flows/update.d.ts +15 -0
- package/dist/commands/flows/update.js +28 -0
- package/dist/commands/placements/create.js +18 -3
- package/dist/commands/placements/update.js +18 -3
- package/dist/lib/api-schemas.d.ts +10 -1
- package/dist/lib/placement-audiences.d.ts +6 -0
- package/dist/lib/placement-audiences.js +25 -0
- package/oclif.manifest.json +1492 -1383
- package/package.json +3 -2
- /package/dist/lib/{asa-confirm.d.ts → confirm.d.ts} +0 -0
- /package/dist/lib/{asa-confirm.js → confirm.js} +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Command, Flags } from '@oclif/core';
|
|
2
2
|
import { asaWrite, createAsaClient, noteReplay } from '../../../lib/asa-client.js';
|
|
3
|
-
import { confirmFlags, confirmMutation } from '../../../lib/asa-confirm.js';
|
|
4
3
|
import { currencyFlag, idempotencyFlags, money, moneyFlag, pricingModelFlag, scheduleFlags, startOfDayUtc, todayUtc, } from '../../../lib/asa-flags.js';
|
|
4
|
+
import { confirmFlags, confirmMutation } from '../../../lib/confirm.js';
|
|
5
5
|
import { isValidUuid } from '../../../lib/flags.js';
|
|
6
6
|
import { printResponse } from '../../../lib/output.js';
|
|
7
7
|
export default class AsaAdGroupsCreate extends Command {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Args, Command, Flags } from '@oclif/core';
|
|
2
2
|
import { asaWrite, createAsaClient, noteReplay } from '../../../lib/asa-client.js';
|
|
3
|
-
import { confirmFlags, confirmMutation } from '../../../lib/asa-confirm.js';
|
|
4
3
|
import { currencyFlag, idempotencyFlags, money, moneyFlag, scheduleFlags, startOfDayUtc } from '../../../lib/asa-flags.js';
|
|
4
|
+
import { confirmFlags, confirmMutation } from '../../../lib/confirm.js';
|
|
5
5
|
import { isValidUuid } from '../../../lib/flags.js';
|
|
6
6
|
import { printResponse } from '../../../lib/output.js';
|
|
7
7
|
export default class AsaAdGroupsUpdate extends Command {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Command, Flags } from '@oclif/core';
|
|
2
2
|
import { asaWrite, createAsaClient, noteReplay } from '../../../lib/asa-client.js';
|
|
3
|
-
import { confirmFlags, confirmMutation } from '../../../lib/asa-confirm.js';
|
|
4
3
|
import { idempotencyFlags } from '../../../lib/asa-flags.js';
|
|
4
|
+
import { confirmFlags, confirmMutation } from '../../../lib/confirm.js';
|
|
5
5
|
import { isValidUuid } from '../../../lib/flags.js';
|
|
6
6
|
import { printResponse } from '../../../lib/output.js';
|
|
7
7
|
export default class AsaAdsCreate extends Command {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Args, Command, Flags } from '@oclif/core';
|
|
2
2
|
import { asaWrite, createAsaClient, noteReplay } from '../../../lib/asa-client.js';
|
|
3
|
-
import { confirmFlags, confirmMutation } from '../../../lib/asa-confirm.js';
|
|
4
3
|
import { idempotencyFlags } from '../../../lib/asa-flags.js';
|
|
4
|
+
import { confirmFlags, confirmMutation } from '../../../lib/confirm.js';
|
|
5
5
|
import { isValidUuid } from '../../../lib/flags.js';
|
|
6
6
|
import { printResponse } from '../../../lib/output.js';
|
|
7
7
|
export default class AsaAdsUpdate extends Command {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { Command, Flags } from '@oclif/core';
|
|
2
2
|
import { readFile } from 'node:fs/promises';
|
|
3
3
|
import { asaWrite, createAsaClient, noteReplay } from '../../../lib/asa-client.js';
|
|
4
|
-
import { confirmFlags, confirmMutation } from '../../../lib/asa-confirm.js';
|
|
5
4
|
import { idempotencyFlags } from '../../../lib/asa-flags.js';
|
|
5
|
+
import { confirmFlags, confirmMutation } from '../../../lib/confirm.js';
|
|
6
6
|
import { printResponse } from '../../../lib/output.js';
|
|
7
7
|
export default class AsaAutomationsCreate extends Command {
|
|
8
8
|
static description = 'Create an automation rule from a JSON rule file';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Args, Command, Flags } from '@oclif/core';
|
|
2
2
|
import { asaWrite, createAsaClient, noteReplay } from '../../../lib/asa-client.js';
|
|
3
|
-
import { confirmFlags, confirmMutation } from '../../../lib/asa-confirm.js';
|
|
4
3
|
import { idempotencyFlags } from '../../../lib/asa-flags.js';
|
|
4
|
+
import { confirmFlags, confirmMutation } from '../../../lib/confirm.js';
|
|
5
5
|
import { isValidUuid } from '../../../lib/flags.js';
|
|
6
6
|
export default class AsaAutomationsRun extends Command {
|
|
7
7
|
static args = {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { Args, Command, Flags } from '@oclif/core';
|
|
2
2
|
import { readFile } from 'node:fs/promises';
|
|
3
3
|
import { asaWrite, createAsaClient, noteReplay } from '../../../lib/asa-client.js';
|
|
4
|
-
import { confirmFlags, confirmMutation } from '../../../lib/asa-confirm.js';
|
|
5
4
|
import { idempotencyFlags } from '../../../lib/asa-flags.js';
|
|
5
|
+
import { confirmFlags, confirmMutation } from '../../../lib/confirm.js';
|
|
6
6
|
import { isValidUuid } from '../../../lib/flags.js';
|
|
7
7
|
import { printResponse } from '../../../lib/output.js';
|
|
8
8
|
export default class AsaAutomationsUpdate extends Command {
|
|
@@ -2,8 +2,8 @@ import { Command, Flags } from '@oclif/core';
|
|
|
2
2
|
import { readFile } from 'node:fs/promises';
|
|
3
3
|
import { basename } from 'node:path';
|
|
4
4
|
import { asaWrite, createAsaClient, noteReplay } from '../../../lib/asa-client.js';
|
|
5
|
-
import { confirmFlags, confirmMutation } from '../../../lib/asa-confirm.js';
|
|
6
5
|
import { idempotencyFlags } from '../../../lib/asa-flags.js';
|
|
6
|
+
import { confirmFlags, confirmMutation } from '../../../lib/confirm.js';
|
|
7
7
|
import { printResponse } from '../../../lib/output.js';
|
|
8
8
|
const TERMINAL_STATUSES = new Set(['failed', 'partial', 'success']);
|
|
9
9
|
export default class AsaCampaignsBulkCreate extends Command {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Command, Flags } from '@oclif/core';
|
|
2
2
|
import { asaWrite, createAsaClient, noteReplay } from '../../../lib/asa-client.js';
|
|
3
|
-
import { confirmFlags, confirmMutation } from '../../../lib/asa-confirm.js';
|
|
4
3
|
import { currencyFlag, idempotencyFlags, invoiceFlags, locInvoiceDetails, money, moneyFlag, reportServingState, } from '../../../lib/asa-flags.js';
|
|
4
|
+
import { confirmFlags, confirmMutation } from '../../../lib/confirm.js';
|
|
5
5
|
import { isValidUuid } from '../../../lib/flags.js';
|
|
6
6
|
import { printResponse } from '../../../lib/output.js';
|
|
7
7
|
export default class AsaCampaignsCreate extends Command {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Args, Command, Flags } from '@oclif/core';
|
|
2
2
|
import { asaWrite, createAsaClient, noteReplay } from '../../../lib/asa-client.js';
|
|
3
|
-
import { confirmFlags, confirmMutation } from '../../../lib/asa-confirm.js';
|
|
4
3
|
import { currencyFlag, idempotencyFlags, invoiceFlags, locInvoiceDetails, money, moneyFlag, reportServingState, } from '../../../lib/asa-flags.js';
|
|
4
|
+
import { confirmFlags, confirmMutation } from '../../../lib/confirm.js';
|
|
5
5
|
import { isValidUuid } from '../../../lib/flags.js';
|
|
6
6
|
import { printResponse } from '../../../lib/output.js';
|
|
7
7
|
export default class AsaCampaignsUpdate extends Command {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { Command, Flags } from '@oclif/core';
|
|
2
2
|
import { readFile } from 'node:fs/promises';
|
|
3
3
|
import { asaWrite, createAsaClient, noteReplay } from '../../../lib/asa-client.js';
|
|
4
|
-
import { confirmFlags, confirmMutation } from '../../../lib/asa-confirm.js';
|
|
5
4
|
import { currencyFlag, idempotencyFlags, MAX_BULK_ITEMS, money, moneyFlag, reportBulkOutcome } from '../../../lib/asa-flags.js';
|
|
5
|
+
import { confirmFlags, confirmMutation } from '../../../lib/confirm.js';
|
|
6
6
|
import { isValidUuid } from '../../../lib/flags.js';
|
|
7
7
|
export default class AsaKeywordsAdd extends Command {
|
|
8
8
|
static description = 'Add targeting keywords to an ad group';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Args, Command, Flags } from '@oclif/core';
|
|
2
2
|
import { asaWrite, createAsaClient, noteReplay } from '../../../lib/asa-client.js';
|
|
3
|
-
import { confirmFlags, confirmMutation } from '../../../lib/asa-confirm.js';
|
|
4
3
|
import { currencyFlag, idempotencyFlags, money, moneyFlag, reportBulkOutcome } from '../../../lib/asa-flags.js';
|
|
4
|
+
import { confirmFlags, confirmMutation } from '../../../lib/confirm.js';
|
|
5
5
|
import { isValidUuid } from '../../../lib/flags.js';
|
|
6
6
|
export default class AsaKeywordsUpdate extends Command {
|
|
7
7
|
static args = {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Command, Flags } from '@oclif/core';
|
|
2
2
|
import { asaWrite, createAsaClient, noteReplay } from '../../../lib/asa-client.js';
|
|
3
|
-
import { confirmFlags, confirmMutation } from '../../../lib/asa-confirm.js';
|
|
4
3
|
import { idempotencyFlags, MAX_BULK_ITEMS, reportBulkOutcome } from '../../../lib/asa-flags.js';
|
|
4
|
+
import { confirmFlags, confirmMutation } from '../../../lib/confirm.js';
|
|
5
5
|
import { isValidUuid } from '../../../lib/flags.js';
|
|
6
6
|
export default class AsaNegativeKeywordsAdd extends Command {
|
|
7
7
|
static description = 'Add negative keywords to an ad group or across a campaign';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Command, Flags } from '@oclif/core';
|
|
2
2
|
import { asaWrite, createAsaClient } from '../../../lib/asa-client.js';
|
|
3
|
-
import { confirmFlags, confirmMutation } from '../../../lib/asa-confirm.js';
|
|
4
3
|
import { idempotencyFlags } from '../../../lib/asa-flags.js';
|
|
4
|
+
import { confirmFlags, confirmMutation } from '../../../lib/confirm.js';
|
|
5
5
|
import { printResponse } from '../../../lib/output.js';
|
|
6
6
|
export default class AsaProductPagesSync extends Command {
|
|
7
7
|
static description = 'Refresh custom product pages from Apple';
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Command } from '@oclif/core';
|
|
2
|
+
import type { FlowDTO } from '../../lib/api-schemas.js';
|
|
3
|
+
export default class FlowsPublish extends Command {
|
|
4
|
+
static args: {
|
|
5
|
+
flow_id: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
|
|
6
|
+
};
|
|
7
|
+
static description: string;
|
|
8
|
+
static enableJsonFlag: boolean;
|
|
9
|
+
static examples: string[];
|
|
10
|
+
static flags: {
|
|
11
|
+
yes: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
12
|
+
app: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
13
|
+
};
|
|
14
|
+
run(): Promise<FlowDTO>;
|
|
15
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { Args, Command } from '@oclif/core';
|
|
2
|
+
import { createAuthenticatedClient } from '../../lib/client-from-config.js';
|
|
3
|
+
import { confirmFlags, confirmMutation } from '../../lib/confirm.js';
|
|
4
|
+
import { appFlag, isValidUuid } from '../../lib/flags.js';
|
|
5
|
+
import { printResponse } from '../../lib/output.js';
|
|
6
|
+
export default class FlowsPublish extends Command {
|
|
7
|
+
static args = {
|
|
8
|
+
flow_id: Args.string({ description: 'Flow ID (UUID)', required: true }),
|
|
9
|
+
};
|
|
10
|
+
static description = 'Publish a flow (async — publication completes in the background)';
|
|
11
|
+
static enableJsonFlag = true;
|
|
12
|
+
static examples = ['<%= config.bin %> flows publish --app UUID 550e8400-e29b-41d4-a716-446655440000'];
|
|
13
|
+
static flags = {
|
|
14
|
+
...appFlag,
|
|
15
|
+
...confirmFlags,
|
|
16
|
+
};
|
|
17
|
+
async run() {
|
|
18
|
+
const { args, flags } = await this.parse(FlowsPublish);
|
|
19
|
+
if (!isValidUuid(args.flow_id)) {
|
|
20
|
+
this.error('Invalid flow ID format.', { exit: 2 });
|
|
21
|
+
}
|
|
22
|
+
const client = await createAuthenticatedClient(this.config);
|
|
23
|
+
const flow = await client.get(`/apps/${flags.app}/flows/${args.flow_id}/`);
|
|
24
|
+
await confirmMutation(this, {
|
|
25
|
+
method: 'POST',
|
|
26
|
+
path: `/apps/${flags.app}/flows/${args.flow_id}/publish/`,
|
|
27
|
+
summary: `Publish flow "${flow.name}" live to end users`,
|
|
28
|
+
}, flags.yes);
|
|
29
|
+
const result = await client.post(`/apps/${flags.app}/flows/${args.flow_id}/publish/`);
|
|
30
|
+
this.log('Publishing started — status: publishing. Publication completes asynchronously.');
|
|
31
|
+
printResponse(result, this.log.bind(this));
|
|
32
|
+
return result;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Command } from '@oclif/core';
|
|
2
|
+
import type { FlowDTO } from '../../lib/api-schemas.js';
|
|
3
|
+
export default class FlowsUpdate extends Command {
|
|
4
|
+
static args: {
|
|
5
|
+
flow_id: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
|
|
6
|
+
};
|
|
7
|
+
static description: string;
|
|
8
|
+
static enableJsonFlag: boolean;
|
|
9
|
+
static examples: string[];
|
|
10
|
+
static flags: {
|
|
11
|
+
name: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
12
|
+
app: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
13
|
+
};
|
|
14
|
+
run(): Promise<FlowDTO>;
|
|
15
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { Args, Command, Flags } from '@oclif/core';
|
|
2
|
+
import { createAuthenticatedClient } from '../../lib/client-from-config.js';
|
|
3
|
+
import { appFlag, isValidUuid } from '../../lib/flags.js';
|
|
4
|
+
import { printResponse } from '../../lib/output.js';
|
|
5
|
+
export default class FlowsUpdate extends Command {
|
|
6
|
+
static args = {
|
|
7
|
+
flow_id: Args.string({ description: 'Flow ID (UUID)', required: true }),
|
|
8
|
+
};
|
|
9
|
+
static description = 'Rename a flow';
|
|
10
|
+
static enableJsonFlag = true;
|
|
11
|
+
static examples = ['<%= config.bin %> flows update --app UUID 550e8400-e29b-41d4-a716-446655440000 --name "Onboarding v2"'];
|
|
12
|
+
static flags = {
|
|
13
|
+
...appFlag,
|
|
14
|
+
name: Flags.string({ description: 'New flow name', required: true }),
|
|
15
|
+
};
|
|
16
|
+
async run() {
|
|
17
|
+
const { args, flags } = await this.parse(FlowsUpdate);
|
|
18
|
+
if (!isValidUuid(args.flow_id)) {
|
|
19
|
+
this.error('Invalid flow ID format.', { exit: 2 });
|
|
20
|
+
}
|
|
21
|
+
const body = { name: flags.name };
|
|
22
|
+
const client = await createAuthenticatedClient(this.config);
|
|
23
|
+
const result = await client.put(`/apps/${flags.app}/flows/${args.flow_id}/`, body);
|
|
24
|
+
this.log('Flow updated!');
|
|
25
|
+
printResponse(result, this.log.bind(this));
|
|
26
|
+
return result;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -2,17 +2,22 @@ import { Command, Flags } from '@oclif/core';
|
|
|
2
2
|
import { createAuthenticatedClient } from '../../lib/client-from-config.js';
|
|
3
3
|
import { appFlag } from '../../lib/flags.js';
|
|
4
4
|
import { printResponse } from '../../lib/output.js';
|
|
5
|
+
import { audienceEntryProblem } from '../../lib/placement-audiences.js';
|
|
5
6
|
export default class PlacementsCreate extends Command {
|
|
6
7
|
static description = 'Create a placement with a paywall';
|
|
7
8
|
static enableJsonFlag = true;
|
|
8
9
|
static examples = [
|
|
9
|
-
'<%= config.bin %> placements create --app UUID --title "Default" --developer-id default --audiences \'[{"segment_ids":[],"paywall_id":"PAYWALL_UUID","priority":0}]\'',
|
|
10
|
+
'<%= config.bin %> placements create --app UUID --title "Default" --developer-id default --audiences \'[{"content_type":"paywall","segment_ids":[],"paywall_id":"PAYWALL_UUID","priority":0}]\'',
|
|
11
|
+
'<%= config.bin %> placements create --app UUID --title "Default" --developer-id default --audiences \'[{"content_type":"flow","segment_ids":[],"flow_id":"FLOW_UUID","priority":0}]\'',
|
|
10
12
|
'<%= config.bin %> placements create --app UUID --title "Default" --developer-id default --paywall-id PAYWALL_UUID',
|
|
11
13
|
];
|
|
12
14
|
static flags = {
|
|
13
15
|
...appFlag,
|
|
14
16
|
audiences: Flags.string({
|
|
15
|
-
description: 'JSON array of audience entries
|
|
17
|
+
description: 'JSON array of audience entries. Every entry needs an explicit content_type. ' +
|
|
18
|
+
'Paywall: {content_type:"paywall", segment_ids, paywall_id, priority}. ' +
|
|
19
|
+
'Flow: {content_type:"flow", segment_ids, flow_id, priority}. ' +
|
|
20
|
+
'A flow must be published first (flows publish) — attaching a draft flow returns 400.',
|
|
16
21
|
exactlyOne: ['paywall-id', 'audiences'],
|
|
17
22
|
}),
|
|
18
23
|
'developer-id': Flags.string({ description: 'Developer ID for the placement', required: true }),
|
|
@@ -36,12 +41,22 @@ export default class PlacementsCreate extends Command {
|
|
|
36
41
|
body.paywall_id = flags['paywall-id'];
|
|
37
42
|
}
|
|
38
43
|
else {
|
|
44
|
+
let parsed;
|
|
39
45
|
try {
|
|
40
|
-
|
|
46
|
+
parsed = JSON.parse(flags.audiences);
|
|
41
47
|
}
|
|
42
48
|
catch (error) {
|
|
43
49
|
this.error(`Invalid --audiences JSON: ${error instanceof Error ? error.message : String(error)}`, { exit: 2 });
|
|
44
50
|
}
|
|
51
|
+
if (!Array.isArray(parsed)) {
|
|
52
|
+
this.error('--audiences must be a JSON array of audience entries.', { exit: 2 });
|
|
53
|
+
}
|
|
54
|
+
for (const [index, entry] of parsed.entries()) {
|
|
55
|
+
const problem = audienceEntryProblem(entry);
|
|
56
|
+
if (problem)
|
|
57
|
+
this.error(`--audiences[${index}]: ${problem}`, { exit: 2 });
|
|
58
|
+
}
|
|
59
|
+
body.audiences = parsed;
|
|
45
60
|
}
|
|
46
61
|
const client = await createAuthenticatedClient(this.config);
|
|
47
62
|
const result = await client.post(`/apps/${flags.app}/placements`, body);
|
|
@@ -2,6 +2,7 @@ import { Args, Command, Flags } from '@oclif/core';
|
|
|
2
2
|
import { createAuthenticatedClient } from '../../lib/client-from-config.js';
|
|
3
3
|
import { appFlag, isValidUuid } from '../../lib/flags.js';
|
|
4
4
|
import { printResponse } from '../../lib/output.js';
|
|
5
|
+
import { audienceEntryProblem } from '../../lib/placement-audiences.js';
|
|
5
6
|
export default class PlacementsUpdate extends Command {
|
|
6
7
|
static args = {
|
|
7
8
|
placement_id: Args.string({ description: 'Placement ID (UUID)', required: true }),
|
|
@@ -9,13 +10,17 @@ export default class PlacementsUpdate extends Command {
|
|
|
9
10
|
static description = 'Update a placement';
|
|
10
11
|
static enableJsonFlag = true;
|
|
11
12
|
static examples = [
|
|
12
|
-
'<%= config.bin %> placements update --app UUID 550e8400-... --title "Default" --developer-id default --audiences \'[{"segment_ids":[],"paywall_id":"PAYWALL_UUID","priority":0}]\'',
|
|
13
|
+
'<%= config.bin %> placements update --app UUID 550e8400-... --title "Default" --developer-id default --audiences \'[{"content_type":"paywall","segment_ids":[],"paywall_id":"PAYWALL_UUID","priority":0}]\'',
|
|
14
|
+
'<%= config.bin %> placements update --app UUID 550e8400-... --title "Default" --developer-id default --audiences \'[{"content_type":"flow","segment_ids":[],"flow_id":"FLOW_UUID","priority":0}]\'',
|
|
13
15
|
'<%= config.bin %> placements update --app UUID 550e8400-... --title "Default" --developer-id default --paywall-id PAYWALL_UUID',
|
|
14
16
|
];
|
|
15
17
|
static flags = {
|
|
16
18
|
...appFlag,
|
|
17
19
|
audiences: Flags.string({
|
|
18
|
-
description: 'JSON array of audience entries
|
|
20
|
+
description: 'JSON array of audience entries. Every entry needs an explicit content_type. ' +
|
|
21
|
+
'Paywall: {content_type:"paywall", segment_ids, paywall_id, priority}. ' +
|
|
22
|
+
'Flow: {content_type:"flow", segment_ids, flow_id, priority}. ' +
|
|
23
|
+
'A flow must be published first (flows publish) — attaching a draft flow returns 400.',
|
|
19
24
|
exactlyOne: ['paywall-id', 'audiences'],
|
|
20
25
|
}),
|
|
21
26
|
'developer-id': Flags.string({ description: 'Developer ID for the placement', required: true }),
|
|
@@ -45,12 +50,22 @@ export default class PlacementsUpdate extends Command {
|
|
|
45
50
|
body.paywall_id = flags['paywall-id'];
|
|
46
51
|
}
|
|
47
52
|
else {
|
|
53
|
+
let parsed;
|
|
48
54
|
try {
|
|
49
|
-
|
|
55
|
+
parsed = JSON.parse(flags.audiences);
|
|
50
56
|
}
|
|
51
57
|
catch (error) {
|
|
52
58
|
this.error(`Invalid --audiences JSON: ${error instanceof Error ? error.message : String(error)}`, { exit: 2 });
|
|
53
59
|
}
|
|
60
|
+
if (!Array.isArray(parsed)) {
|
|
61
|
+
this.error('--audiences must be a JSON array of audience entries.', { exit: 2 });
|
|
62
|
+
}
|
|
63
|
+
for (const [index, entry] of parsed.entries()) {
|
|
64
|
+
const problem = audienceEntryProblem(entry);
|
|
65
|
+
if (problem)
|
|
66
|
+
this.error(`--audiences[${index}]: ${problem}`, { exit: 2 });
|
|
67
|
+
}
|
|
68
|
+
body.audiences = parsed;
|
|
54
69
|
}
|
|
55
70
|
const client = await createAuthenticatedClient(this.config);
|
|
56
71
|
const result = await client.put(`/apps/${flags.app}/placements/${args.placement_id}`, body);
|
|
@@ -129,11 +129,20 @@ export interface SegmentDTO {
|
|
|
129
129
|
id: string;
|
|
130
130
|
title: string;
|
|
131
131
|
}
|
|
132
|
-
export interface
|
|
132
|
+
export interface PlacementPaywallAudienceEntryDTO {
|
|
133
|
+
content_type: 'paywall';
|
|
133
134
|
paywall_id: string;
|
|
134
135
|
priority: number;
|
|
135
136
|
segment_ids?: string[];
|
|
136
137
|
}
|
|
138
|
+
export interface PlacementFlowAudienceEntryDTO {
|
|
139
|
+
content_type: 'flow';
|
|
140
|
+
/** The flow must be `published` (not draft) — the backend returns 400 otherwise. */
|
|
141
|
+
flow_id: string;
|
|
142
|
+
priority: number;
|
|
143
|
+
segment_ids?: string[];
|
|
144
|
+
}
|
|
145
|
+
export type PlacementAudienceEntryDTO = PlacementFlowAudienceEntryDTO | PlacementPaywallAudienceEntryDTO;
|
|
137
146
|
export interface PlacementSummaryDTO {
|
|
138
147
|
developer_id: string;
|
|
139
148
|
id: string;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Returns a human-readable problem string when `entry` is not a valid placement
|
|
3
|
+
* audience entry, or `null` when it is well-formed. Every entry must carry an
|
|
4
|
+
* explicit `content_type` ('paywall' | 'flow'); there is no implicit paywall.
|
|
5
|
+
*/
|
|
6
|
+
export declare function audienceEntryProblem(entry: unknown): null | string;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// Runtime guard for --audiences entries parsed from user/agent-supplied JSON.
|
|
2
|
+
// The DTO union in api-schemas.ts requires content_type, but a JSON.parse gives
|
|
3
|
+
// back `unknown`, so the type alone cannot enforce it — this does, the same way
|
|
4
|
+
// for humans and agents (no prompting).
|
|
5
|
+
/**
|
|
6
|
+
* Returns a human-readable problem string when `entry` is not a valid placement
|
|
7
|
+
* audience entry, or `null` when it is well-formed. Every entry must carry an
|
|
8
|
+
* explicit `content_type` ('paywall' | 'flow'); there is no implicit paywall.
|
|
9
|
+
*/
|
|
10
|
+
export function audienceEntryProblem(entry) {
|
|
11
|
+
if (typeof entry !== 'object' || entry === null) {
|
|
12
|
+
return 'each entry must be a JSON object';
|
|
13
|
+
}
|
|
14
|
+
const { content_type: contentType, flow_id: flowId, paywall_id: paywallId } = entry;
|
|
15
|
+
if (contentType !== 'flow' && contentType !== 'paywall') {
|
|
16
|
+
return 'content_type is required and must be "paywall" or "flow"';
|
|
17
|
+
}
|
|
18
|
+
if (contentType === 'paywall' && typeof paywallId !== 'string') {
|
|
19
|
+
return 'a paywall entry requires paywall_id';
|
|
20
|
+
}
|
|
21
|
+
if (contentType === 'flow' && typeof flowId !== 'string') {
|
|
22
|
+
return 'a flow entry requires flow_id';
|
|
23
|
+
}
|
|
24
|
+
return null;
|
|
25
|
+
}
|