@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
@@ -16,6 +16,62 @@ import { isTelemetryInitialized } from "@superblocksteam/telemetry";
16
16
 
17
17
  import { getMeter } from "../telemetry/index.js";
18
18
 
19
+ /**
20
+ * Allowlist of npm/pnpm error codes the classifier can attach to a
21
+ * `DependencyInstallError`. Used to BOUND the `npm_error_code` metric label:
22
+ * the classifier's unknown-branch extracts the code via a `(\S+)` regex, so an
23
+ * unexpected, malformed, or registry-injected token must never become a new
24
+ * time series. Any code outside this set maps to `"other"`; pnpm's variable
25
+ * `ERR_PNPM_FETCH_<status>` collapses to a single bucket.
26
+ */
27
+ const KNOWN_NPM_ERROR_CODES = new Set<string>([
28
+ // dependency-graph conflicts (the repro)
29
+ "ERESOLVE",
30
+ "ETARGET",
31
+ "EPEERINVALID",
32
+ // not in registry
33
+ "E404",
34
+ // auth
35
+ "E401",
36
+ "E403",
37
+ "EAUTH",
38
+ "EAUTHIP",
39
+ "EAUTHUNKNOWN",
40
+ "EOTP",
41
+ // network / unreachable
42
+ "ENOTFOUND",
43
+ "EAI_AGAIN",
44
+ "ECONNREFUSED",
45
+ "ECONNRESET",
46
+ "ENETUNREACH",
47
+ "ETIMEDOUT",
48
+ "ESOCKETTIMEDOUT",
49
+ // tls
50
+ "UNABLE_TO_VERIFY_LEAF_SIGNATURE",
51
+ "SELF_SIGNED_CERT_IN_CHAIN",
52
+ "DEPTH_ZERO_SELF_SIGNED_CERT",
53
+ "CERT_HAS_EXPIRED",
54
+ "CERT_NOT_YET_VALID",
55
+ "CERT_UNTRUSTED",
56
+ "UNABLE_TO_GET_ISSUER_CERT",
57
+ "UNABLE_TO_GET_ISSUER_CERT_LOCALLY",
58
+ // pnpm
59
+ "ERR_PNPM_META_FETCH_FAIL",
60
+ "ERR_PNPM_FETCH", // collapsed bucket for ERR_PNPM_FETCH_<status>
61
+ ]);
62
+
63
+ /**
64
+ * Normalize an npm/pnpm error code into a bounded metric-label value. Known
65
+ * codes pass through (keeping the diagnostic facet); everything else collapses
66
+ * to `"other"` (or `"none"` when absent) so the
67
+ * `dev_server_initial_install_failure_total` series count stays bounded.
68
+ */
69
+ export function normalizeNpmErrorCodeTag(code: string | undefined): string {
70
+ if (!code) return "none";
71
+ const collapsed = /^ERR_PNPM_FETCH_\d+$/.test(code) ? "ERR_PNPM_FETCH" : code;
72
+ return KNOWN_NPM_ERROR_CODES.has(collapsed) ? collapsed : "other";
73
+ }
74
+
19
75
  /** Dev-server endpoints that produce per-request metrics. */
20
76
  export type DevServerEndpoint =
21
77
  | "_sb_health"
@@ -246,6 +302,46 @@ class DevServerMetrics {
246
302
  .record(durationMs);
247
303
  });
248
304
  }
