import { ActivityParams, WeeklyFactsParams, EnrollmentFactsParams, ListEnrollmentsParams, EnrollOptions, SubjectTrackInput, ListUsersParams } from '@timeback/types/zod'; export { ActivityParams, EnrollmentFactsParams, WeeklyFactsParams } from '@timeback/types/zod'; import { ActivityResponse, WeeklyFacts, EnrollmentFactsResponse, HighestGradeMastered, Application, ApplicationMetrics, Enrollment, ResetGoalsResult, DefaultClass, MapProfile, TimeSaved, SubjectTrack, SubjectTrackGroup, User, Role, DailyActivityMap, AggregatedMetrics } from '@timeback/types/protocols/edubridge'; export { ActivityMetricsData, ActivityResponse, AggregatedMetrics, DailyActivityMap, EnrollmentFacts, EnrollmentFactsResponse, FactsByAppMap, GradeMasteryData, HighestGradeMastered, SubjectMetrics, TimeSpentMetricsData, WeeklyFactRecord, WeeklyFacts } from '@timeback/types/protocols/edubridge'; /** * Type Definitions for `@timeback/internal-logger` * * Central type definitions used across all logger components. * These types define the contract between the logger, formatters, and consumers. */ /** * Log severity levels, ordered from least to most severe. * * - debug: Detailed diagnostic information for developers * - info: General operational messages (app started, request received) * - warn: Something unexpected but not breaking (deprecated API used) * - error: Something failed (request failed, database connection lost) */ type LogLevel = 'debug' | 'info' | 'warn' | 'error'; /** * Runtime environments that determine how logs are formatted. * * - terminal: Local development with colors and icons * - ci: CI/CD pipelines with plain text (no ANSI codes) * - production: JSON lines for log aggregation (DataDog, CloudWatch, etc.) * - browser: Browser console with CSS styling * - test: Test environment with no output */ type Environment$2 = 'terminal' | 'ci' | 'production' | 'browser' | 'test'; /** * Arbitrary key-value data attached to log entries. * * Context is merged into log output - in production it becomes top-level * JSON fields, in terminal it's displayed as key=value pairs. * * @example * log.info('User created', { userId: 123, email: 'foo@bar.com' }) */ type LogContext = Record; /** * A single log entry before it's formatted for output. * * This is the internal representation passed to formatters. * Formatters transform this into environment-specific output. */ interface LogEntry { /** Severity level of this log entry */ level: LogLevel; /** Human-readable log message */ message: string; /** Optional namespace/category (e.g., "api", "db", "auth") */ scope?: string; /** Optional structured data attached to this entry */ context?: LogContext; /** When this log entry was created */ timestamp: Date; } /** * Configuration options for creating a logger instance. */ interface LoggerOptions { /** * Logger scope/namespace for categorizing logs. * Child loggers append to this with colons: "api" → "api:users" */ scope?: string; /** * Minimum log level to output. * Logs below this level are silently ignored. * @default 'info' (or 'debug' if DEBUG env var is set) */ minLevel?: LogLevel; /** * Override automatic environment detection. * Useful for testing or forcing a specific format. */ environment?: Environment$2; /** * Default context added to every log entry from this logger. * Useful for request IDs, user IDs, etc. */ defaultContext?: LogContext; /** * Custom formatter override for this logger instance. * * When provided, this takes precedence over environment-based formatting. * Useful for tests, custom sinks, or temporarily suppressing output. */ formatter?: Formatter; } /** * Function that outputs a log entry in a specific format. * * Each environment has its own formatter. Formatters are responsible * for the actual console.log/write calls. */ type Formatter = (entry: LogEntry) => void; /** * Logger instance with environment-aware formatting. * * Instances are lightweight and can be created freely. * Common pattern: one logger per module/component. */ declare class Logger { /** Namespace for this logger (e.g., "api", "api:users") */ private scope?; /** Minimum level to output (logs below this are ignored) */ private minLevel; /** The detected or configured environment */ private environment; /** Optional explicit formatter override for this logger instance */ private explicitFormatter?; /** Context added to every log entry from this logger */ private defaultContext; /** * Create a new Logger instance. * * Usually you'd use createLogger() instead of new Logger(). */ constructor(options?: LoggerOptions); /** * Create a child logger with an additional scope segment. * * Child loggers inherit minLevel and defaultContext from parent. * Scope is appended with a colon separator. * * @param scope - Additional scope segment to append * @returns New Logger instance with extended scope * * @example * const api = createLogger({ scope: 'api' }) * const users = api.child('users') * users.info('Created') // scope: "api:users" */ child(scope: string): Logger; /** * Create a logger with additional default context. * * The new context is merged with existing default context. * Useful for adding request IDs, user IDs, etc. * * @param context - Additional context to include in all logs * @returns New Logger instance with extended context * * @example * const requestLog = log.withContext({ requestId: 'abc123' }) * requestLog.info('Processing') // requestId included automatically */ withContext(context: LogContext): Logger; /** * Log a debug message. * * Use for detailed diagnostic information useful during development. * These are typically filtered out in production. * * @param message - The log message * @param context - Optional key-value context to include with the log */ debug(message: string, context?: LogContext): void; /** * Log an info message. * * Use for general operational information. * Examples: server started, request received, job completed. * * @param message - The log message * @param context - Optional key-value context to include with the log */ info(message: string, context?: LogContext): void; /** * Log a warning message. * * Use for unexpected but non-breaking issues. * Examples: deprecated API used, retrying operation, approaching limit. * * @param message - The log message * @param context - Optional key-value context to include with the log */ warn(message: string, context?: LogContext): void; /** * Log an error message. * * Use for failures that need attention. * Examples: request failed, database error, unhandled exception. * * @param message - The log message * @param context - Optional key-value context to include with the log */ error(message: string, context?: LogContext): void; /** * Internal method that builds the log entry and passes it to the formatter. * * All public log methods (debug, info, warn, error) delegate here. * * @param level - The log level * @param message - The log message * @param context - Optional key-value context to include with the log */ private log; } /** * Interface for obtaining OAuth2 access tokens. * * Implementations handle token caching and refresh automatically. */ interface TokenProvider { /** * Get a valid access token. * * Returns a cached token if still valid, otherwise fetches a new one. * * @returns A valid access token string * @throws {Error} If token acquisition fails */ getToken(): Promise; /** * Invalidate the cached token. * * Forces the next getToken() call to fetch a fresh token. * Should be called when a request fails with 401 Unauthorized. * * Optional - not all implementations may support invalidation. */ invalidate?(): void; } /** * All supported platforms. */ declare const PLATFORMS: readonly ["BEYOND_AI", "LEARNWITH_AI"]; /** * Where Clause Types * * Type-safe object syntax for building filter expressions. */ /** * Primitive value types that can be used in filters. */ type FilterValue = string | number | boolean | Date; /** * Operators for a single field. * * @example * ```typescript * { status: { ne: 'deleted' } } * { score: { gt: 90 } } * { email: { contains: '@school.edu' } } * { role: { in: ['teacher', 'aide'] } } * ``` */ interface FieldOperators { /** Not equal */ ne?: T; /** Greater than */ gt?: T; /** Greater than or equal */ gte?: T; /** Less than */ lt?: T; /** Less than or equal */ lte?: T; /** Contains substring (strings only) */ contains?: T extends string ? string : never; /** Match any of the values */ in?: T[]; /** Match none of the values */ notIn?: T[]; } /** * A field condition can be: * - A direct value (implies equality) * - An object with operators */ type FieldCondition = T | FieldOperators; /** * Map filter field types to field conditions. * * Each field in F becomes an optional filter condition. * * @typeParam F - Filter fields type (e.g., UserFilterFields) */ type FilterFields = { [K in keyof F]?: FieldCondition; }; /** * OR condition for combining multiple field conditions. */ interface OrCondition { OR: WhereClause[]; } /** * A where clause for filtering entities. * * The type parameter F should be a filter fields type that defines * the available fields and their value types for filtering. * * Multiple fields at the same level are combined with AND. * Use `OR` for explicit OR logic. * * @typeParam F - Filter fields type (e.g., UserFilterFields) * * @example * ```typescript * // Simple equality (implicit AND) * { status: 'active', role: 'teacher' } * // → status='active' AND role='teacher' * ``` * * @example * ```typescript * // With operators * { status: { ne: 'deleted' }, score: { gte: 90 } } * // → status!='deleted' AND score>=90 * ``` * * @example * ```typescript * // OR condition * { OR: [{ role: 'teacher' }, { role: 'aide' }] } * // → role='teacher' OR role='aide' * ``` * * @example * ```typescript * // Match multiple values * { role: { in: ['teacher', 'aide'] } } * // → role='teacher' OR role='aide' * ``` */ type WhereClause = FilterFields | OrCondition; /** * Shared Types * * Common types for API client infrastructure. */ /** * Fetch function signature for HTTP requests. * Avoids Bun-specific extensions on `typeof fetch`. */ type FetchFn$1 = (input: string | URL | Request, init?: RequestInit) => Promise; /** * Supported Timeback platform implementations. */ type Platform$1 = (typeof PLATFORMS)[number]; /** * Supported deployment environments. */ type Environment$1 = 'staging' | 'production'; /** * Auth credentials for environment mode. * Token URL is derived automatically from environment. */ interface EnvAuth$1 { clientId: string; clientSecret: string; } /** * Auth credentials for explicit mode. * Includes authUrl for custom APIs. * @deprecated Use separate authUrl and ProviderAuth fields instead */ interface ExplicitAuth$1 { clientId: string; clientSecret: string; authUrl: string; } /** * Base configuration options shared by all modes. */ interface BaseConfig$1 { /** Request timeout in milliseconds */ timeout?: number; /** Custom fetch implementation */ fetch?: FetchFn$1; } /** * Environment-based configuration for Timeback APIs. */ interface EnvConfig extends BaseConfig$1 { /** Timeback platform implementation (defaults to 'BEYOND_AI') */ platform?: Platform$1; /** Target environment - determines base URL and token URL */ env: Environment$1; /** OAuth2 client credentials */ auth: EnvAuth$1; } /** * Environment-based configuration with shared token provider. */ interface TokenProviderEnvConfig extends BaseConfig$1 { /** Timeback platform implementation (defaults to 'BEYOND_AI') */ platform?: Platform$1; /** Target environment - determines base URL */ env: Environment$1; /** Shared token provider (from @timeback/auth) */ tokenProvider: TokenProvider; } /** * Explicit URL configuration for custom APIs. * Supports both authenticated and public/no-auth services. */ interface ExplicitConfig extends BaseConfig$1 { /** API base URL */ baseUrl: string; /** * OAuth2 token URL. Omit for public/no-auth services. * Can also be provided via auth.authUrl (legacy format). */ authUrl?: string; /** * OAuth2 credentials. Required if authUrl is provided. * Supports both ExplicitAuth (with authUrl) and ProviderAuth (without). */ auth?: ExplicitAuth$1 | ProviderAuth; /** * Use a built-in path profile by name. * Defaults to 'BEYOND_AI' if neither pathProfile nor paths is specified. */ pathProfile?: Platform$1; /** Custom path overrides (takes precedence over pathProfile) */ paths?: Partial; /** Not applicable to explicit config — use `EnvConfig` instead */ env?: never; } /** * Use pre-configured transport. */ interface TransportConfig extends BaseConfig$1 { /** Transport configuration */ transport: TransportLike; } /** * HTTP request options. */ interface RequestOptions$1 { /** HTTP method */ method?: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE'; /** Query parameters to append to the URL */ params?: Record; /** Request body (will be JSON-serialized) */ body?: unknown; /** Additional headers to include */ headers?: Record; /** * Unique identifier for this request. * Used for log correlation and debugging. * Auto-generated if not provided. */ requestId?: string; } /** * Duck-typed transport interface for testing and advanced use. */ interface TransportLike { /** Base URL of the API */ baseUrl: string; /** Make an authenticated request */ request(path: string, options?: RequestOptions$1): Promise; } /** * Configuration using a pre-configured transport. * * For advanced use cases like sharing a transport between clients * or using a custom transport implementation. * * @template T - Transport type (defaults to TransportLike, clients should specify their full transport type) */ interface TransportOnlyConfig { /** Existing transport instance */ transport: T; } /** * Union of all client configuration types. */ type ClientConfig = EnvConfig | TokenProviderEnvConfig | ExplicitConfig | TransportConfig | Partial; /** * Parameters for listing resources with pagination, sorting, and filtering. * * Common across all Timeback APIs (OneRoster, Edubridge, QTI, etc.). * * @typeParam T - Entity type for type-safe `where` clause (defaults to unknown) * * @example * ```typescript * // Type-safe where * client.users.list({ * where: { status: 'active', role: 'teacher' }, * sort: 'familyName', * }) * ``` */ interface ListParams { /** * Maximum items per page. * @default 100 */ limit?: number; /** * Number of items to skip (for pagination). * @default 0 */ offset?: number; /** * Field name to sort results by. * * Type-safe: only valid field names for this resource are accepted. * * @example * ```typescript * sort: 'familyName' * ``` */ sort?: keyof T & string; /** * Sort direction. * @default "asc" */ orderBy?: 'asc' | 'desc'; /** * Type-safe filter using object syntax. * * Multiple fields are combined with AND. Use `OR` for OR logic. * * @example * ```typescript * // Simple equality * where: { status: 'active' } * ``` * * @example * ```typescript * // Multiple fields (AND) * where: { status: 'active', role: 'teacher' } * ``` * * @example * ```typescript * // With operators * where: { score: { gte: 90 }, status: { ne: 'deleted' } } * ``` * * @example * ```typescript * // OR condition * where: { role: { in: ['teacher', 'aide'] } } * ``` */ where?: WhereClause; /** * Fields to include in the response. * Reduces payload size by requesting only needed fields. * @example ['sourcedId', 'givenName', 'familyName'] */ fields?: string[]; /** * Free-text search across multiple fields (proprietary extension). * For users: searches givenName, familyName, email. * @example "john@example.com" */ search?: string; /** * Maximum total items to return across all pages. * * Unlike `limit` (which sets page size), `max` caps the total number * of items yielded by the paginator. Pagination stops once this many * items have been returned. * * @example * ```typescript * // Get at most 50 users total * client.users.list({ max: 50 }) * ``` */ max?: number; } /** * Response from a paginated API request. */ interface PaginatedResponse { /** Array of items in this page */ data: T[]; /** Whether more pages are available */ hasMore: boolean; /** Total count of items (if provided by server) */ total?: number; } /** * Result of fetching a single page of resources. * * @typeParam T - The type of items in the page */ interface PageResult { /** Array of items in this page */ data: T[]; /** Whether more pages are available */ hasMore: boolean; /** Total count of items (if provided by server) */ total?: number; /** Offset to use for fetching the next page */ nextOffset?: number; } /** * Result of an auth check operation. */ interface AuthCheckResult$1 { /** Whether auth succeeded */ ok: boolean; /** Time taken to complete the check (ms) */ latencyMs: number; /** Error message if failed */ error?: string; /** Detailed check results */ checks: { /** Token acquisition succeeded */ tokenAcquisition: boolean; }; } /** * Config Types * * Types for TimebackProvider and provider resolution. */ /** * Caliper API path profile. * Defines paths for Caliper operations. Use `null` for unsupported operations. */ interface CaliperPaths { /** Path for sending events (POST) */ send: string; /** Path for validating events (POST), null if not supported */ validate: string | null; /** Path for listing events (GET), null if not supported */ list: string | null; /** Path template for getting single event (GET), use {id} placeholder */ get: string | null; /** Path template for job status (GET), use {id} placeholder */ jobStatus: string | null; } /** * Webhook API path profile. * Defines paths for webhook management operations. * Nullability is at the platform level (`webhooks: WebhookPaths | null` in PlatformPaths). */ interface WebhookPaths { /** Path for listing webhooks (GET) */ webhookList: string; /** Path template for getting a single webhook (GET), use {id} placeholder */ webhookGet: string; /** Path for creating a webhook (POST) */ webhookCreate: string; /** Path template for updating a webhook (PUT), use {id} placeholder */ webhookUpdate: string; /** Path template for deleting a webhook (DELETE), use {id} placeholder */ webhookDelete: string; /** Path template for activating a webhook (PUT), use {id} placeholder */ webhookActivate: string; /** Path template for deactivating a webhook (PUT), use {id} placeholder */ webhookDeactivate: string; /** Path for listing all webhook filters (GET) */ webhookFilterList: string; /** Path template for getting a single webhook filter (GET), use {id} placeholder */ webhookFilterGet: string; /** Path for creating a webhook filter (POST) */ webhookFilterCreate: string; /** Path template for updating a webhook filter (PUT), use {id} placeholder */ webhookFilterUpdate: string; /** Path template for deleting a webhook filter (DELETE), use {id} placeholder */ webhookFilterDelete: string; /** Path template for listing filters by webhook (GET), use {webhookId} placeholder */ webhookFiltersByWebhook: string; } /** * Reporting API path profile. * Defines paths for reporting MCP and REST operations. * Nullability is at the platform level (`reporting: ReportingPaths | null` in PlatformPaths). */ interface ReportingPaths { /** Path for the reporting MCP JSON-RPC endpoint (POST) */ mcp: string; /** Path template for executing a saved query (GET), use {id} placeholder */ savedQueryExecute: string; /** Path template for checking reporting group membership (GET), use {email} placeholder */ adminGroupCheck: string; /** Path template for adding a user to the reporting group (POST), use {email} placeholder */ adminGroupAdd: string; /** Path template for removing a user from the reporting group (DELETE), use {email} placeholder */ adminGroupRemove: string; } /** * OneRoster API path profile. * Defines the base path prefix for all OneRoster resources. */ interface OneRosterPaths { /** Base path prefix for rostering resources (users, schools, classes, etc.) */ rostering: string; /** Base path prefix for gradebook resources (lineItems, results, etc.) */ gradebook: string; /** Base path prefix for resources API (digital learning resources) */ resources: string; } /** * Edubridge API path profile. * Defines path prefixes for Edubridge operations. */ interface EdubridgePaths { /** Base path prefix for all Edubridge resources */ base: string; } /** * PowerPath API path profile. * Defines path prefixes for PowerPath operations. */ interface PowerPathPaths { /** Base path prefix for all PowerPath resources */ base: string; } /** * CASE API path profile. * Defines path prefix for CASE (Competency and Academic Standards Exchange) operations. */ interface CasePaths { /** Base path prefix for all CASE resources */ base: string; } /** * CLR API path profile. * Defines path prefixes for CLR (Comprehensive Learner Record) operations. */ interface ClrPaths { /** Path for upserting CLR credentials (POST) */ credentials: string; /** Path for API discovery (GET) */ discovery: string; } /** * Platform path profiles for all services. * Use `null` to indicate a service is not supported on the platform. */ interface PlatformPaths { caliper: CaliperPaths; oneroster: OneRosterPaths; webhooks: WebhookPaths | null; reporting: ReportingPaths | null; edubridge: EdubridgePaths | null; powerpath: PowerPathPaths | null; clr: ClrPaths | null; case: CasePaths | null; } /** * Services that have path configuration. * Subset of ServiceName - excludes services without path profiles (e.g., 'qti'). */ type PathEnabledService = keyof PlatformPaths; /** * Supported Timeback platform implementations. */ type Platform = (typeof PLATFORMS)[number]; /** * Supported deployment environments. */ type Environment = 'staging' | 'production'; /** * Supported service names. */ type ServiceName = 'oneroster' | 'caliper' | 'webhooks' | 'reporting' | 'edubridge' | 'qti' | 'powerpath' | 'clr' | 'case'; /** * Resolved endpoint for a single service. */ interface ResolvedEndpoint { /** Base URL for the service API */ baseUrl: string; /** OAuth2 token URL for this endpoint. Undefined for public/no-auth services. */ authUrl?: string; } /** * Auth credentials for a provider. */ interface ProviderAuth { clientId: string; clientSecret: string; } /** * Configuration for environment-based provider. * Uses known Timeback platform endpoints. */ interface ProviderEnvConfig { /** Timeback platform (defaults to 'BEYOND_AI') */ platform?: Platform; /** Target environment */ env: Environment; /** OAuth2 credentials */ auth: ProviderAuth; /** Request timeout in milliseconds */ timeout?: number; } /** * Configuration for explicit URL provider. * Single base URL for all services. */ interface ProviderExplicitConfig { /** Base URL for all services */ baseUrl: string; /** OAuth2 token URL. Omit for public/no-auth services. */ authUrl?: string; /** OAuth2 credentials. Required if authUrl is provided. */ auth?: ProviderAuth; /** Request timeout in milliseconds */ timeout?: number; /** * Use a built-in path profile by name. * Defaults to 'BEYOND_AI' if neither pathProfile nor paths is specified. */ pathProfile?: Platform; /** Custom path overrides (takes precedence over pathProfile) */ paths?: Partial; } /** * Configuration for multi-service provider. * Different URLs for different services. */ interface ProviderServicesConfig { /** Per-service base URLs */ services: Partial>; /** OAuth2 token URL. Omit for public/no-auth services. */ authUrl?: string; /** OAuth2 credentials. Required if authUrl is provided. */ auth?: ProviderAuth; /** Request timeout in milliseconds */ timeout?: number; /** * Use a built-in path profile by name. * Defaults to 'BEYOND_AI' if neither pathProfile nor paths is specified. */ pathProfile?: Platform; /** Custom path overrides (takes precedence over pathProfile) */ paths?: Partial; } /** * Union of all provider configuration types. */ type TimebackProviderConfig = ProviderEnvConfig | ProviderExplicitConfig | ProviderServicesConfig; /** * Provider template - endpoints without auth. * Used internally to define available platform+env combinations. */ interface ProviderTemplate { platform: Platform; env: Environment; } /** * Registry of provider templates indexed by platform and environment. * * Use `satisfies ProviderRegistry` when defining a registry for type checking. * * @example * const myRegistry = { * defaultPlatform: 'MY_PLATFORM', * templates: { * MY_PLATFORM: { * staging: { platform: 'BEYOND_AI', env: 'staging' }, * production: { platform: 'BEYOND_AI', env: 'production' }, * }, * }, * } satisfies ProviderRegistry */ interface ProviderRegistry { /** Default platform when none specified */ defaultPlatform: string; /** Available templates indexed by platform → env */ templates: Record>; } /** * Client config that accepts a pre-built provider. */ interface ProviderClientConfig { /** Pre-built provider */ provider: TimebackProvider; } /** * Timeback Provider * * Encapsulates platform connection configuration including endpoints and auth. * Providers are complete "connection" objects that clients consume. */ /** * Timeback Provider - encapsulates a complete platform connection. * * A provider contains everything needed to connect to Timeback APIs: * - Service endpoints (URLs) * - Authentication credentials * - Configuration options * * Providers can be created from: * - Platform + environment (uses known Timeback endpoints) * - Explicit base URL (single URL for all services) * - Per-service URLs (different URLs for each service) * * @example * ```typescript * // Environment-based provider (Timeback hosted) * const provider = new TimebackProvider({ * platform: 'BEYOND_AI', * env: 'staging', * auth: { clientId: '...', clientSecret: '...' }, * }) * ``` * * @example * ```typescript * // Explicit URL provider (self-hosted) * const provider = new TimebackProvider({ * baseUrl: 'https://api.myschool.edu', * authUrl: 'https://auth.myschool.edu/oauth/token', * auth: { clientId: '...', clientSecret: '...' }, * }) * ``` * * @example * ```typescript * // Per-service URLs * const provider = new TimebackProvider({ * services: { * oneroster: 'https://roster.myschool.edu', * caliper: 'https://analytics.myschool.edu', * }, * authUrl: 'https://auth.myschool.edu/oauth/token', * auth: { clientId: '...', clientSecret: '...' }, * }) * ``` */ declare class TimebackProvider { /** Platform identifier (if using known platform) */ readonly platform?: Platform; /** Environment (if using known platform) */ readonly env?: Environment; /** OAuth2 credentials. Undefined for public/no-auth services. */ readonly auth?: ProviderAuth; /** Request timeout in milliseconds */ readonly timeout: number; /** Resolved endpoints for each service */ /** @internal */ readonly _endpoints: Partial>; /** Token URL for authentication. Undefined for public/no-auth services. */ /** @internal */ readonly _authUrl?: string; /** OAuth2 scope to request with access tokens. */ /** @internal */ readonly _tokenScope?: string; /** API path profiles for this platform */ /** @internal */ readonly _pathProfiles: PlatformPaths; /** Cached TokenManagers by authUrl (for token sharing) */ /** @internal */ readonly _tokenManagers: Map; /** * Create a new TimebackProvider. * * @param config - Provider configuration (env-based, explicit URL, or per-service) * @throws {Error} If configuration is invalid or missing required fields */ constructor(config: TimebackProviderConfig); /** * Get the resolved endpoint for a specific service. * * @param service - Service name (oneroster, caliper, edubridge, qti, powerpath) * @returns Resolved endpoint with baseUrl and authUrl * @throws If the service is not configured in this provider */ getEndpoint(service: ServiceName): ResolvedEndpoint; /** * Check if a service is available in this provider. * * @param service - Service name to check * @returns True if the service is configured */ hasService(service: ServiceName): boolean; /** * Get all configured service names. * * @returns Array of service names available in this provider */ getAvailableServices(): ServiceName[]; /** * Get the token URL for this provider. * @returns The token URL for authentication */ getTokenUrl(): string | undefined; /** * Get endpoint with paths for a service that has path configuration. * * @param service - Service name that has paths in PlatformPaths * @returns Resolved endpoint with baseUrl, authUrl, and paths * @throws If service is not configured or not supported on this platform */ getEndpointWithPaths(service: S & ServiceName): ResolvedEndpoint & { paths: NonNullable; }; /** * Get all path profiles for this provider (raw, may contain nulls). * * @returns Platform path profiles */ getPaths(): PlatformPaths; /** * Get paths for a specific service. * * @param service - Service name * @returns Path configuration for the service * @throws If the service is not supported on this platform */ getServicePaths(service: S): NonNullable; /** * Check if a service is supported on this platform. * * @param service - Service name * @returns true if the service has path configuration */ hasServiceSupport(service: PathEnabledService): boolean; /** * Get a TokenProvider for a specific service. * * TokenProviders are cached by authUrl, so services sharing the same * token endpoint will share the same cached OAuth tokens. * * @param service - Service name (oneroster, caliper, edubridge, qti, powerpath) * @returns Cached TokenProvider for the service's token endpoint, or undefined for public/no-auth services * @throws If the service is not configured in this provider * @throws If auth is required but not configured */ getTokenProvider(service: ServiceName): TokenProvider | undefined; /** * Verify that OAuth authentication is working. * * Attempts to acquire a token using the provider's credentials. * Returns a health check result with success/failure and latency info. * * @returns Auth check result * @throws {Error} If no auth is configured on this provider */ checkAuth(): Promise; /** * Invalidate all cached OAuth tokens. * * Call this when closing the client or when tokens need to be refreshed. * New tokens will be acquired on the next API call. */ invalidateTokens(): void; } /** * Transport Types * * Types for HTTP transport layer. */ /** * Fetch function signature for HTTP requests. * Avoids Bun-specific extensions on `typeof fetch`. */ type FetchFn = (input: string | URL | Request, init?: RequestInit) => Promise; /** * HTTP request options. */ interface RequestOptions { /** HTTP method */ method?: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE'; /** Query parameters to append to the URL */ params?: Record; /** Request body (will be JSON-serialized) */ body?: unknown; /** Additional headers to include */ headers?: Record; /** * Unique identifier for this request. * Used for log correlation and debugging. * Auto-generated if not provided. */ requestId?: string; } /** * Auth credentials for environment mode. * Token URL is derived automatically from environment. */ interface EnvAuth { clientId: string; clientSecret: string; } /** * Auth credentials for explicit mode. * Requires explicit authUrl for custom APIs. */ interface ExplicitAuth { clientId: string; clientSecret: string; authUrl: string; } /** * Base configuration options shared by all modes. */ interface BaseConfig { /** Request timeout in milliseconds */ timeout?: number; /** Custom fetch implementation */ fetch?: FetchFn; } /** * Internal resolved transport configuration. */ interface ResolvedTransportConfig { /** Base URL of the API */ baseUrl: string; /** Request timeout in milliseconds */ timeout: number; /** Fetch implementation */ fetch: FetchFn; /** Token provider for authentication. Undefined for public/no-auth services. */ tokenProvider?: TokenProvider; } /** * Transport configuration with explicit auth. */ interface TransportConfigWithAuth extends BaseConfig { baseUrl: string; auth: ExplicitAuth; tokenProvider?: never; } /** * Transport configuration with shared token provider. */ interface TransportConfigWithTokenProvider extends BaseConfig { baseUrl: string; tokenProvider: TokenProvider; auth?: never; } /** * Transport configuration for public/no-auth services. */ interface TransportConfigNoAuth extends BaseConfig { baseUrl: string; auth?: never; tokenProvider?: never; } /** * Configuration for BaseTransport. */ type BaseTransportConfig = TransportConfigWithAuth | TransportConfigWithTokenProvider | TransportConfigNoAuth; /** * Options for creating a BaseTransport. */ interface BaseTransportOptions { /** Transport configuration */ config: BaseTransportConfig; /** Logger instance for request/response logging */ logger: Logger; } /** * Result of an auth check operation. */ interface AuthCheckResult { /** Whether auth succeeded */ ok: boolean; /** Time taken to complete the check (ms) */ latencyMs: number; /** Error message if failed */ error?: string; /** Detailed check results */ checks: { /** Token acquisition succeeded */ tokenAcquisition: boolean; }; } /** * Base Transport Layer * * HTTP transport with OAuth2 authentication, retries, and error handling. * Clients can extend this for protocol-specific features. * */ /** * Base HTTP transport layer for API communication. * * Handles OAuth2 authentication, request/response lifecycle, * and automatic retries for transient failures. * * Clients can extend this class to add protocol-specific features * like custom error parsing or pagination. */ declare class BaseTransport { protected readonly config: ResolvedTransportConfig; protected readonly log: Logger; /** * Create a new BaseTransport instance. * * @param options - Transport options with config and logger */ constructor(options: BaseTransportOptions); /** * The base URL for API requests. * @returns The base URL */ get baseUrl(): string; /** * Make an authenticated request to the API. * * Automatically retries on transient failures (429, 503). * * @template T - Expected response type * @param path - API endpoint path * @param options - Request options including method, params, body * @returns Parsed JSON response * @throws {ApiError} On API errors (4xx/5xx responses) */ request(path: string, options?: RequestOptions): Promise; /** * Check whether a resource exists at the given path. * * Returns `true` for successful 2xx responses, `false` only for 404 Not Found, * and rethrows all other errors. * * @param path - API endpoint path * @param options - Request options including method, params, body * @returns Promise resolving to whether the resource exists */ exists(path: string, options?: RequestOptions): Promise; /** * Make a raw request, returning the Response object. * * ## Retry Behavior * Automatically retries on transient failures (429, 503) with exponential * backoff. Respects Retry-After header when present. * * ## Timeout Behavior * Uses an operation-level timeout that spans ALL retry attempts. * If configured timeout is 30s, the entire operation (including retries * and backoff delays) must complete within 30s total. * * ## Flow * 1. Build URL from path and query params * 2. Start operation timer * 3. Loop up to MAX_RETRIES times: * a. Check if we've exceeded the operation deadline * b. Get OAuth token (may be cached) * c. Make the HTTP request with per-request timeout * d. If 429/503 and not last attempt → calculate backoff and retry * e. If other error → throw appropriate ApiError subclass * f. If success → return response * 4. If all retries exhausted → throw "Max retries exceeded" * * @param path - API endpoint path (relative to baseUrl) * @param options - Request options (method, params, body, headers) * @returns Raw fetch Response for custom handling * @throws {ApiError} On timeout, non-retryable errors, or max retries exceeded */ requestRaw(path: string, options?: RequestOptions): Promise; /** * Get a valid OAuth2 access token. * @returns Promise resolving to access token or undefined */ protected getAccessToken(): Promise; /** * Construct full URL with query parameters. * * @param path - The relative path or absolute URL * @param params - Query parameters * @returns Full URL string * @throws {Error} If path is an absolute URL (security protection) */ protected buildUrl(path: string, params?: Record): string; /** * Parse successful response or delegate to error handler. * @param response - The fetch Response * @returns Parsed response as type T */ protected handleResponse(response: Response): Promise; /** * Parse JSON response with context-preserving error handling. * * Unlike raw `response.json()`, this method: * - Logs structured error context (URL, status, content-type, body preview) * - Throws `ApiError` with `parseError` and `body` in the response object * - Aids debugging when upstream services return malformed JSON * * @template T - Expected shape of the parsed response * @param response - The fetch Response to parse * @returns Parsed JSON as type T * @throws {ApiError} When JSON parsing fails, with status code and body preview */ protected parseJsonResponse(response: Response): Promise; /** * Parse error response and throw appropriate ApiError subclass. * * Handles both JSON and non-JSON error responses gracefully. * Clients can override this to add protocol-specific error parsing. * * @param response - The error Response (status >= 400) * @param requestId - Request ID for log correlation * @throws {UnauthorizedError} For 401 responses (also invalidates token) * @throws {ForbiddenError} For 403 responses * @throws {NotFoundError} For 404 responses * @throws {ValidationError} For 422 responses * @throws {ApiError} For all other error status codes */ protected handleErrorResponse(response: Response, requestId?: string): Promise; /** * Extract error message from response body. * * Checks common error formats: * - `message` (most APIs) * - `error` (some APIs) * - `imsx_description` (IMS Global: OneRoster, Caliper, QTI) * * Override in client transports for API-specific error formats * not covered here (e.g., Edubridge's `errors[]` array format). * * @param body - The error response body * @param fallback - Fallback message if none found * @returns Extracted error message */ protected extractErrorMessage(body: unknown, fallback: string): string; /** * Delay execution for retry backoff. * * @param ms - Number of milliseconds to delay * @returns Promise that resolves after delay */ protected sleep(ms: number): Promise; /** * Parse Retry-After header value. * * Handles both formats per RFC 7231: * - Numeric seconds: "120" * - HTTP-date: "Wed, 21 Oct 2025 07:28:00 GMT" * * @param retryAfter - Retry-After header value * @param attempt - Current attempt number (0-based) * @returns Delay in milliseconds */ protected parseRetryAfter(retryAfter: string | null, attempt: number): number; } /** * Transport interface for Edubridge client. * * Extends base transport requirements with Edubridge-specific paths. * Required when using transport mode with EdubridgeClient. */ interface EdubridgeTransportLike { /** Base URL of the API */ baseUrl: string; /** API path profiles for Edubridge operations */ paths: EdubridgePaths; /** Make an authenticated request */ request(path: string, options?: RequestOptions): Promise; } /** * All supported Edubridge client configuration types. * * Supports four modes: * - **Provider mode**: `{ provider: TimebackProvider }` — pre-built provider with token sharing * - **Environment mode**: `{ platform?, env, auth }` — Timeback hosted APIs * - **Explicit mode**: `{ baseUrl, auth: { authUrl } }` — custom API URLs * - **Transport mode**: `{ transport }` — custom transport with paths * * The `platform` field (in env mode) selects which Timeback implementation to use: * - `'BEYOND_AI'` (default): BeyondAI's Timeback platform * - `'LEARNWITH_AI'`: Samy's LearnWith.AI platform */ type EdubridgeClientConfig = ClientConfig | TransportOnlyConfig | ProviderClientConfig; /** * Configuration for Edubridge transport. */ interface EdubridgeTransportConfig extends TransportConfigWithTokenProvider { /** API path profiles for Edubridge operations */ paths: EdubridgePaths; } /** * Instance type of EdubridgeClient. */ type EdubridgeClientInstance = InstanceType; /** * Analytics Resource * * Student activity data and metrics. */ /** * Analytics resource for retrieving student activity data. * * Provides access to activity metrics, weekly facts, and grade mastery data. */ declare class AnalyticsResource { private readonly transport; constructor(transport: EdubridgeTransportLike); /** * Get activity data for a date range. * * Returns metrics grouped by date, then by subject. * Accepts dates in YYYY-MM-DD or full ISO 8601 format. * * Bare dates are expanded to cover the full day. When `timezone` is provided, * day boundaries are computed in that timezone before conversion to UTC. * * @param params - Query parameters including email or studentId, startDate, endDate * @returns Full activity response including `facts` and `factsByApp` */ getActivity(params: ActivityParams): Promise; /** * Get weekly facts for a student. * * Returns individual facts grouped by date for a specific week. * Accepts weekDate in YYYY-MM-DD or full ISO 8601 format. * * @param params - Query parameters including email or studentId and weekDate * @returns Weekly facts data */ getWeeklyFacts(params: WeeklyFactsParams): Promise; /** * Get aggregated facts for an enrollment. * * Returns aggregated metrics for all activity within an enrollment. * Accepts dates in YYYY-MM-DD or full ISO 8601 format. * * @param params - Query parameters including enrollmentId and optional date filters * @returns Full enrollment facts response including `facts` and `factsByApp` */ getEnrollmentFacts(params: EnrollmentFactsParams): Promise; /** * Get the highest grade a student has mastered for a subject. * * Returns grade data from multiple sources (Edulastic, placement tests, test-out). * * @param studentId - Student ID * @param subject - Subject name * @returns Highest grade mastered data */ getHighestGradeMastered(studentId: string, subject: string): Promise; } /** * Applications Resource * * Manage and retrieve applications available in the system. */ /** * Applications resource for managing learning platforms. * * Applications represent different learning platforms or educational * software that can be integrated with Timeback. */ declare class ApplicationsResource { private readonly transport; constructor(transport: EdubridgeTransportLike); /** * List all applications. * * @returns List of applications */ list(): Promise; /** * Get metrics for an application. * * @param applicationSourcedId - Application ID * @returns Application metrics */ getMetrics(applicationSourcedId: string): Promise; } /** * Enrollments Resource * * Simplified, course-centric enrollment management. */ /** * Enrollments resource for course-centric enrollment management. * * Provides simplified methods to enroll/unenroll users in courses * without needing to understand the underlying OneRoster academic hierarchy. */ declare class EnrollmentsResource { private readonly transport; constructor(transport: EdubridgeTransportLike); /** * List enrollments with filtering. * * @param params - Query parameters including userId filter * @returns List of course enrollments */ list(params: ListEnrollmentsParams): Promise; /** * Enroll a user in a course. * * Automatically handles creating the appropriate class and academic session * records required by OneRoster. * * @param userId - User ID to enroll * @param courseId - Course ID to enroll in * @param schoolId - Optional school ID (uses user's primary org if not specified) * @param options - Enrollment options (role, metadata, etc.) * @returns Created enrollment */ enroll(userId: string, courseId: string, schoolId?: string, options?: EnrollOptions): Promise; /** * Unenroll a user from a course. * * Marks the enrollment as 'tobedeleted'. * * @param userId - User ID to unenroll * @param courseId - Course ID to unenroll from * @param schoolId - Optional school ID */ unenroll(userId: string, courseId: string, schoolId?: string): Promise; /** * Reset enrollment goals for all users in a course. * * @param courseId - Course ID to reset goals for * @returns Result with count of updated enrollments */ resetGoals(courseId: string): Promise; /** * Reset a user's progress in a course. * * Marks all assessment results for the user/course as 'tobedeleted'. * * @param userId - User ID * @param courseId - Course ID */ resetProgress(userId: string, courseId: string): Promise; /** * Get the default class for a course. * * @param courseId - Course ID * @param schoolId - Optional school ID * @returns Default class and term information */ getDefaultClass(courseId: string, schoolId?: string): Promise; } /** * Learning Reports Resource * * Student learning reports and time tracking. */ /** * Learning Reports resource for student progress data. * * Provides access to MAP profiles and time saved metrics. */ declare class LearningReportsResource { private readonly transport; constructor(transport: EdubridgeTransportLike); /** * Get MAP profile for a user. * * @param userId - User ID * @returns MAP profile data */ getMapProfile(userId: string): Promise; /** * Get time saved metrics for a user. * * @param userId - User ID * @returns Time saved data */ getTimeSaved(userId: string): Promise; } /** * Subject Track Resource * * Manage subject track mappings. */ /** * Subject Track resource for managing subject-to-course mappings. * * Subject tracks determine the target course for each subject and grade level. * For example, for subject 'Math' grade level '9', the target course can be * 'Math Academy 9th Grade'. */ declare class SubjectTrackResource { private readonly transport; constructor(transport: EdubridgeTransportLike); /** * List all subject tracks. * * @returns List of subject tracks */ list(): Promise; /** * Create or update a subject track. * * @param data - Subject track data * @returns The created or updated subject track */ upsert(data: SubjectTrackInput): Promise; /** * Delete a subject track. * * @param id - Subject track ID */ delete(id: string): Promise; /** * List all subject track groups. * * @returns List of subject track groups */ listGroups(): Promise; } /** * Users Resource * * Enhanced user management beyond standard OneRoster. */ /** * Users resource for querying users with enhanced filtering. * * Provides role-based filtering and search capabilities beyond * the standard OneRoster API. */ declare class UsersResource { private readonly transport; constructor(transport: EdubridgeTransportLike); /** * List users with filtering. * * Returns users who have exclusively the specified role(s) and no other roles. * * @param params - Query parameters including required roles filter * @returns List of matching users */ list(params: ListUsersParams): Promise; /** * List all students. * * Convenience method for listing users with student role. * * @param params - Optional query parameters * @returns List of students */ listStudents(params?: Omit): Promise; /** * List all teachers. * * Convenience method for listing users with teacher role. * * @param params - Optional query parameters * @returns List of teachers */ listTeachers(params?: Omit): Promise; /** * Search users by role. * * @param roles - Roles to filter by * @param search - Search term * @param limit - Maximum results * @returns List of matching users */ search(roles: Role[], search: string, limit?: number): Promise; } /** * Edubridge Client * * Main entry point for the Edubridge SDK. */ /** * Edubridge API client for simplified enrollment and analytics operations. * * Provides access to Edubridge endpoints including course-centric enrollments, * user management, analytics, and learning reports. * * @example * ```typescript * // Environment mode (Timeback APIs) * const client = new EdubridgeClient({ * env: 'staging', // or 'production' * auth: { * clientId: 'your-client-id', * clientSecret: 'your-client-secret', * }, * }) * ``` * * @example * ```typescript * // Provider mode (shared tokens) * import { TimebackProvider } from '@timeback/internal-client-infra' * * const provider = new TimebackProvider({ * platform: 'BEYOND_AI', * env: 'staging', * auth: { clientId: '...', clientSecret: '...' }, * }) * * const client = new EdubridgeClient({ provider }) * ``` * * @example * ```typescript * // Explicit mode (custom API) * const client = new EdubridgeClient({ * baseUrl: 'https://api.example.com', * auth: { * clientId: 'your-client-id', * clientSecret: 'your-client-secret', * authUrl: 'https://auth.example.com/oauth2/token', * }, * }) * ``` * * @example * ```typescript * // Environment variables fallback * // Set EDUBRIDGE_BASE_URL, EDUBRIDGE_TOKEN_URL, * // EDUBRIDGE_CLIENT_ID, EDUBRIDGE_CLIENT_SECRET * const client = new EdubridgeClient() * ``` */ declare const EdubridgeClient: { new (config?: EdubridgeClientConfig): { readonly transport: EdubridgeTransportLike; readonly _provider?: TimebackProvider | undefined; readonly enrollments: EnrollmentsResource; readonly users: UsersResource; readonly analytics: AnalyticsResource; readonly applications: ApplicationsResource; readonly subjectTracks: SubjectTrackResource; readonly learningReports: LearningReportsResource; getTransport(): EdubridgeTransportLike; checkAuth(): Promise; }; }; /** * Edubridge Client Factory * * Creates EdubridgeClient classes bound to specific provider registries. */ /** * Create an EdubridgeClient class bound to a specific provider registry. * * @param registry - Provider registry to use (defaults to all Timeback platforms) * @returns EdubridgeClient class bound to the registry */ declare function createEdubridgeClient(registry?: ProviderRegistry): { new (config?: EdubridgeClientConfig): { /** @internal */ readonly transport: EdubridgeTransportLike; /** @internal */ readonly _provider?: TimebackProvider | undefined; /** Query and manage student enrollments in courses, programs, and learning paths */ readonly enrollments: EnrollmentsResource; /** Query and manage user accounts and profiles in the learning platform */ readonly users: UsersResource; /** Access learning analytics including engagement metrics and progress tracking */ readonly analytics: AnalyticsResource; /** Query and manage student applications and admission workflows */ readonly applications: ApplicationsResource; /** Query and manage subject tracks defining structured learning paths and curricula */ readonly subjectTracks: SubjectTrackResource; /** Access detailed learning progress reports and completion status */ readonly learningReports: LearningReportsResource; /** * Get the underlying transport for advanced use cases. * @returns The transport instance used by this client */ getTransport(): EdubridgeTransportLike; /** * Verify that OAuth authentication is working. * @returns Auth check result * @throws {Error} If client was initialized with custom transport (no provider) */ checkAuth(): Promise; }; }; /** * Aggregate activity metrics from a DailyActivityMap. * * Sums up all metrics across dates and subjects into a single totals object. * * @param data - Activity data grouped by date and subject * @returns Aggregated totals * * @example * ```typescript * const activity = await client.analytics.getActivity({ ... }) * const totals = aggregateActivityMetrics(activity.facts) * console.log(`Total XP: ${totals.totalXp}`) * ``` */ declare function aggregateActivityMetrics(data: DailyActivityMap): AggregatedMetrics; /** * Transport Layer * * HTTP transport for Edubridge API communication. */ /** * HTTP transport layer for Edubridge API communication. * * Uses body-based pagination (totalCount, pageNumber, pageCount in response body). */ declare class Transport extends BaseTransport { /** API path profiles for Edubridge operations */ readonly paths: EdubridgePaths; constructor(config: EdubridgeTransportConfig); /** * Make a paginated request using body-based pagination. * * Edubridge APIs return pagination metadata in the response body: * - `totalCount`: Total items across all pages * - `pageCount`: Total number of pages * - `pageNumber`: Current page (1-indexed) * * The returned `data` is the full response body. Use Paginator's `unwrapKey` * to extract the actual items (e.g., "users", "enrollments"). * * @template T - Expected item type in the response * @param path - API endpoint path * @param options - Request options * @returns Normalized paginated response with body as data */ requestPaginated(path: string, options?: RequestOptions): Promise>; /** * Extract error message from Edubridge API error response. * * Edubridge returns errors in array format: * - `errors[].message`: High-level error message * - `errors[].detail`: More specific error detail * - `errors[].meta.issues[]`: Field-level validation errors * * @param body - The error response body * @param fallback - Fallback message if extraction fails * @returns Human-readable error message with field details */ protected extractErrorMessage(body: unknown, fallback: string): string; } export { EdubridgeClient, Transport, aggregateActivityMetrics, createEdubridgeClient }; export type { AuthCheckResult, EdubridgeClientConfig, EdubridgeClientInstance, EnvAuth, Environment, ExplicitAuth, ListParams, PageResult };