kaven-cli 0.4.0 → 0.4.2-alpha.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.
Files changed (57) hide show
  1. package/README.md +181 -207
  2. package/dist/EnvManager-NMS3NMIE.js +15 -0
  3. package/dist/MarketplaceClient-YCFH2VU4.js +1 -0
  4. package/dist/chunk-JHLQ46NG.js +1 -0
  5. package/dist/index.d.ts +4 -0
  6. package/dist/index.js +243 -289
  7. package/dist/tier-table-DQMPQSI2.js +6 -0
  8. package/package.json +26 -10
  9. package/dist/commands/auth/login.js +0 -122
  10. package/dist/commands/auth/logout.js +0 -23
  11. package/dist/commands/auth/whoami.js +0 -36
  12. package/dist/commands/cache/index.js +0 -43
  13. package/dist/commands/config/features.js +0 -1026
  14. package/dist/commands/config/index.js +0 -95
  15. package/dist/commands/index.js +0 -2
  16. package/dist/commands/init/index.js +0 -197
  17. package/dist/commands/init-ci/index.js +0 -153
  18. package/dist/commands/license/index.js +0 -10
  19. package/dist/commands/license/status.js +0 -44
  20. package/dist/commands/license/tier-table.js +0 -46
  21. package/dist/commands/marketplace/browse.js +0 -186
  22. package/dist/commands/marketplace/install.js +0 -263
  23. package/dist/commands/marketplace/list.js +0 -122
  24. package/dist/commands/module/activate.js +0 -206
  25. package/dist/commands/module/add.js +0 -69
  26. package/dist/commands/module/doctor.js +0 -175
  27. package/dist/commands/module/publish.js +0 -258
  28. package/dist/commands/module/remove.js +0 -58
  29. package/dist/commands/telemetry/view.js +0 -27
  30. package/dist/commands/upgrade/check.js +0 -162
  31. package/dist/commands/upgrade/index.js +0 -185
  32. package/dist/core/AuthService.js +0 -222
  33. package/dist/core/CacheManager.js +0 -154
  34. package/dist/core/ConfigManager.js +0 -166
  35. package/dist/core/EnvManager.js +0 -196
  36. package/dist/core/ErrorRecovery.js +0 -192
  37. package/dist/core/LicenseService.js +0 -83
  38. package/dist/core/ManifestParser.js +0 -52
  39. package/dist/core/MarkerService.js +0 -62
  40. package/dist/core/ModuleDoctor.js +0 -451
  41. package/dist/core/ModuleInstaller.js +0 -169
  42. package/dist/core/ProjectInitializer.js +0 -166
  43. package/dist/core/RegistryResolver.js +0 -95
  44. package/dist/core/SchemaActivator.js +0 -270
  45. package/dist/core/ScriptRunner.js +0 -73
  46. package/dist/core/SignatureVerifier.js +0 -75
  47. package/dist/core/index.js +0 -2
  48. package/dist/infrastructure/Container.js +0 -37
  49. package/dist/infrastructure/MarketplaceClient.js +0 -399
  50. package/dist/infrastructure/TelemetryBuffer.js +0 -73
  51. package/dist/infrastructure/TransactionalFileSystem.js +0 -77
  52. package/dist/infrastructure/errors.js +0 -63
  53. package/dist/infrastructure/index.js +0 -2
  54. package/dist/types/auth.js +0 -2
  55. package/dist/types/manifest.js +0 -45
  56. package/dist/types/markers.js +0 -10
  57. package/dist/types/marketplace.js +0 -2
