@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.
@@ -39,7 +39,7 @@ var TASK_STATUS_VALUES = [
39
39
  ];
40
40
  zod.z.enum(TASK_STATUS_VALUES);
41
41
  var REGION_MODE_VALUES = ["must", "preferred"];
42
- zod.z.enum(REGION_MODE_VALUES);
42
+ var RegionMode = zod.z.enum(REGION_MODE_VALUES);
43
43
  var ASSIGNEE_TYPE_VALUES = ["scout", "analyst"];
44
44
  zod.z.enum(ASSIGNEE_TYPE_VALUES);
45
45
  var ASSIGNMENT_STATUS_VALUES = ["active", "completed", "revoked"];
@@ -60,6 +60,21 @@ var SOURCE_ROUTE_VALUES = ["scraper", "monitor", "waiting_for_scraper"];
60
60
  zod.z.enum(SOURCE_ROUTE_VALUES);
61
61
  var SOURCE_STATUS_VALUES = ["active", "paused", "closed", "access_problem"];
62
62
  zod.z.enum(SOURCE_STATUS_VALUES);
63
+ var ACCESS_ISSUE_VALUES = [
64
+ "login_required",
65
+ "private",
66
+ "bot_detection",
67
+ "captcha",
68
+ "geo_blocked",
69
+ "rate_limited",
70
+ "not_found",
71
+ "no_collector",
72
+ "collector_full",
73
+ "other"
74
+ ];
75
+ var AccessIssue = zod.z.enum(ACCESS_ISSUE_VALUES);
76
+ var CAPTURE_WINDOW_MODE_VALUES = ["last_days", "range"];
77
+ var CaptureWindowMode = zod.z.enum(CAPTURE_WINDOW_MODE_VALUES);
63
78
  var DISCOVERED_BY_TYPE_VALUES = ["scout", "analyst", "agent", "client", "import"];
64
79
  zod.z.enum(DISCOVERED_BY_TYPE_VALUES);
65
80
  var SOURCE_IMPORT_KIND_VALUES = ["create", "update"];
@@ -107,6 +122,8 @@ var AGENT_SOURCE_OUTCOME_VALUES = [
107
122
  var AgentSourceOutcome = zod.z.enum(AGENT_SOURCE_OUTCOME_VALUES);
108
123
  var CAPTURE_STATUS_VALUES = ["uploaded", "analyzing", "analyzed", "failed", "expired"];
109
124
  var CaptureStatus = zod.z.enum(CAPTURE_STATUS_VALUES);
125
+ var HOURS_LOG_SOURCE_VALUES = ["manual", "inferred"];
126
+ zod.z.enum(HOURS_LOG_SOURCE_VALUES);
110
127
  var CAPTURE_DOM_STATUS_VALUES = ["ok", "unavailable", "truncated"];
111
128
  var CaptureDomStatus = zod.z.enum(CAPTURE_DOM_STATUS_VALUES);
112
129
  var LLM_CAPABILITY_VALUES = ["plan", "vision_extract", "judge", "chat"];
@@ -199,7 +216,11 @@ var INDEXES = {
199
216
  ],
200
217
  [COLLECTIONS.assigneeLoads]: [{ key: { userId: 1, scope: 1 }, options: { unique: true } }],
201
218
  [COLLECTIONS.missions]: [{ key: { orgId: 1, status: 1, priority: 1 } }],
202
- [COLLECTIONS.tasks]: [{ key: { orgId: 1, missionId: 1, status: 1 } }],
219
+ [COLLECTIONS.tasks]: [
220
+ { key: { orgId: 1, missionId: 1, status: 1 } },
221
+ // Tasks that target a source (cascade on source delete).
222
+ { key: { orgId: 1, "target.sourceId": 1 }, options: { partialFilterExpression: { "target.sourceId": { $exists: true } } } }
223
+ ],
203
224
  [COLLECTIONS.assignments]: [
204
225
  { key: { assigneeUserId: 1, status: 1, orgId: 1 } },
205
226
  { key: { orgId: 1, taskId: 1, status: 1 } },
@@ -212,13 +233,22 @@ var INDEXES = {
212
233
  }
213
234
  }
214
235
  ],
215
- [COLLECTIONS.hoursLogs]: [{ key: { orgId: 1, scoutUserId: 1, date: -1 } }],
236
+ [COLLECTIONS.hoursLogs]: [
237
+ { key: { orgId: 1, scoutUserId: 1, date: -1 } },
238
+ // One inferred row per person + assignment + day (agent-service upserts it).
239
+ {
240
+ key: { orgId: 1, assignmentId: 1, scoutUserId: 1, date: 1 },
241
+ options: { unique: true, partialFilterExpression: { source: "inferred" } }
242
+ }
243
+ ],
216
244
  [COLLECTIONS.sources]: [
217
245
  {
218
246
  key: { orgId: 1, platform: 1, url: 1 },
219
247
  options: { unique: true, partialFilterExpression: NOT_SOFT_DELETED_FILTER }
220
248
  },
221
249
  { key: { orgId: 1, route: 1, status: 1 } },
250
+ // Multikey: the sources attached to a Monitor task (cap counts, agents' version polls).
251
+ { key: { orgId: 1, taskIds: 1 } },
222
252
  // Partition key of the shared database; drives the future split into physical databases.
223
253
  { key: { orgId: 1, databaseId: 1 } }
224
254
  ],
