@superblocksteam/sdk 2.0.123 → 2.0.124-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 (115) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/dist/cli-replacement/automatic-upgrades.d.ts +37 -1
  3. package/dist/cli-replacement/automatic-upgrades.d.ts.map +1 -1
  4. package/dist/cli-replacement/automatic-upgrades.js +162 -10
  5. package/dist/cli-replacement/automatic-upgrades.js.map +1 -1
  6. package/dist/cli-replacement/automatic-upgrades.test.js +377 -8
  7. package/dist/cli-replacement/automatic-upgrades.test.js.map +1 -1
  8. package/dist/cli-replacement/dependency-install-classifier.d.mts +21 -0
  9. package/dist/cli-replacement/dependency-install-classifier.d.mts.map +1 -0
  10. package/dist/cli-replacement/dependency-install-classifier.mjs +83 -0
  11. package/dist/cli-replacement/dependency-install-classifier.mjs.map +1 -0
  12. package/dist/cli-replacement/dependency-install-classifier.test.d.mts +2 -0
  13. package/dist/cli-replacement/dependency-install-classifier.test.d.mts.map +1 -0
  14. package/dist/cli-replacement/dependency-install-classifier.test.mjs +51 -0
  15. package/dist/cli-replacement/dependency-install-classifier.test.mjs.map +1 -0
  16. package/dist/cli-replacement/dev-s3-restore.test.mjs +170 -14
  17. package/dist/cli-replacement/dev-s3-restore.test.mjs.map +1 -1
  18. package/dist/cli-replacement/dev-startup-git-before-dbfs-order.test.mjs +33 -2
  19. package/dist/cli-replacement/dev-startup-git-before-dbfs-order.test.mjs.map +1 -1
  20. package/dist/cli-replacement/dev-token-priming.test.d.mts +31 -0
  21. package/dist/cli-replacement/dev-token-priming.test.d.mts.map +1 -0
  22. package/dist/cli-replacement/dev-token-priming.test.mjs +87 -0
  23. package/dist/cli-replacement/dev-token-priming.test.mjs.map +1 -0
  24. package/dist/cli-replacement/dev.d.mts +36 -0
  25. package/dist/cli-replacement/dev.d.mts.map +1 -1
  26. package/dist/cli-replacement/dev.interception.test.d.mts +2 -0
  27. package/dist/cli-replacement/dev.interception.test.d.mts.map +1 -0
  28. package/dist/cli-replacement/dev.interception.test.mjs +68 -0
  29. package/dist/cli-replacement/dev.interception.test.mjs.map +1 -0
  30. package/dist/cli-replacement/dev.mjs +396 -62
  31. package/dist/cli-replacement/dev.mjs.map +1 -1
  32. package/dist/cli-replacement/home-npmrc.d.mts +180 -0
  33. package/dist/cli-replacement/home-npmrc.d.mts.map +1 -0
  34. package/dist/cli-replacement/home-npmrc.mjs +283 -0
  35. package/dist/cli-replacement/home-npmrc.mjs.map +1 -0
  36. package/dist/cli-replacement/home-npmrc.test.d.mts +10 -0
  37. package/dist/cli-replacement/home-npmrc.test.d.mts.map +1 -0
  38. package/dist/cli-replacement/home-npmrc.test.mjs +582 -0
  39. package/dist/cli-replacement/home-npmrc.test.mjs.map +1 -0
  40. package/dist/cli-replacement/install-packages.classify.test.d.mts +2 -0
  41. package/dist/cli-replacement/install-packages.classify.test.d.mts.map +1 -0
  42. package/dist/cli-replacement/install-packages.classify.test.mjs +125 -0
  43. package/dist/cli-replacement/install-packages.classify.test.mjs.map +1 -0
  44. package/dist/cli-replacement/install-packages.npm-registry.test.d.mts +2 -0
  45. package/dist/cli-replacement/install-packages.npm-registry.test.d.mts.map +1 -0
  46. package/dist/cli-replacement/install-packages.npm-registry.test.mjs +260 -0
  47. package/dist/cli-replacement/install-packages.npm-registry.test.mjs.map +1 -0
  48. package/dist/cli-replacement/post-upgrade-lockfile-strip.d.mts +58 -0
  49. package/dist/cli-replacement/post-upgrade-lockfile-strip.d.mts.map +1 -0
  50. package/dist/cli-replacement/post-upgrade-lockfile-strip.mjs +224 -0
  51. package/dist/cli-replacement/post-upgrade-lockfile-strip.mjs.map +1 -0
  52. package/dist/cli-replacement/post-upgrade-lockfile-strip.test.d.mts +11 -0
  53. package/dist/cli-replacement/post-upgrade-lockfile-strip.test.d.mts.map +1 -0
  54. package/dist/cli-replacement/post-upgrade-lockfile-strip.test.mjs +317 -0
  55. package/dist/cli-replacement/post-upgrade-lockfile-strip.test.mjs.map +1 -0
  56. package/dist/cli-replacement/userconfig-env.integration.test.d.mts +26 -0
  57. package/dist/cli-replacement/userconfig-env.integration.test.d.mts.map +1 -0
  58. package/dist/cli-replacement/userconfig-env.integration.test.mjs +148 -0
  59. package/dist/cli-replacement/userconfig-env.integration.test.mjs.map +1 -0
  60. package/dist/dev-utils/dev-server-metrics.d.mts +25 -0
  61. package/dist/dev-utils/dev-server-metrics.d.mts.map +1 -1
  62. package/dist/dev-utils/dev-server-metrics.mjs +84 -0
  63. package/dist/dev-utils/dev-server-metrics.mjs.map +1 -1
  64. package/dist/dev-utils/dev-server-metrics.test.d.mts +2 -0
  65. package/dist/dev-utils/dev-server-metrics.test.d.mts.map +1 -0
  66. package/dist/dev-utils/dev-server-metrics.test.mjs +26 -0
  67. package/dist/dev-utils/dev-server-metrics.test.mjs.map +1 -0
  68. package/dist/dev-utils/dev-server.d.mts +23 -1
  69. package/dist/dev-utils/dev-server.d.mts.map +1 -1
  70. package/dist/dev-utils/dev-server.mjs +21 -9
  71. package/dist/dev-utils/dev-server.mjs.map +1 -1
  72. package/dist/dev-utils/dev-server.status.test.d.mts +2 -0
  73. package/dist/dev-utils/dev-server.status.test.d.mts.map +1 -0
  74. package/dist/dev-utils/dev-server.status.test.mjs +41 -0
  75. package/dist/dev-utils/dev-server.status.test.mjs.map +1 -0
  76. package/dist/dev-utils/token-manager.d.ts +31 -0
  77. package/dist/dev-utils/token-manager.d.ts.map +1 -1
  78. package/dist/dev-utils/token-manager.js +34 -0
  79. package/dist/dev-utils/token-manager.js.map +1 -1
  80. package/dist/telemetry/local-obs.js +1 -1
  81. package/dist/telemetry/local-obs.js.map +1 -1
  82. package/dist/telemetry/util.js +1 -1
  83. package/dist/types/scoped-jwt-token-payload.d.ts +1 -0
  84. package/dist/types/scoped-jwt-token-payload.d.ts.map +1 -1
  85. package/dist/version-control.d.mts.map +1 -1
  86. package/dist/version-control.mjs +6 -7
  87. package/dist/version-control.mjs.map +1 -1
  88. package/package.json +12 -12
  89. package/src/cli-replacement/automatic-upgrades.test.ts +530 -8
  90. package/src/cli-replacement/automatic-upgrades.ts +179 -7
  91. package/src/cli-replacement/dependency-install-classifier.mts +118 -0
  92. package/src/cli-replacement/dependency-install-classifier.test.mts +72 -0
  93. package/src/cli-replacement/dev-s3-restore.test.mts +210 -14
  94. package/src/cli-replacement/dev-startup-git-before-dbfs-order.test.mts +35 -2
  95. package/src/cli-replacement/dev-token-priming.test.mts +103 -0
  96. package/src/cli-replacement/dev.interception.test.mts +80 -0
  97. package/src/cli-replacement/dev.mts +495 -92
  98. package/src/cli-replacement/home-npmrc.mts +409 -0
  99. package/src/cli-replacement/home-npmrc.test.mts +757 -0
  100. package/src/cli-replacement/install-packages.classify.test.mts +168 -0
  101. package/src/cli-replacement/install-packages.npm-registry.test.mts +345 -0
  102. package/src/cli-replacement/post-upgrade-lockfile-strip.mts +296 -0
  103. package/src/cli-replacement/post-upgrade-lockfile-strip.test.mts +482 -0
  104. package/src/cli-replacement/userconfig-env.integration.test.mts +189 -0
  105. package/src/dev-utils/dev-server-metrics.mts +96 -0
  106. package/src/dev-utils/dev-server-metrics.test.mts +38 -0
  107. package/src/dev-utils/dev-server.mts +48 -8
  108. package/src/dev-utils/dev-server.status.test.mts +58 -0
  109. package/src/dev-utils/token-manager.ts +36 -0
  110. package/src/telemetry/local-obs.ts +1 -1
  111. package/src/telemetry/util.ts +1 -1
  112. package/src/types/scoped-jwt-token-payload.ts +1 -0
  113. package/src/version-control.mts +8 -6
  114. package/tsconfig.tsbuildinfo +1 -1
  115. package/.turbo/turbo-publish-package.log +0 -0
