@timeback/core 0.2.1 → 0.2.2-beta.20260320221119
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/{chunk-aw1d6bdn.js → chunk-2mkbbgd8.js} +1 -1
- package/dist/{chunk-2z9zawsc.js → chunk-bjb7ngh9.js} +210 -210
- package/dist/errors.d.ts +94 -4
- package/dist/errors.js +1 -1
- package/dist/index.d.ts +1350 -16
- package/dist/index.js +24 -6
- package/dist/qti.d.ts +1 -11
- package/dist/types.d.ts +704 -4
- package/dist/utils.d.ts +1 -8
- package/dist/utils.js +2 -2
- package/package.json +1 -1
- package/dist/client.d.ts +0 -228
- package/dist/client.d.ts.map +0 -1
- package/dist/constants.d.ts +0 -24
- package/dist/constants.d.ts.map +0 -1
- package/dist/errors.d.ts.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/lib/broadcast-results.d.ts +0 -20
- package/dist/lib/broadcast-results.d.ts.map +0 -1
- package/dist/manager.d.ts +0 -129
- package/dist/manager.d.ts.map +0 -1
- package/dist/qti.d.ts.map +0 -1
- package/dist/types/index.d.ts +0 -246
- package/dist/types/index.d.ts.map +0 -1
- package/dist/types.d.ts.map +0 -1
- package/dist/utils.d.ts.map +0 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,30 +1,1364 @@
|
|
|
1
|
+
import { CaliperClientInstance } from '@timeback/caliper';
|
|
2
|
+
import { CaseClientInstance } from '@timeback/case';
|
|
3
|
+
import { ClrClientInstance } from '@timeback/clr';
|
|
4
|
+
import { EdubridgeClientInstance } from '@timeback/edubridge';
|
|
5
|
+
import { OneRosterClientInstance } from '@timeback/oneroster';
|
|
6
|
+
import { PowerPathClientInstance } from '@timeback/powerpath';
|
|
7
|
+
import { QtiClientInstance } from '@timeback/qti';
|
|
8
|
+
import { ReportingClientInstance } from '@timeback/reporting';
|
|
9
|
+
import { WebhooksClientInstance } from '@timeback/webhooks';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Interface for obtaining OAuth2 access tokens.
|
|
13
|
+
*
|
|
14
|
+
* Implementations handle token caching and refresh automatically.
|
|
15
|
+
*/
|
|
16
|
+
interface TokenProvider {
|
|
17
|
+
/**
|
|
18
|
+
* Get a valid access token.
|
|
19
|
+
*
|
|
20
|
+
* Returns a cached token if still valid, otherwise fetches a new one.
|
|
21
|
+
*
|
|
22
|
+
* @returns A valid access token string
|
|
23
|
+
* @throws {Error} If token acquisition fails
|
|
24
|
+
*/
|
|
25
|
+
getToken(): Promise<string>;
|
|
26
|
+
/**
|
|
27
|
+
* Invalidate the cached token.
|
|
28
|
+
*
|
|
29
|
+
* Forces the next getToken() call to fetch a fresh token.
|
|
30
|
+
* Should be called when a request fails with 401 Unauthorized.
|
|
31
|
+
*
|
|
32
|
+
* Optional - not all implementations may support invalidation.
|
|
33
|
+
*/
|
|
34
|
+
invalidate?(): void;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* All supported platforms.
|
|
39
|
+
*/
|
|
40
|
+
declare const PLATFORMS$1: readonly ["BEYOND_AI", "LEARNWITH_AI"];
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Where Clause Types
|
|
44
|
+
*
|
|
45
|
+
* Type-safe object syntax for building filter expressions.
|
|
46
|
+
*/
|
|
47
|
+
/**
|
|
48
|
+
* Primitive value types that can be used in filters.
|
|
49
|
+
*/
|
|
50
|
+
type FilterValue = string | number | boolean | Date;
|
|
51
|
+
/**
|
|
52
|
+
* Operators for a single field.
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* ```typescript
|
|
56
|
+
* { status: { ne: 'deleted' } }
|
|
57
|
+
* { score: { gt: 90 } }
|
|
58
|
+
* { email: { contains: '@school.edu' } }
|
|
59
|
+
* { role: { in: ['teacher', 'aide'] } }
|
|
60
|
+
* ```
|
|
61
|
+
*/
|
|
62
|
+
interface FieldOperators<T> {
|
|
63
|
+
/** Not equal */
|
|
64
|
+
ne?: T;
|
|
65
|
+
/** Greater than */
|
|
66
|
+
gt?: T;
|
|
67
|
+
/** Greater than or equal */
|
|
68
|
+
gte?: T;
|
|
69
|
+
/** Less than */
|
|
70
|
+
lt?: T;
|
|
71
|
+
/** Less than or equal */
|
|
72
|
+
lte?: T;
|
|
73
|
+
/** Contains substring (strings only) */
|
|
74
|
+
contains?: T extends string ? string : never;
|
|
75
|
+
/** Match any of the values */
|
|
76
|
+
in?: T[];
|
|
77
|
+
/** Match none of the values */
|
|
78
|
+
notIn?: T[];
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* A field condition can be:
|
|
82
|
+
* - A direct value (implies equality)
|
|
83
|
+
* - An object with operators
|
|
84
|
+
*/
|
|
85
|
+
type FieldCondition<T> = T | FieldOperators<T>;
|
|
86
|
+
/**
|
|
87
|
+
* Map filter field types to field conditions.
|
|
88
|
+
*
|
|
89
|
+
* Each field in F becomes an optional filter condition.
|
|
90
|
+
*
|
|
91
|
+
* @typeParam F - Filter fields type (e.g., UserFilterFields)
|
|
92
|
+
*/
|
|
93
|
+
type FilterFields<F> = {
|
|
94
|
+
[K in keyof F]?: FieldCondition<F[K] & FilterValue>;
|
|
95
|
+
};
|
|
96
|
+
/**
|
|
97
|
+
* OR condition for combining multiple field conditions.
|
|
98
|
+
*/
|
|
99
|
+
interface OrCondition<F> {
|
|
100
|
+
OR: WhereClause<F>[];
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* A where clause for filtering entities.
|
|
104
|
+
*
|
|
105
|
+
* The type parameter F should be a filter fields type that defines
|
|
106
|
+
* the available fields and their value types for filtering.
|
|
107
|
+
*
|
|
108
|
+
* Multiple fields at the same level are combined with AND.
|
|
109
|
+
* Use `OR` for explicit OR logic.
|
|
110
|
+
*
|
|
111
|
+
* @typeParam F - Filter fields type (e.g., UserFilterFields)
|
|
112
|
+
*
|
|
113
|
+
* @example
|
|
114
|
+
* ```typescript
|
|
115
|
+
* // Simple equality (implicit AND)
|
|
116
|
+
* { status: 'active', role: 'teacher' }
|
|
117
|
+
* // → status='active' AND role='teacher'
|
|
118
|
+
* ```
|
|
119
|
+
*
|
|
120
|
+
* @example
|
|
121
|
+
* ```typescript
|
|
122
|
+
* // With operators
|
|
123
|
+
* { status: { ne: 'deleted' }, score: { gte: 90 } }
|
|
124
|
+
* // → status!='deleted' AND score>=90
|
|
125
|
+
* ```
|
|
126
|
+
*
|
|
127
|
+
* @example
|
|
128
|
+
* ```typescript
|
|
129
|
+
* // OR condition
|
|
130
|
+
* { OR: [{ role: 'teacher' }, { role: 'aide' }] }
|
|
131
|
+
* // → role='teacher' OR role='aide'
|
|
132
|
+
* ```
|
|
133
|
+
*
|
|
134
|
+
* @example
|
|
135
|
+
* ```typescript
|
|
136
|
+
* // Match multiple values
|
|
137
|
+
* { role: { in: ['teacher', 'aide'] } }
|
|
138
|
+
* // → role='teacher' OR role='aide'
|
|
139
|
+
* ```
|
|
140
|
+
*/
|
|
141
|
+
type WhereClause<F> = FilterFields<F> | OrCondition<F>;
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Where Clause to Filter String Conversion
|
|
145
|
+
*
|
|
146
|
+
* Converts type-safe where clause objects to OneRoster-compatible filter strings.
|
|
147
|
+
*/
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Converts a type-safe WhereClause to a OneRoster-compatible filter string.
|
|
151
|
+
*
|
|
152
|
+
* This is the primary function for converting the object-based filter syntax
|
|
153
|
+
* to the string format expected by the OneRoster API.
|
|
154
|
+
*
|
|
155
|
+
* @typeParam T - Entity type being filtered
|
|
156
|
+
* @param where - The where clause object
|
|
157
|
+
* @returns The filter string, or `undefined` if the clause is empty
|
|
158
|
+
*
|
|
159
|
+
* @example
|
|
160
|
+
* ```typescript
|
|
161
|
+
* // Simple equality
|
|
162
|
+
* whereToFilter({ status: 'active' })
|
|
163
|
+
* // → "status='active'"
|
|
164
|
+
* ```
|
|
165
|
+
*
|
|
166
|
+
* @example
|
|
167
|
+
* ```typescript
|
|
168
|
+
* // Multiple fields (implicit AND)
|
|
169
|
+
* whereToFilter({ status: 'active', role: 'teacher' })
|
|
170
|
+
* // → "status='active' AND role='teacher'"
|
|
171
|
+
* ```
|
|
172
|
+
*
|
|
173
|
+
* @example
|
|
174
|
+
* ```typescript
|
|
175
|
+
* // Comparison operators
|
|
176
|
+
* whereToFilter({ score: { gte: 90, lte: 100 } })
|
|
177
|
+
* // → "score>=90 AND score<=100"
|
|
178
|
+
* ```
|
|
179
|
+
*
|
|
180
|
+
* @example
|
|
181
|
+
* ```typescript
|
|
182
|
+
* // Not equal
|
|
183
|
+
* whereToFilter({ status: { ne: 'deleted' } })
|
|
184
|
+
* // → "status!='deleted'"
|
|
185
|
+
* ```
|
|
186
|
+
*
|
|
187
|
+
* @example
|
|
188
|
+
* ```typescript
|
|
189
|
+
* // Contains (substring match)
|
|
190
|
+
* whereToFilter({ email: { contains: '@school.edu' } })
|
|
191
|
+
* // → "email~'@school.edu'"
|
|
192
|
+
* ```
|
|
193
|
+
*
|
|
194
|
+
* @example
|
|
195
|
+
* ```typescript
|
|
196
|
+
* // Match any value (OR)
|
|
197
|
+
* whereToFilter({ role: { in: ['teacher', 'aide'] } })
|
|
198
|
+
* // → "role='teacher' OR role='aide'"
|
|
199
|
+
* ```
|
|
200
|
+
*
|
|
201
|
+
* @example
|
|
202
|
+
* ```typescript
|
|
203
|
+
* // Explicit OR across fields
|
|
204
|
+
* whereToFilter({ OR: [{ role: 'teacher' }, { status: 'active' }] })
|
|
205
|
+
* // → "role='teacher' OR status='active'"
|
|
206
|
+
* ```
|
|
207
|
+
*/
|
|
208
|
+
declare function whereToFilter<T>(where: WhereClause<T>): string | undefined;
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Shared Types
|
|
212
|
+
*
|
|
213
|
+
* Common types for API client infrastructure.
|
|
214
|
+
*/
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Result of an auth check operation.
|
|
218
|
+
*/
|
|
219
|
+
interface AuthCheckResult$1 {
|
|
220
|
+
/** Whether auth succeeded */
|
|
221
|
+
ok: boolean;
|
|
222
|
+
/** Time taken to complete the check (ms) */
|
|
223
|
+
latencyMs: number;
|
|
224
|
+
/** Error message if failed */
|
|
225
|
+
error?: string;
|
|
226
|
+
/** Detailed check results */
|
|
227
|
+
checks: {
|
|
228
|
+
/** Token acquisition succeeded */
|
|
229
|
+
tokenAcquisition: boolean;
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Config Types
|
|
235
|
+
*
|
|
236
|
+
* Types for TimebackProvider and provider resolution.
|
|
237
|
+
*/
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Caliper API path profile.
|
|
241
|
+
* Defines paths for Caliper operations. Use `null` for unsupported operations.
|
|
242
|
+
*/
|
|
243
|
+
interface CaliperPaths {
|
|
244
|
+
/** Path for sending events (POST) */
|
|
245
|
+
send: string;
|
|
246
|
+
/** Path for validating events (POST), null if not supported */
|
|
247
|
+
validate: string | null;
|
|
248
|
+
/** Path for listing events (GET), null if not supported */
|
|
249
|
+
list: string | null;
|
|
250
|
+
/** Path template for getting single event (GET), use {id} placeholder */
|
|
251
|
+
get: string | null;
|
|
252
|
+
/** Path template for job status (GET), use {id} placeholder */
|
|
253
|
+
jobStatus: string | null;
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* Webhook API path profile.
|
|
257
|
+
* Defines paths for webhook management operations.
|
|
258
|
+
* Nullability is at the platform level (`webhooks: WebhookPaths | null` in PlatformPaths).
|
|
259
|
+
*/
|
|
260
|
+
interface WebhookPaths {
|
|
261
|
+
/** Path for listing webhooks (GET) */
|
|
262
|
+
webhookList: string;
|
|
263
|
+
/** Path template for getting a single webhook (GET), use {id} placeholder */
|
|
264
|
+
webhookGet: string;
|
|
265
|
+
/** Path for creating a webhook (POST) */
|
|
266
|
+
webhookCreate: string;
|
|
267
|
+
/** Path template for updating a webhook (PUT), use {id} placeholder */
|
|
268
|
+
webhookUpdate: string;
|
|
269
|
+
/** Path template for deleting a webhook (DELETE), use {id} placeholder */
|
|
270
|
+
webhookDelete: string;
|
|
271
|
+
/** Path template for activating a webhook (PUT), use {id} placeholder */
|
|
272
|
+
webhookActivate: string;
|
|
273
|
+
/** Path template for deactivating a webhook (PUT), use {id} placeholder */
|
|
274
|
+
webhookDeactivate: string;
|
|
275
|
+
/** Path for listing all webhook filters (GET) */
|
|
276
|
+
webhookFilterList: string;
|
|
277
|
+
/** Path template for getting a single webhook filter (GET), use {id} placeholder */
|
|
278
|
+
webhookFilterGet: string;
|
|
279
|
+
/** Path for creating a webhook filter (POST) */
|
|
280
|
+
webhookFilterCreate: string;
|
|
281
|
+
/** Path template for updating a webhook filter (PUT), use {id} placeholder */
|
|
282
|
+
webhookFilterUpdate: string;
|
|
283
|
+
/** Path template for deleting a webhook filter (DELETE), use {id} placeholder */
|
|
284
|
+
webhookFilterDelete: string;
|
|
285
|
+
/** Path template for listing filters by webhook (GET), use {webhookId} placeholder */
|
|
286
|
+
webhookFiltersByWebhook: string;
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
289
|
+
* Reporting API path profile.
|
|
290
|
+
* Defines paths for reporting MCP and REST operations.
|
|
291
|
+
* Nullability is at the platform level (`reporting: ReportingPaths | null` in PlatformPaths).
|
|
292
|
+
*/
|
|
293
|
+
interface ReportingPaths {
|
|
294
|
+
/** Path for the reporting MCP JSON-RPC endpoint (POST) */
|
|
295
|
+
mcp: string;
|
|
296
|
+
/** Path template for executing a saved query (GET), use {id} placeholder */
|
|
297
|
+
savedQueryExecute: string;
|
|
298
|
+
/** Path template for checking reporting group membership (GET), use {email} placeholder */
|
|
299
|
+
adminGroupCheck: string;
|
|
300
|
+
/** Path template for adding a user to the reporting group (POST), use {email} placeholder */
|
|
301
|
+
adminGroupAdd: string;
|
|
302
|
+
/** Path template for removing a user from the reporting group (DELETE), use {email} placeholder */
|
|
303
|
+
adminGroupRemove: string;
|
|
304
|
+
}
|
|
305
|
+
/**
|
|
306
|
+
* OneRoster API path profile.
|
|
307
|
+
* Defines the base path prefix for all OneRoster resources.
|
|
308
|
+
*/
|
|
309
|
+
interface OneRosterPaths {
|
|
310
|
+
/** Base path prefix for rostering resources (users, schools, classes, etc.) */
|
|
311
|
+
rostering: string;
|
|
312
|
+
/** Base path prefix for gradebook resources (lineItems, results, etc.) */
|
|
313
|
+
gradebook: string;
|
|
314
|
+
/** Base path prefix for resources API (digital learning resources) */
|
|
315
|
+
resources: string;
|
|
316
|
+
}
|
|
317
|
+
/**
|
|
318
|
+
* Edubridge API path profile.
|
|
319
|
+
* Defines path prefixes for Edubridge operations.
|
|
320
|
+
*/
|
|
321
|
+
interface EdubridgePaths {
|
|
322
|
+
/** Base path prefix for all Edubridge resources */
|
|
323
|
+
base: string;
|
|
324
|
+
}
|
|
325
|
+
/**
|
|
326
|
+
* PowerPath API path profile.
|
|
327
|
+
* Defines path prefixes for PowerPath operations.
|
|
328
|
+
*/
|
|
329
|
+
interface PowerPathPaths {
|
|
330
|
+
/** Base path prefix for all PowerPath resources */
|
|
331
|
+
base: string;
|
|
332
|
+
}
|
|
333
|
+
/**
|
|
334
|
+
* CASE API path profile.
|
|
335
|
+
* Defines path prefix for CASE (Competency and Academic Standards Exchange) operations.
|
|
336
|
+
*/
|
|
337
|
+
interface CasePaths {
|
|
338
|
+
/** Base path prefix for all CASE resources */
|
|
339
|
+
base: string;
|
|
340
|
+
}
|
|
341
|
+
/**
|
|
342
|
+
* CLR API path profile.
|
|
343
|
+
* Defines path prefixes for CLR (Comprehensive Learner Record) operations.
|
|
344
|
+
*/
|
|
345
|
+
interface ClrPaths {
|
|
346
|
+
/** Path for upserting CLR credentials (POST) */
|
|
347
|
+
credentials: string;
|
|
348
|
+
/** Path for API discovery (GET) */
|
|
349
|
+
discovery: string;
|
|
350
|
+
}
|
|
351
|
+
/**
|
|
352
|
+
* Platform path profiles for all services.
|
|
353
|
+
* Use `null` to indicate a service is not supported on the platform.
|
|
354
|
+
*/
|
|
355
|
+
interface PlatformPaths {
|
|
356
|
+
caliper: CaliperPaths;
|
|
357
|
+
oneroster: OneRosterPaths;
|
|
358
|
+
webhooks: WebhookPaths | null;
|
|
359
|
+
reporting: ReportingPaths | null;
|
|
360
|
+
edubridge: EdubridgePaths | null;
|
|
361
|
+
powerpath: PowerPathPaths | null;
|
|
362
|
+
clr: ClrPaths | null;
|
|
363
|
+
case: CasePaths | null;
|
|
364
|
+
}
|
|
365
|
+
/**
|
|
366
|
+
* Services that have path configuration.
|
|
367
|
+
* Subset of ServiceName - excludes services without path profiles (e.g., 'qti').
|
|
368
|
+
*/
|
|
369
|
+
type PathEnabledService = keyof PlatformPaths;
|
|
370
|
+
/**
|
|
371
|
+
* Supported Timeback platform implementations.
|
|
372
|
+
*/
|
|
373
|
+
type Platform$1 = (typeof PLATFORMS$1)[number];
|
|
374
|
+
/**
|
|
375
|
+
* Supported deployment environments.
|
|
376
|
+
*/
|
|
377
|
+
type Environment$1 = 'staging' | 'production';
|
|
378
|
+
/**
|
|
379
|
+
* Supported service names.
|
|
380
|
+
*/
|
|
381
|
+
type ServiceName = 'oneroster' | 'caliper' | 'webhooks' | 'reporting' | 'edubridge' | 'qti' | 'powerpath' | 'clr' | 'case';
|
|
382
|
+
/**
|
|
383
|
+
* Resolved endpoint for a single service.
|
|
384
|
+
*/
|
|
385
|
+
interface ResolvedEndpoint {
|
|
386
|
+
/** Base URL for the service API */
|
|
387
|
+
baseUrl: string;
|
|
388
|
+
/** OAuth2 token URL for this endpoint. Undefined for public/no-auth services. */
|
|
389
|
+
authUrl?: string;
|
|
390
|
+
}
|
|
391
|
+
/**
|
|
392
|
+
* Auth credentials for a provider.
|
|
393
|
+
*/
|
|
394
|
+
interface ProviderAuth {
|
|
395
|
+
clientId: string;
|
|
396
|
+
clientSecret: string;
|
|
397
|
+
}
|
|
398
|
+
/**
|
|
399
|
+
* Configuration for environment-based provider.
|
|
400
|
+
* Uses known Timeback platform endpoints.
|
|
401
|
+
*/
|
|
402
|
+
interface ProviderEnvConfig {
|
|
403
|
+
/** Timeback platform (defaults to 'BEYOND_AI') */
|
|
404
|
+
platform?: Platform$1;
|
|
405
|
+
/** Target environment */
|
|
406
|
+
env: Environment$1;
|
|
407
|
+
/** OAuth2 credentials */
|
|
408
|
+
auth: ProviderAuth;
|
|
409
|
+
/** Request timeout in milliseconds */
|
|
410
|
+
timeout?: number;
|
|
411
|
+
}
|
|
412
|
+
/**
|
|
413
|
+
* Configuration for explicit URL provider.
|
|
414
|
+
* Single base URL for all services.
|
|
415
|
+
*/
|
|
416
|
+
interface ProviderExplicitConfig {
|
|
417
|
+
/** Base URL for all services */
|
|
418
|
+
baseUrl: string;
|
|
419
|
+
/** OAuth2 token URL. Omit for public/no-auth services. */
|
|
420
|
+
authUrl?: string;
|
|
421
|
+
/** OAuth2 credentials. Required if authUrl is provided. */
|
|
422
|
+
auth?: ProviderAuth;
|
|
423
|
+
/** Request timeout in milliseconds */
|
|
424
|
+
timeout?: number;
|
|
425
|
+
/**
|
|
426
|
+
* Use a built-in path profile by name.
|
|
427
|
+
* Defaults to 'BEYOND_AI' if neither pathProfile nor paths is specified.
|
|
428
|
+
*/
|
|
429
|
+
pathProfile?: Platform$1;
|
|
430
|
+
/** Custom path overrides (takes precedence over pathProfile) */
|
|
431
|
+
paths?: Partial<PlatformPaths>;
|
|
432
|
+
}
|
|
433
|
+
/**
|
|
434
|
+
* Configuration for multi-service provider.
|
|
435
|
+
* Different URLs for different services.
|
|
436
|
+
*/
|
|
437
|
+
interface ProviderServicesConfig {
|
|
438
|
+
/** Per-service base URLs */
|
|
439
|
+
services: Partial<Record<ServiceName, string>>;
|
|
440
|
+
/** OAuth2 token URL. Omit for public/no-auth services. */
|
|
441
|
+
authUrl?: string;
|
|
442
|
+
/** OAuth2 credentials. Required if authUrl is provided. */
|
|
443
|
+
auth?: ProviderAuth;
|
|
444
|
+
/** Request timeout in milliseconds */
|
|
445
|
+
timeout?: number;
|
|
446
|
+
/**
|
|
447
|
+
* Use a built-in path profile by name.
|
|
448
|
+
* Defaults to 'BEYOND_AI' if neither pathProfile nor paths is specified.
|
|
449
|
+
*/
|
|
450
|
+
pathProfile?: Platform$1;
|
|
451
|
+
/** Custom path overrides (takes precedence over pathProfile) */
|
|
452
|
+
paths?: Partial<PlatformPaths>;
|
|
453
|
+
}
|
|
454
|
+
/**
|
|
455
|
+
* Union of all provider configuration types.
|
|
456
|
+
*/
|
|
457
|
+
type TimebackProviderConfig = ProviderEnvConfig | ProviderExplicitConfig | ProviderServicesConfig;
|
|
458
|
+
|
|
459
|
+
/**
|
|
460
|
+
* Timeback Provider
|
|
461
|
+
*
|
|
462
|
+
* Encapsulates platform connection configuration including endpoints and auth.
|
|
463
|
+
* Providers are complete "connection" objects that clients consume.
|
|
464
|
+
*/
|
|
465
|
+
|
|
466
|
+
/**
|
|
467
|
+
* Timeback Provider - encapsulates a complete platform connection.
|
|
468
|
+
*
|
|
469
|
+
* A provider contains everything needed to connect to Timeback APIs:
|
|
470
|
+
* - Service endpoints (URLs)
|
|
471
|
+
* - Authentication credentials
|
|
472
|
+
* - Configuration options
|
|
473
|
+
*
|
|
474
|
+
* Providers can be created from:
|
|
475
|
+
* - Platform + environment (uses known Timeback endpoints)
|
|
476
|
+
* - Explicit base URL (single URL for all services)
|
|
477
|
+
* - Per-service URLs (different URLs for each service)
|
|
478
|
+
*
|
|
479
|
+
* @example
|
|
480
|
+
* ```typescript
|
|
481
|
+
* // Environment-based provider (Timeback hosted)
|
|
482
|
+
* const provider = new TimebackProvider({
|
|
483
|
+
* platform: 'BEYOND_AI',
|
|
484
|
+
* env: 'staging',
|
|
485
|
+
* auth: { clientId: '...', clientSecret: '...' },
|
|
486
|
+
* })
|
|
487
|
+
* ```
|
|
488
|
+
*
|
|
489
|
+
* @example
|
|
490
|
+
* ```typescript
|
|
491
|
+
* // Explicit URL provider (self-hosted)
|
|
492
|
+
* const provider = new TimebackProvider({
|
|
493
|
+
* baseUrl: 'https://api.myschool.edu',
|
|
494
|
+
* authUrl: 'https://auth.myschool.edu/oauth/token',
|
|
495
|
+
* auth: { clientId: '...', clientSecret: '...' },
|
|
496
|
+
* })
|
|
497
|
+
* ```
|
|
498
|
+
*
|
|
499
|
+
* @example
|
|
500
|
+
* ```typescript
|
|
501
|
+
* // Per-service URLs
|
|
502
|
+
* const provider = new TimebackProvider({
|
|
503
|
+
* services: {
|
|
504
|
+
* oneroster: 'https://roster.myschool.edu',
|
|
505
|
+
* caliper: 'https://analytics.myschool.edu',
|
|
506
|
+
* },
|
|
507
|
+
* authUrl: 'https://auth.myschool.edu/oauth/token',
|
|
508
|
+
* auth: { clientId: '...', clientSecret: '...' },
|
|
509
|
+
* })
|
|
510
|
+
* ```
|
|
511
|
+
*/
|
|
512
|
+
declare class TimebackProvider {
|
|
513
|
+
/** Platform identifier (if using known platform) */
|
|
514
|
+
readonly platform?: Platform$1;
|
|
515
|
+
/** Environment (if using known platform) */
|
|
516
|
+
readonly env?: Environment$1;
|
|
517
|
+
/** OAuth2 credentials. Undefined for public/no-auth services. */
|
|
518
|
+
readonly auth?: ProviderAuth;
|
|
519
|
+
/** Request timeout in milliseconds */
|
|
520
|
+
readonly timeout: number;
|
|
521
|
+
/** Resolved endpoints for each service */
|
|
522
|
+
/** @internal */
|
|
523
|
+
readonly _endpoints: Partial<Record<ServiceName, ResolvedEndpoint>>;
|
|
524
|
+
/** Token URL for authentication. Undefined for public/no-auth services. */
|
|
525
|
+
/** @internal */
|
|
526
|
+
readonly _authUrl?: string;
|
|
527
|
+
/** OAuth2 scope to request with access tokens. */
|
|
528
|
+
/** @internal */
|
|
529
|
+
readonly _tokenScope?: string;
|
|
530
|
+
/** API path profiles for this platform */
|
|
531
|
+
/** @internal */
|
|
532
|
+
readonly _pathProfiles: PlatformPaths;
|
|
533
|
+
/** Cached TokenManagers by authUrl (for token sharing) */
|
|
534
|
+
/** @internal */
|
|
535
|
+
readonly _tokenManagers: Map<string, TokenProvider>;
|
|
536
|
+
/**
|
|
537
|
+
* Create a new TimebackProvider.
|
|
538
|
+
*
|
|
539
|
+
* @param config - Provider configuration (env-based, explicit URL, or per-service)
|
|
540
|
+
* @throws {Error} If configuration is invalid or missing required fields
|
|
541
|
+
*/
|
|
542
|
+
constructor(config: TimebackProviderConfig);
|
|
543
|
+
/**
|
|
544
|
+
* Get the resolved endpoint for a specific service.
|
|
545
|
+
*
|
|
546
|
+
* @param service - Service name (oneroster, caliper, edubridge, qti, powerpath)
|
|
547
|
+
* @returns Resolved endpoint with baseUrl and authUrl
|
|
548
|
+
* @throws If the service is not configured in this provider
|
|
549
|
+
*/
|
|
550
|
+
getEndpoint(service: ServiceName): ResolvedEndpoint;
|
|
551
|
+
/**
|
|
552
|
+
* Check if a service is available in this provider.
|
|
553
|
+
*
|
|
554
|
+
* @param service - Service name to check
|
|
555
|
+
* @returns True if the service is configured
|
|
556
|
+
*/
|
|
557
|
+
hasService(service: ServiceName): boolean;
|
|
558
|
+
/**
|
|
559
|
+
* Get all configured service names.
|
|
560
|
+
*
|
|
561
|
+
* @returns Array of service names available in this provider
|
|
562
|
+
*/
|
|
563
|
+
getAvailableServices(): ServiceName[];
|
|
564
|
+
/**
|
|
565
|
+
* Get the token URL for this provider.
|
|
566
|
+
* @returns The token URL for authentication
|
|
567
|
+
*/
|
|
568
|
+
getTokenUrl(): string | undefined;
|
|
569
|
+
/**
|
|
570
|
+
* Get endpoint with paths for a service that has path configuration.
|
|
571
|
+
*
|
|
572
|
+
* @param service - Service name that has paths in PlatformPaths
|
|
573
|
+
* @returns Resolved endpoint with baseUrl, authUrl, and paths
|
|
574
|
+
* @throws If service is not configured or not supported on this platform
|
|
575
|
+
*/
|
|
576
|
+
getEndpointWithPaths<S extends PathEnabledService>(service: S & ServiceName): ResolvedEndpoint & {
|
|
577
|
+
paths: NonNullable<PlatformPaths[S]>;
|
|
578
|
+
};
|
|
579
|
+
/**
|
|
580
|
+
* Get all path profiles for this provider (raw, may contain nulls).
|
|
581
|
+
*
|
|
582
|
+
* @returns Platform path profiles
|
|
583
|
+
*/
|
|
584
|
+
getPaths(): PlatformPaths;
|
|
585
|
+
/**
|
|
586
|
+
* Get paths for a specific service.
|
|
587
|
+
*
|
|
588
|
+
* @param service - Service name
|
|
589
|
+
* @returns Path configuration for the service
|
|
590
|
+
* @throws If the service is not supported on this platform
|
|
591
|
+
*/
|
|
592
|
+
getServicePaths<S extends PathEnabledService>(service: S): NonNullable<PlatformPaths[S]>;
|
|
593
|
+
/**
|
|
594
|
+
* Check if a service is supported on this platform.
|
|
595
|
+
*
|
|
596
|
+
* @param service - Service name
|
|
597
|
+
* @returns true if the service has path configuration
|
|
598
|
+
*/
|
|
599
|
+
hasServiceSupport(service: PathEnabledService): boolean;
|
|
600
|
+
/**
|
|
601
|
+
* Get a TokenProvider for a specific service.
|
|
602
|
+
*
|
|
603
|
+
* TokenProviders are cached by authUrl, so services sharing the same
|
|
604
|
+
* token endpoint will share the same cached OAuth tokens.
|
|
605
|
+
*
|
|
606
|
+
* @param service - Service name (oneroster, caliper, edubridge, qti, powerpath)
|
|
607
|
+
* @returns Cached TokenProvider for the service's token endpoint, or undefined for public/no-auth services
|
|
608
|
+
* @throws If the service is not configured in this provider
|
|
609
|
+
* @throws If auth is required but not configured
|
|
610
|
+
*/
|
|
611
|
+
getTokenProvider(service: ServiceName): TokenProvider | undefined;
|
|
612
|
+
/**
|
|
613
|
+
* Verify that OAuth authentication is working.
|
|
614
|
+
*
|
|
615
|
+
* Attempts to acquire a token using the provider's credentials.
|
|
616
|
+
* Returns a health check result with success/failure and latency info.
|
|
617
|
+
*
|
|
618
|
+
* @returns Auth check result
|
|
619
|
+
* @throws {Error} If no auth is configured on this provider
|
|
620
|
+
*/
|
|
621
|
+
checkAuth(): Promise<AuthCheckResult$1>;
|
|
622
|
+
/**
|
|
623
|
+
* Invalidate all cached OAuth tokens.
|
|
624
|
+
*
|
|
625
|
+
* Call this when closing the client or when tokens need to be refreshed.
|
|
626
|
+
* New tokens will be acquired on the next API call.
|
|
627
|
+
*/
|
|
628
|
+
invalidateTokens(): void;
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
/**
|
|
632
|
+
* Transport Types
|
|
633
|
+
*
|
|
634
|
+
* Types for HTTP transport layer.
|
|
635
|
+
*/
|
|
636
|
+
|
|
637
|
+
/**
|
|
638
|
+
* Result of an auth check operation.
|
|
639
|
+
*/
|
|
640
|
+
interface AuthCheckResult {
|
|
641
|
+
/** Whether auth succeeded */
|
|
642
|
+
ok: boolean;
|
|
643
|
+
/** Time taken to complete the check (ms) */
|
|
644
|
+
latencyMs: number;
|
|
645
|
+
/** Error message if failed */
|
|
646
|
+
error?: string;
|
|
647
|
+
/** Detailed check results */
|
|
648
|
+
checks: {
|
|
649
|
+
/** Token acquisition succeeded */
|
|
650
|
+
tokenAcquisition: boolean;
|
|
651
|
+
};
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
/**
|
|
655
|
+
* API Error Classes
|
|
656
|
+
*
|
|
657
|
+
* Base error classes for HTTP API failures.
|
|
658
|
+
* Includes IMS Global error response parsing (OneRoster, QTI, etc.).
|
|
659
|
+
*/
|
|
660
|
+
|
|
661
|
+
/**
|
|
662
|
+
* Base error class for all API errors.
|
|
663
|
+
*
|
|
664
|
+
* Provides access to the HTTP status code and raw response body.
|
|
665
|
+
* Includes IMS Global error parsing (minorCodes, details) for
|
|
666
|
+
* IMS-standard APIs like OneRoster and QTI.
|
|
667
|
+
*
|
|
668
|
+
* @example
|
|
669
|
+
* ```typescript
|
|
670
|
+
* // Catching and inspecting errors
|
|
671
|
+
* try {
|
|
672
|
+
* await client.users.get('non-existent-id')
|
|
673
|
+
* } catch (error) {
|
|
674
|
+
* if (error instanceof ApiError) {
|
|
675
|
+
* console.log(`Error ${error.statusCode}: ${error.message}`)
|
|
676
|
+
* console.log('Minor codes:', error.minorCodes)
|
|
677
|
+
* console.log('Details:', error.details)
|
|
678
|
+
* }
|
|
679
|
+
* }
|
|
680
|
+
* ```
|
|
681
|
+
*/
|
|
682
|
+
declare class ApiError extends Error {
|
|
683
|
+
readonly statusCode?: number | undefined;
|
|
684
|
+
readonly response?: unknown;
|
|
685
|
+
readonly name: string;
|
|
686
|
+
/**
|
|
687
|
+
* Creates a new ApiError.
|
|
688
|
+
*
|
|
689
|
+
* @param message - Human-readable error message
|
|
690
|
+
* @param statusCode - HTTP status code
|
|
691
|
+
* @param response - Raw response body (if available)
|
|
692
|
+
*/
|
|
693
|
+
constructor(message: string, statusCode?: number | undefined, response?: unknown);
|
|
694
|
+
/**
|
|
695
|
+
* Minor error codes from IMS Global error response.
|
|
696
|
+
*
|
|
697
|
+
* For IMS-standard APIs (OneRoster, QTI), provides specific error codes
|
|
698
|
+
* like "unknownobject" or "invaliddata".
|
|
699
|
+
*
|
|
700
|
+
* @returns Array of field/value pairs, or empty array if not IMS format
|
|
701
|
+
*/
|
|
702
|
+
get minorCodes(): Array<{
|
|
703
|
+
field: string;
|
|
704
|
+
value: string;
|
|
705
|
+
}>;
|
|
706
|
+
/**
|
|
707
|
+
* Additional error details from IMS Global response.
|
|
708
|
+
*
|
|
709
|
+
* May contain field-level validation errors or other structured details.
|
|
710
|
+
*
|
|
711
|
+
* @returns Array of key-value objects, or empty array if not present
|
|
712
|
+
*/
|
|
713
|
+
get details(): Array<Record<string, string>>;
|
|
714
|
+
}
|
|
715
|
+
/**
|
|
716
|
+
* Error thrown when authentication fails (HTTP 401).
|
|
717
|
+
*
|
|
718
|
+
* Typically indicates invalid or expired credentials.
|
|
719
|
+
*/
|
|
720
|
+
declare class UnauthorizedError extends ApiError {
|
|
721
|
+
readonly name = "UnauthorizedError";
|
|
722
|
+
constructor(message?: string, response?: unknown);
|
|
723
|
+
}
|
|
724
|
+
/**
|
|
725
|
+
* Error thrown when the client lacks permission for the operation (HTTP 403).
|
|
726
|
+
*
|
|
727
|
+
* The credentials are valid, but the client is not authorized for this action.
|
|
728
|
+
*/
|
|
729
|
+
declare class ForbiddenError extends ApiError {
|
|
730
|
+
readonly name = "ForbiddenError";
|
|
731
|
+
constructor(message?: string, response?: unknown);
|
|
732
|
+
}
|
|
733
|
+
/**
|
|
734
|
+
* Error thrown when a requested resource is not found (HTTP 404).
|
|
735
|
+
*/
|
|
736
|
+
declare class NotFoundError extends ApiError {
|
|
737
|
+
readonly name = "NotFoundError";
|
|
738
|
+
constructor(message?: string, response?: unknown);
|
|
739
|
+
}
|
|
740
|
+
/**
|
|
741
|
+
* Error thrown when request data is invalid (HTTP 422).
|
|
742
|
+
*
|
|
743
|
+
* Check the `details` property for field-level validation errors.
|
|
744
|
+
*/
|
|
745
|
+
declare class ValidationError extends ApiError {
|
|
746
|
+
readonly name = "ValidationError";
|
|
747
|
+
constructor(message?: string, response?: unknown);
|
|
748
|
+
}
|
|
749
|
+
/**
|
|
750
|
+
* Type guard to check if an error is an ApiError.
|
|
751
|
+
*
|
|
752
|
+
* Uses duck typing to work across module boundaries where `instanceof`
|
|
753
|
+
* may fail due to multiple package copies.
|
|
754
|
+
* @param error - The error to check
|
|
755
|
+
* @returns True if error is an ApiError
|
|
756
|
+
*/
|
|
757
|
+
declare function isApiError(error: unknown): error is ApiError;
|
|
758
|
+
|
|
759
|
+
/**
|
|
760
|
+
* All supported platforms.
|
|
761
|
+
*/
|
|
762
|
+
declare const PLATFORMS: readonly ["BEYOND_AI", "LEARNWITH_AI"];
|
|
763
|
+
|
|
764
|
+
/**
|
|
765
|
+
* Timeback Core Types
|
|
766
|
+
*
|
|
767
|
+
* Configuration types for the unified Timeback client,
|
|
768
|
+
* plus re-exports of entity types from all services.
|
|
769
|
+
*
|
|
770
|
+
* @example
|
|
771
|
+
* ```typescript
|
|
772
|
+
* import type { User, School, Organization } from '@timeback/core/types'
|
|
773
|
+
* ```
|
|
774
|
+
*/
|
|
775
|
+
|
|
776
|
+
/**
|
|
777
|
+
* Supported Timeback platform implementations.
|
|
778
|
+
* Derived from the PLATFORMS constant.
|
|
779
|
+
*/
|
|
780
|
+
type Platform = (typeof PLATFORMS)[number];
|
|
781
|
+
/**
|
|
782
|
+
* Timeback deployment environment.
|
|
783
|
+
*/
|
|
784
|
+
type Environment = 'staging' | 'production';
|
|
785
|
+
/**
|
|
786
|
+
* Resolved service URLs for environment mode.
|
|
787
|
+
* @internal
|
|
788
|
+
*/
|
|
789
|
+
interface EnvServiceUrls {
|
|
790
|
+
oneroster: string;
|
|
791
|
+
caliper: string;
|
|
792
|
+
webhooks: string;
|
|
793
|
+
edubridge: string;
|
|
794
|
+
qti: string;
|
|
795
|
+
powerpath?: string;
|
|
796
|
+
authUrl: string;
|
|
797
|
+
}
|
|
798
|
+
/**
|
|
799
|
+
* OAuth2 client credentials for environment mode.
|
|
800
|
+
* Token URL is derived from the environment.
|
|
801
|
+
*/
|
|
802
|
+
interface EnvAuthCredentials {
|
|
803
|
+
clientId: string;
|
|
804
|
+
clientSecret: string;
|
|
805
|
+
}
|
|
806
|
+
/**
|
|
807
|
+
* OAuth2 client credentials with explicit token URL.
|
|
808
|
+
* Required when using baseUrl or services mode.
|
|
809
|
+
*/
|
|
810
|
+
interface ExplicitAuthCredentials {
|
|
811
|
+
clientId: string;
|
|
812
|
+
clientSecret: string;
|
|
813
|
+
authUrl: string;
|
|
814
|
+
}
|
|
815
|
+
/**
|
|
816
|
+
* Service endpoint configuration.
|
|
817
|
+
* Can be a simple URL string or an object with baseUrl and optional authUrl override.
|
|
818
|
+
*/
|
|
819
|
+
type ServiceEndpoint = string | {
|
|
820
|
+
baseUrl: string;
|
|
821
|
+
authUrl?: string;
|
|
822
|
+
};
|
|
823
|
+
/**
|
|
824
|
+
* Explicit URLs for each service.
|
|
825
|
+
* All fields optional — only configure services you need.
|
|
826
|
+
*/
|
|
827
|
+
interface ServiceUrls {
|
|
828
|
+
/** OneRoster API endpoint */
|
|
829
|
+
oneroster?: ServiceEndpoint;
|
|
830
|
+
/** Caliper API endpoint */
|
|
831
|
+
caliper?: ServiceEndpoint;
|
|
832
|
+
/** Webhooks API endpoint */
|
|
833
|
+
webhooks?: ServiceEndpoint;
|
|
834
|
+
/** Edubridge API endpoint */
|
|
835
|
+
edubridge?: ServiceEndpoint;
|
|
836
|
+
/** QTI API endpoint */
|
|
837
|
+
qti?: ServiceEndpoint;
|
|
838
|
+
/** PowerPath API endpoint */
|
|
839
|
+
powerpath?: ServiceEndpoint;
|
|
840
|
+
}
|
|
841
|
+
/**
|
|
842
|
+
* Environment mode: URLs derived from platform and environment.
|
|
843
|
+
*
|
|
844
|
+
* @example
|
|
845
|
+
* ```typescript
|
|
846
|
+
* // BeyondAI platform (default)
|
|
847
|
+
* const client = new TimebackClient({
|
|
848
|
+
* env: 'staging',
|
|
849
|
+
* auth: { clientId: '...', clientSecret: '...' },
|
|
850
|
+
* })
|
|
851
|
+
*
|
|
852
|
+
* // LearnWith.AI platform
|
|
853
|
+
* const client = new TimebackClient({
|
|
854
|
+
* platform: 'LEARNWITH_AI',
|
|
855
|
+
* env: 'production',
|
|
856
|
+
* auth: { clientId: '...', clientSecret: '...' },
|
|
857
|
+
* })
|
|
858
|
+
* ```
|
|
859
|
+
*/
|
|
860
|
+
interface EnvConfig {
|
|
861
|
+
platform?: Platform;
|
|
862
|
+
env: Environment;
|
|
863
|
+
auth?: Partial<EnvAuthCredentials>;
|
|
864
|
+
timeout?: number;
|
|
865
|
+
}
|
|
866
|
+
/**
|
|
867
|
+
* Base URL mode: Single base URL, service paths derived automatically.
|
|
868
|
+
*
|
|
869
|
+
* @example
|
|
870
|
+
* ```typescript
|
|
871
|
+
* const client = new TimebackClient({
|
|
872
|
+
* baseUrl: 'https://timeback.myschool.edu',
|
|
873
|
+
* auth: {
|
|
874
|
+
* clientId: '...',
|
|
875
|
+
* clientSecret: '...',
|
|
876
|
+
* authUrl: 'https://timeback.myschool.edu/oauth/token',
|
|
877
|
+
* },
|
|
878
|
+
* })
|
|
879
|
+
* ```
|
|
880
|
+
*/
|
|
881
|
+
interface BaseUrlConfig {
|
|
882
|
+
baseUrl: string;
|
|
883
|
+
auth: ExplicitAuthCredentials;
|
|
884
|
+
timeout?: number;
|
|
885
|
+
}
|
|
886
|
+
/**
|
|
887
|
+
* Explicit services mode: Full control over each service URL.
|
|
888
|
+
*
|
|
889
|
+
* @example
|
|
890
|
+
* ```typescript
|
|
891
|
+
* const client = new TimebackClient({
|
|
892
|
+
* services: {
|
|
893
|
+
* oneroster: 'https://roster.example.com/v1p2',
|
|
894
|
+
* caliper: 'https://analytics.example.com/caliper',
|
|
895
|
+
* edubridge: 'https://api.example.com/edubridge',
|
|
896
|
+
* qti: 'https://qti.example.com/api',
|
|
897
|
+
* },
|
|
898
|
+
* auth: {
|
|
899
|
+
* clientId: '...',
|
|
900
|
+
* clientSecret: '...',
|
|
901
|
+
* authUrl: 'https://auth.example.com/oauth/token',
|
|
902
|
+
* },
|
|
903
|
+
* })
|
|
904
|
+
* ```
|
|
905
|
+
*/
|
|
906
|
+
interface ServicesConfig {
|
|
907
|
+
services: ServiceUrls;
|
|
908
|
+
auth: ExplicitAuthCredentials;
|
|
909
|
+
timeout?: number;
|
|
910
|
+
}
|
|
911
|
+
/**
|
|
912
|
+
* Provider mode: use a pre-built TimebackProvider.
|
|
913
|
+
*
|
|
914
|
+
* @example
|
|
915
|
+
* ```typescript
|
|
916
|
+
* import { TimebackProvider } from '@timeback/core'
|
|
917
|
+
*
|
|
918
|
+
* const provider = new TimebackProvider({
|
|
919
|
+
* platform: 'BEYOND_AI',
|
|
920
|
+
* env: 'staging',
|
|
921
|
+
* auth: { clientId: '...', clientSecret: '...' },
|
|
922
|
+
* })
|
|
923
|
+
*
|
|
924
|
+
* const client = new TimebackClient({ provider })
|
|
925
|
+
* ```
|
|
926
|
+
*/
|
|
927
|
+
interface ProviderConfig {
|
|
928
|
+
provider: TimebackProvider;
|
|
929
|
+
}
|
|
930
|
+
/**
|
|
931
|
+
* Configuration for the unified Timeback client.
|
|
932
|
+
*
|
|
933
|
+
* Supports four modes:
|
|
934
|
+
* - **Provider**: `{ provider: TimebackProvider }` — pre-built provider
|
|
935
|
+
* - **Environment**: `{ env: 'staging' | 'production', auth: {...} }`
|
|
936
|
+
* - **Base URL**: `{ baseUrl: '...', auth: {..., authUrl: '...' } }`
|
|
937
|
+
* - **Explicit services**: `{ services: {...}, auth: {..., authUrl: '...' } }`
|
|
938
|
+
*/
|
|
939
|
+
type TimebackClientConfig = ProviderConfig | EnvConfig | BaseUrlConfig | ServicesConfig;
|
|
940
|
+
/**
|
|
941
|
+
* Result of a broadcast operation for a single client.
|
|
942
|
+
* Similar to PromiseSettledResult but with simpler `ok` boolean.
|
|
943
|
+
*/
|
|
944
|
+
type BroadcastResult<T> = {
|
|
945
|
+
ok: true;
|
|
946
|
+
value: T;
|
|
947
|
+
} | {
|
|
948
|
+
ok: false;
|
|
949
|
+
error: Error;
|
|
950
|
+
};
|
|
951
|
+
/**
|
|
952
|
+
* Convenience methods available on broadcast results.
|
|
953
|
+
*
|
|
954
|
+
* @typeParam T - The value type returned by successful operations
|
|
955
|
+
* @typeParam TNames - Union of client names (for typed tuples)
|
|
956
|
+
*/
|
|
957
|
+
interface BroadcastResultMethods<T, TNames extends string = string> {
|
|
958
|
+
/** Get all successful results as [name, value] tuples */
|
|
959
|
+
readonly succeeded: Array<[TNames, T]>;
|
|
960
|
+
/** Get all failed results as [name, error] tuples */
|
|
961
|
+
readonly failed: Array<[TNames, Error]>;
|
|
962
|
+
/** True if all operations succeeded */
|
|
963
|
+
readonly allSucceeded: boolean;
|
|
964
|
+
/** True if any operation failed */
|
|
965
|
+
readonly anyFailed: boolean;
|
|
966
|
+
/** Get all successful values (throws if any failed) */
|
|
967
|
+
values(): T[];
|
|
968
|
+
}
|
|
969
|
+
/**
|
|
970
|
+
* Broadcast results with both direct property access and convenience methods.
|
|
971
|
+
*
|
|
972
|
+
* Access results directly by name or use helper methods:
|
|
973
|
+
*
|
|
974
|
+
* @typeParam T - The value type returned by successful operations
|
|
975
|
+
* @typeParam TNames - Union of client names (enables autocomplete)
|
|
976
|
+
*
|
|
977
|
+
* @example
|
|
978
|
+
* ```typescript
|
|
979
|
+
* const results = await manager.broadcast(c => c.oneroster.users.create(user))
|
|
980
|
+
*
|
|
981
|
+
* // Direct access (like a plain object):
|
|
982
|
+
* results.alpha.ok
|
|
983
|
+
* results['beta'].error
|
|
984
|
+
*
|
|
985
|
+
* // Convenience methods:
|
|
986
|
+
* if (results.allSucceeded) {
|
|
987
|
+
* console.log('All platforms synced!')
|
|
988
|
+
* }
|
|
989
|
+
*
|
|
990
|
+
* results.succeeded.forEach(([name, user]) => {
|
|
991
|
+
* console.log(`Created on ${name}:`, user.id)
|
|
992
|
+
* })
|
|
993
|
+
*
|
|
994
|
+
* results.failed.forEach(([name, error]) => {
|
|
995
|
+
* console.error(`Failed on ${name}:`, error.message)
|
|
996
|
+
* })
|
|
997
|
+
* ```
|
|
998
|
+
*/
|
|
999
|
+
type BroadcastResults<T, TNames extends string = string> = {
|
|
1000
|
+
[K in TNames]: BroadcastResult<T>;
|
|
1001
|
+
} & BroadcastResultMethods<T, TNames>;
|
|
1002
|
+
|
|
1003
|
+
/**
|
|
1004
|
+
* Timeback Client
|
|
1005
|
+
*
|
|
1006
|
+
* Unified client for all Timeback education APIs.
|
|
1007
|
+
*/
|
|
1
1008
|
/**
|
|
2
1009
|
* Unified client for Timeback education APIs.
|
|
3
1010
|
*
|
|
1011
|
+
* Provides access to all Timeback APIs with shared authentication:
|
|
1012
|
+
* - **OneRoster**: Rostering and gradebook data
|
|
1013
|
+
* - **Edubridge**: Simplified enrollments and analytics
|
|
1014
|
+
* - **Caliper**: Learning analytics events
|
|
1015
|
+
* - **Reporting**: Ad-hoc queries and saved reporting endpoints
|
|
1016
|
+
* - **QTI**: Assessment content management
|
|
1017
|
+
* - **PowerPath**: Placement tests, lesson plans, and assessments
|
|
1018
|
+
* - **CLR**: Comprehensive Learner Record credentials
|
|
1019
|
+
* - **CASE**: Competency and Academic Standards Exchange
|
|
1020
|
+
*
|
|
1021
|
+
* All sub-clients share a single OAuth token, reducing auth requests.
|
|
1022
|
+
*
|
|
4
1023
|
* @example
|
|
5
1024
|
* ```typescript
|
|
6
|
-
*
|
|
1025
|
+
* // Environment mode
|
|
1026
|
+
* const timeback = new TimebackClient({
|
|
1027
|
+
* env: 'staging',
|
|
1028
|
+
* auth: { clientId: '...', clientSecret: '...' },
|
|
1029
|
+
* })
|
|
1030
|
+
* ```
|
|
7
1031
|
*
|
|
1032
|
+
* @example
|
|
1033
|
+
* ```typescript
|
|
1034
|
+
* // Platform selection
|
|
8
1035
|
* const timeback = new TimebackClient({
|
|
1036
|
+
* platform: 'LEARNWITH_AI',
|
|
1037
|
+
* env: 'production',
|
|
1038
|
+
* auth: { clientId: '...', clientSecret: '...' },
|
|
1039
|
+
* })
|
|
1040
|
+
* ```
|
|
1041
|
+
*
|
|
1042
|
+
* @example
|
|
1043
|
+
* ```typescript
|
|
1044
|
+
* // Provider mode (pre-built provider)
|
|
1045
|
+
* import { TimebackProvider } from '@timeback/core'
|
|
1046
|
+
*
|
|
1047
|
+
* const provider = new TimebackProvider({
|
|
1048
|
+
* platform: 'BEYOND_AI',
|
|
9
1049
|
* env: 'staging',
|
|
1050
|
+
* auth: { clientId: '...', clientSecret: '...' },
|
|
1051
|
+
* })
|
|
1052
|
+
*
|
|
1053
|
+
* const timeback = new TimebackClient({ provider })
|
|
1054
|
+
* ```
|
|
1055
|
+
*
|
|
1056
|
+
* @example
|
|
1057
|
+
* ```typescript
|
|
1058
|
+
* // Base URL mode (self-hosted)
|
|
1059
|
+
* const timeback = new TimebackClient({
|
|
1060
|
+
* baseUrl: 'https://timeback.myschool.edu',
|
|
10
1061
|
* auth: {
|
|
11
|
-
* clientId:
|
|
12
|
-
* clientSecret:
|
|
1062
|
+
* clientId: '...',
|
|
1063
|
+
* clientSecret: '...',
|
|
1064
|
+
* authUrl: 'https://timeback.myschool.edu/oauth/token',
|
|
13
1065
|
* },
|
|
14
1066
|
* })
|
|
1067
|
+
* ```
|
|
1068
|
+
*/
|
|
1069
|
+
declare class TimebackClient {
|
|
1070
|
+
private readonly provider;
|
|
1071
|
+
private _closed;
|
|
1072
|
+
private _oneroster?;
|
|
1073
|
+
private _edubridge?;
|
|
1074
|
+
private _caliper?;
|
|
1075
|
+
private _qti?;
|
|
1076
|
+
private _powerpath?;
|
|
1077
|
+
private _clr?;
|
|
1078
|
+
private _case?;
|
|
1079
|
+
private _reporting?;
|
|
1080
|
+
private _webhooks?;
|
|
1081
|
+
/**
|
|
1082
|
+
* Creates a new Timeback client.
|
|
1083
|
+
*
|
|
1084
|
+
* @param config - Client configuration (env, baseUrl, provider, or services mode).
|
|
1085
|
+
* If omitted, reads from TIMEBACK_ENV, TIMEBACK_CLIENT_ID,
|
|
1086
|
+
* and TIMEBACK_CLIENT_SECRET environment variables.
|
|
1087
|
+
*/
|
|
1088
|
+
constructor(config?: TimebackClientConfig);
|
|
1089
|
+
/**
|
|
1090
|
+
* OneRoster API client for rostering and gradebook operations.
|
|
1091
|
+
*
|
|
1092
|
+
* Lazily initialized on first access. Shares OAuth tokens with other
|
|
1093
|
+
* sub-clients through the provider.
|
|
1094
|
+
*
|
|
1095
|
+
* @returns The OneRoster client instance
|
|
1096
|
+
* @throws {Error} If client has been closed or service not configured
|
|
1097
|
+
*/
|
|
1098
|
+
get oneroster(): OneRosterClientInstance;
|
|
1099
|
+
/**
|
|
1100
|
+
* Edubridge API client for simplified enrollments and analytics.
|
|
1101
|
+
*
|
|
1102
|
+
* Lazily initialized on first access. Shares OAuth tokens with other
|
|
1103
|
+
* sub-clients through the provider.
|
|
1104
|
+
*
|
|
1105
|
+
* @returns The Edubridge client instance
|
|
1106
|
+
* @throws {Error} If client has been closed or service not configured
|
|
1107
|
+
*/
|
|
1108
|
+
get edubridge(): EdubridgeClientInstance;
|
|
1109
|
+
/**
|
|
1110
|
+
* Caliper API client for learning analytics events.
|
|
1111
|
+
*
|
|
1112
|
+
* Lazily initialized on first access. Shares OAuth tokens with other
|
|
1113
|
+
* sub-clients through the provider.
|
|
1114
|
+
*
|
|
1115
|
+
* @returns The Caliper client instance
|
|
1116
|
+
* @throws {Error} If client has been closed or service not configured
|
|
1117
|
+
*/
|
|
1118
|
+
get caliper(): CaliperClientInstance;
|
|
1119
|
+
/**
|
|
1120
|
+
* QTI API client for assessment content management.
|
|
1121
|
+
*
|
|
1122
|
+
* Lazily initialized on first access. Shares OAuth tokens with other
|
|
1123
|
+
* sub-clients through the provider.
|
|
1124
|
+
*
|
|
1125
|
+
* @returns The QTI client instance
|
|
1126
|
+
* @throws {Error} If client has been closed or service not configured
|
|
1127
|
+
*/
|
|
1128
|
+
get qti(): QtiClientInstance;
|
|
1129
|
+
/**
|
|
1130
|
+
* PowerPath API client for placement tests and lesson plans.
|
|
1131
|
+
*
|
|
1132
|
+
* Lazily initialized on first access. Shares OAuth tokens with other
|
|
1133
|
+
* sub-clients through the provider.
|
|
1134
|
+
*
|
|
1135
|
+
* @returns The PowerPath client instance
|
|
1136
|
+
* @throws {Error} If client has been closed or service not configured
|
|
1137
|
+
*/
|
|
1138
|
+
get powerpath(): PowerPathClientInstance;
|
|
1139
|
+
/**
|
|
1140
|
+
* CLR API client for Comprehensive Learner Record credentials.
|
|
1141
|
+
*
|
|
1142
|
+
* Lazily initialized on first access. Shares OAuth tokens with other
|
|
1143
|
+
* sub-clients through the provider.
|
|
1144
|
+
*
|
|
1145
|
+
* @returns The CLR client instance
|
|
1146
|
+
* @throws {Error} If client has been closed or service not configured
|
|
1147
|
+
*/
|
|
1148
|
+
get clr(): ClrClientInstance;
|
|
1149
|
+
/**
|
|
1150
|
+
* CASE API client for Competency and Academic Standards Exchange.
|
|
1151
|
+
*
|
|
1152
|
+
* Lazily initialized on first access. Shares OAuth tokens with other
|
|
1153
|
+
* sub-clients through the provider.
|
|
1154
|
+
*
|
|
1155
|
+
* @returns The CASE client instance
|
|
1156
|
+
* @throws {Error} If client has been closed or service not configured
|
|
1157
|
+
*/
|
|
1158
|
+
get case(): CaseClientInstance;
|
|
1159
|
+
/**
|
|
1160
|
+
* Reporting API client for reporting queries and saved reporting endpoints.
|
|
1161
|
+
*
|
|
1162
|
+
* Lazily initialized on first access. Shares OAuth tokens with other
|
|
1163
|
+
* sub-clients through the provider.
|
|
1164
|
+
*
|
|
1165
|
+
* @returns The Reporting client instance
|
|
1166
|
+
* @throws {Error} If client has been closed or service not configured
|
|
1167
|
+
*/
|
|
1168
|
+
get reporting(): ReportingClientInstance;
|
|
1169
|
+
/**
|
|
1170
|
+
* Webhooks API client for managing webhook registrations and filters.
|
|
1171
|
+
*
|
|
1172
|
+
* Lazily initialized on first access. Shares OAuth tokens with other
|
|
1173
|
+
* sub-clients through the provider.
|
|
1174
|
+
*
|
|
1175
|
+
* @returns The Webhooks client instance
|
|
1176
|
+
* @throws {Error} If client has been closed or service not configured
|
|
1177
|
+
*/
|
|
1178
|
+
get webhooks(): WebhooksClientInstance;
|
|
1179
|
+
/**
|
|
1180
|
+
* Verify that OAuth authentication is working.
|
|
1181
|
+
*
|
|
1182
|
+
* Attempts to acquire a token using the provider's credentials.
|
|
1183
|
+
* Returns a health check result with success/failure and latency info.
|
|
1184
|
+
*
|
|
1185
|
+
* @returns Auth check result
|
|
1186
|
+
* @throws {Error} If client has been closed
|
|
1187
|
+
*/
|
|
1188
|
+
checkAuth(): Promise<AuthCheckResult>;
|
|
1189
|
+
/**
|
|
1190
|
+
* Close the client and release resources.
|
|
1191
|
+
*
|
|
1192
|
+
* After calling close():
|
|
1193
|
+
* - Cached OAuth tokens are invalidated
|
|
1194
|
+
* - Sub-client references are cleared
|
|
1195
|
+
* - Further API calls will throw an error
|
|
1196
|
+
*/
|
|
1197
|
+
close(): void;
|
|
1198
|
+
/**
|
|
1199
|
+
* Check if the client has been closed.
|
|
1200
|
+
* @returns True if closed
|
|
1201
|
+
*/
|
|
1202
|
+
get closed(): boolean;
|
|
1203
|
+
/**
|
|
1204
|
+
* Get the underlying provider for advanced use cases.
|
|
1205
|
+
*
|
|
1206
|
+
* @returns The TimebackProvider instance used by this client
|
|
1207
|
+
*/
|
|
1208
|
+
getProvider(): TimebackProvider;
|
|
1209
|
+
/**
|
|
1210
|
+
* Throw if the client has been closed.
|
|
1211
|
+
*/
|
|
1212
|
+
private assertOpen;
|
|
1213
|
+
/**
|
|
1214
|
+
* Throw if a service is not configured.
|
|
1215
|
+
* @param service - Service name to check
|
|
1216
|
+
*/
|
|
1217
|
+
private assertService;
|
|
1218
|
+
}
|
|
1219
|
+
|
|
1220
|
+
/**
|
|
1221
|
+
* Timeback Manager
|
|
15
1222
|
*
|
|
16
|
-
* for
|
|
17
|
-
*
|
|
18
|
-
|
|
1223
|
+
* Orchestration layer for managing multiple TimebackClient instances.
|
|
1224
|
+
* Enables operations across multiple clients from a single interface.
|
|
1225
|
+
*/
|
|
1226
|
+
|
|
1227
|
+
/**
|
|
1228
|
+
* Manages multiple TimebackClient instances.
|
|
1229
|
+
*
|
|
1230
|
+
* Use this when you need to:
|
|
1231
|
+
* - Manage multiple clients with different configurations
|
|
1232
|
+
* - Fan-out requests to multiple clients simultaneously
|
|
1233
|
+
* - Aggregate data from multiple sources
|
|
1234
|
+
*
|
|
1235
|
+
* The manager tracks registered client names at the type level,
|
|
1236
|
+
* providing autocomplete for `get()` and `has()`.
|
|
1237
|
+
*
|
|
1238
|
+
* @typeParam TNames - Union of registered client names (tracked automatically)
|
|
1239
|
+
*
|
|
1240
|
+
* @example
|
|
1241
|
+
* ```typescript
|
|
1242
|
+
* const manager = new TimebackManager()
|
|
1243
|
+
* .register('alpha', { env: 'production', auth: { ... } })
|
|
1244
|
+
* .register('beta', { env: 'production', auth: { ... } })
|
|
1245
|
+
*
|
|
1246
|
+
* // Autocomplete suggests 'alpha' | 'beta'
|
|
1247
|
+
* const users = await manager.get('alpha').oneroster.users.list()
|
|
1248
|
+
*
|
|
1249
|
+
* // Fan-out to all clients
|
|
1250
|
+
* const results = await manager.broadcast(client => client.oneroster.users.create(user))
|
|
1251
|
+
* // { alpha: { ok: true, value: {...} }, beta: { ok: true, value: {...} } }
|
|
19
1252
|
* ```
|
|
20
1253
|
*/
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
1254
|
+
declare class TimebackManager<TNames extends string = never> {
|
|
1255
|
+
private readonly clients;
|
|
1256
|
+
/**
|
|
1257
|
+
* Register a new client with a given name.
|
|
1258
|
+
*
|
|
1259
|
+
* Returns a new manager type that includes the registered name,
|
|
1260
|
+
* enabling autocomplete for `get()`.
|
|
1261
|
+
*
|
|
1262
|
+
* @param {string} name - Unique identifier for this client
|
|
1263
|
+
* @param {TimebackClientConfig} config - Configuration for the TimebackClient
|
|
1264
|
+
* @returns {TimebackManager<TNames | N>} - A new manager type that includes the registered name, enabling autocomplete for `get()`
|
|
1265
|
+
* @throws {Error} If a client with this name is already registered
|
|
1266
|
+
*/
|
|
1267
|
+
register<N extends string>(name: N, config: TimebackClientConfig): TimebackManager<TNames | N>;
|
|
1268
|
+
/**
|
|
1269
|
+
* Get a registered client by name.
|
|
1270
|
+
*
|
|
1271
|
+
* @param name - The name used when registering the client (autocomplete enabled)
|
|
1272
|
+
* @returns The TimebackClient instance
|
|
1273
|
+
* @throws {Error} If no client with this name is registered
|
|
1274
|
+
*
|
|
1275
|
+
* @example
|
|
1276
|
+
* ```typescript
|
|
1277
|
+
* const client = manager.get('alpha') // autocomplete suggests registered names
|
|
1278
|
+
* const schools = await client.oneroster.schools.list()
|
|
1279
|
+
* ```
|
|
1280
|
+
*/
|
|
1281
|
+
get(name: TNames): TimebackClient;
|
|
1282
|
+
/**
|
|
1283
|
+
* Check if a client with the given name is registered.
|
|
1284
|
+
*
|
|
1285
|
+
* Accepts any string since it's a runtime check.
|
|
1286
|
+
* Returns true only for registered names.
|
|
1287
|
+
*
|
|
1288
|
+
* @param name - The name to check
|
|
1289
|
+
* @returns True if registered
|
|
1290
|
+
*/
|
|
1291
|
+
has(name: string): name is TNames;
|
|
1292
|
+
/**
|
|
1293
|
+
* Get all registered client names.
|
|
1294
|
+
* @returns Array of registered client names
|
|
1295
|
+
*/
|
|
1296
|
+
get names(): string[];
|
|
1297
|
+
/**
|
|
1298
|
+
* Get the number of registered clients.
|
|
1299
|
+
* @returns Number of registered clients
|
|
1300
|
+
*/
|
|
1301
|
+
get size(): number;
|
|
1302
|
+
/**
|
|
1303
|
+
* Execute a function on all registered clients.
|
|
1304
|
+
*
|
|
1305
|
+
* Uses `Promise.allSettled` semantics — always completes, never throws.
|
|
1306
|
+
* Each result indicates success or failure per client.
|
|
1307
|
+
*
|
|
1308
|
+
* All operations run in parallel.
|
|
1309
|
+
*
|
|
1310
|
+
* @param fn - Function to execute on each client (name is typed)
|
|
1311
|
+
* @returns BroadcastResults with typed property access and convenience methods
|
|
1312
|
+
*
|
|
1313
|
+
* @example
|
|
1314
|
+
* ```typescript
|
|
1315
|
+
* const results = await manager.broadcast(c => c.oneroster.users.create(user))
|
|
1316
|
+
*
|
|
1317
|
+
* // Typed property access (autocomplete works)
|
|
1318
|
+
* results.alpha.ok
|
|
1319
|
+
*
|
|
1320
|
+
* if (results.allSucceeded) {
|
|
1321
|
+
* console.log('Synced to all platforms!')
|
|
1322
|
+
* }
|
|
1323
|
+
*
|
|
1324
|
+
* results.succeeded.forEach(([name, user]) => {
|
|
1325
|
+
* console.log(`Created on ${name}:`, user.id)
|
|
1326
|
+
* })
|
|
1327
|
+
* ```
|
|
1328
|
+
*/
|
|
1329
|
+
broadcast<T>(fn: (client: TimebackClient, name: TNames) => T | Promise<T>): Promise<BroadcastResults<T, TNames>>;
|
|
1330
|
+
/**
|
|
1331
|
+
* Unregister and close a client.
|
|
1332
|
+
*
|
|
1333
|
+
* Note: This doesn't update the type — use a new manager if you need
|
|
1334
|
+
* type-safe tracking after unregistration.
|
|
1335
|
+
*
|
|
1336
|
+
* @param name - The name of the client to remove
|
|
1337
|
+
* @returns true if the client was removed, false if it didn't exist
|
|
1338
|
+
*/
|
|
1339
|
+
unregister(name: TNames): boolean;
|
|
1340
|
+
/**
|
|
1341
|
+
* Close all registered clients and clear the registry.
|
|
1342
|
+
*
|
|
1343
|
+
* Call this during application shutdown to release resources.
|
|
1344
|
+
*/
|
|
1345
|
+
close(): void;
|
|
1346
|
+
}
|
|
1347
|
+
|
|
1348
|
+
/**
|
|
1349
|
+
* Timeback API Endpoints
|
|
1350
|
+
*
|
|
1351
|
+
* Re-exports URL constants from the internal constants package.
|
|
1352
|
+
*/
|
|
1353
|
+
|
|
1354
|
+
/**
|
|
1355
|
+
* Get all service URLs for a given platform and environment.
|
|
1356
|
+
*
|
|
1357
|
+
* @param env - Target environment (staging or production)
|
|
1358
|
+
* @param platform - Target platform (defaults to 'BEYOND_AI')
|
|
1359
|
+
* @returns Service URLs for the environment
|
|
1360
|
+
*/
|
|
1361
|
+
declare function getServiceUrlsForEnv(env: Environment, platform?: Platform): EnvServiceUrls;
|
|
1362
|
+
|
|
1363
|
+
export { ApiError, ForbiddenError, NotFoundError, TimebackClient, TimebackManager, TimebackProvider, UnauthorizedError, ValidationError, getServiceUrlsForEnv, isApiError, whereToFilter };
|
|
1364
|
+
export type { AuthCheckResult, BroadcastResult, BroadcastResultMethods, BroadcastResults, EnvServiceUrls, Environment, FieldCondition, FieldOperators, FilterValue, OrCondition, TimebackClientConfig, WhereClause };
|