neozip-cli 0.90.0 → 0.95.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/AGENTS.md +93 -0
- package/CHANGELOG.md +58 -1
- package/DOCUMENTATION.md +22 -30
- package/README.md +104 -42
- package/dist/src/account/account-state.js +95 -0
- package/dist/src/account/format-account-status.js +62 -0
- package/dist/src/account/identity-provision.js +79 -0
- package/dist/src/account/identity-wrap.js +106 -0
- package/dist/src/account/profile-crypto.js +85 -0
- package/dist/src/account/profile-store.js +129 -0
- package/dist/src/account/require-account.js +32 -0
- package/dist/src/account/types.js +3 -0
- package/dist/src/account/wallet-evm.js +46 -0
- package/dist/src/account/wallet-setup.js +33 -0
- package/dist/src/archive/crypto-self.js +117 -0
- package/dist/src/archive/identity-key.js +217 -0
- package/dist/src/archive/recipient-lookup.js +61 -0
- package/dist/src/cli/output.js +100 -0
- package/dist/src/cli/params.js +122 -0
- package/dist/src/cli/schema.js +186 -0
- package/dist/src/cli/validate.js +119 -0
- package/dist/src/commands/mintTimestampProof.js +26 -14
- package/dist/src/config/ConfigSetup.js +82 -423
- package/dist/src/connect/command.js +364 -0
- package/dist/src/connection/bootstrap.js +50 -0
- package/dist/src/connection/cli-guidance.js +101 -0
- package/dist/src/connection/cli-prefs.js +180 -0
- package/dist/src/connection/cli-settings.js +140 -0
- package/dist/src/connection/cli-types.js +14 -0
- package/dist/src/connection/coordinator.js +83 -0
- package/dist/src/connection/credentials.js +33 -0
- package/dist/src/connection/crypto.js +96 -0
- package/dist/src/connection/dump.js +117 -0
- package/dist/src/connection/funding.js +187 -0
- package/dist/src/connection/incomplete-setup.js +89 -0
- package/dist/src/connection/interactive.js +871 -0
- package/dist/src/connection/legacy-profile-reader.js +87 -0
- package/dist/src/connection/magic-link.js +142 -0
- package/dist/src/connection/migrate.js +115 -0
- package/dist/src/connection/onboarding.js +616 -0
- package/dist/src/connection/origin.js +69 -0
- package/dist/src/connection/phase.js +101 -0
- package/dist/src/connection/phone.js +26 -0
- package/dist/src/connection/promote-active.js +56 -0
- package/dist/src/connection/reset.js +56 -0
- package/dist/src/connection/status-report.js +52 -0
- package/dist/src/connection/store.js +406 -0
- package/dist/src/connection/token-auth.js +44 -0
- package/dist/src/connection/types.js +3 -0
- package/dist/src/connection/wallet-json-migration.js +155 -0
- package/dist/src/connection/wallet-login.js +65 -0
- package/dist/src/connection/wallet-setup.js +83 -0
- package/dist/src/constants/wallet-identity.js +14 -0
- package/dist/src/exit-codes.js +54 -10
- package/dist/src/neolist.js +93 -9
- package/dist/src/neounzip.js +217 -59
- package/dist/src/neozip/blockchain.js +18 -18
- package/dist/src/neozip/createZip.js +114 -91
- package/dist/src/neozip/upgradeZip.js +14 -11
- package/dist/src/neozip.js +252 -75
- package/dist/src/skills/command.js +256 -0
- package/dist/src/skills/locate.js +99 -0
- package/dist/src/util/mask.js +34 -0
- package/dist/src/util/token-service-fetch.js +26 -0
- package/env.example +18 -85
- package/package.json +89 -82
- package/skills/neozip-connect/SKILL.md +95 -0
- package/skills/neozip-create/SKILL.md +57 -0
- package/skills/neozip-extract/SKILL.md +58 -0
- package/skills/neozip-legacy/SKILL.md +48 -0
- package/skills/neozip-list/SKILL.md +56 -0
- package/skills/neozip-shared/SKILL.md +60 -0
- package/dist/src/commands/verifyEmail.js +0 -146
- package/dist/src/config/ConfigStore.js +0 -406
|
@@ -0,0 +1,616 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.connectStatus = connectStatus;
|
|
4
|
+
exports.connectRegister = connectRegister;
|
|
5
|
+
exports.connectVerify = connectVerify;
|
|
6
|
+
exports.connectRefresh = connectRefresh;
|
|
7
|
+
exports.connectSelect = connectSelect;
|
|
8
|
+
exports.connectRename = connectRename;
|
|
9
|
+
exports.connectPhoneRequest = connectPhoneRequest;
|
|
10
|
+
exports.connectPhoneVerify = connectPhoneVerify;
|
|
11
|
+
exports.connectWalletCreate = connectWalletCreate;
|
|
12
|
+
exports.connectWalletImportMnemonic = connectWalletImportMnemonic;
|
|
13
|
+
exports.connectWalletImportKey = connectWalletImportKey;
|
|
14
|
+
exports.connectFinish = connectFinish;
|
|
15
|
+
exports.connectSetup = connectSetup;
|
|
16
|
+
exports.connectLogout = connectLogout;
|
|
17
|
+
exports.connectDelete = connectDelete;
|
|
18
|
+
exports.connectMigrate = connectMigrate;
|
|
19
|
+
const identity_provision_1 = require("../account/identity-provision");
|
|
20
|
+
const wallet_setup_1 = require("../account/wallet-setup");
|
|
21
|
+
const token_service_1 = require("neozip-blockchain/token-service");
|
|
22
|
+
const wallet_evm_1 = require("../account/wallet-evm");
|
|
23
|
+
const coordinator_1 = require("./coordinator");
|
|
24
|
+
const wallet_setup_2 = require("./wallet-setup");
|
|
25
|
+
const migrate_1 = require("./migrate");
|
|
26
|
+
const magic_link_1 = require("./magic-link");
|
|
27
|
+
const status_report_1 = require("./status-report");
|
|
28
|
+
const phase_1 = require("./phase");
|
|
29
|
+
const origin_1 = require("./origin");
|
|
30
|
+
const wallet_login_1 = require("./wallet-login");
|
|
31
|
+
const phone_1 = require("./phone");
|
|
32
|
+
const store_1 = require("./store");
|
|
33
|
+
function result(phase, extra = {}) {
|
|
34
|
+
const meta = (0, store_1.getActiveConnection)();
|
|
35
|
+
return {
|
|
36
|
+
success: phase === "ready",
|
|
37
|
+
phase,
|
|
38
|
+
connectionId: meta?.id ?? null,
|
|
39
|
+
tokenServiceOrigin: meta?.tokenServiceOrigin ?? (0, origin_1.resolveTokenServiceOrigin)(),
|
|
40
|
+
nextCommand: (0, phase_1.nextConnectCommand)(phase, {
|
|
41
|
+
email: meta?.email,
|
|
42
|
+
phoneE164: meta?.phoneE164,
|
|
43
|
+
}),
|
|
44
|
+
...extra,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
async function connectStatus(options) {
|
|
48
|
+
if (options?.autoMigrate !== false && (0, migrate_1.hasLegacyMcpProfiles)()) {
|
|
49
|
+
(0, migrate_1.migrateFromMcpProfileStore)();
|
|
50
|
+
}
|
|
51
|
+
const origin = (0, origin_1.resolveTokenServiceOrigin)(options?.tokenServiceUrl);
|
|
52
|
+
(0, store_1.ensureActiveConnection)({ tokenServiceUrl: origin });
|
|
53
|
+
const phase = await (0, phase_1.resolveConnectionPhase)(origin);
|
|
54
|
+
const reachable = await (0, coordinator_1.fetchCoordinatorConfigParsed)(origin);
|
|
55
|
+
const reportPhase = reachable === null && phase !== "ready" ? "degraded" : phase;
|
|
56
|
+
const accounts = options?.verbose ? (0, status_report_1.buildAllAccountDetails)() : undefined;
|
|
57
|
+
const active = (0, store_1.getActiveConnection)();
|
|
58
|
+
return {
|
|
59
|
+
...result(reportPhase, {
|
|
60
|
+
message: reportPhase === "degraded"
|
|
61
|
+
? "Token Service unreachable."
|
|
62
|
+
: reportPhase === "ready"
|
|
63
|
+
? "Connection ready."
|
|
64
|
+
: undefined,
|
|
65
|
+
}),
|
|
66
|
+
connectionId: active?.id ?? null,
|
|
67
|
+
tokenServiceOrigin: origin,
|
|
68
|
+
accounts,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
async function connectRegister(input) {
|
|
72
|
+
if ((0, migrate_1.hasLegacyMcpProfiles)())
|
|
73
|
+
(0, migrate_1.migrateFromMcpProfileStore)();
|
|
74
|
+
const origin = (0, origin_1.resolveTokenServiceOrigin)(input.tokenServiceUrl);
|
|
75
|
+
const email = input.email.trim().toLowerCase();
|
|
76
|
+
(0, store_1.ensureActiveConnection)({ label: input.label, tokenServiceUrl: origin });
|
|
77
|
+
const reg = await (0, token_service_1.registerEmailCli)(origin, email);
|
|
78
|
+
if (!reg.success) {
|
|
79
|
+
return result("degraded", {
|
|
80
|
+
success: false,
|
|
81
|
+
message: reg.error ?? "Failed to send verification email.",
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
return result("awaiting_code", {
|
|
85
|
+
success: true,
|
|
86
|
+
message: input.resend
|
|
87
|
+
? `Verification code re-sent to ${email}. Run neozip connect verify with the 6-digit code.`
|
|
88
|
+
: "Verification code sent. Run neozip connect verify with the 6-digit code.",
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
async function finalizeEmailVerification(origin, connId, accessToken, email, expiresAt) {
|
|
92
|
+
(0, store_1.saveAccessToken)(connId, accessToken, email, expiresAt);
|
|
93
|
+
(0, store_1.applyActiveConnectionToEnv)();
|
|
94
|
+
const updated = (0, store_1.getActiveConnection)();
|
|
95
|
+
if (await (0, phone_1.needsPhoneVerification)(updated, origin)) {
|
|
96
|
+
return result("phone_required", {
|
|
97
|
+
success: true,
|
|
98
|
+
message: "Email verified. Run neozip connect phone request --phone +14155551234, then phone verify with the SMS code.",
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
const phase = (0, phase_1.computeConnectionPhase)();
|
|
102
|
+
return result(phase, {
|
|
103
|
+
success: true,
|
|
104
|
+
message: phase === "ready"
|
|
105
|
+
? "Email verified and connection ready."
|
|
106
|
+
: "Email verified. Configure a Data Wallet, then run neozip connect finish.",
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
async function connectVerify(input) {
|
|
110
|
+
if ((0, migrate_1.hasLegacyMcpProfiles)())
|
|
111
|
+
(0, migrate_1.migrateFromMcpProfileStore)();
|
|
112
|
+
const origin = (0, origin_1.resolveTokenServiceOrigin)(input.tokenServiceUrl);
|
|
113
|
+
const conn = (0, store_1.ensureActiveConnection)({ tokenServiceUrl: origin });
|
|
114
|
+
let email = input.email?.trim().toLowerCase();
|
|
115
|
+
let code = input.code?.trim();
|
|
116
|
+
if (input.magicToken?.trim()) {
|
|
117
|
+
const pair = (0, magic_link_1.extractEmailCodePair)(input.magicToken);
|
|
118
|
+
email = email ?? pair.email;
|
|
119
|
+
code = code ?? pair.code;
|
|
120
|
+
if (!email || !code) {
|
|
121
|
+
const opaque = (0, magic_link_1.normalizeMagicLinkTokenInput)(input.magicToken);
|
|
122
|
+
if (opaque) {
|
|
123
|
+
try {
|
|
124
|
+
const exchanged = await (0, token_service_1.exchangeMagicLinkToken)(origin, opaque);
|
|
125
|
+
return finalizeEmailVerification(origin, conn.id, exchanged.accessToken, exchanged.email, exchanged.expiresAt);
|
|
126
|
+
}
|
|
127
|
+
catch (err) {
|
|
128
|
+
return result("awaiting_code", {
|
|
129
|
+
success: false,
|
|
130
|
+
message: err instanceof Error ? err.message : String(err),
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
if (!email || !code) {
|
|
137
|
+
return result("awaiting_code", {
|
|
138
|
+
success: false,
|
|
139
|
+
message: "Provide --email and --code, or --magic-token (full link, email=…&code=…, or opaque token).",
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
try {
|
|
143
|
+
const verified = await (0, token_service_1.verifyEmailAndExtractToken)(origin, email, code);
|
|
144
|
+
return finalizeEmailVerification(origin, conn.id, verified.accessToken, verified.email, verified.expiresAt);
|
|
145
|
+
}
|
|
146
|
+
catch (err) {
|
|
147
|
+
return result("awaiting_code", {
|
|
148
|
+
success: false,
|
|
149
|
+
message: err instanceof Error ? err.message : String(err),
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Refresh (renew) the Token Service access token without disturbing the wallet
|
|
155
|
+
* or identity. The Token Service has no silent refresh endpoint, so renewal
|
|
156
|
+
* re-runs the email OTP flow: call once to send a code, then again with --code
|
|
157
|
+
* (or --magic-token). Re-verifying only replaces the access token via
|
|
158
|
+
* saveAccessToken(), so a previously "ready" account stays ready.
|
|
159
|
+
*/
|
|
160
|
+
async function connectRefresh(input) {
|
|
161
|
+
if ((0, migrate_1.hasLegacyMcpProfiles)())
|
|
162
|
+
(0, migrate_1.migrateFromMcpProfileStore)();
|
|
163
|
+
const origin = (0, origin_1.resolveTokenServiceOrigin)(input.tokenServiceUrl);
|
|
164
|
+
const conn = (0, store_1.ensureActiveConnection)({ tokenServiceUrl: origin });
|
|
165
|
+
const email = (input.email ?? conn.email ?? "").trim().toLowerCase();
|
|
166
|
+
const hasVerifier = Boolean(input.code?.trim() || input.magicToken?.trim());
|
|
167
|
+
// Preferred path: silent wallet-signature renewal (no email round-trip). Only
|
|
168
|
+
// attempted when the caller did not supply an explicit code/magic token.
|
|
169
|
+
if (!hasVerifier) {
|
|
170
|
+
const walletTry = await (0, wallet_login_1.refreshAccessTokenViaWallet)({
|
|
171
|
+
tokenServiceUrl: input.tokenServiceUrl,
|
|
172
|
+
});
|
|
173
|
+
if (walletTry.ok) {
|
|
174
|
+
return result((0, phase_1.computeConnectionPhase)(), {
|
|
175
|
+
success: true,
|
|
176
|
+
message: "Access token refreshed via wallet signature. Connection ready.",
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
// Otherwise fall through to the email OTP flow below.
|
|
180
|
+
}
|
|
181
|
+
if (!email && !input.magicToken?.trim()) {
|
|
182
|
+
return result((0, phase_1.computeConnectionPhase)(), {
|
|
183
|
+
success: false,
|
|
184
|
+
message: "No account email to refresh. Run neozip connect to set up an account, or pass --email.",
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
// Step 2: a code (or magic token) is present — verify to mint a fresh token.
|
|
188
|
+
if (hasVerifier) {
|
|
189
|
+
const verified = await connectVerify({
|
|
190
|
+
email: email || undefined,
|
|
191
|
+
code: input.code,
|
|
192
|
+
magicToken: input.magicToken,
|
|
193
|
+
tokenServiceUrl: input.tokenServiceUrl,
|
|
194
|
+
});
|
|
195
|
+
if (!verified.success)
|
|
196
|
+
return verified;
|
|
197
|
+
const phase = (0, phase_1.computeConnectionPhase)();
|
|
198
|
+
return result(phase, {
|
|
199
|
+
success: true,
|
|
200
|
+
message: phase === "ready"
|
|
201
|
+
? "Access token refreshed. Connection ready."
|
|
202
|
+
: verified.message ?? `Access token refreshed (phase: ${phase}).`,
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
// Step 1: no code yet — send a fresh verification code.
|
|
206
|
+
const sent = await connectRegister({
|
|
207
|
+
email,
|
|
208
|
+
tokenServiceUrl: input.tokenServiceUrl,
|
|
209
|
+
resend: true,
|
|
210
|
+
});
|
|
211
|
+
if (!sent.success)
|
|
212
|
+
return sent;
|
|
213
|
+
return result("awaiting_code", {
|
|
214
|
+
success: true,
|
|
215
|
+
message: `Verification code sent to ${email}. Complete the refresh with:\n neozip connect refresh --email ${email} --code <6-digit-code>`,
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
function connectSelect(input) {
|
|
219
|
+
if ((0, migrate_1.hasLegacyMcpProfiles)())
|
|
220
|
+
(0, migrate_1.migrateFromMcpProfileStore)();
|
|
221
|
+
try {
|
|
222
|
+
const meta = (0, store_1.selectConnection)(input.connectionId.trim());
|
|
223
|
+
(0, store_1.applyActiveConnectionToEnv)();
|
|
224
|
+
return result((0, phase_1.computeConnectionPhase)(), {
|
|
225
|
+
success: true,
|
|
226
|
+
message: `Active connection: ${meta.label} (${meta.id})`,
|
|
227
|
+
accounts: [(0, status_report_1.buildAccountDetails)(meta, meta.id)],
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
catch (err) {
|
|
231
|
+
return result((0, phase_1.computeConnectionPhase)(), {
|
|
232
|
+
success: false,
|
|
233
|
+
message: err instanceof Error ? err.message : String(err),
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
function connectRename(input) {
|
|
238
|
+
if ((0, migrate_1.hasLegacyMcpProfiles)())
|
|
239
|
+
(0, migrate_1.migrateFromMcpProfileStore)();
|
|
240
|
+
const id = input.connectionId?.trim() || (0, store_1.getActiveConnection)()?.id;
|
|
241
|
+
if (!id) {
|
|
242
|
+
return result("no_profile", {
|
|
243
|
+
success: false,
|
|
244
|
+
message: "No connection to rename.",
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
const nextLabel = input.label.trim();
|
|
248
|
+
if (!nextLabel) {
|
|
249
|
+
return result((0, phase_1.computeConnectionPhase)(), {
|
|
250
|
+
success: false,
|
|
251
|
+
message: "Label is required.",
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
try {
|
|
255
|
+
const meta = (0, store_1.updateConnection)(id, { label: nextLabel });
|
|
256
|
+
return result((0, phase_1.computeConnectionPhaseForId)(id), {
|
|
257
|
+
success: true,
|
|
258
|
+
message: `Renamed connection to "${meta.label}".`,
|
|
259
|
+
accounts: [(0, status_report_1.buildAccountDetails)(meta, (0, store_1.getActiveConnection)()?.id ?? null)],
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
catch (err) {
|
|
263
|
+
return result((0, phase_1.computeConnectionPhase)(), {
|
|
264
|
+
success: false,
|
|
265
|
+
message: err instanceof Error ? err.message : String(err),
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
async function connectPhoneRequest(input) {
|
|
270
|
+
if ((0, migrate_1.hasLegacyMcpProfiles)())
|
|
271
|
+
(0, migrate_1.migrateFromMcpProfileStore)();
|
|
272
|
+
const origin = (0, origin_1.resolveTokenServiceOrigin)(input.tokenServiceUrl);
|
|
273
|
+
const conn = (0, store_1.ensureActiveConnection)({ tokenServiceUrl: origin });
|
|
274
|
+
const secrets = (0, store_1.readActiveConnectionSecrets)();
|
|
275
|
+
if (!secrets?.accessToken || !conn.emailVerified) {
|
|
276
|
+
return result("email_unverified", {
|
|
277
|
+
success: false,
|
|
278
|
+
message: "Verify email first. Run neozip connect verify.",
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
if ((0, phone_1.isPhoneVerified)(conn)) {
|
|
282
|
+
const phase = (0, phase_1.computeConnectionPhase)();
|
|
283
|
+
return result(phase, {
|
|
284
|
+
success: true,
|
|
285
|
+
message: "Phone already verified.",
|
|
286
|
+
});
|
|
287
|
+
}
|
|
288
|
+
try {
|
|
289
|
+
(0, phone_1.validatePhoneE164)(input.phone);
|
|
290
|
+
}
|
|
291
|
+
catch (err) {
|
|
292
|
+
return result("phone_required", {
|
|
293
|
+
success: false,
|
|
294
|
+
message: err instanceof Error ? err.message : String(err),
|
|
295
|
+
});
|
|
296
|
+
}
|
|
297
|
+
const otp = await (0, token_service_1.requestPhoneOtp)(origin, secrets.accessToken, input.phone);
|
|
298
|
+
if (!otp.success) {
|
|
299
|
+
return result("phone_required", {
|
|
300
|
+
success: false,
|
|
301
|
+
message: otp.error ?? "Failed to send phone verification SMS.",
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
return result("phone_required", {
|
|
305
|
+
success: true,
|
|
306
|
+
message: `SMS code sent to ${input.phone.trim()}. Run neozip connect phone verify --phone ${input.phone.trim()} --code <6-digit-code>.`,
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
async function connectPhoneVerify(input) {
|
|
310
|
+
if ((0, migrate_1.hasLegacyMcpProfiles)())
|
|
311
|
+
(0, migrate_1.migrateFromMcpProfileStore)();
|
|
312
|
+
const origin = (0, origin_1.resolveTokenServiceOrigin)(input.tokenServiceUrl);
|
|
313
|
+
const conn = (0, store_1.ensureActiveConnection)({ tokenServiceUrl: origin });
|
|
314
|
+
const secrets = (0, store_1.readActiveConnectionSecrets)();
|
|
315
|
+
if (!secrets?.accessToken || !conn.emailVerified) {
|
|
316
|
+
return result("email_unverified", {
|
|
317
|
+
success: false,
|
|
318
|
+
message: "Verify email first. Run neozip connect verify.",
|
|
319
|
+
});
|
|
320
|
+
}
|
|
321
|
+
try {
|
|
322
|
+
(0, phone_1.validatePhoneE164)(input.phone);
|
|
323
|
+
}
|
|
324
|
+
catch (err) {
|
|
325
|
+
return result("phone_required", {
|
|
326
|
+
success: false,
|
|
327
|
+
message: err instanceof Error ? err.message : String(err),
|
|
328
|
+
});
|
|
329
|
+
}
|
|
330
|
+
const verified = await (0, token_service_1.verifyPhoneOtp)(origin, secrets.accessToken, input.phone, input.code);
|
|
331
|
+
if (!verified.success) {
|
|
332
|
+
return result("phone_required", {
|
|
333
|
+
success: false,
|
|
334
|
+
message: verified.error ?? "Phone verification failed.",
|
|
335
|
+
});
|
|
336
|
+
}
|
|
337
|
+
(0, store_1.savePhoneVerified)(conn.id, input.phone);
|
|
338
|
+
(0, store_1.applyActiveConnectionToEnv)();
|
|
339
|
+
const phase = (0, phase_1.computeConnectionPhase)();
|
|
340
|
+
return result(phase, {
|
|
341
|
+
success: true,
|
|
342
|
+
message: phase === "ready"
|
|
343
|
+
? "Phone verified and connection ready."
|
|
344
|
+
: "Phone verified. Configure a Data Wallet, then run neozip connect finish.",
|
|
345
|
+
});
|
|
346
|
+
}
|
|
347
|
+
async function connectWalletCreate(input) {
|
|
348
|
+
if ((0, migrate_1.hasLegacyMcpProfiles)())
|
|
349
|
+
(0, migrate_1.migrateFromMcpProfileStore)();
|
|
350
|
+
const origin = (0, origin_1.resolveTokenServiceOrigin)(input.tokenServiceUrl);
|
|
351
|
+
(0, store_1.ensureActiveConnection)({ tokenServiceUrl: origin });
|
|
352
|
+
const { conn, secrets } = (0, wallet_setup_2.activeWalletContext)();
|
|
353
|
+
try {
|
|
354
|
+
(0, wallet_setup_2.requireWalletPreconditions)(conn, secrets);
|
|
355
|
+
await (0, wallet_setup_2.requirePhonePreconditions)(conn, origin);
|
|
356
|
+
}
|
|
357
|
+
catch (err) {
|
|
358
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
359
|
+
const phase = message.includes("Phone") ? "phone_required" : "email_unverified";
|
|
360
|
+
return result(phase, { success: false, message });
|
|
361
|
+
}
|
|
362
|
+
if ((0, wallet_setup_2.walletAlreadyConfigured)(conn, secrets)) {
|
|
363
|
+
const phase = (0, phase_1.computeConnectionPhase)();
|
|
364
|
+
return result(phase, {
|
|
365
|
+
success: true,
|
|
366
|
+
message: `Data Wallet already configured (${conn.evmAddress}). Run neozip connect finish.`,
|
|
367
|
+
});
|
|
368
|
+
}
|
|
369
|
+
if (!input.ackBackup) {
|
|
370
|
+
return result("no_wallet", {
|
|
371
|
+
success: false,
|
|
372
|
+
message: "Creating a wallet requires --ack-backup (recovery phrase is shown once on stderr). " +
|
|
373
|
+
wallet_setup_2.WALLET_SETUP_HINT,
|
|
374
|
+
});
|
|
375
|
+
}
|
|
376
|
+
const evm = (0, wallet_setup_2.createLocalWalletIdentity)();
|
|
377
|
+
console.error(`
|
|
378
|
+
Back up your Data Wallet recovery phrase (shown once):
|
|
379
|
+
Address: ${evm.address}
|
|
380
|
+
|
|
381
|
+
Recovery phrase:
|
|
382
|
+
${evm.mnemonic}
|
|
383
|
+
`);
|
|
384
|
+
(0, wallet_setup_2.saveImportedWallet)(conn.id, evm);
|
|
385
|
+
(0, store_1.applyActiveConnectionToEnv)();
|
|
386
|
+
const phase = (0, phase_1.computeConnectionPhase)();
|
|
387
|
+
return result(phase, {
|
|
388
|
+
success: true,
|
|
389
|
+
message: `Data Wallet created (${evm.address}). Run neozip connect finish.`,
|
|
390
|
+
});
|
|
391
|
+
}
|
|
392
|
+
async function connectWalletImportMnemonic(input) {
|
|
393
|
+
if ((0, migrate_1.hasLegacyMcpProfiles)())
|
|
394
|
+
(0, migrate_1.migrateFromMcpProfileStore)();
|
|
395
|
+
const origin = (0, origin_1.resolveTokenServiceOrigin)(input.tokenServiceUrl);
|
|
396
|
+
(0, store_1.ensureActiveConnection)({ tokenServiceUrl: origin });
|
|
397
|
+
const { conn, secrets } = (0, wallet_setup_2.activeWalletContext)();
|
|
398
|
+
try {
|
|
399
|
+
(0, wallet_setup_2.requireWalletPreconditions)(conn, secrets);
|
|
400
|
+
await (0, wallet_setup_2.requirePhonePreconditions)(conn, origin);
|
|
401
|
+
}
|
|
402
|
+
catch (err) {
|
|
403
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
404
|
+
const phase = message.includes("Phone") ? "phone_required" : "email_unverified";
|
|
405
|
+
return result(phase, { success: false, message });
|
|
406
|
+
}
|
|
407
|
+
if ((0, wallet_setup_2.walletAlreadyConfigured)(conn, secrets)) {
|
|
408
|
+
const phase = (0, phase_1.computeConnectionPhase)();
|
|
409
|
+
return result(phase, {
|
|
410
|
+
success: true,
|
|
411
|
+
message: `Data Wallet already configured (${conn.evmAddress}). Run neozip connect finish.`,
|
|
412
|
+
});
|
|
413
|
+
}
|
|
414
|
+
const mnemonic = input.mnemonic.trim();
|
|
415
|
+
if (!mnemonic) {
|
|
416
|
+
return result("no_wallet", { success: false, message: "--mnemonic is required." });
|
|
417
|
+
}
|
|
418
|
+
try {
|
|
419
|
+
const evm = (0, wallet_setup_2.importWalletFromMnemonic)(mnemonic);
|
|
420
|
+
await (0, wallet_setup_2.validateWalletImportAgainstServer)({
|
|
421
|
+
origin,
|
|
422
|
+
accessToken: secrets.accessToken,
|
|
423
|
+
derivedAddress: evm.address,
|
|
424
|
+
force: input.force,
|
|
425
|
+
});
|
|
426
|
+
(0, wallet_setup_2.saveImportedWallet)(conn.id, evm);
|
|
427
|
+
(0, store_1.applyActiveConnectionToEnv)();
|
|
428
|
+
const phase = (0, phase_1.computeConnectionPhase)();
|
|
429
|
+
return result(phase, {
|
|
430
|
+
success: true,
|
|
431
|
+
message: `Imported Data Wallet (${evm.address}). Run neozip connect finish.`,
|
|
432
|
+
});
|
|
433
|
+
}
|
|
434
|
+
catch (err) {
|
|
435
|
+
return result("no_wallet", {
|
|
436
|
+
success: false,
|
|
437
|
+
message: err instanceof Error ? err.message : String(err),
|
|
438
|
+
});
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
async function connectWalletImportKey(input) {
|
|
442
|
+
if ((0, migrate_1.hasLegacyMcpProfiles)())
|
|
443
|
+
(0, migrate_1.migrateFromMcpProfileStore)();
|
|
444
|
+
const origin = (0, origin_1.resolveTokenServiceOrigin)(input.tokenServiceUrl);
|
|
445
|
+
(0, store_1.ensureActiveConnection)({ tokenServiceUrl: origin });
|
|
446
|
+
const { conn, secrets } = (0, wallet_setup_2.activeWalletContext)();
|
|
447
|
+
try {
|
|
448
|
+
(0, wallet_setup_2.requireWalletPreconditions)(conn, secrets);
|
|
449
|
+
await (0, wallet_setup_2.requirePhonePreconditions)(conn, origin);
|
|
450
|
+
}
|
|
451
|
+
catch (err) {
|
|
452
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
453
|
+
const phase = message.includes("Phone") ? "phone_required" : "email_unverified";
|
|
454
|
+
return result(phase, { success: false, message });
|
|
455
|
+
}
|
|
456
|
+
if ((0, wallet_setup_2.walletAlreadyConfigured)(conn, secrets)) {
|
|
457
|
+
const phase = (0, phase_1.computeConnectionPhase)();
|
|
458
|
+
return result(phase, {
|
|
459
|
+
success: true,
|
|
460
|
+
message: `Data Wallet already configured (${conn.evmAddress}). Run neozip connect finish.`,
|
|
461
|
+
});
|
|
462
|
+
}
|
|
463
|
+
const privateKey = input.privateKey.trim();
|
|
464
|
+
if (!privateKey) {
|
|
465
|
+
return result("no_wallet", { success: false, message: "--private-key is required." });
|
|
466
|
+
}
|
|
467
|
+
try {
|
|
468
|
+
const evm = (0, wallet_setup_2.importWalletFromPrivateKey)(privateKey);
|
|
469
|
+
await (0, wallet_setup_2.validateWalletImportAgainstServer)({
|
|
470
|
+
origin,
|
|
471
|
+
accessToken: secrets.accessToken,
|
|
472
|
+
derivedAddress: evm.address,
|
|
473
|
+
force: input.force,
|
|
474
|
+
});
|
|
475
|
+
(0, wallet_setup_2.saveImportedWallet)(conn.id, evm);
|
|
476
|
+
(0, store_1.applyActiveConnectionToEnv)();
|
|
477
|
+
const phase = (0, phase_1.computeConnectionPhase)();
|
|
478
|
+
return result(phase, {
|
|
479
|
+
success: true,
|
|
480
|
+
message: `Imported Data Wallet (${evm.address}). Run neozip connect finish.`,
|
|
481
|
+
});
|
|
482
|
+
}
|
|
483
|
+
catch (err) {
|
|
484
|
+
return result("no_wallet", {
|
|
485
|
+
success: false,
|
|
486
|
+
message: err instanceof Error ? err.message : String(err),
|
|
487
|
+
});
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
async function connectFinish(input) {
|
|
491
|
+
if ((0, migrate_1.hasLegacyMcpProfiles)())
|
|
492
|
+
(0, migrate_1.migrateFromMcpProfileStore)();
|
|
493
|
+
const origin = (0, origin_1.resolveTokenServiceOrigin)(input?.tokenServiceUrl);
|
|
494
|
+
const conn = (0, store_1.ensureActiveConnection)({ tokenServiceUrl: origin });
|
|
495
|
+
const secrets = (0, store_1.readActiveConnectionSecrets)();
|
|
496
|
+
if (!secrets?.accessToken || !conn.emailVerified) {
|
|
497
|
+
return result("email_unverified", {
|
|
498
|
+
success: false,
|
|
499
|
+
message: "Email not verified. Run neozip connect to continue setup.",
|
|
500
|
+
});
|
|
501
|
+
}
|
|
502
|
+
const coordinator = await (0, coordinator_1.fetchCoordinatorConfigParsed)(origin);
|
|
503
|
+
(0, coordinator_1.assertCoordinatorWrapSupported)(coordinator);
|
|
504
|
+
if (await (0, phone_1.needsPhoneVerification)(conn, origin)) {
|
|
505
|
+
return result("phone_required", {
|
|
506
|
+
success: false,
|
|
507
|
+
message: "Phone verification required. Run neozip connect phone request --phone +14155551234, then phone verify.",
|
|
508
|
+
});
|
|
509
|
+
}
|
|
510
|
+
let meta = conn;
|
|
511
|
+
let sec = secrets;
|
|
512
|
+
if (!sec.evmPrivateKeyHex || !meta.evmAddress) {
|
|
513
|
+
if (!input?.createWallet) {
|
|
514
|
+
return result("no_wallet", {
|
|
515
|
+
success: false,
|
|
516
|
+
message: wallet_setup_2.WALLET_SETUP_HINT,
|
|
517
|
+
});
|
|
518
|
+
}
|
|
519
|
+
const evm = (0, wallet_evm_1.generateEvmIdentity)();
|
|
520
|
+
meta = (0, store_1.saveEvmWallet)(meta.id, evm.privateKey, evm.address);
|
|
521
|
+
sec = (0, store_1.readActiveConnectionSecrets)();
|
|
522
|
+
}
|
|
523
|
+
if (!meta.walletId || meta.linkId == null) {
|
|
524
|
+
const linked = await (0, wallet_setup_1.runWalletEnsureAndAttach)(origin, sec.accessToken, sec.evmPrivateKeyHex, meta.evmAddress);
|
|
525
|
+
meta = (0, store_1.saveWalletLink)(meta.id, linked.walletId, linked.linkId, linked.evmAddress);
|
|
526
|
+
}
|
|
527
|
+
if (!meta.identityKeyId) {
|
|
528
|
+
const provisioned = await (0, identity_provision_1.provisionWalletIdentityKey)({
|
|
529
|
+
baseUrl: origin,
|
|
530
|
+
accessToken: sec.accessToken,
|
|
531
|
+
walletId: meta.walletId,
|
|
532
|
+
evmPrivateKey: sec.evmPrivateKeyHex,
|
|
533
|
+
evmAddress: meta.evmAddress,
|
|
534
|
+
});
|
|
535
|
+
meta = (0, store_1.saveIdentityProvision)(meta.id, provisioned.identityKeyId, provisioned.x25519PublicKey);
|
|
536
|
+
}
|
|
537
|
+
(0, store_1.applyActiveConnectionToEnv)();
|
|
538
|
+
return result("ready", {
|
|
539
|
+
success: true,
|
|
540
|
+
message: `Connection ready. Profile stored under ${(0, store_1.getConnectionDir)()}. Reload MCP in Cursor.`,
|
|
541
|
+
});
|
|
542
|
+
}
|
|
543
|
+
async function connectSetup(input) {
|
|
544
|
+
if ((0, migrate_1.hasLegacyMcpProfiles)())
|
|
545
|
+
(0, migrate_1.migrateFromMcpProfileStore)();
|
|
546
|
+
const origin = (0, origin_1.resolveTokenServiceOrigin)(input.tokenServiceUrl);
|
|
547
|
+
(0, store_1.ensureActiveConnection)({
|
|
548
|
+
label: input.label,
|
|
549
|
+
tokenServiceUrl: origin,
|
|
550
|
+
});
|
|
551
|
+
const ver = await connectVerify({
|
|
552
|
+
email: input.email,
|
|
553
|
+
code: input.code,
|
|
554
|
+
tokenServiceUrl: input.tokenServiceUrl,
|
|
555
|
+
});
|
|
556
|
+
if (ver.phase === "phone_required")
|
|
557
|
+
return ver;
|
|
558
|
+
if (ver.phase === "ready")
|
|
559
|
+
return ver;
|
|
560
|
+
const phase = (0, phase_1.computeConnectionPhase)();
|
|
561
|
+
if (phase === "no_wallet" || phase === "wallet_unlinked" || phase === "identity_missing") {
|
|
562
|
+
return result(phase, {
|
|
563
|
+
success: true,
|
|
564
|
+
message: `Email verified (phase: ${phase}). ${wallet_setup_2.WALLET_SETUP_HINT}`,
|
|
565
|
+
});
|
|
566
|
+
}
|
|
567
|
+
return connectFinish({ tokenServiceUrl: input.tokenServiceUrl });
|
|
568
|
+
}
|
|
569
|
+
function connectLogout() {
|
|
570
|
+
const out = (0, store_1.logoutConnection)();
|
|
571
|
+
return result((0, phase_1.computeConnectionPhase)(), {
|
|
572
|
+
success: true,
|
|
573
|
+
message: `Logged out connection "${out.label}". Run neozip connect to set up again.`,
|
|
574
|
+
});
|
|
575
|
+
}
|
|
576
|
+
function connectDelete(input) {
|
|
577
|
+
const id = input?.connectionId?.trim() || (0, store_1.getActiveConnection)()?.id;
|
|
578
|
+
if (!id) {
|
|
579
|
+
return result("no_profile", {
|
|
580
|
+
success: false,
|
|
581
|
+
message: "No connection to delete.",
|
|
582
|
+
});
|
|
583
|
+
}
|
|
584
|
+
const out = (0, store_1.deleteConnection)(id);
|
|
585
|
+
return result((0, phase_1.computeConnectionPhase)(), {
|
|
586
|
+
success: true,
|
|
587
|
+
connectionId: out.newActiveConnectionId,
|
|
588
|
+
message: out.newActiveConnectionId != null
|
|
589
|
+
? `Deleted connection "${out.label}". Active connection updated.`
|
|
590
|
+
: `Deleted connection "${out.label}". No accounts remain.`,
|
|
591
|
+
});
|
|
592
|
+
}
|
|
593
|
+
function connectMigrate() {
|
|
594
|
+
const mcp = (0, migrate_1.migrateFromMcpProfileStore)();
|
|
595
|
+
const wallet = (0, migrate_1.migrateFromWalletJson)();
|
|
596
|
+
const messages = [];
|
|
597
|
+
if (mcp.migrated > 0) {
|
|
598
|
+
messages.push(`Migrated ${mcp.migrated} legacy MCP profile(s) to ${mcp.connectionDir}.`);
|
|
599
|
+
}
|
|
600
|
+
messages.push(...wallet.messages);
|
|
601
|
+
if (messages.length === 0) {
|
|
602
|
+
messages.push("Nothing to migrate (connection store populated, no legacy profiles, no wallet.json).");
|
|
603
|
+
}
|
|
604
|
+
return {
|
|
605
|
+
success: mcp.migrated > 0 || wallet.migratedPrefs || wallet.importedKey,
|
|
606
|
+
phase: (0, phase_1.computeConnectionPhase)(),
|
|
607
|
+
connectionId: (0, store_1.getActiveConnectionId)(),
|
|
608
|
+
tokenServiceOrigin: (0, origin_1.resolveTokenServiceOrigin)(),
|
|
609
|
+
message: messages.join(" "),
|
|
610
|
+
nextCommand: (0, phase_1.nextConnectCommand)((0, phase_1.computeConnectionPhase)(), {
|
|
611
|
+
email: (0, store_1.getActiveConnection)()?.email,
|
|
612
|
+
phoneE164: (0, store_1.getActiveConnection)()?.phoneE164,
|
|
613
|
+
}),
|
|
614
|
+
};
|
|
615
|
+
}
|
|
616
|
+
//# sourceMappingURL=onboarding.js.map
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.KNOWN_TOKEN_SERVICE_PRESETS = exports.NEOZIP_TOKEN_SERVICE_PRODUCTION_URL = exports.NEOZIP_TOKEN_SERVICE_LOCALHOST = exports.NEOZIP_TOKEN_SERVICE_DEFAULT_URL = void 0;
|
|
4
|
+
exports.defaultTokenServiceMenuChoice = defaultTokenServiceMenuChoice;
|
|
5
|
+
exports.connectionLabelForOrigin = connectionLabelForOrigin;
|
|
6
|
+
exports.normalizeTokenServiceOrigin = normalizeTokenServiceOrigin;
|
|
7
|
+
exports.sameTokenServiceOrigin = sameTokenServiceOrigin;
|
|
8
|
+
exports.resolveTokenServiceOrigin = resolveTokenServiceOrigin;
|
|
9
|
+
/** Default token service when none is configured. */
|
|
10
|
+
exports.NEOZIP_TOKEN_SERVICE_DEFAULT_URL = "https://testnet.token-service.neozip.io";
|
|
11
|
+
/** Local token service URL for development. */
|
|
12
|
+
exports.NEOZIP_TOKEN_SERVICE_LOCALHOST = "http://localhost:14789";
|
|
13
|
+
/** Production token service URL. */
|
|
14
|
+
exports.NEOZIP_TOKEN_SERVICE_PRODUCTION_URL = "https://token-service.neozip.io";
|
|
15
|
+
/** Interactive menu order for Token Service deployment picker. */
|
|
16
|
+
exports.KNOWN_TOKEN_SERVICE_PRESETS = [
|
|
17
|
+
{
|
|
18
|
+
name: "NeoZip Testnet",
|
|
19
|
+
url: exports.NEOZIP_TOKEN_SERVICE_DEFAULT_URL,
|
|
20
|
+
description: "NeoZip Token Service (testnet)",
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
name: "NeoZip Production",
|
|
24
|
+
url: exports.NEOZIP_TOKEN_SERVICE_PRODUCTION_URL,
|
|
25
|
+
description: "NeoZip Token Service (production)",
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
name: "Local Development",
|
|
29
|
+
url: exports.NEOZIP_TOKEN_SERVICE_LOCALHOST,
|
|
30
|
+
description: "Local NeoZip Token Service",
|
|
31
|
+
},
|
|
32
|
+
];
|
|
33
|
+
function defaultTokenServiceMenuChoice(serverUrl) {
|
|
34
|
+
const raw = serverUrl?.trim();
|
|
35
|
+
if (!raw)
|
|
36
|
+
return "1";
|
|
37
|
+
const normalized = normalizeTokenServiceOrigin(raw);
|
|
38
|
+
const presetIdx = exports.KNOWN_TOKEN_SERVICE_PRESETS.findIndex((p) => sameTokenServiceOrigin(p.url, normalized));
|
|
39
|
+
if (presetIdx >= 0)
|
|
40
|
+
return String(presetIdx + 1);
|
|
41
|
+
return "4";
|
|
42
|
+
}
|
|
43
|
+
function connectionLabelForOrigin(origin) {
|
|
44
|
+
const normalized = normalizeTokenServiceOrigin(origin);
|
|
45
|
+
const preset = exports.KNOWN_TOKEN_SERVICE_PRESETS.find((p) => sameTokenServiceOrigin(p.url, normalized));
|
|
46
|
+
return preset?.name ?? normalized;
|
|
47
|
+
}
|
|
48
|
+
function normalizeTokenServiceOrigin(url) {
|
|
49
|
+
const trimmed = (url || "").trim();
|
|
50
|
+
if (!trimmed)
|
|
51
|
+
return "";
|
|
52
|
+
const noSlash = trimmed.replace(/\/+$/, "");
|
|
53
|
+
try {
|
|
54
|
+
const u = new URL(noSlash);
|
|
55
|
+
const host = u.hostname.toLowerCase();
|
|
56
|
+
return `${u.protocol}//${host}${u.port ? `:${u.port}` : ""}${u.pathname.replace(/\/+$/, "") || ""}`;
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
return noSlash;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
function sameTokenServiceOrigin(a, b) {
|
|
63
|
+
return normalizeTokenServiceOrigin(a) === normalizeTokenServiceOrigin(b);
|
|
64
|
+
}
|
|
65
|
+
function resolveTokenServiceOrigin(serverUrl) {
|
|
66
|
+
const raw = serverUrl?.trim() || exports.NEOZIP_TOKEN_SERVICE_DEFAULT_URL;
|
|
67
|
+
return normalizeTokenServiceOrigin(raw);
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=origin.js.map
|