@@ -0,0 +1,296 @@
1
+ /**
2
+ * Post-CLI-upgrade lockfile normalization for the dev-server pod's globally
3
+ * installed Superblocks CLI.
4
+ *
5
+ * npm honors `resolved` URLs verbatim, so a tarball whose bundled lockfile
6
+ * entries point at `registry.npmjs.org` keeps fetching from public npm even
7
+ * after we've written a private `.npmrc`. This module strips those URLs
8
+ * post-upgrade so subsequent installs re-resolve through the active registry.
9
+ *
10
+ * The walk from the resolved `superblocks` binary up to the CLI package root
11
+ * is bounded so a misconfigured layout can never mutate arbitrary lockfiles
12
+ * on the filesystem.
13
+ *
14
+ * All failures are logged and swallowed — a failed post-strip must not crash
15
+ * the pod after a working upgrade. The next dev startup repeats the strip
16
+ * idempotently.
17
+ */
18
+
19
+ import * as child_process from "node:child_process";
20
+ import fs from "node:fs/promises";
21
+ import * as path from "node:path";
22
+ import { promisify } from "node:util";
23
+
24
+ import {
25
+ stripResolvedFromLockfile,
26
+ stripResolvedFromLockfilePath,
27
+ } from "@superblocksteam/vite-plugin-file-sync/npm-registry";
28
+
29
+ import { getErrorMeta, type Logger } from "../telemetry/logging.js";
30
+
31
+ const exec = promisify(child_process.exec);
32
+
33
+ const LOG_PREFIX = "[post-upgrade-lockfile-strip]";
34
+
35
+ /**
36
+ * Upper bound on the post-upgrade strip. The I/O is local and small, but the
37
+ * CLI install can live on a network-mounted prefix (custom `npm prefix`,
38
+ * Volta cache, etc.) where a hung `fs.realpath` or `fs.readFile` would
39
+ * otherwise extend `cliUpgradePromise` and block dev-server startup. A
40
+ * timeout keeps the boot path bounded; the underlying I/O is left to settle
41
+ * in the background since every step is idempotent and individually error-
42
+ * swallowing.
43
+ */
44
+ const STRIP_TIMEOUT_MS = 5_000;
45
+
46
+ /**
47
+ * Upper bound on `package.json` lookups when walking up from the resolved
48
+ * `superblocks` binary. The expected path depth is 3 levels
49
+ * (`<prefix>/lib/node_modules/@superblocksteam/cli/bin/run.js` ->
50
+ * `<prefix>/lib/node_modules/@superblocksteam/cli`); 8 leaves headroom for
51
+ * non-standard layouts (Volta, nvm, custom prefixes) without ever climbing
52
+ * out of the install tree.
53
+ */
54
+ const MAX_PACKAGE_ROOT_WALK_DEPTH = 8;
55
+
56
+ // Both names are valid CLI install roots: `cli-ephemeral` is the alias used
57
+ // for snapshot builds (see the alias detection in `version-detection.ts`),
58
+ // and either may appear in the global install depending on which channel the
59
+ // pod was provisioned against.
60
+ const CLI_PACKAGE_NAMES = new Set<string>([
61
+ "@superblocksteam/cli",
62
+ "@superblocksteam/cli-ephemeral",
63
+ ]);
64
+
65
+ /**
66
+ * Injectable subset of `child_process.exec` so tests can stub the
67
+ * `which`/`where` lookup without spawning a real subprocess.
68
+ */
69
+ export type WhichRunner = (binary: string) => Promise<string>;
70
+
71
+ const defaultWhichRunner: WhichRunner = async (binary) => {
72
+ const cmd = process.platform === "win32" ? "where" : "which";
73
+ const { stdout } = await exec(`${cmd} ${binary}`);
74
+ return stdout;
75
+ };
76
+
77
+ /**
78
+ * Discovers the absolute path of the `@superblocksteam/cli` install root
79
+ * (the directory containing the CLI's `package.json`), or returns `undefined`
80
+ * if discovery fails. Discovery failures are non-fatal — the caller logs and
81
+ * skips the strip rather than aborting.
82
+ */
83
+ export async function findGlobalCliInstallDir(
84
+ logger: Logger,
85
+ whichRunner: WhichRunner = defaultWhichRunner,
86
+ ): Promise<string | undefined> {
87
+ let binStdout: string;
88
+ try {
89
+ binStdout = await whichRunner("superblocks");
90
+ } catch (error) {
91
+ logger.warn(
92
+ `${LOG_PREFIX} which/where superblocks failed; skipping strip`,
93
+ {
94
+ ...getErrorMeta(error),
95
+ },
96
+ );
97
+ return undefined;
98
+ }
99
+
100
+ // `which`/`where` may emit multiple lines (e.g. shim + real path on
101
+ // Windows). The first line wins; matches the existing pattern in
102
+ // `version-detection.ts`.
103
+ const binPath = binStdout.trim().split(/\r?\n/)[0]?.trim();
104
+ if (!binPath) {
105
+ logger.warn(
106
+ `${LOG_PREFIX} superblocks binary not found in PATH; skipping strip`,
107
+ );
108
+ return undefined;
109
+ }
110
+
111
+ let realBinPath: string;
112
+ try {
113
+ realBinPath = await fs.realpath(binPath);
114
+ } catch (error) {
115
+ logger.warn(
116
+ `${LOG_PREFIX} realpath failed for superblocks binary; skipping strip`,
117
+ {
118
+ binPath,
119
+ ...getErrorMeta(error),
120
+ },
121
+ );
122
+ return undefined;
123
+ }
124
+
125
+ let dir = path.dirname(realBinPath);
126
+ for (let i = 0; i < MAX_PACKAGE_ROOT_WALK_DEPTH; i++) {
127
+ const candidate = path.join(dir, "package.json");
128
+ let raw: string;
129
+ try {
130
+ raw = await fs.readFile(candidate, "utf-8");
131
+ } catch (error: unknown) {
132
+ const code = (error as NodeJS.ErrnoException | undefined)?.code;
133
+ if (code === "ENOENT") {
134
+ const parent = path.dirname(dir);
135
+ if (parent === dir) {
136
+ break;
137
+ }
138
+ dir = parent;
139
+ continue;
140
+ }
141
+ logger.warn(
142
+ `${LOG_PREFIX} failed to read candidate package.json; skipping strip`,
143
+ {
144
+ candidate,
145
+ code,
146
+ ...getErrorMeta(error),
147
+ },
148
+ );
149
+ return undefined;
150
+ }
151
+
152
+ let parsed: { name?: unknown } | undefined;
153
+ try {
154
+ parsed = JSON.parse(raw) as { name?: unknown };
155
+ } catch (error) {
156
+ logger.warn(
157
+ `${LOG_PREFIX} candidate package.json is not valid JSON; skipping strip`,
158
+ {
159
+ candidate,
160
+ ...getErrorMeta(error),
161
+ },
162
+ );
163
+ return undefined;
164
+ }
165
+
166
+ if (typeof parsed.name === "string" && CLI_PACKAGE_NAMES.has(parsed.name)) {
167
+ return dir;
168
+ }
169
+
170
+ // Found a `package.json` that isn't the CLI's — keep walking up. Some
171
+ // layouts (oclif's update channel) nest the binary under a wrapper
172
+ // package; we don't want to bail on the first unrelated manifest.
173
+ const parent = path.dirname(dir);
174
+ if (parent === dir) {
175
+ break;
176
+ }
177
+ dir = parent;
178
+ }
179
+
180
+ logger.warn(
181
+ `${LOG_PREFIX} could not locate @superblocksteam/cli install root; skipping strip`,
182
+ {
183
+ startedAt: realBinPath,
184
+ },
185
+ );
186
+ return undefined;
187
+ }
188
+
189
+ export interface StripUpgradedCliLockfilesOptions {
190
+ /**
191
+ * Pre-resolved install root. If omitted, `findGlobalCliInstallDir` is used.
192
+ * Tests pass this directly to avoid stubbing `which`.
193
+ */
194
+ installDir?: string;
195
+ whichRunner?: WhichRunner;
196
+ /**
197
+ * Override the strip timeout (ms). Tests use a tight value to exercise the
198
+ * timeout branch without sleeping for the real bound.
199
+ */
200
+ timeoutMs?: number;
201
+ }
202
+
203
+ /**
204
+ * Strips public-host `resolved` URLs from every lockfile under the global
205
+ * CLI install that the auto-upgrade could have refreshed. Returns the
206
+ * resolved install root on success, or `undefined` when discovery failed.
207
+ *
208
+ * Non-fatal: every individual strip already swallows lockfile-level errors
209
+ * (logged in `stripResolvedFromLockfilePath`); this wrapper additionally
210
+ * swallows discovery failures and any unexpected throw from the inner
211
+ * helpers so a successful upgrade is never demoted to a crash by a post-step
212
+ * problem.
213
+ */
214
+ export async function stripUpgradedCliLockfiles(
215
+ logger: Logger,
216
+ options: StripUpgradedCliLockfilesOptions = {},
217
+ ): Promise<{ installDir?: string }> {
218
+ const installDir =
219
+ options.installDir ??
220
+ (await findGlobalCliInstallDir(logger, options.whichRunner));
221
+ if (!installDir) {
222
+ return {};
223
+ }
224
+
225
+ const timeoutMs = options.timeoutMs ?? STRIP_TIMEOUT_MS;
226
+ const start = Date.now();
227
+ // The hidden lockfile listing the CLI itself lives two levels up from
228
+ // installDir under the npm-global layout
229
+ // (<prefix>/lib/node_modules/.package-lock.json).
230
+ const globalHiddenLockfile = path.join(
231
+ path.dirname(path.dirname(installDir)),
232
+ ".package-lock.json",
233
+ );
234
+
235
+ const STRIP_TIMED_OUT = Symbol("STRIP_TIMED_OUT");
236
+ let timeoutHandle: NodeJS.Timeout | undefined;
237
+ const timeoutPromise = new Promise<typeof STRIP_TIMED_OUT>((resolve) => {
238
+ timeoutHandle = setTimeout(() => resolve(STRIP_TIMED_OUT), timeoutMs);
239
+ });
240
+ try {
241
+ const stripWork = Promise.all([
242
+ stripResolvedFromLockfile(installDir),
243
+ stripResolvedFromLockfilePath(globalHiddenLockfile),
244
+ ]);
245
+ const outcome = await Promise.race([stripWork, timeoutPromise]);
246
+ if (outcome === STRIP_TIMED_OUT) {
247
+ logger.warn(
248
+ `${LOG_PREFIX} strip exceeded timeout; continuing without waiting`,
249
+ {
250
+ installDir,
251
+ timeoutMs,
252
+ elapsedMs: Date.now() - start,
253
+ },
254
+ );
255
+ // We're abandoning `stripWork` after the timeout won the race. The
256
+ // inner helpers swallow per-file errors, but their atomic `writeFile`
257
+ // / `rename` calls can still throw (EACCES, EXDEV, ENOSPC, …) — and
258
+ // with no subscriber left on `stripWork`, a late rejection would
259
+ // surface as an unhandled rejection and crash the pod under Node's
260
+ // default policy. Attach a tail handler to keep the post-step
261
+ // non-fatal even when the timeout path is taken.
262
+ stripWork.catch((error) => {
263
+ logger.warn(
264
+ `${LOG_PREFIX} background strip rejected after timeout; ignoring`,
265
+ {
266
+ ...getErrorMeta(error),
267
+ installDir,
268
+ },
269
+ );
270
+ });
271
+ } else {
272
+ logger.info(
273
+ `${LOG_PREFIX} stripped resolved URLs from upgraded CLI lockfiles`,
274
+ {
275
+ installDir,
276
+ elapsedMs: Date.now() - start,
277
+ },
278
+ );
279
+ }
280
+ } catch (error) {
281
+ // The lower-level helpers already swallow per-file errors; this catches
282
+ // any unexpected throw so a post-step problem never surfaces as a failed
283
+ // upgrade.
284
+ logger.warn(`${LOG_PREFIX} unexpected error during strip; continuing`, {
285
+ ...getErrorMeta(error),
286
+ installDir,
287
+ elapsedMs: Date.now() - start,
288
+ });
289
+ } finally {
290
+ if (timeoutHandle) {
291
+ clearTimeout(timeoutHandle);
292
+ }
293
+ }
294
+
295
+ return { installDir };
296
+ }