@dxos/plugin-youtube 0.8.3 → 0.8.4-main.74a063c4e0

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 (156) hide show
  1. package/dist/lib/browser/blueprints/index.mjs +49 -8
  2. package/dist/lib/browser/blueprints/index.mjs.map +4 -4
  3. package/dist/lib/browser/{chunk-C26XKDK2.mjs → chunk-FEQD5TPI.mjs} +4 -4
  4. package/dist/lib/browser/{chunk-C26XKDK2.mjs.map → chunk-FEQD5TPI.mjs.map} +2 -2
  5. package/dist/lib/browser/{chunk-P67QEKBQ.mjs → chunk-GIRFSTHR.mjs} +6 -8
  6. package/dist/lib/browser/chunk-GIRFSTHR.mjs.map +7 -0
  7. package/dist/lib/browser/chunk-GTIWG45H.mjs +157 -0
  8. package/dist/lib/browser/chunk-GTIWG45H.mjs.map +7 -0
  9. package/dist/lib/browser/{clear-synced-videos-EVMJIZPD.mjs → clear-synced-videos-NZIWAVGL.mjs} +7 -8
  10. package/dist/lib/browser/clear-synced-videos-NZIWAVGL.mjs.map +7 -0
  11. package/dist/lib/browser/index.mjs +86 -81
  12. package/dist/lib/browser/index.mjs.map +4 -4
  13. package/dist/lib/browser/meta.json +1 -1
  14. package/dist/lib/browser/{sync-423Q4BDD.mjs → sync-T34US6NO.mjs} +18 -19
  15. package/dist/lib/browser/sync-T34US6NO.mjs.map +7 -0
  16. package/dist/lib/browser/types/index.mjs +2 -4
  17. package/dist/lib/node-esm/blueprints/index.mjs +49 -8
  18. package/dist/lib/node-esm/blueprints/index.mjs.map +4 -4
  19. package/dist/lib/node-esm/{chunk-JSGRZMG3.mjs → chunk-A3SKNJFU.mjs} +6 -8
  20. package/dist/lib/node-esm/chunk-A3SKNJFU.mjs.map +7 -0
  21. package/dist/lib/node-esm/{chunk-JM5SBBP5.mjs → chunk-Q3TVMR5B.mjs} +4 -4
  22. package/dist/lib/node-esm/{chunk-JM5SBBP5.mjs.map → chunk-Q3TVMR5B.mjs.map} +2 -2
  23. package/dist/lib/node-esm/chunk-YOE54ALJ.mjs +158 -0
  24. package/dist/lib/node-esm/chunk-YOE54ALJ.mjs.map +7 -0
  25. package/dist/lib/node-esm/{clear-synced-videos-5UCH6XHL.mjs → clear-synced-videos-ZX7KBPGS.mjs} +7 -8
  26. package/dist/lib/{browser/clear-synced-videos-EVMJIZPD.mjs.map → node-esm/clear-synced-videos-ZX7KBPGS.mjs.map} +2 -2
  27. package/dist/lib/node-esm/index.mjs +86 -81
  28. package/dist/lib/node-esm/index.mjs.map +4 -4
  29. package/dist/lib/node-esm/meta.json +1 -1
  30. package/dist/lib/node-esm/{sync-CEF5DX2J.mjs → sync-RQYQ5LII.mjs} +18 -19
  31. package/dist/lib/node-esm/sync-RQYQ5LII.mjs.map +7 -0
  32. package/dist/lib/node-esm/types/index.mjs +2 -4
  33. package/dist/types/src/YouTubePlugin.d.ts.map +1 -1
  34. package/dist/types/src/capabilities/app-graph-builder.d.ts.map +1 -0
  35. package/dist/types/src/capabilities/blueprint-definition.d.ts.map +1 -0
  36. package/dist/types/src/capabilities/index.d.ts +5 -3
  37. package/dist/types/src/capabilities/index.d.ts.map +1 -1
  38. package/dist/types/src/capabilities/migrations.d.ts +5 -0
  39. package/dist/types/src/capabilities/migrations.d.ts.map +1 -0
  40. package/dist/types/src/capabilities/react-surface.d.ts.map +1 -0
  41. package/dist/types/src/containers/ChannelArticle/ChannelArticle.d.ts +1 -1
  42. package/dist/types/src/containers/ChannelArticle/ChannelArticle.d.ts.map +1 -1
  43. package/dist/types/src/containers/ChannelArticle/index.d.ts +1 -2
  44. package/dist/types/src/containers/ChannelArticle/index.d.ts.map +1 -1
  45. package/dist/types/src/containers/ChannelSettings/index.d.ts +1 -2
  46. package/dist/types/src/containers/ChannelSettings/index.d.ts.map +1 -1
  47. package/dist/types/src/containers/VideoArticle/VideoArticle.d.ts +2 -7
  48. package/dist/types/src/containers/VideoArticle/VideoArticle.d.ts.map +1 -1
  49. package/dist/types/src/containers/VideoArticle/index.d.ts +1 -2
  50. package/dist/types/src/containers/VideoArticle/index.d.ts.map +1 -1
  51. package/dist/types/src/containers/VideoCard/VideoCard.d.ts +2 -2
  52. package/dist/types/src/containers/VideoCard/VideoCard.d.ts.map +1 -1
  53. package/dist/types/src/containers/VideoCard/index.d.ts +1 -2
  54. package/dist/types/src/containers/VideoCard/index.d.ts.map +1 -1
  55. package/dist/types/src/operations/apis/youtube/api.d.ts.map +1 -1
  56. package/dist/types/src/operations/clear-synced-videos.d.ts.map +1 -1
  57. package/dist/types/src/operations/definitions.d.ts +9 -5
  58. package/dist/types/src/operations/definitions.d.ts.map +1 -1
  59. package/dist/types/src/operations/sync.d.ts.map +1 -1
  60. package/dist/types/src/translations.d.ts +38 -38
  61. package/dist/types/src/translations.d.ts.map +1 -1
  62. package/dist/types/src/types/Channel.d.ts +28 -3
  63. package/dist/types/src/types/Channel.d.ts.map +1 -1
  64. package/dist/types/src/types/Video.d.ts +22 -0
  65. package/dist/types/src/types/Video.d.ts.map +1 -1
  66. package/dist/types/tsconfig.tsbuildinfo +1 -1
  67. package/package.json +48 -40
  68. package/src/YouTubePlugin.tsx +12 -6
  69. package/src/blueprints/youtube.ts +1 -1
  70. package/src/capabilities/{app-graph-builder/app-graph-builder.ts → app-graph-builder.ts} +29 -33
  71. package/src/capabilities/{blueprint-definition/blueprint-definition.ts → blueprint-definition.ts} +1 -1
  72. package/src/capabilities/index.ts +7 -4
  73. package/src/capabilities/migrations.ts +35 -0
  74. package/src/capabilities/{react-surface/react-surface.tsx → react-surface.tsx} +16 -18
  75. package/src/containers/ChannelArticle/ChannelArticle.tsx +1 -1
  76. package/src/containers/ChannelArticle/index.ts +1 -3
  77. package/src/containers/ChannelSettings/index.ts +1 -3
  78. package/src/containers/VideoArticle/VideoArticle.tsx +2 -7
  79. package/src/containers/VideoArticle/index.ts +1 -3
  80. package/src/containers/VideoCard/VideoCard.tsx +2 -2
  81. package/src/containers/VideoCard/index.ts +1 -3
  82. package/src/operations/apis/youtube/api.ts +0 -1
  83. package/src/operations/clear-synced-videos.ts +0 -1
  84. package/src/operations/definitions.ts +3 -3
  85. package/src/operations/sync.ts +0 -1
  86. package/src/translations.ts +38 -38
  87. package/src/types/Channel.ts +18 -1
  88. package/src/types/Video.ts +25 -1
  89. package/dist/lib/browser/ChannelArticle-CDQR4BBY.mjs +0 -90
  90. package/dist/lib/browser/ChannelArticle-CDQR4BBY.mjs.map +0 -7
  91. package/dist/lib/browser/ChannelSettings-ZYUNW3VS.mjs +0 -28
  92. package/dist/lib/browser/ChannelSettings-ZYUNW3VS.mjs.map +0 -7
  93. package/dist/lib/browser/VideoArticle-FC4A6E7B.mjs +0 -76
  94. package/dist/lib/browser/VideoArticle-FC4A6E7B.mjs.map +0 -7
  95. package/dist/lib/browser/VideoCard-CCPXDCB7.mjs +0 -64
  96. package/dist/lib/browser/VideoCard-CCPXDCB7.mjs.map +0 -7
  97. package/dist/lib/browser/app-graph-builder-MJY6A6SN.mjs +0 -195
  98. package/dist/lib/browser/app-graph-builder-MJY6A6SN.mjs.map +0 -7
  99. package/dist/lib/browser/blueprint-definition-FRYUYJ22.mjs +0 -22
  100. package/dist/lib/browser/blueprint-definition-FRYUYJ22.mjs.map +0 -7
  101. package/dist/lib/browser/chunk-DFRSBBSO.mjs +0 -21
  102. package/dist/lib/browser/chunk-DFRSBBSO.mjs.map +0 -7
  103. package/dist/lib/browser/chunk-GFRR4TTX.mjs +0 -72
  104. package/dist/lib/browser/chunk-GFRR4TTX.mjs.map +0 -7
  105. package/dist/lib/browser/chunk-MUE22YUM.mjs +0 -57
  106. package/dist/lib/browser/chunk-MUE22YUM.mjs.map +0 -7
  107. package/dist/lib/browser/chunk-P67QEKBQ.mjs.map +0 -7
  108. package/dist/lib/browser/chunk-YMDT37TA.mjs +0 -62
  109. package/dist/lib/browser/chunk-YMDT37TA.mjs.map +0 -7
  110. package/dist/lib/browser/chunk-Z3DGTMKC.mjs +0 -8
  111. package/dist/lib/browser/chunk-Z3DGTMKC.mjs.map +0 -7
  112. package/dist/lib/browser/react-surface-EDA5VYDC.mjs +0 -77
  113. package/dist/lib/browser/react-surface-EDA5VYDC.mjs.map +0 -7
  114. package/dist/lib/browser/sync-423Q4BDD.mjs.map +0 -7
  115. package/dist/lib/node-esm/ChannelArticle-GQ64BO7V.mjs +0 -91
  116. package/dist/lib/node-esm/ChannelArticle-GQ64BO7V.mjs.map +0 -7
  117. package/dist/lib/node-esm/ChannelSettings-DM2HWNKO.mjs +0 -29
  118. package/dist/lib/node-esm/ChannelSettings-DM2HWNKO.mjs.map +0 -7
  119. package/dist/lib/node-esm/VideoArticle-WLTWZO3K.mjs +0 -77
  120. package/dist/lib/node-esm/VideoArticle-WLTWZO3K.mjs.map +0 -7
  121. package/dist/lib/node-esm/VideoCard-FOWQZK75.mjs +0 -65
  122. package/dist/lib/node-esm/VideoCard-FOWQZK75.mjs.map +0 -7
  123. package/dist/lib/node-esm/app-graph-builder-IU5TBAXN.mjs +0 -196
  124. package/dist/lib/node-esm/app-graph-builder-IU5TBAXN.mjs.map +0 -7
  125. package/dist/lib/node-esm/blueprint-definition-W264MZ3D.mjs +0 -23
  126. package/dist/lib/node-esm/blueprint-definition-W264MZ3D.mjs.map +0 -7
  127. package/dist/lib/node-esm/chunk-5KNC2JMP.mjs +0 -58
  128. package/dist/lib/node-esm/chunk-5KNC2JMP.mjs.map +0 -7
  129. package/dist/lib/node-esm/chunk-6BUJ2DQX.mjs +0 -73
  130. package/dist/lib/node-esm/chunk-6BUJ2DQX.mjs.map +0 -7
  131. package/dist/lib/node-esm/chunk-CX6MV3QM.mjs +0 -23
  132. package/dist/lib/node-esm/chunk-CX6MV3QM.mjs.map +0 -7
  133. package/dist/lib/node-esm/chunk-CZSLL3XQ.mjs +0 -63
  134. package/dist/lib/node-esm/chunk-CZSLL3XQ.mjs.map +0 -7
  135. package/dist/lib/node-esm/chunk-JSGRZMG3.mjs.map +0 -7
  136. package/dist/lib/node-esm/chunk-M4S6BE47.mjs +0 -10
  137. package/dist/lib/node-esm/chunk-M4S6BE47.mjs.map +0 -7
  138. package/dist/lib/node-esm/clear-synced-videos-5UCH6XHL.mjs.map +0 -7
  139. package/dist/lib/node-esm/react-surface-5DJAQPHJ.mjs +0 -78
  140. package/dist/lib/node-esm/react-surface-5DJAQPHJ.mjs.map +0 -7
  141. package/dist/lib/node-esm/sync-CEF5DX2J.mjs.map +0 -7
  142. package/dist/types/src/capabilities/app-graph-builder/app-graph-builder.d.ts.map +0 -1
  143. package/dist/types/src/capabilities/app-graph-builder/index.d.ts +0 -3
  144. package/dist/types/src/capabilities/app-graph-builder/index.d.ts.map +0 -1
  145. package/dist/types/src/capabilities/blueprint-definition/blueprint-definition.d.ts.map +0 -1
  146. package/dist/types/src/capabilities/blueprint-definition/index.d.ts +0 -3
  147. package/dist/types/src/capabilities/blueprint-definition/index.d.ts.map +0 -1
  148. package/dist/types/src/capabilities/react-surface/index.d.ts +0 -3
  149. package/dist/types/src/capabilities/react-surface/index.d.ts.map +0 -1
  150. package/dist/types/src/capabilities/react-surface/react-surface.d.ts.map +0 -1
  151. package/src/capabilities/app-graph-builder/index.ts +0 -7
  152. package/src/capabilities/blueprint-definition/index.ts +0 -7
  153. package/src/capabilities/react-surface/index.ts +0 -7
  154. /package/dist/types/src/capabilities/{app-graph-builder/app-graph-builder.d.ts → app-graph-builder.d.ts} +0 -0
  155. /package/dist/types/src/capabilities/{blueprint-definition/blueprint-definition.d.ts → blueprint-definition.d.ts} +0 -0
  156. /package/dist/types/src/capabilities/{react-surface/react-surface.d.ts → react-surface.d.ts} +0 -0
