diff --git a/.cursor/rules/cloudinary.mdc b/.cursor/rules/cloudinary.mdc new file mode 100644 index 00000000..95c7f24e --- /dev/null +++ b/.cursor/rules/cloudinary.mdc @@ -0,0 +1,8 @@ +--- +description: Cloudinary cloudinary_npm — 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..47bd664e --- /dev/null +++ b/.github/copilot-instructions.md @@ -0,0 +1,5 @@ +# Cloudinary cloudinary_npm — 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..65a62a01 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,75 @@ +# AGENTS.md — cloudinary_npm + +## What this package is (one line) +The server-side Cloudinary SDK for Node.js: upload assets, build transformation/delivery URLs, and call the Admin API from your backend, where the `API_SECRET` stays private. + +## When to use this / when NOT to use this +- **Use this when:** your code runs on a **server or build step** (Express, Next.js route handlers, NestJS, serverless, scripts) and needs signed uploads, signed delivery URLs, or account administration — anything that must hold the `API_SECRET`. +- **Do NOT use this when:** you generate delivery URLs **in a browser/frontend bundle** (use `@cloudinary/url-gen`), render React/Angular/Vue components (use the `@cloudinary/*` framework packages), or want the no-code/agent path (use the Cloudinary MCP server). +- **Sibling packages:** `@cloudinary/url-gen` (js-url-gen) = browser-safe URL builder, no secret; `frontend-frameworks` = React/Vue/Angular components on top of url-gen; `next-cloudinary` = Next.js drop-in components. Rule of thumb: server → this package; browser → not this package. + +## Setup +```bash +npm install cloudinary +``` +Required configuration / credentials (read automatically from the environment): +```bash +export CLOUDINARY_URL=cloudinary://:@ +``` + +## Minimal runnable example +```js +const cloudinary = require('cloudinary').v2; +// cloudinary.config() is unnecessary if CLOUDINARY_URL is set. + +(async () => { + const result = await cloudinary.uploader.upload('/home/my_image.jpg', { + upload_preset: 'my_preset', + }); + // Build a delivery URL: 100x150 fill crop, auto format. + const url = cloudinary.url('sample.jpg', { + width: 100, height: 150, crop: 'fill', fetch_format: 'auto', + }); + console.log(result.public_id, url); +})(); +``` + +## Build / test commands (run these after editing) +```bash +npm ci || npm i # install (CI uses npm ci with fallback) +npm test # lint + ES6 mocha specs + dtslint (tools/scripts/test.sh) +npm run lint # eslint ./test ./lib + Node-9-compat lint of cloudinary.js/lib +npm run test-es6 # mocha specs only, no lint/dtslint +npm run test:unit # unit specs only (test/unit/**) — mocked (no live API calls), but `CLOUDINARY_URL` must be set; a dummy value like `cloudinary://x:y@z` suffices +npm run coverage # mocha specs with nyc HTML coverage +npm run dtslint # type-definition tests (types/index.d.ts) + +# Single test — run one spec file (setup.js must load first): +npx mocha --exit --file ./test/setup.js ./test/unit/cloudinaryUtils/getUserAgent.spec.js +# Or filter by test name across the suite: +npx mocha --exit --file ./test/setup.js "./test/**/*spec.js" -g "signature" +``` +Notes: +- `npm test` and `npm run test-es6` hit a real Cloudinary account — they need valid credentials in the environment (`CLOUDINARY_URL`). CI runs `npm run test-with-temp-cloud`, which provisions a temporary cloud first; locally, supply your own. +- Tests are Mocha 7 + `expect.js` + `sinon`; specs live in `test/**/*spec.js` and `test/setup.js` must load first (already wired via the test scripts). + +## Conventions & gotchas +- ESLint with `airbnb-base`; there is no formatter script — match existing style and run `npm run lint` before committing. Source must stay Node-9-compatible (a second lint pass enforces this against `cloudinary.js` and `lib/`); avoid syntax newer than the oldest supported runtime. +- Public entry is `cloudinary.js`; production code lives in `lib/`. The modern surface is `require('cloudinary').v2` — prefer `v2` in examples and new code over the legacy top-level (v1) API. +- TypeScript types are hand-maintained in `types/index.d.ts` and validated by `dtslint` — update them when you change the public API, or `npm test` fails. +- Signed uploads and the Admin API require server-side secrets. Never ship the `api_secret` to a browser bundle. +- Supported runtimes: 2.x requires **Node 9+**; 1.x was Node 6+. CI matrix runs Node 9–24. + +## Canonical docs (leave the repo for depth) +- Node.js SDK guide: https://cloudinary.com/documentation/node_integration +- Upload: https://cloudinary.com/documentation/node_image_and_video_upload +- Asset administration (Admin API): https://cloudinary.com/documentation/node_asset_administration +- Transformation & API references: https://cloudinary.com/documentation/cloudinary_references +- MCP server (agent/no-code path): https://github.com/cloudinary/mcp-servers + +## Agent / MCP note +If a capability is also exposed via the Cloudinary MCP servers, prefer the MCP tool for autonomous task execution and use this SDK for code generation. See cloudinary/mcp-servers. + +## Commit / PR conventions +- Branch off and PR against `master`. Keep the CI matrix green (Node 9–24 via `npm run test-with-temp-cloud`). +- Update `types/index.d.ts` and `CHANGELOG.md` alongside public API changes. Lint and tests must pass before merge. diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 00000000..a2e7c74a --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,38 @@ +@AGENTS.md + +# CLAUDE.md — cloudinary_npm + +## Claude Code-specific notes + +**Primary reference:** `AGENTS.md` (imported above) covers setup, build commands, conventions, and gotchas. Read it before touching any file. + +## What this repo is + +`cloudinary_npm` is the **server-side Node.js SDK** for Cloudinary: upload assets, build transformation/delivery URLs, and call the Admin API from your backend. This is the package that holds `API_SECRET` — never use it in a browser bundle. + +## Key constraints + +- **Entry point:** `cloudinary.js`; production code lives in `lib/`. Always use `require('cloudinary').v2` — the legacy top-level (v1) API is deprecated. +- **TypeScript types** are hand-maintained in `types/index.d.ts`. Update them alongside any public API change or `npm test` (dtslint) will fail. +- **Node 9 compatibility is a hard floor.** A second ESLint pass enforces this against `cloudinary.js` and `lib/`. Avoid syntax unavailable in Node 9. +- **ESLint (`airbnb-base`) only — no formatter.** Match existing style and run `npm run lint` before committing. +- **Branch target:** `master`. Every public API change requires updating both `types/index.d.ts` and `CHANGELOG.md`. + +## Verified build/test commands + +```bash +npm ci || npm i # install (CI uses npm ci) + +npm test # lint + ES6 mocha specs + dtslint — requires CLOUDINARY_URL set +npm run test:unit # unit specs only — mocked (no live API calls), but `CLOUDINARY_URL` must be set; a dummy value like `cloudinary://x:y@z` suffices +npm run lint # eslint ./test ./lib + Node-9 compat lint +npm run dtslint # type-definition tests against types/index.d.ts +npm run coverage # mocha + nyc HTML coverage report + +# Single spec file (setup.js must load first): +npx mocha --exit --file ./test/setup.js ./test/unit/cloudinaryUtils/getUserAgent.spec.js +# Filter by test name across the suite: +npx mocha --exit --file ./test/setup.js "./test/**/*spec.js" -g "signature" +``` + +`npm test` and `npm run test-es6` hit a real Cloudinary account — supply `CLOUDINARY_URL=cloudinary://:@`. CI provisions a temporary cloud via `npm run test-with-temp-cloud`. For offline iteration, use `npm run test:unit`. diff --git a/README.md b/README.md index cfba7c4d..18e17cd3 100644 --- a/README.md +++ b/README.md @@ -1,103 +1,106 @@ -Cloudinary Node SDK -========================= -## About -The Cloudinary Node SDK allows you to quickly and easily integrate your application with Cloudinary. -Effortlessly optimize, transform, upload and manage your cloud's assets. +# Cloudinary Node.js SDK +[![npm version](https://img.shields.io/npm/v/cloudinary.svg)](https://www.npmjs.com/package/cloudinary) +[![license](https://img.shields.io/npm/l/cloudinary.svg)](https://www.npmjs.com/package/cloudinary) +[![CI](https://github.com/cloudinary/cloudinary_npm/actions/workflows/ci.yml/badge.svg)](https://github.com/cloudinary/cloudinary_npm/actions/workflows/ci.yml) -#### Note -This Readme provides basic installation and usage information. -For the complete documentation, see the [Node SDK Guide](https://cloudinary.com/documentation/node_integration). +The `cloudinary` package is the server-side Cloudinary SDK for Node.js. Use it on a server or in a build step to upload assets, build transformation and delivery URLs, and call the Admin API. It holds your API secret, so it handles the operations that can't run in a browser: signed uploads, signed delivery URLs, and asset administration. The current release (2.x) requires Node 9 or later. -## 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 HTML Tags](#Generate-Image-and-Video-HTML-Tags) - - -## Key Features -- [Transform](https://cloudinary.com/documentation/node_video_manipulation#video_transformation_examples) and - [optimize](https://cloudinary.com/documentation/node_image_manipulation#image_optimizations) assets. -- Generate [image](https://cloudinary.com/documentation/node_image_manipulation#deliver_and_transform_images) and - [video](https://cloudinary.com/documentation/node_video_manipulation#video_element) tags. -- [Asset Management](https://cloudinary.com/documentation/node_asset_administration). -- [Secure URLs](https://cloudinary.com/documentation/video_manipulation_and_delivery#generating_secure_https_urls_using_sdks). +## Installation +```bash +npm install cloudinary +``` +## Configuration -## Version Support -| SDK Version | Node version | -|-------------|--------------| -| 1.x.x | Node@6 & up | -| 2.x.x | Node@9 & up | +Require the v2 API and give it your credentials. The SDK reads them automatically from the `CLOUDINARY_URL` environment variable: -## Installation ```bash -npm install cloudinary +CLOUDINARY_URL=cloudinary://:@ ``` -# Usage -### Setup ```js -// Require the Cloudinary library -const cloudinary = require('cloudinary').v2 +const cloudinary = require('cloudinary').v2; +// Credentials come from CLOUDINARY_URL in the environment. ``` -### Transform and Optimize Assets -- [See full documentation](https://cloudinary.com/documentation/node_image_manipulation). +To set them in code instead, call `config()`: ```js -cloudinary.url("sample.jpg", {width: 100, height: 150, crop: "fill", fetch_format: "auto"}) +const cloudinary = require('cloudinary').v2; + +cloudinary.config({ + cloud_name: 'my_cloud_name', + api_key: 'my_key', + api_secret: 'my_secret', +}); ``` -### Upload -- [See full documentation](https://cloudinary.com/documentation/node_image_and_video_upload). -- [Learn more about configuring your uploads with upload presets](https://cloudinary.com/documentation/upload_presets). +Keep the API secret on the server. Don't put it in client-side code or commit it to version control. + +## Quick examples + +### Upload a file with the Node.js SDK + +`uploader.upload()` takes a local path, a remote URL, a data URI, or a base64 string. It returns a Promise when you omit the callback, so `await` works directly. The result includes `public_id` and `secure_url`: + ```js -cloudinary.v2.uploader.upload("/home/my_image.jpg", {upload_preset: "my_preset"}, (error, result)=>{ - console.log(result, error); +const cloudinary = require('cloudinary').v2; +// Credentials come from CLOUDINARY_URL in the environment. + +const result = await cloudinary.uploader.upload('/home/my_image.jpg', { + public_id: 'cms/hero', // optional: where the asset lives in your media library }); +console.log(result.public_id, result.secure_url); ``` -### Large/Chunked Upload -- [See full documentation](https://cloudinary.com/documentation/node_image_and_video_upload#node_js_video_upload). + +### Transform and optimize a delivery URL + +`cloudinary.url()` is synchronous and returns a string — no network call. This one resizes to a 100x150 fill crop and lets Cloudinary pick the format and quality for the requesting browser (`f_auto`, `q_auto`): + ```js - cloudinary.v2.uploader.upload_large(LARGE_RAW_FILE, { - chunk_size: 7000000 - }, (error, result) => {console.log(error)}); +const cloudinary = require('cloudinary').v2; + +const url = cloudinary.url('sample.jpg', { + width: 100, height: 150, crop: 'fill', + fetch_format: 'auto', quality: 'auto', +}); +// https://res.cloudinary.com/demo/image/upload/c_fill,f_auto,h_150,q_auto,w_100/sample.jpg ``` -### Security options -- [See full documentation](https://cloudinary.com/documentation/solution_overview#security). -## Contributions -- Ensure tests run locally (add test command) -- Open a PR and ensure tests pass +### Retrieve asset details + +`api.resource()` takes a public ID and returns the asset's metadata, including its dimensions, format, and `secure_url`: +```js +const cloudinary = require('cloudinary').v2; +// Credentials come from CLOUDINARY_URL in the environment. + +const asset = await cloudinary.api.resource('sample'); +console.log(asset.format, asset.width, asset.height, asset.secure_url); +``` -## Get Help -If you run into an issue or have a question, you can either: -- Issues related to the SDK: [Open a Github issue](https://github.com/cloudinary/cloudinary_npm/issues). -- Issues related to your account: [Open a support ticket](https://cloudinary.com/contact) +## For AI agents +`cloudinary` is the Node.js server-side SDK. Choose it for backend upload, asset administration, and signed URL or tag generation, where the API secret stays private. For other Cloudinary tasks, choose a different 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 | +|---|---| +| Build delivery URLs in the browser | [`@cloudinary/url-gen`](https://github.com/cloudinary/js-url-gen) | +| 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) | +| 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 -- [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): Learn about Cloudinary's products, partners, customers, pricing, and more. +## Links +- [Node.js SDK guide](https://cloudinary.com/documentation/node_integration) +- [Upload](https://cloudinary.com/documentation/node_image_and_video_upload) +- [Asset administration (Admin API)](https://cloudinary.com/documentation/node_asset_administration) +- [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) -## Licence Released under the MIT license.