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,33 @@
|
|
|
1
|
+
import { createFileSessionStore } from '../../../../sdk/core/session.js';
|
|
2
|
+
import { BaseCommand } from '../../../base/base-command.js';
|
|
3
|
+
import { openCurrentMigration } from '../../../context/migration/index.js';
|
|
4
|
+
import { envSuppliesMigration } from '../../../views/migrations/notices.js';
|
|
5
|
+
import { clearLocalSession } from './lib/cleanup.js';
|
|
6
|
+
/** A record rather than an if: a new status cannot be added without a text for it. */
|
|
7
|
+
const messages = {
|
|
8
|
+
logged_out: 'Logged out. Note: the token stays valid server-side until it expires — see `adapty auth revoke`.',
|
|
9
|
+
not_authenticated: 'Not currently authenticated.',
|
|
10
|
+
};
|
|
11
|
+
const ENV_STILL_SET = 'ADAPTY_TOKEN is still set in the environment, so commands stay authenticated. Unset it to finish logging out.';
|
|
12
|
+
export default class AuthLogout extends BaseCommand {
|
|
13
|
+
static description = 'Remove stored credentials and the saved migration selection';
|
|
14
|
+
static examples = ['<%= config.bin %> auth logout'];
|
|
15
|
+
async run() {
|
|
16
|
+
await this.parse(AuthLogout);
|
|
17
|
+
const envTokenSet = process.env.ADAPTY_TOKEN !== undefined && process.env.ADAPTY_TOKEN !== '';
|
|
18
|
+
// No session: an orphaned selection has to go even when the credentials cannot be read.
|
|
19
|
+
const current = openCurrentMigration({ configDir: this.config.configDir });
|
|
20
|
+
if (current.overridden) {
|
|
21
|
+
process.stderr.write(envSuppliesMigration);
|
|
22
|
+
}
|
|
23
|
+
const hadSession = await clearLocalSession(createFileSessionStore(this.config.configDir), current);
|
|
24
|
+
const result = {
|
|
25
|
+
env_token_set: envTokenSet,
|
|
26
|
+
status: hadSession ? 'logged_out' : 'not_authenticated',
|
|
27
|
+
};
|
|
28
|
+
this.render(result, status => (status.env_token_set
|
|
29
|
+
? `${messages[status.status]}\n${ENV_STILL_SET}`
|
|
30
|
+
: messages[status.status]));
|
|
31
|
+
return result;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from './command.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from './command.js';
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { CliError, describeCleanupFailures } from '../../../../errors.js';
|
|
2
|
+
export const clearLocalSession = async (session, context) => {
|
|
3
|
+
let hadSession;
|
|
4
|
+
try {
|
|
5
|
+
hadSession = await session.load() !== undefined;
|
|
6
|
+
}
|
|
7
|
+
catch {
|
|
8
|
+
// Logout can remove unreadable or malformed credentials without decoding them.
|
|
9
|
+
hadSession = true;
|
|
10
|
+
}
|
|
11
|
+
const results = await Promise.allSettled([session.clear(), context.clear()]);
|
|
12
|
+
const failed = describeCleanupFailures([session.path, context.path], results);
|
|
13
|
+
if (failed.length > 0) {
|
|
14
|
+
throw new CliError([
|
|
15
|
+
'Local logout cleanup is incomplete. Could not remove:',
|
|
16
|
+
...failed.map(failure => ` ${failure.file}: ${failure.reason}`),
|
|
17
|
+
'Check file permissions and run `adapty auth logout` again.',
|
|
18
|
+
].join('\n'), 1, 'auth_cleanup_failed', { cause: failed[0]?.cause });
|
|
19
|
+
}
|
|
20
|
+
return hadSession;
|
|
21
|
+
};
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import { build, openSession } from '
|
|
2
|
-
import { BaseCommand } from '
|
|
1
|
+
import { build, openSession } from '../../../base/adapty/index.js';
|
|
2
|
+
import { BaseCommand } from '../../../base/base-command.js';
|
|
3
|
+
import { openCurrentMigration } from '../../../context/migration/index.js';
|
|
4
|
+
import { clearRevokedSession } from './lib/cleanup.js';
|
|
3
5
|
export default class AuthRevoke extends BaseCommand {
|
|
4
|
-
static description = 'Revoke the current token
|
|
6
|
+
static description = 'Revoke the current token and remove matching stored credentials and migration selection';
|
|
5
7
|
static examples = ['<%= config.bin %> auth revoke'];
|
|
6
8
|
async run() {
|
|
7
9
|
await this.parse(AuthRevoke);
|
|
@@ -14,15 +16,13 @@ export default class AuthRevoke extends BaseCommand {
|
|
|
14
16
|
// the server and no local copy to revoke it with — only the dashboard could undo that.
|
|
15
17
|
const adapty = build(session, {
|
|
16
18
|
config: this.config,
|
|
19
|
+
interactive: this.interactive,
|
|
17
20
|
signal: this.signal,
|
|
18
21
|
warn: message => this.warn(message),
|
|
19
22
|
});
|
|
20
23
|
await adapty.auth.revokeToken(session.token);
|
|
21
24
|
// ADAPTY_TOKEN may override a different, still-valid session in the file.
|
|
22
|
-
|
|
23
|
-
if (stored?.token === session.token) {
|
|
24
|
-
await session.store.clear();
|
|
25
|
-
}
|
|
25
|
+
await clearRevokedSession(session.store, openCurrentMigration({ configDir: this.config.configDir, session }), session.token);
|
|
26
26
|
const result = { env_token_set: session.source === 'env', status: 'revoked' };
|
|
27
27
|
this.render(result, status => (status.env_token_set
|
|
28
28
|
? 'Token revoked. ADAPTY_TOKEN is still set and now holds a dead token — unset it.'
|
|
@@ -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 { SessionStore } from '../../../../../sdk/core/session.js';
|
|
2
|
+
import type { CurrentMigration } from '../../../../context/migration/index.js';
|
|
3
|
+
/** Called only after server success; each local cleanup is attempted independently. */
|
|
4
|
+
export declare const clearRevokedSession: (session: SessionStore, context: CurrentMigration, token: string) => Promise<void>;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { CliError, describeCleanupFailures } from '../../../../errors.js';
|
|
2
|
+
/**
|
|
3
|
+
* ADAPTY_TOKEN may override a different, still-valid file session, which revocation must leave
|
|
4
|
+
* alone. Read-then-remove, not a compare-and-delete: a concurrent `login` can land in between and
|
|
5
|
+
* lose its fresh credentials, which asks for another `adapty auth login` and never keeps a revoked
|
|
6
|
+
* token readable. See `CurrentMigration.clearFor`, which drops the selection under the same rule.
|
|
7
|
+
*/
|
|
8
|
+
const clearMatchingSession = async (store, token) => {
|
|
9
|
+
const stored = await store.load();
|
|
10
|
+
if (stored?.token === token) {
|
|
11
|
+
await store.clear();
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
/** Called only after server success; each local cleanup is attempted independently. */
|
|
15
|
+
export const clearRevokedSession = async (session, context, token) => {
|
|
16
|
+
const results = await Promise.allSettled([
|
|
17
|
+
clearMatchingSession(session, token),
|
|
18
|
+
context.clearFor(token),
|
|
19
|
+
]);
|
|
20
|
+
const files = [session.path, context.path];
|
|
21
|
+
const failed = describeCleanupFailures(files, results);
|
|
22
|
+
if (failed.length > 0) {
|
|
23
|
+
throw new CliError([
|
|
24
|
+
'Token revoked on the server, but local cleanup is incomplete for:',
|
|
25
|
+
...failed.map(failure => ` ${failure.file}: ${failure.reason}`),
|
|
26
|
+
'Check or remove these local files; do not repeat revocation.',
|
|
27
|
+
].join('\n'), 1, 'auth_cleanup_failed', { cause: failed[0]?.cause });
|
|
28
|
+
}
|
|
29
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { openSession } from '../../../base/adapty/index.js';
|
|
2
|
+
import { BaseCommand } from '../../../base/base-command.js';
|
|
3
|
+
import { renderStatus } from './lib/render.js';
|
|
4
|
+
export default class AuthStatus extends BaseCommand {
|
|
5
|
+
static description = 'Show the local authentication state (no network)';
|
|
6
|
+
static examples = ['<%= config.bin %> auth status'];
|
|
7
|
+
async run() {
|
|
8
|
+
await this.parse(AuthStatus);
|
|
9
|
+
const session = await openSession(this.config);
|
|
10
|
+
const result = session.token === undefined
|
|
11
|
+
? { authenticated: false, config_path: session.store.path, source: 'none' }
|
|
12
|
+
: {
|
|
13
|
+
authenticated: true,
|
|
14
|
+
config_path: session.store.path,
|
|
15
|
+
email: session.user?.email,
|
|
16
|
+
source: session.source === 'env' ? 'env' : 'file',
|
|
17
|
+
token_prefix: session.token.slice(0, 8),
|
|
18
|
+
};
|
|
19
|
+
this.render(result, renderStatus);
|
|
20
|
+
return result;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -1,7 +1 @@
|
|
|
1
|
-
|
|
2
|
-
import type { Result } from './lib/result.js';
|
|
3
|
-
export default class AuthStatus extends BaseCommand {
|
|
4
|
-
static description: string;
|
|
5
|
-
static examples: string[];
|
|
6
|
-
run(): Promise<Result>;
|
|
7
|
-
}
|
|
1
|
+
export { default } from './command.js';
|
|
@@ -1,22 +1 @@
|
|
|
1
|
-
|
|
2
|
-
import { BaseCommand } from '../../../base/base-command.js';
|
|
3
|
-
import { renderStatus } from './lib/render.js';
|
|
4
|
-
export default class AuthStatus extends BaseCommand {
|
|
5
|
-
static description = 'Show the local authentication state (no network)';
|
|
6
|
-
static examples = ['<%= config.bin %> auth status'];
|
|
7
|
-
async run() {
|
|
8
|
-
await this.parse(AuthStatus);
|
|
9
|
-
const session = await openSession(this.config);
|
|
10
|
-
const result = session.token === undefined
|
|
11
|
-
? { authenticated: false, config_path: session.store.path, source: 'none' }
|
|
12
|
-
: {
|
|
13
|
-
authenticated: true,
|
|
14
|
-
config_path: session.store.path,
|
|
15
|
-
email: session.user?.email,
|
|
16
|
-
source: session.source === 'env' ? 'env' : 'file',
|
|
17
|
-
token_prefix: session.token.slice(0, 8),
|
|
18
|
-
};
|
|
19
|
-
this.render(result, renderStatus);
|
|
20
|
-
return result;
|
|
21
|
-
}
|
|
22
|
-
}
|
|
1
|
+
export { default } from './command.js';
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { MigrationCommand } from '../../../base/adapty/index.js';
|
|
2
|
+
import type { Envelope } from '../../../../sdk/adapty/index.js';
|
|
3
|
+
export default class Close extends MigrationCommand {
|
|
4
|
+
static summary: string;
|
|
5
|
+
static description: string;
|
|
6
|
+
static examples: {
|
|
7
|
+
description: string;
|
|
8
|
+
command: string;
|
|
9
|
+
}[];
|
|
10
|
+
static flags: {
|
|
11
|
+
outcome: import("@oclif/core/interfaces").OptionFlag<"cancel" | "finish", import("@oclif/core/interfaces").CustomOptions>;
|
|
12
|
+
yes: 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
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { Flags } from '@oclif/core';
|
|
2
|
+
import { MigrationCommand } from '../../../base/adapty/index.js';
|
|
3
|
+
import { migrationFlags } from '../../../input/migration.js';
|
|
4
|
+
import { renderEnvelope } from '../../../views/migrations/envelope/envelope.js';
|
|
5
|
+
export default class Close extends MigrationCommand {
|
|
6
|
+
static summary = 'Permanently finish or cancel a migration';
|
|
7
|
+
static description = [
|
|
8
|
+
'Choose finish to mark the migration as completed, or cancel to abandon it.',
|
|
9
|
+
'Both outcomes permanently close the migration and require --yes. No confirmation prompt is shown.',
|
|
10
|
+
'',
|
|
11
|
+
'With --json, returns the full migration response after closing.',
|
|
12
|
+
].join('\n');
|
|
13
|
+
static examples = [
|
|
14
|
+
{
|
|
15
|
+
description: 'Finish the saved migration:',
|
|
16
|
+
command: '<%= config.bin %> migrations close --outcome finish --yes',
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
description: 'Mark the migration as finished:',
|
|
20
|
+
command: '<%= config.bin %> migrations close -m mig_7x2 --outcome finish --yes',
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
description: 'Abandon the migration:',
|
|
24
|
+
command: '<%= config.bin %> migrations close -m mig_7x2 --outcome cancel --yes',
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
description: 'Finish and return the final state as JSON:',
|
|
28
|
+
command: '<%= config.bin %> migrations close -m mig_7x2 --outcome finish --yes --json',
|
|
29
|
+
},
|
|
30
|
+
];
|
|
31
|
+
static flags = {
|
|
32
|
+
...migrationFlags,
|
|
33
|
+
outcome: Flags.option({
|
|
34
|
+
description: 'finish: mark completed; cancel: abandon the migration',
|
|
35
|
+
options: ['finish', 'cancel'],
|
|
36
|
+
required: true,
|
|
37
|
+
})(),
|
|
38
|
+
yes: Flags.boolean({
|
|
39
|
+
char: 'y',
|
|
40
|
+
description: 'Confirm permanent closure of this migration',
|
|
41
|
+
required: true,
|
|
42
|
+
}),
|
|
43
|
+
};
|
|
44
|
+
async run() {
|
|
45
|
+
const { flags } = await this.parse(Close);
|
|
46
|
+
const selection = await this.currentMigration.require(flags.migration);
|
|
47
|
+
const { migration } = await this.adapty.migrations.get(selection.currentMigrationId);
|
|
48
|
+
if (selection.source === 'context') {
|
|
49
|
+
process.stderr.write(`Using saved migration: ${selection.currentMigrationId}\n`);
|
|
50
|
+
}
|
|
51
|
+
const envelope = await this.adapty.migrations.close(selection.currentMigrationId, {
|
|
52
|
+
expectedRevision: migration.revision,
|
|
53
|
+
outcome: flags.outcome,
|
|
54
|
+
});
|
|
55
|
+
this.render(envelope, renderEnvelope);
|
|
56
|
+
return envelope;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from './command.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from './command.js';
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { MigrationCommand } from '../../../base/adapty/index.js';
|
|
2
|
+
import type { Envelope } from '../../../../sdk/adapty/index.js';
|
|
3
|
+
export default class Create extends MigrationCommand {
|
|
4
|
+
static summary: string;
|
|
5
|
+
static description: string;
|
|
6
|
+
static usage: string[];
|
|
7
|
+
static examples: {
|
|
8
|
+
description: string;
|
|
9
|
+
command: string;
|
|
10
|
+
}[];
|
|
11
|
+
static flags: {
|
|
12
|
+
'no-select': import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
13
|
+
name: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
14
|
+
flow: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
15
|
+
app: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
16
|
+
};
|
|
17
|
+
run(): Promise<Envelope>;
|
|
18
|
+
/** Creation has already succeeded: a local failure must not invite a duplicate POST. */
|
|
19
|
+
private select;
|
|
20
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { Flags } from '@oclif/core';
|
|
2
|
+
import { validateCreateMigration } from '../../../../sdk/adapty/migrations/index.js';
|
|
3
|
+
import { assertValid } from '../../../../sdk/core/validation.js';
|
|
4
|
+
import { MigrationCommand } from '../../../base/adapty/index.js';
|
|
5
|
+
import { renderEnvelope } from '../../../views/migrations/envelope/envelope.js';
|
|
6
|
+
import { envOverridesSelection } from '../../../views/migrations/notices.js';
|
|
7
|
+
export default class Create extends MigrationCommand {
|
|
8
|
+
static summary = 'Start a migration into Adapty';
|
|
9
|
+
static description = [
|
|
10
|
+
'Use --name to migrate a catalog into a new Adapty app.',
|
|
11
|
+
'For an existing app, use --flow and --app together. Choose a flow and its app from `adapty migrations list`.',
|
|
12
|
+
'',
|
|
13
|
+
'Creation starts the flow and saves it as current; use `adapty migrations status` to continue.',
|
|
14
|
+
'Use --no-select to keep the previous selection. ADAPTY_MIGRATION overrides saved selection.',
|
|
15
|
+
'With --json, the migration ID is in migration.id.',
|
|
16
|
+
].join('\n');
|
|
17
|
+
static usage = [
|
|
18
|
+
'migrations create --name APP_NAME [--no-select] [--json]',
|
|
19
|
+
'migrations create --flow FLOW --app APP_ID [--no-select] [--json]',
|
|
20
|
+
];
|
|
21
|
+
static examples = [
|
|
22
|
+
{
|
|
23
|
+
description: 'Start a catalog migration into a new app:',
|
|
24
|
+
command: '<%= config.bin %> migrations create --name "Acme Fitness"',
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
description: 'Start transactions for an existing app, if listed as available:',
|
|
28
|
+
command: '<%= config.bin %> migrations create --flow transactions --app 3f2ab1c4-0000-4000-8000-000000000000',
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
description: 'Return the new migration as JSON for an agent or script:',
|
|
32
|
+
command: '<%= config.bin %> migrations create --name "Acme Fitness" --json',
|
|
33
|
+
},
|
|
34
|
+
];
|
|
35
|
+
static flags = {
|
|
36
|
+
'no-select': Flags.boolean({
|
|
37
|
+
description: 'Create without changing the saved migration selection',
|
|
38
|
+
default: false,
|
|
39
|
+
}),
|
|
40
|
+
'name': Flags.string({
|
|
41
|
+
description: 'New Adapty app name; cannot be combined with --flow or --app',
|
|
42
|
+
exclusive: ['app', 'flow'],
|
|
43
|
+
helpValue: 'APP_NAME',
|
|
44
|
+
}),
|
|
45
|
+
'flow': Flags.string({
|
|
46
|
+
dependsOn: ['app'],
|
|
47
|
+
description: 'Available flow from `adapty migrations list`; requires --app',
|
|
48
|
+
helpValue: 'FLOW',
|
|
49
|
+
}),
|
|
50
|
+
'app': Flags.string({
|
|
51
|
+
dependsOn: ['flow'],
|
|
52
|
+
description: 'Existing Adapty app ID (UUID); requires --flow',
|
|
53
|
+
helpValue: 'APP_ID',
|
|
54
|
+
}),
|
|
55
|
+
};
|
|
56
|
+
async run() {
|
|
57
|
+
const { flags } = await this.parse(Create);
|
|
58
|
+
const input = {
|
|
59
|
+
appId: flags.app,
|
|
60
|
+
appName: flags.name,
|
|
61
|
+
flow: flags.flow,
|
|
62
|
+
};
|
|
63
|
+
assertValid(validateCreateMigration(input));
|
|
64
|
+
const envelope = await this.adapty.migrations.create(input);
|
|
65
|
+
const selected = !flags['no-select'] && await this.select(envelope.migration.id);
|
|
66
|
+
const target = selected && !this.currentMigration.overridden ? '' : ` -m ${envelope.migration.id}`;
|
|
67
|
+
this.log('Migration created.');
|
|
68
|
+
this.render(envelope, renderEnvelope);
|
|
69
|
+
this.log(`\nContinue with \`${this.config.bin} migrations status${target}\`.`);
|
|
70
|
+
return envelope;
|
|
71
|
+
}
|
|
72
|
+
/** Creation has already succeeded: a local failure must not invite a duplicate POST. */
|
|
73
|
+
async select(migrationId) {
|
|
74
|
+
try {
|
|
75
|
+
await this.currentMigration.set(migrationId);
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
process.stderr.write(`Warning: Migration ${migrationId} was created, but its selection could not be saved. Continue with \`${this.config.bin} migrations status -m ${migrationId}\`.\n`);
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
81
|
+
if (this.currentMigration.overridden) {
|
|
82
|
+
process.stderr.write(envOverridesSelection);
|
|
83
|
+
}
|
|
84
|
+
return true;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from './command.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from './command.js';
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { BaseCommand } from '../../../base/base-command.js';
|
|
2
|
+
type Result = {
|
|
3
|
+
currentMigrationId: string | null;
|
|
4
|
+
source: 'env' | 'context' | null;
|
|
5
|
+
};
|
|
6
|
+
export default class Current extends BaseCommand {
|
|
7
|
+
static summary: string;
|
|
8
|
+
static description: string;
|
|
9
|
+
static examples: string[];
|
|
10
|
+
run(): Promise<Result>;
|
|
11
|
+
}
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { openSession } from '../../../base/adapty/index.js';
|
|
2
|
+
import { BaseCommand } from '../../../base/base-command.js';
|
|
3
|
+
import { openCurrentMigration } from '../../../context/migration/index.js';
|
|
4
|
+
export default class Current extends BaseCommand {
|
|
5
|
+
static summary = 'Show the effective migration selection and its source (no network)';
|
|
6
|
+
static description = [
|
|
7
|
+
'ADAPTY_MIGRATION takes precedence over the saved selection for the current token.',
|
|
8
|
+
'With no applicable selection, returns null and exits successfully.',
|
|
9
|
+
].join('\n');
|
|
10
|
+
static examples = ['<%= config.bin %> migrations current', '<%= config.bin %> migrations current --json'];
|
|
11
|
+
async run() {
|
|
12
|
+
await this.parse(Current);
|
|
13
|
+
const selection = await openCurrentMigration({
|
|
14
|
+
configDir: this.config.configDir,
|
|
15
|
+
session: await openSession(this.config),
|
|
16
|
+
}).get();
|
|
17
|
+
const result = selection === undefined
|
|
18
|
+
? { currentMigrationId: null, source: null }
|
|
19
|
+
: { currentMigrationId: selection.currentMigrationId, source: selection.source === 'env' ? 'env' : 'context' };
|
|
20
|
+
this.render(result, value => value.currentMigrationId === null
|
|
21
|
+
? `No migration selected. Run \`${this.config.bin} migrations use <id>\`.`
|
|
22
|
+
: `Current migration: ${value.currentMigrationId} (${value.source === 'env' ? 'ADAPTY_MIGRATION' : 'context'})`);
|
|
23
|
+
return result;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from './command.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from './command.js';
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { AdaptyCommand } from '../../../base/adapty/index.js';
|
|
2
|
+
import type { MigrationList } from '../../../../sdk/adapty/index.js';
|
|
3
|
+
export default class List extends AdaptyCommand {
|
|
4
|
+
static summary: string;
|
|
5
|
+
static description: string;
|
|
6
|
+
static examples: {
|
|
7
|
+
description: string;
|
|
8
|
+
command: string;
|
|
9
|
+
}[];
|
|
10
|
+
run(): Promise<MigrationList>;
|
|
11
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { AdaptyCommand } from '../../../base/adapty/index.js';
|
|
2
|
+
import { renderMigrationList } from './lib/render.js';
|
|
3
|
+
export default class List extends AdaptyCommand {
|
|
4
|
+
static summary = 'List migrations and the flows you can start';
|
|
5
|
+
static description = [
|
|
6
|
+
'Use a migration ID with `adapty migrations status -m ID` to continue an existing flow.',
|
|
7
|
+
'Start an available flow with `adapty migrations create --flow FLOW --app APP_ID`.',
|
|
8
|
+
'',
|
|
9
|
+
'With --json, items contains migrations and available contains flows with their target apps.',
|
|
10
|
+
].join('\n');
|
|
11
|
+
static examples = [
|
|
12
|
+
{
|
|
13
|
+
description: 'Find migrations and available flows, grouped by app:',
|
|
14
|
+
command: '<%= config.bin %> migrations list',
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
description: 'Read migration IDs and available flows as JSON:',
|
|
18
|
+
command: '<%= config.bin %> migrations list --json',
|
|
19
|
+
},
|
|
20
|
+
];
|
|
21
|
+
async run() {
|
|
22
|
+
await this.parse(List);
|
|
23
|
+
const list = await this.adapty.migrations.list();
|
|
24
|
+
this.render(list, renderMigrationList);
|
|
25
|
+
return list;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from './command.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from './command.js';
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
const stateOrder = [
|
|
2
|
+
'action_required',
|
|
3
|
+
'running',
|
|
4
|
+
'failed',
|
|
5
|
+
'completed',
|
|
6
|
+
'canceled',
|
|
7
|
+
];
|
|
8
|
+
const stateRank = (state) => {
|
|
9
|
+
const index = stateOrder.findIndex(knownState => knownState === state);
|
|
10
|
+
return index === -1 ? stateOrder.length : index;
|
|
11
|
+
};
|
|
12
|
+
const appLabel = (app) => (app === null ? 'App not created yet' : `${app.name} (${app.id})`);
|
|
13
|
+
const maxWidth = (values) => {
|
|
14
|
+
return values.reduce((max, value) => Math.max(max, value.length), 0);
|
|
15
|
+
};
|
|
16
|
+
const groupByApp = (list) => {
|
|
17
|
+
const groups = new Map();
|
|
18
|
+
const groupFor = (app) => {
|
|
19
|
+
const key = app === null ? null : app.id;
|
|
20
|
+
const existing = groups.get(key);
|
|
21
|
+
if (existing !== undefined) {
|
|
22
|
+
return existing;
|
|
23
|
+
}
|
|
24
|
+
const group = { app, available: [], migrations: [] };
|
|
25
|
+
groups.set(key, group);
|
|
26
|
+
return group;
|
|
27
|
+
};
|
|
28
|
+
for (const migration of list.items) {
|
|
29
|
+
groupFor(migration.app).migrations.push(migration);
|
|
30
|
+
}
|
|
31
|
+
for (const flow of list.available) {
|
|
32
|
+
groupFor(flow.app).available.push(flow);
|
|
33
|
+
}
|
|
34
|
+
return [...groups.values()];
|
|
35
|
+
};
|
|
36
|
+
const renderMigrations = (migrations) => {
|
|
37
|
+
const sorted = [...migrations].sort((a, b) => stateRank(a.state) - stateRank(b.state));
|
|
38
|
+
const idWidth = maxWidth(sorted.map(migration => migration.id));
|
|
39
|
+
const flowWidth = maxWidth(sorted.map(migration => migration.flow));
|
|
40
|
+
const lines = [];
|
|
41
|
+
let heading;
|
|
42
|
+
for (const migration of sorted) {
|
|
43
|
+
if (migration.state !== heading) {
|
|
44
|
+
heading = migration.state;
|
|
45
|
+
lines.push(` ${heading}`);
|
|
46
|
+
}
|
|
47
|
+
const id = migration.id.padEnd(idWidth);
|
|
48
|
+
const flow = migration.flow.padEnd(flowWidth);
|
|
49
|
+
lines.push(` ${id} ${flow} ${migration.updated_at} ${migration.summary}`);
|
|
50
|
+
}
|
|
51
|
+
return lines;
|
|
52
|
+
};
|
|
53
|
+
const renderAvailable = (available) => {
|
|
54
|
+
if (available.length === 0) {
|
|
55
|
+
return [];
|
|
56
|
+
}
|
|
57
|
+
const flowWidth = maxWidth(available.map(flow => flow.flow));
|
|
58
|
+
return [
|
|
59
|
+
' Available to start:',
|
|
60
|
+
...available.map((flow) => {
|
|
61
|
+
const detail = flow.detail === null ? '' : ` ${flow.detail}`;
|
|
62
|
+
return ` ${flow.flow.padEnd(flowWidth)} ${flow.title}${detail}`;
|
|
63
|
+
}),
|
|
64
|
+
];
|
|
65
|
+
};
|
|
66
|
+
const renderGroup = (group) => [
|
|
67
|
+
appLabel(group.app),
|
|
68
|
+
...renderMigrations(group.migrations),
|
|
69
|
+
...renderAvailable(group.available),
|
|
70
|
+
].join('\n');
|
|
71
|
+
/** Group by app, then by migration state. */
|
|
72
|
+
export const renderMigrationList = (list) => {
|
|
73
|
+
if (list.items.length === 0 && list.available.length === 0) {
|
|
74
|
+
return 'No migrations yet. Start one: `adapty migrations create --name "My app"`';
|
|
75
|
+
}
|
|
76
|
+
return groupByApp(list).map(group => renderGroup(group)).join('\n\n');
|
|
77
|
+
};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { MigrationCommand } from '../../../base/adapty/index.js';
|
|
2
|
+
import type { Envelope } from '../../../../sdk/adapty/index.js';
|
|
3
|
+
export default class Run extends MigrationCommand {
|
|
4
|
+
static summary: string;
|
|
5
|
+
static description: string;
|
|
6
|
+
static examples: {
|
|
7
|
+
description: string;
|
|
8
|
+
command: string;
|
|
9
|
+
}[];
|
|
10
|
+
static args: {
|
|
11
|
+
action_id: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
|
|
12
|
+
};
|
|
13
|
+
static flags: {
|
|
14
|
+
input: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
15
|
+
'input-file': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
16
|
+
yes: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
17
|
+
open: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
18
|
+
'no-browser': import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
19
|
+
migration: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
20
|
+
};
|
|
21
|
+
run(): Promise<Envelope>;
|
|
22
|
+
private prepare;
|
|
23
|
+
private runExternalAction;
|
|
24
|
+
private runInputAction;
|
|
25
|
+
}
|