@gdrl/kronos-lib 0.1.4 → 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, d as CostBreakdownResponse, S as ScratchsheetResponse, e as ListScopesResponse, f as GetScopeResponse, g as ScopeSpec, h as CreateScopeResponse, U as UpdateScopeResponse, i as ListTriggersResponse, j as CreateTriggerRequest, k as CreateTriggerResponse, T as TriggerRecord, l as UpdateTriggerRequest, m as UpdateTriggerResponse, D as DeleteTriggerResponse, n as CreateFrontendTokenResponse, o as SkillManageParams, p as SkillManageResponse, q as ContextGraphSummaryResponse, r as ContextGraphReadResponse } from './types-CftFKnhs.mjs';
2
- export { z as ConnectMCPServerRequest, $ as ContextGraphProcedureSummary, B as CostBreakdownPoint, N as CreateFrontendTokenRequest, v as CreateMCPServerRequest, H as CreateScopeRequest, t as IngestMemoryDisposition, u as IngestRequest, s as IngestStatus, y as MCPServerDetails, w as MCPServerStatus, x as MCPServerToolCapabilities, O as OnTriggered, A as RotateMCPServerTokenRequest, F as ScopeDetail, E as ScopeSummary, V as SkillFileContentMode, W as SkillFileInput, X as SkillFileRecord, P as SkillFileType, Z as SkillMetadataRecord, Q as SkillReadMode, _ as SkillSummaryRecord, Y as SkillTreeNode, J as TriggerType } from './types-CftFKnhs.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;
@@ -109,6 +109,38 @@ declare class KronosClient {
109
109
  tenant_user_id?: string;
110
110
  days?: number;
111
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>;
112
144
  /**
113
145
  * Read the current scratchsheet document for a user.
114
146
  */
@@ -283,6 +315,29 @@ declare function generateIdempotencyKey(): string;
283
315
  * Webhook verification utilities for Kronos triggers
284
316
  * Provides secure constant-time comparison for webhook secrets
285
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>;
286
341
  /**
287
342
  * Verify a webhook secret using constant-time comparison to prevent timing attacks.
288
343
  *
@@ -305,6 +360,7 @@ declare function generateIdempotencyKey(): string;
305
360
  * ```
306
361
  */
307
362
  declare function verifyWebhookSecret(receivedSecret: string | null | undefined, storedSecret: string | null | undefined): boolean;
363
+ declare function isBillingUsageWebhookEvent(value: unknown): value is BillingUsageWebhookEvent;
308
364
 
309
365
  /**
310
366
  * Base error for Kronos API failures
@@ -346,4 +402,4 @@ declare class KronosServerError extends KronosError {
346
402
  constructor(message: string, status?: number, body?: unknown);
347
403
  }
348
404
 
349
- export { ConnectMCPServerResponse, ContextGraphReadResponse, ContextGraphSummaryResponse, CostBreakdownResponse, 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, d as CostBreakdownResponse, S as ScratchsheetResponse, e as ListScopesResponse, f as GetScopeResponse, g as ScopeSpec, h as CreateScopeResponse, U as UpdateScopeResponse, i as ListTriggersResponse, j as CreateTriggerRequest, k as CreateTriggerResponse, T as TriggerRecord, l as UpdateTriggerRequest, m as UpdateTriggerResponse, D as DeleteTriggerResponse, n as CreateFrontendTokenResponse, o as SkillManageParams, p as SkillManageResponse, q as ContextGraphSummaryResponse, r as ContextGraphReadResponse } from './types-CftFKnhs.js';
2
- export { z as ConnectMCPServerRequest, $ as ContextGraphProcedureSummary, B as CostBreakdownPoint, N as CreateFrontendTokenRequest, v as CreateMCPServerRequest, H as CreateScopeRequest, t as IngestMemoryDisposition, u as IngestRequest, s as IngestStatus, y as MCPServerDetails, w as MCPServerStatus, x as MCPServerToolCapabilities, O as OnTriggered, A as RotateMCPServerTokenRequest, F as ScopeDetail, E as ScopeSummary, V as SkillFileContentMode, W as SkillFileInput, X as SkillFileRecord, P as SkillFileType, Z as SkillMetadataRecord, Q as SkillReadMode, _ as SkillSummaryRecord, Y as SkillTreeNode, J as TriggerType } from './types-CftFKnhs.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;
@@ -109,6 +109,38 @@ declare class KronosClient {
109
109
  tenant_user_id?: string;
110
110
  days?: number;
111
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>;
112
144
  /**
113
145
  * Read the current scratchsheet document for a user.
114
146
  */
@@ -283,6 +315,29 @@ declare function generateIdempotencyKey(): string;
283
315
  * Webhook verification utilities for Kronos triggers
284
316
  * Provides secure constant-time comparison for webhook secrets
285
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>;
286
341
  /**
287
342
  * Verify a webhook secret using constant-time comparison to prevent timing attacks.
288
343
  *
@@ -305,6 +360,7 @@ declare function generateIdempotencyKey(): string;
305
360
  * ```
306
361
  */
307
362
  declare function verifyWebhookSecret(receivedSecret: string | null | undefined, storedSecret: string | null | undefined): boolean;
363
+ declare function isBillingUsageWebhookEvent(value: unknown): value is BillingUsageWebhookEvent;
308
364
 
309
365
  /**
310
366
  * Base error for Kronos API failures
@@ -346,4 +402,4 @@ declare class KronosServerError extends KronosError {
346
402
  constructor(message: string, status?: number, body?: unknown);
347
403
  }
348
404
 
349
- export { ConnectMCPServerResponse, ContextGraphReadResponse, ContextGraphSummaryResponse, CostBreakdownResponse, 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";
@@ -382,6 +470,109 @@ var KronosClient = class {
382
470
  { method: "GET" }
383
471
  );
384
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
+ }
385
576
  /**
386
577
  * Read the current scratchsheet document for a user.
387
578
  */
@@ -759,23 +950,13 @@ var KronosClient = class {
759
950
  };
760
951
  }
761
952
  };
762
-
763
- // src/webhook-verification.ts
764
- function verifyWebhookSecret(receivedSecret, storedSecret) {
765
- if (!receivedSecret || !storedSecret) {
766
- return false;
767
- }
768
- if (receivedSecret.length !== storedSecret.length) {
769
- return false;
770
- }
771
- let result = 0;
772
- for (let i = 0; i < receivedSecret.length; i++) {
773
- result |= receivedSecret.charCodeAt(i) ^ storedSecret.charCodeAt(i);
774
- }
775
- return result === 0;
776
- }
777
953
  // Annotate the CommonJS export names for ESM import in node:
778
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,
779
960
  KronosBadRequestError,
780
961
  KronosClient,
781
962
  KronosError,
@@ -783,7 +964,12 @@ function verifyWebhookSecret(receivedSecret, storedSecret) {
783
964
  KronosNotFoundError,
784
965
  KronosServerError,
785
966
  KronosUnauthorizedError,
967
+ KronosWebhookError,
968
+ buildKronosWebhookSignatureInput,
786
969
  generateIdempotencyKey,
970
+ isBillingUsageWebhookEvent,
971
+ signKronosWebhookPayload,
972
+ verifyKronosWebhookSignature,
787
973
  verifyWebhookSecret
788
974
  });
789
975
  //# sourceMappingURL=index.js.map