devports 0.0.1 → 1.0.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 (151) hide show
  1. package/CHANGELOG.md +80 -0
  2. package/LICENSE +21 -0
  3. package/README.md +810 -29
  4. package/dist/cli.d.ts +7 -0
  5. package/dist/cli.d.ts.map +1 -0
  6. package/dist/cli.js +329 -0
  7. package/dist/cli.js.map +1 -0
  8. package/dist/commands/allocate.command.d.ts +8 -0
  9. package/dist/commands/allocate.command.d.ts.map +1 -0
  10. package/dist/commands/allocate.command.js +84 -0
  11. package/dist/commands/allocate.command.js.map +1 -0
  12. package/dist/commands/base-command.d.ts +28 -0
  13. package/dist/commands/base-command.d.ts.map +1 -0
  14. package/dist/commands/base-command.js +33 -0
  15. package/dist/commands/base-command.js.map +1 -0
  16. package/dist/commands/check.command.d.ts +7 -0
  17. package/dist/commands/check.command.d.ts.map +1 -0
  18. package/dist/commands/check.command.js +44 -0
  19. package/dist/commands/check.command.js.map +1 -0
  20. package/dist/commands/completion.command.d.ts +7 -0
  21. package/dist/commands/completion.command.d.ts.map +1 -0
  22. package/dist/commands/completion.command.js +116 -0
  23. package/dist/commands/completion.command.js.map +1 -0
  24. package/dist/commands/gitignore.command.d.ts +7 -0
  25. package/dist/commands/gitignore.command.d.ts.map +1 -0
  26. package/dist/commands/gitignore.command.js +61 -0
  27. package/dist/commands/gitignore.command.js.map +1 -0
  28. package/dist/commands/index.d.ts +7 -0
  29. package/dist/commands/index.d.ts.map +1 -0
  30. package/dist/commands/index.js +35 -0
  31. package/dist/commands/index.js.map +1 -0
  32. package/dist/commands/info.command.d.ts +7 -0
  33. package/dist/commands/info.command.d.ts.map +1 -0
  34. package/dist/commands/info.command.js +40 -0
  35. package/dist/commands/info.command.js.map +1 -0
  36. package/dist/commands/list.command.d.ts +8 -0
  37. package/dist/commands/list.command.d.ts.map +1 -0
  38. package/dist/commands/list.command.js +165 -0
  39. package/dist/commands/list.command.js.map +1 -0
  40. package/dist/commands/release.command.d.ts +8 -0
  41. package/dist/commands/release.command.d.ts.map +1 -0
  42. package/dist/commands/release.command.js +89 -0
  43. package/dist/commands/release.command.js.map +1 -0
  44. package/dist/commands/render.command.d.ts +7 -0
  45. package/dist/commands/render.command.d.ts.map +1 -0
  46. package/dist/commands/render.command.js +53 -0
  47. package/dist/commands/render.command.js.map +1 -0
  48. package/dist/commands/reserve.command.d.ts +7 -0
  49. package/dist/commands/reserve.command.d.ts.map +1 -0
  50. package/dist/commands/reserve.command.js +42 -0
  51. package/dist/commands/reserve.command.js.map +1 -0
  52. package/dist/commands/setup.command.d.ts +7 -0
  53. package/dist/commands/setup.command.d.ts.map +1 -0
  54. package/dist/commands/setup.command.js +43 -0
  55. package/dist/commands/setup.command.js.map +1 -0
  56. package/dist/commands/status.command.d.ts +7 -0
  57. package/dist/commands/status.command.d.ts.map +1 -0
  58. package/dist/commands/status.command.js +41 -0
  59. package/dist/commands/status.command.js.map +1 -0
  60. package/dist/commands/unreserve.command.d.ts +7 -0
  61. package/dist/commands/unreserve.command.d.ts.map +1 -0
  62. package/dist/commands/unreserve.command.js +38 -0
  63. package/dist/commands/unreserve.command.js.map +1 -0
  64. package/dist/commands/worktree-add.command.d.ts +7 -0
  65. package/dist/commands/worktree-add.command.d.ts.map +1 -0
  66. package/dist/commands/worktree-add.command.js +68 -0
  67. package/dist/commands/worktree-add.command.js.map +1 -0
  68. package/dist/commands/worktree-remove.command.d.ts +7 -0
  69. package/dist/commands/worktree-remove.command.d.ts.map +1 -0
  70. package/dist/commands/worktree-remove.command.js +33 -0
  71. package/dist/commands/worktree-remove.command.js.map +1 -0
  72. package/dist/completion/bash-completion-template.d.ts +5 -0
  73. package/dist/completion/bash-completion-template.d.ts.map +1 -0
  74. package/dist/completion/bash-completion-template.js +14 -0
  75. package/dist/completion/bash-completion-template.js.map +1 -0
  76. package/dist/completion/bash.sh +208 -0
  77. package/dist/completion/completion-data.d.ts +16 -0
  78. package/dist/completion/completion-data.d.ts.map +1 -0
  79. package/dist/completion/completion-data.js +38 -0
  80. package/dist/completion/completion-data.js.map +1 -0
  81. package/dist/completion/index.d.ts +24 -0
  82. package/dist/completion/index.d.ts.map +1 -0
  83. package/dist/completion/index.js +30 -0
  84. package/dist/completion/index.js.map +1 -0
  85. package/dist/completion/shell-config.d.ts +27 -0
  86. package/dist/completion/shell-config.d.ts.map +1 -0
  87. package/dist/completion/shell-config.js +243 -0
  88. package/dist/completion/shell-config.js.map +1 -0
  89. package/dist/completion/zsh-completion-template.d.ts +5 -0
  90. package/dist/completion/zsh-completion-template.d.ts.map +1 -0
  91. package/dist/completion/zsh-completion-template.js +14 -0
  92. package/dist/completion/zsh-completion-template.js.map +1 -0
  93. package/dist/completion/zsh.sh +164 -0
  94. package/dist/config.d.ts +6 -0
  95. package/dist/config.d.ts.map +1 -0
  96. package/dist/config.js +111 -0
  97. package/dist/config.js.map +1 -0
  98. package/dist/devports-1.0.0.tgz +0 -0
  99. package/dist/execution.d.ts +31 -0
  100. package/dist/execution.d.ts.map +1 -0
  101. package/dist/execution.js +110 -0
  102. package/dist/execution.js.map +1 -0
  103. package/dist/gitignore.d.ts +22 -0
  104. package/dist/gitignore.d.ts.map +1 -0
  105. package/dist/gitignore.js +142 -0
  106. package/dist/gitignore.js.map +1 -0
  107. package/dist/index.d.ts +7 -0
  108. package/dist/index.d.ts.map +1 -0
  109. package/dist/index.js +6 -0
  110. package/dist/index.js.map +1 -0
  111. package/dist/port-manager.d.ts +33 -0
  112. package/dist/port-manager.d.ts.map +1 -0
  113. package/dist/port-manager.js +169 -0
  114. package/dist/port-manager.js.map +1 -0
  115. package/dist/port-utils.d.ts +9 -0
  116. package/dist/port-utils.d.ts.map +1 -0
  117. package/dist/port-utils.js +38 -0
  118. package/dist/port-utils.js.map +1 -0
  119. package/dist/render.d.ts +54 -0
  120. package/dist/render.d.ts.map +1 -0
  121. package/dist/render.js +286 -0
  122. package/dist/render.js.map +1 -0
  123. package/dist/services/lock-manager.d.ts +46 -0
  124. package/dist/services/lock-manager.d.ts.map +1 -0
  125. package/dist/services/lock-manager.js +118 -0
  126. package/dist/services/lock-manager.js.map +1 -0
  127. package/dist/services/response-formatter.d.ts +45 -0
  128. package/dist/services/response-formatter.d.ts.map +1 -0
  129. package/dist/services/response-formatter.js +102 -0
  130. package/dist/services/response-formatter.js.map +1 -0
  131. package/dist/services/validation-service.d.ts +109 -0
  132. package/dist/services/validation-service.d.ts.map +1 -0
  133. package/dist/services/validation-service.js +267 -0
  134. package/dist/services/validation-service.js.map +1 -0
  135. package/dist/setup.d.ts +20 -0
  136. package/dist/setup.d.ts.map +1 -0
  137. package/dist/setup.js +243 -0
  138. package/dist/setup.js.map +1 -0
  139. package/dist/types.d.ts +29 -0
  140. package/dist/types.d.ts.map +1 -0
  141. package/dist/types.js +18 -0
  142. package/dist/types.js.map +1 -0
  143. package/dist/validation.d.ts +69 -0
  144. package/dist/validation.d.ts.map +1 -0
  145. package/dist/validation.js +344 -0
  146. package/dist/validation.js.map +1 -0
  147. package/dist/worktree.d.ts +24 -0
  148. package/dist/worktree.d.ts.map +1 -0
  149. package/dist/worktree.js +245 -0
  150. package/dist/worktree.js.map +1 -0
  151. package/package.json +90 -6
