@superblocksteam/sdk 2.0.6-next.6 → 2.0.6-next.61

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 (41) hide show
  1. package/dist/application-build.mjs +6 -2
  2. package/dist/application-build.mjs.map +1 -1
  3. package/dist/cli-replacement/automatic-upgrades.d.ts +5 -2
  4. package/dist/cli-replacement/automatic-upgrades.d.ts.map +1 -1
  5. package/dist/cli-replacement/automatic-upgrades.js +199 -93
  6. package/dist/cli-replacement/automatic-upgrades.js.map +1 -1
  7. package/dist/cli-replacement/dev.d.mts +1 -2
  8. package/dist/cli-replacement/dev.d.mts.map +1 -1
  9. package/dist/cli-replacement/dev.mjs +53 -29
  10. package/dist/cli-replacement/dev.mjs.map +1 -1
  11. package/dist/dev-utils/dev-logger.d.mts +17 -7
  12. package/dist/dev-utils/dev-logger.d.mts.map +1 -1
  13. package/dist/dev-utils/dev-logger.mjs +50 -9
  14. package/dist/dev-utils/dev-logger.mjs.map +1 -1
  15. package/dist/dev-utils/dev-server.d.mts.map +1 -1
  16. package/dist/dev-utils/dev-server.mjs +8 -12
  17. package/dist/dev-utils/dev-server.mjs.map +1 -1
  18. package/dist/dev-utils/vite-plugin-build-manifest-stub.d.mts +10 -0
  19. package/dist/dev-utils/vite-plugin-build-manifest-stub.d.mts.map +1 -0
  20. package/dist/dev-utils/vite-plugin-build-manifest-stub.mjs +27 -0
  21. package/dist/dev-utils/vite-plugin-build-manifest-stub.mjs.map +1 -0
  22. package/dist/dev-utils/vite-plugin-sb-cdn.d.mts.map +1 -1
  23. package/dist/dev-utils/vite-plugin-sb-cdn.mjs +13 -3
  24. package/dist/dev-utils/vite-plugin-sb-cdn.mjs.map +1 -1
  25. package/dist/vite-plugin-generate-build-manifest.d.mts +21 -0
  26. package/dist/vite-plugin-generate-build-manifest.d.mts.map +1 -0
  27. package/dist/vite-plugin-generate-build-manifest.mjs +131 -0
  28. package/dist/vite-plugin-generate-build-manifest.mjs.map +1 -0
  29. package/dist/vite-plugin-inject-sb-ids-transform.mjs +1 -1
  30. package/dist/vite-plugin-inject-sb-ids-transform.mjs.map +1 -1
  31. package/package.json +6 -4
  32. package/src/application-build.mts +6 -3
  33. package/src/cli-replacement/automatic-upgrades.ts +253 -113
  34. package/src/cli-replacement/dev.mts +67 -42
  35. package/src/dev-utils/dev-logger.mts +94 -20
  36. package/src/dev-utils/dev-server.mts +10 -12
  37. package/src/dev-utils/vite-plugin-build-manifest-stub.mts +30 -0
  38. package/src/dev-utils/vite-plugin-sb-cdn.mts +14 -3
  39. package/src/vite-plugin-generate-build-manifest.mts +193 -0
  40. package/src/vite-plugin-inject-sb-ids-transform.mts +1 -1
  41. package/tsconfig.tsbuildinfo +1 -1
@@ -1,11 +1,13 @@
1
1
  import * as child_process from "node:child_process";
2
2
  import { promisify } from "node:util";
3
3
  import { isNativeError } from "node:util/types";
4
+ import { traceFunction } from "@superblocksteam/shared";
4
5
  import { resolveCommand, type DetectResult } from "package-manager-detector";
5
6
  import { detect } from "package-manager-detector/detect";
6
7
  import gt from "semver/functions/gt.js";
7
8
  import valid from "semver/functions/valid.js";
8
- import { getLogger } from "../dev-utils/dev-logger.mjs";
9
+ import { getErrorMeta, getLogger } from "../dev-utils/dev-logger.mjs";
10
+ import tracer from "../dev-utils/dev-tracer.js";
9
11
  import type { ResponseMeta } from "../socket/handlers.js";
10
12
  import type { ApplicationConfig } from "../types/common.js";
