From adobe-pack
Sets up local dev loop for Adobe APIs (Firefly/PDF/Photoshop) with App Builder CLI, Node.js SDKs, hot reload, and Vitest mocks.
How this skill is triggered — by the user, by Claude, or both
Slash command
/adobe-pack:adobe-local-dev-loopThis skill is limited to the following tools:
The summary Claude sees in its skill listing — used to decide when to auto-load this skill
Set up a fast local development workflow for Adobe integrations using the `aio` CLI for App Builder projects, or a standalone Node.js setup for direct API usage (Firefly Services, PDF Services).
Set up a fast local development workflow for Adobe integrations using the aio CLI for App Builder projects, or a standalone Node.js setup for direct API usage (Firefly Services, PDF Services).
adobe-install-auth setup@adobe/aio-cli installed globally (for App Builder projects)Option A — App Builder (serverless Runtime actions):
# Install Adobe I/O CLI
npm install -g @adobe/aio-cli
# Login (opens browser for IMS auth)
aio login
# Create new App Builder project
aio app init my-adobe-app
# Select: Firefly Services, Adobe I/O Events, etc.
# Run locally with hot reload
aio app run
# Serves at https://localhost:9080 with live Runtime action emulation
Option B — Standalone SDK project:
mkdir my-adobe-project && cd my-adobe-project
npm init -y
npm install @adobe/pdfservices-node-sdk @adobe/firefly-apis dotenv
npm install -D typescript tsx vitest @types/node
my-adobe-project/
├── src/
│ ├── adobe/
│ │ ├── auth.ts # OAuth token management (from install-auth)
│ │ ├── firefly.ts # Firefly API client wrapper
│ │ ├── pdf-services.ts # PDF Services client wrapper
│ │ └── photoshop.ts # Photoshop API client wrapper
│ └── index.ts
├── tests/
│ ├── fixtures/
│ │ └── sample.pdf # Test PDF for extraction tests
│ ├── adobe-auth.test.ts
│ └── firefly.test.ts
├── .env.local # Local secrets (git-ignored)
├── .env.example # Template for team
├── tsconfig.json
└── package.json
{
"scripts": {
"dev": "tsx watch src/index.ts",
"test": "vitest",
"test:watch": "vitest --watch",
"test:integration": "vitest --config vitest.integration.config.ts",
"typecheck": "tsc --noEmit"
}
}
// tests/adobe-auth.test.ts
import { describe, it, expect, vi, beforeEach } from 'vitest';
// Mock the global fetch for token endpoint
const mockFetch = vi.fn();
global.fetch = mockFetch;
import { getAdobeAccessToken } from '../src/adobe/auth';
describe('Adobe OAuth Auth', () => {
beforeEach(() => {
vi.clearAllMocks();
process.env.ADOBE_CLIENT_ID = 'test-client-id';
process.env.ADOBE_CLIENT_SECRET = 'test-secret';
process.env.ADOBE_SCOPES = 'openid,AdobeID';
});
it('should fetch and cache access token', async () => {
mockFetch.mockResolvedValueOnce({
ok: true,
json: async () => ({
access_token: 'test-token-123',
token_type: 'bearer',
expires_in: 86400,
}),
});
const token = await getAdobeAccessToken();
expect(token).toBe('test-token-123');
expect(mockFetch).toHaveBeenCalledWith(
'https://ims-na1.adobelogin.com/ims/token/v3',
expect.objectContaining({ method: 'POST' })
);
});
it('should throw on auth failure', async () => {
mockFetch.mockResolvedValueOnce({
ok: false,
status: 401,
text: async () => 'invalid_client',
});
await expect(getAdobeAccessToken()).rejects.toThrow('Adobe auth failed');
});
});
// tests/firefly-integration.test.ts
import { describe, it, expect } from 'vitest';
import { getAdobeAccessToken } from '../src/adobe/auth';
describe.skipIf(!process.env.ADOBE_CLIENT_ID)('Firefly Integration', () => {
it('should generate an image from prompt', async () => {
const token = await getAdobeAccessToken();
const response = await fetch(
'https://firefly-api.adobe.io/v3/images/generate',
{
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'x-api-key': process.env.ADOBE_CLIENT_ID!,
'Content-Type': 'application/json',
},
body: JSON.stringify({
prompt: 'A simple red circle on white background',
n: 1,
size: { width: 512, height: 512 },
}),
}
);
expect(response.ok).toBe(true);
const result = await response.json();
expect(result.outputs).toHaveLength(1);
expect(result.outputs[0].image.url).toMatch(/^https:\/\//);
}, 30_000); // 30s timeout for API call
});
tsx watch.env.example template for team onboarding| Error | Cause | Solution |
|---|---|---|
aio login hangs | Browser popup blocked | Use aio login --no-open and copy URL manually |
Module not found: @adobe/pdfservices-node-sdk | Missing install | Run npm install @adobe/pdfservices-node-sdk |
| Test timeout on integration | Slow API or rate limit | Increase vitest timeout; check Retry-After header |
ADOBE_CLIENT_ID undefined | Missing .env.local | Copy .env.example to .env.local and fill in values |
See adobe-sdk-patterns for production-ready code patterns.
npx claudepluginhub jeremylongshore/claude-code-plugins-plus-skills --plugin adobe-packImplements layered TypeScript project structure for production Adobe API integrations with Firefly Services, PDF Services, I/O Events, and App Builder, including OAuth auth, error handling, and health checks.
Creates, edits, and optimizes skills for Claude Code, including drafting, evaluating with test prompts, iterating on performance, and improving skill descriptions for better triggering accuracy.