@superblocksteam/sdk 2.0.3-next.162 → 2.0.3-next.163

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.
@@ -1,7 +1,6 @@
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 { isEqual, pickBy } from "lodash-es";
5
4
  import { resolveCommand, type DetectResult } from "package-manager-detector";
6
5
  import { detect } from "package-manager-detector/detect";
7
6
  import gt from "semver/functions/gt.js";
@@ -18,6 +17,11 @@ interface Versions {
18
17
  [pkg: string]: string;
19
18
  }
20
19
 
20
+ interface PackageVersionInfo {
21
+ version: string;
22
+ alias?: string;
23
+ }
24
+
21
25
  interface CheckVersionsErrorResponse {
22
26
  responseMeta: ResponseMeta;
23
27
  }
@@ -27,7 +31,7 @@ interface CheckVersionsSuccessResponse {
27
31
  responseMeta: ResponseMeta;
28
32
  }
29
33
 
30
- async function getRemoteCliLibraryVersions(
34
+ async function getRemoteVersions(
31
35
  config: ApplicationConfig,
32
36
  ): Promise<Versions | undefined> {
33
37
  const { token, superblocksBaseUrl, id } = config;
@@ -40,9 +44,7 @@ async function getRemoteCliLibraryVersions(
40
44
  ),
41
45
  {
42
46
  method: "GET",
43
- headers: {
44
- Authorization: `Bearer ${token}`,
45
- },
47
+ headers: { Authorization: `Bearer ${token}` },
46
48
  },
47
49
  );
48
50
 
@@ -64,57 +66,18 @@ async function getRemoteCliLibraryVersions(
64
66
  }
65
67
  }
66
68
 