@@ -255,7 +285,11 @@ var INDEXES = {
255
285
  [COLLECTIONS.captures]: [
256
286
  { key: { orgId: 1, sessionId: 1, capturedAt: -1 } },
257
287
  // Retention sweep: captures whose blob must be deleted.
258
- { key: { status: 1, expiresAt: 1 } }
288
+ { key: { status: 1, expiresAt: 1 } },
289
+ // Capture worker: oldest waiting (or stale analyzing) captures first.
290
+ { key: { status: 1, createdAt: 1 } },
291
+ // Task-tagged captures: per-assignment dedupe and inferred hours.
292
+ { key: { orgId: 1, assignmentId: 1, userId: 1, capturedAt: 1 } }
259
293
  ],
260
294
  [COLLECTIONS.llmCalls]: [
261
295
  { key: { orgId: 1, createdAt: -1 } },
@@ -340,6 +374,24 @@ OrgSettingsSchema.pick({
340
374
  defaultAnalystTaskLimit: true,
341
375
  timezone: true
342
376
  }).partial();
377
+ var CoverageWindowSchema = zod.z.object({
378
+ start: zod.z.coerce.date(),
379
+ end: zod.z.coerce.date()
380
+ }).refine((w) => w.end.getTime() > w.start.getTime(), {
381
+ message: "coverageWindow.end must be after coverageWindow.start",
382
+ path: ["end"]
383
+ });
384
+ zod.z.object({
385
+ languages: zod.z.array(LanguageCode),
386
+ platforms: zod.z.array(Platform),
387
+ regions: zod.z.array(zod.z.string().min(1)),
388
+ regionMode: RegionMode,
389
+ profession: zod.z.string().min(1).optional(),
390
+ coverageWindow: CoverageWindowSchema.optional(),
391
+ emergency: zod.z.boolean().default(false)
392
+ });
393
+
394
+ // src/zod/agent-session.ts
343
395
  var count = () => zod.z.number().int().min(0).default(0);
344
396
  var AgentSessionStatsSchema = zod.z.object({
345
397
  capturesCount: count(),
@@ -376,6 +428,8 @@ var AgentSessionSchema = zod.z.object({
376
428
  lastSeq: count(),
377
429
  stats: AgentSessionStatsSchema.default({}),
378
430
  budget: AgentSessionBudgetSchema.default({}),
431
+ /** The task's capture window as dates, fixed when the session started (`last_days` counted back from then). */
432
+ captureWindow: CoverageWindowSchema.optional(),
379
433
  /** Mode-specific engine state (search plan cursor, monitor queue). Opaque to clients. */
380
434
  state: zod.z.unknown().optional()
381
435
  }).merge(TimestampsSchema);
@@ -481,7 +535,14 @@ var CaptureDomSummarySchema = zod.z.object({
481
535
  var CaptureSchema = zod.z.object({
482
536
  _id: ObjectIdString,
483
537
  orgId: ClerkOrgId,
484
- sessionId: ObjectIdString,
538
+ /** Legacy: captures uploaded into a live session. Task-tagged captures have none. */
539
+ sessionId: ObjectIdString.optional(),
540
+ /** The assignment (and so the task) the person sent this capture for. */
541
+ assignmentId: ObjectIdString.optional(),
542
+ taskId: ObjectIdString.optional(),
543
+ missionId: ObjectIdString.optional(),
544
+ /** Who sent it; used to work out their hours. */
545
+ userId: ClerkUserId.optional(),
485
546
  /** From `chrome.tabs`, never from page content. */
486
547
  url: zod.z.string().url(),
487
548
  title: zod.z.string().max(500),
@@ -497,6 +558,10 @@ var CaptureSchema = zod.z.object({
497
558
  /** Validated `vision_extract` output; shape depends on session mode. */
498
559
  analysis: zod.z.unknown().optional(),
499
560
  error: zod.z.string().max(1e3).optional(),
561
+ /** Analysis attempts by the capture worker; it gives up (`failed`) after a few. */
562
+ attempts: zod.z.number().int().min(0).default(0),
563
+ /** When the worker claimed it (`analyzing`); an old claim is taken over after a restart. */
564
+ claimedAt: zod.z.coerce.date().optional(),
500
565
  /** Blob deleted and status set to `expired` after this instant (CAPTURE_RETENTION_DAYS). */
501
566
  expiresAt: zod.z.coerce.date()
502
567
  }).merge(TimestampsSchema);
@@ -614,6 +679,51 @@ var SourceImportCreateSchema = SourceImportSchema.omit({
614
679
  committedAt: true
615
680
  });
616
681
  SourceImportCreateSchema.partial();
682
+ var MAX_CAPTURE_WINDOW_DAYS = 90;
683
+ var DAY_MS = 24 * 60 * 60 * 1e3;
684
+ function isHttpUrl(value) {
685
+ try {
686
+ const { protocol } = new URL(value);
687
+ return protocol === "http:" || protocol === "https:";
688
+ } catch {
689
+ return false;
690
+ }
691
+ }
692
+ var WindowDate = zod.z.union([zod.z.date(), zod.z.string().datetime({ offset: true })]).pipe(zod.z.coerce.date());
693
+ zod.z.object({
694
+ sourceId: ObjectIdString.optional(),
695
+ platform: Platform,
696
+ url: zod.z.string().url().refine(isHttpUrl, "Expected an http(s) URL"),
697
+ label: zod.z.string().min(1).max(200).optional(),
698
+ /** Why a person collects it instead of a scraper. */
699
+ accessIssue: AccessIssue.optional(),
700
+ note: zod.z.string().max(500).optional()
701
+ });
702
+ var LastDaysWindowSchema = zod.z.object({
703
+ mode: zod.z.literal(CaptureWindowMode.enum.last_days),
704
+ days: zod.z.number().int().min(1).max(MAX_CAPTURE_WINDOW_DAYS)
705
+ });
706
+ var RangeWindowSchema = zod.z.object({
707
+ mode: zod.z.literal(CaptureWindowMode.enum.range),
708
+ start: WindowDate,
709
+ end: WindowDate
710
+ });
711
+ zod.z.discriminatedUnion("mode", [LastDaysWindowSchema, RangeWindowSchema]).superRefine((w, ctx) => {
712
+ if (w.mode !== "range" || !(w.start instanceof Date) || !(w.end instanceof Date)) return;
713
+ if (w.end.getTime() <= w.start.getTime()) {
714
+ ctx.addIssue({
715
+ code: zod.z.ZodIssueCode.custom,
716
+ message: "captureWindow.end must be after captureWindow.start",
717
+ path: ["end"]
718
+ });
719
+ } else if (w.end.getTime() - w.start.getTime() > MAX_CAPTURE_WINDOW_DAYS * DAY_MS) {
720
+ ctx.addIssue({
721
+ code: zod.z.ZodIssueCode.custom,
722
+ message: `captureWindow range must be at most ${MAX_CAPTURE_WINDOW_DAYS} days`,
723
+ path: ["end"]
724
+ });
725
+ }
726
+ });
617
727
 
618
728
  // src/mongo/schemas.ts
619
729
  var toObject = { ...toJSONOptions, flattenMaps: true };
@@ -664,6 +774,50 @@ var taskCriteriaSchema = new mongoose.Schema(
664
774
  },
665
775
  EMBEDDED
666
776
  );
777
+ var taskTargetSchema = new mongoose.Schema(
778
+ {
779
+ sourceId: { type: ObjectId },
780
+ platform: { type: String, enum: PLATFORM_VALUES, required: true },
781
+ url: { type: String, required: true, minlength: 1 },
782
+ label: { type: String, maxlength: 200 },
783
+ accessIssue: { type: String, enum: ACCESS_ISSUE_VALUES },
784
+ note: { type: String, maxlength: 500 }
785
+ },
786
+ EMBEDDED
787
+ );
788
+ var captureWindowSchema = new mongoose.Schema(
789
+ {
790
+ mode: { type: String, enum: CAPTURE_WINDOW_MODE_VALUES, required: true },
791
+ days: {
792
+ type: Number,
793
+ min: 1,
794
+ max: MAX_CAPTURE_WINDOW_DAYS,
795
+ validate: Number.isInteger,
796
+ required() {
797
+ return this.mode === "last_days";
798
+ }
799
+ },
800
+ start: {
801
+ type: Date,
802
+ required() {
803
+ return this.mode === "range";
804
+ }
805
+ },
806
+ end: {
807
+ type: Date,
808
+ required() {
809
+ return this.mode === "range";
810
+ },
811
+ validate: {
812
+ validator(end) {
813
+ return !this.start || end.getTime() > this.start.getTime();
814
+ },
815
+ message: "captureWindow.end must be after captureWindow.start"
816
+ }
817
+ }
818
+ },
819
+ EMBEDDED
820
+ );
667
821
  var availabilityWindowSchema = new mongoose.Schema(
668
822
  {
669
823
  day: { type: Number, enum: [0, 1, 2, 3, 4, 5, 6], required: true },
@@ -837,6 +991,8 @@ var taskSchema = new mongoose.Schema(
837
991
  keywords: { type: [String], required: true, default: [] },
838
992
  searchQueries: { type: [String], required: true, default: [] },
839
993
  criteria: { type: taskCriteriaSchema, required: true },
994
+ target: { type: taskTargetSchema },
995
+ captureWindow: { type: captureWindowSchema },
840
996
  status: { type: String, enum: TASK_STATUS_VALUES, required: true, default: "draft" },
841
997
  approvedBy: clerkUserIdOptional,
842
998
  approvedAt: { type: Date },
@@ -887,6 +1043,8 @@ var hoursLogSchema = new mongoose.Schema(
887
1043
  minutes: { type: Number, required: true, min: 1, validate: Number.isInteger },
888
1044
  note: { type: String, required: true, default: "" },
889
1045
  date: { type: Date, required: true },
1046
+ assignmentId: { type: ObjectId },
1047
+ source: { type: String, enum: HOURS_LOG_SOURCE_VALUES },
890
1048
  deletedAt: { type: Date }
891
1049
  },
892
1050
  collectionOptions(COLLECTIONS.hoursLogs)
@@ -977,6 +1135,7 @@ var sourceSchema = new mongoose.Schema(
977
1135
  discoveredBy: { type: discoveredBySchema, required: true },
978
1136
  lastCollectedAt: { type: Date },
979
1137
  nextVisitAt: { type: Date },
1138
+ visitIntervalMs: { type: Number, min: 1 },
980
1139
  deletedAt: { type: Date }
981
1140
  },
982
1141
  collectionOptions(COLLECTIONS.sources)
@@ -1121,6 +1280,7 @@ var agentSessionSchema = new mongoose.Schema(
1121
1280
  lastSeq: counter,
1122
1281
  stats: { type: agentSessionStatsSchema, required: true, default: () => ({}) },
1123
1282
  budget: { type: agentSessionBudgetSchema, required: true, default: () => ({}) },
1283
+ captureWindow: { type: coverageWindowSchema },
1124
1284
  state: { type: Mixed }
1125
1285
  },
1126
1286
  collectionOptions(COLLECTIONS.agentSessions)
@@ -1173,7 +1333,11 @@ var captureDomSummarySchema = new mongoose.Schema(
1173
1333
  var captureSchema = new mongoose.Schema(
1174
1334
  {
1175
1335
  orgId: clerkOrgId,
1176
- sessionId: { type: ObjectId, required: true },
1336
+ sessionId: { type: ObjectId },
1337
+ assignmentId: { type: ObjectId },
1338
+ taskId: { type: ObjectId },
1339
+ missionId: { type: ObjectId },
1340
+ userId: clerkUserIdOptional,
1177
1341
  url: { type: String, required: true },
1178
1342
  title: { type: String, required: true, default: "", maxlength: 500 },
1179
1343
  capturedAt: { type: Date, required: true },
@@ -1186,6 +1350,8 @@ var captureSchema = new mongoose.Schema(
1186
1350
  status: { type: String, enum: CAPTURE_STATUS_VALUES, required: true, default: "uploaded" },
1187
1351
  analysis: { type: Mixed },
1188
1352
  error: { type: String, maxlength: 1e3 },
1353
+ attempts: { type: Number, required: true, default: 0, min: 0, validate: Number.isInteger },
1354
+ claimedAt: { type: Date },
1189
1355
  expiresAt: { type: Date, required: true }
1190
1356
  },
1191
1357
  collectionOptions(COLLECTIONS.captures)
@@ -1317,6 +1483,7 @@ exports.blobRefSchema = blobRefSchema;
1317
1483
  exports.captureDomSummarySchema = captureDomSummarySchema;
1318
1484
  exports.captureRegionSchema = captureRegionSchema;
1319
1485
  exports.captureSchema = captureSchema;
1486
+ exports.captureWindowSchema = captureWindowSchema;
1320
1487
  exports.collectorSchema = collectorSchema;
1321
1488
  exports.coverageWindowSchema = coverageWindowSchema;
1322
1489
  exports.dataItemContentSchema = dataItemContentSchema;
@@ -1350,6 +1517,7 @@ exports.specialAccessSchema = specialAccessSchema;
1350
1517
  exports.systemRecommendationSchema = systemRecommendationSchema;
1351
1518
  exports.taskCriteriaSchema = taskCriteriaSchema;
1352
1519
  exports.taskSchema = taskSchema;
1520
+ exports.taskTargetSchema = taskTargetSchema;
1353
1521
  exports.toJSONOptions = toJSONOptions;
1354
1522
  //# sourceMappingURL=index.cjs.map
1355
1523
  //# sourceMappingURL=index.cjs.map