@geekmidas/cli 1.10.16 → 1.10.17

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@geekmidas/cli",
3
- "version": "1.10.16",
3
+ "version": "1.10.17",
4
4
  "description": "CLI tools for building Lambda handlers, server applications, and generating OpenAPI specs",
5
5
  "private": false,
6
6
  "type": "module",
@@ -56,11 +56,11 @@
56
56
  "prompts": "~2.4.2",
57
57
  "tsx": "~4.20.3",
58
58
  "yaml": "~2.8.2",
59
- "@geekmidas/envkit": "~1.0.3",
59
+ "@geekmidas/envkit": "~1.0.4",
60
60
  "@geekmidas/constructs": "~3.0.2",
61
+ "@geekmidas/errors": "~1.0.0",
61
62
  "@geekmidas/logger": "~1.0.0",
62
- "@geekmidas/schema": "~1.0.0",
63
- "@geekmidas/errors": "~1.0.0"
63
+ "@geekmidas/schema": "~1.0.0"
64
64
  },
65
65
  "devDependencies": {
66
66
  "@types/lodash.kebabcase": "^4.1.9",
@@ -1237,6 +1237,28 @@ describe('replacePortInUrl', () => {
1237
1237
  // Only the :5432 before / should be replaced
1238
1238
  expect(result).toBe('postgresql://app:pass5432@localhost:5433/db5432');
1239
1239
  });
1240
+
1241
+ it('should replace port followed by query string', () => {
1242
+ const url = 'pgboss://pgboss:pass@localhost:5432/mydb?schema=pgboss';
1243
+ expect(replacePortInUrl(url, 5432, 5433)).toBe(
1244
+ 'pgboss://pgboss:pass@localhost:5433/mydb?schema=pgboss',
1245
+ );
1246
+ });
1247
+
1248
+ it('should replace port in SNS URL with query params and no path', () => {
1249
+ const url = 'sns://key:secret@localhost:4566?region=us-east-1';
1250
+ expect(replacePortInUrl(url, 4566, 4567)).toBe(
1251
+ 'sns://key:secret@localhost:4567?region=us-east-1',
1252
+ );
1253
+ });
1254
+
1255
+ it('should replace URL-encoded port in query params', () => {
1256
+ const url =
1257
+ 'sns://key:secret@localhost:4566?region=us-east-1&endpoint=http%3A%2F%2Flocalhost%3A4566';
1258
+ expect(replacePortInUrl(url, 4566, 4567)).toBe(
1259
+ 'sns://key:secret@localhost:4567?region=us-east-1&endpoint=http%3A%2F%2Flocalhost%3A4567',
1260
+ );
1261
+ });
1240
1262
  });
1241
1263
 