305
+
306
+ /**
307
+ * Records a degraded startup caused by a failed initial dependency install.
308
+ *
309
+ * All tags are low-cardinality:
310
+ * - `category` is a closed enum from DependencyInstallError (safe).
311
+ * - `npm_error_code` is a bounded npm error code string (e.g. "E401",
312
+ * "ERESOLVE") or `"none"` when absent.
313
+ * - `has_any_registry_configured` is a boolean string (`"true"` /
314
+ * `"false"`) or `"unknown"` when the tri-state is undefined.
315
+ *
316
+ * Do NOT pass raw package names, registry hostnames, or rawError — those
317
+ * are high-cardinality or contain customer-infra identifiers.
318
+ */
319
+ recordInitialInstallFailure({
320
+ category,
321
+ npmErrorCode,
322
+ hasAnyRegistryConfigured,
323
+ }: {
324
+ category: string;
325
+ npmErrorCode?: string;
326
+ hasAnyRegistryConfigured?: boolean;
327
+ }): void {
328
+ const labels = {
329
+ category,
330
+ npm_error_code: normalizeNpmErrorCodeTag(npmErrorCode),
331
+ has_any_registry_configured:
332
+ hasAnyRegistryConfigured === undefined
333
+ ? "unknown"
334
+ : String(hasAnyRegistryConfigured),
335
+ };
336
+ this.record(() => {
337
+ getMeter()
338
+ .createCounter("dev_server_initial_install_failure_total", {
339
+ description:
340
+ "Count of degraded dev-server startups caused by a failed initial dependency install.",
341
+ })
342
+ .add(1, labels);
343
+ });
344
+ }
249
345
  }
250
346
 
251
347
  /** Process-wide dev-server metrics singleton. */
@@ -0,0 +1,38 @@
1
+ import { describe, it, expect } from "vitest";
2
+
3
+ import { normalizeNpmErrorCodeTag } from "./dev-server-metrics.mjs";
4
+
5
+ describe("normalizeNpmErrorCodeTag (metric cardinality bound)", () => {
6
+ it("passes through known npm codes", () => {
7
+ expect(normalizeNpmErrorCodeTag("ERESOLVE")).toBe("ERESOLVE");
8
+ expect(normalizeNpmErrorCodeTag("E404")).toBe("E404");
9
+ expect(normalizeNpmErrorCodeTag("E401")).toBe("E401");
10
+ expect(normalizeNpmErrorCodeTag("ENOTFOUND")).toBe("ENOTFOUND");
11
+ expect(normalizeNpmErrorCodeTag("CERT_HAS_EXPIRED")).toBe(
12
+ "CERT_HAS_EXPIRED",
13
+ );
14
+ });
15
+
16
+ it("collapses variable pnpm fetch codes into one bucket", () => {
17
+ expect(normalizeNpmErrorCodeTag("ERR_PNPM_FETCH_404")).toBe(
18
+ "ERR_PNPM_FETCH",
19
+ );
20
+ expect(normalizeNpmErrorCodeTag("ERR_PNPM_FETCH_500")).toBe(
21
+ "ERR_PNPM_FETCH",
22
+ );
23
+ expect(normalizeNpmErrorCodeTag("ERR_PNPM_META_FETCH_FAIL")).toBe(
24
+ "ERR_PNPM_META_FETCH_FAIL",
25
+ );
26
+ });
27
+
28
+ it("maps unknown / arbitrary / injected tokens to 'other' (cardinality guard)", () => {
29
+ expect(normalizeNpmErrorCodeTag("EWEIRD")).toBe("other");
30
+ expect(normalizeNpmErrorCodeTag("some-random-token")).toBe("other");
31
+ expect(normalizeNpmErrorCodeTag("`;rm -rf /#")).toBe("other");
32
+ });
33
+
34
+ it("maps an absent code to 'none'", () => {
35
+ expect(normalizeNpmErrorCodeTag(undefined)).toBe("none");
36
+ expect(normalizeNpmErrorCodeTag("")).toBe("none");
37
+ });
38
+ });
@@ -14,6 +14,7 @@ import type { HmrOptions, Plugin, UserConfig } from "vite";
14
14
  import type { ViteDevServer } from "vite";
15
15
  import tsconfigPaths from "vite-tsconfig-paths";
16
16
 