@@ -1,166 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.configManager = exports.ConfigManager = exports.configSchema = void 0;
7
- const path_1 = __importDefault(require("path"));
8
- const fs_extra_1 = __importDefault(require("fs-extra"));
9
- const os_1 = __importDefault(require("os"));
10
- const zod_1 = require("zod");
11
- const CONFIG_DIR = path_1.default.join(os_1.default.homedir(), ".kaven");
12
- const CONFIG_PATH = path_1.default.join(CONFIG_DIR, "config.json");
13
- exports.configSchema = zod_1.z.object({
14
- registry: zod_1.z.string().url().default("https://marketplace.kaven.site"),
15
- telemetry: zod_1.z.boolean().default(true),
16
- theme: zod_1.z.enum(["light", "dark"]).default("dark"),
17
- locale: zod_1.z.string().default("en-US"),
18
- // Custom registry support
19
- customRegistry: zod_1.z.string().url().optional(),
20
- // For storing user preferences
21
- lastLogin: zod_1.z.string().datetime().optional(),
22
- projectDefaults: zod_1.z
23
- .object({
24
- dbUrl: zod_1.z.string().optional(),
25
- emailProvider: zod_1.z.enum(["postmark", "resend", "ses", "smtp"]).optional(),
26
- locale: zod_1.z.string().optional(),
27
- currency: zod_1.z.string().optional(),
28
- })
29
- .optional(),
30
- });
31
- class ConfigManager {
32
- config;
33
- constructor() {
34
- this.config = {
35
- registry: "https://marketplace.kaven.site",
36
- telemetry: true,
37
- theme: "dark",
38
- locale: "en-US",
39
- };
40
- }
41
- async initialize() {
42
- await fs_extra_1.default.ensureDir(CONFIG_DIR);
43
- if (await fs_extra_1.default.pathExists(CONFIG_PATH)) {
44
- try {
45
- const raw = await fs_extra_1.default.readJson(CONFIG_PATH);
46
- const parsed = exports.configSchema.safeParse(raw);
47
- if (parsed.success) {
48
- this.config = parsed.data;
49
- }
50
- else {
51
- // If validation fails, use defaults
52
- this.config = {
53
- registry: "https://marketplace.kaven.site",
54
- telemetry: true,
55
- theme: "dark",
56
- locale: "en-US",
57
- };
58
- }
59
- }
60
- catch {
61
- // If file is corrupted, start fresh
62
- this.config = {
63
- registry: "https://marketplace.kaven.site",
64
- telemetry: true,
65
- theme: "dark",
66
- locale: "en-US",
67
- };
68
- }
69
- }
70
- else {
71
- // Initialize with defaults
72
- this.config = {
73
- registry: "https://marketplace.kaven.site",
74
- telemetry: true,
75
- theme: "dark",
76
- locale: "en-US",
77
- };
78
- await this.persist();
79
- }
80
- }
81
- /**
82
- * Get config value with env var override support
83
- * Priority: ENV VAR > config file > CLI arg > default
84
- */
85
- get(key, envVarName) {
86
- // Check environment variable override
87
- if (envVarName) {
88
- const envValue = process.env[envVarName];
89
- if (envValue !== undefined) {
90
- return envValue;
91
- }
92
- }
93
- // Check config file
94
- const value = this.config[key];
95
- if (value !== undefined) {
96
- return value;
97
- }
98
- // Return default from schema
99
- const defaults = exports.configSchema.parse({});
100
- return defaults[key];
101
- }
102
- /**
103
- * Set config value and persist to disk
104
- */
105
- async set(key, value) {
106
- const updateObj = { [key]: value };
107
- const updated = exports.configSchema.safeParse({ ...this.config, ...updateObj });
108
- if (!updated.success) {
109
- const errors = updated.error.issues
110
- .map((issue) => `${issue.path.join(".")}: ${issue.message}`)
111
- .join(", ");
112
- throw new Error(`Invalid config: ${errors}`);
113
- }
114
- this.config = updated.data;
115
- await this.persist();
116
- }
117
- /**
118
- * Get all config
119
- */
120
- getAll() {
121
- return { ...this.config };
122
- }
123
- /**
124
- * Reset config to defaults
125
- */
126
- async reset() {
127
- this.config = {
128
- registry: "https://marketplace.kaven.site",
129
- telemetry: true,
130
- theme: "dark",
131
- locale: "en-US",
132
- };
133
- await this.persist();
134
- }
135
- /**
136
- * Persist config to disk
137
- */
138
- async persist() {
139
- await fs_extra_1.default.ensureDir(CONFIG_DIR);
140
- await fs_extra_1.default.writeJson(CONFIG_PATH, this.config, { spaces: 2 });
141
- }
142
- /**
143
- * Get registry URL (custom or default)
144
- */
145
- getRegistry() {
146
- return (this.config.customRegistry || this.config.registry || "https://marketplace.kaven.site");
147
- }
148
- /**
149
- * Check if telemetry is enabled (can be overridden by env var)
150
- */
151
- isTelemetryEnabled() {
152
- if (process.env.KAVEN_TELEMETRY === "0") {
153
- return false;
154
- }
155
- return this.config.telemetry !== false;
156
- }
157
- /**
158
- * Get config directory path
159
- */
160
- getConfigDir() {
161
- return CONFIG_DIR;
162
- }
163
- }
164
- exports.ConfigManager = ConfigManager;
165
- // Export singleton instance
166
- exports.configManager = new ConfigManager();
@@ -1,196 +0,0 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
- var __importDefault = (this && this.__importDefault) || function (mod) {
36
- return (mod && mod.__esModule) ? mod : { "default": mod };
37
- };
38
- Object.defineProperty(exports, "__esModule", { value: true });
39
- exports.EnvManager = void 0;
40
- const fs = __importStar(require("fs"));
41
- const path = __importStar(require("path"));
42
- const readline = __importStar(require("readline"));
43
- const chalk_1 = __importDefault(require("chalk"));
44
- class EnvManager {
45
- async injectEnvVars(moduleSlug, envVars, options) {
46
- if (options.skipEnv || !envVars || envVars.length === 0) {
47
- return { added: 0, skipped: 0 };
48
- }
49
- const envFilePath = path.join(options.projectDir, options.envFile ?? '.env');
50
- const existingContent = this.readEnvFile(envFilePath);
51
- const existingVars = this.parseEnvFile(existingContent);
52
- const newVars = [];
53
- let skipped = 0;
54
- console.log(chalk_1.default.bold(`\n Environment variables for '${moduleSlug}':\n`));
55
- for (const envDef of envVars) {
56
- if (existingVars.has(envDef.name)) {
57
- console.log(chalk_1.default.dim(` ${envDef.name} — already set, skipping`));
58
- skipped++;
59
- continue;
60
- }
61
- let value;
62
- if (envDef.sensitive) {
63
- value = await this.promptPassword(` ${envDef.name} (${envDef.description})${envDef.default ? ' [****]' : ''}: `);
64
- if (!value && envDef.default)
65
- value = envDef.default;
66
- }
67
- else {
68
- const defaultHint = envDef.default ? ` [${envDef.default}]` : '';
69
- value = await this.promptInput(` ${envDef.name} (${envDef.description})${defaultHint}: `, envDef.default);
70
- }
71
- if (envDef.required && !value) {
72
- console.log(chalk_1.default.yellow(` ${envDef.name} is required.`));
73
- value = envDef.sensitive
74
- ? await this.promptPassword(` ${envDef.name}: `)
75
- : await this.promptInput(` ${envDef.name}: `);
76
- if (!value) {
77
- console.log(chalk_1.default.yellow(` Skipping ${envDef.name} — set it manually in .env`));
78
- skipped++;
79
- continue;
80
- }
81
- }
82
- newVars.push({ name: envDef.name, value });
83
- }
84
- if (newVars.length === 0) {
85
- console.log(chalk_1.default.dim(' No new environment variables to add.'));
86
- return { added: 0, skipped };
87
- }
88
- const markerBlock = this.buildMarkerBlock(moduleSlug, newVars);
89
- this.appendToEnvFile(envFilePath, existingContent, markerBlock);
90
- console.log(chalk_1.default.green(`\n Added ${newVars.length} environment variable(s) to ${options.envFile ?? '.env'}`));
91
- return { added: newVars.length, skipped };
92
- }
93
- removeEnvVars(moduleSlug, options) {
94
- const envFiles = ['.env', '.env.local', '.env.development', '.env.production'];
95
- if (options.envFile)
96
- envFiles.unshift(options.envFile);
97
- let totalRemoved = 0;
98
- for (const envFile of envFiles) {
99
- const envFilePath = path.join(options.projectDir, envFile);
100
- if (!fs.existsSync(envFilePath))
101
- continue;
102
- const content = fs.readFileSync(envFilePath, 'utf-8');
103
- const beginMarker = `# [KAVEN_MODULE:${moduleSlug} BEGIN]`;
104
- const endMarker = `# [KAVEN_MODULE:${moduleSlug} END]`;
105
- const beginIdx = content.indexOf(beginMarker);
106
- const endIdx = content.indexOf(endMarker);
107
- if (beginIdx === -1 || endIdx === -1)
108
- continue;
109
- const block = content.substring(beginIdx, endIdx + endMarker.length);
110
- const varCount = block.split('\n').filter(l => /^[A-Z_]+=/.test(l)).length;
111
- const before = content.substring(0, beginIdx).replace(/\n+$/, '\n');
112
- const after = content.substring(endIdx + endMarker.length + 1);
113
- fs.writeFileSync(envFilePath, before + after);
114
- totalRemoved += varCount;
115
- if (varCount > 0) {
116
- console.log(chalk_1.default.dim(` Removed ${varCount} env var(s) from ${envFile}`));
117
- }
118
- }
119
- return totalRemoved;
120
- }
121
- readEnvFile(filePath) {
122
- try {
123
- return fs.readFileSync(filePath, 'utf-8');
124
- }
125
- catch {
126
- return '';
127
- }
128
- }
129
- parseEnvFile(content) {
130
- const vars = new Map();
131
- for (const line of content.split('\n')) {
132
- const match = line.match(/^([A-Z_][A-Z0-9_]*)=(.*)$/);
133
- if (match)
134
- vars.set(match[1], match[2]);
135
- }
136
- return vars;
137
- }
138
- buildMarkerBlock(moduleSlug, vars) {
139
- return [
140
- `# [KAVEN_MODULE:${moduleSlug} BEGIN]`,
141
- ...vars.map(v => `${v.name}=${v.value}`),
142
- `# [KAVEN_MODULE:${moduleSlug} END]`,
143
- ].join('\n');
144
- }
145
- appendToEnvFile(filePath, existingContent, block) {
146
- fs.mkdirSync(path.dirname(filePath), { recursive: true });
147
- const separator = existingContent.endsWith('\n') || existingContent === '' ? '\n' : '\n\n';
148
- fs.writeFileSync(filePath, existingContent + separator + block + '\n');
149
- }
150
- promptInput(message, defaultValue) {
151
- return new Promise(resolve => {
152
- const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
153
- rl.question(message, answer => {
154
- rl.close();
155
- resolve(answer || defaultValue || '');
156
- });
157
- });
158
- }
159
- promptPassword(message) {
160
- return new Promise(resolve => {
161
- const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
162
- // Hide input by listening to keypress but readline doesn't natively support this
163
- // For simplicity, use standard prompt (production would use a proper password lib)
164
- process.stdout.write(message);
165
- process.stdin.setRawMode?.(true);
166
- process.stdin.resume();
167
- let password = '';
168
- const handler = (key) => {
169
- const char = key.toString();
170
- if (char === '\r' || char === '\n') {
171
- process.stdin.setRawMode?.(false);
172
- process.stdin.pause();
173
- process.stdin.removeListener('data', handler);
174
- process.stdout.write('\n');
175
- rl.close();
176
- resolve(password);
177
- }
178
- else if (char === '\u0003') {
179
- process.exit();
180
- }
181
- else if (char === '\u007f') {
182
- password = password.slice(0, -1);
183
- process.stdout.clearLine(0);
184
- process.stdout.cursorTo(0);
185
- process.stdout.write(message + '*'.repeat(password.length));
186
- }
187
- else {
188
- password += char;
189
- process.stdout.write('*');
190
- }
191
- };
192
- process.stdin.on('data', handler);
193
- });
194
- }
195
- }
196
- exports.EnvManager = EnvManager;
@@ -1,192 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.ErrorRecovery = void 0;
7
- const path_1 = __importDefault(require("path"));
8
- const fs_extra_1 = __importDefault(require("fs-extra"));
9
- const os_1 = __importDefault(require("os"));
10
- const chalk_1 = __importDefault(require("chalk"));
11
- const ora_1 = __importDefault(require("ora"));
12
- /**
13
- * C2.7: Error recovery and validation system
14
- */
15
- class ErrorRecovery {
16
- backupDir;
17
- constructor() {
18
- this.backupDir = path_1.default.join(os_1.default.homedir(), ".kaven", "backups");
19
- }
20
- /**
21
- * Create a backup of the project state before operation
22
- */
23
- async createBackup(projectPath, operationName) {
24
- const timestamp = new Date().toISOString().replace(/[:.]/g, "-").substring(0, 19);
25
- const backupName = `${operationName}-${timestamp}`;
26
- const backupPath = path_1.default.join(this.backupDir, backupName);
27
- try {
28
- await fs_extra_1.default.ensureDir(this.backupDir);
29
- // Backup key files
30
- const files = ["package.json", "pnpm-lock.yaml", ".env", "prisma/schema.prisma"];
31
- for (const file of files) {
32
- const source = path_1.default.join(projectPath, file);
33
- const dest = path_1.default.join(backupPath, file);
34
- if (await fs_extra_1.default.pathExists(source)) {
35
- await fs_extra_1.default.ensureDir(path_1.default.dirname(dest));
36
- await fs_extra_1.default.copy(source, dest);
37
- }
38
- }
39
- return backupPath;
40
- }
41
- catch (error) {
42
- throw new Error(`Failed to create backup: ${error instanceof Error ? error.message : String(error)}`);
43
- }
44
- }
45
- /**
46
- * Rollback from backup
47
- */
48
- async rollback(projectPath, backupPath) {
49
- try {
50
- if (!(await fs_extra_1.default.pathExists(backupPath))) {
51
- throw new Error(`Backup not found at ${backupPath}`);
52
- }
53
- const files = ["package.json", "pnpm-lock.yaml", ".env", "prisma/schema.prisma"];
54
- for (const file of files) {
55
- const source = path_1.default.join(backupPath, file);
56
- const dest = path_1.default.join(projectPath, file);
57
- if (await fs_extra_1.default.pathExists(source)) {
58
- await fs_extra_1.default.copy(source, dest, { overwrite: true });
59
- }
60
- }
61
- }
62
- catch (error) {
63
- throw new Error(`Failed to rollback: ${error instanceof Error ? error.message : String(error)}`);
64
- }
65
- }
66
- /**
67
- * Pre-operation validation
68
- */
69
- async validatePreConditions(projectPath) {
70
- const errors = [];
71
- // Check package.json exists
72
- if (!(await fs_extra_1.default.pathExists(path_1.default.join(projectPath, "package.json")))) {
73
- errors.push("package.json not found");
74
- }
75
- // Check node_modules exists
76
- if (!(await fs_extra_1.default.pathExists(path_1.default.join(projectPath, "node_modules")))) {
77
- errors.push("Dependencies not installed. Run: pnpm install");
78
- }
79
- // Check if git repo (for safety)
80
- const gitDir = path_1.default.join(projectPath, ".git");
81
- if (!(await fs_extra_1.default.pathExists(gitDir))) {
82
- errors.push("Not a git repository. Initialize with: git init && git add . && git commit");
83
- }
84
- return {
85
- valid: errors.length === 0,
86
- errors,
87
- };
88
- }
89
- /**
90
- * Post-operation health check
91
- */
92
- async validatePostConditions(projectPath) {
93
- const issues = [];
94
- // Check package.json is valid JSON
95
- try {
96
- const packageJson = await fs_extra_1.default.readJson(path_1.default.join(projectPath, "package.json"));
97
- if (!packageJson.name) {
98
- issues.push("package.json missing name field");
99
- }
100
- }
101
- catch {
102
- issues.push("package.json is invalid JSON");
103
- }
104
- // Check prisma schema if it exists
105
- const schemaPath = path_1.default.join(projectPath, "prisma", "schema.prisma");
106
- if (await fs_extra_1.default.pathExists(schemaPath)) {
107
- const content = await fs_extra_1.default.readFile(schemaPath, "utf-8");
108
- if (!content.includes("datasource db")) {
109
- issues.push("prisma/schema.prisma missing datasource");
110
- }
111
- }
112
- // Check .env exists or .env.example exists
113
- const envPath = path_1.default.join(projectPath, ".env");
114
- const envExamplePath = path_1.default.join(projectPath, ".env.example");
115
- if (!(await fs_extra_1.default.pathExists(envPath)) && !(await fs_extra_1.default.pathExists(envExamplePath))) {
116
- issues.push("No .env or .env.example file found");
117
- }
118
- return {
119
- healthy: issues.length === 0,
120
- issues,
121
- };
122
- }
123
- /**
124
- * Run operation with automatic rollback on failure
125
- */
126
- async withRollback(projectPath, operationName, operation) {
127
- // Pre-validation
128
- const preCheck = await this.validatePreConditions(projectPath);
129
- if (!preCheck.valid) {
130
- throw new Error(`Pre-conditions not met:\n${preCheck.errors.map((e) => ` - ${e}`).join("\n")}`);
131
- }
132
- // Create backup
133
- const spinner = (0, ora_1.default)("Creating backup...").start();
134
- const backupPath = await this.createBackup(projectPath, operationName);
135
- spinner.succeed(`Backup created at ${backupPath}`);
136
- try {
137
- // Run operation
138
- const result = await operation();
139
- // Post-validation
140
- const postCheck = await this.validatePostConditions(projectPath);
141
- if (!postCheck.healthy) {
142
- spinner.warn("Post-operation issues detected:");
143
- for (const issue of postCheck.issues) {
144
- console.log(chalk_1.default.yellow(` ⚠ ${issue}`));
145
- }
146
- }
147
- return result;
148
- }
149
- catch (error) {
150
- // Rollback on failure
151
- spinner.start("Rolling back...");
152
- try {
153
- await this.rollback(projectPath, backupPath);
154
- spinner.succeed("Rolled back successfully");
155
- }
156
- catch (rollbackError) {
157
- spinner.fail(`Rollback failed: ${rollbackError}`);
158
- console.error(chalk_1.default.red("Manual intervention required:"));
159
- console.error(chalk_1.default.gray(`Backup available at: ${backupPath}`));
160
- }
161
- throw error;
162
- }
163
- }
164
- /**
165
- * List available backups
166
- */
167
- async listBackups() {
168
- if (!(await fs_extra_1.default.pathExists(this.backupDir))) {
169
- return [];
170
- }
171
- const entries = await fs_extra_1.default.readdir(this.backupDir);
172
- return entries.map((name) => ({
173
- name,
174
- path: path_1.default.join(this.backupDir, name),
175
- timestamp: name.substring(name.lastIndexOf("-") + 1),
176
- }));
177
- }
178
- /**
179
- * Clean old backups (keep last N)
180
- */
181
- async cleanupBackups(keepCount = 5) {
182
- const backups = await this.listBackups();
183
- if (backups.length <= keepCount) {
184
- return;
185
- }
186
- const toDelete = backups.slice(keepCount);
187
- for (const backup of toDelete) {
188
- await fs_extra_1.default.remove(backup.path);
189
- }
190
- }
191
- }
192
- exports.ErrorRecovery = ErrorRecovery;
@@ -1,83 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.LicenseService = void 0;
7
- const promises_1 = __importDefault(require("fs/promises"));
8
- const path_1 = __importDefault(require("path"));
9
- const os_1 = __importDefault(require("os"));
10
- const CACHE_FILE = path_1.default.join(os_1.default.homedir(), '.kaven', 'cache', 'licenses.json');
11
- const CACHE_TTL_MS = 60 * 60 * 1000; // 1 hour
12
- class LicenseService {
13
- cacheDir = path_1.default.join(os_1.default.homedir(), '.kaven', 'cache');
14
- /** Luhn mod-31 checksum format check (KAVEN-{TIER}-{8RANDOM}-{CHECKSUM}) */
15
- isValidFormat(licenseKey) {
16
- const pattern = /^KAVEN-(STARTER|COMPLETE|PRO|ENTERPRISE)-[A-Z0-9]{8}-[A-Z0-9]{2}$/;
17
- return pattern.test(licenseKey);
18
- }
19
- async readCache() {
20
- try {
21
- const raw = await promises_1.default.readFile(CACHE_FILE, 'utf-8');
22
- return JSON.parse(raw);
23
- }
24
- catch {
25
- return {};
26
- }
27
- }
28
- async writeCache(cache) {
29
- await promises_1.default.mkdir(this.cacheDir, { recursive: true });
30
- await promises_1.default.writeFile(CACHE_FILE, JSON.stringify(cache, null, 2), 'utf-8');
31
- }
32
- isCacheValid(entry) {
33
- return Date.now() - entry.validatedAt < CACHE_TTL_MS;
34
- }
35
- async getCached(licenseKey) {
36
- const cache = await this.readCache();
37
- const entry = cache[licenseKey];
38
- if (entry && this.isCacheValid(entry))
39
- return entry;
40
- return null;
41
- }
42
- async setCached(entry) {
43
- const cache = await this.readCache();
44
- cache[entry.key] = { ...entry, validatedAt: Date.now() };
45
- await this.writeCache(cache);
46
- }
47
- async validateLicense(licenseKey, requiredTier) {
48
- // 1. Check cache first
49
- const cached = await this.getCached(licenseKey);
50
- if (cached) {
51
- return { valid: true, tier: cached.tier, expiresAt: cached.expiresAt, source: 'cache' };
52
- }
53
- // 2. Format check (offline Luhn-style)
54
- if (!this.isValidFormat(licenseKey)) {
55
- throw new Error('Invalid license key format');
56
- }
57
- // 3. API validation
58
- const { MarketplaceClient } = await import('../infrastructure/MarketplaceClient.js');
59
- const client = new MarketplaceClient();
60
- const result = await client.validateLicense(licenseKey, requiredTier);
61
- // Cache on success
62
- await this.setCached({
63
- key: licenseKey,
64
- tier: result.tier,
65
- expiresAt: result.expiresAt,
66
- validatedAt: Date.now(),
67
- });
68
- return { ...result, source: 'api' };
69
- }
70
- async getLicenseStatus(licenseKey) {
71
- const { MarketplaceClient } = await import('../infrastructure/MarketplaceClient.js');
72
- const client = new MarketplaceClient();
73
- return client.getLicenseStatus(licenseKey);
74
- }
75
- tierLevel(tier) {
76
- const levels = { STARTER: 1, COMPLETE: 2, PRO: 3, ENTERPRISE: 4 };
77
- return levels[tier.toUpperCase()] ?? 0;
78
- }
79
- userHasRequiredTier(userTier, requiredTier) {
80
- return this.tierLevel(userTier) >= this.tierLevel(requiredTier);
81
- }
82
- }
83
- exports.LicenseService = LicenseService;
@@ -1,52 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.ManifestParser = void 0;
7
- const fs_extra_1 = __importDefault(require("fs-extra"));
8
- const manifest_1 = require("../types/manifest");
9
- const zod_1 = require("zod");
10
- class ManifestParser {
11
- async parse(manifestPath) {
12
- if (!(await fs_extra_1.default.pathExists(manifestPath))) {
13
- throw new Error(`Manifest not found: ${manifestPath}`);
14
- }
15
- const content = await fs_extra_1.default.readFile(manifestPath, "utf-8");
16
- let json;
17
- try {
18
- json = JSON.parse(content);
19
- }
20
- catch {
21
- throw new Error(`Failed to parse manifest JSON: ${manifestPath}`);
22
- }
23
- try {
24
- return manifest_1.ModuleManifestSchema.parse(json);
25
- }
26
- catch (error) {
27
- if (error instanceof zod_1.ZodError) {
28
- throw new Error(`Invalid manifest: \n${this.formatZodError(error)}`);
29
- }
30
- throw error;
31
- }
32
- }
33
- async validate(manifestPath) {
34
- try {
35
- await this.parse(manifestPath);
36
- return { valid: true, errors: [] };
37
- }
38
- catch (error) {
39
- const errorMessage = error instanceof Error ? error.message : String(error);
40
- return {
41
- valid: false,
42
- errors: [errorMessage],
43
- };
44
- }
45
- }
46
- formatZodError(error) {
47
- return error.issues
48
- .map((err) => ` - ${err.path.map(String).join(".")}: ${err.message}`)
49
- .join("\n");
50
- }
51
- }
52
- exports.ManifestParser = ManifestParser;