@clipin/convex-wearables 0.0.2 → 0.1.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.
Files changed (104) hide show
  1. package/README.md +395 -0
  2. package/dist/client/index.d.ts +47 -6
  3. package/dist/client/index.d.ts.map +1 -1
  4. package/dist/client/index.js +30 -0
  5. package/dist/client/index.js.map +1 -1
  6. package/dist/client/types.d.ts +83 -0
  7. package/dist/client/types.d.ts.map +1 -1
  8. package/dist/client/types.js.map +1 -1
  9. package/dist/component/_generated/component.d.ts +50 -0
  10. package/dist/component/_generated/component.d.ts.map +1 -0
  11. package/dist/component/_generated/component.js +11 -0
  12. package/dist/component/_generated/component.js.map +1 -0
  13. package/dist/component/backfillJobs.d.ts +11 -11
  14. package/dist/component/connections.d.ts +9 -9
  15. package/dist/component/connections.d.ts.map +1 -1
  16. package/dist/component/connections.js +2 -0
  17. package/dist/component/connections.js.map +1 -1
  18. package/dist/component/dataPoints.d.ts +153 -39
  19. package/dist/component/dataPoints.d.ts.map +1 -1
  20. package/dist/component/dataPoints.js +1048 -139
  21. package/dist/component/dataPoints.js.map +1 -1
  22. package/dist/component/events.d.ts +13 -13
  23. package/dist/component/garminBackfill.d.ts +2 -2
  24. package/dist/component/garminWebhooks.d.ts +2 -2
  25. package/dist/component/garminWebhooks.d.ts.map +1 -1
  26. package/dist/component/garminWebhooks.js +2 -0
  27. package/dist/component/garminWebhooks.js.map +1 -1
  28. package/dist/component/lifecycle.d.ts +1 -1
  29. package/dist/component/lifecycle.d.ts.map +1 -1
  30. package/dist/component/lifecycle.js +39 -1
  31. package/dist/component/lifecycle.js.map +1 -1
  32. package/dist/component/oauthStates.d.ts +3 -3
  33. package/dist/component/schema.d.ts +192 -28
  34. package/dist/component/schema.d.ts.map +1 -1
  35. package/dist/component/schema.js +89 -0
  36. package/dist/component/schema.js.map +1 -1
  37. package/dist/component/sdkPush.d.ts +11 -11
  38. package/dist/component/summaries.d.ts +4 -4
  39. package/dist/component/syncJobs.d.ts +23 -23
  40. package/dist/component/syncWorkflow.d.ts +2 -2
  41. package/dist/component/timeSeriesPolicyUtils.d.ts +97 -0
  42. package/dist/component/timeSeriesPolicyUtils.d.ts.map +1 -0
  43. package/dist/component/timeSeriesPolicyUtils.js +163 -0
  44. package/dist/component/timeSeriesPolicyUtils.js.map +1 -0
  45. package/dist/test.d.ts +581 -0
  46. package/dist/test.d.ts.map +1 -0
  47. package/dist/test.js +17 -0
  48. package/dist/test.js.map +1 -0
  49. package/package.json +12 -2
  50. package/src/client/_generated/_ignore.ts +2 -0
  51. package/src/client/index.test.ts +149 -0
  52. package/src/client/index.ts +859 -0
  53. package/src/client/types.ts +632 -0
  54. package/src/component/_generated/_ignore.ts +2 -0
  55. package/src/component/_generated/api.ts +16 -0
  56. package/src/component/_generated/component.ts +74 -0
  57. package/src/component/_generated/dataModel.ts +40 -0
  58. package/src/component/_generated/server.ts +48 -0
  59. package/src/component/backfillJobs.test.ts +47 -0
  60. package/src/component/backfillJobs.ts +245 -0
  61. package/src/component/connections.test.ts +297 -0
  62. package/src/component/connections.ts +329 -0
  63. package/src/component/convex.config.ts +7 -0
  64. package/src/component/dataPoints.test.ts +827 -0
  65. package/src/component/dataPoints.ts +1676 -0
  66. package/src/component/dataSources.test.ts +247 -0
  67. package/src/component/dataSources.ts +109 -0
  68. package/src/component/events.test.ts +380 -0
  69. package/src/component/events.ts +288 -0
  70. package/src/component/garminBackfill.ts +343 -0
  71. package/src/component/garminWebhooks.test.ts +609 -0
  72. package/src/component/garminWebhooks.ts +656 -0
  73. package/src/component/httpHandlers.ts +153 -0
  74. package/src/component/lifecycle.test.ts +179 -0
  75. package/src/component/lifecycle.ts +128 -0
  76. package/src/component/menstrualCycles.ts +124 -0
  77. package/src/component/oauthActions.ts +261 -0
  78. package/src/component/oauthStates.test.ts +170 -0
  79. package/src/component/oauthStates.ts +85 -0
  80. package/src/component/providerSettings.ts +66 -0
  81. package/src/component/providers/additionalProviders.test.ts +401 -0
  82. package/src/component/providers/garmin.ts +1169 -0
  83. package/src/component/providers/oauth.test.ts +174 -0
  84. package/src/component/providers/oauth.ts +246 -0
  85. package/src/component/providers/polar.ts +220 -0
  86. package/src/component/providers/registry.ts +37 -0
  87. package/src/component/providers/strava.test.ts +195 -0
  88. package/src/component/providers/strava.ts +253 -0
  89. package/src/component/providers/suunto.ts +592 -0
  90. package/src/component/providers/types.ts +189 -0
  91. package/src/component/providers/whoop.ts +600 -0
  92. package/src/component/schema.ts +445 -0
  93. package/src/component/sdkPush.test.ts +367 -0
  94. package/src/component/sdkPush.ts +440 -0
  95. package/src/component/summaries.test.ts +201 -0
  96. package/src/component/summaries.ts +143 -0
  97. package/src/component/syncJobs.test.ts +254 -0
  98. package/src/component/syncJobs.ts +140 -0
  99. package/src/component/syncWorkflow.test.ts +87 -0
  100. package/src/component/syncWorkflow.ts +739 -0
  101. package/src/component/test.setup.ts +6 -0
  102. package/src/component/timeSeriesPolicyUtils.ts +243 -0
  103. package/src/component/workflowManager.ts +19 -0
  104. package/src/test.ts +25 -0
