@gdrl/kronos-lib 0.1.3 → 0.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -1,5 +1,5 @@
1
- import { K as KronosClientConfig, I as IngestResponse, a as IngestStatusResponse, C as CreateMCPServerResponse, L as ListMCPServersResponse, G as GetMCPServerResponse, b as ConnectMCPServerResponse, R as RotateMCPServerTokenResponse, M as MemoryStatsResponse, c as CostSummaryResponse, S as ScratchsheetResponse, d as ListScopesResponse, e as GetScopeResponse, f as ScopeSpec, g as CreateScopeResponse, U as UpdateScopeResponse, h as ListTriggersResponse, i as CreateTriggerRequest, j as CreateTriggerResponse, T as TriggerRecord, k as UpdateTriggerRequest, l as UpdateTriggerResponse, D as DeleteTriggerResponse, m as CreateFrontendTokenResponse, n as SkillManageParams, o as SkillManageResponse, p as ContextGraphSummaryResponse, q as ContextGraphReadResponse } from './types-CPHJocLg.mjs';
2
- export { y as ConnectMCPServerRequest, Z as ContextGraphProcedureSummary, H as CreateFrontendTokenRequest, u as CreateMCPServerRequest, E as CreateScopeRequest, s as IngestMemoryDisposition, t as IngestRequest, r as IngestStatus, x as MCPServerDetails, v as MCPServerStatus, w as MCPServerToolCapabilities, O as OnTriggered, z as RotateMCPServerTokenRequest, B as ScopeDetail, A as ScopeSummary, P as SkillFileContentMode, Q as SkillFileInput, V as SkillFileRecord, J as SkillFileType, X as SkillMetadataRecord, N as SkillReadMode, Y as SkillSummaryRecord, W as SkillTreeNode, F as TriggerType } from './types-CPHJocLg.mjs';
1
+ import { K as KronosClientConfig, I as IngestResponse, a as IngestStatusResponse, C as CreateMCPServerResponse, L as ListMCPServersResponse, G as GetMCPServerResponse, b as ConnectMCPServerResponse, R as RotateMCPServerTokenResponse, M as MemoryStatsResponse, c as CostSummaryResponse, d as CostBreakdownResponse, e as GetBillingUsageWebhookResponse, f as ConfigureBillingUsageWebhookResponse, D as DeleteBillingUsageWebhookResponse, S as ScratchsheetResponse, g as ListScopesResponse, h as GetScopeResponse, i as ScopeSpec, j as CreateScopeResponse, U as UpdateScopeResponse, k as ListTriggersResponse, l as CreateTriggerRequest, m as CreateTriggerResponse, T as TriggerRecord, n as UpdateTriggerRequest, o as UpdateTriggerResponse, p as DeleteTriggerResponse, q as CreateFrontendTokenResponse, r as SkillManageParams, s as SkillManageResponse, t as ContextGraphSummaryResponse, u as ContextGraphReadResponse, B as BillingUsageWebhookEvent } from './types-CTMNKYHj.mjs';
2
+ export { N as BillingUsageWebhookEventData, O as ConfigureBillingUsageWebhookRequest, F as ConnectMCPServerRequest, a5 as ContextGraphProcedureSummary, J as CostBreakdownPoint, Y as CreateFrontendTokenRequest, y as CreateMCPServerRequest, V as CreateScopeRequest, w as IngestMemoryDisposition, x as IngestRequest, v as IngestStatus, E as MCPServerDetails, z as MCPServerStatus, A as MCPServerToolCapabilities, X as OnTriggered, H as RotateMCPServerTokenRequest, Q as ScopeDetail, P as ScopeSummary, $ as SkillFileContentMode, a0 as SkillFileInput, a1 as SkillFileRecord, Z as SkillFileType, a3 as SkillMetadataRecord, _ as SkillReadMode, a4 as SkillSummaryRecord, a2 as SkillTreeNode, W as TriggerType } from './types-CTMNKYHj.mjs';
3
3
 
