@superblocksteam/sdk 2.0.83 → 2.0.84-next.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/dist/cli-replacement/automatic-upgrades.d.ts +0 -6
  3. package/dist/cli-replacement/automatic-upgrades.d.ts.map +1 -1
  4. package/dist/cli-replacement/automatic-upgrades.js +5 -27
  5. package/dist/cli-replacement/automatic-upgrades.js.map +1 -1
  6. package/dist/cli-replacement/dev.d.mts.map +1 -1
  7. package/dist/cli-replacement/dev.mjs +260 -217
  8. package/dist/cli-replacement/dev.mjs.map +1 -1
  9. package/dist/cli-replacement/version-detection.d.ts +71 -0
  10. package/dist/cli-replacement/version-detection.d.ts.map +1 -0
  11. package/dist/cli-replacement/version-detection.js +186 -0
  12. package/dist/cli-replacement/version-detection.js.map +1 -0
  13. package/dist/cli-replacement/version-detection.test.d.ts +5 -0
  14. package/dist/cli-replacement/version-detection.test.d.ts.map +1 -0
  15. package/dist/cli-replacement/version-detection.test.js +257 -0
  16. package/dist/cli-replacement/version-detection.test.js.map +1 -0
  17. package/dist/dev-utils/dev-server.mjs +133 -115
  18. package/dist/dev-utils/dev-server.mjs.map +1 -1
  19. package/dist/telemetry/index.d.ts +4 -4
  20. package/dist/telemetry/index.d.ts.map +1 -1
  21. package/dist/telemetry/index.js +92 -64
  22. package/dist/telemetry/index.js.map +1 -1
  23. package/dist/telemetry/index.test.d.ts +2 -0
  24. package/dist/telemetry/index.test.d.ts.map +1 -0
  25. package/dist/telemetry/index.test.js +93 -0
  26. package/dist/telemetry/index.test.js.map +1 -0
  27. package/dist/telemetry/local-obs.d.ts +73 -0
  28. package/dist/telemetry/local-obs.d.ts.map +1 -0
  29. package/dist/telemetry/local-obs.js +107 -0
  30. package/dist/telemetry/local-obs.js.map +1 -0
  31. package/dist/telemetry/util.d.ts +1 -2
  32. package/dist/telemetry/util.d.ts.map +1 -1
  33. package/dist/telemetry/util.js +26 -4
  34. package/dist/telemetry/util.js.map +1 -1
  35. package/package.json +6 -5
  36. package/src/cli-replacement/automatic-upgrades.ts +10 -42
  37. package/src/cli-replacement/dev.mts +336 -281
  38. package/src/cli-replacement/version-detection.test.ts +336 -0
  39. package/src/cli-replacement/version-detection.ts +220 -0
  40. package/src/dev-utils/dev-server.mts +149 -127
  41. package/src/telemetry/index.test.ts +130 -0
  42. package/src/telemetry/index.ts +105 -83
  43. package/src/telemetry/local-obs.ts +138 -0
  44. package/src/telemetry/util.ts +27 -4
  45. package/tsconfig.tsbuildinfo +1 -1
  46. package/turbo.json +20 -2
@@ -23,10 +23,8 @@ import { detect } from "package-manager-detector/detect";
23
23
  import { AUTO_UPGRADE_EXIT_CODE, createDevServer } from "../index.js";
24
24
  import { getTracer } from "../telemetry/index.js";
25
25
  import { getErrorMeta, getLogger, type Logger } from "../telemetry/logging.js";
