@omen.foundation/node-microservice-runtime 0.1.71 → 0.1.72

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.
@@ -0,0 +1,247 @@
1
+ /**
2
+ * Command handler for scaffolding new microservice projects.
3
+ */
4
+ import fs from 'node:fs/promises';
5
+ import path from 'node:path';
6
+ import { toPascalCase, toKebabCase, validateServiceName } from '../utils/name-utils.js';
7
+ import { fetchLatestRuntimeVersion } from '../utils/version-utils.js';
8
+ import { promptInput } from '../utils/prompt-utils.js';
9
+ /**
10
+ * Handles the scaffold command.
11
+ */
12
+ export async function handleScaffold(args) {
13
+ let serviceName = args[0];
14
+ // Interactive prompt for service name if not provided
15
+ if (!serviceName) {
16
+ serviceName = await promptInput('Enter microservice name (alphanumeric and underscores only)');
17
+ }
18
+ // Validate service name
19
+ if (!serviceName || !validateServiceName(serviceName)) {
20
+ throw new Error(`Invalid microservice name "${serviceName}". Only alphanumeric and underscore characters are allowed.`);
21
+ }
22
+ // Fetch latest runtime version
23
+ console.log('Fetching latest runtime version...');
24
+ const runtimeVersion = await fetchLatestRuntimeVersion();
25
+ console.log(`Using @omen.foundation/node-microservice-runtime version ${runtimeVersion}`);
26
+ // Prompt for optional values
27
+ const displayName = await promptInput('Enter display name for the service (optional)', serviceName);
28
+ const beamoId = await promptInput('Enter Beamable Beamo ID (optional, defaults to service name)', serviceName);
29
+ // Validate beamoId
30
+ if (beamoId && !validateServiceName(beamoId)) {
31
+ throw new Error(`Invalid Beamo ID "${beamoId}". Only alphanumeric and underscore characters are allowed.`);
32
+ }
33
+ const options = {
34
+ serviceName,
35
+ displayName: displayName || serviceName,
36
+ beamoId: beamoId || serviceName,
37
+ runtimeVersion,
38
+ };
39
+ // Check if directory already exists
40
+ const targetDir = path.resolve(process.cwd(), serviceName);
41
+ try {
42
+ await fs.access(targetDir);
43
+ const overwrite = await promptInput(`Directory "${serviceName}" already exists. Overwrite? (y/n)`, 'n');
44
+ if (overwrite.toLowerCase() !== 'y' && overwrite.toLowerCase() !== 'yes') {
45
+ console.log('Scaffold cancelled.');
46
+ return;
47
+ }
48
+ // Remove existing directory
49
+ await fs.rm(targetDir, { recursive: true, force: true });
50
+ }
51
+ catch {
52
+ // Directory doesn't exist, that's fine
53
+ }
54
+ // Generate project structure
55
+ await generateProjectStructure(targetDir, options);
56
+ console.log(`\n✅ Successfully scaffolded microservice "${serviceName}"!`);
57
+ console.log(`\nNext steps:`);
58
+ console.log(` 1. cd ${serviceName}`);
59
+ console.log(` 2. npm install`);
60
+ console.log(` 3. Copy .env.sample to .env and configure your credentials`);
61
+ console.log(` 4. npm run dev`);
62
+ }
63
+ /**
64
+ * Generates the complete project structure.
65
+ */
66
+ async function generateProjectStructure(targetDir, options) {
67
+ // Create directories
68
+ await fs.mkdir(targetDir, { recursive: true });
69
+ await fs.mkdir(path.join(targetDir, 'src'), { recursive: true });
70
+ await fs.mkdir(path.join(targetDir, 'src', 'services'), { recursive: true });
71
+ await fs.mkdir(path.join(targetDir, 'dist'), { recursive: true });
72
+ // Generate files
73
+ await fs.writeFile(path.join(targetDir, 'package.json'), generatePackageJson(options));
74
+ await fs.writeFile(path.join(targetDir, 'tsconfig.json'), generateTsConfig());
75
+ await fs.writeFile(path.join(targetDir, '.env.sample'), generateEnvSample());
76
+ await fs.writeFile(path.join(targetDir, '.gitignore'), generateGitIgnore());
77
+ await fs.writeFile(path.join(targetDir, 'src', 'main.ts'), generateMainTs(options));
78
+ await fs.writeFile(path.join(targetDir, 'src', `${toPascalCase(options.serviceName)}Service.ts`), generateServiceTs(options));
79
+ await fs.writeFile(path.join(targetDir, 'src', 'services', 'example-domain-service.ts'), generateDomainServiceTs());
80
+ }
81
+ /**
82
+ * Generates package.json content.
83
+ */
84
+ function generatePackageJson(options) {
85
+ const serviceNameKebab = toKebabCase(options.serviceName);
86
+ const packageName = `@beamable/${serviceNameKebab}-node-microservice`;
87
+ return JSON.stringify({
88
+ name: packageName,
89
+ version: '0.1.0',
90
+ private: true,
91
+ type: 'module',
92
+ main: 'dist/main.js',
93
+ types: 'dist/main.d.ts',
94
+ scripts: {
95
+ dev: 'tsx --env-file .env src/main.ts',
96
+ build: 'tsc -p tsconfig.json',
97
+ validate: 'npx beamo-node validate --env-file .env',
98
+ publish: 'npx beamo-node publish --env-file .env',
99
+ },
100
+ dependencies: {
101
+ '@omen.foundation/node-microservice-runtime': `^${options.runtimeVersion}`,
102
+ dotenv: '^16.4.7',
103
+ mongodb: '^6.10.0',
104
+ },
105
+ devDependencies: {
106
+ '@types/node': '^20.11.30',
107
+ 'pino-pretty': '^13.0.0',
108
+ tsx: '^4.19.2',
109
+ typescript: '^5.4.5',
110
+ },
111
+ beamable: {
112
+ beamoId: options.beamoId,
113
+ projectType: 'service',
114
+ },
115
+ }, null, 2);
116
+ }
117
+ /**
118
+ * Generates tsconfig.json content.
119
+ */
120
+ function generateTsConfig() {
121
+ return JSON.stringify({
122
+ extends: '../Microservice/tsconfig.base.json',
123
+ compilerOptions: {
124
+ outDir: 'dist',
125
+ rootDir: 'src',
126
+ declaration: true,
127
+ declarationMap: true,
128
+ },
129
+ include: ['src/**/*.ts'],
130
+ exclude: ['dist', 'node_modules'],
131
+ }, null, 2);
132
+ }
133
+ /**
134
+ * Generates .env.sample content.
135
+ */
136
+ function generateEnvSample() {
137
+ return `CID=
138
+ PID=
139
+ HOST=wss://api.beamable.com/socket
140
+ SECRET=
141
+ NAME_PREFIX=
142
+ LOG_LEVEL=info
143
+ BEAMABLE_TOKEN=
144
+ BEAMABLE_API_HOST=https://api.beamable.com
145
+ BEAMABLE_GAME_PID=
146
+ `;
147
+ }
148
+ /**
149
+ * Generates .gitignore content.
150
+ */
151
+ function generateGitIgnore() {
152
+ return `node_modules/
153
+ dist/
154
+ .env
155
+ *.log
156
+ .DS_Store
157
+ `;
158
+ }
159
+ /**
160
+ * Generates main.ts content.
161
+ */
162
+ function generateMainTs(options) {
163
+ const serviceNamePascal = toPascalCase(options.serviceName);
164
+ return `import 'dotenv/config';
165
+ import './${serviceNamePascal}Service.js';
166
+ import { runMicroservice } from '@omen.foundation/node-microservice-runtime';
167
+
168
+ void runMicroservice();
169
+ `;
170
+ }
171
+ /**
172
+ * Generates the main service class file.
173
+ */
174
+ function generateServiceTs(options) {
175
+ const serviceNamePascal = toPascalCase(options.serviceName);
176
+ return `import {
177
+ Microservice,
178
+ Callable,
179
+ ClientCallable,
180
+ ServerCallable,
181
+ SwaggerCategory,
182
+ ConfigureServices,
183
+ type DependencyBuilder,
184
+ type RequestContext,
185
+ } from '@omen.foundation/node-microservice-runtime';
186
+ import { ExampleDomainService } from './services/example-domain-service.js';
187
+
188
+ @Microservice('${options.serviceName}')
189
+ export class ${serviceNamePascal}Service {
190
+ @ConfigureServices
191
+ static register(builder: DependencyBuilder): void {
192
+ builder.addSingletonClass(ExampleDomainService);
193
+ }
194
+
195
+ /**
196
+ * Example of a public Callable endpoint.
197
+ * No authentication required.
198
+ */
199
+ @Callable({ route: 'isTwo' })
200
+ @SwaggerCategory('Examples')
201
+ async isTwo(_ctx: RequestContext): Promise<boolean> {
202
+ return 1 + 1 === 2;
203
+ }
204
+
205
+ /**
206
+ * Example of a ClientCallable endpoint.
207
+ * Requires user authentication (client scope).
208
+ */
209
+ @ClientCallable({ route: 'isThree' })
210
+ @SwaggerCategory('Examples')
211
+ async isThree(_ctx: RequestContext): Promise<boolean> {
212
+ return 1 + 2 === 3;
213
+ }
214
+
215
+ /**
216
+ * Example of a ServerCallable endpoint.
217
+ * Requires server authentication (server scope).
218
+ */
219
+ @ServerCallable({ route: 'isFour' })
220
+ @SwaggerCategory('Examples')
221
+ async isFour(_ctx: RequestContext): Promise<boolean> {
222
+ return 2 + 2 === 4;
223
+ }
224
+ }
225
+ `;
226
+ }
227
+ /**
228
+ * Generates example domain service content.
229
+ */
230
+ function generateDomainServiceTs() {
231
+ return `import type { RequestContext } from '@omen.foundation/node-microservice-runtime';
232
+
233
+ export class ExampleDomainService {
234
+ greet(userId: number): string {
235
+ return \`Hello from Node microservices, user \${userId}!\`;
236
+ }
237
+
238
+ async getServiceInfo(_ctx: RequestContext): Promise<{ service: string; version: string }> {
239
+ return {
240
+ service: 'ExampleDomainService',
241
+ version: '1.0.0',
242
+ };
243
+ }
244
+ }
245
+ `;
246
+ }
247
+ //# sourceMappingURL=scaffold.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scaffold.js","sourceRoot":"","sources":["../../../src/cli/commands/scaffold.ts"],"names":[],"mappings":"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","sourcesContent":["/**\r\n * Command handler for scaffolding new microservice projects.\r\n */\r\n\r\nimport fs from 'node:fs/promises';\r\nimport path from 'node:path';\r\nimport { toPascalCase, toKebabCase, validateServiceName } from '../utils/name-utils.js';\r\nimport { fetchLatestRuntimeVersion } from '../utils/version-utils.js';\r\nimport { promptInput } from '../utils/prompt-utils.js';\r\n\r\ninterface ScaffoldOptions {\r\n serviceName: string;\r\n displayName?: string;\r\n beamoId?: string;\r\n runtimeVersion: string;\r\n}\r\n\r\n/**\r\n * Handles the scaffold command.\r\n */\r\nexport async function handleScaffold(args: string[]): Promise<void> {\r\n let serviceName = args[0];\r\n\r\n // Interactive prompt for service name if not provided\r\n if (!serviceName) {\r\n serviceName = await promptInput('Enter microservice name (alphanumeric and underscores only)');\r\n }\r\n\r\n // Validate service name\r\n if (!serviceName || !validateServiceName(serviceName)) {\r\n throw new Error(\r\n `Invalid microservice name \"${serviceName}\". Only alphanumeric and underscore characters are allowed.`,\r\n );\r\n }\r\n\r\n // Fetch latest runtime version\r\n console.log('Fetching latest runtime version...');\r\n const runtimeVersion = await fetchLatestRuntimeVersion();\r\n console.log(`Using @omen.foundation/node-microservice-runtime version ${runtimeVersion}`);\r\n\r\n // Prompt for optional values\r\n const displayName = await promptInput('Enter display name for the service (optional)', serviceName);\r\n const beamoId = await promptInput('Enter Beamable Beamo ID (optional, defaults to service name)', serviceName);\r\n\r\n // Validate beamoId\r\n if (beamoId && !validateServiceName(beamoId)) {\r\n throw new Error(\r\n `Invalid Beamo ID \"${beamoId}\". Only alphanumeric and underscore characters are allowed.`,\r\n );\r\n }\r\n\r\n const options: ScaffoldOptions = {\r\n serviceName,\r\n displayName: displayName || serviceName,\r\n beamoId: beamoId || serviceName,\r\n runtimeVersion,\r\n };\r\n\r\n // Check if directory already exists\r\n const targetDir = path.resolve(process.cwd(), serviceName);\r\n try {\r\n await fs.access(targetDir);\r\n const overwrite = await promptInput(\r\n `Directory \"${serviceName}\" already exists. Overwrite? (y/n)`,\r\n 'n',\r\n );\r\n if (overwrite.toLowerCase() !== 'y' && overwrite.toLowerCase() !== 'yes') {\r\n console.log('Scaffold cancelled.');\r\n return;\r\n }\r\n // Remove existing directory\r\n await fs.rm(targetDir, { recursive: true, force: true });\r\n } catch {\r\n // Directory doesn't exist, that's fine\r\n }\r\n\r\n // Generate project structure\r\n await generateProjectStructure(targetDir, options);\r\n\r\n console.log(`\\n✅ Successfully scaffolded microservice \"${serviceName}\"!`);\r\n console.log(`\\nNext steps:`);\r\n console.log(` 1. cd ${serviceName}`);\r\n console.log(` 2. npm install`);\r\n console.log(` 3. Copy .env.sample to .env and configure your credentials`);\r\n console.log(` 4. npm run dev`);\r\n}\r\n\r\n/**\r\n * Generates the complete project structure.\r\n */\r\nasync function generateProjectStructure(targetDir: string, options: ScaffoldOptions): Promise<void> {\r\n // Create directories\r\n await fs.mkdir(targetDir, { recursive: true });\r\n await fs.mkdir(path.join(targetDir, 'src'), { recursive: true });\r\n await fs.mkdir(path.join(targetDir, 'src', 'services'), { recursive: true });\r\n await fs.mkdir(path.join(targetDir, 'dist'), { recursive: true });\r\n\r\n // Generate files\r\n await fs.writeFile(path.join(targetDir, 'package.json'), generatePackageJson(options));\r\n await fs.writeFile(path.join(targetDir, 'tsconfig.json'), generateTsConfig());\r\n await fs.writeFile(path.join(targetDir, '.env.sample'), generateEnvSample());\r\n await fs.writeFile(path.join(targetDir, '.gitignore'), generateGitIgnore());\r\n await fs.writeFile(path.join(targetDir, 'src', 'main.ts'), generateMainTs(options));\r\n await fs.writeFile(\r\n path.join(targetDir, 'src', `${toPascalCase(options.serviceName)}Service.ts`),\r\n generateServiceTs(options),\r\n );\r\n await fs.writeFile(\r\n path.join(targetDir, 'src', 'services', 'example-domain-service.ts'),\r\n generateDomainServiceTs(),\r\n );\r\n}\r\n\r\n/**\r\n * Generates package.json content.\r\n */\r\nfunction generatePackageJson(options: ScaffoldOptions): string {\r\n const serviceNameKebab = toKebabCase(options.serviceName);\r\n const packageName = `@beamable/${serviceNameKebab}-node-microservice`;\r\n\r\n return JSON.stringify(\r\n {\r\n name: packageName,\r\n version: '0.1.0',\r\n private: true,\r\n type: 'module',\r\n main: 'dist/main.js',\r\n types: 'dist/main.d.ts',\r\n scripts: {\r\n dev: 'tsx --env-file .env src/main.ts',\r\n build: 'tsc -p tsconfig.json',\r\n validate: 'npx beamo-node validate --env-file .env',\r\n publish: 'npx beamo-node publish --env-file .env',\r\n },\r\n dependencies: {\r\n '@omen.foundation/node-microservice-runtime': `^${options.runtimeVersion}`,\r\n dotenv: '^16.4.7',\r\n mongodb: '^6.10.0',\r\n },\r\n devDependencies: {\r\n '@types/node': '^20.11.30',\r\n 'pino-pretty': '^13.0.0',\r\n tsx: '^4.19.2',\r\n typescript: '^5.4.5',\r\n },\r\n beamable: {\r\n beamoId: options.beamoId,\r\n projectType: 'service',\r\n },\r\n },\r\n null,\r\n 2,\r\n );\r\n}\r\n\r\n/**\r\n * Generates tsconfig.json content.\r\n */\r\nfunction generateTsConfig(): string {\r\n return JSON.stringify(\r\n {\r\n extends: '../Microservice/tsconfig.base.json',\r\n compilerOptions: {\r\n outDir: 'dist',\r\n rootDir: 'src',\r\n declaration: true,\r\n declarationMap: true,\r\n },\r\n include: ['src/**/*.ts'],\r\n exclude: ['dist', 'node_modules'],\r\n },\r\n null,\r\n 2,\r\n );\r\n}\r\n\r\n/**\r\n * Generates .env.sample content.\r\n */\r\nfunction generateEnvSample(): string {\r\n return `CID=\r\nPID=\r\nHOST=wss://api.beamable.com/socket\r\nSECRET=\r\nNAME_PREFIX=\r\nLOG_LEVEL=info\r\nBEAMABLE_TOKEN=\r\nBEAMABLE_API_HOST=https://api.beamable.com\r\nBEAMABLE_GAME_PID=\r\n`;\r\n}\r\n\r\n/**\r\n * Generates .gitignore content.\r\n */\r\nfunction generateGitIgnore(): string {\r\n return `node_modules/\r\ndist/\r\n.env\r\n*.log\r\n.DS_Store\r\n`;\r\n}\r\n\r\n/**\r\n * Generates main.ts content.\r\n */\r\nfunction generateMainTs(options: ScaffoldOptions): string {\r\n const serviceNamePascal = toPascalCase(options.serviceName);\r\n return `import 'dotenv/config';\r\nimport './${serviceNamePascal}Service.js';\r\nimport { runMicroservice } from '@omen.foundation/node-microservice-runtime';\r\n\r\nvoid runMicroservice();\r\n`;\r\n}\r\n\r\n/**\r\n * Generates the main service class file.\r\n */\r\nfunction generateServiceTs(options: ScaffoldOptions): string {\r\n const serviceNamePascal = toPascalCase(options.serviceName);\r\n return `import {\r\n Microservice,\r\n Callable,\r\n ClientCallable,\r\n ServerCallable,\r\n SwaggerCategory,\r\n ConfigureServices,\r\n type DependencyBuilder,\r\n type RequestContext,\r\n} from '@omen.foundation/node-microservice-runtime';\r\nimport { ExampleDomainService } from './services/example-domain-service.js';\r\n\r\n@Microservice('${options.serviceName}')\r\nexport class ${serviceNamePascal}Service {\r\n @ConfigureServices\r\n static register(builder: DependencyBuilder): void {\r\n builder.addSingletonClass(ExampleDomainService);\r\n }\r\n\r\n /**\r\n * Example of a public Callable endpoint.\r\n * No authentication required.\r\n */\r\n @Callable({ route: 'isTwo' })\r\n @SwaggerCategory('Examples')\r\n async isTwo(_ctx: RequestContext): Promise<boolean> {\r\n return 1 + 1 === 2;\r\n }\r\n\r\n /**\r\n * Example of a ClientCallable endpoint.\r\n * Requires user authentication (client scope).\r\n */\r\n @ClientCallable({ route: 'isThree' })\r\n @SwaggerCategory('Examples')\r\n async isThree(_ctx: RequestContext): Promise<boolean> {\r\n return 1 + 2 === 3;\r\n }\r\n\r\n /**\r\n * Example of a ServerCallable endpoint.\r\n * Requires server authentication (server scope).\r\n */\r\n @ServerCallable({ route: 'isFour' })\r\n @SwaggerCategory('Examples')\r\n async isFour(_ctx: RequestContext): Promise<boolean> {\r\n return 2 + 2 === 4;\r\n }\r\n}\r\n`;\r\n}\r\n\r\n/**\r\n * Generates example domain service content.\r\n */\r\nfunction generateDomainServiceTs(): string {\r\n return `import type { RequestContext } from '@omen.foundation/node-microservice-runtime';\r\n\r\nexport class ExampleDomainService {\r\n greet(userId: number): string {\r\n return \\`Hello from Node microservices, user \\${userId}!\\`;\r\n }\r\n\r\n async getServiceInfo(_ctx: RequestContext): Promise<{ service: string; version: string }> {\r\n return {\r\n service: 'ExampleDomainService',\r\n version: '1.0.0',\r\n };\r\n }\r\n}\r\n`;\r\n}\r\n\r\n"]}
package/dist/cli/index.js CHANGED
@@ -7,6 +7,9 @@ import readline from 'node:readline';
7
7
  import { stdin, stdout, exit } from 'node:process';
