@badger_badger/badger_hq 1.5.1 → 1.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -37,7 +37,7 @@ var TASK_STATUS_VALUES = [
37
37
  ];
38
38
  z.enum(TASK_STATUS_VALUES);
39
39
  var REGION_MODE_VALUES = ["must", "preferred"];
40
- z.enum(REGION_MODE_VALUES);
40
+ var RegionMode = z.enum(REGION_MODE_VALUES);
41
41
  var ASSIGNEE_TYPE_VALUES = ["scout", "analyst"];
42
42
  z.enum(ASSIGNEE_TYPE_VALUES);
43
43
  var ASSIGNMENT_STATUS_VALUES = ["active", "completed", "revoked"];
@@ -58,6 +58,21 @@ var SOURCE_ROUTE_VALUES = ["scraper", "monitor", "waiting_for_scraper"];
58
58
  z.enum(SOURCE_ROUTE_VALUES);
59
59
  var SOURCE_STATUS_VALUES = ["active", "paused", "closed", "access_problem"];
60
60
  z.enum(SOURCE_STATUS_VALUES);
61
+ var ACCESS_ISSUE_VALUES = [
62
+ "login_required",
63
+ "private",
64
+ "bot_detection",
65
+ "captcha",
66
+ "geo_blocked",
67
+ "rate_limited",
68
+ "not_found",
69
+ "no_collector",
70
+ "collector_full",
71
+ "other"
72
+ ];
73
+ var AccessIssue = z.enum(ACCESS_ISSUE_VALUES);
74
+ var CAPTURE_WINDOW_MODE_VALUES = ["last_days", "range"];
75
+ var CaptureWindowMode = z.enum(CAPTURE_WINDOW_MODE_VALUES);
61
76
  var DISCOVERED_BY_TYPE_VALUES = ["scout", "analyst", "agent", "client", "import"];
62
77
  z.enum(DISCOVERED_BY_TYPE_VALUES);
63
78
  var SOURCE_IMPORT_KIND_VALUES = ["create", "update"];
@@ -105,6 +120,8 @@ var AGENT_SOURCE_OUTCOME_VALUES = [
105
120
  var AgentSourceOutcome = z.enum(AGENT_SOURCE_OUTCOME_VALUES);
106
121
  var CAPTURE_STATUS_VALUES = ["uploaded", "analyzing", "analyzed", "failed", "expired"];
107
122
  var CaptureStatus = z.enum(CAPTURE_STATUS_VALUES);
123
+ var HOURS_LOG_SOURCE_VALUES = ["manual", "inferred"];
124
+ z.enum(HOURS_LOG_SOURCE_VALUES);
108
125
  var CAPTURE_DOM_STATUS_VALUES = ["ok", "unavailable", "truncated"];
109
126
  var CaptureDomStatus = z.enum(CAPTURE_DOM_STATUS_VALUES);
110
127
  var LLM_CAPABILITY_VALUES = ["plan", "vision_extract", "judge", "chat"];
@@ -197,7 +214,11 @@ var INDEXES = {
197
214
  ],
198
215
  [COLLECTIONS.assigneeLoads]: [{ key: { userId: 1, scope: 1 }, options: { unique: true } }],
199
216
  [COLLECTIONS.missions]: [{ key: { orgId: 1, status: 1, priority: 1 } }],
200
- [COLLECTIONS.tasks]: [{ key: { orgId: 1, missionId: 1, status: 1 } }],
217
+ [COLLECTIONS.tasks]: [
218
+ { key: { orgId: 1, missionId: 1, status: 1 } },
219
+ // Tasks that target a source (cascade on source delete).
220
+ { key: { orgId: 1, "target.sourceId": 1 }, options: { partialFilterExpression: { "target.sourceId": { $exists: true } } } }
221
+ ],
201
222
  [COLLECTIONS.assignments]: [
202
223
  { key: { assigneeUserId: 1, status: 1, orgId: 1 } },
203
224
  { key: { orgId: 1, taskId: 1, status: 1 } },
@@ -210,13 +231,22 @@ var INDEXES = {
210
231
  }
211
232
  }
212
233
  ],
