tailar 0.2.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 (104) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +183 -0
  3. package/README.npm.md +183 -0
  4. package/dist/api/client.d.ts +47 -0
  5. package/dist/api/client.d.ts.map +1 -0
  6. package/dist/api/client.js +329 -0
  7. package/dist/api/client.js.map +1 -0
  8. package/dist/auth/browser.d.ts +11 -0
  9. package/dist/auth/browser.d.ts.map +1 -0
  10. package/dist/auth/browser.js +46 -0
  11. package/dist/auth/browser.js.map +1 -0
  12. package/dist/auth/flow.d.ts +28 -0
  13. package/dist/auth/flow.d.ts.map +1 -0
  14. package/dist/auth/flow.js +171 -0
  15. package/dist/auth/flow.js.map +1 -0
  16. package/dist/auth/storage.d.ts +30 -0
  17. package/dist/auth/storage.d.ts.map +1 -0
  18. package/dist/auth/storage.js +112 -0
  19. package/dist/auth/storage.js.map +1 -0
  20. package/dist/commands/add.d.ts +8 -0
  21. package/dist/commands/add.d.ts.map +1 -0
  22. package/dist/commands/add.js +285 -0
  23. package/dist/commands/add.js.map +1 -0
  24. package/dist/commands/init.d.ts +8 -0
  25. package/dist/commands/init.d.ts.map +1 -0
  26. package/dist/commands/init.js +230 -0
  27. package/dist/commands/init.js.map +1 -0
  28. package/dist/commands/list.d.ts +8 -0
  29. package/dist/commands/list.d.ts.map +1 -0
  30. package/dist/commands/list.js +176 -0
  31. package/dist/commands/list.js.map +1 -0
  32. package/dist/index.d.ts +9 -0
  33. package/dist/index.d.ts.map +1 -0
  34. package/dist/index.js +83 -0
  35. package/dist/index.js.map +1 -0
  36. package/dist/installers/dependencies.d.ts +27 -0
  37. package/dist/installers/dependencies.d.ts.map +1 -0
  38. package/dist/installers/dependencies.js +185 -0
  39. package/dist/installers/dependencies.js.map +1 -0
  40. package/dist/installers/files.d.ts +50 -0
  41. package/dist/installers/files.d.ts.map +1 -0
  42. package/dist/installers/files.js +211 -0
  43. package/dist/installers/files.js.map +1 -0
  44. package/dist/installers/install-feature.d.ts +20 -0
  45. package/dist/installers/install-feature.d.ts.map +1 -0
  46. package/dist/installers/install-feature.js +169 -0
  47. package/dist/installers/install-feature.js.map +1 -0
  48. package/dist/installers/post-install.d.ts +18 -0
  49. package/dist/installers/post-install.d.ts.map +1 -0
  50. package/dist/installers/post-install.js +228 -0
  51. package/dist/installers/post-install.js.map +1 -0
  52. package/dist/installers/templates.d.ts +22 -0
  53. package/dist/installers/templates.d.ts.map +1 -0
  54. package/dist/installers/templates.js +62 -0
  55. package/dist/installers/templates.js.map +1 -0
  56. package/dist/registry/loader.d.ts +21 -0
  57. package/dist/registry/loader.d.ts.map +1 -0
  58. package/dist/registry/loader.js +83 -0
  59. package/dist/registry/loader.js.map +1 -0
  60. package/dist/registry/query.d.ts +55 -0
  61. package/dist/registry/query.d.ts.map +1 -0
  62. package/dist/registry/query.js +123 -0
  63. package/dist/registry/query.js.map +1 -0
  64. package/dist/types/config.d.ts +85 -0
  65. package/dist/types/config.d.ts.map +1 -0
  66. package/dist/types/config.js +7 -0
  67. package/dist/types/config.js.map +1 -0
  68. package/dist/types/index.d.ts +9 -0
  69. package/dist/types/index.d.ts.map +1 -0
  70. package/dist/types/index.js +9 -0
  71. package/dist/types/index.js.map +1 -0
  72. package/dist/types/registry.d.ts +180 -0
  73. package/dist/types/registry.d.ts.map +1 -0
  74. package/dist/types/registry.js +8 -0
  75. package/dist/types/registry.js.map +1 -0
  76. package/dist/types/wizard.d.ts +43 -0
  77. package/dist/types/wizard.d.ts.map +1 -0
  78. package/dist/types/wizard.js +59 -0
  79. package/dist/types/wizard.js.map +1 -0
  80. package/dist/utils/clack-wizard.d.ts +9 -0
  81. package/dist/utils/clack-wizard.d.ts.map +1 -0
  82. package/dist/utils/clack-wizard.js +328 -0
  83. package/dist/utils/clack-wizard.js.map +1 -0
  84. package/dist/utils/config.d.ts +49 -0
  85. package/dist/utils/config.d.ts.map +1 -0
  86. package/dist/utils/config.js +121 -0
  87. package/dist/utils/config.js.map +1 -0
  88. package/dist/utils/logger.d.ts +56 -0
  89. package/dist/utils/logger.d.ts.map +1 -0
  90. package/dist/utils/logger.js +93 -0
  91. package/dist/utils/logger.js.map +1 -0
  92. package/dist/utils/package-manager.d.ts +41 -0
  93. package/dist/utils/package-manager.d.ts.map +1 -0
  94. package/dist/utils/package-manager.js +118 -0
  95. package/dist/utils/package-manager.js.map +1 -0
  96. package/dist/utils/prompts.d.ts +22 -0
  97. package/dist/utils/prompts.d.ts.map +1 -0
  98. package/dist/utils/prompts.js +142 -0
  99. package/dist/utils/prompts.js.map +1 -0
  100. package/dist/utils/validation.d.ts +50 -0
  101. package/dist/utils/validation.d.ts.map +1 -0
  102. package/dist/utils/validation.js +108 -0
  103. package/dist/utils/validation.js.map +1 -0
  104. package/package.json +56 -0