4
4
  declare class KronosClient {
5
5
  private readonly workerUrl;
@@ -102,6 +102,45 @@ declare class KronosClient {
102
102
  getCostSummary(params?: {
103
103
  tenant_user_id?: string;
104
104
  }): Promise<CostSummaryResponse>;
105
+ /**
106
+ * Get daily AI stage cost totals for the app, or for a single user if specified.
107
+ */
108
+ getCostBreakdown(params?: {
109
+ tenant_user_id?: string;
110
+ days?: number;
111
+ }): Promise<CostBreakdownResponse>;
112
+ /**
113
+ * Get the app-level billing usage webhook configuration.
114
+ */
115
+ getBillingUsageWebhook(): Promise<GetBillingUsageWebhookResponse>;
116
+ /**
117
+ * Configure the app-level billing usage webhook.
118
+ */
119
+ configureBillingUsageWebhook(params: {
120
+ webhook_url: string;
121
+ webhook_secret: string;
122
+ event_types?: Array<'billing.usage.updated'>;
123
+ status?: 'active' | 'disabled';
124
+ }): Promise<ConfigureBillingUsageWebhookResponse>;
125
+ /**
126
+ * Delete the app-level billing usage webhook configuration.
127
+ */
128
+ deleteBillingUsageWebhook(): Promise<DeleteBillingUsageWebhookResponse>;
129
+ /**
130
+ * Verify an incoming billing usage webhook against the stored app webhook secret.
131
+ */
132
+ verifyBillingUsageWebhook(params: {
133
+ payload: string;
134
+ signature: string;
135
+ timestamp: string;
136
+ }): Promise<boolean>;
137
+ /**
138
+ * Verify an incoming Kronos webhook request and optionally validate its payload shape.
139
+ */
140
+ verifyWebhook<T = unknown>(request: Request, options?: {
141
+ expectedEventType?: string;
142
+ validate?: (payload: unknown) => payload is T;
143
+ }): Promise<T>;
105
144
  /**
106
145
  * Read the current scratchsheet document for a user.
107
146
  */
@@ -276,6 +315,29 @@ declare function generateIdempotencyKey(): string;
276
315
  * Webhook verification utilities for Kronos triggers
277
316
  * Provides secure constant-time comparison for webhook secrets
278
317
  */
318
+ declare const KRONOS_WEBHOOK_SIGNATURE_HEADER = "x-kronos-signature";
319
+ declare const KRONOS_WEBHOOK_TIMESTAMP_HEADER = "x-kronos-timestamp";
320
+ declare const KRONOS_WEBHOOK_EVENT_ID_HEADER = "x-kronos-event-id";
321
+ declare const KRONOS_WEBHOOK_EVENT_TYPE_HEADER = "x-kronos-event-type";
322
+ declare const BILLING_USAGE_UPDATED_EVENT = "billing.usage.updated";
323
+ declare class KronosWebhookError extends Error {
324
+ status: number;
325
+ constructor(message: string, status?: number);
326
+ }
327
+ declare function buildKronosWebhookSignatureInput(timestamp: string, payload: string): string;
328
+ declare function signKronosWebhookPayload(params: {
329
+ payload: string;
330
+ secret: string;
331
+ timestamp: string;
332
+ }): Promise<string>;
333
+ declare function verifyKronosWebhookSignature(params: {
334
+ payload: string;
335
+ secret: string;
336
+ timestamp: string | null | undefined;
337
+ signature: string | null | undefined;
338
+ toleranceSeconds?: number;
339
+ now?: number;
340
+ }): Promise<boolean>;
279
341
  /**
280
342
  * Verify a webhook secret using constant-time comparison to prevent timing attacks.
281
343
  *
@@ -298,6 +360,7 @@ declare function generateIdempotencyKey(): string;
298
360
  * ```
299
361
  */
300
362
  declare function verifyWebhookSecret(receivedSecret: string | null | undefined, storedSecret: string | null | undefined): boolean;
363
+ declare function isBillingUsageWebhookEvent(value: unknown): value is BillingUsageWebhookEvent;
301
364
 
302
365
  /**
303
366
  * Base error for Kronos API failures
@@ -339,4 +402,4 @@ declare class KronosServerError extends KronosError {
339
402
  constructor(message: string, status?: number, body?: unknown);
340
403
  }
341
404
 
342
- export { ConnectMCPServerResponse, ContextGraphReadResponse, ContextGraphSummaryResponse, CostSummaryResponse, CreateFrontendTokenResponse, CreateMCPServerResponse, CreateScopeResponse, CreateTriggerRequest, CreateTriggerResponse, DeleteTriggerResponse, GetMCPServerResponse, GetScopeResponse, IngestResponse, IngestStatusResponse, KronosBadRequestError, KronosClient, KronosClientConfig, KronosError, KronosForbiddenError, KronosNotFoundError, KronosServerError, KronosUnauthorizedError, ListMCPServersResponse, ListScopesResponse, ListTriggersResponse, MemoryStatsResponse, RotateMCPServerTokenResponse, ScopeSpec, ScratchsheetResponse, SkillManageParams, SkillManageResponse, TriggerRecord, UpdateTriggerRequest, UpdateTriggerResponse, generateIdempotencyKey, verifyWebhookSecret };
405
+ export { BILLING_USAGE_UPDATED_EVENT, BillingUsageWebhookEvent, ConfigureBillingUsageWebhookResponse, ConnectMCPServerResponse, ContextGraphReadResponse, ContextGraphSummaryResponse, CostBreakdownResponse, CostSummaryResponse, CreateFrontendTokenResponse, CreateMCPServerResponse, CreateScopeResponse, CreateTriggerRequest, CreateTriggerResponse, DeleteBillingUsageWebhookResponse, DeleteTriggerResponse, GetBillingUsageWebhookResponse, GetMCPServerResponse, GetScopeResponse, IngestResponse, IngestStatusResponse, KRONOS_WEBHOOK_EVENT_ID_HEADER, KRONOS_WEBHOOK_EVENT_TYPE_HEADER, KRONOS_WEBHOOK_SIGNATURE_HEADER, KRONOS_WEBHOOK_TIMESTAMP_HEADER, KronosBadRequestError, KronosClient, KronosClientConfig, KronosError, KronosForbiddenError, KronosNotFoundError, KronosServerError, KronosUnauthorizedError, KronosWebhookError, ListMCPServersResponse, ListScopesResponse, ListTriggersResponse, MemoryStatsResponse, RotateMCPServerTokenResponse, ScopeSpec, ScratchsheetResponse, SkillManageParams, SkillManageResponse, TriggerRecord, UpdateTriggerRequest, UpdateTriggerResponse, buildKronosWebhookSignatureInput, generateIdempotencyKey, isBillingUsageWebhookEvent, signKronosWebhookPayload, verifyKronosWebhookSignature, verifyWebhookSecret };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { K as KronosClientConfig, I as IngestResponse, a as IngestStatusResponse, C as CreateMCPServerResponse, L as ListMCPServersResponse, G as GetMCPServerResponse, b as ConnectMCPServerResponse, R as RotateMCPServerTokenResponse, M as MemoryStatsResponse, c as CostSummaryResponse, S as ScratchsheetResponse, d as ListScopesResponse, e as GetScopeResponse, f as ScopeSpec, g as CreateScopeResponse, U as UpdateScopeResponse, h as ListTriggersResponse, i as CreateTriggerRequest, j as CreateTriggerResponse, T as TriggerRecord, k as UpdateTriggerRequest, l as UpdateTriggerResponse, D as DeleteTriggerResponse, m as CreateFrontendTokenResponse, n as SkillManageParams, o as SkillManageResponse, p as ContextGraphSummaryResponse, q as ContextGraphReadResponse } from './types-CPHJocLg.js';
2
- export { y as ConnectMCPServerRequest, Z as ContextGraphProcedureSummary, H as CreateFrontendTokenRequest, u as CreateMCPServerRequest, E as CreateScopeRequest, s as IngestMemoryDisposition, t as IngestRequest, r as IngestStatus, x as MCPServerDetails, v as MCPServerStatus, w as MCPServerToolCapabilities, O as OnTriggered, z as RotateMCPServerTokenRequest, B as ScopeDetail, A as ScopeSummary, P as SkillFileContentMode, Q as SkillFileInput, V as SkillFileRecord, J as SkillFileType, X as SkillMetadataRecord, N as SkillReadMode, Y as SkillSummaryRecord, W as SkillTreeNode, F as TriggerType } from './types-CPHJocLg.js';
1
+ import { K as KronosClientConfig, I as IngestResponse, a as IngestStatusResponse, C as CreateMCPServerResponse, L as ListMCPServersResponse, G as GetMCPServerResponse, b as ConnectMCPServerResponse, R as RotateMCPServerTokenResponse, M as MemoryStatsResponse, c as CostSummaryResponse, d as CostBreakdownResponse, e as GetBillingUsageWebhookResponse, f as ConfigureBillingUsageWebhookResponse, D as DeleteBillingUsageWebhookResponse, S as ScratchsheetResponse, g as ListScopesResponse, h as GetScopeResponse, i as ScopeSpec, j as CreateScopeResponse, U as UpdateScopeResponse, k as ListTriggersResponse, l as CreateTriggerRequest, m as CreateTriggerResponse, T as TriggerRecord, n as UpdateTriggerRequest, o as UpdateTriggerResponse, p as DeleteTriggerResponse, q as CreateFrontendTokenResponse, r as SkillManageParams, s as SkillManageResponse, t as ContextGraphSummaryResponse, u as ContextGraphReadResponse, B as BillingUsageWebhookEvent } from './types-CTMNKYHj.js';
2
+ export { N as BillingUsageWebhookEventData, O as ConfigureBillingUsageWebhookRequest, F as ConnectMCPServerRequest, a5 as ContextGraphProcedureSummary, J as CostBreakdownPoint, Y as CreateFrontendTokenRequest, y as CreateMCPServerRequest, V as CreateScopeRequest, w as IngestMemoryDisposition, x as IngestRequest, v as IngestStatus, E as MCPServerDetails, z as MCPServerStatus, A as MCPServerToolCapabilities, X as OnTriggered, H as RotateMCPServerTokenRequest, Q as ScopeDetail, P as ScopeSummary, $ as SkillFileContentMode, a0 as SkillFileInput, a1 as SkillFileRecord, Z as SkillFileType, a3 as SkillMetadataRecord, _ as SkillReadMode, a4 as SkillSummaryRecord, a2 as SkillTreeNode, W as TriggerType } from './types-CTMNKYHj.js';
3
3
 
4
4
  declare class KronosClient {
5
5
  private readonly workerUrl;
@@ -102,6 +102,45 @@ declare class KronosClient {
102
102
  getCostSummary(params?: {
103
103
  tenant_user_id?: string;
104
104
  }): Promise<CostSummaryResponse>;
105
+ /**
106
+ * Get daily AI stage cost totals for the app, or for a single user if specified.
107
+ */
108
+ getCostBreakdown(params?: {
109
+ tenant_user_id?: string;
110
+ days?: number;
111
+ }): Promise<CostBreakdownResponse>;
112
+ /**
113
+ * Get the app-level billing usage webhook configuration.
114
+ */
115
+ getBillingUsageWebhook(): Promise<GetBillingUsageWebhookResponse>;
116
+ /**
117
+ * Configure the app-level billing usage webhook.
118
+ */
119
+ configureBillingUsageWebhook(params: {
120
+ webhook_url: string;
121
+ webhook_secret: string;
122
+ event_types?: Array<'billing.usage.updated'>;
123
+ status?: 'active' | 'disabled';
124
+ }): Promise<ConfigureBillingUsageWebhookResponse>;
125
+ /**
126
+ * Delete the app-level billing usage webhook configuration.
127
+ */
128
+ deleteBillingUsageWebhook(): Promise<DeleteBillingUsageWebhookResponse>;
129
+ /**
130
+ * Verify an incoming billing usage webhook against the stored app webhook secret.
131
+ */
132
+ verifyBillingUsageWebhook(params: {
133
+ payload: string;
134
+ signature: string;
135
+ timestamp: string;
136
+ }): Promise<boolean>;
137
+ /**
138
+ * Verify an incoming Kronos webhook request and optionally validate its payload shape.
139
+ */
140
+ verifyWebhook<T = unknown>(request: Request, options?: {
141
+ expectedEventType?: string;
142
+ validate?: (payload: unknown) => payload is T;
143
+ }): Promise<T>;
105
144
  /**
106
145
  * Read the current scratchsheet document for a user.
107
146
  */
@@ -276,6 +315,29 @@ declare function generateIdempotencyKey(): string;
276
315
  * Webhook verification utilities for Kronos triggers
277
316
  * Provides secure constant-time comparison for webhook secrets
278
317
  */
318
+ declare const KRONOS_WEBHOOK_SIGNATURE_HEADER = "x-kronos-signature";
319
+ declare const KRONOS_WEBHOOK_TIMESTAMP_HEADER = "x-kronos-timestamp";
320
+ declare const KRONOS_WEBHOOK_EVENT_ID_HEADER = "x-kronos-event-id";
321
+ declare const KRONOS_WEBHOOK_EVENT_TYPE_HEADER = "x-kronos-event-type";
322
+ declare const BILLING_USAGE_UPDATED_EVENT = "billing.usage.updated";
323
+ declare class KronosWebhookError extends Error {
324
+ status: number;
325
+ constructor(message: string, status?: number);
326
+ }
327
+ declare function buildKronosWebhookSignatureInput(timestamp: string, payload: string): string;
328
+ declare function signKronosWebhookPayload(params: {
329
+ payload: string;
330
+ secret: string;
331
+ timestamp: string;
332
+ }): Promise<string>;
333
+ declare function verifyKronosWebhookSignature(params: {
334
+ payload: string;
335
+ secret: string;
336
+ timestamp: string | null | undefined;
337
+ signature: string | null | undefined;
338
+ toleranceSeconds?: number;
339
+ now?: number;
340
+ }): Promise<boolean>;
279
341
  /**
280
342
  * Verify a webhook secret using constant-time comparison to prevent timing attacks.
281
343
  *
@@ -298,6 +360,7 @@ declare function generateIdempotencyKey(): string;
298
360
  * ```
299
361
  */
300
362
  declare function verifyWebhookSecret(receivedSecret: string | null | undefined, storedSecret: string | null | undefined): boolean;
363
+ declare function isBillingUsageWebhookEvent(value: unknown): value is BillingUsageWebhookEvent;
301
364
 
302
365
  /**
303
366
  * Base error for Kronos API failures
@@ -339,4 +402,4 @@ declare class KronosServerError extends KronosError {
339
402
  constructor(message: string, status?: number, body?: unknown);
340
403
  }
341
404
 
342
- export { ConnectMCPServerResponse, ContextGraphReadResponse, ContextGraphSummaryResponse, CostSummaryResponse, CreateFrontendTokenResponse, CreateMCPServerResponse, CreateScopeResponse, CreateTriggerRequest, CreateTriggerResponse, DeleteTriggerResponse, GetMCPServerResponse, GetScopeResponse, IngestResponse, IngestStatusResponse, KronosBadRequestError, KronosClient, KronosClientConfig, KronosError, KronosForbiddenError, KronosNotFoundError, KronosServerError, KronosUnauthorizedError, ListMCPServersResponse, ListScopesResponse, ListTriggersResponse, MemoryStatsResponse, RotateMCPServerTokenResponse, ScopeSpec, ScratchsheetResponse, SkillManageParams, SkillManageResponse, TriggerRecord, UpdateTriggerRequest, UpdateTriggerResponse, generateIdempotencyKey, verifyWebhookSecret };
405
+ export { BILLING_USAGE_UPDATED_EVENT, BillingUsageWebhookEvent, ConfigureBillingUsageWebhookResponse, ConnectMCPServerResponse, ContextGraphReadResponse, ContextGraphSummaryResponse, CostBreakdownResponse, CostSummaryResponse, CreateFrontendTokenResponse, CreateMCPServerResponse, CreateScopeResponse, CreateTriggerRequest, CreateTriggerResponse, DeleteBillingUsageWebhookResponse, DeleteTriggerResponse, GetBillingUsageWebhookResponse, GetMCPServerResponse, GetScopeResponse, IngestResponse, IngestStatusResponse, KRONOS_WEBHOOK_EVENT_ID_HEADER, KRONOS_WEBHOOK_EVENT_TYPE_HEADER, KRONOS_WEBHOOK_SIGNATURE_HEADER, KRONOS_WEBHOOK_TIMESTAMP_HEADER, KronosBadRequestError, KronosClient, KronosClientConfig, KronosError, KronosForbiddenError, KronosNotFoundError, KronosServerError, KronosUnauthorizedError, KronosWebhookError, ListMCPServersResponse, ListScopesResponse, ListTriggersResponse, MemoryStatsResponse, RotateMCPServerTokenResponse, ScopeSpec, ScratchsheetResponse, SkillManageParams, SkillManageResponse, TriggerRecord, UpdateTriggerRequest, UpdateTriggerResponse, buildKronosWebhookSignatureInput, generateIdempotencyKey, isBillingUsageWebhookEvent, signKronosWebhookPayload, verifyKronosWebhookSignature, verifyWebhookSecret };
package/dist/index.js CHANGED
@@ -20,6 +20,11 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/index.ts
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
+ BILLING_USAGE_UPDATED_EVENT: () => BILLING_USAGE_UPDATED_EVENT,
24
+ KRONOS_WEBHOOK_EVENT_ID_HEADER: () => KRONOS_WEBHOOK_EVENT_ID_HEADER,
25
+ KRONOS_WEBHOOK_EVENT_TYPE_HEADER: () => KRONOS_WEBHOOK_EVENT_TYPE_HEADER,
26
+ KRONOS_WEBHOOK_SIGNATURE_HEADER: () => KRONOS_WEBHOOK_SIGNATURE_HEADER,
27
+ KRONOS_WEBHOOK_TIMESTAMP_HEADER: () => KRONOS_WEBHOOK_TIMESTAMP_HEADER,
23
28
  KronosBadRequestError: () => KronosBadRequestError,
24
29
  KronosClient: () => KronosClient,
25
30
  KronosError: () => KronosError,
@@ -27,7 +32,12 @@ __export(index_exports, {
27
32
  KronosNotFoundError: () => KronosNotFoundError,
28
33
  KronosServerError: () => KronosServerError,
29
34
  KronosUnauthorizedError: () => KronosUnauthorizedError,
35
+ KronosWebhookError: () => KronosWebhookError,
36
+ buildKronosWebhookSignatureInput: () => buildKronosWebhookSignatureInput,
30
37
  generateIdempotencyKey: () => generateIdempotencyKey,
38
+ isBillingUsageWebhookEvent: () => isBillingUsageWebhookEvent,
39
+ signKronosWebhookPayload: () => signKronosWebhookPayload,
40
+ verifyKronosWebhookSignature: () => verifyKronosWebhookSignature,
31
41
  verifyWebhookSecret: () => verifyWebhookSecret
32
42
  });
33
43
  module.exports = __toCommonJS(index_exports);
@@ -87,6 +97,84 @@ function generateIdempotencyKey() {
87
97
  return `idem_${Date.now()}_${Math.random().toString(36).slice(2, 11)}`;
88
98
  }
89
99
 
100
+ // src/webhook-verification.ts
101
+ var KRONOS_WEBHOOK_SIGNATURE_HEADER = "x-kronos-signature";
102
+ var KRONOS_WEBHOOK_TIMESTAMP_HEADER = "x-kronos-timestamp";
103
+ var KRONOS_WEBHOOK_EVENT_ID_HEADER = "x-kronos-event-id";
104
+ var KRONOS_WEBHOOK_EVENT_TYPE_HEADER = "x-kronos-event-type";
105
+ var BILLING_USAGE_UPDATED_EVENT = "billing.usage.updated";
106
+ var KronosWebhookError = class extends Error {
107
+ constructor(message, status = 400) {
108
+ super(message);
109
+ this.name = "KronosWebhookError";
110
+ this.status = status;
111
+ }
112
+ };
113
+ function hexFromBytes(bytes) {
114
+ return Array.from(bytes).map((byte) => byte.toString(16).padStart(2, "0")).join("");
115
+ }
116
+ function buildKronosWebhookSignatureInput(timestamp, payload) {
117
+ return `${timestamp}.${payload}`;
118
+ }
119
+ async function signKronosWebhookPayload(params) {
120
+ const key = await crypto.subtle.importKey(
121
+ "raw",
122
+ new TextEncoder().encode(params.secret),
123
+ { name: "HMAC", hash: "SHA-256" },
124
+ false,
125
+ ["sign"]
126
+ );
127
+ const signature = await crypto.subtle.sign(
128
+ "HMAC",
129
+ key,
130
+ new TextEncoder().encode(
131
+ buildKronosWebhookSignatureInput(params.timestamp, params.payload)
132
+ )
133
+ );
134
+ return hexFromBytes(new Uint8Array(signature));
135
+ }
136
+ async function verifyKronosWebhookSignature(params) {
137
+ if (!params.timestamp || !params.signature || !params.secret) {
138
+ return false;
139
+ }
140
+ const toleranceSeconds = params.toleranceSeconds ?? 300;
141
+ const now = params.now ?? Math.floor(Date.now() / 1e3);
142
+ const timestampSeconds = Number(params.timestamp);
143
+ if (!Number.isFinite(timestampSeconds)) {
144
+ return false;
145
+ }
146
+ if (Math.abs(now - timestampSeconds) > toleranceSeconds) {
147
+ return false;
148
+ }
149
+ const expected = await signKronosWebhookPayload({
150
+ payload: params.payload,
151
+ secret: params.secret,
152
+ timestamp: params.timestamp
153
+ });
154
+ return verifyWebhookSecret(params.signature, expected);
155
+ }
156
+ function verifyWebhookSecret(receivedSecret, storedSecret) {
157
+ if (!receivedSecret || !storedSecret) {
158
+ return false;
159
+ }
160
+ if (receivedSecret.length !== storedSecret.length) {
161
+ return false;
162
+ }
163
+ let result = 0;
164
+ for (let i = 0; i < receivedSecret.length; i++) {
165
+ result |= receivedSecret.charCodeAt(i) ^ storedSecret.charCodeAt(i);
166
+ }
167
+ return result === 0;
168
+ }
169
+ function isBillingUsageWebhookEvent(value) {
170
+ if (!value || typeof value !== "object") {
171
+ return false;
172
+ }
173
+ const event = value;
174
+ const data = event.data;
175
+ return event.type === BILLING_USAGE_UPDATED_EVENT && typeof event.id === "string" && typeof event.created_at === "string" && !!data && typeof data.app_id === "string" && typeof data.tenant_user_id === "string" && typeof data.total_cost_usd === "number" && typeof data.latest_run_cost_usd === "number" && typeof data.updated_at === "string";
176
+ }
177
+
90
178
  // src/client.ts
91
179
  var DEFAULT_WORKER_URL = "https://api.kronos.ai";
92
180
  var DEFAULT_MASTRA_URL = "https://mastra.kronos.ai";
@@ -364,6 +452,127 @@ var KronosClient = class {
364
452
  { method: "GET" }
365
453
  );
366
454
  }
455
+ /**
456
+ * Get daily AI stage cost totals for the app, or for a single user if specified.
457
+ */
458
+ async getCostBreakdown(params = {}) {
459
+ const query = new URLSearchParams({
460
+ app_id: this.appId
461
+ });
462
+ if (params.tenant_user_id) {
463
+ query.set("tenant_user_id", params.tenant_user_id);
464
+ }
465
+ if (typeof params.days === "number" && Number.isFinite(params.days)) {
466
+ query.set("days", String(Math.trunc(params.days)));
467
+ }
468
+ return this.workerFetch(
469
+ `/v1/costs/breakdown?${query.toString()}`,
470
+ { method: "GET" }
471
+ );
472
+ }
473
+ /**
474
+ * Get the app-level billing usage webhook configuration.
475
+ */
476
+ async getBillingUsageWebhook() {
477
+ const query = new URLSearchParams({
478
+ app_id: this.appId
479
+ });
480
+ return this.workerFetch(
481
+ `/v1/webhooks/billing-usage?${query.toString()}`,
482
+ { method: "GET" }
483
+ );
484
+ }
485
+ /**
486
+ * Configure the app-level billing usage webhook.
487
+ */
488
+ async configureBillingUsageWebhook(params) {
489
+ return this.workerFetch(
490
+ "/v1/webhooks/billing-usage",
491
+ {
492
+ method: "PUT",
493
+ json: {
494
+ app_id: this.appId,
495
+ webhook_url: params.webhook_url,
496
+ webhook_secret: params.webhook_secret,
497
+ event_types: params.event_types,
498
+ status: params.status
499
+ }
500
+ }
501
+ );
502
+ }
503
+ /**
504
+ * Delete the app-level billing usage webhook configuration.
505
+ */
506
+ async deleteBillingUsageWebhook() {
507
+ const query = new URLSearchParams({
508
+ app_id: this.appId
509
+ });
510
+ return this.workerFetch(
511
+ `/v1/webhooks/billing-usage?${query.toString()}`,
512
+ { method: "DELETE" }
513
+ );
514
+ }
515
+ /**
516
+ * Verify an incoming billing usage webhook against the stored app webhook secret.
517
+ */
518
+ async verifyBillingUsageWebhook(params) {
519
+ const response = await this.workerFetch(
520
+ "/v1/webhooks/billing-usage/verify",
521
+ {
522
+ method: "POST",
523
+ json: {
524
+ app_id: this.appId,
525
+ payload: params.payload,
526
+ received_signature: params.signature,
527
+ received_timestamp: params.timestamp
528
+ }
529
+ }
530
+ );
531
+ return response.valid;
532
+ }
533
+ /**
534
+ * Verify an incoming Kronos webhook request and optionally validate its payload shape.
535
+ */
536
+ async verifyWebhook(request, options = {}) {
537
+ const payload = await request.text();
538
+ const signature = request.headers.get(KRONOS_WEBHOOK_SIGNATURE_HEADER);
539
+ const timestamp = request.headers.get(KRONOS_WEBHOOK_TIMESTAMP_HEADER);
540
+ if (!signature || !timestamp) {
541
+ throw new KronosWebhookError("Missing webhook signature headers", 401);
542
+ }
543
+ const response = await this.workerFetch(
544
+ "/v1/webhooks/verify",
545
+ {
546
+ method: "POST",
547
+ json: {
548
+ app_id: this.appId,
549
+ payload,
550
+ received_signature: signature,
551
+ received_timestamp: timestamp
552
+ }
553
+ }
554
+ );
555
+ if (!response.valid) {
556
+ throw new KronosWebhookError("Invalid webhook signature", 401);
557
+ }
558
+ const eventType = request.headers.get(KRONOS_WEBHOOK_EVENT_TYPE_HEADER);
559
+ if (options.expectedEventType && eventType !== options.expectedEventType) {
560
+ throw new KronosWebhookError(
561
+ `Unsupported webhook event type: ${eventType ?? "missing"}`,
562
+ 400
563
+ );
564
+ }
565
+ let parsedPayload;
566
+ try {
567
+ parsedPayload = JSON.parse(payload);
568
+ } catch {
569
+ throw new KronosWebhookError("Invalid webhook payload", 400);
570
+ }
571
+ if (options.validate && !options.validate(parsedPayload)) {
572
+ throw new KronosWebhookError("Invalid webhook payload", 400);
573
+ }
574
+ return parsedPayload;
575
+ }
367
576
  /**
368
577
  * Read the current scratchsheet document for a user.
369
578
  */
@@ -741,23 +950,13 @@ var KronosClient = class {
741
950
  };
742
951
  }
743
952
  };
