adapty 0.8.8 → 0.9.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/README.md +147 -2
- package/dist/cli/base/adapty/adapty-command.d.ts +3 -2
- package/dist/cli/base/adapty/adapty-command.js +8 -5
- package/dist/cli/base/adapty/build.d.ts +6 -1
- package/dist/cli/base/adapty/build.js +1 -0
- package/dist/cli/base/adapty/index.d.ts +1 -0
- package/dist/cli/base/adapty/index.js +1 -0
- package/dist/cli/base/adapty/migration-command.d.ts +11 -0
- package/dist/cli/base/adapty/migration-command.js +17 -0
- package/dist/cli/base/base-command.d.ts +6 -0
- package/dist/cli/base/base-command.js +14 -0
- package/dist/cli/commands/apps/create.d.ts +1 -1
- package/dist/cli/commands/apps/get.js +1 -1
- package/dist/cli/commands/apps/list.js +1 -1
- package/dist/cli/commands/apps/update.js +1 -1
- package/dist/cli/commands/attribution/report/command.d.ts +18 -0
- package/dist/cli/commands/attribution/report/command.js +93 -0
- package/dist/cli/commands/attribution/report/index.d.ts +1 -18
- package/dist/cli/commands/attribution/report/index.js +1 -93
- package/dist/cli/commands/attribution/values.js +1 -1
- package/dist/cli/commands/auth/login.js +1 -0
- package/dist/cli/commands/auth/{logout.d.ts → logout/command.d.ts} +1 -1
- package/dist/cli/commands/auth/logout/command.js +33 -0
- package/dist/cli/commands/auth/logout/index.d.ts +1 -0
- package/dist/cli/commands/auth/logout/index.js +1 -0
- package/dist/cli/commands/auth/logout/lib/cleanup.d.ts +3 -0
- package/dist/cli/commands/auth/logout/lib/cleanup.js +21 -0
- package/dist/cli/commands/auth/{revoke.d.ts → revoke/command.d.ts} +1 -1
- package/dist/cli/commands/auth/{revoke.js → revoke/command.js} +7 -7
- package/dist/cli/commands/auth/revoke/index.d.ts +1 -0
- package/dist/cli/commands/auth/revoke/index.js +1 -0
- package/dist/cli/commands/auth/revoke/lib/cleanup.d.ts +4 -0
- package/dist/cli/commands/auth/revoke/lib/cleanup.js +29 -0
- package/dist/cli/commands/auth/status/command.d.ts +7 -0
- package/dist/cli/commands/auth/status/command.js +22 -0
- package/dist/cli/commands/auth/status/index.d.ts +1 -7
- package/dist/cli/commands/auth/status/index.js +1 -22
- package/dist/cli/commands/migrations/close/command.d.ts +16 -0
- package/dist/cli/commands/migrations/close/command.js +58 -0
- package/dist/cli/commands/migrations/close/index.d.ts +1 -0
- package/dist/cli/commands/migrations/close/index.js +1 -0
- package/dist/cli/commands/migrations/create/command.d.ts +20 -0
- package/dist/cli/commands/migrations/create/command.js +86 -0
- package/dist/cli/commands/migrations/create/index.d.ts +1 -0
- package/dist/cli/commands/migrations/create/index.js +1 -0
- package/dist/cli/commands/migrations/current/command.d.ts +12 -0
- package/dist/cli/commands/migrations/current/command.js +25 -0
- package/dist/cli/commands/migrations/current/index.d.ts +1 -0
- package/dist/cli/commands/migrations/current/index.js +1 -0
- package/dist/cli/commands/migrations/list/command.d.ts +11 -0
- package/dist/cli/commands/migrations/list/command.js +27 -0
- package/dist/cli/commands/migrations/list/index.d.ts +1 -0
- package/dist/cli/commands/migrations/list/index.js +1 -0
- package/dist/cli/commands/migrations/list/lib/render.d.ts +3 -0
- package/dist/cli/commands/migrations/list/lib/render.js +77 -0
- package/dist/cli/commands/migrations/run/command.d.ts +25 -0
- package/dist/cli/commands/migrations/run/command.js +141 -0
- package/dist/cli/commands/migrations/run/index.d.ts +1 -0
- package/dist/cli/commands/migrations/run/index.js +1 -0
- package/dist/cli/commands/migrations/run/lib/action-view.d.ts +7 -0
- package/dist/cli/commands/migrations/run/lib/action-view.js +2 -0
- package/dist/cli/commands/migrations/run/lib/actions.d.ts +4 -0
- package/dist/cli/commands/migrations/run/lib/actions.js +20 -0
- package/dist/cli/commands/migrations/run/lib/https.d.ts +1 -0
- package/dist/cli/commands/migrations/run/lib/https.js +8 -0
- package/dist/cli/commands/migrations/run/lib/input.d.ts +10 -0
- package/dist/cli/commands/migrations/run/lib/input.js +51 -0
- package/dist/cli/commands/migrations/run/lib/open-link.d.ts +7 -0
- package/dist/cli/commands/migrations/run/lib/open-link.js +11 -0
- package/dist/cli/commands/migrations/show/command.d.ts +17 -0
- package/dist/cli/commands/migrations/show/command.js +47 -0
- package/dist/cli/commands/migrations/show/index.d.ts +1 -0
- package/dist/cli/commands/migrations/show/index.js +1 -0
- package/dist/cli/commands/migrations/show/lib/render.d.ts +4 -0
- package/dist/cli/commands/migrations/show/lib/render.js +27 -0
- package/dist/cli/commands/migrations/status/command.d.ts +18 -0
- package/dist/cli/commands/migrations/status/command.js +54 -0
- package/dist/cli/commands/migrations/status/index.d.ts +1 -0
- package/dist/cli/commands/migrations/status/index.js +1 -0
- package/dist/cli/commands/migrations/status/lib/flags.d.ts +8 -0
- package/dist/cli/commands/migrations/status/lib/flags.js +29 -0
- package/dist/cli/commands/migrations/status/lib/notice.d.ts +3 -0
- package/dist/cli/commands/migrations/status/lib/notice.js +10 -0
- package/dist/cli/commands/migrations/steps/command.d.ts +14 -0
- package/dist/cli/commands/migrations/steps/command.js +34 -0
- package/dist/cli/commands/migrations/steps/index.d.ts +1 -0
- package/dist/cli/commands/migrations/steps/index.js +1 -0
- package/dist/cli/commands/migrations/steps/lib/render.d.ts +3 -0
- package/dist/cli/commands/migrations/steps/lib/render.js +28 -0
- package/dist/cli/commands/migrations/unuse/command.d.ts +11 -0
- package/dist/cli/commands/migrations/unuse/command.js +23 -0
- package/dist/cli/commands/migrations/unuse/index.d.ts +1 -0
- package/dist/cli/commands/migrations/unuse/index.js +1 -0
- package/dist/cli/commands/migrations/use/command.d.ts +14 -0
- package/dist/cli/commands/migrations/use/command.js +24 -0
- package/dist/cli/commands/migrations/use/index.d.ts +1 -0
- package/dist/cli/commands/migrations/use/index.js +1 -0
- package/dist/cli/context/migration/current.d.ts +32 -0
- package/dist/cli/context/migration/current.js +30 -0
- package/dist/cli/context/migration/index.d.ts +4 -0
- package/dist/cli/context/migration/index.js +2 -0
- package/dist/cli/context/migration/model.d.ts +14 -0
- package/dist/cli/context/migration/model.js +30 -0
- package/dist/cli/context/migration/resolve.d.ts +16 -0
- package/dist/cli/context/migration/resolve.js +26 -0
- package/dist/cli/context/migration/store.d.ts +9 -0
- package/dist/cli/context/migration/store.js +99 -0
- package/dist/cli/errors/wizard.d.ts +5 -0
- package/dist/cli/errors/wizard.js +54 -0
- package/dist/cli/errors.d.ts +37 -4
- package/dist/cli/errors.js +58 -4
- package/dist/cli/input/app.d.ts +8 -0
- package/dist/cli/{flags.js → input/app.js} +2 -9
- package/dist/cli/input/migration.d.ts +7 -0
- package/dist/cli/input/migration.js +17 -0
- package/dist/cli/input/pagination.d.ts +11 -0
- package/dist/cli/input/pagination.js +8 -0
- package/dist/cli/views/migrations/envelope/action-block.d.ts +2 -0
- package/dist/cli/views/migrations/envelope/action-block.js +32 -0
- package/dist/cli/views/migrations/envelope/envelope.d.ts +3 -0
- package/dist/cli/views/migrations/envelope/envelope.js +40 -0
- package/dist/cli/views/migrations/envelope/issue-block.d.ts +2 -0
- package/dist/cli/views/migrations/envelope/issue-block.js +13 -0
- package/dist/cli/views/migrations/notices.d.ts +7 -0
- package/dist/cli/views/migrations/notices.js +7 -0
- package/dist/commands/access-levels/create.js +1 -1
- package/dist/commands/access-levels/get.js +1 -1
- package/dist/commands/access-levels/list.js +1 -1
- package/dist/commands/access-levels/update.js +1 -1
- package/dist/commands/asa/campaigns/create.d.ts +0 -1
- package/dist/commands/asa/campaigns/create.js +0 -2
- package/dist/commands/asa/campaigns/update.d.ts +0 -1
- package/dist/commands/asa/campaigns/update.js +1 -5
- package/dist/commands/auth/logout.d.ts +1 -1
- package/dist/commands/auth/logout.js +1 -1
- package/dist/commands/auth/revoke.d.ts +1 -1
- package/dist/commands/auth/revoke.js +1 -1
- package/dist/commands/flows/config/get.js +1 -1
- package/dist/commands/flows/config/update.js +1 -1
- package/dist/commands/flows/config/validate.js +1 -1
- package/dist/commands/flows/create.js +1 -1
- package/dist/commands/flows/get.js +1 -1
- package/dist/commands/flows/list.js +1 -1
- package/dist/commands/flows/media/upload.js +1 -1
- package/dist/commands/flows/publish.js +1 -1
- package/dist/commands/flows/update.js +1 -1
- package/dist/commands/migrations/close.d.ts +1 -0
- package/dist/commands/migrations/close.js +2 -0
- package/dist/commands/migrations/create.d.ts +1 -0
- package/dist/commands/migrations/create.js +2 -0
- package/dist/commands/migrations/current.d.ts +1 -0
- package/dist/commands/migrations/current.js +1 -0
- package/dist/commands/migrations/list.d.ts +1 -0
- package/dist/commands/migrations/list.js +2 -0
- package/dist/commands/migrations/run.d.ts +1 -0
- package/dist/commands/migrations/run.js +2 -0
- package/dist/commands/migrations/show.d.ts +1 -0
- package/dist/commands/migrations/show.js +2 -0
- package/dist/commands/migrations/status.d.ts +1 -0
- package/dist/commands/migrations/status.js +2 -0
- package/dist/commands/migrations/steps.d.ts +1 -0
- package/dist/commands/migrations/steps.js +2 -0
- package/dist/commands/migrations/unuse.d.ts +1 -0
- package/dist/commands/migrations/unuse.js +1 -0
- package/dist/commands/migrations/use.d.ts +1 -0
- package/dist/commands/migrations/use.js +1 -0
- package/dist/commands/paywalls/create.js +1 -1
- package/dist/commands/paywalls/get.js +1 -1
- package/dist/commands/paywalls/list.js +1 -1
- package/dist/commands/paywalls/placements.js +1 -1
- package/dist/commands/paywalls/update.js +1 -1
- package/dist/commands/placements/create.js +1 -1
- package/dist/commands/placements/get.js +1 -1
- package/dist/commands/placements/list.js +1 -1
- package/dist/commands/placements/update.js +1 -1
- package/dist/commands/products/create.js +1 -1
- package/dist/commands/products/get.js +1 -1
- package/dist/commands/products/list.js +1 -1
- package/dist/commands/products/update.js +1 -1
- package/dist/commands/segments/get.js +1 -1
- package/dist/commands/segments/list.js +1 -1
- package/dist/lib/asa-flags.js +1 -3
- package/dist/sdk/adapty/errors.d.ts +4 -0
- package/dist/sdk/adapty/errors.js +25 -0
- package/dist/sdk/adapty/index.d.ts +5 -0
- package/dist/sdk/adapty/index.js +29 -3
- package/dist/sdk/adapty/migrations/action.d.ts +15 -0
- package/dist/sdk/adapty/migrations/action.js +17 -0
- package/dist/sdk/adapty/migrations/close.d.ts +16 -0
- package/dist/sdk/adapty/migrations/close.js +7 -0
- package/dist/sdk/adapty/migrations/create.d.ts +16 -0
- package/dist/sdk/adapty/migrations/create.js +43 -0
- package/dist/sdk/adapty/migrations/index.d.ts +9 -0
- package/dist/sdk/adapty/migrations/index.js +4 -0
- package/dist/sdk/adapty/migrations/model.d.ts +100 -0
- package/dist/sdk/adapty/migrations/model.js +1 -0
- package/dist/sdk/adapty/migrations/resource.d.ts +27 -0
- package/dist/sdk/adapty/migrations/resource.js +52 -0
- package/dist/sdk/adapty/migrations/wait.d.ts +6 -0
- package/dist/sdk/adapty/migrations/wait.js +9 -0
- package/oclif.manifest.json +2119 -1528
- package/package.json +4 -1
- package/dist/cli/commands/auth/logout.js +0 -28
- package/dist/cli/flags.d.ts +0 -20
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { Args, Flags } from '@oclif/core';
|
|
2
|
+
import { MigrationCommand } from '../../../base/adapty/index.js';
|
|
3
|
+
import { CliError, exitCode } from '../../../errors.js';
|
|
4
|
+
import { migrationFlags } from '../../../input/migration.js';
|
|
5
|
+
import { renderEnvelope } from '../../../views/migrations/envelope/envelope.js';
|
|
6
|
+
import { actionView } from './lib/action-view.js';
|
|
7
|
+
import { findAction, unknownActionMessage, unsupportedActionMessage } from './lib/actions.js';
|
|
8
|
+
import { readActionInput } from './lib/input.js';
|
|
9
|
+
import { openLink } from './lib/open-link.js';
|
|
10
|
+
export default class Run extends MigrationCommand {
|
|
11
|
+
static summary = 'Run an input action or open an external action link';
|
|
12
|
+
static description = [
|
|
13
|
+
'Choose an action ID from next_actions or available_actions in `adapty migrations status -m ID --json`.',
|
|
14
|
+
'Replace ACTION_ID in the examples with an offered action ID.',
|
|
15
|
+
'For input actions, read the resources in reads and prepare a JSON object matching input_schema.',
|
|
16
|
+
'Omitting input sends {}. Review confirm before passing --yes.',
|
|
17
|
+
'Without --yes, actions requiring confirmation exit with code 6. No confirmation prompt is shown.',
|
|
18
|
+
'',
|
|
19
|
+
'External actions print a link and open it in an interactive terminal. Complete the browser step, then check status.',
|
|
20
|
+
'External actions reject --input and --input-file, including stdin.',
|
|
21
|
+
'Pipes and --json require --open to launch a browser; BROWSER=none disables it.',
|
|
22
|
+
'File uploads are not supported; use the dashboard or an offered Cloud Export action.',
|
|
23
|
+
'',
|
|
24
|
+
'With --json, returns the full migration response (before the browser step for external actions).',
|
|
25
|
+
'After a revision_conflict error, read status and review the action before retrying.',
|
|
26
|
+
].join('\n');
|
|
27
|
+
static examples = [
|
|
28
|
+
{
|
|
29
|
+
description: 'Run an offered action on the saved migration after reviewing confirm:',
|
|
30
|
+
command: '<%= config.bin %> migrations run ACTION_ID --yes',
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
description: 'Read current action IDs and input schemas first:',
|
|
34
|
+
command: '<%= config.bin %> migrations status -m mig_7x2 --json',
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
description: 'Submit an empty JSON object, if the action input_schema allows it:',
|
|
38
|
+
command: '<%= config.bin %> migrations run ACTION_ID -m mig_7x2 --input \'{}\'',
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
description: 'Submit a file matching input_schema, after reviewing confirm:',
|
|
42
|
+
command: '<%= config.bin %> migrations run ACTION_ID -m mig_7x2 --input-file ./decisions.json --yes --json',
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
description: 'Read the same prepared input from stdin:',
|
|
46
|
+
command: '<%= config.bin %> migrations run ACTION_ID -m mig_7x2 --input-file - --yes --json < ./decisions.json',
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
description: 'Get an external action link without opening a browser:',
|
|
50
|
+
command: '<%= config.bin %> migrations run ACTION_ID -m mig_7x2 --no-browser',
|
|
51
|
+
},
|
|
52
|
+
];
|
|
53
|
+
static args = {
|
|
54
|
+
action_id: Args.string({
|
|
55
|
+
description: 'Offered action ID from `adapty migrations status`',
|
|
56
|
+
required: true,
|
|
57
|
+
}),
|
|
58
|
+
};
|
|
59
|
+
static flags = {
|
|
60
|
+
...migrationFlags,
|
|
61
|
+
'input': Flags.string({
|
|
62
|
+
description: 'Input action data as a JSON object matching input_schema',
|
|
63
|
+
exclusive: ['input-file'],
|
|
64
|
+
helpValue: 'JSON',
|
|
65
|
+
}),
|
|
66
|
+
'input-file': Flags.string({
|
|
67
|
+
description: 'Read an input action\'s JSON object from a file; use - for stdin',
|
|
68
|
+
exclusive: ['input'],
|
|
69
|
+
helpValue: 'PATH',
|
|
70
|
+
}),
|
|
71
|
+
'yes': Flags.boolean({
|
|
72
|
+
char: 'y',
|
|
73
|
+
default: false,
|
|
74
|
+
description: 'Confirm the input action after reviewing its confirmation text',
|
|
75
|
+
}),
|
|
76
|
+
'open': Flags.boolean({
|
|
77
|
+
default: false,
|
|
78
|
+
description: 'Open an external action\'s HTTPS link, including with pipes or --json',
|
|
79
|
+
exclusive: ['no-browser'],
|
|
80
|
+
}),
|
|
81
|
+
'no-browser': Flags.boolean({
|
|
82
|
+
default: false,
|
|
83
|
+
description: 'Show the external action without opening a browser',
|
|
84
|
+
exclusive: ['open'],
|
|
85
|
+
}),
|
|
86
|
+
};
|
|
87
|
+
async run() {
|
|
88
|
+
const context = await this.prepare();
|
|
89
|
+
if (context.href !== undefined) {
|
|
90
|
+
return this.runExternalAction(context, context.href);
|
|
91
|
+
}
|
|
92
|
+
return this.runInputAction(context);
|
|
93
|
+
}
|
|
94
|
+
async prepare() {
|
|
95
|
+
const { args, flags } = await this.parse(Run);
|
|
96
|
+
// Inline input and files are read before the request; stdin waits for the action kind.
|
|
97
|
+
const fromStdin = flags['input-file'] === '-';
|
|
98
|
+
const input = fromStdin ? undefined : await readActionInput(flags);
|
|
99
|
+
const selection = await this.currentMigration.require(flags.migration);
|
|
100
|
+
const envelope = await this.adapty.migrations.get(selection.currentMigrationId);
|
|
101
|
+
const action = findAction(envelope, args.action_id);
|
|
102
|
+
if (action === undefined) {
|
|
103
|
+
throw new CliError(unknownActionMessage(envelope, args.action_id), exitCode.usage, 'action_not_found');
|
|
104
|
+
}
|
|
105
|
+
const href = 'href' in action ? action.href : undefined;
|
|
106
|
+
if (href !== undefined && (flags.input !== undefined || flags['input-file'] !== undefined)) {
|
|
107
|
+
throw new CliError(`Action \`${action.action_id}\` hands over a link and does not accept --input or --input-file. Remove the input option and complete the step in the browser.`, exitCode.usage, 'action_input_unsupported');
|
|
108
|
+
}
|
|
109
|
+
return {
|
|
110
|
+
action, envelope, flags, href, selection,
|
|
111
|
+
input: fromStdin && action.kind === 'input' ? await readActionInput(flags) : input,
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
async runExternalAction(context, href) {
|
|
115
|
+
this.render({ action: context.action, migrationId: context.envelope.migration.id }, actionView);
|
|
116
|
+
await openLink(href, context.flags, this.interactive);
|
|
117
|
+
return context.envelope;
|
|
118
|
+
}
|
|
119
|
+
async runInputAction({ action, envelope, flags, input, selection }) {
|
|
120
|
+
if (action.kind !== 'input' && action.kind !== 'upload' && action.kind !== 'external') {
|
|
121
|
+
this.render({ action, migrationId: envelope.migration.id }, actionView);
|
|
122
|
+
return envelope;
|
|
123
|
+
}
|
|
124
|
+
if (action.kind !== 'input') {
|
|
125
|
+
throw new CliError(unsupportedActionMessage(action), exitCode.usage, 'action_unsupported');
|
|
126
|
+
}
|
|
127
|
+
if (action.confirm !== null && !flags.yes) {
|
|
128
|
+
const message = `${action.confirm}\n\nRe-run with --yes to do it.`;
|
|
129
|
+
throw new CliError(message, exitCode.confirmRequired, 'confirm_required');
|
|
130
|
+
}
|
|
131
|
+
if (selection.source === 'context') {
|
|
132
|
+
process.stderr.write(`Using saved migration: ${selection.currentMigrationId}\n`);
|
|
133
|
+
}
|
|
134
|
+
const result = await this.adapty.migrations.runAction(selection.currentMigrationId, action.action_id, {
|
|
135
|
+
expectedRevision: envelope.migration.revision,
|
|
136
|
+
input,
|
|
137
|
+
});
|
|
138
|
+
this.render(result, renderEnvelope);
|
|
139
|
+
return result;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from './command.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from './command.js';
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { Action, Envelope } from '../../../../../sdk/adapty/index.js';
|
|
2
|
+
export declare const findAction: (envelope: Envelope, actionId: string) => Action | undefined;
|
|
3
|
+
export declare const unknownActionMessage: (envelope: Envelope, actionId: string) => string;
|
|
4
|
+
export declare const unsupportedActionMessage: (action: Action) => string;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
const offered = (envelope) => [...envelope.next_actions, ...envelope.available_actions];
|
|
2
|
+
export const findAction = (envelope, actionId) => {
|
|
3
|
+
return offered(envelope).find(action => action.action_id === actionId);
|
|
4
|
+
};
|
|
5
|
+
const line = (action) => ` ${action.action_id} (${action.kind}) ${action.title}`;
|
|
6
|
+
export const unknownActionMessage = (envelope, actionId) => {
|
|
7
|
+
const actions = offered(envelope);
|
|
8
|
+
if (actions.length === 0) {
|
|
9
|
+
const { state, summary } = envelope.migration;
|
|
10
|
+
return `No action \`${actionId}\` here: this migration offers none right now (state: ${state}).\n${summary}`;
|
|
11
|
+
}
|
|
12
|
+
return [`No action \`${actionId}\` here. Available now:`, ...actions.map(line)].join('\n');
|
|
13
|
+
};
|
|
14
|
+
export const unsupportedActionMessage = (action) => {
|
|
15
|
+
const detail = action.detail === null ? '' : `\n${action.detail}`;
|
|
16
|
+
if (action.kind === 'upload') {
|
|
17
|
+
return `\`${action.action_id}\` (${action.title}) uploads a file, which this adapty-cli cannot do yet.${detail}\nUse the dashboard or an offered Cloud Export action.`;
|
|
18
|
+
}
|
|
19
|
+
return `\`${action.action_id}\` (${action.title}) is a "${action.kind}" action: it needs a newer adapty-cli.${detail}`;
|
|
20
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const isHttps: (href: string) => boolean;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
type InputFlags = {
|
|
2
|
+
'input'?: string | undefined;
|
|
3
|
+
'input-file'?: string | undefined;
|
|
4
|
+
};
|
|
5
|
+
/**
|
|
6
|
+
* Read inline JSON, a file, or stdin, and answer with an input the action request accepts.
|
|
7
|
+
* The caller checks the action kind before waiting on stdin.
|
|
8
|
+
*/
|
|
9
|
+
export declare const readActionInput: (flags: InputFlags) => Promise<unknown>;
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
import { validateActionInput } from '../../../../../sdk/adapty/migrations/index.js';
|
|
3
|
+
import { ValidationError } from '../../../../../sdk/core/errors.js';
|
|
4
|
+
import { assertValid } from '../../../../../sdk/core/validation.js';
|
|
5
|
+
/** CLI error formatting maps inputFile to --input-file. */
|
|
6
|
+
const invalid = (path, message) => {
|
|
7
|
+
throw new ValidationError([{ message, path }]);
|
|
8
|
+
};
|
|
9
|
+
const reason = (error) => (error instanceof Error ? error.message : String(error));
|
|
10
|
+
const parseJson = (raw, path) => {
|
|
11
|
+
try {
|
|
12
|
+
return JSON.parse(raw);
|
|
13
|
+
}
|
|
14
|
+
catch (error) {
|
|
15
|
+
return invalid(path, `is not valid JSON: ${reason(error)}`);
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
const readFile = (path) => {
|
|
19
|
+
try {
|
|
20
|
+
return readFileSync(path, 'utf8');
|
|
21
|
+
}
|
|
22
|
+
catch (error) {
|
|
23
|
+
return invalid('inputFile', `cannot be read: ${reason(error)}`);
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
const readStdin = async () => {
|
|
27
|
+
const chunks = [];
|
|
28
|
+
for await (const chunk of process.stdin) {
|
|
29
|
+
chunks.push(chunk);
|
|
30
|
+
}
|
|
31
|
+
return Buffer.concat(chunks).toString('utf8');
|
|
32
|
+
};
|
|
33
|
+
const parseActionInput = async (flags) => {
|
|
34
|
+
if (flags.input !== undefined) {
|
|
35
|
+
return parseJson(flags.input, 'input');
|
|
36
|
+
}
|
|
37
|
+
const path = flags['input-file'];
|
|
38
|
+
if (path === undefined) {
|
|
39
|
+
return undefined;
|
|
40
|
+
}
|
|
41
|
+
return parseJson(path === '-' ? await readStdin() : readFile(path), 'inputFile');
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* Read inline JSON, a file, or stdin, and answer with an input the action request accepts.
|
|
45
|
+
* The caller checks the action kind before waiting on stdin.
|
|
46
|
+
*/
|
|
47
|
+
export const readActionInput = async (flags) => {
|
|
48
|
+
const input = await parseActionInput(flags);
|
|
49
|
+
assertValid(validateActionInput(input));
|
|
50
|
+
return input;
|
|
51
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import open from 'open';
|
|
2
|
+
import { isHttps } from './https.js';
|
|
3
|
+
/** Piped and JSON output require --open to launch a browser. */
|
|
4
|
+
export const openLink = async (href, flags, interactive) => {
|
|
5
|
+
const wanted = flags.open || interactive;
|
|
6
|
+
const allowed = !flags['no-browser'] && process.env.BROWSER !== 'none' && isHttps(href);
|
|
7
|
+
if (!wanted || !allowed) {
|
|
8
|
+
return;
|
|
9
|
+
}
|
|
10
|
+
await open(href).catch(() => undefined);
|
|
11
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { MigrationCommand } from '../../../base/adapty/index.js';
|
|
2
|
+
import type { Envelope } from '../../../../sdk/adapty/index.js';
|
|
3
|
+
export default class Show extends MigrationCommand {
|
|
4
|
+
static summary: string;
|
|
5
|
+
static description: string;
|
|
6
|
+
static examples: {
|
|
7
|
+
description: string;
|
|
8
|
+
command: string;
|
|
9
|
+
}[];
|
|
10
|
+
static args: {
|
|
11
|
+
resource: import("@oclif/core/interfaces").Arg<string | undefined, Record<string, unknown>>;
|
|
12
|
+
};
|
|
13
|
+
static flags: {
|
|
14
|
+
migration: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
15
|
+
};
|
|
16
|
+
run(): Promise<Envelope>;
|
|
17
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { Args } from '@oclif/core';
|
|
2
|
+
import { MigrationCommand } from '../../../base/adapty/index.js';
|
|
3
|
+
import { migrationFlags } from '../../../input/migration.js';
|
|
4
|
+
import { renderResources, renderResult } from './lib/render.js';
|
|
5
|
+
export default class Show extends MigrationCommand {
|
|
6
|
+
static summary = 'List migration resources or read one resource';
|
|
7
|
+
static description = [
|
|
8
|
+
'Omit RESOURCE to list what can be read now. Use a name from that list, such as apps or mapping.',
|
|
9
|
+
'',
|
|
10
|
+
'Reading a resource prints its data as JSON. With --json, returns the full migration response.',
|
|
11
|
+
'Resource data is in result (null if no data is available yet).',
|
|
12
|
+
].join('\n');
|
|
13
|
+
static examples = [
|
|
14
|
+
{
|
|
15
|
+
description: 'Read the RevenueCat apps of the selected migration:',
|
|
16
|
+
command: '<%= config.bin %> migrations show apps',
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
description: 'List resource names available now:',
|
|
20
|
+
command: '<%= config.bin %> migrations show -m mig_7x2',
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
description: 'Read mapping data, if listed as available:',
|
|
24
|
+
command: '<%= config.bin %> migrations show mapping -m mig_7x2',
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
description: 'Extract only the resource data (requires jq):',
|
|
28
|
+
command: '<%= config.bin %> migrations show mapping -m mig_7x2 --json | jq \'.result\'',
|
|
29
|
+
},
|
|
30
|
+
];
|
|
31
|
+
static args = {
|
|
32
|
+
resource: Args.string({
|
|
33
|
+
description: 'Resource name; omit to list what can be read now',
|
|
34
|
+
}),
|
|
35
|
+
};
|
|
36
|
+
static flags = { ...migrationFlags };
|
|
37
|
+
async run() {
|
|
38
|
+
const { args, flags } = await this.parse(Show);
|
|
39
|
+
const selection = await this.currentMigration.require(flags.migration);
|
|
40
|
+
const { resource } = args;
|
|
41
|
+
const envelope = resource === undefined
|
|
42
|
+
? await this.adapty.migrations.get(selection.currentMigrationId)
|
|
43
|
+
: await this.adapty.migrations.resource(selection.currentMigrationId, resource);
|
|
44
|
+
this.render(envelope, resource === undefined ? renderResources : renderResult);
|
|
45
|
+
return envelope;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from './command.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from './command.js';
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
const maxWidth = (values) => {
|
|
2
|
+
return values.reduce((max, value) => Math.max(max, value.length), 0);
|
|
3
|
+
};
|
|
4
|
+
const resourceLine = (resource, width) => {
|
|
5
|
+
return ` ${resource.name.padEnd(width)} ${resource.title}`;
|
|
6
|
+
};
|
|
7
|
+
export const renderResources = (envelope) => {
|
|
8
|
+
const { resources } = envelope;
|
|
9
|
+
const [first] = resources;
|
|
10
|
+
if (first === undefined) {
|
|
11
|
+
return `Nothing to read yet: ${envelope.migration.summary}`;
|
|
12
|
+
}
|
|
13
|
+
const width = maxWidth(resources.map(resource => resource.name));
|
|
14
|
+
return [
|
|
15
|
+
'Readable now:',
|
|
16
|
+
...resources.map(resource => resourceLine(resource, width)),
|
|
17
|
+
'',
|
|
18
|
+
`Read one: \`adapty migrations show ${first.name} -m ${envelope.migration.id}\``,
|
|
19
|
+
].join('\n');
|
|
20
|
+
};
|
|
21
|
+
/** Use JSON because resource shapes vary by flow. */
|
|
22
|
+
export const renderResult = (envelope) => {
|
|
23
|
+
if (envelope.result === null) {
|
|
24
|
+
return `No data in this resource yet: ${envelope.migration.summary}`;
|
|
25
|
+
}
|
|
26
|
+
return JSON.stringify(envelope.result, null, 2);
|
|
27
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { MigrationCommand } from '../../../base/adapty/index.js';
|
|
2
|
+
import type { Envelope } from '../../../../sdk/adapty/index.js';
|
|
3
|
+
export default class Status extends MigrationCommand {
|
|
4
|
+
static summary: string;
|
|
5
|
+
static description: string;
|
|
6
|
+
static examples: {
|
|
7
|
+
description: string;
|
|
8
|
+
command: string;
|
|
9
|
+
}[];
|
|
10
|
+
static flags: {
|
|
11
|
+
timeout: import("@oclif/core/interfaces").OptionFlag<number | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
12
|
+
wait: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
13
|
+
migration: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
14
|
+
};
|
|
15
|
+
run(): Promise<Envelope>;
|
|
16
|
+
/** Timeout returns the last response with exit 0; Ctrl+C cancels with exit 130. */
|
|
17
|
+
private waitForMigration;
|
|
18
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { MigrationCommand } from '../../../base/adapty/index.js';
|
|
2
|
+
import { migrationFlags } from '../../../input/migration.js';
|
|
3
|
+
import { renderEnvelope } from '../../../views/migrations/envelope/envelope.js';
|
|
4
|
+
import { waitFlags } from './lib/flags.js';
|
|
5
|
+
import { pollNotice } from './lib/notice.js';
|
|
6
|
+
export default class Status extends MigrationCommand {
|
|
7
|
+
static summary = 'Show migration state, issues, and available actions';
|
|
8
|
+
static description = [
|
|
9
|
+
'Read next_actions for the next steps and available_actions for optional actions.',
|
|
10
|
+
'Use --json to read each action\'s input_schema, reads, and confirmation text.',
|
|
11
|
+
'',
|
|
12
|
+
'--wait returns when the revision changes, the state leaves running, or the polling budget runs out.',
|
|
13
|
+
'Exit 0 means the request succeeded, even if the migration is still running or has failed.',
|
|
14
|
+
'Check migration.state in JSON output. Progress goes to stderr. Ctrl+C exits with code 130.',
|
|
15
|
+
].join('\n');
|
|
16
|
+
static examples = [
|
|
17
|
+
{
|
|
18
|
+
description: 'Inspect the saved migration:',
|
|
19
|
+
command: '<%= config.bin %> migrations status',
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
description: 'See the current state and what to do next:',
|
|
23
|
+
command: '<%= config.bin %> migrations status -m mig_7x2',
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
description: 'Read action IDs, input schemas, and confirmation text as JSON:',
|
|
27
|
+
command: '<%= config.bin %> migrations status -m mig_7x2 --json',
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
description: 'Wait for a change with a five-minute polling budget:',
|
|
31
|
+
command: '<%= config.bin %> migrations status -m mig_7x2 --wait --timeout 5m --json',
|
|
32
|
+
},
|
|
33
|
+
];
|
|
34
|
+
static flags = { ...migrationFlags, ...waitFlags };
|
|
35
|
+
async run() {
|
|
36
|
+
const { flags } = await this.parse(Status);
|
|
37
|
+
const selection = await this.currentMigration.require(flags.migration);
|
|
38
|
+
const envelope = flags.wait
|
|
39
|
+
? await this.waitForMigration(selection.currentMigrationId, flags.timeout)
|
|
40
|
+
: await this.adapty.migrations.get(selection.currentMigrationId);
|
|
41
|
+
this.render(envelope, renderEnvelope);
|
|
42
|
+
return envelope;
|
|
43
|
+
}
|
|
44
|
+
/** Timeout returns the last response with exit 0; Ctrl+C cancels with exit 130. */
|
|
45
|
+
async waitForMigration(id, timeoutMs) {
|
|
46
|
+
return this.adapty.migrations.waitFor(id, {
|
|
47
|
+
onPoll: (envelope, delayMs) => {
|
|
48
|
+
process.stderr.write(`${pollNotice(envelope, delayMs)}\n`);
|
|
49
|
+
},
|
|
50
|
+
signal: this.signal,
|
|
51
|
+
timeoutMs,
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from './command.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from './command.js';
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Keep defaults out of these flags so dependsOn can detect a missing --wait.
|
|
3
|
+
* The SDK supplies the default timeout.
|
|
4
|
+
*/
|
|
5
|
+
export declare const waitFlags: {
|
|
6
|
+
timeout: import("@oclif/core/interfaces").OptionFlag<number | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
7
|
+
wait: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
8
|
+
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { Errors, Flags } from '@oclif/core';
|
|
2
|
+
import { exitCode } from '../../../../errors.js';
|
|
3
|
+
const DURATION_PATTERN = /^(\d+)(m|s)?$/;
|
|
4
|
+
const MAX_WAIT_SECONDS = 600;
|
|
5
|
+
const durationHint = `Use seconds or minutes, e.g. 300s or 5m, up to ${MAX_WAIT_SECONDS}s.`;
|
|
6
|
+
const parseDuration = (input) => {
|
|
7
|
+
const match = DURATION_PATTERN.exec(input);
|
|
8
|
+
const amount = Number(match?.[1]);
|
|
9
|
+
const seconds = match?.[2] === 'm' ? amount * 60 : amount;
|
|
10
|
+
return Number.isFinite(seconds) && seconds >= 1 && seconds <= MAX_WAIT_SECONDS
|
|
11
|
+
? Promise.resolve(seconds * 1000)
|
|
12
|
+
: Promise.reject(new Errors.CLIError(`Invalid duration \`${input}\`. ${durationHint}`, { exit: exitCode.usage }));
|
|
13
|
+
};
|
|
14
|
+
/** Parse seconds or minutes into milliseconds for the SDK. */
|
|
15
|
+
const duration = Flags.custom({ parse: async (input) => parseDuration(input) });
|
|
16
|
+
/**
|
|
17
|
+
* Keep defaults out of these flags so dependsOn can detect a missing --wait.
|
|
18
|
+
* The SDK supplies the default timeout.
|
|
19
|
+
*/
|
|
20
|
+
export const waitFlags = {
|
|
21
|
+
timeout: duration({
|
|
22
|
+
dependsOn: ['wait'],
|
|
23
|
+
description: 'Polling budget with --wait: 1-600s, default 120s (e.g. 300, 300s, 5m); in-flight requests may take longer',
|
|
24
|
+
helpValue: 'DURATION',
|
|
25
|
+
}),
|
|
26
|
+
wait: Flags.boolean({
|
|
27
|
+
description: 'Poll for a revision or state change, then return the latest response',
|
|
28
|
+
}),
|
|
29
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
const workDone = (progress) => {
|
|
2
|
+
const done = progress.total === null ? String(progress.done) : `${progress.done} of ${progress.total}`;
|
|
3
|
+
return `${done} ${progress.unit}`;
|
|
4
|
+
};
|
|
5
|
+
/** Format a progress line for stderr, including when progress or its total is unknown. */
|
|
6
|
+
export const pollNotice = (envelope, delayMs) => {
|
|
7
|
+
const { progress, state } = envelope.migration;
|
|
8
|
+
const work = progress === null ? state : `${state} ${workDone(progress)}`;
|
|
9
|
+
return `${work} — checking again in ${Math.round(delayMs / 1000)}s`;
|
|
10
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { MigrationCommand } from '../../../base/adapty/index.js';
|
|
2
|
+
import type { Envelope } from '../../../../sdk/adapty/index.js';
|
|
3
|
+
export default class Steps extends MigrationCommand {
|
|
4
|
+
static summary: string;
|
|
5
|
+
static description: string;
|
|
6
|
+
static examples: {
|
|
7
|
+
description: string;
|
|
8
|
+
command: string;
|
|
9
|
+
}[];
|
|
10
|
+
static flags: {
|
|
11
|
+
migration: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
12
|
+
};
|
|
13
|
+
run(): Promise<Envelope>;
|
|
14
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { MigrationCommand } from '../../../base/adapty/index.js';
|
|
2
|
+
import { migrationFlags } from '../../../input/migration.js';
|
|
3
|
+
import { renderSteps } from './lib/render.js';
|
|
4
|
+
export default class Steps extends MigrationCommand {
|
|
5
|
+
static summary = 'Show the migration checklist and step statuses';
|
|
6
|
+
static description = [
|
|
7
|
+
'Shows done, active, and locked steps in migration order.',
|
|
8
|
+
'To find actions you can run, use `adapty migrations status -m ID`.',
|
|
9
|
+
'',
|
|
10
|
+
'With --json, the full migration response is returned; the checklist is in steps.',
|
|
11
|
+
].join('\n');
|
|
12
|
+
static examples = [
|
|
13
|
+
{
|
|
14
|
+
description: 'View the saved migration checklist:',
|
|
15
|
+
command: '<%= config.bin %> migrations steps',
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
description: 'View the checklist:',
|
|
19
|
+
command: '<%= config.bin %> migrations steps -m mig_7x2',
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
description: 'Extract the checklist as JSON (requires jq):',
|
|
23
|
+
command: '<%= config.bin %> migrations steps -m mig_7x2 --json | jq \'.steps\'',
|
|
24
|
+
},
|
|
25
|
+
];
|
|
26
|
+
static flags = { ...migrationFlags };
|
|
27
|
+
async run() {
|
|
28
|
+
const { flags } = await this.parse(Steps);
|
|
29
|
+
const selection = await this.currentMigration.require(flags.migration);
|
|
30
|
+
const envelope = await this.adapty.migrations.get(selection.currentMigrationId);
|
|
31
|
+
this.render(envelope, renderSteps);
|
|
32
|
+
return envelope;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from './command.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from './command.js';
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/** Unknown statuses are displayed as text; satisfies checks that all known statuses have a mark. */
|
|
2
|
+
const marks = {
|
|
3
|
+
active: '[>]',
|
|
4
|
+
done: '[x]',
|
|
5
|
+
locked: '[ ]',
|
|
6
|
+
};
|
|
7
|
+
const markOf = (status) => marks[status] ?? `[${status}]`;
|
|
8
|
+
const maxWidth = (values) => {
|
|
9
|
+
return values.reduce((max, value) => Math.max(max, value.length), 0);
|
|
10
|
+
};
|
|
11
|
+
const stepLine = (step, widths) => {
|
|
12
|
+
const mark = markOf(step.status).padEnd(widths.mark);
|
|
13
|
+
const stepId = step.step_id.padEnd(widths.stepId);
|
|
14
|
+
const summary = step.summary === null ? '' : ` ${step.summary}`;
|
|
15
|
+
return `${mark} ${stepId} ${step.title}${summary}`;
|
|
16
|
+
};
|
|
17
|
+
/** Keep server order and step IDs so users can match steps to issues and actions. */
|
|
18
|
+
export const renderSteps = (envelope) => {
|
|
19
|
+
const { steps } = envelope;
|
|
20
|
+
if (steps.length === 0) {
|
|
21
|
+
return `No steps yet: ${envelope.migration.summary}`;
|
|
22
|
+
}
|
|
23
|
+
const widths = {
|
|
24
|
+
mark: maxWidth(steps.map(step => markOf(step.status))),
|
|
25
|
+
stepId: maxWidth(steps.map(step => step.step_id)),
|
|
26
|
+
};
|
|
27
|
+
return steps.map(step => stepLine(step, widths)).join('\n');
|
|
28
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { BaseCommand } from '../../../base/base-command.js';
|
|
2
|
+
type Result = {
|
|
3
|
+
currentMigrationId: null;
|
|
4
|
+
};
|
|
5
|
+
export default class Unuse extends BaseCommand {
|
|
6
|
+
static summary: string;
|
|
7
|
+
static description: string;
|
|
8
|
+
static examples: string[];
|
|
9
|
+
run(): Promise<Result>;
|
|
10
|
+
}
|
|
11
|
+
export {};
|