@@ -1,12 +1,53 @@
1
- import {
2
- youtube_default
3
- } from "../chunk-MUE22YUM.mjs";
4
- import "../chunk-Z3DGTMKC.mjs";
5
- import "../chunk-C26XKDK2.mjs";
6
- import "../chunk-P67QEKBQ.mjs";
7
- import "../chunk-GFRR4TTX.mjs";
8
- import "../chunk-YMDT37TA.mjs";
9
1
  import "../chunk-J5LGTIGS.mjs";
2
+
3
+ // src/blueprints/youtube.ts
4
+ import { Blueprint, Template } from "@dxos/blueprints";
5
+ import { trim } from "@dxos/util";
6
+ import { ClearSyncedVideos, Sync } from "#operations";
7
+ var BLUEPRINT_KEY = "dxos.org/blueprint/youtube";
8
+ var make = () => Blueprint.make({
9
+ key: BLUEPRINT_KEY,
10
+ name: "YouTube",
11
+ tools: Blueprint.toolDefinitions({
12
+ operations: [
13
+ Sync,
14
+ ClearSyncedVideos
15
+ ],
16
+ tools: []
17
+ }),
18
+ instructions: Template.make({
19
+ source: trim`
20
+ You manage YouTube channel subscriptions and video content.
21
+
22
+ # Summary formatting:
23
+ - Format summaries as markdown documents without extra comments.
24
+ - Use markdown formatting for headings and bullet points.
25
+ - Format video summaries as lists with key points.
26
+
27
+ # References
28
+ - Use references to objects in the form of:
29
+ @dxn:queue:data:B6INSIBY3CBEF4M5VZRYBCMAHQMPYK5AJ:01K24XMVHSZHS97SG1VTVQDM5Z:01K24XPK464FSCKVQJAB2H662M
30
+ - References are rendered as rich content in the response to the user.
31
+
32
+ # Video Analysis
33
+ When analyzing videos:
34
+ - Summarize the key topics and themes.
35
+ - Extract important quotes or statements.
36
+ - Identify action items or recommendations.
37
+ - Note any timestamps for important sections.
38
+
39
+ # Transcript Usage
40
+ - Videos may include transcripts that can be used for deeper analysis.
41
+ - When summarizing content, reference the transcript for accuracy.
42
+ - Transcripts include timestamps that can help locate specific content.
43
+ `
44
+ })
45
+ });
46
+ var blueprint = {
47
+ key: BLUEPRINT_KEY,
48
+ make
49
+ };
50
+ var youtube_default = blueprint;
10
51
  export {
11
52
  youtube_default as YouTubeBlueprint
12
53
  };
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": [],
4
- "sourcesContent": [],
5
- "mappings": "",
6
- "names": []
3
+ "sources": ["../../../../src/blueprints/youtube.ts"],
4
+ "sourcesContent": ["//\n// Copyright 2024 DXOS.org\n//\n\nimport { type AppCapabilities } from '@dxos/app-toolkit';\nimport { Blueprint, Template } from '@dxos/blueprints';\nimport { trim } from '@dxos/util';\n\nimport { ClearSyncedVideos, Sync } from '#operations';\n\nconst BLUEPRINT_KEY = 'dxos.org/blueprint/youtube';\n\nconst make = () =>\n Blueprint.make({\n key: BLUEPRINT_KEY,\n name: 'YouTube',\n tools: Blueprint.toolDefinitions({ operations: [Sync, ClearSyncedVideos], tools: [] }),\n instructions: Template.make({\n source: trim`\n You manage YouTube channel subscriptions and video content.\n\n # Summary formatting:\n - Format summaries as markdown documents without extra comments.\n - Use markdown formatting for headings and bullet points.\n - Format video summaries as lists with key points.\n\n # References\n - Use references to objects in the form of:\n @dxn:queue:data:B6INSIBY3CBEF4M5VZRYBCMAHQMPYK5AJ:01K24XMVHSZHS97SG1VTVQDM5Z:01K24XPK464FSCKVQJAB2H662M\n - References are rendered as rich content in the response to the user.\n\n # Video Analysis\n When analyzing videos:\n - Summarize the key topics and themes.\n - Extract important quotes or statements.\n - Identify action items or recommendations.\n - Note any timestamps for important sections.\n\n # Transcript Usage\n - Videos may include transcripts that can be used for deeper analysis.\n - When summarizing content, reference the transcript for accuracy.\n - Transcripts include timestamps that can help locate specific content.\n `,\n }),\n });\n\nconst blueprint: AppCapabilities.BlueprintDefinition = {\n key: BLUEPRINT_KEY,\n make,\n};\n\nexport default blueprint;\n"],
5
+ "mappings": ";;;AAKA,SAASA,WAAWC,gBAAgB;AACpC,SAASC,YAAY;AAErB,SAASC,mBAAmBC,YAAY;AAExC,IAAMC,gBAAgB;AAEtB,IAAMC,OAAO,MACXC,UAAUD,KAAK;EACbE,KAAKH;EACLI,MAAM;EACNC,OAAOH,UAAUI,gBAAgB;IAAEC,YAAY;MAACC;MAAMC;;IAAoBJ,OAAO,CAAA;EAAG,CAAA;EACpFK,cAAcC,SAASV,KAAK;IAC1BW,QAAQC;;;;;;;;;;;;;;;;;;;;;;;;;EAyBV,CAAA;AACF,CAAA;AAEF,IAAMC,YAAiD;EACrDX,KAAKH;EACLC;AACF;AAEA,IAAA,kBAAea;",
6
+ "names": ["Blueprint", "Template", "trim", "ClearSyncedVideos", "Sync", "BLUEPRINT_KEY", "make", "Blueprint", "key", "name", "tools", "toolDefinitions", "operations", "Sync", "ClearSyncedVideos", "instructions", "Template", "source", "trim", "blueprint"]
7
7
  }
