@dxos/plugin-youtube 0.8.4-main.bcb3aa67d6 → 0.8.4-main.fcfe5033a5

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.
Files changed (77) hide show
  1. package/dist/lib/browser/{chunk-5N5SWF3I.mjs → chunk-FEQD5TPI.mjs} +2 -2
  2. package/dist/lib/browser/{chunk-5N5SWF3I.mjs.map → chunk-FEQD5TPI.mjs.map} +2 -2
  3. package/dist/lib/browser/{chunk-SWWE4LUJ.mjs → chunk-GIRFSTHR.mjs} +4 -4
  4. package/dist/lib/browser/{chunk-SWWE4LUJ.mjs.map → chunk-GIRFSTHR.mjs.map} +3 -3
  5. package/dist/lib/browser/{clear-synced-videos-PIKJZET3.mjs → clear-synced-videos-PMP332H3.mjs} +8 -8
  6. package/dist/lib/browser/clear-synced-videos-PMP332H3.mjs.map +7 -0
  7. package/dist/lib/browser/index.mjs +5 -5
  8. package/dist/lib/browser/index.mjs.map +3 -3
  9. package/dist/lib/browser/meta.json +1 -1
  10. package/dist/lib/browser/{sync-II7O2LPG.mjs → sync-T34US6NO.mjs} +15 -15
  11. package/dist/lib/browser/sync-T34US6NO.mjs.map +7 -0
  12. package/dist/lib/node-esm/{chunk-RL46XZ2D.mjs → chunk-A3SKNJFU.mjs} +4 -4
  13. package/dist/lib/node-esm/{chunk-RL46XZ2D.mjs.map → chunk-A3SKNJFU.mjs.map} +3 -3
  14. package/dist/lib/node-esm/{chunk-BVKMXV2G.mjs → chunk-Q3TVMR5B.mjs} +2 -2
  15. package/dist/lib/node-esm/{chunk-BVKMXV2G.mjs.map → chunk-Q3TVMR5B.mjs.map} +2 -2
  16. package/dist/lib/node-esm/{clear-synced-videos-Q3MZO2CD.mjs → clear-synced-videos-SLEDJ5WI.mjs} +8 -8
  17. package/dist/lib/node-esm/clear-synced-videos-SLEDJ5WI.mjs.map +7 -0
  18. package/dist/lib/node-esm/index.mjs +5 -5
  19. package/dist/lib/node-esm/index.mjs.map +3 -3
  20. package/dist/lib/node-esm/meta.json +1 -1
  21. package/dist/lib/node-esm/{sync-BEXQNNSH.mjs → sync-RQYQ5LII.mjs} +15 -15
  22. package/dist/lib/node-esm/sync-RQYQ5LII.mjs.map +7 -0
  23. package/dist/types/src/capabilities/app-graph-builder.d.ts.map +1 -1
  24. package/dist/types/src/capabilities/index.d.ts +1 -1
  25. package/dist/types/src/capabilities/index.d.ts.map +1 -1
  26. package/dist/types/src/capabilities/migrations.d.ts +1 -1
  27. package/dist/types/src/capabilities/react-surface.d.ts.map +1 -1
  28. package/dist/types/src/containers/ChannelArticle/ChannelArticle.d.ts +1 -1
  29. package/dist/types/src/containers/ChannelArticle/ChannelArticle.d.ts.map +1 -1
  30. package/dist/types/src/containers/ChannelArticle/index.d.ts +1 -2
  31. package/dist/types/src/containers/ChannelArticle/index.d.ts.map +1 -1
  32. package/dist/types/src/containers/ChannelProperties/ChannelProperties.d.ts +7 -0
  33. package/dist/types/src/containers/ChannelProperties/ChannelProperties.d.ts.map +1 -0
  34. package/dist/types/src/containers/ChannelProperties/index.d.ts +2 -0
  35. package/dist/types/src/containers/ChannelProperties/index.d.ts.map +1 -0
  36. package/dist/types/src/containers/VideoArticle/VideoArticle.d.ts +2 -2
  37. package/dist/types/src/containers/VideoArticle/VideoArticle.d.ts.map +1 -1
  38. package/dist/types/src/containers/VideoArticle/index.d.ts +1 -2
  39. package/dist/types/src/containers/VideoArticle/index.d.ts.map +1 -1
  40. package/dist/types/src/containers/VideoCard/VideoCard.d.ts +2 -2
  41. package/dist/types/src/containers/VideoCard/VideoCard.d.ts.map +1 -1
  42. package/dist/types/src/containers/VideoCard/index.d.ts +1 -2
  43. package/dist/types/src/containers/VideoCard/index.d.ts.map +1 -1
  44. package/dist/types/src/containers/index.d.ts +3 -3
  45. package/dist/types/src/containers/index.d.ts.map +1 -1
  46. package/dist/types/src/operations/apis/youtube/api.d.ts.map +1 -1
  47. package/dist/types/src/operations/clear-synced-videos.d.ts.map +1 -1
  48. package/dist/types/src/operations/definitions.d.ts +3 -3
  49. package/dist/types/src/operations/definitions.d.ts.map +1 -1
  50. package/dist/types/src/operations/sync.d.ts.map +1 -1
  51. package/dist/types/tsconfig.tsbuildinfo +1 -1
  52. package/package.json +40 -40
  53. package/src/YouTubePlugin.tsx +3 -3
  54. package/src/capabilities/app-graph-builder.ts +13 -14
  55. package/src/capabilities/react-surface.tsx +20 -21
  56. package/src/containers/ChannelArticle/ChannelArticle.tsx +1 -1
  57. package/src/containers/ChannelArticle/index.ts +1 -3
  58. package/src/containers/{ChannelSettings/ChannelSettings.tsx → ChannelProperties/ChannelProperties.tsx} +2 -2
  59. package/src/containers/ChannelProperties/index.ts +5 -0
  60. package/src/containers/VideoArticle/VideoArticle.tsx +2 -2
  61. package/src/containers/VideoArticle/index.ts +1 -3
  62. package/src/containers/VideoCard/VideoCard.tsx +2 -2
  63. package/src/containers/VideoCard/index.ts +1 -3
  64. package/src/containers/index.ts +4 -4
  65. package/src/operations/apis/youtube/api.ts +0 -1
  66. package/src/operations/clear-synced-videos.ts +3 -4
  67. package/src/operations/definitions.ts +3 -3
  68. package/src/operations/sync.ts +0 -1
  69. package/dist/lib/browser/clear-synced-videos-PIKJZET3.mjs.map +0 -7
  70. package/dist/lib/browser/sync-II7O2LPG.mjs.map +0 -7
  71. package/dist/lib/node-esm/clear-synced-videos-Q3MZO2CD.mjs.map +0 -7
  72. package/dist/lib/node-esm/sync-BEXQNNSH.mjs.map +0 -7
  73. package/dist/types/src/containers/ChannelSettings/ChannelSettings.d.ts +0 -7
  74. package/dist/types/src/containers/ChannelSettings/ChannelSettings.d.ts.map +0 -1
  75. package/dist/types/src/containers/ChannelSettings/index.d.ts +0 -3
  76. package/dist/types/src/containers/ChannelSettings/index.d.ts.map +0 -1
  77. package/src/containers/ChannelSettings/index.ts +0 -7
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  GoogleCredentials,
3
3
  youtube_exports
4
- } from "./chunk-5N5SWF3I.mjs";
4
+ } from "./chunk-FEQD5TPI.mjs";
5
5
  import {
6
6
  Sync
7
- } from "./chunk-SWWE4LUJ.mjs";
7
+ } from "./chunk-GIRFSTHR.mjs";
8
8
  import {
9
9
  Video_exports
10
10
  } from "./chunk-GTIWG45H.mjs";
