@timeback/webhooks 0.2.0 → 0.2.1-beta.20260331190459

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.ts CHANGED
@@ -1,149 +1,1093 @@
1
- import * as _timeback_internal_client_infra from '@timeback/internal-client-infra';
2
- import { BaseTransportConfig, WebhookPaths, ClientConfig, TransportOnlyConfig, RequestOptions, ProviderClientConfig, ProviderRegistry, TimebackProvider, AuthCheckResult, BaseTransport } from '@timeback/internal-client-infra';
3
- export { AuthCheckResult, EnvAuth, Environment, ExplicitAuth } from '@timeback/internal-client-infra';
4
-
5
- type input<T> = T extends {
6
- _zod: {
7
- input: any;
8
- };
9
- } ? T["_zod"]["input"] : unknown;
1
+ import { WebhookCreateInput, WebhookUpdateInput, WebhookFilterCreateInput, WebhookFilterUpdateInput } from '@timeback/types/zod';
2
+ export { WebhookCreateInput, WebhookFilterCreateInput, WebhookFilterUpdateInput, WebhookUpdateInput } from '@timeback/types/zod';
3
+ import { Webhook, WebhookDeleteResponse, WebhookFilter, WebhookFilterDeleteResponse } from '@timeback/types/protocols/webhooks';
4
+ export { FilterOperation, FilterType, Webhook, WebhookFilter } from '@timeback/types/protocols/webhooks';
10
5
 
11
6
  /**
12
- * Webhook Schemas
7
+ * Interface for obtaining OAuth2 access tokens.
13
8
  *
14
- * Zod schemas for webhook and webhook filter inputs.
9
+ * Implementations handle token caching and refresh automatically.
15
10
  */
11
+ interface TokenProvider {
12
+ /**
13
+ * Get a valid access token.
14
+ *
15
+ * Returns a cached token if still valid, otherwise fetches a new one.
16
+ *
17
+ * @returns A valid access token string
18
+ * @throws {Error} If token acquisition fails
19
+ */
20
+ getToken(): Promise<string>;
21
+ /**
22
+ * Invalidate the cached token.
23
+ *
24
+ * Forces the next getToken() call to fetch a fresh token.
25
+ * Should be called when a request fails with 401 Unauthorized.
26
+ *
27
+ * Optional - not all implementations may support invalidation.
28
+ */
29
+ invalidate?(): void;
30
+ }
16
31
 
32
+ /**
33
+ * All supported platforms.
34
+ */
35
+ declare const PLATFORMS: readonly ["BEYOND_AI", "LEARNWITH_AI"];
17
36
 
37
+ /**
38
+ * Type Definitions for `@timeback/internal-logger`
39
+ *
40
+ * Central type definitions used across all logger components.
41
+ * These types define the contract between the logger, formatters, and consumers.
42
+ */
43
+ /**
44
+ * Log severity levels, ordered from least to most severe.
45
+ *
46
+ * - debug: Detailed diagnostic information for developers
47
+ * - info: General operational messages (app started, request received)
48
+ * - warn: Something unexpected but not breaking (deprecated API used)
49
+ * - error: Something failed (request failed, database connection lost)
50
+ */
51
+ type LogLevel = 'debug' | 'info' | 'warn' | 'error';
52
+ /**
53
+ * Runtime environments that determine how logs are formatted.
54
+ *
55
+ * - terminal: Local development with colors and icons
56
+ * - ci: CI/CD pipelines with plain text (no ANSI codes)
57
+ * - production: JSON lines for log aggregation (DataDog, CloudWatch, etc.)
58
+ * - browser: Browser console with CSS styling
59
+ * - test: Test environment with no output
60
+ */
61
+ type Environment$2 = 'terminal' | 'ci' | 'production' | 'browser' | 'test';
62
+ /**
63
+ * Arbitrary key-value data attached to log entries.
64
+ *
65
+ * Context is merged into log output - in production it becomes top-level
66
+ * JSON fields, in terminal it's displayed as key=value pairs.
67
+ *
68
+ * @example
69
+ * log.info('User created', { userId: 123, email: 'foo@bar.com' })
70
+ */
71
+ type LogContext = Record<string, unknown>;
72
+ /**
73
+ * Configuration options for creating a logger instance.
74
+ */
75
+ interface LoggerOptions {
76
+ /**
77
+ * Logger scope/namespace for categorizing logs.
78
+ * Child loggers append to this with colons: "api" → "api:users"
79
+ */
80
+ scope?: string;
81
+ /**
82
+ * Minimum log level to output.
83
+ * Logs below this level are silently ignored.
84
+ * @default 'info' (or 'debug' if DEBUG env var is set)
85
+ */
86
+ minLevel?: LogLevel;
87
+ /**
88
+ * Override automatic environment detection.
89
+ * Useful for testing or forcing a specific format.
90
+ */
91
+ environment?: Environment$2;
92
+ /**
93
+ * Default context added to every log entry from this logger.
94
+ * Useful for request IDs, user IDs, etc.
95
+ */
96
+ defaultContext?: LogContext;
97
+ }
18
98
 
