@zapier/youtube-connector 0.0.0 → 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,93 @@
1
+ Elastic License 2.0
2
+
3
+ URL: https://www.elastic.co/licensing/elastic-license
4
+
5
+ ## Acceptance
6
+
7
+ By using the software, you agree to all of the terms and conditions below.
8
+
9
+ ## Copyright License
10
+
11
+ The licensor grants you a non-exclusive, royalty-free, worldwide,
12
+ non-sublicensable, non-transferable license to use, copy, distribute, make
13
+ available, and prepare derivative works of the software, in each case subject to
14
+ the limitations and conditions below.
15
+
16
+ ## Limitations
17
+
18
+ You may not provide the software to third parties as a hosted or managed
19
+ service, where the service provides users with access to any substantial set of
20
+ the features or functionality of the software.
21
+
22
+ You may not move, change, disable, or circumvent the license key functionality
23
+ in the software, and you may not remove or obscure any functionality in the
24
+ software that is protected by the license key.
25
+
26
+ You may not alter, remove, or obscure any licensing, copyright, or other notices
27
+ of the licensor in the software. Any use of the licensor's trademarks is subject
28
+ to applicable law.
29
+
30
+ ## Patents
31
+
32
+ The licensor grants you a license, under any patent claims the licensor can
33
+ license, or becomes able to license, to make, have made, use, sell, offer for
34
+ sale, import and have imported the software, in each case subject to the
35
+ limitations and conditions in this license. This license does not cover any
36
+ patent claims that you cause to be infringed by modifications or additions to
37
+ the software. If you or your company make any written claim that the software
38
+ infringes or contributes to infringement of any patent, your patent license for
39
+ the software granted under these terms ends immediately. If your company makes
40
+ such a claim, your patent license ends immediately for work on behalf of your
41
+ company.
42
+
43
+ ## Notices
44
+
45
+ You must ensure that anyone who gets a copy of any part of the software from you
46
+ also gets a copy of these terms.
47
+
48
+ If you modify the software, you must include in any modified copies of the
49
+ software prominent notices stating that you have modified the software.
50
+
51
+ ## No Other Rights
52
+
53
+ These terms do not imply any licenses other than those expressly granted in
54
+ these terms.
55
+
56
+ ## Termination
57
+
58
+ If you use the software in violation of these terms, such use is not licensed,
59
+ and your licenses will automatically terminate. If the licensor provides you
60
+ with a notice of your violation, and you cease all violation of this license no
61
+ later than 30 days after you receive that notice, your licenses will be
62
+ reinstated retroactively. However, if you violate these terms after such
63
+ reinstatement, any additional violation of these terms will cause your licenses
64
+ to terminate automatically and permanently.
65
+
66
+ ## No Liability
67
+
68
+ *As far as the law allows, the software comes as is, without any warranty or
69
+ condition, and the licensor will not be liable to you for any damages arising
70
+ out of these terms or the use or nature of the software, under any kind of
71
+ legal claim.*
72
+
73
+ ## Definitions
74
+
75
+ The **licensor** is the entity offering these terms, and the **software** is the
76
+ software the licensor makes available under these terms, including any portion
77
+ of it.
78
+
79
+ **you** refers to the individual or entity agreeing to these terms.
80
+
81
+ **your company** is any legal entity, sole proprietorship, or other kind of
82
+ organization that you work for, plus all organizations that have control over,
83
+ are under the control of, or are under common control with that
84
+ organization. **control** means ownership of substantially all the assets of an
85
+ entity, or the power to direct its management and policies by vote, contract, or
86
+ otherwise. Control can be direct or indirect.
87
+
88
+ **your licenses** are all the licenses granted to you for the software under
89
+ these terms.
90
+
91
+ **use** means anything you do with the software requiring one of your licenses.
92
+
93
+ **trademark** means trademarks, service marks, and similar rights.
package/NOTICE ADDED
@@ -0,0 +1,8 @@
1
+ Independent, unofficial connector for YouTube.
2
+
3
+ Zapier licenses only the connector code in this package, under the Elastic
4
+ License 2.0. Zapier grants no rights in YouTube's API, services, data,
5
+ schemas, documentation, or other materials, which remain the property of
6
+ YouTube. YouTube and its logos are trademarks of their owner, used only to
7
+ identify the service this connector works with. Not affiliated with, endorsed
8
+ by, or sponsored by YouTube.
package/README.md CHANGED
@@ -1,4 +1,119 @@
1
1
  # @zapier/youtube-connector
2
2
 
