@superblocksteam/sdk 2.0.123 → 2.0.124-next.1

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 +403 -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 +47 -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 +486 -65
  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 +554 -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 +597 -95
  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
@@ -14,9 +14,11 @@ import {
14
14
  } from "vitest";
15
15
 
16
16
  const execMock = vi.fn();
17
+ const execFileMock = vi.fn();
17
18
  vi.mock("node:child_process", () => ({
18
- default: { exec: execMock },
19
+ default: { exec: execMock, execFile: execFileMock },
19
20
  exec: execMock,
21
+ execFile: execFileMock,
20
22
  }));
21
23
 
22
24
  vi.mock("node:readline", () => ({
@@ -89,7 +91,12 @@ vi.mock("colorette", () => ({
89
91
  green: (s: string) => s,
90
92
  }));
91
93
 
92
- vi.mock("@superblocksteam/shared", () => ({
94
+ vi.mock("@superblocksteam/shared", async (importOriginal) => ({
95
+ // dev.mts now transitively loads @superblocksteam/shared (via the npm-error
96
+ // classifier re-exported from vite-plugin-file-sync/npm-registry — APPS-4450),
97
+ // pulling in many named exports (DeploymentTypeEnum, ISocket, …). Spread the
98
+ // real module so the closed overrides below don't have to enumerate them.
99
+ ...((await importOriginal()) as Record<string, unknown>),
93
100
  buildGithubSuperblocksSyncWorkflow: vi.fn(),
94
101
  buildGithubSuperblocksSyncWorkflowFromBaseUrl: vi.fn(),
95
102
  ConflictError: class ConflictError extends Error {},
@@ -110,6 +117,7 @@ vi.mock("@superblocksteam/vite-plugin-file-sync/ai-service", () => ({
110
117
  initialize = vi.fn(async () => undefined);
111
118
  removeIntegrationCache = vi.fn(async () => undefined);
112
119
  chatSessionStore = { invalidateCache: vi.fn() };
120
+ getNpmRegistryClient = vi.fn(() => undefined);
113
121
  },
114
122
  AiServiceFeatureFlags: class {
115
123
  static create = vi.fn(() => ({}));
@@ -121,6 +129,10 @@ vi.mock("@superblocksteam/vite-plugin-file-sync/ai-service", () => ({
121
129
  stripResolvedFromLockfile: vi.fn(async () => undefined),
122
130
  }));
123
131
 
132
+ vi.mock("@superblocksteam/vite-plugin-file-sync/npm-registry", () => ({
133
+ shouldIgnoreInstallScripts: vi.fn(() => false),
134
+ }));
135
+
124
136
  const { startupOpLog, buildMockGitService } = vi.hoisted(() => {
125
137
  const startupOpLog: string[] = [];
126
138
  function buildMockGitService(cwd: string) {
@@ -254,6 +266,25 @@ vi.mock("./automatic-upgrades.js", () => ({
254
266
  checkVersionsAndWritePackageJson: (
255
267
  ...args: Parameters<typeof mockCheckVersions>
256
268
  ) => mockCheckVersions(...args),
269
+ buildInstallEnv: (userconfigPath: string) => ({
270
+ ...process.env,
271
+ NPM_CONFIG_USERCONFIG: userconfigPath,
272
+ PNPM_CONFIG_USERCONFIG: userconfigPath,
273
+ }),
274
+ }));
275
+
276
+ // The home `~/.npmrc` writer (APPS-4231) is a best-effort step that runs
277
+ // before auto-upgrade. Mock it out here so this test stays focused on the
278
+ // git-before-DBFS ordering. The `AiService` mock above exposes a minimal
279
+ // `getNpmRegistryClient()` stub so the call site doesn't `TypeError`
280
+ // and silently swallow this mock.
281
+ vi.mock("./home-npmrc.mjs", () => ({
282
+ syncHomeNpmrc: vi.fn(async () => ({
283
+ outcome: "skipped-not-configured",
284
+ path: "/tmp/.superblocks/npmrc",
285
+ })),
286
+ superblocksNpmrcPath: vi.fn(() => "/tmp/.superblocks/npmrc"),
287
+ superblocksLogsPath: vi.fn((appDir: string) => `${appDir}/.superblocks/logs`),
257
288
  }));
258
289
 
259
290
  vi.mock("./git-repo-setup.mjs", () => ({
@@ -330,6 +361,8 @@ function buildDevOptions(cwd: string, overrides: Record<string, unknown> = {}) {
330
361
  tokenManager: {
331
362
  getToken: vi.fn(() => "test-token"),
332
363
  onTokenRefresh: vi.fn(),
364
+ updateToken: vi.fn(),
365
+ getCurrentToken: vi.fn(() => "test-token"),
333
366
  },
334
367
  getCurrentToken: vi.fn(() => "test-token"),
335
368
  sdk: buildMockSdk(),
@@ -0,0 +1,103 @@
1
+ /**
2
+ * Tests for the cold-start `TokenManager` priming step (APPS-4231 follow-up).
3
+ *
4
+ * Background
5
+ * ----------
6
+ * `NpmRegistryClient.getJwt()` (`packages/vite-plugin-file-sync/src/ai-service/index.ts`)
7
+ * has two bearer-credential sources:
8
+ * 1. `tokenManagerJwt`, seeded synchronously at `AiService` construction
9
+ * from `tokenManager.getCurrentToken()` and kept current via the
10
+ * `tokenUpdated` listener for future refreshes.
11
+ * 2. `clark?.context?.jwt`, primed lazily by the first socket RPC's
12
+ * `peerAuthorization` header (`socket-manager.ts`).
13
+ *
14
+ * `TokenManager.updateToken()` has exactly one production writer outside
15
+ * `dev()` itself: `AuthHotReloadServer` (`auth-hot-reload.mts`). That socket
16
+ * is explicitly disabled on live-edit pods (SABS sets
17
+ * `SUPERBLOCKS_AUTH_HOT_RELOAD=false`). So on cold start neither source is
18
+ * primed until the UI socket lands — which is AFTER `syncHomeNpmrc` and
19
+ * AFTER the AiService's `TemplateRenderer` prefetch fires.
20
+ *
21
+ * The CLI does have a usable token in scope at `dev()` entry
22
+ * (`tokenConfig.token`, sourced from auth.json or `/_sb_activate`).
23
+ * `primeTokenManagerWithInitialToken` seeds it. Because `TokenManager`
24
+ * retains the current token as state and consumers read it synchronously
25
+ * during construction (see `getCurrentToken()` on `ITokenManager`), the
26
+ * call-site ordering between the prime and consumer construction is NOT
27
+ * load-bearing: the seed reaches AiService whether the prime fires before
28
+ * or after `new AiService(...)`.
29
+ */
30
+
31
+ import { describe, expect, it, vi } from "vitest";
32
+
33
+ import { TokenManager } from "../dev-utils/token-manager.js";
34
+ import { primeTokenManagerWithInitialToken } from "./dev.mjs";
35
+
36
+ describe("primeTokenManagerWithInitialToken", () => {
37
+ it("emits a `tokenUpdated` event carrying the supplied token to listeners subscribed before the call", () => {
38
+ const tokenManager = new TokenManager();
39
+ const events: string[] = [];
40
+ tokenManager.on("tokenUpdated", (event) => {
41
+ events.push(event.token);
42
+ });
43
+
44
+ primeTokenManagerWithInitialToken(tokenManager, "jwt-from-cold-start");
45
+
46
+ expect(events).toEqual(["jwt-from-cold-start"]);
47
+ });
48
+
49
+ it("no-ops when the token is empty (no spurious `tokenUpdated` event)", () => {
50
+ const tokenManager = new TokenManager();
51
+ const events: string[] = [];
52
+ tokenManager.on("tokenUpdated", (event) => {
53
+ events.push(event.token);
54
+ });
55
+
56
+ primeTokenManagerWithInitialToken(tokenManager, "");
57
+
58
+ expect(events).toEqual([]);
59
+ });
60
+ });
61
+
62
+ describe("TokenManager state retention (cold-start contract)", () => {
63
+ it("exposes the primed token via getCurrentToken() to consumers constructed AFTER the prime call", () => {
64
+ // This is what makes the dev.mts call site order-independent. AiService
65
+ // reads tokenManager.getCurrentToken() synchronously in its constructor
66
+ // to seed `tokenManagerJwt` — so even if `dev()` primes BEFORE
67
+ // `new AiService(...)`, the seed survives.
68
+ const tokenManager = new TokenManager();
69
+ primeTokenManagerWithInitialToken(tokenManager, "seed-jwt");
70
+
71
+ expect(tokenManager.getCurrentToken()).toBe("seed-jwt");
72
+ });
73
+
74
+ it("returns undefined from getCurrentToken() when no token has been set", () => {
75
+ const tokenManager = new TokenManager();
76
+
77
+ expect(tokenManager.getCurrentToken()).toBeUndefined();
78
+ });
79
+
80
+ it("does NOT auto-replay prior emissions to late-attached listeners", () => {
81
+ // Deliberate: auto-replaying would cause refresh-handling subscribers
82
+ // (e.g. AutoConnectingRpcClient, which closes and reconnects the socket
83
+ // on every `tokenUpdated`) to fire on what is conceptually a seed read.
84
+ // Late-attached subscribers MUST opt in via `getCurrentToken()` if they
85
+ // need the current value at attach time; the event channel is for
86
+ // changes only.
87
+ const tokenManager = new TokenManager();
88
+ primeTokenManagerWithInitialToken(tokenManager, "abc");
89
+
90
+ const lateListener = vi.fn();
91
+ tokenManager.on("tokenUpdated", lateListener);
92
+
93
+ expect(lateListener).not.toHaveBeenCalled();
94
+ });
95
+
96
+ it("overwrites the stored token on each updateToken call so refreshes win", () => {
97
+ const tokenManager = new TokenManager();
98
+ primeTokenManagerWithInitialToken(tokenManager, "first");
99
+ tokenManager.updateToken("second");
100
+
101
+ expect(tokenManager.getCurrentToken()).toBe("second");
102
+ });
103
+ });
@@ -0,0 +1,80 @@
1
+ import { describe, it, expect, vi, beforeEach } from "vitest";
2
+
3
+ import { InitialInstallFailed } from "./dependency-install-classifier.mjs";
4
+ import { handleStartupError } from "./dev.mjs";
5
+
6
+ // Mock the metrics module so we can assert recordInitialInstallFailure calls.
7
+ // vi.mock is hoisted, so we use vi.hoisted to declare the spy before the factory.
8
+ const { recordInitialInstallFailureMock } = vi.hoisted(() => ({
9
+ recordInitialInstallFailureMock: vi.fn(),
10
+ }));
11
+ vi.mock("../dev-utils/dev-server-metrics.mjs", () => ({
12
+ devServerMetrics: {
13
+ recordInitialInstallFailure: recordInitialInstallFailureMock,
14
+ flush: vi.fn(),
15
+ recordEndpoint: vi.fn(),
16
+ recordSocketUpgrade: vi.fn(),
17
+ recordViteEagerInit: vi.fn(),
18
+ recordWarmPrewarm: vi.fn(),
19
+ recordWarmActivation: vi.fn(),
20
+ recordWarmHandoff: vi.fn(),
21
+ },
22
+ }));
23
+
24
+ const makeLogger = () =>
25
+ ({ error: () => {}, info: () => {}, warn: () => {} }) as any;
26
+
27
+ beforeEach(() => {
28
+ recordInitialInstallFailureMock.mockClear();
29
+ });
30
+
31
+ describe("handleStartupError", () => {
32
+ it("records + does NOT exit for InitialInstallFailed", () => {
33
+ const status = { serverErrors: [] as any[] };
34
+ const marker = new InitialInstallFailed({
35
+ type: "dev-server/dependency-install",
36
+ timestamp: "t",
37
+ category: "dependency_conflict",
38
+ rawError: "x",
39
+ });
40
+ const decision = handleStartupError(marker, status, makeLogger());
41
+ expect(decision).toBe("degrade");
42
+ expect(status.serverErrors).toHaveLength(1);
43
+ });
44
+
45
+ it("emits the install-failure metric with category on the degrade path", () => {
46
+ const status = { serverErrors: [] as any[] };
47
+ const marker = new InitialInstallFailed({
48
+ type: "dev-server/dependency-install",
49
+ timestamp: "t",
50
+ category: "registry_auth_failed",
51
+ npmErrorCode: "E401",
52
+ hasAnyRegistryConfigured: true,
53
+ rawError: "x",
54
+ });
55
+ handleStartupError(marker, status, makeLogger());
56
+ expect(recordInitialInstallFailureMock).toHaveBeenCalledOnce();
57
+ expect(recordInitialInstallFailureMock).toHaveBeenCalledWith({
58
+ category: "registry_auth_failed",
59
+ npmErrorCode: "E401",
60
+ hasAnyRegistryConfigured: true,
61
+ });
62
+ });
63
+
64
+ it("does NOT emit the install-failure metric on the exit path", () => {
65
+ const status = { serverErrors: [] as any[] };
66
+ handleStartupError(new Error("lock failed"), status, makeLogger());
67
+ expect(recordInitialInstallFailureMock).not.toHaveBeenCalled();
68
+ });
69
+
70
+ it("exits for a non-marker error (upgrade / lock / sync)", () => {
71
+ const status = { serverErrors: [] as any[] };
72
+ const decision = handleStartupError(
73
+ new Error("lock failed"),
74
+ status,
75
+ makeLogger(),
76
+ );
77
+ expect(decision).toBe("exit");
78
+ expect(status.serverErrors).toHaveLength(0);
79
+ });
80
+ });