19
- // ═══════════════════════════════════════════════════════════════════════════════
20
- // WEBHOOK INPUTS
21
- // ═══════════════════════════════════════════════════════════════════════════════
22
-
23
- declare const WebhookCreateInput = z
24
- .object({
25
- name: NonEmptyString,
26
- targetUrl: z.url('targetUrl must be a valid URL'),
27
- secret: NonEmptyString,
28
- active: z.boolean(),
29
- sensor: z.string().nullable().optional(),
30
- description: z.string().nullable().optional(),
31
- })
32
- .strict()
33
-
34
- // ═══════════════════════════════════════════════════════════════════════════════
35
- // TYPE EXPORTS (REQUEST INPUTS)
36
- // ═══════════════════════════════════════════════════════════════════════════════
37
-
38
- type WebhookCreateInput = input<typeof WebhookCreateInput>
39
-
40
- declare const WebhookUpdateInput = WebhookCreateInput
41
- type WebhookUpdateInput = input<typeof WebhookUpdateInput>
99
+ /**
100
+ * Logger instance with environment-aware formatting.
101
+ *
102
+ * Instances are lightweight and can be created freely.
103
+ * Common pattern: one logger per module/component.
104
+ */
105
+ declare class Logger {
106
+ /** Namespace for this logger (e.g., "api", "api:users") */
107
+ private scope?;
108
+ /** Minimum level to output (logs below this are ignored) */
109
+ private minLevel;
110
+ /** The detected or configured environment */
111
+ private environment;
112
+ /** Function that formats and outputs log entries */
113
+ private formatter;
114
+ /** Context added to every log entry from this logger */
115
+ private defaultContext;
116
+ /**
117
+ * Create a new Logger instance.
118
+ *
119
+ * Usually you'd use createLogger() instead of new Logger().
120
+ */
121
+ constructor(options?: LoggerOptions);
122
+ /**
123
+ * Create a child logger with an additional scope segment.
124
+ *
125
+ * Child loggers inherit minLevel and defaultContext from parent.
126
+ * Scope is appended with a colon separator.
127
+ *
128
+ * @param scope - Additional scope segment to append
129
+ * @returns New Logger instance with extended scope
130
+ *
131
+ * @example
132
+ * const api = createLogger({ scope: 'api' })
133
+ * const users = api.child('users')
134
+ * users.info('Created') // scope: "api:users"
135
+ */
136
+ child(scope: string): Logger;
137
+ /**
138
+ * Create a logger with additional default context.
139
+ *
140
+ * The new context is merged with existing default context.
141
+ * Useful for adding request IDs, user IDs, etc.
142
+ *
143
+ * @param context - Additional context to include in all logs
144
+ * @returns New Logger instance with extended context
145
+ *
146
+ * @example
147
+ * const requestLog = log.withContext({ requestId: 'abc123' })
148
+ * requestLog.info('Processing') // requestId included automatically
149
+ */
150
+ withContext(context: LogContext): Logger;
151
+ /**
152
+ * Log a debug message.
153
+ *
154
+ * Use for detailed diagnostic information useful during development.
155
+ * These are typically filtered out in production.
156
+ *
157
+ * @param message - The log message
158
+ * @param context - Optional key-value context to include with the log
159
+ */
160
+ debug(message: string, context?: LogContext): void;
161
+ /**
162
+ * Log an info message.
163
+ *
164
+ * Use for general operational information.
165
+ * Examples: server started, request received, job completed.
166
+ *
167
+ * @param message - The log message
168
+ * @param context - Optional key-value context to include with the log
169
+ */
170
+ info(message: string, context?: LogContext): void;
171
+ /**
172
+ * Log a warning message.
173
+ *
174
+ * Use for unexpected but non-breaking issues.
175
+ * Examples: deprecated API used, retrying operation, approaching limit.
176
+ *
177
+ * @param message - The log message
178
+ * @param context - Optional key-value context to include with the log
179
+ */
180
+ warn(message: string, context?: LogContext): void;
181
+ /**
182
+ * Log an error message.
183
+ *
184
+ * Use for failures that need attention.
185
+ * Examples: request failed, database error, unhandled exception.
186
+ *
187
+ * @param message - The log message
188
+ * @param context - Optional key-value context to include with the log
189
+ */
190
+ error(message: string, context?: LogContext): void;
191
+ /**
192
+ * Internal method that builds the log entry and passes it to the formatter.
193
+ *
194
+ * All public log methods (debug, info, warn, error) delegate here.
195
+ *
196
+ * @param level - The log level
197
+ * @param message - The log message
198
+ * @param context - Optional key-value context to include with the log
199
+ */
200
+ private log;
201
+ }
42
202
 
43
- declare const WebhookFilterCreateInput = z
44
- .object({
45
- webhookId: NonEmptyString,
46
- filterKey: NonEmptyString,
47
- filterValue: NonEmptyString,
48
- filterType: WebhookFilterType,
49
- filterOperator: WebhookFilterOperation,
50
- active: z.boolean(),
51
- })
52
- .strict()
53
- type WebhookFilterCreateInput = input<typeof WebhookFilterCreateInput>
203
+ /**
204
+ * Shared Types
205
+ *
206
+ * Common types for API client infrastructure.
207
+ */
54
208
 
