@clipin/convex-wearables 0.0.3 → 0.1.1
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/README.md +395 -0
- package/dist/client/index.d.ts +38 -2
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +34 -3
- package/dist/client/index.js.map +1 -1
- package/dist/client/types.d.ts +83 -0
- package/dist/client/types.d.ts.map +1 -1
- package/dist/client/types.js.map +1 -1
- package/dist/component/dataPoints.d.ts +148 -34
- package/dist/component/dataPoints.d.ts.map +1 -1
- package/dist/component/dataPoints.js +1048 -139
- package/dist/component/dataPoints.js.map +1 -1
- package/dist/component/lifecycle.d.ts.map +1 -1
- package/dist/component/lifecycle.js +37 -1
- package/dist/component/lifecycle.js.map +1 -1
- package/dist/component/schema.d.ts +166 -2
- package/dist/component/schema.d.ts.map +1 -1
- package/dist/component/schema.js +89 -0
- package/dist/component/schema.js.map +1 -1
- package/dist/component/timeSeriesPolicyUtils.d.ts +97 -0
- package/dist/component/timeSeriesPolicyUtils.d.ts.map +1 -0
- package/dist/component/timeSeriesPolicyUtils.js +163 -0
- package/dist/component/timeSeriesPolicyUtils.js.map +1 -0
- package/dist/test.d.ts +162 -2
- package/dist/test.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/client/index.test.ts +179 -0
- package/src/client/index.ts +87 -7
- package/src/client/types.ts +99 -0
- package/src/component/dataPoints.test.ts +546 -1
- package/src/component/dataPoints.ts +1526 -155
- package/src/component/lifecycle.ts +42 -1
- package/src/component/schema.ts +106 -0
- package/src/component/timeSeriesPolicyUtils.ts +243 -0
package/src/client/index.test.ts
CHANGED
|
@@ -3,6 +3,7 @@ import {
|
|
|
3
3
|
getSdkSyncPath,
|
|
4
4
|
getSdkSyncUrl,
|
|
5
5
|
oauthCallback,
|
|
6
|
+
registerRoutes,
|
|
6
7
|
stravaWebhookEvent,
|
|
7
8
|
stravaWebhookVerify,
|
|
8
9
|
WearablesClient,
|
|
@@ -49,4 +50,182 @@ describe("package exports", () => {
|
|
|
49
50
|
expect(typeof stravaWebhookVerify).toBe("function");
|
|
50
51
|
expect(typeof stravaWebhookEvent).toBe("function");
|
|
51
52
|
});
|
|
53
|
+
|
|
54
|
+
it("exposes time-series storage policy helpers on the client", async () => {
|
|
55
|
+
const component = {
|
|
56
|
+
dataPoints: {
|
|
57
|
+
getTimeSeriesPolicyConfiguration: "getPolicyConfiguration",
|
|
58
|
+
getUserTimeSeriesPolicyPreset: "getUserPreset",
|
|
59
|
+
getEffectiveTimeSeriesPolicy: "getEffectivePolicy",
|
|
60
|
+
replaceTimeSeriesPolicyConfiguration: "replacePolicyConfiguration",
|
|
61
|
+
setUserTimeSeriesPolicyPreset: "setUserPreset",
|
|
62
|
+
},
|
|
63
|
+
} as unknown as WearablesComponent;
|
|
64
|
+
|
|
65
|
+
const client = new WearablesClient(component, { providers: {} });
|
|
66
|
+
|
|
67
|
+
const queryCalls: Array<{ ref: unknown; args: unknown }> = [];
|
|
68
|
+
const mutationCalls: Array<{ ref: unknown; args: unknown }> = [];
|
|
69
|
+
|
|
70
|
+
const queryCtx: Parameters<WearablesClient["getTimeSeriesPolicyConfiguration"]>[0] = {
|
|
71
|
+
runQuery: async (...args: unknown[]) => {
|
|
72
|
+
const [ref, queryArgs] = args as unknown as [unknown, unknown?];
|
|
73
|
+
queryCalls.push({ ref, args: queryArgs });
|
|
74
|
+
return null as never;
|
|
75
|
+
},
|
|
76
|
+
};
|
|
77
|
+
const mutationCtx: Parameters<WearablesClient["replaceTimeSeriesPolicyConfiguration"]>[0] = {
|
|
78
|
+
runMutation: async (...args: unknown[]) => {
|
|
79
|
+
const [ref, mutationArgs] = args as unknown as [unknown, unknown?];
|
|
80
|
+
mutationCalls.push({ ref, args: mutationArgs });
|
|
81
|
+
return null as never;
|
|
82
|
+
},
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
await client.getTimeSeriesPolicyConfiguration(queryCtx);
|
|
86
|
+
await client.getUserTimeSeriesPolicyPreset(queryCtx, {
|
|
87
|
+
userId: "user-1",
|
|
88
|
+
});
|
|
89
|
+
await client.getEffectiveTimeSeriesPolicy(queryCtx, {
|
|
90
|
+
userId: "user-1",
|
|
91
|
+
provider: "garmin",
|
|
92
|
+
seriesType: "heart_rate",
|
|
93
|
+
});
|
|
94
|
+
await client.replaceTimeSeriesPolicyConfiguration(mutationCtx, {
|
|
95
|
+
defaultRules: [
|
|
96
|
+
{
|
|
97
|
+
provider: "garmin",
|
|
98
|
+
seriesType: "heart_rate",
|
|
99
|
+
tiers: [
|
|
100
|
+
{ kind: "raw", fromAge: "0m", toAge: "24h" },
|
|
101
|
+
{ kind: "rollup", fromAge: "24h", toAge: "7d", bucket: "30m" },
|
|
102
|
+
{ kind: "rollup", fromAge: "7d", toAge: null, bucket: "3h" },
|
|
103
|
+
],
|
|
104
|
+
},
|
|
105
|
+
],
|
|
106
|
+
});
|
|
107
|
+
await client.setUserTimeSeriesPolicyPreset(mutationCtx, {
|
|
108
|
+
userId: "user-1",
|
|
109
|
+
presetKey: "pro",
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
expect(queryCalls).toEqual([
|
|
113
|
+
{ ref: "getPolicyConfiguration", args: {} },
|
|
114
|
+
{ ref: "getUserPreset", args: { userId: "user-1" } },
|
|
115
|
+
{
|
|
116
|
+
ref: "getEffectivePolicy",
|
|
117
|
+
args: {
|
|
118
|
+
userId: "user-1",
|
|
119
|
+
provider: "garmin",
|
|
120
|
+
seriesType: "heart_rate",
|
|
121
|
+
},
|
|
122
|
+
},
|
|
123
|
+
]);
|
|
124
|
+
expect(mutationCalls).toEqual([
|
|
125
|
+
{
|
|
126
|
+
ref: "replacePolicyConfiguration",
|
|
127
|
+
args: {
|
|
128
|
+
defaultRules: [
|
|
129
|
+
{
|
|
130
|
+
provider: "garmin",
|
|
131
|
+
seriesType: "heart_rate",
|
|
132
|
+
tiers: [
|
|
133
|
+
{ kind: "raw", fromAge: "0m", toAge: "24h" },
|
|
134
|
+
{ kind: "rollup", fromAge: "24h", toAge: "7d", bucket: "30m" },
|
|
135
|
+
{ kind: "rollup", fromAge: "7d", toAge: null, bucket: "3h" },
|
|
136
|
+
],
|
|
137
|
+
},
|
|
138
|
+
],
|
|
139
|
+
},
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
ref: "setUserPreset",
|
|
143
|
+
args: {
|
|
144
|
+
userId: "user-1",
|
|
145
|
+
presetKey: "pro",
|
|
146
|
+
},
|
|
147
|
+
},
|
|
148
|
+
]);
|
|
149
|
+
});
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
describe("registerRoutes", () => {
|
|
153
|
+
it("schedules Garmin push ingestion and acknowledges the webhook immediately", async () => {
|
|
154
|
+
const routes: Array<{
|
|
155
|
+
handler: { _handler: (ctx: unknown, request: Request) => Promise<Response> };
|
|
156
|
+
method: string;
|
|
157
|
+
path: string;
|
|
158
|
+
}> = [];
|
|
159
|
+
const http = {
|
|
160
|
+
route: (route: (typeof routes)[number]) => {
|
|
161
|
+
routes.push(route);
|
|
162
|
+
},
|
|
163
|
+
};
|
|
164
|
+
const processPushPayload = "wearables.garminWebhooks.processPushPayload";
|
|
165
|
+
const component = {
|
|
166
|
+
garminWebhooks: {
|
|
167
|
+
processPushPayload,
|
|
168
|
+
},
|
|
169
|
+
} as unknown as WearablesComponent;
|
|
170
|
+
|
|
171
|
+
registerRoutes(http as never, component, {
|
|
172
|
+
garmin: {
|
|
173
|
+
clientId: "garmin-client-id",
|
|
174
|
+
oauthCallbackPath: false,
|
|
175
|
+
webhookPath: "/webhooks/garmin/push",
|
|
176
|
+
healthPath: false,
|
|
177
|
+
},
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
const pushRoute = routes.find(
|
|
181
|
+
(route) => route.path === "/webhooks/garmin/push" && route.method === "POST",
|
|
182
|
+
);
|
|
183
|
+
expect(pushRoute).toBeDefined();
|
|
184
|
+
|
|
185
|
+
const scheduled: Array<{ delayMs: number; functionRef: unknown; args: unknown }> = [];
|
|
186
|
+
const ctx = {
|
|
187
|
+
scheduler: {
|
|
188
|
+
runAfter: async (delayMs: number, functionRef: unknown, args: unknown) => {
|
|
189
|
+
scheduled.push({ delayMs, functionRef, args });
|
|
190
|
+
return "scheduled-garmin-push";
|
|
191
|
+
},
|
|
192
|
+
},
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
const response = await pushRoute!.handler._handler(
|
|
196
|
+
ctx,
|
|
197
|
+
new Request("https://example.com/webhooks/garmin/push", {
|
|
198
|
+
method: "POST",
|
|
199
|
+
headers: {
|
|
200
|
+
"content-type": "application/json",
|
|
201
|
+
"garmin-client-id": "garmin-client-id",
|
|
202
|
+
},
|
|
203
|
+
body: JSON.stringify({
|
|
204
|
+
dailies: [
|
|
205
|
+
{
|
|
206
|
+
userId: "garmin-user-1",
|
|
207
|
+
summaryId: "daily-1",
|
|
208
|
+
startTimeInSeconds: 1_776_988_800,
|
|
209
|
+
durationInSeconds: 86_400,
|
|
210
|
+
steps: 12_345,
|
|
211
|
+
},
|
|
212
|
+
],
|
|
213
|
+
}),
|
|
214
|
+
}),
|
|
215
|
+
);
|
|
216
|
+
|
|
217
|
+
expect(response.status).toBe(200);
|
|
218
|
+
expect(await response.text()).toBe("OK");
|
|
219
|
+
expect(scheduled).toHaveLength(1);
|
|
220
|
+
expect(scheduled[0]).toMatchObject({
|
|
221
|
+
delayMs: 0,
|
|
222
|
+
functionRef: processPushPayload,
|
|
223
|
+
});
|
|
224
|
+
expect(scheduled[0]?.args).toMatchObject({
|
|
225
|
+
garminClientId: "garmin-client-id",
|
|
226
|
+
});
|
|
227
|
+
expect(JSON.parse((scheduled[0]?.args as { payloadJson: string }).payloadJson)).toMatchObject({
|
|
228
|
+
dailies: [{ summaryId: "daily-1" }],
|
|
229
|
+
});
|
|
230
|
+
});
|
|
52
231
|
});
|
package/src/client/index.ts
CHANGED
|
@@ -21,6 +21,7 @@ import type {
|
|
|
21
21
|
Connection,
|
|
22
22
|
DailySummary,
|
|
23
23
|
DataPoint,
|
|
24
|
+
EffectiveTimeSeriesPolicy,
|
|
24
25
|
EventCategory,
|
|
25
26
|
EventsPage,
|
|
26
27
|
GarminRoutesConfig,
|
|
@@ -36,7 +37,12 @@ import type {
|
|
|
36
37
|
SdkSyncPayload,
|
|
37
38
|
SyncJob,
|
|
38
39
|
SyncStatus,
|
|
40
|
+
TimeSeriesMaintenanceInput,
|
|
39
41
|
TimeSeriesPage,
|
|
42
|
+
TimeSeriesPolicyConfiguration,
|
|
43
|
+
TimeSeriesPolicyPresetInput,
|
|
44
|
+
TimeSeriesPolicyRuleInput,
|
|
45
|
+
UserTimeSeriesPolicyPreset,
|
|
40
46
|
WearablesConfig,
|
|
41
47
|
} from "./types.js";
|
|
42
48
|
|
|
@@ -54,6 +60,7 @@ export type {
|
|
|
54
60
|
Connection,
|
|
55
61
|
DailySummary,
|
|
56
62
|
DataPoint,
|
|
63
|
+
EffectiveTimeSeriesPolicy,
|
|
57
64
|
EventCategory,
|
|
58
65
|
EventsPage,
|
|
59
66
|
GarminRoutesConfig,
|
|
@@ -69,7 +76,12 @@ export type {
|
|
|
69
76
|
SdkSyncPayload,
|
|
70
77
|
SyncJob,
|
|
71
78
|
SyncStatus,
|
|
79
|
+
TimeSeriesMaintenanceInput,
|
|
72
80
|
TimeSeriesPage,
|
|
81
|
+
TimeSeriesPolicyConfiguration,
|
|
82
|
+
TimeSeriesPolicyPresetInput,
|
|
83
|
+
TimeSeriesPolicyRuleInput,
|
|
84
|
+
UserTimeSeriesPolicyPreset,
|
|
73
85
|
WearablesConfig,
|
|
74
86
|
};
|
|
75
87
|
|
|
@@ -234,6 +246,69 @@ export class WearablesClient {
|
|
|
234
246
|
return await ctx.runQuery(this.component.dataPoints.getAvailableSeriesTypes, args);
|
|
235
247
|
}
|
|
236
248
|
|
|
249
|
+
/**
|
|
250
|
+
* Get persisted time-series policy configuration.
|
|
251
|
+
*/
|
|
252
|
+
async getTimeSeriesPolicyConfiguration(ctx: QueryRunner): Promise<TimeSeriesPolicyConfiguration> {
|
|
253
|
+
return (await ctx.runQuery(
|
|
254
|
+
this.component.dataPoints.getTimeSeriesPolicyConfiguration,
|
|
255
|
+
{},
|
|
256
|
+
)) as TimeSeriesPolicyConfiguration;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Get the preset assigned to a user, if any.
|
|
261
|
+
*/
|
|
262
|
+
async getUserTimeSeriesPolicyPreset(
|
|
263
|
+
ctx: QueryRunner,
|
|
264
|
+
args: { userId: string },
|
|
265
|
+
): Promise<UserTimeSeriesPolicyPreset | null> {
|
|
266
|
+
return (await ctx.runQuery(
|
|
267
|
+
this.component.dataPoints.getUserTimeSeriesPolicyPreset,
|
|
268
|
+
args,
|
|
269
|
+
)) as UserTimeSeriesPolicyPreset | null;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* Resolve the effective time-series policy for a user/provider/series triple.
|
|
274
|
+
*/
|
|
275
|
+
async getEffectiveTimeSeriesPolicy(
|
|
276
|
+
ctx: QueryRunner,
|
|
277
|
+
args: { userId: string; provider: ProviderName; seriesType: string },
|
|
278
|
+
): Promise<EffectiveTimeSeriesPolicy> {
|
|
279
|
+
return (await ctx.runQuery(
|
|
280
|
+
this.component.dataPoints.getEffectiveTimeSeriesPolicy,
|
|
281
|
+
args,
|
|
282
|
+
)) as EffectiveTimeSeriesPolicy;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* Replace the persisted time-series policy configuration.
|
|
287
|
+
*/
|
|
288
|
+
async replaceTimeSeriesPolicyConfiguration(
|
|
289
|
+
ctx: MutationRunner,
|
|
290
|
+
args: {
|
|
291
|
+
defaultRules: TimeSeriesPolicyRuleInput[];
|
|
292
|
+
presets?: TimeSeriesPolicyPresetInput[];
|
|
293
|
+
maintenance?: TimeSeriesMaintenanceInput;
|
|
294
|
+
},
|
|
295
|
+
): Promise<{ defaultRulesStored: number; presetsStored: number }> {
|
|
296
|
+
return await ctx.runMutation(
|
|
297
|
+
this.component.dataPoints.replaceTimeSeriesPolicyConfiguration,
|
|
298
|
+
args,
|
|
299
|
+
);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* Assign or clear a user-specific policy preset.
|
|
304
|
+
*/
|
|
305
|
+
async setUserTimeSeriesPolicyPreset(
|
|
306
|
+
ctx: MutationRunner,
|
|
307
|
+
args: { userId: string; presetKey: string | null },
|
|
308
|
+
): Promise<null> {
|
|
309
|
+
return await ctx.runMutation(this.component.dataPoints.setUserTimeSeriesPolicyPreset, args);
|
|
310
|
+
}
|
|
311
|
+
|
|
237
312
|
// -----------------------------------------------------------------------
|
|
238
313
|
// Data Access — Summaries
|
|
239
314
|
// -----------------------------------------------------------------------
|
|
@@ -506,13 +581,18 @@ export function registerRoutes(
|
|
|
506
581
|
});
|
|
507
582
|
|
|
508
583
|
try {
|
|
509
|
-
await ctx.
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
584
|
+
const scheduledFunctionId = await ctx.scheduler.runAfter(
|
|
585
|
+
0,
|
|
586
|
+
component.garminWebhooks.processPushPayload,
|
|
587
|
+
{
|
|
588
|
+
payloadJson: JSON.stringify(payload),
|
|
589
|
+
garminClientId: garminClientId ?? "",
|
|
590
|
+
},
|
|
591
|
+
);
|
|
592
|
+
|
|
593
|
+
console.info("Garmin webhook ingestion scheduled", {
|
|
515
594
|
componentFunction: GARMIN_PUSH_COMPONENT_FUNCTION,
|
|
595
|
+
scheduledFunctionId,
|
|
516
596
|
payloadSummary,
|
|
517
597
|
});
|
|
518
598
|
|
|
@@ -523,7 +603,7 @@ export function registerRoutes(
|
|
|
523
603
|
serializedError.message.includes("Couldn't resolve") &&
|
|
524
604
|
serializedError.message.includes(GARMIN_PUSH_COMPONENT_FUNCTION);
|
|
525
605
|
|
|
526
|
-
console.error("Garmin webhook
|
|
606
|
+
console.error("Garmin webhook scheduling failed", {
|
|
527
607
|
componentFunction: GARMIN_PUSH_COMPONENT_FUNCTION,
|
|
528
608
|
payloadSummary,
|
|
529
609
|
error: serializedError,
|
package/src/client/types.ts
CHANGED
|
@@ -26,6 +26,10 @@ export type SyncJobStatus = "queued" | "running" | "completed" | "failed" | "can
|
|
|
26
26
|
|
|
27
27
|
export type BackfillJobStatus = "queued" | "running" | "completed" | "failed" | "canceled";
|
|
28
28
|
|
|
29
|
+
export type DurationInput = string | number;
|
|
30
|
+
|
|
31
|
+
export type TimeSeriesRollupAggregation = "avg" | "min" | "max" | "last" | "count";
|
|
32
|
+
|
|
29
33
|
// ---------------------------------------------------------------------------
|
|
30
34
|
// Provider configuration (passed by app)
|
|
31
35
|
// ---------------------------------------------------------------------------
|
|
@@ -287,6 +291,13 @@ export type HealthEvent = WorkoutEvent | SleepEvent;
|
|
|
287
291
|
export interface DataPoint {
|
|
288
292
|
timestamp: number;
|
|
289
293
|
value: number;
|
|
294
|
+
resolution?: "raw" | "rollup";
|
|
295
|
+
bucketMinutes?: number;
|
|
296
|
+
avg?: number;
|
|
297
|
+
min?: number;
|
|
298
|
+
max?: number;
|
|
299
|
+
last?: number;
|
|
300
|
+
count?: number;
|
|
290
301
|
}
|
|
291
302
|
|
|
292
303
|
export interface TimeSeriesPage {
|
|
@@ -295,6 +306,94 @@ export interface TimeSeriesPage {
|
|
|
295
306
|
hasMore: boolean;
|
|
296
307
|
}
|
|
297
308
|
|
|
309
|
+
export interface TimeSeriesRawTierInput {
|
|
310
|
+
kind: "raw";
|
|
311
|
+
fromAge: DurationInput;
|
|
312
|
+
toAge: DurationInput | null;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
export interface TimeSeriesRollupTierInput {
|
|
316
|
+
kind: "rollup";
|
|
317
|
+
fromAge: DurationInput;
|
|
318
|
+
toAge: DurationInput | null;
|
|
319
|
+
bucket: DurationInput;
|
|
320
|
+
aggregations?: TimeSeriesRollupAggregation[];
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
export type TimeSeriesTierInput = TimeSeriesRawTierInput | TimeSeriesRollupTierInput;
|
|
324
|
+
|
|
325
|
+
export interface TimeSeriesPolicyRuleInput {
|
|
326
|
+
provider?: ProviderName;
|
|
327
|
+
seriesType?: string;
|
|
328
|
+
tiers: TimeSeriesTierInput[];
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
export interface TimeSeriesPolicyPresetInput {
|
|
332
|
+
key: string;
|
|
333
|
+
rules: TimeSeriesPolicyRuleInput[];
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
export interface TimeSeriesMaintenanceInput {
|
|
337
|
+
enabled?: boolean;
|
|
338
|
+
interval?: DurationInput;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
export interface TimeSeriesRawTier {
|
|
342
|
+
kind: "raw";
|
|
343
|
+
fromAgeMs: number;
|
|
344
|
+
toAgeMs: number | null;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
export interface TimeSeriesRollupTier {
|
|
348
|
+
kind: "rollup";
|
|
349
|
+
fromAgeMs: number;
|
|
350
|
+
toAgeMs: number | null;
|
|
351
|
+
bucketMs: number;
|
|
352
|
+
aggregations: TimeSeriesRollupAggregation[];
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
export type TimeSeriesTier = TimeSeriesRawTier | TimeSeriesRollupTier;
|
|
356
|
+
|
|
357
|
+
export interface TimeSeriesPolicyRule {
|
|
358
|
+
_id: string;
|
|
359
|
+
policySetKind: "default" | "preset";
|
|
360
|
+
policySetKey: string;
|
|
361
|
+
updatedAt: number;
|
|
362
|
+
scope: "global" | "provider" | "series" | "provider_series";
|
|
363
|
+
provider?: ProviderName;
|
|
364
|
+
seriesType?: string;
|
|
365
|
+
tiers: TimeSeriesTier[];
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
export interface TimeSeriesPolicyPreset {
|
|
369
|
+
key: string;
|
|
370
|
+
rules: TimeSeriesPolicyRule[];
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
export interface TimeSeriesPolicyConfiguration {
|
|
374
|
+
maintenance: {
|
|
375
|
+
enabled: boolean;
|
|
376
|
+
intervalMs: number;
|
|
377
|
+
};
|
|
378
|
+
defaultRules: TimeSeriesPolicyRule[];
|
|
379
|
+
presets: TimeSeriesPolicyPreset[];
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
export interface UserTimeSeriesPolicyPreset {
|
|
383
|
+
userId: string;
|
|
384
|
+
presetKey: string;
|
|
385
|
+
updatedAt: number;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
export interface EffectiveTimeSeriesPolicy {
|
|
389
|
+
provider: ProviderName;
|
|
390
|
+
seriesType: string;
|
|
391
|
+
sourceKind: "preset" | "default" | "builtin";
|
|
392
|
+
sourceKey: string | null;
|
|
393
|
+
matchedScope: "default" | "global" | "provider" | "series" | "provider_series";
|
|
394
|
+
tiers: TimeSeriesTier[];
|
|
395
|
+
}
|
|
396
|
+
|
|
298
397
|
// ---------------------------------------------------------------------------
|
|
299
398
|
// Events page
|
|
300
399
|
// ---------------------------------------------------------------------------
|