@churchapps/content-providers 0.5.0 → 0.6.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.
- package/README.md +8 -2
- package/dist/index.cjs +49 -21
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +31 -109
- package/dist/index.d.ts +31 -109
- package/dist/index.js +49 -21
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -93,6 +93,9 @@ var OAuthHelper = class {
|
|
|
93
93
|
}
|
|
94
94
|
async buildAuthUrl(config, codeVerifier, redirectUri, state) {
|
|
95
95
|
const codeChallenge = await generateCodeChallenge(codeVerifier);
|
|
96
|
+
return { url: this.buildAuthUrlFromChallenge(config, codeChallenge, redirectUri, state || ""), challengeMethod: "S256" };
|
|
97
|
+
}
|
|
98
|
+
buildAuthUrlFromChallenge(config, codeChallenge, redirectUri, state) {
|
|
96
99
|
const params = new URLSearchParams({
|
|
97
100
|
response_type: "code",
|
|
98
101
|
client_id: config.clientId,
|
|
@@ -100,9 +103,9 @@ var OAuthHelper = class {
|
|
|
100
103
|
scope: config.scopes.join(" "),
|
|
101
104
|
code_challenge: codeChallenge,
|
|
102
105
|
code_challenge_method: "S256",
|
|
103
|
-
state
|
|
106
|
+
state
|
|
104
107
|
});
|
|
105
|
-
return
|
|
108
|
+
return `${config.oauthBase}/authorize?${params.toString()}`;
|
|
106
109
|
}
|
|
107
110
|
async exchangeCodeForTokens(config, _providerId, code, codeVerifier, redirectUri) {
|
|
108
111
|
try {
|
|
@@ -284,12 +287,15 @@ function filesToInstructions(name, files, section) {
|
|
|
284
287
|
const items = section ? [{ id: section.id, itemType: "section", label: section.label ?? name, children: actions }] : actions;
|
|
285
288
|
return { name, items };
|
|
286
289
|
}
|
|
290
|
+
function instructionItemMediaType(item) {
|
|
291
|
+
return detectMediaType(`${item.downloadUrl || ""} ${item.label || ""}`, item.mediaType);
|
|
292
|
+
}
|
|
287
293
|
function instructionsToPlaylist(instructions) {
|
|
288
294
|
const files = [];
|
|
289
295
|
function extractFiles(items) {
|
|
290
296
|
for (const item of items) {
|
|
291
297
|
if (item.downloadUrl && (item.itemType === "file" || !item.children?.length)) {
|
|
292
|
-
files.push({ type: "file", id: item.id || item.relatedId || generateId(), title: item.label || "Untitled", mediaType:
|
|
298
|
+
files.push({ type: "file", id: item.id || item.relatedId || generateId(), title: item.label || "Untitled", mediaType: instructionItemMediaType(item), url: item.downloadUrl, downloadUrl: item.downloadUrl, seconds: item.seconds, thumbnail: item.thumbnail });
|
|
293
299
|
}
|
|
294
300
|
if (item.children) extractFiles(item.children);
|
|
295
301
|
}
|
|
@@ -399,6 +405,7 @@ function extractArray(response, ...keys) {
|
|
|
399
405
|
var APlayProvider = class extends BaseProvider {
|
|
400
406
|
constructor() {
|
|
401
407
|
super(...arguments);
|
|
408
|
+
this.oauthHelper = new OAuthHelper();
|
|
402
409
|
this.id = "aplay";
|
|
403
410
|
this.name = "APlay";
|
|
404
411
|
this.logos = { light: "https://www.joinamazing.com/_assets/v11/3ba846c5afd7e73d27bc4d87b63d423e7ae2dc73.svg", dark: "https://www.joinamazing.com/_assets/v11/3ba846c5afd7e73d27bc4d87b63d423e7ae2dc73.svg" };
|
|
@@ -468,6 +475,18 @@ var APlayProvider = class extends BaseProvider {
|
|
|
468
475
|
async checkMediaLicense(mediaId, auth) {
|
|
469
476
|
return checkMediaLicense(mediaId, auth);
|
|
470
477
|
}
|
|
478
|
+
generateCodeVerifier() {
|
|
479
|
+
return this.oauthHelper.generateCodeVerifier();
|
|
480
|
+
}
|
|
481
|
+
async buildAuthUrl(codeVerifier, redirectUri, state) {
|
|
482
|
+
return this.oauthHelper.buildAuthUrl(this.config, codeVerifier, redirectUri, state || this.id);
|
|
483
|
+
}
|
|
484
|
+
buildAuthUrlFromChallenge(codeChallenge, redirectUri, state) {
|
|
485
|
+
return this.oauthHelper.buildAuthUrlFromChallenge(this.config, codeChallenge, redirectUri, state);
|
|
486
|
+
}
|
|
487
|
+
async exchangeCodeForTokens(code, codeVerifier, redirectUri) {
|
|
488
|
+
return this.oauthHelper.exchangeCodeForTokens(this.config, this.id, code, codeVerifier, redirectUri);
|
|
489
|
+
}
|
|
471
490
|
};
|
|
472
491
|
|
|
473
492
|
// src/providers/signPresenter/SignPresenterProvider.ts
|
|
@@ -546,13 +565,15 @@ var SignPresenterProvider = class extends BaseProvider {
|
|
|
546
565
|
const instructions = filesToInstructions(title, files, { id: playlistId + "-section", label: title });
|
|
547
566
|
return { name: title, items: [{ id: playlistId + "-header", itemType: "header", label: title, children: instructions.items }] };
|
|
548
567
|
}
|
|
549
|
-
// Auth methods
|
|
550
568
|
generateCodeVerifier() {
|
|
551
569
|
return this.oauthHelper.generateCodeVerifier();
|
|
552
570
|
}
|
|
553
571
|
async buildAuthUrl(codeVerifier, redirectUri, state) {
|
|
554
572
|
return this.oauthHelper.buildAuthUrl(this.config, codeVerifier, redirectUri, state || this.id);
|
|
555
573
|
}
|
|
574
|
+
buildAuthUrlFromChallenge(codeChallenge, redirectUri, state) {
|
|
575
|
+
return this.oauthHelper.buildAuthUrlFromChallenge(this.config, codeChallenge, redirectUri, state);
|
|
576
|
+
}
|
|
556
577
|
async exchangeCodeForTokens(code, codeVerifier, redirectUri) {
|
|
557
578
|
return this.oauthHelper.exchangeCodeForTokens(this.config, this.id, code, codeVerifier, redirectUri);
|
|
558
579
|
}
|
|
@@ -925,8 +946,7 @@ function registerProvider(provider) {
|
|
|
925
946
|
}
|
|
926
947
|
|
|
927
948
|
// src/providers/b1Church/B1ChurchAuth.ts
|
|
928
|
-
|
|
929
|
-
const codeChallenge = await generateCodeChallenge(codeVerifier);
|
|
949
|
+
function buildB1AuthUrlFromChallenge(config, appBase, redirectUri, codeChallenge, state) {
|
|
930
950
|
const oauthParams = new URLSearchParams({
|
|
931
951
|
response_type: "code",
|
|
932
952
|
client_id: config.clientId,
|
|
@@ -934,10 +954,13 @@ async function buildB1AuthUrl(config, appBase, redirectUri, codeVerifier, state)
|
|
|
934
954
|
scope: config.scopes.join(" "),
|
|
935
955
|
code_challenge: codeChallenge,
|
|
936
956
|
code_challenge_method: "S256",
|
|
937
|
-
state
|
|
957
|
+
state
|
|
938
958
|
});
|
|
939
|
-
|
|
940
|
-
|
|
959
|
+
return `${appBase}/oauth?${oauthParams.toString()}`;
|
|
960
|
+
}
|
|
961
|
+
async function buildB1AuthUrl(config, appBase, redirectUri, codeVerifier, state) {
|
|
962
|
+
const codeChallenge = await generateCodeChallenge(codeVerifier);
|
|
963
|
+
return { url: buildB1AuthUrlFromChallenge(config, appBase, redirectUri, codeChallenge, state || ""), challengeMethod: "S256" };
|
|
941
964
|
}
|
|
942
965
|
async function exchangeCodeForTokensWithPKCE(config, code, redirectUri, codeVerifier) {
|
|
943
966
|
try {
|
|
@@ -1169,6 +1192,7 @@ function collectFilesFromNode(node) {
|
|
|
1169
1192
|
id: node.id,
|
|
1170
1193
|
name: node.label || "",
|
|
1171
1194
|
url: node.downloadUrl,
|
|
1195
|
+
fileType: instructionItemMediaType(node),
|
|
1172
1196
|
seconds: node.seconds || 10
|
|
1173
1197
|
});
|
|
1174
1198
|
}
|
|
@@ -1234,6 +1258,9 @@ function findFirstThumbnail(items) {
|
|
|
1234
1258
|
}
|
|
1235
1259
|
return void 0;
|
|
1236
1260
|
}
|
|
1261
|
+
function isLessonsChurchContent(plan) {
|
|
1262
|
+
return !plan.providerId || plan.providerId === "lessonschurch";
|
|
1263
|
+
}
|
|
1237
1264
|
function isExternalProviderItem(item) {
|
|
1238
1265
|
if (!item.providerId || item.providerId === "b1church") return false;
|
|
1239
1266
|
if (item.providerPath) return true;
|
|
@@ -1260,10 +1287,16 @@ var B1ChurchProvider = class extends BaseProvider {
|
|
|
1260
1287
|
this.capabilities = { browse: true, playlist: true, instructions: true, mediaLicensing: false };
|
|
1261
1288
|
this.planTypeId = null;
|
|
1262
1289
|
}
|
|
1290
|
+
generateCodeVerifier() {
|
|
1291
|
+
return generateCodeVerifier();
|
|
1292
|
+
}
|
|
1263
1293
|
async buildAuthUrl(codeVerifier, redirectUri, state) {
|
|
1264
1294
|
return buildB1AuthUrl(this.config, this.appBase, redirectUri, codeVerifier, state);
|
|
1265
1295
|
}
|
|
1266
|
-
|
|
1296
|
+
buildAuthUrlFromChallenge(codeChallenge, redirectUri, state) {
|
|
1297
|
+
return buildB1AuthUrlFromChallenge(this.config, this.appBase, redirectUri, codeChallenge, state);
|
|
1298
|
+
}
|
|
1299
|
+
async exchangeCodeForTokens(code, codeVerifier, redirectUri) {
|
|
1267
1300
|
return exchangeCodeForTokensWithPKCE(this.config, code, redirectUri, codeVerifier);
|
|
1268
1301
|
}
|
|
1269
1302
|
async exchangeCodeForTokensWithSecret(code, redirectUri, clientSecret) {
|
|
@@ -1399,7 +1432,7 @@ var B1ChurchProvider = class extends BaseProvider {
|
|
|
1399
1432
|
const planFolder = plans.find((p) => p.id === planId);
|
|
1400
1433
|
if (!planFolder) return null;
|
|
1401
1434
|
const churchId = planFolder.churchId;
|
|
1402
|
-
const venueId = planFolder.contentId;
|
|
1435
|
+
const venueId = isLessonsChurchContent(planFolder) ? planFolder.contentId : void 0;
|
|
1403
1436
|
const planTitle = planFolder.name || "Plan";
|
|
1404
1437
|
if (!churchId) {
|
|
1405
1438
|
console.warn("[B1Church getInstructions] planFolder missing churchId:", planFolder.id);
|
|
@@ -1508,7 +1541,7 @@ var B1ChurchProvider = class extends BaseProvider {
|
|
|
1508
1541
|
return null;
|
|
1509
1542
|
}
|
|
1510
1543
|
const churchId = planFolder.churchId;
|
|
1511
|
-
const venueId = planFolder.contentId;
|
|
1544
|
+
const venueId = isLessonsChurchContent(planFolder) ? planFolder.contentId : void 0;
|
|
1512
1545
|
if (!churchId) {
|
|
1513
1546
|
console.warn("[B1Church] getPlaylist: planFolder missing churchId:", planFolder.id);
|
|
1514
1547
|
return null;
|
|
@@ -1532,7 +1565,7 @@ var B1ChurchProvider = class extends BaseProvider {
|
|
|
1532
1565
|
const venueFeed = venueId ? await fetchVenueFeed(venueId) : null;
|
|
1533
1566
|
const files = [];
|
|
1534
1567
|
for (const sectionItem of planItems) {
|
|
1535
|
-
for (const child of sectionItem.children
|
|
1568
|
+
for (const child of sectionItem.children?.length ? sectionItem.children : [sectionItem]) {
|
|
1536
1569
|
const childItemType = child.itemType;
|
|
1537
1570
|
const isSectionType = childItemType === "section" || childItemType === "lessonSection" || childItemType === "providerSection";
|
|
1538
1571
|
const canExpandLocally = isSectionType && venueFeed && child.relatedId;
|
|
@@ -1663,7 +1696,6 @@ var DropboxProvider = class extends BaseProvider {
|
|
|
1663
1696
|
mediaLicensing: false
|
|
1664
1697
|
};
|
|
1665
1698
|
}
|
|
1666
|
-
// -- Pagination helper --
|
|
1667
1699
|
dropboxPost(endpoint, body, auth) {
|
|
1668
1700
|
if (!auth) {
|
|
1669
1701
|
console.error("[Dropbox] No auth token provided");
|
|
@@ -1697,7 +1729,6 @@ var DropboxProvider = class extends BaseProvider {
|
|
|
1697
1729
|
}
|
|
1698
1730
|
return allEntries;
|
|
1699
1731
|
}
|
|
1700
|
-
// -- File link helpers --
|
|
1701
1732
|
async getSharedLink(filePath, auth) {
|
|
1702
1733
|
if (!auth) return null;
|
|
1703
1734
|
try {
|
|
@@ -1753,7 +1784,6 @@ var DropboxProvider = class extends BaseProvider {
|
|
|
1753
1784
|
);
|
|
1754
1785
|
return results.filter((r) => r.viewUrl || r.downloadUrl).map((r) => fileEntryToContentFile(r.entry, r.viewUrl || r.downloadUrl, r.downloadUrl));
|
|
1755
1786
|
}
|
|
1756
|
-
// -- Leaf detection --
|
|
1757
1787
|
async checkIsLeaf(folderPath, auth) {
|
|
1758
1788
|
const response = await this.dropboxPost(
|
|
1759
1789
|
"/2/files/list_folder",
|
|
@@ -1763,7 +1793,6 @@ var DropboxProvider = class extends BaseProvider {
|
|
|
1763
1793
|
if (!response) return false;
|
|
1764
1794
|
return !response.entries.some((e) => e[".tag"] === "folder");
|
|
1765
1795
|
}
|
|
1766
|
-
// -- IProvider methods --
|
|
1767
1796
|
async browse(path, auth) {
|
|
1768
1797
|
const dropboxPath = path && path !== "/" ? path.startsWith("/") ? path : "/" + path : "";
|
|
1769
1798
|
const allEntries = await this.listAllEntries(dropboxPath, auth);
|
|
@@ -1775,7 +1804,6 @@ var DropboxProvider = class extends BaseProvider {
|
|
|
1775
1804
|
const fileItems = await this.resolveFileLinks(mediaFiles, auth);
|
|
1776
1805
|
return [...folderItems, ...fileItems];
|
|
1777
1806
|
}
|
|
1778
|
-
/** Resolve a folder path to playable files (list + media filter + link resolution). */
|
|
1779
1807
|
async resolveMediaFiles(path, auth) {
|
|
1780
1808
|
if (!path || path === "/") return null;
|
|
1781
1809
|
const dropboxPath = path.startsWith("/") ? path : "/" + path;
|
|
@@ -1797,7 +1825,6 @@ var DropboxProvider = class extends BaseProvider {
|
|
|
1797
1825
|
const folderName = segments[segments.length - 1] || "Dropbox";
|
|
1798
1826
|
return filesToInstructions(folderName, resolved.files, { id: "dropbox-section", label: folderName });
|
|
1799
1827
|
}
|
|
1800
|
-
// -- Auth methods --
|
|
1801
1828
|
generateCodeVerifier() {
|
|
1802
1829
|
return this.oauthHelper.generateCodeVerifier();
|
|
1803
1830
|
}
|
|
@@ -1854,7 +1881,8 @@ var PlanningCenterProvider = class extends BaseProvider {
|
|
|
1854
1881
|
this.logos = { light: "https://www.planningcenter.com/icons/icon-512x512.png", dark: "https://www.planningcenter.com/icons/icon-512x512.png" };
|
|
1855
1882
|
this.config = { id: "planningcenter", name: "Planning Center", apiBase: "https://api.planningcenteronline.com", oauthBase: "https://api.planningcenteronline.com/oauth", clientId: "", scopes: ["services"] };
|
|
1856
1883
|
this.requiresAuth = true;
|
|
1857
|
-
|
|
1884
|
+
// No client-side auth flow: clientId is unset and no PKCE methods exist. Auth tokens must be supplied externally (server-side).
|
|
1885
|
+
this.authTypes = [];
|
|
1858
1886
|
// Plan items come back without media URLs, so playlist/instructions are not actually supported yet.
|
|
1859
1887
|
this.capabilities = { browse: true, playlist: false, instructions: false, mediaLicensing: false };
|
|
1860
1888
|
}
|
|
@@ -16317,7 +16345,7 @@ function getAvailableProviders(ids) {
|
|
|
16317
16345
|
}
|
|
16318
16346
|
|
|
16319
16347
|
// src/index.ts
|
|
16320
|
-
var VERSION = true ? "0.
|
|
16348
|
+
var VERSION = true ? "0.6.0" : "dev";
|
|
16321
16349
|
export {
|
|
16322
16350
|
APlayProvider,
|
|
16323
16351
|
B1ChurchProvider,
|