@omen.foundation/node-microservice-runtime 0.1.87 → 0.1.89

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": "@omen.foundation/node-microservice-runtime",
3
- "version": "0.1.87",
3
+ "version": "0.1.89",
4
4
  "description": "Beamable microservice runtime for Node.js/TypeScript services.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -296,17 +296,25 @@ async function verifyManifestExists(baseUrl, tag, headers) {
296
296
 
297
297
  async function prepareUploadLocation(baseUrl, headers) {
298
298
  const url = new URL('blobs/uploads/', baseUrl);
299
- // Debug logging only - removed verbose output
300
299
  // Match C# CLI exactly: StringContent("") sets Content-Type and Content-Length
300
+ const requestHeaders = {
301
+ ...headers,
302
+ 'Content-Type': 'text/plain; charset=utf-8',
303
+ 'Content-Length': '0',
304
+ };
305
+
306
+ if (process.env.BEAMO_DEBUG === '1' || process.env.BEAMO_NODE_DEBUG === '1') {
307
+ console.error(`[beamo-node] [SUBSTEP: Prepare Upload Location]`);
308
+ console.error(`[beamo-node] URL: ${url}`);
309
+ console.error(`[beamo-node] Method: POST`);
310
+ console.error(`[beamo-node] Headers:`, JSON.stringify(requestHeaders, null, 2));
311
+ }
312
+
301
313
  let response;
302
314
  try {
303
315
  response = await fetch(url, {
304
316
  method: 'POST',
305
- headers: {
306
- ...headers,
307
- 'Content-Type': 'text/plain; charset=utf-8',
308
- 'Content-Length': '0',
309
- },
317
+ headers: requestHeaders,
310
318
  body: '', // Empty body
311
319
  });
312
320
  } catch (error) {
@@ -319,15 +327,20 @@ async function prepareUploadLocation(baseUrl, headers) {
319
327
  ...(error instanceof Error && error.cause ? { cause: error.cause } : {}),
320
328
  };
321
329
  if (process.env.BEAMO_DEBUG === '1' || process.env.BEAMO_NODE_DEBUG === '1') {
322
- console.error('[beamo-node] Network error preparing upload location:', errorDetails);
330
+ console.error('[beamo-node] Network error:', errorDetails);
323
331
  }
324
332
  throw new Error(`Network error preparing upload location: ${errorMsg}. URL: ${url.toString()}`);
325
333
  }
326
334
 
335
+ if (process.env.BEAMO_DEBUG === '1' || process.env.BEAMO_NODE_DEBUG === '1') {
336
+ console.error(`[beamo-node] Response Status: ${response.status}`);
337
+ console.error(`[beamo-node] Response Headers:`, JSON.stringify(Object.fromEntries(response.headers.entries()), null, 2));
338
+ }
339
+
327
340
  if (!response.ok) {
328
341
  const text = await response.text();
329
342
  if (process.env.BEAMO_DEBUG === '1' || process.env.BEAMO_NODE_DEBUG === '1') {
330
- console.error('[beamo-node] Upload location failed', {
343
+ console.error('[beamo-node] Upload location failed', {
331
344
  status: response.status,
332
345
  statusText: response.statusText,
333
346
  headers: Object.fromEntries(response.headers.entries()),
@@ -336,11 +349,25 @@ async function prepareUploadLocation(baseUrl, headers) {
336
349
  }
337
350
  throw new Error(`Failed to prepare upload location: ${response.status} ${text}`);
338
351
  }
339
- return response.headers.get('location');
352
+ const location = response.headers.get('location');
353
+ if (process.env.BEAMO_DEBUG === '1' || process.env.BEAMO_NODE_DEBUG === '1') {
354
+ console.error(`[beamo-node] Upload Location: ${location}`);
355
+ }
356
+ return location;
340
357
  }
341
358
 
342
359
  async function uploadBlob(baseUrl, digest, buffer, headers) {
343
- if (await checkBlobExists(baseUrl, digest, headers)) {
360
+ if (process.env.BEAMO_DEBUG === '1' || process.env.BEAMO_NODE_DEBUG === '1') {
361
+ console.error(`[beamo-node] [SUBSTEP: Upload Blob]`);
362
+ console.error(`[beamo-node] Digest: ${digest}`);
363
+ console.error(`[beamo-node] Size: ${buffer.length} bytes`);
364
+ }
365
+
366
+ const exists = await checkBlobExists(baseUrl, digest, headers);
367
+ if (exists) {
368
+ if (process.env.BEAMO_DEBUG === '1' || process.env.BEAMO_NODE_DEBUG === '1') {
369
+ console.error(`[beamo-node] Blob already exists, skipping upload`);
370
+ }
344
371
  return { digest, size: buffer.length };
345
372
  }
346
373
 
@@ -357,17 +384,36 @@ async function uploadBlob(baseUrl, digest, buffer, headers) {
357
384
  locationUrl.searchParams.set('digest', digest);
358
385
  const uploadUrl = locationUrl;
359
386
 
387
+ if (process.env.BEAMO_DEBUG === '1' || process.env.BEAMO_NODE_DEBUG === '1') {
388
+ console.error(`[beamo-node] Upload URL: ${uploadUrl}`);
389
+ console.error(`[beamo-node] Method: PUT`);
390
+ const uploadHeaders = { ...headers, 'Content-Type': 'application/octet-stream' };
391
+ console.error(`[beamo-node] Upload Headers:`, JSON.stringify(uploadHeaders, null, 2));
392
+ }
393
+
360
394
  const response = await fetch(uploadUrl, {
361
395
  method: 'PUT',
362
396
  headers: { ...headers, 'Content-Type': 'application/octet-stream' },
363
397
  body: buffer,
364
398
  });
365
399
 
400
+ if (process.env.BEAMO_DEBUG === '1' || process.env.BEAMO_NODE_DEBUG === '1') {
401
+ console.error(`[beamo-node] Response Status: ${response.status}`);
402
+ console.error(`[beamo-node] Response Headers:`, JSON.stringify(Object.fromEntries(response.headers.entries()), null, 2));
403
+ }
404
+
366
405
  if (!response.ok) {
367
406
  const text = await response.text();
407
+ if (process.env.BEAMO_DEBUG === '1' || process.env.BEAMO_NODE_DEBUG === '1') {
408
+ console.error(`[beamo-node] Response Body: ${text.substring(0, 500)}`);
409
+ }
368
410
  throw new Error(`Failed to upload blob ${digest}: ${response.status} ${text}`);
369
411
  }
370
412
 
413
+ if (process.env.BEAMO_DEBUG === '1' || process.env.BEAMO_NODE_DEBUG === '1') {
414
+ console.error(`[beamo-node] Blob upload successful`);
415
+ }
416
+
371
417
  return { digest, size: buffer.length };
372
418
  }
373
419
 
@@ -376,19 +422,39 @@ async function uploadManifest(baseUrl, manifestJson, shortImageId, headers) {
376
422
  // The backend looks up images using this short imageId tag
377
423
  const manifestJsonString = JSON.stringify(manifestJson);
378
424
  const url = new URL(`manifests/${shortImageId}`, baseUrl);
379
-
380
- // Debug logging only
381
- // Debug logging only - removed verbose output
425
+ const requestHeaders = { ...headers, 'Content-Type': MANIFEST_MEDIA_TYPE };
426
+
427
+ if (process.env.BEAMO_DEBUG === '1' || process.env.BEAMO_NODE_DEBUG === '1') {
428
+ console.error(`[beamo-node] [SUBSTEP: Upload Manifest to Registry]`);
429
+ console.error(`[beamo-node] URL: ${url}`);
430
+ console.error(`[beamo-node] Method: PUT`);
431
+ console.error(`[beamo-node] Tag: ${shortImageId}`);
432
+ console.error(`[beamo-node] Headers:`, JSON.stringify(requestHeaders, null, 2));
433
+ console.error(`[beamo-node] Manifest JSON:`, manifestJsonString);
434
+ }
382
435
 
383
436
  const response = await fetch(url, {
384
437
  method: 'PUT',
385
- headers: { ...headers, 'Content-Type': MANIFEST_MEDIA_TYPE },
438
+ headers: requestHeaders,
386
439
  body: manifestJsonString,
387
440
  });
441
+
442
+ if (process.env.BEAMO_DEBUG === '1' || process.env.BEAMO_NODE_DEBUG === '1') {
443
+ console.error(`[beamo-node] Response Status: ${response.status}`);
444
+ console.error(`[beamo-node] Response Headers:`, JSON.stringify(Object.fromEntries(response.headers.entries()), null, 2));
445
+ }
446
+
388
447
  if (!response.ok) {
389
448
  const text = await response.text();
449
+ if (process.env.BEAMO_DEBUG === '1' || process.env.BEAMO_NODE_DEBUG === '1') {
450
+ console.error(`[beamo-node] Response Body: ${text.substring(0, 500)}`);
451
+ }
390
452
  throw new Error(`Failed to upload manifest: ${response.status} ${text}`);
391
453
  }
454
+
455
+ if (process.env.BEAMO_DEBUG === '1' || process.env.BEAMO_NODE_DEBUG === '1') {
456
+ console.error(`[beamo-node] Manifest upload successful`);
457
+ }
392
458
  }
393
459
 
394
460
  async function fetchJson(url, options = {}) {
@@ -477,13 +543,26 @@ async function getScopedAccessToken(apiHost, cid, pid, refreshToken, fallbackTok
477
543
 
478
544
  async function getRegistryUrl(apiHost, token, cid, pid) {
479
545
  const scope = pid ? `${cid}.${pid}` : cid;
480
- const body = await fetchJson(new URL('/basic/beamo/registry', apiHost), {
481
- headers: {
482
- Authorization: `Bearer ${token}`,
483
- Accept: 'application/json',
484
- ...(scope ? { 'X-BEAM-SCOPE': scope } : {}),
485
- },
486
- });
546
+ const url = new URL('/basic/beamo/registry', apiHost);
547
+ const headers = {
548
+ Authorization: `Bearer ${token}`,
549
+ Accept: 'application/json',
550
+ ...(scope ? { 'X-BEAM-SCOPE': scope } : {}),
551
+ };
552
+
553
+ if (process.env.BEAMO_DEBUG === '1' || process.env.BEAMO_NODE_DEBUG === '1') {
554
+ console.error(`[beamo-node] [STEP: Get Registry URL]`);
555
+ console.error(`[beamo-node] URL: ${url}`);
556
+ console.error(`[beamo-node] Headers:`, JSON.stringify(headers, null, 2));
557
+ console.error(`[beamo-node] Scope: ${scope}`);
558
+ }
559
+
560
+ const body = await fetchJson(url, { headers });
561
+
562
+ if (process.env.BEAMO_DEBUG === '1' || process.env.BEAMO_NODE_DEBUG === '1') {
563
+ console.error(`[beamo-node] Response:`, JSON.stringify(body, null, 2));
564
+ }
565
+
487
566
  const uri = body.uri || body.registry || body.url;
488
567
  if (!uri) {
489
568
  throw new Error('Registry URI response missing "uri" field.');
@@ -492,7 +571,13 @@ async function getRegistryUrl(apiHost, token, cid, pid) {
492
571
  const normalized = uri.includes('://') ? uri : `https://${uri}`;
493
572
  const parsed = new URL(normalized);
494
573
  // parsedUri.Host in C# is just the hostname (no port), so we use hostname here
495
- return `${parsed.protocol}//${parsed.hostname}/v2/`;
574
+ const registryUrl = `${parsed.protocol}//${parsed.hostname}/v2/`;
575
+
576
+ if (process.env.BEAMO_DEBUG === '1' || process.env.BEAMO_NODE_DEBUG === '1') {
577
+ console.error(`[beamo-node] Normalized Registry URL: ${registryUrl}`);
578
+ }
579
+
580
+ return registryUrl;
496
581
  }
497
582
 
498
583
  async function uploadDockerImage({
@@ -516,9 +601,18 @@ async function uploadDockerImage({
516
601
  'x-ks-projectid': pid, // Use realm PID (matches backend's rc.projectId in DockerRegistryClient)
517
602
  'x-ks-token': token, // Access token from login
518
603
  };
604
+
519
605
  if (process.env.BEAMO_DEBUG === '1' || process.env.BEAMO_NODE_DEBUG === '1') {
520
- console.error(`[beamo-node] Uploading to: ${baseUrl}`);
521
- console.error(`[beamo-node] Upload headers PID: ${pid} (realm), gamePid: ${gamePid}`);
606
+ console.error(`[beamo-node] [STEP: Upload Docker Image]`);
607
+ console.error(`[beamo-node] Base URL: ${baseUrl}`);
608
+ console.error(`[beamo-node] Registry URL: ${registryUrl}`);
609
+ console.error(`[beamo-node] Unique Name: ${uniqueName}`);
610
+ console.error(`[beamo-node] Service ID: ${serviceId}`);
611
+ console.error(`[beamo-node] CID: ${cid}`);
612
+ console.error(`[beamo-node] Realm PID: ${pid}`);
613
+ console.error(`[beamo-node] Game PID: ${gamePid}`);
614
+ console.error(`[beamo-node] Full Image ID: ${fullImageId}`);
615
+ console.error(`[beamo-node] Upload Headers:`, JSON.stringify(headers, null, 2));
522
616
  }
523
617
 
524
618
  const { manifestEntry, configBuffer, layers } = await readDockerImageTar(imageTarPath);
@@ -527,16 +621,38 @@ async function uploadDockerImage({
527
621
  if (progress) {
528
622
  process.stdout.write(`\r${colors.blue}↑${colors.reset} Uploading config...`);
529
623
  }
530
- const configDigest = await uploadBlob(baseUrl, sha256Digest(configBuffer), configBuffer, headers);
624
+ const configDigestValue = sha256Digest(configBuffer);
625
+ if (process.env.BEAMO_DEBUG === '1' || process.env.BEAMO_NODE_DEBUG === '1') {
626
+ console.error(`[beamo-node] [SUBSTEP: Upload Config]`);
627
+ console.error(`[beamo-node] Config Digest: ${configDigestValue}`);
628
+ console.error(`[beamo-node] Config Size: ${configBuffer.length} bytes`);
629
+ }
630
+ const configDigest = await uploadBlob(baseUrl, configDigestValue, configBuffer, headers);
631
+ if (process.env.BEAMO_DEBUG === '1' || process.env.BEAMO_NODE_DEBUG === '1') {
632
+ console.error(`[beamo-node] Config Upload Result:`, JSON.stringify(configDigest, null, 2));
633
+ }
531
634
 
532
635
  // Upload layers with progress
533
636
  const layerDescriptors = [];
534
637
  const totalLayers = layers.length;
638
+ if (process.env.BEAMO_DEBUG === '1' || process.env.BEAMO_NODE_DEBUG === '1') {
639
+ console.error(`[beamo-node] [SUBSTEP: Upload Layers]`);
640
+ console.error(`[beamo-node] Total Layers: ${totalLayers}`);
641
+ }
535
642
  for (let i = 0; i < layers.length; i++) {
536
643
  if (progress) {
537
644
  process.stdout.write(`\r${colors.blue}↑${colors.reset} Uploading layers (${i + 1}/${totalLayers})...`);
538
645
  }
539
- const descriptor = await uploadBlob(baseUrl, sha256Digest(layers[i].buffer), layers[i].buffer, headers);
646
+ const layerDigestValue = sha256Digest(layers[i].buffer);
647
+ if (process.env.BEAMO_DEBUG === '1' || process.env.BEAMO_NODE_DEBUG === '1') {
648
+ console.error(`[beamo-node] Layer ${i + 1}/${totalLayers}:`);
649
+ console.error(`[beamo-node] Digest: ${layerDigestValue}`);
650
+ console.error(`[beamo-node] Size: ${layers[i].buffer.length} bytes`);
651
+ }
652
+ const descriptor = await uploadBlob(baseUrl, layerDigestValue, layers[i].buffer, headers);
653
+ if (process.env.BEAMO_DEBUG === '1' || process.env.BEAMO_NODE_DEBUG === '1') {
654
+ console.error(`[beamo-node] Upload Result:`, JSON.stringify(descriptor, null, 2));
655
+ }
540
656
  layerDescriptors.push({
541
657
  digest: descriptor.digest,
542
658
  size: descriptor.size,
@@ -560,7 +676,15 @@ async function uploadDockerImage({
560
676
  process.stdout.write(`\r${colors.blue}↑${colors.reset} Uploading manifest...`);
561
677
  }
562
678
  const shortImageId = shortDigest(fullImageId);
679
+ if (process.env.BEAMO_DEBUG === '1' || process.env.BEAMO_NODE_DEBUG === '1') {
680
+ console.error(`[beamo-node] [SUBSTEP: Upload Manifest]`);
681
+ console.error(`[beamo-node] Short Image ID: ${shortImageId}`);
682
+ console.error(`[beamo-node] Manifest JSON:`, JSON.stringify(uploadManifestJson, null, 2));
683
+ }
563
684
  await uploadManifest(baseUrl, uploadManifestJson, shortImageId, headers);
685
+ if (process.env.BEAMO_DEBUG === '1' || process.env.BEAMO_NODE_DEBUG === '1') {
686
+ console.error(`[beamo-node] Manifest Upload Complete`);
687
+ }
564
688
  if (progress) {
565
689
  process.stdout.write('\r');
566
690
  }
@@ -852,32 +976,52 @@ async function updateManifest({
852
976
  storageReferences,
853
977
  };
854
978
 
979
+ const publishUrl = new URL('/api/beamo/manifests', apiHost);
980
+ const publishHeaders = {
981
+ Authorization: `Bearer ${token}`,
982
+ Accept: 'application/json',
983
+ 'Content-Type': 'application/json',
984
+ 'X-BEAM-SCOPE': `${cid}.${pid}`,
985
+ };
986
+
855
987
  if (process.env.BEAMO_DEBUG === '1' || process.env.BEAMO_NODE_DEBUG === '1') {
856
- console.error(`[beamo-node] Publishing manifest with imageId: ${shortImageId}`);
857
- console.error(`[beamo-node] Service: ${serviceId}, CID: ${cid}, PID: ${pid}`);
858
- console.error(`[beamo-node] Manifest service entry:`, JSON.stringify(mappedServices.find(s => s.serviceName === serviceId), null, 2));
988
+ console.error(`[beamo-node] [STEP: Publish Manifest to Backend]`);
989
+ console.error(`[beamo-node] URL: ${publishUrl}`);
990
+ console.error(`[beamo-node] Method: POST`);
991
+ console.error(`[beamo-node] Headers:`, JSON.stringify(publishHeaders, null, 2));
992
+ console.error(`[beamo-node] Service: ${serviceId}`);
993
+ console.error(`[beamo-node] CID: ${cid}`);
994
+ console.error(`[beamo-node] PID: ${pid}`);
995
+ console.error(`[beamo-node] Short Image ID: ${shortImageId}`);
996
+ console.error(`[beamo-node] Request Body:`, JSON.stringify(requestBody, null, 2));
997
+ console.error(`[beamo-node] Service Entry in Manifest:`, JSON.stringify(mappedServices.find(s => s.serviceName === serviceId), null, 2));
859
998
  }
860
999
 
861
- const response = await fetch(new URL('/api/beamo/manifests', apiHost), {
1000
+ const response = await fetch(publishUrl, {
862
1001
  method: 'POST',
863
- headers: {
864
- Authorization: `Bearer ${token}`,
865
- Accept: 'application/json',
866
- 'Content-Type': 'application/json',
867
- 'X-BEAM-SCOPE': `${cid}.${pid}`,
868
- },
1002
+ headers: publishHeaders,
869
1003
  body: JSON.stringify(requestBody),
870
1004
  });
871
1005
 
1006
+ if (process.env.BEAMO_DEBUG === '1' || process.env.BEAMO_NODE_DEBUG === '1') {
1007
+ console.error(`[beamo-node] Response Status: ${response.status}`);
1008
+ console.error(`[beamo-node] Response Headers:`, JSON.stringify(Object.fromEntries(response.headers.entries()), null, 2));
1009
+ }
1010
+
872
1011
  if (!response.ok) {
873
1012
  const text = await response.text();
874
1013
  if (process.env.BEAMO_DEBUG === '1' || process.env.BEAMO_NODE_DEBUG === '1') {
875
- console.error(`[beamo-node] Manifest publish failed: ${response.status}`);
876
- console.error(`[beamo-node] Response: ${text}`);
877
- console.error(`[beamo-node] Request body:`, JSON.stringify(requestBody, null, 2));
1014
+ console.error(`[beamo-node] Response Body: ${text}`);
1015
+ console.error(`[beamo-node] Full Request Body (for debugging):`, JSON.stringify(requestBody, null, 2));
878
1016
  }
879
1017
  throw new Error(`Failed to publish manifest: ${response.status} ${text}`);
880
1018
  }
1019
+
1020
+ const responseBody = await response.json();
1021
+ if (process.env.BEAMO_DEBUG === '1' || process.env.BEAMO_NODE_DEBUG === '1') {
1022
+ console.error(`[beamo-node] Response Body:`, JSON.stringify(responseBody, null, 2));
1023
+ console.error(`[beamo-node] ✓ Manifest published successfully`);
1024
+ }
881
1025
  }
882
1026
 
883
1027
  async function prepareDockerContext({ entry, distDir, openapiPath, packageJson, packageLock, nodeVersion }) {
@@ -1108,12 +1252,20 @@ async function main() {
1108
1252
 
1109
1253
  // Use resolvedGamePid for registry URL and uniqueName - backend checks using game PID scope
1110
1254
  // The pid variable might be a realm PID, but the backend expects game PID for registry operations
1255
+ if (process.env.BEAMO_DEBUG === '1' || process.env.BEAMO_NODE_DEBUG === '1') {
1256
+ console.error(`[beamo-node] [STEP: Calculate Registry Path]`);
1257
+ console.error(`[beamo-node] CID: ${cid}`);
1258
+ console.error(`[beamo-node] Realm PID: ${pid}`);
1259
+ console.error(`[beamo-node] Resolved Game PID: ${resolvedGamePid}`);
1260
+ console.error(`[beamo-node] Service ID: ${serviceId}`);
1261
+ }
1111
1262
  const registryUrl = await getRegistryUrl(apiHost, token, cid, resolvedGamePid);
1112
- const uniqueName = md5Hex(`${cid}_${resolvedGamePid}_${serviceId}`).substring(0, 30);
1263
+ const uniqueNameInput = `${cid}_${resolvedGamePid}_${serviceId}`;
1264
+ const uniqueName = md5Hex(uniqueNameInput).substring(0, 30);
1113
1265
  if (process.env.BEAMO_DEBUG === '1' || process.env.BEAMO_NODE_DEBUG === '1') {
1114
- console.error(`[beamo-node] Registry URL: ${registryUrl}`);
1115
- console.error(`[beamo-node] Unique name: ${uniqueName}`);
1116
- console.error(`[beamo-node] CID: ${cid}, PID: ${pid}, Game PID: ${resolvedGamePid}`);
1266
+ console.error(`[beamo-node] Unique Name Input: ${uniqueNameInput}`);
1267
+ console.error(`[beamo-node] Unique Name (MD5 first 30 chars): ${uniqueName}`);
1268
+ console.error(`[beamo-node] Registry URL: ${registryUrl}`);
1117
1269
  }
1118
1270
  progress.complete('Authenticated');
1119
1271
 
@@ -1139,7 +1291,7 @@ async function main() {
1139
1291
  const baseUrl = `${registryUrl}${uniqueName}/`;
1140
1292
  const verifyHeaders = {
1141
1293
  'x-ks-clientid': cid,
1142
- 'x-ks-projectid': resolvedGamePid || pid, // Use gamePid to match registry scope
1294
+ 'x-ks-projectid': pid, // Use realm PID (matches backend's rc.projectId when checking registry)
1143
1295
  'x-ks-token': token,
1144
1296
  };
1145
1297