@fotovid/sdk 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Fotovid
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,72 @@
1
+ # @fotovid/sdk
2
+
3
+ Thin, typed TypeScript/Node client for the [Fotovid](https://fotovid.co) media API. POST a URL, await the finished file — no ffmpeg binary in your bundle.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install @fotovid/sdk
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ```ts
14
+ import Fotovid from "@fotovid/sdk";
15
+
16
+ const fotovid = new Fotovid({ apiKey: process.env.FOTOVID_API_KEY });
17
+
18
+ const res = await fotovid.video.watermark({
19
+ source_url: "https://cdn.example.com/clip.mp4",
20
+ watermark_type: "image",
21
+ watermark_image_url: "https://cdn.example.com/logo.png",
22
+ position: "bottom-right",
23
+ opacity: 0.8,
24
+ });
25
+
26
+ console.log(res.url); // URL to the finished file — hosted, time-limited, opaque; see expires_at, store your own copy
27
+ ```
28
+
29
+ ## Operations
30
+
31
+ | Method | Endpoint |
32
+ | --- | --- |
33
+ | `fotovid.video.watermark(input)` | `POST /v1/video/watermark` |
34
+ | `fotovid.image.watermark(input)` | `POST /v1/image/watermark` |
35
+ | `fotovid.video.trim(input)` | `POST /v1/video/trim` |
36
+ | `fotovid.video.extractAudio(input)` | `POST /v1/video/extract-audio` |
37
+ | `fotovid.audio.trim(input)` | `POST /v1/audio/trim` |
38
+ | `fotovid.video.thumbnail(input)` | `POST /v1/video/extract-cover` |
39
+ | `fotovid.video.probe(input)` | `POST /v1/video/probe` |
40
+
41
+ Parameter names match the API 1:1 (`source_url`, `watermark_image_url`, …). Every
42
+ media operation returns `{ id, type, url, expires_at, duration? }`; `probe`
43
+ returns video metadata.
44
+
45
+ ## Config
46
+
47
+ ```ts
48
+ new Fotovid({
49
+ apiKey: "p6_<key_id>:<secret>", // or set FOTOVID_API_KEY
50
+ baseUrl: "https://api.fotovid.co", // optional
51
+ fetch: customFetch, // optional, defaults to global fetch (Node 18+)
52
+ });
53
+ ```
54
+
55
+ ## Idempotency
56
+
57
+ Every operation is billed, so the API requires an `Idempotency-Key` header. The
58
+ SDK sends a fresh key per call automatically — you don't have to do anything. To
59
+ safely retry a request without being charged twice, pass the same key both times:
60
+
61
+ ```ts
62
+ const idempotencyKey = crypto.randomUUID();
63
+ const opts = { idempotencyKey };
64
+
65
+ await fotovid.video.watermark(input, opts);
66
+ // A retry with the same key replays the original result instead of re-charging.
67
+ await fotovid.video.watermark(input, opts);
68
+ ```
69
+
70
+ ## License
71
+
72
+ MIT
package/dist/index.cjs ADDED
@@ -0,0 +1,121 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ Fotovid: () => Fotovid,
24
+ FotovidError: () => FotovidError,
25
+ default: () => Fotovid
26
+ });
27
+ module.exports = __toCommonJS(index_exports);
28
+
29
+ // src/error.ts
30
+ function isRecord(value) {
31
+ return typeof value === "object" && value !== null;
32
+ }
33
+ var FotovidError = class extends Error {
34
+ /** HTTP status code of the failed response. */
35
+ status;
36
+ /** Parsed error body, when the response carried one. */
37
+ detail;
38
+ /** Seconds to wait before retrying, from the `Retry-After` header (e.g. 429/503). */
39
+ retryAfter;
40
+ constructor(status, detail, retryAfter) {
41
+ let message;
42
+ if (isRecord(detail)) {
43
+ if (typeof detail.detail === "string") {
44
+ message = detail.detail;
45
+ } else if (typeof detail.message === "string") {
46
+ message = detail.message;
47
+ }
48
+ }
49
+ super(message ?? `Fotovid API request failed with status ${status}`);
50
+ this.name = "FotovidError";
51
+ this.status = status;
52
+ this.detail = detail;
53
+ this.retryAfter = retryAfter;
54
+ }
55
+ };
56
+
57
+ // src/client.ts
58
+ var DEFAULT_BASE_URL = "https://api.fotovid.co";
59
+ function resolveApiKey(explicit) {
60
+ const key = explicit ?? (typeof process !== "undefined" ? process.env?.FOTOVID_API_KEY : void 0);
61
+ if (!key) {
62
+ throw new Error(
63
+ "Fotovid: missing API key. Pass { apiKey } or set FOTOVID_API_KEY."
64
+ );
65
+ }
66
+ return key;
67
+ }
68
+ var Fotovid = class {
69
+ #apiKey;
70
+ #baseUrl;
71
+ #fetch;
72
+ constructor(options = {}) {
73
+ this.#apiKey = resolveApiKey(options.apiKey);
74
+ this.#baseUrl = options.baseUrl ?? DEFAULT_BASE_URL;
75
+ this.#fetch = options.fetch ?? globalThis.fetch;
76
+ }
77
+ async #post(path, input, options) {
78
+ const { source_url, ...params } = input;
79
+ const response = await this.#fetch(new URL(path, this.#baseUrl), {
80
+ method: "POST",
81
+ headers: {
82
+ "content-type": "application/json",
83
+ authorization: `Bearer ${this.#apiKey}`,
84
+ // Billed endpoints require an idempotency key; default to a fresh
85
+ // UUID per call, overridable to make a retry replay (not re-charge).
86
+ "idempotency-key": options?.idempotencyKey ?? globalThis.crypto.randomUUID()
87
+ },
88
+ body: JSON.stringify({ source_url, params })
89
+ });
90
+ if (!response.ok) {
91
+ let detail;
92
+ try {
93
+ detail = await response.json();
94
+ } catch {
95
+ }
96
+ const ra = response.headers.get("retry-after");
97
+ const retryAfter = ra ? Number(ra) : void 0;
98
+ throw new FotovidError(response.status, detail, retryAfter);
99
+ }
100
+ return await response.json();
101
+ }
102
+ video = {
103
+ watermark: (input, options) => this.#post("/v1/video/watermark", input, options),
104
+ trim: (input, options) => this.#post("/v1/video/trim", input, options),
105
+ extractAudio: (input, options) => this.#post("/v1/video/extract-audio", input, options),
106
+ thumbnail: (input, options) => this.#post("/v1/video/extract-cover", input, options),
107
+ probe: (input, options) => this.#post("/v1/video/probe", input, options)
108
+ };
109
+ image = {
110
+ watermark: (input, options) => this.#post("/v1/image/watermark", input, options)
111
+ };
112
+ audio = {
113
+ trim: (input, options) => this.#post("/v1/audio/trim", input, options)
114
+ };
115
+ };
116
+ // Annotate the CommonJS export names for ESM import in node:
117
+ 0 && (module.exports = {
118
+ Fotovid,
119
+ FotovidError
120
+ });
121
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/error.ts","../src/client.ts"],"sourcesContent":["export { Fotovid, Fotovid as default } from \"./client.js\";\nexport { FotovidError } from \"./error.js\";\nexport type {\n\tExtractAudioInput,\n\tFotovidOptions,\n\tImageFormat,\n\tImageWatermarkInput,\n\tMediaResult,\n\tProbeInput,\n\tProbeResult,\n\tRequestOptions,\n\tThumbnailInput,\n\tTrimAudioInput,\n\tTrimInput,\n\tVideoWatermarkInput,\n\tWatermarkPosition,\n\tWatermarkType,\n\tX264Preset,\n} from \"./types.js\";\n","function isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null;\n}\n\n/** Thrown when the Fotovid API returns a non-2xx response. */\nexport class FotovidError extends Error {\n\t/** HTTP status code of the failed response. */\n\treadonly status: number;\n\t/** Parsed error body, when the response carried one. */\n\treadonly detail: unknown;\n\t/** Seconds to wait before retrying, from the `Retry-After` header (e.g. 429/503). */\n\treadonly retryAfter?: number;\n\n\tconstructor(status: number, detail: unknown, retryAfter?: number) {\n\t\tlet message: string | undefined;\n\t\tif (isRecord(detail)) {\n\t\t\tif (typeof detail.detail === \"string\") {\n\t\t\t\tmessage = detail.detail;\n\t\t\t} else if (typeof detail.message === \"string\") {\n\t\t\t\tmessage = detail.message;\n\t\t\t}\n\t\t}\n\t\tsuper(message ?? `Fotovid API request failed with status ${status}`);\n\t\tthis.name = \"FotovidError\";\n\t\tthis.status = status;\n\t\tthis.detail = detail;\n\t\tthis.retryAfter = retryAfter;\n\t}\n}\n","import { FotovidError } from \"./error.js\";\nimport type {\n\tExtractAudioInput,\n\tFotovidOptions,\n\tImageWatermarkInput,\n\tMediaResult,\n\tProbeInput,\n\tProbeResult,\n\tRequestOptions,\n\tThumbnailInput,\n\tTrimAudioInput,\n\tTrimInput,\n\tVideoWatermarkInput,\n} from \"./types.js\";\n\nconst DEFAULT_BASE_URL = \"https://api.fotovid.co\";\n\nfunction resolveApiKey(explicit: string | undefined): string {\n\tconst key =\n\t\texplicit ??\n\t\t(typeof process !== \"undefined\" ? process.env?.FOTOVID_API_KEY : undefined);\n\tif (!key) {\n\t\tthrow new Error(\n\t\t\t\"Fotovid: missing API key. Pass { apiKey } or set FOTOVID_API_KEY.\",\n\t\t);\n\t}\n\treturn key;\n}\n\n/**\n * Typed client for the Fotovid media API. Methods mirror the REST resources\n * (`client.video.*`, `client.image.*`, `client.audio.*`); parameter names\n * match the API 1:1 (`source_url`, `watermark_image_url`, …).\n */\nexport class Fotovid {\n\treadonly #apiKey: string;\n\treadonly #baseUrl: string;\n\treadonly #fetch: typeof globalThis.fetch;\n\n\tconstructor(options: FotovidOptions = {}) {\n\t\tthis.#apiKey = resolveApiKey(options.apiKey);\n\t\tthis.#baseUrl = options.baseUrl ?? DEFAULT_BASE_URL;\n\t\tthis.#fetch = options.fetch ?? globalThis.fetch;\n\t}\n\n\tasync #post<T>(\n\t\tpath: string,\n\t\tinput: { source_url: string },\n\t\toptions?: RequestOptions,\n\t): Promise<T> {\n\t\tconst { source_url, ...params } = input;\n\t\tconst response = await this.#fetch(new URL(path, this.#baseUrl), {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: {\n\t\t\t\t\"content-type\": \"application/json\",\n\t\t\t\tauthorization: `Bearer ${this.#apiKey}`,\n\t\t\t\t// Billed endpoints require an idempotency key; default to a fresh\n\t\t\t\t// UUID per call, overridable to make a retry replay (not re-charge).\n\t\t\t\t\"idempotency-key\":\n\t\t\t\t\toptions?.idempotencyKey ?? globalThis.crypto.randomUUID(),\n\t\t\t},\n\t\t\tbody: JSON.stringify({ source_url, params }),\n\t\t});\n\t\tif (!response.ok) {\n\t\t\tlet detail: unknown;\n\t\t\ttry {\n\t\t\t\tdetail = await response.json();\n\t\t\t} catch {\n\t\t\t\t// non-JSON error body — leave detail undefined\n\t\t\t}\n\t\t\tconst ra = response.headers.get(\"retry-after\");\n\t\t\tconst retryAfter = ra ? Number(ra) : undefined;\n\t\t\tthrow new FotovidError(response.status, detail, retryAfter);\n\t\t}\n\t\treturn (await response.json()) as T;\n\t}\n\n\treadonly video = {\n\t\twatermark: (\n\t\t\tinput: VideoWatermarkInput,\n\t\t\toptions?: RequestOptions,\n\t\t): Promise<MediaResult> =>\n\t\t\tthis.#post<MediaResult>(\"/v1/video/watermark\", input, options),\n\t\ttrim: (input: TrimInput, options?: RequestOptions): Promise<MediaResult> =>\n\t\t\tthis.#post<MediaResult>(\"/v1/video/trim\", input, options),\n\t\textractAudio: (\n\t\t\tinput: ExtractAudioInput,\n\t\t\toptions?: RequestOptions,\n\t\t): Promise<MediaResult> =>\n\t\t\tthis.#post<MediaResult>(\"/v1/video/extract-audio\", input, options),\n\t\tthumbnail: (\n\t\t\tinput: ThumbnailInput,\n\t\t\toptions?: RequestOptions,\n\t\t): Promise<MediaResult> =>\n\t\t\tthis.#post<MediaResult>(\"/v1/video/extract-cover\", input, options),\n\t\tprobe: (\n\t\t\tinput: ProbeInput,\n\t\t\toptions?: RequestOptions,\n\t\t): Promise<ProbeResult> =>\n\t\t\tthis.#post<ProbeResult>(\"/v1/video/probe\", input, options),\n\t};\n\n\treadonly image = {\n\t\twatermark: (\n\t\t\tinput: ImageWatermarkInput,\n\t\t\toptions?: RequestOptions,\n\t\t): Promise<MediaResult> =>\n\t\t\tthis.#post<MediaResult>(\"/v1/image/watermark\", input, options),\n\t};\n\n\treadonly audio = {\n\t\ttrim: (\n\t\t\tinput: TrimAudioInput,\n\t\t\toptions?: RequestOptions,\n\t\t): Promise<MediaResult> =>\n\t\t\tthis.#post<MediaResult>(\"/v1/audio/trim\", input, options),\n\t};\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,SAAS,SAAS,OAAkD;AACnE,SAAO,OAAO,UAAU,YAAY,UAAU;AAC/C;AAGO,IAAM,eAAN,cAA2B,MAAM;AAAA;AAAA,EAE9B;AAAA;AAAA,EAEA;AAAA;AAAA,EAEA;AAAA,EAET,YAAY,QAAgB,QAAiB,YAAqB;AACjE,QAAI;AACJ,QAAI,SAAS,MAAM,GAAG;AACrB,UAAI,OAAO,OAAO,WAAW,UAAU;AACtC,kBAAU,OAAO;AAAA,MAClB,WAAW,OAAO,OAAO,YAAY,UAAU;AAC9C,kBAAU,OAAO;AAAA,MAClB;AAAA,IACD;AACA,UAAM,WAAW,0CAA0C,MAAM,EAAE;AACnE,SAAK,OAAO;AACZ,SAAK,SAAS;AACd,SAAK,SAAS;AACd,SAAK,aAAa;AAAA,EACnB;AACD;;;ACbA,IAAM,mBAAmB;AAEzB,SAAS,cAAc,UAAsC;AAC5D,QAAM,MACL,aACC,OAAO,YAAY,cAAc,QAAQ,KAAK,kBAAkB;AAClE,MAAI,CAAC,KAAK;AACT,UAAM,IAAI;AAAA,MACT;AAAA,IACD;AAAA,EACD;AACA,SAAO;AACR;AAOO,IAAM,UAAN,MAAc;AAAA,EACX;AAAA,EACA;AAAA,EACA;AAAA,EAET,YAAY,UAA0B,CAAC,GAAG;AACzC,SAAK,UAAU,cAAc,QAAQ,MAAM;AAC3C,SAAK,WAAW,QAAQ,WAAW;AACnC,SAAK,SAAS,QAAQ,SAAS,WAAW;AAAA,EAC3C;AAAA,EAEA,MAAM,MACL,MACA,OACA,SACa;AACb,UAAM,EAAE,YAAY,GAAG,OAAO,IAAI;AAClC,UAAM,WAAW,MAAM,KAAK,OAAO,IAAI,IAAI,MAAM,KAAK,QAAQ,GAAG;AAAA,MAChE,QAAQ;AAAA,MACR,SAAS;AAAA,QACR,gBAAgB;AAAA,QAChB,eAAe,UAAU,KAAK,OAAO;AAAA;AAAA;AAAA,QAGrC,mBACC,SAAS,kBAAkB,WAAW,OAAO,WAAW;AAAA,MAC1D;AAAA,MACA,MAAM,KAAK,UAAU,EAAE,YAAY,OAAO,CAAC;AAAA,IAC5C,CAAC;AACD,QAAI,CAAC,SAAS,IAAI;AACjB,UAAI;AACJ,UAAI;AACH,iBAAS,MAAM,SAAS,KAAK;AAAA,MAC9B,QAAQ;AAAA,MAER;AACA,YAAM,KAAK,SAAS,QAAQ,IAAI,aAAa;AAC7C,YAAM,aAAa,KAAK,OAAO,EAAE,IAAI;AACrC,YAAM,IAAI,aAAa,SAAS,QAAQ,QAAQ,UAAU;AAAA,IAC3D;AACA,WAAQ,MAAM,SAAS,KAAK;AAAA,EAC7B;AAAA,EAES,QAAQ;AAAA,IAChB,WAAW,CACV,OACA,YAEA,KAAK,MAAmB,uBAAuB,OAAO,OAAO;AAAA,IAC9D,MAAM,CAAC,OAAkB,YACxB,KAAK,MAAmB,kBAAkB,OAAO,OAAO;AAAA,IACzD,cAAc,CACb,OACA,YAEA,KAAK,MAAmB,2BAA2B,OAAO,OAAO;AAAA,IAClE,WAAW,CACV,OACA,YAEA,KAAK,MAAmB,2BAA2B,OAAO,OAAO;AAAA,IAClE,OAAO,CACN,OACA,YAEA,KAAK,MAAmB,mBAAmB,OAAO,OAAO;AAAA,EAC3D;AAAA,EAES,QAAQ;AAAA,IAChB,WAAW,CACV,OACA,YAEA,KAAK,MAAmB,uBAAuB,OAAO,OAAO;AAAA,EAC/D;AAAA,EAES,QAAQ;AAAA,IAChB,MAAM,CACL,OACA,YAEA,KAAK,MAAmB,kBAAkB,OAAO,OAAO;AAAA,EAC1D;AACD;","names":[]}
@@ -0,0 +1,137 @@
1
+ /** Anchor position for a watermark overlay. */
2
+ type WatermarkPosition = "top-left" | "top-right" | "bottom-left" | "bottom-right" | "center";
3
+ /** Output image format for image-producing operations. */
4
+ type ImageFormat = "webp" | "jpeg" | "jpg" | "png";
5
+ /** Watermark variant. */
6
+ type WatermarkType = "text" | "image" | "combo";
7
+ /** x264 encode preset (video watermark only). */
8
+ type X264Preset = "ultrafast" | "superfast" | "veryfast" | "faster" | "fast" | "medium" | "slow" | "slower" | "veryslow" | "placebo";
9
+ /** Every request carries the source media URL. */
10
+ interface SourceInput {
11
+ /** Public http(s) URL of the source media. */
12
+ source_url: string;
13
+ }
14
+ interface VideoWatermarkInput extends SourceInput {
15
+ watermark_type?: WatermarkType;
16
+ /** Overlay text, ≤1000 chars (required for text/combo). */
17
+ text?: string;
18
+ /** Text size in px, 8–200 (text/combo). */
19
+ font_size?: number;
20
+ /** Text color: a name (letters only) or #RRGGBB[AA] (text/combo). */
21
+ font_color?: string;
22
+ /** Logo image URL (required for image/combo). */
23
+ watermark_image_url?: string;
24
+ /** Logo width as a fraction of source width, >0–1 (image/combo). */
25
+ scale?: number;
26
+ /** Watermark opacity, >0–1. */
27
+ opacity?: number;
28
+ position?: WatermarkPosition;
29
+ /** Edge padding in px, 0–500. */
30
+ padding?: number;
31
+ output_format?: ImageFormat;
32
+ /** Lossy quality 1–100 (png ignores it). */
33
+ quality?: number;
34
+ /** x264 encode preset — video only. */
35
+ preset?: X264Preset;
36
+ }
37
+ type ImageWatermarkInput = Omit<VideoWatermarkInput, "preset">;
38
+ interface TrimInput extends SourceInput {
39
+ /** Window start in seconds (inclusive). Required by the API. */
40
+ start: number;
41
+ /** Window end in seconds (exclusive); must be greater than start. Required by the API. */
42
+ end: number;
43
+ }
44
+ type ExtractAudioInput = SourceInput;
45
+ interface TrimAudioInput extends SourceInput {
46
+ /** Window start in seconds (inclusive). Required by the API. */
47
+ start: number;
48
+ /** Window end in seconds (exclusive); must be greater than start. Required by the API. */
49
+ end: number;
50
+ }
51
+ interface ThumbnailInput extends SourceInput {
52
+ /** Frame timestamp in seconds (default ~1s). */
53
+ at?: number;
54
+ output_format?: ImageFormat;
55
+ /** Lossy quality 1–100 (png ignores it). */
56
+ quality?: number;
57
+ }
58
+ type ProbeInput = SourceInput;
59
+ /** Result of a media-producing operation. */
60
+ interface MediaResult {
61
+ /** Result record id (echoed on idempotent replay). */
62
+ id: string;
63
+ /** Task type that produced this result. */
64
+ type: string;
65
+ /** Download URL — hosted, time-limited, opaque; don't parse it, see `expires_at`. Store your own copy. */
66
+ url: string;
67
+ /** RFC 3339 time the download URL expires. */
68
+ expires_at: string;
69
+ /** Result media duration in seconds, when known. */
70
+ duration?: number;
71
+ }
72
+ /** Result of a probe — metadata only, no artifact. */
73
+ interface ProbeResult {
74
+ id: string;
75
+ type: string;
76
+ width: number;
77
+ height: number;
78
+ durationSec: number;
79
+ /** Frame rate as ffprobe reports r_frame_rate (e.g. "30/1"). */
80
+ fps: string;
81
+ /** First video stream codec (e.g. "h264"). */
82
+ codec: string;
83
+ hasAlpha: boolean;
84
+ }
85
+ interface FotovidOptions {
86
+ /** API key `p6_<key_id>:<secret>`. Falls back to `FOTOVID_API_KEY`. */
87
+ apiKey?: string;
88
+ /** API base URL. Defaults to https://api.fotovid.co */
89
+ baseUrl?: string;
90
+ /** Custom fetch implementation (defaults to the global fetch). */
91
+ fetch?: typeof globalThis.fetch;
92
+ }
93
+ /** Per-request options. */
94
+ interface RequestOptions {
95
+ /**
96
+ * Idempotency key (1–255 printable ASCII). Defaults to a fresh UUID per
97
+ * call. Reuse the same key with the same body to safely retry a billed
98
+ * request — the API replays the original result instead of charging again.
99
+ */
100
+ idempotencyKey?: string;
101
+ }
102
+
103
+ /**
104
+ * Typed client for the Fotovid media API. Methods mirror the REST resources
105
+ * (`client.video.*`, `client.image.*`, `client.audio.*`); parameter names
106
+ * match the API 1:1 (`source_url`, `watermark_image_url`, …).
107
+ */
108
+ declare class Fotovid {
109
+ #private;
110
+ constructor(options?: FotovidOptions);
111
+ readonly video: {
112
+ watermark: (input: VideoWatermarkInput, options?: RequestOptions) => Promise<MediaResult>;
113
+ trim: (input: TrimInput, options?: RequestOptions) => Promise<MediaResult>;
114
+ extractAudio: (input: ExtractAudioInput, options?: RequestOptions) => Promise<MediaResult>;
115
+ thumbnail: (input: ThumbnailInput, options?: RequestOptions) => Promise<MediaResult>;
116
+ probe: (input: ProbeInput, options?: RequestOptions) => Promise<ProbeResult>;
117
+ };
118
+ readonly image: {
119
+ watermark: (input: ImageWatermarkInput, options?: RequestOptions) => Promise<MediaResult>;
120
+ };
121
+ readonly audio: {
122
+ trim: (input: TrimAudioInput, options?: RequestOptions) => Promise<MediaResult>;
123
+ };
124
+ }
125
+
126
+ /** Thrown when the Fotovid API returns a non-2xx response. */
127
+ declare class FotovidError extends Error {
128
+ /** HTTP status code of the failed response. */
129
+ readonly status: number;
130
+ /** Parsed error body, when the response carried one. */
131
+ readonly detail: unknown;
132
+ /** Seconds to wait before retrying, from the `Retry-After` header (e.g. 429/503). */
133
+ readonly retryAfter?: number;
134
+ constructor(status: number, detail: unknown, retryAfter?: number);
135
+ }
136
+
137
+ export { type ExtractAudioInput, Fotovid, FotovidError, type FotovidOptions, type ImageFormat, type ImageWatermarkInput, type MediaResult, type ProbeInput, type ProbeResult, type RequestOptions, type ThumbnailInput, type TrimAudioInput, type TrimInput, type VideoWatermarkInput, type WatermarkPosition, type WatermarkType, type X264Preset, Fotovid as default };
@@ -0,0 +1,137 @@
1
+ /** Anchor position for a watermark overlay. */
2
+ type WatermarkPosition = "top-left" | "top-right" | "bottom-left" | "bottom-right" | "center";
3
+ /** Output image format for image-producing operations. */
4
+ type ImageFormat = "webp" | "jpeg" | "jpg" | "png";
5
+ /** Watermark variant. */
6
+ type WatermarkType = "text" | "image" | "combo";
7
+ /** x264 encode preset (video watermark only). */
8
+ type X264Preset = "ultrafast" | "superfast" | "veryfast" | "faster" | "fast" | "medium" | "slow" | "slower" | "veryslow" | "placebo";
9
+ /** Every request carries the source media URL. */
10
+ interface SourceInput {
11
+ /** Public http(s) URL of the source media. */
12
+ source_url: string;
13
+ }
14
+ interface VideoWatermarkInput extends SourceInput {
15
+ watermark_type?: WatermarkType;
16
+ /** Overlay text, ≤1000 chars (required for text/combo). */
17
+ text?: string;
18
+ /** Text size in px, 8–200 (text/combo). */
19
+ font_size?: number;
20
+ /** Text color: a name (letters only) or #RRGGBB[AA] (text/combo). */
21
+ font_color?: string;
22
+ /** Logo image URL (required for image/combo). */
23
+ watermark_image_url?: string;
24
+ /** Logo width as a fraction of source width, >0–1 (image/combo). */
25
+ scale?: number;
26
+ /** Watermark opacity, >0–1. */
27
+ opacity?: number;
28
+ position?: WatermarkPosition;
29
+ /** Edge padding in px, 0–500. */
30
+ padding?: number;
31
+ output_format?: ImageFormat;
32
+ /** Lossy quality 1–100 (png ignores it). */
33
+ quality?: number;
34
+ /** x264 encode preset — video only. */
35
+ preset?: X264Preset;
36
+ }
37
+ type ImageWatermarkInput = Omit<VideoWatermarkInput, "preset">;
38
+ interface TrimInput extends SourceInput {
39
+ /** Window start in seconds (inclusive). Required by the API. */
40
+ start: number;
41
+ /** Window end in seconds (exclusive); must be greater than start. Required by the API. */
42
+ end: number;
43
+ }
44
+ type ExtractAudioInput = SourceInput;
45
+ interface TrimAudioInput extends SourceInput {
46
+ /** Window start in seconds (inclusive). Required by the API. */
47
+ start: number;
48
+ /** Window end in seconds (exclusive); must be greater than start. Required by the API. */
49
+ end: number;
50
+ }
51
+ interface ThumbnailInput extends SourceInput {
52
+ /** Frame timestamp in seconds (default ~1s). */
53
+ at?: number;
54
+ output_format?: ImageFormat;
55
+ /** Lossy quality 1–100 (png ignores it). */
56
+ quality?: number;
57
+ }
58
+ type ProbeInput = SourceInput;
59
+ /** Result of a media-producing operation. */
60
+ interface MediaResult {
61
+ /** Result record id (echoed on idempotent replay). */
62
+ id: string;
63
+ /** Task type that produced this result. */
64
+ type: string;
65
+ /** Download URL — hosted, time-limited, opaque; don't parse it, see `expires_at`. Store your own copy. */
66
+ url: string;
67
+ /** RFC 3339 time the download URL expires. */
68
+ expires_at: string;
69
+ /** Result media duration in seconds, when known. */
70
+ duration?: number;
71
+ }
72
+ /** Result of a probe — metadata only, no artifact. */
73
+ interface ProbeResult {
74
+ id: string;
75
+ type: string;
76
+ width: number;
77
+ height: number;
78
+ durationSec: number;
79
+ /** Frame rate as ffprobe reports r_frame_rate (e.g. "30/1"). */
80
+ fps: string;
81
+ /** First video stream codec (e.g. "h264"). */
82
+ codec: string;
83
+ hasAlpha: boolean;
84
+ }
85
+ interface FotovidOptions {
86
+ /** API key `p6_<key_id>:<secret>`. Falls back to `FOTOVID_API_KEY`. */
87
+ apiKey?: string;
88
+ /** API base URL. Defaults to https://api.fotovid.co */
89
+ baseUrl?: string;
90
+ /** Custom fetch implementation (defaults to the global fetch). */
91
+ fetch?: typeof globalThis.fetch;
92
+ }
93
+ /** Per-request options. */
94
+ interface RequestOptions {
95
+ /**
96
+ * Idempotency key (1–255 printable ASCII). Defaults to a fresh UUID per
97
+ * call. Reuse the same key with the same body to safely retry a billed
98
+ * request — the API replays the original result instead of charging again.
99
+ */
100
+ idempotencyKey?: string;
101
+ }
102
+
103
+ /**
104
+ * Typed client for the Fotovid media API. Methods mirror the REST resources
105
+ * (`client.video.*`, `client.image.*`, `client.audio.*`); parameter names
106
+ * match the API 1:1 (`source_url`, `watermark_image_url`, …).
107
+ */
108
+ declare class Fotovid {
109
+ #private;
110
+ constructor(options?: FotovidOptions);
111
+ readonly video: {
112
+ watermark: (input: VideoWatermarkInput, options?: RequestOptions) => Promise<MediaResult>;
113
+ trim: (input: TrimInput, options?: RequestOptions) => Promise<MediaResult>;
114
+ extractAudio: (input: ExtractAudioInput, options?: RequestOptions) => Promise<MediaResult>;
115
+ thumbnail: (input: ThumbnailInput, options?: RequestOptions) => Promise<MediaResult>;
116
+ probe: (input: ProbeInput, options?: RequestOptions) => Promise<ProbeResult>;
117
+ };
118
+ readonly image: {
119
+ watermark: (input: ImageWatermarkInput, options?: RequestOptions) => Promise<MediaResult>;
120
+ };
121
+ readonly audio: {
122
+ trim: (input: TrimAudioInput, options?: RequestOptions) => Promise<MediaResult>;
123
+ };
124
+ }
125
+
126
+ /** Thrown when the Fotovid API returns a non-2xx response. */
127
+ declare class FotovidError extends Error {
128
+ /** HTTP status code of the failed response. */
129
+ readonly status: number;
130
+ /** Parsed error body, when the response carried one. */
131
+ readonly detail: unknown;
132
+ /** Seconds to wait before retrying, from the `Retry-After` header (e.g. 429/503). */
133
+ readonly retryAfter?: number;
134
+ constructor(status: number, detail: unknown, retryAfter?: number);
135
+ }
136
+
137
+ export { type ExtractAudioInput, Fotovid, FotovidError, type FotovidOptions, type ImageFormat, type ImageWatermarkInput, type MediaResult, type ProbeInput, type ProbeResult, type RequestOptions, type ThumbnailInput, type TrimAudioInput, type TrimInput, type VideoWatermarkInput, type WatermarkPosition, type WatermarkType, type X264Preset, Fotovid as default };
package/dist/index.js ADDED
@@ -0,0 +1,93 @@
1
+ // src/error.ts
2
+ function isRecord(value) {
3
+ return typeof value === "object" && value !== null;
4
+ }
5
+ var FotovidError = class extends Error {
6
+ /** HTTP status code of the failed response. */
7
+ status;
8
+ /** Parsed error body, when the response carried one. */
9
+ detail;
10
+ /** Seconds to wait before retrying, from the `Retry-After` header (e.g. 429/503). */
11
+ retryAfter;
12
+ constructor(status, detail, retryAfter) {
13
+ let message;
14
+ if (isRecord(detail)) {
15
+ if (typeof detail.detail === "string") {
16
+ message = detail.detail;
17
+ } else if (typeof detail.message === "string") {
18
+ message = detail.message;
19
+ }
20
+ }
21
+ super(message ?? `Fotovid API request failed with status ${status}`);
22
+ this.name = "FotovidError";
23
+ this.status = status;
24
+ this.detail = detail;
25
+ this.retryAfter = retryAfter;
26
+ }
27
+ };
28
+
29
+ // src/client.ts
30
+ var DEFAULT_BASE_URL = "https://api.fotovid.co";
31
+ function resolveApiKey(explicit) {
32
+ const key = explicit ?? (typeof process !== "undefined" ? process.env?.FOTOVID_API_KEY : void 0);
33
+ if (!key) {
34
+ throw new Error(
35
+ "Fotovid: missing API key. Pass { apiKey } or set FOTOVID_API_KEY."
36
+ );
37
+ }
38
+ return key;
39
+ }
40
+ var Fotovid = class {
41
+ #apiKey;
42
+ #baseUrl;
43
+ #fetch;
44
+ constructor(options = {}) {
45
+ this.#apiKey = resolveApiKey(options.apiKey);
46
+ this.#baseUrl = options.baseUrl ?? DEFAULT_BASE_URL;
47
+ this.#fetch = options.fetch ?? globalThis.fetch;
48
+ }
49
+ async #post(path, input, options) {
50
+ const { source_url, ...params } = input;
51
+ const response = await this.#fetch(new URL(path, this.#baseUrl), {
52
+ method: "POST",
53
+ headers: {
54
+ "content-type": "application/json",
55
+ authorization: `Bearer ${this.#apiKey}`,
56
+ // Billed endpoints require an idempotency key; default to a fresh
57
+ // UUID per call, overridable to make a retry replay (not re-charge).
58
+ "idempotency-key": options?.idempotencyKey ?? globalThis.crypto.randomUUID()
59
+ },
60
+ body: JSON.stringify({ source_url, params })
61
+ });
62
+ if (!response.ok) {
63
+ let detail;
64
+ try {
65
+ detail = await response.json();
66
+ } catch {
67
+ }
68
+ const ra = response.headers.get("retry-after");
69
+ const retryAfter = ra ? Number(ra) : void 0;
70
+ throw new FotovidError(response.status, detail, retryAfter);
71
+ }
72
+ return await response.json();
73
+ }
74
+ video = {
75
+ watermark: (input, options) => this.#post("/v1/video/watermark", input, options),
76
+ trim: (input, options) => this.#post("/v1/video/trim", input, options),
77
+ extractAudio: (input, options) => this.#post("/v1/video/extract-audio", input, options),
78
+ thumbnail: (input, options) => this.#post("/v1/video/extract-cover", input, options),
79
+ probe: (input, options) => this.#post("/v1/video/probe", input, options)
80
+ };
81
+ image = {
82
+ watermark: (input, options) => this.#post("/v1/image/watermark", input, options)
83
+ };
84
+ audio = {
85
+ trim: (input, options) => this.#post("/v1/audio/trim", input, options)
86
+ };
87
+ };
88
+ export {
89
+ Fotovid,
90
+ FotovidError,
91
+ Fotovid as default
92
+ };
93
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/error.ts","../src/client.ts"],"sourcesContent":["function isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null;\n}\n\n/** Thrown when the Fotovid API returns a non-2xx response. */\nexport class FotovidError extends Error {\n\t/** HTTP status code of the failed response. */\n\treadonly status: number;\n\t/** Parsed error body, when the response carried one. */\n\treadonly detail: unknown;\n\t/** Seconds to wait before retrying, from the `Retry-After` header (e.g. 429/503). */\n\treadonly retryAfter?: number;\n\n\tconstructor(status: number, detail: unknown, retryAfter?: number) {\n\t\tlet message: string | undefined;\n\t\tif (isRecord(detail)) {\n\t\t\tif (typeof detail.detail === \"string\") {\n\t\t\t\tmessage = detail.detail;\n\t\t\t} else if (typeof detail.message === \"string\") {\n\t\t\t\tmessage = detail.message;\n\t\t\t}\n\t\t}\n\t\tsuper(message ?? `Fotovid API request failed with status ${status}`);\n\t\tthis.name = \"FotovidError\";\n\t\tthis.status = status;\n\t\tthis.detail = detail;\n\t\tthis.retryAfter = retryAfter;\n\t}\n}\n","import { FotovidError } from \"./error.js\";\nimport type {\n\tExtractAudioInput,\n\tFotovidOptions,\n\tImageWatermarkInput,\n\tMediaResult,\n\tProbeInput,\n\tProbeResult,\n\tRequestOptions,\n\tThumbnailInput,\n\tTrimAudioInput,\n\tTrimInput,\n\tVideoWatermarkInput,\n} from \"./types.js\";\n\nconst DEFAULT_BASE_URL = \"https://api.fotovid.co\";\n\nfunction resolveApiKey(explicit: string | undefined): string {\n\tconst key =\n\t\texplicit ??\n\t\t(typeof process !== \"undefined\" ? process.env?.FOTOVID_API_KEY : undefined);\n\tif (!key) {\n\t\tthrow new Error(\n\t\t\t\"Fotovid: missing API key. Pass { apiKey } or set FOTOVID_API_KEY.\",\n\t\t);\n\t}\n\treturn key;\n}\n\n/**\n * Typed client for the Fotovid media API. Methods mirror the REST resources\n * (`client.video.*`, `client.image.*`, `client.audio.*`); parameter names\n * match the API 1:1 (`source_url`, `watermark_image_url`, …).\n */\nexport class Fotovid {\n\treadonly #apiKey: string;\n\treadonly #baseUrl: string;\n\treadonly #fetch: typeof globalThis.fetch;\n\n\tconstructor(options: FotovidOptions = {}) {\n\t\tthis.#apiKey = resolveApiKey(options.apiKey);\n\t\tthis.#baseUrl = options.baseUrl ?? DEFAULT_BASE_URL;\n\t\tthis.#fetch = options.fetch ?? globalThis.fetch;\n\t}\n\n\tasync #post<T>(\n\t\tpath: string,\n\t\tinput: { source_url: string },\n\t\toptions?: RequestOptions,\n\t): Promise<T> {\n\t\tconst { source_url, ...params } = input;\n\t\tconst response = await this.#fetch(new URL(path, this.#baseUrl), {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: {\n\t\t\t\t\"content-type\": \"application/json\",\n\t\t\t\tauthorization: `Bearer ${this.#apiKey}`,\n\t\t\t\t// Billed endpoints require an idempotency key; default to a fresh\n\t\t\t\t// UUID per call, overridable to make a retry replay (not re-charge).\n\t\t\t\t\"idempotency-key\":\n\t\t\t\t\toptions?.idempotencyKey ?? globalThis.crypto.randomUUID(),\n\t\t\t},\n\t\t\tbody: JSON.stringify({ source_url, params }),\n\t\t});\n\t\tif (!response.ok) {\n\t\t\tlet detail: unknown;\n\t\t\ttry {\n\t\t\t\tdetail = await response.json();\n\t\t\t} catch {\n\t\t\t\t// non-JSON error body — leave detail undefined\n\t\t\t}\n\t\t\tconst ra = response.headers.get(\"retry-after\");\n\t\t\tconst retryAfter = ra ? Number(ra) : undefined;\n\t\t\tthrow new FotovidError(response.status, detail, retryAfter);\n\t\t}\n\t\treturn (await response.json()) as T;\n\t}\n\n\treadonly video = {\n\t\twatermark: (\n\t\t\tinput: VideoWatermarkInput,\n\t\t\toptions?: RequestOptions,\n\t\t): Promise<MediaResult> =>\n\t\t\tthis.#post<MediaResult>(\"/v1/video/watermark\", input, options),\n\t\ttrim: (input: TrimInput, options?: RequestOptions): Promise<MediaResult> =>\n\t\t\tthis.#post<MediaResult>(\"/v1/video/trim\", input, options),\n\t\textractAudio: (\n\t\t\tinput: ExtractAudioInput,\n\t\t\toptions?: RequestOptions,\n\t\t): Promise<MediaResult> =>\n\t\t\tthis.#post<MediaResult>(\"/v1/video/extract-audio\", input, options),\n\t\tthumbnail: (\n\t\t\tinput: ThumbnailInput,\n\t\t\toptions?: RequestOptions,\n\t\t): Promise<MediaResult> =>\n\t\t\tthis.#post<MediaResult>(\"/v1/video/extract-cover\", input, options),\n\t\tprobe: (\n\t\t\tinput: ProbeInput,\n\t\t\toptions?: RequestOptions,\n\t\t): Promise<ProbeResult> =>\n\t\t\tthis.#post<ProbeResult>(\"/v1/video/probe\", input, options),\n\t};\n\n\treadonly image = {\n\t\twatermark: (\n\t\t\tinput: ImageWatermarkInput,\n\t\t\toptions?: RequestOptions,\n\t\t): Promise<MediaResult> =>\n\t\t\tthis.#post<MediaResult>(\"/v1/image/watermark\", input, options),\n\t};\n\n\treadonly audio = {\n\t\ttrim: (\n\t\t\tinput: TrimAudioInput,\n\t\t\toptions?: RequestOptions,\n\t\t): Promise<MediaResult> =>\n\t\t\tthis.#post<MediaResult>(\"/v1/audio/trim\", input, options),\n\t};\n}\n"],"mappings":";AAAA,SAAS,SAAS,OAAkD;AACnE,SAAO,OAAO,UAAU,YAAY,UAAU;AAC/C;AAGO,IAAM,eAAN,cAA2B,MAAM;AAAA;AAAA,EAE9B;AAAA;AAAA,EAEA;AAAA;AAAA,EAEA;AAAA,EAET,YAAY,QAAgB,QAAiB,YAAqB;AACjE,QAAI;AACJ,QAAI,SAAS,MAAM,GAAG;AACrB,UAAI,OAAO,OAAO,WAAW,UAAU;AACtC,kBAAU,OAAO;AAAA,MAClB,WAAW,OAAO,OAAO,YAAY,UAAU;AAC9C,kBAAU,OAAO;AAAA,MAClB;AAAA,IACD;AACA,UAAM,WAAW,0CAA0C,MAAM,EAAE;AACnE,SAAK,OAAO;AACZ,SAAK,SAAS;AACd,SAAK,SAAS;AACd,SAAK,aAAa;AAAA,EACnB;AACD;;;ACbA,IAAM,mBAAmB;AAEzB,SAAS,cAAc,UAAsC;AAC5D,QAAM,MACL,aACC,OAAO,YAAY,cAAc,QAAQ,KAAK,kBAAkB;AAClE,MAAI,CAAC,KAAK;AACT,UAAM,IAAI;AAAA,MACT;AAAA,IACD;AAAA,EACD;AACA,SAAO;AACR;AAOO,IAAM,UAAN,MAAc;AAAA,EACX;AAAA,EACA;AAAA,EACA;AAAA,EAET,YAAY,UAA0B,CAAC,GAAG;AACzC,SAAK,UAAU,cAAc,QAAQ,MAAM;AAC3C,SAAK,WAAW,QAAQ,WAAW;AACnC,SAAK,SAAS,QAAQ,SAAS,WAAW;AAAA,EAC3C;AAAA,EAEA,MAAM,MACL,MACA,OACA,SACa;AACb,UAAM,EAAE,YAAY,GAAG,OAAO,IAAI;AAClC,UAAM,WAAW,MAAM,KAAK,OAAO,IAAI,IAAI,MAAM,KAAK,QAAQ,GAAG;AAAA,MAChE,QAAQ;AAAA,MACR,SAAS;AAAA,QACR,gBAAgB;AAAA,QAChB,eAAe,UAAU,KAAK,OAAO;AAAA;AAAA;AAAA,QAGrC,mBACC,SAAS,kBAAkB,WAAW,OAAO,WAAW;AAAA,MAC1D;AAAA,MACA,MAAM,KAAK,UAAU,EAAE,YAAY,OAAO,CAAC;AAAA,IAC5C,CAAC;AACD,QAAI,CAAC,SAAS,IAAI;AACjB,UAAI;AACJ,UAAI;AACH,iBAAS,MAAM,SAAS,KAAK;AAAA,MAC9B,QAAQ;AAAA,MAER;AACA,YAAM,KAAK,SAAS,QAAQ,IAAI,aAAa;AAC7C,YAAM,aAAa,KAAK,OAAO,EAAE,IAAI;AACrC,YAAM,IAAI,aAAa,SAAS,QAAQ,QAAQ,UAAU;AAAA,IAC3D;AACA,WAAQ,MAAM,SAAS,KAAK;AAAA,EAC7B;AAAA,EAES,QAAQ;AAAA,IAChB,WAAW,CACV,OACA,YAEA,KAAK,MAAmB,uBAAuB,OAAO,OAAO;AAAA,IAC9D,MAAM,CAAC,OAAkB,YACxB,KAAK,MAAmB,kBAAkB,OAAO,OAAO;AAAA,IACzD,cAAc,CACb,OACA,YAEA,KAAK,MAAmB,2BAA2B,OAAO,OAAO;AAAA,IAClE,WAAW,CACV,OACA,YAEA,KAAK,MAAmB,2BAA2B,OAAO,OAAO;AAAA,IAClE,OAAO,CACN,OACA,YAEA,KAAK,MAAmB,mBAAmB,OAAO,OAAO;AAAA,EAC3D;AAAA,EAES,QAAQ;AAAA,IAChB,WAAW,CACV,OACA,YAEA,KAAK,MAAmB,uBAAuB,OAAO,OAAO;AAAA,EAC/D;AAAA,EAES,QAAQ;AAAA,IAChB,MAAM,CACL,OACA,YAEA,KAAK,MAAmB,kBAAkB,OAAO,OAAO;AAAA,EAC1D;AACD;","names":[]}
package/package.json ADDED
@@ -0,0 +1,55 @@
1
+ {
2
+ "name": "@fotovid/sdk",
3
+ "version": "0.1.0",
4
+ "description": "Typed TypeScript/Node client for the Fotovid media API",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "main": "./dist/index.cjs",
8
+ "module": "./dist/index.js",
9
+ "types": "./dist/index.d.ts",
10
+ "exports": {
11
+ ".": {
12
+ "import": {
13
+ "types": "./dist/index.d.ts",
14
+ "default": "./dist/index.js"
15
+ },
16
+ "require": {
17
+ "types": "./dist/index.d.cts",
18
+ "default": "./dist/index.cjs"
19
+ }
20
+ }
21
+ },
22
+ "files": [
23
+ "dist",
24
+ "README.md"
25
+ ],
26
+ "sideEffects": false,
27
+ "engines": {
28
+ "node": ">=20"
29
+ },
30
+ "publishConfig": {
31
+ "access": "public",
32
+ "provenance": true
33
+ },
34
+ "keywords": [
35
+ "fotovid",
36
+ "ffmpeg",
37
+ "watermark",
38
+ "video",
39
+ "media",
40
+ "serverless",
41
+ "api",
42
+ "sdk"
43
+ ],
44
+ "repository": {
45
+ "type": "git",
46
+ "url": "git+https://github.com/twinrise/fotovid-js.git",
47
+ "directory": "packages/sdk"
48
+ },
49
+ "homepage": "https://github.com/twinrise/fotovid-js/tree/main/packages/sdk",
50
+ "bugs": "https://github.com/twinrise/fotovid-js/issues",
51
+ "scripts": {
52
+ "build": "tsup",
53
+ "typecheck": "tsc --noEmit"
54
+ }
55
+ }