67
- async function installPackageVersions(pm: DetectResult, versions: Versions) {
68
- const installCommand = resolveCommand(
69
- pm.agent,
70
- "install",
71
- Object.entries(versions).map(
72
- ([pkg, version]) => `@superblocksteam/${pkg}@${version}`,
73
- ),
74
- );
75
-
76
- if (!installCommand) {
77
- console.error(
78
- "We could not determine how to upgrade your Superblocks packages.",
79
- );
80
- return;
81
- }
82
-
83
- const { command, args } = installCommand;
84
-
85
- // upgrade packages
86
- return await exec(`${command} ${args.join(" ")}`);
87
- }
88
-
89
- async function findSuperblocksExecutable(): Promise<string | undefined> {
69
+ async function getCurrentCliVersion(): Promise<string | undefined> {
90
70
  try {
91
- // Use cross-platform approach to find superblocks executable
92
71
  const command = process.platform === "win32" ? "where" : "which";
93
72
  const { stdout } = await exec(`${command} superblocks`);
94
- return stdout.trim();
95
- } catch {
96
- return undefined;
97
- }
98
- }
73
+ const superblocksPath = stdout.trim();
99
74
 
100
- async function getLocalCliLibraryVersions(
101
- pm: DetectResult,
102
- ): Promise<Partial<Versions>> {
103
- return {
104
- cli: await getLocalCliVersion(),
105
- library: await getLocalPackageVersion(pm, "library"),
106
- };
107
- }
75
+ if (!superblocksPath) return undefined;
108
76
 
109
- async function getLocalCliVersion(): Promise<string | undefined> {
110
- try {
111
- const superblocksPath = await findSuperblocksExecutable();
112
- if (!superblocksPath) {
113
- return undefined;
114
- }
115
-
116
- const { stdout } = await exec(`${superblocksPath} version --json`);
117
- const json = JSON.parse(stdout) as Record<string, string>;
77
+ const { stdout: versionOutput } = await exec(
78
+ `${superblocksPath} version --json`,
79
+ );
80
+ const json = JSON.parse(versionOutput) as Record<string, string>;
118
81
  // Extract version from string like "@superblocksteam/cli/2.0.0-next.1" or "@superblocksteam/cli-ephemeral/2.0.0-SNAPSHOT.1749077365"
119
82
  return json.cliVersion?.replace(/@superblocksteam\/cli(-ephemeral)?\//, "");
120
83
  } catch (error) {
@@ -125,99 +88,153 @@ async function getLocalCliVersion(): Promise<string | undefined> {
125
88
  }
126
89
  }
127
90
 
128
- async function getLocalPackageVersion(
91
+ async function getCurrentLibraryVersion(
129
92
  pm: DetectResult,
130
- pkg: string,
131
- global?: boolean,
132
- ) {
93
+ ): Promise<PackageVersionInfo | undefined> {
133
94
  try {
134
- // Configure commands and parsing logic based on package manager type
135
95
  switch (pm.agent) {
136
- case "npm": {
137
- const { stdout } = await exec(
138
- `npm list ${global ? "--global" : ""} @superblocksteam/${pkg} --json`,
139
- {
140
- cwd: process.cwd(),
141
- },
142
- );
143
- const parsed = JSON.parse(stdout);
144
- return (
145
- parsed.dependencies?.[`@superblocksteam/${pkg}`]?.version ??
146
- parsed.devDependencies?.[`@superblocksteam/${pkg}`]?.version
147
- );
148
- }
149
- case "pnpm": {
150
- const { stdout } = await exec(
151
- `pnpm list ${global ? "--global" : ""} @superblocksteam/${pkg} --json`,
152
- { cwd: process.cwd() },
153
- );
154
- const parsed = JSON.parse(stdout);
155
- // Check the structure based on actual output
156
- return (
157
- parsed[0]?.dependencies?.[`@superblocksteam/${pkg}`]?.version ??
158
- parsed[0]?.devDependencies?.[`@superblocksteam/${pkg}`]?.version
159
- );
160
- }
96
+ case "npm":
97
+ return await getNpmLibraryVersion();
98
+ case "pnpm":
99
+ return await getPnpmLibraryVersion();
161
100
  default:
162
101
  console.error(
163
- `${pm.agent} is currently not supported. Your application will not be upgraded automatically.`,
102
+ `${pm.agent} is currently not supported for automatic upgrades.`,
164
103
  );
165
- return;
104
+ return undefined;
166
105
  }
167
- } catch (e) {
106
+ } catch (error) {
168
107
  console.error(
169
- "We couldn't resolve your current Superblocks package versions. Your application will not be upgraded automatically.",
108
+ "Could not resolve current library version. Skipping automatic upgrade.",
170
109
  );
171
- console.error(e);
172
- return;
110
+ console.error(error);
111
+ return undefined;
173
112
  }
174
113
  }
175
114
 
176
- /**
177
- * Check if the CLI is updatable via the oclif update command
178
- * This indicates it was installed through a prebuilt installer (and updates the CLI)
179
- */
180
- async function tryCliUpdateCommand(version: string): Promise<boolean> {
115
+ async function getNpmLibraryVersion(): Promise<PackageVersionInfo | undefined> {
116
+ const { stdout } = await exec("npm list @superblocksteam/library --json", {
117
+ cwd: process.cwd(),
118
+ });
119
+ const parsed = JSON.parse(stdout);
120
+ const packageData =
121
+ parsed.dependencies?.["@superblocksteam/library"] ??
122
+ parsed.devDependencies?.["@superblocksteam/library"];
123
+
124
+ if (!packageData?.version) return undefined;
125
+
126
+ // Check if this is an alias by examining the resolved URL
127
+ const resolved = packageData.resolved;
128
+ if (resolved && resolved.includes("@superblocksteam/")) {
129
+ const aliasMatch = resolved.match(/@superblocksteam\/([^\/]+)/);
130
+ if (aliasMatch && aliasMatch[1] !== "library") {
131
+ return {
132
+ version: packageData.version,
133
+ alias: `@superblocksteam/${aliasMatch[1]}`,
134
+ };
135
+ }
136
+ }
137
+
138
+ return { version: packageData.version };
139
+ }
140
+
141
+ async function getPnpmLibraryVersion(): Promise<
142
+ { version: string; alias?: string } | undefined
143
+ > {
144
+ // First try the original package name
145
+ let packageData: any;
146
+
181
147
  try {
182
- const superblocksPath = await findSuperblocksExecutable();
183
- if (!superblocksPath) {
184
- return false;
148
+ const result = await exec("pnpm list @superblocksteam/library --json", {
149
+ cwd: process.cwd(),
150
+ });
151
+ const parsed = JSON.parse(result.stdout);
152
+ packageData =
153
+ parsed[0]?.dependencies?.["@superblocksteam/library"] ??
154
+ parsed[0]?.devDependencies?.["@superblocksteam/library"];
155
+ } catch {
156
+ // Package not found with original name, might be aliased
157
+ }
158
+
159
+ // If not found, try the ephemeral alias
160
+ if (!packageData?.version) {
161
+ try {
162
+ const aliasResult = await exec(
163
+ "pnpm list @superblocksteam/library-ephemeral --json",
164
+ { cwd: process.cwd() },
165
+ );
166
+ const aliasParsed = JSON.parse(aliasResult.stdout);
167
+ packageData =
168
+ aliasParsed[0]?.dependencies?.["@superblocksteam/library"] ??
169
+ aliasParsed[0]?.devDependencies?.["@superblocksteam/library"];
170
+ } catch {
171
+ return undefined;
185
172
  }
173
+ }
186
174
 
187
- // Check if the CLI is installed in a way that allows direct updates
188
- // We'll try running the update command with --version to see if it shows an updatable message
189
- const { stdout } = await exec(
190
- `${superblocksPath} update --version=${version}`,
191
- );
175
+ if (!packageData?.version) return undefined;
192
176
 
193
- // If it mentions "not updatable" in either stdout or stderr, it's not a prebuilt installer
194
- return !stdout.includes("not updatable");
177
+ // Check if this is an alias by looking at the 'from' field
178
+ const from = packageData.from;
179
+ if (from && from !== "@superblocksteam/library") {
180
+ return {
181
+ version: packageData.version,
182
+ alias: from,
183
+ };
184
+ }
185
+
186
+ return { version: packageData.version };
187
+ }
188
+
189
+ async function upgradeCliWithOclif(targetVersion: string): Promise<boolean> {
190
+ try {
191
+ const command = process.platform === "win32" ? "where" : "which";
192
+ const { stdout } = await exec(`${command} superblocks`);
193
+ const superblocksPath = stdout.trim();
194
+
195
+ if (!superblocksPath) return false;
196
+
197
+ const { stdout: updateOutput } = await exec(
198
+ `${superblocksPath} update --version=${targetVersion}`,
199
+ );
200
+ return !updateOutput.includes("not updatable");
195
201
  } catch (error) {
196
202
  if (isNativeError(error)) {
197
- logger.error(`Error checking updatability: ${error.message}`);
203
+ logger.error(`Error checking CLI updatability: ${error.message}`);
198
204
  }
199
205
  return false;
200
206
  }
201
207
  }
202
208
 
203
- /**
204
- * Restart the CLI
205
- */
209
+ async function upgradePackageWithPackageManager(
210
+ pm: DetectResult,
211
+ packageName: string,
212
+ targetVersion: string,
213
+ alias?: string,
214
+ ): Promise<void> {
215
+ const packageSpec = alias
216
+ ? `@superblocksteam/${packageName}@npm:${alias}@${targetVersion}`
217
+ : `@superblocksteam/${packageName}@${targetVersion}`;
218
+
219
+ const installCommand = resolveCommand(pm.agent, "install", [packageSpec]);
220
+
221
+ if (!installCommand) {
222
+ console.error("Could not determine how to upgrade Superblocks packages.");
223
+ return;
224
+ }
225
+
226
+ const { command, args } = installCommand;
227
+ await exec(`${command} ${args.join(" ")}`);
228
+ }
229
+
206
230
  async function restartCli() {
207
- // Get the args that were used to start the current process
208
231
  const args = process.argv.slice(1);
209
-
210
- // Create a new process with the same arguments
211
232
  const child = child_process.spawn(process.execPath, [...args], {
212
233
  detached: true,
213
234
  stdio: "inherit",
214
235
  env: process.env,
215
236
  });
216
-
217
- // Disconnect the child from the parent
218
237
  child.unref();
219
-
220
- // Exit the current process after the next tick to ensure any logs were written to stdout
221
238
  process.nextTick(() => process.exit(0));
222
239
  }
223
240
 
@@ -225,6 +242,7 @@ export async function checkVersionsAndUpgrade(
225
242
  lockService: LockService,
226
243
  config?: ApplicationConfig,
227
244
  ) {
245
+ // Detect package manager
228
246
  const pm = await detect({
229
247
  strategies: [
230
248
  "packageManager-field",
@@ -235,70 +253,69 @@ export async function checkVersionsAndUpgrade(
235
253
  cwd: process.cwd(),
236
254
  });
237
255
 
238
- if (!pm) return;
239
- if (!config?.id) return;
256
+ if (!pm || !config?.id) return;
240
257
 
241
- const localVersions = await getLocalCliLibraryVersions(pm);
258
+ // Get current versions
259
+ const currentCliVersion = await getCurrentCliVersion();
260
+ const currentLibraryInfo = await getCurrentLibraryVersion(pm);
242
261
 
262
+ // Skip if we're in local development
243
263
  if (
244
- // don't attempt upgrades in local development
245
- Object.values(localVersions).some(
246
- (x) => !x || !valid(x) || x.startsWith("file:") || x.startsWith("link:"),
247
- )
264
+ !currentCliVersion ||
265
+ !valid(currentCliVersion) ||
266
+ currentCliVersion.startsWith("file:") ||
267
+ currentCliVersion.startsWith("link:") ||
268
+ !currentLibraryInfo ||
269
+ !valid(currentLibraryInfo.version) ||
270
+ currentLibraryInfo.version.startsWith("file:") ||
271
+ currentLibraryInfo.version.startsWith("link:")
248
272
  ) {
249
273
  return;
250
274
  }
251
275
 
252
- const serverVersions = await getRemoteCliLibraryVersions(config);
276
+ // Get target versions from server
277
+ const targetVersions = await getRemoteVersions(config);
278
+ if (!targetVersions) return;
253
279
 
254
- // don't attempt upgrades if
255
- if (
256
- // server versions could not be fetched, or
257
- !serverVersions ||
258
- // we have a different # of libraries in server/local
259
- Object.keys(localVersions).length !== Object.keys(serverVersions).length
260
- ) {
261
- return;
262
- }
263
-
264
- const isUpToDate = isEqual(localVersions, serverVersions);
265
-
266
- if (isUpToDate) return;
280
+ // Check if CLI needs upgrade
281
+ const cliNeedsUpgrade =
282
+ targetVersions.cli && gt(targetVersions.cli, currentCliVersion);
267
283
 
268
- // Determine which packages need to be updated
269
- const packagesToUpdate = pickBy(localVersions, (_, key) => {
270
- try {
271
- return gt(serverVersions[key], (localVersions as Versions)[key]);
272
- } catch {
273
- return false;
274
- }
275
- }) as Versions;
284
+ // Check if library needs upgrade
285
+ const libraryNeedsUpgrade =
286
+ targetVersions.library &&
287
+ gt(targetVersions.library, currentLibraryInfo.version);
276
288
 
277
- if (Object.keys(packagesToUpdate).length === 0) {
278
- return;
289
+ if (!cliNeedsUpgrade && !libraryNeedsUpgrade) {
290
+ return; // Everything is up to date
279
291
  }
280
292
 
281
293
  let cliUpdated = false;
282
294
  let libraryUpdated = false;
283
295
 
284
- // Handle CLI update separately if it needs updating
285
- if (packagesToUpdate.cli) {
286
- // Try to update using Oclif's builtin update command
287
- const isUpdated = await tryCliUpdateCommand(serverVersions.cli);
296
+ // Upgrade CLI if needed
297
+ if (cliNeedsUpgrade) {
298
+ const oclifUpgradeSucceeded = await upgradeCliWithOclif(targetVersions.cli);
288
299
 
289
- if (!isUpdated) {
290
- // try to update using package manager (npm/pnpm/yarn)
291
- await installPackageVersions(pm, { cli: serverVersions.cli });
300
+ if (!oclifUpgradeSucceeded) {
301
+ // Fall back to package manager upgrade
302
+ await upgradePackageWithPackageManager(pm, "cli", targetVersions.cli);
292
303
  cliUpdated = true;
293
304
  }
294
305
  }
295
306
 
296
- // Always use package manager for library updates
297
- if (packagesToUpdate.library) {
298
- await installPackageVersions(pm, { library: serverVersions.library });
307
+ // Upgrade library if needed
308
+ if (libraryNeedsUpgrade) {
309
+ await upgradePackageWithPackageManager(
310
+ pm,
311
+ "library",
312
+ targetVersions.library,
313
+ currentLibraryInfo.alias,
314
+ );
299
315
  libraryUpdated = true;
300
316
  }
301
317
 
318
+ // Log what was updated
302
319
  if (cliUpdated && libraryUpdated) {
303
320
  logger.info(
304
321
  "@superblocksteam/cli and @superblocksteam/library have been updated.",
@@ -309,8 +326,10 @@ export async function checkVersionsAndUpgrade(
309
326
  logger.info("@superblocksteam/library has been updated.");
310
327
  }
311
328
 
312
- logger.info("Restarting the CLI…");
313
-
314
- await lockService.releaseLock();
315
- await restartCli();
329
+ // Restart CLI if anything was updated
330
+ if (cliUpdated || libraryUpdated) {
331
+ logger.info("Restarting the CLI…");
332
+ await lockService.releaseLock();
333
+ await restartCli();
334
+ }
316
335
  }