@@ -0,0 +1,267 @@
1
+ /**
2
+ * Consolidated validation service - eliminates duplication in validation logic
3
+ * Implements configurable validation patterns for DRY compliance
4
+ */
5
+ export class ValidationError extends Error {
6
+ constructor(message) {
7
+ super(message);
8
+ this.name = 'ValidationError';
9
+ }
10
+ }
11
+ /**
12
+ * Common validation patterns
13
+ */
14
+ export const ValidationPatterns = {
15
+ PROJECT_SERVICE: /^[a-zA-Z0-9._-]+$/,
16
+ BRANCH_NAME: /^[a-zA-Z0-9._/-]+$/,
17
+ SAFE_PATH: /^[a-zA-Z0-9._/-]+$/,
18
+ SHELL_DANGEROUS: /[;|&$`<>(){}[\]"'\\*?~]/,
19
+ };
20
+ /**
21
+ * Predefined validation configurations for common use cases
22
+ */
23
+ export const ValidationConfigs = {
24
+ PROJECT_NAME: {
25
+ name: 'Project name',
26
+ maxLength: 50,
27
+ pattern: ValidationPatterns.PROJECT_SERVICE,
28
+ disallowedPrefixes: ['.', '-'],
29
+ required: true,
30
+ },
31
+ SERVICE_NAME: {
32
+ name: 'Service name',
33
+ maxLength: 30,
34
+ pattern: ValidationPatterns.PROJECT_SERVICE,
35
+ disallowedPrefixes: ['.', '-'],
36
+ required: true,
37
+ },
38
+ BRANCH_NAME: {
39
+ name: 'Branch name',
40
+ maxLength: 100,
41
+ pattern: ValidationPatterns.BRANCH_NAME,
42
+ required: true,
43
+ },
44
+ PORT_NUMBER: {
45
+ name: 'Port number',
46
+ min: 1024,
47
+ max: 65535,
48
+ integer: true,
49
+ required: true,
50
+ },
51
+ TEMPLATE_PATH: {
52
+ name: 'Template path',
53
+ allowedExtensions: ['.devports'],
54
+ maxLength: 500,
55
+ allowRelative: true,
56
+ },
57
+ WORKTREE_PATH: {
58
+ name: 'Worktree path',
59
+ maxLength: 500,
60
+ allowRelative: true,
61
+ },
62
+ OUTPUT_PATH: {
63
+ name: 'Output path',
64
+ maxLength: 500,
65
+ allowRelative: true,
66
+ },
67
+ };
68
+ /**
69
+ * Centralized validation service with configurable validators
70
+ */
71
+ export class ValidationService {
72
+ /**
73
+ * Validate a string value with configurable rules
74
+ */
75
+ static validateString(value, config) {
76
+ // Required check
77
+ if (config.required && (!value || typeof value !== 'string')) {
78
+ throw new ValidationError(config.customErrorMessage ?? `${config.name} is required`);
79
+ }
80
+ if (!value) {
81
+ return '';
82
+ }
83
+ // Length validation
84
+ if (config.maxLength && value.length > config.maxLength) {
85
+ throw new ValidationError(config.customErrorMessage ??
86
+ `${config.name} must be ${config.maxLength} characters or less`);
87
+ }
88
+ if (config.minLength && value.length < config.minLength) {
89
+ throw new ValidationError(config.customErrorMessage ??
90
+ `${config.name} must be at least ${config.minLength} characters`);
91
+ }
92
+ // Pattern validation
93
+ if (config.pattern && !config.pattern.test(value)) {
94
+ throw new ValidationError(config.customErrorMessage ??
95
+ `${config.name} can only contain letters, numbers, dots, underscores, and hyphens`);
96
+ }
97
+ // Prefix validation
98
+ if (config.disallowedPrefixes) {
99
+ for (const prefix of config.disallowedPrefixes) {
100
+ if (value.startsWith(prefix)) {
101
+ throw new ValidationError(config.customErrorMessage ??
102
+ `${config.name} cannot start with "${prefix}"`);
103
+ }
104
+ }
105
+ }
106
+ return value.trim();
107
+ }
108
+ /**
109
+ * Validate a numeric value with configurable rules
110
+ */
111
+ static validateNumber(value, config) {
112
+ // Required check
113
+ if (config.required &&
114
+ (value === undefined || value === null || value === '')) {
115
+ throw new ValidationError(config.customErrorMessage ?? `${config.name} is required`);
116
+ }
117
+ const numValue = typeof value === 'string' ? parseFloat(value) : value;
118
+ if (isNaN(numValue)) {
119
+ throw new ValidationError(config.customErrorMessage ?? `${config.name} must be a valid number`);
120
+ }
121
+ // Integer check
122
+ if (config.integer && !Number.isInteger(numValue)) {
123
+ throw new ValidationError(config.customErrorMessage ?? `${config.name} must be an integer`);
124
+ }
125
+ // Range validation
126
+ if (config.min !== undefined && numValue < config.min) {
127
+ throw new ValidationError(config.customErrorMessage ??
128
+ `${config.name} must be at least ${config.min}`);
129
+ }
130
+ if (config.max !== undefined && numValue > config.max) {
131
+ throw new ValidationError(config.customErrorMessage ??
132
+ `${config.name} must be at most ${config.max}`);
133
+ }
134
+ return numValue;
135
+ }
136
+ /**
137
+ * Validate a path with configurable rules
138
+ */
139
+ static validatePath(value, config) {
140
+ if (!value || typeof value !== 'string') {
141
+ throw new ValidationError(config.customErrorMessage ?? `${config.name} is required`);
142
+ }
143
+ // Length validation
144
+ if (config.maxLength && value.length > config.maxLength) {
145
+ throw new ValidationError(config.customErrorMessage ??
146
+ `${config.name} must be ${config.maxLength} characters or less`);
147
+ }
148
+ // Extension validation
149
+ if (config.allowedExtensions && config.allowedExtensions.length > 0) {
150
+ const hasValidExtension = config.allowedExtensions.some((ext) => value.endsWith(ext));
151
+ if (!hasValidExtension) {
152
+ throw new ValidationError(config.customErrorMessage ??
153
+ `${config.name} must have one of these extensions: ${config.allowedExtensions.join(', ')}`);
154
+ }
155
+ }
156
+ // Shell metacharacter check for security
157
+ if (ValidationPatterns.SHELL_DANGEROUS.test(value)) {
158
+ throw new ValidationError(config.customErrorMessage ??
159
+ `${config.name} contains dangerous characters that could be used for shell injection`);
160
+ }
161
+ return value.trim();
162
+ }
163
+ /**
164
+ * Convenience methods using predefined configurations
165
+ */
166
+ static validateProjectName(value) {
167
+ return this.validateString(value, ValidationConfigs.PROJECT_NAME);
168
+ }
169
+ static validateServiceName(value) {
170
+ return this.validateString(value, ValidationConfigs.SERVICE_NAME);
171
+ }
172
+ static validateBranchName(value) {
173
+ return this.validateString(value, ValidationConfigs.BRANCH_NAME);
174
+ }
175
+ static validatePort(value) {
176
+ return this.validateNumber(value, ValidationConfigs.PORT_NUMBER);
177
+ }
178
+ static validateTemplatePath(value) {
179
+ return this.validatePath(value, ValidationConfigs.TEMPLATE_PATH);
180
+ }
181
+ static validateWorktreePath(value) {
182
+ return this.validatePath(value, ValidationConfigs.WORKTREE_PATH);
183
+ }
184
+ static validateOutputPath(value) {
185
+ return this.validatePath(value, ValidationConfigs.OUTPUT_PATH);
186
+ }
187
+ /**
188
+ * Validate service type against allowed types
189
+ */
190
+ static validateServiceType(type) {
191
+ if (!type || typeof type !== 'string') {
192
+ throw new ValidationError('Service type is required');
193
+ }
194
+ const validTypes = ['postgres', 'mysql', 'redis', 'api', 'app', 'custom'];
195
+ const normalizedType = type.toLowerCase().trim();
196
+ if (!validTypes.includes(normalizedType)) {
197
+ throw new ValidationError(`Invalid service type. Must be one of: ${validTypes.join(', ')}`);
198
+ }
199
+ return normalizedType;
200
+ }
201
+ /**
202
+ * Validate script file path for post-hooks and similar
203
+ */
204
+ static validateScriptPath(path) {
205
+ // Uses the same validation logic as template paths but with script-specific extensions
206
+ return this.validatePath(path, {
207
+ name: 'script path',
208
+ maxLength: 200,
209
+ mustExist: true,
210
+ allowRelative: true,
211
+ allowedExtensions: [
212
+ '.sh',
213
+ '.bash',
214
+ '.zsh',
215
+ '.js',
216
+ '.mjs',
217
+ '.ts',
218
+ '.py',
219
+ '.rb',
220
+ ],
221
+ });
222
+ }
223
+ /**
224
+ * Validate an array of service definitions in "service" or "service:type" format
225
+ */
226
+ static validateServices(services) {
227
+ if (!Array.isArray(services)) {
228
+ throw new ValidationError('Services must be an array');
229
+ }
230
+ return services.map((serviceStr, index) => {
231
+ if (!serviceStr || typeof serviceStr !== 'string') {
232
+ throw new ValidationError(`Service at index ${index} is invalid`);
233
+ }
234
+ const trimmed = serviceStr.trim();
235
+ const parts = trimmed.split(':');
236
+ if (parts.length === 1) {
237
+ // Format: service (use same name for type)
238
+ const service = this.validateServiceName(parts[0]);
239
+ const type = this.validateServiceType(parts[0]);
240
+ return { service, type };
241
+ }
242
+ else if (parts.length === 2) {
243
+ // Format: service:type
244
+ const service = this.validateServiceName(parts[0]);
245
+ const type = this.validateServiceType(parts[1]);
246
+ return { service, type };
247
+ }
248
+ else {
249
+ throw new ValidationError(`Invalid service format at index ${index}. Use 'service' or 'service:type'`);
250
+ }
251
+ });
252
+ }
253
+ /**
254
+ * Sanitize string for safe display/logging, removing dangerous characters
255
+ */
256
+ static sanitizeForDisplay(input, maxLength = 100) {
257
+ if (!input || typeof input !== 'string') {
258
+ return '';
259
+ }
260
+ // Remove control characters and limit length
261
+ return (input
262
+ // eslint-disable-next-line no-control-regex
263
+ .replace(/[\x00-\x1F\x7F]/g, '') // Remove control characters
264
+ .substring(0, maxLength));
265
+ }
266
+ }
267
+ //# sourceMappingURL=validation-service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validation-service.js","sourceRoot":"","sources":["../../src/services/validation-service.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,OAAO,eAAgB,SAAQ,KAAK;IACxC,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,iBAAiB,CAAC;IAChC,CAAC;CACF;AAuCD;;GAEG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG;IAChC,eAAe,EAAE,mBAAmB;IACpC,WAAW,EAAE,oBAAoB;IACjC,SAAS,EAAE,oBAAoB;IAC/B,eAAe,EAAE,yBAAyB;CAClC,CAAC;AAEX;;GAEG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG;IAC/B,YAAY,EAAE;QACZ,IAAI,EAAE,cAAc;QACpB,SAAS,EAAE,EAAE;QACb,OAAO,EAAE,kBAAkB,CAAC,eAAe;QAC3C,kBAAkB,EAAE,CAAC,GAAG,EAAE,GAAG,CAAC;QAC9B,QAAQ,EAAE,IAAI;KACW;IAE3B,YAAY,EAAE;QACZ,IAAI,EAAE,cAAc;QACpB,SAAS,EAAE,EAAE;QACb,OAAO,EAAE,kBAAkB,CAAC,eAAe;QAC3C,kBAAkB,EAAE,CAAC,GAAG,EAAE,GAAG,CAAC;QAC9B,QAAQ,EAAE,IAAI;KACW;IAE3B,WAAW,EAAE;QACX,IAAI,EAAE,aAAa;QACnB,SAAS,EAAE,GAAG;QACd,OAAO,EAAE,kBAAkB,CAAC,WAAW;QACvC,QAAQ,EAAE,IAAI;KACW;IAE3B,WAAW,EAAE;QACX,IAAI,EAAE,aAAa;QACnB,GAAG,EAAE,IAAI;QACT,GAAG,EAAE,KAAK;QACV,OAAO,EAAE,IAAI;QACb,QAAQ,EAAE,IAAI;KACY;IAE5B,aAAa,EAAE;QACb,IAAI,EAAE,eAAe;QACrB,iBAAiB,EAAE,CAAC,WAAW,CAAC;QAChC,SAAS,EAAE,GAAG;QACd,aAAa,EAAE,IAAI;KACI;IAEzB,aAAa,EAAE;QACb,IAAI,EAAE,eAAe;QACrB,SAAS,EAAE,GAAG;QACd,aAAa,EAAE,IAAI;KACI;IAEzB,WAAW,EAAE;QACX,IAAI,EAAE,aAAa;QACnB,SAAS,EAAE,GAAG;QACd,aAAa,EAAE,IAAI;KACI;CACjB,CAAC;AAEX;;GAEG;AACH,MAAM,OAAO,iBAAiB;IAC5B;;OAEG;IACH,MAAM,CAAC,cAAc,CAAC,KAAa,EAAE,MAA8B;QACjE,iBAAiB;QACjB,IAAI,MAAM,CAAC,QAAQ,IAAI,CAAC,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,CAAC,EAAE,CAAC;YAC7D,MAAM,IAAI,eAAe,CACvB,MAAM,CAAC,kBAAkB,IAAI,GAAG,MAAM,CAAC,IAAI,cAAc,CAC1D,CAAC;QACJ,CAAC;QAED,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,oBAAoB;QACpB,IAAI,MAAM,CAAC,SAAS,IAAI,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC,SAAS,EAAE,CAAC;YACxD,MAAM,IAAI,eAAe,CACvB,MAAM,CAAC,kBAAkB;gBACvB,GAAG,MAAM,CAAC,IAAI,YAAY,MAAM,CAAC,SAAS,qBAAqB,CAClE,CAAC;QACJ,CAAC;QAED,IAAI,MAAM,CAAC,SAAS,IAAI,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC,SAAS,EAAE,CAAC;YACxD,MAAM,IAAI,eAAe,CACvB,MAAM,CAAC,kBAAkB;gBACvB,GAAG,MAAM,CAAC,IAAI,qBAAqB,MAAM,CAAC,SAAS,aAAa,CACnE,CAAC;QACJ,CAAC;QAED,qBAAqB;QACrB,IAAI,MAAM,CAAC,OAAO,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;YAClD,MAAM,IAAI,eAAe,CACvB,MAAM,CAAC,kBAAkB;gBACvB,GAAG,MAAM,CAAC,IAAI,oEAAoE,CACrF,CAAC;QACJ,CAAC;QAED,oBAAoB;QACpB,IAAI,MAAM,CAAC,kBAAkB,EAAE,CAAC;YAC9B,KAAK,MAAM,MAAM,IAAI,MAAM,CAAC,kBAAkB,EAAE,CAAC;gBAC/C,IAAI,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;oBAC7B,MAAM,IAAI,eAAe,CACvB,MAAM,CAAC,kBAAkB;wBACvB,GAAG,MAAM,CAAC,IAAI,uBAAuB,MAAM,GAAG,CACjD,CAAC;gBACJ,CAAC;YACH,CAAC;QACH,CAAC;QAED,OAAO,KAAK,CAAC,IAAI,EAAE,CAAC;IACtB,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,cAAc,CACnB,KAAsB,EACtB,MAA+B;QAE/B,iBAAiB;QACjB,IACE,MAAM,CAAC,QAAQ;YACf,CAAC,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,EAAE,CAAC,EACvD,CAAC;YACD,MAAM,IAAI,eAAe,CACvB,MAAM,CAAC,kBAAkB,IAAI,GAAG,MAAM,CAAC,IAAI,cAAc,CAC1D,CAAC;QACJ,CAAC;QAED,MAAM,QAAQ,GAAG,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;QAEvE,IAAI,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC;YACpB,MAAM,IAAI,eAAe,CACvB,MAAM,CAAC,kBAAkB,IAAI,GAAG,MAAM,CAAC,IAAI,yBAAyB,CACrE,CAAC;QACJ,CAAC;QAED,gBAAgB;QAChB,IAAI,MAAM,CAAC,OAAO,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,EAAE,CAAC;YAClD,MAAM,IAAI,eAAe,CACvB,MAAM,CAAC,kBAAkB,IAAI,GAAG,MAAM,CAAC,IAAI,qBAAqB,CACjE,CAAC;QACJ,CAAC;QAED,mBAAmB;QACnB,IAAI,MAAM,CAAC,GAAG,KAAK,SAAS,IAAI,QAAQ,GAAG,MAAM,CAAC,GAAG,EAAE,CAAC;YACtD,MAAM,IAAI,eAAe,CACvB,MAAM,CAAC,kBAAkB;gBACvB,GAAG,MAAM,CAAC,IAAI,qBAAqB,MAAM,CAAC,GAAG,EAAE,CAClD,CAAC;QACJ,CAAC;QAED,IAAI,MAAM,CAAC,GAAG,KAAK,SAAS,IAAI,QAAQ,GAAG,MAAM,CAAC,GAAG,EAAE,CAAC;YACtD,MAAM,IAAI,eAAe,CACvB,MAAM,CAAC,kBAAkB;gBACvB,GAAG,MAAM,CAAC,IAAI,oBAAoB,MAAM,CAAC,GAAG,EAAE,CACjD,CAAC;QACJ,CAAC;QAED,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,YAAY,CAAC,KAAa,EAAE,MAA4B;QAC7D,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;YACxC,MAAM,IAAI,eAAe,CACvB,MAAM,CAAC,kBAAkB,IAAI,GAAG,MAAM,CAAC,IAAI,cAAc,CAC1D,CAAC;QACJ,CAAC;QAED,oBAAoB;QACpB,IAAI,MAAM,CAAC,SAAS,IAAI,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC,SAAS,EAAE,CAAC;YACxD,MAAM,IAAI,eAAe,CACvB,MAAM,CAAC,kBAAkB;gBACvB,GAAG,MAAM,CAAC,IAAI,YAAY,MAAM,CAAC,SAAS,qBAAqB,CAClE,CAAC;QACJ,CAAC;QAED,uBAAuB;QACvB,IAAI,MAAM,CAAC,iBAAiB,IAAI,MAAM,CAAC,iBAAiB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACpE,MAAM,iBAAiB,GAAG,MAAM,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAC9D,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,CACpB,CAAC;YACF,IAAI,CAAC,iBAAiB,EAAE,CAAC;gBACvB,MAAM,IAAI,eAAe,CACvB,MAAM,CAAC,kBAAkB;oBACvB,GAAG,MAAM,CAAC,IAAI,uCAAuC,MAAM,CAAC,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAC7F,CAAC;YACJ,CAAC;QACH,CAAC;QAED,yCAAyC;QACzC,IAAI,kBAAkB,CAAC,eAAe,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;YACnD,MAAM,IAAI,eAAe,CACvB,MAAM,CAAC,kBAAkB;gBACvB,GAAG,MAAM,CAAC,IAAI,uEAAuE,CACxF,CAAC;QACJ,CAAC;QAED,OAAO,KAAK,CAAC,IAAI,EAAE,CAAC;IACtB,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,mBAAmB,CAAC,KAAa;QACtC,OAAO,IAAI,CAAC,cAAc,CAAC,KAAK,EAAE,iBAAiB,CAAC,YAAY,CAAC,CAAC;IACpE,CAAC;IAED,MAAM,CAAC,mBAAmB,CAAC,KAAa;QACtC,OAAO,IAAI,CAAC,cAAc,CAAC,KAAK,EAAE,iBAAiB,CAAC,YAAY,CAAC,CAAC;IACpE,CAAC;IAED,MAAM,CAAC,kBAAkB,CAAC,KAAa;QACrC,OAAO,IAAI,CAAC,cAAc,CAAC,KAAK,EAAE,iBAAiB,CAAC,WAAW,CAAC,CAAC;IACnE,CAAC;IAED,MAAM,CAAC,YAAY,CAAC,KAAsB;QACxC,OAAO,IAAI,CAAC,cAAc,CAAC,KAAK,EAAE,iBAAiB,CAAC,WAAW,CAAC,CAAC;IACnE,CAAC;IAED,MAAM,CAAC,oBAAoB,CAAC,KAAa;QACvC,OAAO,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE,iBAAiB,CAAC,aAAa,CAAC,CAAC;IACnE,CAAC;IAED,MAAM,CAAC,oBAAoB,CAAC,KAAa;QACvC,OAAO,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE,iBAAiB,CAAC,aAAa,CAAC,CAAC;IACnE,CAAC;IAED,MAAM,CAAC,kBAAkB,CAAC,KAAa;QACrC,OAAO,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE,iBAAiB,CAAC,WAAW,CAAC,CAAC;IACjE,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,mBAAmB,CAAC,IAAY;QACrC,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;YACtC,MAAM,IAAI,eAAe,CAAC,0BAA0B,CAAC,CAAC;QACxD,CAAC;QAED,MAAM,UAAU,GAAG,CAAC,UAAU,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,CAAC,CAAC;QAC1E,MAAM,cAAc,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,CAAC;QAEjD,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC;YACzC,MAAM,IAAI,eAAe,CACvB,yCAAyC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CACjE,CAAC;QACJ,CAAC;QAED,OAAO,cAAc,CAAC;IACxB,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,kBAAkB,CAAC,IAAY;QACpC,uFAAuF;QACvF,OAAO,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE;YAC7B,IAAI,EAAE,aAAa;YACnB,SAAS,EAAE,GAAG;YACd,SAAS,EAAE,IAAI;YACf,aAAa,EAAE,IAAI;YACnB,iBAAiB,EAAE;gBACjB,KAAK;gBACL,OAAO;gBACP,MAAM;gBACN,KAAK;gBACL,MAAM;gBACN,KAAK;gBACL,KAAK;gBACL,KAAK;aACN;SACF,CAAC,CAAC;IACL,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,gBAAgB,CACrB,QAAkB;QAElB,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC7B,MAAM,IAAI,eAAe,CAAC,2BAA2B,CAAC,CAAC;QACzD,CAAC;QAED,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC,UAAU,EAAE,KAAK,EAAE,EAAE;YACxC,IAAI,CAAC,UAAU,IAAI,OAAO,UAAU,KAAK,QAAQ,EAAE,CAAC;gBAClD,MAAM,IAAI,eAAe,CAAC,oBAAoB,KAAK,aAAa,CAAC,CAAC;YACpE,CAAC;YAED,MAAM,OAAO,GAAG,UAAU,CAAC,IAAI,EAAE,CAAC;YAClC,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YAEjC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACvB,2CAA2C;gBAC3C,MAAM,OAAO,GAAG,IAAI,CAAC,mBAAmB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;gBACnD,MAAM,IAAI,GAAG,IAAI,CAAC,mBAAmB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;gBAChD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;YAC3B,CAAC;iBAAM,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBAC9B,uBAAuB;gBACvB,MAAM,OAAO,GAAG,IAAI,CAAC,mBAAmB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;gBACnD,MAAM,IAAI,GAAG,IAAI,CAAC,mBAAmB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;gBAChD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;YAC3B,CAAC;iBAAM,CAAC;gBACN,MAAM,IAAI,eAAe,CACvB,mCAAmC,KAAK,mCAAmC,CAC5E,CAAC;YACJ,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,kBAAkB,CAAC,KAAa,EAAE,YAAoB,GAAG;QAC9D,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;YACxC,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,6CAA6C;QAC7C,OAAO,CACL,KAAK;YACH,4CAA4C;aAC3C,OAAO,CAAC,kBAAkB,EAAE,EAAE,CAAC,CAAC,4BAA4B;aAC5D,SAAS,CAAC,CAAC,EAAE,SAAS,CAAC,CAC3B,CAAC;IACJ,CAAC;CACF"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Secure setup operations with input validation and safe command execution
3
+ */
4
+ export interface SetupOptions {
5
+ template?: string;
6
+ services?: string[];
7
+ force?: boolean;
8
+ skipRender?: boolean;
9
+ postHook?: string;
10
+ }
11
+ export interface SetupResult {
12
+ projectName: string;
13
+ allocatedPorts: Record<string, number>;
14
+ renderedFiles: string[];
15
+ }
16
+ /**
17
+ * Secure version of setupCurrentDirectory with input validation and safe execution
18
+ */
19
+ export declare function setupCurrentDirectory(options?: SetupOptions): Promise<SetupResult>;
20
+ //# sourceMappingURL=setup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../src/setup.ts"],"names":[],"mappings":"AAAA;;GAEG;AAmBH,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,WAAW;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACvC,aAAa,EAAE,MAAM,EAAE,CAAC;CACzB;AAED;;GAEG;AACH,wBAAsB,qBAAqB,CACzC,OAAO,GAAE,YAAiB,GACzB,OAAO,CAAC,WAAW,CAAC,CAqKtB"}
package/dist/setup.js ADDED
@@ -0,0 +1,243 @@
1
+ /**
2
+ * Secure setup operations with input validation and safe command execution
3
+ */
4
+ import { existsSync, readFileSync, writeFileSync, statSync } from 'fs';
5
+ import { basename, join } from 'path';
6
+ import { glob } from 'glob';
7
+ import { allocatePort } from './port-manager.js';
8
+ import { detectServicesFromTemplate, extractProjectNameFromTemplate, makeUrlSafe, processTemplate, } from './render.js';
9
+ import { safeScriptExecution } from './execution.js';
10
+ import { validateServices, validateTemplatePath, validateScriptPath, } from './validation.js';
11
+ /**
12
+ * Secure version of setupCurrentDirectory with input validation and safe execution
13
+ */
14
+ export async function setupCurrentDirectory(options = {}) {
15
+ // Safety check: ensure we're in a main clone, not a worktree
16
+ if (!isMainClone()) {
17
+ throw new Error('Setup can only be run in the main repository clone. ' +
18
+ 'Use "devports worktree add" to create worktrees with port allocation.');
19
+ }
20
+ // Validate all inputs first (but don't check template existence yet - handled later)
21
+ const validatedTemplate = options.template;
22
+ const validatedPostHook = options.postHook
23
+ ? validateScriptPath(options.postHook)
24
+ : undefined;
25
+ let validatedServices;
26
+ if (options.services) {
27
+ const validatedServiceList = validateServices(options.services);
28
+ validatedServices = validatedServiceList.map((s) => `${s.service}:${s.type}`);
29
+ }
30
+ const currentDir = process.cwd();
31
+ const envPath = join(currentDir, '.env');
32
+ const backupPath = join(currentDir, '.env.backup');
33
+ // Check if .env already exists
34
+ if (existsSync(envPath) && !options.force) {
35
+ throw new Error('.env file already exists. Use --force to overwrite (this will create .env.backup).');
36
+ }
37
+ // Backup existing .env if using --force
38
+ if (existsSync(envPath) && options.force) {
39
+ writeFileSync(backupPath, readFileSync(envPath, 'utf-8'));
40
+ console.log(`📋 Backed up existing .env to .env.backup`);
41
+ }
42
+ // Determine template and extract project info
43
+ const templatePath = validatedTemplate
44
+ ? validatedTemplate.startsWith('/')
45
+ ? validatedTemplate
46
+ : join(currentDir, validatedTemplate)
47
+ : join(currentDir, '.env.devports');
48
+ let templateContent = null;
49
+ let projectName = null;
50
+ let services;
51
+ if (existsSync(templatePath)) {
52
+ // Validate template path if it exists
53
+ if (validatedTemplate) {
54
+ validateTemplatePath(templatePath);
55
+ }
56
+ try {
57
+ templateContent = readFileSync(templatePath, 'utf-8');
58
+ services =
59
+ validatedServices ??
60
+ detectServicesFromTemplate(templateContent, templatePath);
61
+ // If no services detected from template, fall back to default
62
+ if (!validatedServices && services.length === 0) {
63
+ services = detectServicesFromEnv();
64
+ }
65
+ projectName = extractProjectNameFromTemplate(templateContent);
66
+ }
67
+ catch {
68
+ console.warn(`⚠️ Could not read template ${templatePath}, falling back to detection`);
69
+ services = validatedServices ?? detectServicesFromEnv();
70
+ }
71
+ }
72
+ else if (validatedServices) {
73
+ services = validatedServices;
74
+ }
75
+ else {
76
+ services = detectServicesFromEnv();
77
+ }
78
+ // Use project name from template or directory name
79
+ const finalProjectName = projectName ?? basename(process.cwd());
80
+ const urlSafeProjectName = makeUrlSafe(finalProjectName);
81
+ console.log(`✅ Setting up ${finalProjectName}...`);
82
+ if (services.length > 0) {
83
+ console.log(`📍 Detected services: ${services.map((s) => s.split(':')[0]).join(', ')}`);
84
+ }
85
+ // Allocate ports for each service
86
+ const allocatedPorts = {};
87
+ const serviceTypes = {};
88
+ for (const service of services) {
89
+ const [serviceName, serviceType] = service.split(':');
90
+ const port = await allocatePort(urlSafeProjectName, serviceName, serviceType);
91
+ allocatedPorts[serviceName] = port;
92
+ serviceTypes[serviceName] = serviceType;
93
+ }
94
+ if (Object.keys(allocatedPorts).length > 0) {
95
+ console.log('🔌 Allocated ports:');
96
+ for (const [service, port] of Object.entries(allocatedPorts)) {
97
+ const type = serviceTypes[service];
98
+ console.log(` ${service}: ${port} (${type})`);
99
+ }
100
+ }
101
+ // Generate .env file
102
+ if (templateContent) {
103
+ const processedContent = processTemplate(templateContent, allocatedPorts, urlSafeProjectName, templatePath);
104
+ writeFileSync(envPath, processedContent);
105
+ console.log(`📝 Generated .env from ${basename(templatePath)}`);
106
+ }
107
+ else if (Object.keys(allocatedPorts).length > 0) {
108
+ // Create basic .env with just port variables
109
+ const envContent = `${[
110
+ '# Generated by devports setup',
111
+ `DEVPORTS_PROJECT_NAME=${finalProjectName}`,
112
+ '',
113
+ ...Object.entries(allocatedPorts).map(([serviceName, port]) => `${serviceName.toUpperCase()}_PORT=${port}`),
114
+ ].join('\n')}\n`;
115
+ writeFileSync(envPath, envContent);
116
+ console.log('📝 Generated basic .env with allocated ports');
117
+ }
118
+ // Auto-render *.devports files
119
+ const renderedFiles = [];
120
+ if (!options.skipRender) {
121
+ const rendered = await autoRenderDevportsFiles(process.cwd(), allocatedPorts, urlSafeProjectName);
122
+ renderedFiles.push(...rendered);
123
+ }
124
+ // Run post-hook if available
125
+ if (validatedPostHook || existsSync('.devports/hooks/post-setup')) {
126
+ await runPostHook(process.cwd(), allocatedPorts, urlSafeProjectName, validatedPostHook);
127
+ }
128
+ console.log('✅ Setup complete!');
129
+ return {
130
+ projectName: finalProjectName,
131
+ allocatedPorts,
132
+ renderedFiles,
133
+ };
134
+ }
135
+ /**
136
+ * Check if we're in the main clone (not a worktree)
137
+ */
138
+ function isMainClone() {
139
+ try {
140
+ // In main clone, .git is a directory
141
+ // In worktree, .git is a file containing path to main .git
142
+ const gitPath = join(process.cwd(), '.git');
143
+ return existsSync(gitPath) && statSync(gitPath).isDirectory();
144
+ }
145
+ catch {
146
+ return false;
147
+ }
148
+ }
149
+ /**
150
+ * Detect services from existing .env file in current directory
151
+ */
152
+ function detectServicesFromEnv() {
153
+ const services = [];
154
+ const envPath = join(process.cwd(), '.env');
155
+ if (existsSync(envPath)) {
156
+ const envContent = readFileSync(envPath, 'utf-8');
157
+ const portPatterns = [
158
+ { regex: /DATABASE_PORT|POSTGRES_PORT/i, service: 'postgres:postgres' },
159
+ { regex: /MYSQL_PORT/i, service: 'mysql:mysql' },
160
+ { regex: /REDIS_PORT/i, service: 'redis:redis' },
161
+ { regex: /API_PORT/i, service: 'api:api' },
162
+ { regex: /APP_PORT|WEB_PORT/i, service: 'app:app' },
163
+ ];
164
+ for (const pattern of portPatterns) {
165
+ if (pattern.regex.test(envContent) &&
166
+ !services.includes(pattern.service)) {
167
+ services.push(pattern.service);
168
+ }
169
+ }
170
+ }
171
+ // Default to postgres if nothing detected
172
+ if (services.length === 0) {
173
+ services.push('postgres:postgres');
174
+ }
175
+ return services;
176
+ }
177
+ /**
178
+ * Auto-render any *.devports files found in the current directory
179
+ */
180
+ async function autoRenderDevportsFiles(currentPath, allocatedPorts, projectName) {
181
+ try {
182
+ const devportsFiles = await glob('**/*.devports', {
183
+ cwd: currentPath,
184
+ ignore: ['node_modules/**', '.git/**'],
185
+ });
186
+ if (devportsFiles.length === 0) {
187
+ return [];
188
+ }
189
+ console.log(`🔄 Auto-rendering ${devportsFiles.length} *.devports files...`);
190
+ const renderedFiles = [];
191
+ for (const devportsFile of devportsFiles) {
192
+ const fullDevportsPath = join(currentPath, devportsFile);
193
+ const outputPath = join(currentPath, devportsFile.replace(/\.devports$/, ''));
194
+ try {
195
+ const templateContent = readFileSync(fullDevportsPath, 'utf-8');
196
+ const processedContent = processTemplate(templateContent, allocatedPorts, projectName, devportsFile);
197
+ writeFileSync(outputPath, processedContent);
198
+ const outputFileName = devportsFile.replace(/\.devports$/, '');
199
+ console.log(` ${outputFileName} (from ${devportsFile})`);
200
+ renderedFiles.push(outputFileName);
201
+ }
202
+ catch (error) {
203
+ console.warn(`⚠️ Failed to render ${devportsFile}: ${error.message}`);
204
+ }
205
+ }
206
+ return renderedFiles;
207
+ }
208
+ catch (error) {
209
+ console.warn(`⚠️ Error during auto-rendering: ${error.message}`);
210
+ return [];
211
+ }
212
+ }
213
+ /**
214
+ * Run post-setup hook if available (secure version)
215
+ */
216
+ async function runPostHook(currentPath, allocatedPorts, projectName, customHook) {
217
+ const hookScript = customHook ?? '.devports/hooks/post-setup';
218
+ if (!existsSync(hookScript)) {
219
+ return;
220
+ }
221
+ try {
222
+ console.log('🔗 Running post-setup hook...');
223
+ // Prepare environment variables
224
+ const hookEnv = {
225
+ DEVPORTS_PROJECT_NAME: projectName,
226
+ DEVPORTS_SETUP_PATH: currentPath,
227
+ };
228
+ // Add all port variables
229
+ for (const [service, port] of Object.entries(allocatedPorts)) {
230
+ const varName = `${service.toUpperCase().replace(/-/g, '_')}_PORT`;
231
+ hookEnv[varName] = port.toString();
232
+ }
233
+ // Execute hook script safely
234
+ await safeScriptExecution(hookScript, hookEnv, {
235
+ cwd: currentPath,
236
+ });
237
+ console.log('✅ Post-setup hook completed');
238
+ }
239
+ catch (error) {
240
+ console.warn(`⚠️ Post-setup hook failed: ${error.message}`);
241
+ }
242
+ }
243
+ //# sourceMappingURL=setup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setup.js","sourceRoot":"","sources":["../src/setup.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ export interface PortRange {
2
+ start: number;
3
+ end: number;
4
+ }
5
+ export interface Config {
6
+ ranges: Record<string, PortRange>;
7
+ registryPath: string;
8
+ }
9
+ export interface PortAllocation {
10
+ port: number;
11
+ project: string;
12
+ service: string;
13
+ type: string;
14
+ allocatedAt: string;
15
+ note?: string;
16
+ }
17
+ export interface Registry {
18
+ allocations: PortAllocation[];
19
+ reservations: {
20
+ port: number;
21
+ reason: string;
22
+ reservedAt: string;
23
+ }[];
24
+ }
25
+ export declare const VALID_PORT_TYPES: readonly ["postgres", "mysql", "redis", "api", "app", "custom"];
26
+ export type PortType = (typeof VALID_PORT_TYPES)[number];
27
+ export declare function isValidPortType(type: string): type is PortType;
28
+ export declare function getValidPortTypes(): string;
29
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,MAAM;IACrB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IAClC,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,QAAQ;IACvB,WAAW,EAAE,cAAc,EAAE,CAAC;IAC9B,YAAY,EAAE;QACZ,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,EAAE,MAAM,CAAC;QACf,UAAU,EAAE,MAAM,CAAC;KACpB,EAAE,CAAC;CACL;AAGD,eAAO,MAAM,gBAAgB,iEAOnB,CAAC;AAEX,MAAM,MAAM,QAAQ,GAAG,CAAC,OAAO,gBAAgB,CAAC,CAAC,MAAM,CAAC,CAAC;AAGzD,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,IAAI,QAAQ,CAE9D;AAGD,wBAAgB,iBAAiB,IAAI,MAAM,CAE1C"}
package/dist/types.js ADDED
@@ -0,0 +1,18 @@
1
+ // Valid port types - exported for validation
2
+ export const VALID_PORT_TYPES = [
3
+ 'postgres',
4
+ 'mysql',
5
+ 'redis',
6
+ 'api',
7
+ 'app',
8
+ 'custom',
9
+ ];
10
+ // Helper to validate port type
11
+ export function isValidPortType(type) {
12
+ return VALID_PORT_TYPES.includes(type);
13
+ }
14
+ // Helper to get valid types as string
15
+ export function getValidPortTypes() {
16
+ return VALID_PORT_TYPES.join(', ');
17
+ }
18
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AA4BA,6CAA6C;AAC7C,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC9B,UAAU;IACV,OAAO;IACP,OAAO;IACP,KAAK;IACL,KAAK;IACL,QAAQ;CACA,CAAC;AAIX,+BAA+B;AAC/B,MAAM,UAAU,eAAe,CAAC,IAAY;IAC1C,OAAO,gBAAgB,CAAC,QAAQ,CAAC,IAAgB,CAAC,CAAC;AACrD,CAAC;AAED,sCAAsC;AACtC,MAAM,UAAU,iBAAiB;IAC/B,OAAO,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACrC,CAAC"}