@@ -5,7 +5,7 @@ export declare const providerName: import("convex/values").VUnion<"garmin" | "su
5
5
  /**
6
6
  * Connection status enum.
7
7
  */
8
- export declare const connectionStatus: import("convex/values").VUnion<"active" | "inactive" | "revoked" | "expired" | "error", [import("convex/values").VLiteral<"active", "required">, import("convex/values").VLiteral<"inactive", "required">, import("convex/values").VLiteral<"revoked", "required">, import("convex/values").VLiteral<"expired", "required">, import("convex/values").VLiteral<"error", "required">], "required", never>;
8
+ export declare const connectionStatus: import("convex/values").VUnion<"error" | "active" | "inactive" | "revoked" | "expired", [import("convex/values").VLiteral<"active", "required">, import("convex/values").VLiteral<"inactive", "required">, import("convex/values").VLiteral<"revoked", "required">, import("convex/values").VLiteral<"expired", "required">, import("convex/values").VLiteral<"error", "required">], "required", never>;
9
9
  /**
10
10
  * Event category — top-level classification.
11
11
  */
@@ -13,11 +13,15 @@ export declare const eventCategory: import("convex/values").VUnion<"workout" | "
13
13
  /**
14
14
  * Sync job status.
15
15
  */
16
- export declare const syncJobStatus: import("convex/values").VUnion<"queued" | "running" | "completed" | "failed" | "canceled", [import("convex/values").VLiteral<"queued", "required">, import("convex/values").VLiteral<"running", "required">, import("convex/values").VLiteral<"completed", "required">, import("convex/values").VLiteral<"failed", "required">, import("convex/values").VLiteral<"canceled", "required">], "required", never>;
16
+ export declare const syncJobStatus: import("convex/values").VUnion<"failed" | "canceled" | "running" | "completed" | "queued", [import("convex/values").VLiteral<"queued", "required">, import("convex/values").VLiteral<"running", "required">, import("convex/values").VLiteral<"completed", "required">, import("convex/values").VLiteral<"failed", "required">, import("convex/values").VLiteral<"canceled", "required">], "required", never>;
17
17
  /**
18
18
  * Backfill job status.
19
19
  */