55
- declare const WebhookFilterUpdateInput = WebhookFilterCreateInput
56
- type WebhookFilterUpdateInput = input<typeof WebhookFilterUpdateInput>
209
+ /**
210
+ * Fetch function signature for HTTP requests.
211
+ * Avoids Bun-specific extensions on `typeof fetch`.
212
+ */
213
+ type FetchFn$1 = (input: string | URL | Request, init?: RequestInit) => Promise<Response>;
214
+ /**
215
+ * Supported Timeback platform implementations.
216
+ */
217
+ type Platform$1 = (typeof PLATFORMS)[number];
218
+ /**
219
+ * Supported deployment environments.
220
+ */
221
+ type Environment$1 = 'staging' | 'production';
222
+ /**
223
+ * Auth credentials for environment mode.
224
+ * Token URL is derived automatically from environment.
225
+ */
226
+ interface EnvAuth$1 {
227
+ clientId: string;
228
+ clientSecret: string;
229
+ }
230
+ /**
231
+ * Auth credentials for explicit mode.
232
+ * Includes authUrl for custom APIs.
233
+ * @deprecated Use separate authUrl and ProviderAuth fields instead
234
+ */
235
+ interface ExplicitAuth$1 {
236
+ clientId: string;
237
+ clientSecret: string;
238
+ authUrl: string;
239
+ }
240
+ /**
241
+ * Base configuration options shared by all modes.
242
+ */
243
+ interface BaseConfig$1 {
244
+ /** Request timeout in milliseconds */
245
+ timeout?: number;
246
+ /** Custom fetch implementation */
247
+ fetch?: FetchFn$1;
248
+ }
249
+ /**
250
+ * Environment-based configuration for Timeback APIs.
251
+ */
252
+ interface EnvConfig extends BaseConfig$1 {
253
+ /** Timeback platform implementation (defaults to 'BEYOND_AI') */
254
+ platform?: Platform$1;
255
+ /** Target environment - determines base URL and token URL */
256
+ env: Environment$1;
257
+ /** OAuth2 client credentials */
258
+ auth: EnvAuth$1;
259
+ }
260
+ /**
261
+ * Environment-based configuration with shared token provider.
262
+ */
263
+ interface TokenProviderEnvConfig extends BaseConfig$1 {
264
+ /** Timeback platform implementation (defaults to 'BEYOND_AI') */
265
+ platform?: Platform$1;
266
+ /** Target environment - determines base URL */
267
+ env: Environment$1;
268
+ /** Shared token provider (from @timeback/auth) */
269
+ tokenProvider: TokenProvider;
270
+ }
271
+ /**
272
+ * Explicit URL configuration for custom APIs.
273
+ * Supports both authenticated and public/no-auth services.
274
+ */
275
+ interface ExplicitConfig extends BaseConfig$1 {
276
+ /** API base URL */
277
+ baseUrl: string;
278
+ /**
279
+ * OAuth2 token URL. Omit for public/no-auth services.
280
+ * Can also be provided via auth.authUrl (legacy format).
281
+ */
282
+ authUrl?: string;
283
+ /**
284
+ * OAuth2 credentials. Required if authUrl is provided.
285
+ * Supports both ExplicitAuth (with authUrl) and ProviderAuth (without).
286
+ */
287
+ auth?: ExplicitAuth$1 | ProviderAuth;
288
+ /**
289
+ * Use a built-in path profile by name.
290
+ * Defaults to 'BEYOND_AI' if neither pathProfile nor paths is specified.
291
+ */
292
+ pathProfile?: Platform$1;
293
+ /** Custom path overrides (takes precedence over pathProfile) */
294
+ paths?: Partial<PlatformPaths>;
295
+ /** Not applicable to explicit config — use `EnvConfig` instead */
296
+ env?: never;
297
+ }
298
+ /**
299
+ * Use pre-configured transport.
300
+ */
301
+ interface TransportConfig extends BaseConfig$1 {
302
+ /** Transport configuration */
303
+ transport: TransportLike;
304
+ }
305
+ /**
306
+ * HTTP request options.
307
+ */
308
+ interface RequestOptions$1 {
309
+ /** HTTP method */
310
+ method?: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
311
+ /** Query parameters to append to the URL */
312
+ params?: Record<string, string | number | boolean | undefined>;
313
+ /** Request body (will be JSON-serialized) */
314
+ body?: unknown;
315
+ /** Additional headers to include */
316
+ headers?: Record<string, string>;
317
+ /**
318
+ * Unique identifier for this request.
319
+ * Used for log correlation and debugging.
320
+ * Auto-generated if not provided.
321
+ */
322
+ requestId?: string;
323
+ }
324
+ /**
325
+ * Duck-typed transport interface for testing and advanced use.
326
+ */
327
+ interface TransportLike {
328
+ /** Base URL of the API */
329
+ baseUrl: string;
330
+ /** Make an authenticated request */
331
+ request<T>(path: string, options?: RequestOptions$1): Promise<T>;
332
+ }
333
+ /**
334
+ * Configuration using a pre-configured transport.
335
+ *
336
+ * For advanced use cases like sharing a transport between clients
337
+ * or using a custom transport implementation.
338
+ *
339
+ * @template T - Transport type (defaults to TransportLike, clients should specify their full transport type)
340
+ */
341
+ interface TransportOnlyConfig<T extends TransportLike = TransportLike> {
342
+ /** Existing transport instance */
343
+ transport: T;
344
+ }
345
+ /**
346
+ * Union of all client configuration types.
347
+ */
348
+ type ClientConfig = EnvConfig | TokenProviderEnvConfig | ExplicitConfig | TransportConfig | Partial<ExplicitConfig>;
349
+ /**
350
+ * Result of an auth check operation.
351
+ */
352
+ interface AuthCheckResult$1 {
353
+ /** Whether auth succeeded */
354
+ ok: boolean;
355
+ /** Time taken to complete the check (ms) */
356
+ latencyMs: number;
357
+ /** Error message if failed */
358
+ error?: string;
359
+ /** Detailed check results */
360
+ checks: {
361
+ /** Token acquisition succeeded */
362
+ tokenAcquisition: boolean;
363
+ };
364
+ }
57
365
 
58
366
  /**
59
- * Webhook Types
367
+ * Config Types
60
368
  *
61
- * Type definitions for the Webhooks API.
369
+ * Types for TimebackProvider and provider resolution.
62
370
  */
63
371
 
