rivet-design 0.28.1 → 0.28.3

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 (89) hide show
  1. package/dist/cli/commands/libraryOpen.js +1 -0
  2. package/dist/cli/commands/mcpServe.js +5 -1
  3. package/dist/cli/commands/open.js +17 -6
  4. package/dist/cli/commands/profile.js +8 -1
  5. package/dist/cli/commands/profileDisconnect.d.ts +3 -0
  6. package/dist/cli/commands/profileDisconnect.js +34 -0
  7. package/dist/cli/commands/serve.js +2 -0
  8. package/dist/cli/commands/shared.js +4 -1
  9. package/dist/cli/envelope.d.ts +1 -0
  10. package/dist/cli/router.js +8 -2
  11. package/dist/jest.globalSetup.d.ts +3 -0
  12. package/dist/jest.globalSetup.js +19 -0
  13. package/dist/library/browserLaunch.d.ts +2 -1
  14. package/dist/library/browserLaunch.js +3 -2
  15. package/dist/proxy-middleware/proxy-config.d.ts +0 -1
  16. package/dist/proxy-middleware/proxy-config.js +6 -34
  17. package/dist/routes/agentVariants.js +20 -173
  18. package/dist/routes/referenceProfiles.js +3 -3
  19. package/dist/routes/static.js +8 -2
  20. package/dist/server.d.ts +1 -1
  21. package/dist/server.js +15 -26
  22. package/dist/services/AuthService.js +7 -61
  23. package/dist/services/IntegrationsClient.d.ts +2 -1
  24. package/dist/services/IntegrationsClient.js +46 -20
  25. package/dist/services/TelemetryService.d.ts +16 -2
  26. package/dist/services/TelemetryService.js +18 -0
  27. package/dist/services/accessTokenRefresh.js +2 -2
  28. package/dist/services/profiles/DesignProfiles.d.ts +16 -0
  29. package/dist/services/profiles/DesignProfiles.js +78 -17
  30. package/dist/services/profiles/ProfileAnalysis.d.ts +3 -0
  31. package/dist/services/profiles/ProfileAnalysis.js +66 -1
  32. package/dist/services/profiles/ProfileImports.d.ts +2 -0
  33. package/dist/services/profiles/ProfileImports.js +2 -0
  34. package/dist/services/templates/viteReactTs.js +1 -1
  35. package/dist/storage/profiles/ProfileRecords.d.ts +17 -0
  36. package/dist/storage/profiles/ProfileRecords.js +45 -7
  37. package/dist/storage/profiles/migrations.d.ts +2 -2
  38. package/dist/storage/profiles/migrations.js +7 -0
  39. package/dist/storage/profiles/schema.d.ts +48 -0
  40. package/dist/storage/profiles/schema.js +3 -0
  41. package/dist/types/api-responses.d.ts +39 -0
  42. package/dist/types/api-responses.js +12 -1
  43. package/dist/types/design-profile.d.ts +12 -0
  44. package/dist/types/design-profile.js +10 -1
  45. package/dist/types/rivet-page-types.d.ts +48 -0
  46. package/dist/types/rivet-page-types.js +6 -0
  47. package/dist/utils/failureReason.js +1 -1
  48. package/dist/utils/hostedLogPrivacy.js +1 -1
  49. package/dist/utils/launchRuntime.d.ts +2 -0
  50. package/dist/utils/launchRuntime.js +12 -0
  51. package/dist/utils/rivetPage.d.ts +8 -0
  52. package/dist/utils/rivetPage.js +24 -0
  53. package/dist/utils/rivetPage.testHelpers.d.ts +6 -0
  54. package/dist/utils/rivetPage.testHelpers.js +18 -0
  55. package/dist/utils/rivetPageDocument.d.ts +7 -0
  56. package/dist/utils/rivetPageDocument.js +41 -0
  57. package/dist/utils/scriptJson.d.ts +2 -0
  58. package/dist/utils/scriptJson.js +9 -0
  59. package/dist/utils/skills/cli-guidance.d.ts +1 -1
  60. package/dist/utils/skills/cli-guidance.js +2 -1
  61. package/dist/utils/uiDistPath.d.ts +2 -0
  62. package/dist/utils/uiDistPath.js +22 -0
  63. package/package.json +8 -5
  64. package/src/ui/dist/assets/LibraryEntry-CSU5OJwC.js +2 -0
  65. package/src/ui/dist/assets/google-g-CpxN0HWb.png +0 -0
  66. package/src/ui/dist/assets/main-B89lcZEY.css +1 -0
  67. package/src/ui/dist/assets/main-DeCxjHC1.js +204 -0
  68. package/src/ui/dist/index.html +3 -3
  69. package/src/ui/dist/pages/empty-project.html +53 -0
  70. package/src/ui/dist/pages/rivet-page.html +53 -0
  71. package/dist/routes/emptyStatePage.d.ts +0 -2
  72. package/dist/routes/emptyStatePage.js +0 -589
  73. package/src/ui/dist/assets/LibraryEntry-DS6Ce0sW.js +0 -112
  74. package/src/ui/dist/assets/logo-animation/clasp.png +0 -0
  75. package/src/ui/dist/assets/logo-animation/eraser.png +0 -0
  76. package/src/ui/dist/assets/logo-animation/playdough.png +0 -0
  77. package/src/ui/dist/assets/logo-animation/sea/bubblephone.png +0 -0
  78. package/src/ui/dist/assets/logo-animation/sea/cart.png +0 -0
  79. package/src/ui/dist/assets/logo-animation/sea/chair.png +0 -0
  80. package/src/ui/dist/assets/logo-animation/sea/desk.png +0 -0
  81. package/src/ui/dist/assets/logo-animation/sea/mug.png +0 -0
  82. package/src/ui/dist/assets/logo-animation/sea/pitcher.png +0 -0
  83. package/src/ui/dist/assets/logo-animation/sea/pot.png +0 -0
  84. package/src/ui/dist/assets/logo-animation/sea/startac.png +0 -0
  85. package/src/ui/dist/assets/logo-animation/sea/terracotta-1.png +0 -0
  86. package/src/ui/dist/assets/logo-animation/sea/terracotta-2.png +0 -0
  87. package/src/ui/dist/assets/logo-animation/sea/vhsplant.png +0 -0
  88. package/src/ui/dist/assets/main-CQSk-6km.css +0 -1
  89. package/src/ui/dist/assets/main-DkKRuatC.js +0 -218
