@doist/twist-cli 2.39.0 → 2.41.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/CHANGELOG.md +12 -0
- package/dist/commands/account/current.d.ts +4 -0
- package/dist/commands/account/current.d.ts.map +1 -0
- package/dist/commands/account/current.js +46 -0
- package/dist/commands/account/current.js.map +1 -0
- package/dist/commands/account/helpers.d.ts +8 -0
- package/dist/commands/account/helpers.d.ts.map +1 -0
- package/dist/commands/account/helpers.js +18 -0
- package/dist/commands/account/helpers.js.map +1 -0
- package/dist/commands/account/index.d.ts +3 -0
- package/dist/commands/account/index.d.ts.map +1 -0
- package/dist/commands/account/index.js +30 -0
- package/dist/commands/account/index.js.map +1 -0
- package/dist/commands/account/list.d.ts +4 -0
- package/dist/commands/account/list.d.ts.map +1 -0
- package/dist/commands/account/list.js +30 -0
- package/dist/commands/account/list.js.map +1 -0
- package/dist/commands/account/remove.d.ts +4 -0
- package/dist/commands/account/remove.d.ts.map +1 -0
- package/dist/commands/account/remove.js +18 -0
- package/dist/commands/account/remove.js.map +1 -0
- package/dist/commands/account/use.d.ts +4 -0
- package/dist/commands/account/use.d.ts.map +1 -0
- package/dist/commands/account/use.js +13 -0
- package/dist/commands/account/use.js.map +1 -0
- package/dist/commands/auth/helpers.d.ts +1 -1
- package/dist/commands/auth/helpers.d.ts.map +1 -1
- package/dist/commands/auth/helpers.js.map +1 -1
- package/dist/commands/auth/store-wrap.d.ts +1 -1
- package/dist/commands/auth/store-wrap.d.ts.map +1 -1
- package/dist/commands/auth/store-wrap.js +16 -1
- package/dist/commands/auth/store-wrap.js.map +1 -1
- package/dist/commands/auth/token.d.ts.map +1 -1
- package/dist/commands/auth/token.js +19 -10
- package/dist/commands/auth/token.js.map +1 -1
- package/dist/commands/config/view.d.ts.map +1 -1
- package/dist/commands/config/view.js +17 -1
- package/dist/commands/config/view.js.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/auth-constants.d.ts +9 -0
- package/dist/lib/auth-constants.d.ts.map +1 -0
- package/dist/lib/auth-constants.js +9 -0
- package/dist/lib/auth-constants.js.map +1 -0
- package/dist/lib/auth-provider.d.ts +41 -7
- package/dist/lib/auth-provider.d.ts.map +1 -1
- package/dist/lib/auth-provider.js +179 -106
- package/dist/lib/auth-provider.js.map +1 -1
- package/dist/lib/auth.d.ts +13 -12
- package/dist/lib/auth.d.ts.map +1 -1
- package/dist/lib/auth.js +46 -238
- package/dist/lib/auth.js.map +1 -1
- package/dist/lib/config.d.ts +21 -1
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +62 -3
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/errors.d.ts +1 -1
- package/dist/lib/errors.d.ts.map +1 -1
- package/dist/lib/errors.js.map +1 -1
- package/dist/lib/migrate-auth.d.ts +14 -0
- package/dist/lib/migrate-auth.d.ts.map +1 -0
- package/dist/lib/migrate-auth.js +61 -0
- package/dist/lib/migrate-auth.js.map +1 -0
- package/dist/lib/skills/content.d.ts +1 -1
- package/dist/lib/skills/content.d.ts.map +1 -1
- package/dist/lib/skills/content.js +3 -0
- package/dist/lib/skills/content.js.map +1 -1
- package/dist/lib/twist-account.d.ts +22 -0
- package/dist/lib/twist-account.d.ts.map +1 -0
- package/dist/lib/twist-account.js +23 -0
- package/dist/lib/twist-account.js.map +1 -0
- package/dist/lib/user-records.d.ts +15 -0
- package/dist/lib/user-records.d.ts.map +1 -0
- package/dist/lib/user-records.js +84 -0
- package/dist/lib/user-records.js.map +1 -0
- package/dist/postinstall.js +4 -0
- package/dist/postinstall.js.map +1 -1
- package/package.json +1 -1
package/dist/lib/auth.js
CHANGED
|
@@ -1,262 +1,70 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { getConfig
|
|
1
|
+
import { SecureStoreUnavailableError } from '@doist/cli-core/auth';
|
|
2
|
+
import { createTwistTokenStore, getActiveTokenSource } from './auth-provider.js';
|
|
3
|
+
import { getConfig } from './config.js';
|
|
4
4
|
import { CliError } from './errors.js';
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
import { getDefaultUserRecord } from './user-records.js';
|
|
6
|
+
export { SecureStoreUnavailableError };
|
|
7
|
+
export const TOKEN_ENV_VAR = 'TWIST_API_TOKEN';
|
|
7
8
|
export const SECURE_STORE_DESCRIPTION = 'system credential manager';
|
|
8
|
-
function getSecureStore() {
|
|
9
|
-
return createSecureStore({ serviceName: SECURE_STORE_SERVICE, account: SECURE_STORE_ACCOUNT });
|
|
10
|
-
}
|
|
11
9
|
export class NoTokenError extends CliError {
|
|
12
10
|
constructor() {
|
|
13
11
|
super('NO_TOKEN', `No API token found. Set ${TOKEN_ENV_VAR} or run \`tw auth login\` or \`tw auth token <token>\`.`, ['Set TWIST_API_TOKEN or run: tw auth login'], 'info');
|
|
14
12
|
this.name = 'NoTokenError';
|
|
15
13
|
}
|
|
16
14
|
}
|
|
17
|
-
|
|
15
|
+
/** Read the active token. The store wraps env-var precedence internally. */
|
|
18
16
|
export async function getApiToken() {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
if (envToken) {
|
|
22
|
-
return envToken;
|
|
23
|
-
}
|
|
24
|
-
const config = await getConfig();
|
|
25
|
-
const configToken = getConfigToken(config);
|
|
26
|
-
const secureStore = getSecureStore();
|
|
27
|
-
if (configToken) {
|
|
28
|
-
try {
|
|
29
|
-
await secureStore.setSecret(configToken);
|
|
30
|
-
const cleanupWarning = await cleanupAuthFallbackState(config, 'Token was migrated to secure storage,');
|
|
31
|
-
if (cleanupWarning) {
|
|
32
|
-
warn(cleanupWarning);
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
catch (error) {
|
|
36
|
-
if (!(error instanceof SecureStoreUnavailableError)) {
|
|
37
|
-
throw error;
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
return configToken;
|
|
41
|
-
}
|
|
42
|
-
if (config.pendingSecureStoreClear) {
|
|
43
|
-
try {
|
|
44
|
-
await secureStore.deleteSecret();
|
|
45
|
-
const cleanupWarning = await cleanupAuthFallbackState(config, 'Secure-store token was removed,');
|
|
46
|
-
if (cleanupWarning) {
|
|
47
|
-
warn(cleanupWarning);
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
catch (error) {
|
|
51
|
-
if (!(error instanceof SecureStoreUnavailableError)) {
|
|
52
|
-
throw error;
|
|
53
|
-
}
|
|
54
|
-
}
|
|
17
|
+
const snapshot = await createTwistTokenStore().active();
|
|
18
|
+
if (!snapshot)
|
|
55
19
|
throw new NoTokenError();
|
|
56
|
-
|
|
57
|
-
try {
|
|
58
|
-
const storedToken = await secureStore.getSecret();
|
|
59
|
-
if (storedToken?.trim()) {
|
|
60
|
-
return storedToken;
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
catch (error) {
|
|
64
|
-
if (!(error instanceof SecureStoreUnavailableError)) {
|
|
65
|
-
throw error;
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
throw new NoTokenError();
|
|
20
|
+
return snapshot.token;
|
|
69
21
|
}
|
|
22
|
+
/** Token + metadata in one round-trip for `tw config view` / `tw doctor`. */
|
|
70
23
|
export async function probeApiToken() {
|
|
71
|
-
const
|
|
72
|
-
if (
|
|
73
|
-
return {
|
|
74
|
-
token: envToken,
|
|
75
|
-
metadata: { authMode: 'unknown', source: 'env' },
|
|
76
|
-
};
|
|
77
|
-
}
|
|
78
|
-
const config = await getConfig();
|
|
79
|
-
const configToken = getConfigToken(config);
|
|
80
|
-
if (configToken) {
|
|
81
|
-
return {
|
|
82
|
-
token: configToken,
|
|
83
|
-
metadata: {
|
|
84
|
-
authMode: config.authMode ?? 'unknown',
|
|
85
|
-
authScope: config.authScope,
|
|
86
|
-
authUserId: config.authUserId,
|
|
87
|
-
authUserName: config.authUserName,
|
|
88
|
-
source: 'config-file',
|
|
89
|
-
},
|
|
90
|
-
};
|
|
91
|
-
}
|
|
92
|
-
if (config.pendingSecureStoreClear) {
|
|
24
|
+
const snapshot = await createTwistTokenStore().active();
|
|
25
|
+
if (!snapshot)
|
|
93
26
|
throw new NoTokenError();
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
metadata: {
|
|
102
|
-
authMode: config.authMode ?? 'unknown',
|
|
103
|
-
authScope: config.authScope,
|
|
104
|
-
authUserId: config.authUserId,
|
|
105
|
-
authUserName: config.authUserName,
|
|
106
|
-
source: 'secure-store',
|
|
107
|
-
},
|
|
108
|
-
};
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
catch (error) {
|
|
112
|
-
if (!(error instanceof SecureStoreUnavailableError)) {
|
|
113
|
-
throw error;
|
|
114
|
-
}
|
|
115
|
-
throw error;
|
|
116
|
-
}
|
|
117
|
-
throw new NoTokenError();
|
|
27
|
+
const source = await getActiveTokenSource();
|
|
28
|
+
return {
|
|
29
|
+
token: snapshot.token,
|
|
30
|
+
metadata: source === 'env'
|
|
31
|
+
? { authMode: 'unknown', source: 'env' }
|
|
32
|
+
: { ...toAccountFields(snapshot.account), source },
|
|
33
|
+
};
|
|
118
34
|
}
|
|
35
|
+
/**
|
|
36
|
+
* Auth metadata for `tw auth status` and `ensureWriteAllowed`. Falls back
|
|
37
|
+
* to v1 flat fields when no v2 record exists so a legacy `read-only` token
|
|
38
|
+
* isn't reported as `'unknown'` — that would skip the local READ_ONLY guard.
|
|
39
|
+
*/
|
|
119
40
|
export async function getAuthMetadata() {
|
|
120
|
-
|
|
121
|
-
if (envToken) {
|
|
41
|
+
if (process.env[TOKEN_ENV_VAR])
|
|
122
42
|
return { authMode: 'unknown', source: 'env' };
|
|
123
|
-
}
|
|
124
43
|
const config = await getConfig();
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
throw new CliError('INVALID_TOKEN', 'Invalid token: Token must be at least 10 characters', [
|
|
137
|
-
'Run: tw auth login',
|
|
138
|
-
'Or set TWIST_API_TOKEN environment variable',
|
|
139
|
-
]);
|
|
140
|
-
}
|
|
141
|
-
const trimmedToken = token.trim();
|
|
142
|
-
const secureStore = getSecureStore();
|
|
143
|
-
try {
|
|
144
|
-
await secureStore.setSecret(trimmedToken);
|
|
145
|
-
const existingConfig = await getConfig();
|
|
146
|
-
const warning = await cleanupAuthFallbackState(existingConfig, 'Token was stored securely,');
|
|
147
|
-
// Persist auth metadata to config — needed for ensureWriteAllowed() enforcement
|
|
148
|
-
try {
|
|
149
|
-
await saveAuthMetadata(options);
|
|
150
|
-
}
|
|
151
|
-
catch {
|
|
152
|
-
if (options.authMode && options.authMode !== 'unknown') {
|
|
153
|
-
warn(`Could not persist auth mode '${options.authMode}' to config. CLI-side write protection may not work in future sessions.`);
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
return warning ? { storage: 'secure-store', warning } : { storage: 'secure-store' };
|
|
157
|
-
}
|
|
158
|
-
catch (error) {
|
|
159
|
-
if (!(error instanceof SecureStoreUnavailableError)) {
|
|
160
|
-
throw error;
|
|
161
|
-
}
|
|
44
|
+
const record = getDefaultUserRecord(config);
|
|
45
|
+
if (record)
|
|
46
|
+
return { ...toAccountFields(record.account), source: 'config' };
|
|
47
|
+
if (config.token?.trim() || config.authUserId !== undefined || config.authMode) {
|
|
48
|
+
return {
|
|
49
|
+
authMode: config.authMode ?? 'unknown',
|
|
50
|
+
authScope: config.authScope,
|
|
51
|
+
authUserId: config.authUserId,
|
|
52
|
+
authUserName: config.authUserName,
|
|
53
|
+
source: 'config',
|
|
54
|
+
};
|
|
162
55
|
}
|
|
163
|
-
|
|
164
|
-
config.token = trimmedToken;
|
|
165
|
-
delete config.pendingSecureStoreClear;
|
|
166
|
-
config.authMode = options.authMode ?? 'unknown';
|
|
167
|
-
config.authScope = options.authScope;
|
|
168
|
-
config.authUserId = options.authUserId;
|
|
169
|
-
config.authUserName = options.authUserName;
|
|
170
|
-
await writeConfig(config);
|
|
171
|
-
return {
|
|
172
|
-
storage: 'config-file',
|
|
173
|
-
warning: buildFallbackWarning('token saved as plaintext in'),
|
|
174
|
-
};
|
|
56
|
+
return { authMode: 'unknown', source: 'config' };
|
|
175
57
|
}
|
|
176
|
-
|
|
177
|
-
const config = await getConfig();
|
|
178
|
-
const secureStore = getSecureStore();
|
|
179
|
-
// Clear auth metadata from the in-memory config object so all subsequent
|
|
180
|
-
// writes (cleanupAuthFallbackState, withPendingSecureStoreClear) persist
|
|
181
|
-
// the removal atomically alongside other state changes.
|
|
182
|
-
delete config.authMode;
|
|
183
|
-
delete config.authScope;
|
|
184
|
-
delete config.authUserId;
|
|
185
|
-
delete config.authUserName;
|
|
186
|
-
try {
|
|
187
|
-
await secureStore.deleteSecret();
|
|
188
|
-
const warning = await cleanupAuthFallbackState(config, 'Secure-store token was removed,');
|
|
189
|
-
return warning ? { storage: 'secure-store', warning } : { storage: 'secure-store' };
|
|
190
|
-
}
|
|
191
|
-
catch (error) {
|
|
192
|
-
if (!(error instanceof SecureStoreUnavailableError)) {
|
|
193
|
-
throw error;
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
await writeConfig(withPendingSecureStoreClear(config));
|
|
58
|
+
function toAccountFields(account) {
|
|
197
59
|
return {
|
|
198
|
-
|
|
199
|
-
|
|
60
|
+
authMode: account.authMode,
|
|
61
|
+
authScope: account.authScope || undefined,
|
|
62
|
+
authUserId: account.id ? toAuthUserId(account.id) : undefined,
|
|
63
|
+
authUserName: account.label || undefined,
|
|
200
64
|
};
|
|
201
65
|
}
|
|
202
|
-
|
|
203
|
-
const
|
|
204
|
-
|
|
205
|
-
config.authScope = options.authScope;
|
|
206
|
-
config.authUserId = options.authUserId;
|
|
207
|
-
config.authUserName = options.authUserName;
|
|
208
|
-
await setConfig(config);
|
|
209
|
-
}
|
|
210
|
-
/**
|
|
211
|
-
* Auth-local cousin of `setConfig` that deletes the file when the resulting
|
|
212
|
-
* config has no own keys. The public `setConfig` always serializes (even
|
|
213
|
-
* `{}`) — this wrapper exists for the auth flows that strip the legacy
|
|
214
|
-
* plaintext token and want to leave nothing behind.
|
|
215
|
-
*/
|
|
216
|
-
async function writeConfig(config) {
|
|
217
|
-
if (Object.keys(config).length === 0) {
|
|
218
|
-
try {
|
|
219
|
-
await unlink(getConfigPath());
|
|
220
|
-
}
|
|
221
|
-
catch (error) {
|
|
222
|
-
if (!isMissingFileError(error)) {
|
|
223
|
-
throw error;
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
return;
|
|
227
|
-
}
|
|
228
|
-
await setConfig(config);
|
|
229
|
-
}
|
|
230
|
-
async function cleanupAuthFallbackState(config, warningPrefix) {
|
|
231
|
-
try {
|
|
232
|
-
await writeConfig(withoutAuthFallbackState(config));
|
|
233
|
-
return undefined;
|
|
234
|
-
}
|
|
235
|
-
catch (error) {
|
|
236
|
-
return buildConfigCleanupWarning(warningPrefix, error);
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
function getConfigToken(config) {
|
|
240
|
-
return typeof config.token === 'string' && config.token.trim() ? config.token.trim() : null;
|
|
241
|
-
}
|
|
242
|
-
function withoutAuthFallbackState(config) {
|
|
243
|
-
const { token: _token, pendingSecureStoreClear: _pending, ...rest } = config;
|
|
244
|
-
return rest;
|
|
245
|
-
}
|
|
246
|
-
function withPendingSecureStoreClear(config) {
|
|
247
|
-
return { ...withoutAuthFallbackState(config), pendingSecureStoreClear: true };
|
|
248
|
-
}
|
|
249
|
-
function buildFallbackWarning(action) {
|
|
250
|
-
return `${SECURE_STORE_DESCRIPTION} unavailable; ${action} ${getConfigPath()}`;
|
|
251
|
-
}
|
|
252
|
-
function buildConfigCleanupWarning(prefix, error) {
|
|
253
|
-
const detail = error instanceof Error && error.message ? ` (${error.message})` : '';
|
|
254
|
-
return `${prefix} but could not remove legacy plaintext token from ${getConfigPath()}${detail}`;
|
|
255
|
-
}
|
|
256
|
-
function isMissingFileError(error) {
|
|
257
|
-
return error instanceof Error && 'code' in error && error.code === 'ENOENT';
|
|
258
|
-
}
|
|
259
|
-
function warn(message) {
|
|
260
|
-
console.error(`Warning: ${message}`);
|
|
66
|
+
function toAuthUserId(id) {
|
|
67
|
+
const num = Number(id);
|
|
68
|
+
return Number.isFinite(num) && num > 0 ? num : undefined;
|
|
261
69
|
}
|
|
262
70
|
//# sourceMappingURL=auth.js.map
|
package/dist/lib/auth.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/lib/auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/lib/auth.ts"],"names":[],"mappings":"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"}
|
package/dist/lib/config.d.ts
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Current on-disk schema version. Bumped when the persisted layout requires
|
|
3
|
+
* a one-time migration. One-way gate — no rollback.
|
|
4
|
+
*/
|
|
5
|
+
export declare const CONFIG_VERSION: 2;
|
|
1
6
|
/**
|
|
2
7
|
* Resolve the canonical config path lazily. Computing on each call (instead of
|
|
3
8
|
* caching at module load) keeps the path responsive to vitest's `vi.doMock`
|
|
@@ -11,14 +16,29 @@ export declare const UPDATE_CHANNELS: ReadonlySet<UpdateChannel>;
|
|
|
11
16
|
export interface UserSettings {
|
|
12
17
|
unarchiveNewThreads?: boolean;
|
|
13
18
|
}
|
|
19
|
+
/**
|
|
20
|
+
* One row of the `users[]` array. `id` is the stringified numeric Twist user
|
|
21
|
+
* id. `token` is a plaintext fallback persisted only when the keyring is
|
|
22
|
+
* unavailable at write time.
|
|
23
|
+
*/
|
|
24
|
+
export type StoredUser = {
|
|
25
|
+
id: string;
|
|
26
|
+
name: string;
|
|
27
|
+
authMode?: AuthMode;
|
|
28
|
+
authScope?: string;
|
|
29
|
+
token?: string;
|
|
30
|
+
};
|
|
14
31
|
export interface Config {
|
|
32
|
+
config_version?: number;
|
|
33
|
+
users?: StoredUser[];
|
|
34
|
+
defaultUserId?: string;
|
|
15
35
|
token?: string;
|
|
16
36
|
pendingSecureStoreClear?: boolean;
|
|
17
|
-
currentWorkspace?: number;
|
|
18
37
|
authMode?: AuthMode;
|
|
19
38
|
authScope?: string;
|
|
20
39
|
authUserId?: number;
|
|
21
40
|
authUserName?: string;
|
|
41
|
+
currentWorkspace?: number;
|
|
22
42
|
updateChannel?: UpdateChannel;
|
|
23
43
|
userSettings?: UserSettings;
|
|
24
44
|
}
|
package/dist/lib/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAWA;;;;;GAKG;AACH,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AAED,MAAM,MAAM,QAAQ,GAAG,WAAW,GAAG,YAAY,GAAG,SAAS,CAAA;AAC7D,MAAM,MAAM,aAAa,GAAG,QAAQ,GAAG,aAAa,CAAA;
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAWA;;;GAGG;AACH,eAAO,MAAM,cAAc,EAAG,CAAU,CAAA;AAExC;;;;;GAKG;AACH,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AAED,MAAM,MAAM,QAAQ,GAAG,WAAW,GAAG,YAAY,GAAG,SAAS,CAAA;AAC7D,MAAM,MAAM,aAAa,GAAG,QAAQ,GAAG,aAAa,CAAA;AA+BpD,eAAO,MAAM,eAAe,EAAE,WAAW,CAAC,aAAa,CAAsC,CAAA;AAE7F,MAAM,WAAW,YAAY;IACzB,mBAAmB,CAAC,EAAE,OAAO,CAAA;CAChC;AAED;;;;GAIG;AACH,MAAM,MAAM,UAAU,GAAG;IACrB,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,CAAC,EAAE,QAAQ,CAAA;IACnB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,KAAK,CAAC,EAAE,MAAM,CAAA;CACjB,CAAA;AAED,MAAM,WAAW,MAAM;IACnB,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,KAAK,CAAC,EAAE,UAAU,EAAE,CAAA;IACpB,aAAa,CAAC,EAAE,MAAM,CAAA;IAGtB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,uBAAuB,CAAC,EAAE,OAAO,CAAA;IACjC,QAAQ,CAAC,EAAE,QAAQ,CAAA;IACnB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,YAAY,CAAC,EAAE,MAAM,CAAA;IAErB,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,aAAa,CAAC,EAAE,aAAa,CAAA;IAC7B,YAAY,CAAC,EAAE,YAAY,CAAA;CAC9B;AAuCD;;;;;GAKG;AACH,wBAAsB,SAAS,IAAI,OAAO,CAAC,MAAM,CAAC,CAGjD;AAED,MAAM,MAAM,gBAAgB,GAAG;IAAE,KAAK,EAAE,SAAS,CAAA;CAAE,GAAG;IAAE,KAAK,EAAE,SAAS,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAA;AAE1F;;;;GAIG;AACH,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,gBAAgB,CAAC,CAkClE;AAED,mFAAmF;AACnF,wBAAsB,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE7D;AAED;;;;;GAKG;AACH,wBAAsB,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAE1E;AAED,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,EAAE,CAsIjF"}
|
package/dist/lib/config.js
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import { getConfigPath as getConfigPathCore, readConfig as readConfigCore, readConfigStrict as readConfigStrictCore, updateConfig as updateConfigCore, writeConfig as writeConfigCore, } from '@doist/cli-core';
|
|
2
2
|
import { CliError } from './errors.js';
|
|
3
3
|
const APP_NAME = 'twist-cli';
|
|
4
|
+
/**
|
|
5
|
+
* Current on-disk schema version. Bumped when the persisted layout requires
|
|
6
|
+
* a one-time migration. One-way gate — no rollback.
|
|
7
|
+
*/
|
|
8
|
+
export const CONFIG_VERSION = 2;
|
|
4
9
|
/**
|
|
5
10
|
* Resolve the canonical config path lazily. Computing on each call (instead of
|
|
6
11
|
* caching at module load) keeps the path responsive to vitest's `vi.doMock`
|
|
@@ -19,11 +24,20 @@ const KNOWN_CONFIG_KEYS = new Set([
|
|
|
19
24
|
'authUserId',
|
|
20
25
|
'authUserName',
|
|
21
26
|
'updateChannel',
|
|
22
|
-
// Snake_case alias
|
|
23
|
-
//
|
|
24
|
-
// see `fromDiskShape` / `toDiskShape` for the persistence-seam translation.
|
|
27
|
+
// Snake_case alias on disk for cli-core's update command; the in-memory
|
|
28
|
+
// `Config` exposes only `updateChannel` (see `fromDiskShape`/`toDiskShape`).
|
|
25
29
|
'update_channel',
|
|
26
30
|
'userSettings',
|
|
31
|
+
'config_version',
|
|
32
|
+
'users',
|
|
33
|
+
'defaultUserId',
|
|
34
|
+
]);
|
|
35
|
+
const KNOWN_STORED_USER_KEYS = new Set([
|
|
36
|
+
'id',
|
|
37
|
+
'name',
|
|
38
|
+
'authMode',
|
|
39
|
+
'authScope',
|
|
40
|
+
'token',
|
|
27
41
|
]);
|
|
28
42
|
const KNOWN_USER_SETTINGS_KEYS = new Set(['unarchiveNewThreads']);
|
|
29
43
|
const AUTH_MODES = new Set(['read-only', 'read-write', 'unknown']);
|
|
@@ -151,6 +165,51 @@ export function validateConfigForDoctor(config) {
|
|
|
151
165
|
!UPDATE_CHANNELS.has(config.update_channel))) {
|
|
152
166
|
issues.push('update_channel must be one of: stable, pre-release');
|
|
153
167
|
}
|
|
168
|
+
if (config.config_version !== undefined &&
|
|
169
|
+
(typeof config.config_version !== 'number' || !Number.isInteger(config.config_version))) {
|
|
170
|
+
issues.push('config_version must be an integer');
|
|
171
|
+
}
|
|
172
|
+
if (config.defaultUserId !== undefined && typeof config.defaultUserId !== 'string') {
|
|
173
|
+
issues.push('defaultUserId must be a string');
|
|
174
|
+
}
|
|
175
|
+
if (config.users !== undefined) {
|
|
176
|
+
if (!Array.isArray(config.users)) {
|
|
177
|
+
issues.push('users must be an array');
|
|
178
|
+
}
|
|
179
|
+
else {
|
|
180
|
+
for (let i = 0; i < config.users.length; i++) {
|
|
181
|
+
const user = config.users[i];
|
|
182
|
+
if (user === null || typeof user !== 'object' || Array.isArray(user)) {
|
|
183
|
+
issues.push(`users[${i}] must be an object`);
|
|
184
|
+
continue;
|
|
185
|
+
}
|
|
186
|
+
const userRecord = user;
|
|
187
|
+
for (const key of Object.keys(userRecord)) {
|
|
188
|
+
if (!KNOWN_STORED_USER_KEYS.has(key)) {
|
|
189
|
+
issues.push(`users[${i}] contains unrecognized key "${key}"`);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
if (typeof userRecord.id !== 'string') {
|
|
193
|
+
issues.push(`users[${i}].id must be a string`);
|
|
194
|
+
}
|
|
195
|
+
if (typeof userRecord.name !== 'string') {
|
|
196
|
+
issues.push(`users[${i}].name must be a string`);
|
|
197
|
+
}
|
|
198
|
+
if (userRecord.authMode !== undefined &&
|
|
199
|
+
(typeof userRecord.authMode !== 'string' ||
|
|
200
|
+
!AUTH_MODES.has(userRecord.authMode))) {
|
|
201
|
+
issues.push(`users[${i}].authMode must be one of: read-only, read-write, unknown`);
|
|
202
|
+
}
|
|
203
|
+
if (userRecord.authScope !== undefined &&
|
|
204
|
+
typeof userRecord.authScope !== 'string') {
|
|
205
|
+
issues.push(`users[${i}].authScope must be a string`);
|
|
206
|
+
}
|
|
207
|
+
if (userRecord.token !== undefined && typeof userRecord.token !== 'string') {
|
|
208
|
+
issues.push(`users[${i}].token must be a string`);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
154
213
|
if (config.userSettings !== undefined) {
|
|
155
214
|
const userSettings = config.userSettings;
|
|
156
215
|
if (userSettings === null ||
|
package/dist/lib/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,aAAa,IAAI,iBAAiB,EAClC,UAAU,IAAI,cAAc,EAC5B,gBAAgB,IAAI,oBAAoB,EACxC,YAAY,IAAI,gBAAgB,EAChC,WAAW,IAAI,eAAe,GACjC,MAAM,iBAAiB,CAAA;AACxB,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AAEtC,MAAM,QAAQ,GAAG,WAAW,CAAA;AAE5B;;;;;GAKG;AACH,MAAM,UAAU,aAAa;IACzB,OAAO,iBAAiB,CAAC,QAAQ,CAAC,CAAA;AACtC,CAAC;AAKD,MAAM,iBAAiB,GAAwB,IAAI,GAAG,CAAC;IACnD,OAAO;IACP,yBAAyB;IACzB,kBAAkB;IAClB,UAAU;IACV,WAAW;IACX,YAAY;IACZ,cAAc;IACd,eAAe;IACf,
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"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"}
|
package/dist/lib/errors.d.ts
CHANGED
|
@@ -6,7 +6,7 @@ export type { ErrorType } from '@doist/cli-core';
|
|
|
6
6
|
* This union provides intellisense suggestions while still accepting any string,
|
|
7
7
|
* allowing dynamic codes and future additions.
|
|
8
8
|
*/
|
|
9
|
-
export type ErrorCode = 'AUTH_FAILED' | 'INSUFFICIENT_SCOPE' | 'INVALID_TOKEN' | 'NO_TOKEN' | 'READ_ONLY' | 'CONFLICTING_OPTIONS' | 'INVALID_CURSOR' | 'INVALID_DATE' | 'INVALID_ID' | 'INVALID_MINUTES' | 'INVALID_REF' | 'INVALID_SCOPE' | 'INVALID_STATE' | 'INVALID_TYPE' | 'INVALID_URL' | 'INVALID_VALUE' | 'MISSING_CONTENT' | 'MISSING_YES_FLAG' | 'UNKNOWN_KEY' | 'INVALID_NAME' | 'MISSING_USERS' | 'ACCOUNT_NOT_FOUND' | 'CHANNEL_NOT_FOUND' | 'GROUP_NOT_FOUND' | 'NOT_FOUND' | 'USER_NOT_FOUND' | 'WORKSPACE_NOT_FOUND' | 'AMBIGUOUS_CHANNEL' | 'AMBIGUOUS_GROUP' | 'AMBIGUOUS_USER' | 'AMBIGUOUS_WORKSPACE' | 'ALREADY_INSTALLED' | 'BATCH_FAILED' | 'FILE_READ_ERROR' | 'NOT_CREATOR' | 'NOT_INSTALLED' | 'UNKNOWN_AGENT' | 'API_ERROR' | 'INTERNAL_ERROR' | 'CONFIG_READ_FAILED' | 'CONFIG_INVALID_JSON' | 'CONFIG_INVALID_SHAPE' | (string & {});
|
|
9
|
+
export type ErrorCode = 'AUTH_FAILED' | 'AUTH_MIGRATION_PENDING' | 'INSUFFICIENT_SCOPE' | 'INVALID_TOKEN' | 'NO_TOKEN' | 'READ_ONLY' | 'CONFLICTING_OPTIONS' | 'INVALID_CURSOR' | 'INVALID_DATE' | 'INVALID_ID' | 'INVALID_MINUTES' | 'INVALID_REF' | 'INVALID_SCOPE' | 'INVALID_STATE' | 'INVALID_TYPE' | 'INVALID_URL' | 'INVALID_VALUE' | 'MISSING_CONTENT' | 'MISSING_YES_FLAG' | 'UNKNOWN_KEY' | 'INVALID_NAME' | 'MISSING_USERS' | 'ACCOUNT_NOT_FOUND' | 'CHANNEL_NOT_FOUND' | 'GROUP_NOT_FOUND' | 'NOT_FOUND' | 'USER_NOT_FOUND' | 'WORKSPACE_NOT_FOUND' | 'AMBIGUOUS_CHANNEL' | 'AMBIGUOUS_GROUP' | 'AMBIGUOUS_USER' | 'AMBIGUOUS_WORKSPACE' | 'ALREADY_INSTALLED' | 'BATCH_FAILED' | 'FILE_READ_ERROR' | 'NOT_CREATOR' | 'NOT_INSTALLED' | 'UNKNOWN_AGENT' | 'API_ERROR' | 'INTERNAL_ERROR' | 'CONFIG_READ_FAILED' | 'CONFIG_INVALID_JSON' | 'CONFIG_INVALID_SHAPE' | (string & {});
|
|
10
10
|
/**
|
|
11
11
|
* Check whether an error is a Twist API 403 "Insufficient scope" response.
|
|
12
12
|
* Works with any error shaped like TwistRequestError (httpStatusCode + responseData).
|
package/dist/lib/errors.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/lib/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,IAAI,YAAY,EAAE,KAAK,YAAY,EAAE,KAAK,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAE7F,OAAO,EAAE,YAAY,EAAE,CAAA;AACvB,YAAY,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAEhD;;;;GAIG;AACH,MAAM,MAAM,SAAS,GAEf,aAAa,GACb,oBAAoB,GACpB,eAAe,GACf,UAAU,GACV,WAAW,GAEX,qBAAqB,GACrB,gBAAgB,GAChB,cAAc,GACd,YAAY,GACZ,iBAAiB,GACjB,aAAa,GACb,eAAe,GACf,eAAe,GACf,cAAc,GACd,aAAa,GACb,eAAe,GACf,iBAAiB,GACjB,kBAAkB,GAClB,aAAa,GACb,cAAc,GACd,eAAe,GAEf,mBAAmB,GACnB,mBAAmB,GACnB,iBAAiB,GACjB,WAAW,GACX,gBAAgB,GAChB,qBAAqB,GAErB,mBAAmB,GACnB,iBAAiB,GACjB,gBAAgB,GAChB,qBAAqB,GAErB,mBAAmB,GACnB,cAAc,GACd,iBAAiB,GACjB,aAAa,GACb,eAAe,GACf,eAAe,GAEf,WAAW,GACX,gBAAgB,GAEhB,oBAAoB,GACpB,qBAAqB,GACrB,sBAAsB,GAEtB,CAAC,MAAM,GAAG,EAAE,CAAC,CAAA;AAEnB;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAkB3D;AAED;;;;;;;;;GASG;AACH,qBAAa,QAAS,SAAQ,YAAY,CAAC,SAAS,CAAC;gBAE7C,IAAI,EAAE,SAAS,GAAG,YAAY,EAC9B,OAAO,EAAE,MAAM,EACf,KAAK,CAAC,EAAE,MAAM,EAAE,EAChB,IAAI,GAAE,SAAmB;CAIhC"}
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/lib/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,IAAI,YAAY,EAAE,KAAK,YAAY,EAAE,KAAK,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAE7F,OAAO,EAAE,YAAY,EAAE,CAAA;AACvB,YAAY,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAEhD;;;;GAIG;AACH,MAAM,MAAM,SAAS,GAEf,aAAa,GACb,wBAAwB,GACxB,oBAAoB,GACpB,eAAe,GACf,UAAU,GACV,WAAW,GAEX,qBAAqB,GACrB,gBAAgB,GAChB,cAAc,GACd,YAAY,GACZ,iBAAiB,GACjB,aAAa,GACb,eAAe,GACf,eAAe,GACf,cAAc,GACd,aAAa,GACb,eAAe,GACf,iBAAiB,GACjB,kBAAkB,GAClB,aAAa,GACb,cAAc,GACd,eAAe,GAEf,mBAAmB,GACnB,mBAAmB,GACnB,iBAAiB,GACjB,WAAW,GACX,gBAAgB,GAChB,qBAAqB,GAErB,mBAAmB,GACnB,iBAAiB,GACjB,gBAAgB,GAChB,qBAAqB,GAErB,mBAAmB,GACnB,cAAc,GACd,iBAAiB,GACjB,aAAa,GACb,eAAe,GACf,eAAe,GAEf,WAAW,GACX,gBAAgB,GAEhB,oBAAoB,GACpB,qBAAqB,GACrB,sBAAsB,GAEtB,CAAC,MAAM,GAAG,EAAE,CAAC,CAAA;AAEnB;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAkB3D;AAED;;;;;;;;;GASG;AACH,qBAAa,QAAS,SAAQ,YAAY,CAAC,SAAS,CAAC;gBAE7C,IAAI,EAAE,SAAS,GAAG,YAAY,EAC9B,OAAO,EAAE,MAAM,EACf,KAAK,CAAC,EAAE,MAAM,EAAE,EAChB,IAAI,GAAE,SAAmB;CAIhC"}
|
package/dist/lib/errors.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/lib/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,IAAI,YAAY,EAAqC,MAAM,iBAAiB,CAAA;AAE7F,OAAO,EAAE,YAAY,EAAE,CAAA;
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/lib/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,IAAI,YAAY,EAAqC,MAAM,iBAAiB,CAAA;AAE7F,OAAO,EAAE,YAAY,EAAE,CAAA;AA8DvB;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CAAC,KAAc;IAC9C,IACI,OAAO,KAAK,KAAK,QAAQ;QACzB,KAAK,KAAK,IAAI;QACd,CAAC,CAAC,gBAAgB,IAAI,KAAK,CAAC;QAC5B,CAAC,CAAC,cAAc,IAAI,KAAK,CAAC,EAC5B,CAAC;QACC,OAAO,KAAK,CAAA;IAChB,CAAC;IACD,MAAM,EAAE,cAAc,EAAE,YAAY,EAAE,GAAG,KAGxC,CAAA;IACD,OAAO,CACH,cAAc,KAAK,GAAG;QACtB,OAAO,YAAY,EAAE,YAAY,KAAK,QAAQ;QAC9C,YAAY,CAAC,YAAY,CAAC,QAAQ,CAAC,oBAAoB,CAAC,CAC3D,CAAA;AACL,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,OAAO,QAAS,SAAQ,YAAuB;IACjD,YACI,IAA8B,EAC9B,OAAe,EACf,KAAgB,EAChB,OAAkB,OAAO;QAEzB,KAAK,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAA;IACzC,CAAC;CACJ"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type MigrateAuthResult } from '@doist/cli-core/auth';
|
|
2
|
+
import type { TwistAccount } from './auth-provider.js';
|
|
3
|
+
/**
|
|
4
|
+
* One-time migration of v1 auth state into the v2 `users[]` shape. Called
|
|
5
|
+
* by postinstall and by the lazy hook in `createTwistTokenStore`. Idempotent
|
|
6
|
+
* via the `config_version` marker.
|
|
7
|
+
*
|
|
8
|
+
* Uses raw `TwistApi` rather than `createWrappedTwistClient` to keep this
|
|
9
|
+
* module out of the runtime auth/token-store import graph.
|
|
10
|
+
*/
|
|
11
|
+
export declare function runMigrateLegacyAuth(options?: {
|
|
12
|
+
silent: boolean;
|
|
13
|
+
}): Promise<MigrateAuthResult<TwistAccount>>;
|
|
14
|
+
//# sourceMappingURL=migrate-auth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"migrate-auth.d.ts","sourceRoot":"","sources":["../../src/lib/migrate-auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,iBAAiB,EAAqB,MAAM,sBAAsB,CAAA;AAGhF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAYtD;;;;;;;GAOG;AACH,wBAAsB,oBAAoB,CACtC,OAAO,GAAE;IAAE,MAAM,EAAE,OAAO,CAAA;CAAqB,GAChD,OAAO,CAAC,iBAAiB,CAAC,YAAY,CAAC,CAAC,CAuC1C"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { migrateLegacyAuth } from '@doist/cli-core/auth';
|
|
2
|
+
import { TwistApi } from '@doist/twist-sdk';
|
|
3
|
+
import { LEGACY_KEYRING_ACCOUNT, SECURE_STORE_SERVICE } from './auth-constants.js';
|
|
4
|
+
import { getConfig, updateConfig } from './config.js';
|
|
5
|
+
import { toTwistAccount } from './twist-account.js';
|
|
6
|
+
import { createTwistUserRecordStore } from './user-records.js';
|
|
7
|
+
/**
|
|
8
|
+
* Pinned to this migration's target schema. Decoupled from the exported
|
|
9
|
+
* `CONFIG_VERSION` so a future bump doesn't make this helper re-run for
|
|
10
|
+
* users who are already on v2 or beyond.
|
|
11
|
+
*/
|
|
12
|
+
const V2_SCHEMA_VERSION = 2;
|
|
13
|
+
/**
|
|
14
|
+
* One-time migration of v1 auth state into the v2 `users[]` shape. Called
|
|
15
|
+
* by postinstall and by the lazy hook in `createTwistTokenStore`. Idempotent
|
|
16
|
+
* via the `config_version` marker.
|
|
17
|
+
*
|
|
18
|
+
* Uses raw `TwistApi` rather than `createWrappedTwistClient` to keep this
|
|
19
|
+
* module out of the runtime auth/token-store import graph.
|
|
20
|
+
*/
|
|
21
|
+
export async function runMigrateLegacyAuth(options = { silent: true }) {
|
|
22
|
+
return migrateLegacyAuth({
|
|
23
|
+
serviceName: SECURE_STORE_SERVICE,
|
|
24
|
+
legacyAccount: LEGACY_KEYRING_ACCOUNT,
|
|
25
|
+
userRecords: createTwistUserRecordStore(),
|
|
26
|
+
hasMigrated: async () => {
|
|
27
|
+
const config = await getConfig();
|
|
28
|
+
return (config.config_version ?? 0) >= V2_SCHEMA_VERSION;
|
|
29
|
+
},
|
|
30
|
+
markMigrated: async () => {
|
|
31
|
+
await updateConfig({ config_version: V2_SCHEMA_VERSION });
|
|
32
|
+
},
|
|
33
|
+
loadLegacyPlaintextToken: async () => {
|
|
34
|
+
const config = await getConfig();
|
|
35
|
+
return config.token?.trim() || null;
|
|
36
|
+
},
|
|
37
|
+
identifyAccount: async (token) => {
|
|
38
|
+
const [user, config] = await Promise.all([
|
|
39
|
+
new TwistApi(token).users.getSessionUser(),
|
|
40
|
+
getConfig(),
|
|
41
|
+
]);
|
|
42
|
+
return toTwistAccount(user, {
|
|
43
|
+
authMode: config.authMode,
|
|
44
|
+
authScope: config.authScope,
|
|
45
|
+
});
|
|
46
|
+
},
|
|
47
|
+
cleanupLegacyConfig: async () => {
|
|
48
|
+
await updateConfig({
|
|
49
|
+
token: undefined,
|
|
50
|
+
authMode: undefined,
|
|
51
|
+
authScope: undefined,
|
|
52
|
+
authUserId: undefined,
|
|
53
|
+
authUserName: undefined,
|
|
54
|
+
pendingSecureStoreClear: undefined,
|
|
55
|
+
});
|
|
56
|
+
},
|
|
57
|
+
silent: options.silent,
|
|
58
|
+
logPrefix: 'twist-cli',
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=migrate-auth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"migrate-auth.js","sourceRoot":"","sources":["../../src/lib/migrate-auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAA0B,iBAAiB,EAAE,MAAM,sBAAsB,CAAA;AAChF,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAA;AAC3C,OAAO,EAAE,sBAAsB,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAA;AAElF,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AACrD,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;AACnD,OAAO,EAAE,0BAA0B,EAAE,MAAM,mBAAmB,CAAA;AAE9D;;;;GAIG;AACH,MAAM,iBAAiB,GAAG,CAAC,CAAA;AAE3B;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACtC,UAA+B,EAAE,MAAM,EAAE,IAAI,EAAE;IAE/C,OAAO,iBAAiB,CAAe;QACnC,WAAW,EAAE,oBAAoB;QACjC,aAAa,EAAE,sBAAsB;QACrC,WAAW,EAAE,0BAA0B,EAAE;QACzC,WAAW,EAAE,KAAK,IAAI,EAAE;YACpB,MAAM,MAAM,GAAG,MAAM,SAAS,EAAE,CAAA;YAChC,OAAO,CAAC,MAAM,CAAC,cAAc,IAAI,CAAC,CAAC,IAAI,iBAAiB,CAAA;QAC5D,CAAC;QACD,YAAY,EAAE,KAAK,IAAI,EAAE;YACrB,MAAM,YAAY,CAAC,EAAE,cAAc,EAAE,iBAAiB,EAAE,CAAC,CAAA;QAC7D,CAAC;QACD,wBAAwB,EAAE,KAAK,IAAI,EAAE;YACjC,MAAM,MAAM,GAAG,MAAM,SAAS,EAAE,CAAA;YAChC,OAAO,MAAM,CAAC,KAAK,EAAE,IAAI,EAAE,IAAI,IAAI,CAAA;QACvC,CAAC;QACD,eAAe,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE;YAC7B,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;gBACrC,IAAI,QAAQ,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,cAAc,EAAE;gBAC1C,SAAS,EAAE;aACd,CAAC,CAAA;YACF,OAAO,cAAc,CAAC,IAAI,EAAE;gBACxB,QAAQ,EAAE,MAAM,CAAC,QAAQ;gBACzB,SAAS,EAAE,MAAM,CAAC,SAAS;aAC9B,CAAC,CAAA;QACN,CAAC;QACD,mBAAmB,EAAE,KAAK,IAAI,EAAE;YAC5B,MAAM,YAAY,CAAC;gBACf,KAAK,EAAE,SAAS;gBAChB,QAAQ,EAAE,SAAS;gBACnB,SAAS,EAAE,SAAS;gBACpB,UAAU,EAAE,SAAS;gBACrB,YAAY,EAAE,SAAS;gBACvB,uBAAuB,EAAE,SAAS;aACrC,CAAC,CAAA;QACN,CAAC;QACD,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,SAAS,EAAE,WAAW;KACzB,CAAC,CAAA;AACN,CAAC"}
|