64
- // ═══════════════════════════════════════════════════════════════════════════════
65
- // ENUMS
66
- // ═══════════════════════════════════════════════════════════════════════════════
372
+ /**
373
+ * Caliper API path profile.
374
+ * Defines paths for Caliper operations. Use `null` for unsupported operations.
375
+ */
376
+ interface CaliperPaths {
377
+ /** Path for sending events (POST) */
378
+ send: string;
379
+ /** Path for validating events (POST), null if not supported */
380
+ validate: string | null;
381
+ /** Path for listing events (GET), null if not supported */
382
+ list: string | null;
383
+ /** Path template for getting single event (GET), use {id} placeholder */
384
+ get: string | null;
385
+ /** Path template for job status (GET), use {id} placeholder */
386
+ jobStatus: string | null;
387
+ }
388
+ /**
389
+ * Webhook API path profile.
390
+ * Defines paths for webhook management operations.
391
+ * Nullability is at the platform level (`webhooks: WebhookPaths | null` in PlatformPaths).
392
+ */
393
+ interface WebhookPaths {
394
+ /** Path for listing webhooks (GET) */
395
+ webhookList: string;
396
+ /** Path template for getting a single webhook (GET), use {id} placeholder */
397
+ webhookGet: string;
398
+ /** Path for creating a webhook (POST) */
399
+ webhookCreate: string;
400
+ /** Path template for updating a webhook (PUT), use {id} placeholder */
401
+ webhookUpdate: string;
402
+ /** Path template for deleting a webhook (DELETE), use {id} placeholder */
403
+ webhookDelete: string;
404
+ /** Path template for activating a webhook (PUT), use {id} placeholder */
405
+ webhookActivate: string;
406
+ /** Path template for deactivating a webhook (PUT), use {id} placeholder */
407
+ webhookDeactivate: string;
408
+ /** Path for listing all webhook filters (GET) */
409
+ webhookFilterList: string;
410
+ /** Path template for getting a single webhook filter (GET), use {id} placeholder */
411
+ webhookFilterGet: string;
412
+ /** Path for creating a webhook filter (POST) */
413
+ webhookFilterCreate: string;
414
+ /** Path template for updating a webhook filter (PUT), use {id} placeholder */
415
+ webhookFilterUpdate: string;
416
+ /** Path template for deleting a webhook filter (DELETE), use {id} placeholder */
417
+ webhookFilterDelete: string;
418
+ /** Path template for listing filters by webhook (GET), use {webhookId} placeholder */
419
+ webhookFiltersByWebhook: string;
420
+ }
421
+ /**
422
+ * Reporting API path profile.
423
+ * Defines paths for reporting MCP and REST operations.
424
+ * Nullability is at the platform level (`reporting: ReportingPaths | null` in PlatformPaths).
425
+ */
426
+ interface ReportingPaths {
427
+ /** Path for the reporting MCP JSON-RPC endpoint (POST) */
428
+ mcp: string;
429
+ /** Path template for executing a saved query (GET), use {id} placeholder */
430
+ savedQueryExecute: string;
431
+ /** Path template for checking reporting group membership (GET), use {email} placeholder */
432
+ adminGroupCheck: string;
433
+ /** Path template for adding a user to the reporting group (POST), use {email} placeholder */
434
+ adminGroupAdd: string;
435
+ /** Path template for removing a user from the reporting group (DELETE), use {email} placeholder */
436
+ adminGroupRemove: string;
437
+ }
438
+ /**
439
+ * OneRoster API path profile.
440
+ * Defines the base path prefix for all OneRoster resources.
441
+ */
442
+ interface OneRosterPaths {
443
+ /** Base path prefix for rostering resources (users, schools, classes, etc.) */
444
+ rostering: string;
445
+ /** Base path prefix for gradebook resources (lineItems, results, etc.) */
446
+ gradebook: string;
447
+ /** Base path prefix for resources API (digital learning resources) */
448
+ resources: string;
449
+ }
450
+ /**
451
+ * Edubridge API path profile.
452
+ * Defines path prefixes for Edubridge operations.
453
+ */
454
+ interface EdubridgePaths {
455
+ /** Base path prefix for all Edubridge resources */
456
+ base: string;
457
+ }
458
+ /**
459
+ * PowerPath API path profile.
460
+ * Defines path prefixes for PowerPath operations.
461
+ */
462
+ interface PowerPathPaths {
463
+ /** Base path prefix for all PowerPath resources */
464
+ base: string;
465
+ }
466
+ /**
467
+ * CASE API path profile.
468
+ * Defines path prefix for CASE (Competency and Academic Standards Exchange) operations.
469
+ */
470
+ interface CasePaths {
471
+ /** Base path prefix for all CASE resources */
472
+ base: string;
473
+ }
474
+ /**
475
+ * CLR API path profile.
476
+ * Defines path prefixes for CLR (Comprehensive Learner Record) operations.
477
+ */
478
+ interface ClrPaths {
479
+ /** Path for upserting CLR credentials (POST) */
480
+ credentials: string;
481
+ /** Path for API discovery (GET) */
482
+ discovery: string;
483
+ }
484
+ /**
485
+ * Platform path profiles for all services.
486
+ * Use `null` to indicate a service is not supported on the platform.
487
+ */
488
+ interface PlatformPaths {
489
+ caliper: CaliperPaths;
490
+ oneroster: OneRosterPaths;
491
+ webhooks: WebhookPaths | null;
492
+ reporting: ReportingPaths | null;
493
+ edubridge: EdubridgePaths | null;
494
+ powerpath: PowerPathPaths | null;
495
+ clr: ClrPaths | null;
496
+ case: CasePaths | null;
497
+ }
498
+ /**
499
+ * Services that have path configuration.
500
+ * Subset of ServiceName - excludes services without path profiles (e.g., 'qti').
501
+ */
502
+ type PathEnabledService = keyof PlatformPaths;
503
+ /**
504
+ * Supported Timeback platform implementations.
505
+ */
506
+ type Platform = (typeof PLATFORMS)[number];
507
+ /**
508
+ * Supported deployment environments.
509
+ */
510
+ type Environment = 'staging' | 'production';
511
+ /**
512
+ * Supported service names.
513
+ */
514
+ type ServiceName = 'oneroster' | 'caliper' | 'webhooks' | 'reporting' | 'edubridge' | 'qti' | 'powerpath' | 'clr' | 'case';
515
+ /**
516
+ * Resolved endpoint for a single service.
517
+ */
518
+ interface ResolvedEndpoint {
519
+ /** Base URL for the service API */
520
+ baseUrl: string;
521
+ /** OAuth2 token URL for this endpoint. Undefined for public/no-auth services. */
522
+ authUrl?: string;
523
+ }
524
+ /**
525
+ * Auth credentials for a provider.
526
+ */
527
+ interface ProviderAuth {
528
+ clientId: string;
529
+ clientSecret: string;
530
+ }
531
+ /**
532
+ * Configuration for environment-based provider.
533
+ * Uses known Timeback platform endpoints.
534
+ */
535
+ interface ProviderEnvConfig {
536
+ /** Timeback platform (defaults to 'BEYOND_AI') */
537
+ platform?: Platform;
538
+ /** Target environment */
539
+ env: Environment;
540
+ /** OAuth2 credentials */
541
+ auth: ProviderAuth;
542
+ /** Request timeout in milliseconds */
543
+ timeout?: number;
544
+ }
545
+ /**
546
+ * Configuration for explicit URL provider.
547
+ * Single base URL for all services.
548
+ */
549
+ interface ProviderExplicitConfig {
550
+ /** Base URL for all services */
551
+ baseUrl: string;
552
+ /** OAuth2 token URL. Omit for public/no-auth services. */
553
+ authUrl?: string;
554
+ /** OAuth2 credentials. Required if authUrl is provided. */
555
+ auth?: ProviderAuth;
556
+ /** Request timeout in milliseconds */
557
+ timeout?: number;
558
+ /**
559
+ * Use a built-in path profile by name.
560
+ * Defaults to 'BEYOND_AI' if neither pathProfile nor paths is specified.
561
+ */
562
+ pathProfile?: Platform;
563
+ /** Custom path overrides (takes precedence over pathProfile) */
564
+ paths?: Partial<PlatformPaths>;
565
+ }
566
+ /**
567
+ * Configuration for multi-service provider.
568
+ * Different URLs for different services.
569
+ */
570
+ interface ProviderServicesConfig {
571
+ /** Per-service base URLs */
572
+ services: Partial<Record<ServiceName, string>>;
573
+ /** OAuth2 token URL. Omit for public/no-auth services. */
574
+ authUrl?: string;
575
+ /** OAuth2 credentials. Required if authUrl is provided. */
576
+ auth?: ProviderAuth;
577
+ /** Request timeout in milliseconds */
578
+ timeout?: number;
579
+ /**
580
+ * Use a built-in path profile by name.
581
+ * Defaults to 'BEYOND_AI' if neither pathProfile nor paths is specified.
582
+ */
583
+ pathProfile?: Platform;
584
+ /** Custom path overrides (takes precedence over pathProfile) */
585
+ paths?: Partial<PlatformPaths>;
586
+ }
587
+ /**
588
+ * Union of all provider configuration types.
589
+ */
590
+ type TimebackProviderConfig = ProviderEnvConfig | ProviderExplicitConfig | ProviderServicesConfig;
591
+ /**
592
+ * Provider template - endpoints without auth.
593
+ * Used internally to define available platform+env combinations.
594
+ */
595
+ interface ProviderTemplate {
596
+ platform: Platform;
597
+ env: Environment;
598
+ }
599
+ /**
600
+ * Registry of provider templates indexed by platform and environment.
601
+ *
602
+ * Use `satisfies ProviderRegistry` when defining a registry for type checking.
603
+ *
604
+ * @example
605
+ * const myRegistry = {
606
+ * defaultPlatform: 'MY_PLATFORM',
607
+ * templates: {
608
+ * MY_PLATFORM: {
609
+ * staging: { platform: 'BEYOND_AI', env: 'staging' },
610
+ * production: { platform: 'BEYOND_AI', env: 'production' },
611
+ * },
612
+ * },
613
+ * } satisfies ProviderRegistry
614
+ */
615
+ interface ProviderRegistry {
616
+ /** Default platform when none specified */
617
+ defaultPlatform: string;
618
+ /** Available templates indexed by platform → env */
619
+ templates: Record<string, Record<string, ProviderTemplate>>;
620
+ }
621
+ /**
622
+ * Client config that accepts a pre-built provider.
623
+ */
624
+ interface ProviderClientConfig {
625
+ /** Pre-built provider */
626
+ provider: TimebackProvider;
627
+ }
67
628
 
