@churchapps/content-providers 0.1.0

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.
@@ -0,0 +1,671 @@
1
+ interface ContentProviderAuthData {
2
+ access_token: string;
3
+ refresh_token: string;
4
+ token_type: string;
5
+ created_at: number;
6
+ expires_in: number;
7
+ scope: string;
8
+ }
9
+ /** A single endpoint value - either a static string or a function that generates a path */
10
+ type EndpointValue = string | ((...args: string[]) => string);
11
+ /** Configuration for provider API endpoints */
12
+ type EndpointsConfig = Record<string, EndpointValue>;
13
+ interface ContentProviderConfig {
14
+ id: string;
15
+ name: string;
16
+ apiBase: string;
17
+ oauthBase: string;
18
+ clientId: string;
19
+ scopes: string[];
20
+ supportsDeviceFlow?: boolean;
21
+ deviceAuthEndpoint?: string;
22
+ endpoints: EndpointsConfig;
23
+ }
24
+ interface DeviceAuthorizationResponse {
25
+ device_code: string;
26
+ user_code: string;
27
+ verification_uri: string;
28
+ verification_uri_complete?: string;
29
+ expires_in: number;
30
+ interval?: number;
31
+ }
32
+ interface DeviceFlowState {
33
+ status: "loading" | "awaiting_user" | "polling" | "success" | "error" | "expired";
34
+ deviceAuth?: DeviceAuthorizationResponse;
35
+ error?: string;
36
+ pollCount?: number;
37
+ }
38
+ type AuthType = "none" | "oauth_pkce" | "device_flow" | "form_login";
39
+ interface ProviderLogos {
40
+ light: string;
41
+ dark: string;
42
+ }
43
+ interface ProviderInfo {
44
+ id: string;
45
+ name: string;
46
+ logos: ProviderLogos;
47
+ implemented: boolean;
48
+ requiresAuth: boolean;
49
+ authTypes: AuthType[];
50
+ capabilities: ProviderCapabilities;
51
+ }
52
+ interface ContentFolder {
53
+ type: "folder";
54
+ id: string;
55
+ title: string;
56
+ thumbnail?: string;
57
+ isLeaf?: boolean;
58
+ path: string;
59
+ }
60
+ interface ContentFile {
61
+ type: "file";
62
+ id: string;
63
+ title: string;
64
+ mediaType: "video" | "image";
65
+ thumbnail?: string;
66
+ url: string;
67
+ downloadUrl?: string;
68
+ muxPlaybackId?: string;
69
+ decryptionKey?: string;
70
+ mediaId?: string;
71
+ pingbackUrl?: string;
72
+ seconds?: number;
73
+ loop?: boolean;
74
+ loopVideo?: boolean;
75
+ streamUrl?: string;
76
+ /** Provider-specific metadata that varies by provider implementation */
77
+ providerData?: Record<string, unknown>;
78
+ }
79
+ type ContentItem = ContentFolder | ContentFile;
80
+ declare function isContentFolder(item: ContentItem): item is ContentFolder;
81
+ declare function isContentFile(item: ContentItem): item is ContentFile;
82
+ type DeviceFlowPollResult = ContentProviderAuthData | {
83
+ error: string;
84
+ shouldSlowDown?: boolean;
85
+ } | null;
86
+ interface PlanPresentation {
87
+ id: string;
88
+ name: string;
89
+ actionType: "play" | "other";
90
+ files: ContentFile[];
91
+ providerData?: Record<string, unknown>;
92
+ }
93
+ interface PlanSection {
94
+ id: string;
95
+ name: string;
96
+ presentations: PlanPresentation[];
97
+ }
98
+ interface Plan {
99
+ id: string;
100
+ name: string;
101
+ description?: string;
102
+ thumbnail?: string;
103
+ sections: PlanSection[];
104
+ allFiles: ContentFile[];
105
+ }
106
+ interface FeedFileInterface {
107
+ id?: string;
108
+ name?: string;
109
+ url?: string;
110
+ streamUrl?: string;
111
+ seconds?: number;
112
+ fileType?: string;
113
+ thumbnail?: string;
114
+ }
115
+ interface FeedActionInterface {
116
+ id?: string;
117
+ actionType?: string;
118
+ content?: string;
119
+ files?: FeedFileInterface[];
120
+ }
121
+ interface FeedSectionInterface {
122
+ id?: string;
123
+ name?: string;
124
+ actions?: FeedActionInterface[];
125
+ }
126
+ interface FeedVenueInterface {
127
+ id?: string;
128
+ lessonId?: string;
129
+ name?: string;
130
+ lessonName?: string;
131
+ lessonDescription?: string;
132
+ lessonImage?: string;
133
+ sections?: FeedSectionInterface[];
134
+ }
135
+ interface InstructionItem {
136
+ id?: string;
137
+ itemType?: string;
138
+ relatedId?: string;
139
+ label?: string;
140
+ actionType?: string;
141
+ content?: string;
142
+ seconds?: number;
143
+ children?: InstructionItem[];
144
+ downloadUrl?: string;
145
+ thumbnail?: string;
146
+ }
147
+ interface Instructions {
148
+ name?: string;
149
+ items: InstructionItem[];
150
+ }
151
+ interface VenueActionInterface {
152
+ id?: string;
153
+ name?: string;
154
+ actionType?: string;
155
+ seconds?: number;
156
+ }
157
+ interface VenueSectionActionsInterface {
158
+ id?: string;
159
+ name?: string;
160
+ actions?: VenueActionInterface[];
161
+ }
162
+ interface VenueActionsResponseInterface {
163
+ venueName?: string;
164
+ sections?: VenueSectionActionsInterface[];
165
+ }
166
+ interface ProviderCapabilities {
167
+ browse: boolean;
168
+ presentations: boolean;
169
+ playlist: boolean;
170
+ instructions: boolean;
171
+ mediaLicensing: boolean;
172
+ }
173
+ type MediaLicenseStatus = "valid" | "expired" | "not_licensed" | "unknown";
174
+ interface MediaLicenseResult {
175
+ mediaId: string;
176
+ status: MediaLicenseStatus;
177
+ message?: string;
178
+ expiresAt?: string | number;
179
+ }
180
+ /**
181
+ * Core provider interface - all providers should implement this
182
+ */
183
+ interface IProvider {
184
+ readonly id: string;
185
+ readonly name: string;
186
+ readonly logos: ProviderLogos;
187
+ readonly config: ContentProviderConfig;
188
+ readonly requiresAuth: boolean;
189
+ readonly capabilities: ProviderCapabilities;
190
+ readonly authTypes: AuthType[];
191
+ browse(path?: string | null, auth?: ContentProviderAuthData | null): Promise<ContentItem[]>;
192
+ supportsDeviceFlow(): boolean;
193
+ generateCodeVerifier?(): string;
194
+ buildAuthUrl?(codeVerifier: string, redirectUri: string, state?: string): Promise<{
195
+ url: string;
196
+ challengeMethod: string;
197
+ }>;
198
+ exchangeCodeForTokens?(code: string, codeVerifier: string, redirectUri: string): Promise<ContentProviderAuthData | null>;
199
+ initiateDeviceFlow?(): Promise<DeviceAuthorizationResponse | null>;
200
+ pollDeviceFlowToken?(deviceCode: string): Promise<DeviceFlowPollResult>;
201
+ getPlaylist?(path: string, auth?: ContentProviderAuthData | null, resolution?: number): Promise<ContentFile[] | null>;
202
+ getInstructions?(path: string, auth?: ContentProviderAuthData | null): Promise<Instructions | null>;
203
+ checkMediaLicense?(mediaId: string, auth?: ContentProviderAuthData | null): Promise<MediaLicenseResult | null>;
204
+ }
205
+
206
+ declare function detectMediaType(url: string, explicitType?: string): "video" | "image";
207
+ declare function createFolder(id: string, title: string, path: string, thumbnail?: string, isLeaf?: boolean): ContentFolder;
208
+ declare function createFile(id: string, title: string, url: string, options?: {
209
+ mediaType?: "video" | "image";
210
+ thumbnail?: string;
211
+ muxPlaybackId?: string;
212
+ seconds?: number;
213
+ loop?: boolean;
214
+ loopVideo?: boolean;
215
+ streamUrl?: string;
216
+ }): ContentFile;
217
+
218
+ /**
219
+ * Path parsing utilities for content providers.
220
+ * Paths follow the format: /segment1/segment2/segment3/...
221
+ * Example: /lessons/programId/studyId/lessonId/venueId
222
+ */
223
+ interface ParsedPath {
224
+ segments: string[];
225
+ depth: number;
226
+ }
227
+ /**
228
+ * Parse a path string into segments and depth.
229
+ * @param path - The path to parse (e.g., "/lessons/abc123/def456")
230
+ * @returns Object with segments array and depth count
231
+ */
232
+ declare function parsePath(path: string | null | undefined): ParsedPath;
233
+ /**
234
+ * Get a specific segment from a path by index.
235
+ * @param path - The path to parse
236
+ * @param index - Zero-based index of the segment to retrieve
237
+ * @returns The segment at the given index, or null if not found
238
+ */
239
+ declare function getSegment(path: string | null | undefined, index: number): string | null;
240
+ /**
241
+ * Build a path string from segments.
242
+ * @param segments - Array of path segments
243
+ * @returns Path string with leading slash
244
+ */
245
+ declare function buildPath(segments: string[]): string;
246
+ /**
247
+ * Append a segment to an existing path.
248
+ * @param basePath - The base path
249
+ * @param segment - The segment to append
250
+ * @returns New path with segment appended
251
+ */
252
+ declare function appendToPath(basePath: string | null | undefined, segment: string): string;
253
+
254
+ /**
255
+ * Navigate to a specific item using a dot-notation path.
256
+ * Path format: "0.2.1" means items[0].children[2].children[1]
257
+ */
258
+ declare function navigateToPath(instructions: Instructions, path: string): InstructionItem | null;
259
+ /**
260
+ * Generate a path string for an item given its position in the tree.
261
+ * Used when selecting an item to store its path.
262
+ */
263
+ declare function generatePath(indices: number[]): string;
264
+
265
+ interface DurationEstimationConfig {
266
+ secondsPerImage: number;
267
+ wordsPerMinute: number;
268
+ }
269
+ declare const DEFAULT_DURATION_CONFIG: DurationEstimationConfig;
270
+ /**
271
+ * Count words in text (splits on whitespace)
272
+ */
273
+ declare function countWords(text: string): number;
274
+ /**
275
+ * Estimate duration for image content
276
+ * @returns Duration in seconds (default: 15)
277
+ */
278
+ declare function estimateImageDuration(config?: Partial<DurationEstimationConfig>): number;
279
+ /**
280
+ * Estimate duration for text content based on word count
281
+ * @param text - The text content
282
+ * @param config - Optional configuration overrides
283
+ * @returns Duration in seconds
284
+ */
285
+ declare function estimateTextDuration(text: string, config?: Partial<DurationEstimationConfig>): number;
286
+ /**
287
+ * Estimate duration based on media type
288
+ * @param mediaType - "video" | "image" | "text"
289
+ * @param options - Text content or word count for text estimation
290
+ * @returns Duration in seconds (0 for video/unknown)
291
+ */
292
+ declare function estimateDuration(mediaType: "video" | "image" | "text", options?: {
293
+ text?: string;
294
+ wordCount?: number;
295
+ config?: Partial<DurationEstimationConfig>;
296
+ }): number;
297
+
298
+ declare function presentationsToPlaylist(plan: Plan): ContentFile[];
299
+ declare function presentationsToExpandedInstructions(plan: Plan): Instructions;
300
+ declare function instructionsToPlaylist(instructions: Instructions): ContentFile[];
301
+ declare const expandedInstructionsToPlaylist: typeof instructionsToPlaylist;
302
+ declare function instructionsToPresentations(instructions: Instructions, planId?: string): Plan;
303
+ declare const expandedInstructionsToPresentations: typeof instructionsToPresentations;
304
+ declare function playlistToPresentations(files: ContentFile[], planName?: string, sectionName?: string): Plan;
305
+ declare function playlistToInstructions(files: ContentFile[], name?: string): Instructions;
306
+ declare const playlistToExpandedInstructions: typeof playlistToInstructions;
307
+
308
+ declare const FormatConverters_expandedInstructionsToPlaylist: typeof expandedInstructionsToPlaylist;
309
+ declare const FormatConverters_expandedInstructionsToPresentations: typeof expandedInstructionsToPresentations;
310
+ declare const FormatConverters_instructionsToPlaylist: typeof instructionsToPlaylist;
311
+ declare const FormatConverters_instructionsToPresentations: typeof instructionsToPresentations;
312
+ declare const FormatConverters_playlistToExpandedInstructions: typeof playlistToExpandedInstructions;
313
+ declare const FormatConverters_playlistToInstructions: typeof playlistToInstructions;
314
+ declare const FormatConverters_playlistToPresentations: typeof playlistToPresentations;
315
+ declare const FormatConverters_presentationsToExpandedInstructions: typeof presentationsToExpandedInstructions;
316
+ declare const FormatConverters_presentationsToPlaylist: typeof presentationsToPlaylist;
317
+ declare namespace FormatConverters {
318
+ export { FormatConverters_expandedInstructionsToPlaylist as expandedInstructionsToPlaylist, FormatConverters_expandedInstructionsToPresentations as expandedInstructionsToPresentations, FormatConverters_instructionsToPlaylist as instructionsToPlaylist, FormatConverters_instructionsToPresentations as instructionsToPresentations, FormatConverters_playlistToExpandedInstructions as playlistToExpandedInstructions, FormatConverters_playlistToInstructions as playlistToInstructions, FormatConverters_playlistToPresentations as playlistToPresentations, FormatConverters_presentationsToExpandedInstructions as presentationsToExpandedInstructions, FormatConverters_presentationsToPlaylist as presentationsToPlaylist };
319
+ }
320
+
321
+ interface FormatResolverOptions {
322
+ allowLossy?: boolean;
323
+ }
324
+ interface ResolvedFormatMeta {
325
+ isNative: boolean;
326
+ sourceFormat?: "playlist" | "presentations" | "instructions";
327
+ isLossy: boolean;
328
+ }
329
+ declare class FormatResolver {
330
+ private provider;
331
+ private options;
332
+ constructor(provider: IProvider, options?: FormatResolverOptions);
333
+ getProvider(): IProvider;
334
+ /** Extract the last segment from a path to use as fallback ID/title */
335
+ private getIdFromPath;
336
+ getPlaylist(path: string, auth?: ContentProviderAuthData | null): Promise<ContentFile[] | null>;
337
+ getPlaylistWithMeta(path: string, auth?: ContentProviderAuthData | null): Promise<{
338
+ data: ContentFile[] | null;
339
+ meta: ResolvedFormatMeta;
340
+ }>;
341
+ getInstructions(path: string, auth?: ContentProviderAuthData | null): Promise<Instructions | null>;
342
+ getInstructionsWithMeta(path: string, auth?: ContentProviderAuthData | null): Promise<{
343
+ data: Instructions | null;
344
+ meta: ResolvedFormatMeta;
345
+ }>;
346
+ }
347
+
348
+ declare class OAuthHelper {
349
+ generateCodeVerifier(): string;
350
+ generateCodeChallenge(verifier: string): Promise<string>;
351
+ buildAuthUrl(config: ContentProviderConfig, codeVerifier: string, redirectUri: string, state?: string): Promise<{
352
+ url: string;
353
+ challengeMethod: string;
354
+ }>;
355
+ exchangeCodeForTokens(config: ContentProviderConfig, _providerId: string, code: string, codeVerifier: string, redirectUri: string): Promise<ContentProviderAuthData | null>;
356
+ }
357
+
358
+ declare class TokenHelper {
359
+ isAuthValid(auth: ContentProviderAuthData | null | undefined): boolean;
360
+ isTokenExpired(auth: ContentProviderAuthData): boolean;
361
+ refreshToken(config: ContentProviderConfig, auth: ContentProviderAuthData): Promise<ContentProviderAuthData | null>;
362
+ }
363
+
364
+ declare class DeviceFlowHelper {
365
+ supportsDeviceFlow(config: ContentProviderConfig): boolean;
366
+ initiateDeviceFlow(config: ContentProviderConfig): Promise<DeviceAuthorizationResponse | null>;
367
+ pollDeviceFlowToken(config: ContentProviderConfig, deviceCode: string): Promise<DeviceFlowPollResult>;
368
+ calculatePollDelay(baseInterval?: number, slowDownCount?: number): number;
369
+ }
370
+
371
+ declare class ApiHelper {
372
+ createAuthHeaders(auth: ContentProviderAuthData | null | undefined): Record<string, string> | null;
373
+ apiRequest<T>(config: ContentProviderConfig, _providerId: string, path: string, auth?: ContentProviderAuthData | null, method?: "GET" | "POST", body?: unknown): Promise<T | null>;
374
+ }
375
+
376
+ /**
377
+ * APlay Provider
378
+ *
379
+ * Path structure (variable depth based on module products):
380
+ * /modules -> list modules
381
+ * /modules/{moduleId} -> list products OR libraries (depends on module)
382
+ * /modules/{moduleId}/products/{productId} -> list libraries (if module has multiple products)
383
+ * /modules/{moduleId}/products/{productId}/{libraryId} -> media files
384
+ * /modules/{moduleId}/libraries/{libraryId} -> media files (if module has 0-1 products)
385
+ */
386
+ declare class APlayProvider implements IProvider {
387
+ private readonly apiHelper;
388
+ private apiRequest;
389
+ readonly id = "aplay";
390
+ readonly name = "APlay";
391
+ readonly logos: ProviderLogos;
392
+ readonly config: ContentProviderConfig;
393
+ readonly requiresAuth = true;
394
+ readonly authTypes: AuthType[];
395
+ readonly capabilities: ProviderCapabilities;
396
+ browse(path?: string | null, auth?: ContentProviderAuthData | null): Promise<ContentItem[]>;
397
+ private getModules;
398
+ private getModuleContent;
399
+ private getLibraryFolders;
400
+ private getMediaFiles;
401
+ getPlaylist(path: string, auth?: ContentProviderAuthData | null, _resolution?: number): Promise<ContentFile[] | null>;
402
+ getInstructions(path: string, auth?: ContentProviderAuthData | null): Promise<Instructions | null>;
403
+ checkMediaLicense(mediaId: string, auth?: ContentProviderAuthData | null): Promise<MediaLicenseResult | null>;
404
+ supportsDeviceFlow(): boolean;
405
+ }
406
+
407
+ /**
408
+ * SignPresenter Provider
409
+ *
410
+ * Path structure:
411
+ * /playlists -> list playlists
412
+ * /playlists/{playlistId} -> list messages (files)
413
+ */
414
+ declare class SignPresenterProvider implements IProvider {
415
+ private readonly apiHelper;
416
+ private readonly oauthHelper;
417
+ private readonly deviceFlowHelper;
418
+ private apiRequest;
419
+ readonly id = "signpresenter";
420
+ readonly name = "SignPresenter";
421
+ readonly logos: ProviderLogos;
422
+ readonly config: ContentProviderConfig;
423
+ readonly requiresAuth = true;
424
+ readonly authTypes: AuthType[];
425
+ readonly capabilities: ProviderCapabilities;
426
+ browse(path?: string | null, auth?: ContentProviderAuthData | null): Promise<ContentItem[]>;
427
+ private getPlaylists;
428
+ private getMessages;
429
+ getPlaylist(path: string, auth?: ContentProviderAuthData | null, _resolution?: number): Promise<ContentFile[] | null>;
430
+ getInstructions(path: string, auth?: ContentProviderAuthData | null): Promise<Instructions | null>;
431
+ supportsDeviceFlow(): boolean;
432
+ generateCodeVerifier(): string;
433
+ buildAuthUrl(codeVerifier: string, redirectUri: string, state?: string): Promise<{
434
+ url: string;
435
+ challengeMethod: string;
436
+ }>;
437
+ exchangeCodeForTokens(code: string, codeVerifier: string, redirectUri: string): Promise<ContentProviderAuthData | null>;
438
+ initiateDeviceFlow(): Promise<DeviceAuthorizationResponse | null>;
439
+ pollDeviceFlowToken(deviceCode: string): Promise<DeviceFlowPollResult>;
440
+ }
441
+
442
+ /**
443
+ * LessonsChurch Provider
444
+ *
445
+ * Path structure:
446
+ * /lessons -> programs
447
+ * /lessons/{programId} -> studies
448
+ * /lessons/{programId}/{studyId} -> lessons
449
+ * /lessons/{programId}/{studyId}/{lessonId} -> venues
450
+ * /lessons/{programId}/{studyId}/{lessonId}/{venueId} -> playlist files
451
+ *
452
+ * /addons -> categories
453
+ * /addons/{category} -> add-on files
454
+ */
455
+ declare class LessonsChurchProvider implements IProvider {
456
+ readonly id = "lessonschurch";
457
+ readonly name = "Lessons.church";
458
+ readonly logos: ProviderLogos;
459
+ readonly config: ContentProviderConfig;
460
+ readonly requiresAuth = false;
461
+ readonly authTypes: AuthType[];
462
+ readonly capabilities: ProviderCapabilities;
463
+ getPlaylist(path: string, _auth?: ContentProviderAuthData | null, resolution?: number): Promise<ContentFile[] | null>;
464
+ browse(path?: string | null, _auth?: ContentProviderAuthData | null): Promise<ContentItem[]>;
465
+ private browseLessons;
466
+ private getPrograms;
467
+ private getStudies;
468
+ private getLessons;
469
+ private getVenues;
470
+ private getPlaylistFiles;
471
+ private browseAddOns;
472
+ private getAddOnCategories;
473
+ private getAddOnsByCategory;
474
+ getInstructions(path: string, _auth?: ContentProviderAuthData | null): Promise<Instructions | null>;
475
+ supportsDeviceFlow(): boolean;
476
+ }
477
+
478
+ declare class B1ChurchProvider implements IProvider {
479
+ private readonly apiHelper;
480
+ private readonly externalContentCache;
481
+ private apiRequest;
482
+ readonly id = "b1church";
483
+ readonly name = "B1.Church";
484
+ readonly logos: ProviderLogos;
485
+ readonly config: ContentProviderConfig;
486
+ private appBase;
487
+ readonly requiresAuth = true;
488
+ readonly authTypes: AuthType[];
489
+ readonly capabilities: ProviderCapabilities;
490
+ buildAuthUrl(codeVerifier: string, redirectUri: string, state?: string): Promise<{
491
+ url: string;
492
+ challengeMethod: string;
493
+ }>;
494
+ exchangeCodeForTokensWithPKCE(code: string, redirectUri: string, codeVerifier: string): Promise<ContentProviderAuthData | null>;
495
+ exchangeCodeForTokensWithSecret(code: string, redirectUri: string, clientSecret: string): Promise<ContentProviderAuthData | null>;
496
+ refreshTokenWithSecret(authData: ContentProviderAuthData, clientSecret: string): Promise<ContentProviderAuthData | null>;
497
+ initiateDeviceFlow(): Promise<DeviceAuthorizationResponse | null>;
498
+ pollDeviceFlowToken(deviceCode: string): Promise<DeviceFlowPollResult>;
499
+ browse(path?: string | null, authData?: ContentProviderAuthData | null): Promise<ContentItem[]>;
500
+ getInstructions(path: string, authData?: ContentProviderAuthData | null): Promise<Instructions | null>;
501
+ private processInstructionItems;
502
+ private findItemByPath;
503
+ private findPresentationByPath;
504
+ getPlaylist(path: string, authData?: ContentProviderAuthData | null, resolution?: number): Promise<ContentFile[] | null>;
505
+ supportsDeviceFlow(): boolean;
506
+ }
507
+
508
+ declare class DropboxProvider implements IProvider {
509
+ private readonly oauthHelper;
510
+ readonly id = "dropbox";
511
+ readonly name = "Dropbox";
512
+ readonly logos: ProviderLogos;
513
+ readonly config: ContentProviderConfig;
514
+ readonly requiresAuth = true;
515
+ readonly authTypes: AuthType[];
516
+ readonly capabilities: ProviderCapabilities;
517
+ private dropboxPost;
518
+ private listAllEntries;
519
+ private getSharedLink;
520
+ private sharedLinkToRawUrl;
521
+ private getTemporaryLink;
522
+ private resolveFileLinks;
523
+ private checkIsLeaf;
524
+ browse(path?: string | null, auth?: ContentProviderAuthData | null): Promise<ContentItem[]>;
525
+ getPlaylist(path: string, auth?: ContentProviderAuthData | null, _resolution?: number): Promise<ContentFile[] | null>;
526
+ getInstructions(path: string, auth?: ContentProviderAuthData | null): Promise<Instructions | null>;
527
+ supportsDeviceFlow(): boolean;
528
+ generateCodeVerifier(): string;
529
+ buildAuthUrl(codeVerifier: string, redirectUri: string, state?: string): Promise<{
530
+ url: string;
531
+ challengeMethod: string;
532
+ }>;
533
+ exchangeCodeForTokens(code: string, codeVerifier: string, redirectUri: string): Promise<ContentProviderAuthData | null>;
534
+ }
535
+
536
+ /**
537
+ * PlanningCenter Provider
538
+ *
539
+ * Path structure:
540
+ * /serviceTypes -> list service types
541
+ * /serviceTypes/{serviceTypeId} -> list plans
542
+ * /serviceTypes/{serviceTypeId}/{planId} -> plan items (leaf)
543
+ */
544
+ declare class PlanningCenterProvider implements IProvider {
545
+ private readonly apiHelper;
546
+ private apiRequest;
547
+ readonly id = "planningcenter";
548
+ readonly name = "Planning Center";
549
+ readonly logos: ProviderLogos;
550
+ readonly config: ContentProviderConfig;
551
+ private readonly ONE_WEEK_MS;
552
+ readonly requiresAuth = true;
553
+ readonly authTypes: AuthType[];
554
+ readonly capabilities: ProviderCapabilities;
555
+ browse(path?: string | null, auth?: ContentProviderAuthData | null): Promise<ContentItem[]>;
556
+ private getServiceTypes;
557
+ private getPlans;
558
+ private getPlanItems;
559
+ supportsDeviceFlow(): boolean;
560
+ }
561
+
562
+ /**
563
+ * BibleProject Provider
564
+ *
565
+ * Path structure:
566
+ * / -> list collections
567
+ * /{collectionSlug} -> list videos in collection
568
+ * /{collectionSlug}/{videoId} -> single video
569
+ */
570
+ declare class BibleProjectProvider implements IProvider {
571
+ readonly id = "bibleproject";
572
+ readonly name = "The Bible Project";
573
+ readonly logos: ProviderLogos;
574
+ readonly config: ContentProviderConfig;
575
+ private data;
576
+ readonly requiresAuth = false;
577
+ readonly authTypes: AuthType[];
578
+ readonly capabilities: ProviderCapabilities;
579
+ browse(path?: string | null, _auth?: ContentProviderAuthData | null): Promise<ContentItem[]>;
580
+ private getCollections;
581
+ private getLessonFolders;
582
+ private getVideoFile;
583
+ getPlaylist(path: string, _auth?: ContentProviderAuthData | null, _resolution?: number): Promise<ContentFile[] | null>;
584
+ getInstructions(path: string, _auth?: ContentProviderAuthData | null): Promise<Instructions | null>;
585
+ supportsDeviceFlow(): boolean;
586
+ }
587
+
588
+ /**
589
+ * HighVoltageKids Provider
590
+ *
591
+ * Path structure:
592
+ * / -> list collections (Elementary, Preschool)
593
+ * /{collectionSlug} -> list studies
594
+ * /{collectionSlug}/{studyId} -> list lessons
595
+ * /{collectionSlug}/{studyId}/{lessonId} -> lesson files (leaf)
596
+ */
597
+ declare class HighVoltageKidsProvider implements IProvider {
598
+ readonly id = "highvoltagekids";
599
+ readonly name = "High Voltage Kids";
600
+ readonly logos: ProviderLogos;
601
+ readonly config: ContentProviderConfig;
602
+ private data;
603
+ readonly requiresAuth = false;
604
+ readonly authTypes: AuthType[];
605
+ readonly capabilities: ProviderCapabilities;
606
+ browse(path?: string | null, _auth?: ContentProviderAuthData | null): Promise<ContentItem[]>;
607
+ getPlaylist(path: string, _auth?: ContentProviderAuthData | null, _resolution?: number): Promise<ContentFile[] | null>;
608
+ getInstructions(path: string, _auth?: ContentProviderAuthData | null): Promise<Instructions | null>;
609
+ supportsDeviceFlow(): boolean;
610
+ }
611
+
612
+ /**
613
+ * Jesus Film Project Provider
614
+ *
615
+ * Uses the public Arclight API to browse video content from jesusfilm.org.
616
+ *
617
+ * Path structure:
618
+ * / -> categories (Feature Films, Series, Collections)
619
+ * /{category} -> list items in category
620
+ * /{category}/{mediaComponentId} -> single video file
621
+ */
622
+ declare class JesusFilmProvider implements IProvider {
623
+ readonly id = "jesusfilm";
624
+ readonly name = "Jesus Film Project";
625
+ readonly logos: ProviderLogos;
626
+ readonly config: ContentProviderConfig;
627
+ readonly requiresAuth = false;
628
+ readonly authTypes: AuthType[];
629
+ readonly capabilities: ProviderCapabilities;
630
+ private fetchApi;
631
+ browse(path?: string | null, _auth?: ContentProviderAuthData | null): Promise<ContentItem[]>;
632
+ private getCategories;
633
+ private getItemsInCategory;
634
+ private getVideoFile;
635
+ private extractMuxPlaybackId;
636
+ getPlaylist(path: string, _auth?: ContentProviderAuthData | null, _resolution?: number): Promise<ContentFile[] | null>;
637
+ private fetchVideoFiles;
638
+ getInstructions(path: string, _auth?: ContentProviderAuthData | null): Promise<Instructions | null>;
639
+ supportsDeviceFlow(): boolean;
640
+ }
641
+
642
+ /**
643
+ * Get a provider by ID.
644
+ */
645
+ declare function getProvider(providerId: string): IProvider | null;
646
+ /**
647
+ * Get all registered providers.
648
+ */
649
+ declare function getAllProviders(): IProvider[];
650
+ /**
651
+ * Register a custom provider.
652
+ */
653
+ declare function registerProvider(provider: IProvider): void;
654
+ /**
655
+ * Get provider configuration by ID (for backward compatibility).
656
+ */
657
+ declare function getProviderConfig(providerId: string): ContentProviderConfig | null;
658
+ /**
659
+ * Get list of available providers with their info including logos and auth types.
660
+ * Includes both implemented providers and coming soon providers.
661
+ * @param ids - Optional array of provider IDs to filter the results. If provided, only providers with matching IDs will be returned.
662
+ */
663
+ declare function getAvailableProviders(ids?: string[]): ProviderInfo[];
664
+
665
+ /**
666
+ * @churchapps/content-provider-helper
667
+ * Helper classes for interacting with third party content providers
668
+ */
669
+ declare const VERSION = "0.0.5";
670
+
671
+ export { APlayProvider, ApiHelper, type AuthType, B1ChurchProvider, BibleProjectProvider, type ContentFile, type ContentFolder, type ContentItem, type ContentProviderAuthData, type ContentProviderConfig, DEFAULT_DURATION_CONFIG, type DeviceAuthorizationResponse, DeviceFlowHelper, type DeviceFlowPollResult, type DeviceFlowState, DropboxProvider, type DurationEstimationConfig, type EndpointValue, type EndpointsConfig, type FeedActionInterface, type FeedFileInterface, type FeedSectionInterface, type FeedVenueInterface, FormatConverters, FormatResolver, type FormatResolverOptions, HighVoltageKidsProvider, type IProvider, type InstructionItem, type Instructions, JesusFilmProvider, LessonsChurchProvider, type MediaLicenseResult, type MediaLicenseStatus, OAuthHelper, type Plan, type PlanPresentation, type PlanSection, PlanningCenterProvider, type ProviderCapabilities, type ProviderInfo, type ProviderLogos, type ResolvedFormatMeta, SignPresenterProvider, TokenHelper, VERSION, type VenueActionInterface, type VenueActionsResponseInterface, type VenueSectionActionsInterface, appendToPath, buildPath, countWords, createFile, createFolder, detectMediaType, estimateDuration, estimateImageDuration, estimateTextDuration, generatePath, getAllProviders, getAvailableProviders, getProvider, getProviderConfig, getSegment, isContentFile, isContentFolder, navigateToPath, parsePath, registerProvider };