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.
- package/dist/cli/commands/libraryOpen.js +1 -0
- package/dist/cli/commands/mcpServe.js +5 -1
- package/dist/cli/commands/open.js +17 -6
- package/dist/cli/commands/profile.js +8 -1
- package/dist/cli/commands/profileDisconnect.d.ts +3 -0
- package/dist/cli/commands/profileDisconnect.js +34 -0
- package/dist/cli/commands/serve.js +2 -0
- package/dist/cli/commands/shared.js +4 -1
- package/dist/cli/envelope.d.ts +1 -0
- package/dist/cli/router.js +8 -2
- package/dist/jest.globalSetup.d.ts +3 -0
- package/dist/jest.globalSetup.js +19 -0
- package/dist/library/browserLaunch.d.ts +2 -1
- package/dist/library/browserLaunch.js +3 -2
- package/dist/proxy-middleware/proxy-config.d.ts +0 -1
- package/dist/proxy-middleware/proxy-config.js +6 -34
- package/dist/routes/agentVariants.js +20 -173
- package/dist/routes/referenceProfiles.js +3 -3
- package/dist/routes/static.js +8 -2
- package/dist/server.d.ts +1 -1
- package/dist/server.js +15 -26
- package/dist/services/AuthService.js +7 -61
- package/dist/services/IntegrationsClient.d.ts +2 -1
- package/dist/services/IntegrationsClient.js +46 -20
- package/dist/services/TelemetryService.d.ts +16 -2
- package/dist/services/TelemetryService.js +18 -0
- package/dist/services/accessTokenRefresh.js +2 -2
- package/dist/services/profiles/DesignProfiles.d.ts +16 -0
- package/dist/services/profiles/DesignProfiles.js +78 -17
- package/dist/services/profiles/ProfileAnalysis.d.ts +3 -0
- package/dist/services/profiles/ProfileAnalysis.js +66 -1
- package/dist/services/profiles/ProfileImports.d.ts +2 -0
- package/dist/services/profiles/ProfileImports.js +2 -0
- package/dist/services/templates/viteReactTs.js +1 -1
- package/dist/storage/profiles/ProfileRecords.d.ts +17 -0
- package/dist/storage/profiles/ProfileRecords.js +45 -7
- package/dist/storage/profiles/migrations.d.ts +2 -2
- package/dist/storage/profiles/migrations.js +7 -0
- package/dist/storage/profiles/schema.d.ts +48 -0
- package/dist/storage/profiles/schema.js +3 -0
- package/dist/types/api-responses.d.ts +39 -0
- package/dist/types/api-responses.js +12 -1
- package/dist/types/design-profile.d.ts +12 -0
- package/dist/types/design-profile.js +10 -1
- package/dist/types/rivet-page-types.d.ts +48 -0
- package/dist/types/rivet-page-types.js +6 -0
- package/dist/utils/failureReason.js +1 -1
- package/dist/utils/hostedLogPrivacy.js +1 -1
- package/dist/utils/launchRuntime.d.ts +2 -0
- package/dist/utils/launchRuntime.js +12 -0
- package/dist/utils/rivetPage.d.ts +8 -0
- package/dist/utils/rivetPage.js +24 -0
- package/dist/utils/rivetPage.testHelpers.d.ts +6 -0
- package/dist/utils/rivetPage.testHelpers.js +18 -0
- package/dist/utils/rivetPageDocument.d.ts +7 -0
- package/dist/utils/rivetPageDocument.js +41 -0
- package/dist/utils/scriptJson.d.ts +2 -0
- package/dist/utils/scriptJson.js +9 -0
- package/dist/utils/skills/cli-guidance.d.ts +1 -1
- package/dist/utils/skills/cli-guidance.js +2 -1
- package/dist/utils/uiDistPath.d.ts +2 -0
- package/dist/utils/uiDistPath.js +22 -0
- package/package.json +8 -5
- package/src/ui/dist/assets/LibraryEntry-CSU5OJwC.js +2 -0
- package/src/ui/dist/assets/google-g-CpxN0HWb.png +0 -0
- package/src/ui/dist/assets/main-B89lcZEY.css +1 -0
- package/src/ui/dist/assets/main-DeCxjHC1.js +204 -0
- package/src/ui/dist/index.html +3 -3
- package/src/ui/dist/pages/empty-project.html +53 -0
- package/src/ui/dist/pages/rivet-page.html +53 -0
- package/dist/routes/emptyStatePage.d.ts +0 -2
- package/dist/routes/emptyStatePage.js +0 -589
- package/src/ui/dist/assets/LibraryEntry-DS6Ce0sW.js +0 -112
- package/src/ui/dist/assets/logo-animation/clasp.png +0 -0
- package/src/ui/dist/assets/logo-animation/eraser.png +0 -0
- package/src/ui/dist/assets/logo-animation/playdough.png +0 -0
- package/src/ui/dist/assets/logo-animation/sea/bubblephone.png +0 -0
- package/src/ui/dist/assets/logo-animation/sea/cart.png +0 -0
- package/src/ui/dist/assets/logo-animation/sea/chair.png +0 -0
- package/src/ui/dist/assets/logo-animation/sea/desk.png +0 -0
- package/src/ui/dist/assets/logo-animation/sea/mug.png +0 -0
- package/src/ui/dist/assets/logo-animation/sea/pitcher.png +0 -0
- package/src/ui/dist/assets/logo-animation/sea/pot.png +0 -0
- package/src/ui/dist/assets/logo-animation/sea/startac.png +0 -0
- package/src/ui/dist/assets/logo-animation/sea/terracotta-1.png +0 -0
- package/src/ui/dist/assets/logo-animation/sea/terracotta-2.png +0 -0
- package/src/ui/dist/assets/logo-animation/sea/vhsplant.png +0 -0
- package/src/ui/dist/assets/main-CQSk-6km.css +0 -1
- package/src/ui/dist/assets/main-DkKRuatC.js +0 -218
|
@@ -41,8 +41,16 @@ const ProviderRateLimit_1 = require("../../utils/ProviderRateLimit");
|
|
|
41
41
|
const design_profile_3 = require("../../types/design-profile");
|
|
42
42
|
const errorMessage_1 = require("../../utils/errorMessage");
|
|
43
43
|
const APPROVAL_TIMEOUT_MS = 45_000;
|
|
44
|
+
const MS_PER_HOUR = 3_600_000;
|
|
44
45
|
const SAVED_REFERENCE_IMAGE_LIMIT = 20;
|
|
45
46
|
const VERIFICATION_TARGET_INSTRUCTIONS = 'Choose tools for the actual browser, simulator, or other target. Do not assume a URL, DOM, CSS, or Playwright. If required tools or the target are unavailable, report unable to verify.';
|
|
47
|
+
const preparationOffReason = ({ mode, isEnabled, }) => {
|
|
48
|
+
if (mode === 'off')
|
|
49
|
+
return 'request_mode_off';
|
|
50
|
+
if (!isEnabled)
|
|
51
|
+
return 'profile_disabled';
|
|
52
|
+
return 'no_uploads';
|
|
53
|
+
};
|
|
46
54
|
const librarySources = (records) => records.sources().map(({ id, title, provider, isIncluded }) => ({
|
|
47
55
|
id,
|
|
48
56
|
title,
|
|
@@ -544,21 +552,25 @@ class DesignProfiles {
|
|
|
544
552
|
async importReferences(input) {
|
|
545
553
|
const request = reference_onboarding_1.ReferenceApprovalSchema.parse(input);
|
|
546
554
|
const accountId = this.options.accountId();
|
|
555
|
+
if (!accountId)
|
|
556
|
+
throw new Error('Sign in to Rivet to connect design references');
|
|
557
|
+
const context = await this.context();
|
|
558
|
+
const wasEnabled = context.records.profile().isEnabled;
|
|
547
559
|
const plan = await this.withReferenceRecords(async (records, currentAccountId) => {
|
|
548
560
|
const pending = records.plans.plan(request.id);
|
|
549
561
|
if (!pending.approvedAt)
|
|
550
562
|
await this.planning(records, currentAccountId).verifyAccount(pending.profile, AbortSignal.timeout(APPROVAL_TIMEOUT_MS));
|
|
551
563
|
return records.approvePlan(request);
|
|
552
564
|
});
|
|
553
|
-
if (accountId !== this.options.accountId())
|
|
554
|
-
throw new Error('Profile account changed during import approval');
|
|
555
|
-
const context = await this.context();
|
|
556
565
|
if (context.accountId !== accountId ||
|
|
557
566
|
accountId !== this.options.accountId())
|
|
558
567
|
throw new Error('Profile account changed during import approval');
|
|
559
|
-
if (context.records.profile().isEnabled)
|
|
568
|
+
if (context.records.profile().isEnabled) {
|
|
569
|
+
if (!wasEnabled)
|
|
570
|
+
this.resume(context, plan.jobIds);
|
|
560
571
|
for (const id of plan.jobIds)
|
|
561
|
-
this.enqueue(context, () => this.runImport(context, id));
|
|
572
|
+
this.enqueue(context, () => this.runImport(context, id, 'connect'));
|
|
573
|
+
}
|
|
562
574
|
return (0, reference_onboarding_1.referencePlanSummary)(plan);
|
|
563
575
|
}
|
|
564
576
|
planning(records, accountId) {
|
|
@@ -668,12 +680,15 @@ class DesignProfiles {
|
|
|
668
680
|
await this.flush(context, job.runtime);
|
|
669
681
|
context.records.completeRebuild(job.id);
|
|
670
682
|
context.issue = null;
|
|
683
|
+
const sources = context.records.sources();
|
|
671
684
|
this.options.telemetry?.trackProfileOperation({
|
|
672
685
|
stage: 'maintenance',
|
|
673
686
|
operation: 'index_rebuild',
|
|
674
687
|
outcome: 'completed',
|
|
675
688
|
durationMs: Date.now() - started,
|
|
676
689
|
referenceCount: context.records.coverage().indexed,
|
|
690
|
+
providerCount: new Set(sources.map((source) => source.provider)).size,
|
|
691
|
+
sourceCount: sources.length,
|
|
677
692
|
});
|
|
678
693
|
}
|
|
679
694
|
catch (error) {
|
|
@@ -682,6 +697,7 @@ class DesignProfiles {
|
|
|
682
697
|
operation: 'index_rebuild',
|
|
683
698
|
outcome: 'failed',
|
|
684
699
|
durationMs: Date.now() - started,
|
|
700
|
+
error,
|
|
685
701
|
});
|
|
686
702
|
throw error;
|
|
687
703
|
}
|
|
@@ -763,7 +779,7 @@ class DesignProfiles {
|
|
|
763
779
|
isComplete: true,
|
|
764
780
|
total: new Set(references.map((reference) => reference.remoteId)).size,
|
|
765
781
|
});
|
|
766
|
-
this.enqueue(context, () => this.runImport(context, job.id));
|
|
782
|
+
this.enqueue(context, () => this.runImport(context, job.id, 'upload'));
|
|
767
783
|
return { source, jobId: job.id };
|
|
768
784
|
}
|
|
769
785
|
async pins(projectId) {
|
|
@@ -797,7 +813,7 @@ class DesignProfiles {
|
|
|
797
813
|
},
|
|
798
814
|
runtime: value.runtime,
|
|
799
815
|
});
|
|
800
|
-
this.enqueue(context, () => this.runImport(context, result.job.id));
|
|
816
|
+
this.enqueue(context, () => this.runImport(context, result.job.id, 'upload'));
|
|
801
817
|
return { source: result.source, jobId: result.job.id };
|
|
802
818
|
}
|
|
803
819
|
async connect(input) {
|
|
@@ -852,7 +868,7 @@ class DesignProfiles {
|
|
|
852
868
|
throw new Error('Profile account changed or was disabled during X authorization');
|
|
853
869
|
}
|
|
854
870
|
const result = context.imports.connect({ ...input, xAccount });
|
|
855
|
-
this.enqueue(context, () => this.runImport(context, result.job.id));
|
|
871
|
+
this.enqueue(context, () => this.runImport(context, result.job.id, 'connect'));
|
|
856
872
|
return result;
|
|
857
873
|
}
|
|
858
874
|
async updateJob({ id, action, }) {
|
|
@@ -866,7 +882,7 @@ class DesignProfiles {
|
|
|
866
882
|
state: action === 'pause' ? 'paused' : 'pending',
|
|
867
883
|
});
|
|
868
884
|
if (action !== 'pause')
|
|
869
|
-
this.enqueue(context, () => this.runImport(context, id));
|
|
885
|
+
this.enqueue(context, () => this.runImport(context, id, 'retry'));
|
|
870
886
|
return this.status();
|
|
871
887
|
}
|
|
872
888
|
async refresh({ id, runtime }) {
|
|
@@ -880,7 +896,7 @@ class DesignProfiles {
|
|
|
880
896
|
if (!(0, design_profile_1.isRemoteProfileProvider)(source.provider))
|
|
881
897
|
throw new Error('Only connected provider sources support refresh');
|
|
882
898
|
const job = context.records.startImport({ sourceId: id, runtime });
|
|
883
|
-
this.enqueue(context, () => this.runImport(context, job.id));
|
|
899
|
+
this.enqueue(context, () => this.runImport(context, job.id, 'refresh'));
|
|
884
900
|
return { job };
|
|
885
901
|
}
|
|
886
902
|
async updateSource({ id, isIncluded, isRemoved, runtime, }) {
|
|
@@ -1152,13 +1168,26 @@ class DesignProfiles {
|
|
|
1152
1168
|
failedUploadCount: undefined,
|
|
1153
1169
|
}
|
|
1154
1170
|
: packet;
|
|
1171
|
+
const selectedProviders = result.selected.flatMap((item) => context.records.reference(item.id)?.provider ?? []);
|
|
1155
1172
|
this.options.telemetry?.trackProfileOperation({
|
|
1156
1173
|
stage: 'preparation',
|
|
1157
1174
|
operation: 'preparation',
|
|
1158
1175
|
outcome: 'completed',
|
|
1159
1176
|
durationMs: result.durationMs,
|
|
1160
1177
|
referenceCount: result.selected.length,
|
|
1178
|
+
candidateCount: result.candidateIds.length,
|
|
1161
1179
|
status: result.status,
|
|
1180
|
+
...(selectedProviders.length
|
|
1181
|
+
? { providerMix: [...new Set(selectedProviders)].sort() }
|
|
1182
|
+
: {}),
|
|
1183
|
+
...(result.status === 'off'
|
|
1184
|
+
? {
|
|
1185
|
+
offReason: preparationOffReason({
|
|
1186
|
+
mode: validated.mode,
|
|
1187
|
+
isEnabled: context.records.profile().isEnabled,
|
|
1188
|
+
}),
|
|
1189
|
+
}
|
|
1190
|
+
: {}),
|
|
1162
1191
|
});
|
|
1163
1192
|
return { ...result, profileId: context.records.profile().id, accountId };
|
|
1164
1193
|
}
|
|
@@ -1204,7 +1233,7 @@ class DesignProfiles {
|
|
|
1204
1233
|
runtime,
|
|
1205
1234
|
});
|
|
1206
1235
|
reference = context.records.references(saved.source.id)[0];
|
|
1207
|
-
this.enqueue(context, () => this.runImport(context, saved.job.id));
|
|
1236
|
+
this.enqueue(context, () => this.runImport(context, saved.job.id, 'attachment'));
|
|
1208
1237
|
}
|
|
1209
1238
|
if (!reference)
|
|
1210
1239
|
throw new Error('Saved image reference is unavailable');
|
|
@@ -1292,13 +1321,14 @@ class DesignProfiles {
|
|
|
1292
1321
|
media,
|
|
1293
1322
|
agent,
|
|
1294
1323
|
isCurrentAccount: () => this.options.accountId() === accountId,
|
|
1324
|
+
telemetry: this.options.telemetry,
|
|
1295
1325
|
}),
|
|
1296
1326
|
schedule: new ProfileImportSchedule_1.ProfileImportSchedule({
|
|
1297
1327
|
records,
|
|
1298
1328
|
isActive: () => this.current === context &&
|
|
1299
1329
|
!context.abort.signal.aborted &&
|
|
1300
1330
|
this.options.accountId() === accountId,
|
|
1301
|
-
onReady: (id) => this.enqueue(context, () => this.runImport(context, id)),
|
|
1331
|
+
onReady: (id) => this.enqueue(context, () => this.runImport(context, id, 'cooldown_retry')),
|
|
1302
1332
|
}),
|
|
1303
1333
|
abort: new AbortController(),
|
|
1304
1334
|
work: Promise.resolve(),
|
|
@@ -1316,15 +1346,15 @@ class DesignProfiles {
|
|
|
1316
1346
|
this.opening = undefined;
|
|
1317
1347
|
}
|
|
1318
1348
|
}
|
|
1319
|
-
resume(context) {
|
|
1349
|
+
resume(context, claimedJobIds = []) {
|
|
1320
1350
|
this.enqueue(context, async () => {
|
|
1321
1351
|
await context.memory.start();
|
|
1322
1352
|
context.issue = null;
|
|
1323
1353
|
});
|
|
1324
1354
|
for (const job of context.records
|
|
1325
1355
|
.jobs()
|
|
1326
|
-
.filter((job) => job.state === 'pending'))
|
|
1327
|
-
this.enqueue(context, () => this.runImport(context, job.id));
|
|
1356
|
+
.filter((job) => job.state === 'pending' && !claimedJobIds.includes(job.id)))
|
|
1357
|
+
this.enqueue(context, () => this.runImport(context, job.id, 'resume'));
|
|
1328
1358
|
this.enqueue(context, () => this.runRebuild(context));
|
|
1329
1359
|
}
|
|
1330
1360
|
enqueue(context, operation) {
|
|
@@ -1343,36 +1373,64 @@ class DesignProfiles {
|
|
|
1343
1373
|
while (context.records.pendingIndex(1).length)
|
|
1344
1374
|
await context.index.flush(runtime, context.abort.signal);
|
|
1345
1375
|
}
|
|
1346
|
-
async runImport(context, id) {
|
|
1376
|
+
async runImport(context, id, kind) {
|
|
1347
1377
|
if (!context.schedule.isReady(id))
|
|
1348
1378
|
return;
|
|
1349
1379
|
const job = context.records.jobs().find((item) => item.id === id);
|
|
1350
1380
|
if (!job || job.state !== 'pending')
|
|
1351
1381
|
return;
|
|
1352
1382
|
const started = Date.now();
|
|
1383
|
+
const importContext = {
|
|
1384
|
+
provider: context.records
|
|
1385
|
+
.sources()
|
|
1386
|
+
.find((source) => source.id === job.sourceId)?.provider,
|
|
1387
|
+
importKind: kind,
|
|
1388
|
+
};
|
|
1389
|
+
const syncTimes = context.records
|
|
1390
|
+
.jobs()
|
|
1391
|
+
.filter((item) => item.sourceId === job.sourceId && item.state === 'complete')
|
|
1392
|
+
.map((item) => Date.parse(item.updatedAt));
|
|
1393
|
+
const lastSyncedAt = syncTimes.length ? Math.max(...syncTimes) : undefined;
|
|
1394
|
+
let step = 'memory_start';
|
|
1353
1395
|
try {
|
|
1354
1396
|
await context.memory.start();
|
|
1355
1397
|
const source = context.records.source(job.sourceId);
|
|
1356
|
-
|
|
1398
|
+
const isSync = (0, design_profile_1.isRemoteProfileProvider)(source.provider);
|
|
1399
|
+
if (isSync) {
|
|
1400
|
+
step = 'enumerate';
|
|
1357
1401
|
await context.imports.enumerate(id, context.abort.signal);
|
|
1402
|
+
step = 'download';
|
|
1358
1403
|
await context.imports.download(id, context.abort.signal);
|
|
1359
1404
|
}
|
|
1405
|
+
step = 'analysis';
|
|
1360
1406
|
await context.analysis.run({ jobId: id, signal: context.abort.signal });
|
|
1361
1407
|
if (context.records.jobs().find((item) => item.id === id)?.state !==
|
|
1362
1408
|
'pending')
|
|
1363
1409
|
return;
|
|
1410
|
+
step = 'index';
|
|
1364
1411
|
context.records.queueIndex(job.runtime);
|
|
1365
1412
|
await this.runRebuild(context);
|
|
1366
1413
|
if (context.records.jobs().find((item) => item.id === id)?.state !==
|
|
1367
1414
|
'pending')
|
|
1368
1415
|
return;
|
|
1369
1416
|
context.records.updateJob({ id, state: 'complete' });
|
|
1417
|
+
const completed = context.records.jobs().find((item) => item.id === id);
|
|
1370
1418
|
this.options.telemetry?.trackProfileOperation({
|
|
1371
1419
|
stage: 'import',
|
|
1372
1420
|
operation: 'import',
|
|
1373
1421
|
outcome: 'completed',
|
|
1374
1422
|
durationMs: Date.now() - started,
|
|
1375
1423
|
referenceCount: context.records.references(job.sourceId).length,
|
|
1424
|
+
...importContext,
|
|
1425
|
+
...(isSync && completed
|
|
1426
|
+
? {
|
|
1427
|
+
addedCount: completed.addedCount,
|
|
1428
|
+
removedCount: completed.removedCount,
|
|
1429
|
+
...(lastSyncedAt === undefined
|
|
1430
|
+
? {}
|
|
1431
|
+
: { staleHours: (started - lastSyncedAt) / MS_PER_HOUR }),
|
|
1432
|
+
}
|
|
1433
|
+
: {}),
|
|
1376
1434
|
});
|
|
1377
1435
|
}
|
|
1378
1436
|
catch (error) {
|
|
@@ -1387,6 +1445,7 @@ class DesignProfiles {
|
|
|
1387
1445
|
operation: 'import',
|
|
1388
1446
|
outcome: 'deferred',
|
|
1389
1447
|
durationMs: Date.now() - started,
|
|
1448
|
+
...importContext,
|
|
1390
1449
|
});
|
|
1391
1450
|
return;
|
|
1392
1451
|
}
|
|
@@ -1395,6 +1454,8 @@ class DesignProfiles {
|
|
|
1395
1454
|
operation: 'import',
|
|
1396
1455
|
outcome: 'failed',
|
|
1397
1456
|
durationMs: Date.now() - started,
|
|
1457
|
+
...importContext,
|
|
1458
|
+
failedStep: error instanceof ProfileRecords_1.UnfinishedImport ? error.step : step,
|
|
1398
1459
|
error,
|
|
1399
1460
|
});
|
|
1400
1461
|
if (!context.abort.signal.aborted &&
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import type { ProfileRecords } from '../../storage/profiles/ProfileRecords';
|
|
2
2
|
import type { ProfileMedia } from './ProfileMedia';
|
|
3
3
|
import type { ProfileAgent } from './ProfileAgent';
|
|
4
|
+
import type { TelemetryService } from '../TelemetryService';
|
|
4
5
|
interface ProfileAnalysisOptions {
|
|
5
6
|
records: ProfileRecords;
|
|
6
7
|
media: ProfileMedia;
|
|
7
8
|
agent: Pick<ProfileAgent, 'run'>;
|
|
8
9
|
isCurrentAccount: () => boolean;
|
|
9
10
|
batchSize?: 1 | 2 | 4;
|
|
11
|
+
telemetry?: Pick<TelemetryService, 'trackProfileOperation'>;
|
|
10
12
|
}
|
|
11
13
|
export declare class ProfileAnalysis {
|
|
12
14
|
private readonly options;
|
|
@@ -17,6 +19,7 @@ export declare class ProfileAnalysis {
|
|
|
17
19
|
}): Promise<void>;
|
|
18
20
|
private isPending;
|
|
19
21
|
private analyze;
|
|
22
|
+
private track;
|
|
20
23
|
private fail;
|
|
21
24
|
}
|
|
22
25
|
export {};
|
|
@@ -4,6 +4,15 @@ exports.ProfileAnalysis = void 0;
|
|
|
4
4
|
const modelContract_1 = require("./modelContract");
|
|
5
5
|
const analysisBatch_1 = require("./analysisBatch");
|
|
6
6
|
const errorMessage_1 = require("../../utils/errorMessage");
|
|
7
|
+
const failureReason_1 = require("../../utils/failureReason");
|
|
8
|
+
const analysisMediaKind = (references) => {
|
|
9
|
+
const kinds = new Set(references.flatMap((reference) => reference.media.length
|
|
10
|
+
? reference.media.map((media) => media.representation)
|
|
11
|
+
: ['text']));
|
|
12
|
+
if (kinds.size > 1)
|
|
13
|
+
return 'mixed';
|
|
14
|
+
return [...kinds][0] ?? 'text';
|
|
15
|
+
};
|
|
7
16
|
class ProfileAnalysis {
|
|
8
17
|
options;
|
|
9
18
|
constructor(options) {
|
|
@@ -14,7 +23,12 @@ class ProfileAnalysis {
|
|
|
14
23
|
const job = records.jobs().find((item) => item.id === jobId);
|
|
15
24
|
if (!job || job.state !== 'pending')
|
|
16
25
|
return;
|
|
17
|
-
const input = {
|
|
26
|
+
const input = {
|
|
27
|
+
jobId,
|
|
28
|
+
runtime: job.runtime,
|
|
29
|
+
signal,
|
|
30
|
+
provider: records.source(job.sourceId).provider,
|
|
31
|
+
};
|
|
18
32
|
let batch = [];
|
|
19
33
|
for (const reference of records.references(job.sourceId)) {
|
|
20
34
|
if (!this.isPending(input))
|
|
@@ -23,6 +37,7 @@ class ProfileAnalysis {
|
|
|
23
37
|
continue;
|
|
24
38
|
if (reference.media.length < (reference.remoteImages?.length ?? 0))
|
|
25
39
|
continue;
|
|
40
|
+
let startedAt = Date.now();
|
|
26
41
|
try {
|
|
27
42
|
if (!(0, analysisBatch_1.fitsAnalysisBatch)([reference]))
|
|
28
43
|
throw new Error('Reference exceeds the analysis budget; split it into smaller references');
|
|
@@ -35,6 +50,7 @@ class ProfileAnalysis {
|
|
|
35
50
|
batch = [];
|
|
36
51
|
if (!this.isPending(input))
|
|
37
52
|
return;
|
|
53
|
+
startedAt = Date.now();
|
|
38
54
|
}
|
|
39
55
|
const images = await Promise.all(reference.media.map((image) => media.resolve(image)));
|
|
40
56
|
batch.push({ reference, images });
|
|
@@ -43,6 +59,13 @@ class ProfileAnalysis {
|
|
|
43
59
|
if (!this.isPending(input))
|
|
44
60
|
return;
|
|
45
61
|
this.fail({ jobId, reference, error });
|
|
62
|
+
this.track({
|
|
63
|
+
job: input,
|
|
64
|
+
references: [reference],
|
|
65
|
+
outcome: 'failed',
|
|
66
|
+
startedAt,
|
|
67
|
+
error,
|
|
68
|
+
});
|
|
46
69
|
}
|
|
47
70
|
}
|
|
48
71
|
if (batch.length && this.isPending(input))
|
|
@@ -60,6 +83,7 @@ class ProfileAnalysis {
|
|
|
60
83
|
return;
|
|
61
84
|
const { batch, runtime, signal, jobId } = input;
|
|
62
85
|
const { agent, records } = this.options;
|
|
86
|
+
const startedAt = Date.now();
|
|
63
87
|
let result;
|
|
64
88
|
try {
|
|
65
89
|
result = await agent.run({
|
|
@@ -73,8 +97,18 @@ class ProfileAnalysis {
|
|
|
73
97
|
return;
|
|
74
98
|
for (const { reference } of batch)
|
|
75
99
|
this.fail({ jobId, reference, error });
|
|
100
|
+
this.track({
|
|
101
|
+
job: input,
|
|
102
|
+
references: batch.map((item) => item.reference),
|
|
103
|
+
outcome: 'failed',
|
|
104
|
+
startedAt,
|
|
105
|
+
error,
|
|
106
|
+
});
|
|
76
107
|
return;
|
|
77
108
|
}
|
|
109
|
+
const analyzed = [];
|
|
110
|
+
const failed = [];
|
|
111
|
+
let failure;
|
|
78
112
|
for (const { reference, images } of batch) {
|
|
79
113
|
if (!this.isPending(input))
|
|
80
114
|
return;
|
|
@@ -95,11 +129,41 @@ class ProfileAnalysis {
|
|
|
95
129
|
usage: (0, analysisBatch_1.analysisUsage)((0, modelContract_1.reportedProfileUsage)(result.usage), batch.length),
|
|
96
130
|
});
|
|
97
131
|
records.clearFailure(reference.id, 'analysis');
|
|
132
|
+
analyzed.push(reference);
|
|
98
133
|
}
|
|
99
134
|
catch (error) {
|
|
100
135
|
this.fail({ jobId, reference, error });
|
|
136
|
+
failed.push(reference);
|
|
137
|
+
failure ??= error;
|
|
101
138
|
}
|
|
102
139
|
}
|
|
140
|
+
if (analyzed.length)
|
|
141
|
+
this.track({
|
|
142
|
+
job: input,
|
|
143
|
+
references: analyzed,
|
|
144
|
+
outcome: 'completed',
|
|
145
|
+
startedAt,
|
|
146
|
+
});
|
|
147
|
+
if (failed.length)
|
|
148
|
+
this.track({
|
|
149
|
+
job: input,
|
|
150
|
+
references: failed,
|
|
151
|
+
outcome: 'failed',
|
|
152
|
+
startedAt,
|
|
153
|
+
error: failure,
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
track({ job, references, outcome, startedAt, error, }) {
|
|
157
|
+
this.options.telemetry?.trackProfileOperation({
|
|
158
|
+
stage: 'analysis',
|
|
159
|
+
operation: 'analysis',
|
|
160
|
+
outcome,
|
|
161
|
+
durationMs: Date.now() - startedAt,
|
|
162
|
+
referenceCount: references.length,
|
|
163
|
+
provider: job.provider,
|
|
164
|
+
mediaKind: analysisMediaKind(references),
|
|
165
|
+
error,
|
|
166
|
+
});
|
|
103
167
|
}
|
|
104
168
|
fail({ jobId, reference, error, }) {
|
|
105
169
|
this.options.records.saveFailure({
|
|
@@ -108,6 +172,7 @@ class ProfileAnalysis {
|
|
|
108
172
|
revision: reference.revision,
|
|
109
173
|
stage: 'analysis',
|
|
110
174
|
error: (0, errorMessage_1.errorMessage)(error, 'Reference analysis failed'),
|
|
175
|
+
reasonCode: (0, failureReason_1.failureReasonCode)(error),
|
|
111
176
|
});
|
|
112
177
|
}
|
|
113
178
|
}
|
|
@@ -12,6 +12,7 @@ const ProfileMedia_1 = require("./ProfileMedia");
|
|
|
12
12
|
const boardPage_1 = require("./boardPage");
|
|
13
13
|
const sourceContext_1 = require("../../agent-variants/sourceContext");
|
|
14
14
|
const errorMessage_1 = require("../../utils/errorMessage");
|
|
15
|
+
const failureReason_1 = require("../../utils/failureReason");
|
|
15
16
|
const DOWNLOAD_TIMEOUT_MS = 20_000;
|
|
16
17
|
const MAX_REDIRECTS = 5;
|
|
17
18
|
const MEDIA_HOSTS = ['pinimg.com', 'are.na', 'cloudfront.net', 'amazonaws.com'];
|
|
@@ -202,6 +203,7 @@ class ProfileImports {
|
|
|
202
203
|
revision: current.revision,
|
|
203
204
|
stage: 'download',
|
|
204
205
|
error: (0, errorMessage_1.errorMessage)(error, 'Image download failed'),
|
|
206
|
+
reasonCode: (0, failureReason_1.failureReasonCode)(error),
|
|
205
207
|
});
|
|
206
208
|
}
|
|
207
209
|
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { ProfilePlans } from './ProfilePlans';
|
|
2
2
|
import { type GuidanceDocument, type GuidanceInput, type GuidanceSelection, type GuidanceUpdate, type SavedGuidance } from '../../types/guidance';
|
|
3
|
+
import { type ProfileImportStep } from '../../types/design-profile';
|
|
4
|
+
import type { FailureReasonCode } from '../../utils/failureReason';
|
|
3
5
|
import type { DesignLibraryReference } from '../../types/design-library';
|
|
4
6
|
import type { ProfileCandidate, ProfileCollectionProgress, ProfileIndexWork, ProfileObservation, ProfileReference, ProfileReferenceInput, ProfileRuntime, ProfileSourceInput } from '../../types/design-profile';
|
|
5
7
|
type ImportPage = {
|
|
@@ -12,6 +14,12 @@ type ImportPage = {
|
|
|
12
14
|
title?: string;
|
|
13
15
|
collection?: ProfileCollectionProgress;
|
|
14
16
|
};
|
|
17
|
+
type UnfinishedImportStep = Extract<ProfileImportStep, 'enumerate' | 'download' | 'analysis'>;
|
|
18
|
+
export declare class UnfinishedImport extends Error {
|
|
19
|
+
readonly step: UnfinishedImportStep;
|
|
20
|
+
readonly reasonCode: FailureReasonCode;
|
|
21
|
+
constructor(step: UnfinishedImportStep, reasonCode: FailureReasonCode);
|
|
22
|
+
}
|
|
15
23
|
export declare class ProfileRecords {
|
|
16
24
|
readonly directory: string;
|
|
17
25
|
private readonly db;
|
|
@@ -245,6 +253,8 @@ export declare class ProfileRecords {
|
|
|
245
253
|
total: number | null;
|
|
246
254
|
error: string | null;
|
|
247
255
|
updatedAt: string;
|
|
256
|
+
addedCount: number;
|
|
257
|
+
removedCount: number;
|
|
248
258
|
};
|
|
249
259
|
};
|
|
250
260
|
startImport({ sourceId, runtime, }: {
|
|
@@ -262,6 +272,8 @@ export declare class ProfileRecords {
|
|
|
262
272
|
total: number | null;
|
|
263
273
|
error: string | null;
|
|
264
274
|
updatedAt: string;
|
|
275
|
+
addedCount: number;
|
|
276
|
+
removedCount: number;
|
|
265
277
|
};
|
|
266
278
|
private writeImport;
|
|
267
279
|
jobs(): {
|
|
@@ -276,6 +288,8 @@ export declare class ProfileRecords {
|
|
|
276
288
|
total: number | null;
|
|
277
289
|
error: string | null;
|
|
278
290
|
updatedAt: string;
|
|
291
|
+
addedCount: number;
|
|
292
|
+
removedCount: number;
|
|
279
293
|
}[];
|
|
280
294
|
deferImport({ id, retryAfterMs }: {
|
|
281
295
|
id: string;
|
|
@@ -290,12 +304,14 @@ export declare class ProfileRecords {
|
|
|
290
304
|
state: 'pending' | 'paused' | 'failed' | 'complete';
|
|
291
305
|
error?: string | null;
|
|
292
306
|
}): void;
|
|
307
|
+
private unfinishedImport;
|
|
293
308
|
failures(jobId?: string): {
|
|
294
309
|
jobId: string;
|
|
295
310
|
referenceId: string;
|
|
296
311
|
revision: number;
|
|
297
312
|
stage: "download" | "analysis";
|
|
298
313
|
error: string;
|
|
314
|
+
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;
|
|
299
315
|
attempts: number;
|
|
300
316
|
updatedAt: string;
|
|
301
317
|
}[];
|
|
@@ -305,6 +321,7 @@ export declare class ProfileRecords {
|
|
|
305
321
|
revision: number;
|
|
306
322
|
stage: 'download' | 'analysis';
|
|
307
323
|
error: string;
|
|
324
|
+
reasonCode: FailureReasonCode;
|
|
308
325
|
}): void;
|
|
309
326
|
clearFailure(referenceId: string, stage: 'download' | 'analysis'): void;
|
|
310
327
|
saveImportPage(input: ImportPage): void;
|
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.ProfileRecords = void 0;
|
|
6
|
+
exports.ProfileRecords = exports.UnfinishedImport = void 0;
|
|
7
7
|
const guidanceVerifier_1 = require("./guidanceVerifier");
|
|
8
8
|
const guidance_verifier_1 = require("../../types/guidance-verifier");
|
|
9
9
|
const reference_connectors_1 = require("../../types/reference-connectors");
|
|
@@ -25,6 +25,17 @@ const MIN_RETRY_MS = 1000;
|
|
|
25
25
|
const MAX_BACKOFF_EXPONENT = 4;
|
|
26
26
|
const MAX_DATE_MS = 8_640_000_000_000_000;
|
|
27
27
|
const identity = (...parts) => (0, crypto_1.createHash)('sha256').update(JSON.stringify(parts)).digest('hex');
|
|
28
|
+
class UnfinishedImport extends Error {
|
|
29
|
+
step;
|
|
30
|
+
reasonCode;
|
|
31
|
+
constructor(step, reasonCode) {
|
|
32
|
+
super('Import has unfinished references');
|
|
33
|
+
this.step = step;
|
|
34
|
+
this.reasonCode = reasonCode;
|
|
35
|
+
this.name = 'UnfinishedImport';
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
exports.UnfinishedImport = UnfinishedImport;
|
|
28
39
|
const guidanceDocument = (document) => guidance_1.GuidanceDocumentSchema.parse({
|
|
29
40
|
id: document.id,
|
|
30
41
|
title: document.title,
|
|
@@ -649,18 +660,33 @@ class ProfileRecords {
|
|
|
649
660
|
const job = this.jobs().find((item) => item.id === id);
|
|
650
661
|
if (!job || job.state === 'superseded')
|
|
651
662
|
throw new Error('Import job is no longer active');
|
|
652
|
-
if (state === 'complete'
|
|
653
|
-
(job.state !== 'pending'
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
663
|
+
if (state === 'complete') {
|
|
664
|
+
if (job.state !== 'pending')
|
|
665
|
+
throw new Error('Import has unfinished references');
|
|
666
|
+
const unfinished = this.unfinishedImport(job);
|
|
667
|
+
if (unfinished)
|
|
668
|
+
throw unfinished;
|
|
669
|
+
}
|
|
658
670
|
this.db
|
|
659
671
|
.update(schema_1.importJobs)
|
|
660
672
|
.set({ state, error, updatedAt: new Date().toISOString() })
|
|
661
673
|
.where((0, drizzle_orm_1.eq)(schema_1.importJobs.id, id))
|
|
662
674
|
.run();
|
|
663
675
|
}
|
|
676
|
+
unfinishedImport(job) {
|
|
677
|
+
if (!job.isEnumerated)
|
|
678
|
+
return new UnfinishedImport('enumerate', 'unknown');
|
|
679
|
+
const failures = this.failures(job.id);
|
|
680
|
+
for (const stage of ['download', 'analysis']) {
|
|
681
|
+
const failure = failures.find((item) => item.stage === stage);
|
|
682
|
+
if (failure)
|
|
683
|
+
return new UnfinishedImport(stage, failure.reasonCode ?? 'unknown');
|
|
684
|
+
}
|
|
685
|
+
const isAnalysisMissing = this.references(job.sourceId).some((reference) => !reference.unsupportedReason && !this.observation(reference.id));
|
|
686
|
+
return isAnalysisMissing
|
|
687
|
+
? new UnfinishedImport('analysis', 'unknown')
|
|
688
|
+
: null;
|
|
689
|
+
}
|
|
664
690
|
failures(jobId) {
|
|
665
691
|
return this.db
|
|
666
692
|
.select({ failure: schema_1.referenceFailures })
|
|
@@ -777,7 +803,15 @@ class ProfileRecords {
|
|
|
777
803
|
.where((0, drizzle_orm_1.and)((0, drizzle_orm_1.eq)(schema_1.importCursors.jobId, jobId), (0, drizzle_orm_1.eq)(schema_1.importCursors.cursor, cursor)))
|
|
778
804
|
.get())
|
|
779
805
|
throw new Error('Provider returned a repeated page cursor');
|
|
806
|
+
let addedCount = 0;
|
|
780
807
|
for (const item of validated) {
|
|
808
|
+
const isMember = this.db
|
|
809
|
+
.select()
|
|
810
|
+
.from(schema_1.memberships)
|
|
811
|
+
.where((0, drizzle_orm_1.and)((0, drizzle_orm_1.eq)(schema_1.memberships.sourceId, job.sourceId), (0, drizzle_orm_1.eq)(schema_1.memberships.referenceId, identity(item.provider, item.remoteId))))
|
|
812
|
+
.get();
|
|
813
|
+
if (!isMember)
|
|
814
|
+
addedCount += 1;
|
|
781
815
|
const reference = this.writeReference(job.sourceId, item, job.id);
|
|
782
816
|
if (collection)
|
|
783
817
|
this.db
|
|
@@ -819,6 +853,7 @@ class ProfileRecords {
|
|
|
819
853
|
.set({ resolvedRemoteId: remoteId, ...(title ? { title } : {}) })
|
|
820
854
|
.where((0, drizzle_orm_1.eq)(schema_1.sources.id, job.sourceId))
|
|
821
855
|
.run();
|
|
856
|
+
let removedCount = 0;
|
|
822
857
|
if (isComplete) {
|
|
823
858
|
const unseen = this.db
|
|
824
859
|
.select()
|
|
@@ -834,6 +869,7 @@ class ProfileRecords {
|
|
|
834
869
|
if (reference)
|
|
835
870
|
this.queueOrphan(reference);
|
|
836
871
|
});
|
|
872
|
+
removedCount = unseen.length;
|
|
837
873
|
}
|
|
838
874
|
this.db
|
|
839
875
|
.update(schema_1.importJobs)
|
|
@@ -843,6 +879,8 @@ class ProfileRecords {
|
|
|
843
879
|
total: collection && isComplete ? enumerated : (total ?? job.total),
|
|
844
880
|
state: 'pending',
|
|
845
881
|
isEnumerated: isComplete,
|
|
882
|
+
addedCount: job.addedCount + addedCount,
|
|
883
|
+
removedCount: job.removedCount + removedCount,
|
|
846
884
|
updatedAt: new Date().toISOString(),
|
|
847
885
|
})
|
|
848
886
|
.where((0, drizzle_orm_1.eq)(schema_1.importJobs.id, job.id))
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export declare const PROFILE_SCHEMA = "\nCREATE TABLE profile (singleton INTEGER PRIMARY KEY CHECK(singleton = 1), id TEXT NOT NULL UNIQUE, is_enabled INTEGER NOT NULL, revision INTEGER NOT NULL);\nCREATE TABLE sources (id TEXT PRIMARY KEY, provider TEXT NOT NULL, remote_id TEXT NOT NULL,\n title TEXT NOT NULL, url TEXT, is_included INTEGER NOT NULL, removed_at TEXT, resolved_remote_id TEXT,\n UNIQUE(provider, remote_id));\nCREATE TABLE profile_references (id TEXT PRIMARY KEY, revision INTEGER NOT NULL,\n content_hash TEXT NOT NULL, body TEXT NOT NULL);\nCREATE TABLE memberships (source_id TEXT NOT NULL REFERENCES sources(id),\n reference_id TEXT NOT NULL REFERENCES profile_references(id), seen_job_id TEXT,\n PRIMARY KEY(source_id, reference_id));\nCREATE INDEX memberships_reference ON memberships(reference_id);\nCREATE TABLE observations (reference_id TEXT PRIMARY KEY REFERENCES profile_references(id),\n revision INTEGER NOT NULL, body TEXT NOT NULL);\nCREATE TABLE index_work (reference_id TEXT PRIMARY KEY REFERENCES profile_references(id),\n id TEXT NOT NULL, revision INTEGER NOT NULL, operation TEXT NOT NULL,\n engine_id TEXT, state TEXT NOT NULL);\nCREATE TABLE import_jobs (id TEXT PRIMARY KEY, source_id TEXT NOT NULL REFERENCES sources(id),\n runtime TEXT NOT NULL, state TEXT NOT NULL, cursor TEXT, enumerated INTEGER NOT NULL,\n total INTEGER, error TEXT, updated_at TEXT NOT NULL, is_enumerated INTEGER NOT NULL DEFAULT 0);\nCREATE INDEX import_jobs_source ON import_jobs(source_id);\nCREATE TABLE index_rebuild (singleton INTEGER PRIMARY KEY CHECK(singleton = 1), id TEXT NOT NULL, runtime TEXT NOT NULL);\n\nCREATE TABLE import_cursors (job_id TEXT NOT NULL REFERENCES import_jobs(id), cursor TEXT NOT NULL, PRIMARY KEY(job_id, cursor));\nCREATE TABLE reference_failures (job_id TEXT NOT NULL REFERENCES import_jobs(id), reference_id TEXT NOT NULL REFERENCES profile_references(id), revision INTEGER NOT NULL, stage TEXT NOT NULL, error TEXT NOT NULL, attempts INTEGER NOT NULL, updated_at TEXT NOT NULL, PRIMARY KEY(job_id, reference_id, stage));\n\nCREATE TABLE provider_cooldowns (provider TEXT PRIMARY KEY, retry_at TEXT NOT NULL, attempts INTEGER NOT NULL);\nCREATE TABLE import_collection_references (job_id TEXT NOT NULL REFERENCES import_jobs(id), collection_id TEXT NOT NULL, reference_id TEXT NOT NULL REFERENCES profile_references(id), PRIMARY KEY(job_id, collection_id, reference_id));\n\nCREATE TABLE reference_discoveries (id TEXT PRIMARY KEY, body TEXT NOT NULL);\nCREATE TABLE reference_plans (id TEXT PRIMARY KEY, body TEXT NOT NULL);\nCREATE TABLE planned_sources (source_id TEXT PRIMARY KEY REFERENCES sources(id), discovery_id TEXT NOT NULL REFERENCES reference_discoveries(id), collection_id TEXT NOT NULL);\nCREATE TABLE reference_onboarding (singleton INTEGER PRIMARY KEY CHECK(singleton = 1), state TEXT NOT NULL, offered_at TEXT, remind_at TEXT);\n\nCREATE TABLE connector_onboarding (provider TEXT PRIMARY KEY, state TEXT NOT NULL, offered_at TEXT, remind_at TEXT);\nCREATE TABLE guidance (id TEXT PRIMARY KEY, title TEXT NOT NULL, markdown TEXT NOT NULL, is_enabled INTEGER NOT NULL);\nALTER TABLE guidance ADD COLUMN attachments TEXT;\nALTER TABLE guidance ADD COLUMN \"references\" TEXT;\nALTER TABLE guidance ADD COLUMN verifier TEXT;\n";
|
|
2
|
-
export declare const PROFILE_MIGRATIONS: readonly ["ALTER TABLE import_jobs ADD COLUMN is_enumerated INTEGER NOT NULL DEFAULT 0", "CREATE TABLE index_rebuild (singleton INTEGER PRIMARY KEY CHECK(singleton = 1), id TEXT NOT NULL, runtime TEXT NOT NULL);", "ALTER TABLE sources ADD COLUMN resolved_remote_id TEXT; \nCREATE TABLE import_cursors (job_id TEXT NOT NULL REFERENCES import_jobs(id), cursor TEXT NOT NULL, PRIMARY KEY(job_id, cursor));\nCREATE TABLE reference_failures (job_id TEXT NOT NULL REFERENCES import_jobs(id), reference_id TEXT NOT NULL REFERENCES profile_references(id), revision INTEGER NOT NULL, stage TEXT NOT NULL, error TEXT NOT NULL, attempts INTEGER NOT NULL, updated_at TEXT NOT NULL, PRIMARY KEY(job_id, reference_id, stage));\n", "CREATE TABLE provider_cooldowns (provider TEXT PRIMARY KEY, retry_at TEXT NOT NULL, attempts INTEGER NOT NULL);", "CREATE TABLE import_collection_references (job_id TEXT NOT NULL REFERENCES import_jobs(id), collection_id TEXT NOT NULL, reference_id TEXT NOT NULL REFERENCES profile_references(id), PRIMARY KEY(job_id, collection_id, reference_id));", "\nCREATE TABLE reference_discoveries (id TEXT PRIMARY KEY, body TEXT NOT NULL);\nCREATE TABLE reference_plans (id TEXT PRIMARY KEY, body TEXT NOT NULL);\nCREATE TABLE planned_sources (source_id TEXT PRIMARY KEY REFERENCES sources(id), discovery_id TEXT NOT NULL REFERENCES reference_discoveries(id), collection_id TEXT NOT NULL);\nCREATE TABLE reference_onboarding (singleton INTEGER PRIMARY KEY CHECK(singleton = 1), state TEXT NOT NULL, offered_at TEXT, remind_at TEXT);\n", "CREATE TABLE connector_onboarding (provider TEXT PRIMARY KEY, state TEXT NOT NULL, offered_at TEXT, remind_at TEXT);", "CREATE TABLE guidance (id TEXT PRIMARY KEY, title TEXT NOT NULL, markdown TEXT NOT NULL, is_enabled INTEGER NOT NULL);", "ALTER TABLE guidance ADD COLUMN attachments TEXT;", "ALTER TABLE guidance ADD COLUMN \"references\" TEXT;", "ALTER TABLE guidance ADD COLUMN verifier TEXT;"];
|
|
1
|
+
export declare const PROFILE_SCHEMA = "\nCREATE TABLE profile (singleton INTEGER PRIMARY KEY CHECK(singleton = 1), id TEXT NOT NULL UNIQUE, is_enabled INTEGER NOT NULL, revision INTEGER NOT NULL);\nCREATE TABLE sources (id TEXT PRIMARY KEY, provider TEXT NOT NULL, remote_id TEXT NOT NULL,\n title TEXT NOT NULL, url TEXT, is_included INTEGER NOT NULL, removed_at TEXT, resolved_remote_id TEXT,\n UNIQUE(provider, remote_id));\nCREATE TABLE profile_references (id TEXT PRIMARY KEY, revision INTEGER NOT NULL,\n content_hash TEXT NOT NULL, body TEXT NOT NULL);\nCREATE TABLE memberships (source_id TEXT NOT NULL REFERENCES sources(id),\n reference_id TEXT NOT NULL REFERENCES profile_references(id), seen_job_id TEXT,\n PRIMARY KEY(source_id, reference_id));\nCREATE INDEX memberships_reference ON memberships(reference_id);\nCREATE TABLE observations (reference_id TEXT PRIMARY KEY REFERENCES profile_references(id),\n revision INTEGER NOT NULL, body TEXT NOT NULL);\nCREATE TABLE index_work (reference_id TEXT PRIMARY KEY REFERENCES profile_references(id),\n id TEXT NOT NULL, revision INTEGER NOT NULL, operation TEXT NOT NULL,\n engine_id TEXT, state TEXT NOT NULL);\nCREATE TABLE import_jobs (id TEXT PRIMARY KEY, source_id TEXT NOT NULL REFERENCES sources(id),\n runtime TEXT NOT NULL, state TEXT NOT NULL, cursor TEXT, enumerated INTEGER NOT NULL,\n total INTEGER, error TEXT, updated_at TEXT NOT NULL, is_enumerated INTEGER NOT NULL DEFAULT 0);\nCREATE INDEX import_jobs_source ON import_jobs(source_id);\nCREATE TABLE index_rebuild (singleton INTEGER PRIMARY KEY CHECK(singleton = 1), id TEXT NOT NULL, runtime TEXT NOT NULL);\n\nCREATE TABLE import_cursors (job_id TEXT NOT NULL REFERENCES import_jobs(id), cursor TEXT NOT NULL, PRIMARY KEY(job_id, cursor));\nCREATE TABLE reference_failures (job_id TEXT NOT NULL REFERENCES import_jobs(id), reference_id TEXT NOT NULL REFERENCES profile_references(id), revision INTEGER NOT NULL, stage TEXT NOT NULL, error TEXT NOT NULL, attempts INTEGER NOT NULL, updated_at TEXT NOT NULL, PRIMARY KEY(job_id, reference_id, stage));\n\nCREATE TABLE provider_cooldowns (provider TEXT PRIMARY KEY, retry_at TEXT NOT NULL, attempts INTEGER NOT NULL);\nCREATE TABLE import_collection_references (job_id TEXT NOT NULL REFERENCES import_jobs(id), collection_id TEXT NOT NULL, reference_id TEXT NOT NULL REFERENCES profile_references(id), PRIMARY KEY(job_id, collection_id, reference_id));\n\nCREATE TABLE reference_discoveries (id TEXT PRIMARY KEY, body TEXT NOT NULL);\nCREATE TABLE reference_plans (id TEXT PRIMARY KEY, body TEXT NOT NULL);\nCREATE TABLE planned_sources (source_id TEXT PRIMARY KEY REFERENCES sources(id), discovery_id TEXT NOT NULL REFERENCES reference_discoveries(id), collection_id TEXT NOT NULL);\nCREATE TABLE reference_onboarding (singleton INTEGER PRIMARY KEY CHECK(singleton = 1), state TEXT NOT NULL, offered_at TEXT, remind_at TEXT);\n\nCREATE TABLE connector_onboarding (provider TEXT PRIMARY KEY, state TEXT NOT NULL, offered_at TEXT, remind_at TEXT);\nCREATE TABLE guidance (id TEXT PRIMARY KEY, title TEXT NOT NULL, markdown TEXT NOT NULL, is_enabled INTEGER NOT NULL);\nALTER TABLE guidance ADD COLUMN attachments TEXT;\nALTER TABLE guidance ADD COLUMN \"references\" TEXT;\nALTER TABLE guidance ADD COLUMN verifier TEXT;\n\nALTER TABLE import_jobs ADD COLUMN added_count INTEGER NOT NULL DEFAULT 0;\nALTER TABLE import_jobs ADD COLUMN removed_count INTEGER NOT NULL DEFAULT 0;\nALTER TABLE reference_failures ADD COLUMN reason_code TEXT;\n\n";
|
|
2
|
+
export declare const PROFILE_MIGRATIONS: readonly ["ALTER TABLE import_jobs ADD COLUMN is_enumerated INTEGER NOT NULL DEFAULT 0", "CREATE TABLE index_rebuild (singleton INTEGER PRIMARY KEY CHECK(singleton = 1), id TEXT NOT NULL, runtime TEXT NOT NULL);", "ALTER TABLE sources ADD COLUMN resolved_remote_id TEXT; \nCREATE TABLE import_cursors (job_id TEXT NOT NULL REFERENCES import_jobs(id), cursor TEXT NOT NULL, PRIMARY KEY(job_id, cursor));\nCREATE TABLE reference_failures (job_id TEXT NOT NULL REFERENCES import_jobs(id), reference_id TEXT NOT NULL REFERENCES profile_references(id), revision INTEGER NOT NULL, stage TEXT NOT NULL, error TEXT NOT NULL, attempts INTEGER NOT NULL, updated_at TEXT NOT NULL, PRIMARY KEY(job_id, reference_id, stage));\n", "CREATE TABLE provider_cooldowns (provider TEXT PRIMARY KEY, retry_at TEXT NOT NULL, attempts INTEGER NOT NULL);", "CREATE TABLE import_collection_references (job_id TEXT NOT NULL REFERENCES import_jobs(id), collection_id TEXT NOT NULL, reference_id TEXT NOT NULL REFERENCES profile_references(id), PRIMARY KEY(job_id, collection_id, reference_id));", "\nCREATE TABLE reference_discoveries (id TEXT PRIMARY KEY, body TEXT NOT NULL);\nCREATE TABLE reference_plans (id TEXT PRIMARY KEY, body TEXT NOT NULL);\nCREATE TABLE planned_sources (source_id TEXT PRIMARY KEY REFERENCES sources(id), discovery_id TEXT NOT NULL REFERENCES reference_discoveries(id), collection_id TEXT NOT NULL);\nCREATE TABLE reference_onboarding (singleton INTEGER PRIMARY KEY CHECK(singleton = 1), state TEXT NOT NULL, offered_at TEXT, remind_at TEXT);\n", "CREATE TABLE connector_onboarding (provider TEXT PRIMARY KEY, state TEXT NOT NULL, offered_at TEXT, remind_at TEXT);", "CREATE TABLE guidance (id TEXT PRIMARY KEY, title TEXT NOT NULL, markdown TEXT NOT NULL, is_enabled INTEGER NOT NULL);", "ALTER TABLE guidance ADD COLUMN attachments TEXT;", "ALTER TABLE guidance ADD COLUMN \"references\" TEXT;", "ALTER TABLE guidance ADD COLUMN verifier TEXT;", "\nALTER TABLE import_jobs ADD COLUMN added_count INTEGER NOT NULL DEFAULT 0;\nALTER TABLE import_jobs ADD COLUMN removed_count INTEGER NOT NULL DEFAULT 0;\nALTER TABLE reference_failures ADD COLUMN reason_code TEXT;\n"];
|
|
3
3
|
export declare const PROFILE_SCHEMA_VERSION: number;
|
|
4
4
|
//# sourceMappingURL=migrations.d.ts.map
|