neozip-cli 0.90.0 → 0.95.1

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.
Files changed (76) hide show
  1. package/AGENTS.md +93 -0
  2. package/CHANGELOG.md +70 -1
  3. package/DOCUMENTATION.md +22 -30
  4. package/README.md +214 -48
  5. package/dist/src/account/account-state.js +95 -0
  6. package/dist/src/account/format-account-status.js +62 -0
  7. package/dist/src/account/identity-provision.js +79 -0
  8. package/dist/src/account/identity-wrap.js +106 -0
  9. package/dist/src/account/profile-crypto.js +85 -0
  10. package/dist/src/account/profile-store.js +129 -0
  11. package/dist/src/account/require-account.js +32 -0
  12. package/dist/src/account/token-service-funding.js +151 -0
  13. package/dist/src/account/token-service-identity.js +488 -0
  14. package/dist/src/account/types.js +3 -0
  15. package/dist/src/account/wallet-evm.js +46 -0
  16. package/dist/src/account/wallet-setup.js +33 -0
  17. package/dist/src/archive/crypto-self.js +117 -0
  18. package/dist/src/archive/identity-key.js +217 -0
  19. package/dist/src/archive/recipient-lookup.js +61 -0
  20. package/dist/src/cli/output.js +100 -0
  21. package/dist/src/cli/params.js +122 -0
  22. package/dist/src/cli/schema.js +186 -0
  23. package/dist/src/cli/validate.js +119 -0
  24. package/dist/src/commands/mintTimestampProof.js +26 -14
  25. package/dist/src/commands/verifyEmail.js +9 -9
  26. package/dist/src/config/ConfigSetup.js +82 -423
  27. package/dist/src/config/ConfigStore.js +0 -33
  28. package/dist/src/connect/command.js +364 -0
  29. package/dist/src/connection/bootstrap.js +50 -0
  30. package/dist/src/connection/cli-guidance.js +101 -0
  31. package/dist/src/connection/cli-prefs.js +180 -0
  32. package/dist/src/connection/cli-settings.js +140 -0
  33. package/dist/src/connection/cli-types.js +14 -0
  34. package/dist/src/connection/coordinator.js +83 -0
  35. package/dist/src/connection/credentials.js +33 -0
  36. package/dist/src/connection/crypto.js +96 -0
  37. package/dist/src/connection/dump.js +117 -0
  38. package/dist/src/connection/funding.js +187 -0
  39. package/dist/src/connection/incomplete-setup.js +89 -0
  40. package/dist/src/connection/interactive.js +871 -0
  41. package/dist/src/connection/legacy-profile-reader.js +87 -0
  42. package/dist/src/connection/magic-link.js +142 -0
  43. package/dist/src/connection/migrate.js +115 -0
  44. package/dist/src/connection/onboarding.js +616 -0
  45. package/dist/src/connection/origin.js +69 -0
  46. package/dist/src/connection/phase.js +101 -0
  47. package/dist/src/connection/phone.js +26 -0
  48. package/dist/src/connection/promote-active.js +56 -0
  49. package/dist/src/connection/reset.js +56 -0
  50. package/dist/src/connection/status-report.js +52 -0
  51. package/dist/src/connection/store.js +406 -0
  52. package/dist/src/connection/token-auth.js +44 -0
  53. package/dist/src/connection/types.js +3 -0
  54. package/dist/src/connection/wallet-json-migration.js +155 -0
  55. package/dist/src/connection/wallet-login.js +65 -0
  56. package/dist/src/connection/wallet-setup.js +83 -0
  57. package/dist/src/constants/wallet-identity.js +14 -0
  58. package/dist/src/exit-codes.js +54 -10
  59. package/dist/src/neolist.js +93 -9
  60. package/dist/src/neounzip.js +217 -59
  61. package/dist/src/neozip/blockchain.js +18 -18
  62. package/dist/src/neozip/createZip.js +114 -91
  63. package/dist/src/neozip/upgradeZip.js +14 -11
  64. package/dist/src/neozip.js +252 -75
  65. package/dist/src/skills/command.js +256 -0
  66. package/dist/src/skills/locate.js +99 -0
  67. package/dist/src/util/mask.js +34 -0
  68. package/dist/src/util/token-service-fetch.js +26 -0
  69. package/env.example +18 -85
  70. package/package.json +89 -82
  71. package/skills/neozip-connect/SKILL.md +95 -0
  72. package/skills/neozip-create/SKILL.md +57 -0
  73. package/skills/neozip-extract/SKILL.md +58 -0
  74. package/skills/neozip-legacy/SKILL.md +48 -0
  75. package/skills/neozip-list/SKILL.md +56 -0
  76. package/skills/neozip-shared/SKILL.md +60 -0