20
- export declare const backfillStatus: import("convex/values").VUnion<"queued" | "running" | "completed" | "failed" | "canceled", [import("convex/values").VLiteral<"queued", "required">, import("convex/values").VLiteral<"running", "required">, import("convex/values").VLiteral<"completed", "required">, import("convex/values").VLiteral<"failed", "required">, import("convex/values").VLiteral<"canceled", "required">], "required", never>;
20
+ export declare const backfillStatus: import("convex/values").VUnion<"failed" | "canceled" | "running" | "completed" | "queued", [import("convex/values").VLiteral<"queued", "required">, import("convex/values").VLiteral<"running", "required">, import("convex/values").VLiteral<"completed", "required">, import("convex/values").VLiteral<"failed", "required">, import("convex/values").VLiteral<"canceled", "required">], "required", never>;
21
+ /**
22
+ * Supported rollup aggregations.
23
+ */
24
+ export declare const timeSeriesAggregation: import("convex/values").VUnion<"avg" | "min" | "max" | "last" | "count", [import("convex/values").VLiteral<"avg", "required">, import("convex/values").VLiteral<"min", "required">, import("convex/values").VLiteral<"max", "required">, import("convex/values").VLiteral<"last", "required">, import("convex/values").VLiteral<"count", "required">], "required", never>;
21
25
  declare const _default: import("convex/server").SchemaDefinition<{
22
26
  connections: import("convex/server").TableDefinition<import("convex/values").VObject<{
23
27
  providerUserId?: string | undefined;
@@ -28,7 +32,7 @@ declare const _default: import("convex/server").SchemaDefinition<{
28
32
  scope?: string | undefined;
29
33
  lastSyncedAt?: number | undefined;
30
34
  provider: "garmin" | "suunto" | "polar" | "whoop" | "strava" | "apple" | "samsung" | "google";
31
- status: "active" | "inactive" | "revoked" | "expired" | "error";
35
+ status: "error" | "active" | "inactive" | "revoked" | "expired";
32
36
  userId: string;
33
37
  }, {
34
38
  userId: import("convex/values").VString<string, "required">;
@@ -39,7 +43,7 @@ declare const _default: import("convex/server").SchemaDefinition<{
39
43
  refreshToken: import("convex/values").VString<string | undefined, "optional">;
40
44
  tokenExpiresAt: import("convex/values").VFloat64<number | undefined, "optional">;
41
45
  scope: import("convex/values").VString<string | undefined, "optional">;
42
- status: import("convex/values").VUnion<"active" | "inactive" | "revoked" | "expired" | "error", [import("convex/values").VLiteral<"active", "required">, import("convex/values").VLiteral<"inactive", "required">, import("convex/values").VLiteral<"revoked", "required">, import("convex/values").VLiteral<"expired", "required">, import("convex/values").VLiteral<"error", "required">], "required", never>;
46
+ status: import("convex/values").VUnion<"error" | "active" | "inactive" | "revoked" | "expired", [import("convex/values").VLiteral<"active", "required">, import("convex/values").VLiteral<"inactive", "required">, import("convex/values").VLiteral<"revoked", "required">, import("convex/values").VLiteral<"expired", "required">, import("convex/values").VLiteral<"error", "required">], "required", never>;
43
47
  lastSyncedAt: import("convex/values").VFloat64<number | undefined, "optional">;
44
48
  }, "required", "provider" | "status" | "userId" | "providerUserId" | "providerUsername" | "accessToken" | "refreshToken" | "tokenExpiresAt" | "scope" | "lastSyncedAt">, {
45
49
  by_user: ["userId", "_creationTime"];
@@ -72,26 +76,58 @@ declare const _default: import("convex/server").SchemaDefinition<{
72
76
  }, {}, {}>;
73
77
  dataPoints: import("convex/server").TableDefinition<import("convex/values").VObject<{
74
78
  externalId?: string | undefined;
79
+ dataSourceId: import("convex/values").GenericId<"dataSources">;
75
80
  seriesType: string;
76
81
  recordedAt: number;
77
82
  value: number;
78
- dataSourceId: import("convex/values").GenericId<"dataSources">;
79
83
  }, {
80
84
  dataSourceId: import("convex/values").VId<import("convex/values").GenericId<"dataSources">, "required">;
81
85
  seriesType: import("convex/values").VString<string, "required">;
82
86
  recordedAt: import("convex/values").VFloat64<number, "required">;
83
87
  value: import("convex/values").VFloat64<number, "required">;
84
88
  externalId: import("convex/values").VString<string | undefined, "optional">;
85
- }, "required", "externalId" | "seriesType" | "recordedAt" | "value" | "dataSourceId">, {
89
+ }, "required", "dataSourceId" | "seriesType" | "recordedAt" | "value" | "externalId">, {
86
90
  by_source_type_time: ["dataSourceId", "seriesType", "recordedAt", "_creationTime"];
87
91
  by_type_time: ["seriesType", "recordedAt", "_creationTime"];
88
92
  }, {}, {}>;
93
+ timeSeriesRollups: import("convex/server").TableDefinition<import("convex/values").VObject<{
94
+ avg: number;
95
+ min: number;
96
+ max: number;
97
+ last: number;
98
+ count: number;
99
+ dataSourceId: import("convex/values").GenericId<"dataSources">;
100
+ seriesType: string;
101
+ bucketMs: number;
102
+ bucketStart: number;
103
+ bucketEnd: number;
104
+ lastRecordedAt: number;
105
+ updatedAt: number;
106
+ }, {
107
+ dataSourceId: import("convex/values").VId<import("convex/values").GenericId<"dataSources">, "required">;
108
+ seriesType: import("convex/values").VString<string, "required">;
109
+ bucketMs: import("convex/values").VFloat64<number, "required">;
110
+ bucketStart: import("convex/values").VFloat64<number, "required">;
111
+ bucketEnd: import("convex/values").VFloat64<number, "required">;
112
+ avg: import("convex/values").VFloat64<number, "required">;
113
+ min: import("convex/values").VFloat64<number, "required">;
114
+ max: import("convex/values").VFloat64<number, "required">;
115
+ last: import("convex/values").VFloat64<number, "required">;
116
+ lastRecordedAt: import("convex/values").VFloat64<number, "required">;
117
+ count: import("convex/values").VFloat64<number, "required">;
118
+ updatedAt: import("convex/values").VFloat64<number, "required">;
119
+ }, "required", "avg" | "min" | "max" | "last" | "count" | "dataSourceId" | "seriesType" | "bucketMs" | "bucketStart" | "bucketEnd" | "lastRecordedAt" | "updatedAt">, {
120
+ by_source_type_bucket: ["dataSourceId", "seriesType", "bucketStart", "_creationTime"];
121
+ by_source_type_bucket_size: ["dataSourceId", "seriesType", "bucketMs", "bucketStart", "_creationTime"];
122
+ by_source_bucket: ["dataSourceId", "bucketStart", "_creationTime"];
123
+ by_type_bucket: ["seriesType", "bucketStart", "_creationTime"];
124
+ }, {}, {}>;
89
125
  events: import("convex/server").TableDefinition<import("convex/values").VObject<{
90
126
  type?: string | undefined;
127
+ externalId?: string | undefined;
91
128
  sourceName?: string | undefined;
92
129
  durationSeconds?: number | undefined;
93
130
  endDatetime?: number | undefined;
94
- externalId?: string | undefined;
95
131
  heartRateMin?: number | undefined;
96
132
  heartRateMax?: number | undefined;
97
133
  heartRateAvg?: number | undefined;
@@ -119,10 +155,10 @@ declare const _default: import("convex/server").SchemaDefinition<{
119
155
  startTime: number;
120
156
  endTime: number;
121
157
  }[] | undefined;
122
- category: "workout" | "sleep";
123
- startDatetime: number;
124
158
  userId: string;
125
159
  dataSourceId: import("convex/values").GenericId<"dataSources">;
160
+ category: "workout" | "sleep";
161
+ startDatetime: number;
126
162
  }, {
127
163
  dataSourceId: import("convex/values").VId<import("convex/values").GenericId<"dataSources">, "required">;
128
164
  userId: import("convex/values").VString<string, "required">;
@@ -168,7 +204,7 @@ declare const _default: import("convex/server").SchemaDefinition<{
168
204
  startTime: import("convex/values").VFloat64<number, "required">;
169
205
  endTime: import("convex/values").VFloat64<number, "required">;
170
206
  }, "required", "stage" | "startTime" | "endTime">, "optional">;
171
- }, "required", "category" | "type" | "sourceName" | "durationSeconds" | "startDatetime" | "endDatetime" | "externalId" | "heartRateMin" | "heartRateMax" | "heartRateAvg" | "energyBurned" | "distance" | "stepsCount" | "maxSpeed" | "maxWatts" | "movingTimeSeconds" | "totalElevationGain" | "averageSpeed" | "averageWatts" | "elevHigh" | "elevLow" | "sleepTotalDurationMinutes" | "sleepTimeInBedMinutes" | "sleepEfficiencyScore" | "sleepDeepMinutes" | "sleepRemMinutes" | "sleepLightMinutes" | "sleepAwakeMinutes" | "isNap" | "sleepStages" | "userId" | "dataSourceId">, {
207
+ }, "required", "type" | "userId" | "dataSourceId" | "externalId" | "category" | "sourceName" | "durationSeconds" | "startDatetime" | "endDatetime" | "heartRateMin" | "heartRateMax" | "heartRateAvg" | "energyBurned" | "distance" | "stepsCount" | "maxSpeed" | "maxWatts" | "movingTimeSeconds" | "totalElevationGain" | "averageSpeed" | "averageWatts" | "elevHigh" | "elevLow" | "sleepTotalDurationMinutes" | "sleepTimeInBedMinutes" | "sleepEfficiencyScore" | "sleepDeepMinutes" | "sleepRemMinutes" | "sleepLightMinutes" | "sleepAwakeMinutes" | "isNap" | "sleepStages">, {
172
208
  by_user_category_time: ["userId", "category", "startDatetime", "_creationTime"];
173
209
  by_source_category_time: ["dataSourceId", "category", "startDatetime", "_creationTime"];
174
210
  by_source_start_end: ["dataSourceId", "startDatetime", "endDatetime", "_creationTime"];
@@ -203,8 +239,8 @@ declare const _default: import("convex/server").SchemaDefinition<{
203
239
  avgStressLevel?: number | undefined;
204
240
  bodyBattery?: number | undefined;
205
241
  spo2Avg?: number | undefined;
206
- category: string;
207
242
  userId: string;
243
+ category: string;
208
244
  date: string;
209
245
  }, {
210
246
  userId: import("convex/values").VString<string, "required">;
@@ -238,29 +274,29 @@ declare const _default: import("convex/server").SchemaDefinition<{
238
274
  avgStressLevel: import("convex/values").VFloat64<number | undefined, "optional">;
239
275
  bodyBattery: import("convex/values").VFloat64<number | undefined, "optional">;
240
276
  spo2Avg: import("convex/values").VFloat64<number | undefined, "optional">;
241
- }, "required", "category" | "userId" | "date" | "totalSteps" | "totalCalories" | "activeCalories" | "activeMinutes" | "totalDistance" | "floorsClimbed" | "avgHeartRate" | "maxHeartRate" | "minHeartRate" | "sleepDurationMinutes" | "sleepEfficiency" | "deepSleepMinutes" | "remSleepMinutes" | "lightSleepMinutes" | "awakeDuringMinutes" | "timeInBedMinutes" | "hrvAvg" | "hrvRmssd" | "restingHeartRate" | "recoveryScore" | "weight" | "bodyFatPercentage" | "bodyMassIndex" | "leanBodyMass" | "bodyTemperature" | "avgStressLevel" | "bodyBattery" | "spo2Avg">, {
277
+ }, "required", "userId" | "category" | "date" | "totalSteps" | "totalCalories" | "activeCalories" | "activeMinutes" | "totalDistance" | "floorsClimbed" | "avgHeartRate" | "maxHeartRate" | "minHeartRate" | "sleepDurationMinutes" | "sleepEfficiency" | "deepSleepMinutes" | "remSleepMinutes" | "lightSleepMinutes" | "awakeDuringMinutes" | "timeInBedMinutes" | "hrvAvg" | "hrvRmssd" | "restingHeartRate" | "recoveryScore" | "weight" | "bodyFatPercentage" | "bodyMassIndex" | "leanBodyMass" | "bodyTemperature" | "avgStressLevel" | "bodyBattery" | "spo2Avg">, {
242
278
  by_user_category_date: ["userId", "category", "date", "_creationTime"];
243
279
  by_user_date: ["userId", "date", "_creationTime"];
244
280
  }, {}, {}>;
245
281
  syncJobs: import("convex/server").TableDefinition<import("convex/values").VObject<{
246
282
  error?: string | undefined;
283
+ completedAt?: number | undefined;
284
+ workflowId?: string | undefined;
247
285
  mode?: "manual" | "cron" | "webhook" | undefined;
248
286
  triggerSource?: string | undefined;
249
- completedAt?: number | undefined;
250
287
  recordsProcessed?: number | undefined;
251
- workflowId?: string | undefined;
252
288
  windowStart?: number | undefined;
253
289
  windowEnd?: number | undefined;
254
290
  attempt?: number | undefined;
255
291
  lastHeartbeatAt?: number | undefined;
256
292
  cursor?: string | undefined;
257
293
  currentPhase?: "events" | "dataPoints" | "summaries" | undefined;
294
+ startedAt: number;
258
295
  provider: "garmin" | "suunto" | "polar" | "whoop" | "strava" | "apple" | "samsung" | "google";
259
- status: "queued" | "running" | "completed" | "failed" | "canceled";
296
+ status: "failed" | "canceled" | "running" | "completed" | "queued";
260
297
  userId: string;
261
298
  connectionId: import("convex/values").GenericId<"connections">;
262
299
  idempotencyKey: string;
263
- startedAt: number;
264
300
  }, {
265
301
  connectionId: import("convex/values").VId<import("convex/values").GenericId<"connections">, "required">;
266
302
  userId: import("convex/values").VString<string, "required">;
@@ -268,7 +304,7 @@ declare const _default: import("convex/server").SchemaDefinition<{
268
304
  mode: import("convex/values").VUnion<"manual" | "cron" | "webhook" | undefined, [import("convex/values").VLiteral<"manual", "required">, import("convex/values").VLiteral<"cron", "required">, import("convex/values").VLiteral<"webhook", "required">], "optional", never>;
269
305
  triggerSource: import("convex/values").VString<string | undefined, "optional">;
270
306
  idempotencyKey: import("convex/values").VString<string, "required">;
271
- status: import("convex/values").VUnion<"queued" | "running" | "completed" | "failed" | "canceled", [import("convex/values").VLiteral<"queued", "required">, import("convex/values").VLiteral<"running", "required">, import("convex/values").VLiteral<"completed", "required">, import("convex/values").VLiteral<"failed", "required">, import("convex/values").VLiteral<"canceled", "required">], "required", never>;
307
+ status: import("convex/values").VUnion<"failed" | "canceled" | "running" | "completed" | "queued", [import("convex/values").VLiteral<"queued", "required">, import("convex/values").VLiteral<"running", "required">, import("convex/values").VLiteral<"completed", "required">, import("convex/values").VLiteral<"failed", "required">, import("convex/values").VLiteral<"canceled", "required">], "required", never>;
272
308
  startedAt: import("convex/values").VFloat64<number, "required">;
273
309
  completedAt: import("convex/values").VFloat64<number | undefined, "optional">;
274
310
  error: import("convex/values").VString<string | undefined, "optional">;
@@ -280,7 +316,7 @@ declare const _default: import("convex/server").SchemaDefinition<{
280
316
  lastHeartbeatAt: import("convex/values").VFloat64<number | undefined, "optional">;
281
317
  cursor: import("convex/values").VString<string | undefined, "optional">;
282
318
  currentPhase: import("convex/values").VUnion<"events" | "dataPoints" | "summaries" | undefined, [import("convex/values").VLiteral<"events", "required">, import("convex/values").VLiteral<"dataPoints", "required">, import("convex/values").VLiteral<"summaries", "required">], "optional", never>;
283
- }, "required", "error" | "provider" | "status" | "userId" | "connectionId" | "mode" | "triggerSource" | "idempotencyKey" | "startedAt" | "completedAt" | "recordsProcessed" | "workflowId" | "windowStart" | "windowEnd" | "attempt" | "lastHeartbeatAt" | "cursor" | "currentPhase">, {
319
+ }, "required", "error" | "startedAt" | "completedAt" | "workflowId" | "provider" | "status" | "userId" | "connectionId" | "mode" | "triggerSource" | "idempotencyKey" | "recordsProcessed" | "windowStart" | "windowEnd" | "attempt" | "lastHeartbeatAt" | "cursor" | "currentPhase">, {
284
320
  by_user: ["userId", "_creationTime"];
285
321
  by_connection: ["connectionId", "_creationTime"];
286
322
  by_user_provider: ["userId", "provider", "_creationTime"];
@@ -292,9 +328,9 @@ declare const _default: import("convex/server").SchemaDefinition<{
292
328
  oauthStates: import("convex/server").TableDefinition<import("convex/values").VObject<{
293
329
  codeVerifier?: string | undefined;
294
330
  redirectUri?: string | undefined;
331
+ state: string;
295
332
  provider: "garmin" | "suunto" | "polar" | "whoop" | "strava" | "apple" | "samsung" | "google";
296
333
  userId: string;
297
- state: string;
298
334
  createdAt: number;
299
335
  }, {
300
336
  state: import("convex/values").VString<string, "required">;
@@ -303,14 +339,14 @@ declare const _default: import("convex/server").SchemaDefinition<{
303
339
  codeVerifier: import("convex/values").VString<string | undefined, "optional">;
304
340
  redirectUri: import("convex/values").VString<string | undefined, "optional">;
305
341
  createdAt: import("convex/values").VFloat64<number, "required">;
306
- }, "required", "provider" | "userId" | "state" | "codeVerifier" | "redirectUri" | "createdAt">, {
342
+ }, "required", "state" | "provider" | "userId" | "codeVerifier" | "redirectUri" | "createdAt">, {
307
343
  by_state: ["state", "_creationTime"];
308
344
  }, {}, {}>;
309
345
  providerSettings: import("convex/server").TableDefinition<import("convex/values").VObject<{
346
+ updatedAt?: number | undefined;
310
347
  clientId?: string | undefined;
311
348
  clientSecret?: string | undefined;
312
349
  subscriptionKey?: string | undefined;
313
- updatedAt?: number | undefined;
314
350
  provider: "garmin" | "suunto" | "polar" | "whoop" | "strava" | "apple" | "samsung" | "google";
315
351
  isEnabled: boolean;
316
352
  }, {
@@ -320,9 +356,137 @@ declare const _default: import("convex/server").SchemaDefinition<{
320
356
  clientSecret: import("convex/values").VString<string | undefined, "optional">;
321
357
  subscriptionKey: import("convex/values").VString<string | undefined, "optional">;
322
358
  updatedAt: import("convex/values").VFloat64<number | undefined, "optional">;
323
- }, "required", "provider" | "isEnabled" | "clientId" | "clientSecret" | "subscriptionKey" | "updatedAt">, {
359
+ }, "required", "provider" | "updatedAt" | "isEnabled" | "clientId" | "clientSecret" | "subscriptionKey">, {
324
360
  by_provider: ["provider", "_creationTime"];
325
361
  }, {}, {}>;
362
+ timeSeriesPolicyRules: import("convex/server").TableDefinition<import("convex/values").VObject<{
363
+ provider?: "garmin" | "suunto" | "polar" | "whoop" | "strava" | "apple" | "samsung" | "google" | undefined;
364
+ seriesType?: string | undefined;
365
+ updatedAt: number;
366
+ policySetKind: "default" | "preset";
367
+ policySetKey: string;
368
+ scopeKey: string;
369
+ tiers: ({
370
+ kind: "raw";
371
+ fromAgeMs: number;
372
+ toAgeMs: number | null;
373
+ } | {
374
+ kind: "rollup";
375
+ bucketMs: number;
376
+ fromAgeMs: number;
377
+ toAgeMs: number | null;
378
+ aggregations: ("avg" | "min" | "max" | "last" | "count")[];
379
+ })[];
380
+ }, {
381
+ policySetKind: import("convex/values").VUnion<"default" | "preset", [import("convex/values").VLiteral<"default", "required">, import("convex/values").VLiteral<"preset", "required">], "required", never>;
382
+ policySetKey: import("convex/values").VString<string, "required">;
383
+ scopeKey: import("convex/values").VString<string, "required">;
384
+ provider: import("convex/values").VUnion<"garmin" | "suunto" | "polar" | "whoop" | "strava" | "apple" | "samsung" | "google" | undefined, [import("convex/values").VLiteral<"garmin", "required">, import("convex/values").VLiteral<"suunto", "required">, import("convex/values").VLiteral<"polar", "required">, import("convex/values").VLiteral<"whoop", "required">, import("convex/values").VLiteral<"strava", "required">, import("convex/values").VLiteral<"apple", "required">, import("convex/values").VLiteral<"samsung", "required">, import("convex/values").VLiteral<"google", "required">], "optional", never>;
385
+ seriesType: import("convex/values").VString<string | undefined, "optional">;
386
+ tiers: import("convex/values").VArray<({
387
+ kind: "raw";
388
+ fromAgeMs: number;
389
+ toAgeMs: number | null;
390
+ } | {
391
+ kind: "rollup";
392
+ bucketMs: number;
393
+ fromAgeMs: number;
394
+ toAgeMs: number | null;
395
+ aggregations: ("avg" | "min" | "max" | "last" | "count")[];
396
+ })[], import("convex/values").VUnion<{
397
+ kind: "raw";
398
+ fromAgeMs: number;
399
+ toAgeMs: number | null;
400
+ } | {
401
+ kind: "rollup";
402
+ bucketMs: number;
403
+ fromAgeMs: number;
404
+ toAgeMs: number | null;
405
+ aggregations: ("avg" | "min" | "max" | "last" | "count")[];
406
+ }, [import("convex/values").VObject<{
407
+ kind: "raw";
408
+ fromAgeMs: number;
409
+ toAgeMs: number | null;
410
+ }, {
411
+ kind: import("convex/values").VLiteral<"raw", "required">;
412
+ fromAgeMs: import("convex/values").VFloat64<number, "required">;
413
+ toAgeMs: import("convex/values").VUnion<number | null, [import("convex/values").VFloat64<number, "required">, import("convex/values").VNull<null, "required">], "required", never>;
414
+ }, "required", "kind" | "fromAgeMs" | "toAgeMs">, import("convex/values").VObject<{
415
+ kind: "rollup";
416
+ bucketMs: number;
417
+ fromAgeMs: number;
418
+ toAgeMs: number | null;
419
+ aggregations: ("avg" | "min" | "max" | "last" | "count")[];
420
+ }, {
421
+ kind: import("convex/values").VLiteral<"rollup", "required">;
422
+ fromAgeMs: import("convex/values").VFloat64<number, "required">;
423
+ toAgeMs: import("convex/values").VUnion<number | null, [import("convex/values").VFloat64<number, "required">, import("convex/values").VNull<null, "required">], "required", never>;
424
+ bucketMs: import("convex/values").VFloat64<number, "required">;
425
+ aggregations: import("convex/values").VArray<("avg" | "min" | "max" | "last" | "count")[], import("convex/values").VUnion<"avg" | "min" | "max" | "last" | "count", [import("convex/values").VLiteral<"avg", "required">, import("convex/values").VLiteral<"min", "required">, import("convex/values").VLiteral<"max", "required">, import("convex/values").VLiteral<"last", "required">, import("convex/values").VLiteral<"count", "required">], "required", never>, "required">;
426
+ }, "required", "kind" | "bucketMs" | "fromAgeMs" | "toAgeMs" | "aggregations">], "required", "kind" | "bucketMs" | "fromAgeMs" | "toAgeMs" | "aggregations">, "required">;
427
+ updatedAt: import("convex/values").VFloat64<number, "required">;
428
+ }, "required", "provider" | "seriesType" | "updatedAt" | "policySetKind" | "policySetKey" | "scopeKey" | "tiers">, {
429
+ by_set: ["policySetKind", "policySetKey", "_creationTime"];
430
+ by_set_scope: ["policySetKind", "policySetKey", "provider", "seriesType", "_creationTime"];
431
+ }, {}, {}>;
432
+ timeSeriesPolicyAssignments: import("convex/server").TableDefinition<import("convex/values").VObject<{
433
+ userId: string;
434
+ updatedAt: number;
435
+ presetKey: string;
436
+ }, {
437
+ userId: import("convex/values").VString<string, "required">;
438
+ presetKey: import("convex/values").VString<string, "required">;
439
+ updatedAt: import("convex/values").VFloat64<number, "required">;
440
+ }, "required", "userId" | "updatedAt" | "presetKey">, {
441
+ by_user: ["userId", "_creationTime"];
442
+ by_preset: ["presetKey", "_creationTime"];
443
+ }, {}, {}>;
444
+ timeSeriesPolicySettings: import("convex/server").TableDefinition<import("convex/values").VObject<{
445
+ scheduledAt?: number | undefined;
446
+ lastRunAt?: number | undefined;
447
+ lastError?: string | undefined;
448
+ updatedAt: number;
449
+ key: string;
450
+ maintenanceEnabled: boolean;
451
+ maintenanceIntervalMs: number;
452
+ }, {
453
+ key: import("convex/values").VString<string, "required">;
454
+ maintenanceEnabled: import("convex/values").VBoolean<boolean, "required">;
455
+ maintenanceIntervalMs: import("convex/values").VFloat64<number, "required">;
456
+ scheduledAt: import("convex/values").VFloat64<number | undefined, "optional">;
457
+ lastRunAt: import("convex/values").VFloat64<number | undefined, "optional">;
458
+ lastError: import("convex/values").VString<string | undefined, "optional">;
459
+ updatedAt: import("convex/values").VFloat64<number, "required">;
460
+ }, "required", "updatedAt" | "key" | "maintenanceEnabled" | "maintenanceIntervalMs" | "scheduledAt" | "lastRunAt" | "lastError">, {
461
+ by_key: ["key", "_creationTime"];
462
+ }, {}, {}>;
463
+ timeSeriesSeriesState: import("convex/server").TableDefinition<import("convex/values").VObject<{
464
+ connectionId?: import("convex/values").GenericId<"connections"> | undefined;
465
+ lastMaintenanceAt?: number | undefined;
466
+ provider: "garmin" | "suunto" | "polar" | "whoop" | "strava" | "apple" | "samsung" | "google";
467
+ userId: string;
468
+ dataSourceId: import("convex/values").GenericId<"dataSources">;
469
+ seriesType: string;
470
+ updatedAt: number;
471
+ latestRecordedAt: number;
472
+ lastIngestedAt: number;
473
+ nextMaintenanceAt: number;
474
+ }, {
475
+ dataSourceId: import("convex/values").VId<import("convex/values").GenericId<"dataSources">, "required">;
476
+ connectionId: import("convex/values").VId<import("convex/values").GenericId<"connections"> | undefined, "optional">;
477
+ userId: import("convex/values").VString<string, "required">;
478
+ provider: import("convex/values").VUnion<"garmin" | "suunto" | "polar" | "whoop" | "strava" | "apple" | "samsung" | "google", [import("convex/values").VLiteral<"garmin", "required">, import("convex/values").VLiteral<"suunto", "required">, import("convex/values").VLiteral<"polar", "required">, import("convex/values").VLiteral<"whoop", "required">, import("convex/values").VLiteral<"strava", "required">, import("convex/values").VLiteral<"apple", "required">, import("convex/values").VLiteral<"samsung", "required">, import("convex/values").VLiteral<"google", "required">], "required", never>;
479
+ seriesType: import("convex/values").VString<string, "required">;
480
+ latestRecordedAt: import("convex/values").VFloat64<number, "required">;
481
+ lastIngestedAt: import("convex/values").VFloat64<number, "required">;
482
+ nextMaintenanceAt: import("convex/values").VFloat64<number, "required">;
483
+ lastMaintenanceAt: import("convex/values").VFloat64<number | undefined, "optional">;
484
+ updatedAt: import("convex/values").VFloat64<number, "required">;
485
+ }, "required", "provider" | "userId" | "connectionId" | "dataSourceId" | "seriesType" | "updatedAt" | "latestRecordedAt" | "lastIngestedAt" | "nextMaintenanceAt" | "lastMaintenanceAt">, {
486
+ by_source_series: ["dataSourceId", "seriesType", "_creationTime"];
487
+ by_next_maintenance: ["nextMaintenanceAt", "_creationTime"];
488
+ by_user: ["userId", "_creationTime"];
489
+ }, {}, {}>;
326
490
  providerPriorities: import("convex/server").TableDefinition<import("convex/values").VObject<{
327
491
  provider: "garmin" | "suunto" | "polar" | "whoop" | "strava" | "apple" | "samsung" | "google";
328
492
  priority: number;
@@ -379,7 +543,7 @@ declare const _default: import("convex/server").SchemaDefinition<{
379
543
  pregnancyCycleStartDate: import("convex/values").VString<string | undefined, "optional">;
380
544
  pregnancyTitle: import("convex/values").VString<string | undefined, "optional">;
381
545
  numberOfBabies: import("convex/values").VString<string | undefined, "optional">;
382
- }, "required", "externalId" | "provider" | "userId" | "currentPhase" | "periodStartDate" | "dayInCycle" | "cycleLength" | "predictedCycleLength" | "periodLength" | "currentPhaseType" | "lengthOfCurrentPhase" | "daysUntilNextPhase" | "isPredictedCycle" | "fertileWindowStart" | "lengthOfFertileWindow" | "lastUpdatedAt" | "isPregnant" | "pregnancyDueDate" | "pregnancyOriginalDueDate" | "pregnancyCycleStartDate" | "pregnancyTitle" | "numberOfBabies">, {
546
+ }, "required", "provider" | "userId" | "externalId" | "currentPhase" | "periodStartDate" | "dayInCycle" | "cycleLength" | "predictedCycleLength" | "periodLength" | "currentPhaseType" | "lengthOfCurrentPhase" | "daysUntilNextPhase" | "isPredictedCycle" | "fertileWindowStart" | "lengthOfFertileWindow" | "lastUpdatedAt" | "isPregnant" | "pregnancyDueDate" | "pregnancyOriginalDueDate" | "pregnancyCycleStartDate" | "pregnancyTitle" | "numberOfBabies">, {
383
547
  by_user_date: ["userId", "periodStartDate", "_creationTime"];
384
548
  by_user_provider: ["userId", "provider", "_creationTime"];
385
549
  by_external_id: ["externalId", "_creationTime"];
@@ -395,18 +559,18 @@ declare const _default: import("convex/server").SchemaDefinition<{
395
559
  currentAttempt?: number | undefined;
396
560
  currentEventId?: string | undefined;
397
561
  completedDataTypes?: string[] | undefined;
562
+ startedAt: number;
398
563
  provider: "garmin" | "suunto" | "polar" | "whoop" | "strava" | "apple" | "samsung" | "google";
399
- status: "queued" | "running" | "completed" | "failed" | "canceled";
564
+ status: "failed" | "canceled" | "running" | "completed" | "queued";
400
565
  userId: string;
401
566
  connectionId: import("convex/values").GenericId<"connections">;
402
- startedAt: number;
403
567
  dataType: string;
404
568
  }, {
405
569
  connectionId: import("convex/values").VId<import("convex/values").GenericId<"connections">, "required">;
406
570
  userId: import("convex/values").VString<string, "required">;
407
571
  provider: import("convex/values").VUnion<"garmin" | "suunto" | "polar" | "whoop" | "strava" | "apple" | "samsung" | "google", [import("convex/values").VLiteral<"garmin", "required">, import("convex/values").VLiteral<"suunto", "required">, import("convex/values").VLiteral<"polar", "required">, import("convex/values").VLiteral<"whoop", "required">, import("convex/values").VLiteral<"strava", "required">, import("convex/values").VLiteral<"apple", "required">, import("convex/values").VLiteral<"samsung", "required">, import("convex/values").VLiteral<"google", "required">], "required", never>;
408
572
  dataType: import("convex/values").VString<string, "required">;
409
- status: import("convex/values").VUnion<"queued" | "running" | "completed" | "failed" | "canceled", [import("convex/values").VLiteral<"queued", "required">, import("convex/values").VLiteral<"running", "required">, import("convex/values").VLiteral<"completed", "required">, import("convex/values").VLiteral<"failed", "required">, import("convex/values").VLiteral<"canceled", "required">], "required", never>;
573
+ status: import("convex/values").VUnion<"failed" | "canceled" | "running" | "completed" | "queued", [import("convex/values").VLiteral<"queued", "required">, import("convex/values").VLiteral<"running", "required">, import("convex/values").VLiteral<"completed", "required">, import("convex/values").VLiteral<"failed", "required">, import("convex/values").VLiteral<"canceled", "required">], "required", never>;
410
574
  startedAt: import("convex/values").VFloat64<number, "required">;
411
575
  completedAt: import("convex/values").VFloat64<number | undefined, "optional">;
412
576
  error: import("convex/values").VString<string | undefined, "optional">;
@@ -418,7 +582,7 @@ declare const _default: import("convex/server").SchemaDefinition<{
418
582
  currentEventId: import("convex/values").VString<string | undefined, "optional">;
419
583
  completedDataTypes: import("convex/values").VArray<string[] | undefined, import("convex/values").VString<string, "required">, "optional">;
420
584
  lastHeartbeatAt: import("convex/values").VFloat64<number | undefined, "optional">;
421
- }, "required", "error" | "provider" | "status" | "userId" | "connectionId" | "startedAt" | "completedAt" | "workflowId" | "windowStart" | "windowEnd" | "lastHeartbeatAt" | "dataType" | "currentDataType" | "currentAttempt" | "currentEventId" | "completedDataTypes">, {
585
+ }, "required", "error" | "startedAt" | "completedAt" | "workflowId" | "provider" | "status" | "userId" | "connectionId" | "windowStart" | "windowEnd" | "lastHeartbeatAt" | "dataType" | "currentDataType" | "currentAttempt" | "currentEventId" | "completedDataTypes">, {
422
586
  by_connection: ["connectionId", "_creationTime"];
423
587
  by_connection_type: ["connectionId", "dataType", "_creationTime"];
424
588
  by_status: ["status", "_creationTime"];
@@ -1 +1 @@
1
- {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/component/schema.ts"],"names":[],"mappings":"AAGA;;GAEG;AACH,eAAO,MAAM,YAAY,wkBASxB,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,gBAAgB,yYAM5B,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,aAAa,0LAAoD,CAAC;AAE/E;;GAEG;AACH,eAAO,MAAM,aAAa,+YAMzB,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,cAAc,+YAM1B,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAMF,wBAuRG"}
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/component/schema.ts"],"names":[],"mappings":"AAGA;;GAEG;AACH,eAAO,MAAM,YAAY,wkBASxB,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,gBAAgB,yYAM5B,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,aAAa,0LAAoD,CAAC;AAE/E;;GAEG;AACH,eAAO,MAAM,aAAa,+YAMzB,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,cAAc,+YAM1B,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,qBAAqB,2WAMjC,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAMF,wBAsXG"}
@@ -20,6 +20,10 @@ export const syncJobStatus = v.union(v.literal("queued"), v.literal("running"),
20
20
  * Backfill job status.
21
21
  */
22
22
  export const backfillStatus = v.union(v.literal("queued"), v.literal("running"), v.literal("completed"), v.literal("failed"), v.literal("canceled"));
23
+ /**
24
+ * Supported rollup aggregations.
25
+ */
26
+ export const timeSeriesAggregation = v.union(v.literal("avg"), v.literal("min"), v.literal("max"), v.literal("last"), v.literal("count"));
23
27
  // ---------------------------------------------------------------------------
24
28
  // Schema
25
29
  // ---------------------------------------------------------------------------
@@ -72,6 +76,27 @@ export default defineSchema({
72
76
  .index("by_source_type_time", ["dataSourceId", "seriesType", "recordedAt"])
73
77
  .index("by_type_time", ["seriesType", "recordedAt"]),
74
78
  // -------------------------------------------------------------------------
79
+ // Time-Series Rollups — bucketed storage for dense historical series
80
+ // -------------------------------------------------------------------------
81
+ timeSeriesRollups: defineTable({
82
+ dataSourceId: v.id("dataSources"),
83
+ seriesType: v.string(),
84
+ bucketMs: v.number(),
85
+ bucketStart: v.number(),
86
+ bucketEnd: v.number(),
87
+ avg: v.number(),
88
+ min: v.number(),
89
+ max: v.number(),
90
+ last: v.number(),
91
+ lastRecordedAt: v.number(),
92
+ count: v.number(),
93
+ updatedAt: v.number(),
94
+ })
95
+ .index("by_source_type_bucket", ["dataSourceId", "seriesType", "bucketStart"])
96
+ .index("by_source_type_bucket_size", ["dataSourceId", "seriesType", "bucketMs", "bucketStart"])
97
+ .index("by_source_bucket", ["dataSourceId", "bucketStart"])
98
+ .index("by_type_bucket", ["seriesType", "bucketStart"]),
99
+ // -------------------------------------------------------------------------
75
100
  // Events — workouts and sleep sessions
76
101
  // -------------------------------------------------------------------------
77
102
  events: defineTable({
@@ -214,6 +239,70 @@ export default defineSchema({
214
239
  updatedAt: v.optional(v.number()),
215
240
  }).index("by_provider", ["provider"]),
216
241
  // -------------------------------------------------------------------------
242
+ // Time-Series Policy Rules — default and preset-based storage rules
243
+ // -------------------------------------------------------------------------
244
+ timeSeriesPolicyRules: defineTable({
245
+ policySetKind: v.union(v.literal("default"), v.literal("preset")),
246
+ policySetKey: v.string(), // "__default__" or host-defined preset key
247
+ scopeKey: v.string(),
248
+ provider: v.optional(providerName),
249
+ seriesType: v.optional(v.string()),
250
+ tiers: v.array(v.union(v.object({
251
+ kind: v.literal("raw"),
252
+ fromAgeMs: v.number(),
253
+ toAgeMs: v.union(v.number(), v.null()),
254
+ }), v.object({
255
+ kind: v.literal("rollup"),
256
+ fromAgeMs: v.number(),
257
+ toAgeMs: v.union(v.number(), v.null()),
258
+ bucketMs: v.number(),
259
+ aggregations: v.array(timeSeriesAggregation),
260
+ }))),
261
+ updatedAt: v.number(),
262
+ })
263
+ .index("by_set", ["policySetKind", "policySetKey"])
264
+ .index("by_set_scope", ["policySetKind", "policySetKey", "provider", "seriesType"]),
265
+ // -------------------------------------------------------------------------
266
+ // Time-Series Policy Assignments — per-user preset selection
267
+ // -------------------------------------------------------------------------
268
+ timeSeriesPolicyAssignments: defineTable({
269
+ userId: v.string(),
270
+ presetKey: v.string(),
271
+ updatedAt: v.number(),
272
+ })
273
+ .index("by_user", ["userId"])
274
+ .index("by_preset", ["presetKey"]),
275
+ // -------------------------------------------------------------------------
276
+ // Time-Series Policy Settings — singleton settings for maintenance
277
+ // -------------------------------------------------------------------------
278
+ timeSeriesPolicySettings: defineTable({
279
+ key: v.string(),
280
+ maintenanceEnabled: v.boolean(),
281
+ maintenanceIntervalMs: v.number(),
282
+ scheduledAt: v.optional(v.number()),
283
+ lastRunAt: v.optional(v.number()),
284
+ lastError: v.optional(v.string()),
285
+ updatedAt: v.number(),
286
+ }).index("by_key", ["key"]),
287
+ // -------------------------------------------------------------------------
288
+ // Time-Series Series State — per source/series maintenance cursor
289
+ // -------------------------------------------------------------------------
290
+ timeSeriesSeriesState: defineTable({
291
+ dataSourceId: v.id("dataSources"),
292
+ connectionId: v.optional(v.id("connections")),
293
+ userId: v.string(),
294
+ provider: providerName,
295
+ seriesType: v.string(),
296
+ latestRecordedAt: v.number(),
297
+ lastIngestedAt: v.number(),
298
+ nextMaintenanceAt: v.number(),
299
+ lastMaintenanceAt: v.optional(v.number()),
300
+ updatedAt: v.number(),
301
+ })
302
+ .index("by_source_series", ["dataSourceId", "seriesType"])
303
+ .index("by_next_maintenance", ["nextMaintenanceAt"])
304
+ .index("by_user", ["userId"]),
305
+ // -------------------------------------------------------------------------
217
306
  // Provider Priorities — sync order when multiple providers have same data
218
307
  // -------------------------------------------------------------------------
219
308
  providerPriorities: defineTable({