68
- /** Supported data types for webhook filter values */
69
- type FilterType = 'string' | 'number' | 'boolean'
629
+ /**
630
+ * Timeback Provider
631
+ *
632
+ * Encapsulates platform connection configuration including endpoints and auth.
633
+ * Providers are complete "connection" objects that clients consume.
634
+ */
70
635
 
71
- /** Supported filter comparison operations */
72
- type FilterOperation =
73
- | 'eq'
74
- | 'neq'
75
- | 'gt'
76
- | 'gte'
77
- | 'lt'
78
- | 'lte'
79
- | 'contains'
80
- | 'notContains'
81
- | 'in'
82
- | 'notIn'
83
- | 'startsWith'
84
- | 'endsWith'
85
- | 'regexp'
636
+ /**
637
+ * Timeback Provider - encapsulates a complete platform connection.
638
+ *
639
+ * A provider contains everything needed to connect to Timeback APIs:
640
+ * - Service endpoints (URLs)
641
+ * - Authentication credentials
642
+ * - Configuration options
643
+ *
644
+ * Providers can be created from:
645
+ * - Platform + environment (uses known Timeback endpoints)
646
+ * - Explicit base URL (single URL for all services)
647
+ * - Per-service URLs (different URLs for each service)
648
+ *
649
+ * @example
650
+ * ```typescript
651
+ * // Environment-based provider (Timeback hosted)
652
+ * const provider = new TimebackProvider({
653
+ * platform: 'BEYOND_AI',
654
+ * env: 'staging',
655
+ * auth: { clientId: '...', clientSecret: '...' },
656
+ * })
657
+ * ```
658
+ *
659
+ * @example
660
+ * ```typescript
661
+ * // Explicit URL provider (self-hosted)
662
+ * const provider = new TimebackProvider({
663
+ * baseUrl: 'https://api.myschool.edu',
664
+ * authUrl: 'https://auth.myschool.edu/oauth/token',
665
+ * auth: { clientId: '...', clientSecret: '...' },
666
+ * })
667
+ * ```
668
+ *
669
+ * @example
670
+ * ```typescript
671
+ * // Per-service URLs
672
+ * const provider = new TimebackProvider({
673
+ * services: {
674
+ * oneroster: 'https://roster.myschool.edu',
675
+ * caliper: 'https://analytics.myschool.edu',
676
+ * },
677
+ * authUrl: 'https://auth.myschool.edu/oauth/token',
678
+ * auth: { clientId: '...', clientSecret: '...' },
679
+ * })
680
+ * ```
681
+ */
682
+ declare class TimebackProvider {
683
+ /** Platform identifier (if using known platform) */
684
+ readonly platform?: Platform;
685
+ /** Environment (if using known platform) */
686
+ readonly env?: Environment;
687
+ /** OAuth2 credentials. Undefined for public/no-auth services. */
688
+ readonly auth?: ProviderAuth;
689
+ /** Request timeout in milliseconds */
690
+ readonly timeout: number;
691
+ /** Resolved endpoints for each service */
692
+ /** @internal */
693
+ readonly _endpoints: Partial<Record<ServiceName, ResolvedEndpoint>>;
694
+ /** Token URL for authentication. Undefined for public/no-auth services. */
695
+ /** @internal */
696
+ readonly _authUrl?: string;
697
+ /** OAuth2 scope to request with access tokens. */
698
+ /** @internal */
699
+ readonly _tokenScope?: string;
700
+ /** API path profiles for this platform */
701
+ /** @internal */
702
+ readonly _pathProfiles: PlatformPaths;
703
+ /** Cached TokenManagers by authUrl (for token sharing) */
704
+ /** @internal */
705
+ readonly _tokenManagers: Map<string, TokenProvider>;
706
+ /**
707
+ * Create a new TimebackProvider.
708
+ *
709
+ * @param config - Provider configuration (env-based, explicit URL, or per-service)
710
+ * @throws {Error} If configuration is invalid or missing required fields
711
+ */
712
+ constructor(config: TimebackProviderConfig);
713
+ /**
714
+ * Get the resolved endpoint for a specific service.
715
+ *
716
+ * @param service - Service name (oneroster, caliper, edubridge, qti, powerpath)
717
+ * @returns Resolved endpoint with baseUrl and authUrl
718
+ * @throws If the service is not configured in this provider
719
+ */
720
+ getEndpoint(service: ServiceName): ResolvedEndpoint;
721
+ /**
722
+ * Check if a service is available in this provider.
723
+ *
724
+ * @param service - Service name to check
725
+ * @returns True if the service is configured
726
+ */
727
+ hasService(service: ServiceName): boolean;
728
+ /**
729
+ * Get all configured service names.
730
+ *
731
+ * @returns Array of service names available in this provider
732
+ */
733
+ getAvailableServices(): ServiceName[];
734
+ /**
735
+ * Get the token URL for this provider.
736
+ * @returns The token URL for authentication
737
+ */
738
+ getTokenUrl(): string | undefined;
739
+ /**
740
+ * Get endpoint with paths for a service that has path configuration.
741
+ *
742
+ * @param service - Service name that has paths in PlatformPaths
743
+ * @returns Resolved endpoint with baseUrl, authUrl, and paths
744
+ * @throws If service is not configured or not supported on this platform
745
+ */
746
+ getEndpointWithPaths<S extends PathEnabledService>(service: S & ServiceName): ResolvedEndpoint & {
747
+ paths: NonNullable<PlatformPaths[S]>;
748
+ };
749
+ /**
750
+ * Get all path profiles for this provider (raw, may contain nulls).
751
+ *
752
+ * @returns Platform path profiles
753
+ */
754
+ getPaths(): PlatformPaths;
755
+ /**
756
+ * Get paths for a specific service.
757
+ *
758
+ * @param service - Service name
759
+ * @returns Path configuration for the service
760
+ * @throws If the service is not supported on this platform
761
+ */
762
+ getServicePaths<S extends PathEnabledService>(service: S): NonNullable<PlatformPaths[S]>;
763
+ /**
764
+ * Check if a service is supported on this platform.
765
+ *
766
+ * @param service - Service name
767
+ * @returns true if the service has path configuration
768
+ */
769
+ hasServiceSupport(service: PathEnabledService): boolean;
770
+ /**
771
+ * Get a TokenProvider for a specific service.
772
+ *
773
+ * TokenProviders are cached by authUrl, so services sharing the same
774
+ * token endpoint will share the same cached OAuth tokens.
775
+ *
776
+ * @param service - Service name (oneroster, caliper, edubridge, qti, powerpath)
777
+ * @returns Cached TokenProvider for the service's token endpoint, or undefined for public/no-auth services
778
+ * @throws If the service is not configured in this provider
779
+ * @throws If auth is required but not configured
780
+ */
781
+ getTokenProvider(service: ServiceName): TokenProvider | undefined;
782
+ /**
783
+ * Verify that OAuth authentication is working.
784
+ *
785
+ * Attempts to acquire a token using the provider's credentials.
786
+ * Returns a health check result with success/failure and latency info.
787
+ *
788
+ * @returns Auth check result
789
+ * @throws {Error} If no auth is configured on this provider
790
+ */
791
+ checkAuth(): Promise<AuthCheckResult$1>;
792
+ /**
793
+ * Invalidate all cached OAuth tokens.
794
+ *
795
+ * Call this when closing the client or when tokens need to be refreshed.
796
+ * New tokens will be acquired on the next API call.
797
+ */
798
+ invalidateTokens(): void;
799
+ }
86
800
 
