@superblocksteam/sdk 2.0.83-next.1 → 2.0.83

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 +6 -0
  3. package/dist/cli-replacement/automatic-upgrades.d.ts.map +1 -1
  4. package/dist/cli-replacement/automatic-upgrades.js +27 -5
  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 +217 -260
  8. package/dist/cli-replacement/dev.mjs.map +1 -1
  9. package/dist/dev-utils/dev-server.mjs +115 -133
  10. package/dist/dev-utils/dev-server.mjs.map +1 -1
  11. package/dist/telemetry/index.d.ts +4 -4
  12. package/dist/telemetry/index.d.ts.map +1 -1
  13. package/dist/telemetry/index.js +64 -92
  14. package/dist/telemetry/index.js.map +1 -1
  15. package/dist/telemetry/util.d.ts +2 -1
  16. package/dist/telemetry/util.d.ts.map +1 -1
  17. package/dist/telemetry/util.js +4 -26
  18. package/dist/telemetry/util.js.map +1 -1
  19. package/package.json +5 -6
  20. package/src/cli-replacement/automatic-upgrades.ts +42 -10
  21. package/src/cli-replacement/dev.mts +281 -336
  22. package/src/dev-utils/dev-server.mts +127 -149
  23. package/src/telemetry/index.ts +83 -105
  24. package/src/telemetry/util.ts +4 -27
  25. package/tsconfig.tsbuildinfo +1 -1
  26. package/turbo.json +2 -20
  27. package/dist/cli-replacement/version-detection.d.ts +0 -71
  28. package/dist/cli-replacement/version-detection.d.ts.map +0 -1
  29. package/dist/cli-replacement/version-detection.js +0 -186
  30. package/dist/cli-replacement/version-detection.js.map +0 -1
  31. package/dist/cli-replacement/version-detection.test.d.ts +0 -5
  32. package/dist/cli-replacement/version-detection.test.d.ts.map +0 -1
  33. package/dist/cli-replacement/version-detection.test.js +0 -257
  34. package/dist/cli-replacement/version-detection.test.js.map +0 -1
  35. package/dist/telemetry/index.test.d.ts +0 -2
  36. package/dist/telemetry/index.test.d.ts.map +0 -1
  37. package/dist/telemetry/index.test.js +0 -93
  38. package/dist/telemetry/index.test.js.map +0 -1
  39. package/dist/telemetry/local-obs.d.ts +0 -73
  40. package/dist/telemetry/local-obs.d.ts.map +0 -1
  41. package/dist/telemetry/local-obs.js +0 -107
  42. package/dist/telemetry/local-obs.js.map +0 -1
  43. package/src/cli-replacement/version-detection.test.ts +0 -336
  44. package/src/cli-replacement/version-detection.ts +0 -220
  45. package/src/telemetry/index.test.ts +0 -130
  46. package/src/telemetry/local-obs.ts +0 -138
@@ -23,8 +23,10 @@ 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 { checkVersionsAndWritePackageJson } from "./automatic-upgrades.js";
27
- import { getCurrentCliVersion } from "./version-detection.js";
26
+ import {
27
+ checkVersionsAndWritePackageJson,
28
+ getCurrentCliVersion,
29
+ } from "./automatic-upgrades.js";
28
30
  import type {
29
31
  AuthHotReloadServer,
30
32
  TokenManager,
@@ -282,379 +284,322 @@ export async function dev(options: {
282
284
  const logger = getLogger(options.logger);
283
285
  const skipAutoUpgrade = autoUpgradeMode === DevServerAutoUpgradeMode.SKIP;
284
286
 
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
- }
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
293
 
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
- );
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
+ );
307
298
 
308
- const port = devServerPort ?? 5173;
299
+ const port = devServerPort ?? 5173;
309
300
 
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
- );
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
+ );
310
+
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
+ });
319
330
 
