@jam-nodes/playground 0.1.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 (62) hide show
  1. package/dist/commands/credentials.d.ts +6 -0
  2. package/dist/commands/credentials.d.ts.map +1 -0
  3. package/dist/commands/credentials.js +205 -0
  4. package/dist/commands/credentials.js.map +1 -0
  5. package/dist/commands/index.d.ts +5 -0
  6. package/dist/commands/index.d.ts.map +1 -0
  7. package/dist/commands/index.js +5 -0
  8. package/dist/commands/index.js.map +1 -0
  9. package/dist/commands/init.d.ts +6 -0
  10. package/dist/commands/init.d.ts.map +1 -0
  11. package/dist/commands/init.js +76 -0
  12. package/dist/commands/init.js.map +1 -0
  13. package/dist/commands/list.d.ts +6 -0
  14. package/dist/commands/list.d.ts.map +1 -0
  15. package/dist/commands/list.js +111 -0
  16. package/dist/commands/list.js.map +1 -0
  17. package/dist/commands/run.d.ts +6 -0
  18. package/dist/commands/run.d.ts.map +1 -0
  19. package/dist/commands/run.js +245 -0
  20. package/dist/commands/run.js.map +1 -0
  21. package/dist/credentials/env-provider.d.ts +54 -0
  22. package/dist/credentials/env-provider.d.ts.map +1 -0
  23. package/dist/credentials/env-provider.js +177 -0
  24. package/dist/credentials/env-provider.js.map +1 -0
  25. package/dist/credentials/index.d.ts +2 -0
  26. package/dist/credentials/index.d.ts.map +1 -0
  27. package/dist/credentials/index.js +2 -0
  28. package/dist/credentials/index.js.map +1 -0
  29. package/dist/index.d.ts +3 -0
  30. package/dist/index.d.ts.map +1 -0
  31. package/dist/index.js +24 -0
  32. package/dist/index.js.map +1 -0
  33. package/dist/ui/index.d.ts +2 -0
  34. package/dist/ui/index.d.ts.map +1 -0
  35. package/dist/ui/index.js +2 -0
  36. package/dist/ui/index.js.map +1 -0
  37. package/dist/ui/prompts.d.ts +49 -0
  38. package/dist/ui/prompts.d.ts.map +1 -0
  39. package/dist/ui/prompts.js +189 -0
  40. package/dist/ui/prompts.js.map +1 -0
  41. package/dist/utils/index.d.ts +2 -0
  42. package/dist/utils/index.d.ts.map +1 -0
  43. package/dist/utils/index.js +2 -0
  44. package/dist/utils/index.js.map +1 -0
  45. package/dist/utils/mock-generator.d.ts +11 -0
  46. package/dist/utils/mock-generator.d.ts.map +1 -0
  47. package/dist/utils/mock-generator.js +199 -0
  48. package/dist/utils/mock-generator.js.map +1 -0
  49. package/package.json +53 -0
  50. package/src/commands/credentials.ts +242 -0
  51. package/src/commands/index.ts +4 -0
  52. package/src/commands/init.ts +80 -0
  53. package/src/commands/list.ts +124 -0
  54. package/src/commands/run.ts +273 -0
  55. package/src/credentials/env-provider.ts +208 -0
  56. package/src/credentials/index.ts +10 -0
  57. package/src/index.ts +32 -0
  58. package/src/ui/index.ts +9 -0
  59. package/src/ui/prompts.ts +259 -0
  60. package/src/utils/index.ts +1 -0
  61. package/src/utils/mock-generator.ts +227 -0
  62. package/tsconfig.json +15 -0
