diff --git a/.cursor/rules/cloudinary.mdc b/.cursor/rules/cloudinary.mdc new file mode 100644 index 00000000..9fdc2e0c --- /dev/null +++ b/.cursor/rules/cloudinary.mdc @@ -0,0 +1,8 @@ +--- +description: Cloudinary js-url-gen — agent guide +alwaysApply: true +--- + +Read and follow `AGENTS.md` in the repository root. It is the single +authoritative guide for this package: build/test commands, conventions, +gotchas, and when to use this SDK versus a sibling Cloudinary package. diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 00000000..c54051a3 --- /dev/null +++ b/.github/copilot-instructions.md @@ -0,0 +1,5 @@ +# Cloudinary js-url-gen — instructions for AI coding agents + +Read `AGENTS.md` in the repository root and follow it. It is the single +authoritative guide for this package: build/test commands, conventions, +gotchas, and when to use this SDK versus a sibling Cloudinary package. diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 00000000..c1c6d60e --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,72 @@ +# AGENTS.md — js-url-gen (`@cloudinary/url-gen`) + +## What this package is (one line) +Browser-safe, framework-agnostic builder for Cloudinary image and video **delivery/transformation URLs** — returns strings, holds no `API_SECRET`, and has no upload or admin surface. + +## When to use this / when NOT to use this +- **Use this when:** you are generating optimized image/video delivery URLs in any JS/TS **frontend** (resize, crop, `f_auto`, `q_auto`) and only need to *display* media. +- **Do NOT use this when:** you need to *upload* assets, call the Admin API, or sign URLs — that work needs a server secret and belongs in [`cloudinary`](https://github.com/cloudinary/cloudinary_npm) (`cloudinary_npm`). Never ship an `API_SECRET` to a browser bundle. +- **Sibling packages:** + - React / Angular / Vue components → [`@cloudinary/react` · `@cloudinary/ng` · `@cloudinary/vue`](https://github.com/cloudinary/frontend-frameworks). They build *on top of* this package — same URL builder underneath. (The Angular package is `@cloudinary/ng`; `@cloudinary/angular` on npm is an abandoned beta.) + - Server-side upload / admin / signed URLs → [`cloudinary_npm`](https://github.com/cloudinary/cloudinary_npm). This package is its mirror image: same platform, opposite side of the network boundary. + - No-code / autonomous agent path → the [Cloudinary MCP servers](https://github.com/cloudinary/mcp-servers). + - Transformation actions live in the [`@cloudinary/transformation-builder-sdk`](https://github.com/cloudinary/js-transformation-builder-sdk) dependency (see gotchas). + +## Setup +```bash +npm install @cloudinary/url-gen +``` +No credentials required at install or runtime — only a public `cloudName`. There is **no** `API_SECRET` config; if you reach for one, you are in the wrong package (see above). + +## Minimal runnable example +```javascript +import {Cloudinary} from '@cloudinary/url-gen'; +import {Resize} from '@cloudinary/url-gen/actions/resize'; + +const cld = new Cloudinary({cloud: {cloudName: 'demo'}, url: {secure: true}}); + +const img = cld.image('sample'); +img.resize(Resize.scale().width(100).height(100)); + +console.log(img.toURL()); +// https://res.cloudinary.com/demo/image/upload/c_scale,w_100,h_100/sample +``` +Use `cld.video(...)` for video; both expose `.toURL()`. + +## Build / test commands (run these after editing) +```bash +npm install +npm run lint # eslint src + __TESTS__ (.ts) — runs lint:src then lint:test +npm run test # build → tsc type-check → build → jest --coverage → bundle-size check +npm run build # bash ./scripts/build.sh — full dist (ESM + rollup + entrypoints) +``` +Faster inner loops while iterating: +```bash +npm run test:unit # jest only, no build/coverage/size gates +npm run test:unit:watch # jest --watch +npm run test:types # tsc --project tsconfig.test.json +``` +CI runs on Travis (`.travis.yml`) only — there is no `.github/workflows`. It runs exactly `npm run lint` then `npm run test` on Node **14** and **16** (Node 18 is present but commented out as not yet supported). + +## Conventions & gotchas +- **Source is TypeScript** under `src/`; lint is `eslint --ext .ts`. Prettier is a devDependency — match existing formatting. +- **`npm run test` is heavy** — it builds twice, type-checks, runs coverage, and enforces a bundle-size budget (`test:size` / `bundlewatch`). For quick checks use `npm run test:unit`. Bundle size is a hard concern here: this package is tree-shakeable ES modules and ships **untranspiled ES6** on purpose. Don't add transpilation or pull in dependencies that bloat dist. +- **Tree-shakeable imports.** Import each action from its own deep path (`@cloudinary/url-gen/actions/resize`), not a barrel — deep `exports` are defined in `package.json`. Preserve that shape when adding modules. +- **Transformations live in the dependency.** `@cloudinary/transformation-builder-sdk` ships as a dependency and owns every transformation action. You can import them from `@cloudinary/url-gen/actions/*` (re-exported, as docs show) or directly from `@cloudinary/transformation-builder-sdk/actions/*`. Behavior changes to a transformation may belong in that repo, not this one. +- **No upload/admin code belongs here.** This SDK only emits URL strings. Keep the secret-free, browser-safe boundary intact — no `fetch` to authenticated endpoints, no secrets. +- **Consumers testing with Jest** need `babel-jest` transforms for `@cloudinary/url-gen` + `@cloudinary/transformation-builder-sdk` (they ship untranspiled). That's a downstream gotcha, not a repo build step — keep the dist untranspiled. + +## Canonical docs (leave the repo for depth) +- URL-Gen integration guide: https://cloudinary.com/documentation/javascript_integration +- URL-Gen SDK reference: https://cloudinary.com/documentation/sdks/js/url-gen/index.html +- Transformation Builder reference: https://cloudinary.com/documentation/sdks/js/transformation-builder/index.html +- Image / video transformations: https://cloudinary.com/documentation/javascript_image_transformations · https://cloudinary.com/documentation/javascript_video_transformations +- MCP servers (agent / no-code path): https://github.com/cloudinary/mcp-servers + +## Agent / MCP note +For autonomous task execution prefer the [Cloudinary MCP servers](https://github.com/cloudinary/mcp-servers); use this SDK when **generating frontend code** that builds delivery URLs. This package never uploads or administers assets — route those tasks to the MCP server or `cloudinary_npm`. + +## Commit / PR conventions +- Run `npm run lint` and `npm run test` locally before opening a PR — these are the exact CI gates. +- A `.github/pull_request_template.md` exists; fill it out. Maintainer review is required before merge. +- Releases are handled by maintainers via `release-it` (`npm run release`) — do not bump the version manually in a PR. diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 00000000..cfb1eb9f --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,36 @@ +@AGENTS.md + +# CLAUDE.md — js-url-gen + +## What this repo is + +`js-url-gen` is the browser-safe TypeScript library for building Cloudinary image and video delivery URLs. It returns URL strings, ships no credentials, and has no upload or admin surface. Published as `@cloudinary/url-gen`. + +## Key constraints + +- **No `API_SECRET` here.** This SDK is browser-safe by design. Anything requiring a secret (uploads, Admin API, signed URLs) belongs in `cloudinary_npm`. +- **Import from deep paths, not the barrel.** `import {fill} from '@cloudinary/url-gen/actions/resize'` works; `import {fill} from '@cloudinary/url-gen'` throws "not exported". Deep `exports` paths are declared in `package.json`. +- **Transformation actions live in a dependency.** `@cloudinary/transformation-builder-sdk` owns every action. Import from `@cloudinary/url-gen/actions/*` (re-exported) or directly from `@cloudinary/transformation-builder-sdk/actions/*` — both resolve to the same code. +- **Source is TypeScript** under `src/`; lint requires `eslint --ext .ts`. Match existing Prettier formatting. +- **`npm run test` is heavy** — build twice, tsc type-check, jest --coverage, and a bundle-size gate. Use `npm run test:unit` for inner-loop feedback. +- **Bundle size is a hard constraint.** The package ships untranspiled ES6 modules for tree-shaking. Don't add transpilation steps or pull in dependencies that bloat dist. +- **Consumers testing with Jest** must configure `babel-jest` transforms for both `@cloudinary/url-gen` and `@cloudinary/transformation-builder-sdk` (they ship untranspiled). This is a downstream concern — do not change the dist format. +- **CI uses Travis** (`.travis.yml`), not GitHub Actions. Verified Node targets: 14, 16. Node 18 present but commented out as not yet supported. + +## Verified build / test commands + +```bash +npm install +npm run lint # eslint src + __TESTS__ (.ts) — runs lint:src then lint:test +npm run test # build → tsc type-check → build → jest --coverage → bundle-size check +``` + +Faster inner loops: + +```bash +npm run test:unit # jest only, no build/coverage/size gates +npm run test:unit:watch # jest --watch +npm run test:types # tsc --project tsconfig.test.json +``` + +CI gate = `npm run lint` then `npm run test`. Run both before opening a PR. diff --git a/README.md b/README.md index 460ee3fb..58c1088f 100644 --- a/README.md +++ b/README.md @@ -1,195 +1,109 @@ -You are invited to influence our new SDK -[Click here to view github discussion](https://github.com/cloudinary/js-url-gen/discussions/602) -========================= - - - -Cloudinary URL-Gen SDK -========================= -[![Build Status](https://api.travis-ci.com/cloudinary/js-url-gen.svg?branch=master)](https://app.travis-ci.com/github/cloudinary/js-url-gen) -## About -The Cloudinary URL-Gen SDK allows you to quickly and easily integrate your application with Cloudinary. -Effortlessly optimize and transform your cloud's assets. - -This SDK can also be used with [popular frontend frameworks](https://cloudinary.com/documentation/sdks/js/frontend-frameworks/index.html). - -### Additional documentation -This Readme provides basic installation and usage information. -For the complete documentation, see the [URL-Gen SDK Guide](https://cloudinary.com/documentation/javascript_integration) and the [URL-Gen Reference](https://cloudinary.com/documentation/sdks/js/url-gen/index.html). - -NOTE: When using the url-gen library, an additional transformation-builder-sdk library is installed as a dependency. -This library handles the transformation generation part of the URL and as such, all transformation actions are imported from this library. -Therefore, you can import all transformations either from @cloudinary/url-gen (as demonstrated in the documentation), or directly from the transformation-builder-sdk library, for example: -```javascript -import {scale} from '@cloudinary/transformation-builder-sdk/actions/resize'; -``` - -You can find all available transformations in the [Transformation Builder reference](https://cloudinary.com/documentation/sdks/js/transformation-builder/index.html). - - -## Table of Contents -- [Key Features](#key-features) -- [Version Support](#Version-Support) -- [Installation](#installation) -- [Usage](#usage) - - [Setup](#Setup) - - [Transform and Optimize Assets](#Transform-and-Optimize-Assets) - - [Generate Image and Video URLs](#Generate-Image-and-Video-URLs) - - [Transpilation](#Transpilation) - - [Testing with Jest](#Testing-with-jest) -- [Contributions](#Contributions) -- [Get Help](#Get-Help) -- [Additional Resources](#Additional-Resources) - -## Key Features -- [Transform image](https://cloudinary.com/documentation/javascript_image_transformations) assets (links to docs). -- [Transform video](https://cloudinary.com/documentation/javascript_video_transformations) assets (links to docs). - - -## Version Support - -### Note! -This SDK is cross-platform, but only the Node.js versions are worth mentioning - -| SDK Version | Node.js 14 | Node.js 16 | -|-------------|------------|------------| -| 1.x | V | V | +# Cloudinary URL-Gen SDK +[![npm version](https://img.shields.io/npm/v/@cloudinary/url-gen.svg)](https://www.npmjs.com/package/@cloudinary/url-gen) +[![license](https://img.shields.io/npm/l/@cloudinary/url-gen.svg)](https://www.npmjs.com/package/@cloudinary/url-gen) +The `@cloudinary/url-gen` package is the browser-safe Cloudinary SDK for JavaScript and TypeScript that builds image and video delivery URLs. It turns a public ID like `sample` into an optimized, transformed URL string and holds no API secret, so it runs in any frontend. The package is browser-targeted and ships untranspiled ES modules; it has no Node engine floor, and its CI builds against Node 14 and 16. ## Installation -### Install using your favorite package manager (yarn, npm) + ```bash npm install @cloudinary/url-gen ``` -```bash -yarn add @cloudinary/url-gen -``` -## Usage -### Setup +## Configuration + +This SDK never holds an API secret. It only composes public delivery URLs, so the only value it needs is your public cloud name. Create one `Cloudinary` instance and reuse it: + ```javascript -// Import the Cloudinary class import {Cloudinary} from '@cloudinary/url-gen'; -// Create your instance const cld = new Cloudinary({ cloud: { - cloudName: 'demo' + cloudName: 'my_cloud_name', // public cloud name, safe in the browser }, url: { - secure: true // force https, set to false to force http - } + secure: true, // force https (the default) + }, }); ``` +There's no `CLOUDINARY_URL`, `api_key`, or `api_secret` to set here. Keep the API secret out of client-side code and version control — anything that needs it (uploads, Admin API, signed URLs) runs on a server with [`cloudinary`](https://github.com/cloudinary/cloudinary_npm). -### Transform and Optimize Assets -- [See full documentation](https://cloudinary.com/documentation/javascript_image_transformations) -```javascript -// Create a new instance if you haven't (see above for the details) -const cld = new Cloudinary({/*...*/}) +## Quick examples -// Let's create a new image -const myImage = cld.image('sample'); +### Build a transformed delivery URL -// Import the resize transformation and apply it to myImage -import {Resize} from '@cloudinary/url-gen/actions/resize'; +Create an image asset with `cld.image('')`, chain a resize action, then call `.toURL()`. `.toURL()` is synchronous and makes no network call. Import each action from its deep path so bundlers can tree-shake it: -// Resize the image to 100x100 -myImage.resize(Resize.scale().width(100).height(100)); +```javascript +import {Cloudinary} from '@cloudinary/url-gen'; +import {fill} from '@cloudinary/url-gen/actions/resize'; -// When we're done, we can apply all our changes and create a URL. -const myURL = myImage.toURL(); +const cld = new Cloudinary({cloud: {cloudName: 'demo'}}); -// https://res.cloudinary.com/demo/image/upload/c_scale,w_100,h_100/sample -console.log(myURL); +const url = cld.image('sample') + .resize(fill().width(100).height(150)) + .toURL(); +// https://res.cloudinary.com/demo/image/upload/c_fill,w_100,h_150/sample ``` -### Generate Image and Video URLs -The library supports transformations on both images and videos. Please use the appropriate method, as per below: +### Deliver an auto-optimized image - - Use `cld.image()` to generate image URLs and transformations - - Use `cld.video()` to generate video URLs and transformations +`format('auto')` (`f_auto`) lets Cloudinary serve AVIF or WebP to browsers that support it, and `quality('auto')` (`q_auto`) picks the smallest quality that still looks right. Both come from the `delivery` action path: -Both the `image()` and `video()` methods allow you to use `toURL()` to generate the final, transformed asset URL. +```javascript +import {Cloudinary} from '@cloudinary/url-gen'; +import {format, quality} from '@cloudinary/url-gen/actions/delivery'; -### File upload -This SDK does not provide file upload functionality, however there are [several methods of uploading from the client side](https://cloudinary.com/documentation/javascript_image_and_video_upload). +const cld = new Cloudinary({cloud: {cloudName: 'demo'}}); -### Transpilation -`@cloudinary/url-gen` is shipped as untranspiled ES6 code. -`@cloudinary/url-gen` is optimized around bundle size, as such we do not transpile our distributed modules, -we leave the decision of what browsers to support, and what transpilations to apply, to you, the user. +const url = cld.image('sample') + .delivery(format('auto')) + .delivery(quality('auto')) + .toURL(); +// https://res.cloudinary.com/demo/image/upload/f_auto/q_auto/sample +``` -### Testing with Jest -As mentioned above, we're shipping `@cloudinary/url-gen` with ES6 code, as this provides great tree-shaking potential. -it also requires a few adjustments when testing. +### Build an optimized video URL -In jest.config, you'll need to add these lines to allow babel to transpile our code. -```json -{ - "transform": { - "node_modules/@cloudinary/url-gen": "babel-jest", - "node_modules/@cloudinary/transformation-builder-sdk": "babel-jest" - }, - "transformIgnorePatterns": ["/node_modules/(?!(@cloudinary/url-gen|@cloudinary/transformation-builder-sdk))"] -} -``` -Make sure to install babel-jest: -`npm install babel-jest` - -You'll also need to ensure you have a `babel.config.js` file (and not a `.babelrc`), and that -it's configured properly to transpile code, - -*As an example*: -```js -module.exports = { - "presets": [ - "@babel/preset-env" - ] -}; -``` +The same delivery actions work on video. Use `cld.video('')` to target the video resource type: -## Contributions -- Clone this repository -- Create a fork -- Make your changes -- Run tests locally `npm run test` -- Build project locally `npm run build` -- Push your changes -- Await a review from the maintainers +```javascript +import {Cloudinary} from '@cloudinary/url-gen'; +import {format, quality} from '@cloudinary/url-gen/actions/delivery'; +const cld = new Cloudinary({cloud: {cloudName: 'demo'}}); -## Get Help -If you run into an issue or have a question, you can either: -- [Open a Github issue](https://github.com/cloudinary/js-url-gen/issues) (for issues related to the SDK) -- [Open a support ticket](https://cloudinary.com/contact) (for issues related to your account) +const url = cld.video('dog') + .delivery(format('auto')) + .delivery(quality('auto')) + .toURL(); +// https://res.cloudinary.com/demo/video/upload/f_auto/q_auto/dog +``` -Additional resources can be found here: -- [Getting started](https://cloudinary.com/documentation/sdks/js/url-gen/tutorial-gettingStarted.html) -- [Annotated Code Examples](https://cloudinary.com/documentation/sdks/js/url-gen/tutorial-annotatedExamples.html) -- [Setup & Configuration](https://cloudinary.com/documentation/sdks/js/url-gen/tutorial-configuration_.html) +## For AI agents +`@cloudinary/url-gen` is the browser-safe, framework-agnostic builder for Cloudinary image and video delivery URLs; it returns strings and has no upload, admin, or secret surface. Import each action from its deep path (`@cloudinary/url-gen/actions/resize`), not from the package root — a bare `import {fill} from '@cloudinary/url-gen'` throws. For tasks this package doesn't cover, use a sibling package: -## About Cloudinary -Cloudinary is a powerful media API for websites and mobile apps alike, Cloudinary enables developers to efficiently manage, transform, optimize, and deliver images and videos through multiple CDNs. Ultimately, viewers enjoy responsive and personalized visual-media experiences—irrespective of the viewing device. +| Task | Package | +|---|---| +| Upload, Admin API, or signed URLs on a server | [`cloudinary`](https://github.com/cloudinary/cloudinary_npm) | +| Render React, Angular, or Vue components | [`@cloudinary/react` / `@cloudinary/ng` / `@cloudinary/vue`](https://github.com/cloudinary/frontend-frameworks) | +| Drop-in Next.js components | [`next-cloudinary`](https://github.com/cloudinary-community/next-cloudinary) | +| The transformation-action engine this package re-exports | [`@cloudinary/transformation-builder-sdk`](https://github.com/cloudinary/js-transformation-builder-sdk) | +| Run Cloudinary operations as agent tools | [Cloudinary MCP servers](https://github.com/cloudinary/mcp-servers) | +The Angular package is `@cloudinary/ng`. `@cloudinary/angular` on npm is an abandoned Beta — don't use it. -## Additional Resources -- [React SDK](https://www.npmjs.com/package/@cloudinary/react) -- [Angular SDK](https://www.npmjs.com/package/@cloudinary/angular) -- [Use with a Frontend Framework](https://cloudinary.com/documentation/sdks/js/frontend-frameworks/index.html) -- [Cloudinary Transformation and REST API References](https://cloudinary.com/documentation/cloudinary_references): Comprehensive references, including syntax and examples for all SDKs. -- [MediaJams.dev](https://mediajams.dev/): Bite-size use-case tutorials written by and for Cloudinary Developers -- [DevJams](https://www.youtube.com/playlist?list=PL8dVGjLA2oMr09amgERARsZyrOz_sPvqw): Cloudinary developer podcasts on YouTube. -- [Cloudinary Academy](https://training.cloudinary.com/): Free self-paced courses, instructor-led virtual courses, and on-site courses. -- [Code Explorers and Feature Demos](https://cloudinary.com/documentation/code_explorers_demos_index): A one-stop shop for all code explorers, Postman collections, and feature demos found in the docs. -- [Cloudinary Roadmap](https://cloudinary.com/roadmap): Your chance to follow, vote, or suggest what Cloudinary should develop next. -- [Cloudinary Facebook Community](https://www.facebook.com/groups/CloudinaryCommunity): Learn from and offer help to other Cloudinary developers. -- [Cloudinary Account Registration](https://cloudinary.com/users/register/free): Free Cloudinary account registration. -- [Cloudinary Website](https://cloudinary.com) +## Links +- [JavaScript SDK guide](https://cloudinary.com/documentation/javascript_integration) +- [URL-Gen SDK reference](https://cloudinary.com/documentation/sdks/js/url-gen/index.html) +- [Image transformations](https://cloudinary.com/documentation/javascript_image_transformations) +- [Video transformations](https://cloudinary.com/documentation/javascript_video_transformations) +- [Transformation and API references](https://cloudinary.com/documentation/cloudinary_references) +- [Documentation llms.txt index](https://cloudinary.com/documentation/llms.txt) +- [Package on npm](https://www.npmjs.com/package/@cloudinary/url-gen) -## Licence Released under the MIT license.