3
- > **Placeholder** published to bootstrap OIDC Trusted Publisher configuration.
4
- > The real package is published via GitLab CI once trust is established.
3
+ _Independent, unofficial connector for YouTube. Not affiliated with, endorsed by, or sponsored by YouTube. "YouTube" is a trademark of its owner, used only to identify the service this connector works with._
4
+
5
+ Agent-callable YouTube tools — search and read videos, update and delete videos, manage playlists and playlist items, read and post comments, rate videos, manage subscriptions, and read channel and caption metadata. Use when the user mentions YouTube or wants to find, comment on, or organize YouTube videos and playlists, even if they don't name YouTube explicitly.
6
+
7
+ This connector wraps the [YouTube Data API v3](https://developers.google.com/youtube/v3) (`https://www.googleapis.com/youtube/v3/`) behind 22 agent-callable tools spanning video discovery and detail, video update / delete, playlist and playlist-item management, comment reading and posting, subscriptions, and the channel / category / caption read surfaces an agent needs to resolve ids. Auth is Google OAuth 2.0 — a single access token whose capabilities are gated by OAuth scope and by resource ownership.
8
+
9
+ This connector is the same artifact across four shapes: MCP server, CLI bin, importable Node module, and an [Agent Skill](https://agentskills.io/) anchored by [`SKILL.md`](SKILL.md). Pick the shape that matches how your agent runs.
10
+
11
+ ## Install
12
+
13
+ ```bash
14
+ # Run a tool with zero install — npx fetches the package on first use
15
+ YOUTUBE_ACCESS_TOKEN=xxx npx @zapier/youtube-connector run <toolName> '{ ... }' --connection env:YOUTUBE_ACCESS_TOKEN
16
+
17
+ # Install as a dependency to import the tools in your own code
18
+ npm install @zapier/youtube-connector
19
+
20
+ # Or install as an Agent Skill (https://agentskills.io)
21
+ npx skills zapier/connectors --skill youtube
22
+ ```
23
+
24
+ Auth is one `[<resolver>:]<value>` connection string passed with `--connection`. The value is a _selector_, not the secret: `--connection zapier:<connection-id>` routes through Zapier-managed auth (recommended; no third-party secret enters the agent's environment — store the id in `YOUTUBE_ZAPIER_CONNECTION_ID` and pass `--connection "zapier:$YOUTUBE_ZAPIER_CONNECTION_ID"` if you like), and `--connection env:YOUTUBE_ACCESS_TOKEN` reads a direct token from `$YOUTUBE_ACCESS_TOKEN` (the token stays in `env`, never on argv; Google access tokens expire ~1h and are not refreshed in direct mode). The `<resolver>:` prefix is optional — a bare value is claimed by the first matching resolver. See [`SKILL.md`](SKILL.md#auth) for the scope matrix and how to find a connection ID.
25
+
26
+ ## Tools
27
+
28
+ | Tool | Description |
29
+ | ------------------------- | ------------------------------------------------------------------------------------------- |
30
+ | `searchVideos` | Search videos by keyword, channel, date, or duration (id + snippet only; quota-heavy). |
31
+ | `getVideo` | Get full details of one or more videos by id — snippet, statistics, contentDetails, status. |
32
+ | `updateVideo` | Update a video's metadata (read-modify-write — only the fields you pass change). |
33
+ | `deleteVideo` | Permanently delete a video you own. |
34
+ | `rateVideo` | Like, dislike, or clear your rating on a video. |
35
+ | `listPlaylists` | List playlists owned by the user or a channel, or fetch playlists by id. |
36
+ | `createPlaylist` | Create a new playlist on the user's channel. |
37
+ | `updatePlaylist` | Update a playlist's title, description, or privacy (replaces, doesn't merge). |
38
+ | `deletePlaylist` | Permanently delete a playlist you own. |
39
+ | `listPlaylistItems` | List the videos in a playlist, in order (each item carries its playlistItem id). |
40
+ | `addVideoToPlaylist` | Add a video to a playlist you own. |
41
+ | `removeVideoFromPlaylist` | Remove an item from a playlist (by playlistItem id, not video id). |
42
+ | `listComments` | List top-level comment threads on a video, each with its first replies. |
43
+ | `postComment` | Post a new top-level comment on a video (needs the comment scope). |
44
+ | `replyToComment` | Reply to an existing top-level comment thread (needs the comment scope). |
45
+ | `getChannel` | Get a channel's profile, statistics, and uploads-playlist id (by mine / id / @handle). |
46
+ | `listVideoCategories` | List the assignable video categories for a region. |
47
+ | `listSubscriptions` | List the user's subscriptions, or check a subscription to one channel. |
48
+ | `subscribeToChannel` | Subscribe the user to a channel. |
49
+ | `unsubscribeFromChannel` | Unsubscribe the user from a channel (by subscription id, not channel id). |
50
+ | `listCaptions` | List the caption tracks available for a video (needs the comment/caption scope). |
51
+ | `downloadCaption` | Download a caption track's text in a chosen format (srt/vtt/sbv/scc/ttml). |
52
+
53
+ Run `npx @zapier/youtube-connector run <toolName> --help` to see any tool's exact input contract + the available resolvers.
54
+
55
+ ## Usage
56
+
57
+ ```ts
58
+ import { getVideo } from "@zapier/youtube-connector";
59
+
60
+ // Each named export is the consumer-facing (input, opts) => Promise<{ data, meta }>.
61
+ const { data } = await getVideo(
62
+ { id: "dQw4w9WgXcQ" },
63
+ { connection: "env:YOUTUBE_ACCESS_TOKEN" },
64
+ );
65
+ // data.items[0].statistics.viewCount — counts are returned as strings, not numbers.
66
+ ```
67
+
68
+ `data` is the tool's output (its `outputSchema`); `meta.outputDataValidation` reports what validation did. Pass `{ skipOutputDataValidation: true }` in the run options for the raw, unvalidated output. See [`SKILL.md`](SKILL.md#output-format) for the full envelope contract.
69
+
70
+ ## MCP Server
71
+
72
+ Add one stanza to any MCP-aware client (Claude Desktop, Cursor, Claude Code, …) to auto-discover the tools over stdio:
73
+
74
+ <!-- prettier-ignore -->
75
+ ```jsonc
76
+ // e.g. claude_desktop_config.json or .cursor/mcp.json
77
+ {
78
+ "mcpServers": {
79
+ "youtube": {
80
+ "command": "npx",
81
+ "args": ["@zapier/youtube-connector", "mcp", "--connection", "zapier:<connection-id>"],
82
+ }
83
+ }
84
+ }
85
+ ```
86
+
87
+ No Zapier account? Use the `env:` resolver — point `--connection` at an env-var name and keep the token in `env`: `"args": ["@zapier/youtube-connector", "mcp", "--connection", "env:YOUTUBE_ACCESS_TOKEN"]` with `"env": { "YOUTUBE_ACCESS_TOKEN": "xxx" }`.
88
+
89
+ ## When to use this
90
+
91
+ - An agent needs to read YouTube data — find videos, pull a video's full statistics and details, enumerate a playlist or a channel's uploads, or read comment threads.
92
+ - An agent needs to manage a creator's own content — update videos, organize playlists, post or reply to comments, or manage subscriptions.
93
+ - You want a single, scope-gated OAuth surface over the YouTube Data API that resolves ids (channels → uploads playlist, categories, caption tracks) the way an agent reasons about them.
94
+
95
+ ## When NOT to use this
96
+
97
+ - **Analytics / reporting** (views-over-time, watch-time, revenue, demographics) — not covered; that's the YouTube Analytics API.
98
+ - **Video upload, custom thumbnails, live streaming, comment moderation, caption upload, or channel administration** — out of scope for v1 (video upload and thumbnails require binary media uploads the connection transport doesn't support; captions are read-only here).
99
+ - **Bulk discovery via search** — `search.list` costs 100 quota units and is eventually consistent; to enumerate a known channel's videos, prefer `getChannel` → `listPlaylistItems` on the uploads playlist.
100
+
101
+ ## Links
102
+
103
+ - [`SKILL.md`](SKILL.md) — runtime guidance for agents
104
+ - [YouTube Data API v3 reference](https://developers.google.com/youtube/v3)
105
+ - [Source](https://github.com/zapier/connectors/tree/main/apps/youtube)
106
+
107
+ ## Legal
108
+
109
+ **Scope of license.** Zapier licenses only the connector code in this package. Zapier grants no rights in YouTube's API, services, data, schemas, documentation, or other materials, which remain the property of YouTube. Your use of YouTube's API is governed by your own agreement with YouTube.
110
+
111
+ **Trademarks and affiliation.** YouTube and its logos are trademarks of their owner, used here only to identify the service this connector works with. This connector is not affiliated with, endorsed by, or sponsored by YouTube.
112
+
113
+ **Your responsibility.** This connector calls YouTube's API using credentials you supply. You are responsible for holding a valid YouTube account, for complying with YouTube's API terms, developer policies, and acceptable use rules, and for the data you send and receive through it.
114
+
115
+ **No warranty.** This connector is provided "as is," without warranty of any kind, and is not an official YouTube product. Zapier is not responsible for changes YouTube makes to its API or for any consequence of your use of YouTube's API. See the repository LICENSE for the full disclaimer.
116
+
117
+ **Forks.** You may fork and modify this connector under the Elastic License 2.0. You may state that your fork is "based on" Zapier's connector, but you may not use the "Zapier" name or logo as the name or branding of your fork, or in any way that suggests Zapier produces, endorses, or supports it.
118
+
119
+ Licensed under the Elastic License 2.0. See the repository LICENSE and NOTICE.
package/SKILL.md ADDED
@@ -0,0 +1,162 @@
1
+ ---
2
+ name: youtube
3
+ description: Agent-callable YouTube tools — search and read videos, update and delete videos, manage playlists and playlist items, read and post comments, rate videos, manage subscriptions, and read channel and caption metadata. Use when the user mentions YouTube or wants to find, comment on, or organize YouTube videos and playlists, even if they don't name YouTube explicitly.
4
+ license: Elastic-2.0
5
+ compatibility: Requires Node.js 22.18+ or Bun 1.x; run `npm install` in this directory first.
6
+ metadata:
7
+ title: YouTube
8
+ source: https://github.com/zapier/connectors/blob/main/apps/youtube/SKILL.md
9
+ zapier-app-key: YouTubeV2CLIAPI
10
+ api-docs: https://developers.google.com/youtube/v3
11
+ ---
12
+
13
+ # YouTube
14
+
15
+ _Independent, unofficial connector for YouTube. Not affiliated with, endorsed by, or sponsored by YouTube. "YouTube" is a trademark of its owner, used only to identify the service this connector works with._
16
+
17
+ Tools for working with YouTube against the [YouTube Data API v3](https://developers.google.com/youtube/v3) (`https://www.googleapis.com/youtube/v3/`): search and read videos, update or delete videos, like or dislike videos, create and manage playlists and their items, read and post comments, manage subscriptions, and read channel, category, and caption metadata. 22 tools across video discovery, video and playlist management, community engagement, and the read surfaces an agent needs to resolve ids.
18
+
19
+ ## When to use this connector
20
+
21
+ - An agent needs to **find or read** video data — search for videos, get a video's full statistics and details, list the videos in a playlist, or read a channel's profile and uploads.
22
+ - An agent needs to **manage videos** — update an existing video's metadata without wiping the fields it didn't touch, like/dislike, or delete a video it owns.
23
+ - An agent needs to **organize playlists** — create, update, or delete playlists, and add or remove videos.
24
+ - An agent needs to **engage with the community** — read comment threads, post a comment, reply to a thread, or subscribe / unsubscribe to channels.
25
+
26
+ ## Scripts
27
+
28
+ One file per tool in [`scripts/`](scripts/); each tool's `inputSchema` / `outputSchema` (Zod) in the script file is the source of truth for its contract. All tools use the single connection `youtube`.
29
+
30
+ | Script | Tool name | Connections | Description |
31
+ | -------------------------------------------------------------------------- | ------------------------- | ----------- | ------------------------------------------------------------------------------------------------ |
32
+ | [`scripts/searchVideos.ts`](scripts/searchVideos.ts) | `searchVideos` | `youtube` | Search videos by keyword, channel, date, or duration (id + snippet only; separate quota bucket). |
33
+ | [`scripts/getVideo.ts`](scripts/getVideo.ts) | `getVideo` | `youtube` | Get full details of one or more videos by id — snippet, statistics, contentDetails, status. |
34
+ | [`scripts/updateVideo.ts`](scripts/updateVideo.ts) | `updateVideo` | `youtube` | Update a video's metadata (read-modify-write — only the fields you pass change). |
35
+ | [`scripts/deleteVideo.ts`](scripts/deleteVideo.ts) | `deleteVideo` | `youtube` | Permanently delete a video you own. |
36
+ | [`scripts/rateVideo.ts`](scripts/rateVideo.ts) | `rateVideo` | `youtube` | Like, dislike, or clear your rating on a video. |
37
+ | [`scripts/listPlaylists.ts`](scripts/listPlaylists.ts) | `listPlaylists` | `youtube` | List playlists owned by the user or a channel, or fetch playlists by id. |
38
+ | [`scripts/createPlaylist.ts`](scripts/createPlaylist.ts) | `createPlaylist` | `youtube` | Create a new playlist on the user's channel. |
39
+ | [`scripts/updatePlaylist.ts`](scripts/updatePlaylist.ts) | `updatePlaylist` | `youtube` | Update a playlist's title, description, or privacy (replaces, doesn't merge). |
40
+ | [`scripts/deletePlaylist.ts`](scripts/deletePlaylist.ts) | `deletePlaylist` | `youtube` | Permanently delete a playlist you own. |
41
+ | [`scripts/listPlaylistItems.ts`](scripts/listPlaylistItems.ts) | `listPlaylistItems` | `youtube` | List the videos in a playlist, in order (each item carries its playlistItem id). |
42
+ | [`scripts/addVideoToPlaylist.ts`](scripts/addVideoToPlaylist.ts) | `addVideoToPlaylist` | `youtube` | Add a video to a playlist you own. |
43
+ | [`scripts/removeVideoFromPlaylist.ts`](scripts/removeVideoFromPlaylist.ts) | `removeVideoFromPlaylist` | `youtube` | Remove an item from a playlist (by playlistItem id, not video id). |
44
+ | [`scripts/listComments.ts`](scripts/listComments.ts) | `listComments` | `youtube` | List top-level comment threads on a video, each with its first replies. |
45
+ | [`scripts/postComment.ts`](scripts/postComment.ts) | `postComment` | `youtube` | Post a new top-level comment on a video (needs the comment scope). |
46
+ | [`scripts/replyToComment.ts`](scripts/replyToComment.ts) | `replyToComment` | `youtube` | Reply to an existing top-level comment thread (needs the comment scope). |
47
+ | [`scripts/getChannel.ts`](scripts/getChannel.ts) | `getChannel` | `youtube` | Get a channel's profile, statistics, and uploads-playlist id (by mine / id / @handle). |
48
+ | [`scripts/listVideoCategories.ts`](scripts/listVideoCategories.ts) | `listVideoCategories` | `youtube` | List the assignable video categories for a region. |
49
+ | [`scripts/listSubscriptions.ts`](scripts/listSubscriptions.ts) | `listSubscriptions` | `youtube` | List the user's subscriptions, or check a subscription to one channel. |
50
+ | [`scripts/subscribeToChannel.ts`](scripts/subscribeToChannel.ts) | `subscribeToChannel` | `youtube` | Subscribe the user to a channel. |
51
+ | [`scripts/unsubscribeFromChannel.ts`](scripts/unsubscribeFromChannel.ts) | `unsubscribeFromChannel` | `youtube` | Unsubscribe the user from a channel (by subscription id, not channel id). |
52
+ | [`scripts/listCaptions.ts`](scripts/listCaptions.ts) | `listCaptions` | `youtube` | List the caption tracks available for a video (needs the comment/caption scope). |
53
+ | [`scripts/downloadCaption.ts`](scripts/downloadCaption.ts) | `downloadCaption` | `youtube` | Download a caption track's text in a chosen format (srt/vtt/sbv/scc/ttml). |
54
+
55
+ **Always learn a script's input contract before calling it — never guess field names, casing, or types.** Run `--help` on either entrypoint — `./scripts/<script>.ts --help` or `npx @zapier/youtube-connector run <script> --help` — which renders `inputSchema` as JSON Schema and lists the connection flag(s) and available resolvers.
56
+
57
+ ## Output format
58
+
59
+ Every script returns a `{ data, meta }` envelope (same shape across the CLI's JSON output, the imported SDK return value, and the MCP tool's `structuredContent`):
60
+
61
+ - **`data`** — the script's result (the shape declared by its `outputSchema`).
62
+ - **`meta.outputDataValidation`** — what validating `data` did:
63
+ - `{ skipped: false, droppedPaths: null }` — validated, nothing removed.
64
+ - `{ skipped: false, droppedPaths: [...], instruction }` — validated, but those paths (fields the API returned that the `outputSchema` doesn't declare) were stripped from `data`. If you need them, re-run with output validation skipped.
65
+ - `{ skipped: true }` — validation was bypassed; `data` is the raw, unchecked API output.
66
+
67
+ **Reading dropped fields / `skipOutputDataValidation`.** To receive the raw, unvalidated result, set the single token `skipOutputDataValidation` — CLI: append `--skipOutputDataValidation`; MCP: pass `meta: { skipOutputDataValidation: true }` as a tool argument; SDK: pass `{ skipOutputDataValidation: true }` in the run options. Input validation is never skipped.
68
+
69
+ **Trimming the result / `filterOutputData`.** To shrink a large result down to the fields you need, pass a jq expression that post-processes `data` — CLI: append `--filterOutputData '<jq>'`; MCP: pass `meta: { filterOutputData: "<jq>" }` as a tool argument. The jq runs against `data` only, NOT the `{ data, meta }` envelope, so write it rooted at `data` (see this script's output schema). The transformed value replaces `data`, `meta` is preserved, and the result is NOT re-validated against the output schema. The imported SDK has no `filterOutputData` option — reshape the returned `data` in code instead.
70
+
71
+ ## Disambiguation & refusals
72
+
73
+ **Disambiguation before a write.** Before writing against a video, playlist, or channel you looked up by name (e.g. a video from `searchVideos`, a playlist from `listPlaylists`, a channel from `getChannel`/`searchVideos`), count the **exact case-insensitive title matches**:
74
+
75
+ - **Exactly one match** — act on it. Don't over-ask; a single unambiguous match is the answer.
76
+ - **Two or more that tie** — stop. List the tied candidates with a distinguishing field (channel title, publish date, view count, or the id) and ask the user which one they mean. Titles are not unique on YouTube — many videos and channels share a name — so never pick arbitrarily and never write to all of them.
77
+
78
+ **Mind the id traps.** `removeVideoFromPlaylist` takes the **playlistItem** id from `listPlaylistItems`, not the video id. `unsubscribeFromChannel` takes the **subscription** id from `listSubscriptions`, not the channel id. Passing the wrong id is the most common failure; resolve via the listed tool first.
79
+
80
+ **Unsupported operations — say so and stop; don't fake it with another tool.** This catalog deliberately does not:
81
+
82
+ - **Report analytics** (views-over-time, watch-time, revenue, demographics). There is no analytics tool. Don't substitute a video's lifetime `statistics` counts and present them as an analytics report.
83
+ - **Moderate comments** (edit, delete, hide, mark as spam, or set moderation status) — only reading, posting, and replying are supported. Replies are single-level: you cannot reply to a reply.
84
+ - **Live-stream** (create or manage broadcasts/streams) or **upload/replace captions** — captions are read-only here (list + download).
85
+ - **Upload videos or set custom thumbnails** — there is no `uploadVideo` or `setVideoThumbnail` tool. These require binary media uploads, which the connection transport does not support.
86
+ - **Administer a channel** (edit channel branding, sections, or settings).
87
+
88
+ If asked for any of these, tell the user it's unsupported and stop — don't reach for an unrelated tool to approximate it.
89
+
90
+ ## Auth
91
+
92
+ YouTube uses **Google OAuth 2.0** with a single access token, resolved into the one `youtube` connection slot. Every tool uses the same credential; what a token can do is gated by **OAuth scope** (granted at connect) and by **resource ownership** (you can only modify videos, playlists, and subscriptions you own), not by token type. Pass auth as one connection string with `--connection [<resolver>:]<value>` (CLI / MCP) or `{ connection: "[<resolver>:]<value>" }` (imported). The value is a _selector_, not the secret. Two resolvers — the Zapier-managed one is recommended:
93
+
94
+ - **`zapier:<connection-id>`** _(recommended)_ — Zapier-managed auth. Route through a Zapier YouTube connection; the Zapier auth, retries, and governance layer injects the token and **handles refresh for you**. **Prerequisite: a Zapier account** (free signup at <https://zapier.com>). Find the ID with the Zapier SDK CLI: `npx @zapier/zapier-sdk-cli list-connections YouTubeV2CLIAPI` (run `login` first if unauthenticated; add `--json` for machine output).
95
+ - **`env:<ENV_VAR>`** — direct mode, for bring-your-own-token or local testing. Read a Google OAuth access token from the named environment variable (conventionally `env:YOUTUBE_ACCESS_TOKEN`, with the token exported in `YOUTUBE_ACCESS_TOKEN`). The token must carry the scopes for the tools you call. Google access tokens expire ~1 hour after issue and are **not** refreshed in direct mode, so this suits short-lived / testing use.
96
+
97
+ **Scopes.** The connection should be granted the access the tools you use need:
98
+
99
+ - `youtube.readonly` — all read / list tools (search, videos, playlists, playlist items, channels, categories, subscriptions, comment threads).
100
+ - `youtube` — manage tools: playlist create/update/delete, playlist-item add/remove, subscribe/unsubscribe, video update/delete, **and rateVideo** (rating does _not_ need the comment scope).
101
+ - `youtube.force-ssl` — **required** for all comment writes (`postComment`, `replyToComment`) and for **all caption** operations (`listCaptions`, `downloadCaption`).
102
+
103
+ A request made with an insufficient scope returns **403**; reconnect YouTube with the broader access. A 403 because you don't **own** the resource is a different problem — reconnecting won't help.
104
+
105
+ If no connection is passed the script fails with an actionable error telling you to `Pass --connection [<resolver>:]<value>` and lists the resolvers in match order.
106
+
107
+ ## Using this skill
108
+
109
+ ### 0. Pre-flight and auth
110
+
111
+ Run the bundled pre-flight check **once** at the start of a session to learn how to run the scripts in the current harness, then run scripts directly — reuse the result for the rest of the session. It detects a usable runtime (Node 22.18+ or Bun) and that dependencies are installed; it does **not** probe the network or auth (the scripts own that). Read `PREFLIGHT_STATUS` first — the single verdict token; `PREFLIGHT_RUNNER` names the runtime.
112
+
113
+ ```bash
114
+ ./preflight.sh
115
+ ```
116
+
117
+ Exit `0` **READY**: follow `PREFLIGHT_RECOMMENDATION` — it gives the exact `--help` command to run next. The `--help` output renders `inputSchema` as JSON Schema, lists the connection flag(s) the script reads and every resolver each accepts, and tells you exactly what to provide. Use the runner from `PREFLIGHT_RUNNER` against the local script path — never `npx` (a sandbox that blocked the dep install may also block registry fetches). If a script call later fails with a network error, egress is blocked — recommend the user set up Zapier's remote MCP at `https://mcp.zapier.com`.
118
+
119
+ Exit `1` **NEEDS_ACTION**: follow `PREFLIGHT_RECOMMENDATION` — it spells out the single self-verifying install step and the exact `--help` command to run afterward.
120
+
121
+ The three invocation paths below all assume the pre-flight reported `READY`.
122
+
123
+ ### 1. Execute scripts directly
124
+
125
+ When the agent has shell access to the installed directory, run a script file straight from `scripts/`. Each script is `chmod +x` with a Node-targeted shebang. **Run `--help` first** to read the input contract and confirm an auth resolver is ready — `--help` is the one path for both "learn the input contract" and "check auth":
126
+
127
+ ```bash
128
+ # Inspect the contract + resolvers first
129
+ ./scripts/getVideo.ts --help
130
+
131
+ # Then invoke (direct token — token stays in env)
132
+ YOUTUBE_ACCESS_TOKEN=ya29.xxx ./scripts/getVideo.ts '{"id":"dQw4w9WgXcQ"}' --connection env:YOUTUBE_ACCESS_TOKEN
133
+
134
+ # Or route through a Zapier connection
135
+ ./scripts/searchVideos.ts '{"q":"lo-fi beats"}' --connection zapier:conn_xxx
136
+ ```
137
+
138
+ Prerequisites: Node.js 22.18+ (or Bun 1.x) on `PATH`, plus `npm install` once in this directory. Pin the runtime explicitly with `node scripts/<name>.ts …` or `bun scripts/<name>.ts …` when needed — all forms run the same script body.
139
+
140
+ ### 2. Use the package's CLI
141
+
142
+ ```bash
143
+ YOUTUBE_ACCESS_TOKEN=ya29.xxx npx @zapier/youtube-connector run getVideo '{"id":"dQw4w9WgXcQ"}' --connection env:YOUTUBE_ACCESS_TOKEN
144
+ npx @zapier/youtube-connector --help # all scripts
145
+ npx @zapier/youtube-connector run getVideo --help # per-script schema + resolvers
146
+ ```
147
+
148
+ Same scripts, different entry point. Use `bunx` when `PREFLIGHT_RUNNER` is `bun`. Some harnesses block `npx`/`bunx` — fall back to (1).
149
+
150
+ ### 3. Use as a recipe
151
+
152
+ When no shipped script matches, read this `SKILL.md`, the [`references/`](references/) files, and the `scripts/` files as a recipe to generate custom code. Each script is one `export default defineTool({...})` from `@zapier/connectors-sdk` referencing the connection key `"youtube"`; imitate that shape (Zod input/output schemas, `(input, ctx) => …` run body, the direct-mode auth being a Bearer token in the `Authorization` header). If you persist generated code, add a comment pointing back to this skill's source:
153
+
154
+ ```ts
155
+ // Source: https://github.com/zapier/connectors/blob/main/apps/youtube/SKILL.md
156
+ ```
157
+
158
+ ## API quirks worth knowing
159
+
160
+ | Reference | Load when |
161
+ | ------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
162
+ | [`references/youtube-api-gotchas.md`](references/youtube-api-gotchas.md) | Before relying on counts, quotas, scopes, pagination, IDs, or any non-obvious response field — covers the `part` model, the per-bucket quota system, the error envelope and `reason`→recovery mapping, OAuth scope requirements (`youtube`, `youtube.force-ssl`), counts-as-strings, and per-resource quirks for videos, search, playlists, comments, captions, channels, and subscriptions. |
package/cli.js ADDED
@@ -0,0 +1,71 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Connector CLI entry point.
4
+ *
5
+ * When dist/cli.js is present (npm install route, or after a local build):
6
+ * → delegates to the compiled CLI, works on any Node version.
7
+ *
8
+ * When dist/ is absent (git-clone route, no build step):
9
+ * → handles the `build` subcommand directly (any Node version, no TS needed),
10
+ * then falls through to cli.ts for all other subcommands (requires Node 22.18+
11
+ * or Bun for TypeScript stripping outside node_modules).
12
+ *
13
+ * `build` subcommand: compiles the connector so that
14
+ * `import { search } from "@zapier/notion-connector"` works on any Node version
15
+ * even when the connector was installed from a git/file source. Invoked
16
+ * automatically by the `prepare` lifecycle hook on git-clone installs.
17
+ * Tries `npx tsup`, falls back to `bunx tsup`, exits 0 regardless so that
18
+ * `npm install` / `pnpm install` never fails in restricted environments.
19
+ *
20
+ * Managed by @zapier/connectors-dev — do not edit; synced byte-for-byte
21
+ * across every connector.
22
+ */
23
+ import { spawnSync } from "node:child_process";
24
+ import { existsSync } from "node:fs";
25
+ import { dirname, join } from "node:path";
26
+ import { fileURLToPath } from "node:url";
27
+
28
+ const dir = dirname(fileURLToPath(import.meta.url));
29
+
30
+ if (process.argv[2] === "build") {
31
+ if (!existsSync(join(dir, "dist", "cli.js"))) {
32
+ // Try the locally-installed tsup binary first so module resolution for
33
+ // typescript (a required tsup peer) works from the connector's own
34
+ // node_modules. Fall back to npx/bunx for environments without a local
35
+ // install (e.g. fresh git-clone before npm install).
36
+ const localTsup = join(dir, "node_modules", ".bin", "tsup");
37
+ const candidates = existsSync(localTsup)
38
+ ? [
39
+ [process.execPath, [localTsup]],
40
+ ["npx", ["tsup"]],
41
+ ["bunx", ["tsup"]],
42
+ ]
43
+ : [
44
+ ["npx", ["tsup"]],
45
+ ["bunx", ["tsup"]],
46
+ ];
47
+ for (const [cmd, args] of candidates) {
48
+ const { status } = spawnSync(cmd, args, {
49
+ stdio: "inherit",
50
+ shell: true,
51
+ cwd: dir,
52
+ });
53
+ if (status === 0) break;
54
+ }
55
+ }
56
+ process.exit(0);
57
+ }
58
+
59
+ // Spawn the target as a subprocess so it runs as the entry point.
60
+ // Dynamic import() would set import.meta.main = false, causing
61
+ // runDispatchCli to return early without executing anything.
62
+ const target = existsSync(join(dir, "dist", "cli.js"))
63
+ ? join(dir, "dist", "cli.js")
64
+ : join(dir, "cli.ts");
65
+
66
+ const { status } = spawnSync(
67
+ process.execPath,
68
+ [target, ...process.argv.slice(2)],
69
+ { stdio: "inherit" },
70
+ );
71
+ process.exit(status ?? 1);
package/cli.ts ADDED
@@ -0,0 +1,5 @@
1
+ import { runDispatchCli } from "@zapier/connectors-sdk";
2
+
3
+ import connector from "./index.ts";
4
+
5
+ await runDispatchCli(import.meta, connector);
package/connections.ts ADDED
@@ -0,0 +1,8 @@
1
+ import {
2
+ defineEnvTokenResolver,
3
+ zapierConnectionResolver,
4
+ } from "@zapier/connectors-sdk";
5
+
6
+ export const connectionResolvers = {
7
+ youtube: [zapierConnectionResolver, defineEnvTokenResolver()],
8
+ } as const;
package/dist/cli.js ADDED
@@ -0,0 +1,4 @@
1
+ // cli.ts
2
+ import { runDispatchCli } from "@zapier/connectors-sdk";
3
+ import connector from "./index.js";
4
+ await runDispatchCli(import.meta, connector);