From 27e7d4564621b7f417c42a71df7461a122a82e15 Mon Sep 17 00:00:00 2001 From: Ajax Davis Date: Thu, 15 Jan 2026 04:56:52 +1000 Subject: [PATCH] feat(sprites): add sprites-url-get and sprites-url-set tools New tools for managing sprite URL access settings: - sprites-url-get: Get the public URL and auth settings for a sprite - sprites-url-set: Set URL auth to 'public' or 'sprite' (private) Both published as @tpmjs/tools-sprites-url-get and @tpmjs/tools-sprites-url-set v0.1.0 --- .../official/sprites-url-get/package.json | 70 ++++++++++ .../official/sprites-url-get/src/index.ts | 110 +++++++++++++++ .../official/sprites-url-get/tsconfig.json | 11 ++ .../official/sprites-url-get/tsup.config.ts | 10 ++ .../official/sprites-url-set/package.json | 76 +++++++++++ .../official/sprites-url-set/src/index.ts | 125 ++++++++++++++++++ .../official/sprites-url-set/tsconfig.json | 11 ++ .../official/sprites-url-set/tsup.config.ts | 10 ++ pnpm-lock.yaml | 32 +++++ 9 files changed, 455 insertions(+) create mode 100644 packages/tools/official/sprites-url-get/package.json create mode 100644 packages/tools/official/sprites-url-get/src/index.ts create mode 100644 packages/tools/official/sprites-url-get/tsconfig.json create mode 100644 packages/tools/official/sprites-url-get/tsup.config.ts create mode 100644 packages/tools/official/sprites-url-set/package.json create mode 100644 packages/tools/official/sprites-url-set/src/index.ts create mode 100644 packages/tools/official/sprites-url-set/tsconfig.json create mode 100644 packages/tools/official/sprites-url-set/tsup.config.ts diff --git a/packages/tools/official/sprites-url-get/package.json b/packages/tools/official/sprites-url-get/package.json new file mode 100644 index 0000000..e63a92e --- /dev/null +++ b/packages/tools/official/sprites-url-get/package.json @@ -0,0 +1,70 @@ +{ + "name": "@tpmjs/tools-sprites-url-get", + "version": "0.1.0", + "description": "Get the public URL and access settings for a sprite", + "type": "module", + "keywords": [ + "tpmjs", + "sprites", + "sandbox", + "code-execution", + "ai" + ], + "exports": { + ".": { + "types": "./dist/index.d.ts", + "default": "./dist/index.js" + } + }, + "files": [ + "dist" + ], + "scripts": { + "build": "tsup", + "dev": "tsup --watch", + "type-check": "tsc --noEmit", + "clean": "rm -rf dist .turbo" + }, + "devDependencies": { + "@tpmjs/tsconfig": "workspace:*", + "tsup": "^8.5.1", + "typescript": "^5.9.3" + }, + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "https://github.com/anthropics/tpmjs.git", + "directory": "packages/tools/official/sprites-url-get" + }, + "homepage": "https://tpmjs.com", + "license": "MIT", + "tpmjs": { + "category": "sandbox", + "frameworks": [ + "vercel-ai" + ], + "tools": [ + { + "name": "spritesUrlGetTool", + "description": "Get the public URL and access settings for a sprite. Returns the URL that can be used to access web servers running on port 8080 in the sprite.", + "parameters": [ + { + "name": "name", + "type": "string", + "description": "Name of the sprite to get URL for", + "required": true + } + ], + "returns": { + "type": "SpriteUrl", + "description": "Sprite URL and auth settings" + } + } + ] + }, + "dependencies": { + "ai": "6.0.23" + } +} diff --git a/packages/tools/official/sprites-url-get/src/index.ts b/packages/tools/official/sprites-url-get/src/index.ts new file mode 100644 index 0000000..cf6fded --- /dev/null +++ b/packages/tools/official/sprites-url-get/src/index.ts @@ -0,0 +1,110 @@ +/** + * Sprites URL Get Tool for TPMJS + * Retrieves the public URL and access settings for a sprite. + * + * @requires SPRITES_TOKEN environment variable + */ + +import { jsonSchema, tool } from 'ai'; + +const SPRITES_API_BASE = 'https://api.sprites.dev/v1'; + +export interface SpriteUrl { + url: string; + auth: 'sprite' | 'public'; + name: string; + status: string; +} + +type SpritesUrlGetInput = { + name: string; +}; + +function getSpritesToken(): string { + const token = process.env.SPRITES_TOKEN; + if (!token) { + throw new Error( + 'SPRITES_TOKEN environment variable is required. Get your token from https://sprites.dev' + ); + } + return token; +} + +export const spritesUrlGetTool = tool({ + description: + 'Get the public URL and access settings for a sprite. Returns the URL that can be used to access web servers running on port 8080 in the sprite. The URL format is https://{name}-{id}.sprites.app', + inputSchema: jsonSchema({ + type: 'object', + properties: { + name: { + type: 'string', + description: 'Name of the sprite to get URL for', + }, + }, + required: ['name'], + additionalProperties: false, + }), + async execute({ name }): Promise { + if (!name || typeof name !== 'string') { + throw new Error('Sprite name is required and must be a string'); + } + + const token = getSpritesToken(); + + let response: Response; + try { + const controller = new AbortController(); + const timeoutId = setTimeout(() => controller.abort(), 30000); + + response = await fetch(`${SPRITES_API_BASE}/sprites/${encodeURIComponent(name)}`, { + method: 'GET', + headers: { + Authorization: `Bearer ${token}`, + 'User-Agent': 'TPMJS/1.0', + }, + signal: controller.signal, + }); + + clearTimeout(timeoutId); + } catch (error) { + if (error instanceof Error) { + if (error.name === 'AbortError') { + throw new Error(`Request to get URL for sprite "${name}" timed out`); + } + throw new Error(`Failed to get URL for sprite "${name}": ${error.message}`); + } + throw new Error(`Failed to get URL for sprite "${name}": Unknown network error`); + } + + if (!response.ok) { + if (response.status === 404) { + throw new Error(`Sprite "${name}" not found`); + } + if (response.status === 401) { + throw new Error('Invalid SPRITES_TOKEN. Check your API token at https://sprites.dev'); + } + const errorText = await response.text().catch(() => 'Unknown error'); + throw new Error( + `Failed to get URL for sprite "${name}": HTTP ${response.status} - ${errorText}` + ); + } + + let data: Record; + try { + data = (await response.json()) as Record; + } catch { + throw new Error('Failed to parse response from Sprites API'); + } + + const urlSettings = data.url_settings as Record | undefined; + + return { + url: (data.url as string) || '', + auth: (urlSettings?.auth as 'sprite' | 'public') || 'sprite', + name: (data.name as string) || name, + status: (data.status as string) || 'unknown', + }; + }, +}); + +export default spritesUrlGetTool; diff --git a/packages/tools/official/sprites-url-get/tsconfig.json b/packages/tools/official/sprites-url-get/tsconfig.json new file mode 100644 index 0000000..6521d56 --- /dev/null +++ b/packages/tools/official/sprites-url-get/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "@tpmjs/tsconfig/base.json", + "compilerOptions": { + "outDir": "dist", + "rootDir": "src", + "incremental": false, + "composite": false + }, + "include": ["src"], + "exclude": ["node_modules", "dist"] +} diff --git a/packages/tools/official/sprites-url-get/tsup.config.ts b/packages/tools/official/sprites-url-get/tsup.config.ts new file mode 100644 index 0000000..a242871 --- /dev/null +++ b/packages/tools/official/sprites-url-get/tsup.config.ts @@ -0,0 +1,10 @@ +import { defineConfig } from 'tsup'; + +export default defineConfig({ + entry: ['src/index.ts'], + format: ['esm'], + dts: true, + clean: true, + treeshake: true, + splitting: false, +}); diff --git a/packages/tools/official/sprites-url-set/package.json b/packages/tools/official/sprites-url-set/package.json new file mode 100644 index 0000000..e433593 --- /dev/null +++ b/packages/tools/official/sprites-url-set/package.json @@ -0,0 +1,76 @@ +{ + "name": "@tpmjs/tools-sprites-url-set", + "version": "0.1.0", + "description": "Set the access settings for a sprite URL (public or private)", + "type": "module", + "keywords": [ + "tpmjs", + "sprites", + "sandbox", + "code-execution", + "ai" + ], + "exports": { + ".": { + "types": "./dist/index.d.ts", + "default": "./dist/index.js" + } + }, + "files": [ + "dist" + ], + "scripts": { + "build": "tsup", + "dev": "tsup --watch", + "type-check": "tsc --noEmit", + "clean": "rm -rf dist .turbo" + }, + "devDependencies": { + "@tpmjs/tsconfig": "workspace:*", + "tsup": "^8.5.1", + "typescript": "^5.9.3" + }, + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "https://github.com/anthropics/tpmjs.git", + "directory": "packages/tools/official/sprites-url-set" + }, + "homepage": "https://tpmjs.com", + "license": "MIT", + "tpmjs": { + "category": "sandbox", + "frameworks": [ + "vercel-ai" + ], + "tools": [ + { + "name": "spritesUrlSetTool", + "description": "Set the access settings for a sprite URL. Use 'public' to allow anyone to access the sprite URL, or 'sprite' to require authentication.", + "parameters": [ + { + "name": "name", + "type": "string", + "description": "Name of the sprite to update", + "required": true + }, + { + "name": "auth", + "type": "string", + "description": "Access mode - 'public' for public access, 'sprite' for authenticated access only", + "required": true + } + ], + "returns": { + "type": "SpriteUrlResult", + "description": "Updated sprite URL and settings" + } + } + ] + }, + "dependencies": { + "ai": "6.0.23" + } +} diff --git a/packages/tools/official/sprites-url-set/src/index.ts b/packages/tools/official/sprites-url-set/src/index.ts new file mode 100644 index 0000000..bf474f4 --- /dev/null +++ b/packages/tools/official/sprites-url-set/src/index.ts @@ -0,0 +1,125 @@ +/** + * Sprites URL Set Tool for TPMJS + * Sets the access settings for a sprite URL (public or private). + * + * @requires SPRITES_TOKEN environment variable + */ + +import { jsonSchema, tool } from 'ai'; + +const SPRITES_API_BASE = 'https://api.sprites.dev/v1'; + +export interface SpriteUrlResult { + url: string; + auth: 'sprite' | 'public'; + name: string; + updated: boolean; +} + +type SpritesUrlSetInput = { + name: string; + auth: 'sprite' | 'public'; +}; + +function getSpritesToken(): string { + const token = process.env.SPRITES_TOKEN; + if (!token) { + throw new Error( + 'SPRITES_TOKEN environment variable is required. Get your token from https://sprites.dev' + ); + } + return token; +} + +export const spritesUrlSetTool = tool({ + description: + "Set the access settings for a sprite URL. Use 'public' to allow anyone to access the sprite URL (for web servers, APIs, webhooks), or 'sprite' to require authentication. The sprite must have a server listening on port 8080 for the URL to work.", + inputSchema: jsonSchema({ + type: 'object', + properties: { + name: { + type: 'string', + description: 'Name of the sprite to update', + }, + auth: { + type: 'string', + enum: ['sprite', 'public'], + description: + "Access mode - 'public' for public access, 'sprite' for authenticated access only", + }, + }, + required: ['name', 'auth'], + additionalProperties: false, + }), + async execute({ name, auth }): Promise { + if (!name || typeof name !== 'string') { + throw new Error('Sprite name is required and must be a string'); + } + if (auth !== 'sprite' && auth !== 'public') { + throw new Error("Auth must be 'sprite' or 'public'"); + } + + const token = getSpritesToken(); + + let response: Response; + try { + const controller = new AbortController(); + const timeoutId = setTimeout(() => controller.abort(), 30000); + + // PUT /v1/sprites/{name} with url_settings + response = await fetch(`${SPRITES_API_BASE}/sprites/${encodeURIComponent(name)}`, { + method: 'PUT', + headers: { + Authorization: `Bearer ${token}`, + 'Content-Type': 'application/json', + 'User-Agent': 'TPMJS/1.0', + }, + body: JSON.stringify({ + url_settings: { auth }, + }), + signal: controller.signal, + }); + + clearTimeout(timeoutId); + } catch (error) { + if (error instanceof Error) { + if (error.name === 'AbortError') { + throw new Error(`Request to set URL auth for sprite "${name}" timed out`); + } + throw new Error(`Failed to set URL auth for sprite "${name}": ${error.message}`); + } + throw new Error(`Failed to set URL auth for sprite "${name}": Unknown network error`); + } + + if (!response.ok) { + if (response.status === 404) { + throw new Error(`Sprite "${name}" not found`); + } + if (response.status === 401) { + throw new Error('Invalid SPRITES_TOKEN. Check your API token at https://sprites.dev'); + } + const errorText = await response.text().catch(() => 'Unknown error'); + throw new Error( + `Failed to set URL auth for sprite "${name}": HTTP ${response.status} - ${errorText}` + ); + } + + let data: Record; + try { + data = (await response.json()) as Record; + } catch { + throw new Error('Failed to parse response from Sprites API'); + } + + const urlSettings = data.url_settings as Record | undefined; + + return { + url: (data.url as string) || '', + auth: (urlSettings?.auth as 'sprite' | 'public') || auth, + name: (data.name as string) || name, + updated: true, + }; + }, +}); + +export default spritesUrlSetTool; diff --git a/packages/tools/official/sprites-url-set/tsconfig.json b/packages/tools/official/sprites-url-set/tsconfig.json new file mode 100644 index 0000000..6521d56 --- /dev/null +++ b/packages/tools/official/sprites-url-set/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "@tpmjs/tsconfig/base.json", + "compilerOptions": { + "outDir": "dist", + "rootDir": "src", + "incremental": false, + "composite": false + }, + "include": ["src"], + "exclude": ["node_modules", "dist"] +} diff --git a/packages/tools/official/sprites-url-set/tsup.config.ts b/packages/tools/official/sprites-url-set/tsup.config.ts new file mode 100644 index 0000000..a242871 --- /dev/null +++ b/packages/tools/official/sprites-url-set/tsup.config.ts @@ -0,0 +1,10 @@ +import { defineConfig } from 'tsup'; + +export default defineConfig({ + entry: ['src/index.ts'], + format: ['esm'], + dts: true, + clean: true, + treeshake: true, + splitting: false, +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 06cf916..db0bdf2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -3187,6 +3187,38 @@ importers: specifier: ^5.9.3 version: 5.9.3 + packages/tools/official/sprites-url-get: + dependencies: + ai: + specifier: 6.0.23 + version: 6.0.23(zod@4.3.5) + devDependencies: + '@tpmjs/tsconfig': + specifier: workspace:* + version: link:../../../config/tsconfig + tsup: + specifier: ^8.5.1 + version: 8.5.1(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.2) + typescript: + specifier: ^5.9.3 + version: 5.9.3 + + packages/tools/official/sprites-url-set: + dependencies: + ai: + specifier: 6.0.23 + version: 6.0.23(zod@4.3.5) + devDependencies: + '@tpmjs/tsconfig': + specifier: workspace:* + version: link:../../../config/tsconfig + tsup: + specifier: ^8.5.1 + version: 8.5.1(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.2) + typescript: + specifier: ^5.9.3 + version: 5.9.3 + packages/tools/official/stacktrace-parse: dependencies: ai: