newo 3.4.0 → 3.4.2

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 (79) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/api.d.ts +3 -1
  3. package/dist/api.js +49 -1
  4. package/dist/application/migration/MigrationEngine.d.ts +141 -0
  5. package/dist/application/migration/MigrationEngine.js +322 -0
  6. package/dist/application/migration/index.d.ts +5 -0
  7. package/dist/application/migration/index.js +5 -0
  8. package/dist/application/sync/SyncEngine.d.ts +134 -0
  9. package/dist/application/sync/SyncEngine.js +335 -0
  10. package/dist/application/sync/index.d.ts +5 -0
  11. package/dist/application/sync/index.js +5 -0
  12. package/dist/cli/commands/create-attribute.js +1 -1
  13. package/dist/cli/commands/create-customer.d.ts +3 -0
  14. package/dist/cli/commands/create-customer.js +159 -0
  15. package/dist/cli/commands/diff.d.ts +6 -0
  16. package/dist/cli/commands/diff.js +288 -0
  17. package/dist/cli/commands/help.js +63 -3
  18. package/dist/cli/commands/logs.d.ts +18 -0
  19. package/dist/cli/commands/logs.js +283 -0
  20. package/dist/cli/commands/pull.js +114 -10
  21. package/dist/cli/commands/push.js +122 -12
  22. package/dist/cli/commands/update-attribute.d.ts +3 -0
  23. package/dist/cli/commands/update-attribute.js +78 -0
  24. package/dist/cli/commands/watch.d.ts +6 -0
  25. package/dist/cli/commands/watch.js +195 -0
  26. package/dist/cli-new/bootstrap.d.ts +74 -0
  27. package/dist/cli-new/bootstrap.js +154 -0
  28. package/dist/cli-new/di/Container.d.ts +64 -0
  29. package/dist/cli-new/di/Container.js +122 -0
  30. package/dist/cli-new/di/tokens.d.ts +77 -0
  31. package/dist/cli-new/di/tokens.js +76 -0
  32. package/dist/cli.js +20 -0
  33. package/dist/domain/resources/common/types.d.ts +71 -0
  34. package/dist/domain/resources/common/types.js +42 -0
  35. package/dist/domain/strategies/sync/AkbSyncStrategy.d.ts +63 -0
  36. package/dist/domain/strategies/sync/AkbSyncStrategy.js +274 -0
  37. package/dist/domain/strategies/sync/AttributeSyncStrategy.d.ts +87 -0
  38. package/dist/domain/strategies/sync/AttributeSyncStrategy.js +378 -0
  39. package/dist/domain/strategies/sync/ConversationSyncStrategy.d.ts +61 -0
  40. package/dist/domain/strategies/sync/ConversationSyncStrategy.js +232 -0
  41. package/dist/domain/strategies/sync/ISyncStrategy.d.ts +149 -0
  42. package/dist/domain/strategies/sync/ISyncStrategy.js +24 -0
  43. package/dist/domain/strategies/sync/IntegrationSyncStrategy.d.ts +68 -0
  44. package/dist/domain/strategies/sync/IntegrationSyncStrategy.js +413 -0
  45. package/dist/domain/strategies/sync/ProjectSyncStrategy.d.ts +111 -0
  46. package/dist/domain/strategies/sync/ProjectSyncStrategy.js +523 -0
  47. package/dist/domain/strategies/sync/index.d.ts +13 -0
  48. package/dist/domain/strategies/sync/index.js +19 -0
  49. package/dist/sync/migrate.js +99 -23
  50. package/dist/types.d.ts +124 -0
  51. package/package.json +3 -1
  52. package/src/api.ts +53 -2
  53. package/src/application/migration/MigrationEngine.ts +492 -0
  54. package/src/application/migration/index.ts +5 -0
  55. package/src/application/sync/SyncEngine.ts +467 -0
  56. package/src/application/sync/index.ts +5 -0
  57. package/src/cli/commands/create-attribute.ts +1 -1
  58. package/src/cli/commands/create-customer.ts +185 -0
  59. package/src/cli/commands/diff.ts +360 -0
  60. package/src/cli/commands/help.ts +63 -3
  61. package/src/cli/commands/logs.ts +329 -0
  62. package/src/cli/commands/pull.ts +128 -11
  63. package/src/cli/commands/push.ts +131 -13
  64. package/src/cli/commands/update-attribute.ts +82 -0
  65. package/src/cli/commands/watch.ts +227 -0
  66. package/src/cli-new/bootstrap.ts +252 -0
  67. package/src/cli-new/di/Container.ts +152 -0
  68. package/src/cli-new/di/tokens.ts +105 -0
  69. package/src/cli.ts +25 -0
  70. package/src/domain/resources/common/types.ts +106 -0
  71. package/src/domain/strategies/sync/AkbSyncStrategy.ts +358 -0
  72. package/src/domain/strategies/sync/AttributeSyncStrategy.ts +508 -0
  73. package/src/domain/strategies/sync/ConversationSyncStrategy.ts +299 -0
  74. package/src/domain/strategies/sync/ISyncStrategy.ts +182 -0
  75. package/src/domain/strategies/sync/IntegrationSyncStrategy.ts +522 -0
  76. package/src/domain/strategies/sync/ProjectSyncStrategy.ts +747 -0
  77. package/src/domain/strategies/sync/index.ts +46 -0
  78. package/src/sync/migrate.ts +103 -24
  79. package/src/types.ts +135 -0
@@ -0,0 +1,134 @@
1
+ /**
2
+ * SyncEngine - Core synchronization orchestrator
3
+ *
4
+ * This is the central engine that coordinates sync operations across all resource types.
5
+ * It uses the Strategy pattern to handle different resources uniformly.
6
+ *
7
+ * Key benefits:
8
+ * - One engine handles projects, integrations, AKB, attributes, conversations
9
+ * - Adding new resource = implement one strategy class
10
+ * - No duplicate pull/push logic
11
+ * - Easy to test (mock strategies)
12
+ */
13
+ import type { ISyncStrategy, PullOptions, PullResult, PushResult, StatusSummary, ValidationResult } from '../../domain/strategies/sync/ISyncStrategy.js';
14
+ import type { CustomerConfig, ILogger } from '../../domain/resources/common/types.js';
15
+ /**
16
+ * Combined pull result from all strategies
17
+ */
18
+ export interface SyncPullResult {
19
+ customer: string;
20
+ resources: Array<{
21
+ resourceType: string;
22
+ displayName: string;
23
+ result: PullResult;
24
+ }>;
25
+ totalItems: number;
26
+ errors: string[];
27
+ }
28
+ /**
29
+ * Combined push result from all strategies
30
+ */
31
+ export interface SyncPushResult {
32
+ customer: string;
33
+ resources: Array<{
34
+ resourceType: string;
35
+ displayName: string;
36
+ result: PushResult;
37
+ }>;
38
+ totalCreated: number;
39
+ totalUpdated: number;
40
+ totalDeleted: number;
41
+ errors: string[];
42
+ }
43
+ /**
44
+ * Status report for all resources
45
+ */
46
+ export interface StatusReport {
47
+ customer: string;
48
+ resources: StatusSummary[];
49
+ totalChanges: number;
50
+ }
51
+ /**
52
+ * Sync error with context
53
+ */
54
+ export declare class SyncError extends Error {
55
+ resourceType: string;
56
+ cause?: Error | undefined;
57
+ constructor(message: string, resourceType: string, cause?: Error | undefined);
58
+ }
59
+ /**
60
+ * Validation error with details
61
+ */
62
+ export declare class ValidationError extends Error {
63
+ results: ValidationResult[];
64
+ constructor(message: string, results: ValidationResult[]);
65
+ }
66
+ /**
67
+ * SyncEngine Options
68
+ */
69
+ export interface SyncEngineOptions {
70
+ /**
71
+ * Stop on first error instead of continuing
72
+ */
73
+ stopOnError?: boolean;
74
+ /**
75
+ * Run strategies in parallel where possible
76
+ */
77
+ parallel?: boolean;
78
+ }
79
+ /**
80
+ * SyncEngine - Generic synchronization orchestrator
81
+ *
82
+ * Orchestrates pull/push/status operations across all registered strategies.
83
+ */
84
+ export declare class SyncEngine {
85
+ private logger;
86
+ private options;
87
+ private strategies;
88
+ constructor(strategies: ISyncStrategy[], logger: ILogger, options?: SyncEngineOptions);
89
+ /**
90
+ * Register a new strategy
91
+ */
92
+ registerStrategy(strategy: ISyncStrategy): void;
93
+ /**
94
+ * Get a specific strategy by resource type
95
+ */
96
+ getStrategy(resourceType: string): ISyncStrategy | undefined;
97
+ /**
98
+ * Get all registered strategies
99
+ */
100
+ getStrategies(): ISyncStrategy[];
101
+ /**
102
+ * Pull ALL resources using registered strategies
103
+ */
104
+ pullAll(customer: CustomerConfig, options?: PullOptions): Promise<SyncPullResult>;
105
+ /**
106
+ * Pull specific resource types
107
+ */
108
+ pullSelected(customer: CustomerConfig, resourceTypes: string[], options?: PullOptions): Promise<SyncPullResult>;
109
+ /**
110
+ * Push ALL changed resources using registered strategies
111
+ */
112
+ pushAll(customer: CustomerConfig): Promise<SyncPushResult>;
113
+ /**
114
+ * Push specific resource types
115
+ */
116
+ pushSelected(customer: CustomerConfig, resourceTypes: string[]): Promise<SyncPushResult>;
117
+ /**
118
+ * Get status for ALL resources
119
+ */
120
+ getStatus(customer: CustomerConfig): Promise<StatusReport>;
121
+ /**
122
+ * Get status for specific resource types
123
+ */
124
+ getStatusSelected(customer: CustomerConfig, resourceTypes: string[]): Promise<StatusReport>;
125
+ /**
126
+ * Helper to execute pull with a single strategy
127
+ */
128
+ private pullWithStrategy;
129
+ }
130
+ /**
131
+ * Factory function for creating SyncEngine with default strategies
132
+ */
133
+ export declare function createSyncEngine(strategies: ISyncStrategy[], logger: ILogger, options?: SyncEngineOptions): SyncEngine;
134
+ //# sourceMappingURL=SyncEngine.d.ts.map
@@ -0,0 +1,335 @@
1
+ /**
2
+ * SyncEngine - Core synchronization orchestrator
3
+ *
4
+ * This is the central engine that coordinates sync operations across all resource types.
5
+ * It uses the Strategy pattern to handle different resources uniformly.
6
+ *
7
+ * Key benefits:
8
+ * - One engine handles projects, integrations, AKB, attributes, conversations
9
+ * - Adding new resource = implement one strategy class
10
+ * - No duplicate pull/push logic
11
+ * - Easy to test (mock strategies)
12
+ */
13
+ /**
14
+ * Sync error with context
15
+ */
16
+ export class SyncError extends Error {
17
+ resourceType;
18
+ cause;
19
+ constructor(message, resourceType, cause) {
20
+ super(message);
21
+ this.resourceType = resourceType;
22
+ this.cause = cause;
23
+ this.name = 'SyncError';
24
+ }
25
+ }
26
+ /**
27
+ * Validation error with details
28
+ */
29
+ export class ValidationError extends Error {
30
+ results;
31
+ constructor(message, results) {
32
+ super(message);
33
+ this.results = results;
34
+ this.name = 'ValidationError';
35
+ }
36
+ }
37
+ /**
38
+ * SyncEngine - Generic synchronization orchestrator
39
+ *
40
+ * Orchestrates pull/push/status operations across all registered strategies.
41
+ */
42
+ export class SyncEngine {
43
+ logger;
44
+ options;
45
+ strategies = new Map();
46
+ constructor(strategies, logger, options = {}) {
47
+ this.logger = logger;
48
+ this.options = options;
49
+ for (const strategy of strategies) {
50
+ this.strategies.set(strategy.resourceType, strategy);
51
+ }
52
+ }
53
+ /**
54
+ * Register a new strategy
55
+ */
56
+ registerStrategy(strategy) {
57
+ this.strategies.set(strategy.resourceType, strategy);
58
+ }
59
+ /**
60
+ * Get a specific strategy by resource type
61
+ */
62
+ getStrategy(resourceType) {
63
+ return this.strategies.get(resourceType);
64
+ }
65
+ /**
66
+ * Get all registered strategies
67
+ */
68
+ getStrategies() {
69
+ return Array.from(this.strategies.values());
70
+ }
71
+ /**
72
+ * Pull ALL resources using registered strategies
73
+ */
74
+ async pullAll(customer, options = {}) {
75
+ this.logger.info(`📥 Pulling all resources for customer: ${customer.idn}`);
76
+ const result = {
77
+ customer: customer.idn,
78
+ resources: [],
79
+ totalItems: 0,
80
+ errors: []
81
+ };
82
+ const strategies = Array.from(this.strategies.values());
83
+ if (this.options.parallel) {
84
+ // Parallel execution
85
+ const pullPromises = strategies.map(async (strategy) => {
86
+ try {
87
+ return await this.pullWithStrategy(strategy, customer, options);
88
+ }
89
+ catch (error) {
90
+ const message = `Failed to pull ${strategy.displayName}: ${error instanceof Error ? error.message : String(error)}`;
91
+ if (this.options.stopOnError) {
92
+ throw new SyncError(message, strategy.resourceType, error instanceof Error ? error : undefined);
93
+ }
94
+ result.errors.push(message);
95
+ return null;
96
+ }
97
+ });
98
+ const pullResults = await Promise.all(pullPromises);
99
+ for (const pullResult of pullResults) {
100
+ if (pullResult) {
101
+ result.resources.push(pullResult);
102
+ result.totalItems += pullResult.result.count;
103
+ }
104
+ }
105
+ }
106
+ else {
107
+ // Sequential execution
108
+ for (const strategy of strategies) {
109
+ this.logger.info(` 📦 Pulling ${strategy.displayName}...`);
110
+ try {
111
+ const pullResult = await this.pullWithStrategy(strategy, customer, options);
112
+ result.resources.push(pullResult);
113
+ result.totalItems += pullResult.result.count;
114
+ this.logger.info(` ✅ Pulled ${pullResult.result.count} ${strategy.displayName}`);
115
+ }
116
+ catch (error) {
117
+ const message = `Failed to pull ${strategy.displayName}: ${error instanceof Error ? error.message : String(error)}`;
118
+ this.logger.error(message, error);
119
+ if (this.options.stopOnError) {
120
+ throw new SyncError(message, strategy.resourceType, error instanceof Error ? error : undefined);
121
+ }
122
+ result.errors.push(message);
123
+ }
124
+ }
125
+ }
126
+ this.logger.info(`✅ Pull completed: ${result.totalItems} items from ${result.resources.length} resource types`);
127
+ return result;
128
+ }
129
+ /**
130
+ * Pull specific resource types
131
+ */
132
+ async pullSelected(customer, resourceTypes, options = {}) {
133
+ this.logger.info(`📥 Pulling selected resources for customer: ${customer.idn}`);
134
+ const result = {
135
+ customer: customer.idn,
136
+ resources: [],
137
+ totalItems: 0,
138
+ errors: []
139
+ };
140
+ for (const resourceType of resourceTypes) {
141
+ const strategy = this.strategies.get(resourceType);
142
+ if (!strategy) {
143
+ result.errors.push(`Unknown resource type: ${resourceType}`);
144
+ continue;
145
+ }
146
+ this.logger.info(` 📦 Pulling ${strategy.displayName}...`);
147
+ try {
148
+ const pullResult = await this.pullWithStrategy(strategy, customer, options);
149
+ result.resources.push(pullResult);
150
+ result.totalItems += pullResult.result.count;
151
+ this.logger.info(` ✅ Pulled ${pullResult.result.count} ${strategy.displayName}`);
152
+ }
153
+ catch (error) {
154
+ const message = `Failed to pull ${strategy.displayName}: ${error instanceof Error ? error.message : String(error)}`;
155
+ this.logger.error(message, error);
156
+ if (this.options.stopOnError) {
157
+ throw new SyncError(message, strategy.resourceType, error instanceof Error ? error : undefined);
158
+ }
159
+ result.errors.push(message);
160
+ }
161
+ }
162
+ return result;
163
+ }
164
+ /**
165
+ * Push ALL changed resources using registered strategies
166
+ */
167
+ async pushAll(customer) {
168
+ this.logger.info(`📤 Pushing changes for customer: ${customer.idn}`);
169
+ const result = {
170
+ customer: customer.idn,
171
+ resources: [],
172
+ totalCreated: 0,
173
+ totalUpdated: 0,
174
+ totalDeleted: 0,
175
+ errors: []
176
+ };
177
+ for (const strategy of this.strategies.values()) {
178
+ this.logger.info(` 🔍 Checking changes for ${strategy.displayName}...`);
179
+ try {
180
+ const changes = await strategy.getChanges(customer);
181
+ if (changes.length === 0) {
182
+ this.logger.verbose(` No changes for ${strategy.displayName}`);
183
+ continue;
184
+ }
185
+ this.logger.info(` Found ${changes.length} changes in ${strategy.displayName}`);
186
+ // Validate before push
187
+ const items = changes.map(c => c.item);
188
+ const validation = await strategy.validate(customer, items);
189
+ if (!validation.valid) {
190
+ const errorMessages = validation.errors.map(e => `${e.field}: ${e.message}`).join(', ');
191
+ throw new ValidationError(`Validation failed: ${errorMessages}`, [validation]);
192
+ }
193
+ // Push changes
194
+ const pushResult = await strategy.push(customer, changes);
195
+ result.resources.push({
196
+ resourceType: strategy.resourceType,
197
+ displayName: strategy.displayName,
198
+ result: pushResult
199
+ });
200
+ result.totalCreated += pushResult.created;
201
+ result.totalUpdated += pushResult.updated;
202
+ result.totalDeleted += pushResult.deleted;
203
+ result.errors.push(...pushResult.errors);
204
+ this.logger.info(` ✅ Pushed: ${pushResult.created} created, ${pushResult.updated} updated, ${pushResult.deleted} deleted`);
205
+ }
206
+ catch (error) {
207
+ const message = `Failed to push ${strategy.displayName}: ${error instanceof Error ? error.message : String(error)}`;
208
+ this.logger.error(message, error);
209
+ if (this.options.stopOnError) {
210
+ throw new SyncError(message, strategy.resourceType, error instanceof Error ? error : undefined);
211
+ }
212
+ result.errors.push(message);
213
+ }
214
+ }
215
+ this.logger.info(`✅ Push completed: ${result.totalCreated} created, ${result.totalUpdated} updated, ${result.totalDeleted} deleted`);
216
+ return result;
217
+ }
218
+ /**
219
+ * Push specific resource types
220
+ */
221
+ async pushSelected(customer, resourceTypes) {
222
+ this.logger.info(`📤 Pushing selected resources for customer: ${customer.idn}`);
223
+ const result = {
224
+ customer: customer.idn,
225
+ resources: [],
226
+ totalCreated: 0,
227
+ totalUpdated: 0,
228
+ totalDeleted: 0,
229
+ errors: []
230
+ };
231
+ for (const resourceType of resourceTypes) {
232
+ const strategy = this.strategies.get(resourceType);
233
+ if (!strategy) {
234
+ result.errors.push(`Unknown resource type: ${resourceType}`);
235
+ continue;
236
+ }
237
+ try {
238
+ const changes = await strategy.getChanges(customer);
239
+ if (changes.length === 0) {
240
+ continue;
241
+ }
242
+ // Validate before push
243
+ const items = changes.map(c => c.item);
244
+ const validation = await strategy.validate(customer, items);
245
+ if (!validation.valid) {
246
+ const errorMessages = validation.errors.map(e => `${e.field}: ${e.message}`).join(', ');
247
+ throw new ValidationError(`Validation failed: ${errorMessages}`, [validation]);
248
+ }
249
+ const pushResult = await strategy.push(customer, changes);
250
+ result.resources.push({
251
+ resourceType: strategy.resourceType,
252
+ displayName: strategy.displayName,
253
+ result: pushResult
254
+ });
255
+ result.totalCreated += pushResult.created;
256
+ result.totalUpdated += pushResult.updated;
257
+ result.totalDeleted += pushResult.deleted;
258
+ result.errors.push(...pushResult.errors);
259
+ }
260
+ catch (error) {
261
+ const message = `Failed to push ${strategy.displayName}: ${error instanceof Error ? error.message : String(error)}`;
262
+ this.logger.error(message, error);
263
+ if (this.options.stopOnError) {
264
+ throw new SyncError(message, strategy.resourceType, error instanceof Error ? error : undefined);
265
+ }
266
+ result.errors.push(message);
267
+ }
268
+ }
269
+ return result;
270
+ }
271
+ /**
272
+ * Get status for ALL resources
273
+ */
274
+ async getStatus(customer) {
275
+ const report = {
276
+ customer: customer.idn,
277
+ resources: [],
278
+ totalChanges: 0
279
+ };
280
+ for (const strategy of this.strategies.values()) {
281
+ try {
282
+ const status = await strategy.getStatus(customer);
283
+ report.resources.push(status);
284
+ report.totalChanges += status.changedCount;
285
+ }
286
+ catch (error) {
287
+ this.logger.error(`Failed to get status for ${strategy.displayName}`, error);
288
+ }
289
+ }
290
+ return report;
291
+ }
292
+ /**
293
+ * Get status for specific resource types
294
+ */
295
+ async getStatusSelected(customer, resourceTypes) {
296
+ const report = {
297
+ customer: customer.idn,
298
+ resources: [],
299
+ totalChanges: 0
300
+ };
301
+ for (const resourceType of resourceTypes) {
302
+ const strategy = this.strategies.get(resourceType);
303
+ if (!strategy) {
304
+ continue;
305
+ }
306
+ try {
307
+ const status = await strategy.getStatus(customer);
308
+ report.resources.push(status);
309
+ report.totalChanges += status.changedCount;
310
+ }
311
+ catch (error) {
312
+ this.logger.error(`Failed to get status for ${strategy.displayName}`, error);
313
+ }
314
+ }
315
+ return report;
316
+ }
317
+ /**
318
+ * Helper to execute pull with a single strategy
319
+ */
320
+ async pullWithStrategy(strategy, customer, options) {
321
+ const result = await strategy.pull(customer, options);
322
+ return {
323
+ resourceType: strategy.resourceType,
324
+ displayName: strategy.displayName,
325
+ result
326
+ };
327
+ }
328
+ }
329
+ /**
330
+ * Factory function for creating SyncEngine with default strategies
331
+ */
332
+ export function createSyncEngine(strategies, logger, options) {
333
+ return new SyncEngine(strategies, logger, options);
334
+ }
335
+ //# sourceMappingURL=SyncEngine.js.map
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Sync Application Layer Exports
3
+ */
4
+ export * from './SyncEngine.js';
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Sync Application Layer Exports
3
+ */
4
+ export * from './SyncEngine.js';
5
+ //# sourceMappingURL=index.js.map
@@ -9,7 +9,7 @@ export async function handleCreateAttributeCommand(customerConfig, args, verbose
9
9
  const selectedCustomer = requireSingleCustomer(customerConfig, args.customer);
10
10
  // Parse arguments
11
11
  const idn = args._[1];
12
- const value = args.value || '';
12
+ const value = args.value !== undefined ? String(args.value) : '';
13
13
  const title = args.title || idn;
14
14
  const description = args.description || '';
15
15
  const group = args.group || 'General';
@@ -0,0 +1,3 @@
1
+ import type { MultiCustomerConfig, CliArgs } from '../../types.js';
2
+ export declare function handleCreateCustomerCommand(customerConfig: MultiCustomerConfig, args: CliArgs, verbose?: boolean): Promise<void>;
3
+ //# sourceMappingURL=create-customer.d.ts.map
@@ -0,0 +1,159 @@
1
+ /**
2
+ * Create Customer Command Handler - Creates a new NEWO customer account
3
+ *
4
+ * This command creates an empty NEWO customer using the v3 API.
5
+ * It requires the api_secret attribute from the source customer account.
6
+ */
7
+ import { makeClient, createNewoCustomer, getCustomerAttributes } from '../../api.js';
8
+ import { getValidAccessToken } from '../../auth.js';
9
+ import { requireSingleCustomer } from '../customer-selection.js';
10
+ export async function handleCreateCustomerCommand(customerConfig, args, verbose = false) {
11
+ try {
12
+ const selectedCustomer = requireSingleCustomer(customerConfig, args.customer);
13
+ // Parse arguments
14
+ const organizationName = args._[1];
15
+ const email = args.email;
16
+ const tenant = args.tenant || 'newo';
17
+ const phone = args.phone || '';
18
+ const comment = args.comment || '';
19
+ const status = args.status || 'temporal';
20
+ const projectIdn = args.project;
21
+ const externalId = args['external-id'];
22
+ // Validate required parameters
23
+ if (!organizationName) {
24
+ console.error('Error: Organization name is required');
25
+ console.error('Usage: newo create-customer <organization_name> --email <email> [options]');
26
+ console.error('');
27
+ console.error('Options:');
28
+ console.error(' --email <email> Owner email (required)');
29
+ console.error(' --tenant <tenant> Tenant name (default: newo)');
30
+ console.error(' --phone <phone> Contact phone number');
31
+ console.error(' --comment <comment> Comment or notes');
32
+ console.error(' --status <status> temporal or permanent (default: temporal)');
33
+ console.error(' --project <idn> Project IDN to install (e.g., naf)');
34
+ console.error(' --external-id <id> External customer ID for tracking');
35
+ console.error('');
36
+ console.error('Example:');
37
+ console.error(' newo create-customer "Acme Corp" --email owner@acme.com --project naf');
38
+ process.exit(1);
39
+ }
40
+ if (!email) {
41
+ console.error('Error: Owner email is required (--email <email>)');
42
+ process.exit(1);
43
+ }
44
+ if (verbose) {
45
+ console.log(`📝 Creating new NEWO customer...`);
46
+ console.log(` Organization: ${organizationName}`);
47
+ console.log(` Owner Email: ${email}`);
48
+ console.log(` Tenant: ${tenant}`);
49
+ console.log(` Status: ${status}`);
50
+ if (phone)
51
+ console.log(` Phone: ${phone}`);
52
+ if (comment)
53
+ console.log(` Comment: ${comment}`);
54
+ if (projectIdn)
55
+ console.log(` Project: ${projectIdn}`);
56
+ if (externalId)
57
+ console.log(` External ID: ${externalId}`);
58
+ }
59
+ // Get access token and create client
60
+ const accessToken = await getValidAccessToken(selectedCustomer);
61
+ const client = await makeClient(verbose, accessToken);
62
+ // Get api_secret from customer attributes
63
+ console.log('🔑 Fetching API secret from customer attributes...');
64
+ const attributesResponse = await getCustomerAttributes(client, true);
65
+ const apiSecretAttr = attributesResponse.attributes.find(attr => attr.idn === 'api_secret');
66
+ if (!apiSecretAttr || !apiSecretAttr.value) {
67
+ console.error('Error: api_secret attribute not found in customer account');
68
+ console.error('This command requires the api_secret attribute to create new customers.');
69
+ process.exit(1);
70
+ }
71
+ const apiSecret = typeof apiSecretAttr.value === 'string' ? apiSecretAttr.value : String(apiSecretAttr.value);
72
+ if (verbose) {
73
+ console.log(`✅ API secret found (${apiSecret.substring(0, 6)}...)`);
74
+ }
75
+ // Build members array
76
+ const members = [
77
+ {
78
+ email: email,
79
+ role: 'owner',
80
+ tenants: [tenant]
81
+ }
82
+ ];
83
+ // Build projects array if project specified
84
+ const projects = [];
85
+ if (projectIdn) {
86
+ projects.push({
87
+ idn: projectIdn
88
+ });
89
+ }
90
+ // Build customer object - only include optional fields if they have values
91
+ const customerData = {
92
+ organization_name: organizationName,
93
+ tenant: tenant,
94
+ members: members,
95
+ contact_email: email,
96
+ organization_type: 'customer',
97
+ organization_status: status,
98
+ attributes: [
99
+ {
100
+ idn: 'empty',
101
+ value: 'True'
102
+ }
103
+ ]
104
+ };
105
+ // Add optional fields only if they have values
106
+ if (comment) {
107
+ customerData.comment = comment;
108
+ }
109
+ if (phone) {
110
+ customerData.contact_phone = phone;
111
+ }
112
+ if (externalId) {
113
+ customerData.external_customer_id = externalId;
114
+ }
115
+ // Build customer creation request
116
+ const createRequest = {
117
+ secret: apiSecret,
118
+ customer: customerData
119
+ };
120
+ // Add projects only if specified
121
+ if (projects.length > 0) {
122
+ createRequest.projects = projects;
123
+ }
124
+ if (verbose) {
125
+ console.log('📤 Creating customer with request:');
126
+ console.log(JSON.stringify(createRequest, null, 2));
127
+ }
128
+ // Create the customer
129
+ console.log('🚀 Creating customer...');
130
+ const response = await createNewoCustomer(client, createRequest);
131
+ console.log('');
132
+ console.log('✅ Customer created successfully!');
133
+ console.log(` Customer IDN: ${response.idn}`);
134
+ console.log(` Customer ID: ${response.id}`);
135
+ console.log(` Organization: ${organizationName}`);
136
+ console.log(` Owner: ${email}`);
137
+ if (projectIdn) {
138
+ console.log(` Project: ${projectIdn}`);
139
+ }
140
+ console.log('');
141
+ console.log('📝 Next steps:');
142
+ console.log(` 1. Add the new customer to your .env file:`);
143
+ console.log(` NEWO_${response.idn}_API_KEY=<api_key>`);
144
+ console.log(` 2. Or use the customer_intercom integration to manage the new customer`);
145
+ }
146
+ catch (error) {
147
+ const errMessage = error instanceof Error ? error.message : String(error);
148
+ console.error('❌ Failed to create customer:', errMessage);
149
+ // Provide more detailed error info if available
150
+ if (error && typeof error === 'object' && 'response' in error) {
151
+ const axiosError = error;
152
+ if (axiosError.response?.data) {
153
+ console.error(' API Error:', JSON.stringify(axiosError.response.data, null, 2));
154
+ }
155
+ }
156
+ process.exit(1);
157
+ }
158
+ }
159
+ //# sourceMappingURL=create-customer.js.map
@@ -0,0 +1,6 @@
1
+ import type { MultiCustomerConfig, CliArgs } from '../../types.js';
2
+ /**
3
+ * Main diff command handler
4
+ */
5
+ export declare function handleDiffCommand(customerConfig: MultiCustomerConfig, args: CliArgs, verbose: boolean): Promise<void>;
6
+ //# sourceMappingURL=diff.d.ts.map