26
- import {
27
- checkVersionsAndWritePackageJson,
28
- getCurrentCliVersion,
29
- } from "./automatic-upgrades.js";
26
+ import { checkVersionsAndWritePackageJson } from "./automatic-upgrades.js";
27
+ import { getCurrentCliVersion } from "./version-detection.js";
30
28
  import type {
31
29
  AuthHotReloadServer,
32
30
  TokenManager,
@@ -284,322 +282,379 @@ export async function dev(options: {
284
282
  const logger = getLogger(options.logger);
285
283
  const skipAutoUpgrade = autoUpgradeMode === DevServerAutoUpgradeMode.SKIP;
286
284
 
287
- // Add check for node_modules
288
- if (!fs.existsSync(path.join(cwd, "node_modules"))) {
289
- throw new Error(
290
- 'node_modules folder is missing. Please run "npm install" first.',
291
- );
292
- }
293
-
294
- const cliVersion = await getCurrentCliVersion();
295
- logger.info(
296
- `Running command: ${options.superblocksPath} dev${options.uploadFirst ? " --upload-first" : ""}${options.downloadFirst ? " --download-first" : ""} with baseUrl: ${tokenConfig.superblocksBaseUrl}, cliVersion: ${cliVersion?.version}${cliVersion?.alias ? ` (${cliVersion.alias})` : ""}`,
297
- );
298
-
299
- const port = devServerPort ?? 5173;
300
-
301
- const fsOperationQueue = new OperationQueue();
302
- if (applicationConfig && !skipSync) {
303
- const rpcClient = new AutoConnectingRpcClient(
304
- tokenConfig.superblocksBaseUrl,
305
- tokenConfig.token,
306
- tracer,
307
- tokenManager,
308
- logger,
309
- );
285
+ await tracer.startActiveSpan("devServerStartup", async (startupSpan) => {
286
+ try {
287
+ // Add check for node_modules
288
+ if (!fs.existsSync(path.join(cwd, "node_modules"))) {
289
+ throw new Error(
290
+ 'node_modules folder is missing. Please run "npm install" first.',
291
+ );
292
+ }
310
293
 
311
- // Get feature flags for inactivity timeout
312
- const featureFlags = await sdk.getFeatureFlagsForCurrentUser();
313
- const lockType =
314
- process.env.SUPERBLOCKS_IS_CSB === "true" ? LockType.CSB : LockType.LOCAL;
315
- const inactivityTimeoutMs =
316
- lockType === LockType.CSB
317
- ? featureFlags.devServerCloudInactivityTimeoutMinutes() * 60 * 1000
318
- : featureFlags.devServerLocalInactivityTimeoutMinutes() * 60 * 1000;
319
-
320
- lockService = new LockService({
321
- superblocksBaseUrl: tokenConfig.superblocksBaseUrl,
322
- applicationId: applicationConfig.id,
323
- branchName: applicationConfig.branchName,
324
- lockType: lockType,
325
- tracer,
326
- logger,
327
- rpcClient,
328
- inactivityThresholdMs: inactivityTimeoutMs,
329
- });
294
+ const cliVersion = await tracer.startActiveSpan(
295
+ "getCurrentCliVersion",
296
+ async (span) => {
297
+ try {
298
+ return await getCurrentCliVersion();
299
+ } finally {
300
+ span.end();
301
+ }
302
+ },
303
+ );
304
+ logger.info(
305
+ `Running command: ${options.superblocksPath} dev${options.uploadFirst ? " --upload-first" : ""}${options.downloadFirst ? " --download-first" : ""} with baseUrl: ${tokenConfig.superblocksBaseUrl}, cliVersion: ${cliVersion?.version}${cliVersion?.alias ? ` (${cliVersion.alias})` : ""}`,
306
+ );
330
307
 
331
- syncService = new SyncService({
332
- appRootDirPath: cwd,
333
- applicationId: applicationConfig.id,
334
- branchName: applicationConfig.branchName,
335
- fsOperationQueue,
336
- lockService: lockService,
337
- tracer,
338
- superblocksBaseUrl: tokenConfig.superblocksBaseUrl,
339
- rpcClient,
340
- logger,
341
- });
308
+ const port = devServerPort ?? 5173;
342
309
 
343
- logger.info("Checking if local files are synced with the server");
310
+ const fsOperationQueue = new OperationQueue();
311
+ if (applicationConfig && !skipSync) {
312
+ const rpcClient = new AutoConnectingRpcClient(
313
+ tokenConfig.superblocksBaseUrl,
314
+ tokenConfig.token,
315
+ tracer,
316
+ tokenManager,
317
+ logger,
318
+ );
344
319
 
345
- try {
346
- await maskUnixSignals(async () => {
347
- if (lockService) {
348
- const lockSvc = lockService;
349
- await tracer.startActiveSpan("acquiringInitialLock", async (span) => {
320
+ // Get feature flags for inactivity timeout
321
+ const featureFlags = await tracer.startActiveSpan(
322
+ "getFeatureFlags",
323
+ async (span) => {
350
324
  try {
351
- // If --force-takeover flag is set, immediately force takeover instead of acquiring
352
- if (options.forceTakeover) {
353
- logger.info("Force takeover requested, taking over lock...");
354
- await lockSvc.forceTakeover();
355
- logger.info("Lock acquired successfully via force takeover.");
356
- } else {
357
- await lockSvc.acquireLock();
358
- }
359
- } catch (error) {
360
- // If we got a conflict error (409), inspect the lock for more information
361
- if (error instanceof ConflictError) {
362
- await handleLockConflict(error, lockSvc, span, logger);
363
- return;
364
- }
365
-
366
- logger.error(
367
- "Failed to acquire lock on application",
368
- getErrorMeta(error),
369
- );
370
- span.setStatus({
371
- code: SpanStatusCode.ERROR,
372
- message: JSON.stringify(error),
373
- });
374
- passErrorToVSCode(
375
- (error as { context?: { message: string } }).context?.message,
376
- logger,
377
- );
378
- throw new Error(
379
- `Failed to acquire lock on application: ${error}`,
380
- );
325
+ return await sdk.getFeatureFlagsForCurrentUser();
381
326
  } finally {
382
327
  span.end();
383
328
  }
384
- });
385
- }
386
-
387
- const [localContents, serverHash, currentUser] =
388
- await tracer.startActiveSpan("fetchInitInfo", async (span) => {
389
- const results = await Promise.all([
390
- sdk.hashLocalDirectory(cwd),
391
- getDraftOrLiveEditHash(sdk, applicationConfig, logger),
392
- sdk.fetchCurrentUser(),
393
- ]);
394
- span.end();
395
- return results;
396
- });
397
-
398
- aiService = new AiService({
329
+ },
330
+ );
331
+ const lockType =
332
+ process.env.SUPERBLOCKS_IS_CSB === "true"
333
+ ? LockType.CSB
334
+ : LockType.LOCAL;
335
+ const inactivityTimeoutMs =
336
+ lockType === LockType.CSB
337
+ ? featureFlags.devServerCloudInactivityTimeoutMinutes() * 60 * 1000
338
+ : featureFlags.devServerLocalInactivityTimeoutMinutes() * 60 * 1000;
339
+
340
+ lockService = new LockService({
399
341
  superblocksBaseUrl: tokenConfig.superblocksBaseUrl,
400
- appRootDirPath: options.cwd,
401
342
  applicationId: applicationConfig.id,
402
- organizationId: currentUser.organizations[0].id,
403
- fsOperationQueue,
404
- draftInterface: syncService as DraftInterface,
343
+ branchName: applicationConfig.branchName,
344
+ lockType: lockType,
345
+ tracer,
346
+ logger,
405
347
  rpcClient,
348
+ inactivityThresholdMs: inactivityTimeoutMs,
349
+ });
350
+
351
+ syncService = new SyncService({
352
+ appRootDirPath: cwd,
353
+ applicationId: applicationConfig.id,
354
+ branchName: applicationConfig.branchName,
355
+ fsOperationQueue,
356
+ lockService: lockService,
406
357
  tracer,
358
+ superblocksBaseUrl: tokenConfig.superblocksBaseUrl,
359
+ rpcClient,
407
360
  logger,
408
- tokenManager,
409
- features: AiServiceFeatureFlags.create(
410
- currentUser.flagBootstrap as Record<string, unknown> | undefined,
411
- ),
412
- pluginExecutionVersions:
413
- currentUser.organizations[0].pluginExecutionVersions,
414
361
  });
415
362
 
416
- await aiService.initialize();
363
+ logger.info("Checking if local files are synced with the server");
364
+
365
+ try {
366
+ await maskUnixSignals(async () => {
367
+ if (lockService) {
368
+ const lockSvc = lockService;
369
+ await tracer.startActiveSpan(
370
+ "acquiringInitialLock",
371
+ async (span) => {
372
+ try {
373
+ // If --force-takeover flag is set, immediately force takeover instead of acquiring
374
+ if (options.forceTakeover) {
375
+ logger.info(
376
+ "Force takeover requested, taking over lock...",
377
+ );
378
+ await lockSvc.forceTakeover();
379
+ logger.info(
380
+ "Lock acquired successfully via force takeover.",
381
+ );
382
+ } else {
383
+ await lockSvc.acquireLock();
384
+ }
385
+ } catch (error) {
386
+ // If we got a conflict error (409), inspect the lock for more information
387
+ if (error instanceof ConflictError) {
388
+ await handleLockConflict(error, lockSvc, span, logger);
389
+ return;
390
+ }
391
+
392
+ logger.error(
393
+ "Failed to acquire lock on application",
394
+ getErrorMeta(error),
395
+ );
396
+ span.setStatus({
397
+ code: SpanStatusCode.ERROR,
398
+ message: JSON.stringify(error),
399
+ });
400
+ passErrorToVSCode(
401
+ (error as { context?: { message: string } }).context
402
+ ?.message,
403
+ logger,
404
+ );
405
+ throw new Error(
406
+ `Failed to acquire lock on application: ${error}`,
407
+ );
408
+ } finally {
409
+ span.end();
410
+ }
411
+ },
412
+ );
413
+ }
417
414
 
418
- const isSynced = localContents.hash === serverHash;
415
+ const [localContents, serverHash, currentUser] =
416
+ await tracer.startActiveSpan("fetchInitInfo", async (span) => {
417
+ try {
418
+ const results = await Promise.all([
419
+ sdk.hashLocalDirectory(cwd),
420
+ getDraftOrLiveEditHash(sdk, applicationConfig, logger),
421
+ sdk.fetchCurrentUser(),
422
+ ]);
423
+ return results;
424
+ } finally {
425
+ span.end();
426
+ }
427
+ });
419
428
 
420
- if (isSynced) {
421
- logger.info(
422
- `Local files are in sync with the server on branch '${applicationConfig.branchName}', local hash: ${localContents.hash}, server hash: ${serverHash}`,
423
- );
424
- } else {
425
- logger.info(
426
- `Local files are out of sync with the server on branch '${applicationConfig.branchName}', local hash: ${localContents.hash}, server hash: ${serverHash}`,
427
- );
428
- }
429
+ aiService = new AiService({
430
+ superblocksBaseUrl: tokenConfig.superblocksBaseUrl,
431
+ appRootDirPath: options.cwd,
432
+ applicationId: applicationConfig.id,
433
+ organizationId: currentUser.organizations[0].id,
434
+ fsOperationQueue,
435
+ draftInterface: syncService as DraftInterface,
436
+ rpcClient,
437
+ tracer,
438
+ logger,
439
+ tokenManager,
440
+ features: AiServiceFeatureFlags.create(
441
+ currentUser.flagBootstrap as
442
+ | Record<string, unknown>
443
+ | undefined,
444
+ ),
445
+ pluginExecutionVersions:
446
+ currentUser.organizations[0].pluginExecutionVersions,
447
+ });
448
+
449
+ await tracer.startActiveSpan(
450
+ "aiServiceInitialize",
451
+ async (span) => {
452
+ try {
453
+ await aiService!.initialize();
454
+ } finally {
455
+ span.end();
456
+ }
457
+ },
458
+ );
429
459
 
430
- if (!(downloadFirst || uploadFirst)) {
431
- throw new Error(
432
- "You must choose --download-first or --upload-first to use the dev command",
433
- );
434
- }
435
- if (downloadFirst && uploadFirst) {
436
- throw new Error("Choose either --download-first or --upload-first");
437
- }
460
+ const isSynced = localContents.hash === serverHash;
438
461
 
439
- let hasPackageChanged = false;
462
+ if (isSynced) {
463
+ logger.info(
464
+ `Local files are in sync with the server on branch '${applicationConfig.branchName}', local hash: ${localContents.hash}, server hash: ${serverHash}`,
465
+ );
466
+ } else {
467
+ logger.info(
468
+ `Local files are out of sync with the server on branch '${applicationConfig.branchName}', local hash: ${localContents.hash}, server hash: ${serverHash}`,
469
+ );
470
+ }
440
471
 
441
- const packageJsonBefore = await readPkgJson(cwd);
472
+ if (!(downloadFirst || uploadFirst)) {
473
+ throw new Error(
474
+ "You must choose --download-first or --upload-first to use the dev command",
475
+ );
476
+ }
477
+ if (downloadFirst && uploadFirst) {
478
+ throw new Error(
479
+ "Choose either --download-first or --upload-first",
480
+ );
481
+ }
442
482
 
443
- if (downloadFirst && !isSynced) {
444
- await tracer.startActiveSpan("downloadFirst", async (span) => {
445
- logger.info(
446
- `Starting download of branch '${applicationConfig.branchName}'`,
447
- );
483
+ let hasPackageChanged = false;
448
484
 
449
- await syncService!.downloadDirectory();
450
- span.end();
451
- });
452
- }
485
+ const packageJsonBefore = await readPkgJson(cwd);
453
486
 
454
- let hasCliUpdated = false;
455
- let upgradePromises: Promise<void>[] = [];
456
- const forceUpgrade =
457
- options.autoUpgradeMode === DevServerAutoUpgradeMode.FORCE;
458
- // Determine whether we must try to auto-upgrade the CLI
459
- if (!skipAutoUpgrade || forceUpgrade) {
460
- await tracer.startActiveSpan(
461
- "versionCheckAndUpgrade",
462
- async (span) => {
463
- if (lockService) {
464
- const applicationConfigWithTokenConfigAndUserInfo: ApplicationConfigWithTokenConfigAndUserInfo =
465
- {
466
- ...applicationConfig,
467
- superblocksBaseUrl: tokenConfig.superblocksBaseUrl,
468
- token: tokenConfig.token,
469
- userId: currentUser.user.id,
470
- userEmail: currentUser.user.email,
471
- organizationId: currentUser.user.currentOrganizationId,
472
- featureFlags: sdk.getFeatureFlagsForUser(currentUser),
473
- };
474
-
475
- const result = await checkVersionsAndWritePackageJson(
476
- lockService,
477
- applicationConfigWithTokenConfigAndUserInfo,
478
- forceUpgrade,
487
+ if (downloadFirst && !isSynced) {
488
+ await tracer.startActiveSpan("downloadFirst", async (span) => {
489
+ logger.info(
490
+ `Starting download of branch '${applicationConfig.branchName}'`,
479
491
  );
480
- hasCliUpdated = result.cliUpdated;
481
- upgradePromises = result.upgradePromises;
482
- } else {
483
- logger.warn(
484
- "Lock service is not available, skipping version check and upgrade",
485
- );
486
- }
487
- span.end();
488
- },
489
- );
490
- }
491
492
 
492
- const packageJsonAfter = await readPkgJson(cwd);
493
+ await syncService!.downloadDirectory();
494
+ span.end();
495
+ });
496
+ }
493
497
 
494
- if (packageJsonBefore && packageJsonAfter) {
495
- hasPackageChanged =
496
- JSON.stringify(packageJsonBefore, null, 2) !==
497
- JSON.stringify(packageJsonAfter, null, 2);
498
- } else if (packageJsonAfter) {
499
- hasPackageChanged = true;
500
- logger.info("package.json was created, installing packages…");
501
- }
498
+ let hasCliUpdated = false;
499
+ let upgradePromises: Promise<void>[] = [];
500
+ const forceUpgrade =
501
+ options.autoUpgradeMode === DevServerAutoUpgradeMode.FORCE;
502
+ // Determine whether we must try to auto-upgrade the CLI
503
+ if (!skipAutoUpgrade || forceUpgrade) {
504
+ await tracer.startActiveSpan(
505
+ "versionCheckAndUpgrade",
506
+ async (span) => {
507
+ if (lockService) {
508
+ const applicationConfigWithTokenConfigAndUserInfo: ApplicationConfigWithTokenConfigAndUserInfo =
509
+ {
510
+ ...applicationConfig,
511
+ superblocksBaseUrl: tokenConfig.superblocksBaseUrl,
512
+ token: tokenConfig.token,
513
+ userId: currentUser.user.id,
514
+ userEmail: currentUser.user.email,
515
+ organizationId: currentUser.user.currentOrganizationId,
516
+ featureFlags: sdk.getFeatureFlagsForUser(currentUser),
517
+ };
518
+
519
+ const result = await checkVersionsAndWritePackageJson(
520
+ lockService,
521
+ applicationConfigWithTokenConfigAndUserInfo,
522
+ forceUpgrade,
523
+ );
524
+ hasCliUpdated = result.cliUpdated;
525
+ upgradePromises = result.upgradePromises;
526
+ } else {
527
+ logger.warn(
528
+ "Lock service is not available, skipping version check and upgrade",
529
+ );
530
+ }
531
+ span.end();
532
+ },
533
+ );
534
+ }
502
535
 
503
- if (hasPackageChanged || upgradePromises.length > 0) {
504
- logger.info("Installing packages…");
505
- await tracer.startActiveSpan("installPackages", async (span) => {
506
- // Upgrade global CLI and local packages in parallel - improves performance
507
- await Promise.all([
508
- ...upgradePromises,
509
- installPackages(cwd, logger),
510
- ]);
511
- span.end();
512
- });
513
- } else {
514
- logger.info(
515
- "package.json has not changed, skipping package installation",
516
- );
517
- }
536
+ const packageJsonAfter = await readPkgJson(cwd);
518
537
 
519
- if (hasPackageChanged || uploadFirst) {
520
- logger.info(
521
- `Uploading local files to branch '${applicationConfig.branchName}' on server before starting`,
522
- );
523
- await tracer.startActiveSpan(
524
- "uploadFirstOrPackageChanged",
525
- async (span) => {
526
- await syncService!.uploadDirectory("cli:sdk");
527
- await syncService!.uploadDirectoryNowIfNeeded("cli:sdk");
528
- span.end();
529
- },
530
- );
531
- }
538
+ if (packageJsonBefore && packageJsonAfter) {
539
+ hasPackageChanged =
540
+ JSON.stringify(packageJsonBefore, null, 2) !==
541
+ JSON.stringify(packageJsonAfter, null, 2);
542
+ } else if (packageJsonAfter) {
543
+ hasPackageChanged = true;
544
+ logger.info("package.json was created, installing packages…");
545
+ }
546
+
547
+ if (hasPackageChanged || upgradePromises.length > 0) {
548
+ logger.info("Installing packages…");
549
+ await tracer.startActiveSpan("installPackages", async (span) => {
550
+ try {
551
+ // Upgrade global CLI and local packages in parallel - improves performance
552
+ await Promise.all([
553
+ ...upgradePromises,
554
+ installPackages(cwd, logger),
555
+ ]);
556
+ } finally {
557
+ span.end();
558
+ }
559
+ });
560
+ } else {
561
+ logger.info(
562
+ "package.json has not changed, skipping package installation",
563
+ );
564
+ }
565
+
566
+ if (hasPackageChanged || uploadFirst) {
567
+ logger.info(
568
+ `Uploading local files to branch '${applicationConfig.branchName}' on server before starting`,
569
+ );
570
+ await tracer.startActiveSpan(
571
+ "uploadFirstOrPackageChanged",
572
+ async (span) => {
573
+ await syncService!.uploadDirectory("cli:sdk");
574
+ await syncService!.uploadDirectoryNowIfNeeded("cli:sdk");
575
+ span.end();
576
+ },
577
+ );
578
+ }
532
579
 
533
- if (hasCliUpdated) {
580
+ if (hasCliUpdated) {
581
+ try {
582
+ logger.info("Releasing lock before restarting the dev server");
583
+ await aiService?.removeIntegrationCache();
584
+ await lockService?.shutdown({ serverInitiated: false });
585
+ } catch (e) {
586
+ logger.error(
587
+ "Error releasing lock before restarting the dev server",
588
+ getErrorMeta(e),
589
+ );
590
+ }
591
+ logger.info("CLI was updated, restarting the dev server…");
592
+ process.exit(AUTO_UPGRADE_EXIT_CODE);
593
+ }
594
+ });
595
+ } catch (error: any) {
596
+ logger.error(error.message);
534
597
  try {
535
- logger.info("Releasing lock before restarting the dev server");
536
598
  await aiService?.removeIntegrationCache();
537
- await lockService?.shutdown({ serverInitiated: false });
538
- } catch (e) {
539
- logger.error(
540
- "Error releasing lock before restarting the dev server",
541
- getErrorMeta(e),
542
- );
599
+ await lockService?.shutdownAndExit();
600
+ } finally {
601
+ // this is redundant, but it's here to make sure the lock service is shutdown and the process exits
602
+ process.exit(1);
543
603
  }
544
- logger.info("CLI was updated, restarting the dev server…");
545
- process.exit(AUTO_UPGRADE_EXIT_CODE);
546
604
  }
547
- });
548
- } catch (error: any) {
549
- logger.error(error.message);
550
- try {
551
- await aiService?.removeIntegrationCache();
552
- await lockService?.shutdownAndExit();
553
- } finally {
554
- // this is redundant, but it's here to make sure the lock service is shutdown and the process exits
555
- process.exit(1);
605
+ } else {
606
+ logger.info("Skipping directory sync");
556
607
  }
557
- }
558
- } else {
559
- logger.info("Skipping directory sync");
560
- }
561
608
 
562
- const httpServer = await tracer.startActiveSpan(
563
- "createDevServer",
564
- async (span) => {
565
- const result = await createDevServer({
566
- root: options.cwd,
567
- mode: "development",
568
- port: port,
569
- fsOperationQueue,
570
- syncService: syncService,
571
- lockService: lockService,
572
- aiService: aiService,
573
- logger: options.logger,
574
- sdk,
575
- });
576
- span.end();
577
- return result;
578
- },
579
- );
609
+ const httpServer = await tracer.startActiveSpan(
610
+ "createDevServer",
611
+ async (span) => {
612
+ const result = await createDevServer({
613
+ root: options.cwd,
614
+ mode: "development",
615
+ port: port,
616
+ fsOperationQueue,
617
+ syncService: syncService,
618
+ lockService: lockService,
619
+ aiService: aiService,
620
+ logger: options.logger,
621
+ sdk,
622
+ });
623
+ span.end();
624
+ return result;
625
+ },
626
+ );
580
627
 
581
- options.signal?.addEventListener("abort", () => {
582
- logger.info("Server closed");
583
- httpServer.close();
584
- // Stop auth hot-reload server on abort
585
- if (authHotReloadServer) {
586
- authHotReloadServer.stop().catch((error: any) => {
587
- logger.warn(`Error stopping auth hot-reload server: ${error}`);
628
+ options.signal?.addEventListener("abort", () => {
629
+ logger.info("Server closed");
630
+ httpServer.close();
631
+ // Stop auth hot-reload server on abort
632
+ if (authHotReloadServer) {
633
+ authHotReloadServer.stop().catch((error: any) => {
634
+ logger.warn(`Error stopping auth hot-reload server: ${error}`);
635
+ });
636
+ }
637
+ // Clean up AI service cache (must happen before app switches directories)
638
+ aiService?.removeIntegrationCache().catch((error: any) => {
639
+ logger.warn(`Error removing integration cache: ${error}`);
640
+ });
641
+ lockService?.shutdownAndExit().catch(() => {
642
+ // this is redundant, but it's here to make sure the lock service is shutdown and the process exits
643
+ process.exit(1);
644
+ });
588
645
  });
646
+
647
+ logger.debug(green(`Local server started at port ${port}`));
648
+ logger.debug(green(`Visit your application at:`));
649
+ logger.debug(green(`http://localhost:${port}`));
650
+
651
+ startupSpan.end();
652
+ } catch (error) {
653
+ startupSpan.setStatus({ code: SpanStatusCode.ERROR });
654
+ startupSpan.end();
655
+ throw error;
589
656
  }
590
- // Clean up AI service cache (must happen before app switches directories)
591
- aiService?.removeIntegrationCache().catch((error: any) => {
592
- logger.warn(`Error removing integration cache: ${error}`);
593
- });
594
- lockService?.shutdownAndExit().catch(() => {
595
- // this is redundant, but it's here to make sure the lock service is shutdown and the process exits
596
- process.exit(1);
597
- });
598
657
  });
599
-
600
- logger.debug(green(`Local server started at port ${port}`));
601
- logger.debug(green(`Visit your application at:`));
602
- logger.debug(green(`http://localhost:${port}`));
603
658
  }
604
659
  async function getDraftOrLiveEditHash(
605
660
  sdk: SuperblocksSdk,