@churchapps/content-providers 0.9.3 → 0.10.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/dist/index.cjs CHANGED
@@ -36,6 +36,7 @@ __export(index_exports, {
36
36
  SignPresenterProvider: () => SignPresenterProvider,
37
37
  TokenHelper: () => TokenHelper,
38
38
  VERSION: () => VERSION,
39
+ authIsExpired: () => authIsExpired,
39
40
  getAllProviders: () => getAllProviders,
40
41
  getAvailableProviders: () => getAvailableProviders,
41
42
  getProvider: () => getProvider,
@@ -82,18 +83,32 @@ function toAuthData(data, fallbacks) {
82
83
  ...planTypeId ? { planTypeId } : {}
83
84
  };
84
85
  }
85
- var TokenHelper = class {
86
+ function authIsExpired(auth, nowMs = Date.now()) {
87
+ if (!auth?.created_at || !auth.expires_in) return true;
88
+ const lifetimeMs = auth.expires_in * 1e3;
89
+ const expiresAt = (auth.created_at + auth.expires_in) * 1e3;
90
+ const bufferMs = Math.min(5 * 60 * 1e3, Math.floor(lifetimeMs / 10));
91
+ return nowMs > expiresAt - bufferMs;
92
+ }
93
+ var _TokenHelper = class _TokenHelper {
86
94
  isAuthValid(auth) {
87
- if (!auth) return false;
88
- return !this.isTokenExpired(auth);
95
+ return !authIsExpired(auth);
89
96
  }
90
97
  isTokenExpired(auth) {
91
- if (!auth.created_at || !auth.expires_in) return true;
92
- const expiresAt = (auth.created_at + auth.expires_in) * 1e3;
93
- return Date.now() > expiresAt - 5 * 60 * 1e3;
98
+ return authIsExpired(auth);
94
99
  }
95
100
  async refreshToken(config, auth) {
96
101
  if (!auth.refresh_token) return null;
102
+ const key = `${config.oauthBase}|${config.clientId}|${auth.refresh_token}`;
103
+ const existing = _TokenHelper.inflight.get(key);
104
+ if (existing) return existing;
105
+ const pending = this.doRefresh(config, auth).finally(() => {
106
+ _TokenHelper.inflight.delete(key);
107
+ });
108
+ _TokenHelper.inflight.set(key, pending);
109
+ return pending;
110
+ }
111
+ async doRefresh(config, auth) {
97
112
  try {
98
113
  const params = new URLSearchParams({
99
114
  grant_type: "refresh_token",
@@ -114,6 +129,8 @@ var TokenHelper = class {
114
129
  }
115
130
  }
116
131
  };
132
+ _TokenHelper.inflight = /* @__PURE__ */ new Map();
133
+ var TokenHelper = _TokenHelper;
117
134
 
118
135
  // src/helpers/OAuthHelper.ts
119
136
  function generateCodeVerifier() {
@@ -321,6 +338,12 @@ function isMediaFile(filename) {
321
338
  const lower = filename.toLowerCase();
322
339
  return [...VIDEO_EXTENSIONS, ...IMAGE_EXTENSIONS, ...AUDIO_EXTENSIONS].some((ext) => lower.endsWith(ext));
323
340
  }
341
+ function isPlaylistMedia(url, fileType, name) {
342
+ if (fileType?.startsWith("video/") || fileType?.startsWith("audio/") || fileType === "video" || fileType === "audio") return true;
343
+ const haystack = `${url} ${name || ""}`.toLowerCase();
344
+ if (haystack.includes("stream.mux.com") || haystack.includes("externalvideos/download")) return true;
345
+ return [...VIDEO_EXTENSIONS, ...AUDIO_EXTENSIONS].some((ext) => haystack.includes(ext));
346
+ }
324
347
  function createFolder(id, title, path, thumbnail, isLeaf) {
325
348
  return { type: "folder", id, title, path, thumbnail, isLeaf };
326
349
  }
@@ -994,6 +1017,18 @@ var LessonsChurchProvider = class extends BaseProvider {
994
1017
  const filtered = allAddOns.filter((a) => a.category === decodedCategory);
995
1018
  return filtered.map((addOn) => createFolder(addOn.id, addOn.name, `${currentPath}/${addOn.id}`, addOn.image, true));
996
1019
  }
1020
+ /** Flatten feed download bundles into printable files, keeping playlist media (videos already in the run-of-show) out. */
1021
+ convertFeedDownloads(bundles) {
1022
+ const result = [];
1023
+ for (const bundle of bundles || []) {
1024
+ const files = (bundle.files || []).filter((f) => f.url && !isPlaylistMedia(f.url, f.fileType, f.name));
1025
+ for (const file of files) {
1026
+ const title = (files.length === 1 ? bundle.name || file.name : file.name || bundle.name) || "Download";
1027
+ result.push({ id: file.id, title, url: file.url, fileType: file.fileType, bytes: file.bytes });
1028
+ }
1029
+ }
1030
+ return result;
1031
+ }
997
1032
  async getInstructions(path, _auth) {
998
1033
  const venueId = getSegment(path, 4);
999
1034
  if (venueId) {
@@ -1005,7 +1040,8 @@ var LessonsChurchProvider = class extends BaseProvider {
1005
1040
  if (!planItemsResponse) return null;
1006
1041
  const lessonImage = feedResponse?.lessonImage;
1007
1042
  const sectionActionsMap = buildSectionActionsMap(actionsResponse, lessonImage, feedResponse);
1008
- return { name: planItemsResponse.venueName, items: (planItemsResponse.items || []).map((item) => processInstructionItem(item, sectionActionsMap, lessonImage)) };
1043
+ const downloads = this.convertFeedDownloads(feedResponse?.downloads);
1044
+ return { name: planItemsResponse.venueName, items: (planItemsResponse.items || []).map((item) => processInstructionItem(item, sectionActionsMap, lessonImage)), downloads: downloads.length > 0 ? downloads : void 0 };
1009
1045
  }
1010
1046
  const { segments } = parsePath(path);
1011
1047
  if (segments[0] === "addons" && segments.length === 3) {
@@ -17775,7 +17811,10 @@ var GoCurriculumProvider = class extends BaseProvider {
17775
17811
  if (!files) return null;
17776
17812
  const collection = (await this.getData()).catalog.find((c) => c.id === segments[0]);
17777
17813
  const lesson = collection?.lessons.find((l) => l.id === segments[1]);
17778
- return filesToInstructions(lesson?.name || "Lesson", files);
17814
+ const instructions = filesToInstructions(lesson?.name || "Lesson", files);
17815
+ const downloads = (lesson?.resources || []).filter((r) => r.url && !isPlaylistMedia(r.url, void 0, r.file)).map((r) => ({ id: slugify(r.file || r.title), title: r.title || r.file, url: r.url }));
17816
+ if (downloads.length > 0) instructions.downloads = downloads;
17817
+ return instructions;
17779
17818
  }
17780
17819
  generateCodeVerifier() {
17781
17820
  return this.oauthHelper.generateCodeVerifier();
@@ -18022,7 +18061,7 @@ function getAvailableProviders(ids) {
18022
18061
  }
18023
18062
 
18024
18063
  // src/index.ts
18025
- var VERSION = true ? "0.9.3" : "dev";
18064
+ var VERSION = true ? "0.10.0" : "dev";
18026
18065
  // Annotate the CommonJS export names for ESM import in node:
18027
18066
  0 && (module.exports = {
18028
18067
  APlayProvider,
@@ -18041,6 +18080,7 @@ var VERSION = true ? "0.9.3" : "dev";
18041
18080
  SignPresenterProvider,
18042
18081
  TokenHelper,
18043
18082
  VERSION,
18083
+ authIsExpired,
18044
18084
  getAllProviders,
18045
18085
  getAvailableProviders,
18046
18086
  getProvider,