8
8
  import { fileURLToPath } from 'node:url';
9
9
  import dotenv from 'dotenv';
10
+ import { handleScaffold } from './commands/scaffold.js';
11
+ import { handleAddFederation } from './commands/add-federation.js';
12
+ import { handleAddStorage } from './commands/add-storage.js';
10
13
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
11
14
  const SERVICE_NAME = 'beamo-node';
12
15
  const CONFIG_DIR = path.join(os.homedir(), '.beamo-node');
@@ -545,6 +548,15 @@ async function main() {
545
548
  case 'profiles':
546
549
  await listProfiles(configStore);
547
550
  break;
551
+ case 'scaffold':
552
+ await handleScaffold(args);
553
+ break;
554
+ case 'add-federation':
555
+ await handleAddFederation(args);
556
+ break;
557
+ case 'add-storage':
558
+ await handleAddStorage(args);
559
+ break;
548
560
  default:
549
561
  console.error(`Unknown command: ${command}`);
550
562
  printHelp();
@@ -576,12 +588,18 @@ Usage:
576
588
  beamo-node publish [--profile ID] [--cid CID --pid PID --host HOST] [-- ...publish flags...]
577
589
  beamo-node validate [--profile ID] [--cid CID --pid PID --host HOST] [-- ...validate flags...]
578
590
  beamo-node profiles
591
+ beamo-node scaffold [<service-name>]
592
+ beamo-node add-federation [<identity-name>]
593
+ beamo-node add-storage [<storage-name>]
579
594
 
580
595
  Commands:
581
- login Authenticate with Beamable and store credentials securely.
582
- publish Run the publish pipeline using stored credentials (forwards extra flags to the publish script).
583
- validate Generate OpenAPI docs and validate the project (forwards extra flags).
584
- profiles List stored profiles and indicate the default selection.
596
+ login Authenticate with Beamable and store credentials securely.
597
+ publish Run the publish pipeline using stored credentials (forwards extra flags to the publish script).
598
+ validate Generate OpenAPI docs and validate the project (forwards extra flags).
599
+ profiles List stored profiles and indicate the default selection.
600
+ scaffold Generate a new microservice project structure.
601
+ add-federation Add federated inventory support to an existing microservice.
602
+ add-storage Add storage support to an existing microservice.
585
603
  `);
586
604
  }
587
605
  main().catch((error) => {
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"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","sourcesContent":["#!/usr/bin/env node\r\n\r\nimport fs from 'node:fs/promises';\r\nimport path from 'node:path';\r\nimport os from 'node:os';\r\nimport { spawn } from 'node:child_process';\r\nimport readline from 'node:readline';\r\nimport { stdin, stdout, exit } from 'node:process';\r\nimport { fileURLToPath } from 'node:url';\r\nimport dotenv from 'dotenv';\r\n\r\ntype KeytarModule = typeof import('keytar');\r\n\r\nconst __dirname = path.dirname(fileURLToPath(import.meta.url));\r\n\r\ninterface TokenRecord {\r\n accessToken: string;\r\n refreshToken: string;\r\n expiresAt?: number;\r\n}\r\n\r\ninterface ProfileConfig {\r\n id: string;\r\n cid: string;\r\n pid: string;\r\n host: string;\r\n apiHost: string;\r\n email: string;\r\n lastUsed?: number;\r\n}\r\n\r\ninterface ConfigFile {\r\n profiles: Record<string, ProfileConfig>;\r\n lastUsed?: string;\r\n}\r\n\r\ninterface LoginOptions {\r\n cid: string;\r\n pid: string;\r\n host: string;\r\n email: string;\r\n password: string;\r\n}\r\n\r\ninterface ProfileSelectionOptions {\r\n cid?: string;\r\n pid?: string;\r\n host?: string;\r\n profileId?: string;\r\n}\r\n\r\nconst SERVICE_NAME = 'beamo-node';\r\nconst CONFIG_DIR = path.join(os.homedir(), '.beamo-node');\r\nconst CONFIG_FILE = path.join(CONFIG_DIR, 'config.json');\r\nconst TOKEN_FALLBACK_DIR = path.join(CONFIG_DIR, 'tokens');\r\nconst DEFAULT_SOCKET_HOST = 'wss://api.beamable.com/socket';\r\nconst MIN_TOKEN_BUFFER_MS = 60_000;\r\n\r\nclass CredentialStore {\r\n private keytar?: KeytarModule;\r\n\r\n private constructor(keytar?: KeytarModule) {\r\n this.keytar = keytar;\r\n }\r\n\r\n static async create(): Promise<CredentialStore> {\r\n try {\r\n // eslint-disable-next-line @typescript-eslint/consistent-type-imports\r\n const keytarModule: KeytarModule = (await import('keytar')).default;\r\n return new CredentialStore(keytarModule);\r\n } catch (error) {\r\n console.warn('[beamo-node] keytar not available, falling back to file-based credential storage.');\r\n return new CredentialStore();\r\n }\r\n }\r\n\r\n async get(account: string): Promise<TokenRecord | undefined> {\r\n if (this.keytar) {\r\n const payload = await this.keytar.getPassword(SERVICE_NAME, account);\r\n if (!payload) {\r\n return undefined;\r\n }\r\n return this.parseTokenPayload(payload);\r\n }\r\n\r\n const filePath = this.fallbackPath(account);\r\n try {\r\n const payload = await fs.readFile(filePath, 'utf8');\r\n return this.parseTokenPayload(payload);\r\n } catch (error) {\r\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') {\r\n return undefined;\r\n }\r\n throw error;\r\n }\r\n }\r\n\r\n async set(account: string, record: TokenRecord): Promise<void> {\r\n const payload = JSON.stringify(record);\r\n if (this.keytar) {\r\n await this.keytar.setPassword(SERVICE_NAME, account, payload);\r\n return;\r\n }\r\n\r\n await fs.mkdir(TOKEN_FALLBACK_DIR, { recursive: true });\r\n const filePath = this.fallbackPath(account);\r\n await fs.writeFile(filePath, payload, { mode: 0o600, encoding: 'utf8' });\r\n }\r\n\r\n async clear(account: string): Promise<void> {\r\n if (this.keytar) {\r\n await this.keytar.deletePassword(SERVICE_NAME, account);\r\n return;\r\n }\r\n try {\r\n await fs.unlink(this.fallbackPath(account));\r\n } catch (error) {\r\n if ((error as NodeJS.ErrnoException).code !== 'ENOENT') {\r\n throw error;\r\n }\r\n }\r\n }\r\n\r\n private parseTokenPayload(payload: string): TokenRecord {\r\n const parsed = JSON.parse(payload) as Partial<TokenRecord>;\r\n if (!parsed || typeof parsed !== 'object') {\r\n throw new Error('Stored credentials are malformed.');\r\n }\r\n if (typeof parsed.accessToken !== 'string' || typeof parsed.refreshToken !== 'string') {\r\n throw new Error('Stored credentials missing access or refresh token.');\r\n }\r\n return {\r\n accessToken: parsed.accessToken,\r\n refreshToken: parsed.refreshToken,\r\n expiresAt: typeof parsed.expiresAt === 'number' ? parsed.expiresAt : undefined,\r\n };\r\n }\r\n\r\n private fallbackPath(account: string): string {\r\n const safe = Buffer.from(account).toString('base64url');\r\n return path.join(TOKEN_FALLBACK_DIR, `${safe}.json`);\r\n }\r\n}\r\n\r\nclass ConfigStore {\r\n async load(): Promise<ConfigFile> {\r\n try {\r\n const payload = await fs.readFile(CONFIG_FILE, 'utf8');\r\n const data = JSON.parse(payload) as ConfigFile;\r\n return {\r\n profiles: data?.profiles ?? {},\r\n lastUsed: data?.lastUsed,\r\n };\r\n } catch (error) {\r\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') {\r\n return { profiles: {} };\r\n }\r\n throw error;\r\n }\r\n }\r\n\r\n async save(config: ConfigFile): Promise<void> {\r\n await fs.mkdir(CONFIG_DIR, { recursive: true });\r\n const payload = JSON.stringify(config, null, 2);\r\n await fs.writeFile(CONFIG_FILE, `${payload}\\n`, { encoding: 'utf8', mode: 0o600 });\r\n }\r\n}\r\n\r\nclass TokenManager {\r\n constructor(private readonly store: CredentialStore) {}\r\n\r\n async login(options: LoginOptions): Promise<TokenRecord> {\r\n const apiHost = normalizeApiHost(options.host);\r\n // Scope should be cid.pid if both are provided (matches official CLI behavior)\r\n const scope = options.pid ? `${options.cid}.${options.pid}` : options.cid;\r\n // Admin accounts require customerScoped: true (matches C# CLI behavior)\r\n // The registry will accept customer-scoped tokens when proper headers are used\r\n const customerScoped = true;\r\n const response = await fetch(new URL('/basic/auth/token', apiHost), {\r\n method: 'POST',\r\n headers: {\r\n Accept: 'application/json',\r\n 'Content-Type': 'application/json',\r\n ...(scope ? { 'X-BEAM-SCOPE': scope } : {}),\r\n },\r\n body: JSON.stringify({\r\n grant_type: 'password',\r\n username: options.email,\r\n password: options.password,\r\n customerScoped,\r\n }),\r\n });\r\n\r\n if (!response.ok) {\r\n const message = await safeReadError(response);\r\n throw new Error(`Login failed (${response.status}): ${message}`);\r\n }\r\n\r\n const body = (await response.json()) as Record<string, unknown>;\r\n const accessToken = typeof body.access_token === 'string' ? body.access_token : undefined;\r\n const refreshToken = typeof body.refresh_token === 'string' ? body.refresh_token : undefined;\r\n const expiresIn = typeof body.expires_in === 'number' ? body.expires_in : Number(body.expires_in ?? 0);\r\n\r\n if (!accessToken || !refreshToken) {\r\n throw new Error('Login response did not contain access and refresh tokens.');\r\n }\r\n\r\n const expiresAt = Number.isFinite(expiresIn) && expiresIn > 0 ? Date.now() + expiresIn * 1000 : undefined;\r\n const record: TokenRecord = { accessToken, refreshToken, expiresAt };\r\n const account = profileKey({ cid: options.cid, pid: options.pid, apiHost });\r\n\r\n await this.store.set(account, record);\r\n return record;\r\n }\r\n\r\n async getValidTokens(cid: string, pid: string, host: string, forceRealmScoped = false): Promise<TokenRecord> {\r\n const apiHost = normalizeApiHost(host);\r\n const account = profileKey({ cid, pid, apiHost });\r\n\r\n const existing = await this.store.get(account);\r\n if (!existing) {\r\n throw new Error(`No stored credentials for ${cid}.${pid} (${apiHost}). Run \"beamo-node login\" first.`);\r\n }\r\n\r\n // Refresh token if expired or if explicitly requested\r\n // Note: If login was done with PID, tokens are already realm-scoped\r\n if (forceRealmScoped || isTokenExpired(existing.expiresAt)) {\r\n if (process.env.BEAMO_DEBUG === '1' || process.env.BEAMO_NODE_DEBUG === '1') {\r\n console.log(`[beamo-node] Refreshing token (forceRealmScoped=${forceRealmScoped}, expired=${isTokenExpired(existing.expiresAt)})`);\r\n }\r\n const refreshed = await this.refreshToken(existing.refreshToken, cid, pid, apiHost);\r\n await this.store.set(account, refreshed);\r\n return refreshed;\r\n }\r\n\r\n return existing;\r\n }\r\n\r\n private async refreshToken(refreshToken: string, cid: string, pid: string, apiHost: string): Promise<TokenRecord> {\r\n const scope = pid ? `${cid}.${pid}` : cid;\r\n const response = await fetch(new URL('/basic/auth/token', apiHost), {\r\n method: 'POST',\r\n headers: {\r\n Accept: 'application/json',\r\n 'Content-Type': 'application/json',\r\n ...(scope ? { 'X-BEAM-SCOPE': scope } : {}),\r\n },\r\n body: JSON.stringify({\r\n grant_type: 'refresh_token',\r\n refresh_token: refreshToken,\r\n // Don't include customerScoped - refresh tokens inherit scope from the refresh token itself\r\n // Setting X-BEAM-SCOPE header should be enough to get a realm-scoped token\r\n }),\r\n });\r\n\r\n if (!response.ok) {\r\n const message = await safeReadError(response);\r\n throw new Error(`Failed to refresh token (${response.status}): ${message}`);\r\n }\r\n\r\n const body = (await response.json()) as Record<string, unknown>;\r\n const accessToken = typeof body.access_token === 'string' ? body.access_token : undefined;\r\n const newRefreshToken = typeof body.refresh_token === 'string' ? body.refresh_token : refreshToken;\r\n const expiresIn = typeof body.expires_in === 'number' ? body.expires_in : Number(body.expires_in ?? 0);\r\n\r\n if (!accessToken) {\r\n throw new Error('Refresh token response missing access token.');\r\n }\r\n\r\n const expiresAt = Number.isFinite(expiresIn) && expiresIn > 0 ? Date.now() + expiresIn * 1000 : undefined;\r\n \r\n // Verify the refreshed token works with realm scope\r\n if (pid && process.env.BEAMO_DEBUG === '1') {\r\n try {\r\n const testUrl = new URL('/basic/accounts/me', apiHost);\r\n const testResponse = await fetch(testUrl, {\r\n headers: {\r\n Authorization: `Bearer ${accessToken}`,\r\n Accept: 'application/json',\r\n 'X-BEAM-SCOPE': scope,\r\n },\r\n });\r\n if (!testResponse.ok) {\r\n console.warn(`[beamo-node] Warning: Refreshed token validation failed (${testResponse.status}). Token may still be customer-scoped.`);\r\n }\r\n } catch {\r\n // Ignore validation errors in debug mode\r\n }\r\n }\r\n \r\n return { accessToken, refreshToken: newRefreshToken, expiresAt };\r\n }\r\n}\r\n\r\nfunction parseCommandLine(argv: string[]): { command?: string; args: string[] } {\r\n const [command, ...rest] = argv;\r\n return { command, args: rest };\r\n}\r\n\r\nfunction splitArgs(args: string[], recognizedFlags: Set<string>): { flags: Record<string, string | boolean>; forward: string[] } {\r\n const flags: Record<string, string | boolean> = {};\r\n const forward: string[] = [];\r\n\r\n for (let index = 0; index < args.length; index += 1) {\r\n const token = args[index];\r\n if (!token.startsWith('-')) {\r\n forward.push(token);\r\n continue;\r\n }\r\n\r\n const key = token.replace(/^--/, '');\r\n\r\n if (recognizedFlags.has(key)) {\r\n const next = args[index + 1];\r\n if (next !== undefined && !next.startsWith('-')) {\r\n flags[key] = next;\r\n index += 1;\r\n } else {\r\n flags[key] = true;\r\n }\r\n } else {\r\n forward.push(token);\r\n const next = args[index + 1];\r\n if (next !== undefined && !next.startsWith('-')) {\r\n forward.push(next);\r\n index += 1;\r\n }\r\n }\r\n }\r\n\r\n return { flags, forward };\r\n}\r\n\r\nasync function promptInput(question: string, defaultValue?: string): Promise<string> {\r\n const rl = readline.createInterface({ input: stdin, output: stdout });\r\n return new Promise<string>((resolve) => {\r\n rl.question(defaultValue ? `${question} (${defaultValue}): ` : `${question}: `, (answer) => {\r\n rl.close();\r\n const value = answer.trim();\r\n resolve(value === '' && defaultValue !== undefined ? defaultValue : value);\r\n });\r\n });\r\n}\r\n\r\nasync function promptHidden(question: string): Promise<string> {\r\n const rl = readline.createInterface({ input: stdin, output: stdout } as readline.ReadLineOptions & { stdoutMuted?: boolean });\r\n\r\n return new Promise<string>((resolve) => {\r\n const mutable = rl as readline.Interface & {\r\n stdoutMuted?: boolean;\r\n _writeToOutput?: (stringToWrite: string) => void;\r\n output?: typeof stdout;\r\n };\r\n mutable.stdoutMuted = true;\r\n const originalWrite = mutable._writeToOutput?.bind(mutable);\r\n const outputStream = mutable.output ?? stdout;\r\n mutable._writeToOutput = (stringToWrite: string) => {\r\n if (mutable.stdoutMuted) {\r\n outputStream.write('*');\r\n } else if (originalWrite) {\r\n originalWrite(stringToWrite);\r\n } else {\r\n outputStream.write(stringToWrite);\r\n }\r\n };\r\n\r\n mutable.question(`${question}: `, (answer) => {\r\n mutable.close();\r\n stdout.write(os.EOL);\r\n resolve(answer);\r\n });\r\n });\r\n}\r\n\r\nasync function handleLogin(args: string[], configStore: ConfigStore, tokenManager: TokenManager): Promise<void> {\r\n const { flags } = splitArgs(args, new Set(['cid', 'pid', 'host', 'email']));\r\n const envDefaults = await loadEnvDefaults();\r\n\r\n const cid = typeof flags.cid === 'string' ? flags.cid : await promptInput('CID', envDefaults.cid);\r\n const pid = typeof flags.pid === 'string' ? flags.pid : await promptInput('PID', envDefaults.pid);\r\n const hostDefault = envDefaults.host ?? DEFAULT_SOCKET_HOST;\r\n const host = typeof flags.host === 'string' ? flags.host : await promptInput('Host', hostDefault);\r\n const email = typeof flags.email === 'string' ? flags.email : await promptInput('Email');\r\n const password = await promptHidden('Password');\r\n\r\n if (!cid || !pid || !host || !email || !password) {\r\n throw new Error('CID, PID, host, email, and password are required.');\r\n }\r\n\r\n const record = await tokenManager.login({ cid, pid, host, email, password });\r\n const config = await configStore.load();\r\n const apiHost = normalizeApiHost(host);\r\n const id = profileKey({ cid, pid, apiHost });\r\n\r\n config.profiles[id] = {\r\n id,\r\n cid,\r\n pid,\r\n host,\r\n apiHost,\r\n email,\r\n lastUsed: Date.now(),\r\n };\r\n config.lastUsed = id;\r\n\r\n await configStore.save(config);\r\n\r\n console.log(`Login successful for ${email} (${cid}.${pid}).`);\r\n if (!record.expiresAt) {\r\n console.warn('[beamo-node] Access token does not include an expiration. You may need to re-login if publish fails.');\r\n }\r\n}\r\n\r\nasync function handlePublish(args: string[], configStore: ConfigStore, tokenManager: TokenManager): Promise<void> {\r\n const { flags, forward } = splitArgs(args, new Set(['cid', 'pid', 'host', 'profile']));\r\n const profile = await resolveProfile(flags, configStore);\r\n\r\n // Refresh token if expired (customer-scoped tokens work with registry when proper headers are used)\r\n // The C# CLI uses the same access token for both registry API calls and Docker registry uploads\r\n const tokens = await tokenManager.getValidTokens(profile.cid, profile.pid, profile.host, false);\r\n const env = buildCommandEnv(profile, tokens);\r\n\r\n const scriptArgs = buildScriptArgs(forward, profile, true); // publish needs --api-host\r\n \r\n // Automatically add --env-file .env if .env exists and --env-file wasn't explicitly provided\r\n const hasEnvFileFlag = forward.some((arg, i) => arg === '--env-file' || (i > 0 && forward[i - 1] === '--env-file'));\r\n if (!hasEnvFileFlag) {\r\n const envPath = path.resolve('.env');\r\n try {\r\n await fs.access(envPath);\r\n scriptArgs.push('--env-file', '.env');\r\n } catch {\r\n // .env file doesn't exist, that's okay\r\n }\r\n }\r\n \r\n const scriptPath = path.resolve(__dirname, '../../scripts/publish-service.mjs');\r\n await runScript(scriptPath, scriptArgs, env);\r\n}\r\n\r\nasync function handleValidate(args: string[], configStore: ConfigStore, tokenManager: TokenManager): Promise<void> {\r\n const { flags, forward } = splitArgs(args, new Set(['cid', 'pid', 'host', 'profile']));\r\n const profile = await resolveProfile(flags, configStore);\r\n\r\n // Validation does not require tokens, but downstream scripts expect CID/PID/HOST env values.\r\n const tokens = await tokenManager.getValidTokens(profile.cid, profile.pid, profile.host);\r\n const env = buildCommandEnv(profile, tokens);\r\n\r\n const scriptArgs = buildScriptArgs(forward, profile, false); // validate doesn't need --api-host\r\n \r\n // Automatically add --env-file .env if .env exists and --env-file wasn't explicitly provided\r\n const hasEnvFileFlag = forward.some((arg, i) => arg === '--env-file' || (i > 0 && forward[i - 1] === '--env-file'));\r\n if (!hasEnvFileFlag) {\r\n const envPath = path.resolve('.env');\r\n try {\r\n await fs.access(envPath);\r\n scriptArgs.push('--env-file', '.env');\r\n } catch {\r\n // .env file doesn't exist, that's okay\r\n }\r\n }\r\n \r\n const scriptPath = path.resolve(__dirname, '../../scripts/validate-service.mjs');\r\n await runScript(scriptPath, scriptArgs, env);\r\n}\r\n\r\nasync function resolveProfile(flags: Record<string, string | boolean>, configStore: ConfigStore): Promise<ProfileConfig> {\r\n const config = await configStore.load();\r\n\r\n if (typeof flags.profile === 'string') {\r\n const explicit = config.profiles[flags.profile];\r\n if (!explicit) {\r\n throw new Error(`Profile \"${flags.profile}\" not found. Run \"beamo-node login\" to create it.`);\r\n }\r\n config.lastUsed = explicit.id;\r\n await configStore.save(config);\r\n return explicit;\r\n }\r\n\r\n const directOptions: ProfileSelectionOptions = {\r\n cid: typeof flags.cid === 'string' ? flags.cid : undefined,\r\n pid: typeof flags.pid === 'string' ? flags.pid : undefined,\r\n host: typeof flags.host === 'string' ? flags.host : undefined,\r\n };\r\n\r\n if (directOptions.cid && directOptions.pid && directOptions.host) {\r\n const apiHost = normalizeApiHost(directOptions.host);\r\n const id = profileKey({ cid: directOptions.cid, pid: directOptions.pid, apiHost });\r\n const profile = config.profiles[id];\r\n if (!profile) {\r\n throw new Error(`No stored credentials for ${directOptions.cid}.${directOptions.pid}. Run \"beamo-node login\" first.`);\r\n }\r\n profile.lastUsed = Date.now();\r\n config.lastUsed = profile.id;\r\n await configStore.save(config);\r\n return profile;\r\n }\r\n\r\n if (!config.lastUsed) {\r\n if (Object.keys(config.profiles).length === 0) {\r\n throw new Error('No stored credentials found. Run \"beamo-node login\" first.');\r\n }\r\n throw new Error('Multiple profiles found. Specify one with \"--profile <id>\" or run \"beamo-node login\" first.');\r\n }\r\n\r\n const profile = config.profiles[config.lastUsed];\r\n if (!profile) {\r\n throw new Error(`Last used profile \"${config.lastUsed}\" is missing. Run \"beamo-node login\" to refresh credentials.`);\r\n }\r\n\r\n profile.lastUsed = Date.now();\r\n config.lastUsed = profile.id;\r\n await configStore.save(config);\r\n return profile;\r\n}\r\n\r\nfunction buildScriptArgs(original: string[], profile: ProfileConfig, includeApiHost = true): string[] {\r\n const hasFlag = (flag: string) => original.some((token) => token === flag);\r\n const args: string[] = [...original];\r\n if (!hasFlag('--cid')) {\r\n args.push('--cid', profile.cid);\r\n }\r\n if (!hasFlag('--pid')) {\r\n args.push('--pid', profile.pid);\r\n }\r\n if (!hasFlag('--host')) {\r\n args.push('--host', profile.host);\r\n }\r\n if (includeApiHost && !hasFlag('--api-host')) {\r\n args.push('--api-host', profile.apiHost);\r\n }\r\n return args;\r\n}\r\n\r\nfunction buildCommandEnv(profile: ProfileConfig, tokens: TokenRecord): NodeJS.ProcessEnv {\r\n return {\r\n ...process.env,\r\n BEAMABLE_TOKEN: tokens.accessToken,\r\n ACCESS_TOKEN: tokens.accessToken,\r\n BEAMABLE_REFRESH_TOKEN: tokens.refreshToken,\r\n REFRESH_TOKEN: tokens.refreshToken,\r\n BEAMABLE_CID: profile.cid,\r\n CID: profile.cid,\r\n BEAMABLE_PID: profile.pid,\r\n PID: profile.pid,\r\n BEAMABLE_HOST: profile.host,\r\n HOST: profile.host,\r\n BEAMABLE_API_HOST: profile.apiHost,\r\n };\r\n}\r\n\r\nasync function runScript(command: string, args: string[], env: NodeJS.ProcessEnv): Promise<void> {\r\n const isNodeScript = /\\.(mjs|cjs|js)$/i.test(command);\r\n const executable = isNodeScript ? process.execPath : command;\r\n const finalArgs = isNodeScript ? [command, ...args] : args;\r\n const shouldUseShell = process.platform === 'win32' && !isNodeScript;\r\n const debug = process.env.BEAMO_DEBUG === '1' || process.env.BEAMO_NODE_DEBUG === '1';\r\n if (debug) {\r\n console.log(\r\n `[beamo-node] command=\"${command}\" exec=\"${executable}\" args=${JSON.stringify(\r\n finalArgs,\r\n )} shell=${shouldUseShell} cwd=${process.cwd()}`,\r\n );\r\n }\r\n\r\n await new Promise<void>((resolve, reject) => {\r\n const child = spawn(executable, finalArgs, {\r\n stdio: 'inherit',\r\n env,\r\n shell: shouldUseShell,\r\n });\r\n\r\n child.on('error', (error) => reject(error));\r\n child.on('exit', (code) => {\r\n if (code === 0) {\r\n resolve();\r\n } else {\r\n reject(new Error(`Command failed with exit code ${code ?? 'unknown'}.`));\r\n }\r\n });\r\n });\r\n}\r\n\r\nfunction normalizeApiHost(host: string): string {\r\n const trimmed = host.trim();\r\n if (trimmed.startsWith('wss://')) {\r\n return `https://${trimmed.substring('wss://'.length).replace(/\\/socket$/, '')}`;\r\n }\r\n if (trimmed.startsWith('ws://')) {\r\n return `http://${trimmed.substring('ws://'.length).replace(/\\/socket$/, '')}`;\r\n }\r\n let normalized = trimmed.replace(/\\/socket$/, '').replace(/\\/$/, '');\r\n if (!/^https?:\\/\\//i.test(normalized)) {\r\n normalized = `https://${normalized}`;\r\n }\r\n return normalized;\r\n}\r\n\r\nfunction profileKey(input: { cid: string; pid: string; apiHost: string }): string {\r\n return `${input.cid}.${input.pid}@${input.apiHost}`;\r\n}\r\n\r\nfunction isTokenExpired(expiresAt?: number): boolean {\r\n if (!expiresAt || !Number.isFinite(expiresAt)) {\r\n return true;\r\n }\r\n return Date.now() + MIN_TOKEN_BUFFER_MS >= expiresAt;\r\n}\r\n\r\nasync function safeReadError(response: Response): Promise<string> {\r\n try {\r\n const body = await response.text();\r\n if (!body) {\r\n return 'No response body';\r\n }\r\n try {\r\n const parsed = JSON.parse(body) as Record<string, unknown>;\r\n return typeof parsed.error === 'string'\r\n ? parsed.error\r\n : typeof parsed.message === 'string'\r\n ? parsed.message\r\n : body;\r\n } catch {\r\n return body;\r\n }\r\n } catch {\r\n return 'No response body';\r\n }\r\n}\r\n\r\nasync function main(): Promise<void> {\r\n const [, , ...argv] = process.argv;\r\n const { command, args } = parseCommandLine(argv);\r\n\r\n if (!command || command === '--help' || command === '-h') {\r\n printHelp();\r\n return;\r\n }\r\n\r\n const credentialStore = await CredentialStore.create();\r\n const tokenManager = new TokenManager(credentialStore);\r\n const configStore = new ConfigStore();\r\n\r\n switch (command) {\r\n case 'login':\r\n await handleLogin(args, configStore, tokenManager);\r\n break;\r\n case 'publish':\r\n await handlePublish(args, configStore, tokenManager);\r\n break;\r\n case 'validate':\r\n await handleValidate(args, configStore, tokenManager);\r\n break;\r\n case 'profiles':\r\n await listProfiles(configStore);\r\n break;\r\n default:\r\n console.error(`Unknown command: ${command}`);\r\n printHelp();\r\n exit(1);\r\n }\r\n}\r\n\r\nasync function listProfiles(configStore: ConfigStore): Promise<void> {\r\n const config = await configStore.load();\r\n const entries = Object.values(config.profiles).sort((a, b) => (b.lastUsed ?? 0) - (a.lastUsed ?? 0));\r\n if (entries.length === 0) {\r\n console.log('No stored profiles. Run \"beamo-node login\" to create one.');\r\n return;\r\n }\r\n console.log('Stored profiles:');\r\n for (const profile of entries) {\r\n const marker = config.lastUsed === profile.id ? '*' : ' ';\r\n console.log(` ${marker} ${profile.id}`);\r\n console.log(` CID: ${profile.cid}`);\r\n console.log(` PID: ${profile.pid}`);\r\n console.log(` Host: ${profile.host}`);\r\n console.log(` Email: ${profile.email}`);\r\n }\r\n}\r\n\r\nfunction printHelp(): void {\r\n console.log(`beamo-node CLI\r\n\r\nUsage:\r\n beamo-node login [--cid CID] [--pid PID] [--host HOST] [--email EMAIL]\r\n beamo-node publish [--profile ID] [--cid CID --pid PID --host HOST] [-- ...publish flags...]\r\n beamo-node validate [--profile ID] [--cid CID --pid PID --host HOST] [-- ...validate flags...]\r\n beamo-node profiles\r\n\r\nCommands:\r\n login Authenticate with Beamable and store credentials securely.\r\n publish Run the publish pipeline using stored credentials (forwards extra flags to the publish script).\r\n validate Generate OpenAPI docs and validate the project (forwards extra flags).\r\n profiles List stored profiles and indicate the default selection.\r\n`);\r\n}\r\n\r\nmain().catch((error) => {\r\n console.error(error instanceof Error ? error.message : error);\r\n exit(1);\r\n});\r\n\r\nasync function loadEnvDefaults(): Promise<ProfileSelectionOptions> {\r\n const envPath = path.resolve('.env');\r\n try {\r\n const content = await fs.readFile(envPath, 'utf8');\r\n const parsed = dotenv.parse(content);\r\n const cid = parsed.BEAMABLE_CID ?? parsed.CID ?? undefined;\r\n const pid = parsed.BEAMABLE_PID ?? parsed.PID ?? undefined;\r\n const host = parsed.BEAMABLE_HOST ?? parsed.HOST ?? undefined;\r\n return {\r\n cid: cid?.trim() || undefined,\r\n pid: pid?.trim() || undefined,\r\n host: host?.trim() || undefined,\r\n };\r\n } catch (error) {\r\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') {\r\n return {};\r\n }\r\n throw error;\r\n }\r\n}\r\n\r\n\r\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"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","sourcesContent":["#!/usr/bin/env node\r\n\r\nimport fs from 'node:fs/promises';\r\nimport path from 'node:path';\r\nimport os from 'node:os';\r\nimport { spawn } from 'node:child_process';\r\nimport readline from 'node:readline';\r\nimport { stdin, stdout, exit } from 'node:process';\r\nimport { fileURLToPath } from 'node:url';\r\nimport dotenv from 'dotenv';\r\nimport { handleScaffold } from './commands/scaffold.js';\r\nimport { handleAddFederation } from './commands/add-federation.js';\r\nimport { handleAddStorage } from './commands/add-storage.js';\r\n\r\ntype KeytarModule = typeof import('keytar');\r\n\r\nconst __dirname = path.dirname(fileURLToPath(import.meta.url));\r\n\r\ninterface TokenRecord {\r\n accessToken: string;\r\n refreshToken: string;\r\n expiresAt?: number;\r\n}\r\n\r\ninterface ProfileConfig {\r\n id: string;\r\n cid: string;\r\n pid: string;\r\n host: string;\r\n apiHost: string;\r\n email: string;\r\n lastUsed?: number;\r\n}\r\n\r\ninterface ConfigFile {\r\n profiles: Record<string, ProfileConfig>;\r\n lastUsed?: string;\r\n}\r\n\r\ninterface LoginOptions {\r\n cid: string;\r\n pid: string;\r\n host: string;\r\n email: string;\r\n password: string;\r\n}\r\n\r\ninterface ProfileSelectionOptions {\r\n cid?: string;\r\n pid?: string;\r\n host?: string;\r\n profileId?: string;\r\n}\r\n\r\nconst SERVICE_NAME = 'beamo-node';\r\nconst CONFIG_DIR = path.join(os.homedir(), '.beamo-node');\r\nconst CONFIG_FILE = path.join(CONFIG_DIR, 'config.json');\r\nconst TOKEN_FALLBACK_DIR = path.join(CONFIG_DIR, 'tokens');\r\nconst DEFAULT_SOCKET_HOST = 'wss://api.beamable.com/socket';\r\nconst MIN_TOKEN_BUFFER_MS = 60_000;\r\n\r\nclass CredentialStore {\r\n private keytar?: KeytarModule;\r\n\r\n private constructor(keytar?: KeytarModule) {\r\n this.keytar = keytar;\r\n }\r\n\r\n static async create(): Promise<CredentialStore> {\r\n try {\r\n // eslint-disable-next-line @typescript-eslint/consistent-type-imports\r\n const keytarModule: KeytarModule = (await import('keytar')).default;\r\n return new CredentialStore(keytarModule);\r\n } catch (error) {\r\n console.warn('[beamo-node] keytar not available, falling back to file-based credential storage.');\r\n return new CredentialStore();\r\n }\r\n }\r\n\r\n async get(account: string): Promise<TokenRecord | undefined> {\r\n if (this.keytar) {\r\n const payload = await this.keytar.getPassword(SERVICE_NAME, account);\r\n if (!payload) {\r\n return undefined;\r\n }\r\n return this.parseTokenPayload(payload);\r\n }\r\n\r\n const filePath = this.fallbackPath(account);\r\n try {\r\n const payload = await fs.readFile(filePath, 'utf8');\r\n return this.parseTokenPayload(payload);\r\n } catch (error) {\r\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') {\r\n return undefined;\r\n }\r\n throw error;\r\n }\r\n }\r\n\r\n async set(account: string, record: TokenRecord): Promise<void> {\r\n const payload = JSON.stringify(record);\r\n if (this.keytar) {\r\n await this.keytar.setPassword(SERVICE_NAME, account, payload);\r\n return;\r\n }\r\n\r\n await fs.mkdir(TOKEN_FALLBACK_DIR, { recursive: true });\r\n const filePath = this.fallbackPath(account);\r\n await fs.writeFile(filePath, payload, { mode: 0o600, encoding: 'utf8' });\r\n }\r\n\r\n async clear(account: string): Promise<void> {\r\n if (this.keytar) {\r\n await this.keytar.deletePassword(SERVICE_NAME, account);\r\n return;\r\n }\r\n try {\r\n await fs.unlink(this.fallbackPath(account));\r\n } catch (error) {\r\n if ((error as NodeJS.ErrnoException).code !== 'ENOENT') {\r\n throw error;\r\n }\r\n }\r\n }\r\n\r\n private parseTokenPayload(payload: string): TokenRecord {\r\n const parsed = JSON.parse(payload) as Partial<TokenRecord>;\r\n if (!parsed || typeof parsed !== 'object') {\r\n throw new Error('Stored credentials are malformed.');\r\n }\r\n if (typeof parsed.accessToken !== 'string' || typeof parsed.refreshToken !== 'string') {\r\n throw new Error('Stored credentials missing access or refresh token.');\r\n }\r\n return {\r\n accessToken: parsed.accessToken,\r\n refreshToken: parsed.refreshToken,\r\n expiresAt: typeof parsed.expiresAt === 'number' ? parsed.expiresAt : undefined,\r\n };\r\n }\r\n\r\n private fallbackPath(account: string): string {\r\n const safe = Buffer.from(account).toString('base64url');\r\n return path.join(TOKEN_FALLBACK_DIR, `${safe}.json`);\r\n }\r\n}\r\n\r\nclass ConfigStore {\r\n async load(): Promise<ConfigFile> {\r\n try {\r\n const payload = await fs.readFile(CONFIG_FILE, 'utf8');\r\n const data = JSON.parse(payload) as ConfigFile;\r\n return {\r\n profiles: data?.profiles ?? {},\r\n lastUsed: data?.lastUsed,\r\n };\r\n } catch (error) {\r\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') {\r\n return { profiles: {} };\r\n }\r\n throw error;\r\n }\r\n }\r\n\r\n async save(config: ConfigFile): Promise<void> {\r\n await fs.mkdir(CONFIG_DIR, { recursive: true });\r\n const payload = JSON.stringify(config, null, 2);\r\n await fs.writeFile(CONFIG_FILE, `${payload}\\n`, { encoding: 'utf8', mode: 0o600 });\r\n }\r\n}\r\n\r\nclass TokenManager {\r\n constructor(private readonly store: CredentialStore) {}\r\n\r\n async login(options: LoginOptions): Promise<TokenRecord> {\r\n const apiHost = normalizeApiHost(options.host);\r\n // Scope should be cid.pid if both are provided (matches official CLI behavior)\r\n const scope = options.pid ? `${options.cid}.${options.pid}` : options.cid;\r\n // Admin accounts require customerScoped: true (matches C# CLI behavior)\r\n // The registry will accept customer-scoped tokens when proper headers are used\r\n const customerScoped = true;\r\n const response = await fetch(new URL('/basic/auth/token', apiHost), {\r\n method: 'POST',\r\n headers: {\r\n Accept: 'application/json',\r\n 'Content-Type': 'application/json',\r\n ...(scope ? { 'X-BEAM-SCOPE': scope } : {}),\r\n },\r\n body: JSON.stringify({\r\n grant_type: 'password',\r\n username: options.email,\r\n password: options.password,\r\n customerScoped,\r\n }),\r\n });\r\n\r\n if (!response.ok) {\r\n const message = await safeReadError(response);\r\n throw new Error(`Login failed (${response.status}): ${message}`);\r\n }\r\n\r\n const body = (await response.json()) as Record<string, unknown>;\r\n const accessToken = typeof body.access_token === 'string' ? body.access_token : undefined;\r\n const refreshToken = typeof body.refresh_token === 'string' ? body.refresh_token : undefined;\r\n const expiresIn = typeof body.expires_in === 'number' ? body.expires_in : Number(body.expires_in ?? 0);\r\n\r\n if (!accessToken || !refreshToken) {\r\n throw new Error('Login response did not contain access and refresh tokens.');\r\n }\r\n\r\n const expiresAt = Number.isFinite(expiresIn) && expiresIn > 0 ? Date.now() + expiresIn * 1000 : undefined;\r\n const record: TokenRecord = { accessToken, refreshToken, expiresAt };\r\n const account = profileKey({ cid: options.cid, pid: options.pid, apiHost });\r\n\r\n await this.store.set(account, record);\r\n return record;\r\n }\r\n\r\n async getValidTokens(cid: string, pid: string, host: string, forceRealmScoped = false): Promise<TokenRecord> {\r\n const apiHost = normalizeApiHost(host);\r\n const account = profileKey({ cid, pid, apiHost });\r\n\r\n const existing = await this.store.get(account);\r\n if (!existing) {\r\n throw new Error(`No stored credentials for ${cid}.${pid} (${apiHost}). Run \"beamo-node login\" first.`);\r\n }\r\n\r\n // Refresh token if expired or if explicitly requested\r\n // Note: If login was done with PID, tokens are already realm-scoped\r\n if (forceRealmScoped || isTokenExpired(existing.expiresAt)) {\r\n if (process.env.BEAMO_DEBUG === '1' || process.env.BEAMO_NODE_DEBUG === '1') {\r\n console.log(`[beamo-node] Refreshing token (forceRealmScoped=${forceRealmScoped}, expired=${isTokenExpired(existing.expiresAt)})`);\r\n }\r\n const refreshed = await this.refreshToken(existing.refreshToken, cid, pid, apiHost);\r\n await this.store.set(account, refreshed);\r\n return refreshed;\r\n }\r\n\r\n return existing;\r\n }\r\n\r\n private async refreshToken(refreshToken: string, cid: string, pid: string, apiHost: string): Promise<TokenRecord> {\r\n const scope = pid ? `${cid}.${pid}` : cid;\r\n const response = await fetch(new URL('/basic/auth/token', apiHost), {\r\n method: 'POST',\r\n headers: {\r\n Accept: 'application/json',\r\n 'Content-Type': 'application/json',\r\n ...(scope ? { 'X-BEAM-SCOPE': scope } : {}),\r\n },\r\n body: JSON.stringify({\r\n grant_type: 'refresh_token',\r\n refresh_token: refreshToken,\r\n // Don't include customerScoped - refresh tokens inherit scope from the refresh token itself\r\n // Setting X-BEAM-SCOPE header should be enough to get a realm-scoped token\r\n }),\r\n });\r\n\r\n if (!response.ok) {\r\n const message = await safeReadError(response);\r\n throw new Error(`Failed to refresh token (${response.status}): ${message}`);\r\n }\r\n\r\n const body = (await response.json()) as Record<string, unknown>;\r\n const accessToken = typeof body.access_token === 'string' ? body.access_token : undefined;\r\n const newRefreshToken = typeof body.refresh_token === 'string' ? body.refresh_token : refreshToken;\r\n const expiresIn = typeof body.expires_in === 'number' ? body.expires_in : Number(body.expires_in ?? 0);\r\n\r\n if (!accessToken) {\r\n throw new Error('Refresh token response missing access token.');\r\n }\r\n\r\n const expiresAt = Number.isFinite(expiresIn) && expiresIn > 0 ? Date.now() + expiresIn * 1000 : undefined;\r\n \r\n // Verify the refreshed token works with realm scope\r\n if (pid && process.env.BEAMO_DEBUG === '1') {\r\n try {\r\n const testUrl = new URL('/basic/accounts/me', apiHost);\r\n const testResponse = await fetch(testUrl, {\r\n headers: {\r\n Authorization: `Bearer ${accessToken}`,\r\n Accept: 'application/json',\r\n 'X-BEAM-SCOPE': scope,\r\n },\r\n });\r\n if (!testResponse.ok) {\r\n console.warn(`[beamo-node] Warning: Refreshed token validation failed (${testResponse.status}). Token may still be customer-scoped.`);\r\n }\r\n } catch {\r\n // Ignore validation errors in debug mode\r\n }\r\n }\r\n \r\n return { accessToken, refreshToken: newRefreshToken, expiresAt };\r\n }\r\n}\r\n\r\nfunction parseCommandLine(argv: string[]): { command?: string; args: string[] } {\r\n const [command, ...rest] = argv;\r\n return { command, args: rest };\r\n}\r\n\r\nfunction splitArgs(args: string[], recognizedFlags: Set<string>): { flags: Record<string, string | boolean>; forward: string[] } {\r\n const flags: Record<string, string | boolean> = {};\r\n const forward: string[] = [];\r\n\r\n for (let index = 0; index < args.length; index += 1) {\r\n const token = args[index];\r\n if (!token.startsWith('-')) {\r\n forward.push(token);\r\n continue;\r\n }\r\n\r\n const key = token.replace(/^--/, '');\r\n\r\n if (recognizedFlags.has(key)) {\r\n const next = args[index + 1];\r\n if (next !== undefined && !next.startsWith('-')) {\r\n flags[key] = next;\r\n index += 1;\r\n } else {\r\n flags[key] = true;\r\n }\r\n } else {\r\n forward.push(token);\r\n const next = args[index + 1];\r\n if (next !== undefined && !next.startsWith('-')) {\r\n forward.push(next);\r\n index += 1;\r\n }\r\n }\r\n }\r\n\r\n return { flags, forward };\r\n}\r\n\r\nasync function promptInput(question: string, defaultValue?: string): Promise<string> {\r\n const rl = readline.createInterface({ input: stdin, output: stdout });\r\n return new Promise<string>((resolve) => {\r\n rl.question(defaultValue ? `${question} (${defaultValue}): ` : `${question}: `, (answer) => {\r\n rl.close();\r\n const value = answer.trim();\r\n resolve(value === '' && defaultValue !== undefined ? defaultValue : value);\r\n });\r\n });\r\n}\r\n\r\nasync function promptHidden(question: string): Promise<string> {\r\n const rl = readline.createInterface({ input: stdin, output: stdout } as readline.ReadLineOptions & { stdoutMuted?: boolean });\r\n\r\n return new Promise<string>((resolve) => {\r\n const mutable = rl as readline.Interface & {\r\n stdoutMuted?: boolean;\r\n _writeToOutput?: (stringToWrite: string) => void;\r\n output?: typeof stdout;\r\n };\r\n mutable.stdoutMuted = true;\r\n const originalWrite = mutable._writeToOutput?.bind(mutable);\r\n const outputStream = mutable.output ?? stdout;\r\n mutable._writeToOutput = (stringToWrite: string) => {\r\n if (mutable.stdoutMuted) {\r\n outputStream.write('*');\r\n } else if (originalWrite) {\r\n originalWrite(stringToWrite);\r\n } else {\r\n outputStream.write(stringToWrite);\r\n }\r\n };\r\n\r\n mutable.question(`${question}: `, (answer) => {\r\n mutable.close();\r\n stdout.write(os.EOL);\r\n resolve(answer);\r\n });\r\n });\r\n}\r\n\r\nasync function handleLogin(args: string[], configStore: ConfigStore, tokenManager: TokenManager): Promise<void> {\r\n const { flags } = splitArgs(args, new Set(['cid', 'pid', 'host', 'email']));\r\n const envDefaults = await loadEnvDefaults();\r\n\r\n const cid = typeof flags.cid === 'string' ? flags.cid : await promptInput('CID', envDefaults.cid);\r\n const pid = typeof flags.pid === 'string' ? flags.pid : await promptInput('PID', envDefaults.pid);\r\n const hostDefault = envDefaults.host ?? DEFAULT_SOCKET_HOST;\r\n const host = typeof flags.host === 'string' ? flags.host : await promptInput('Host', hostDefault);\r\n const email = typeof flags.email === 'string' ? flags.email : await promptInput('Email');\r\n const password = await promptHidden('Password');\r\n\r\n if (!cid || !pid || !host || !email || !password) {\r\n throw new Error('CID, PID, host, email, and password are required.');\r\n }\r\n\r\n const record = await tokenManager.login({ cid, pid, host, email, password });\r\n const config = await configStore.load();\r\n const apiHost = normalizeApiHost(host);\r\n const id = profileKey({ cid, pid, apiHost });\r\n\r\n config.profiles[id] = {\r\n id,\r\n cid,\r\n pid,\r\n host,\r\n apiHost,\r\n email,\r\n lastUsed: Date.now(),\r\n };\r\n config.lastUsed = id;\r\n\r\n await configStore.save(config);\r\n\r\n console.log(`Login successful for ${email} (${cid}.${pid}).`);\r\n if (!record.expiresAt) {\r\n console.warn('[beamo-node] Access token does not include an expiration. You may need to re-login if publish fails.');\r\n }\r\n}\r\n\r\nasync function handlePublish(args: string[], configStore: ConfigStore, tokenManager: TokenManager): Promise<void> {\r\n const { flags, forward } = splitArgs(args, new Set(['cid', 'pid', 'host', 'profile']));\r\n const profile = await resolveProfile(flags, configStore);\r\n\r\n // Refresh token if expired (customer-scoped tokens work with registry when proper headers are used)\r\n // The C# CLI uses the same access token for both registry API calls and Docker registry uploads\r\n const tokens = await tokenManager.getValidTokens(profile.cid, profile.pid, profile.host, false);\r\n const env = buildCommandEnv(profile, tokens);\r\n\r\n const scriptArgs = buildScriptArgs(forward, profile, true); // publish needs --api-host\r\n \r\n // Automatically add --env-file .env if .env exists and --env-file wasn't explicitly provided\r\n const hasEnvFileFlag = forward.some((arg, i) => arg === '--env-file' || (i > 0 && forward[i - 1] === '--env-file'));\r\n if (!hasEnvFileFlag) {\r\n const envPath = path.resolve('.env');\r\n try {\r\n await fs.access(envPath);\r\n scriptArgs.push('--env-file', '.env');\r\n } catch {\r\n // .env file doesn't exist, that's okay\r\n }\r\n }\r\n \r\n const scriptPath = path.resolve(__dirname, '../../scripts/publish-service.mjs');\r\n await runScript(scriptPath, scriptArgs, env);\r\n}\r\n\r\nasync function handleValidate(args: string[], configStore: ConfigStore, tokenManager: TokenManager): Promise<void> {\r\n const { flags, forward } = splitArgs(args, new Set(['cid', 'pid', 'host', 'profile']));\r\n const profile = await resolveProfile(flags, configStore);\r\n\r\n // Validation does not require tokens, but downstream scripts expect CID/PID/HOST env values.\r\n const tokens = await tokenManager.getValidTokens(profile.cid, profile.pid, profile.host);\r\n const env = buildCommandEnv(profile, tokens);\r\n\r\n const scriptArgs = buildScriptArgs(forward, profile, false); // validate doesn't need --api-host\r\n \r\n // Automatically add --env-file .env if .env exists and --env-file wasn't explicitly provided\r\n const hasEnvFileFlag = forward.some((arg, i) => arg === '--env-file' || (i > 0 && forward[i - 1] === '--env-file'));\r\n if (!hasEnvFileFlag) {\r\n const envPath = path.resolve('.env');\r\n try {\r\n await fs.access(envPath);\r\n scriptArgs.push('--env-file', '.env');\r\n } catch {\r\n // .env file doesn't exist, that's okay\r\n }\r\n }\r\n \r\n const scriptPath = path.resolve(__dirname, '../../scripts/validate-service.mjs');\r\n await runScript(scriptPath, scriptArgs, env);\r\n}\r\n\r\nasync function resolveProfile(flags: Record<string, string | boolean>, configStore: ConfigStore): Promise<ProfileConfig> {\r\n const config = await configStore.load();\r\n\r\n if (typeof flags.profile === 'string') {\r\n const explicit = config.profiles[flags.profile];\r\n if (!explicit) {\r\n throw new Error(`Profile \"${flags.profile}\" not found. Run \"beamo-node login\" to create it.`);\r\n }\r\n config.lastUsed = explicit.id;\r\n await configStore.save(config);\r\n return explicit;\r\n }\r\n\r\n const directOptions: ProfileSelectionOptions = {\r\n cid: typeof flags.cid === 'string' ? flags.cid : undefined,\r\n pid: typeof flags.pid === 'string' ? flags.pid : undefined,\r\n host: typeof flags.host === 'string' ? flags.host : undefined,\r\n };\r\n\r\n if (directOptions.cid && directOptions.pid && directOptions.host) {\r\n const apiHost = normalizeApiHost(directOptions.host);\r\n const id = profileKey({ cid: directOptions.cid, pid: directOptions.pid, apiHost });\r\n const profile = config.profiles[id];\r\n if (!profile) {\r\n throw new Error(`No stored credentials for ${directOptions.cid}.${directOptions.pid}. Run \"beamo-node login\" first.`);\r\n }\r\n profile.lastUsed = Date.now();\r\n config.lastUsed = profile.id;\r\n await configStore.save(config);\r\n return profile;\r\n }\r\n\r\n if (!config.lastUsed) {\r\n if (Object.keys(config.profiles).length === 0) {\r\n throw new Error('No stored credentials found. Run \"beamo-node login\" first.');\r\n }\r\n throw new Error('Multiple profiles found. Specify one with \"--profile <id>\" or run \"beamo-node login\" first.');\r\n }\r\n\r\n const profile = config.profiles[config.lastUsed];\r\n if (!profile) {\r\n throw new Error(`Last used profile \"${config.lastUsed}\" is missing. Run \"beamo-node login\" to refresh credentials.`);\r\n }\r\n\r\n profile.lastUsed = Date.now();\r\n config.lastUsed = profile.id;\r\n await configStore.save(config);\r\n return profile;\r\n}\r\n\r\nfunction buildScriptArgs(original: string[], profile: ProfileConfig, includeApiHost = true): string[] {\r\n const hasFlag = (flag: string) => original.some((token) => token === flag);\r\n const args: string[] = [...original];\r\n if (!hasFlag('--cid')) {\r\n args.push('--cid', profile.cid);\r\n }\r\n if (!hasFlag('--pid')) {\r\n args.push('--pid', profile.pid);\r\n }\r\n if (!hasFlag('--host')) {\r\n args.push('--host', profile.host);\r\n }\r\n if (includeApiHost && !hasFlag('--api-host')) {\r\n args.push('--api-host', profile.apiHost);\r\n }\r\n return args;\r\n}\r\n\r\nfunction buildCommandEnv(profile: ProfileConfig, tokens: TokenRecord): NodeJS.ProcessEnv {\r\n return {\r\n ...process.env,\r\n BEAMABLE_TOKEN: tokens.accessToken,\r\n ACCESS_TOKEN: tokens.accessToken,\r\n BEAMABLE_REFRESH_TOKEN: tokens.refreshToken,\r\n REFRESH_TOKEN: tokens.refreshToken,\r\n BEAMABLE_CID: profile.cid,\r\n CID: profile.cid,\r\n BEAMABLE_PID: profile.pid,\r\n PID: profile.pid,\r\n BEAMABLE_HOST: profile.host,\r\n HOST: profile.host,\r\n BEAMABLE_API_HOST: profile.apiHost,\r\n };\r\n}\r\n\r\nasync function runScript(command: string, args: string[], env: NodeJS.ProcessEnv): Promise<void> {\r\n const isNodeScript = /\\.(mjs|cjs|js)$/i.test(command);\r\n const executable = isNodeScript ? process.execPath : command;\r\n const finalArgs = isNodeScript ? [command, ...args] : args;\r\n const shouldUseShell = process.platform === 'win32' && !isNodeScript;\r\n const debug = process.env.BEAMO_DEBUG === '1' || process.env.BEAMO_NODE_DEBUG === '1';\r\n if (debug) {\r\n console.log(\r\n `[beamo-node] command=\"${command}\" exec=\"${executable}\" args=${JSON.stringify(\r\n finalArgs,\r\n )} shell=${shouldUseShell} cwd=${process.cwd()}`,\r\n );\r\n }\r\n\r\n await new Promise<void>((resolve, reject) => {\r\n const child = spawn(executable, finalArgs, {\r\n stdio: 'inherit',\r\n env,\r\n shell: shouldUseShell,\r\n });\r\n\r\n child.on('error', (error) => reject(error));\r\n child.on('exit', (code) => {\r\n if (code === 0) {\r\n resolve();\r\n } else {\r\n reject(new Error(`Command failed with exit code ${code ?? 'unknown'}.`));\r\n }\r\n });\r\n });\r\n}\r\n\r\nfunction normalizeApiHost(host: string): string {\r\n const trimmed = host.trim();\r\n if (trimmed.startsWith('wss://')) {\r\n return `https://${trimmed.substring('wss://'.length).replace(/\\/socket$/, '')}`;\r\n }\r\n if (trimmed.startsWith('ws://')) {\r\n return `http://${trimmed.substring('ws://'.length).replace(/\\/socket$/, '')}`;\r\n }\r\n let normalized = trimmed.replace(/\\/socket$/, '').replace(/\\/$/, '');\r\n if (!/^https?:\\/\\//i.test(normalized)) {\r\n normalized = `https://${normalized}`;\r\n }\r\n return normalized;\r\n}\r\n\r\nfunction profileKey(input: { cid: string; pid: string; apiHost: string }): string {\r\n return `${input.cid}.${input.pid}@${input.apiHost}`;\r\n}\r\n\r\nfunction isTokenExpired(expiresAt?: number): boolean {\r\n if (!expiresAt || !Number.isFinite(expiresAt)) {\r\n return true;\r\n }\r\n return Date.now() + MIN_TOKEN_BUFFER_MS >= expiresAt;\r\n}\r\n\r\nasync function safeReadError(response: Response): Promise<string> {\r\n try {\r\n const body = await response.text();\r\n if (!body) {\r\n return 'No response body';\r\n }\r\n try {\r\n const parsed = JSON.parse(body) as Record<string, unknown>;\r\n return typeof parsed.error === 'string'\r\n ? parsed.error\r\n : typeof parsed.message === 'string'\r\n ? parsed.message\r\n : body;\r\n } catch {\r\n return body;\r\n }\r\n } catch {\r\n return 'No response body';\r\n }\r\n}\r\n\r\nasync function main(): Promise<void> {\r\n const [, , ...argv] = process.argv;\r\n const { command, args } = parseCommandLine(argv);\r\n\r\n if (!command || command === '--help' || command === '-h') {\r\n printHelp();\r\n return;\r\n }\r\n\r\n const credentialStore = await CredentialStore.create();\r\n const tokenManager = new TokenManager(credentialStore);\r\n const configStore = new ConfigStore();\r\n\r\n switch (command) {\r\n case 'login':\r\n await handleLogin(args, configStore, tokenManager);\r\n break;\r\n case 'publish':\r\n await handlePublish(args, configStore, tokenManager);\r\n break;\r\n case 'validate':\r\n await handleValidate(args, configStore, tokenManager);\r\n break;\r\n case 'profiles':\r\n await listProfiles(configStore);\r\n break;\r\n case 'scaffold':\r\n await handleScaffold(args);\r\n break;\r\n case 'add-federation':\r\n await handleAddFederation(args);\r\n break;\r\n case 'add-storage':\r\n await handleAddStorage(args);\r\n break;\r\n default:\r\n console.error(`Unknown command: ${command}`);\r\n printHelp();\r\n exit(1);\r\n }\r\n}\r\n\r\nasync function listProfiles(configStore: ConfigStore): Promise<void> {\r\n const config = await configStore.load();\r\n const entries = Object.values(config.profiles).sort((a, b) => (b.lastUsed ?? 0) - (a.lastUsed ?? 0));\r\n if (entries.length === 0) {\r\n console.log('No stored profiles. Run \"beamo-node login\" to create one.');\r\n return;\r\n }\r\n console.log('Stored profiles:');\r\n for (const profile of entries) {\r\n const marker = config.lastUsed === profile.id ? '*' : ' ';\r\n console.log(` ${marker} ${profile.id}`);\r\n console.log(` CID: ${profile.cid}`);\r\n console.log(` PID: ${profile.pid}`);\r\n console.log(` Host: ${profile.host}`);\r\n console.log(` Email: ${profile.email}`);\r\n }\r\n}\r\n\r\nfunction printHelp(): void {\r\n console.log(`beamo-node CLI\r\n\r\nUsage:\r\n beamo-node login [--cid CID] [--pid PID] [--host HOST] [--email EMAIL]\r\n beamo-node publish [--profile ID] [--cid CID --pid PID --host HOST] [-- ...publish flags...]\r\n beamo-node validate [--profile ID] [--cid CID --pid PID --host HOST] [-- ...validate flags...]\r\n beamo-node profiles\r\n beamo-node scaffold [<service-name>]\r\n beamo-node add-federation [<identity-name>]\r\n beamo-node add-storage [<storage-name>]\r\n\r\nCommands:\r\n login Authenticate with Beamable and store credentials securely.\r\n publish Run the publish pipeline using stored credentials (forwards extra flags to the publish script).\r\n validate Generate OpenAPI docs and validate the project (forwards extra flags).\r\n profiles List stored profiles and indicate the default selection.\r\n scaffold Generate a new microservice project structure.\r\n add-federation Add federated inventory support to an existing microservice.\r\n add-storage Add storage support to an existing microservice.\r\n`);\r\n}\r\n\r\nmain().catch((error) => {\r\n console.error(error instanceof Error ? error.message : error);\r\n exit(1);\r\n});\r\n\r\nasync function loadEnvDefaults(): Promise<ProfileSelectionOptions> {\r\n const envPath = path.resolve('.env');\r\n try {\r\n const content = await fs.readFile(envPath, 'utf8');\r\n const parsed = dotenv.parse(content);\r\n const cid = parsed.BEAMABLE_CID ?? parsed.CID ?? undefined;\r\n const pid = parsed.BEAMABLE_PID ?? parsed.PID ?? undefined;\r\n const host = parsed.BEAMABLE_HOST ?? parsed.HOST ?? undefined;\r\n return {\r\n cid: cid?.trim() || undefined,\r\n pid: pid?.trim() || undefined,\r\n host: host?.trim() || undefined,\r\n };\r\n } catch (error) {\r\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') {\r\n return {};\r\n }\r\n throw error;\r\n }\r\n}\r\n\r\n\r\n"]}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Utility functions for transforming service names and validating naming conventions.
3
+ */
4
+ /**
5
+ * Converts a string to PascalCase.
6
+ * @example "my-service" -> "MyService"
7
+ * @example "user_profile" -> "UserProfile"
8
+ */
9
+ export declare function toPascalCase(str: string): string;
10
+ /**
11
+ * Converts a string to kebab-case.
12
+ * @example "MyService" -> "my-service"
13
+ * @example "user_profile" -> "user-profile"
14
+ */
15
+ export declare function toKebabCase(str: string): string;
16
+ /**
17
+ * Converts a string to camelCase.
18
+ * @example "MyService" -> "myService"
19
+ * @example "user-profile" -> "userProfile"
20
+ */
21
+ export declare function toCamelCase(str: string): string;
22
+ /**
23
+ * Validates that a service name matches the required pattern.
24
+ * Only alphanumeric characters and underscores are allowed.
25
+ */
26
+ export declare function validateServiceName(name: string): boolean;
27
+ //# sourceMappingURL=name-utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"name-utils.d.ts","sourceRoot":"","sources":["../../../src/cli/utils/name-utils.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAKhD;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAK/C;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAG/C;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEzD"}