@@ -0,0 +1,186 @@
1
+ "use strict";
2
+ /**
3
+ * Machine-readable schema introspection.
4
+ *
5
+ * Unlike a REST CLI with a Discovery document, NeoZip's commands are described
6
+ * by a hand-authored registry. `neozip schema <command>` emits the accepted
7
+ * `--params` fields, the `--json` payload shape, output shape, and exit codes so
8
+ * an agent can construct calls without scraping `--help`.
9
+ */
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.getCommandSchema = getCommandSchema;
12
+ exports.listSchemaCommands = listSchemaCommands;
13
+ exports.handleSchemaCommand = handleSchemaCommand;
14
+ const NEOZIP_SCHEMA = {
15
+ command: 'neozip',
16
+ summary: 'Create or update an archive, optionally with blockchain tokenization.',
17
+ output: 'Human text by default. Pass --format json for a structured result. --dry-run previews without writing.',
18
+ params: [
19
+ { name: 'level', type: 'number', description: 'Compression level 0-9 (0=store).', default: 6, legacySafe: true },
20
+ { name: 'compression', type: 'string', enum: ['zstd', 'deflate'], description: 'Compression algorithm.', default: 'zstd', legacySafe: false },
21
+ { name: 'legacy', type: 'boolean', description: 'Produce an InfoZip/PKZIP-compatible archive (forces deflate/store + PKZIP, disables NeoZip extensions).', default: false, legacySafe: true },
22
+ { name: 'encrypt', type: 'boolean', description: 'Encrypt entries (prompts for password unless password is given).', default: false, legacySafe: true },
23
+ { name: 'password', type: 'string', description: 'Encryption password. Use with care (visible in process list).', legacySafe: true },
24
+ { name: 'encryptionMethod', type: 'string', enum: ['aes256', 'pkzip'], description: 'Encryption method. --legacy forces pkzip.', default: 'aes256', legacySafe: false },
25
+ { name: 'blockchain', type: 'boolean', description: 'Enable blockchain tokenization. Incompatible with legacy.', default: false, legacySafe: false },
26
+ { name: 'blockchainOts', type: 'boolean', description: 'Add an OpenTimestamps (Bitcoin) proof. Incompatible with legacy.', default: false, legacySafe: false },
27
+ { name: 'blockchainTokenService', type: 'boolean', description: 'Add a Token Service timestamp (requires neozip connect). Incompatible with legacy.', default: false, legacySafe: false },
28
+ { name: 'network', type: 'string', description: 'Blockchain network name (e.g. base-sepolia).', default: 'base-sepolia', legacySafe: false },
29
+ { name: 'recurse', type: 'boolean', description: 'Recurse into directories.', default: false, legacySafe: true },
30
+ { name: 'junkPaths', type: 'boolean', description: 'Store only file names, not directory paths.', default: false, legacySafe: true },
31
+ { name: 'include', type: 'string[]', description: 'Glob patterns to include.', legacySafe: true },
32
+ { name: 'exclude', type: 'string[]', description: 'Glob patterns to exclude.', legacySafe: true },
33
+ { name: 'inMemory', type: 'boolean', description: 'Use in-memory compression.', default: false, legacySafe: true },
34
+ { name: 'testIntegrity', type: 'boolean', description: 'Test the archive after creation.', default: false, legacySafe: true },
35
+ { name: 'verbose', type: 'boolean', description: 'Verbose output.', default: false, legacySafe: true },
36
+ { name: 'quiet', type: 'boolean', description: 'Suppress output.', default: false, legacySafe: true },
37
+ ],
38
+ payload: [
39
+ { name: 'archive', type: 'string', description: 'Output archive path (positional arg 1).' },
40
+ { name: 'files', type: 'string[]', description: 'Files/directories to add (positional args 2+).' },
41
+ { name: 'include', type: 'string[]', description: 'Glob patterns to include.' },
42
+ { name: 'exclude', type: 'string[]', description: 'Glob patterns to exclude.' },
43
+ ],
44
+ exitCodes: [
45
+ { code: 0, meaning: 'Success' },
46
+ { code: 10, meaning: 'Parameter error' },
47
+ { code: 15, meaning: "Can't write archive" },
48
+ { code: 18, meaning: "Can't find archive" },
49
+ { code: 26, meaning: 'Blockchain configuration error' },
50
+ ],
51
+ notes: [
52
+ 'Output format is selected with --format json (not --json). --json supplies the payload.',
53
+ 'Example: neozip --format json --params \'{"level":9,"legacy":true}\' --json \'{"files":["a.txt","dir/"]}\' out.zip',
54
+ ],
55
+ };
56
+ const NEOUNZIP_SCHEMA = {
57
+ command: 'neounzip',
58
+ summary: 'Extract, test, or list an archive.',
59
+ output: 'Human text by default. Pass --format json for a structured result. --dry-run previews the extraction plan.',
60
+ params: [
61
+ { name: 'exdir', type: 'string', description: 'Extraction directory (zip-slip validated).' },
62
+ { name: 'overwrite', type: 'boolean', description: 'Overwrite existing files.', default: false },
63
+ { name: 'never', type: 'boolean', description: 'Never overwrite existing files.', default: false },
64
+ { name: 'junkPaths', type: 'boolean', description: 'Strip directory paths on extraction.', default: false },
65
+ { name: 'testOnly', type: 'boolean', description: 'Test archive integrity only.', default: false },
66
+ { name: 'listOnly', type: 'boolean', description: 'List archive contents only.', default: false },
67
+ { name: 'preVerify', type: 'boolean', description: 'Verify integrity/blockchain before extracting.', default: false },
68
+ { name: 'password', type: 'string', description: 'Decryption password.' },
69
+ { name: 'include', type: 'string[]', description: 'Glob patterns to include.' },
70
+ { name: 'exclude', type: 'string[]', description: 'Glob patterns to exclude.' },
71
+ { name: 'skipBlockchain', type: 'boolean', description: 'Skip blockchain verification.', default: false },
72
+ { name: 'inMemory', type: 'boolean', description: 'Use in-memory processing.', default: false },
73
+ { name: 'verbose', type: 'boolean', description: 'Verbose output.', default: false },
74
+ { name: 'quiet', type: 'boolean', description: 'Suppress output.', default: false },
75
+ ],
76
+ payload: [
77
+ { name: 'archive', type: 'string', description: 'Archive path (positional arg 1).' },
78
+ { name: 'exdir', type: 'string', description: 'Extraction directory (positional arg 2 or exdir).' },
79
+ { name: 'filePatterns', type: 'string[]', description: 'Entry name patterns to extract (positional args 3+).' },
80
+ ],
81
+ exitCodes: [
82
+ { code: 0, meaning: 'Success' },
83
+ { code: 1, meaning: 'Warning (completed with issues)' },
84
+ { code: 9, meaning: 'Files not found' },
85
+ { code: 10, meaning: 'Invalid options' },
86
+ { code: 82, meaning: 'Bad password' },
87
+ ],
88
+ notes: [
89
+ 'Extraction refuses entries that escape the target directory (zip-slip protection).',
90
+ 'Example: neounzip --format json --params \'{"exdir":"out","overwrite":true}\' archive.zip',
91
+ ],
92
+ };
93
+ const NEOLIST_SCHEMA = {
94
+ command: 'neolist',
95
+ summary: 'List the contents of an archive.',
96
+ output: 'Human text by default. Pass --format json (or the legacy -j/--json) for JSON.',
97
+ params: [
98
+ { name: 'sortBy', type: 'string', enum: ['name', 'size', 'date'], description: 'Sort order.' },
99
+ { name: 'include', type: 'string[]', description: 'Glob patterns to include.' },
100
+ { name: 'exclude', type: 'string[]', description: 'Glob patterns to exclude.' },
101
+ { name: 'noComments', type: 'boolean', description: 'Suppress comments.', default: false },
102
+ { name: 'inMemory', type: 'boolean', description: 'Use in-memory processing.', default: false },
103
+ { name: 'verbose', type: 'boolean', description: 'Verbose output.', default: false },
104
+ ],
105
+ exitCodes: [
106
+ { code: 0, meaning: 'Success' },
107
+ { code: 9, meaning: 'Files not found' },
108
+ { code: 10, meaning: 'Invalid options' },
109
+ { code: 82, meaning: 'Password-protected (cannot list)' },
110
+ ],
111
+ notes: ['Example: neolist --format json archive.zip'],
112
+ };
113
+ const CONNECT_SCHEMA = {
114
+ command: 'connect',
115
+ summary: 'Token Service account + wallet setup. Shares ~/.neozip/connection/ with NeoZip Desktop and MCP.',
116
+ output: 'Pass --json on any subcommand for a structured ConnectCliResult.',
117
+ params: [
118
+ { name: 'email', type: 'string', description: 'Account email for register/verify.' },
119
+ { name: 'code', type: 'string', description: 'Verification code.' },
120
+ { name: 'phone', type: 'string', description: 'E.164 phone number for phone verification.' },
121
+ { name: 'connectionId', type: 'string', description: 'Target a specific connection.' },
122
+ { name: 'tokenServiceUrl', type: 'string', description: 'Override the Token Service URL.' },
123
+ { name: 'label', type: 'string', description: 'Friendly label for the connection.' },
124
+ { name: 'network', type: 'string', description: 'Network name for connect fund (e.g. base-sepolia).' },
125
+ { name: 'chain', type: 'number', description: 'Chain id for connect fund (overrides --network).' },
126
+ ],
127
+ exitCodes: [
128
+ { code: 0, meaning: 'Success' },
129
+ { code: 12, meaning: 'Command failed' },
130
+ ],
131
+ notes: [
132
+ 'Subcommands: status, register, verify, refresh, fund, phone, wallet, finish, select, rename, dump, settings, migrate, logout, delete, reset.',
133
+ 'connect refresh renews an expired access token (silent wallet-signature login, else email OTP).',
134
+ 'connect fund [request|status|policy] requests native gas for the Data Wallet from the Token Service funding API.',
135
+ 'Non-interactive subcommands accept --json for structured output. The bare wizard requires a TTY.',
136
+ ],
137
+ };
138
+ const REGISTRY = {
139
+ neozip: NEOZIP_SCHEMA,
140
+ zip: NEOZIP_SCHEMA,
141
+ neounzip: NEOUNZIP_SCHEMA,
142
+ unzip: NEOUNZIP_SCHEMA,
143
+ neolist: NEOLIST_SCHEMA,
144
+ list: NEOLIST_SCHEMA,
145
+ connect: CONNECT_SCHEMA,
146
+ };
147
+ /** Look up a command schema by name (case-insensitive, with aliases). */
148
+ function getCommandSchema(command) {
149
+ return REGISTRY[command.toLowerCase()];
150
+ }
151
+ /** List the canonical introspectable command names. */
152
+ function listSchemaCommands() {
153
+ return ['neozip', 'neounzip', 'neolist', 'connect'];
154
+ }
155
+ /**
156
+ * Handle `neozip schema [command]`. Prints JSON to stdout. Returns the process
157
+ * exit code (0 on success, 10 on a bad command name).
158
+ */
159
+ function handleSchemaCommand(args) {
160
+ const target = args[0];
161
+ if (!target) {
162
+ // No command given: emit an index of available commands.
163
+ const index = {
164
+ ok: true,
165
+ commands: listSchemaCommands(),
166
+ usage: 'neozip schema <neozip|neounzip|neolist|connect>',
167
+ };
168
+ process.stdout.write(JSON.stringify(index, null, 2) + '\n');
169
+ return 0;
170
+ }
171
+ const schema = getCommandSchema(target);
172
+ if (!schema) {
173
+ process.stdout.write(JSON.stringify({
174
+ ok: false,
175
+ error: {
176
+ code: 'UNKNOWN_COMMAND',
177
+ message: `Unknown command "${target}"`,
178
+ commands: listSchemaCommands(),
179
+ },
180
+ }, null, 2) + '\n');
181
+ return 10;
182
+ }
183
+ process.stdout.write(JSON.stringify({ ok: true, schema }, null, 2) + '\n');
184
+ return 0;
185
+ }
186
+ //# sourceMappingURL=schema.js.map
@@ -0,0 +1,119 @@
1
+ "use strict";
2
+ /**
3
+ * Input hardening for agent-driven (and adversarial) input.
4
+ *
5
+ * Agents hallucinate. Treat all CLI/JSON-supplied strings as untrusted:
6
+ * - Reject control characters and dangerous Unicode (zero-width, bidi
7
+ * overrides) that can hide intent in file names and paths.
8
+ * - Prevent zip-slip: extracted entries must resolve inside the target dir.
9
+ *
10
+ * Adapted from the patterns in the Google Workspace CLI `validate.rs`.
11
+ */
12
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
13
+ if (k2 === undefined) k2 = k;
14
+ var desc = Object.getOwnPropertyDescriptor(m, k);
15
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
16
+ desc = { enumerable: true, get: function() { return m[k]; } };
17
+ }
18
+ Object.defineProperty(o, k2, desc);
19
+ }) : (function(o, m, k, k2) {
20
+ if (k2 === undefined) k2 = k;
21
+ o[k2] = m[k];
22
+ }));
23
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
24
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
25
+ }) : function(o, v) {
26
+ o["default"] = v;
27
+ });
28
+ var __importStar = (this && this.__importStar) || (function () {
29
+ var ownKeys = function(o) {
30
+ ownKeys = Object.getOwnPropertyNames || function (o) {
31
+ var ar = [];
32
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
33
+ return ar;
34
+ };
35
+ return ownKeys(o);
36
+ };
37
+ return function (mod) {
38
+ if (mod && mod.__esModule) return mod;
39
+ var result = {};
40
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
41
+ __setModuleDefault(result, mod);
42
+ return result;
43
+ };
44
+ })();
45
+ Object.defineProperty(exports, "__esModule", { value: true });
46
+ exports.ValidationError = void 0;
47
+ exports.rejectControlChars = rejectControlChars;
48
+ exports.assertSafeArchiveName = assertSafeArchiveName;
49
+ exports.validateSafeOutputDir = validateSafeOutputDir;
50
+ exports.resolveSafeExtractPath = resolveSafeExtractPath;
51
+ const path = __importStar(require("path"));
52
+ /** Raised when input fails a hardening check. */
53
+ class ValidationError extends Error {
54
+ constructor(message) {
55
+ super(message);
56
+ this.name = 'ValidationError';
57
+ }
58
+ }
59
+ exports.ValidationError = ValidationError;
60
+ // C0 controls (0x00-0x1F), DEL (0x7F), and C1 controls (0x80-0x9F).
61
+ const CONTROL_CHARS = /[\u0000-\u001F\u007F-\u009F]/;
62
+ // Zero-width and bidirectional-override characters that can disguise paths.
63
+ const DANGEROUS_UNICODE = /[\u200B-\u200F\u202A-\u202E\u2060-\u2064\u2066-\u206F\uFEFF]/;
64
+ /**
65
+ * Reject control characters and dangerous Unicode in a value. Returns the value
66
+ * unchanged when it is safe.
67
+ */
68
+ function rejectControlChars(value, label) {
69
+ if (CONTROL_CHARS.test(value)) {
70
+ throw new ValidationError(`${label} contains control characters`);
71
+ }
72
+ if (DANGEROUS_UNICODE.test(value)) {
73
+ throw new ValidationError(`${label} contains disallowed Unicode characters`);
74
+ }
75
+ return value;
76
+ }
77
+ /**
78
+ * Validate an archive name / file path for control characters. Does not enforce
79
+ * a sandbox (archives may legitimately live anywhere the user can write).
80
+ */
81
+ function assertSafeArchiveName(name) {
82
+ return rejectControlChars(name, 'Archive name');
83
+ }
84
+ /**
85
+ * Validate an output directory string. Rejects control chars and returns the
86
+ * resolved absolute path.
87
+ */
88
+ function validateSafeOutputDir(dir, label = 'Output directory') {
89
+ rejectControlChars(dir, label);
90
+ return path.resolve(dir);
91
+ }
92
+ /**
93
+ * Resolve an archive entry name against a target extraction directory and ensure
94
+ * the result stays inside that directory (zip-slip protection).
95
+ *
96
+ * - Rejects control characters / dangerous Unicode in the entry name.
97
+ * - Rejects absolute entry paths.
98
+ * - Rejects `..` traversal that escapes the target directory.
99
+ *
100
+ * Returns the safe absolute destination path for the entry.
101
+ */
102
+ function resolveSafeExtractPath(targetDir, entryName) {
103
+ rejectControlChars(entryName, `Entry "${entryName}"`);
104
+ // Normalize Windows separators so checks are consistent cross-platform.
105
+ const normalizedEntry = entryName.replace(/\\/g, '/');
106
+ if (path.isAbsolute(normalizedEntry) || /^[A-Za-z]:[\\/]/.test(normalizedEntry)) {
107
+ throw new ValidationError(`Entry "${entryName}" uses an absolute path (refusing to extract)`);
108
+ }
109
+ const resolvedTarget = path.resolve(targetDir);
110
+ const destination = path.resolve(resolvedTarget, normalizedEntry);
111
+ const withSep = resolvedTarget.endsWith(path.sep)
112
+ ? resolvedTarget
113
+ : resolvedTarget + path.sep;
114
+ if (destination !== resolvedTarget && !destination.startsWith(withSep)) {
115
+ throw new ValidationError(`Entry "${entryName}" escapes the extraction directory (path traversal)`);
116
+ }
117
+ return destination;
118
+ }
119
+ //# sourceMappingURL=validate.js.map
@@ -48,9 +48,11 @@ const os = __importStar(require("os"));
48
48
  const ethers_1 = require("ethers");