213
- [COLLECTIONS.hoursLogs]: [{ key: { orgId: 1, scoutUserId: 1, date: -1 } }],
234
+ [COLLECTIONS.hoursLogs]: [
235
+ { key: { orgId: 1, scoutUserId: 1, date: -1 } },
236
+ // One inferred row per person + assignment + day (agent-service upserts it).
237
+ {
238
+ key: { orgId: 1, assignmentId: 1, scoutUserId: 1, date: 1 },
239
+ options: { unique: true, partialFilterExpression: { source: "inferred" } }
240
+ }
241
+ ],
214
242
  [COLLECTIONS.sources]: [
215
243
  {
216
244
  key: { orgId: 1, platform: 1, url: 1 },
217
245
  options: { unique: true, partialFilterExpression: NOT_SOFT_DELETED_FILTER }
218
246
  },
219
247
  { key: { orgId: 1, route: 1, status: 1 } },
248
+ // Multikey: the sources attached to a Monitor task (cap counts, agents' version polls).
249
+ { key: { orgId: 1, taskIds: 1 } },
220
250
  // Partition key of the shared database; drives the future split into physical databases.
221
251
  { key: { orgId: 1, databaseId: 1 } }
222
252
  ],
@@ -253,7 +283,11 @@ var INDEXES = {
253
283
  [COLLECTIONS.captures]: [
254
284
  { key: { orgId: 1, sessionId: 1, capturedAt: -1 } },
255
285
  // Retention sweep: captures whose blob must be deleted.
256
- { key: { status: 1, expiresAt: 1 } }
286
+ { key: { status: 1, expiresAt: 1 } },
287
+ // Capture worker: oldest waiting (or stale analyzing) captures first.
288
+ { key: { status: 1, createdAt: 1 } },
289
+ // Task-tagged captures: per-assignment dedupe and inferred hours.
290
+ { key: { orgId: 1, assignmentId: 1, userId: 1, capturedAt: 1 } }
257
291
  ],
258
292
  [COLLECTIONS.llmCalls]: [
259
293
  { key: { orgId: 1, createdAt: -1 } },
@@ -338,6 +372,24 @@ OrgSettingsSchema.pick({
338
372
  defaultAnalystTaskLimit: true,
339
373
  timezone: true
340
374
  }).partial();
375
+ var CoverageWindowSchema = z.object({
376
+ start: z.coerce.date(),
377
+ end: z.coerce.date()
378
+ }).refine((w) => w.end.getTime() > w.start.getTime(), {
379
+ message: "coverageWindow.end must be after coverageWindow.start",
380
+ path: ["end"]
381
+ });
382
+ z.object({
383
+ languages: z.array(LanguageCode),
384
+ platforms: z.array(Platform),
385
+ regions: z.array(z.string().min(1)),
386
+ regionMode: RegionMode,
387
+ profession: z.string().min(1).optional(),
388
+ coverageWindow: CoverageWindowSchema.optional(),
389
+ emergency: z.boolean().default(false)
390
+ });
391
+
392
+ // src/zod/agent-session.ts
341
393
  var count = () => z.number().int().min(0).default(0);
342
394
  var AgentSessionStatsSchema = z.object({
343
395
  capturesCount: count(),
@@ -374,6 +426,8 @@ var AgentSessionSchema = z.object({
374
426
  lastSeq: count(),
375
427
  stats: AgentSessionStatsSchema.default({}),
376
428
  budget: AgentSessionBudgetSchema.default({}),
429
+ /** The task's capture window as dates, fixed when the session started (`last_days` counted back from then). */
430
+ captureWindow: CoverageWindowSchema.optional(),
377
431
  /** Mode-specific engine state (search plan cursor, monitor queue). Opaque to clients. */
378
432
  state: z.unknown().optional()
379
433
  }).merge(TimestampsSchema);
@@ -479,7 +533,14 @@ var CaptureDomSummarySchema = z.object({
479
533
  var CaptureSchema = z.object({
480
534
  _id: ObjectIdString,
481
535
  orgId: ClerkOrgId,
482
- sessionId: ObjectIdString,
536
+ /** Legacy: captures uploaded into a live session. Task-tagged captures have none. */
537
+ sessionId: ObjectIdString.optional(),
538
+ /** The assignment (and so the task) the person sent this capture for. */
539
+ assignmentId: ObjectIdString.optional(),
540
+ taskId: ObjectIdString.optional(),
541
+ missionId: ObjectIdString.optional(),
542
+ /** Who sent it; used to work out their hours. */
543
+ userId: ClerkUserId.optional(),
483
544
  /** From `chrome.tabs`, never from page content. */
484
545
  url: z.string().url(),
485
546
  title: z.string().max(500),
@@ -495,6 +556,10 @@ var CaptureSchema = z.object({
495
556
  /** Validated `vision_extract` output; shape depends on session mode. */
496
557
  analysis: z.unknown().optional(),
497
558
  error: z.string().max(1e3).optional(),
559
+ /** Analysis attempts by the capture worker; it gives up (`failed`) after a few. */
560
+ attempts: z.number().int().min(0).default(0),
561
+ /** When the worker claimed it (`analyzing`); an old claim is taken over after a restart. */
562
+ claimedAt: z.coerce.date().optional(),
498
563
  /** Blob deleted and status set to `expired` after this instant (CAPTURE_RETENTION_DAYS). */
499
564
  expiresAt: z.coerce.date()
500
565
  }).merge(TimestampsSchema);
@@ -612,6 +677,51 @@ var SourceImportCreateSchema = SourceImportSchema.omit({
612
677
  committedAt: true
613
678
  });
614
679
  SourceImportCreateSchema.partial();
680
+ var MAX_CAPTURE_WINDOW_DAYS = 90;
681
+ var DAY_MS = 24 * 60 * 60 * 1e3;
682
+ function isHttpUrl(value) {
683
+ try {
684
+ const { protocol } = new URL(value);
685
+ return protocol === "http:" || protocol === "https:";
686
+ } catch {
687
+ return false;
688
+ }
689
+ }
690
+ var WindowDate = z.union([z.date(), z.string().datetime({ offset: true })]).pipe(z.coerce.date());
691
+ z.object({
692
+ sourceId: ObjectIdString.optional(),
693
+ platform: Platform,
694
+ url: z.string().url().refine(isHttpUrl, "Expected an http(s) URL"),
695
+ label: z.string().min(1).max(200).optional(),
696
+ /** Why a person collects it instead of a scraper. */
697
+ accessIssue: AccessIssue.optional(),
698
+ note: z.string().max(500).optional()
699
+ });
700
+ var LastDaysWindowSchema = z.object({
701
+ mode: z.literal(CaptureWindowMode.enum.last_days),
702
+ days: z.number().int().min(1).max(MAX_CAPTURE_WINDOW_DAYS)
703
+ });
704
+ var RangeWindowSchema = z.object({
705
+ mode: z.literal(CaptureWindowMode.enum.range),
706
+ start: WindowDate,
707
+ end: WindowDate
708
+ });
709
+ z.discriminatedUnion("mode", [LastDaysWindowSchema, RangeWindowSchema]).superRefine((w, ctx) => {
710
+ if (w.mode !== "range" || !(w.start instanceof Date) || !(w.end instanceof Date)) return;
711
+ if (w.end.getTime() <= w.start.getTime()) {
712
+ ctx.addIssue({
713
+ code: z.ZodIssueCode.custom,
714
+ message: "captureWindow.end must be after captureWindow.start",
715
+ path: ["end"]
716
+ });
717
+ } else if (w.end.getTime() - w.start.getTime() > MAX_CAPTURE_WINDOW_DAYS * DAY_MS) {
718
+ ctx.addIssue({
719
+ code: z.ZodIssueCode.custom,
720
+ message: `captureWindow range must be at most ${MAX_CAPTURE_WINDOW_DAYS} days`,
721
+ path: ["end"]
722
+ });
723
+ }
724
+ });
615
725
 
616
726
  // src/mongo/schemas.ts
617
727
  var toObject = { ...toJSONOptions, flattenMaps: true };
@@ -662,6 +772,50 @@ var taskCriteriaSchema = new Schema(
662
772
  },
663
773
  EMBEDDED
664
774
  );
775
+ var taskTargetSchema = new Schema(
776
+ {
777
+ sourceId: { type: ObjectId },
778
+ platform: { type: String, enum: PLATFORM_VALUES, required: true },
779
+ url: { type: String, required: true, minlength: 1 },
780
+ label: { type: String, maxlength: 200 },
781
+ accessIssue: { type: String, enum: ACCESS_ISSUE_VALUES },
782
+ note: { type: String, maxlength: 500 }
783
+ },
784
+ EMBEDDED
785
+ );
786
+ var captureWindowSchema = new Schema(
787
+ {
788
+ mode: { type: String, enum: CAPTURE_WINDOW_MODE_VALUES, required: true },
789
+ days: {
790
+ type: Number,
791
+ min: 1,
792
+ max: MAX_CAPTURE_WINDOW_DAYS,
793
+ validate: Number.isInteger,
794
+ required() {
795
+ return this.mode === "last_days";
796
+ }
797
+ },
798
+ start: {
799
+ type: Date,
800
+ required() {
801
+ return this.mode === "range";
802
+ }
803
+ },
804
+ end: {
805
+ type: Date,
806
+ required() {
807
+ return this.mode === "range";
808
+ },
809
+ validate: {
810
+ validator(end) {
811
+ return !this.start || end.getTime() > this.start.getTime();
812
+ },
813
+ message: "captureWindow.end must be after captureWindow.start"
814
+ }
815
+ }
816
+ },
817
+ EMBEDDED
818
+ );
665
819
  var availabilityWindowSchema = new Schema(
666
820
  {
667
821
  day: { type: Number, enum: [0, 1, 2, 3, 4, 5, 6], required: true },
@@ -835,6 +989,8 @@ var taskSchema = new Schema(
835
989
  keywords: { type: [String], required: true, default: [] },
836
990
  searchQueries: { type: [String], required: true, default: [] },
837
991
  criteria: { type: taskCriteriaSchema, required: true },
992
+ target: { type: taskTargetSchema },
993
+ captureWindow: { type: captureWindowSchema },
838
994
  status: { type: String, enum: TASK_STATUS_VALUES, required: true, default: "draft" },
839
995
  approvedBy: clerkUserIdOptional,
840
996
  approvedAt: { type: Date },
@@ -885,6 +1041,8 @@ var hoursLogSchema = new Schema(
885
1041
  minutes: { type: Number, required: true, min: 1, validate: Number.isInteger },
886
1042
  note: { type: String, required: true, default: "" },
887
1043
  date: { type: Date, required: true },
1044
+ assignmentId: { type: ObjectId },
1045
+ source: { type: String, enum: HOURS_LOG_SOURCE_VALUES },
888
1046
  deletedAt: { type: Date }
889
1047
  },
890
1048
  collectionOptions(COLLECTIONS.hoursLogs)
@@ -975,6 +1133,7 @@ var sourceSchema = new Schema(
975
1133
  discoveredBy: { type: discoveredBySchema, required: true },
976
1134
  lastCollectedAt: { type: Date },
977
1135
  nextVisitAt: { type: Date },
1136
+ visitIntervalMs: { type: Number, min: 1 },
978
1137
  deletedAt: { type: Date }
979
1138
  },
980
1139
  collectionOptions(COLLECTIONS.sources)
@@ -1119,6 +1278,7 @@ var agentSessionSchema = new Schema(
1119
1278
  lastSeq: counter,
1120
1279
  stats: { type: agentSessionStatsSchema, required: true, default: () => ({}) },
1121
1280
  budget: { type: agentSessionBudgetSchema, required: true, default: () => ({}) },
1281
+ captureWindow: { type: coverageWindowSchema },
1122
1282
  state: { type: Mixed }
1123
1283
  },
1124
1284
  collectionOptions(COLLECTIONS.agentSessions)
@@ -1171,7 +1331,11 @@ var captureDomSummarySchema = new Schema(
1171
1331
  var captureSchema = new Schema(
1172
1332
  {
1173
1333
  orgId: clerkOrgId,
1174
- sessionId: { type: ObjectId, required: true },
1334
+ sessionId: { type: ObjectId },
1335
+ assignmentId: { type: ObjectId },
1336
+ taskId: { type: ObjectId },
1337
+ missionId: { type: ObjectId },
1338
+ userId: clerkUserIdOptional,
1175
1339
  url: { type: String, required: true },
1176
1340
  title: { type: String, required: true, default: "", maxlength: 500 },
1177
1341
  capturedAt: { type: Date, required: true },
@@ -1184,6 +1348,8 @@ var captureSchema = new Schema(
1184
1348
  status: { type: String, enum: CAPTURE_STATUS_VALUES, required: true, default: "uploaded" },
1185
1349
  analysis: { type: Mixed },
1186
1350
  error: { type: String, maxlength: 1e3 },
1351
+ attempts: { type: Number, required: true, default: 0, min: 0, validate: Number.isInteger },
1352
+ claimedAt: { type: Date },
1187
1353
  expiresAt: { type: Date, required: true }
1188
1354
  },
1189
1355
  collectionOptions(COLLECTIONS.captures)
@@ -1294,6 +1460,6 @@ function registerModels(conn) {
1294
1460
  };
1295
1461
  }
1296
1462
 
1297
- export { COLLECTIONS, INDEXES, MODEL_NAMES, NOT_SOFT_DELETED_FILTER, SCHEMAS, TASK_VERSION_HOOK_OPS, agentMessageSchema, agentSessionBudgetSchema, agentSessionSchema, agentSessionStatsSchema, analystProfileSchema, applyIndexes, assigneeLoadSchema, assignmentSchema, auditLogSchema, auditTargetSchema, availabilityWindowSchema, blobRefSchema, captureDomSummarySchema, captureRegionSchema, captureSchema, collectorSchema, coverageWindowSchema, dataItemContentSchema, dataItemEntitySchema, dataItemSchema, databaseSchema, deploymentSchema, deploymentStepSchema, discoveredBySchema, geoSchema, hoursLogSchema, incrementTaskVersion, llmCallSchema, llmUsageSchema, missionSchema, objectIdsToStrings, orgSettingsSchema, platformAccessSchema, ratingSummarySchema, registerModels, scoutProfileSchema, scoutRatingSchema, scraperMetricSchema, scraperSchema, sourceImportRowErrorSchema, sourceImportSchema, sourceImportSummarySchema, sourceRatingSchema, sourceSchema, specialAccessSchema, systemRecommendationSchema, taskCriteriaSchema, taskSchema, toJSONOptions };
1463
+ export { COLLECTIONS, INDEXES, MODEL_NAMES, NOT_SOFT_DELETED_FILTER, SCHEMAS, TASK_VERSION_HOOK_OPS, agentMessageSchema, agentSessionBudgetSchema, agentSessionSchema, agentSessionStatsSchema, analystProfileSchema, applyIndexes, assigneeLoadSchema, assignmentSchema, auditLogSchema, auditTargetSchema, availabilityWindowSchema, blobRefSchema, captureDomSummarySchema, captureRegionSchema, captureSchema, captureWindowSchema, collectorSchema, coverageWindowSchema, dataItemContentSchema, dataItemEntitySchema, dataItemSchema, databaseSchema, deploymentSchema, deploymentStepSchema, discoveredBySchema, geoSchema, hoursLogSchema, incrementTaskVersion, llmCallSchema, llmUsageSchema, missionSchema, objectIdsToStrings, orgSettingsSchema, platformAccessSchema, ratingSummarySchema, registerModels, scoutProfileSchema, scoutRatingSchema, scraperMetricSchema, scraperSchema, sourceImportRowErrorSchema, sourceImportSchema, sourceImportSummarySchema, sourceRatingSchema, sourceSchema, specialAccessSchema, systemRecommendationSchema, taskCriteriaSchema, taskSchema, taskTargetSchema, toJSONOptions };
1298
1464
  //# sourceMappingURL=index.js.map
1299
1465
  //# sourceMappingURL=index.js.map