@churchapps/content-provider-helper 0.0.1 → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +1511 -1280
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +363 -447
- package/dist/index.d.ts +363 -447
- package/dist/index.js +1493 -1280
- package/dist/index.js.map +1 -1
- package/package.json +9 -2
package/dist/index.d.cts
CHANGED
|
@@ -1,241 +1,99 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* OAuth token data returned after successful authentication.
|
|
3
|
-
*/
|
|
4
1
|
interface ContentProviderAuthData {
|
|
5
|
-
/** The access token for API requests */
|
|
6
2
|
access_token: string;
|
|
7
|
-
/** The refresh token for obtaining new access tokens */
|
|
8
3
|
refresh_token: string;
|
|
9
|
-
/** Token type, typically "Bearer" */
|
|
10
4
|
token_type: string;
|
|
11
|
-
/** Unix timestamp (seconds) when the token was created */
|
|
12
5
|
created_at: number;
|
|
13
|
-
/** Token lifetime in seconds */
|
|
14
6
|
expires_in: number;
|
|
15
|
-
/** Space-separated list of granted scopes */
|
|
16
7
|
scope: string;
|
|
17
8
|
}
|
|
18
|
-
/**
|
|
19
|
-
* Configuration for a content provider's API and OAuth settings.
|
|
20
|
-
*/
|
|
21
9
|
interface ContentProviderConfig {
|
|
22
|
-
/** Unique identifier for the provider */
|
|
23
10
|
id: string;
|
|
24
|
-
/** Display name of the provider */
|
|
25
11
|
name: string;
|
|
26
|
-
/** Base URL for API requests */
|
|
27
12
|
apiBase: string;
|
|
28
|
-
/** Base URL for OAuth endpoints */
|
|
29
13
|
oauthBase: string;
|
|
30
|
-
/** OAuth client ID */
|
|
31
14
|
clientId: string;
|
|
32
|
-
/** OAuth scopes to request */
|
|
33
15
|
scopes: string[];
|
|
34
|
-
/** Whether the provider supports device flow authentication */
|
|
35
16
|
supportsDeviceFlow?: boolean;
|
|
36
|
-
/** Endpoint path for device authorization (relative to oauthBase) */
|
|
37
17
|
deviceAuthEndpoint?: string;
|
|
38
|
-
/** API endpoint paths - can be static strings or functions that generate paths */
|
|
39
18
|
endpoints: Record<string, string | ((...args: string[]) => string)>;
|
|
40
19
|
}
|
|
41
|
-
/**
|
|
42
|
-
* Response from the device authorization endpoint (RFC 8628).
|
|
43
|
-
*/
|
|
44
20
|
interface DeviceAuthorizationResponse {
|
|
45
|
-
/** Device verification code for polling */
|
|
46
21
|
device_code: string;
|
|
47
|
-
/** User code to display for manual entry */
|
|
48
22
|
user_code: string;
|
|
49
|
-
/** URL where user should authenticate */
|
|
50
23
|
verification_uri: string;
|
|
51
|
-
/** Complete URL with user code pre-filled */
|
|
52
24
|
verification_uri_complete?: string;
|
|
53
|
-
/** Seconds until the codes expire */
|
|
54
25
|
expires_in: number;
|
|
55
|
-
/** Minimum polling interval in seconds */
|
|
56
26
|
interval?: number;
|
|
57
27
|
}
|
|
58
|
-
/**
|
|
59
|
-
* Current state of a device flow authentication process.
|
|
60
|
-
*/
|
|
61
28
|
interface DeviceFlowState {
|
|
62
|
-
|
|
63
|
-
* Current status of the device flow.
|
|
64
|
-
* - `loading`: Initiating device flow
|
|
65
|
-
* - `awaiting_user`: Waiting for user to authenticate
|
|
66
|
-
* - `polling`: Polling for token
|
|
67
|
-
* - `success`: Authentication completed
|
|
68
|
-
* - `error`: An error occurred
|
|
69
|
-
* - `expired`: Device code expired
|
|
70
|
-
*/
|
|
71
|
-
status: 'loading' | 'awaiting_user' | 'polling' | 'success' | 'error' | 'expired';
|
|
72
|
-
/** Device authorization response data */
|
|
29
|
+
status: "loading" | "awaiting_user" | "polling" | "success" | "error" | "expired";
|
|
73
30
|
deviceAuth?: DeviceAuthorizationResponse;
|
|
74
|
-
/** Error message if status is 'error' */
|
|
75
31
|
error?: string;
|
|
76
|
-
/** Number of poll attempts made */
|
|
77
32
|
pollCount?: number;
|
|
78
33
|
}
|
|
79
|
-
|
|
80
|
-
* Authentication type supported by a provider.
|
|
81
|
-
* - `none`: No authentication required (public API)
|
|
82
|
-
* - `oauth_pkce`: OAuth 2.0 with PKCE
|
|
83
|
-
* - `device_flow`: OAuth 2.0 Device Authorization Flow (RFC 8628)
|
|
84
|
-
* - `form_login`: Form-based login (username/password) with session cookies
|
|
85
|
-
*/
|
|
86
|
-
type AuthType = 'none' | 'oauth_pkce' | 'device_flow' | 'form_login';
|
|
87
|
-
/**
|
|
88
|
-
* Provider logo URLs for light and dark themes.
|
|
89
|
-
*/
|
|
34
|
+
type AuthType = "none" | "oauth_pkce" | "device_flow" | "form_login";
|
|
90
35
|
interface ProviderLogos {
|
|
91
|
-
/** Logo URL for light theme backgrounds */
|
|
92
36
|
light: string;
|
|
93
|
-
/** Logo URL for dark theme backgrounds */
|
|
94
37
|
dark: string;
|
|
95
38
|
}
|
|
96
|
-
/**
|
|
97
|
-
* Information about a content provider.
|
|
98
|
-
*/
|
|
99
39
|
interface ProviderInfo {
|
|
100
|
-
/** Unique identifier for the provider */
|
|
101
40
|
id: string;
|
|
102
|
-
/** Display name of the provider */
|
|
103
41
|
name: string;
|
|
104
|
-
/** Provider logos */
|
|
105
42
|
logos: ProviderLogos;
|
|
106
|
-
/** Whether the provider is fully implemented */
|
|
107
43
|
implemented: boolean;
|
|
108
|
-
/** Whether the provider requires authentication */
|
|
109
44
|
requiresAuth: boolean;
|
|
110
|
-
/** Supported authentication types */
|
|
111
45
|
authTypes: AuthType[];
|
|
112
|
-
/** Provider capabilities */
|
|
113
46
|
capabilities: ProviderCapabilities;
|
|
114
47
|
}
|
|
115
|
-
/**
|
|
116
|
-
* A folder in the content hierarchy. Can be navigated into to retrieve child items.
|
|
117
|
-
*/
|
|
118
48
|
interface ContentFolder {
|
|
119
|
-
|
|
120
|
-
type: 'folder';
|
|
121
|
-
/** Unique identifier for this folder */
|
|
49
|
+
type: "folder";
|
|
122
50
|
id: string;
|
|
123
|
-
/** Display title */
|
|
124
51
|
title: string;
|
|
125
|
-
/** Optional thumbnail/cover image URL */
|
|
126
52
|
image?: string;
|
|
127
|
-
|
|
53
|
+
isLeaf?: boolean;
|
|
54
|
+
path: string;
|
|
128
55
|
providerData?: Record<string, unknown>;
|
|
129
56
|
}
|
|
130
|
-
/**
|
|
131
|
-
* A playable media file (video or image).
|
|
132
|
-
*/
|
|
133
57
|
interface ContentFile {
|
|
134
|
-
|
|
135
|
-
type: 'file';
|
|
136
|
-
/** Unique identifier for this file */
|
|
58
|
+
type: "file";
|
|
137
59
|
id: string;
|
|
138
|
-
/** Display title */
|
|
139
60
|
title: string;
|
|
140
|
-
|
|
141
|
-
* Media type of the file.
|
|
142
|
-
* - `video`: Video content (.mp4, .webm, .m3u8, etc.)
|
|
143
|
-
* - `image`: Image content (.jpg, .png, etc.)
|
|
144
|
-
*/
|
|
145
|
-
mediaType: 'video' | 'image';
|
|
146
|
-
/** Optional preview/cover image URL */
|
|
61
|
+
mediaType: "video" | "image";
|
|
147
62
|
image?: string;
|
|
148
|
-
/** URL to the media file */
|
|
149
63
|
url: string;
|
|
150
|
-
/**
|
|
151
|
-
* Optional URL for embedded preview/player.
|
|
152
|
-
* - For iframe-based providers (e.g., Lessons.church): an embed URL
|
|
153
|
-
* - For direct media providers: same as url, or omitted to use url directly
|
|
154
|
-
*/
|
|
155
64
|
embedUrl?: string;
|
|
156
|
-
/** Mux playback ID for Mux-hosted videos */
|
|
157
65
|
muxPlaybackId?: string;
|
|
158
|
-
/** Decryption key for encrypted media (provider-specific) */
|
|
159
66
|
decryptionKey?: string;
|
|
160
|
-
/** Provider-specific media ID for tracking/licensing */
|
|
161
67
|
mediaId?: string;
|
|
162
|
-
/** URL to ping after 30+ seconds of playback (licensing requirement) */
|
|
163
68
|
pingbackUrl?: string;
|
|
164
|
-
/** Provider-specific data (e.g., duration, loop settings) */
|
|
165
69
|
providerData?: Record<string, unknown>;
|
|
166
70
|
}
|
|
167
|
-
/**
|
|
168
|
-
* A content item - either a folder or a file.
|
|
169
|
-
*/
|
|
170
71
|
type ContentItem = ContentFolder | ContentFile;
|
|
171
|
-
/**
|
|
172
|
-
* Type guard to check if a ContentItem is a ContentFolder.
|
|
173
|
-
*/
|
|
174
72
|
declare function isContentFolder(item: ContentItem): item is ContentFolder;
|
|
175
|
-
/**
|
|
176
|
-
* Type guard to check if a ContentItem is a ContentFile.
|
|
177
|
-
*/
|
|
178
73
|
declare function isContentFile(item: ContentItem): item is ContentFile;
|
|
179
|
-
/**
|
|
180
|
-
* Result from polling the device flow token endpoint.
|
|
181
|
-
* - `ContentProviderAuthData`: Authentication succeeded
|
|
182
|
-
* - `{ error, shouldSlowDown }`: Still pending or should slow down
|
|
183
|
-
* - `null`: Authentication failed or expired
|
|
184
|
-
*/
|
|
185
74
|
type DeviceFlowPollResult = ContentProviderAuthData | {
|
|
186
75
|
error: string;
|
|
187
76
|
shouldSlowDown?: boolean;
|
|
188
77
|
} | null;
|
|
189
|
-
/**
|
|
190
|
-
* A presentation within a plan section (e.g., a song, video, or activity).
|
|
191
|
-
*/
|
|
192
78
|
interface PlanPresentation {
|
|
193
|
-
/** Unique identifier */
|
|
194
79
|
id: string;
|
|
195
|
-
/** Display name */
|
|
196
80
|
name: string;
|
|
197
|
-
|
|
198
|
-
* Type of action/presentation.
|
|
199
|
-
* - `play`: Main playable content
|
|
200
|
-
* - `add-on`: Supplementary content
|
|
201
|
-
* - `other`: Non-playable item (song lyrics, notes, etc.)
|
|
202
|
-
*/
|
|
203
|
-
actionType: 'play' | 'add-on' | 'other';
|
|
204
|
-
/** Media files associated with this presentation */
|
|
81
|
+
actionType: "play" | "add-on" | "other";
|
|
205
82
|
files: ContentFile[];
|
|
206
83
|
}
|
|
207
|
-
/**
|
|
208
|
-
* A section within a plan containing multiple presentations.
|
|
209
|
-
*/
|
|
210
84
|
interface PlanSection {
|
|
211
|
-
/** Unique identifier */
|
|
212
85
|
id: string;
|
|
213
|
-
/** Section name (e.g., "Worship", "Message", "Closing") */
|
|
214
86
|
name: string;
|
|
215
|
-
/** Presentations within this section */
|
|
216
87
|
presentations: PlanPresentation[];
|
|
217
88
|
}
|
|
218
|
-
/**
|
|
219
|
-
* A complete plan/service with sections and presentations.
|
|
220
|
-
* Returned by `getPresentations()`.
|
|
221
|
-
*/
|
|
222
89
|
interface Plan {
|
|
223
|
-
/** Unique identifier */
|
|
224
90
|
id: string;
|
|
225
|
-
/** Plan name */
|
|
226
91
|
name: string;
|
|
227
|
-
/** Optional description */
|
|
228
92
|
description?: string;
|
|
229
|
-
/** Optional cover image URL */
|
|
230
93
|
image?: string;
|
|
231
|
-
/** Ordered sections in the plan */
|
|
232
94
|
sections: PlanSection[];
|
|
233
|
-
/** Flat list of all files in the plan */
|
|
234
95
|
allFiles: ContentFile[];
|
|
235
96
|
}
|
|
236
|
-
/**
|
|
237
|
-
* A file within a venue feed.
|
|
238
|
-
*/
|
|
239
97
|
interface FeedFileInterface {
|
|
240
98
|
id?: string;
|
|
241
99
|
name?: string;
|
|
@@ -244,26 +102,17 @@ interface FeedFileInterface {
|
|
|
244
102
|
seconds?: number;
|
|
245
103
|
fileType?: string;
|
|
246
104
|
}
|
|
247
|
-
/**
|
|
248
|
-
* An action within a venue feed section.
|
|
249
|
-
*/
|
|
250
105
|
interface FeedActionInterface {
|
|
251
106
|
id?: string;
|
|
252
107
|
actionType?: string;
|
|
253
108
|
content?: string;
|
|
254
109
|
files?: FeedFileInterface[];
|
|
255
110
|
}
|
|
256
|
-
/**
|
|
257
|
-
* A section within a venue feed.
|
|
258
|
-
*/
|
|
259
111
|
interface FeedSectionInterface {
|
|
260
112
|
id?: string;
|
|
261
113
|
name?: string;
|
|
262
114
|
actions?: FeedActionInterface[];
|
|
263
115
|
}
|
|
264
|
-
/**
|
|
265
|
-
* Complete venue feed data from Lessons.church API.
|
|
266
|
-
*/
|
|
267
116
|
interface FeedVenueInterface {
|
|
268
117
|
id?: string;
|
|
269
118
|
lessonId?: string;
|
|
@@ -273,447 +122,513 @@ interface FeedVenueInterface {
|
|
|
273
122
|
lessonImage?: string;
|
|
274
123
|
sections?: FeedSectionInterface[];
|
|
275
124
|
}
|
|
276
|
-
/**
|
|
277
|
-
* An item in the instruction hierarchy.
|
|
278
|
-
*/
|
|
279
125
|
interface InstructionItem {
|
|
280
|
-
/** Unique identifier */
|
|
281
126
|
id?: string;
|
|
282
|
-
/** Type of instruction item */
|
|
283
127
|
itemType?: string;
|
|
284
|
-
/** ID of related content */
|
|
285
128
|
relatedId?: string;
|
|
286
|
-
/** Display label */
|
|
287
129
|
label?: string;
|
|
288
|
-
/** Description or notes */
|
|
289
130
|
description?: string;
|
|
290
|
-
/** Duration in seconds */
|
|
291
131
|
seconds?: number;
|
|
292
|
-
/** Child instruction items */
|
|
293
132
|
children?: InstructionItem[];
|
|
294
|
-
/** URL for embedded content viewer */
|
|
295
133
|
embedUrl?: string;
|
|
296
134
|
}
|
|
297
|
-
/**
|
|
298
|
-
* Instructions/run sheet for a venue.
|
|
299
|
-
* Returned by `getInstructions()` and `getExpandedInstructions()`.
|
|
300
|
-
*/
|
|
301
135
|
interface Instructions {
|
|
302
|
-
/** Name of the venue */
|
|
303
136
|
venueName?: string;
|
|
304
|
-
/** Hierarchical list of instruction items */
|
|
305
137
|
items: InstructionItem[];
|
|
306
138
|
}
|
|
307
|
-
/**
|
|
308
|
-
* An action within a venue section.
|
|
309
|
-
*/
|
|
310
139
|
interface VenueActionInterface {
|
|
311
140
|
id?: string;
|
|
312
141
|
name?: string;
|
|
313
142
|
actionType?: string;
|
|
314
143
|
seconds?: number;
|
|
315
144
|
}
|
|
316
|
-
/**
|
|
317
|
-
* A section with its actions.
|
|
318
|
-
*/
|
|
319
145
|
interface VenueSectionActionsInterface {
|
|
320
146
|
id?: string;
|
|
321
147
|
name?: string;
|
|
322
148
|
actions?: VenueActionInterface[];
|
|
323
149
|
}
|
|
324
|
-
/**
|
|
325
|
-
* Response containing venue actions organized by section.
|
|
326
|
-
*/
|
|
327
150
|
interface VenueActionsResponseInterface {
|
|
328
151
|
venueName?: string;
|
|
329
152
|
sections?: VenueSectionActionsInterface[];
|
|
330
153
|
}
|
|
331
|
-
/**
|
|
332
|
-
* Capabilities supported by a content provider.
|
|
333
|
-
*/
|
|
334
154
|
interface ProviderCapabilities {
|
|
335
|
-
/** Whether the provider supports browsing content hierarchy */
|
|
336
155
|
browse: boolean;
|
|
337
|
-
/** Whether `getPresentations()` returns structured plan data */
|
|
338
156
|
presentations: boolean;
|
|
339
|
-
/** Whether `getPlaylist()` returns a flat list of media files */
|
|
340
157
|
playlist: boolean;
|
|
341
|
-
/** Whether `getInstructions()` returns instruction data */
|
|
342
158
|
instructions: boolean;
|
|
343
|
-
/** Whether `getExpandedInstructions()` returns expanded instruction data */
|
|
344
159
|
expandedInstructions: boolean;
|
|
345
|
-
/** Whether `checkMediaLicense()` returns license information */
|
|
346
160
|
mediaLicensing: boolean;
|
|
347
161
|
}
|
|
348
|
-
|
|
349
|
-
* License status for media content.
|
|
350
|
-
*/
|
|
351
|
-
type MediaLicenseStatus = 'valid' | 'expired' | 'not_licensed' | 'unknown';
|
|
352
|
-
/**
|
|
353
|
-
* Response from `checkMediaLicense()`.
|
|
354
|
-
*/
|
|
162
|
+
type MediaLicenseStatus = "valid" | "expired" | "not_licensed" | "unknown";
|
|
355
163
|
interface MediaLicenseResult {
|
|
356
|
-
/** The media ID that was checked */
|
|
357
164
|
mediaId: string;
|
|
358
|
-
/** Current license status */
|
|
359
165
|
status: MediaLicenseStatus;
|
|
360
|
-
/** Human-readable message about the license */
|
|
361
166
|
message?: string;
|
|
362
|
-
/** When the license expires (ISO 8601 string or Unix timestamp) */
|
|
363
167
|
expiresAt?: string | number;
|
|
364
168
|
}
|
|
169
|
+
/**
|
|
170
|
+
* Core provider interface - all providers should implement this
|
|
171
|
+
*/
|
|
172
|
+
interface IProvider {
|
|
173
|
+
readonly id: string;
|
|
174
|
+
readonly name: string;
|
|
175
|
+
readonly logos: ProviderLogos;
|
|
176
|
+
readonly config: ContentProviderConfig;
|
|
177
|
+
readonly requiresAuth: boolean;
|
|
178
|
+
readonly capabilities: ProviderCapabilities;
|
|
179
|
+
readonly authTypes: AuthType[];
|
|
180
|
+
browse(path?: string | null, auth?: ContentProviderAuthData | null): Promise<ContentItem[]>;
|
|
181
|
+
getPresentations(path: string, auth?: ContentProviderAuthData | null): Promise<Plan | null>;
|
|
182
|
+
getPlaylist?(path: string, auth?: ContentProviderAuthData | null, resolution?: number): Promise<ContentFile[] | null>;
|
|
183
|
+
getInstructions?(path: string, auth?: ContentProviderAuthData | null): Promise<Instructions | null>;
|
|
184
|
+
getExpandedInstructions?(path: string, auth?: ContentProviderAuthData | null): Promise<Instructions | null>;
|
|
185
|
+
checkMediaLicense?(mediaId: string, auth?: ContentProviderAuthData | null): Promise<MediaLicenseResult | null>;
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* @deprecated Use IProvider instead. This interface will be removed in a future version.
|
|
189
|
+
*/
|
|
190
|
+
interface IContentProvider {
|
|
191
|
+
readonly id: string;
|
|
192
|
+
readonly name: string;
|
|
193
|
+
readonly logos: ProviderLogos;
|
|
194
|
+
readonly config: ContentProviderConfig;
|
|
195
|
+
browse(path?: string | null, auth?: ContentProviderAuthData | null): Promise<ContentItem[]>;
|
|
196
|
+
getPresentations(path: string, auth?: ContentProviderAuthData | null): Promise<Plan | null>;
|
|
197
|
+
getPlaylist(path: string, auth?: ContentProviderAuthData | null, resolution?: number): Promise<ContentFile[] | null>;
|
|
198
|
+
getInstructions(path: string, auth?: ContentProviderAuthData | null): Promise<Instructions | null>;
|
|
199
|
+
getExpandedInstructions(path: string, auth?: ContentProviderAuthData | null): Promise<Instructions | null>;
|
|
200
|
+
requiresAuth(): boolean;
|
|
201
|
+
getCapabilities(): ProviderCapabilities;
|
|
202
|
+
checkMediaLicense(mediaId: string, auth?: ContentProviderAuthData | null): Promise<MediaLicenseResult | null>;
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* @deprecated Use auth helpers directly (OAuthHelper, DeviceFlowHelper, TokenHelper) with provider.config.
|
|
206
|
+
* This interface will be removed in a future version.
|
|
207
|
+
*/
|
|
208
|
+
interface IAuthProvider {
|
|
209
|
+
getAuthTypes(): AuthType[];
|
|
210
|
+
isAuthValid(auth: ContentProviderAuthData | null | undefined): boolean;
|
|
211
|
+
isTokenExpired(auth: ContentProviderAuthData): boolean;
|
|
212
|
+
refreshToken(auth: ContentProviderAuthData): Promise<ContentProviderAuthData | null>;
|
|
213
|
+
generateCodeVerifier(): string;
|
|
214
|
+
generateCodeChallenge(verifier: string): Promise<string>;
|
|
215
|
+
buildAuthUrl(codeVerifier: string, redirectUri: string, state?: string): Promise<{
|
|
216
|
+
url: string;
|
|
217
|
+
challengeMethod: string;
|
|
218
|
+
}>;
|
|
219
|
+
exchangeCodeForTokens(code: string, codeVerifier: string, redirectUri: string): Promise<ContentProviderAuthData | null>;
|
|
220
|
+
supportsDeviceFlow(): boolean;
|
|
221
|
+
initiateDeviceFlow(): Promise<DeviceAuthorizationResponse | null>;
|
|
222
|
+
pollDeviceFlowToken(deviceCode: string): Promise<DeviceFlowPollResult>;
|
|
223
|
+
calculatePollDelay(baseInterval?: number, slowDownCount?: number): number;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
declare function detectMediaType(url: string, explicitType?: string): "video" | "image";
|
|
227
|
+
declare function createFolder(id: string, title: string, path: string, image?: string, providerData?: Record<string, unknown>, isLeaf?: boolean): ContentFolder;
|
|
228
|
+
declare function createFile(id: string, title: string, url: string, options?: {
|
|
229
|
+
mediaType?: "video" | "image";
|
|
230
|
+
image?: string;
|
|
231
|
+
muxPlaybackId?: string;
|
|
232
|
+
providerData?: Record<string, unknown>;
|
|
233
|
+
}): ContentFile;
|
|
365
234
|
|
|
366
235
|
/**
|
|
367
|
-
*
|
|
368
|
-
*
|
|
369
|
-
*
|
|
370
|
-
|
|
236
|
+
* Path parsing utilities for content providers.
|
|
237
|
+
* Paths follow the format: /segment1/segment2/segment3/...
|
|
238
|
+
* Example: /lessons/programId/studyId/lessonId/venueId
|
|
239
|
+
*/
|
|
240
|
+
interface ParsedPath {
|
|
241
|
+
segments: string[];
|
|
242
|
+
depth: number;
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Parse a path string into segments and depth.
|
|
246
|
+
* @param path - The path to parse (e.g., "/lessons/abc123/def456")
|
|
247
|
+
* @returns Object with segments array and depth count
|
|
248
|
+
*/
|
|
249
|
+
declare function parsePath(path: string | null | undefined): ParsedPath;
|
|
250
|
+
/**
|
|
251
|
+
* Get a specific segment from a path by index.
|
|
252
|
+
* @param path - The path to parse
|
|
253
|
+
* @param index - Zero-based index of the segment to retrieve
|
|
254
|
+
* @returns The segment at the given index, or null if not found
|
|
371
255
|
*/
|
|
372
|
-
declare function
|
|
256
|
+
declare function getSegment(path: string | null | undefined, index: number): string | null;
|
|
257
|
+
/**
|
|
258
|
+
* Build a path string from segments.
|
|
259
|
+
* @param segments - Array of path segments
|
|
260
|
+
* @returns Path string with leading slash
|
|
261
|
+
*/
|
|
262
|
+
declare function buildPath(segments: string[]): string;
|
|
263
|
+
/**
|
|
264
|
+
* Append a segment to an existing path.
|
|
265
|
+
* @param basePath - The base path
|
|
266
|
+
* @param segment - The segment to append
|
|
267
|
+
* @returns New path with segment appended
|
|
268
|
+
*/
|
|
269
|
+
declare function appendToPath(basePath: string | null | undefined, segment: string): string;
|
|
270
|
+
|
|
271
|
+
declare function presentationsToPlaylist(plan: Plan): ContentFile[];
|
|
272
|
+
declare function presentationsToInstructions(plan: Plan): Instructions;
|
|
273
|
+
declare function presentationsToExpandedInstructions(plan: Plan): Instructions;
|
|
274
|
+
declare function instructionsToPlaylist(instructions: Instructions): ContentFile[];
|
|
275
|
+
declare const expandedInstructionsToPlaylist: typeof instructionsToPlaylist;
|
|
276
|
+
declare function instructionsToPresentations(instructions: Instructions, planId?: string): Plan;
|
|
277
|
+
declare const expandedInstructionsToPresentations: typeof instructionsToPresentations;
|
|
278
|
+
declare function collapseInstructions(instructions: Instructions, maxDepth?: number): Instructions;
|
|
279
|
+
declare function playlistToPresentations(files: ContentFile[], planName?: string, sectionName?: string): Plan;
|
|
280
|
+
declare function playlistToInstructions(files: ContentFile[], venueName?: string): Instructions;
|
|
281
|
+
declare const playlistToExpandedInstructions: typeof playlistToInstructions;
|
|
282
|
+
|
|
283
|
+
declare const FormatConverters_collapseInstructions: typeof collapseInstructions;
|
|
284
|
+
declare const FormatConverters_expandedInstructionsToPlaylist: typeof expandedInstructionsToPlaylist;
|
|
285
|
+
declare const FormatConverters_expandedInstructionsToPresentations: typeof expandedInstructionsToPresentations;
|
|
286
|
+
declare const FormatConverters_instructionsToPlaylist: typeof instructionsToPlaylist;
|
|
287
|
+
declare const FormatConverters_instructionsToPresentations: typeof instructionsToPresentations;
|
|
288
|
+
declare const FormatConverters_playlistToExpandedInstructions: typeof playlistToExpandedInstructions;
|
|
289
|
+
declare const FormatConverters_playlistToInstructions: typeof playlistToInstructions;
|
|
290
|
+
declare const FormatConverters_playlistToPresentations: typeof playlistToPresentations;
|
|
291
|
+
declare const FormatConverters_presentationsToExpandedInstructions: typeof presentationsToExpandedInstructions;
|
|
292
|
+
declare const FormatConverters_presentationsToInstructions: typeof presentationsToInstructions;
|
|
293
|
+
declare const FormatConverters_presentationsToPlaylist: typeof presentationsToPlaylist;
|
|
294
|
+
declare namespace FormatConverters {
|
|
295
|
+
export { FormatConverters_collapseInstructions as collapseInstructions, 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_presentationsToInstructions as presentationsToInstructions, FormatConverters_presentationsToPlaylist as presentationsToPlaylist };
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
interface FormatResolverOptions {
|
|
299
|
+
allowLossy?: boolean;
|
|
300
|
+
}
|
|
301
|
+
interface ResolvedFormatMeta {
|
|
302
|
+
isNative: boolean;
|
|
303
|
+
sourceFormat?: "playlist" | "presentations" | "instructions" | "expandedInstructions";
|
|
304
|
+
isLossy: boolean;
|
|
305
|
+
}
|
|
306
|
+
declare class FormatResolver {
|
|
307
|
+
private provider;
|
|
308
|
+
private options;
|
|
309
|
+
constructor(provider: IProvider, options?: FormatResolverOptions);
|
|
310
|
+
getProvider(): IProvider;
|
|
311
|
+
/** Extract the last segment from a path to use as fallback ID/title */
|
|
312
|
+
private getIdFromPath;
|
|
313
|
+
getPlaylist(path: string, auth?: ContentProviderAuthData | null): Promise<ContentFile[] | null>;
|
|
314
|
+
getPlaylistWithMeta(path: string, auth?: ContentProviderAuthData | null): Promise<{
|
|
315
|
+
data: ContentFile[] | null;
|
|
316
|
+
meta: ResolvedFormatMeta;
|
|
317
|
+
}>;
|
|
318
|
+
getPresentations(path: string, auth?: ContentProviderAuthData | null): Promise<Plan | null>;
|
|
319
|
+
getPresentationsWithMeta(path: string, auth?: ContentProviderAuthData | null): Promise<{
|
|
320
|
+
data: Plan | null;
|
|
321
|
+
meta: ResolvedFormatMeta;
|
|
322
|
+
}>;
|
|
323
|
+
getInstructions(path: string, auth?: ContentProviderAuthData | null): Promise<Instructions | null>;
|
|
324
|
+
getInstructionsWithMeta(path: string, auth?: ContentProviderAuthData | null): Promise<{
|
|
325
|
+
data: Instructions | null;
|
|
326
|
+
meta: ResolvedFormatMeta;
|
|
327
|
+
}>;
|
|
328
|
+
getExpandedInstructions(path: string, auth?: ContentProviderAuthData | null): Promise<Instructions | null>;
|
|
329
|
+
getExpandedInstructionsWithMeta(path: string, auth?: ContentProviderAuthData | null): Promise<{
|
|
330
|
+
data: Instructions | null;
|
|
331
|
+
meta: ResolvedFormatMeta;
|
|
332
|
+
}>;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
declare class OAuthHelper {
|
|
336
|
+
generateCodeVerifier(): string;
|
|
337
|
+
generateCodeChallenge(verifier: string): Promise<string>;
|
|
338
|
+
buildAuthUrl(config: ContentProviderConfig, codeVerifier: string, redirectUri: string, state?: string): Promise<{
|
|
339
|
+
url: string;
|
|
340
|
+
challengeMethod: string;
|
|
341
|
+
}>;
|
|
342
|
+
exchangeCodeForTokens(config: ContentProviderConfig, providerId: string, code: string, codeVerifier: string, redirectUri: string): Promise<ContentProviderAuthData | null>;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
declare class TokenHelper {
|
|
346
|
+
isAuthValid(auth: ContentProviderAuthData | null | undefined): boolean;
|
|
347
|
+
isTokenExpired(auth: ContentProviderAuthData): boolean;
|
|
348
|
+
refreshToken(config: ContentProviderConfig, auth: ContentProviderAuthData): Promise<ContentProviderAuthData | null>;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
declare class DeviceFlowHelper {
|
|
352
|
+
supportsDeviceFlow(config: ContentProviderConfig): boolean;
|
|
353
|
+
initiateDeviceFlow(config: ContentProviderConfig): Promise<DeviceAuthorizationResponse | null>;
|
|
354
|
+
pollDeviceFlowToken(config: ContentProviderConfig, deviceCode: string): Promise<DeviceFlowPollResult>;
|
|
355
|
+
calculatePollDelay(baseInterval?: number, slowDownCount?: number): number;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
declare class ApiHelper {
|
|
359
|
+
createAuthHeaders(auth: ContentProviderAuthData | null | undefined): Record<string, string> | null;
|
|
360
|
+
apiRequest<T>(config: ContentProviderConfig, providerId: string, path: string, auth?: ContentProviderAuthData | null, method?: "GET" | "POST", body?: unknown): Promise<T | null>;
|
|
361
|
+
}
|
|
373
362
|
|
|
374
363
|
/**
|
|
375
|
-
*
|
|
376
|
-
*
|
|
377
|
-
*
|
|
378
|
-
* ## Main Methods (for consumers)
|
|
379
|
-
*
|
|
380
|
-
* ### Content Browsing
|
|
381
|
-
* - `browse(folder?, auth?)` - Browse content hierarchy (root if no folder, or folder contents)
|
|
382
|
-
*
|
|
383
|
-
* ### Structured Data
|
|
384
|
-
* - `getPresentations(folder, auth?)` - Get structured plan with sections and presentations
|
|
385
|
-
* - `getInstructions(folder, auth?)` - Get instruction/run sheet data
|
|
386
|
-
* - `getExpandedInstructions(folder, auth?)` - Get expanded instructions with actions
|
|
387
|
-
*
|
|
388
|
-
* ### Provider Info
|
|
389
|
-
* - `requiresAuth()` - Whether authentication is needed
|
|
390
|
-
* - `getCapabilities()` - What features the provider supports
|
|
391
|
-
* - `getAuthTypes()` - Supported authentication methods
|
|
392
|
-
*
|
|
393
|
-
* ### Authentication (OAuth 2.0 PKCE)
|
|
394
|
-
* - `buildAuthUrl(codeVerifier, redirectUri)` - Build OAuth authorization URL
|
|
395
|
-
* - `exchangeCodeForTokens(code, codeVerifier, redirectUri)` - Exchange code for tokens
|
|
396
|
-
* - `refreshToken(auth)` - Refresh an expired access token
|
|
397
|
-
* - `isAuthValid(auth)` - Check if auth data is still valid
|
|
398
|
-
*
|
|
399
|
-
* ### Device Flow Authentication (RFC 8628)
|
|
400
|
-
* - `supportsDeviceFlow()` - Whether device flow is supported
|
|
401
|
-
* - `initiateDeviceFlow()` - Start device authorization
|
|
402
|
-
* - `pollDeviceFlowToken(deviceCode)` - Poll for token after user authorizes
|
|
364
|
+
* @deprecated Use IProvider interface instead. Providers should implement IProvider directly
|
|
365
|
+
* and use helper classes (OAuthHelper, TokenHelper, DeviceFlowHelper, ApiHelper) via composition.
|
|
366
|
+
* This class will be removed in a future version.
|
|
403
367
|
*/
|
|
404
|
-
declare abstract class ContentProvider {
|
|
405
|
-
/** Unique identifier for the provider (e.g., 'lessonschurch', 'aplay') */
|
|
368
|
+
declare abstract class ContentProvider implements IContentProvider, IAuthProvider {
|
|
406
369
|
abstract readonly id: string;
|
|
407
|
-
/** Display name of the provider */
|
|
408
370
|
abstract readonly name: string;
|
|
409
|
-
/** Provider logos for light and dark themes */
|
|
410
371
|
abstract readonly logos: ProviderLogos;
|
|
411
|
-
/** Provider configuration including API endpoints and OAuth settings */
|
|
412
372
|
abstract readonly config: ContentProviderConfig;
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
* Get a structured plan with sections and presentations for a folder.
|
|
423
|
-
* @param folder - The folder to get presentations for (typically a venue or playlist)
|
|
424
|
-
* @param auth - Optional authentication data
|
|
425
|
-
* @returns Plan object with sections, presentations, and files, or null if not supported
|
|
426
|
-
*/
|
|
427
|
-
abstract getPresentations(folder: ContentFolder, auth?: ContentProviderAuthData | null): Promise<Plan | null>;
|
|
428
|
-
/**
|
|
429
|
-
* Get a flat list of media files (playlist) for a folder.
|
|
430
|
-
* Override in subclass if the provider supports playlists.
|
|
431
|
-
* @param _folder - The folder to get playlist for (typically a venue or playlist folder)
|
|
432
|
-
* @param _auth - Optional authentication data
|
|
433
|
-
* @param _resolution - Optional resolution hint for video quality
|
|
434
|
-
* @returns Array of ContentFile objects, or null if not supported
|
|
435
|
-
*/
|
|
436
|
-
getPlaylist(_folder: ContentFolder, _auth?: ContentProviderAuthData | null, _resolution?: number): Promise<ContentFile[] | null>;
|
|
437
|
-
/**
|
|
438
|
-
* Get instruction/run sheet data for a folder.
|
|
439
|
-
* Override in subclass if the provider supports instructions.
|
|
440
|
-
* @param _folder - The folder to get instructions for
|
|
441
|
-
* @param _auth - Optional authentication data
|
|
442
|
-
* @returns Instructions object, or null if not supported
|
|
443
|
-
*/
|
|
444
|
-
getInstructions(_folder: ContentFolder, _auth?: ContentProviderAuthData | null): Promise<Instructions | null>;
|
|
445
|
-
/**
|
|
446
|
-
* Get expanded instruction data with actions for a folder.
|
|
447
|
-
* Override in subclass if the provider supports expanded instructions.
|
|
448
|
-
* @param _folder - The folder to get expanded instructions for
|
|
449
|
-
* @param _auth - Optional authentication data
|
|
450
|
-
* @returns Instructions object with expanded action data, or null if not supported
|
|
451
|
-
*/
|
|
452
|
-
getExpandedInstructions(_folder: ContentFolder, _auth?: ContentProviderAuthData | null): Promise<Instructions | null>;
|
|
453
|
-
/**
|
|
454
|
-
* Check if this provider requires authentication.
|
|
455
|
-
* @returns true if authentication is required
|
|
456
|
-
*/
|
|
373
|
+
protected readonly oauthHelper: OAuthHelper;
|
|
374
|
+
protected readonly tokenHelper: TokenHelper;
|
|
375
|
+
protected readonly deviceFlowHelper: DeviceFlowHelper;
|
|
376
|
+
protected readonly apiHelper: ApiHelper;
|
|
377
|
+
abstract browse(path?: string | null, auth?: ContentProviderAuthData | null): Promise<ContentItem[]>;
|
|
378
|
+
abstract getPresentations(path: string, auth?: ContentProviderAuthData | null): Promise<Plan | null>;
|
|
379
|
+
getPlaylist(path: string, auth?: ContentProviderAuthData | null, _resolution?: number): Promise<ContentFile[] | null>;
|
|
380
|
+
getInstructions(path: string, auth?: ContentProviderAuthData | null): Promise<Instructions | null>;
|
|
381
|
+
getExpandedInstructions(path: string, auth?: ContentProviderAuthData | null): Promise<Instructions | null>;
|
|
457
382
|
requiresAuth(): boolean;
|
|
458
|
-
/**
|
|
459
|
-
* Get the capabilities supported by this provider.
|
|
460
|
-
* Override in subclass to indicate supported features.
|
|
461
|
-
* @returns ProviderCapabilities object
|
|
462
|
-
*/
|
|
463
383
|
getCapabilities(): ProviderCapabilities;
|
|
464
|
-
/**
|
|
465
|
-
* Check the license status for a specific media item.
|
|
466
|
-
* Override in subclass if the provider requires license validation.
|
|
467
|
-
* @param _mediaId - The media ID to check
|
|
468
|
-
* @param _auth - Optional authentication data
|
|
469
|
-
* @returns MediaLicenseResult object, or null if not supported
|
|
470
|
-
*/
|
|
471
384
|
checkMediaLicense(_mediaId: string, _auth?: ContentProviderAuthData | null): Promise<MediaLicenseResult | null>;
|
|
472
|
-
/**
|
|
473
|
-
* Get the authentication types supported by this provider.
|
|
474
|
-
* @returns Array of supported AuthType values ('none', 'oauth_pkce', 'device_flow')
|
|
475
|
-
*/
|
|
476
385
|
getAuthTypes(): AuthType[];
|
|
477
|
-
/**
|
|
478
|
-
* Check if the provided auth data is still valid (not expired).
|
|
479
|
-
* @param auth - Authentication data to validate
|
|
480
|
-
* @returns true if auth is valid and not expired
|
|
481
|
-
*/
|
|
482
386
|
isAuthValid(auth: ContentProviderAuthData | null | undefined): boolean;
|
|
483
|
-
/**
|
|
484
|
-
* Check if a token is expired (with 5-minute buffer).
|
|
485
|
-
* @param auth - Authentication data to check
|
|
486
|
-
* @returns true if token is expired or will expire within 5 minutes
|
|
487
|
-
*/
|
|
488
387
|
isTokenExpired(auth: ContentProviderAuthData): boolean;
|
|
489
|
-
|
|
490
|
-
* Generate a random code verifier for PKCE.
|
|
491
|
-
* @returns A 64-character random string
|
|
492
|
-
*/
|
|
388
|
+
refreshToken(auth: ContentProviderAuthData): Promise<ContentProviderAuthData | null>;
|
|
493
389
|
generateCodeVerifier(): string;
|
|
494
|
-
/**
|
|
495
|
-
* Generate a code challenge from a code verifier using SHA-256.
|
|
496
|
-
* @param verifier - The code verifier string
|
|
497
|
-
* @returns Base64url-encoded SHA-256 hash of the verifier
|
|
498
|
-
*/
|
|
499
390
|
generateCodeChallenge(verifier: string): Promise<string>;
|
|
500
|
-
/**
|
|
501
|
-
* Build the OAuth authorization URL for PKCE flow.
|
|
502
|
-
* @param codeVerifier - The code verifier (store this for token exchange)
|
|
503
|
-
* @param redirectUri - The redirect URI to return to after authorization
|
|
504
|
-
* @param state - Optional state parameter for CSRF protection (defaults to provider ID)
|
|
505
|
-
* @returns Object with authorization URL and challenge method
|
|
506
|
-
*/
|
|
507
391
|
buildAuthUrl(codeVerifier: string, redirectUri: string, state?: string): Promise<{
|
|
508
392
|
url: string;
|
|
509
393
|
challengeMethod: string;
|
|
510
394
|
}>;
|
|
511
|
-
/**
|
|
512
|
-
* Exchange an authorization code for access and refresh tokens.
|
|
513
|
-
* @param code - The authorization code from the callback
|
|
514
|
-
* @param codeVerifier - The original code verifier used to generate the challenge
|
|
515
|
-
* @param redirectUri - The redirect URI (must match the one used in buildAuthUrl)
|
|
516
|
-
* @returns Authentication data, or null if exchange failed
|
|
517
|
-
*/
|
|
518
395
|
exchangeCodeForTokens(code: string, codeVerifier: string, redirectUri: string): Promise<ContentProviderAuthData | null>;
|
|
519
|
-
/**
|
|
520
|
-
* Refresh an expired access token using the refresh token.
|
|
521
|
-
* @param auth - The current authentication data (must include refresh_token)
|
|
522
|
-
* @returns New authentication data, or null if refresh failed
|
|
523
|
-
*/
|
|
524
|
-
refreshToken(auth: ContentProviderAuthData): Promise<ContentProviderAuthData | null>;
|
|
525
|
-
/**
|
|
526
|
-
* Check if this provider supports device flow authentication.
|
|
527
|
-
* @returns true if device flow is supported
|
|
528
|
-
*/
|
|
529
396
|
supportsDeviceFlow(): boolean;
|
|
530
|
-
/**
|
|
531
|
-
* Initiate the device authorization flow (RFC 8628).
|
|
532
|
-
* @returns Device authorization response with user_code and verification_uri, or null if not supported
|
|
533
|
-
*/
|
|
534
397
|
initiateDeviceFlow(): Promise<DeviceAuthorizationResponse | null>;
|
|
535
|
-
/**
|
|
536
|
-
* Poll for a token after user has authorized the device.
|
|
537
|
-
* @param deviceCode - The device_code from initiateDeviceFlow response
|
|
538
|
-
* @returns Auth data if successful, error object if pending/slow_down, or null if failed/expired
|
|
539
|
-
*/
|
|
540
398
|
pollDeviceFlowToken(deviceCode: string): Promise<DeviceFlowPollResult>;
|
|
541
|
-
/**
|
|
542
|
-
* Calculate the delay between device flow poll attempts.
|
|
543
|
-
* @param baseInterval - Base interval in seconds (default: 5)
|
|
544
|
-
* @param slowDownCount - Number of slow_down responses received
|
|
545
|
-
* @returns Delay in milliseconds
|
|
546
|
-
*/
|
|
547
399
|
calculatePollDelay(baseInterval?: number, slowDownCount?: number): number;
|
|
548
|
-
/**
|
|
549
|
-
* Create authorization headers for API requests.
|
|
550
|
-
* @param auth - Authentication data
|
|
551
|
-
* @returns Headers object with Authorization header, or null if no auth
|
|
552
|
-
*/
|
|
553
400
|
protected createAuthHeaders(auth: ContentProviderAuthData | null | undefined): Record<string, string> | null;
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
* @param path - API endpoint path (appended to config.apiBase)
|
|
557
|
-
* @param auth - Optional authentication data
|
|
558
|
-
* @param method - HTTP method (default: 'GET')
|
|
559
|
-
* @param body - Optional request body (for POST requests)
|
|
560
|
-
* @returns Parsed JSON response, or null if request failed
|
|
561
|
-
*/
|
|
562
|
-
protected apiRequest<T>(path: string, auth?: ContentProviderAuthData | null, method?: 'GET' | 'POST', body?: unknown): Promise<T | null>;
|
|
563
|
-
/**
|
|
564
|
-
* Helper to create a ContentFolder object.
|
|
565
|
-
* @param id - Unique identifier
|
|
566
|
-
* @param title - Display title
|
|
567
|
-
* @param image - Optional image URL
|
|
568
|
-
* @param providerData - Optional provider-specific data
|
|
569
|
-
* @returns ContentFolder object
|
|
570
|
-
*/
|
|
571
|
-
protected createFolder(id: string, title: string, image?: string, providerData?: Record<string, unknown>): ContentFolder;
|
|
572
|
-
/**
|
|
573
|
-
* Helper to create a ContentFile object with automatic media type detection.
|
|
574
|
-
* @param id - Unique identifier
|
|
575
|
-
* @param title - Display title
|
|
576
|
-
* @param url - Media URL
|
|
577
|
-
* @param options - Optional properties (mediaType, image, muxPlaybackId, providerData)
|
|
578
|
-
* @returns ContentFile object
|
|
579
|
-
*/
|
|
401
|
+
protected apiRequest<T>(path: string, auth?: ContentProviderAuthData | null, method?: "GET" | "POST", body?: unknown): Promise<T | null>;
|
|
402
|
+
protected createFolder(id: string, title: string, path: string, image?: string, providerData?: Record<string, unknown>, isLeaf?: boolean): ContentFolder;
|
|
580
403
|
protected createFile(id: string, title: string, url: string, options?: {
|
|
581
|
-
mediaType?:
|
|
404
|
+
mediaType?: "video" | "image";
|
|
582
405
|
image?: string;
|
|
583
406
|
muxPlaybackId?: string;
|
|
584
407
|
providerData?: Record<string, unknown>;
|
|
585
408
|
}): ContentFile;
|
|
586
409
|
}
|
|
587
410
|
|
|
588
|
-
|
|
411
|
+
/**
|
|
412
|
+
* APlay Provider
|
|
413
|
+
*
|
|
414
|
+
* Path structure (variable depth based on module products):
|
|
415
|
+
* /modules -> list modules
|
|
416
|
+
* /modules/{moduleId} -> list products OR libraries (depends on module)
|
|
417
|
+
* /modules/{moduleId}/products/{productId} -> list libraries (if module has multiple products)
|
|
418
|
+
* /modules/{moduleId}/products/{productId}/{libraryId} -> media files
|
|
419
|
+
* /modules/{moduleId}/libraries/{libraryId} -> media files (if module has 0-1 products)
|
|
420
|
+
*/
|
|
421
|
+
declare class APlayProvider implements IProvider {
|
|
422
|
+
private readonly apiHelper;
|
|
423
|
+
private apiRequest;
|
|
589
424
|
readonly id = "aplay";
|
|
590
425
|
readonly name = "APlay";
|
|
591
426
|
readonly logos: ProviderLogos;
|
|
592
427
|
readonly config: ContentProviderConfig;
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
428
|
+
readonly requiresAuth = true;
|
|
429
|
+
readonly authTypes: AuthType[];
|
|
430
|
+
readonly capabilities: ProviderCapabilities;
|
|
431
|
+
browse(path?: string | null, auth?: ContentProviderAuthData | null): Promise<ContentItem[]>;
|
|
432
|
+
private getModules;
|
|
433
|
+
private getModuleContent;
|
|
596
434
|
private getLibraryFolders;
|
|
597
435
|
private getMediaFiles;
|
|
598
|
-
getPresentations(
|
|
599
|
-
/**
|
|
600
|
-
* Check the license status for a specific media item.
|
|
601
|
-
* Returns license information including pingback URL if licensed.
|
|
602
|
-
*/
|
|
436
|
+
getPresentations(path: string, auth?: ContentProviderAuthData | null): Promise<Plan | null>;
|
|
603
437
|
checkMediaLicense(mediaId: string, auth?: ContentProviderAuthData | null): Promise<MediaLicenseResult | null>;
|
|
604
438
|
}
|
|
605
439
|
|
|
606
|
-
|
|
440
|
+
/**
|
|
441
|
+
* SignPresenter Provider
|
|
442
|
+
*
|
|
443
|
+
* Path structure:
|
|
444
|
+
* /playlists -> list playlists
|
|
445
|
+
* /playlists/{playlistId} -> list messages (files)
|
|
446
|
+
*/
|
|
447
|
+
declare class SignPresenterProvider implements IProvider {
|
|
448
|
+
private readonly apiHelper;
|
|
449
|
+
private apiRequest;
|
|
607
450
|
readonly id = "signpresenter";
|
|
608
451
|
readonly name = "SignPresenter";
|
|
609
452
|
readonly logos: ProviderLogos;
|
|
610
453
|
readonly config: ContentProviderConfig;
|
|
611
|
-
|
|
612
|
-
|
|
454
|
+
readonly requiresAuth = true;
|
|
455
|
+
readonly authTypes: AuthType[];
|
|
456
|
+
readonly capabilities: ProviderCapabilities;
|
|
457
|
+
browse(path?: string | null, auth?: ContentProviderAuthData | null): Promise<ContentItem[]>;
|
|
458
|
+
private getPlaylists;
|
|
613
459
|
private getMessages;
|
|
614
|
-
getPresentations(
|
|
460
|
+
getPresentations(path: string, auth?: ContentProviderAuthData | null): Promise<Plan | null>;
|
|
615
461
|
}
|
|
616
462
|
|
|
617
|
-
|
|
463
|
+
/**
|
|
464
|
+
* LessonsChurch Provider
|
|
465
|
+
*
|
|
466
|
+
* Path structure:
|
|
467
|
+
* /lessons -> programs
|
|
468
|
+
* /lessons/{programId} -> studies
|
|
469
|
+
* /lessons/{programId}/{studyId} -> lessons
|
|
470
|
+
* /lessons/{programId}/{studyId}/{lessonId} -> venues
|
|
471
|
+
* /lessons/{programId}/{studyId}/{lessonId}/{venueId} -> playlist files
|
|
472
|
+
*
|
|
473
|
+
* /addons -> categories
|
|
474
|
+
* /addons/{category} -> add-on files
|
|
475
|
+
*/
|
|
476
|
+
declare class LessonsChurchProvider implements IProvider {
|
|
618
477
|
readonly id = "lessonschurch";
|
|
619
478
|
readonly name = "Lessons.church";
|
|
620
479
|
readonly logos: ProviderLogos;
|
|
621
480
|
readonly config: ContentProviderConfig;
|
|
622
|
-
requiresAuth
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
481
|
+
readonly requiresAuth = false;
|
|
482
|
+
readonly authTypes: AuthType[];
|
|
483
|
+
readonly capabilities: ProviderCapabilities;
|
|
484
|
+
getPlaylist(path: string, _auth?: ContentProviderAuthData | null, resolution?: number): Promise<ContentFile[] | null>;
|
|
485
|
+
private apiRequest;
|
|
486
|
+
browse(path?: string | null, _auth?: ContentProviderAuthData | null): Promise<ContentItem[]>;
|
|
487
|
+
private browseLessons;
|
|
627
488
|
private getPrograms;
|
|
628
489
|
private getStudies;
|
|
629
490
|
private getLessons;
|
|
630
491
|
private getVenues;
|
|
631
492
|
private getPlaylistFiles;
|
|
493
|
+
private browseAddOns;
|
|
632
494
|
private getAddOnCategories;
|
|
633
495
|
private getAddOnsByCategory;
|
|
634
496
|
private convertAddOnToFile;
|
|
635
|
-
getPresentations(
|
|
636
|
-
getInstructions(
|
|
637
|
-
getExpandedInstructions(
|
|
497
|
+
getPresentations(path: string, _auth?: ContentProviderAuthData | null): Promise<Plan | null>;
|
|
498
|
+
getInstructions(path: string, _auth?: ContentProviderAuthData | null): Promise<Instructions | null>;
|
|
499
|
+
getExpandedInstructions(path: string, _auth?: ContentProviderAuthData | null): Promise<Instructions | null>;
|
|
500
|
+
private normalizeItemType;
|
|
638
501
|
private getEmbedUrl;
|
|
639
502
|
private convertVenueToPlan;
|
|
640
503
|
}
|
|
641
504
|
|
|
642
|
-
declare class B1ChurchProvider
|
|
505
|
+
declare class B1ChurchProvider implements IProvider {
|
|
506
|
+
private readonly apiHelper;
|
|
507
|
+
private apiRequest;
|
|
643
508
|
readonly id = "b1church";
|
|
644
509
|
readonly name = "B1.Church";
|
|
645
510
|
readonly logos: ProviderLogos;
|
|
646
511
|
readonly config: ContentProviderConfig;
|
|
647
512
|
private appBase;
|
|
648
|
-
requiresAuth
|
|
649
|
-
|
|
650
|
-
|
|
513
|
+
readonly requiresAuth = true;
|
|
514
|
+
readonly authTypes: AuthType[];
|
|
515
|
+
readonly capabilities: ProviderCapabilities;
|
|
516
|
+
buildAuthUrl(codeVerifier: string, redirectUri: string, state?: string): Promise<{
|
|
651
517
|
url: string;
|
|
652
518
|
challengeMethod: string;
|
|
653
519
|
}>;
|
|
520
|
+
exchangeCodeForTokensWithPKCE(code: string, redirectUri: string, codeVerifier: string): Promise<ContentProviderAuthData | null>;
|
|
654
521
|
exchangeCodeForTokensWithSecret(code: string, redirectUri: string, clientSecret: string): Promise<ContentProviderAuthData | null>;
|
|
655
522
|
refreshTokenWithSecret(authData: ContentProviderAuthData, clientSecret: string): Promise<ContentProviderAuthData | null>;
|
|
656
523
|
initiateDeviceFlow(): Promise<DeviceAuthorizationResponse | null>;
|
|
657
524
|
pollDeviceFlowToken(deviceCode: string): Promise<DeviceFlowPollResult>;
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
* Plans are leaf nodes - use getPresentations(), getPlaylist(), getInstructions()
|
|
665
|
-
* to get plan content.
|
|
666
|
-
*/
|
|
667
|
-
browse(folder?: ContentFolder | null, authData?: ContentProviderAuthData | null): Promise<ContentItem[]>;
|
|
668
|
-
getPresentations(folder: ContentFolder, authData?: ContentProviderAuthData | null): Promise<Plan | null>;
|
|
669
|
-
getInstructions(folder: ContentFolder, authData?: ContentProviderAuthData | null): Promise<Instructions | null>;
|
|
670
|
-
getPlaylist(folder: ContentFolder, authData?: ContentProviderAuthData | null): Promise<ContentFile[]>;
|
|
525
|
+
browse(path?: string | null, authData?: ContentProviderAuthData | null): Promise<ContentItem[]>;
|
|
526
|
+
getPresentations(path: string, authData?: ContentProviderAuthData | null): Promise<Plan | null>;
|
|
527
|
+
getInstructions(path: string, authData?: ContentProviderAuthData | null): Promise<Instructions | null>;
|
|
528
|
+
getExpandedInstructions(path: string, authData?: ContentProviderAuthData | null): Promise<Instructions | null>;
|
|
529
|
+
private processInstructionItems;
|
|
530
|
+
getPlaylist(path: string, authData?: ContentProviderAuthData | null, resolution?: number): Promise<ContentFile[] | null>;
|
|
671
531
|
}
|
|
672
532
|
|
|
673
|
-
|
|
533
|
+
/**
|
|
534
|
+
* PlanningCenter Provider
|
|
535
|
+
*
|
|
536
|
+
* Path structure:
|
|
537
|
+
* /serviceTypes -> list service types
|
|
538
|
+
* /serviceTypes/{serviceTypeId} -> list plans
|
|
539
|
+
* /serviceTypes/{serviceTypeId}/{planId} -> plan items (leaf)
|
|
540
|
+
*/
|
|
541
|
+
declare class PlanningCenterProvider implements IProvider {
|
|
542
|
+
private readonly apiHelper;
|
|
543
|
+
private apiRequest;
|
|
674
544
|
readonly id = "planningcenter";
|
|
675
545
|
readonly name = "Planning Center";
|
|
676
546
|
readonly logos: ProviderLogos;
|
|
677
547
|
readonly config: ContentProviderConfig;
|
|
678
548
|
private readonly ONE_WEEK_MS;
|
|
679
|
-
requiresAuth
|
|
680
|
-
|
|
681
|
-
|
|
549
|
+
readonly requiresAuth = true;
|
|
550
|
+
readonly authTypes: AuthType[];
|
|
551
|
+
readonly capabilities: ProviderCapabilities;
|
|
552
|
+
browse(path?: string | null, auth?: ContentProviderAuthData | null): Promise<ContentItem[]>;
|
|
553
|
+
private getServiceTypes;
|
|
682
554
|
private getPlans;
|
|
683
555
|
private getPlanItems;
|
|
684
|
-
getPresentations(
|
|
556
|
+
getPresentations(path: string, auth?: ContentProviderAuthData | null): Promise<Plan | null>;
|
|
685
557
|
private convertToPresentation;
|
|
686
558
|
private convertSongToPresentation;
|
|
687
559
|
private convertMediaToPresentation;
|
|
688
560
|
private formatDate;
|
|
689
561
|
}
|
|
690
562
|
|
|
691
|
-
|
|
563
|
+
/**
|
|
564
|
+
* BibleProject Provider
|
|
565
|
+
*
|
|
566
|
+
* Path structure:
|
|
567
|
+
* / -> list collections
|
|
568
|
+
* /{collectionSlug} -> list videos in collection
|
|
569
|
+
* /{collectionSlug}/{videoId} -> single video
|
|
570
|
+
*/
|
|
571
|
+
declare class BibleProjectProvider implements IProvider {
|
|
692
572
|
readonly id = "bibleproject";
|
|
693
573
|
readonly name = "The Bible Project";
|
|
694
574
|
readonly logos: ProviderLogos;
|
|
695
575
|
readonly config: ContentProviderConfig;
|
|
696
576
|
private data;
|
|
697
|
-
requiresAuth
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
577
|
+
readonly requiresAuth = false;
|
|
578
|
+
readonly authTypes: AuthType[];
|
|
579
|
+
readonly capabilities: ProviderCapabilities;
|
|
580
|
+
browse(path?: string | null, _auth?: ContentProviderAuthData | null): Promise<ContentItem[]>;
|
|
581
|
+
private getCollections;
|
|
582
|
+
private getLessonFolders;
|
|
583
|
+
private getVideoFile;
|
|
584
|
+
getPresentations(path: string, _auth?: ContentProviderAuthData | null): Promise<Plan | null>;
|
|
585
|
+
getPlaylist(path: string, _auth?: ContentProviderAuthData | null, _resolution?: number): Promise<ContentFile[] | null>;
|
|
586
|
+
private slugify;
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
/**
|
|
590
|
+
* HighVoltageKids Provider
|
|
591
|
+
*
|
|
592
|
+
* Path structure:
|
|
593
|
+
* / -> list collections (Elementary, Preschool)
|
|
594
|
+
* /{collectionSlug} -> list studies
|
|
595
|
+
* /{collectionSlug}/{studyId} -> list lessons
|
|
596
|
+
* /{collectionSlug}/{studyId}/{lessonId} -> lesson files (leaf)
|
|
597
|
+
*/
|
|
598
|
+
declare class HighVoltageKidsProvider implements IProvider {
|
|
599
|
+
readonly id = "highvoltagekids";
|
|
600
|
+
readonly name = "High Voltage Kids";
|
|
601
|
+
readonly logos: ProviderLogos;
|
|
602
|
+
readonly config: ContentProviderConfig;
|
|
603
|
+
private data;
|
|
604
|
+
readonly requiresAuth = false;
|
|
605
|
+
readonly authTypes: AuthType[];
|
|
606
|
+
readonly capabilities: ProviderCapabilities;
|
|
607
|
+
browse(path?: string | null, _auth?: ContentProviderAuthData | null): Promise<ContentItem[]>;
|
|
608
|
+
private getCollections;
|
|
609
|
+
private getStudyFolders;
|
|
701
610
|
private getLessonFolders;
|
|
611
|
+
private getLessonFiles;
|
|
612
|
+
getPresentations(path: string, _auth?: ContentProviderAuthData | null): Promise<Plan | null>;
|
|
613
|
+
getPlaylist(path: string, _auth?: ContentProviderAuthData | null, _resolution?: number): Promise<ContentFile[] | null>;
|
|
614
|
+
getExpandedInstructions(path: string, _auth?: ContentProviderAuthData | null): Promise<Instructions | null>;
|
|
702
615
|
private slugify;
|
|
616
|
+
private groupFilesIntoActions;
|
|
617
|
+
private getBaseName;
|
|
703
618
|
}
|
|
704
619
|
|
|
705
620
|
/**
|
|
706
621
|
* Get a provider by ID.
|
|
707
622
|
*/
|
|
708
|
-
declare function getProvider(providerId: string):
|
|
623
|
+
declare function getProvider(providerId: string): IProvider | null;
|
|
709
624
|
/**
|
|
710
625
|
* Get all registered providers.
|
|
711
626
|
*/
|
|
712
|
-
declare function getAllProviders():
|
|
627
|
+
declare function getAllProviders(): IProvider[];
|
|
713
628
|
/**
|
|
714
629
|
* Register a custom provider.
|
|
715
630
|
*/
|
|
716
|
-
declare function registerProvider(provider:
|
|
631
|
+
declare function registerProvider(provider: IProvider): void;
|
|
717
632
|
/**
|
|
718
633
|
* Get provider configuration by ID (for backward compatibility).
|
|
719
634
|
*/
|
|
@@ -721,8 +636,9 @@ declare function getProviderConfig(providerId: string): ContentProviderConfig |
|
|
|
721
636
|
/**
|
|
722
637
|
* Get list of available providers with their info including logos and auth types.
|
|
723
638
|
* Includes both implemented providers and coming soon providers.
|
|
639
|
+
* @param ids - Optional array of provider IDs to filter the results. If provided, only providers with matching IDs will be returned.
|
|
724
640
|
*/
|
|
725
|
-
declare function getAvailableProviders(): ProviderInfo[];
|
|
641
|
+
declare function getAvailableProviders(ids?: string[]): ProviderInfo[];
|
|
726
642
|
|
|
727
643
|
/**
|
|
728
644
|
* @churchapps/content-provider-helper
|
|
@@ -730,4 +646,4 @@ declare function getAvailableProviders(): ProviderInfo[];
|
|
|
730
646
|
*/
|
|
731
647
|
declare const VERSION = "0.0.1";
|
|
732
648
|
|
|
733
|
-
export { APlayProvider, type AuthType, B1ChurchProvider, BibleProjectProvider, type ContentFile, type ContentFolder, type ContentItem, ContentProvider, type ContentProviderAuthData, type ContentProviderConfig, type DeviceAuthorizationResponse, type DeviceFlowPollResult, type DeviceFlowState, type FeedActionInterface, type FeedFileInterface, type FeedSectionInterface, type FeedVenueInterface, type InstructionItem, type Instructions, LessonsChurchProvider, type MediaLicenseResult, type MediaLicenseStatus, type Plan, type PlanPresentation, type PlanSection, PlanningCenterProvider, type ProviderCapabilities, type ProviderInfo, type ProviderLogos, SignPresenterProvider, VERSION, type VenueActionInterface, type VenueActionsResponseInterface, type VenueSectionActionsInterface, detectMediaType, getAllProviders, getAvailableProviders, getProvider, getProviderConfig, isContentFile, isContentFolder, registerProvider };
|
|
649
|
+
export { APlayProvider, ApiHelper, type AuthType, B1ChurchProvider, BibleProjectProvider, type ContentFile, type ContentFolder, type ContentItem, ContentProvider, type ContentProviderAuthData, type ContentProviderConfig, type DeviceAuthorizationResponse, DeviceFlowHelper, type DeviceFlowPollResult, type DeviceFlowState, type FeedActionInterface, type FeedFileInterface, type FeedSectionInterface, type FeedVenueInterface, FormatConverters, FormatResolver, type FormatResolverOptions, HighVoltageKidsProvider, type IAuthProvider, type IContentProvider, type IProvider, type InstructionItem, type Instructions, 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, collapseInstructions, createFile, createFolder, detectMediaType, expandedInstructionsToPlaylist, expandedInstructionsToPresentations, getAllProviders, getAvailableProviders, getProvider, getProviderConfig, getSegment, instructionsToPlaylist, instructionsToPresentations, isContentFile, isContentFolder, parsePath, playlistToExpandedInstructions, playlistToInstructions, playlistToPresentations, presentationsToExpandedInstructions, presentationsToInstructions, presentationsToPlaylist, registerProvider };
|