744
-
745
- // src/webhook-verification.ts
746
- function verifyWebhookSecret(receivedSecret, storedSecret) {
747
- if (!receivedSecret || !storedSecret) {
748
- return false;
749
- }
750
- if (receivedSecret.length !== storedSecret.length) {
751
- return false;
752
- }
753
- let result = 0;
754
- for (let i = 0; i < receivedSecret.length; i++) {
755
- result |= receivedSecret.charCodeAt(i) ^ storedSecret.charCodeAt(i);
756
- }
757
- return result === 0;
758
- }
759
953
  // Annotate the CommonJS export names for ESM import in node:
760
954
  0 && (module.exports = {
955
+ BILLING_USAGE_UPDATED_EVENT,
956
+ KRONOS_WEBHOOK_EVENT_ID_HEADER,
957
+ KRONOS_WEBHOOK_EVENT_TYPE_HEADER,
958
+ KRONOS_WEBHOOK_SIGNATURE_HEADER,
959
+ KRONOS_WEBHOOK_TIMESTAMP_HEADER,
761
960
  KronosBadRequestError,
762
961
  KronosClient,
763
962
  KronosError,
@@ -765,7 +964,12 @@ function verifyWebhookSecret(receivedSecret, storedSecret) {
765
964
  KronosNotFoundError,
766
965
  KronosServerError,
767
966
  KronosUnauthorizedError,
967
+ KronosWebhookError,
968
+ buildKronosWebhookSignatureInput,
768
969
  generateIdempotencyKey,
970
+ isBillingUsageWebhookEvent,
971
+ signKronosWebhookPayload,
972
+ verifyKronosWebhookSignature,
769
973
  verifyWebhookSecret
770
974
  });
771
975
  //# sourceMappingURL=index.js.map