@@ -9,7 +9,7 @@ import * as Layer from "effect/Layer";
9
9
  import { Database } from "@dxos/echo";
10
10
  import { CredentialsService } from "@dxos/functions";
11
11
  import { log } from "@dxos/log";
12
- var __dxlog_file = "/Users/mykola/dev/dxos/packages/plugins/plugin-youtube/src/operations/services/google-credentials.ts";
12
+ var __dxlog_file = "/__w/dxos/dxos/packages/plugins/plugin-youtube/src/operations/services/google-credentials.ts";
13
13
  var makeService = (cachedToken) => ({
14
14
  get: () => cachedToken ? Effect.succeed(cachedToken) : Effect.map(CredentialsService.getCredential({
15
15
  service: "google.com"
@@ -261,7 +261,7 @@ var CaptionsListResponse = Schema.Struct({
261
261
  });
262
262
 
263
263
  // src/operations/apis/youtube/api.ts
264
- var __dxlog_file2 = "/Users/mykola/dev/dxos/packages/plugins/plugin-youtube/src/operations/apis/youtube/api.ts";
264
+ var __dxlog_file2 = "/__w/dxos/dxos/packages/plugins/plugin-youtube/src/operations/apis/youtube/api.ts";
265
265
  var API_URL = "https://www.googleapis.com/youtube/v3";
266
266
  var createUrl = (parts, params) => {
267
267
  const url = new URL(parts.filter(Boolean).join("/"));
@@ -286,7 +286,7 @@ var makeYouTubeApiRequest = Effect2.fn("makeYouTubeApiRequest")(function* (url)
286
286
  if (response.error) {
287
287
  log2.catch(response.error, void 0, {
288
288
  F: __dxlog_file2,
289
- L: 81,
289
+ L: 80,
290
290
  S: this,
291
291
  C: (f, a) => f(...a)
292
292
  });
@@ -352,4 +352,4 @@ export {
352
352
  GoogleCredentials,
353
353
  youtube_exports
354
354
  };
355
- //# sourceMappingURL=chunk-C26XKDK2.mjs.map
355
+ //# sourceMappingURL=chunk-FEQD5TPI.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,15 +1,13 @@
1
1
  import {
2
- Channel_exports
3
- } from "./chunk-GFRR4TTX.mjs";
4
- import {
2
+ Channel_exports,
5
3
  Video_exports
6
- } from "./chunk-YMDT37TA.mjs";
4
+ } from "./chunk-GTIWG45H.mjs";
7
5
 
8
6
  // src/operations/definitions.ts
9
- import { Operation } from "@dxos/operation";
10
7
  import * as Schema from "effect/Schema";
11
8
  import { Database, Feed, Ref } from "@dxos/echo";
12
9
  import { CredentialsService } from "@dxos/functions";
10
+ import { Operation } from "@dxos/operation";
13
11
  var Sync = Operation.make({
14
12
  meta: {
15
13
  key: "dxos.org/function/youtube/sync",
@@ -37,7 +35,7 @@ var Sync = Operation.make({
37
35
  ],
38
36
  services: [
39
37
  Database.Service,
40
- Feed.Service,
38
+ Feed.FeedService,
41
39
  CredentialsService
42
40
  ]
43
41
  });
@@ -61,7 +59,7 @@ var ClearSyncedVideos = Operation.make({
61
59
  ],
62
60
  services: [
63
61
  Database.Service,
64
- Feed.Service
62
+ Feed.FeedService
65
63
  ]
66
64
  });
67
65
 
@@ -69,4 +67,4 @@ export {
69
67
  Sync,
70
68
  ClearSyncedVideos
71
69
  };
72
- //# sourceMappingURL=chunk-P67QEKBQ.mjs.map
70
+ //# sourceMappingURL=chunk-GIRFSTHR.mjs.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/operations/definitions.ts"],
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
+ }
@@ -0,0 +1,157 @@
1
+ import {
2
+ __export
3
+ } from "./chunk-J5LGTIGS.mjs";
4
+
5
+ // src/types/types.ts
6
+ var YouTubeOperation = {};
7
+
8
+ // src/types/Channel.ts
9
+ var Channel_exports = {};
10
+ __export(Channel_exports, {
11
+ CreateYouTubeChannelSchema: () => CreateYouTubeChannelSchema,
12
+ LegacyYouTubeChannel: () => LegacyYouTubeChannel,
13
+ YouTubeChannel: () => YouTubeChannel,
14
+ instanceOf: () => instanceOf,
15
+ make: () => make
16
+ });
17
+ import * as Schema from "effect/Schema";
18
+ import { Annotation, Feed, Obj, Ref, Type } from "@dxos/echo";
19
+ import { FormInputAnnotation } from "@dxos/echo/internal";
20
+ import { FeedAnnotation } from "@dxos/schema";
21
+ import { AccessToken } from "@dxos/types";
22
+ var LegacyYouTubeChannel = Schema.Struct({
23
+ name: Schema.String.pipe(Schema.optional),
24
+ channelId: Schema.String.pipe(Schema.optional),
25
+ channelUrl: Schema.String.pipe(Schema.optional),
26
+ feed: Ref.Ref(Feed.Feed),
27
+ lastSyncedAt: Schema.String.pipe(Schema.optional),
28
+ accessToken: Schema.optional(Ref.Ref(AccessToken.AccessToken))
29
+ }).pipe(Type.object({
30
+ typename: "org.dxos.type.youtube-channel",
31
+ version: "0.1.0"
32
+ }));
33
+ var YouTubeChannel = Schema.Struct({
34
+ /** Display name for the channel. */
35
+ name: Schema.String.pipe(Schema.optional),
36
+ /** YouTube channel ID (e.g., UC...). */
37
+ channelId: Schema.String.pipe(Schema.optional),
38
+ /** YouTube channel URL or handle. */
39
+ channelUrl: Schema.String.pipe(Schema.optional),
40
+ /** Feed containing YouTubeVideo objects. */
41
+ feed: Ref.Ref(Feed.Feed).pipe(FormInputAnnotation.set(false)),
42
+ /** Last sync timestamp. */
43
+ lastSyncedAt: Schema.String.pipe(FormInputAnnotation.set(false), Schema.optional),
44
+ /** Google API credentials for fetching channel data. */
45
+ accessToken: Schema.optional(Ref.Ref(AccessToken.AccessToken).annotations({
46
+ title: "Account",
47
+ description: "Google account credentials for syncing this YouTube channel."
48
+ }))
49
+ }).pipe(Type.object({
50
+ typename: "org.dxos.type.youtubeChannel",
51
+ version: "0.1.0"
52
+ }), Annotation.IconAnnotation.set({
53
+ icon: "ph--youtube-logo--regular",
54
+ hue: "red"
55
+ }), FeedAnnotation.set(true));
56
+ var instanceOf = (value) => Obj.instanceOf(YouTubeChannel, value);
57
+ var CreateYouTubeChannelSchema = Schema.Struct({
58
+ name: Schema.optional(Schema.String.annotations({
59
+ title: "Name"
60
+ })),
61
+ channelUrl: Schema.optional(Schema.String.annotations({
62
+ title: "Channel URL",
63
+ description: "YouTube channel URL, handle (e.g., @channelname), or channel ID."
64
+ })),
65
+ accessToken: Schema.optional(Ref.Ref(AccessToken.AccessToken).annotations({
66
+ title: "Account",
67
+ description: "Google account credentials for syncing this YouTube channel."
68
+ }))
69
+ });
70
+ var make = (props = {}) => {
71
+ const feed = Feed.make();
72
+ const channel = Obj.make(YouTubeChannel, {
73
+ feed: Ref.make(feed),
74
+ ...props
75
+ });
76
+ Obj.setParent(feed, channel);
77
+ return channel;
78
+ };
79
+
80
+ // src/types/Video.ts
81
+ var Video_exports = {};
82
+ __export(Video_exports, {
83
+ LegacyYouTubeVideo: () => LegacyYouTubeVideo,
84
+ TranscriptSegment: () => TranscriptSegment,
85
+ YouTubeVideo: () => YouTubeVideo,
86
+ instanceOf: () => instanceOf2
87
+ });
88
+ import * as Schema2 from "effect/Schema";
89
+ import { Annotation as Annotation2, Obj as Obj2, Type as Type2 } from "@dxos/echo";
90
+ var TranscriptSegment = Schema2.Struct({
91
+ /** Transcript text. */
92
+ text: Schema2.String,
93
+ /** Start time in seconds. */
94
+ offset: Schema2.Number,
95
+ /** Duration in seconds. */
96
+ duration: Schema2.Number
97
+ });
98
+ var LegacyYouTubeVideo = Schema2.Struct({
99
+ title: Schema2.String,
100
+ videoId: Schema2.String,
101
+ description: Schema2.String.pipe(Schema2.optional),
102
+ url: Schema2.String,
103
+ thumbnailUrl: Schema2.String.pipe(Schema2.optional),
104
+ channelTitle: Schema2.String.pipe(Schema2.optional),
105
+ publishedAt: Schema2.String,
106
+ duration: Schema2.String.pipe(Schema2.optional),
107
+ viewCount: Schema2.Number.pipe(Schema2.optional),
108
+ likeCount: Schema2.Number.pipe(Schema2.optional),
109
+ transcript: Schema2.String.pipe(Schema2.optional),
110
+ transcriptSegments: Schema2.Array(TranscriptSegment).pipe(Schema2.optional),
111
+ transcriptFetched: Schema2.Boolean.pipe(Schema2.optional)
112
+ }).pipe(Type2.object({
113
+ typename: "org.dxos.type.youtube-video",
114
+ version: "0.1.0"
115
+ }));
116
+ var YouTubeVideo = Schema2.Struct({
117
+ /** Video title. */
118
+ title: Schema2.String,
119
+ /** YouTube video ID. */
120
+ videoId: Schema2.String,
121
+ /** Video description. */
122
+ description: Schema2.String.pipe(Schema2.optional),
123
+ /** Video URL. */
124
+ url: Schema2.String,
125
+ /** Thumbnail URL. */
126
+ thumbnailUrl: Schema2.String.pipe(Schema2.optional),
127
+ /** Channel name. */
128
+ channelTitle: Schema2.String.pipe(Schema2.optional),
129
+ /** Published date as ISO string. */
130
+ publishedAt: Schema2.String,
131
+ /** Video duration in ISO 8601 format (e.g., PT1H30M15S). */
132
+ duration: Schema2.String.pipe(Schema2.optional),
133
+ /** View count. */
134
+ viewCount: Schema2.Number.pipe(Schema2.optional),
135
+ /** Like count. */
136
+ likeCount: Schema2.Number.pipe(Schema2.optional),
137
+ /** Full transcript text. */
138
+ transcript: Schema2.String.pipe(Schema2.optional),
139
+ /** Transcript segments with timestamps. */
140
+ transcriptSegments: Schema2.Array(TranscriptSegment).pipe(Schema2.optional),
141
+ /** True when transcript text was successfully loaded; false when disabled or none available. */
142
+ transcriptFetched: Schema2.Boolean.pipe(Schema2.optional)
143
+ }).pipe(Type2.object({
144
+ typename: "org.dxos.type.youtubeVideo",
145
+ version: "0.1.0"
146
+ }), Annotation2.IconAnnotation.set({
147
+ icon: "ph--play--regular",
148
+ hue: "red"
149
+ }));
150
+ var instanceOf2 = (value) => Obj2.instanceOf(YouTubeVideo, value);
151
+
152
+ export {
153
+ YouTubeOperation,
154
+ Channel_exports,
155
+ Video_exports
156
+ };
157
+ //# sourceMappingURL=chunk-GTIWG45H.mjs.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/types/types.ts", "../../../src/types/Channel.ts", "../../../src/types/Video.ts"],
4
+ "sourcesContent": ["//\n// Copyright 2024 DXOS.org\n//\n\n/**\n * YouTube plugin operations (placeholder for future expansion).\n */\nexport const YouTubeOperation = {\n // Operations will be defined here when needed.\n} as const;\n", "//\n// Copyright 2024 DXOS.org\n//\n\nimport * as Schema from 'effect/Schema';\n\nimport { Annotation, Feed, Obj, Ref, Type } from '@dxos/echo';\nimport { FormInputAnnotation } from '@dxos/echo/internal';\nimport { FeedAnnotation } from '@dxos/schema';\nimport { AccessToken } from '@dxos/types';\n\n// @import-as-namespace\n\n/** @deprecated Use YouTubeChannel instead. */\nexport const LegacyYouTubeChannel = Schema.Struct({\n name: Schema.String.pipe(Schema.optional),\n channelId: Schema.String.pipe(Schema.optional),\n channelUrl: Schema.String.pipe(Schema.optional),\n feed: Ref.Ref(Feed.Feed),\n lastSyncedAt: Schema.String.pipe(Schema.optional),\n accessToken: Schema.optional(Ref.Ref(AccessToken.AccessToken)),\n}).pipe(\n Type.object({\n typename: 'org.dxos.type.youtube-channel',\n version: '0.1.0',\n }),\n);\n\nexport interface LegacyYouTubeChannel extends Schema.Schema.Type<typeof LegacyYouTubeChannel> {}\n\n/**\n * YouTubeChannel schema representing a YouTube channel to sync videos from.\n */\nexport const YouTubeChannel = Schema.Struct({\n /** Display name for the channel. */\n name: Schema.String.pipe(Schema.optional),\n /** YouTube channel ID (e.g., UC...). */\n channelId: Schema.String.pipe(Schema.optional),\n /** YouTube channel URL or handle. */\n channelUrl: Schema.String.pipe(Schema.optional),\n /** Feed containing YouTubeVideo objects. */\n feed: Ref.Ref(Feed.Feed).pipe(FormInputAnnotation.set(false)),\n /** Last sync timestamp. */\n lastSyncedAt: Schema.String.pipe(FormInputAnnotation.set(false), Schema.optional),\n /** Google API credentials for fetching channel data. */\n accessToken: Schema.optional(\n Ref.Ref(AccessToken.AccessToken).annotations({\n title: 'Account',\n description: 'Google account credentials for syncing this YouTube channel.',\n }),\n ),\n}).pipe(\n Type.object({\n typename: 'org.dxos.type.youtubeChannel',\n version: '0.1.0',\n }),\n Annotation.IconAnnotation.set({\n icon: 'ph--youtube-logo--regular',\n hue: 'red',\n }),\n FeedAnnotation.set(true),\n);\n\nexport interface YouTubeChannel extends Schema.Schema.Type<typeof YouTubeChannel> {}\n\n/** Checks if a value is a YouTubeChannel object. */\nexport const instanceOf = (value: unknown): value is YouTubeChannel => Obj.instanceOf(YouTubeChannel, value);\n\nexport const CreateYouTubeChannelSchema = Schema.Struct({\n name: Schema.optional(Schema.String.annotations({ title: 'Name' })),\n channelUrl: Schema.optional(\n Schema.String.annotations({\n title: 'Channel URL',\n description: 'YouTube channel URL, handle (e.g., @channelname), or channel ID.',\n }),\n ),\n accessToken: Schema.optional(\n Ref.Ref(AccessToken.AccessToken).annotations({\n title: 'Account',\n description: 'Google account credentials for syncing this YouTube channel.',\n }),\n ),\n});\nexport interface CreateYouTubeChannelSchema extends Schema.Schema.Type<typeof CreateYouTubeChannelSchema> {}\n\ntype YouTubeChannelProps = Omit<Obj.MakeProps<typeof YouTubeChannel>, 'feed' | 'lastSyncedAt'>;\n\n/** Creates a YouTubeChannel object with a backing feed. */\nexport const make = (props: YouTubeChannelProps = {}) => {\n const feed = Feed.make();\n const channel = Obj.make(YouTubeChannel, {\n feed: Ref.make(feed),\n ...props,\n });\n Obj.setParent(feed, channel);\n return channel;\n};\n", "//\n// Copyright 2024 DXOS.org\n//\n\nimport * as Schema from 'effect/Schema';\n\nimport { Annotation, Obj, Type } from '@dxos/echo';\n\n/**\n * Transcript segment from a YouTube video.\n */\nexport const TranscriptSegment = Schema.Struct({\n /** Transcript text. */\n text: Schema.String,\n /** Start time in seconds. */\n offset: Schema.Number,\n /** Duration in seconds. */\n duration: Schema.Number,\n});\n\nexport type TranscriptSegment = Schema.Schema.Type<typeof TranscriptSegment>;\n\n/** @deprecated Use YouTubeVideo instead. */\nexport const LegacyYouTubeVideo = Schema.Struct({\n title: Schema.String,\n videoId: Schema.String,\n description: Schema.String.pipe(Schema.optional),\n url: Schema.String,\n thumbnailUrl: Schema.String.pipe(Schema.optional),\n channelTitle: Schema.String.pipe(Schema.optional),\n publishedAt: Schema.String,\n duration: Schema.String.pipe(Schema.optional),\n viewCount: Schema.Number.pipe(Schema.optional),\n likeCount: Schema.Number.pipe(Schema.optional),\n transcript: Schema.String.pipe(Schema.optional),\n transcriptSegments: Schema.Array(TranscriptSegment).pipe(Schema.optional),\n transcriptFetched: Schema.Boolean.pipe(Schema.optional),\n}).pipe(\n Type.object({\n typename: 'org.dxos.type.youtube-video',\n version: '0.1.0',\n }),\n);\n\nexport interface LegacyYouTubeVideo extends Schema.Schema.Type<typeof LegacyYouTubeVideo> {}\n\n/**\n * YouTubeVideo schema representing a video from a YouTube channel.\n */\nexport const YouTubeVideo = Schema.Struct({\n /** Video title. */\n title: Schema.String,\n /** YouTube video ID. */\n videoId: Schema.String,\n /** Video description. */\n description: Schema.String.pipe(Schema.optional),\n /** Video URL. */\n url: Schema.String,\n /** Thumbnail URL. */\n thumbnailUrl: Schema.String.pipe(Schema.optional),\n /** Channel name. */\n channelTitle: Schema.String.pipe(Schema.optional),\n /** Published date as ISO string. */\n publishedAt: Schema.String,\n /** Video duration in ISO 8601 format (e.g., PT1H30M15S). */\n duration: Schema.String.pipe(Schema.optional),\n /** View count. */\n viewCount: Schema.Number.pipe(Schema.optional),\n /** Like count. */\n likeCount: Schema.Number.pipe(Schema.optional),\n /** Full transcript text. */\n transcript: Schema.String.pipe(Schema.optional),\n /** Transcript segments with timestamps. */\n transcriptSegments: Schema.Array(TranscriptSegment).pipe(Schema.optional),\n /** True when transcript text was successfully loaded; false when disabled or none available. */\n transcriptFetched: Schema.Boolean.pipe(Schema.optional),\n}).pipe(\n Type.object({\n typename: 'org.dxos.type.youtubeVideo',\n version: '0.1.0',\n }),\n Annotation.IconAnnotation.set({\n icon: 'ph--play--regular',\n hue: 'red',\n }),\n);\n\nexport interface YouTubeVideo extends Schema.Schema.Type<typeof YouTubeVideo> {}\n\n/** Checks if a value is a YouTubeVideo object. */\nexport const instanceOf = (value: unknown): value is YouTubeVideo => Obj.instanceOf(YouTubeVideo, value);\n"],
5
+ "mappings": "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",
6
+ "names": ["YouTubeOperation", "Schema", "Annotation", "Feed", "Obj", "Ref", "Type", "FormInputAnnotation", "FeedAnnotation", "AccessToken", "LegacyYouTubeChannel", "Struct", "name", "String", "pipe", "optional", "channelId", "channelUrl", "feed", "Ref", "Feed", "lastSyncedAt", "accessToken", "AccessToken", "Type", "object", "typename", "version", "YouTubeChannel", "FormInputAnnotation", "set", "annotations", "title", "description", "Annotation", "IconAnnotation", "icon", "hue", "FeedAnnotation", "instanceOf", "value", "Obj", "CreateYouTubeChannelSchema", "make", "props", "channel", "setParent", "instanceOf", "Schema", "Annotation", "Obj", "Type", "TranscriptSegment", "Struct", "text", "String", "offset", "Number", "duration", "LegacyYouTubeVideo", "title", "videoId", "description", "pipe", "optional", "url", "thumbnailUrl", "channelTitle", "publishedAt", "viewCount", "likeCount", "transcript", "transcriptSegments", "Array", "transcriptFetched", "Boolean", "Type", "object", "typename", "version", "YouTubeVideo", "Annotation", "IconAnnotation", "set", "icon", "hue", "instanceOf", "value", "Obj"]
7
+ }
@@ -1,10 +1,9 @@
1
1
  import {
2
2
  ClearSyncedVideos
3
- } from "./chunk-P67QEKBQ.mjs";
4
- import "./chunk-GFRR4TTX.mjs";
3
+ } from "./chunk-GIRFSTHR.mjs";
5
4
  import {
6
5
  Video_exports
7
- } from "./chunk-YMDT37TA.mjs";
6
+ } from "./chunk-GTIWG45H.mjs";
8
7
  import "./chunk-J5LGTIGS.mjs";
9
8
 
10
9
  // src/operations/clear-synced-videos.ts
@@ -12,13 +11,13 @@ import * as Effect from "effect/Effect";
12
11
  import { Database, Feed, Filter, Obj, Ref } from "@dxos/echo";
13
12
  import { log } from "@dxos/log";
14
13
  import { Operation } from "@dxos/operation";
15
- var __dxlog_file = "/Users/mykola/dev/dxos/packages/plugins/plugin-youtube/src/operations/clear-synced-videos.ts";
14
+ var __dxlog_file = "/__w/dxos/dxos/packages/plugins/plugin-youtube/src/operations/clear-synced-videos.ts";
16
15
  var handler = ClearSyncedVideos.pipe(Operation.withHandler(({ channel: channelRef }) => Effect.gen(function* () {
17
16
  log("clearing youtube channel synced videos", {
18
17
  channel: channelRef.dxn.toString()
19
18
  }, {
20
19
  F: __dxlog_file,
21
- L: 18,
20
+ L: 17,
22
21
  S: this,
23
22
  C: (f, a) => f(...a)
24
23
  });
@@ -29,7 +28,7 @@ var handler = ClearSyncedVideos.pipe(Operation.withHandler(({ channel: channelRe
29
28
  count: videos.length
30
29
  }, {
31
30
  F: __dxlog_file,
32
- L: 23,
31
+ L: 22,
33
32
  S: this,
34
33
  C: (f, a) => f(...a)
35
34
  });
@@ -51,7 +50,7 @@ var handler = ClearSyncedVideos.pipe(Operation.withHandler(({ channel: channelRe
51
50
  removedVideos: videos.length
52
51
  }, {
53
52
  F: __dxlog_file,
54
- L: 44,
53
+ L: 43,
55
54
  S: this,
56
55
  C: (f, a) => f(...a)
57
56
  });
@@ -63,4 +62,4 @@ var clear_synced_videos_default = handler;
63
62
  export {
64
63
  clear_synced_videos_default as default
65
64
  };
66
- //# sourceMappingURL=clear-synced-videos-EVMJIZPD.mjs.map
65
+ //# sourceMappingURL=clear-synced-videos-NZIWAVGL.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, (mutable) => {\n mutable.feed = Ref.make(newFeed);\n delete mutable.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,CAACyB,YAAAA;AACnBA,YAAQhB,OAAOiB,IAAIN,KAAKD,OAAAA;AACxB,WAAOM,QAAQE;EACjB,CAAA;AAEA,MAAIjB,OAAOQ,SAAS,GAAG;AACrB,WAAOP,KAAKiB,OAAOpB,SAASE,MAAAA;EAC9B;AAEA,aAAWmB,SAASnB,QAAQ;AAC1B,WAAOJ,SAASsB,OAAOC,KAAAA;EACzB;AAEA,SAAOvB,SAASsB,OAAOpB,OAAAA;AAEvBL,MAAI,iCAAiC;IAAE2B,eAAepB,OAAOQ;EAAO,GAAA;;;;;;AACpE,SAAO;IAAEY,eAAepB,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", "mutable", "Ref", "lastSyncedAt", "remove", "video", "removedVideos"]
7
+ }