320
- // Get feature flags for inactivity timeout
321
- const featureFlags = await tracer.startActiveSpan(
322
- "getFeatureFlags",
323
- async (span) => {
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
+ });
342
+
343
+ logger.info("Checking if local files are synced with the server");
344
+
345
+ try {
346
+ await maskUnixSignals(async () => {
347
+ if (lockService) {
348
+ const lockSvc = lockService;
349
+ await tracer.startActiveSpan("acquiringInitialLock", async (span) => {
324
350
  try {
325
- return await sdk.getFeatureFlagsForCurrentUser();
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
+ );
326
381
  } finally {
327
382
  span.end();
328
383
  }
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({
341
- superblocksBaseUrl: tokenConfig.superblocksBaseUrl,
342
- applicationId: applicationConfig.id,
343
- branchName: applicationConfig.branchName,
344
- lockType: lockType,
345
- tracer,
346
- logger,
347
- rpcClient,
348
- inactivityThresholdMs: inactivityTimeoutMs,
349
- });
384
+ });
385
+ }
350
386
 
351
- syncService = new SyncService({
352
- appRootDirPath: cwd,
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({
399
+ superblocksBaseUrl: tokenConfig.superblocksBaseUrl,
400
+ appRootDirPath: options.cwd,
353
401
  applicationId: applicationConfig.id,
354
- branchName: applicationConfig.branchName,
402
+ organizationId: currentUser.organizations[0].id,
355
403
  fsOperationQueue,
356
- lockService: lockService,
357
- tracer,
358
- superblocksBaseUrl: tokenConfig.superblocksBaseUrl,
404
+ draftInterface: syncService as DraftInterface,
359
405
  rpcClient,
406
+ tracer,
360
407
  logger,
408
+ tokenManager,
409
+ features: AiServiceFeatureFlags.create(
410
+ currentUser.flagBootstrap as Record<string, unknown> | undefined,
411
+ ),
412
+ pluginExecutionVersions:
413
+ currentUser.organizations[0].pluginExecutionVersions,
361
414
  });
362
415
 
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
- }
416
+ await aiService.initialize();
414
417
 
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
- });
418
+ const isSynced = localContents.hash === serverHash;
428
419
 
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
- );
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
+ }
459
429
 
460
- const isSynced = localContents.hash === serverHash;
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
+ }
461
438
 
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
- }
439
+ let hasPackageChanged = false;
471
440
 
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
- }
441
+ const packageJsonBefore = await readPkgJson(cwd);
482
442
 
483
- let hasPackageChanged = false;
443
+ if (downloadFirst && !isSynced) {
444
+ await tracer.startActiveSpan("downloadFirst", async (span) => {
445
+ logger.info(
446
+ `Starting download of branch '${applicationConfig.branchName}'`,
447
+ );
484
448
 
485
- const packageJsonBefore = await readPkgJson(cwd);
449
+ await syncService!.downloadDirectory();
450
+ span.end();
451
+ });
452
+ }
486
453
 
487
- if (downloadFirst && !isSynced) {
488
- await tracer.startActiveSpan("downloadFirst", async (span) => {
489
- logger.info(
490
- `Starting download of branch '${applicationConfig.branchName}'`,
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,
491
479
  );
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
+ }
492
491
 
493
- await syncService!.downloadDirectory();
494
- span.end();
495
- });
496
- }
497
-
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
- }
535
-
536
- const packageJsonAfter = await readPkgJson(cwd);
492
+ const packageJsonAfter = await readPkgJson(cwd);
537
493
 
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
- }
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
+ }
546
502
 
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
- }
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
+ }
565
518
 
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
- }
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
+ }
579
532
 
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);
533
+ if (hasCliUpdated) {
597
534
  try {
535
+ logger.info("Releasing lock before restarting the dev server");
598
536
  await aiService?.removeIntegrationCache();
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);
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
+ );
603
543
  }
544
+ logger.info("CLI was updated, restarting the dev server…");
545
+ process.exit(AUTO_UPGRADE_EXIT_CODE);
604
546
  }
605
- } else {
606
- logger.info("Skipping directory sync");
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);
607
556
  }
557
+ }
558
+ } else {
559
+ logger.info("Skipping directory sync");
560
+ }
608
561
 
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
- );
627
-
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
- });
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,
645
575
  });
576
+ span.end();
577
+ return result;
578
+ },
579
+ );
646
580
 
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;
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}`);
588
+ });
656
589
  }
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
+ });
657
598
  });
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}`));
658
603
  }
659
604
  async function getDraftOrLiveEditHash(
660
605
  sdk: SuperblocksSdk,