package/dist/server.d.ts CHANGED
@@ -7,7 +7,6 @@ import type { VariantRunService } from './services/VariantRunService';
7
7
  import type { VariantsRuntime } from './services/VariantsRuntime';
8
8
  export declare const INACTIVE_VARIANTS_EVENT_HEARTBEAT_MS = 30000;
9
9
  export declare const RIVET_CORS_ALLOWED_HEADERS: string[];
10
- export declare const DIST_UI_PATH: string;
11
10
  type RivetUiBootstrap = {
12
11
  agentApplyMode: 'embedded' | 'external' | null;
13
12
  queueAccessToken: string | null;
@@ -58,6 +57,7 @@ export type ServerOptions = Omit<CLIOptions, 'help' | 'version' | 'debug'> & {
58
57
  userHost?: string;
59
58
  beforeShutdown?: () => Promise<void>;
60
59
  resolveLibraryOrigin?: () => string | undefined;
60
+ resolveProjectName?: (projectPath: string) => string | undefined;
61
61
  createLibraryViewUrl?: (view: 'projects' | 'references') => Promise<string | null>;
62
62
  };
63
63
  export type ServerHandle = {
package/dist/server.js CHANGED
@@ -36,7 +36,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
36
36
  return (mod && mod.__esModule) ? mod : { "default": mod };
37
37
  };
38
38
  Object.defineProperty(exports, "__esModule", { value: true });
39
- exports.startServer = exports.runServerShutdownTasks = exports.isRivetCorsOriginAllowed = exports.isRivetUiStaticAssetPath = exports.isEmbeddedAgentUiHost = exports.resolveEmbeddedAgentUiOrigin = exports.resolveRivetListenHost = exports.sendInactiveVariantsEventStream = exports.readRivetUiIndexHtml = exports.injectRivetUiBootstrap = exports.DIST_UI_PATH = exports.RIVET_CORS_ALLOWED_HEADERS = exports.INACTIVE_VARIANTS_EVENT_HEARTBEAT_MS = void 0;
39
+ exports.startServer = exports.runServerShutdownTasks = exports.isRivetCorsOriginAllowed = exports.isRivetUiStaticAssetPath = exports.isEmbeddedAgentUiHost = exports.resolveEmbeddedAgentUiOrigin = exports.resolveRivetListenHost = exports.sendInactiveVariantsEventStream = exports.readRivetUiIndexHtml = exports.injectRivetUiBootstrap = exports.RIVET_CORS_ALLOWED_HEADERS = exports.INACTIVE_VARIANTS_EVENT_HEARTBEAT_MS = void 0;
40
40
  const editorSession_1 = require("./cli/editorSession");
41
41
  const editorAccess_1 = require("./routes/editorAccess");
42
42
  const editorAccess_2 = require("./utils/editorAccess");
@@ -77,6 +77,8 @@ const VariantHistoryService_1 = require("./services/VariantHistoryService");
77
77
  const RequestAuthContext_1 = require("./services/RequestAuthContext");
78
78
  const middleware_1 = require("./routes/library/middleware");
79
79
  const errorMessage_1 = require("./utils/errorMessage");
80
+ const scriptJson_1 = require("./utils/scriptJson");
81
+ const uiDistPath_1 = require("./utils/uiDistPath");
80
82
  const pluginContext_1 = require("./hosts/pluginContext");
81
83
  const log = (0, index_core_1.createLogger)('RivetServer');
82
84
  const QUEUE_ACCESS_TOKEN_BYTES = 32;
@@ -93,36 +95,21 @@ exports.RIVET_CORS_ALLOWED_HEADERS = [
93
95
  'x-rivet-queue-token',
94
96
  editorAccess_2.EDITOR_ACCESS_TOKEN_HEADER,
95
97
  ];
96
- const resolveUiPath = () => {
97
- const bundledPath = path_1.default.join(__dirname, 'ui/dist');
98
- const devPath = path_1.default.join(__dirname, '../src/ui/dist');
99
- if (fs_1.default.existsSync(bundledPath)) {
100
- log.debug(`Using bundled UI path: ${bundledPath}`);
101
- return bundledPath;
102
- }
103
- log.debug(`Using development UI path: ${devPath}`);
104
- return devPath;
105
- };
106
- exports.DIST_UI_PATH = resolveUiPath();
107
98
  const NO_USER_DEV_SERVER_PORT = 0;
108
99
  const setNoStoreHeaders = (res) => {
109
100
  res.setHeader('Cache-Control', 'no-store, no-cache, must-revalidate, proxy-revalidate');
110
101
  res.setHeader('Pragma', 'no-cache');
111
102
  res.setHeader('Expires', '0');
112
103
  };
113
- const escapeScriptJson = (value) => JSON.stringify(value)
114
- .replace(/</g, '\\u003c')
115
- .replace(/\u2028/g, '\\u2028')
116
- .replace(/\u2029/g, '\\u2029');
117
104
  const injectRivetUiBootstrap = (html, bootstrap) => {
118
- const script = `<script id="${RIVET_BOOTSTRAP_SCRIPT_ID}">window.__RIVET_BOOTSTRAP__=${escapeScriptJson(bootstrap)};</script>`;
105
+ const script = `<script id="${RIVET_BOOTSTRAP_SCRIPT_ID}">window.__RIVET_BOOTSTRAP__=${(0, scriptJson_1.escapeScriptJson)(bootstrap)};</script>`;
119
106
  if (html.includes('</head>')) {
120
107
  return html.replace('</head>', `${script}</head>`);
121
108
  }
122
109
  return `${script}${html}`;
123
110
  };
124
111
  exports.injectRivetUiBootstrap = injectRivetUiBootstrap;
125
- const readRivetUiIndexHtml = () => fs_1.default.readFileSync(path_1.default.join(exports.DIST_UI_PATH, RIVET_UI_INDEX_FILENAME), 'utf8');
112
+ const readRivetUiIndexHtml = () => fs_1.default.readFileSync(path_1.default.join(uiDistPath_1.DIST_UI_PATH, RIVET_UI_INDEX_FILENAME), 'utf8');
126
113
  exports.readRivetUiIndexHtml = readRivetUiIndexHtml;
127
114
  const sendInactiveVariantsEventStream = (req, res) => {
128
115
  res.set({
@@ -366,15 +353,15 @@ const startServer = async (options) => {
366
353
  const serve = express_1.default.static(directory, uiStaticOptions);
367
354
  return (req, res, next) => isPreviewRequest(req) ? next() : serve(req, res, next);
368
355
  };
369
- app.use('/assets', serveEditorAssets(path_1.default.join(exports.DIST_UI_PATH, 'assets')));
370
- app.use('/rivet/assets', serveEditorAssets(path_1.default.join(exports.DIST_UI_PATH, 'assets')));
371
- app.use('/fonts', serveEditorAssets(path_1.default.join(exports.DIST_UI_PATH, 'fonts')));
372
- app.use('/rivet/fonts', serveEditorAssets(path_1.default.join(exports.DIST_UI_PATH, 'fonts')));
356
+ app.use('/assets', serveEditorAssets(path_1.default.join(uiDistPath_1.DIST_UI_PATH, 'assets')));
357
+ app.use('/rivet/assets', serveEditorAssets(path_1.default.join(uiDistPath_1.DIST_UI_PATH, 'assets')));
358
+ app.use('/fonts', serveEditorAssets(path_1.default.join(uiDistPath_1.DIST_UI_PATH, 'fonts')));
359
+ app.use('/rivet/fonts', serveEditorAssets(path_1.default.join(uiDistPath_1.DIST_UI_PATH, 'fonts')));
373
360
  app.get('/favicon.ico', (_req, res) => {
374
- res.sendFile('favicon.ico', { root: exports.DIST_UI_PATH });
361
+ res.sendFile('favicon.ico', { root: uiDistPath_1.DIST_UI_PATH });
375
362
  });
376
363
  app.get('/rivet/favicon.ico', (_req, res) => {
377
- res.sendFile('favicon.ico', { root: exports.DIST_UI_PATH });
364
+ res.sendFile('favicon.ico', { root: uiDistPath_1.DIST_UI_PATH });
378
365
  });
379
366
  app.get(/^\/rivet\/library(?:\/.*)?$/, (req, res) => {
380
367
  const resolvedLibraryOrigin = options.resolveLibraryOrigin?.();
@@ -391,7 +378,7 @@ const startServer = async (options) => {
391
378
  }
392
379
  sendRivetUiIndex(req, res);
393
380
  });
394
- log.info(`Serving UI assets from: ${exports.DIST_UI_PATH}`);
381
+ log.info(`Serving UI assets from: ${uiDistPath_1.DIST_UI_PATH}`);
395
382
  if (framework === 'static' && !hasUserDevServer) {
396
383
  app.get('/', (req, res, next) => {
397
384
  if (isPreviewRequest(req)) {
@@ -500,17 +487,19 @@ const startServer = async (options) => {
500
487
  app.get('/api/config', async (_req, res) => {
501
488
  const configManager = (0, ConfigManager_1.getConfigManager)();
502
489
  const livePath = sessionBridge?.getProjectPath() ?? projectPath;
490
+ const initiator = sessionBridge?.getSessionRuntimeInfo().sessionInitiator;
503
491
  res.json({
504
492
  agentModeAvailable: configManager.isAuthenticated(),
505
493
  email: configManager.getEmail(),
506
494
  userId: configManager.getUserId(),
507
495
  name: configManager.getDisplayName(),
508
496
  isMCPSession: sessionBridge?.isActive() ?? false,
509
- mcpEditor: mcpEditor ?? null,
497
+ mcpEditor: mcpEditor ?? (initiator?.kind === 'agent' ? initiator.agent : null),
510
498
  agentApplyMode: sessionBridge?.isActive()
511
499
  ? (agentApplyMode ?? 'external')
512
500
  : null,
513
501
  projectPath: livePath,
502
+ projectName: options.resolveProjectName?.(livePath) ?? path_1.default.basename(livePath),
514
503
  projectId: options.projectId ?? null,
515
504
  libraryOrigin: options.resolveLibraryOrigin?.() ?? null,
516
505
  });
@@ -36,6 +36,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.AuthService = exports.validateAccessToken = void 0;
37
37
  const zod_1 = require("zod");
38
38
  const logger_1 = require("../utils/logger");
39
+ const rivetPage_1 = require("../utils/rivetPage");
40
+ const rivet_page_types_1 = require("../types/rivet-page-types");
39
41
  const ConfigManager_1 = require("./ConfigManager");
40
42
  const http_1 = require("http");
41
43
  const accessTokenRefresh_1 = require("./accessTokenRefresh");
@@ -46,7 +48,6 @@ const proxy_1 = require("../config/proxy");
46
48
  const log = (0, logger_1.createLogger)('AuthService');
47
49
  const LOOPBACK_HOST = '127.0.0.1';
48
50
  const LOOPBACK_PORT = 0;
49
- const CALLBACK_COMPLETE_PATH = '/complete';
50
51
  const OAUTH_CALLBACK_TIMEOUT_MS = 120_000;
51
52
  const MAX_CALLBACK_BODY_BYTES = 64 * 1024;
52
53
  const PROFILE_FETCH_TIMEOUT_MS = 10_000;
@@ -101,64 +102,6 @@ const readRequestBody = (request) => {
101
102
  request.on('error', reject);
102
103
  });
103
104
  };
104
- const getLoopbackCallbackHtml = () => {
105
- return `<!doctype html>
106
- <html>
107
- <head>
108
- <meta charset="utf-8" />
109
- <meta name="viewport" content="width=device-width, initial-scale=1" />
110
- <title>Rivet authentication</title>
111
- <style>
112
- body {
113
- margin: 0;
114
- min-height: 100vh;
115
- display: grid;
116
- place-items: center;
117
- font-family: system-ui, sans-serif;
118
- background: #0b0b0f;
119
- color: #fff;
120
- }
121
- main {
122
- max-width: 420px;
123
- padding: 32px;
124
- text-align: center;
125
- }
126
- </style>
127
- </head>
128
- <body>
129
- <main>
130
- <h1>Finishing Rivet sign in...</h1>
131
- <p>You can return to your editor after this page completes.</p>
132
- </main>
133
- <script>
134
- const params = new URLSearchParams(window.location.search);
135
- const hash = new URLSearchParams(window.location.hash.slice(1));
136
- if (window.location.hash) {
137
- window.history.replaceState(
138
- null,
139
- document.title,
140
- window.location.pathname + window.location.search
141
- );
142
- }
143
- fetch('/complete', {
144
- method: 'POST',
145
- headers: { 'Content-Type': 'application/json' },
146
- body: JSON.stringify({
147
- sessionId: params.get('session'),
148
- accessToken: hash.get('access_token'),
149
- refreshToken: hash.get('refresh_token')
150
- })
151
- }).then((response) => {
152
- document.querySelector('h1').textContent = response.ok
153
- ? 'Rivet sign in complete'
154
- : 'Rivet sign in failed';
155
- }).catch(() => {
156
- document.querySelector('h1').textContent = 'Rivet sign in failed';
157
- });
158
- </script>
159
- </body>
160
- </html>`;
161
- };
162
105
  const validateAccessToken = async (proxyUrl, accessToken) => {
163
106
  const response = await fetch(`${proxyUrl.replace(/\/$/, '')}/api/user/profile`, {
164
107
  method: 'GET',
@@ -204,11 +147,14 @@ const createLoopbackOAuthCallback = async () => {
204
147
  const server = (0, http_1.createServer)((request, response) => {
205
148
  const url = new URL(request.url ?? '/', `http://${LOOPBACK_HOST}`);
206
149
  if (request.method === 'GET') {
207
- sendTextResponse(response, 200, getLoopbackCallbackHtml());
150
+ sendTextResponse(response, 200, (0, rivetPage_1.renderRivetPage)({
151
+ page: { kind: 'sign-in-callback' },
152
+ head: { title: 'Rivet authentication' },
153
+ }));
208
154
  return;
209
155
  }
210
156
  if (request.method !== 'POST' ||
211
- url.pathname !== CALLBACK_COMPLETE_PATH) {
157
+ url.pathname !== rivet_page_types_1.SIGN_IN_CALLBACK_COMPLETE_PATH) {
212
158
  sendTextResponse(response, 404, 'Not found');
213
159
  return;
214
160
  }
@@ -114,6 +114,7 @@ export type IntegrationDisconnectResult = {
114
114
  status: 'ok';
115
115
  } | {
116
116
  status: 'error';
117
+ reason: 'auth_required' | 'account_changed' | 'request_failed';
117
118
  message: string;
118
119
  };
119
120
  export type IntegrationProvider = 'pinterest' | 'arena' | 'x';
@@ -213,6 +214,6 @@ export declare class IntegrationsClient {
213
214
  }): Promise<XBookmarksResult>;
214
215
  listIntegrations(): Promise<IntegrationListResult>;
215
216
  connect(provider: IntegrationProvider): Promise<IntegrationConnectResult>;
216
- disconnect(provider: IntegrationProvider): Promise<IntegrationDisconnectResult>;
217
+ disconnect(provider: IntegrationProvider, expectedAccountId?: string): Promise<IntegrationDisconnectResult>;
217
218
  }
218
219
  //# sourceMappingURL=IntegrationsClient.d.ts.map
@@ -17,6 +17,7 @@ const RequestAuthContext_1 = require("./RequestAuthContext");
17
17
  const errorMessage_1 = require("../utils/errorMessage");
18
18
  const log = (0, logger_1.createLogger)('IntegrationsClient');
19
19
  const REQUEST_TIMEOUT_MS = 30_000;
20
+ const ACCOUNT_CHANGED_MESSAGE = 'Rivet account changed. Retry with the intended account.';
20
21
  const NormalizedPinSchema = zod_1.z.object({
21
22
  id: zod_1.z.string(),
22
23
  image_urls: zod_1.z.array(zod_1.z.string()),
@@ -132,6 +133,8 @@ const IntegrationConnectBodySchema = zod_1.z.object({
132
133
  message: zod_1.z.string().optional(),
133
134
  error: zod_1.z.string().optional(),
134
135
  });
136
+ const IntegrationDisconnectBodySchema = zod_1.z.object({ success: zod_1.z.literal(true) });
137
+ const XDisconnectBodySchema = zod_1.z.object({ status: zod_1.z.literal('ok') });
135
138
  const INTEGRATION_PROVIDERS = [
136
139
  'pinterest',
137
140
  'arena',
@@ -160,7 +163,7 @@ class IntegrationsClient {
160
163
  }
161
164
  return token;
162
165
  }
163
- async requestWithBearer(request) {
166
+ async requestWithBearer(request, expectedAccountId) {
164
167
  const token = await this.getBearerToken();
165
168
  if (!token) {
166
169
  return null;
@@ -182,6 +185,9 @@ class IntegrationsClient {
182
185
  if (!refreshed) {
183
186
  return response;
184
187
  }
188
+ if (expectedAccountId !== undefined &&
189
+ this.configManager.getUserId() !== expectedAccountId)
190
+ throw new Error(ACCOUNT_CHANGED_MESSAGE);
185
191
  updateAuth(refreshed);
186
192
  return request(refreshed.token);
187
193
  }
@@ -492,31 +498,51 @@ class IntegrationsClient {
492
498
  };
493
499
  }
494
500
  }
495
- async disconnect(provider) {
496
- const del = async (bearer) => fetch(`${this.proxyUrl}/api/integrations/${provider}`, {
497
- method: 'DELETE',
498
- headers: { Authorization: `Bearer ${bearer}` },
499
- });
501
+ async disconnect(provider, expectedAccountId) {
502
+ const isAccountCurrent = () => expectedAccountId === undefined ||
503
+ this.configManager.getUserId() === expectedAccountId;
504
+ const accountChanged = {
505
+ status: 'error',
506
+ reason: 'account_changed',
507
+ message: ACCOUNT_CHANGED_MESSAGE,
508
+ };
509
+ const requestFailed = {
510
+ status: 'error',
511
+ reason: 'request_failed',
512
+ message: 'Could not confirm reference account disconnection. Check your Rivet sign-in and connection, then retry.',
513
+ };
514
+ const del = async (bearer) => {
515
+ if (!isAccountCurrent())
516
+ throw new Error(accountChanged.message);
517
+ return fetch(`${this.proxyUrl}/api/integrations/${provider}`, {
518
+ method: 'DELETE',
519
+ headers: { Authorization: `Bearer ${bearer}` },
520
+ signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),
521
+ });
522
+ };
500
523
  try {
501
- const response = await this.requestWithBearer(del);
502
- if (!response) {
503
- return { status: 'error', message: 'Not authenticated' };
504
- }
505
- if (!response.ok) {
506
- const text = await response.text().catch(() => '');
524
+ if (!isAccountCurrent())
525
+ return accountChanged;
526
+ const response = await this.requestWithBearer(del, expectedAccountId);
527
+ if (!response || response.status === 401)
507
528
  return {
508
529
  status: 'error',
509
- message: `Disconnect failed (${response.status}): ${text.slice(0, 200)}`,
530
+ reason: 'auth_required',
531
+ message: 'Sign in to Rivet before disconnecting a reference account.',
510
532
  };
511
- }
533
+ if (!response.ok)
534
+ return requestFailed;
535
+ const acknowledgement = await response.json();
536
+ const schema = provider === 'x'
537
+ ? XDisconnectBodySchema
538
+ : IntegrationDisconnectBodySchema;
539
+ if (!schema.safeParse(acknowledgement).success)
540
+ return requestFailed;
512
541
  return { status: 'ok' };
513
542
  }
514
- catch (error) {
515
- log.warn('Integration disconnect error:', error);
516
- return {
517
- status: 'error',
518
- message: (0, errorMessage_1.errorMessage)(error, 'Unknown error'),
519
- };
543
+ catch {
544
+ log.warn('Integration disconnect request failed');
545
+ return isAccountCurrent() ? requestFailed : accountChanged;
520
546
  }
521
547
  }
522
548
  }
@@ -1,6 +1,7 @@
1
1
  import { type AccountIdentity } from './ConfigManager';
2
2
  import type { BrowserMetadata, DesignContextKind, ServerUnavailableReason, VariantContextMetadata, VerificationMetadata } from '../cli/telemetry';
3
3
  import type { GuidanceErrorCode, GuidanceSelection } from '../types/guidance';
4
+ import { type ProfileImportKind, type ProfileImportStep, type ProfileMedia, type ProfilePreparationOffReason, type ProfileProvider } from '../types/design-profile';
4
5
  import type { MCPAuthMethod, MCPAuthState, MCPOnboardingCorrelation, MCPOAuthCallbackResult } from './MCPOnboardingTelemetry';
5
6
  import { type MCPVariantsTelemetryMetadata } from './MCPVariantsTelemetry';
6
7
  export type RequestRejectionReason = 'host_not_allowed' | 'origin_not_allowed' | 'editor_token_on_preview';
@@ -21,13 +22,25 @@ export interface LibraryOperation {
21
22
  error?: unknown;
22
23
  }
23
24
  export interface ProfileOperation {
24
- stage: 'action' | 'import' | 'preparation' | 'maintenance';
25
- operation: 'reference_discovery' | 'reference_lookup' | 'reference_search' | 'reference_plan' | 'reference_approval' | 'reference_onboarding' | 'reference_onboarding_offered' | 'enable' | 'disable' | 'text_import' | 'image_import' | 'variant_import' | 'source_connect' | 'source_refresh' | 'job_control' | 'source_control' | 'index_rebuild' | 'import' | 'preparation';
25
+ stage: 'action' | 'import' | 'preparation' | 'maintenance' | 'analysis';
26
+ operation: 'reference_discovery' | 'reference_lookup' | 'reference_search' | 'reference_plan' | 'reference_approval' | 'reference_onboarding' | 'reference_onboarding_offered' | 'enable' | 'disable' | 'text_import' | 'image_import' | 'variant_import' | 'source_connect' | 'source_refresh' | 'job_control' | 'source_control' | 'index_rebuild' | 'import' | 'preparation' | 'analysis';
26
27
  outcome: 'completed' | 'failed' | 'deferred';
27
28
  durationMs: number;
28
29
  referenceCount?: number;
29
30
  status?: 'selected' | 'empty' | 'off' | 'unavailable' | 'timeout';
30
31
  error?: unknown;
32
+ provider?: ProfileProvider;
33
+ importKind?: ProfileImportKind;
34
+ failedStep?: ProfileImportStep;
35
+ addedCount?: number;
36
+ removedCount?: number;
37
+ staleHours?: number;
38
+ mediaKind?: ProfileMedia['representation'] | 'text' | 'mixed';
39
+ candidateCount?: number;
40
+ providerMix?: ProfileProvider[];
41
+ offReason?: ProfilePreparationOffReason;
42
+ providerCount?: number;
43
+ sourceCount?: number;
31
44
  }
32
45
  export interface GuidanceOperation {
33
46
  operation: 'add' | 'update' | 'remove' | 'resolve' | 'delivery' | 'verifier';
@@ -78,6 +91,7 @@ export declare class TelemetryService {
78
91
  callerRunId?: string;
79
92
  designContextKind?: DesignContextKind;
80
93
  source?: 'cli' | 'mcp';
94
+ error?: unknown;
81
95
  } & VariantContextMetadata & BrowserMetadata & VerificationMetadata): void;
82
96
  trackAuthStarted(data: {
83
97
  surface: AuthTelemetrySurface;
@@ -13,6 +13,7 @@ const telemetryContract_1 = require("../config/telemetryContract");
13
13
  const failureReason_1 = require("../utils/failureReason");
14
14
  const posthog_1 = require("../config/posthog");
15
15
  const proxy_1 = require("../config/proxy");
16
+ const design_profile_1 = require("../types/design-profile");
16
17
  const MCPVariantsTelemetry_1 = require("./MCPVariantsTelemetry");
17
18
  const errorMessage_1 = require("../utils/errorMessage");
18
19
  const serverUnavailable_1 = require("../cli/serverUnavailable");
@@ -43,6 +44,7 @@ const mcpEditorEventValue = (editor) => {
43
44
  return 'other';
44
45
  };
45
46
  const HASH_PREFIX_LENGTH = 12;
47
+ const optionalProperty = (key, value) => value === undefined ? {} : { [key]: value };
46
48
  class TelemetryService {
47
49
  trackGuidanceOperation(data) {
48
50
  this.track(`mcp_guidance_${data.operation}_${data.outcome}`, {
@@ -62,7 +64,20 @@ class TelemetryService {
62
64
  ...(data.referenceCount !== undefined
63
65
  ? { reference_count: data.referenceCount }
64
66
  : {}),
67
+ ...optionalProperty('candidate_count', data.candidateCount),
65
68
  ...(data.status ? { status: data.status } : {}),
69
+ ...optionalProperty('off_reason', data.offReason),
70
+ ...optionalProperty('provider_mix', data.providerMix),
71
+ ...optionalProperty('provider', data.provider),
72
+ ...optionalProperty('media_kind', data.mediaKind),
73
+ ...optionalProperty('job_kind', data.importKind),
74
+ ...optionalProperty('trigger', data.importKind && design_profile_1.PROFILE_IMPORT_TRIGGERS[data.importKind]),
75
+ ...optionalProperty('failed_step', data.failedStep),
76
+ ...optionalProperty('added_count', data.addedCount),
77
+ ...optionalProperty('removed_count', data.removedCount),
78
+ ...optionalProperty('stale_hours', data.staleHours),
79
+ ...optionalProperty('provider_count', data.providerCount),
80
+ ...optionalProperty('source_count', data.sourceCount),
66
81
  ...(0, failureReason_1.failureReasonCodeProperties)(data.error),
67
82
  });
68
83
  }
@@ -306,6 +321,9 @@ class TelemetryService {
306
321
  error_code: data.errorCode,
307
322
  is_recoverable: data.isRecoverable,
308
323
  server_unavailable_reason: data.serverUnavailableReason,
324
+ ...(data.command === 'mcp'
325
+ ? (0, failureReason_1.failureReasonProperties)(data.error)
326
+ : (0, failureReason_1.failureReasonCodeProperties)(data.error)),
309
327
  duration_ms: data.durationMs,
310
328
  caller_agent: data.callerAgent,
311
329
  caller_model: data.callerModel,
@@ -79,8 +79,8 @@ const refreshAccessTokenViaProxy = async (params) => {
79
79
  }
80
80
  return null;
81
81
  }
82
- catch (error) {
83
- log.warn('Proxy token refresh request failed', { error });
82
+ catch {
83
+ log.warn('Proxy token refresh request failed');
84
84
  return null;
85
85
  }
86
86
  };
@@ -74,6 +74,7 @@ export declare class DesignProfiles {
74
74
  revision: number;
75
75
  stage: "download" | "analysis";
76
76
  error: string;
77
+ reasonCode: "timeout" | "unknown" | "aborted" | "multiple_lockfiles" | "unsupported_package_manager" | "invalid_package_manager_field" | "invalid_manifest" | "invalid_workspace" | "path_outside_workspace" | "dangling_symlink" | "version_unreadable" | "version_mismatch" | "no_install_command" | "install_failed" | "lockfile_outdated" | "engine_incompatible" | "install_script_failed" | "installer_unstoppable" | "inputs_changed" | "ENOENT" | "EACCES" | "EPERM" | "EEXIST" | "ENOTDIR" | "EISDIR" | "ELOOP" | "ENOSPC" | "EMFILE" | "EADDRINUSE" | "ECONNREFUSED" | "ECONNRESET" | "ETIMEDOUT" | "EBUSY" | "ENOTSUP" | "EINVAL" | "ENOTEMPTY" | "EROFS" | "EAI_AGAIN" | null;
77
78
  attempts: number;
78
79
  updatedAt: string;
79
80
  }[];
@@ -88,6 +89,8 @@ export declare class DesignProfiles {
88
89
  total: number | null;
89
90
  error: string | null;
90
91
  updatedAt: string;
92
+ addedCount: number;
93
+ removedCount: number;
91
94
  }[];
92
95
  id: string;
93
96
  revision: string;
@@ -687,6 +690,8 @@ export declare class DesignProfiles {
687
690
  total: number | null;
688
691
  error: string | null;
689
692
  updatedAt: string;
693
+ addedCount: number;
694
+ removedCount: number;
690
695
  }[];
691
696
  rebuild: {
692
697
  singleton: number;
@@ -720,6 +725,7 @@ export declare class DesignProfiles {
720
725
  revision: number;
721
726
  stage: "download" | "analysis";
722
727
  error: string;
728
+ reasonCode: "timeout" | "unknown" | "aborted" | "multiple_lockfiles" | "unsupported_package_manager" | "invalid_package_manager_field" | "invalid_manifest" | "invalid_workspace" | "path_outside_workspace" | "dangling_symlink" | "version_unreadable" | "version_mismatch" | "no_install_command" | "install_failed" | "lockfile_outdated" | "engine_incompatible" | "install_script_failed" | "installer_unstoppable" | "inputs_changed" | "ENOENT" | "EACCES" | "EPERM" | "EEXIST" | "ENOTDIR" | "EISDIR" | "ELOOP" | "ENOSPC" | "EMFILE" | "EADDRINUSE" | "ECONNREFUSED" | "ECONNRESET" | "ETIMEDOUT" | "EBUSY" | "ENOTSUP" | "EINVAL" | "ENOTEMPTY" | "EROFS" | "EAI_AGAIN" | null;
723
729
  attempts: number;
724
730
  updatedAt: string;
725
731
  }[];
@@ -768,6 +774,8 @@ export declare class DesignProfiles {
768
774
  total: number | null;
769
775
  error: string | null;
770
776
  updatedAt: string;
777
+ addedCount: number;
778
+ removedCount: number;
771
779
  }[];
772
780
  rebuild: {
773
781
  singleton: number;
@@ -828,6 +836,8 @@ export declare class DesignProfiles {
828
836
  total: number | null;
829
837
  error: string | null;
830
838
  updatedAt: string;
839
+ addedCount: number;
840
+ removedCount: number;
831
841
  }[];
832
842
  rebuild: {
833
843
  singleton: number;
@@ -965,6 +975,8 @@ export declare class DesignProfiles {
965
975
  total: number | null;
966
976
  error: string | null;
967
977
  updatedAt: string;
978
+ addedCount: number;
979
+ removedCount: number;
968
980
  };
969
981
  } | {
970
982
  status: "authorization_required";
@@ -1003,6 +1015,8 @@ export declare class DesignProfiles {
1003
1015
  total: number | null;
1004
1016
  error: string | null;
1005
1017
  updatedAt: string;
1018
+ addedCount: number;
1019
+ removedCount: number;
1006
1020
  }[];
1007
1021
  rebuild: {
1008
1022
  singleton: number;
@@ -1049,6 +1063,8 @@ export declare class DesignProfiles {
1049
1063
  total: number | null;
1050
1064
  error: string | null;
1051
1065
  updatedAt: string;
1066
+ addedCount: number;
1067
+ removedCount: number;
1052
1068
  };
1053
1069
  }>;
1054
1070
  updateSource({ id, isIncluded, isRemoved, runtime, }: {