49
49
  const node_1 = __importDefault(require("neozipkit/node"));
50
50
  const node_2 = require("neozipkit/node");
51
- const zipstamp_server_1 = require("neozip-blockchain/zipstamp-server");
51
+ const token_service_1 = require("neozip-blockchain/token-service");
52
52
  const neozip_blockchain_1 = require("neozip-blockchain");
53
- const blockchain_1 = require("../neozip/blockchain");
53
+ const cli_guidance_1 = require("../connection/cli-guidance");
54
+ const funding_1 = require("../connection/funding");
55
+ const bootstrap_1 = require("../connection/bootstrap");
54
56
  const RPC_BY_CHAIN = {
55
57
  84532: 'https://sepolia.base.org',
56
58
  421614: 'https://sepolia-rollup.arbitrum.io/rpc',
@@ -78,27 +80,34 @@ function getErrorMessage(error) {
78
80
  */
79
81
  async function runMintTimestampProof(options) {
80
82
  const { inputPath, outputPath, walletKey: cliWalletKey, debug = false } = options;
83
+ const walletGuidance = (0, cli_guidance_1.requireConnectionReady)('On-chain mint', 'wallet');
84
+ if (walletGuidance) {
85
+ console.error(walletGuidance);
86
+ return false;
87
+ }
81
88
  if (!fs.existsSync(inputPath)) {
82
89
  console.error(`Error: ZIP file not found: ${inputPath}`);
83
90
  return false;
84
91
  }
85
- const walletKey = (0, blockchain_1.getWalletPasskey)(cliWalletKey, true);
92
+ const creds = (0, bootstrap_1.readCliConnectionCredentials)();
93
+ const walletKey = cliWalletKey || creds.walletKey;
86
94
  if (!walletKey) {
95
+ console.error('Error: No wallet key in connection store. Run: neozip connect');
87
96
  return false;
88
97
  }
89
98
  const zip = new node_1.default();
90
99
  await zip.loadZipFile(inputPath);
91
100
  const entries = zip.getDirectory() || [];
92
- const metadataResult = (0, zipstamp_server_1.findMetadataEntry)(entries);
101
+ const metadataResult = (0, token_service_1.findMetadataEntry)(entries);
93
102
  if (!metadataResult) {
94
- console.error('No Zipstamp timestamp found in ZIP file');
103
+ console.error('No Token Service timestamp found in ZIP file');
95
104
  return false;
96
105
  }
97
106
  if (metadataResult.type !== 'confirmed') {
98
107
  console.error('Archive must have confirmed timestamp (TIMESTAMP.NZIP). Run "neozip upgrade <archive>" first.');
99
108
  return false;
100
109
  }
101
- let timestampMetadata = await (0, zipstamp_server_1.extractTimestampData)(zip, metadataResult.entry);
110
+ let timestampMetadata = await (0, token_service_1.extractTimestampData)(zip, metadataResult.entry);
102
111
  if (!timestampMetadata || !timestampMetadata.digest) {
103
112
  // Fallback for file-based ZIPs where zip.extract() may not work
104
113
  try {
@@ -123,14 +132,16 @@ async function runMintTimestampProof(options) {
123
132
  }
124
133
  const chainId = timestampMetadata.chainId ?? 84532;
125
134
  const batchId = timestampMetadata.batchId ?? undefined;
135
+ const serverUrl = (0, bootstrap_1.resolveVerifyServerUrl)(timestampMetadata.serverUrl);
136
+ const tsOpts = { debug, serverUrl };
126
137
  console.log('Checking NFT status...');
127
- const nftStatus = await (0, zipstamp_server_1.checkNFTStatus)(timestampMetadata.digest, chainId, { debug });
138
+ const nftStatus = await (0, token_service_1.checkNFTStatus)(timestampMetadata.digest, chainId, tsOpts);
128
139
  if (nftStatus.isMinted && nftStatus.tokenId) {
129
140
  console.log(`Digest already minted as token #${nftStatus.tokenId}`);
130
141
  console.log('Proceeding to create TOKEN.NZIP with existing token data...');
131
142
  }
132
143
  console.log('Preparing mint data...');
133
- const prepareResult = await (0, zipstamp_server_1.prepareMint)(timestampMetadata.digest, chainId, batchId, { debug });
144
+ const prepareResult = await (0, token_service_1.prepareMint)(timestampMetadata.digest, chainId, batchId, tsOpts);
134
145
  if (!prepareResult.success || !prepareResult.mintData) {
135
146
  console.error(`Error: ${prepareResult.error || 'Failed to prepare mint data'}`);
136
147
  return false;
@@ -159,6 +170,7 @@ async function runMintTimestampProof(options) {
159
170
  const mintFeeWei = BigInt(mintData.mintFeeWei);
160
171
  if (balance < mintFeeWei) {
161
172
  console.error(`Error: Insufficient balance. Required: ${mintData.mintFee} ETH`);
173
+ console.error(` ${(0, funding_1.formatLowBalanceFundingHint)()}`);
162
174
  return false;
163
175
  }
164
176
  const nftContract = new ethers_1.ethers.Contract(mintData.nftContractAddress, neozip_blockchain_1.NZIP_CONTRACT_ABI_V250, wallet);
@@ -197,14 +209,14 @@ async function runMintTimestampProof(options) {
197
209
  let existingTokenId;
198
210
  let existingOwner;
199
211
  let existingBlockNumber;
200
- const existingStatus = await (0, zipstamp_server_1.checkNFTStatus)(timestampMetadata.digest, chainId, { debug });
212
+ const existingStatus = await (0, token_service_1.checkNFTStatus)(timestampMetadata.digest, chainId, tsOpts);
201
213
  if (existingStatus.isMinted && existingStatus.tokenId) {
202
214
  existingTokenId = existingStatus.tokenId;
203
215
  existingOwner = existingStatus.owner;
204
216
  existingBlockNumber = existingStatus.proofData?.batchBlockNumber;
205
217
  }
206
218
  if (!existingTokenId) {
207
- const verifyRes = await (0, zipstamp_server_1.verifyDigest)(timestampMetadata.digest, chainId, batchId ?? undefined, undefined, { debug });
219
+ const verifyRes = await (0, token_service_1.verifyDigest)(timestampMetadata.digest, chainId, batchId ?? undefined, undefined, tsOpts);
208
220
  if (verifyRes.verified && verifyRes.tokenId) {
209
221
  existingTokenId = verifyRes.tokenId;
210
222
  existingOwner = verifyRes.owner;
@@ -219,7 +231,7 @@ async function runMintTimestampProof(options) {
219
231
  console.log(`Using existing token #${tokenId}. Creating TOKEN.NZIP...`);
220
232
  }
221
233
  else {
222
- console.error('Mint failed: digest is already minted on-chain but token details could not be retrieved. Try the Zipstamp server or block explorer for this digest.');
234
+ console.error('Mint failed: digest is already minted on-chain but token details could not be retrieved. Try the Token Service or block explorer for this digest.');
223
235
  console.error(`Details: ${msg}`);
224
236
  return false;
225
237
  }
@@ -251,10 +263,10 @@ async function runMintTimestampProof(options) {
251
263
  batchTimestamp: mintData.batchTimestamp,
252
264
  registryAddress: mintData.registryAddress,
253
265
  nftContractAddress: mintData.nftContractAddress,
254
- serverUrl: (0, zipstamp_server_1.getZipStampServerUrl)(),
266
+ serverUrl: serverUrl ?? '',
255
267
  },
256
268
  };
257
- const metadataFiles = (0, zipstamp_server_1.getMetadataFileNames)();
269
+ const metadataFiles = (0, token_service_1.getMetadataFileNames)();
258
270
  const outPath = outputPath ?? inputPath.replace(/(\.nzip|\.zip)$/i, '-nft$1');
259
271
  const tempDir = path.dirname(outPath) || '.';
260
272
  const tempPath = path.join(tempDir, `.neozip-mint-${Date.now()}.tmp`);
@@ -286,7 +298,7 @@ async function runMintTimestampProof(options) {
286
298
  zipCopy.writeCentralDirectoryAndEOCD(destPath, allEntries, { zipComment: '' });
287
299
  fs.renameSync(destPath, outPath);
288
300
  console.log(`Output: ${outPath}`);
289
- // Summary matching Zipstamp verification style
301
+ // Summary matching Token Service verification style
290
302
  console.log('\nšŸ”— Mint complete:');
291
303
  console.log(' - Status: āœ… MINTED');
292
304
  console.log(' - Stamp type: NZIP-NFT (tokenized archive)');
@@ -1,8 +1,8 @@
1
1
  "use strict";
2
2
  /**
3
- * Verify email for Zipstamp timestamping
3
+ * Verify email for Token Service timestamping
4
4
  *
5
- * Sets a default email for Zipstamp timestamps. Checks with the server whether
5
+ * Sets a default email for Token Service timestamps. Checks with the server whether
6
6
  * the email is already verified; if not, sends a magic link. Always saves as default.
7
7
  */
8
8
  var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
@@ -41,7 +41,7 @@ var __importStar = (this && this.__importStar) || (function () {
41
41
  Object.defineProperty(exports, "__esModule", { value: true });
42
42
  exports.runVerifyEmail = runVerifyEmail;
43
43
  const readline = __importStar(require("readline"));
44
- const zipstamp_server_1 = require("neozip-blockchain/zipstamp-server");
44
+ const token_service_1 = require("neozip-blockchain/token-service");
45
45
  const ConfigStore_1 = require("../config/ConfigStore");
46
46
  const EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
47
47
  function isValidEmail(email) {
@@ -74,8 +74,8 @@ async function runVerifyEmail(options) {
74
74
  });
75
75
  };
76
76
  try {
77
- console.log('\nšŸ“§ Zipstamp Email Configuration\n');
78
- console.log('Zipstamp requires a verified email to create timestamped ZIP files.');
77
+ console.log('\nšŸ“§ Token Service Email Configuration\n');
78
+ console.log('Token Service requires a verified email to create timestamped ZIP files.');
79
79
  console.log('');
80
80
  const config = ConfigStore_1.ConfigStore.getConfig();
81
81
  const defaultEmail = options?.email || config.timestampEmail || '';
@@ -92,20 +92,20 @@ async function runVerifyEmail(options) {
92
92
  }
93
93
  // --set-default: skip server check, just save
94
94
  if (options?.setDefaultOnly) {
95
- const saved = ConfigStore_1.ConfigStore.set('zipstamp.timestampEmail', email);
95
+ const saved = ConfigStore_1.ConfigStore.set('tokenService.timestampEmail', email);
96
96
  if (!saved) {
97
97
  console.error('āŒ Failed to save email to configuration');
98
98
  rl.close();
99
99
  return false;
100
100
  }
101
- console.log(`\nāœ… ${email} set as default for Zipstamp timestamps.`);
101
+ console.log(`\nāœ… ${email} set as default for Token Service timestamps.`);
102
102
  console.log('\nšŸ’” You can now create timestamped ZIPs: neozip -ts <archive> <files>\n');
103
103
  rl.close();
104
104
  return true;
105
105
  }
106
106
  // Check with server: register returns status (already verified vs magic link sent)
107
107
  console.log(`\nšŸ“¤ Checking verification status for ${email}...`);
108
- const registerResult = await (0, zipstamp_server_1.registerEmail)(email, {
108
+ const registerResult = await (0, token_service_1.registerEmail)(email, {
109
109
  debug: options?.debug,
110
110
  });
111
111
  if (!registerResult.success) {
@@ -118,7 +118,7 @@ async function runVerifyEmail(options) {
118
118
  const alreadyVerified = res.verified === true ||
119
119
  res.alreadyVerified === true ||
120
120
  isAlreadyVerifiedMessage(msg);
121
- const saved = ConfigStore_1.ConfigStore.set('zipstamp.timestampEmail', email);
121
+ const saved = ConfigStore_1.ConfigStore.set('tokenService.timestampEmail', email);
122
122
  if (!saved) {
123
123
  console.error('āŒ Failed to save email to configuration');
124
124
  rl.close();