87
- // ═══════════════════════════════════════════════════════════════════════════════
88
- // ENTITIES
89
- // ═══════════════════════════════════════════════════════════════════════════════
801
+ /**
802
+ * Transport Types
803
+ *
804
+ * Types for HTTP transport layer.
805
+ */
90
806
 
91
- /** A registered webhook */
92
- interface Webhook {
93
- /** Unique webhook identifier (UUID) */
94
- id: string
95
- /** Associated sensor identifier, null if not scoped to a sensor */
96
- sensor: string | null
97
- /** Human-readable webhook name */
98
- name: string
99
- /** Optional webhook description */
100
- description: string | null
101
- /** Destination URL that receives event payloads */
102
- targetUrl: string
103
- /** Shared secret used to sign webhook payloads */
104
- secret: string
105
- /** Whether the webhook is currently active */
106
- active: boolean
107
- /** ISO 8601 creation timestamp */
108
- created_at: string | null
109
- /** ISO 8601 last update timestamp */
110
- updated_at: string | null
111
- /** ISO 8601 soft-delete timestamp, null if not deleted */
112
- deleted_at: string | null
807
+ /**
808
+ * Fetch function signature for HTTP requests.
809
+ * Avoids Bun-specific extensions on `typeof fetch`.
810
+ */
811
+ type FetchFn = (input: string | URL | Request, init?: RequestInit) => Promise<Response>;
812
+ /**
813
+ * HTTP request options.
814
+ */
815
+ interface RequestOptions {
816
+ /** HTTP method */
817
+ method?: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
818
+ /** Query parameters to append to the URL */
819
+ params?: Record<string, string | number | boolean | undefined>;
820
+ /** Request body (will be JSON-serialized) */
821
+ body?: unknown;
822
+ /** Additional headers to include */
823
+ headers?: Record<string, string>;
824
+ /**
825
+ * Unique identifier for this request.
826
+ * Used for log correlation and debugging.
827
+ * Auto-generated if not provided.
828
+ */
829
+ requestId?: string;
113
830
  }
114
-
115
- /** A filter attached to a webhook that controls which events trigger delivery */
116
- interface WebhookFilter {
117
- /** Unique filter identifier (UUID) */
118
- id: string
119
- /** UUID of the parent webhook */
120
- webhookId: string
121
- /** Event field to filter on (e.g., 'type', 'action') */
122
- filterKey: string
123
- /** Value to compare against */
124
- filterValue: string
125
- /** Data type of the filter value */
126
- filterType: FilterType
127
- /** Comparison operator */
128
- filterOperator: FilterOperation
129
- /** Whether the filter is currently active */
130
- active: boolean
131
- /** ISO 8601 creation timestamp */
132
- created_at: string | null
133
- /** ISO 8601 last update timestamp */
134
- updated_at: string | null
135
- /** ISO 8601 soft-delete timestamp, null if not deleted */
136
- deleted_at: string | null
831
+ /**
832
+ * Auth credentials for environment mode.
833
+ * Token URL is derived automatically from environment.
834
+ */
835
+ interface EnvAuth {
836
+ clientId: string;
837
+ clientSecret: string;
137
838
  }
138
-
139
- /** Response for DELETE /webhooks/:id */
140
- interface WebhookDeleteResponse {
141
- message: string
839
+ /**
840
+ * Auth credentials for explicit mode.
841
+ * Requires explicit authUrl for custom APIs.
842
+ */
843
+ interface ExplicitAuth {
844
+ clientId: string;
845
+ clientSecret: string;
846
+ authUrl: string;
847
+ }
848
+ /**
849
+ * Base configuration options shared by all modes.
850
+ */
851
+ interface BaseConfig {
852
+ /** Request timeout in milliseconds */
853
+ timeout?: number;
854
+ /** Custom fetch implementation */
855
+ fetch?: FetchFn;
856
+ }
857
+ /**
858
+ * Internal resolved transport configuration.
859
+ */
860
+ interface ResolvedTransportConfig {
861
+ /** Base URL of the API */
862
+ baseUrl: string;
863
+ /** Request timeout in milliseconds */
864
+ timeout: number;
865
+ /** Fetch implementation */
866
+ fetch: FetchFn;
867
+ /** Token provider for authentication. Undefined for public/no-auth services. */
868
+ tokenProvider?: TokenProvider;
869
+ }
870
+ /**
871
+ * Transport configuration with explicit auth.
872
+ */
873
+ interface TransportConfigWithAuth extends BaseConfig {
874
+ baseUrl: string;
875
+ auth: ExplicitAuth;
876
+ tokenProvider?: never;
877
+ }
878
+ /**
879
+ * Transport configuration with shared token provider.
880
+ */
881
+ interface TransportConfigWithTokenProvider extends BaseConfig {
882
+ baseUrl: string;
883
+ tokenProvider: TokenProvider;
884
+ auth?: never;
885
+ }
886
+ /**
887
+ * Transport configuration for public/no-auth services.
888
+ */
889
+ interface TransportConfigNoAuth extends BaseConfig {
890
+ baseUrl: string;
891
+ auth?: never;
892
+ tokenProvider?: never;
893
+ }
894
+ /**
895
+ * Configuration for BaseTransport.
896
+ */
897
+ type BaseTransportConfig = TransportConfigWithAuth | TransportConfigWithTokenProvider | TransportConfigNoAuth;
898
+ /**
899
+ * Options for creating a BaseTransport.
900
+ */
901
+ interface BaseTransportOptions {
902
+ /** Transport configuration */
903
+ config: BaseTransportConfig;
904
+ /** Logger instance for request/response logging */
905
+ logger: Logger;
906
+ }
907
+ /**
908
+ * Result of an auth check operation.
909
+ */
910
+ interface AuthCheckResult {
911
+ /** Whether auth succeeded */
912
+ ok: boolean;
913
+ /** Time taken to complete the check (ms) */
914
+ latencyMs: number;
915
+ /** Error message if failed */
916
+ error?: string;
917
+ /** Detailed check results */
918
+ checks: {
919
+ /** Token acquisition succeeded */
920
+ tokenAcquisition: boolean;
921
+ };
142
922
  }
143
923
 
144
- /** Response for DELETE /webhook-filters/:id */
145
- interface WebhookFilterDeleteResponse {
146
- message: string
924
+ /**
925
+ * Base Transport Layer
926
+ *
927
+ * HTTP transport with OAuth2 authentication, retries, and error handling.
928
+ * Clients can extend this for protocol-specific features.
929
+ *
930
+ */
931
+ /**
932
+ * Base HTTP transport layer for API communication.
933
+ *
934
+ * Handles OAuth2 authentication, request/response lifecycle,
935
+ * and automatic retries for transient failures.
936
+ *
937
+ * Clients can extend this class to add protocol-specific features
938
+ * like custom error parsing or pagination.
939
+ */
940
+ declare class BaseTransport {
941
+ protected readonly config: ResolvedTransportConfig;
942
+ protected readonly log: Logger;
943
+ /**
944
+ * Create a new BaseTransport instance.
945
+ *
946
+ * @param options - Transport options with config and logger
947
+ */
948
+ constructor(options: BaseTransportOptions);
949
+ /**
950
+ * The base URL for API requests.
951
+ * @returns The base URL
952
+ */
953
+ get baseUrl(): string;
954
+ /**
955
+ * Make an authenticated request to the API.
956
+ *
957
+ * Automatically retries on transient failures (429, 503).
958
+ *
959
+ * @template T - Expected response type
960
+ * @param path - API endpoint path
961
+ * @param options - Request options including method, params, body
962
+ * @returns Parsed JSON response
963
+ * @throws {ApiError} On API errors (4xx/5xx responses)
964
+ */
965
+ request<T>(path: string, options?: RequestOptions): Promise<T>;
966
+ /**
967
+ * Check whether a resource exists at the given path.
968
+ *
969
+ * Returns `true` for successful 2xx responses, `false` only for 404 Not Found,
970
+ * and rethrows all other errors.
971
+ *
972
+ * @param path - API endpoint path
973
+ * @param options - Request options including method, params, body
974
+ * @returns Promise resolving to whether the resource exists
975
+ */
976
+ exists(path: string, options?: RequestOptions): Promise<boolean>;
977
+ /**
978
+ * Make a raw request, returning the Response object.
979
+ *
980
+ * ## Retry Behavior
981
+ * Automatically retries on transient failures (429, 503) with exponential
982
+ * backoff. Respects Retry-After header when present.
983
+ *
984
+ * ## Timeout Behavior
985
+ * Uses an operation-level timeout that spans ALL retry attempts.
986
+ * If configured timeout is 30s, the entire operation (including retries
987
+ * and backoff delays) must complete within 30s total.
988
+ *
989
+ * ## Flow
990
+ * 1. Build URL from path and query params
991
+ * 2. Start operation timer
992
+ * 3. Loop up to MAX_RETRIES times:
993
+ * a. Check if we've exceeded the operation deadline
994
+ * b. Get OAuth token (may be cached)
995
+ * c. Make the HTTP request with per-request timeout
996
+ * d. If 429/503 and not last attempt → calculate backoff and retry
997
+ * e. If other error → throw appropriate ApiError subclass
998
+ * f. If success → return response
999
+ * 4. If all retries exhausted → throw "Max retries exceeded"
1000
+ *
1001
+ * @param path - API endpoint path (relative to baseUrl)
1002
+ * @param options - Request options (method, params, body, headers)
1003
+ * @returns Raw fetch Response for custom handling
1004
+ * @throws {ApiError} On timeout, non-retryable errors, or max retries exceeded
1005
+ */
1006
+ requestRaw(path: string, options?: RequestOptions): Promise<Response>;
1007
+ /**
1008
+ * Get a valid OAuth2 access token.
1009
+ * @returns Promise resolving to access token or undefined
1010
+ */
1011
+ protected getAccessToken(): Promise<string | undefined>;
1012
+ /**
1013
+ * Construct full URL with query parameters.
1014
+ *
1015
+ * @param path - The relative path or absolute URL
1016
+ * @param params - Query parameters
1017
+ * @returns Full URL string
1018
+ * @throws {Error} If path is an absolute URL (security protection)
1019
+ */
1020
+ protected buildUrl(path: string, params?: Record<string, string | number | boolean | undefined>): string;
1021
+ /**
1022
+ * Parse successful response or delegate to error handler.
1023
+ * @param response - The fetch Response
1024
+ * @returns Parsed response as type T
1025
+ */
1026
+ protected handleResponse<T>(response: Response): Promise<T>;
1027
+ /**
1028
+ * Parse JSON response with context-preserving error handling.
1029
+ *
1030
+ * Unlike raw `response.json()`, this method:
1031
+ * - Logs structured error context (URL, status, content-type, body preview)
1032
+ * - Throws `ApiError` with `parseError` and `body` in the response object
1033
+ * - Aids debugging when upstream services return malformed JSON
1034
+ *
1035
+ * @template T - Expected shape of the parsed response
1036
+ * @param response - The fetch Response to parse
1037
+ * @returns Parsed JSON as type T
1038
+ * @throws {ApiError} When JSON parsing fails, with status code and body preview
1039
+ */
1040
+ protected parseJsonResponse<T>(response: Response): Promise<T>;
1041
+ /**
1042
+ * Parse error response and throw appropriate ApiError subclass.
1043
+ *
1044
+ * Handles both JSON and non-JSON error responses gracefully.
1045
+ * Clients can override this to add protocol-specific error parsing.
1046
+ *
1047
+ * @param response - The error Response (status >= 400)
1048
+ * @param requestId - Request ID for log correlation
1049
+ * @throws {UnauthorizedError} For 401 responses (also invalidates token)
1050
+ * @throws {ForbiddenError} For 403 responses
1051
+ * @throws {NotFoundError} For 404 responses
1052
+ * @throws {ValidationError} For 422 responses
1053
+ * @throws {ApiError} For all other error status codes
1054
+ */
1055
+ protected handleErrorResponse(response: Response, requestId?: string): Promise<never>;
1056
+ /**
1057
+ * Extract error message from response body.
1058
+ *
1059
+ * Checks common error formats:
1060
+ * - `message` (most APIs)
1061
+ * - `error` (some APIs)
1062
+ * - `imsx_description` (IMS Global: OneRoster, Caliper, QTI)
1063
+ *
1064
+ * Override in client transports for API-specific error formats
1065
+ * not covered here (e.g., Edubridge's `errors[]` array format).
1066
+ *
1067
+ * @param body - The error response body
1068
+ * @param fallback - Fallback message if none found
1069
+ * @returns Extracted error message
1070
+ */
1071
+ protected extractErrorMessage(body: unknown, fallback: string): string;
1072
+ /**
1073
+ * Delay execution for retry backoff.
1074
+ *
1075
+ * @param ms - Number of milliseconds to delay
1076
+ * @returns Promise that resolves after delay
1077
+ */
1078
+ protected sleep(ms: number): Promise<void>;
1079
+ /**
1080
+ * Parse Retry-After header value.
1081
+ *
1082
+ * Handles both formats per RFC 7231:
1083
+ * - Numeric seconds: "120"
1084
+ * - HTTP-date: "Wed, 21 Oct 2025 07:28:00 GMT"
1085
+ *
1086
+ * @param retryAfter - Retry-After header value
1087
+ * @param attempt - Current attempt number (0-based)
1088
+ * @returns Delay in milliseconds
1089
+ */
1090
+ protected parseRetryAfter(retryAfter: string | null, attempt: number): number;
147
1091
  }
148
1092
 
149
1093
  /**
@@ -467,11 +1411,11 @@ declare class WebhookFiltersResource {
467
1411
  declare const WebhooksClient: {
468
1412
  new (config?: WebhooksClientConfig): {
469
1413
  readonly transport: WebhooksTransportLike;
470
- readonly _provider?: _timeback_internal_client_infra.TimebackProvider | undefined;
1414
+ readonly _provider?: TimebackProvider | undefined;
471
1415
  readonly webhooks: WebhooksResource;
472
1416
  readonly webhookFilters: WebhookFiltersResource;
473
1417
  getTransport(): WebhooksTransportLike;
474
- checkAuth(): Promise<_timeback_internal_client_infra.AuthCheckResult>;
1418
+ checkAuth(): Promise<AuthCheckResult>;
475
1419
  };
476
1420
  };
477
1421
 
@@ -528,5 +1472,5 @@ declare class Transport extends BaseTransport {
528
1472
  constructor(config: WebhooksTransportConfig);
529
1473
  }
530
1474
 
531
- export { Transport, WebhookCreateInput, WebhookFilterCreateInput, WebhookFilterUpdateInput, WebhookUpdateInput, WebhooksClient, createWebhooksClient };
532
- export type { FilterOperation, FilterType, Webhook, WebhookFilter, WebhooksClientConfig, WebhooksClientInstance };
1475
+ export { Transport, WebhooksClient, createWebhooksClient };
1476
+ export type { AuthCheckResult, EnvAuth, Environment, ExplicitAuth, WebhooksClientConfig, WebhooksClientInstance };