@decoloop/aistudio-client
v0.1.0
Published
Professional TypeScript client for creating secure AI Studio sessions on the server and generating product visualizations in the browser.
Downloads
157
Readme
@decoloop/aistudio-client
Professional TypeScript client for creating secure AI Studio sessions on the server and generating product visualizations in the browser.
Overview
@decoloop/aistudio-client is split into two focused clients:
AiStudioServerClientcreates short-lived browser session tokens from a trusted server environment.AiStudioBrowserClientuses those session tokens from the browser to submit room photos, product metadata, and optional texture data for image generation.
This split keeps the permanent AI Studio API key out of browser code. The server owns the secret API key and exchanges it for a constrained session token. The browser only receives that temporary session token and uses it for generation requests.
Token authentication flow
The API key must only be used by backend code. Browser code must authenticate with a session token returned by AiStudioServerClient.createSession.
+-------------+ 1. Request session +------------------+
| Browser | -------------------------------> | Your backend |
+-------------+ +------------------+
^ |
| | 2. Create session
| | with API key
| v
| +------------------+
| | AI Studio |
| +------------------+
| |
| 3. Return session token |
+---------------------------------------------------+
|
| 4. Generate image with session token
v
+-------------+ +------------------+
| Browser | -------------------------------> | AI Studio |
+-------------+ +------------------+Recommended flow:
- The browser calls an endpoint on your backend to request an AI Studio session.
- Your backend uses
AiStudioServerClientwith the permanent API key. - AI Studio returns a session token.
- Your backend returns only the session token to the browser.
- The browser uses
AiStudioBrowserClientwith the session token to generate images.
Installation & imports
Install the package from the workspace package registry or consume it directly from the monorepo library.
npm install @decoloop/aistudio-clientImport the server client only from backend code:
import {
AiStudioServerClient,
type SessionRequest,
type SessionResponse,
} from '@decoloop/aistudio-client';Import the browser client from frontend code:
import {
AiStudioBrowserClient,
ModelId,
ProductType,
type ImageGenerationOptions,
} from '@decoloop/aistudio-client';Server-side usage
Use AiStudioServerClient in a trusted server runtime. The constructor intentionally throws when instantiated in a browser environment to prevent accidental API key exposure.
import {
AiStudioServerClient,
type SessionRequest,
type SessionResponse,
} from '@decoloop/aistudio-client';
const aiStudio = new AiStudioServerClient({
apiKey: process.env.AISTUDIO_API_KEY!,
baseUrl: 'https://api.example.com',
});
export async function createAiStudioSession(): Promise<SessionResponse> {
const request: SessionRequest = {
maxUses: 3,
expiresInSeconds: 900,
allowedOrigins: ['https://customer.example.com'],
metadata: 'customer-project-123',
};
return await aiStudio.createSession(request);
}Example Express route:
import express from 'express';
import { AiStudioServerClient } from '@decoloop/aistudio-client';
const router = express.Router();
const aiStudio = new AiStudioServerClient({
apiKey: process.env.AISTUDIO_API_KEY!,
baseUrl: process.env.AISTUDIO_BASE_URL!,
});
router.post('/aistudio/session', async (_request, response, next) => {
try {
const session = await aiStudio.createSession({
maxUses: 1,
expiresInSeconds: 600,
allowedOrigins: ['https://customer.example.com'],
metadata: 'image-generation-checkout',
});
response.json(session);
} catch (error) {
next(error);
}
});
export default router;AiStudioServerClient configuration
| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| apiKey | string | Yes | Permanent AI Studio API key. Keep this value on the server only. |
| baseUrl | string | Yes | Base URL of the AI Studio API. A trailing slash is removed automatically. |
createSession(request) parameters
| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| maxUses | number | No | Maximum number of generation requests allowed for the returned session token. |
| expiresInSeconds | number | No | Session lifetime in seconds. Prefer short-lived tokens. |
| allowedOrigins | string[] | No | Browser origins allowed to use the session token. Use exact production origins. |
| metadata | string | No | Application-defined metadata for tracing or auditing the session. |
createSession(request) response
interface SessionResponse {
token: string;
}Return token to the browser. Do not return the permanent API key or any server-side configuration.
Browser-side usage
Use AiStudioBrowserClient after your frontend has obtained a session token from your backend.
import {
AiStudioBrowserClient,
ModelId,
ProductType,
type ImageGenerationOptions,
} from '@decoloop/aistudio-client';
async function generateCurtainPreview(roomPhoto: File): Promise<string> {
const sessionResponse = await fetch('/api/aistudio/session', {
method: 'POST',
});
if (!sessionResponse.ok) {
throw new Error('Unable to create AI Studio session.');
}
const { token } = (await sessionResponse.json()) as { token: string };
const client = new AiStudioBrowserClient({
sessionToken: token,
baseUrl: 'https://api.example.com',
});
const options: ImageGenerationOptions = {
textureId: 'linen-warm-white',
width: 280,
height: 240,
lining: 'blackout',
};
const imageBlob = await client.generateImage(
roomPhoto,
ProductType.Curtains,
ModelId.DoublePleat,
options,
);
return URL.createObjectURL(imageBlob);
}Example with a custom texture file:
const imageBlob = await client.generateImage(
roomPhoto,
ProductType.RollerBlind,
ModelId.RollerStandard,
{
customTexture: textureFile,
opacity: 0.92,
chainSide: 'right',
},
);AiStudioBrowserClient configuration
| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| sessionToken | string | Yes | Short-lived token created by AiStudioServerClient.createSession. |
| baseUrl | string | Yes | Base URL of the AI Studio API. A trailing slash is removed automatically. |
generateImage(roomPhoto, productType, modelId, options) parameters
| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| roomPhoto | Blob \| File | Yes | Source room image to use for visualization. |
| productType | ProductType | Yes | Product category to render, such as curtains or roller blinds. |
| modelId | ModelId | Yes | Product model identifier. Use a model compatible with the selected product type. |
| options | ImageGenerationOptions | No | Optional texture and product settings. |
generateImage(...) response
generateImage returns a Promise<Blob> containing the generated image. Convert it to an object URL for previewing in the browser, upload it to storage, or pass it to another browser API.
const imageBlob = await client.generateImage(
roomPhoto,
ProductType.Curtains,
ModelId.Wave,
);
const previewUrl = URL.createObjectURL(imageBlob);How options is serialized
AiStudioBrowserClient sends generation requests as multipart/form-data with these parts:
| Form part | Content | Description |
| --- | --- | --- |
| metadata | JSON Blob | Contains productType, modelId, optional textureId, and a settings object. |
| roomPhoto | Blob \| File | Source room image. |
| customTexture | Blob \| File | Optional texture image when options.customTexture is provided. |
The metadata JSON is shaped as follows:
{
"productType": "Curtains",
"modelId": "double_pleat",
"textureId": "linen-warm-white",
"settings": {
"width": "280",
"height": "240",
"lining": "blackout"
}
}Serialization rules:
productTypeandmodelIdare always included inmetadata.options.textureIdis copied tometadata.textureId.options.customTextureis appended as the separatecustomTextureform part.customTextureandtextureIdare not copied intometadata.settings.- Every other defined, non-null option is copied into
metadata.settingsand converted withString(value). - The browser request uses
Authorization: Bearer <sessionToken>and does not manually setContent-Type, allowing the browser to add the multipart boundary.
Types & API references
ProductType
enum ProductType {
Curtains = 'Curtains',
RollerBlind = 'RollerBlind',
}ModelId
enum ModelId {
SinglePleat = 'single_pleat',
DoublePleat = 'double_pleat',
Wave = 'wave',
Eyelet = 'eyelet',
RomanBlind = 'roman_blind',
RollerStandard = 'roller_standard',
}SessionRequest
interface SessionRequest {
maxUses?: number;
expiresInSeconds?: number;
allowedOrigins?: string[];
metadata?: string;
}SessionResponse
interface SessionResponse {
token: string;
}ImageGenerationOptions
interface ImageGenerationOptions {
customTexture?: Blob | File;
textureId?: string;
[key: string]: any;
}Use textureId for server-known textures and customTexture for user-provided texture files. Additional keys are supported for product-specific settings and are serialized into the settings object.
Security & best practices
- Never instantiate
AiStudioServerClientin browser code. - Never expose the permanent AI Studio API key to frontend bundles, HTML, logs, telemetry, or network responses.
- Store the API key in a secure server-side secret store or environment variable.
- Create short-lived session tokens with the smallest practical
expiresInSecondsvalue. - Limit
maxUsesto the number of generations required for the current user action. - Set
allowedOriginsto exact trusted origins instead of broad wildcard-like values. - Validate uploaded images before passing them to AI Studio, including file size, MIME type, and user permissions.
- Avoid logging session tokens, generated image payloads, room photos, or custom texture files.
- Revoke or rotate permanent API keys according to your organization security policy.
Error handling and license
Both clients throw an Error when AI Studio responds with a non-success HTTP status.
- Session creation failures use the message format
AiStudio session creation failed: <status> <statusText>. - Image generation failures use the message format
AiStudio image generation failed: <status> <statusText>. - Network failures and malformed responses are surfaced by the underlying
fetchimplementation.
Recommended handling:
try {
const imageBlob = await client.generateImage(
roomPhoto,
ProductType.Curtains,
ModelId.SinglePleat,
);
return URL.createObjectURL(imageBlob);
} catch (error) {
console.error('AI Studio generation failed.', error);
throw new Error('The preview could not be generated. Please try again.');
}This package is proprietary software owned by Sieval. All rights are reserved. Usage, copying, modification, and distribution are only permitted under an agreement with Sieval or another explicitly granted written license.
