Skip to main content ホーム クリエイター comeonoliver skillshub adobe-sdk-patterns
adobe-sdk-patterns Apply production-ready patterns for Adobe Firefly Services SDK, PDF Services SDK,
and raw REST API usage in TypeScript and Python.
Use when implementing Adobe integrations, refactoring SDK usage,
or establishing team coding standards for Adobe APIs.
Trigger with phrases like "adobe SDK patterns", "adobe best practices",
"adobe code patterns", "idiomatic adobe", "adobe typescript".
インストールへ移動 Skills Marketplace コミュニティが作成したAIスキルを発見・探索
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
直接コマンドでは確認用 Prompt が省略されます。実行前にソースを確認してください。
npx skills add https://github.com/ComeOnOliver/skillshub --skill adobe-sdk-patternsコマンドは1行のまま表示されます。コピー前に横へスクロールして全体を確認してください。
ローカルで確認しますか?SkillsMP が現在取得できるファイルをダウンロードできます。
Zipをダウンロード ダウンロード中... このリポジトリの他の Skills Review product and feature risk before an AI coding agent starts implementation.
Use Xquik for X data and confirmation-gated X actions: tweet search, user lookup, follower export, media download, monitors, webhooks, MCP, and SDK workflows.
Canton Network open-source ecosystem guide covering DAML SDK, Canton runtime, and Splice applications. Use when working with Canton Network, DAML smart contracts, or building decentralized applications.
name adobe-sdk-patterns description Apply production-ready patterns for Adobe Firefly Services SDK, PDF Services SDK,
and raw REST API usage in TypeScript and Python.
Use when implementing Adobe integrations, refactoring SDK usage,
or establishing team coding standards for Adobe APIs.
Trigger with phrases like "adobe SDK patterns", "adobe best practices",
"adobe code patterns", "idiomatic adobe", "adobe typescript".
allowed-tools Read, Write, Edit version 1.0.0 license MIT author Jeremy Longshore <jeremy@intentsolutions.io> tags ["saas","design","adobe"] compatible-with claude-code
Adobe SDK Patterns
Overview
Production-ready patterns for Adobe SDK usage across Firefly Services (@adobe/firefly-apis, @adobe/photoshop-apis, @adobe/lightroom-apis), PDF Services (@adobe/pdfservices-node-sdk), and direct REST API calls.
Prerequisites
Completed adobe-install-auth setup
Familiarity with async/await patterns
Understanding of the Adobe API you are integrating
Instructions
Pattern 1: Singleton Auth Client with Token Caching
import { ServicePrincipalCredentials , PDFServices } from '@adobe/pdfservices-node-sdk' ;
let pdfServicesInstance : PDFServices | null = null ;
let tokenCache : { token : string ; expiresAt : number } | null = null ;
export function getPDFServices ( ): PDFServices {
if (!pdfServicesInstance) {
const credentials = new ServicePrincipalCredentials ({
clientId : process.env .ADOBE_CLIENT_ID !,
clientSecret : process.env .ADOBE_CLIENT_SECRET !,
});
pdfServicesInstance = new PDFServices ({ credentials });
}
return pdfServicesInstance;
}
( ): < > {
(tokenCache && tokenCache. > . () + ) {
tokenCache. ;
}
res = ( , {
: ,
: { : },
: ({
: process. . !,
: process. . !,
: ,
: process. . !,
}),
});
(!res. ) ( );
data = res. ();
tokenCache = { : data. , : . () + data. * };
tokenCache. ;
}
export
async
function
getAccessToken
Promise
string
if
expiresAt
Date
now
300_000
return
token
const
await
fetch
'https://ims-na1.adobelogin.com/ims/token/v3'
method
'POST'
headers
'Content-Type'
'application/x-www-form-urlencoded'
body
new
URLSearchParams
client_id
env
ADOBE_CLIENT_ID
client_secret
env
ADOBE_CLIENT_SECRET
grant_type
'client_credentials'
scope
env
ADOBE_SCOPES
if
ok
throw
new
Error
`Adobe IMS token error: ${res.status} `
const
await
json
token
access_token
expiresAt
Date
now
expires_in
1000
return
token
Pattern 2: Typed API Wrapper with Error Classification
export class AdobeApiError extends Error {
constructor (
message : string ,
public readonly status : number ,
public readonly code : string ,
public readonly retryable : boolean ,
public readonly retryAfter ?: number
) {
super (message);
this .name = 'AdobeApiError' ;
}
}
export async function adobeApiFetch<T>(
url : string ,
options : RequestInit & { apiKey ?: string }
): Promise <T> {
const token = await getAccessToken ();
const { apiKey, ...fetchOptions } = options;
const response = await fetch (url, {
...fetchOptions,
headers : {
'Authorization' : `Bearer ${token} ` ,
'x-api-key' : apiKey || process.env .ADOBE_CLIENT_ID !,
'Content-Type' : 'application/json' ,
...fetchOptions.headers ,
},
});
if (!response.ok ) {
const body = await response.text ();
const retryAfter = response.headers .get ('Retry-After' );
throw new AdobeApiError (
`Adobe API ${response.status} : ${body} ` ,
response.status ,
response.status === 429 ? 'RATE_LIMITED' :
response.status === 401 ? 'AUTH_EXPIRED' :
response.status >= 500 ? 'SERVER_ERROR' : 'CLIENT_ERROR' ,
response.status === 429 || response.status >= 500 ,
retryAfter ? parseInt (retryAfter) : undefined
);
}
return response.json ();
}
Pattern 3: Retry with Exponential Backoff
export async function withRetry<T>(
operation : () => Promise <T>,
config = { maxRetries : 3 , baseDelayMs : 1000 }
): Promise <T> {
for (let attempt = 0 ; attempt <= config.maxRetries ; attempt++) {
try {
return await operation ();
} catch (err : any ) {
if (attempt === config.maxRetries ) throw err;
if (err instanceof AdobeApiError && !err.retryable ) throw err;
const delay = err.retryAfter
? err.retryAfter * 1000
: config.baseDelayMs * Math .pow (2 , attempt) + Math .random () * 500 ;
console .warn (`Adobe retry ${attempt + 1 } /${config.maxRetries} in ${delay} ms` );
await new Promise (r => setTimeout (r, delay));
}
}
throw new Error ('Unreachable' );
}
Pattern 4: Job Polling for Async APIs (Photoshop, Lightroom)
interface AdobeJobStatus {
status : 'pending' | 'running' | 'succeeded' | 'failed' ;
_links ?: { self : { href : string } };
output ?: any ;
error ?: { code : string ; message : string };
}
export async function pollAdobeJob (
statusUrl : string ,
options = { intervalMs: 2000 , timeoutMs: 120_000 }
): Promise <AdobeJobStatus > {
const token = await getAccessToken ();
const deadline = Date .now () + options.timeoutMs ;
while (Date .now () < deadline) {
const res = await fetch (statusUrl, {
headers : {
'Authorization' : `Bearer ${token} ` ,
'x-api-key' : process.env .ADOBE_CLIENT_ID !,
},
});
const status : AdobeJobStatus = await res.json ();
if (status.status === 'succeeded' ) return status;
if (status.status === 'failed' ) {
throw new Error (`Adobe job failed: ${status.error?.message || 'Unknown error' } ` );
}
await new Promise (r => setTimeout (r, options.intervalMs ));
}
throw new Error ('Adobe job polling timeout' );
}
Pattern 5: Zod Validation for API Responses import { z } from 'zod' ;
const FireflyImageOutputSchema = z.object ({
outputs : z.array (z.object ({
image : z.object ({
url : z.string ().url (),
}),
seed : z.number (),
})),
});
const PhotoshopJobSchema = z.object ({
status : z.enum (['pending' , 'running' , 'succeeded' , 'failed' ]),
_links : z.object ({
self : z.object ({ href : z.string ().url () }),
}).optional (),
});
const raw = await adobeApiFetch<unknown >(fireflyUrl, { method : 'POST' , body });
const validated = FireflyImageOutputSchema .parse (raw);
Output
Type-safe client singleton with token caching
Error classification (retryable vs permanent)
Automatic retry with Adobe Retry-After header support
Async job polling for Photoshop/Lightroom operations
Zod runtime validation for API responses
Error Handling Pattern Use Case Benefit Token caching All API calls Avoids redundant IMS token requests Error classification Retry decisions Only retries transient failures Job polling Photoshop/Lightroom Handles async operation lifecycle Zod validation All responses Catches API contract changes at runtime
Resources
Next Steps Apply patterns in adobe-core-workflow-a for real-world usage.