stophy 0.1.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/dist/index.js ADDED
@@ -0,0 +1,249 @@
1
+ import { createClient, createConfig } from '@hey-api/client-fetch';
2
+
3
+ // src/index.ts
4
+ var client = createClient(createConfig({
5
+ baseUrl: "https://api.stophy.dev"
6
+ }));
7
+
8
+ // src/generated/sdk.gen.ts
9
+ var getVideo = (options) => {
10
+ return (options.client ?? client).post({
11
+ security: [
12
+ {
13
+ scheme: "bearer",
14
+ type: "http"
15
+ }
16
+ ],
17
+ url: "/v1/video",
18
+ ...options,
19
+ headers: {
20
+ "Content-Type": "application/json",
21
+ ...options?.headers
22
+ }
23
+ });
24
+ };
25
+ var searchVideos = (options) => {
26
+ return (options.client ?? client).post({
27
+ security: [
28
+ {
29
+ scheme: "bearer",
30
+ type: "http"
31
+ }
32
+ ],
33
+ url: "/v1/search",
34
+ ...options,
35
+ headers: {
36
+ "Content-Type": "application/json",
37
+ ...options?.headers
38
+ }
39
+ });
40
+ };
41
+ var getChannel = (options) => {
42
+ return (options.client ?? client).post({
43
+ security: [
44
+ {
45
+ scheme: "bearer",
46
+ type: "http"
47
+ }
48
+ ],
49
+ url: "/v1/channel",
50
+ ...options,
51
+ headers: {
52
+ "Content-Type": "application/json",
53
+ ...options?.headers
54
+ }
55
+ });
56
+ };
57
+ var getPlaylist = (options) => {
58
+ return (options.client ?? client).post({
59
+ security: [
60
+ {
61
+ scheme: "bearer",
62
+ type: "http"
63
+ }
64
+ ],
65
+ url: "/v1/playlist",
66
+ ...options,
67
+ headers: {
68
+ "Content-Type": "application/json",
69
+ ...options?.headers
70
+ }
71
+ });
72
+ };
73
+ var getSuggestions = (options) => {
74
+ return (options.client ?? client).get({
75
+ security: [
76
+ {
77
+ scheme: "bearer",
78
+ type: "http"
79
+ }
80
+ ],
81
+ url: "/v1/suggest",
82
+ ...options
83
+ });
84
+ };
85
+ var getCredits = (options) => {
86
+ return (options?.client ?? client).get({
87
+ security: [
88
+ {
89
+ scheme: "bearer",
90
+ type: "http"
91
+ }
92
+ ],
93
+ url: "/v1/credits",
94
+ ...options
95
+ });
96
+ };
97
+ var getLogs = (options) => {
98
+ return (options?.client ?? client).get({
99
+ security: [
100
+ {
101
+ scheme: "bearer",
102
+ type: "http"
103
+ }
104
+ ],
105
+ url: "/v1/logs",
106
+ ...options
107
+ });
108
+ };
109
+ var getUsage = (options) => {
110
+ return (options?.client ?? client).get({
111
+ security: [
112
+ {
113
+ scheme: "bearer",
114
+ type: "http"
115
+ }
116
+ ],
117
+ url: "/v1/usage",
118
+ ...options
119
+ });
120
+ };
121
+
122
+ // src/index.ts
123
+ var StophyError = class extends Error {
124
+ code;
125
+ status;
126
+ requestId;
127
+ details;
128
+ constructor(message, opts) {
129
+ super(message);
130
+ this.name = "StophyError";
131
+ this.status = opts.status;
132
+ this.code = opts.code;
133
+ this.requestId = opts.requestId;
134
+ this.details = opts.details;
135
+ }
136
+ };
137
+ var Stophy = class {
138
+ /** The underlying fetch client, if you need lower-level access. */
139
+ client;
140
+ constructor(options) {
141
+ if (!options?.apiKey) {
142
+ throw new Error("Stophy: `apiKey` is required.");
143
+ }
144
+ const baseFetch = options.fetch ?? globalThis.fetch;
145
+ this.client = createClient(
146
+ createConfig({
147
+ baseUrl: options.baseUrl ?? "https://api.stophy.dev",
148
+ auth: () => options.apiKey,
149
+ headers: options.headers,
150
+ fetch: withRetries(
151
+ baseFetch,
152
+ options.maxRetries ?? 2,
153
+ options.retryInitialDelayMs ?? 500
154
+ )
155
+ })
156
+ );
157
+ }
158
+ async video(body) {
159
+ return unwrap(await getVideo({ client: this.client, body }));
160
+ }
161
+ /** Search YouTube, optionally filtered by type, sort, date, duration, and features. */
162
+ async search(body) {
163
+ return unwrap(await searchVideos({ client: this.client, body }));
164
+ }
165
+ /** Channel metadata and content. Switch sections with `tab`. */
166
+ async channel(body) {
167
+ return unwrap(await getChannel({ client: this.client, body }));
168
+ }
169
+ /** Playlist items. Page through long playlists with `continuationToken`. */
170
+ async playlist(body) {
171
+ return unwrap(await getPlaylist({ client: this.client, body }));
172
+ }
173
+ /** Search autocomplete suggestions. */
174
+ async suggest(query) {
175
+ return unwrap(await getSuggestions({ client: this.client, query }));
176
+ }
177
+ /** Your current credit balance. */
178
+ async credits() {
179
+ return unwrap(await getCredits({ client: this.client }));
180
+ }
181
+ /** Recent API request logs. */
182
+ async logs(query) {
183
+ return unwrap(await getLogs({ client: this.client, query }));
184
+ }
185
+ /** Daily credit and request counts. */
186
+ async usage(query) {
187
+ return unwrap(await getUsage({ client: this.client, query }));
188
+ }
189
+ };
190
+ var RETRYABLE_STATUS = /* @__PURE__ */ new Set([429, 500, 502, 503, 504]);
191
+ function withRetries(baseFetch, maxRetries, initialDelayMs) {
192
+ if (maxRetries <= 0) {
193
+ return baseFetch;
194
+ }
195
+ return async (input, init) => {
196
+ for (let attempt = 0; ; attempt++) {
197
+ const request = input instanceof Request ? input.clone() : input;
198
+ try {
199
+ const response = await baseFetch(request, init);
200
+ if (attempt < maxRetries && RETRYABLE_STATUS.has(response.status)) {
201
+ await sleep(retryAfterMs(response) ?? backoffMs(attempt, initialDelayMs));
202
+ continue;
203
+ }
204
+ return response;
205
+ } catch (error) {
206
+ if (attempt >= maxRetries) {
207
+ throw error;
208
+ }
209
+ await sleep(backoffMs(attempt, initialDelayMs));
210
+ }
211
+ }
212
+ };
213
+ }
214
+ function backoffMs(attempt, base) {
215
+ const window = base * 2 ** attempt;
216
+ return window / 2 + Math.random() * (window / 2);
217
+ }
218
+ function retryAfterMs(response) {
219
+ const header = response.headers.get("retry-after");
220
+ if (!header) {
221
+ return null;
222
+ }
223
+ const seconds = Number(header);
224
+ if (!Number.isNaN(seconds)) {
225
+ return seconds * 1e3;
226
+ }
227
+ const date = Date.parse(header);
228
+ return Number.isNaN(date) ? null : Math.max(0, date - Date.now());
229
+ }
230
+ function sleep(ms) {
231
+ return new Promise((resolve) => setTimeout(resolve, ms));
232
+ }
233
+ function unwrap(result) {
234
+ if (result.error !== void 0 || result.data === void 0) {
235
+ const err = result.error ?? {};
236
+ throw new StophyError(err.error ?? `Stophy request failed with status ${result.response.status}`, {
237
+ status: result.response.status,
238
+ code: err.code,
239
+ requestId: result.response.headers.get("x-request-id") ?? void 0,
240
+ details: err.details
241
+ });
242
+ }
243
+ return result.data;
244
+ }
245
+ var index_default = Stophy;
246
+
247
+ export { Stophy, StophyError, index_default as default };
248
+ //# sourceMappingURL=index.js.map
249
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/generated/client.gen.ts","../src/generated/sdk.gen.ts","../src/index.ts"],"names":["createClient","createConfig"],"mappings":"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","file":"index.js","sourcesContent":["// This file is auto-generated by @hey-api/openapi-ts\n\nimport type { ClientOptions } from './types.gen';\nimport { type Config, type ClientOptions as DefaultClientOptions, createClient, createConfig } from '@hey-api/client-fetch';\n\n/**\n * The `createClientConfig()` function will be called on client initialization\n * and the returned object will become the client's initial configuration.\n *\n * You may want to initialize your client this way instead of calling\n * `setConfig()`. This is useful for example if you're using Next.js\n * to ensure your client always has the correct values.\n */\nexport type CreateClientConfig<T extends DefaultClientOptions = ClientOptions> = (override?: Config<DefaultClientOptions & T>) => Config<Required<DefaultClientOptions> & T>;\n\nexport const client = createClient(createConfig<ClientOptions>({\n baseUrl: 'https://api.stophy.dev'\n}));","// This file is auto-generated by @hey-api/openapi-ts\n\nimport type { Options as ClientOptions, TDataShape, Client } from '@hey-api/client-fetch';\nimport type { GetVideoData, GetVideoResponse, GetVideoError, SearchVideosData, SearchVideosResponse, SearchVideosError, GetChannelData, GetChannelResponse, GetChannelError, GetPlaylistData, GetPlaylistResponse, GetPlaylistError, GetSuggestionsData, GetSuggestionsResponse, GetSuggestionsError, GetCreditsData, GetCreditsResponse, GetCreditsError, GetLogsData, GetLogsResponse, GetLogsError, GetUsageData, GetUsageResponse, GetUsageError } from './types.gen';\nimport { client as _heyApiClient } from './client.gen';\n\nexport type Options<TData extends TDataShape = TDataShape, ThrowOnError extends boolean = boolean> = ClientOptions<TData, ThrowOnError> & {\n /**\n * You can provide a client instance returned by `createClient()` instead of\n * individual options. This might be also useful if you want to implement a\n * custom client.\n */\n client?: Client;\n /**\n * You can pass arbitrary values through the `meta` object. This can be\n * used to access values that aren't defined as part of the SDK function.\n */\n meta?: Record<string, unknown>;\n};\n\n/**\n * Video\n * Fetch video details, transcript, comments, replies, or live chat. Pass type: details for metadata, transcript for timestamped captions, comments for top-level comments, replies for a comment thread (pass the repliesToken from a comment as continuationToken), or livechat for live stream chat messages.\n */\nexport const getVideo = <ThrowOnError extends boolean = false>(options: Options<GetVideoData, ThrowOnError>) => {\n return (options.client ?? _heyApiClient).post<GetVideoResponse, GetVideoError, ThrowOnError>({\n security: [\n {\n scheme: 'bearer',\n type: 'http'\n }\n ],\n url: '/v1/video',\n ...options,\n headers: {\n 'Content-Type': 'application/json',\n ...options?.headers\n }\n });\n};\n\n/**\n * Search\n * Search YouTube with optional filters for content type, sort order, upload date, duration, and features. Returns paginated results.\n */\nexport const searchVideos = <ThrowOnError extends boolean = false>(options: Options<SearchVideosData, ThrowOnError>) => {\n return (options.client ?? _heyApiClient).post<SearchVideosResponse, SearchVideosError, ThrowOnError>({\n security: [\n {\n scheme: 'bearer',\n type: 'http'\n }\n ],\n url: '/v1/search',\n ...options,\n headers: {\n 'Content-Type': 'application/json',\n ...options?.headers\n }\n });\n};\n\n/**\n * Channel\n * Retrieve channel metadata and content by channelUrl. Use the tab field to switch between videos, shorts, playlists, and about info.\n */\nexport const getChannel = <ThrowOnError extends boolean = false>(options: Options<GetChannelData, ThrowOnError>) => {\n return (options.client ?? _heyApiClient).post<GetChannelResponse, GetChannelError, ThrowOnError>({\n security: [\n {\n scheme: 'bearer',\n type: 'http'\n }\n ],\n url: '/v1/channel',\n ...options,\n headers: {\n 'Content-Type': 'application/json',\n ...options?.headers\n }\n });\n};\n\n/**\n * Playlist\n * Retrieve items from a YouTube playlist. Use continuationToken to page through long playlists.\n */\nexport const getPlaylist = <ThrowOnError extends boolean = false>(options: Options<GetPlaylistData, ThrowOnError>) => {\n return (options.client ?? _heyApiClient).post<GetPlaylistResponse, GetPlaylistError, ThrowOnError>({\n security: [\n {\n scheme: 'bearer',\n type: 'http'\n }\n ],\n url: '/v1/playlist',\n ...options,\n headers: {\n 'Content-Type': 'application/json',\n ...options?.headers\n }\n });\n};\n\n/**\n * Suggest\n * Get YouTube search autocomplete suggestions for a query.\n */\nexport const getSuggestions = <ThrowOnError extends boolean = false>(options: Options<GetSuggestionsData, ThrowOnError>) => {\n return (options.client ?? _heyApiClient).get<GetSuggestionsResponse, GetSuggestionsError, ThrowOnError>({\n security: [\n {\n scheme: 'bearer',\n type: 'http'\n }\n ],\n url: '/v1/suggest',\n ...options\n });\n};\n\n/**\n * Credits\n * Return the current credit balance for the authenticated API key.\n */\nexport const getCredits = <ThrowOnError extends boolean = false>(options?: Options<GetCreditsData, ThrowOnError>) => {\n return (options?.client ?? _heyApiClient).get<GetCreditsResponse, GetCreditsError, ThrowOnError>({\n security: [\n {\n scheme: 'bearer',\n type: 'http'\n }\n ],\n url: '/v1/credits',\n ...options\n });\n};\n\n/**\n * Logs\n * Return recent API request logs for the authenticated key.\n */\nexport const getLogs = <ThrowOnError extends boolean = false>(options?: Options<GetLogsData, ThrowOnError>) => {\n return (options?.client ?? _heyApiClient).get<GetLogsResponse, GetLogsError, ThrowOnError>({\n security: [\n {\n scheme: 'bearer',\n type: 'http'\n }\n ],\n url: '/v1/logs',\n ...options\n });\n};\n\n/**\n * Usage\n * Return daily credit and request counts for the authenticated key.\n */\nexport const getUsage = <ThrowOnError extends boolean = false>(options?: Options<GetUsageData, ThrowOnError>) => {\n return (options?.client ?? _heyApiClient).get<GetUsageResponse, GetUsageError, ThrowOnError>({\n security: [\n {\n scheme: 'bearer',\n type: 'http'\n }\n ],\n url: '/v1/usage',\n ...options\n });\n};","import { createClient, createConfig, type Client } from \"@hey-api/client-fetch\";\nimport * as ops from \"./generated/sdk.gen\";\nimport type {\n ErrorResponse,\n GetVideoData,\n GetVideoResponse,\n SearchVideosData,\n SearchVideosResponse,\n GetChannelData,\n GetChannelResponse,\n GetPlaylistData,\n GetPlaylistResponse,\n GetSuggestionsData,\n GetSuggestionsResponse,\n GetCreditsResponse,\n GetLogsData,\n GetLogsResponse,\n GetUsageData,\n GetUsageResponse,\n VideoDetailsData,\n TranscriptResult,\n CommentsData,\n LiveChatData,\n} from \"./generated/types.gen\";\n\n/** A video response with `data` narrowed to the shape for a given request `type`. */\ntype VideoResponseFor<D> = Omit<GetVideoResponse, \"data\"> & { data: D };\n\nexport * from \"./generated/types.gen\";\n\nexport interface StophyOptions {\n /** API key from your dashboard. Sent as `Authorization: Bearer <key>`. */\n apiKey: string;\n /** Defaults to `https://api.stophy.dev`. */\n baseUrl?: string;\n /** Bring your own `fetch` (handy for tests or non-global runtimes). */\n fetch?: typeof globalThis.fetch;\n /** Sent with every request. */\n headers?: Record<string, string>;\n /**\n * Retry attempts for transient failures (network errors and\n * 429/500/502/503/504). Set to `0` to disable. Defaults to `2`.\n */\n maxRetries?: number;\n /** Base delay for backoff, in ms. Defaults to `500`. */\n retryInitialDelayMs?: number;\n}\n\n/** Thrown when the API responds with a non-2xx status. */\nexport class StophyError extends Error {\n readonly code?: ErrorResponse[\"code\"];\n readonly status: number;\n readonly requestId?: string;\n readonly details?: unknown;\n\n constructor(\n message: string,\n opts: {\n status: number;\n code?: ErrorResponse[\"code\"];\n requestId?: string;\n details?: unknown;\n },\n ) {\n super(message);\n this.name = \"StophyError\";\n this.status = opts.status;\n this.code = opts.code;\n this.requestId = opts.requestId;\n this.details = opts.details;\n }\n}\n\n/**\n * Stophy API client — YouTube context API for AI agents.\n *\n * ```ts\n * const stophy = new Stophy({ apiKey: process.env.STOPHY_API_KEY! });\n * const { data } = await stophy.video({ type: \"transcript\", videoUrl });\n * ```\n */\nexport class Stophy {\n /** The underlying fetch client, if you need lower-level access. */\n readonly client: Client;\n\n constructor(options: StophyOptions) {\n if (!options?.apiKey) {\n throw new Error(\"Stophy: `apiKey` is required.\");\n }\n const baseFetch = options.fetch ?? globalThis.fetch;\n this.client = createClient(\n createConfig({\n baseUrl: options.baseUrl ?? \"https://api.stophy.dev\",\n auth: () => options.apiKey,\n headers: options.headers,\n fetch: withRetries(\n baseFetch,\n options.maxRetries ?? 2,\n options.retryInitialDelayMs ?? 500,\n ),\n }),\n );\n }\n\n /** Video details, transcript, comments, replies, or live chat — pick with `type`. */\n async video(\n body: GetVideoData[\"body\"] & { type: \"details\" },\n ): Promise<VideoResponseFor<VideoDetailsData>>;\n async video(\n body: GetVideoData[\"body\"] & { type: \"transcript\" },\n ): Promise<VideoResponseFor<TranscriptResult>>;\n async video(\n body: GetVideoData[\"body\"] & { type: \"comments\" | \"replies\" },\n ): Promise<VideoResponseFor<CommentsData>>;\n async video(\n body: GetVideoData[\"body\"] & { type: \"livechat\" },\n ): Promise<VideoResponseFor<LiveChatData>>;\n async video(body: GetVideoData[\"body\"]): Promise<GetVideoResponse>;\n async video(body: GetVideoData[\"body\"]): Promise<GetVideoResponse> {\n return unwrap(await ops.getVideo({ client: this.client, body }));\n }\n\n /** Search YouTube, optionally filtered by type, sort, date, duration, and features. */\n async search(body: SearchVideosData[\"body\"]): Promise<SearchVideosResponse> {\n return unwrap(await ops.searchVideos({ client: this.client, body }));\n }\n\n /** Channel metadata and content. Switch sections with `tab`. */\n async channel(body: GetChannelData[\"body\"]): Promise<GetChannelResponse> {\n return unwrap(await ops.getChannel({ client: this.client, body }));\n }\n\n /** Playlist items. Page through long playlists with `continuationToken`. */\n async playlist(body: GetPlaylistData[\"body\"]): Promise<GetPlaylistResponse> {\n return unwrap(await ops.getPlaylist({ client: this.client, body }));\n }\n\n /** Search autocomplete suggestions. */\n async suggest(query: GetSuggestionsData[\"query\"]): Promise<GetSuggestionsResponse> {\n return unwrap(await ops.getSuggestions({ client: this.client, query }));\n }\n\n /** Your current credit balance. */\n async credits(): Promise<GetCreditsResponse> {\n return unwrap(await ops.getCredits({ client: this.client }));\n }\n\n /** Recent API request logs. */\n async logs(query?: GetLogsData[\"query\"]): Promise<GetLogsResponse> {\n return unwrap(await ops.getLogs({ client: this.client, query }));\n }\n\n /** Daily credit and request counts. */\n async usage(query?: GetUsageData[\"query\"]): Promise<GetUsageResponse> {\n return unwrap(await ops.getUsage({ client: this.client, query }));\n }\n}\n\nconst RETRYABLE_STATUS = new Set([429, 500, 502, 503, 504]);\n\ntype FetchFn = (input: Request | URL | string, init?: RequestInit) => Promise<Response>;\n\n// Wrap a fetch so transient failures (network errors and retryable statuses)\n// are retried with exponential backoff + jitter, honoring `Retry-After`.\n// Every Stophy endpoint is a read, so retrying is always safe.\nfunction withRetries(\n baseFetch: typeof globalThis.fetch,\n maxRetries: number,\n initialDelayMs: number,\n): FetchFn {\n if (maxRetries <= 0) {\n return baseFetch;\n }\n return async (input, init) => {\n for (let attempt = 0; ; attempt++) {\n // Clone so the body survives a retry when `input` is a Request.\n const request = input instanceof Request ? input.clone() : input;\n try {\n const response = await baseFetch(request, init);\n if (attempt < maxRetries && RETRYABLE_STATUS.has(response.status)) {\n await sleep(retryAfterMs(response) ?? backoffMs(attempt, initialDelayMs));\n continue;\n }\n return response;\n } catch (error) {\n if (attempt >= maxRetries) {\n throw error;\n }\n await sleep(backoffMs(attempt, initialDelayMs));\n }\n }\n };\n}\n\nfunction backoffMs(attempt: number, base: number): number {\n const window = base * 2 ** attempt;\n return window / 2 + Math.random() * (window / 2);\n}\n\nfunction retryAfterMs(response: Response): number | null {\n const header = response.headers.get(\"retry-after\");\n if (!header) {\n return null;\n }\n const seconds = Number(header);\n if (!Number.isNaN(seconds)) {\n return seconds * 1000;\n }\n const date = Date.parse(header);\n return Number.isNaN(date) ? null : Math.max(0, date - Date.now());\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n// Pull `data` out of a result, or throw a StophyError if the call failed.\nfunction unwrap<T>(result: {\n data?: T;\n error?: unknown;\n response: Response;\n}): T {\n if (result.error !== undefined || result.data === undefined) {\n const err = (result.error ?? {}) as Partial<ErrorResponse>;\n throw new StophyError(err.error ?? `Stophy request failed with status ${result.response.status}`, {\n status: result.response.status,\n code: err.code,\n requestId: result.response.headers.get(\"x-request-id\") ?? undefined,\n details: err.details,\n });\n }\n return result.data;\n}\n\nexport default Stophy;\n"]}
package/package.json ADDED
@@ -0,0 +1,48 @@
1
+ {
2
+ "name": "stophy",
3
+ "version": "0.1.1",
4
+ "description": "Official TypeScript SDK for Stophy - The YouTube context API for AI agents.",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "homepage": "https://stophy.dev",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "https://github.com/stophy/typescript-sdk.git"
11
+ },
12
+ "keywords": [
13
+ "stophy",
14
+ "youtube",
15
+ "transcript",
16
+ "sdk",
17
+ "ai-agents"
18
+ ],
19
+ "main": "./dist/index.cjs",
20
+ "module": "./dist/index.js",
21
+ "types": "./dist/index.d.ts",
22
+ "exports": {
23
+ ".": {
24
+ "types": "./dist/index.d.ts",
25
+ "import": "./dist/index.js",
26
+ "require": "./dist/index.cjs"
27
+ }
28
+ },
29
+ "files": [
30
+ "dist"
31
+ ],
32
+ "scripts": {
33
+ "generate": "openapi-ts",
34
+ "build": "tsup",
35
+ "test": "bun test ../../test/typescript",
36
+ "check-types": "tsc --noEmit",
37
+ "prepublishOnly": "npm run generate && npm run build"
38
+ },
39
+ "devDependencies": {
40
+ "@hey-api/openapi-ts": "^0.64.0",
41
+ "@types/bun": "^1.1.14",
42
+ "tsup": "^8.3.5",
43
+ "typescript": "^5.7.0"
44
+ },
45
+ "dependencies": {
46
+ "@hey-api/client-fetch": "^0.10.2"
47
+ }
48
+ }