17
+ import type { ServerError } from "@superblocksteam/library-shared/types";
17
18
  import {
18
19
  JwtVerifier,
19
20
  SUPERBLOCKS_LIVE_GIT_BRANCH,
@@ -430,6 +431,14 @@ interface CreateDevServerOptions {
430
431
  * responding before the full server takes over.
431
432
  */
432
433
  warmActivationStart?: number;
434
+ /**
435
+ * Server-side errors (e.g. dependency-install failures) to surface to the UI
436
+ * via `/_sb_connect` and `/_sb_status`. Optional and read at request time, so
437
+ * the caller can mutate the referenced object after `createDevServer` returns
438
+ * and have later requests reflect the change. Treated as `{ serverErrors: [] }`
439
+ * when absent.
440
+ */
441
+ devServerStatus?: { serverErrors: ServerError[] };
433
442
  }
434
443
 
435
444
  let httpServer: http.Server;
@@ -472,6 +481,19 @@ function attachUpgradeMetricsListener(server: http.Server): void {
472
481
  });
473
482
  }
474
483
 
484
+ /**
485
+ * Merges the live `serverErrors` list onto a status/health payload returned by
486
+ * `/_sb_connect` and `/_sb_status`. `devServerStatus` is optional and may omit
487
+ * `serverErrors`; both cases yield an empty array so the UI always receives a
488
+ * well-formed `serverErrors` field.
489
+ */
490
+ export function buildStatusPayload<T extends object>(
491
+ base: T,
492
+ devServerStatus?: { serverErrors?: ServerError[] },
493
+ ): T & { serverErrors: ServerError[] } {
494
+ return { ...base, serverErrors: devServerStatus?.serverErrors ?? [] };
495
+ }
496
+
475
497
  // The "Dev Server" is a long-running HTTP server that manages the Vite server