@@ -0,0 +1,242 @@
1
+ import { Command } from 'commander';
2
+ import chalk from 'chalk';
3
+ import inquirer from 'inquirer';
4
+ import {
5
+ getCredentials,
6
+ saveCredentials,
7
+ deleteCredentials,
8
+ listSavedCredentials,
9
+ getCredentialSource,
10
+ clearAllCredentials,
11
+ getStorePath,
12
+ } from '../credentials/index.js';
13
+
14
+ /**
15
+ * Known credential types and their required fields
16
+ */
17
+ const CREDENTIAL_SCHEMAS: Record<
18
+ string,
19
+ Array<{ name: string; message: string; type?: 'input' | 'password' }>
20
+ > = {
21
+ apollo: [{ name: 'apiKey', message: 'Apollo API Key:', type: 'password' }],
22
+ hunter: [{ name: 'apiKey', message: 'Hunter API Key:', type: 'password' }],
23
+ openai: [{ name: 'apiKey', message: 'OpenAI API Key:', type: 'password' }],
24
+ anthropic: [{ name: 'apiKey', message: 'Anthropic API Key:', type: 'password' }],
25
+ sendgrid: [{ name: 'apiKey', message: 'SendGrid API Key:', type: 'password' }],
26
+ hubspot: [{ name: 'apiKey', message: 'HubSpot API Key:', type: 'password' }],
27
+ clearbit: [{ name: 'apiKey', message: 'Clearbit API Key:', type: 'password' }],
28
+ dropcontact: [{ name: 'apiKey', message: 'Dropcontact API Key:', type: 'password' }],
29
+ twitter: [{ name: 'bearerToken', message: 'Twitter Bearer Token:', type: 'password' }],
30
+ linkedin: [{ name: 'accessToken', message: 'LinkedIn Access Token:', type: 'password' }],
31
+ reddit: [
32
+ { name: 'clientId', message: 'Reddit Client ID:', type: 'input' },
33
+ { name: 'clientSecret', message: 'Reddit Client Secret:', type: 'password' },
34
+ ],
35
+ dataforseo: [
36
+ { name: 'login', message: 'DataForSEO Login:', type: 'input' },
37
+ { name: 'password', message: 'DataForSEO Password:', type: 'password' },
38
+ ],
39
+ };
40
+
41
+ /**
42
+ * Credentials command - manage saved credentials
43
+ */
44
+ export const credentialsCommand = new Command('credentials')
45
+ .alias('creds')
46
+ .description('Manage saved credentials');
47
+
48
+ /**
49
+ * List saved credentials
50
+ */
51
+ credentialsCommand
52
+ .command('list')
53
+ .description('List all saved credentials')
54
+ .action(async () => {
55
+ const saved = listSavedCredentials();
56
+
57
+ console.log();
58
+ console.log(chalk.bold('Saved Credentials'));
59
+ console.log(chalk.dim(`Store: ${getStorePath()}`));
60
+ console.log();
61
+
62
+ if (saved.length === 0) {
63
+ console.log(chalk.dim('No credentials saved yet.'));
64
+ console.log(chalk.dim('Use "jam-playground credentials set <service>" to add credentials.'));
65
+ return;
66
+ }
67
+
68
+ for (const service of saved) {
69
+ const source = await getCredentialSource(service);
70
+ const icon = source === 'env' ? '🌍' : '💾';
71
+ console.log(` ${icon} ${chalk.bold(service)} ${chalk.dim(`(${source})`)}`);
72
+ }
73
+
74
+ console.log();
75
+ console.log(chalk.dim('🌍 = from environment, 💾 = saved to config'));
76
+ });
77
+
78
+ /**
79
+ * Set credentials for a service
80
+ */
81
+ credentialsCommand
82
+ .command('set <service>')
83
+ .description('Set credentials for a service')
84
+ .action(async (service: string) => {
85
+ const serviceLower = service.toLowerCase();
86
+
87
+ // Get schema for this service
88
+ const schema = CREDENTIAL_SCHEMAS[serviceLower];
89
+
90
+ if (!schema) {
91
+ console.log(chalk.yellow(`Unknown service: ${service}`));
92
+ console.log(chalk.dim('Known services:'));
93
+ console.log(chalk.dim(` ${Object.keys(CREDENTIAL_SCHEMAS).join(', ')}`));
94
+ console.log();
95
+
96
+ // Allow custom single API key
97
+ const { proceed } = await inquirer.prompt([
98
+ {
99
+ type: 'confirm',
100
+ name: 'proceed',
101
+ message: 'Would you like to set a custom API key for this service?',
102
+ default: true,
103
+ },
104
+ ]);
105
+
106
+ if (!proceed) return;
107
+
108
+ const { apiKey } = await inquirer.prompt([
109
+ {
110
+ type: 'password',
111
+ name: 'apiKey',
112
+ message: `${service} API Key:`,
113
+ mask: '*',
114
+ },
115
+ ]);
116
+
117
+ saveCredentials(serviceLower, { apiKey });
118
+ console.log(chalk.green(`✓ ${service} credentials saved`));
119
+ return;
120
+ }
121
+
122
+ // Check if already exists
123
+ const existing = await getCredentials(serviceLower);
124
+ if (existing) {
125
+ const { overwrite } = await inquirer.prompt([
126
+ {
127
+ type: 'confirm',
128
+ name: 'overwrite',
129
+ message: `Credentials for ${service} already exist. Overwrite?`,
130
+ default: false,
131
+ },
132
+ ]);
133
+ if (!overwrite) return;
134
+ }
135
+
136
+ // Prompt for credentials
137
+ console.log();
138
+ console.log(chalk.dim(`Enter credentials for ${service}:`));
139
+
140
+ const answers = await inquirer.prompt(
141
+ schema.map((field) => ({
142
+ type: field.type || 'password',
143
+ name: field.name,
144
+ message: field.message,
145
+ mask: '*',
146
+ }))
147
+ );
148
+
149
+ saveCredentials(serviceLower, answers);
150
+ console.log(chalk.green(`✓ ${service} credentials saved`));
151
+ });
152
+
153
+ /**
154
+ * Delete credentials for a service
155
+ */
156
+ credentialsCommand
157
+ .command('delete <service>')
158
+ .alias('rm')
159
+ .description('Delete credentials for a service')
160
+ .action(async (service: string) => {
161
+ const serviceLower = service.toLowerCase();
162
+
163
+ // Check if exists
164
+ const existing = await getCredentials(serviceLower);
165
+ if (!existing) {
166
+ console.log(chalk.yellow(`No credentials found for ${service}`));
167
+ return;
168
+ }
169
+
170
+ const { confirm } = await inquirer.prompt([
171
+ {
172
+ type: 'confirm',
173
+ name: 'confirm',
174
+ message: `Delete credentials for ${service}?`,
175
+ default: false,
176
+ },
177
+ ]);
178
+
179
+ if (!confirm) return;
180
+
181
+ if (deleteCredentials(serviceLower)) {
182
+ console.log(chalk.green(`✓ ${service} credentials deleted`));
183
+ } else {
184
+ console.log(chalk.yellow(`Could not delete ${service} credentials`));
185
+ }
186
+ });
187
+
188
+ /**
189
+ * Check credentials for a service
190
+ */
191
+ credentialsCommand
192
+ .command('check <service>')
193
+ .description('Check if credentials exist for a service')
194
+ .action(async (service: string) => {
195
+ const serviceLower = service.toLowerCase();
196
+ const source = await getCredentialSource(serviceLower);
197
+
198
+ if (source) {
199
+ console.log(chalk.green(`✓ ${service} credentials found (${source})`));
200
+ } else {
201
+ console.log(chalk.red(`✗ ${service} credentials not found`));
202
+ }
203
+ });
204
+
205
+ /**
206
+ * Clear all saved credentials
207
+ */
208
+ credentialsCommand
209
+ .command('clear')
210
+ .description('Clear all saved credentials')
211
+ .action(async () => {
212
+ const saved = listSavedCredentials();
213
+
214
+ if (saved.length === 0) {
215
+ console.log(chalk.dim('No credentials to clear.'));
216
+ return;
217
+ }
218
+
219
+ const { confirm } = await inquirer.prompt([
220
+ {
221
+ type: 'confirm',
222
+ name: 'confirm',
223
+ message: `Delete all ${saved.length} saved credentials?`,
224
+ default: false,
225
+ },
226
+ ]);
227
+
228
+ if (!confirm) return;
229
+
230
+ clearAllCredentials();
231
+ console.log(chalk.green('✓ All credentials cleared'));
232
+ });
233
+
234
+ /**
235
+ * Show credential store path
236
+ */
237
+ credentialsCommand
238
+ .command('path')
239
+ .description('Show the credential store path')
240
+ .action(() => {
241
+ console.log(getStorePath());
242
+ });
@@ -0,0 +1,4 @@
1
+ export { listCommand } from './list.js';
2
+ export { runCommand } from './run.js';
3
+ export { initCommand } from './init.js';
4
+ export { credentialsCommand } from './credentials.js';
@@ -0,0 +1,80 @@
1
+ import { Command } from 'commander';
2
+ import chalk from 'chalk';
3
+ import * as fs from 'fs';
4
+ import * as path from 'path';
5
+
6
+ /**
7
+ * Template for .env file
8
+ */
9
+ const ENV_TEMPLATE = `# jam-nodes Playground Configuration
10
+ # Add your API keys below
11
+
12
+ # Apollo.io (Contact Search)
13
+ # JAM_APOLLO_API_KEY=your_api_key_here
14
+
15
+ # Hunter.io (Email Finder)
16
+ # JAM_HUNTER_API_KEY=your_api_key_here
17
+
18
+ # OpenAI (AI Features)
19
+ # JAM_OPENAI_API_KEY=your_api_key_here
20
+
21
+ # Anthropic (AI Features)
22
+ # JAM_ANTHROPIC_API_KEY=your_api_key_here
23
+
24
+ # Twitter/X (Social Monitoring)
25
+ # JAM_TWITTER_BEARER_TOKEN=your_bearer_token_here
26
+
27
+ # Reddit (Social Monitoring)
28
+ # JAM_REDDIT_CLIENT_ID=your_client_id_here
29
+ # JAM_REDDIT_CLIENT_SECRET=your_client_secret_here
30
+
31
+ # LinkedIn (Social Monitoring)
32
+ # JAM_LINKEDIN_ACCESS_TOKEN=your_access_token_here
33
+
34
+ # DataForSEO (SEO Tools)
35
+ # JAM_DATAFORSEO_LOGIN=your_login_here
36
+ # JAM_DATAFORSEO_PASSWORD=your_password_here
37
+
38
+ # SendGrid (Email Sending)
39
+ # JAM_SENDGRID_API_KEY=your_api_key_here
40
+
41
+ # HubSpot (CRM)
42
+ # JAM_HUBSPOT_API_KEY=your_api_key_here
43
+
44
+ # Clearbit (Enrichment)
45
+ # JAM_CLEARBIT_API_KEY=your_api_key_here
46
+
47
+ # Dropcontact (Enrichment)
48
+ # JAM_DROPCONTACT_API_KEY=your_api_key_here
49
+ `;
50
+
51
+ /**
52
+ * Init command - initializes a .env file with template
53
+ */
54
+ export const initCommand = new Command('init')
55
+ .description('Initialize a .env file with credential template')
56
+ .option('-f, --force', 'Overwrite existing .env file')
57
+ .option('-p, --path <path>', 'Custom path for .env file', '.env')
58
+ .action((options) => {
59
+ const envPath = path.resolve(process.cwd(), options.path);
60
+
61
+ // Check if file exists
62
+ if (fs.existsSync(envPath) && !options.force) {
63
+ console.log(chalk.yellow(`⚠ ${options.path} already exists`));
64
+ console.log(chalk.dim('Use --force to overwrite'));
65
+ return;
66
+ }
67
+
68
+ // Write template
69
+ fs.writeFileSync(envPath, ENV_TEMPLATE, 'utf-8');
70
+
71
+ console.log(chalk.green(`✓ Created ${options.path}`));
72
+ console.log();
73
+ console.log(chalk.dim('Edit the file to add your API keys.'));
74
+ console.log(chalk.dim('Uncomment and fill in the keys you need.'));
75
+ console.log();
76
+ console.log(chalk.bold('Quick start:'));
77
+ console.log(chalk.dim('1. Open .env in your editor'));
78
+ console.log(chalk.dim('2. Add your API keys'));
79
+ console.log(chalk.dim('3. Run: jam-playground run <node-type>'));
80
+ });
@@ -0,0 +1,124 @@
1
+ import { Command } from 'commander';
2
+ import chalk from 'chalk';
3
+ import { createRegistry, type NodeCategory } from '@jam-nodes/core';
4
+ import { builtInNodes } from '@jam-nodes/nodes';
5
+
6
+ // Create and populate the registry
7
+ const registry = createRegistry();
8
+ for (const node of builtInNodes) {
9
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
10
+ registry.register(node as any);
11
+ }
12
+
13
+ /**
14
+ * Category colors for display
15
+ */
16
+ const categoryColors: Record<NodeCategory, (text: string) => string> = {
17
+ logic: chalk.blue,
18
+ transform: chalk.green,
19
+ integration: chalk.magenta,
20
+ action: chalk.yellow,
21
+ };
22
+
23
+ /**
24
+ * Category labels for display
25
+ */
26
+ const categoryLabels: Record<NodeCategory, string> = {
27
+ logic: 'Logic',
28
+ transform: 'Transform',
29
+ integration: 'Integration',
30
+ action: 'Action',
31
+ };
32
+
33
+ /**
34
+ * List command - displays all available nodes
35
+ */
36
+ export const listCommand = new Command('list')
37
+ .description('List all available jam-nodes')
38
+ .option('-c, --category <category>', 'Filter by category (logic, transform, integration, action)')
39
+ .option('--json', 'Output as JSON')
40
+ .action((options) => {
41
+ const allDefinitions = registry.getAllDefinitions();
42
+
43
+ // Filter by category if specified
44
+ let definitions = allDefinitions;
45
+ if (options.category) {
46
+ const category = options.category.toLowerCase() as NodeCategory;
47
+ definitions = allDefinitions.filter((d) => d.category === category);
48
+
49
+ if (definitions.length === 0) {
50
+ console.log(chalk.yellow(`No nodes found in category: ${options.category}`));
51
+ console.log(chalk.dim(`Available categories: logic, transform, integration, action`));
52
+ return;
53
+ }
54
+ }
55
+
56
+ // JSON output
57
+ if (options.json) {
58
+ const output = definitions.map((d) => ({
59
+ type: d.type,
60
+ name: d.name,
61
+ description: d.description,
62
+ category: d.category,
63
+ estimatedDuration: d.estimatedDuration,
64
+ capabilities: d.capabilities,
65
+ }));
66
+ console.log(JSON.stringify(output, null, 2));
67
+ return;
68
+ }
69
+
70
+ // Group by category
71
+ const byCategory = definitions.reduce(
72
+ (acc, def) => {
73
+ const cat = def.category;
74
+ if (!acc[cat]) acc[cat] = [];
75
+ acc[cat].push(def);
76
+ return acc;
77
+ },
78
+ {} as Record<NodeCategory, typeof definitions>
79
+ );
80
+
81
+ // Header
82
+ console.log();
83
+ console.log(chalk.bold('Available jam-nodes'));
84
+ console.log(chalk.dim(`Total: ${definitions.length} nodes`));
85
+ console.log();
86
+
87
+ // Display by category
88
+ const categories: NodeCategory[] = ['logic', 'transform', 'integration', 'action'];
89
+
90
+ for (const category of categories) {
91
+ const nodes = byCategory[category];
92
+ if (!nodes || nodes.length === 0) continue;
93
+
94
+ const colorFn = categoryColors[category];
95
+ const label = categoryLabels[category];
96
+
97
+ console.log(colorFn(`━━━ ${label} (${nodes.length}) ━━━`));
98
+ console.log();
99
+
100
+ for (const node of nodes) {
101
+ console.log(` ${chalk.bold(node.type)}`);
102
+ console.log(` ${chalk.dim(node.name)} - ${node.description}`);
103
+
104
+ // Show capabilities if present
105
+ const caps = node.capabilities;
106
+ if (caps) {
107
+ const capList: string[] = [];
108
+ if (caps.supportsEnrichment) capList.push('enrichment');
109
+ if (caps.supportsBulkActions) capList.push('bulk');
110
+ if (caps.supportsRerun) capList.push('rerun');
111
+ if (caps.supportsApproval) capList.push('approval');
112
+ if (capList.length > 0) {
113
+ console.log(` ${chalk.dim('Capabilities:')} ${capList.join(', ')}`);
114
+ }
115
+ }
116
+
117
+ console.log();
118
+ }
119
+ }
120
+
121
+ // Usage hint
122
+ console.log(chalk.dim('Run a node: jam-playground run <node-type>'));
123
+ console.log(chalk.dim('Example: jam-playground run conditional'));
124
+ });