@@ -0,0 +1,185 @@
1
+ /**
2
+ * Dependency Manager
3
+ *
4
+ * Handles merging dependencies into package.json and running install commands.
5
+ */
6
+ import { readFile, writeFile } from "fs/promises";
7
+ import { join } from "path";
8
+ import { execSync } from "child_process";
9
+ import { getInstallCommand } from "../utils/package-manager.js";
10
+ /**
11
+ * Read package.json
12
+ */
13
+ async function readPackageJson(projectPath) {
14
+ const packagePath = join(projectPath, "package.json");
15
+ const content = await readFile(packagePath, "utf-8");
16
+ return JSON.parse(content);
17
+ }
18
+ /**
19
+ * Write package.json
20
+ */
21
+ async function writePackageJson(projectPath, pkg) {
22
+ const packagePath = join(projectPath, "package.json");
23
+ const content = JSON.stringify(pkg, null, 2) + "\n";
24
+ await writeFile(packagePath, content, "utf-8");
25
+ }
26
+ /**
27
+ * Merge dependencies into package.json
28
+ */
29
+ export async function mergeDependencies(projectPath, dependencyMaps) {
30
+ const pkg = await readPackageJson(projectPath);
31
+ const added = {
32
+ dependencies: [],
33
+ devDependencies: [],
34
+ };
35
+ const conflicts = [];
36
+ // Ensure dependency objects exist
37
+ pkg.dependencies = pkg.dependencies || {};
38
+ pkg.devDependencies = pkg.devDependencies || {};
39
+ // Helper to resolve version conflicts by using the higher version
40
+ // Only reports conflicts if versions are truly incompatible (different major versions)
41
+ function resolveVersionConflict(existing, incoming) {
42
+ if (existing === incoming) {
43
+ return { version: existing, isConflict: false };
44
+ }
45
+ // Extract version numbers from semver ranges (e.g., ^0.561.0 -> 0.561.0)
46
+ const extractVersion = (v) => {
47
+ // Remove range prefixes (^, ~, >=, etc.)
48
+ return v.replace(/^[\^~>=<]+/, "");
49
+ };
50
+ // Extract prefix (^, ~, etc.)
51
+ const extractPrefix = (v) => {
52
+ const match = v.match(/^([\^~>=<]+)/);
53
+ return match ? match[1] : "^";
54
+ };
55
+ const existingVersion = extractVersion(existing);
56
+ const incomingVersion = extractVersion(incoming);
57
+ const existingPrefix = extractPrefix(existing);
58
+ const incomingPrefix = extractPrefix(incoming);
59
+ // Parse version numbers for comparison (major.minor.patch)
60
+ const parseVersion = (v) => {
61
+ return v.split(".").map((n) => parseInt(n, 10) || 0);
62
+ };
63
+ const existingParts = parseVersion(existingVersion);
64
+ const incomingParts = parseVersion(incomingVersion);
65
+ // Check if versions are compatible (same major version with compatible prefixes)
66
+ // For ^ prefix, versions with same major are compatible
67
+ const sameMajor = existingParts[0] === incomingParts[0];
68
+ const compatiblePrefixes = (existingPrefix === "^" && incomingPrefix === "^") ||
69
+ (existingPrefix === "~" && incomingPrefix === "~") ||
70
+ existingPrefix === incomingPrefix;
71
+ // Compare versions part by part
72
+ let useIncoming = false;
73
+ for (let i = 0; i < Math.max(existingParts.length, incomingParts.length); i++) {
74
+ const existingPart = existingParts[i] || 0;
75
+ const incomingPart = incomingParts[i] || 0;
76
+ if (incomingPart > existingPart) {
77
+ useIncoming = true;
78
+ break;
79
+ }
80
+ else if (incomingPart < existingPart) {
81
+ break;
82
+ }
83
+ }
84
+ // Use the higher version, preserving the prefix from the higher version
85
+ const higherVersion = useIncoming ? incoming : existing;
86
+ // Only report as conflict if versions are truly incompatible:
87
+ // - Different major versions (breaking changes)
88
+ // - Different prefixes that affect compatibility (^ vs ~ vs exact)
89
+ // For same major version with compatible prefixes, they're compatible (no conflict)
90
+ const isConflict = !(sameMajor && compatiblePrefixes);
91
+ return { version: higherVersion, isConflict };
92
+ }
93
+ // Merge all dependency maps
94
+ for (const depMap of dependencyMaps) {
95
+ // Merge dependencies
96
+ if (depMap.dependencies) {
97
+ for (const [name, version] of Object.entries(depMap.dependencies)) {
98
+ const existing = pkg.dependencies[name];
99
+ if (existing) {
100
+ const resolved = resolveVersionConflict(existing, version);
101
+ if (resolved.isConflict) {
102
+ conflicts.push(`${name}: ${existing} vs ${version} (using ${resolved.version})`);
103
+ }
104
+ pkg.dependencies[name] = resolved.version;
105
+ }
106
+ else {
107
+ pkg.dependencies[name] = version;
108
+ }
109
+ added.dependencies.push(name);
110
+ }
111
+ }
112
+ // Merge devDependencies
113
+ if (depMap.devDependencies) {
114
+ for (const [name, version] of Object.entries(depMap.devDependencies)) {
115
+ const existing = pkg.devDependencies[name];
116
+ if (existing) {
117
+ const resolved = resolveVersionConflict(existing, version);
118
+ if (resolved.isConflict) {
119
+ conflicts.push(`${name}: ${existing} vs ${version} (using ${resolved.version})`);
120
+ }
121
+ pkg.devDependencies[name] = resolved.version;
122
+ }
123
+ else {
124
+ pkg.devDependencies[name] = version;
125
+ }
126
+ added.devDependencies.push(name);
127
+ }
128
+ }
129
+ }
130
+ // Sort dependencies alphabetically
131
+ pkg.dependencies = sortObject(pkg.dependencies);
132
+ pkg.devDependencies = sortObject(pkg.devDependencies);
133
+ // Write updated package.json
134
+ await writePackageJson(projectPath, pkg);
135
+ return { added, conflicts };
136
+ }
137
+ /**
138
+ * Sort object keys alphabetically
139
+ */
140
+ function sortObject(obj) {
141
+ return Object.keys(obj)
142
+ .sort()
143
+ .reduce((sorted, key) => {
144
+ sorted[key] = obj[key];
145
+ return sorted;
146
+ }, {});
147
+ }
148
+ /**
149
+ * Run package manager install
150
+ */
151
+ export async function runInstall(projectPath, packageManager, options = {}) {
152
+ let command = getInstallCommand(packageManager);
153
+ // Add legacy peer deps flag for npm to handle version conflicts
154
+ if (packageManager === "npm") {
155
+ command += " --legacy-peer-deps";
156
+ }
157
+ try {
158
+ execSync(command, {
159
+ cwd: projectPath,
160
+ stdio: options.silent ? "ignore" : "inherit",
161
+ });
162
+ }
163
+ catch (error) {
164
+ throw new Error(`Failed to run ${command}: ${error}`);
165
+ }
166
+ }
167
+ /**
168
+ * Collect all dependencies from entry and its variants
169
+ */
170
+ export function collectDependencies(entry, selectedVariant) {
171
+ const deps = [];
172
+ // Add entry's base dependencies
173
+ if (entry.dependencies) {
174
+ deps.push(entry.dependencies);
175
+ }
176
+ // Add variant-specific dependencies
177
+ if (selectedVariant && entry.variants) {
178
+ const variant = entry.variants.find((v) => v.name === selectedVariant);
179
+ if (variant?.dependencies) {
180
+ deps.push(variant.dependencies);
181
+ }
182
+ }
183
+ return deps;
184
+ }
185
+ //# sourceMappingURL=dependencies.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dependencies.js","sourceRoot":"","sources":["../../src/installers/dependencies.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,50 @@
1
+ /**
2
+ * File Installer
3
+ *
4
+ * Handles file installation, template substitution, and path resolution.
5
+ * Always uses API endpoint for fetching files.
6
+ */
7
+ import { FileMapping, ProjectContext } from "../types/index.js";
8
+ /**
9
+ * Resolve template variables in a path
10
+ */
11
+ export declare function resolveTemplatePath(path: string, context: ProjectContext, variables?: Record<string, string>): string;
12
+ /**
13
+ * Apply template substitution to file content
14
+ */
15
+ export declare function applyTemplateSubstitution(content: string, variables: Record<string, string>): string;
16
+ /**
17
+ * Merge JSON content with existing JSON file
18
+ */
19
+ export declare function mergeJsonContent(existingContent: string, newContent: string): string;
20
+ /**
21
+ * Check if file exists at target location
22
+ */
23
+ export declare function checkFileExists(projectPath: string, targetPath: string): boolean;
24
+ /**
25
+ * Install a single file
26
+ */
27
+ export declare function installFile(sourceContent: string, projectPath: string, targetPath: string, variables?: Record<string, string>, options?: {
28
+ overwrite?: boolean;
29
+ strategy?: "override" | "merge";
30
+ }): Promise<void>;
31
+ /**
32
+ * Install multiple files from file mappings
33
+ * Files are always fetched from API endpoint.
34
+ */
35
+ export declare function installFiles(projectPath: string, fileMappings: FileMapping[], context: ProjectContext, variables: Record<string, string> | undefined, options: {
36
+ overwrite?: boolean;
37
+ dryRun?: boolean;
38
+ componentType: "feature" | "block" | "component" | "template";
39
+ componentName: string;
40
+ variant?: string;
41
+ registryEntry?: {
42
+ requiresSubscription?: boolean;
43
+ subscriptionTier?: number;
44
+ };
45
+ }): Promise<{
46
+ installed: string[];
47
+ skipped: string[];
48
+ conflicts: string[];
49
+ }>;
50
+ //# sourceMappingURL=files.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"files.d.ts","sourceRoot":"","sources":["../../src/installers/files.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAIhE;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,cAAc,EACvB,SAAS,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,GACrC,MAAM,CAuBR;AAED;;GAEG;AACH,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAChC,MAAM,CASR;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,eAAe,EAAE,MAAM,EACvB,UAAU,EAAE,MAAM,GACjB,MAAM,CAYR;AA8BD;;GAEG;AACH,wBAAgB,eAAe,CAC7B,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,MAAM,GACjB,OAAO,CAGT;AAED;;GAEG;AACH,wBAAsB,WAAW,CAC/B,aAAa,EAAE,MAAM,EACrB,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,MAAM,EAClB,SAAS,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,EACtC,OAAO,GAAE;IACP,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,QAAQ,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC;CAC5B,GACL,OAAO,CAAC,IAAI,CAAC,CAmCf;AA0BD;;;GAGG;AACH,wBAAsB,YAAY,CAChC,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,WAAW,EAAE,EAC3B,OAAO,EAAE,cAAc,EACvB,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,YAAK,EACtC,OAAO,EAAE;IACP,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,aAAa,EAAE,SAAS,GAAG,OAAO,GAAG,WAAW,GAAG,UAAU,CAAC;IAC9D,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,aAAa,CAAC,EAAE;QACd,oBAAoB,CAAC,EAAE,OAAO,CAAC;QAC/B,gBAAgB,CAAC,EAAE,MAAM,CAAC;KAC3B,CAAC;CACH,GACA,OAAO,CAAC;IACT,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,SAAS,EAAE,MAAM,EAAE,CAAC;CACrB,CAAC,CAqGD"}
@@ -0,0 +1,211 @@
1
+ /**
2
+ * File Installer
3
+ *
4
+ * Handles file installation, template substitution, and path resolution.
5
+ * Always uses API endpoint for fetching files.
6
+ */
7
+ import { readFile, writeFile, mkdir } from "fs/promises";
8
+ import { existsSync } from "fs";
9
+ import { join, dirname } from "path";
10
+ import { fetchComponentFile, checkSubscription } from "../api/client.js";
11
+ /**
12
+ * Resolve template variables in a path
13
+ */
14
+ export function resolveTemplatePath(path, context, variables = {}) {
15
+ let resolved = path;
16
+ // Built-in variables
17
+ const srcDir = context.structure.hasSrcFolder ? "src" : "";
18
+ const appDir = context.structure.hasSrcFolder ? "src/app" : "app";
19
+ const allVariables = {
20
+ SRC_DIR: srcDir,
21
+ APP_DIR: appDir,
22
+ ...variables,
23
+ };
24
+ // Replace all variables
25
+ for (const [key, value] of Object.entries(allVariables)) {
26
+ const placeholder = `{{${key}}}`;
27
+ resolved = resolved.replace(new RegExp(placeholder, "g"), value);
28
+ }
29
+ // Clean up empty path segments
30
+ resolved = resolved.replace(/\/+/g, "/").replace(/^\//, "");
31
+ return resolved;
32
+ }
33
+ /**
34
+ * Apply template substitution to file content
35
+ */
36
+ export function applyTemplateSubstitution(content, variables) {
37
+ let result = content;
38
+ for (const [key, value] of Object.entries(variables)) {
39
+ const placeholder = `{{${key}}}`;
40
+ result = result.replace(new RegExp(placeholder, "g"), value);
41
+ }
42
+ return result;
43
+ }
44
+ /**
45
+ * Merge JSON content with existing JSON file
46
+ */
47
+ export function mergeJsonContent(existingContent, newContent) {
48
+ try {
49
+ const existing = JSON.parse(existingContent);
50
+ const newData = JSON.parse(newContent);
51
+ // Deep merge the objects
52
+ const merged = deepMerge(existing, newData);
53
+ return JSON.stringify(merged, null, 2);
54
+ }
55
+ catch (error) {
56
+ throw new Error(`Failed to merge JSON: ${error}`);
57
+ }
58
+ }
59
+ /**
60
+ * Deep merge two objects
61
+ */
62
+ function deepMerge(target, source) {
63
+ if (!isObject(target) || !isObject(source)) {
64
+ return source;
65
+ }
66
+ const result = { ...target };
67
+ for (const key in source) {
68
+ if (isObject(source[key]) && isObject(target[key])) {
69
+ result[key] = deepMerge(target[key], source[key]);
70
+ }
71
+ else {
72
+ result[key] = source[key];
73
+ }
74
+ }
75
+ return result;
76
+ }
77
+ /**
78
+ * Check if value is an object
79
+ */
80
+ function isObject(value) {
81
+ return value !== null && typeof value === "object" && !Array.isArray(value);
82
+ }
83
+ /**
84
+ * Check if file exists at target location
85
+ */
86
+ export function checkFileExists(projectPath, targetPath) {
87
+ const fullPath = join(projectPath, targetPath);
88
+ return existsSync(fullPath);
89
+ }
90
+ /**
91
+ * Install a single file
92
+ */
93
+ export async function installFile(sourceContent, projectPath, targetPath, variables = {}, options = {}) {
94
+ const fullTargetPath = join(projectPath, targetPath);
95
+ const fileExists = existsSync(fullTargetPath);
96
+ // Apply template substitution
97
+ let processedContent = applyTemplateSubstitution(sourceContent, variables);
98
+ // Handle merge strategy for existing files
99
+ if (fileExists && options.strategy === "merge") {
100
+ // Check if it's a JSON file
101
+ if (targetPath.endsWith(".json")) {
102
+ const existingContent = await readFile(fullTargetPath, "utf-8");
103
+ processedContent = mergeJsonContent(existingContent, processedContent);
104
+ }
105
+ else {
106
+ throw new Error(`Merge strategy only supported for JSON files: ${targetPath}`);
107
+ }
108
+ }
109
+ else if (fileExists &&
110
+ !options.overwrite &&
111
+ options.strategy !== "merge" &&
112
+ options.strategy !== "override") {
113
+ // File exists and we're not overwriting, merging, or using override strategy
114
+ throw new Error(`File already exists: ${targetPath}`);
115
+ }
116
+ // If strategy is 'override', we automatically overwrite (no error thrown)
117
+ // Ensure directory exists
118
+ const dir = dirname(fullTargetPath);
119
+ await mkdir(dir, { recursive: true });
120
+ // Write file
121
+ await writeFile(fullTargetPath, processedContent, "utf-8");
122
+ }
123
+ /**
124
+ * Fetch file content from API endpoint
125
+ */
126
+ async function fetchFileFromAPI(type, name, filePath, variant, requireAuth) {
127
+ try {
128
+ return await fetchComponentFile(type, name, filePath, { variant, requireAuth });
129
+ }
130
+ catch (error) {
131
+ if (error instanceof Error && error.message.includes("Access denied")) {
132
+ throw error;
133
+ }
134
+ throw new Error(`Failed to fetch file from API: ${error instanceof Error ? error.message : String(error)}`);
135
+ }
136
+ }
137
+ /**
138
+ * Install multiple files from file mappings
139
+ * Files are always fetched from API endpoint.
140
+ */
141
+ export async function installFiles(projectPath, fileMappings, context, variables = {}, options) {
142
+ const installed = [];
143
+ const skipped = [];
144
+ const conflicts = [];
145
+ // Determine if authentication is required based on registry entry
146
+ // This prevents repeated authentication prompts for paid components
147
+ const requireAuth = options.registryEntry?.requiresSubscription === true &&
148
+ (options.registryEntry.subscriptionTier || 0) > 0;
149
+ // Check subscription before installing
150
+ // Note: This is a secondary check - the main check should happen in add.ts
151
+ // This is here as a safety net, but we should fail if subscription check fails
152
+ // If registryEntry is provided and component is free, skip the check
153
+ if (options.componentType && options.componentName) {
154
+ try {
155
+ const accessCheck = await checkSubscription(options.componentType, options.componentName, options.registryEntry);
156
+ if (!accessCheck.accessible) {
157
+ throw new Error(accessCheck.reason ||
158
+ "Subscription required. Visit https://tailar.dev/choose-plan to upgrade.");
159
+ }
160
+ }
161
+ catch (error) {
162
+ // Always throw subscription/authentication errors - don't silently continue
163
+ if (error instanceof Error &&
164
+ (error.message.includes("Subscription") ||
165
+ error.message.includes("Authentication") ||
166
+ error.message.includes("Access denied"))) {
167
+ throw error;
168
+ }
169
+ // For other errors, also throw to prevent installation without proper verification
170
+ throw new Error(`Failed to verify subscription access: ${error instanceof Error ? error.message : String(error)}`);
171
+ }
172
+ }
173
+ for (const mapping of fileMappings) {
174
+ // Resolve target path
175
+ const targetPath = resolveTemplatePath(mapping.target, context, variables);
176
+ // Determine strategy (default to override)
177
+ const strategy = mapping.strategy || "override";
178
+ // For merge and override strategies, we don't check conflicts upfront
179
+ // They handle existing files automatically (merge merges, override overwrites)
180
+ // Only check conflicts if no explicit strategy is set and overwrite is not enabled
181
+ if (!mapping.strategy &&
182
+ checkFileExists(projectPath, targetPath) &&
183
+ !options.overwrite) {
184
+ conflicts.push(targetPath);
185
+ continue;
186
+ }
187
+ // If strategy is explicitly set to 'override', treat it as overwrite=true
188
+ const effectiveOverwrite = options.overwrite || mapping.strategy === "override";
189
+ // Skip if dry run
190
+ if (options.dryRun) {
191
+ installed.push(targetPath);
192
+ continue;
193
+ }
194
+ try {
195
+ let sourceContent;
196
+ // Always fetch from API
197
+ sourceContent = await fetchFileFromAPI(options.componentType, options.componentName, mapping.source, options.variant, requireAuth);
198
+ // Install file
199
+ await installFile(sourceContent, projectPath, targetPath, variables, {
200
+ overwrite: effectiveOverwrite,
201
+ strategy: strategy,
202
+ });
203
+ installed.push(targetPath);
204
+ }
205
+ catch (error) {
206
+ throw new Error(`Failed to install ${targetPath}: ${error}`);
207
+ }
208
+ }
209
+ return { installed, skipped, conflicts };
210
+ }
211
+ //# sourceMappingURL=files.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"files.js","sourceRoot":"","sources":["../../src/installers/files.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Programmatic install of a registry feature (same pipeline as tailar add).
3
+ */
4
+ export interface InstallFeatureOptions {
5
+ yes?: boolean;
6
+ force?: boolean;
7
+ variant?: string;
8
+ provider?: string;
9
+ /** Skip prompts; merged into answers for variant resolution */
10
+ presetAnswers?: Record<string, unknown>;
11
+ }
12
+ export interface InstallFeatureResult {
13
+ postInstallSteps: unknown[];
14
+ hasDependencies: boolean;
15
+ }
16
+ /**
17
+ * Install a single registry entry by name. Caller must install dependencies first if needed.
18
+ */
19
+ export declare function installFeature(projectPath: string, name: string, options?: InstallFeatureOptions): Promise<InstallFeatureResult>;
20
+ //# sourceMappingURL=install-feature.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"install-feature.d.ts","sourceRoot":"","sources":["../../src/installers/install-feature.ts"],"names":[],"mappings":"AAAA;;GAEG;AAyBH,MAAM,WAAW,qBAAqB;IACpC,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,+DAA+D;IAC/D,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACzC;AAED,MAAM,WAAW,oBAAoB;IACnC,gBAAgB,EAAE,OAAO,EAAE,CAAC;IAC5B,eAAe,EAAE,OAAO,CAAC;CAC1B;AAYD;;GAEG;AACH,wBAAsB,cAAc,CAClC,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,qBAA0B,GAClC,OAAO,CAAC,oBAAoB,CAAC,CAgK/B"}
@@ -0,0 +1,169 @@
1
+ /**
2
+ * Programmatic install of a registry feature (same pipeline as tailar add).
3
+ */
4
+ import { readConfig, writeConfig, addInstalledItem, } from '../utils/config.js';
5
+ import { detectPackageManager } from '../utils/package-manager.js';
6
+ import { detectProjectStructure } from '../utils/validation.js';
7
+ import { loadRegistry } from '../registry/loader.js';
8
+ import { getEntry, getVariant } from '../registry/query.js';
9
+ import { runPrompts } from '../utils/prompts.js';
10
+ import { installFiles } from './files.js';
11
+ import { mergeDependencies, collectDependencies } from './dependencies.js';
12
+ import { collectTemplateVariables, extractVariablesFromAnswers, mergeVariables, } from './templates.js';
13
+ import { isAuthenticated, authenticate } from '../auth/flow.js';
14
+ import { checkSubscription } from '../api/client.js';
15
+ import { logger } from '../utils/logger.js';
16
+ function defaultAnswersFromQuestions(questions) {
17
+ const out = {};
18
+ for (const q of questions) {
19
+ if (q.default !== undefined)
20
+ out[q.name] = q.default;
21
+ }
22
+ return out;
23
+ }
24
+ /**
25
+ * Install a single registry entry by name. Caller must install dependencies first if needed.
26
+ */
27
+ export async function installFeature(projectPath, name, options = {}) {
28
+ const config = await readConfig(projectPath);
29
+ if (!config) {
30
+ throw new Error('Tailar not initialized. Run tailar init first.');
31
+ }
32
+ const structure = detectProjectStructure(projectPath);
33
+ const packageManager = detectPackageManager(projectPath);
34
+ const context = {
35
+ root: projectPath,
36
+ packageManager,
37
+ structure,
38
+ config,
39
+ };
40
+ const registry = await loadRegistry();
41
+ const entry = getEntry(registry, name);
42
+ if (!entry) {
43
+ throw new Error(`Entry not found: ${name}`);
44
+ }
45
+ const requiresSubscription = entry.requiresSubscription === true && (entry.subscriptionTier || 0) > 0;
46
+ if (requiresSubscription) {
47
+ if (!(await isAuthenticated())) {
48
+ await authenticate();
49
+ }
50
+ const accessCheck = await checkSubscription(entry.type, name);
51
+ if (!accessCheck.accessible) {
52
+ throw new Error(accessCheck.reason || 'Subscription required');
53
+ }
54
+ }
55
+ let answers = {};
56
+ if (entry.questions && entry.questions.length > 0) {
57
+ if (options.presetAnswers) {
58
+ answers = { ...options.presetAnswers };
59
+ }
60
+ else if (!options.yes) {
61
+ answers = await runPrompts(entry.questions, {
62
+ skipPrompts: false,
63
+ defaults: {
64
+ variant: options.variant,
65
+ provider: options.provider,
66
+ },
67
+ });
68
+ }
69
+ else {
70
+ answers = defaultAnswersFromQuestions(entry.questions);
71
+ if (options.variant)
72
+ answers.variant = options.variant;
73
+ if (options.provider) {
74
+ const resolver = entry.variantResolver;
75
+ if (resolver?.answerKey) {
76
+ answers[resolver.answerKey] = options.provider;
77
+ }
78
+ }
79
+ }
80
+ }
81
+ if (options.provider && entry.variantResolver?.answerKey) {
82
+ answers[entry.variantResolver.answerKey] = options.provider;
83
+ }
84
+ if (options.variant)
85
+ answers.variant = options.variant;
86
+ let selectedVariant;
87
+ if (options.variant) {
88
+ selectedVariant = options.variant;
89
+ }
90
+ else if (typeof answers.variant === 'string') {
91
+ selectedVariant = answers.variant;
92
+ }
93
+ else if (entry.variantResolver) {
94
+ const resolver = entry.variantResolver;
95
+ if (resolver.detect && context.config) {
96
+ const installedFeature = context.config.installed.features.find((f) => f.name === resolver.detect);
97
+ if (installedFeature?.variant) {
98
+ if (resolver.mapping) {
99
+ const mapped = resolver.mapping[installedFeature.variant];
100
+ selectedVariant = mapped || installedFeature.variant;
101
+ }
102
+ else {
103
+ selectedVariant = installedFeature.variant;
104
+ }
105
+ }
106
+ }
107
+ if (!selectedVariant && resolver.answerKey) {
108
+ const answerValue = options.provider ?? answers[resolver.answerKey];
109
+ if (answerValue !== undefined) {
110
+ if (resolver.mapping) {
111
+ const mapped = resolver.mapping[String(answerValue)];
112
+ selectedVariant = mapped || String(answerValue);
113
+ }
114
+ else {
115
+ selectedVariant = String(answerValue);
116
+ }
117
+ }
118
+ }
119
+ if (!selectedVariant && resolver.default) {
120
+ selectedVariant = resolver.default;
121
+ }
122
+ }
123
+ const variant = selectedVariant ? getVariant(entry, selectedVariant) : undefined;
124
+ let templateVars = {};
125
+ if (entry.templates && entry.templates.length > 0) {
126
+ templateVars = await collectTemplateVariables(entry.templates, {
127
+ skipPrompts: true,
128
+ });
129
+ }
130
+ const answerVars = extractVariablesFromAnswers(answers);
131
+ const allVars = mergeVariables(templateVars, answerVars);
132
+ let files = [...entry.files];
133
+ if (variant?.files)
134
+ files.push(...variant.files);
135
+ const result = await installFiles(context.root, files, context, allVars, {
136
+ overwrite: options.force || true,
137
+ componentType: entry.type,
138
+ componentName: entry.name,
139
+ variant: selectedVariant,
140
+ registryEntry: entry,
141
+ });
142
+ if (result.conflicts.length > 0 && !options.force) {
143
+ throw new Error(`File conflicts: ${result.conflicts.join(', ')}`);
144
+ }
145
+ logger.success(`Installed ${result.installed.length} files for ${entry.label}`);
146
+ const deps = collectDependencies(entry, selectedVariant);
147
+ let hasDependencies = false;
148
+ if (deps.length > 0) {
149
+ await mergeDependencies(context.root, deps);
150
+ hasDependencies = true;
151
+ }
152
+ const postInstallSteps = [
153
+ ...(entry.postInstall || []),
154
+ ...(variant?.postInstall || []),
155
+ ];
156
+ const provider = options.provider ||
157
+ answers.emailProvider ||
158
+ answers.dbProvider;
159
+ if (!context.config)
160
+ throw new Error('Config missing');
161
+ const updatedConfig = addInstalledItem(context.config, entry.type, name, {
162
+ variant: selectedVariant,
163
+ provider,
164
+ });
165
+ await writeConfig(context.root, updatedConfig);
166
+ context.config = updatedConfig;
167
+ return { postInstallSteps, hasDependencies };
168
+ }
169
+ //# sourceMappingURL=install-feature.js.map