11
13
  import type { LockService } from "@superblocksteam/vite-plugin-file-sync/lock-service";
@@ -55,7 +57,7 @@ async function getRemoteVersions(
55
57
  return data.data;
56
58
  } else {
57
59
  const error = (await response.json()) as CheckVersionsErrorResponse;
58
- console.log(
60
+ logger.error(
59
61
  `Could not get latest CLI version: ${error.responseMeta.message}`,
60
62
  );
61
63
  }
@@ -68,7 +70,9 @@ async function getRemoteVersions(
68
70
  }
69
71
  }
70
72
 
71
- export async function getCurrentCliVersion(): Promise<string | undefined> {
73
+ export async function getCurrentCliVersion(): Promise<
74
+ PackageVersionInfo | undefined
75
+ > {
72
76
  try {
73
77
  const command = process.platform === "win32" ? "where" : "which";
74
78
  const { stdout } = await exec(`${command} superblocks`);
@@ -85,7 +89,16 @@ export async function getCurrentCliVersion(): Promise<string | undefined> {
85
89
  /@superblocksteam\/cli(-ephemeral)?\//,
86
90
  "",
87
91
  );
88
- return version;
92
+
93
+ const aliasMatch = json.cliVersion?.match(/@superblocksteam\/([^\/]+)/);
94
+ if (aliasMatch && aliasMatch[1] !== "cli") {
95
+ return {
96
+ version: version,
97
+ alias: `@superblocksteam/${aliasMatch[1]}`,
98
+ };
99
+ }
100
+
101
+ return { version };
89
102
  } catch (error) {
90
103
  if (isNativeError(error)) {
91
104
  logger.error(`Error getting CLI version: ${error.message}`);
@@ -104,16 +117,16 @@ export async function getCurrentLibraryVersion(
104
117
  case "pnpm":
105
118
  return await getPnpmLibraryVersion();
106
119
  default:
107
- console.error(
120
+ logger.error(
108
121
  `${pm.agent} is currently not supported for automatic upgrades.`,
109
122
  );
110
123
  return undefined;
111
124
  }
112
125
  } catch (error) {
113
- console.error(
126
+ logger.error(
114
127
  "Could not resolve current library version. Skipping automatic upgrade.",
128
+ getErrorMeta(error),
115
129
  );
116
- console.error(error);
117
130
  return undefined;
118
131
  }
119
132
  }
@@ -200,10 +213,10 @@ async function upgradeCliWithOclif(targetVersion: string): Promise<boolean> {
200
213
 
201
214
  if (!superblocksPath) return false;
202
215
 
203
- const { stdout: updateOutput } = await exec(
216
+ const { stdout: updateOutput, stderr: updateErrorOutput } = await exec(
204
217
  `${superblocksPath} update --version=${targetVersion}`,
205
218
  );
206
- return !updateOutput.includes("not updatable");
219
+ return !(updateOutput + updateErrorOutput).includes("not updatable");
207
220
  } catch (error) {
208
221
  if (isNativeError(error)) {
209
222
  logger.error(`Error checking CLI updatability: ${error.message}`);
@@ -216,21 +229,61 @@ async function upgradePackageWithPackageManager(
216
229
  pm: DetectResult,
217
230
  packageName: string,
218
231
  targetVersion: string,
219
- alias?: string,
232
+ {
233
+ alias,
234
+ global,
235
+ }: {
236
+ alias?: string;
237
+ global?: boolean;
238
+ },
220
239
  ): Promise<void> {
221
240
  const packageSpec = alias
222
241
  ? `@superblocksteam/${packageName}@npm:${alias}@${targetVersion}`
223
242
  : `@superblocksteam/${packageName}@${targetVersion}`;
224
243
 
225
- const installCommand = resolveCommand(pm.agent, "install", [packageSpec]);
244
+ const installCommand = resolveCommand(
245
+ pm.agent,
246
+ global ? "global" : "install",
247
+ [packageSpec],
248
+ );
226
249
 
227
250
  if (!installCommand) {
228
- console.error("Could not determine how to upgrade Superblocks packages.");
251
+ logger.error("Could not determine how to upgrade Superblocks packages.");
229
252
  return;
230
253
  }
231
254
 
232
255
  const { command, args } = installCommand;
233
- await exec(`${command} ${args.join(" ")}`);
256
+ logger.info(
257
+ `Running ${command} ${args.join(" ")} to upgrade ${packageName}...`,
258
+ );
259
+ let resolver: (value: void | PromiseLike<void>) => void;
260
+ let rejecter: (reason?: any) => void;
261
+ const promise = new Promise<void>((resolve, reject) => {
262
+ resolver = resolve;
263
+ rejecter = reject;
264
+ });
265
+ const cp = child_process.exec(
266
+ `${command} ${args.join(" ")}`,
267
+ {
268
+ cwd: process.cwd(),
269
+ },
270
+ (error) => {
271
+ if (error) {
272
+ logger.error(`Failed to upgrade ${packageName} to ${targetVersion}`);
273
+ rejecter(error);
274
+ } else {
275
+ logger.info(`Successfully upgraded ${packageName} to ${targetVersion}`);
276
+ resolver();
277
+ }
278
+ },
279
+ );
280
+ cp.stdout?.on("data", (data) => {
281
+ logger.info(data);
282
+ });
283
+ cp.stderr?.on("data", (data) => {
284
+ logger.warn(data);
285
+ });
286
+ return promise;
234
287
  }
235
288
 
236
289
  export async function getCurrentLibraryVersionWithoutPM(): Promise<
@@ -255,109 +308,196 @@ export async function getCurrentLibraryVersionWithoutPM(): Promise<
255
308
  export async function checkVersionsAndUpgrade(
256
309
  lockService: LockService,
257
310
  config?: ApplicationConfig,
258
- ) {
259
- // Detect package manager
260
- const pm = await detect({
261
- strategies: [
262
- "packageManager-field",
263
- "lockfile",
264
- "install-metadata",
265
- "devEngines-field",
266
- ],
267
- cwd: process.cwd(),
268
- });
269
-
270
- if (!pm || !config?.id) return;
271
-
272
- // Get current versions
273
- const currentCliVersion = await getCurrentCliVersion();
274
- const currentLibraryInfo = await getCurrentLibraryVersion(pm);
275
-
276
- // Skip if we're in local development
277
- if (
278
- !currentCliVersion ||
279
- !valid(currentCliVersion) ||
280
- currentCliVersion.startsWith("file:") ||
281
- currentCliVersion.startsWith("link:") ||
282
- !currentLibraryInfo ||
283
- !valid(currentLibraryInfo.version) ||
284
- currentLibraryInfo.version.startsWith("file:") ||
285
- currentLibraryInfo.version.startsWith("link:")
286
- ) {
287
- return;
288
- }
311
+ ): Promise<{
312
+ cliUpdated: boolean;
313
+ libraryUpdated: boolean;
314
+ }> {
315
+ const cliUpdated = false;
316
+ const libraryUpdated = false;
317
+ let hasFailedToUpgrade = false;
318
+
319
+ logger.info("Checking versions");
320
+
321
+ await traceFunction({
322
+ name: "checkVersionsAndUpgrade",
323
+ tracer,
324
+ fn: async () => {
325
+ // Detect package manager
326
+ const pm = await traceFunction({
327
+ name: "detectPackageManager",
328
+ tracer,
329
+ fn: async () => {
330
+ return await detect({
331
+ strategies: [
332
+ "packageManager-field",
333
+ "lockfile",
334
+ "install-metadata",
335
+ "devEngines-field",
336
+ ],
337
+ cwd: process.cwd(),
338
+ });
339
+ },
340
+ });
341
+
342
+ if (!pm || !config?.id) return;
343
+
344
+ // Get current versions
345
+ const currentCliInfo = await traceFunction({
346
+ name: "getCurrentCliVersion",
347
+ tracer,
348
+ fn: async () => {
349
+ return await getCurrentCliVersion();
350
+ },
351
+ });
352
+ const currentLibraryInfo = await traceFunction({
353
+ name: "getCurrentLibraryVersion",
354
+ tracer,
355
+ fn: async () => {
356
+ return await getCurrentLibraryVersion(pm);
357
+ },
358
+ });
359
+
360
+ // Skip if we're in local development
361
+ if (
362
+ !currentCliInfo ||
363
+ !valid(currentCliInfo.version) ||
364
+ currentCliInfo.version.startsWith("file:") ||
365
+ currentCliInfo.version.startsWith("link:") ||
366
+ !currentLibraryInfo ||
367
+ !valid(currentLibraryInfo.version) ||
368
+ currentLibraryInfo.version.startsWith("file:") ||
369
+ currentLibraryInfo.version.startsWith("link:")
370
+ ) {
371
+ return;
372
+ }
373
+
374
+ // Get target versions from server
375
+ const targetVersions = await traceFunction({
376
+ name: "getRemoteVersions",
377
+ tracer,
378
+ fn: async () => {
379
+ return await getRemoteVersions(config);
380
+ },
381
+ });
382
+ if (!targetVersions) return;
383
+
384
+ let cliNeedsUpgrade: boolean | string;
385
+ let libraryNeedsUpgrade: boolean | string;
386
+ try {
387
+ // If version is latest, then semver can throw an error
388
+ // Check if CLI needs upgrade
389
+ cliNeedsUpgrade =
390
+ targetVersions.cli && gt(targetVersions.cli, currentCliInfo.version);
391
+
392
+ // Check if library needs upgrade
393
+ libraryNeedsUpgrade =
394
+ targetVersions.library &&
395
+ gt(targetVersions.library, currentLibraryInfo.version);
396
+ } catch (error) {
397
+ logger.error(
398
+ "Error checking versions to upgrade, releasing lock and exiting",
399
+ getErrorMeta(error),
400
+ );
401
+ await traceFunction({
402
+ name: "shutdownLockService",
403
+ tracer,
404
+ fn: async () => {
405
+ await lockService.shutdown({
406
+ serverInitiated: false,
407
+ });
408
+ },
409
+ });
410
+ hasFailedToUpgrade = true;
411
+ return;
412
+ }
413
+
414
+ if (!cliNeedsUpgrade && !libraryNeedsUpgrade) {
415
+ return; // Everything is up to date
416
+ }
417
+
418
+ let cliUpdated = false;
419
+ let libraryUpdated = false;
420
+
421
+ // Upgrade CLI if needed
422
+ if (cliNeedsUpgrade) {
423
+ logger.info(
424
+ `Beginning CLI upgrade from ${currentCliInfo.version} to ${targetVersions.cli}`,
425
+ );
289
426
 
290
- // Get target versions from server
291
- const targetVersions = await getRemoteVersions(config);
292
- if (!targetVersions) return;
427
+ const oclifUpgradeSucceeded = await traceFunction({
428
+ name: "upgradeCliWithOclif",
429
+ tracer,
430
+ fn: async () => {
431
+ return await upgradeCliWithOclif(targetVersions.cli);
432
+ },
433
+ });
434
+ if (!oclifUpgradeSucceeded) {
435
+ logger.info(`Falling back to package manager upgrade for CLI`);
436
+ // Fall back to package manager upgrade
437
+ await traceFunction({
438
+ name: "upgradePackageWithPackageManager - cli",
439
+ tracer,
440
+ fn: async () => {
441
+ await upgradePackageWithPackageManager(
442
+ pm,
443
+ "cli",
444
+ targetVersions.cli,
445
+ {
446
+ alias: currentCliInfo.alias,
447
+ global: true,
448
+ },
449
+ );
450
+ },
451
+ });
452
+ cliUpdated = true;
453
+ }
454
+ }
455
+
456
+ // Upgrade library if needed
457
+ if (libraryNeedsUpgrade) {
458
+ logger.info(
459
+ `Beginning library upgrade from ${currentLibraryInfo.version} to ${targetVersions.library}`,
460
+ );
461
+ await traceFunction({
462
+ name: "upgradePackageWithPackageManager - library",
463
+ tracer,
464
+ fn: async () => {
465
+ await upgradePackageWithPackageManager(
466
+ pm,
467
+ "library",
468
+ targetVersions.library,
469
+ {
470
+ alias: currentLibraryInfo.alias,
471
+ global: false,
472
+ },
473
+ );
474
+ },
475
+ });
476
+ libraryUpdated = true;
477
+ }
478
+
479
+ // Log what was updated
480
+ if (cliUpdated && libraryUpdated) {
481
+ logger.info(
482
+ "@superblocksteam/cli and @superblocksteam/library have been updated.",
483
+ );
484
+ } else if (cliUpdated) {
485
+ logger.info("@superblocksteam/cli has been updated.");
486
+ } else if (libraryUpdated) {
487
+ logger.info("@superblocksteam/library has been updated.");
488
+ } else {
489
+ logger.info("No upgrades needed");
490
+ }
491
+ },
492
+ });
293
493
 
294
- let cliNeedsUpgrade: boolean | string;
295
- let libraryNeedsUpgrade: boolean | string;
296
- try {
297
- // If version is latest, then semver can throw an error
298
- // Check if CLI needs upgrade
299
- cliNeedsUpgrade =
300
- targetVersions.cli && gt(targetVersions.cli, currentCliVersion);
301
-
302
- // Check if library needs upgrade
303
- libraryNeedsUpgrade =
304
- targetVersions.library &&
305
- gt(targetVersions.library, currentLibraryInfo.version);
306
- } catch (error) {
307
- console.warn(
308
- "Error checking versions to upgrade, releasing lock and exiting",
309
- error,
310
- );
311
- await lockService.shutdown({
312
- serverInitiated: false,
313
- });
494
+ // Restart CLI if anything was updated
495
+ if (hasFailedToUpgrade) {
314
496
  process.exit(1);
315
497
  }
316
498
 
317
- if (!cliNeedsUpgrade && !libraryNeedsUpgrade) {
318
- return; // Everything is up to date
319
- }
320
-
321
- let cliUpdated = false;
322
- let libraryUpdated = false;
323
-
324
- // Upgrade CLI if needed
325
- if (cliNeedsUpgrade) {
326
- const oclifUpgradeSucceeded = await upgradeCliWithOclif(targetVersions.cli);
327
-
328
- if (!oclifUpgradeSucceeded) {
329
- // Fall back to package manager upgrade
330
- await upgradePackageWithPackageManager(pm, "cli", targetVersions.cli);
331
- cliUpdated = true;
332
- }
333
- }
334
-
335
- // Upgrade library if needed
336
- if (libraryNeedsUpgrade) {
337
- await upgradePackageWithPackageManager(
338
- pm,
339
- "library",
340
- targetVersions.library,
341
- currentLibraryInfo.alias,
342
- );
343
- libraryUpdated = true;
344
- }
345
-
346
- // Log what was updated
347
- if (cliUpdated && libraryUpdated) {
348
- logger.info(
349
- "@superblocksteam/cli and @superblocksteam/library have been updated.",
350
- );
351
- } else if (cliUpdated) {
352
- logger.info("@superblocksteam/cli has been updated.");
353
- } else if (libraryUpdated) {
354
- logger.info("@superblocksteam/library has been updated.");
355
- }
356
-
357
- // Restart CLI if anything was updated
358
- if (cliUpdated || libraryUpdated) {
359
- logger.info("Restarting the CLI…");
360
- await lockService.releaseLock();
361
- process.exit(AUTO_UPGRADE_EXIT_CODE);
362
- }
499
+ return {
500
+ cliUpdated,
501
+ libraryUpdated,
502
+ };
363
503
  }
@@ -1,7 +1,6 @@
1
1
  import "../dev-utils/dev-tracer.js";
2
2
 
3
3
  import * as child_process from "node:child_process";
4
- import * as fsp from "node:fs/promises";
5
4
  import path from "node:path";
6
5
  import { promisify } from "node:util";
7
6
  import { maskUnixSignals } from "@superblocksteam/util";
@@ -18,7 +17,7 @@ import fs from "fs-extra";
18
17
  import { resolveCommand } from "package-manager-detector";
19
18
  import { detect } from "package-manager-detector/detect";
20
19
 
21
- import { getLogger } from "../dev-utils/dev-logger.mjs";
20
+ import { getErrorMeta, getLogger } from "../dev-utils/dev-logger.mjs";
22
21
  import { createDevServer } from "../dev-utils/dev-server.mjs";
23
22
  import tracer from "../dev-utils/dev-tracer.js";
24
23
  import { SuperblocksSdk } from "../sdk.js";
@@ -27,6 +26,7 @@ import {
27
26
  getCurrentCliVersion,
28
27
  getCurrentLibraryVersionWithoutPM,
29
28
  } from "./automatic-upgrades.js";
29
+ import { AUTO_UPGRADE_EXIT_CODE } from "./automatic-upgrades.js";
30
30
  import type { DevLogger } from "../dev-utils/dev-logger.mjs";
31
31
  import type { ApplicationConfig } from "../types/common.js";
32
32
  import type { DraftInterface } from "@superblocksteam/vite-plugin-file-sync/draft-interface";
@@ -93,7 +93,6 @@ async function installPackages(cwd: string, logger: DevLogger) {
93
93
  export async function dev(options: {
94
94
  /* cwd is required */
95
95
  cwd: string;
96
- pidfilePath?: string;
97
96
  devServerPort?: number;
98
97
 
99
98
  /* user control of sync operations */
@@ -107,7 +106,7 @@ export async function dev(options: {
107
106
  /* For debugging purposes to get location of the cli */
108
107
  superblocksPath?: string;
109
108
  /* For redirecting output, like when running outside of the CLI */
110
- logger?: (message: string) => void;
109
+ logger?: (...messages: (string | Error)[]) => void;
111
110
 
112
111
  /* For a child process when restarting the dev server for automatic upgrades */
113
112
  skipAutoUpgrade?: boolean;
@@ -119,7 +118,6 @@ export async function dev(options: {
119
118
 
120
119
  const {
121
120
  cwd,
122
- pidfilePath,
123
121
  devServerPort,
124
122
  downloadFirst,
125
123
  uploadFirst,
@@ -128,12 +126,6 @@ export async function dev(options: {
128
126
  skipAutoUpgrade,
129
127
  } = options;
130
128
 
131
- const cliVersion = await getCurrentCliVersion();
132
- const libraryVersion = await getCurrentLibraryVersionWithoutPM();
133
- logger.info(
134
- `Running command: ${options.superblocksPath} dev${options.uploadFirst ? " --upload-first" : ""}${options.downloadFirst ? " --download-first" : ""} with baseUrl: ${applicationConfig?.superblocksBaseUrl}, cliVersion: ${cliVersion}, libraryVersion: ${libraryVersion?.alias} ${libraryVersion?.version}`,
135
- );
136
-
137
129
  // Add check for node_modules
138
130
  if (!fs.existsSync(path.join(cwd, "node_modules"))) {
139
131
  throw new Error(
@@ -141,9 +133,13 @@ export async function dev(options: {
141
133
  );
142
134
  }
143
135
 
144
- if (pidfilePath) {
145
- await fsp.writeFile(pidfilePath, `${process.pid}\n`);
146
- }
136
+ logger.info("Starting dev server");
137
+
138
+ const cliVersion = await getCurrentCliVersion();
139
+ const libraryVersion = await getCurrentLibraryVersionWithoutPM();
140
+ logger.info(
141
+ `Running command: ${options.superblocksPath} dev${options.uploadFirst ? " --upload-first" : ""}${options.downloadFirst ? " --download-first" : ""} with baseUrl: ${applicationConfig?.superblocksBaseUrl}, cliVersion: ${cliVersion}, libraryVersion: ${libraryVersion?.alias} ${libraryVersion?.version}`,
142
+ );
147
143
 
148
144
  const port = devServerPort ?? 5173;
149
145
 
@@ -188,17 +184,11 @@ export async function dev(options: {
188
184
  if (lockService) {
189
185
  try {
190
186
  await lockService!.acquireLock();
191
-
192
- // TODO(code-mode): package naming is preventing upgrade in ephemeral environments
193
- if (
194
- !process.env.PACKAGE_SUFFIX ||
195
- process.env.PACKAGE_SUFFIX === "" ||
196
- !skipAutoUpgrade
197
- ) {
198
- await checkVersionsAndUpgrade(lockService, applicationConfig);
199
- }
200
187
  } catch (error) {
201
- logger.error("Failed to acquire lock on application", error);
188
+ logger.error(
189
+ "Failed to acquire lock on application",
190
+ getErrorMeta(error),
191
+ );
202
192
  passErrorToVSCode(
203
193
  (error as { context?: { message: string } }).context?.message,
204
194
  logger,
@@ -222,7 +212,6 @@ export async function dev(options: {
222
212
  appRootDirPath: options.cwd,
223
213
  applicationId: applicationConfig.id,
224
214
  organizationId: currentUser.organizations[0].id,
225
- anthropicApiKey: process.env.ANTHROPIC_API_KEY || "",
226
215
  fsOperationQueue,
227
216
  draftInterface: syncService! as DraftInterface,
228
217
  tracer,
@@ -232,11 +221,10 @@ export async function dev(options: {
232
221
 
233
222
  if (isSynced) {
234
223
  logger.info("Local files are in sync with the server");
235
- return;
224
+ } else {
225
+ logger.info("Local files are out of sync with the server");
236
226
  }
237
227
 
238
- logger.info("Local files are out of sync with the server");
239
-
240
228
  if (!(downloadFirst || uploadFirst)) {
241
229
  throw new Error(
242
230
  "You must choose --download-first or --upload-first to use the dev command",
@@ -246,37 +234,70 @@ export async function dev(options: {
246
234
  throw new Error("Choose either --download-first or --upload-first");
247
235
  }
248
236
 
237
+ let hasPackageChanged = false;
238
+
249
239
  if (downloadFirst) {
250
- logger.info(
251
- "Starting directory sync from server before starting the local server",
252
- );
240
+ logger.info("Starting download");
253
241
 
254
- // Read package.json before download
255
242
  const packageJsonBefore = await readPkgJson(cwd);
256
-
257
243
  await syncService!.downloadDirectory();
258
-
259
- // Read package.json after download and compare
260
244
  const packageJsonAfter = await readPkgJson(cwd);
261
245
 
262
- // Check if package.json changed
263
246
  if (packageJsonBefore && packageJsonAfter) {
264
247
  const diff = diffJson(packageJsonBefore, packageJsonAfter);
265
- const hasChanges = diff.some((part) => part.added || part.removed);
248
+ hasPackageChanged = diff.some((part) => part.added || part.removed);
249
+ } else if (packageJsonAfter) {
250
+ hasPackageChanged = true;
251
+ logger.info("package.json was created, installing packages…");
252
+ }
253
+ }
266
254
 
267
- if (hasChanges) {
268
- logger.info("package.json has changed, installing packages…");
269
- await installPackages(cwd, logger);
255
+ let hasCliUpdated = false;
256
+ if (
257
+ !process.env.PACKAGE_SUFFIX ||
258
+ process.env.PACKAGE_SUFFIX === "" ||
259
+ !skipAutoUpgrade
260
+ ) {
261
+ if (lockService) {
262
+ const result = await checkVersionsAndUpgrade(
263
+ lockService,
264
+ applicationConfig,
265
+ );
266
+ if (result?.libraryUpdated) {
267
+ hasPackageChanged = true;
270
268
  }
269
+ hasCliUpdated = result?.cliUpdated ?? false;
270
+ } else {
271
+ logger.warn(
272
+ "Lock service is not available, skipping version check and upgrade",
273
+ );
271
274
  }
272
- } else if (uploadFirst) {
275
+ }
276
+
277
+ if (hasPackageChanged) {
278
+ logger.info("Installing packages…");
279
+ await installPackages(cwd, logger);
280
+ }
281
+
282
+ if (hasPackageChanged || uploadFirst) {
273
283
  logger.info("Uploading local files to server before starting");
274
284
  await syncService!.uploadDirectory();
285
+ await syncService!.uploadDirectoryNowIfNeeded();
286
+ }
287
+
288
+ if (hasCliUpdated) {
289
+ logger.info("CLI was updated, restarting the dev server…");
290
+ process.exit(AUTO_UPGRADE_EXIT_CODE);
275
291
  }
276
292
  });
277
293
  } catch (error: any) {
278
294
  logger.error(error.message);
279
- process.exit(1);
295
+ try {
296
+ await lockService?.shutdownAndExit();
297
+ } finally {
298
+ // this is redundant, but it's here to make sure the lock service is shutdown and the process exits
299
+ process.exit(1);
300
+ }
280
301
  }
281
302
  } else {
282
303
  logger.info("Skipping directory sync");
@@ -296,6 +317,10 @@ export async function dev(options: {
296
317
  options.signal?.addEventListener("abort", () => {
297
318
  logger.info("Server closed");
298
319
  httpServer.close();
320
+ lockService?.shutdownAndExit().catch(() => {
321
+ // this is redundant, but it's here to make sure the lock service is shutdown and the process exits
322
+ process.exit(1);
323
+ });
299
324
  });
300
325
 
301
326
  logger.debug(green(`Local server started at port ${port}`));