1242
1264
  describe('rewriteUrlsWithPorts', () => {
@@ -1384,6 +1406,52 @@ describe('rewriteUrlsWithPorts', () => {
1384
1406
  expect(result.POSTGRES_HOST).toBe('localhost');
1385
1407
  });
1386
1408
 
1409
+ it('should rewrite EVENT_PUBLISHER_CONNECTION_STRING and EVENT_SUBSCRIBER_CONNECTION_STRING', () => {
1410
+ const secrets = {
1411
+ EVENT_PUBLISHER_CONNECTION_STRING:
1412
+ 'pgboss://pgboss:pass@localhost:5432/mydb?schema=pgboss',
1413
+ EVENT_SUBSCRIBER_CONNECTION_STRING:
1414
+ 'pgboss://pgboss:pass@localhost:5432/mydb?schema=pgboss',
1415
+ };
1416
+ const result = rewriteUrlsWithPorts(secrets, {
1417
+ dockerEnv: { POSTGRES_HOST_PORT: '5433' },
1418
+ ports: { POSTGRES_HOST_PORT: 5433 },
1419
+ mappings: [pgMapping],
1420
+ });
1421
+ expect(result.EVENT_PUBLISHER_CONNECTION_STRING).toBe(
1422
+ 'pgboss://pgboss:pass@localhost:5433/mydb?schema=pgboss',
1423
+ );
1424
+ expect(result.EVENT_SUBSCRIBER_CONNECTION_STRING).toBe(
1425
+ 'pgboss://pgboss:pass@localhost:5433/mydb?schema=pgboss',
1426
+ );
1427
+ });
1428
+
1429
+ it('should rewrite SNS connection strings with encoded endpoint port', () => {
1430
+ const localstackMapping = {
1431
+ service: 'localstack',
1432
+ envVar: 'LOCALSTACK_PORT',
1433
+ defaultPort: 4566,
1434
+ containerPort: 4566,
1435
+ };
1436
+ const secrets = {
1437
+ EVENT_PUBLISHER_CONNECTION_STRING:
1438
+ 'sns://LSIAkey:secret@localhost:4566?region=us-east-1&endpoint=http%3A%2F%2Flocalhost%3A4566',
1439
+ EVENT_SUBSCRIBER_CONNECTION_STRING:
1440
+ 'sqs://LSIAkey:secret@localhost:4566?region=us-east-1&endpoint=http%3A%2F%2Flocalhost%3A4566',
1441
+ };
1442
+ const result = rewriteUrlsWithPorts(secrets, {
1443
+ dockerEnv: { LOCALSTACK_PORT: '4567' },
1444
+ ports: { LOCALSTACK_PORT: 4567 },
1445
+ mappings: [localstackMapping],
1446
+ });
1447
+ expect(result.EVENT_PUBLISHER_CONNECTION_STRING).toBe(
1448
+ 'sns://LSIAkey:secret@localhost:4567?region=us-east-1&endpoint=http%3A%2F%2Flocalhost%3A4567',
1449
+ );
1450
+ expect(result.EVENT_SUBSCRIBER_CONNECTION_STRING).toBe(
1451
+ 'sqs://LSIAkey:secret@localhost:4567?region=us-east-1&endpoint=http%3A%2F%2Flocalhost%3A4567',
1452
+ );
1453
+ });
1454
+
1387
1455
  it('should return empty for no mappings', () => {
1388
1456
  const result = rewriteUrlsWithPorts(
1389
1457
  {},
package/src/dev/index.ts CHANGED
@@ -348,7 +348,17 @@ export function replacePortInUrl(
348
348
  newPort: number,
349
349
  ): string {
350
350
  if (oldPort === newPort) return url;
351
- return url.replace(new RegExp(`:${oldPort}(?=/|$)`, 'g'), `:${newPort}`);
351
+ // Replace literal :port (in authority section)
352
+ let result = url.replace(
353
+ new RegExp(`:${oldPort}(?=[/?#]|$)`, 'g'),
354
+ `:${newPort}`,
355
+ );
356
+ // Replace URL-encoded :port (e.g., in query params like endpoint=http%3A%2F%2Flocalhost%3A4566)
357
+ result = result.replace(
358
+ new RegExp(`%3A${oldPort}(?=[%/?#&]|$)`, 'gi'),
359
+ `%3A${newPort}`,
360
+ );
361
+ return result;
352
362
  }
353
363
 
354
364
  /**
@@ -402,6 +412,7 @@ export function rewriteUrlsWithPorts(
402
412
  if (
403
413
  !key.endsWith('_URL') &&
404
414
  !key.endsWith('_ENDPOINT') &&
415
+ !key.endsWith('_CONNECTION_STRING') &&
405
416
  key !== 'DATABASE_URL'
406
417
  )
407
418
  continue;
@@ -2246,20 +2257,17 @@ export async function execCommand(
2246
2257
  logger.log(`🔐 Loaded ${secretCount} secret(s)`);
2247
2258
  }
2248
2259
 
2249
- // Rewrite URLs with resolved Docker ports (from gkm dev)
2250
- const composePath = join(secretsRoot, 'docker-compose.yml');
2251
- const mappings = parseComposePortMappings(composePath);
2252
- if (mappings.length > 0) {
2253
- const ports = await loadPortState(secretsRoot);
2254
- if (Object.keys(ports).length > 0) {
2255
- const rewritten = rewriteUrlsWithPorts(credentials, {
2256
- dockerEnv: {},
2257
- ports,
2258
- mappings,
2259
- });
2260
- Object.assign(credentials, rewritten);
2261
- logger.log(`🔌 Applied ${Object.keys(ports).length} port mapping(s)`);
2262
- }
2260
+ // Resolve actual Docker ports from running containers (not just saved state)
2261
+ const resolvedPorts = await resolveServicePorts(secretsRoot);
2262
+ if (
2263
+ resolvedPorts.mappings.length > 0 &&
2264
+ Object.keys(resolvedPorts.ports).length > 0
2265
+ ) {
2266
+ const rewritten = rewriteUrlsWithPorts(credentials, resolvedPorts);
2267
+ Object.assign(credentials, rewritten);
2268
+ logger.log(
2269
+ `🔌 Applied ${Object.keys(resolvedPorts.ports).length} port mapping(s)`,
2270
+ );
2263
2271
  }
2264
2272
 
2265
2273
  // Inject dependency URLs (works for both frontend and backend apps)
@@ -35,7 +35,7 @@ export const GEEKMIDAS_VERSIONS = {
35
35
  '@geekmidas/constructs': '~3.0.2',
36
36
  '@geekmidas/db': '~1.0.0',
37
37
  '@geekmidas/emailkit': '~1.0.0',
38
- '@geekmidas/envkit': '~1.0.3',
38
+ '@geekmidas/envkit': '~1.0.4',
39
39
  '@geekmidas/errors': '~1.0.0',
40
40
  '@geekmidas/events': '~1.1.0',
41
41
  '@geekmidas/logger': '~1.0.0',