476
498
  export async function createDevServer({
477
499
  root,
@@ -490,6 +512,7 @@ export async function createDevServer({
490
512
  superblocksBaseUrl: explicitBaseUrl,
491
513
  existingServer,
492
514
  warmActivationStart,
515
+ devServerStatus,
493
516
  }: CreateDevServerOptions) {
494
517
  const logger = getLogger(loggerOverride);
495
518
  if (httpServer) {
@@ -818,16 +841,32 @@ export async function createDevServer({
818
841
  // Wait for it to be ready before responding.
819
842
  try {
820
843
  await vitePromise;
821
- res.send(JSON.stringify(healthResponse));
844
+ res.send(
845
+ JSON.stringify(buildStatusPayload(healthResponse, devServerStatus)),
846
+ );
822
847
  } catch (e) {
823
848
  logger.error(
824
849
  "Vite server failed to initialize",
825
850
  getErrorMeta(e as Error),
826
851
  );
827
852
  res.locals.sbFailureType = "vite_init";
853
+ // Carry `devServerStatus.serverErrors` onto the failure body too.
854
+ // The 200 path uses `buildStatusPayload` to surface startup errors
855
+ // (e.g. dependency-install failures) to the editor's readiness path;
856
+ // doing the same here means a Vite-init failure that also recorded
857
+ // an install failure doesn't silently drop the install context from
858
+ // the wire — any consumer that inspects the non-ok body still sees
859
+ // a well-formed `serverErrors` array alongside the generic `error`.
828
860
  res
829
861
  .status(500)
830
- .send(JSON.stringify({ error: "Dev server failed to initialize" }));
862
+ .send(
863
+ JSON.stringify(
864
+ buildStatusPayload(
865
+ { error: "Dev server failed to initialize" },
866
+ devServerStatus,
867
+ ),
868
+ ),
869
+ );
831
870
  }
832
871
  });
833
872
 
@@ -883,13 +922,14 @@ export async function createDevServer({
883
922
  app.get("/_sb_status", authHandler, async (_req, res) => {
884
923
  res.setHeader("Content-Type", "application/json");
885
924
  if (lockService?.isLocked) {
886
- res.send({
887
- connectedUsers: lockService.connectedUsers,
888
- });
925
+ res.send(
926
+ buildStatusPayload(
927
+ { connectedUsers: lockService.connectedUsers },
928
+ devServerStatus,
929
+ ),
930
+ );
889
931
  } else {
890
- res.send({
891
- connectedUsers: [],
892
- });
932
+ res.send(buildStatusPayload({ connectedUsers: [] }, devServerStatus));
893
933
  }
894
934
  });
895
935
 
@@ -0,0 +1,58 @@
1
+ import { describe, expect, it } from "vitest";
2
+
3
+ import type { ServerError } from "@superblocksteam/library-shared/types";
4
+
5
+ // Static import so the slow `dev-server.mjs` module graph (vite, react plugin,
6
+ // workspace deps) loads during file evaluation rather than inside each test,
7
+ // where the cold-import cost easily exceeds the default 5s test timeout.
8
+ import { buildStatusPayload } from "./dev-server.mjs";
9
+
10
+ describe("buildStatusPayload", () => {
11
+ it("merges serverErrors from devServerStatus onto the base payload", () => {
12
+ const installError: ServerError = {
13
+ type: "dev-server/dependency-install",
14
+ timestamp: "2026-05-29T00:00:00.000Z",
15
+ category: "not_in_registry",
16
+ packages: [{ name: "left-pad" }],
17
+ rawError: "boom",
18
+ };
19
+
20
+ expect(
21
+ buildStatusPayload(
22
+ { connectedUsers: ["a@example.com"] },
23
+ { serverErrors: [installError] },
24
+ ),
25
+ ).toEqual({
26
+ connectedUsers: ["a@example.com"],
27
+ serverErrors: [installError],
28
+ });
29
+ });
30
+
31
+ it("preserves all base fields while adding serverErrors", () => {
32
+ expect(
33
+ buildStatusPayload(
34
+ { status: "healthy", applicationId: "app-1", cliVersion: "1.2.3" },
35
+ { serverErrors: [] },
36
+ ),
37
+ ).toEqual({
38
+ status: "healthy",
39
+ applicationId: "app-1",
40
+ cliVersion: "1.2.3",
41
+ serverErrors: [],
42
+ });
43
+ });
44
+
45
+ it("yields an empty serverErrors array when devServerStatus is absent", () => {
46
+ expect(buildStatusPayload({ connectedUsers: [] })).toEqual({
47
+ connectedUsers: [],
48
+ serverErrors: [],
49
+ });
50
+ });
51
+
52
+ it("yields an empty serverErrors array when devServerStatus.serverErrors is absent", () => {
53
+ expect(buildStatusPayload({ connectedUsers: [] }, {})).toEqual({
54
+ connectedUsers: [],
55
+ serverErrors: [],
56
+ });
57
+ });
58
+ });
@@ -2,8 +2,44 @@ import { EventEmitter } from "node:events";
2
2
 
3
3
  import type { ITokenManager, TokenUpdateEvent } from "@superblocksteam/util";
4
4
 
5
+ /**
6
+ * Holds the active bearer credential and notifies subscribers on change.
7
+ *
8
+ * Two access patterns are intentionally supported and serve distinct roles:
9
+ *
10
+ * - `updateToken(t)` writes the current token AND emits `tokenUpdated`.
11
+ * The event stream is the **refresh channel**: subscribers (e.g.
12
+ * `AutoConnectingRpcClient`, `AiService`) react to changes (e.g. tear
13
+ * down a socket and reconnect with the new credential).
14
+ *
15
+ * - `getCurrentToken()` returns the most recently set token, or
16
+ * `undefined` if none. This is the **seed channel**: consumers that
17
+ * need a bearer credential at construction time read it directly.
18
+ * Without this, a consumer whose listener is attached *after* a prior
19
+ * `updateToken()` would silently observe nothing — Node `EventEmitter`
20
+ * has no replay. Closes the cold-start gap for `NpmRegistryClient`
21
+ * when the CLI primes the manager from `tokenConfig.token` at startup.
22
+ *
23
+ * Events are deliberately NOT auto-replayed on `on(...)`: a fresh
24
+ * subscriber receives only future emissions. Auto-replay would make a
25
+ * late-attached refresh handler (e.g. one that closes and reconnects a
26
+ * socket) fire on what is conceptually a seed read, producing spurious
27
+ * tear-down/reconnect churn.
28
+ *
29
+ * The current implementation does not surface a `clearToken()` API.
30
+ * Today's lifecycle never needs one — a process holds at most one user's
31
+ * credentials and exits when they log out. Add one if/when a multi-tenant
32
+ * or in-process re-auth path requires it.
33
+ */
5
34
  export class TokenManager extends EventEmitter implements ITokenManager {
35
+ private currentToken: string | undefined;
36
+
6
37
  updateToken(newToken: string): void {
38
+ this.currentToken = newToken;
7
39
  this.emit("tokenUpdated", { token: newToken } as TokenUpdateEvent);
8
40
  }
41
+
42
+ getCurrentToken(): string | undefined {
43
+ return this.currentToken;
44
+ }
9
45
  }
@@ -25,7 +25,7 @@
25
25
 
26
26
  import { DeploymentTypeEnum } from "@superblocksteam/shared";
27
27
 
28
- const DEFAULT_LOCAL_OTEL_ENDPOINT = "http://localhost:24318";
28
+ const DEFAULT_LOCAL_OTEL_ENDPOINT = "http://localhost:4318";
29
29
  const DEFAULT_ML_APP_NAME = "superblocks-ai-code-gen";
30
30
 
31
31
  export interface LocalObsConfig {
@@ -9,7 +9,7 @@ export const SERVICE_NAME = "sdk-dev-server";
9
9
  * 1. SUPERBLOCKS_OTEL_COLLECTOR_URL env var (for local obs mode)
10
10
  * 2. Superblocks API endpoint derived from base URL
11
11
  *
12
- * When SUPERBLOCKS_OTEL_COLLECTOR_URL is set (e.g., http://localhost:24318),
12
+ * When SUPERBLOCKS_OTEL_COLLECTOR_URL is set (e.g., http://localhost:4318),
13
13
  * telemetry is sent directly to the local OTEL collector.
14
14
  *
15
15
  * Note: This returns the BASE URL. The telemetry library appends /v1/traces,
@@ -9,4 +9,5 @@ export interface SuperblocksScopedJwtPayload {
9
9
  dir_hash?: string;
10
10
  user_email: string;
11
11
  user_type: string;
12
+ app_engine_version?: "1.0" | "2.0";
12
13
  }
@@ -511,13 +511,15 @@ export async function writeResourceToDisk(
511
511
  getApiRepresentation(featureFlags, backendConfig);
512
512
 
513
513
  // Write the API file(s)
514
+ const apiPromises: Array<Promise<void>> = [];
514
515
  const apiInfo = await writeBackendApi(
515
516
  resource,
516
517
  backendDirName,
517
- [],
518
+ apiPromises,
518
519
  apiRepresentation,
519
520
  existingFilePaths,
520
521
  );
522
+ await Promise.all(apiPromises);
521
523
  if (apiRepresentation.extractLargeSourceFiles) {
522
524
  backendConfig.sourceFiles = apiInfo.sourceFiles;
523
525
  }
@@ -696,7 +698,6 @@ async function writeV1ApplicationToDisk(
696
698
  }
697
699
  }
698
700
 
699
- const appApis: Record<string, ApiInfo> = {};
700
701
  if (resource.apis && resource.apis.length) {
701
702
  for (const api of resource.apis as ApiWrapper[]) {
702
703
  const apiInfo = await writeAppApi(
@@ -719,11 +720,12 @@ async function writeV1ApplicationToDisk(
719
720
  newApplicationConfig.apis[apiId] = apiInfo.name;
720
721
  }
721
722
  }
722
- await Promise.all(apiPromises);
723
723
  }
724
- if (apiRepresentation.extractLargeSourceFiles) {
725
- newApplicationConfig.appApis = appApis;
726
- } else if (!newApplicationConfig.apis) {
724
+ await Promise.all(apiPromises);
725
+ if (
726
+ !apiRepresentation.extractLargeSourceFiles &&
727
+ !newApplicationConfig.apis
728
+ ) {
727
729
  // Make sure there is an empty object even if there are no APIs
728
730
  newApplicationConfig.apis = {};
729
731
  }