@@ -71,7 +71,7 @@ var handler = Sync.pipe(Operation.withHandler(({ channel: channelRef, restricted
71
71
  includeTranscripts
72
72
  }, {
73
73
  F: __dxlog_file2,
74
- L: 28,
74
+ L: 27,
75
75
  S: this,
76
76
  C: (f, a) => f(...a)
77
77
  });
@@ -83,7 +83,7 @@ var handler = Sync.pipe(Operation.withHandler(({ channel: channelRef, restricted
83
83
  const channelInfo = extractChannelInfo(channelUrl);
84
84
  log2("extracted channel info", channelInfo, {
85
85
  F: __dxlog_file2,
86
- L: 38,
86
+ L: 37,
87
87
  S: this,
88
88
  C: (f, a) => f(...a)
89
89
  });
@@ -94,7 +94,7 @@ var handler = Sync.pipe(Operation.withHandler(({ channel: channelRef, restricted
94
94
  uploadsPlaylistId
95
95
  }, {
96
96
  F: __dxlog_file2,
97
- L: 41,
97
+ L: 40,
98
98
  S: this,
99
99
  C: (f, a) => f(...a)
100
100
  });
@@ -111,7 +111,7 @@ var handler = Sync.pipe(Operation.withHandler(({ channel: channelRef, restricted
111
111
  count: existingVideoIds.size
112
112
  }, {
113
113
  F: __dxlog_file2,
114
- L: 54,
114
+ L: 53,
115
115
  S: this,
116
116
  C: (f, a) => f(...a)
117
117
  });
@@ -124,7 +124,7 @@ var handler = Sync.pipe(Operation.withHandler(({ channel: channelRef, restricted
124
124
  channelTitle
125
125
  }, {
126
126
  F: __dxlog_file2,
127
- L: 68,
127
+ L: 67,
128
128
  S: this,
129
129
  C: (f, a) => f(...a)
130
130
  });
@@ -237,7 +237,7 @@ var fetchPlaylistVideos = (uploadsPlaylistId, maxVideos) => {
237
237
  hasMore: Boolean(response.nextPageToken)
238
238
  }, {
239
239
  F: __dxlog_file2,
240
- L: 187,
240
+ L: 186,
241
241
  S: this,
242
242
  C: (f, a) => f(...a)
243
243
  });
@@ -278,7 +278,7 @@ var streamVideosToFeed = Effect2.fn(function* (uploadsPlaylistId, feed, existing
278
278
  videoId
279
279
  }, {
280
280
  F: __dxlog_file2,
281
- L: 251,
281
+ L: 250,
282
282
  S: this,
283
283
  C: (f, a) => f(...a)
284
284
  });
@@ -290,7 +290,7 @@ var streamVideosToFeed = Effect2.fn(function* (uploadsPlaylistId, feed, existing
290
290
  count: videoIds.length
291
291
  }, {
292
292
  F: __dxlog_file2,
293
- L: 261,
293
+ L: 260,
294
294
  S: this,
295
295
  C: (f, a) => f(...a)
296
296
  });
@@ -305,7 +305,7 @@ var streamVideosToFeed = Effect2.fn(function* (uploadsPlaylistId, feed, existing
305
305
  videoId: item.id
306
306
  }, {
307
307
  F: __dxlog_file2,
308
- L: 275,
308
+ L: 274,
309
309
  S: this,
310
310
  C: (f, a) => f(...a)
311
311
  });
@@ -317,7 +317,7 @@ var streamVideosToFeed = Effect2.fn(function* (uploadsPlaylistId, feed, existing
317
317
  length: transcript.fullText.length
318
318
  }, {
319
319
  F: __dxlog_file2,
320
- L: 279,
320
+ L: 278,
321
321
  S: this,
322
322
  C: (f, a) => f(...a)
323
323
  });
@@ -326,7 +326,7 @@ var streamVideosToFeed = Effect2.fn(function* (uploadsPlaylistId, feed, existing
326
326
  videoId: item.id
327
327
  }, {
328
328
  F: __dxlog_file2,
329
- L: 281,
329
+ L: 280,
330
330
  S: this,
331
331
  C: (f, a) => f(...a)
332
332
  });
@@ -342,7 +342,7 @@ var streamVideosToFeed = Effect2.fn(function* (uploadsPlaylistId, feed, existing
342
342
  count: videos.length
343
343
  }, {
344
344
  F: __dxlog_file2,
345
- L: 297,
345
+ L: 296,
346
346
  S: this,
347
347
  C: (f, a) => f(...a)
348
348
  });
@@ -356,4 +356,4 @@ var sync_default = handler;
356
356
  export {
357
357
  sync_default as default
358
358
  };
359
- //# sourceMappingURL=sync-II7O2LPG.mjs.map
359
+ //# sourceMappingURL=sync-T34US6NO.mjs.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/operations/sync.ts", "../../../src/operations/transcript.ts"],
4
+ "sourcesContent": ["//\n// Copyright 2024 DXOS.org\n//\n\nimport * as FetchHttpClient from '@effect/platform/FetchHttpClient';\nimport * as Chunk from 'effect/Chunk';\nimport * as Effect from 'effect/Effect';\nimport * as Function from 'effect/Function';\nimport * as Layer from 'effect/Layer';\nimport * as Option from 'effect/Option';\nimport * as Predicate from 'effect/Predicate';\nimport * as Stream from 'effect/Stream';\n\nimport { Database, Feed, Filter, Obj, Ref } from '@dxos/echo';\nimport { log } from '@dxos/log';\nimport { Operation } from '@dxos/operation';\n\nimport { Channel, Video } from '../types';\nimport { YouTube } from './apis';\nimport { Sync } from './definitions';\nimport { GoogleCredentials } from './services/google-credentials';\nimport { fetchTranscript } from './transcript';\n\nconst handler: Operation.WithHandler<typeof Sync> = Sync.pipe(\n Operation.withHandler(({ channel: channelRef, restrictedMode = false, includeTranscripts = true }) =>\n Effect.gen(function* () {\n log('syncing youtube channel', { channel: channelRef.dxn.toString(), restrictedMode, includeTranscripts });\n const channel = yield* Database.load(channelRef);\n\n const channelUrl =\n (channel as Channel.YouTubeChannel).channelUrl ?? (channel as Channel.YouTubeChannel).channelId;\n if (!channelUrl) {\n return yield* Effect.fail(new Error('No channel URL or ID configured'));\n }\n\n const channelInfo = extractChannelInfo(channelUrl);\n log('extracted channel info', channelInfo);\n\n const { channelId, channelTitle, uploadsPlaylistId } = yield* getUploadsPlaylistId(channelInfo);\n log('found channel', { channelId, channelTitle, uploadsPlaylistId });\n\n Obj.change(channel as Channel.YouTubeChannel, (channelObj) => {\n channelObj.channelId = channelId;\n if (!channelObj.name) {\n channelObj.name = channelTitle;\n }\n });\n\n // Get the feed and query for existing videos.\n const feed = yield* Database.load((channel as Channel.YouTubeChannel).feed as Ref.Ref<Feed.Feed>);\n const existingVideos = yield* Feed.runQuery(feed, Filter.type(Video.YouTubeVideo));\n const existingVideoIds = new Set(existingVideos.map((video: Video.YouTubeVideo) => video.videoId));\n log('existing videos', { count: existingVideoIds.size });\n\n const newVideosCount = yield* streamVideosToFeed(\n uploadsPlaylistId,\n feed,\n existingVideoIds,\n restrictedMode,\n includeTranscripts,\n );\n\n Obj.change(channel as Channel.YouTubeChannel, (channelObj) => {\n channelObj.lastSyncedAt = new Date().toISOString();\n });\n\n log('sync complete', { newVideos: newVideosCount, channelTitle });\n return {\n newVideos: newVideosCount,\n channelTitle,\n };\n }).pipe(Effect.provide(Layer.mergeAll(FetchHttpClient.layer, GoogleCredentials.fromChannelRef(channelRef)))),\n ),\n);\n\nconst STREAMING_CONFIG = {\n /** Videos per page from YouTube API. */\n maxResults: 50,\n /** Parallel transcript fetches. */\n transcriptFetchConcurrency: 3,\n /** In-flight video buffer. */\n bufferSize: 10,\n /** Videos per feed append. */\n feedBatchSize: 10,\n /** Max videos in restricted mode. */\n restrictedMax: 20,\n} as const;\n\n/**\n * Extracts channel ID from various YouTube URL formats.\n */\nconst extractChannelInfo = (\n urlOrHandle: string,\n): { type: 'id'; value: string } | { type: 'handle'; value: string } | { type: 'url'; value: string } => {\n const trimmed = urlOrHandle.trim();\n\n if (trimmed.startsWith('@')) {\n return { type: 'handle', value: trimmed.slice(1) };\n }\n\n if (trimmed.startsWith('UC') && trimmed.length === 24) {\n return { type: 'id', value: trimmed };\n }\n\n try {\n const url = new URL(trimmed);\n const pathname = url.pathname;\n\n if (pathname.startsWith('/channel/')) {\n const channelId = pathname.split('/')[2];\n if (channelId) {\n return { type: 'id', value: channelId };\n }\n }\n\n if (pathname.startsWith('/@')) {\n return { type: 'handle', value: pathname.slice(2) };\n }\n\n if (pathname.startsWith('/c/') || pathname.startsWith('/user/')) {\n const name = pathname.split('/')[2];\n if (name) {\n return { type: 'handle', value: name };\n }\n }\n } catch {\n if (/^[a-zA-Z0-9_-]+$/.test(trimmed)) {\n return { type: 'handle', value: trimmed };\n }\n }\n\n return { type: 'url', value: trimmed };\n};\n\n/**\n * Gets the uploads playlist ID for a channel.\n */\nconst getUploadsPlaylistId = Effect.fn(function* (channelInfo: { type: string; value: string }) {\n let channelResponse;\n\n if (channelInfo.type === 'id') {\n channelResponse = yield* YouTube.getChannel(channelInfo.value);\n } else {\n channelResponse = yield* YouTube.getChannelByHandle(channelInfo.value);\n }\n\n const channel = channelResponse.items[0];\n if (!channel) {\n return yield* Effect.fail(new Error(`Channel not found: ${channelInfo.value}`));\n }\n\n const uploadsPlaylistId = channel.contentDetails?.relatedPlaylists?.uploads;\n if (!uploadsPlaylistId) {\n return yield* Effect.fail(new Error(`No uploads playlist found for channel: ${channelInfo.value}`));\n }\n\n return {\n channelId: channel.id,\n channelTitle: channel.snippet?.title ?? '',\n uploadsPlaylistId,\n };\n});\n\n/**\n * Fetches videos from an uploads playlist, returning them from newest to oldest.\n */\nconst fetchPlaylistVideos = (uploadsPlaylistId: string, maxVideos?: number) => {\n let videoCount = 0;\n\n return Stream.unfoldChunkEffect({ pageToken: Option.none<string>(), done: false }, (state) =>\n Effect.gen(function* () {\n if (state.done || (maxVideos && videoCount >= maxVideos)) {\n return Option.none();\n }\n\n const response = yield* YouTube.listPlaylistItems(\n uploadsPlaylistId,\n STREAMING_CONFIG.maxResults,\n Option.getOrUndefined(state.pageToken),\n );\n\n const videoIds = response.items\n .map((item) => item.snippet?.resourceId?.videoId)\n .filter((id): id is string => Boolean(id));\n\n log('fetched playlist items', {\n count: videoIds.length,\n pageToken: Option.getOrUndefined(state.pageToken),\n hasMore: Boolean(response.nextPageToken),\n });\n\n videoCount += videoIds.length;\n\n const nextState = {\n pageToken: Option.fromNullable(response.nextPageToken),\n done: !response.nextPageToken || (maxVideos !== undefined && videoCount >= maxVideos),\n };\n\n return Option.some([Chunk.fromIterable(videoIds), nextState]);\n }),\n );\n};\n\ntype TranscriptData = { segments: Video.TranscriptSegment[]; fullText: string };\n\n/**\n * Maps YouTube API video item to YouTubeVideo data.\n */\nconst mapVideoData = (\n item: YouTube.VideoItem,\n transcript: TranscriptData | undefined,\n includeTranscripts: boolean,\n): Omit<Video.YouTubeVideo, 'id' | '~@dxos/echo/Kind'> => {\n const hasTranscript = Boolean(transcript?.fullText?.trim());\n return {\n title: item.snippet?.title ?? 'Untitled',\n videoId: item.id,\n description: item.snippet?.description,\n url: `https://www.youtube.com/watch?v=${item.id}`,\n thumbnailUrl:\n item.snippet?.thumbnails?.high?.url ??\n item.snippet?.thumbnails?.medium?.url ??\n item.snippet?.thumbnails?.default?.url,\n channelTitle: item.snippet?.channelTitle,\n publishedAt: item.snippet?.publishedAt ?? new Date().toISOString(),\n duration: item.contentDetails?.duration,\n viewCount: item.statistics?.viewCount ? parseInt(item.statistics.viewCount, 10) : undefined,\n likeCount: item.statistics?.likeCount ? parseInt(item.statistics.likeCount, 10) : undefined,\n transcript: transcript && hasTranscript ? transcript.fullText : undefined,\n transcriptSegments: transcript && hasTranscript ? transcript.segments : undefined,\n transcriptFetched: includeTranscripts ? hasTranscript : false,\n };\n};\n\n/**\n * Stream videos with transcripts into a DXOS feed.\n */\nconst streamVideosToFeed = Effect.fn(function* (\n uploadsPlaylistId: string,\n feed: Feed.Feed,\n existingVideoIds: Set<string>,\n restricted: boolean,\n includeTranscripts: boolean,\n) {\n const count = yield* Function.pipe(\n fetchPlaylistVideos(uploadsPlaylistId, restricted ? STREAMING_CONFIG.restrictedMax : undefined),\n Stream.filter((videoId) => {\n const isDuplicate = existingVideoIds.has(videoId);\n if (isDuplicate) {\n log('skipping duplicate video', { videoId });\n }\n return !isDuplicate;\n }),\n restricted ? Stream.take(STREAMING_CONFIG.restrictedMax) : Function.identity,\n Stream.grouped(10),\n Stream.flatMap(\n (videoIdChunk) =>\n Effect.gen(function* () {\n const videoIds = Chunk.toArray(videoIdChunk);\n log('fetching video details', { count: videoIds.length });\n\n const response = yield* YouTube.getVideoDetails(videoIds);\n return response.items;\n }),\n { concurrency: 1 },\n ),\n Stream.flatMap((items) => Stream.fromIterable(items)),\n Stream.flatMap(\n (item) =>\n Effect.gen(function* () {\n let transcript: TranscriptData | undefined;\n\n if (includeTranscripts) {\n log('fetching transcript', { videoId: item.id });\n const result = yield* fetchTranscript(item.id);\n if (result) {\n transcript = result;\n log('transcript fetched', { videoId: item.id, length: transcript.fullText.length });\n } else {\n log('no transcript available', { videoId: item.id });\n }\n }\n\n return mapVideoData(item, transcript, includeTranscripts);\n }),\n {\n concurrency: STREAMING_CONFIG.transcriptFetchConcurrency,\n bufferSize: STREAMING_CONFIG.bufferSize,\n },\n ),\n Stream.filter(Predicate.isNotNullable),\n Stream.grouped(STREAMING_CONFIG.feedBatchSize),\n Stream.mapEffect((batch) =>\n Effect.gen(function* () {\n const videos = Chunk.toArray(batch);\n log('appending batch to feed', { count: videos.length });\n const videoObjects = videos.map((video) => Obj.make(Video.YouTubeVideo, video));\n yield* Feed.append(feed, videoObjects);\n return videos.length;\n }),\n ),\n Stream.runFold(0, (acc, batchCount) => acc + batchCount),\n );\n\n return count;\n});\n\nexport default handler;\n", "//\n// Copyright 2024 DXOS.org\n//\n\nimport * as Effect from 'effect/Effect';\n\nimport { log } from '@dxos/log';\n\nimport type { TranscriptSegment } from '../types/Video';\n\nexport type TranscriptResult = {\n segments: TranscriptSegment[];\n fullText: string;\n};\n\n/**\n * Fetches captions for a YouTube video using youtube-caption-extractor.\n * Works in both browser and Node/edge environments.\n */\nexport const fetchTranscript = (videoId: string, lang?: string): Effect.Effect<TranscriptResult | undefined> =>\n Effect.tryPromise({\n try: async () => {\n const { getSubtitles } = await import('youtube-caption-extractor');\n const subtitles = await getSubtitles({ videoID: videoId, lang: lang ?? 'en' });\n\n if (!subtitles || subtitles.length === 0) {\n return undefined;\n }\n\n const segments: TranscriptSegment[] = subtitles.map((sub) => ({\n text: sub.text,\n offset: parseFloat(sub.start),\n duration: parseFloat(sub.dur),\n }));\n\n const fullText = segments.map((segment) => segment.text).join(' ');\n return { segments, fullText };\n },\n catch: (error) => {\n log('failed to fetch transcript', { videoId, error });\n return undefined;\n },\n }).pipe(\n Effect.catchAll(() => Effect.succeed(undefined)),\n Effect.timeout('30 seconds'),\n Effect.catchAll(() => Effect.succeed(undefined)),\n );\n"],
5
+ "mappings": "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",
6
+ "names": ["FetchHttpClient", "Chunk", "Effect", "Function", "Layer", "Option", "Predicate", "Stream", "Database", "Feed", "Filter", "Obj", "log", "Operation", "Effect", "log", "fetchTranscript", "videoId", "lang", "tryPromise", "try", "getSubtitles", "subtitles", "videoID", "length", "undefined", "segments", "map", "sub", "text", "offset", "parseFloat", "start", "duration", "dur", "fullText", "segment", "join", "catch", "error", "pipe", "catchAll", "succeed", "timeout", "handler", "Sync", "pipe", "Operation", "withHandler", "channel", "channelRef", "restrictedMode", "includeTranscripts", "gen", "log", "dxn", "toString", "Database", "load", "channelUrl", "channelId", "fail", "Error", "channelInfo", "extractChannelInfo", "channelTitle", "uploadsPlaylistId", "getUploadsPlaylistId", "Obj", "change", "channelObj", "name", "feed", "existingVideos", "Feed", "runQuery", "Filter", "type", "Video", "YouTubeVideo", "existingVideoIds", "Set", "map", "video", "videoId", "count", "size", "newVideosCount", "streamVideosToFeed", "lastSyncedAt", "Date", "toISOString", "newVideos", "provide", "mergeAll", "layer", "GoogleCredentials", "fromChannelRef", "STREAMING_CONFIG", "maxResults", "transcriptFetchConcurrency", "bufferSize", "feedBatchSize", "restrictedMax", "urlOrHandle", "trimmed", "trim", "startsWith", "value", "slice", "length", "url", "URL", "pathname", "split", "test", "fn", "channelResponse", "YouTube", "getChannel", "getChannelByHandle", "items", "contentDetails", "relatedPlaylists", "uploads", "id", "snippet", "title", "fetchPlaylistVideos", "maxVideos", "videoCount", "unfoldChunkEffect", "pageToken", "none", "done", "state", "response", "listPlaylistItems", "getOrUndefined", "videoIds", "item", "resourceId", "filter", "Boolean", "hasMore", "nextPageToken", "nextState", "fromNullable", "undefined", "some", "fromIterable", "mapVideoData", "transcript", "hasTranscript", "fullText", "description", "thumbnailUrl", "thumbnails", "high", "medium", "default", "publishedAt", "duration", "viewCount", "statistics", "parseInt", "likeCount", "transcriptSegments", "segments", "transcriptFetched", "restricted", "isDuplicate", "has", "take", "identity", "grouped", "flatMap", "videoIdChunk", "toArray", "getVideoDetails", "concurrency", "result", "fetchTranscript", "isNotNullable", "mapEffect", "batch", "videos", "videoObjects", "make", "append", "runFold", "acc", "batchCount"]
7
+ }
@@ -5,10 +5,10 @@ import {
5
5
  } from "./chunk-YOE54ALJ.mjs";
6
6
 
7
7
  // src/operations/definitions.ts
8
- import { Operation } from "@dxos/operation";
9
8
  import * as Schema from "effect/Schema";
10
9
  import { Database, Feed, Ref } from "@dxos/echo";
11
10
  import { CredentialsService } from "@dxos/functions";
11
+ import { Operation } from "@dxos/operation";
12
12
  var Sync = Operation.make({
13
13
  meta: {
14
14
  key: "dxos.org/function/youtube/sync",
@@ -36,7 +36,7 @@ var Sync = Operation.make({
36
36
  ],
37
37
  services: [
38
38
  Database.Service,
39
- Feed.Service,
39
+ Feed.FeedService,
40
40
  CredentialsService
41
41
  ]
42
42
  });
@@ -60,7 +60,7 @@ var ClearSyncedVideos = Operation.make({
60
60
  ],
61
61
  services: [
62
62
  Database.Service,
63
- Feed.Service
63
+ Feed.FeedService
64
64
  ]
65
65
  });
66
66
 
@@ -68,4 +68,4 @@ export {
68
68
  Sync,
69
69
  ClearSyncedVideos
70
70
  };
71
- //# sourceMappingURL=chunk-RL46XZ2D.mjs.map
71
+ //# sourceMappingURL=chunk-A3SKNJFU.mjs.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/operations/definitions.ts"],
4
- "sourcesContent": ["//\n// Copyright 2024 DXOS.org\n//\n\nimport { Operation } from '@dxos/operation';\nimport * as Schema from 'effect/Schema';\n\nimport { Database, Feed, Ref } from '@dxos/echo';\nimport { CredentialsService } from '@dxos/functions';\n\nimport { Channel, Video } from '../types';\n\nexport const Sync = Operation.make({\n meta: {\n key: 'dxos.org/function/youtube/sync',\n name: 'Sync YouTube Channel',\n description: 'Sync videos from a YouTube channel to the feed.',\n },\n input: Schema.Struct({\n channel: Ref.Ref(Channel.YouTubeChannel).annotations({\n description: 'Reference to the YouTube channel to sync videos from.',\n }),\n restrictedMode: Schema.Boolean.pipe(\n Schema.annotations({\n description:\n 'Use restricted mode to limit to max 20 videos. Reduces API calls. Useful for testing or quick syncs.',\n }),\n Schema.optional,\n ),\n includeTranscripts: Schema.Boolean.pipe(\n Schema.annotations({\n description:\n 'Whether to fetch transcripts: Data API when your account can manage the video, otherwise watch-page captions (browser uses a public CORS proxy for YouTube fetches).',\n }),\n Schema.optional,\n ),\n }),\n output: Schema.Struct({\n newVideos: Schema.Number,\n channelTitle: Schema.String.pipe(Schema.optional),\n }),\n types: [Channel.YouTubeChannel, Video.YouTubeVideo],\n services: [Database.Service, Feed.Service, CredentialsService],\n});\n\nexport const ClearSyncedVideos = Operation.make({\n meta: {\n key: 'dxos.org/function/youtube/clear-synced-videos',\n name: 'Clear Synced YouTube Videos',\n description: 'Remove all synced videos from the channel by replacing its feed with a new empty feed.',\n },\n input: Schema.Struct({\n channel: Ref.Ref(Channel.YouTubeChannel).annotations({\n description: 'Reference to the YouTube channel whose synced videos should be cleared.',\n }),\n }),\n output: Schema.Struct({\n removedVideos: Schema.Number,\n }),\n types: [Channel.YouTubeChannel, Video.YouTubeVideo],\n services: [Database.Service, Feed.Service],\n});\n"],
5
- "mappings": ";;;;;;;AAIA,SAASA,iBAAiB;AAC1B,YAAYC,YAAY;AAExB,SAASC,UAAUC,MAAMC,WAAW;AACpC,SAASC,0BAA0B;AAI5B,IAAMC,OAAOC,UAAUC,KAAK;EACjCC,MAAM;IACJC,KAAK;IACLC,MAAM;IACNC,aAAa;EACf;EACAC,OAAcC,cAAO;IACnBC,SAASC,IAAIA,IAAIC,gBAAQC,cAAc,EAAEC,YAAY;MACnDP,aAAa;IACf,CAAA;IACAQ,gBAAuBC,eAAQC,KACtBH,mBAAY;MACjBP,aACE;IACJ,CAAA,GACOW,eAAQ;IAEjBC,oBAA2BH,eAAQC,KAC1BH,mBAAY;MACjBP,aACE;IACJ,CAAA,GACOW,eAAQ;EAEnB,CAAA;EACAE,QAAeX,cAAO;IACpBY,WAAkBC;IAClBC,cAAqBC,cAAOP,KAAYC,eAAQ;EAClD,CAAA;EACAO,OAAO;IAACb,gBAAQC;IAAgBa,cAAMC;;EACtCC,UAAU;IAACC,SAASC;IAASC,KAAKD;IAASE;;AAC7C,CAAA;AAEO,IAAMC,oBAAoB/B,UAAUC,KAAK;EAC9CC,MAAM;IACJC,KAAK;IACLC,MAAM;IACNC,aAAa;EACf;EACAC,OAAcC,cAAO;IACnBC,SAASC,IAAIA,IAAIC,gBAAQC,cAAc,EAAEC,YAAY;MACnDP,aAAa;IACf,CAAA;EACF,CAAA;EACAa,QAAeX,cAAO;IACpByB,eAAsBZ;EACxB,CAAA;EACAG,OAAO;IAACb,gBAAQC;IAAgBa,cAAMC;;EACtCC,UAAU;IAACC,SAASC;IAASC,KAAKD;;AACpC,CAAA;",
6
- "names": ["Operation", "Schema", "Database", "Feed", "Ref", "CredentialsService", "Sync", "Operation", "make", "meta", "key", "name", "description", "input", "Struct", "channel", "Ref", "Channel", "YouTubeChannel", "annotations", "restrictedMode", "Boolean", "pipe", "optional", "includeTranscripts", "output", "newVideos", "Number", "channelTitle", "String", "types", "Video", "YouTubeVideo", "services", "Database", "Service", "Feed", "CredentialsService", "ClearSyncedVideos", "removedVideos"]
4
+ "sourcesContent": ["//\n// Copyright 2024 DXOS.org\n//\n\nimport * as Schema from 'effect/Schema';\n\nimport { Database, Feed, Ref } from '@dxos/echo';\nimport { CredentialsService } from '@dxos/functions';\nimport { Operation } from '@dxos/operation';\n\nimport { Channel, Video } from '../types';\n\nexport const Sync = Operation.make({\n meta: {\n key: 'dxos.org/function/youtube/sync',\n name: 'Sync YouTube Channel',\n description: 'Sync videos from a YouTube channel to the feed.',\n },\n input: Schema.Struct({\n channel: Ref.Ref(Channel.YouTubeChannel).annotations({\n description: 'Reference to the YouTube channel to sync videos from.',\n }),\n restrictedMode: Schema.Boolean.pipe(\n Schema.annotations({\n description:\n 'Use restricted mode to limit to max 20 videos. Reduces API calls. Useful for testing or quick syncs.',\n }),\n Schema.optional,\n ),\n includeTranscripts: Schema.Boolean.pipe(\n Schema.annotations({\n description:\n 'Whether to fetch transcripts: Data API when your account can manage the video, otherwise watch-page captions (browser uses a public CORS proxy for YouTube fetches).',\n }),\n Schema.optional,\n ),\n }),\n output: Schema.Struct({\n newVideos: Schema.Number,\n channelTitle: Schema.String.pipe(Schema.optional),\n }),\n types: [Channel.YouTubeChannel, Video.YouTubeVideo],\n services: [Database.Service, Feed.FeedService, CredentialsService],\n});\n\nexport const ClearSyncedVideos = Operation.make({\n meta: {\n key: 'dxos.org/function/youtube/clear-synced-videos',\n name: 'Clear Synced YouTube Videos',\n description: 'Remove all synced videos from the channel by replacing its feed with a new empty feed.',\n },\n input: Schema.Struct({\n channel: Ref.Ref(Channel.YouTubeChannel).annotations({\n description: 'Reference to the YouTube channel whose synced videos should be cleared.',\n }),\n }),\n output: Schema.Struct({\n removedVideos: Schema.Number,\n }),\n types: [Channel.YouTubeChannel, Video.YouTubeVideo],\n services: [Database.Service, Feed.FeedService],\n});\n"],
5
+ "mappings": ";;;;;;;AAIA,YAAYA,YAAY;AAExB,SAASC,UAAUC,MAAMC,WAAW;AACpC,SAASC,0BAA0B;AACnC,SAASC,iBAAiB;AAInB,IAAMC,OAAOC,UAAUC,KAAK;EACjCC,MAAM;IACJC,KAAK;IACLC,MAAM;IACNC,aAAa;EACf;EACAC,OAAcC,cAAO;IACnBC,SAASC,IAAIA,IAAIC,gBAAQC,cAAc,EAAEC,YAAY;MACnDP,aAAa;IACf,CAAA;IACAQ,gBAAuBC,eAAQC,KACtBH,mBAAY;MACjBP,aACE;IACJ,CAAA,GACOW,eAAQ;IAEjBC,oBAA2BH,eAAQC,KAC1BH,mBAAY;MACjBP,aACE;IACJ,CAAA,GACOW,eAAQ;EAEnB,CAAA;EACAE,QAAeX,cAAO;IACpBY,WAAkBC;IAClBC,cAAqBC,cAAOP,KAAYC,eAAQ;EAClD,CAAA;EACAO,OAAO;IAACb,gBAAQC;IAAgBa,cAAMC;;EACtCC,UAAU;IAACC,SAASC;IAASC,KAAKC;IAAaC;;AACjD,CAAA;AAEO,IAAMC,oBAAoBhC,UAAUC,KAAK;EAC9CC,MAAM;IACJC,KAAK;IACLC,MAAM;IACNC,aAAa;EACf;EACAC,OAAcC,cAAO;IACnBC,SAASC,IAAIA,IAAIC,gBAAQC,cAAc,EAAEC,YAAY;MACnDP,aAAa;IACf,CAAA;EACF,CAAA;EACAa,QAAeX,cAAO;IACpB0B,eAAsBb;EACxB,CAAA;EACAG,OAAO;IAACb,gBAAQC;IAAgBa,cAAMC;;EACtCC,UAAU;IAACC,SAASC;IAASC,KAAKC;;AACpC,CAAA;",
6
+ "names": ["Schema", "Database", "Feed", "Ref", "CredentialsService", "Operation", "Sync", "Operation", "make", "meta", "key", "name", "description", "input", "Struct", "channel", "Ref", "Channel", "YouTubeChannel", "annotations", "restrictedMode", "Boolean", "pipe", "optional", "includeTranscripts", "output", "newVideos", "Number", "channelTitle", "String", "types", "Video", "YouTubeVideo", "services", "Database", "Service", "Feed", "FeedService", "CredentialsService", "ClearSyncedVideos", "removedVideos"]
7
7
  }
@@ -287,7 +287,7 @@ var makeYouTubeApiRequest = Effect2.fn("makeYouTubeApiRequest")(function* (url)
287
287
  if (response.error) {
288
288
  log2.catch(response.error, void 0, {
289
289
  F: __dxlog_file2,
290
- L: 81,
290
+ L: 80,
291
291
  S: this,
292
292
  C: (f, a) => f(...a)
293
293
  });
@@ -353,4 +353,4 @@ export {
353
353
  GoogleCredentials,
354
354
  youtube_exports
355
355
  };
356
- //# sourceMappingURL=chunk-BVKMXV2G.mjs.map
356
+ //# sourceMappingURL=chunk-Q3TVMR5B.mjs.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/operations/services/google-credentials.ts", "../../../src/operations/apis/youtube/index.ts", "../../../src/operations/apis/youtube/api.ts", "../../../src/operations/apis/youtube/types.ts"],
4
- "sourcesContent": ["//\n// Copyright 2024 DXOS.org\n//\n\nimport * as Context from 'effect/Context';\nimport * as Effect from 'effect/Effect';\nimport * as Layer from 'effect/Layer';\n\nimport { Database, type Ref } from '@dxos/echo';\nimport { CredentialsService } from '@dxos/functions';\nimport { log } from '@dxos/log';\nimport { type AccessToken } from '@dxos/types';\n\nimport type * as Channel from '../../types/Channel';\n\n/**\n * Creates the service interface from a cached token.\n * Falls back to database credentials if no cached token is provided.\n */\nconst makeService = (cachedToken: string | undefined): Context.Tag.Service<GoogleCredentials> => ({\n get: () =>\n cachedToken\n ? Effect.succeed(cachedToken)\n : Effect.map(CredentialsService.getCredential({ service: 'google.com' }), (credential) => credential.apiKey!),\n});\n\n/**\n * Loads access token from a ref if available.\n */\nconst loadAccessToken = (accessTokenRef: Ref.Ref<AccessToken.AccessToken> | undefined, label: string) =>\n Effect.gen(function* () {\n if (accessTokenRef) {\n const accessToken = yield* Database.load(accessTokenRef);\n if (accessToken?.token) {\n log(`using ${label}-specific access token`, { note: accessToken.note });\n return accessToken.token;\n }\n }\n return undefined;\n });\n\n/**\n * Service for accessing Google API credentials.\n * Provides the Google API token either from an object's access token or falls back to database credentials.\n */\n// TODO(dmaretskyi): Remove this service.\nexport class GoogleCredentials extends Context.Tag('GoogleCredentials')<\n GoogleCredentials,\n {\n /** Returns the Google API token. */\n get: () => Effect.Effect<string, never, CredentialsService>;\n }\n>() {\n /**\n * Creates a credentials layer from a channel.\n * Pre-loads the access token during layer construction.\n */\n static fromChannel = (channel: Channel.YouTubeChannel) =>\n Layer.effect(GoogleCredentials, Effect.map(loadAccessToken(channel.accessToken, 'channel'), makeService));\n\n /**\n * Creates a credentials layer from a channel ref.\n * Loads the channel and pre-loads the access token during layer construction.\n */\n static fromChannelRef = (channelRef: Ref.Ref<Channel.YouTubeChannel>) =>\n Layer.effect(\n GoogleCredentials,\n Effect.flatMap(Database.load(channelRef), (channel) =>\n Effect.map(loadAccessToken(channel.accessToken, 'channel'), makeService),\n ),\n );\n\n /**\n * Default layer that uses database credentials.\n * Use this for operations that don't have an associated channel.\n */\n static default = Layer.succeed(GoogleCredentials, makeService(undefined));\n\n /** Convenience accessor - returns the Google API token. */\n static get = () => Effect.flatMap(GoogleCredentials, (service) => service.get());\n}\n", "//\n// Copyright 2024 DXOS.org\n//\n\nexport * from './api';\nexport * from './types';\n", "//\n// Copyright 2024 DXOS.org\n//\n\nimport * as HttpClient from '@effect/platform/HttpClient';\nimport * as HttpClientRequest from '@effect/platform/HttpClientRequest';\nimport * as Effect from 'effect/Effect';\nimport type * as ParseResult from 'effect/ParseResult';\nimport * as Schedule from 'effect/Schedule';\nimport * as Schema from 'effect/Schema';\n\nimport { withAuthorization } from '@dxos/functions';\nimport { log } from '@dxos/log';\n\nimport { GoogleCredentials } from '../../services/google-credentials';\n\nimport {\n ChannelsResponse,\n ErrorResponse,\n PlaylistItemsResponse,\n SearchResponse,\n VideosResponse,\n YouTubeError,\n} from './types';\n\nconst API_URL = 'https://www.googleapis.com/youtube/v3';\n\n/**\n * Creates a URL from path segments and query parameters.\n */\nconst createUrl = (parts: (string | undefined)[], params?: Record<string, unknown>): URL => {\n const url = new URL(parts.filter(Boolean).join('/'));\n if (params) {\n Object.entries(params)\n .filter(([_, value]) => value != null)\n .forEach(([key, value]) => url.searchParams.set(key, String(value)));\n }\n return url;\n};\n\n/**\n * Decode response and handle YouTube API errors.\n */\nconst decodeAndHandleErrors =\n <S extends Schema.Schema.Any>(schema: S) =>\n (\n data: unknown,\n ): Effect.Effect<Schema.Schema.Type<S>, YouTubeError | ParseResult.ParseError, Schema.Schema.Context<S>> =>\n Schema.decodeUnknown(Schema.Union(schema, ErrorResponse))(data).pipe(\n Effect.flatMap((response) => {\n if ('error' in response) {\n return Effect.fail(YouTubeError.fromErrorResponse(response));\n } else {\n return Effect.succeed(response);\n }\n }),\n );\n\n/**\n * Makes an authenticated HTTP request to a YouTube API endpoint.\n */\nconst makeYouTubeApiRequest = Effect.fn('makeYouTubeApiRequest')(function* (url: string) {\n const token = yield* GoogleCredentials.get();\n\n const httpClient = yield* HttpClient.HttpClient.pipe(Effect.map(withAuthorization(token, 'Bearer')));\n const httpClientWithTracerDisabled = httpClient.pipe(HttpClient.withTracerDisabledWhen(() => true));\n\n const request = HttpClientRequest.get(url);\n\n const response = yield* request.pipe(\n HttpClientRequest.setHeader('accept', 'application/json'),\n httpClientWithTracerDisabled.execute,\n Effect.flatMap((res) => res.json),\n Effect.timeout('10 seconds'),\n Effect.retry(Schedule.exponential(1_000).pipe(Schedule.compose(Schedule.recurs(3)))),\n Effect.scoped,\n Effect.withSpan('YouTubeApiRequest'),\n );\n\n if ((response as Record<string, unknown>).error) {\n log.catch((response as Record<string, unknown>).error);\n }\n\n return response;\n});\n\n/**\n * Get channel details by channel ID.\n * https://developers.google.com/youtube/v3/docs/channels/list\n */\nexport const getChannel = Effect.fn(function* (channelId: string) {\n const url = createUrl([API_URL, 'channels'], {\n part: 'snippet,contentDetails',\n id: channelId,\n }).toString();\n return yield* makeYouTubeApiRequest(url).pipe(Effect.flatMap(decodeAndHandleErrors(ChannelsResponse)));\n});\n\n/**\n * Get channel by username/handle.\n * https://developers.google.com/youtube/v3/docs/channels/list\n */\nexport const getChannelByHandle = Effect.fn(function* (handle: string) {\n const url = createUrl([API_URL, 'channels'], {\n part: 'snippet,contentDetails',\n forHandle: handle.startsWith('@') ? handle.slice(1) : handle,\n }).toString();\n return yield* makeYouTubeApiRequest(url).pipe(Effect.flatMap(decodeAndHandleErrors(ChannelsResponse)));\n});\n\n/**\n * Search for channels by query.\n * https://developers.google.com/youtube/v3/docs/search/list\n */\nexport const searchChannels = Effect.fn(function* (query: string, maxResults = 10) {\n const url = createUrl([API_URL, 'search'], {\n part: 'snippet',\n type: 'channel',\n q: query,\n maxResults,\n }).toString();\n return yield* makeYouTubeApiRequest(url).pipe(Effect.flatMap(decodeAndHandleErrors(SearchResponse)));\n});\n\n/**\n * List videos from a playlist (used to get uploads from a channel's uploads playlist).\n * https://developers.google.com/youtube/v3/docs/playlistItems/list\n */\nexport const listPlaylistItems = Effect.fn(function* (playlistId: string, maxResults = 50, pageToken?: string) {\n const url = createUrl([API_URL, 'playlistItems'], {\n part: 'snippet,contentDetails',\n playlistId,\n maxResults,\n pageToken,\n }).toString();\n return yield* makeYouTubeApiRequest(url).pipe(Effect.flatMap(decodeAndHandleErrors(PlaylistItemsResponse)));\n});\n\n/**\n * Get detailed video information including statistics and duration.\n * https://developers.google.com/youtube/v3/docs/videos/list\n */\nexport const getVideoDetails = Effect.fn(function* (videoIds: string[]) {\n const url = createUrl([API_URL, 'videos'], {\n part: 'snippet,contentDetails,statistics',\n id: videoIds.join(','),\n }).toString();\n return yield* makeYouTubeApiRequest(url).pipe(Effect.flatMap(decodeAndHandleErrors(VideosResponse)));\n});\n", "//\n// Copyright 2024 DXOS.org\n//\n\nimport * as Schema from 'effect/Schema';\n\n/**\n * YouTube API error response.\n */\nexport class YouTubeError extends Schema.TaggedError<YouTubeError>()('YouTubeError', {\n code: Schema.Number,\n message: Schema.String,\n status: Schema.optional(Schema.String),\n}) {\n static fromErrorResponse(response: ErrorResponse) {\n return new YouTubeError({\n code: response.error.code,\n message: response.error.message,\n status: response.error.status,\n });\n }\n}\n\nexport const ErrorResponse = Schema.Struct({\n error: Schema.Struct({\n code: Schema.Number,\n message: Schema.String,\n status: Schema.optional(Schema.String),\n }),\n});\n\nexport type ErrorResponse = Schema.Schema.Type<typeof ErrorResponse>;\n\n/**\n * YouTube channel snippet from search/channel API.\n */\nexport const ChannelSnippet = Schema.Struct({\n title: Schema.String,\n description: Schema.optional(Schema.String),\n customUrl: Schema.optional(Schema.String),\n publishedAt: Schema.optional(Schema.String),\n thumbnails: Schema.optional(\n Schema.Struct({\n default: Schema.optional(Schema.Struct({ url: Schema.String })),\n medium: Schema.optional(Schema.Struct({ url: Schema.String })),\n high: Schema.optional(Schema.Struct({ url: Schema.String })),\n }),\n ),\n});\n\n/**\n * YouTube channel item from channels API.\n */\nexport const ChannelItem = Schema.Struct({\n kind: Schema.String,\n etag: Schema.String,\n id: Schema.String,\n snippet: Schema.optional(ChannelSnippet),\n contentDetails: Schema.optional(\n Schema.Struct({\n relatedPlaylists: Schema.optional(\n Schema.Struct({\n uploads: Schema.optional(Schema.String),\n }),\n ),\n }),\n ),\n});\n\n/**\n * YouTube channels list response.\n */\nexport const ChannelsResponse = Schema.Struct({\n kind: Schema.String,\n etag: Schema.String,\n pageInfo: Schema.optional(\n Schema.Struct({\n totalResults: Schema.Number,\n resultsPerPage: Schema.Number,\n }),\n ),\n items: Schema.Array(ChannelItem),\n});\n\nexport type ChannelsResponse = Schema.Schema.Type<typeof ChannelsResponse>;\n\n/**\n * Video snippet from search/playlistItems API.\n */\nexport const VideoSnippet = Schema.Struct({\n publishedAt: Schema.String,\n channelId: Schema.optional(Schema.String),\n title: Schema.String,\n description: Schema.optional(Schema.String),\n thumbnails: Schema.optional(\n Schema.Struct({\n default: Schema.optional(Schema.Struct({ url: Schema.String })),\n medium: Schema.optional(Schema.Struct({ url: Schema.String })),\n high: Schema.optional(Schema.Struct({ url: Schema.String })),\n standard: Schema.optional(Schema.Struct({ url: Schema.String })),\n maxres: Schema.optional(Schema.Struct({ url: Schema.String })),\n }),\n ),\n channelTitle: Schema.optional(Schema.String),\n playlistId: Schema.optional(Schema.String),\n position: Schema.optional(Schema.Number),\n resourceId: Schema.optional(\n Schema.Struct({\n kind: Schema.String,\n videoId: Schema.String,\n }),\n ),\n});\n\n/**\n * Content details for a video.\n */\nexport const VideoContentDetails = Schema.Struct({\n videoId: Schema.optional(Schema.String),\n videoPublishedAt: Schema.optional(Schema.String),\n duration: Schema.optional(Schema.String),\n});\n\n/**\n * Video statistics.\n */\nexport const VideoStatistics = Schema.Struct({\n viewCount: Schema.optional(Schema.String),\n likeCount: Schema.optional(Schema.String),\n commentCount: Schema.optional(Schema.String),\n});\n\n/**\n * Video item from videos API.\n */\nexport const VideoItem = Schema.Struct({\n kind: Schema.String,\n etag: Schema.String,\n id: Schema.String,\n snippet: Schema.optional(VideoSnippet),\n contentDetails: Schema.optional(VideoContentDetails),\n statistics: Schema.optional(VideoStatistics),\n});\n\nexport type VideoItem = Schema.Schema.Type<typeof VideoItem>;\n\n/**\n * YouTube videos list response.\n */\nexport const VideosResponse = Schema.Struct({\n kind: Schema.String,\n etag: Schema.String,\n nextPageToken: Schema.optional(Schema.String),\n prevPageToken: Schema.optional(Schema.String),\n pageInfo: Schema.optional(\n Schema.Struct({\n totalResults: Schema.Number,\n resultsPerPage: Schema.Number,\n }),\n ),\n items: Schema.Array(VideoItem),\n});\n\nexport type VideosResponse = Schema.Schema.Type<typeof VideosResponse>;\n\n/**\n * Playlist item from playlistItems API.\n */\nexport const PlaylistItem = Schema.Struct({\n kind: Schema.String,\n etag: Schema.String,\n id: Schema.String,\n snippet: Schema.optional(VideoSnippet),\n contentDetails: Schema.optional(VideoContentDetails),\n});\n\n/**\n * YouTube playlist items response.\n */\nexport const PlaylistItemsResponse = Schema.Struct({\n kind: Schema.String,\n etag: Schema.String,\n nextPageToken: Schema.optional(Schema.String),\n prevPageToken: Schema.optional(Schema.String),\n pageInfo: Schema.optional(\n Schema.Struct({\n totalResults: Schema.Number,\n resultsPerPage: Schema.Number,\n }),\n ),\n items: Schema.Array(PlaylistItem),\n});\n\nexport type PlaylistItemsResponse = Schema.Schema.Type<typeof PlaylistItemsResponse>;\n\n/**\n * Search result item.\n */\nexport const SearchItem = Schema.Struct({\n kind: Schema.String,\n etag: Schema.String,\n id: Schema.Struct({\n kind: Schema.String,\n videoId: Schema.optional(Schema.String),\n channelId: Schema.optional(Schema.String),\n playlistId: Schema.optional(Schema.String),\n }),\n snippet: Schema.optional(VideoSnippet),\n});\n\n/**\n * YouTube search response.\n */\nexport const SearchResponse = Schema.Struct({\n kind: Schema.String,\n etag: Schema.String,\n nextPageToken: Schema.optional(Schema.String),\n prevPageToken: Schema.optional(Schema.String),\n pageInfo: Schema.optional(\n Schema.Struct({\n totalResults: Schema.Number,\n resultsPerPage: Schema.Number,\n }),\n ),\n items: Schema.Array(SearchItem),\n});\n\nexport type SearchResponse = Schema.Schema.Type<typeof SearchResponse>;\n\n/**\n * Caption track from captions.list.\n */\nexport const CaptionResource = Schema.Struct({\n id: Schema.String,\n snippet: Schema.optional(\n Schema.Struct({\n videoId: Schema.optional(Schema.String),\n language: Schema.optional(Schema.String),\n name: Schema.optional(Schema.String),\n trackKind: Schema.optional(Schema.String),\n }),\n ),\n});\n\n/**\n * YouTube captions.list response.\n */\nexport const CaptionsListResponse = Schema.Struct({\n kind: Schema.String,\n etag: Schema.String,\n items: Schema.optional(Schema.Array(CaptionResource)),\n});\n\nexport type CaptionsListResponse = Schema.Schema.Type<typeof CaptionsListResponse>;\n"],
5
- "mappings": ";;;;;;AAIA,YAAYA,aAAa;AACzB,YAAYC,YAAY;AACxB,YAAYC,WAAW;AAEvB,SAASC,gBAA0B;AACnC,SAASC,0BAA0B;AACnC,SAASC,WAAW;;AASpB,IAAMC,cAAc,CAACC,iBAA6E;EAChGC,KAAK,MACHD,cACWE,eAAQF,WAAAA,IACRG,WAAIN,mBAAmBO,cAAc;IAAEC,SAAS;EAAa,CAAA,GAAI,CAACC,eAAeA,WAAWC,MAAM;AACjH;AAKA,IAAMC,kBAAkB,CAACC,gBAA8DC,UAC9EC,WAAI,aAAA;AACT,MAAIF,gBAAgB;AAClB,UAAMG,cAAc,OAAOhB,SAASiB,KAAKJ,cAAAA;AACzC,QAAIG,aAAaE,OAAO;AACtBhB,UAAI,SAASY,KAAAA,0BAA+B;QAAEK,MAAMH,YAAYG;MAAK,GAAA;;;;;;AACrE,aAAOH,YAAYE;IACrB;EACF;AACA,SAAOE;AACT,CAAA;AAOK,IAAMC,oBAAN,MAAMA,2BAAkCC,YAAI,mBAAA,EAAA,EAAA;;;;;EAWjD,OAAOC,cAAc,CAACC,YACdC,aAAOJ,oBAA0Bd,WAAIK,gBAAgBY,QAAQR,aAAa,SAAA,GAAYb,WAAAA,CAAAA;;;;;EAM9F,OAAOuB,iBAAiB,CAACC,eACjBF,aACJJ,oBACOO,eAAQ5B,SAASiB,KAAKU,UAAAA,GAAa,CAACH,YAClCjB,WAAIK,gBAAgBY,QAAQR,aAAa,SAAA,GAAYb,WAAAA,CAAAA,CAAAA;;;;;EAQlE,OAAO0B,UAAgBvB,cAAQe,oBAAmBlB,YAAYiB,MAAAA,CAAAA;;EAG9D,OAAOf,MAAM,MAAauB,eAAQP,oBAAmB,CAACZ,YAAYA,QAAQJ,IAAG,CAAA;AAC/E;;;AChFA;;;;;;;;;;;;;;;;;;;;;;;;;;ACIA,YAAYyB,gBAAgB;AAC5B,YAAYC,uBAAuB;AACnC,YAAYC,aAAY;AAExB,YAAYC,cAAc;AAC1B,YAAYC,aAAY;AAExB,SAASC,yBAAyB;AAClC,SAASC,OAAAA,YAAW;;;ACRpB,YAAYC,YAAY;AAKjB,IAAMC,eAAN,MAAMA,sBAA4BC,mBAAW,EAAiB,gBAAgB;EACnFC,MAAaC;EACbC,SAAgBC;EAChBC,QAAeC,gBAAgBF,aAAM;AACvC,CAAA,EAAA;EACE,OAAOG,kBAAkBC,UAAyB;AAChD,WAAO,IAAIT,cAAa;MACtBE,MAAMO,SAASC,MAAMR;MACrBE,SAASK,SAASC,MAAMN;MACxBE,QAAQG,SAASC,MAAMJ;IACzB,CAAA;EACF;AACF;AAEO,IAAMK,gBAAuBC,cAAO;EACzCF,OAAcE,cAAO;IACnBV,MAAaC;IACbC,SAAgBC;IAChBC,QAAeC,gBAAgBF,aAAM;EACvC,CAAA;AACF,CAAA;AAOO,IAAMQ,iBAAwBD,cAAO;EAC1CE,OAAcT;EACdU,aAAoBR,gBAAgBF,aAAM;EAC1CW,WAAkBT,gBAAgBF,aAAM;EACxCY,aAAoBV,gBAAgBF,aAAM;EAC1Ca,YAAmBX,gBACVK,cAAO;IACZO,SAAgBZ,gBAAgBK,cAAO;MAAEQ,KAAYf;IAAO,CAAA,CAAA;IAC5DgB,QAAed,gBAAgBK,cAAO;MAAEQ,KAAYf;IAAO,CAAA,CAAA;IAC3DiB,MAAaf,gBAAgBK,cAAO;MAAEQ,KAAYf;IAAO,CAAA,CAAA;EAC3D,CAAA,CAAA;AAEJ,CAAA;AAKO,IAAMkB,cAAqBX,cAAO;EACvCY,MAAanB;EACboB,MAAapB;EACbqB,IAAWrB;EACXsB,SAAgBpB,gBAASM,cAAAA;EACzBe,gBAAuBrB,gBACdK,cAAO;IACZiB,kBAAyBtB,gBAChBK,cAAO;MACZkB,SAAgBvB,gBAAgBF,aAAM;IACxC,CAAA,CAAA;EAEJ,CAAA,CAAA;AAEJ,CAAA;AAKO,IAAM0B,mBAA0BnB,cAAO;EAC5CY,MAAanB;EACboB,MAAapB;EACb2B,UAAiBzB,gBACRK,cAAO;IACZqB,cAAqB9B;IACrB+B,gBAAuB/B;EACzB,CAAA,CAAA;EAEFgC,OAAcC,aAAMb,WAAAA;AACtB,CAAA;AAOO,IAAMc,eAAsBzB,cAAO;EACxCK,aAAoBZ;EACpBiC,WAAkB/B,gBAAgBF,aAAM;EACxCS,OAAcT;EACdU,aAAoBR,gBAAgBF,aAAM;EAC1Ca,YAAmBX,gBACVK,cAAO;IACZO,SAAgBZ,gBAAgBK,cAAO;MAAEQ,KAAYf;IAAO,CAAA,CAAA;IAC5DgB,QAAed,gBAAgBK,cAAO;MAAEQ,KAAYf;IAAO,CAAA,CAAA;IAC3DiB,MAAaf,gBAAgBK,cAAO;MAAEQ,KAAYf;IAAO,CAAA,CAAA;IACzDkC,UAAiBhC,gBAAgBK,cAAO;MAAEQ,KAAYf;IAAO,CAAA,CAAA;IAC7DmC,QAAejC,gBAAgBK,cAAO;MAAEQ,KAAYf;IAAO,CAAA,CAAA;EAC7D,CAAA,CAAA;EAEFoC,cAAqBlC,gBAAgBF,aAAM;EAC3CqC,YAAmBnC,gBAAgBF,aAAM;EACzCsC,UAAiBpC,gBAAgBJ,aAAM;EACvCyC,YAAmBrC,gBACVK,cAAO;IACZY,MAAanB;IACbwC,SAAgBxC;EAClB,CAAA,CAAA;AAEJ,CAAA;AAKO,IAAMyC,sBAA6BlC,cAAO;EAC/CiC,SAAgBtC,gBAAgBF,aAAM;EACtC0C,kBAAyBxC,gBAAgBF,aAAM;EAC/C2C,UAAiBzC,gBAAgBF,aAAM;AACzC,CAAA;AAKO,IAAM4C,kBAAyBrC,cAAO;EAC3CsC,WAAkB3C,gBAAgBF,aAAM;EACxC8C,WAAkB5C,gBAAgBF,aAAM;EACxC+C,cAAqB7C,gBAAgBF,aAAM;AAC7C,CAAA;AAKO,IAAMgD,YAAmBzC,cAAO;EACrCY,MAAanB;EACboB,MAAapB;EACbqB,IAAWrB;EACXsB,SAAgBpB,gBAAS8B,YAAAA;EACzBT,gBAAuBrB,gBAASuC,mBAAAA;EAChCQ,YAAmB/C,gBAAS0C,eAAAA;AAC9B,CAAA;AAOO,IAAMM,iBAAwB3C,cAAO;EAC1CY,MAAanB;EACboB,MAAapB;EACbmD,eAAsBjD,gBAAgBF,aAAM;EAC5CoD,eAAsBlD,gBAAgBF,aAAM;EAC5C2B,UAAiBzB,gBACRK,cAAO;IACZqB,cAAqB9B;IACrB+B,gBAAuB/B;EACzB,CAAA,CAAA;EAEFgC,OAAcC,aAAMiB,SAAAA;AACtB,CAAA;AAOO,IAAMK,eAAsB9C,cAAO;EACxCY,MAAanB;EACboB,MAAapB;EACbqB,IAAWrB;EACXsB,SAAgBpB,gBAAS8B,YAAAA;EACzBT,gBAAuBrB,gBAASuC,mBAAAA;AAClC,CAAA;AAKO,IAAMa,wBAA+B/C,cAAO;EACjDY,MAAanB;EACboB,MAAapB;EACbmD,eAAsBjD,gBAAgBF,aAAM;EAC5CoD,eAAsBlD,gBAAgBF,aAAM;EAC5C2B,UAAiBzB,gBACRK,cAAO;IACZqB,cAAqB9B;IACrB+B,gBAAuB/B;EACzB,CAAA,CAAA;EAEFgC,OAAcC,aAAMsB,YAAAA;AACtB,CAAA;AAOO,IAAME,aAAoBhD,cAAO;EACtCY,MAAanB;EACboB,MAAapB;EACbqB,IAAWd,cAAO;IAChBY,MAAanB;IACbwC,SAAgBtC,gBAAgBF,aAAM;IACtCiC,WAAkB/B,gBAAgBF,aAAM;IACxCqC,YAAmBnC,gBAAgBF,aAAM;EAC3C,CAAA;EACAsB,SAAgBpB,gBAAS8B,YAAAA;AAC3B,CAAA;AAKO,IAAMwB,iBAAwBjD,cAAO;EAC1CY,MAAanB;EACboB,MAAapB;EACbmD,eAAsBjD,gBAAgBF,aAAM;EAC5CoD,eAAsBlD,gBAAgBF,aAAM;EAC5C2B,UAAiBzB,gBACRK,cAAO;IACZqB,cAAqB9B;IACrB+B,gBAAuB/B;EACzB,CAAA,CAAA;EAEFgC,OAAcC,aAAMwB,UAAAA;AACtB,CAAA;AAOO,IAAME,kBAAyBlD,cAAO;EAC3Cc,IAAWrB;EACXsB,SAAgBpB,gBACPK,cAAO;IACZiC,SAAgBtC,gBAAgBF,aAAM;IACtC0D,UAAiBxD,gBAAgBF,aAAM;IACvC2D,MAAazD,gBAAgBF,aAAM;IACnC4D,WAAkB1D,gBAAgBF,aAAM;EAC1C,CAAA,CAAA;AAEJ,CAAA;AAKO,IAAM6D,uBAA8BtD,cAAO;EAChDY,MAAanB;EACboB,MAAapB;EACb8B,OAAc5B,gBAAgB6B,aAAM0B,eAAAA,CAAAA;AACtC,CAAA;;;;ADlOA,IAAMK,UAAU;AAKhB,IAAMC,YAAY,CAACC,OAA+BC,WAAAA;AAChD,QAAMC,MAAM,IAAIC,IAAIH,MAAMI,OAAOC,OAAAA,EAASC,KAAK,GAAA,CAAA;AAC/C,MAAIL,QAAQ;AACVM,WAAOC,QAAQP,MAAAA,EACZG,OAAO,CAAC,CAACK,GAAGC,KAAAA,MAAWA,SAAS,IAAA,EAChCC,QAAQ,CAAC,CAACC,KAAKF,KAAAA,MAAWR,IAAIW,aAAaC,IAAIF,KAAKG,OAAOL,KAAAA,CAAAA,CAAAA;EAChE;AACA,SAAOR;AACT;AAKA,IAAMc,wBACJ,CAA8BC,WAC9B,CACEC,SAEOC,sBAAqBC,cAAMH,QAAQI,aAAAA,CAAAA,EAAgBH,IAAAA,EAAMI,KACvDC,gBAAQ,CAACC,aAAAA;AACd,MAAI,WAAWA,UAAU;AACvB,WAAcC,aAAKC,aAAaC,kBAAkBH,QAAAA,CAAAA;EACpD,OAAO;AACL,WAAcI,gBAAQJ,QAAAA;EACxB;AACF,CAAA,CAAA;AAMN,IAAMK,wBAA+BC,WAAG,uBAAA,EAAyB,WAAW5B,KAAW;AACrF,QAAM6B,QAAQ,OAAOC,kBAAkBC,IAAG;AAE1C,QAAMC,aAAa,OAAkBC,sBAAWb,KAAYc,YAAIC,kBAAkBN,OAAO,QAAA,CAAA,CAAA;AACzF,QAAMO,+BAA+BJ,WAAWZ,KAAgBiB,kCAAuB,MAAM,IAAA,CAAA;AAE7F,QAAMC,UAA4BP,sBAAI/B,GAAAA;AAEtC,QAAMsB,WAAW,OAAOgB,QAAQlB,KACZmB,4BAAU,UAAU,kBAAA,GACtCH,6BAA6BI,SACtBnB,gBAAQ,CAACoB,QAAQA,IAAIC,IAAI,GACzBC,gBAAQ,YAAA,GACRC,cAAeC,qBAAY,GAAA,EAAOzB,KAAc0B,iBAAiBC,gBAAO,CAAA,CAAA,CAAA,CAAA,GACxEC,gBACAC,iBAAS,mBAAA,CAAA;AAGlB,MAAK3B,SAAqC4B,OAAO;AAC/CC,IAAAA,KAAIC,MAAO9B,SAAqC4B,OAAK,QAAA;;;;;;EACvD;AAEA,SAAO5B;AACT,CAAA;AAMO,IAAM+B,aAAoBzB,WAAG,WAAW0B,WAAiB;AAC9D,QAAMtD,MAAMH,UAAU;IAACD;IAAS;KAAa;IAC3C2D,MAAM;IACNC,IAAIF;EACN,CAAA,EAAGG,SAAQ;AACX,SAAO,OAAO9B,sBAAsB3B,GAAAA,EAAKoB,KAAYC,gBAAQP,sBAAsB4C,gBAAAA,CAAAA,CAAAA;AACrF,CAAA;AAMO,IAAMC,qBAA4B/B,WAAG,WAAWgC,QAAc;AACnE,QAAM5D,MAAMH,UAAU;IAACD;IAAS;KAAa;IAC3C2D,MAAM;IACNM,WAAWD,OAAOE,WAAW,GAAA,IAAOF,OAAOG,MAAM,CAAA,IAAKH;EACxD,CAAA,EAAGH,SAAQ;AACX,SAAO,OAAO9B,sBAAsB3B,GAAAA,EAAKoB,KAAYC,gBAAQP,sBAAsB4C,gBAAAA,CAAAA,CAAAA;AACrF,CAAA;AAMO,IAAMM,iBAAwBpC,WAAG,WAAWqC,OAAeC,aAAa,IAAE;AAC/E,QAAMlE,MAAMH,UAAU;IAACD;IAAS;KAAW;IACzC2D,MAAM;IACNY,MAAM;IACNC,GAAGH;IACHC;EACF,CAAA,EAAGT,SAAQ;AACX,SAAO,OAAO9B,sBAAsB3B,GAAAA,EAAKoB,KAAYC,gBAAQP,sBAAsBuD,cAAAA,CAAAA,CAAAA;AACrF,CAAA;AAMO,IAAMC,oBAA2B1C,WAAG,WAAW2C,YAAoBL,aAAa,IAAIM,WAAkB;AAC3G,QAAMxE,MAAMH,UAAU;IAACD;IAAS;KAAkB;IAChD2D,MAAM;IACNgB;IACAL;IACAM;EACF,CAAA,EAAGf,SAAQ;AACX,SAAO,OAAO9B,sBAAsB3B,GAAAA,EAAKoB,KAAYC,gBAAQP,sBAAsB2D,qBAAAA,CAAAA,CAAAA;AACrF,CAAA;AAMO,IAAMC,kBAAyB9C,WAAG,WAAW+C,UAAkB;AACpE,QAAM3E,MAAMH,UAAU;IAACD;IAAS;KAAW;IACzC2D,MAAM;IACNC,IAAImB,SAASvE,KAAK,GAAA;EACpB,CAAA,EAAGqD,SAAQ;AACX,SAAO,OAAO9B,sBAAsB3B,GAAAA,EAAKoB,KAAYC,gBAAQP,sBAAsB8D,cAAAA,CAAAA,CAAAA;AACrF,CAAA;",
4
+ "sourcesContent": ["//\n// Copyright 2024 DXOS.org\n//\n\nimport * as Context from 'effect/Context';\nimport * as Effect from 'effect/Effect';\nimport * as Layer from 'effect/Layer';\n\nimport { Database, type Ref } from '@dxos/echo';\nimport { CredentialsService } from '@dxos/functions';\nimport { log } from '@dxos/log';\nimport { type AccessToken } from '@dxos/types';\n\nimport type * as Channel from '../../types/Channel';\n\n/**\n * Creates the service interface from a cached token.\n * Falls back to database credentials if no cached token is provided.\n */\nconst makeService = (cachedToken: string | undefined): Context.Tag.Service<GoogleCredentials> => ({\n get: () =>\n cachedToken\n ? Effect.succeed(cachedToken)\n : Effect.map(CredentialsService.getCredential({ service: 'google.com' }), (credential) => credential.apiKey!),\n});\n\n/**\n * Loads access token from a ref if available.\n */\nconst loadAccessToken = (accessTokenRef: Ref.Ref<AccessToken.AccessToken> | undefined, label: string) =>\n Effect.gen(function* () {\n if (accessTokenRef) {\n const accessToken = yield* Database.load(accessTokenRef);\n if (accessToken?.token) {\n log(`using ${label}-specific access token`, { note: accessToken.note });\n return accessToken.token;\n }\n }\n return undefined;\n });\n\n/**\n * Service for accessing Google API credentials.\n * Provides the Google API token either from an object's access token or falls back to database credentials.\n */\n// TODO(dmaretskyi): Remove this service.\nexport class GoogleCredentials extends Context.Tag('GoogleCredentials')<\n GoogleCredentials,\n {\n /** Returns the Google API token. */\n get: () => Effect.Effect<string, never, CredentialsService>;\n }\n>() {\n /**\n * Creates a credentials layer from a channel.\n * Pre-loads the access token during layer construction.\n */\n static fromChannel = (channel: Channel.YouTubeChannel) =>\n Layer.effect(GoogleCredentials, Effect.map(loadAccessToken(channel.accessToken, 'channel'), makeService));\n\n /**\n * Creates a credentials layer from a channel ref.\n * Loads the channel and pre-loads the access token during layer construction.\n */\n static fromChannelRef = (channelRef: Ref.Ref<Channel.YouTubeChannel>) =>\n Layer.effect(\n GoogleCredentials,\n Effect.flatMap(Database.load(channelRef), (channel) =>\n Effect.map(loadAccessToken(channel.accessToken, 'channel'), makeService),\n ),\n );\n\n /**\n * Default layer that uses database credentials.\n * Use this for operations that don't have an associated channel.\n */\n static default = Layer.succeed(GoogleCredentials, makeService(undefined));\n\n /** Convenience accessor - returns the Google API token. */\n static get = () => Effect.flatMap(GoogleCredentials, (service) => service.get());\n}\n", "//\n// Copyright 2024 DXOS.org\n//\n\nexport * from './api';\nexport * from './types';\n", "//\n// Copyright 2024 DXOS.org\n//\n\nimport * as HttpClient from '@effect/platform/HttpClient';\nimport * as HttpClientRequest from '@effect/platform/HttpClientRequest';\nimport * as Effect from 'effect/Effect';\nimport type * as ParseResult from 'effect/ParseResult';\nimport * as Schedule from 'effect/Schedule';\nimport * as Schema from 'effect/Schema';\n\nimport { withAuthorization } from '@dxos/functions';\nimport { log } from '@dxos/log';\n\nimport { GoogleCredentials } from '../../services/google-credentials';\nimport {\n ChannelsResponse,\n ErrorResponse,\n PlaylistItemsResponse,\n SearchResponse,\n VideosResponse,\n YouTubeError,\n} from './types';\n\nconst API_URL = 'https://www.googleapis.com/youtube/v3';\n\n/**\n * Creates a URL from path segments and query parameters.\n */\nconst createUrl = (parts: (string | undefined)[], params?: Record<string, unknown>): URL => {\n const url = new URL(parts.filter(Boolean).join('/'));\n if (params) {\n Object.entries(params)\n .filter(([_, value]) => value != null)\n .forEach(([key, value]) => url.searchParams.set(key, String(value)));\n }\n return url;\n};\n\n/**\n * Decode response and handle YouTube API errors.\n */\nconst decodeAndHandleErrors =\n <S extends Schema.Schema.Any>(schema: S) =>\n (\n data: unknown,\n ): Effect.Effect<Schema.Schema.Type<S>, YouTubeError | ParseResult.ParseError, Schema.Schema.Context<S>> =>\n Schema.decodeUnknown(Schema.Union(schema, ErrorResponse))(data).pipe(\n Effect.flatMap((response) => {\n if ('error' in response) {\n return Effect.fail(YouTubeError.fromErrorResponse(response));\n } else {\n return Effect.succeed(response);\n }\n }),\n );\n\n/**\n * Makes an authenticated HTTP request to a YouTube API endpoint.\n */\nconst makeYouTubeApiRequest = Effect.fn('makeYouTubeApiRequest')(function* (url: string) {\n const token = yield* GoogleCredentials.get();\n\n const httpClient = yield* HttpClient.HttpClient.pipe(Effect.map(withAuthorization(token, 'Bearer')));\n const httpClientWithTracerDisabled = httpClient.pipe(HttpClient.withTracerDisabledWhen(() => true));\n\n const request = HttpClientRequest.get(url);\n\n const response = yield* request.pipe(\n HttpClientRequest.setHeader('accept', 'application/json'),\n httpClientWithTracerDisabled.execute,\n Effect.flatMap((res) => res.json),\n Effect.timeout('10 seconds'),\n Effect.retry(Schedule.exponential(1_000).pipe(Schedule.compose(Schedule.recurs(3)))),\n Effect.scoped,\n Effect.withSpan('YouTubeApiRequest'),\n );\n\n if ((response as Record<string, unknown>).error) {\n log.catch((response as Record<string, unknown>).error);\n }\n\n return response;\n});\n\n/**\n * Get channel details by channel ID.\n * https://developers.google.com/youtube/v3/docs/channels/list\n */\nexport const getChannel = Effect.fn(function* (channelId: string) {\n const url = createUrl([API_URL, 'channels'], {\n part: 'snippet,contentDetails',\n id: channelId,\n }).toString();\n return yield* makeYouTubeApiRequest(url).pipe(Effect.flatMap(decodeAndHandleErrors(ChannelsResponse)));\n});\n\n/**\n * Get channel by username/handle.\n * https://developers.google.com/youtube/v3/docs/channels/list\n */\nexport const getChannelByHandle = Effect.fn(function* (handle: string) {\n const url = createUrl([API_URL, 'channels'], {\n part: 'snippet,contentDetails',\n forHandle: handle.startsWith('@') ? handle.slice(1) : handle,\n }).toString();\n return yield* makeYouTubeApiRequest(url).pipe(Effect.flatMap(decodeAndHandleErrors(ChannelsResponse)));\n});\n\n/**\n * Search for channels by query.\n * https://developers.google.com/youtube/v3/docs/search/list\n */\nexport const searchChannels = Effect.fn(function* (query: string, maxResults = 10) {\n const url = createUrl([API_URL, 'search'], {\n part: 'snippet',\n type: 'channel',\n q: query,\n maxResults,\n }).toString();\n return yield* makeYouTubeApiRequest(url).pipe(Effect.flatMap(decodeAndHandleErrors(SearchResponse)));\n});\n\n/**\n * List videos from a playlist (used to get uploads from a channel's uploads playlist).\n * https://developers.google.com/youtube/v3/docs/playlistItems/list\n */\nexport const listPlaylistItems = Effect.fn(function* (playlistId: string, maxResults = 50, pageToken?: string) {\n const url = createUrl([API_URL, 'playlistItems'], {\n part: 'snippet,contentDetails',\n playlistId,\n maxResults,\n pageToken,\n }).toString();\n return yield* makeYouTubeApiRequest(url).pipe(Effect.flatMap(decodeAndHandleErrors(PlaylistItemsResponse)));\n});\n\n/**\n * Get detailed video information including statistics and duration.\n * https://developers.google.com/youtube/v3/docs/videos/list\n */\nexport const getVideoDetails = Effect.fn(function* (videoIds: string[]) {\n const url = createUrl([API_URL, 'videos'], {\n part: 'snippet,contentDetails,statistics',\n id: videoIds.join(','),\n }).toString();\n return yield* makeYouTubeApiRequest(url).pipe(Effect.flatMap(decodeAndHandleErrors(VideosResponse)));\n});\n", "//\n// Copyright 2024 DXOS.org\n//\n\nimport * as Schema from 'effect/Schema';\n\n/**\n * YouTube API error response.\n */\nexport class YouTubeError extends Schema.TaggedError<YouTubeError>()('YouTubeError', {\n code: Schema.Number,\n message: Schema.String,\n status: Schema.optional(Schema.String),\n}) {\n static fromErrorResponse(response: ErrorResponse) {\n return new YouTubeError({\n code: response.error.code,\n message: response.error.message,\n status: response.error.status,\n });\n }\n}\n\nexport const ErrorResponse = Schema.Struct({\n error: Schema.Struct({\n code: Schema.Number,\n message: Schema.String,\n status: Schema.optional(Schema.String),\n }),\n});\n\nexport type ErrorResponse = Schema.Schema.Type<typeof ErrorResponse>;\n\n/**\n * YouTube channel snippet from search/channel API.\n */\nexport const ChannelSnippet = Schema.Struct({\n title: Schema.String,\n description: Schema.optional(Schema.String),\n customUrl: Schema.optional(Schema.String),\n publishedAt: Schema.optional(Schema.String),\n thumbnails: Schema.optional(\n Schema.Struct({\n default: Schema.optional(Schema.Struct({ url: Schema.String })),\n medium: Schema.optional(Schema.Struct({ url: Schema.String })),\n high: Schema.optional(Schema.Struct({ url: Schema.String })),\n }),\n ),\n});\n\n/**\n * YouTube channel item from channels API.\n */\nexport const ChannelItem = Schema.Struct({\n kind: Schema.String,\n etag: Schema.String,\n id: Schema.String,\n snippet: Schema.optional(ChannelSnippet),\n contentDetails: Schema.optional(\n Schema.Struct({\n relatedPlaylists: Schema.optional(\n Schema.Struct({\n uploads: Schema.optional(Schema.String),\n }),\n ),\n }),\n ),\n});\n\n/**\n * YouTube channels list response.\n */\nexport const ChannelsResponse = Schema.Struct({\n kind: Schema.String,\n etag: Schema.String,\n pageInfo: Schema.optional(\n Schema.Struct({\n totalResults: Schema.Number,\n resultsPerPage: Schema.Number,\n }),\n ),\n items: Schema.Array(ChannelItem),\n});\n\nexport type ChannelsResponse = Schema.Schema.Type<typeof ChannelsResponse>;\n\n/**\n * Video snippet from search/playlistItems API.\n */\nexport const VideoSnippet = Schema.Struct({\n publishedAt: Schema.String,\n channelId: Schema.optional(Schema.String),\n title: Schema.String,\n description: Schema.optional(Schema.String),\n thumbnails: Schema.optional(\n Schema.Struct({\n default: Schema.optional(Schema.Struct({ url: Schema.String })),\n medium: Schema.optional(Schema.Struct({ url: Schema.String })),\n high: Schema.optional(Schema.Struct({ url: Schema.String })),\n standard: Schema.optional(Schema.Struct({ url: Schema.String })),\n maxres: Schema.optional(Schema.Struct({ url: Schema.String })),\n }),\n ),\n channelTitle: Schema.optional(Schema.String),\n playlistId: Schema.optional(Schema.String),\n position: Schema.optional(Schema.Number),\n resourceId: Schema.optional(\n Schema.Struct({\n kind: Schema.String,\n videoId: Schema.String,\n }),\n ),\n});\n\n/**\n * Content details for a video.\n */\nexport const VideoContentDetails = Schema.Struct({\n videoId: Schema.optional(Schema.String),\n videoPublishedAt: Schema.optional(Schema.String),\n duration: Schema.optional(Schema.String),\n});\n\n/**\n * Video statistics.\n */\nexport const VideoStatistics = Schema.Struct({\n viewCount: Schema.optional(Schema.String),\n likeCount: Schema.optional(Schema.String),\n commentCount: Schema.optional(Schema.String),\n});\n\n/**\n * Video item from videos API.\n */\nexport const VideoItem = Schema.Struct({\n kind: Schema.String,\n etag: Schema.String,\n id: Schema.String,\n snippet: Schema.optional(VideoSnippet),\n contentDetails: Schema.optional(VideoContentDetails),\n statistics: Schema.optional(VideoStatistics),\n});\n\nexport type VideoItem = Schema.Schema.Type<typeof VideoItem>;\n\n/**\n * YouTube videos list response.\n */\nexport const VideosResponse = Schema.Struct({\n kind: Schema.String,\n etag: Schema.String,\n nextPageToken: Schema.optional(Schema.String),\n prevPageToken: Schema.optional(Schema.String),\n pageInfo: Schema.optional(\n Schema.Struct({\n totalResults: Schema.Number,\n resultsPerPage: Schema.Number,\n }),\n ),\n items: Schema.Array(VideoItem),\n});\n\nexport type VideosResponse = Schema.Schema.Type<typeof VideosResponse>;\n\n/**\n * Playlist item from playlistItems API.\n */\nexport const PlaylistItem = Schema.Struct({\n kind: Schema.String,\n etag: Schema.String,\n id: Schema.String,\n snippet: Schema.optional(VideoSnippet),\n contentDetails: Schema.optional(VideoContentDetails),\n});\n\n/**\n * YouTube playlist items response.\n */\nexport const PlaylistItemsResponse = Schema.Struct({\n kind: Schema.String,\n etag: Schema.String,\n nextPageToken: Schema.optional(Schema.String),\n prevPageToken: Schema.optional(Schema.String),\n pageInfo: Schema.optional(\n Schema.Struct({\n totalResults: Schema.Number,\n resultsPerPage: Schema.Number,\n }),\n ),\n items: Schema.Array(PlaylistItem),\n});\n\nexport type PlaylistItemsResponse = Schema.Schema.Type<typeof PlaylistItemsResponse>;\n\n/**\n * Search result item.\n */\nexport const SearchItem = Schema.Struct({\n kind: Schema.String,\n etag: Schema.String,\n id: Schema.Struct({\n kind: Schema.String,\n videoId: Schema.optional(Schema.String),\n channelId: Schema.optional(Schema.String),\n playlistId: Schema.optional(Schema.String),\n }),\n snippet: Schema.optional(VideoSnippet),\n});\n\n/**\n * YouTube search response.\n */\nexport const SearchResponse = Schema.Struct({\n kind: Schema.String,\n etag: Schema.String,\n nextPageToken: Schema.optional(Schema.String),\n prevPageToken: Schema.optional(Schema.String),\n pageInfo: Schema.optional(\n Schema.Struct({\n totalResults: Schema.Number,\n resultsPerPage: Schema.Number,\n }),\n ),\n items: Schema.Array(SearchItem),\n});\n\nexport type SearchResponse = Schema.Schema.Type<typeof SearchResponse>;\n\n/**\n * Caption track from captions.list.\n */\nexport const CaptionResource = Schema.Struct({\n id: Schema.String,\n snippet: Schema.optional(\n Schema.Struct({\n videoId: Schema.optional(Schema.String),\n language: Schema.optional(Schema.String),\n name: Schema.optional(Schema.String),\n trackKind: Schema.optional(Schema.String),\n }),\n ),\n});\n\n/**\n * YouTube captions.list response.\n */\nexport const CaptionsListResponse = Schema.Struct({\n kind: Schema.String,\n etag: Schema.String,\n items: Schema.optional(Schema.Array(CaptionResource)),\n});\n\nexport type CaptionsListResponse = Schema.Schema.Type<typeof CaptionsListResponse>;\n"],
5
+ "mappings": "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",
6
6
  "names": ["Context", "Effect", "Layer", "Database", "CredentialsService", "log", "makeService", "cachedToken", "get", "succeed", "map", "getCredential", "service", "credential", "apiKey", "loadAccessToken", "accessTokenRef", "label", "gen", "accessToken", "load", "token", "note", "undefined", "GoogleCredentials", "Tag", "fromChannel", "channel", "effect", "fromChannelRef", "channelRef", "flatMap", "default", "HttpClient", "HttpClientRequest", "Effect", "Schedule", "Schema", "withAuthorization", "log", "Schema", "YouTubeError", "TaggedError", "code", "Number", "message", "String", "status", "optional", "fromErrorResponse", "response", "error", "ErrorResponse", "Struct", "ChannelSnippet", "title", "description", "customUrl", "publishedAt", "thumbnails", "default", "url", "medium", "high", "ChannelItem", "kind", "etag", "id", "snippet", "contentDetails", "relatedPlaylists", "uploads", "ChannelsResponse", "pageInfo", "totalResults", "resultsPerPage", "items", "Array", "VideoSnippet", "channelId", "standard", "maxres", "channelTitle", "playlistId", "position", "resourceId", "videoId", "VideoContentDetails", "videoPublishedAt", "duration", "VideoStatistics", "viewCount", "likeCount", "commentCount", "VideoItem", "statistics", "VideosResponse", "nextPageToken", "prevPageToken", "PlaylistItem", "PlaylistItemsResponse", "SearchItem", "SearchResponse", "CaptionResource", "language", "name", "trackKind", "CaptionsListResponse", "API_URL", "createUrl", "parts", "params", "url", "URL", "filter", "Boolean", "join", "Object", "entries", "_", "value", "forEach", "key", "searchParams", "set", "String", "decodeAndHandleErrors", "schema", "data", "decodeUnknown", "Union", "ErrorResponse", "pipe", "flatMap", "response", "fail", "YouTubeError", "fromErrorResponse", "succeed", "makeYouTubeApiRequest", "fn", "token", "GoogleCredentials", "get", "httpClient", "HttpClient", "map", "withAuthorization", "httpClientWithTracerDisabled", "withTracerDisabledWhen", "request", "setHeader", "execute", "res", "json", "timeout", "retry", "exponential", "compose", "recurs", "scoped", "withSpan", "error", "log", "catch", "getChannel", "channelId", "part", "id", "toString", "ChannelsResponse", "getChannelByHandle", "handle", "forHandle", "startsWith", "slice", "searchChannels", "query", "maxResults", "type", "q", "SearchResponse", "listPlaylistItems", "playlistId", "pageToken", "PlaylistItemsResponse", "getVideoDetails", "videoIds", "VideosResponse"]
7
7
  }
@@ -1,7 +1,7 @@
1
1
  import { createRequire } from 'node:module';const require = createRequire(import.meta.url);
2
2
  import {
3
3
  ClearSyncedVideos
4
- } from "./chunk-RL46XZ2D.mjs";
4
+ } from "./chunk-A3SKNJFU.mjs";
5
5
  import {
6
6
  Video_exports
7
7
  } from "./chunk-YOE54ALJ.mjs";
@@ -18,7 +18,7 @@ var handler = ClearSyncedVideos.pipe(Operation.withHandler(({ channel: channelRe
18
18
  channel: channelRef.dxn.toString()
19
19
  }, {
20
20
  F: __dxlog_file,
21
- L: 18,
21
+ L: 17,
22
22
  S: this,
23
23
  C: (f, a) => f(...a)
24
24
  });
@@ -29,16 +29,16 @@ var handler = ClearSyncedVideos.pipe(Operation.withHandler(({ channel: channelRe
29
29
  count: videos.length
30
30
  }, {
31
31
  F: __dxlog_file,
32
- L: 23,
32
+ L: 22,
33
33
  S: this,
34
34
  C: (f, a) => f(...a)
35
35
  });
36
36
  const newFeed = Feed.make();
37
37
  yield* Database.add(newFeed);
38
38
  Obj.setParent(newFeed, channel);
39
- Obj.change(channel, (mutable) => {
40
- mutable.feed = Ref.make(newFeed);
41
- delete mutable.lastSyncedAt;
39
+ Obj.change(channel, (channel2) => {
40
+ channel2.feed = Ref.make(newFeed);
41
+ delete channel2.lastSyncedAt;
42
42
  });
43
43
  if (videos.length > 0) {
44
44
  yield* Feed.remove(oldFeed, videos);
@@ -51,7 +51,7 @@ var handler = ClearSyncedVideos.pipe(Operation.withHandler(({ channel: channelRe
51
51
  removedVideos: videos.length
52
52
  }, {
53
53
  F: __dxlog_file,
54
- L: 44,
54
+ L: 43,
55
55
  S: this,
56
56
  C: (f, a) => f(...a)
57
57
  });
@@ -63,4 +63,4 @@ var clear_synced_videos_default = handler;
63
63
  export {
64
64
  clear_synced_videos_default as default
65
65
  };
66
- //# sourceMappingURL=clear-synced-videos-Q3MZO2CD.mjs.map
66
+ //# sourceMappingURL=clear-synced-videos-SLEDJ5WI.mjs.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/operations/clear-synced-videos.ts"],
4
+ "sourcesContent": ["//\n// Copyright 2025 DXOS.org\n//\n\nimport * as Effect from 'effect/Effect';\n\nimport { Database, Feed, Filter, Obj, Ref } from '@dxos/echo';\nimport { log } from '@dxos/log';\nimport { Operation } from '@dxos/operation';\n\nimport { Channel, Video } from '../types';\nimport { ClearSyncedVideos } from './definitions';\n\nconst handler: Operation.WithHandler<typeof ClearSyncedVideos> = ClearSyncedVideos.pipe(\n Operation.withHandler(({ channel: channelRef }) =>\n Effect.gen(function* () {\n log('clearing youtube channel synced videos', { channel: channelRef.dxn.toString() });\n const channel = (yield* Database.load(channelRef)) as Channel.YouTubeChannel;\n const oldFeed = yield* Database.load(channel.feed as Ref.Ref<Feed.Feed>);\n\n const videos = yield* Feed.runQuery(oldFeed, Filter.type(Video.YouTubeVideo));\n log('removing synced videos', { count: videos.length });\n\n const newFeed = Feed.make();\n yield* Database.add(newFeed);\n Obj.setParent(newFeed, channel);\n\n Obj.change(channel, (channel) => {\n channel.feed = Ref.make(newFeed);\n delete channel.lastSyncedAt;\n });\n\n if (videos.length > 0) {\n yield* Feed.remove(oldFeed, videos);\n }\n\n for (const video of videos) {\n yield* Database.remove(video);\n }\n\n yield* Database.remove(oldFeed);\n\n log('replaced youtube channel feed', { removedVideos: videos.length });\n return { removedVideos: videos.length };\n }),\n ),\n);\n\nexport default handler;\n"],
5
+ "mappings": ";;;;;;;;;;AAIA,YAAYA,YAAY;AAExB,SAASC,UAAUC,MAAMC,QAAQC,KAAKC,WAAW;AACjD,SAASC,WAAW;AACpB,SAASC,iBAAiB;;AAK1B,IAAMC,UAA2DC,kBAAkBC,KACjFC,UAAUC,YAAY,CAAC,EAAEC,SAASC,WAAU,MACnCC,WAAI,aAAA;AACTC,MAAI,0CAA0C;IAAEH,SAASC,WAAWG,IAAIC,SAAQ;EAAG,GAAA;;;;;;AACnF,QAAML,UAAW,OAAOM,SAASC,KAAKN,UAAAA;AACtC,QAAMO,UAAU,OAAOF,SAASC,KAAKP,QAAQS,IAAI;AAEjD,QAAMC,SAAS,OAAOC,KAAKC,SAASJ,SAASK,OAAOC,KAAKC,cAAMC,YAAY,CAAA;AAC3Eb,MAAI,0BAA0B;IAAEc,OAAOP,OAAOQ;EAAO,GAAA;;;;;;AAErD,QAAMC,UAAUR,KAAKS,KAAI;AACzB,SAAOd,SAASe,IAAIF,OAAAA;AACpBG,MAAIC,UAAUJ,SAASnB,OAAAA;AAEvBsB,MAAIE,OAAOxB,SAAS,CAACA,aAAAA;AACnBA,IAAAA,SAAQS,OAAOgB,IAAIL,KAAKD,OAAAA;AACxB,WAAOnB,SAAQ0B;EACjB,CAAA;AAEA,MAAIhB,OAAOQ,SAAS,GAAG;AACrB,WAAOP,KAAKgB,OAAOnB,SAASE,MAAAA;EAC9B;AAEA,aAAWkB,SAASlB,QAAQ;AAC1B,WAAOJ,SAASqB,OAAOC,KAAAA;EACzB;AAEA,SAAOtB,SAASqB,OAAOnB,OAAAA;AAEvBL,MAAI,iCAAiC;IAAE0B,eAAenB,OAAOQ;EAAO,GAAA;;;;;;AACpE,SAAO;IAAEW,eAAenB,OAAOQ;EAAO;AACxC,CAAA,CAAA,CAAA;AAIJ,IAAA,8BAAevB;",
6
+ "names": ["Effect", "Database", "Feed", "Filter", "Obj", "Ref", "log", "Operation", "handler", "ClearSyncedVideos", "pipe", "Operation", "withHandler", "channel", "channelRef", "gen", "log", "dxn", "toString", "Database", "load", "oldFeed", "feed", "videos", "Feed", "runQuery", "Filter", "type", "Video", "YouTubeVideo", "count", "length", "newFeed", "make", "add", "Obj", "setParent", "change", "Ref", "lastSyncedAt", "remove", "video", "removedVideos"]
7
+ }
@@ -1,11 +1,11 @@
1
1
  import { createRequire } from 'node:module';const require = createRequire(import.meta.url);
2
2
  import {
3
3
  youtube_exports
4
- } from "./chunk-BVKMXV2G.mjs";
4
+ } from "./chunk-Q3TVMR5B.mjs";
5
5
  import {
6
6
  ClearSyncedVideos,
7
7
  Sync
8
- } from "./chunk-RL46XZ2D.mjs";
8
+ } from "./chunk-A3SKNJFU.mjs";
9
9
  import "./chunk-YOE54ALJ.mjs";
10
10
  import "./chunk-HSLMI22Q.mjs";
11
11
 
@@ -28,7 +28,7 @@ var meta = {
28
28
 
29
29
  // src/operations/index.ts
30
30
  import { OperationHandlerSet } from "@dxos/operation";
31
- var YouTubeHandlers = OperationHandlerSet.lazy(() => import("./clear-synced-videos-Q3MZO2CD.mjs"), () => import("./sync-BEXQNNSH.mjs"));
31
+ var YouTubeHandlers = OperationHandlerSet.lazy(() => import("./clear-synced-videos-SLEDJ5WI.mjs"), () => import("./sync-RQYQ5LII.mjs"));
32
32
 
33
33
  // src/YouTubePlugin.tsx
34
34
  import * as Effect from "effect/Effect";
@@ -41,7 +41,9 @@ import { AttentionEvents } from "@dxos/plugin-attention/types";
41
41
  import { ClientEvents } from "@dxos/plugin-client/types";
42
42
  import { SpaceOperation } from "@dxos/plugin-space/operations";
43
43
  import { YouTubeBlueprint } from "#blueprints";
44
+ import { AppGraphBuilder, BlueprintDefinition, Migrations, ReactSurface } from "#capabilities";
44
45
  import { meta as meta3 } from "#meta";
46
+ import { Channel as Channel2, Video as Video2 } from "#types";
45
47
 
46
48
  // src/translations.ts
47
49
  import { meta as meta2 } from "#meta";
@@ -96,8 +98,6 @@ var translations = [
96
98
  ];
97
99
 
98
100
  // src/YouTubePlugin.tsx
99
- import { Channel as Channel2, Video as Video2 } from "#types";
100
- import { AppGraphBuilder, BlueprintDefinition, Migrations, ReactSurface } from "#capabilities";
101
101
  var YouTubePlugin = Plugin.define(meta3).pipe(AppPlugin.addAppGraphModule({
102
102
  activatesOn: ActivationEvent.allOf(AppActivationEvents.SetupAppGraph, AttentionEvents.AttentionReady),
103
103
  activate: AppGraphBuilder
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/meta.ts", "../../../src/operations/index.ts", "../../../src/YouTubePlugin.tsx", "../../../src/translations.ts"],
4
- "sourcesContent": ["//\n// Copyright 2024 DXOS.org\n//\n\nimport { type Plugin } from '@dxos/app-framework';\nimport { trim } from '@dxos/util';\n\nexport const meta: Plugin.Meta = {\n id: 'org.dxos.plugin.youtube',\n name: 'YouTube',\n description: trim`\n YouTube channel subscription and video feed management.\n Sync videos from channels and access transcripts for analysis.\n `,\n icon: 'ph--youtube-logo--regular',\n iconHue: 'red',\n source: 'https://github.com/dxos/dxos/tree/main/packages/plugins/plugin-youtube',\n tags: ['labs'],\n};\n", "//\n// Copyright 2024 DXOS.org\n//\n\nimport { OperationHandlerSet } from '@dxos/operation';\n\nexport { YouTube } from './apis';\nexport * from './definitions';\n\nexport const YouTubeHandlers = OperationHandlerSet.lazy(\n () => import('./clear-synced-videos'),\n () => import('./sync'),\n);\n", "//\n// Copyright 2024 DXOS.org\n//\n\nimport * as Effect from 'effect/Effect';\nimport * as Option from 'effect/Option';\n\nimport { ActivationEvent, Plugin } from '@dxos/app-framework';\nimport { AppActivationEvents, AppPlugin } from '@dxos/app-toolkit';\nimport { Annotation } from '@dxos/echo';\nimport { Operation } from '@dxos/operation';\nimport { AttentionEvents } from '@dxos/plugin-attention/types';\nimport { ClientEvents } from '@dxos/plugin-client/types';\nimport { type CreateObject } from '@dxos/plugin-space/types';\nimport { SpaceOperation } from '@dxos/plugin-space/operations';\n\nimport { YouTubeBlueprint } from '#blueprints';\nimport { meta } from '#meta';\nimport { translations } from './translations';\nimport { Channel, Video } from '#types';\n\nimport { AppGraphBuilder, BlueprintDefinition, Migrations, ReactSurface } from '#capabilities';\n\nexport const YouTubePlugin = Plugin.define(meta).pipe(\n AppPlugin.addAppGraphModule({\n activatesOn: ActivationEvent.allOf(AppActivationEvents.SetupAppGraph, AttentionEvents.AttentionReady),\n activate: AppGraphBuilder,\n }),\n AppPlugin.addBlueprintDefinitionModule({ activate: BlueprintDefinition }),\n AppPlugin.addMetadataModule({\n metadata: [\n {\n id: Channel.YouTubeChannel.typename,\n metadata: {\n label: (object: Channel.YouTubeChannel) => object.name ?? object.channelUrl ?? object.channelId ?? 'YouTube',\n icon: Annotation.IconAnnotation.get(Channel.YouTubeChannel).pipe(Option.getOrThrow).icon,\n iconHue: Annotation.IconAnnotation.get(Channel.YouTubeChannel).pipe(Option.getOrThrow).hue ?? 'white',\n blueprints: [YouTubeBlueprint.key],\n inputSchema: Channel.CreateYouTubeChannelSchema,\n createObject: ((props, options) =>\n Effect.gen(function* () {\n const object = Channel.make(props);\n return yield* Operation.invoke(SpaceOperation.AddObject, {\n object,\n target: options.target,\n hidden: true,\n targetNodeId: options.targetNodeId,\n });\n })) satisfies CreateObject,\n },\n },\n {\n id: Video.YouTubeVideo.typename,\n metadata: {\n label: (object: Video.YouTubeVideo) => object.title,\n icon: Annotation.IconAnnotation.get(Video.YouTubeVideo).pipe(Option.getOrThrow).icon,\n iconHue: Annotation.IconAnnotation.get(Video.YouTubeVideo).pipe(Option.getOrThrow).hue ?? 'white',\n },\n },\n ],\n }),\n AppPlugin.addSchemaModule({\n schema: [Channel.YouTubeChannel, Video.YouTubeVideo],\n }),\n AppPlugin.addSurfaceModule({ activate: ReactSurface }),\n AppPlugin.addTranslationsModule({ translations }),\n Plugin.addModule({\n activatesOn: ClientEvents.SetupMigration,\n activate: Migrations,\n }),\n Plugin.make,\n);\n", "//\n// Copyright 2024 DXOS.org\n//\n\nimport { type Resource } from '@dxos/react-ui';\n\nimport { meta } from '#meta';\nimport { Channel, Video } from '#types';\n\nexport const translations = [\n {\n 'en-US': {\n [Channel.YouTubeChannel.typename]: {\n 'typename.label': 'YouTube Channel',\n 'typename.label_zero': 'YouTube Channels',\n 'typename.label_one': 'YouTube Channel',\n 'typename.label_other': 'YouTube Channels',\n 'object-name.placeholder': 'New YouTube channel',\n 'add-object.label': 'Add YouTube channel',\n 'rename-object.label': 'Rename YouTube channel',\n 'delete-object.label': 'Delete YouTube channel',\n 'object-deleted.label': 'YouTube channel deleted',\n },\n [Video.YouTubeVideo.typename]: {\n 'typename.label': 'Video',\n 'typename.label_zero': 'Videos',\n 'typename.label_one': 'Video',\n 'typename.label_other': 'Videos',\n 'object-name.placeholder': 'New video',\n 'add-object.label': 'Add video',\n 'rename-object.label': 'Rename video',\n 'delete-object.label': 'Delete video',\n 'object-deleted.label': 'Video deleted',\n },\n [meta.id]: {\n 'plugin.name': 'YouTube',\n 'channel.label': 'YouTube Channel',\n 'video.label': 'Video',\n 'sync-channel.label': 'Sync channel',\n 'sync-channel-error.title': 'Failed to sync channel',\n 'clear-synced-videos.label': 'Clear synced videos',\n 'clear-synced-videos-error.title': 'Failed to clear synced videos',\n 'close.label': 'Close',\n 'new-channel.label': 'New YouTube Channel',\n 'empty-channel.message': 'No videos synced yet',\n 'no-video.message': 'Select a video to view it',\n\n 'channel-account.label': 'Account',\n 'channel-account.placeholder': 'Select account...',\n 'channel-sync.label': 'Channel Sync',\n\n 'enable-background-sync.label': 'Enable background sync',\n 'enabling-background-sync.label': 'Enabling...',\n 'disable-background-sync.label': 'Disable background sync',\n 'view-trigger.label': 'View trigger',\n },\n },\n },\n] as const satisfies Resource[];\n"],
5
- "mappings": "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",
6
- "names": ["trim", "meta", "id", "name", "description", "trim", "icon", "iconHue", "source", "tags", "OperationHandlerSet", "YouTubeHandlers", "OperationHandlerSet", "lazy", "Effect", "Option", "ActivationEvent", "Plugin", "AppActivationEvents", "AppPlugin", "Annotation", "Operation", "AttentionEvents", "ClientEvents", "SpaceOperation", "YouTubeBlueprint", "meta", "meta", "Channel", "Video", "translations", "Channel", "YouTubeChannel", "typename", "Video", "YouTubeVideo", "meta", "id", "Channel", "Video", "AppGraphBuilder", "BlueprintDefinition", "Migrations", "ReactSurface", "YouTubePlugin", "Plugin", "define", "meta", "pipe", "AppPlugin", "addAppGraphModule", "activatesOn", "ActivationEvent", "allOf", "AppActivationEvents", "SetupAppGraph", "AttentionEvents", "AttentionReady", "activate", "AppGraphBuilder", "addBlueprintDefinitionModule", "BlueprintDefinition", "addMetadataModule", "metadata", "id", "Channel", "YouTubeChannel", "typename", "label", "object", "name", "channelUrl", "channelId", "icon", "Annotation", "IconAnnotation", "get", "getOrThrow", "iconHue", "hue", "blueprints", "YouTubeBlueprint", "key", "inputSchema", "CreateYouTubeChannelSchema", "createObject", "props", "options", "gen", "make", "Operation", "invoke", "SpaceOperation", "AddObject", "target", "hidden", "targetNodeId", "Video", "YouTubeVideo", "title", "addSchemaModule", "schema", "addSurfaceModule", "ReactSurface", "addTranslationsModule", "translations", "addModule", "ClientEvents", "SetupMigration", "Migrations"]
4
+ "sourcesContent": ["//\n// Copyright 2024 DXOS.org\n//\n\nimport { type Plugin } from '@dxos/app-framework';\nimport { trim } from '@dxos/util';\n\nexport const meta: Plugin.Meta = {\n id: 'org.dxos.plugin.youtube',\n name: 'YouTube',\n description: trim`\n YouTube channel subscription and video feed management.\n Sync videos from channels and access transcripts for analysis.\n `,\n icon: 'ph--youtube-logo--regular',\n iconHue: 'red',\n source: 'https://github.com/dxos/dxos/tree/main/packages/plugins/plugin-youtube',\n tags: ['labs'],\n};\n", "//\n// Copyright 2024 DXOS.org\n//\n\nimport { OperationHandlerSet } from '@dxos/operation';\n\nexport { YouTube } from './apis';\nexport * from './definitions';\n\nexport const YouTubeHandlers = OperationHandlerSet.lazy(\n () => import('./clear-synced-videos'),\n () => import('./sync'),\n);\n", "//\n// Copyright 2024 DXOS.org\n//\n\nimport * as Effect from 'effect/Effect';\nimport * as Option from 'effect/Option';\n\nimport { ActivationEvent, Plugin } from '@dxos/app-framework';\nimport { AppActivationEvents, AppPlugin } from '@dxos/app-toolkit';\nimport { Annotation } from '@dxos/echo';\nimport { Operation } from '@dxos/operation';\nimport { AttentionEvents } from '@dxos/plugin-attention/types';\nimport { ClientEvents } from '@dxos/plugin-client/types';\nimport { SpaceOperation } from '@dxos/plugin-space/operations';\nimport { type CreateObject } from '@dxos/plugin-space/types';\n\nimport { YouTubeBlueprint } from '#blueprints';\nimport { AppGraphBuilder, BlueprintDefinition, Migrations, ReactSurface } from '#capabilities';\nimport { meta } from '#meta';\nimport { Channel, Video } from '#types';\n\nimport { translations } from './translations';\n\nexport const YouTubePlugin = Plugin.define(meta).pipe(\n AppPlugin.addAppGraphModule({\n activatesOn: ActivationEvent.allOf(AppActivationEvents.SetupAppGraph, AttentionEvents.AttentionReady),\n activate: AppGraphBuilder,\n }),\n AppPlugin.addBlueprintDefinitionModule({ activate: BlueprintDefinition }),\n AppPlugin.addMetadataModule({\n metadata: [\n {\n id: Channel.YouTubeChannel.typename,\n metadata: {\n label: (object: Channel.YouTubeChannel) => object.name ?? object.channelUrl ?? object.channelId ?? 'YouTube',\n icon: Annotation.IconAnnotation.get(Channel.YouTubeChannel).pipe(Option.getOrThrow).icon,\n iconHue: Annotation.IconAnnotation.get(Channel.YouTubeChannel).pipe(Option.getOrThrow).hue ?? 'white',\n blueprints: [YouTubeBlueprint.key],\n inputSchema: Channel.CreateYouTubeChannelSchema,\n createObject: ((props, options) =>\n Effect.gen(function* () {\n const object = Channel.make(props);\n return yield* Operation.invoke(SpaceOperation.AddObject, {\n object,\n target: options.target,\n hidden: true,\n targetNodeId: options.targetNodeId,\n });\n })) satisfies CreateObject,\n },\n },\n {\n id: Video.YouTubeVideo.typename,\n metadata: {\n label: (object: Video.YouTubeVideo) => object.title,\n icon: Annotation.IconAnnotation.get(Video.YouTubeVideo).pipe(Option.getOrThrow).icon,\n iconHue: Annotation.IconAnnotation.get(Video.YouTubeVideo).pipe(Option.getOrThrow).hue ?? 'white',\n },\n },\n ],\n }),\n AppPlugin.addSchemaModule({\n schema: [Channel.YouTubeChannel, Video.YouTubeVideo],\n }),\n AppPlugin.addSurfaceModule({ activate: ReactSurface }),\n AppPlugin.addTranslationsModule({ translations }),\n Plugin.addModule({\n activatesOn: ClientEvents.SetupMigration,\n activate: Migrations,\n }),\n Plugin.make,\n);\n", "//\n// Copyright 2024 DXOS.org\n//\n\nimport { type Resource } from '@dxos/react-ui';\n\nimport { meta } from '#meta';\nimport { Channel, Video } from '#types';\n\nexport const translations = [\n {\n 'en-US': {\n [Channel.YouTubeChannel.typename]: {\n 'typename.label': 'YouTube Channel',\n 'typename.label_zero': 'YouTube Channels',\n 'typename.label_one': 'YouTube Channel',\n 'typename.label_other': 'YouTube Channels',\n 'object-name.placeholder': 'New YouTube channel',\n 'add-object.label': 'Add YouTube channel',\n 'rename-object.label': 'Rename YouTube channel',\n 'delete-object.label': 'Delete YouTube channel',\n 'object-deleted.label': 'YouTube channel deleted',\n },\n [Video.YouTubeVideo.typename]: {\n 'typename.label': 'Video',\n 'typename.label_zero': 'Videos',\n 'typename.label_one': 'Video',\n 'typename.label_other': 'Videos',\n 'object-name.placeholder': 'New video',\n 'add-object.label': 'Add video',\n 'rename-object.label': 'Rename video',\n 'delete-object.label': 'Delete video',\n 'object-deleted.label': 'Video deleted',\n },\n [meta.id]: {\n 'plugin.name': 'YouTube',\n 'channel.label': 'YouTube Channel',\n 'video.label': 'Video',\n 'sync-channel.label': 'Sync channel',\n 'sync-channel-error.title': 'Failed to sync channel',\n 'clear-synced-videos.label': 'Clear synced videos',\n 'clear-synced-videos-error.title': 'Failed to clear synced videos',\n 'close.label': 'Close',\n 'new-channel.label': 'New YouTube Channel',\n 'empty-channel.message': 'No videos synced yet',\n 'no-video.message': 'Select a video to view it',\n\n 'channel-account.label': 'Account',\n 'channel-account.placeholder': 'Select account...',\n 'channel-sync.label': 'Channel Sync',\n\n 'enable-background-sync.label': 'Enable background sync',\n 'enabling-background-sync.label': 'Enabling...',\n 'disable-background-sync.label': 'Disable background sync',\n 'view-trigger.label': 'View trigger',\n },\n },\n },\n] as const satisfies Resource[];\n"],
5
+ "mappings": "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",
6
+ "names": ["trim", "meta", "id", "name", "description", "trim", "icon", "iconHue", "source", "tags", "OperationHandlerSet", "YouTubeHandlers", "OperationHandlerSet", "lazy", "Effect", "Option", "ActivationEvent", "Plugin", "AppActivationEvents", "AppPlugin", "Annotation", "Operation", "AttentionEvents", "ClientEvents", "SpaceOperation", "YouTubeBlueprint", "AppGraphBuilder", "BlueprintDefinition", "Migrations", "ReactSurface", "meta", "Channel", "Video", "meta", "Channel", "Video", "translations", "Channel", "YouTubeChannel", "typename", "Video", "YouTubeVideo", "meta", "id", "YouTubePlugin", "Plugin", "define", "meta", "pipe", "AppPlugin", "addAppGraphModule", "activatesOn", "ActivationEvent", "allOf", "AppActivationEvents", "SetupAppGraph", "AttentionEvents", "AttentionReady", "activate", "AppGraphBuilder", "addBlueprintDefinitionModule", "BlueprintDefinition", "addMetadataModule", "metadata", "id", "Channel", "YouTubeChannel", "typename", "label", "object", "name", "channelUrl", "channelId", "icon", "Annotation", "IconAnnotation", "get", "getOrThrow", "iconHue", "hue", "blueprints", "YouTubeBlueprint", "key", "inputSchema", "CreateYouTubeChannelSchema", "createObject", "props", "options", "gen", "make", "Operation", "invoke", "SpaceOperation", "AddObject", "target", "hidden", "targetNodeId", "Video", "YouTubeVideo", "title", "addSchemaModule", "schema", "addSurfaceModule", "ReactSurface", "addTranslationsModule", "translations", "addModule", "ClientEvents", "SetupMigration", "Migrations"]
7
7
  }