@coduckai/sdk 0.2.0 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ai/index.cjs +2 -2
- package/dist/ai/index.cjs.map +1 -1
- package/dist/ai/index.js +2 -2
- package/dist/ai/index.js.map +1 -1
- package/dist/client/index.cjs +1 -1
- package/dist/client/index.cjs.map +1 -1
- package/dist/client/index.d.cts +1 -1
- package/dist/client/index.d.ts +1 -1
- package/dist/client/index.js +1 -1
- package/dist/client/index.js.map +1 -1
- package/dist/payments/index.cjs +11 -9
- package/dist/payments/index.cjs.map +1 -1
- package/dist/payments/index.d.cts +7 -3
- package/dist/payments/index.d.ts +7 -3
- package/dist/payments/index.js +11 -9
- package/dist/payments/index.js.map +1 -1
- package/package.json +1 -1
package/dist/ai/index.cjs
CHANGED
|
@@ -88,7 +88,7 @@ async function anthropicChat(options) {
|
|
|
88
88
|
const client = new Anthropic({ apiKey: config.ai?.apiKey || process.env.ANTHROPIC_API_KEY });
|
|
89
89
|
const messages = options.messages.filter((m) => m.role !== "system").map((m) => ({ role: m.role, content: m.content }));
|
|
90
90
|
const response = await client.messages.create({
|
|
91
|
-
model: options.model || "claude-sonnet-4-
|
|
91
|
+
model: options.model || "claude-sonnet-4-6",
|
|
92
92
|
max_tokens: options.maxTokens || 4096,
|
|
93
93
|
...options.system && { system: options.system },
|
|
94
94
|
messages,
|
|
@@ -109,7 +109,7 @@ async function* anthropicStreamChat(options) {
|
|
|
109
109
|
const client = new Anthropic({ apiKey: config.ai?.apiKey || process.env.ANTHROPIC_API_KEY });
|
|
110
110
|
const messages = options.messages.filter((m) => m.role !== "system").map((m) => ({ role: m.role, content: m.content }));
|
|
111
111
|
const stream = client.messages.stream({
|
|
112
|
-
model: options.model || "claude-sonnet-4-
|
|
112
|
+
model: options.model || "claude-sonnet-4-6",
|
|
113
113
|
max_tokens: options.maxTokens || 4096,
|
|
114
114
|
...options.system && { system: options.system },
|
|
115
115
|
messages,
|
package/dist/ai/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/internal/env.ts","../../src/internal/config.ts","../../src/ai/index.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Environment variable helpers\n */\n\nexport function getEnv(key: string, fallback?: string): string | undefined {\n return process.env[key] || fallback;\n}\n\nexport function requireEnv(key: string): string {\n const val = process.env[key];\n if (!val) {\n throw new Error(`@coduckai/sdk: Missing required environment variable: ${key}`);\n }\n return val;\n}\n\nexport function isServer(): boolean {\n return typeof window === 'undefined';\n}\n\nexport function assertServer(moduleName: string): void {\n if (!isServer()) {\n throw new Error(\n `@coduckai/sdk/${moduleName} is server-only. Use @coduckai/sdk/client for browser code.`\n );\n }\n}\n","/**\n * Global SDK configuration\n *\n * CoDuck apps use env vars automatically — no configure() needed.\n * Standalone usage can call configure() to override.\n */\n\nexport interface SDKConfig {\n auth?: {\n jwtSecret?: string;\n jwtExpiresIn?: string;\n bcryptRounds?: number;\n };\n db?: {\n connectionString?: string;\n };\n client?: {\n baseUrl?: string;\n tokenKey?: string;\n };\n payments?: {\n stripeSecretKey?: string;\n connectedAccountId?: string;\n webhookSecret?: string;\n };\n ai?: {\n provider?: 'openai' | 'anthropic';\n apiKey?: string;\n };\n}\n\nlet globalConfig: SDKConfig = {};\n\nexport function setConfig(config: SDKConfig): void {\n globalConfig = { ...globalConfig, ...config };\n}\n\nexport function getConfig(): SDKConfig {\n return globalConfig;\n}\n","/**\n * @coduckai/sdk/ai — AI Providers (server-only)\n *\n * Unified interface for OpenAI and Anthropic. Auto-detects provider from env vars.\n * Set OPENAI_API_KEY for OpenAI or ANTHROPIC_API_KEY for Anthropic.\n */\n\nimport { assertServer } from '../internal/env';\nimport { getConfig } from '../internal/config';\n\nassertServer('ai');\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface ChatMessage {\n role: 'user' | 'assistant' | 'system';\n content: string;\n}\n\nexport interface ChatOptions {\n system?: string;\n messages: ChatMessage[];\n model?: string;\n maxTokens?: number;\n temperature?: number;\n}\n\nexport interface ChatResponse {\n text: string;\n usage: { inputTokens: number; outputTokens: number };\n}\n\nexport interface StreamChunk {\n text: string;\n done: boolean;\n}\n\nexport type AIProvider = 'openai' | 'anthropic' | null;\n\n// ---------------------------------------------------------------------------\n// Provider detection\n// ---------------------------------------------------------------------------\n\nfunction detectProvider(): AIProvider {\n const config = getConfig();\n if (config.ai?.provider) return config.ai.provider;\n if (process.env.OPENAI_API_KEY) return 'openai';\n if (process.env.ANTHROPIC_API_KEY) return 'anthropic';\n return null;\n}\n\nfunction requireProvider(): AIProvider & string {\n const provider = detectProvider();\n if (!provider) {\n throw new Error(\n '@coduckai/sdk/ai: No AI provider configured. Set OPENAI_API_KEY or ANTHROPIC_API_KEY.'\n );\n }\n return provider;\n}\n\n// ---------------------------------------------------------------------------\n// OpenAI\n// ---------------------------------------------------------------------------\n\nasync function openaiChat(options: ChatOptions): Promise<ChatResponse> {\n const { default: OpenAI } = await import('openai');\n const config = getConfig();\n const client = new OpenAI({ apiKey: config.ai?.apiKey || process.env.OPENAI_API_KEY });\n\n const messages: Array<{ role: string; content: string }> = [];\n if (options.system) {\n messages.push({ role: 'system', content: options.system });\n }\n messages.push(...options.messages);\n\n const response = await client.chat.completions.create({\n model: options.model || 'gpt-4o',\n messages: messages as any,\n max_tokens: options.maxTokens || 4096,\n temperature: options.temperature ?? 0.7,\n });\n\n return {\n text: response.choices[0]?.message?.content || '',\n usage: {\n inputTokens: response.usage?.prompt_tokens || 0,\n outputTokens: response.usage?.completion_tokens || 0,\n },\n };\n}\n\nasync function* openaiStreamChat(options: ChatOptions): AsyncGenerator<StreamChunk> {\n const { default: OpenAI } = await import('openai');\n const config = getConfig();\n const client = new OpenAI({ apiKey: config.ai?.apiKey || process.env.OPENAI_API_KEY });\n\n const messages: Array<{ role: string; content: string }> = [];\n if (options.system) {\n messages.push({ role: 'system', content: options.system });\n }\n messages.push(...options.messages);\n\n const stream = await client.chat.completions.create({\n model: options.model || 'gpt-4o',\n messages: messages as any,\n max_tokens: options.maxTokens || 4096,\n temperature: options.temperature ?? 0.7,\n stream: true,\n });\n\n for await (const chunk of stream) {\n const text = chunk.choices[0]?.delta?.content || '';\n const done = chunk.choices[0]?.finish_reason !== null && chunk.choices[0]?.finish_reason !== undefined;\n if (text) yield { text, done: false };\n if (done) yield { text: '', done: true };\n }\n}\n\n// ---------------------------------------------------------------------------\n// Anthropic\n// ---------------------------------------------------------------------------\n\nasync function anthropicChat(options: ChatOptions): Promise<ChatResponse> {\n const { default: Anthropic } = await import('@anthropic-ai/sdk');\n const config = getConfig();\n const client = new Anthropic({ apiKey: config.ai?.apiKey || process.env.ANTHROPIC_API_KEY });\n\n const messages = options.messages\n .filter(m => m.role !== 'system')\n .map(m => ({ role: m.role as 'user' | 'assistant', content: m.content }));\n\n const response = await client.messages.create({\n model: options.model || 'claude-sonnet-4-5-20250929',\n max_tokens: options.maxTokens || 4096,\n ...(options.system && { system: options.system }),\n messages,\n ...(options.temperature !== undefined && { temperature: options.temperature }),\n });\n\n const textBlock = response.content.find((b: any) => b.type === 'text');\n\n return {\n text: (textBlock as any)?.text || '',\n usage: {\n inputTokens: response.usage?.input_tokens || 0,\n outputTokens: response.usage?.output_tokens || 0,\n },\n };\n}\n\nasync function* anthropicStreamChat(options: ChatOptions): AsyncGenerator<StreamChunk> {\n const { default: Anthropic } = await import('@anthropic-ai/sdk');\n const config = getConfig();\n const client = new Anthropic({ apiKey: config.ai?.apiKey || process.env.ANTHROPIC_API_KEY });\n\n const messages = options.messages\n .filter(m => m.role !== 'system')\n .map(m => ({ role: m.role as 'user' | 'assistant', content: m.content }));\n\n const stream = client.messages.stream({\n model: options.model || 'claude-sonnet-4-5-20250929',\n max_tokens: options.maxTokens || 4096,\n ...(options.system && { system: options.system }),\n messages,\n ...(options.temperature !== undefined && { temperature: options.temperature }),\n });\n\n for await (const event of stream) {\n if (event.type === 'content_block_delta' && (event.delta as any).type === 'text_delta') {\n yield { text: (event.delta as any).text, done: false };\n } else if (event.type === 'message_stop') {\n yield { text: '', done: true };\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// AI API\n// ---------------------------------------------------------------------------\n\nexport const ai = {\n /**\n * Send a chat completion request. Auto-detects OpenAI or Anthropic from env vars.\n */\n async chat(options: ChatOptions): Promise<ChatResponse> {\n const provider = requireProvider();\n return provider === 'openai' ? openaiChat(options) : anthropicChat(options);\n },\n\n /**\n * Stream a chat completion. Returns an async iterable of text chunks.\n */\n streamChat(options: ChatOptions): AsyncGenerator<StreamChunk> {\n const provider = requireProvider();\n return provider === 'openai' ? openaiStreamChat(options) : anthropicStreamChat(options);\n },\n\n /**\n * Stream AI response directly to an Express response as SSE.\n * Handles headers, streaming, error handling, and cleanup.\n */\n async streamToSSE(res: any, options: ChatOptions): Promise<void> {\n res.writeHead(200, {\n 'Content-Type': 'text/event-stream',\n 'Cache-Control': 'no-cache',\n Connection: 'keep-alive',\n });\n\n try {\n for await (const chunk of ai.streamChat(options)) {\n if (chunk.text) {\n res.write(`data: ${JSON.stringify({ text: chunk.text })}\\n\\n`);\n }\n if (chunk.done) {\n res.write(`data: ${JSON.stringify({ done: true })}\\n\\n`);\n }\n }\n } catch (error: any) {\n res.write(`data: ${JSON.stringify({ error: error.message })}\\n\\n`);\n } finally {\n res.end();\n }\n },\n\n /**\n * Generate an image (OpenAI DALL-E only).\n */\n async generateImage(options: { prompt: string; size?: string }): Promise<{ url: string }> {\n const provider = detectProvider();\n if (provider !== 'openai') {\n throw new Error('@coduckai/sdk/ai: generateImage() requires OpenAI. Set OPENAI_API_KEY.');\n }\n\n const { default: OpenAI } = await import('openai');\n const config = getConfig();\n const client = new OpenAI({ apiKey: config.ai?.apiKey || process.env.OPENAI_API_KEY });\n\n const response = await client.images.generate({\n model: 'dall-e-3',\n prompt: options.prompt,\n size: (options.size as any) || '1024x1024',\n n: 1,\n });\n\n return { url: response.data?.[0]?.url || '' };\n },\n\n /**\n * Returns the detected AI provider ('openai' | 'anthropic' | null).\n */\n getProvider(): AIProvider {\n return detectProvider();\n },\n};\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/internal/env.ts","../../src/internal/config.ts","../../src/ai/index.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Environment variable helpers\n */\n\nexport function getEnv(key: string, fallback?: string): string | undefined {\n return process.env[key] || fallback;\n}\n\nexport function requireEnv(key: string): string {\n const val = process.env[key];\n if (!val) {\n throw new Error(`@coduckai/sdk: Missing required environment variable: ${key}`);\n }\n return val;\n}\n\nexport function isServer(): boolean {\n return typeof window === 'undefined';\n}\n\nexport function assertServer(moduleName: string): void {\n if (!isServer()) {\n throw new Error(\n `@coduckai/sdk/${moduleName} is server-only. Use @coduckai/sdk/client for browser code.`\n );\n }\n}\n","/**\n * Global SDK configuration\n *\n * CoDuck apps use env vars automatically — no configure() needed.\n * Standalone usage can call configure() to override.\n */\n\nexport interface SDKConfig {\n auth?: {\n jwtSecret?: string;\n jwtExpiresIn?: string;\n bcryptRounds?: number;\n };\n db?: {\n connectionString?: string;\n };\n client?: {\n baseUrl?: string;\n tokenKey?: string;\n };\n payments?: {\n stripeSecretKey?: string;\n connectedAccountId?: string;\n webhookSecret?: string;\n };\n ai?: {\n provider?: 'openai' | 'anthropic';\n apiKey?: string;\n };\n}\n\nlet globalConfig: SDKConfig = {};\n\nexport function setConfig(config: SDKConfig): void {\n globalConfig = { ...globalConfig, ...config };\n}\n\nexport function getConfig(): SDKConfig {\n return globalConfig;\n}\n","/**\n * @coduckai/sdk/ai — AI Providers (server-only)\n *\n * Unified interface for OpenAI and Anthropic. Auto-detects provider from env vars.\n * Set OPENAI_API_KEY for OpenAI or ANTHROPIC_API_KEY for Anthropic.\n */\n\nimport { assertServer } from '../internal/env';\nimport { getConfig } from '../internal/config';\n\nassertServer('ai');\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface ChatMessage {\n role: 'user' | 'assistant' | 'system';\n content: string;\n}\n\nexport interface ChatOptions {\n system?: string;\n messages: ChatMessage[];\n model?: string;\n maxTokens?: number;\n temperature?: number;\n}\n\nexport interface ChatResponse {\n text: string;\n usage: { inputTokens: number; outputTokens: number };\n}\n\nexport interface StreamChunk {\n text: string;\n done: boolean;\n}\n\nexport type AIProvider = 'openai' | 'anthropic' | null;\n\n// ---------------------------------------------------------------------------\n// Provider detection\n// ---------------------------------------------------------------------------\n\nfunction detectProvider(): AIProvider {\n const config = getConfig();\n if (config.ai?.provider) return config.ai.provider;\n if (process.env.OPENAI_API_KEY) return 'openai';\n if (process.env.ANTHROPIC_API_KEY) return 'anthropic';\n return null;\n}\n\nfunction requireProvider(): AIProvider & string {\n const provider = detectProvider();\n if (!provider) {\n throw new Error(\n '@coduckai/sdk/ai: No AI provider configured. Set OPENAI_API_KEY or ANTHROPIC_API_KEY.'\n );\n }\n return provider;\n}\n\n// ---------------------------------------------------------------------------\n// OpenAI\n// ---------------------------------------------------------------------------\n\nasync function openaiChat(options: ChatOptions): Promise<ChatResponse> {\n const { default: OpenAI } = await import('openai');\n const config = getConfig();\n const client = new OpenAI({ apiKey: config.ai?.apiKey || process.env.OPENAI_API_KEY });\n\n const messages: Array<{ role: string; content: string }> = [];\n if (options.system) {\n messages.push({ role: 'system', content: options.system });\n }\n messages.push(...options.messages);\n\n const response = await client.chat.completions.create({\n model: options.model || 'gpt-4o',\n messages: messages as any,\n max_tokens: options.maxTokens || 4096,\n temperature: options.temperature ?? 0.7,\n });\n\n return {\n text: response.choices[0]?.message?.content || '',\n usage: {\n inputTokens: response.usage?.prompt_tokens || 0,\n outputTokens: response.usage?.completion_tokens || 0,\n },\n };\n}\n\nasync function* openaiStreamChat(options: ChatOptions): AsyncGenerator<StreamChunk> {\n const { default: OpenAI } = await import('openai');\n const config = getConfig();\n const client = new OpenAI({ apiKey: config.ai?.apiKey || process.env.OPENAI_API_KEY });\n\n const messages: Array<{ role: string; content: string }> = [];\n if (options.system) {\n messages.push({ role: 'system', content: options.system });\n }\n messages.push(...options.messages);\n\n const stream = await client.chat.completions.create({\n model: options.model || 'gpt-4o',\n messages: messages as any,\n max_tokens: options.maxTokens || 4096,\n temperature: options.temperature ?? 0.7,\n stream: true,\n });\n\n for await (const chunk of stream) {\n const text = chunk.choices[0]?.delta?.content || '';\n const done = chunk.choices[0]?.finish_reason !== null && chunk.choices[0]?.finish_reason !== undefined;\n if (text) yield { text, done: false };\n if (done) yield { text: '', done: true };\n }\n}\n\n// ---------------------------------------------------------------------------\n// Anthropic\n// ---------------------------------------------------------------------------\n\nasync function anthropicChat(options: ChatOptions): Promise<ChatResponse> {\n const { default: Anthropic } = await import('@anthropic-ai/sdk');\n const config = getConfig();\n const client = new Anthropic({ apiKey: config.ai?.apiKey || process.env.ANTHROPIC_API_KEY });\n\n const messages = options.messages\n .filter(m => m.role !== 'system')\n .map(m => ({ role: m.role as 'user' | 'assistant', content: m.content }));\n\n const response = await client.messages.create({\n model: options.model || 'claude-sonnet-4-6',\n max_tokens: options.maxTokens || 4096,\n ...(options.system && { system: options.system }),\n messages,\n ...(options.temperature !== undefined && { temperature: options.temperature }),\n });\n\n const textBlock = response.content.find((b: any) => b.type === 'text');\n\n return {\n text: (textBlock as any)?.text || '',\n usage: {\n inputTokens: response.usage?.input_tokens || 0,\n outputTokens: response.usage?.output_tokens || 0,\n },\n };\n}\n\nasync function* anthropicStreamChat(options: ChatOptions): AsyncGenerator<StreamChunk> {\n const { default: Anthropic } = await import('@anthropic-ai/sdk');\n const config = getConfig();\n const client = new Anthropic({ apiKey: config.ai?.apiKey || process.env.ANTHROPIC_API_KEY });\n\n const messages = options.messages\n .filter(m => m.role !== 'system')\n .map(m => ({ role: m.role as 'user' | 'assistant', content: m.content }));\n\n const stream = client.messages.stream({\n model: options.model || 'claude-sonnet-4-6',\n max_tokens: options.maxTokens || 4096,\n ...(options.system && { system: options.system }),\n messages,\n ...(options.temperature !== undefined && { temperature: options.temperature }),\n });\n\n for await (const event of stream) {\n if (event.type === 'content_block_delta' && (event.delta as any).type === 'text_delta') {\n yield { text: (event.delta as any).text, done: false };\n } else if (event.type === 'message_stop') {\n yield { text: '', done: true };\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// AI API\n// ---------------------------------------------------------------------------\n\nexport const ai = {\n /**\n * Send a chat completion request. Auto-detects OpenAI or Anthropic from env vars.\n */\n async chat(options: ChatOptions): Promise<ChatResponse> {\n const provider = requireProvider();\n return provider === 'openai' ? openaiChat(options) : anthropicChat(options);\n },\n\n /**\n * Stream a chat completion. Returns an async iterable of text chunks.\n */\n streamChat(options: ChatOptions): AsyncGenerator<StreamChunk> {\n const provider = requireProvider();\n return provider === 'openai' ? openaiStreamChat(options) : anthropicStreamChat(options);\n },\n\n /**\n * Stream AI response directly to an Express response as SSE.\n * Handles headers, streaming, error handling, and cleanup.\n */\n async streamToSSE(res: any, options: ChatOptions): Promise<void> {\n res.writeHead(200, {\n 'Content-Type': 'text/event-stream',\n 'Cache-Control': 'no-cache',\n Connection: 'keep-alive',\n });\n\n try {\n for await (const chunk of ai.streamChat(options)) {\n if (chunk.text) {\n res.write(`data: ${JSON.stringify({ text: chunk.text })}\\n\\n`);\n }\n if (chunk.done) {\n res.write(`data: ${JSON.stringify({ done: true })}\\n\\n`);\n }\n }\n } catch (error: any) {\n res.write(`data: ${JSON.stringify({ error: error.message })}\\n\\n`);\n } finally {\n res.end();\n }\n },\n\n /**\n * Generate an image (OpenAI DALL-E only).\n */\n async generateImage(options: { prompt: string; size?: string }): Promise<{ url: string }> {\n const provider = detectProvider();\n if (provider !== 'openai') {\n throw new Error('@coduckai/sdk/ai: generateImage() requires OpenAI. Set OPENAI_API_KEY.');\n }\n\n const { default: OpenAI } = await import('openai');\n const config = getConfig();\n const client = new OpenAI({ apiKey: config.ai?.apiKey || process.env.OPENAI_API_KEY });\n\n const response = await client.images.generate({\n model: 'dall-e-3',\n prompt: options.prompt,\n size: (options.size as any) || '1024x1024',\n n: 1,\n });\n\n return { url: response.data?.[0]?.url || '' };\n },\n\n /**\n * Returns the detected AI provider ('openai' | 'anthropic' | null).\n */\n getProvider(): AIProvider {\n return detectProvider();\n },\n};\n"]}
|
package/dist/ai/index.js
CHANGED
|
@@ -86,7 +86,7 @@ async function anthropicChat(options) {
|
|
|
86
86
|
const client = new Anthropic({ apiKey: config.ai?.apiKey || process.env.ANTHROPIC_API_KEY });
|
|
87
87
|
const messages = options.messages.filter((m) => m.role !== "system").map((m) => ({ role: m.role, content: m.content }));
|
|
88
88
|
const response = await client.messages.create({
|
|
89
|
-
model: options.model || "claude-sonnet-4-
|
|
89
|
+
model: options.model || "claude-sonnet-4-6",
|
|
90
90
|
max_tokens: options.maxTokens || 4096,
|
|
91
91
|
...options.system && { system: options.system },
|
|
92
92
|
messages,
|
|
@@ -107,7 +107,7 @@ async function* anthropicStreamChat(options) {
|
|
|
107
107
|
const client = new Anthropic({ apiKey: config.ai?.apiKey || process.env.ANTHROPIC_API_KEY });
|
|
108
108
|
const messages = options.messages.filter((m) => m.role !== "system").map((m) => ({ role: m.role, content: m.content }));
|
|
109
109
|
const stream = client.messages.stream({
|
|
110
|
-
model: options.model || "claude-sonnet-4-
|
|
110
|
+
model: options.model || "claude-sonnet-4-6",
|
|
111
111
|
max_tokens: options.maxTokens || 4096,
|
|
112
112
|
...options.system && { system: options.system },
|
|
113
113
|
messages,
|
package/dist/ai/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/internal/env.ts","../../src/internal/config.ts","../../src/ai/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Environment variable helpers\n */\n\nexport function getEnv(key: string, fallback?: string): string | undefined {\n return process.env[key] || fallback;\n}\n\nexport function requireEnv(key: string): string {\n const val = process.env[key];\n if (!val) {\n throw new Error(`@coduckai/sdk: Missing required environment variable: ${key}`);\n }\n return val;\n}\n\nexport function isServer(): boolean {\n return typeof window === 'undefined';\n}\n\nexport function assertServer(moduleName: string): void {\n if (!isServer()) {\n throw new Error(\n `@coduckai/sdk/${moduleName} is server-only. Use @coduckai/sdk/client for browser code.`\n );\n }\n}\n","/**\n * Global SDK configuration\n *\n * CoDuck apps use env vars automatically — no configure() needed.\n * Standalone usage can call configure() to override.\n */\n\nexport interface SDKConfig {\n auth?: {\n jwtSecret?: string;\n jwtExpiresIn?: string;\n bcryptRounds?: number;\n };\n db?: {\n connectionString?: string;\n };\n client?: {\n baseUrl?: string;\n tokenKey?: string;\n };\n payments?: {\n stripeSecretKey?: string;\n connectedAccountId?: string;\n webhookSecret?: string;\n };\n ai?: {\n provider?: 'openai' | 'anthropic';\n apiKey?: string;\n };\n}\n\nlet globalConfig: SDKConfig = {};\n\nexport function setConfig(config: SDKConfig): void {\n globalConfig = { ...globalConfig, ...config };\n}\n\nexport function getConfig(): SDKConfig {\n return globalConfig;\n}\n","/**\n * @coduckai/sdk/ai — AI Providers (server-only)\n *\n * Unified interface for OpenAI and Anthropic. Auto-detects provider from env vars.\n * Set OPENAI_API_KEY for OpenAI or ANTHROPIC_API_KEY for Anthropic.\n */\n\nimport { assertServer } from '../internal/env';\nimport { getConfig } from '../internal/config';\n\nassertServer('ai');\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface ChatMessage {\n role: 'user' | 'assistant' | 'system';\n content: string;\n}\n\nexport interface ChatOptions {\n system?: string;\n messages: ChatMessage[];\n model?: string;\n maxTokens?: number;\n temperature?: number;\n}\n\nexport interface ChatResponse {\n text: string;\n usage: { inputTokens: number; outputTokens: number };\n}\n\nexport interface StreamChunk {\n text: string;\n done: boolean;\n}\n\nexport type AIProvider = 'openai' | 'anthropic' | null;\n\n// ---------------------------------------------------------------------------\n// Provider detection\n// ---------------------------------------------------------------------------\n\nfunction detectProvider(): AIProvider {\n const config = getConfig();\n if (config.ai?.provider) return config.ai.provider;\n if (process.env.OPENAI_API_KEY) return 'openai';\n if (process.env.ANTHROPIC_API_KEY) return 'anthropic';\n return null;\n}\n\nfunction requireProvider(): AIProvider & string {\n const provider = detectProvider();\n if (!provider) {\n throw new Error(\n '@coduckai/sdk/ai: No AI provider configured. Set OPENAI_API_KEY or ANTHROPIC_API_KEY.'\n );\n }\n return provider;\n}\n\n// ---------------------------------------------------------------------------\n// OpenAI\n// ---------------------------------------------------------------------------\n\nasync function openaiChat(options: ChatOptions): Promise<ChatResponse> {\n const { default: OpenAI } = await import('openai');\n const config = getConfig();\n const client = new OpenAI({ apiKey: config.ai?.apiKey || process.env.OPENAI_API_KEY });\n\n const messages: Array<{ role: string; content: string }> = [];\n if (options.system) {\n messages.push({ role: 'system', content: options.system });\n }\n messages.push(...options.messages);\n\n const response = await client.chat.completions.create({\n model: options.model || 'gpt-4o',\n messages: messages as any,\n max_tokens: options.maxTokens || 4096,\n temperature: options.temperature ?? 0.7,\n });\n\n return {\n text: response.choices[0]?.message?.content || '',\n usage: {\n inputTokens: response.usage?.prompt_tokens || 0,\n outputTokens: response.usage?.completion_tokens || 0,\n },\n };\n}\n\nasync function* openaiStreamChat(options: ChatOptions): AsyncGenerator<StreamChunk> {\n const { default: OpenAI } = await import('openai');\n const config = getConfig();\n const client = new OpenAI({ apiKey: config.ai?.apiKey || process.env.OPENAI_API_KEY });\n\n const messages: Array<{ role: string; content: string }> = [];\n if (options.system) {\n messages.push({ role: 'system', content: options.system });\n }\n messages.push(...options.messages);\n\n const stream = await client.chat.completions.create({\n model: options.model || 'gpt-4o',\n messages: messages as any,\n max_tokens: options.maxTokens || 4096,\n temperature: options.temperature ?? 0.7,\n stream: true,\n });\n\n for await (const chunk of stream) {\n const text = chunk.choices[0]?.delta?.content || '';\n const done = chunk.choices[0]?.finish_reason !== null && chunk.choices[0]?.finish_reason !== undefined;\n if (text) yield { text, done: false };\n if (done) yield { text: '', done: true };\n }\n}\n\n// ---------------------------------------------------------------------------\n// Anthropic\n// ---------------------------------------------------------------------------\n\nasync function anthropicChat(options: ChatOptions): Promise<ChatResponse> {\n const { default: Anthropic } = await import('@anthropic-ai/sdk');\n const config = getConfig();\n const client = new Anthropic({ apiKey: config.ai?.apiKey || process.env.ANTHROPIC_API_KEY });\n\n const messages = options.messages\n .filter(m => m.role !== 'system')\n .map(m => ({ role: m.role as 'user' | 'assistant', content: m.content }));\n\n const response = await client.messages.create({\n model: options.model || 'claude-sonnet-4-5-20250929',\n max_tokens: options.maxTokens || 4096,\n ...(options.system && { system: options.system }),\n messages,\n ...(options.temperature !== undefined && { temperature: options.temperature }),\n });\n\n const textBlock = response.content.find((b: any) => b.type === 'text');\n\n return {\n text: (textBlock as any)?.text || '',\n usage: {\n inputTokens: response.usage?.input_tokens || 0,\n outputTokens: response.usage?.output_tokens || 0,\n },\n };\n}\n\nasync function* anthropicStreamChat(options: ChatOptions): AsyncGenerator<StreamChunk> {\n const { default: Anthropic } = await import('@anthropic-ai/sdk');\n const config = getConfig();\n const client = new Anthropic({ apiKey: config.ai?.apiKey || process.env.ANTHROPIC_API_KEY });\n\n const messages = options.messages\n .filter(m => m.role !== 'system')\n .map(m => ({ role: m.role as 'user' | 'assistant', content: m.content }));\n\n const stream = client.messages.stream({\n model: options.model || 'claude-sonnet-4-5-20250929',\n max_tokens: options.maxTokens || 4096,\n ...(options.system && { system: options.system }),\n messages,\n ...(options.temperature !== undefined && { temperature: options.temperature }),\n });\n\n for await (const event of stream) {\n if (event.type === 'content_block_delta' && (event.delta as any).type === 'text_delta') {\n yield { text: (event.delta as any).text, done: false };\n } else if (event.type === 'message_stop') {\n yield { text: '', done: true };\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// AI API\n// ---------------------------------------------------------------------------\n\nexport const ai = {\n /**\n * Send a chat completion request. Auto-detects OpenAI or Anthropic from env vars.\n */\n async chat(options: ChatOptions): Promise<ChatResponse> {\n const provider = requireProvider();\n return provider === 'openai' ? openaiChat(options) : anthropicChat(options);\n },\n\n /**\n * Stream a chat completion. Returns an async iterable of text chunks.\n */\n streamChat(options: ChatOptions): AsyncGenerator<StreamChunk> {\n const provider = requireProvider();\n return provider === 'openai' ? openaiStreamChat(options) : anthropicStreamChat(options);\n },\n\n /**\n * Stream AI response directly to an Express response as SSE.\n * Handles headers, streaming, error handling, and cleanup.\n */\n async streamToSSE(res: any, options: ChatOptions): Promise<void> {\n res.writeHead(200, {\n 'Content-Type': 'text/event-stream',\n 'Cache-Control': 'no-cache',\n Connection: 'keep-alive',\n });\n\n try {\n for await (const chunk of ai.streamChat(options)) {\n if (chunk.text) {\n res.write(`data: ${JSON.stringify({ text: chunk.text })}\\n\\n`);\n }\n if (chunk.done) {\n res.write(`data: ${JSON.stringify({ done: true })}\\n\\n`);\n }\n }\n } catch (error: any) {\n res.write(`data: ${JSON.stringify({ error: error.message })}\\n\\n`);\n } finally {\n res.end();\n }\n },\n\n /**\n * Generate an image (OpenAI DALL-E only).\n */\n async generateImage(options: { prompt: string; size?: string }): Promise<{ url: string }> {\n const provider = detectProvider();\n if (provider !== 'openai') {\n throw new Error('@coduckai/sdk/ai: generateImage() requires OpenAI. Set OPENAI_API_KEY.');\n }\n\n const { default: OpenAI } = await import('openai');\n const config = getConfig();\n const client = new OpenAI({ apiKey: config.ai?.apiKey || process.env.OPENAI_API_KEY });\n\n const response = await client.images.generate({\n model: 'dall-e-3',\n prompt: options.prompt,\n size: (options.size as any) || '1024x1024',\n n: 1,\n });\n\n return { url: response.data?.[0]?.url || '' };\n },\n\n /**\n * Returns the detected AI provider ('openai' | 'anthropic' | null).\n */\n getProvider(): AIProvider {\n return detectProvider();\n },\n};\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/internal/env.ts","../../src/internal/config.ts","../../src/ai/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Environment variable helpers\n */\n\nexport function getEnv(key: string, fallback?: string): string | undefined {\n return process.env[key] || fallback;\n}\n\nexport function requireEnv(key: string): string {\n const val = process.env[key];\n if (!val) {\n throw new Error(`@coduckai/sdk: Missing required environment variable: ${key}`);\n }\n return val;\n}\n\nexport function isServer(): boolean {\n return typeof window === 'undefined';\n}\n\nexport function assertServer(moduleName: string): void {\n if (!isServer()) {\n throw new Error(\n `@coduckai/sdk/${moduleName} is server-only. Use @coduckai/sdk/client for browser code.`\n );\n }\n}\n","/**\n * Global SDK configuration\n *\n * CoDuck apps use env vars automatically — no configure() needed.\n * Standalone usage can call configure() to override.\n */\n\nexport interface SDKConfig {\n auth?: {\n jwtSecret?: string;\n jwtExpiresIn?: string;\n bcryptRounds?: number;\n };\n db?: {\n connectionString?: string;\n };\n client?: {\n baseUrl?: string;\n tokenKey?: string;\n };\n payments?: {\n stripeSecretKey?: string;\n connectedAccountId?: string;\n webhookSecret?: string;\n };\n ai?: {\n provider?: 'openai' | 'anthropic';\n apiKey?: string;\n };\n}\n\nlet globalConfig: SDKConfig = {};\n\nexport function setConfig(config: SDKConfig): void {\n globalConfig = { ...globalConfig, ...config };\n}\n\nexport function getConfig(): SDKConfig {\n return globalConfig;\n}\n","/**\n * @coduckai/sdk/ai — AI Providers (server-only)\n *\n * Unified interface for OpenAI and Anthropic. Auto-detects provider from env vars.\n * Set OPENAI_API_KEY for OpenAI or ANTHROPIC_API_KEY for Anthropic.\n */\n\nimport { assertServer } from '../internal/env';\nimport { getConfig } from '../internal/config';\n\nassertServer('ai');\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface ChatMessage {\n role: 'user' | 'assistant' | 'system';\n content: string;\n}\n\nexport interface ChatOptions {\n system?: string;\n messages: ChatMessage[];\n model?: string;\n maxTokens?: number;\n temperature?: number;\n}\n\nexport interface ChatResponse {\n text: string;\n usage: { inputTokens: number; outputTokens: number };\n}\n\nexport interface StreamChunk {\n text: string;\n done: boolean;\n}\n\nexport type AIProvider = 'openai' | 'anthropic' | null;\n\n// ---------------------------------------------------------------------------\n// Provider detection\n// ---------------------------------------------------------------------------\n\nfunction detectProvider(): AIProvider {\n const config = getConfig();\n if (config.ai?.provider) return config.ai.provider;\n if (process.env.OPENAI_API_KEY) return 'openai';\n if (process.env.ANTHROPIC_API_KEY) return 'anthropic';\n return null;\n}\n\nfunction requireProvider(): AIProvider & string {\n const provider = detectProvider();\n if (!provider) {\n throw new Error(\n '@coduckai/sdk/ai: No AI provider configured. Set OPENAI_API_KEY or ANTHROPIC_API_KEY.'\n );\n }\n return provider;\n}\n\n// ---------------------------------------------------------------------------\n// OpenAI\n// ---------------------------------------------------------------------------\n\nasync function openaiChat(options: ChatOptions): Promise<ChatResponse> {\n const { default: OpenAI } = await import('openai');\n const config = getConfig();\n const client = new OpenAI({ apiKey: config.ai?.apiKey || process.env.OPENAI_API_KEY });\n\n const messages: Array<{ role: string; content: string }> = [];\n if (options.system) {\n messages.push({ role: 'system', content: options.system });\n }\n messages.push(...options.messages);\n\n const response = await client.chat.completions.create({\n model: options.model || 'gpt-4o',\n messages: messages as any,\n max_tokens: options.maxTokens || 4096,\n temperature: options.temperature ?? 0.7,\n });\n\n return {\n text: response.choices[0]?.message?.content || '',\n usage: {\n inputTokens: response.usage?.prompt_tokens || 0,\n outputTokens: response.usage?.completion_tokens || 0,\n },\n };\n}\n\nasync function* openaiStreamChat(options: ChatOptions): AsyncGenerator<StreamChunk> {\n const { default: OpenAI } = await import('openai');\n const config = getConfig();\n const client = new OpenAI({ apiKey: config.ai?.apiKey || process.env.OPENAI_API_KEY });\n\n const messages: Array<{ role: string; content: string }> = [];\n if (options.system) {\n messages.push({ role: 'system', content: options.system });\n }\n messages.push(...options.messages);\n\n const stream = await client.chat.completions.create({\n model: options.model || 'gpt-4o',\n messages: messages as any,\n max_tokens: options.maxTokens || 4096,\n temperature: options.temperature ?? 0.7,\n stream: true,\n });\n\n for await (const chunk of stream) {\n const text = chunk.choices[0]?.delta?.content || '';\n const done = chunk.choices[0]?.finish_reason !== null && chunk.choices[0]?.finish_reason !== undefined;\n if (text) yield { text, done: false };\n if (done) yield { text: '', done: true };\n }\n}\n\n// ---------------------------------------------------------------------------\n// Anthropic\n// ---------------------------------------------------------------------------\n\nasync function anthropicChat(options: ChatOptions): Promise<ChatResponse> {\n const { default: Anthropic } = await import('@anthropic-ai/sdk');\n const config = getConfig();\n const client = new Anthropic({ apiKey: config.ai?.apiKey || process.env.ANTHROPIC_API_KEY });\n\n const messages = options.messages\n .filter(m => m.role !== 'system')\n .map(m => ({ role: m.role as 'user' | 'assistant', content: m.content }));\n\n const response = await client.messages.create({\n model: options.model || 'claude-sonnet-4-6',\n max_tokens: options.maxTokens || 4096,\n ...(options.system && { system: options.system }),\n messages,\n ...(options.temperature !== undefined && { temperature: options.temperature }),\n });\n\n const textBlock = response.content.find((b: any) => b.type === 'text');\n\n return {\n text: (textBlock as any)?.text || '',\n usage: {\n inputTokens: response.usage?.input_tokens || 0,\n outputTokens: response.usage?.output_tokens || 0,\n },\n };\n}\n\nasync function* anthropicStreamChat(options: ChatOptions): AsyncGenerator<StreamChunk> {\n const { default: Anthropic } = await import('@anthropic-ai/sdk');\n const config = getConfig();\n const client = new Anthropic({ apiKey: config.ai?.apiKey || process.env.ANTHROPIC_API_KEY });\n\n const messages = options.messages\n .filter(m => m.role !== 'system')\n .map(m => ({ role: m.role as 'user' | 'assistant', content: m.content }));\n\n const stream = client.messages.stream({\n model: options.model || 'claude-sonnet-4-6',\n max_tokens: options.maxTokens || 4096,\n ...(options.system && { system: options.system }),\n messages,\n ...(options.temperature !== undefined && { temperature: options.temperature }),\n });\n\n for await (const event of stream) {\n if (event.type === 'content_block_delta' && (event.delta as any).type === 'text_delta') {\n yield { text: (event.delta as any).text, done: false };\n } else if (event.type === 'message_stop') {\n yield { text: '', done: true };\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// AI API\n// ---------------------------------------------------------------------------\n\nexport const ai = {\n /**\n * Send a chat completion request. Auto-detects OpenAI or Anthropic from env vars.\n */\n async chat(options: ChatOptions): Promise<ChatResponse> {\n const provider = requireProvider();\n return provider === 'openai' ? openaiChat(options) : anthropicChat(options);\n },\n\n /**\n * Stream a chat completion. Returns an async iterable of text chunks.\n */\n streamChat(options: ChatOptions): AsyncGenerator<StreamChunk> {\n const provider = requireProvider();\n return provider === 'openai' ? openaiStreamChat(options) : anthropicStreamChat(options);\n },\n\n /**\n * Stream AI response directly to an Express response as SSE.\n * Handles headers, streaming, error handling, and cleanup.\n */\n async streamToSSE(res: any, options: ChatOptions): Promise<void> {\n res.writeHead(200, {\n 'Content-Type': 'text/event-stream',\n 'Cache-Control': 'no-cache',\n Connection: 'keep-alive',\n });\n\n try {\n for await (const chunk of ai.streamChat(options)) {\n if (chunk.text) {\n res.write(`data: ${JSON.stringify({ text: chunk.text })}\\n\\n`);\n }\n if (chunk.done) {\n res.write(`data: ${JSON.stringify({ done: true })}\\n\\n`);\n }\n }\n } catch (error: any) {\n res.write(`data: ${JSON.stringify({ error: error.message })}\\n\\n`);\n } finally {\n res.end();\n }\n },\n\n /**\n * Generate an image (OpenAI DALL-E only).\n */\n async generateImage(options: { prompt: string; size?: string }): Promise<{ url: string }> {\n const provider = detectProvider();\n if (provider !== 'openai') {\n throw new Error('@coduckai/sdk/ai: generateImage() requires OpenAI. Set OPENAI_API_KEY.');\n }\n\n const { default: OpenAI } = await import('openai');\n const config = getConfig();\n const client = new OpenAI({ apiKey: config.ai?.apiKey || process.env.OPENAI_API_KEY });\n\n const response = await client.images.generate({\n model: 'dall-e-3',\n prompt: options.prompt,\n size: (options.size as any) || '1024x1024',\n n: 1,\n });\n\n return { url: response.data?.[0]?.url || '' };\n },\n\n /**\n * Returns the detected AI provider ('openai' | 'anthropic' | null).\n */\n getProvider(): AIProvider {\n return detectProvider();\n },\n};\n"]}
|
package/dist/client/index.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/client/index.ts"],"names":["axios"],"mappings":";;;;;;;;;;;;AAeA,IAAM,SAAA,GAAY,OAAA;AAEX,SAAS,SAAS,KAAA,EAAqB;AAC5C,EAAA,IAAI,OAAO,iBAAiB,WAAA,EAAa;AACvC,IAAA,YAAA,CAAa,OAAA,CAAQ,WAAW,KAAK,CAAA;AAAA,EACvC;AACF;AAEO,SAAS,QAAA,GAA0B;AACxC,EAAA,IAAI,OAAO,iBAAiB,WAAA,EAAa;AACvC,IAAA,OAAO,YAAA,CAAa,QAAQ,SAAS,CAAA;AAAA,EACvC;AACA,EAAA,OAAO,IAAA;AACT;AAEO,SAAS,UAAA,GAAmB;AACjC,EAAA,IAAI,OAAO,iBAAiB,WAAA,EAAa;AACvC,IAAA,YAAA,CAAa,WAAW,SAAS,CAAA;AAAA,EACnC;AACF;AAEO,SAAS,eAAA,GAA2B;AACzC,EAAA,OAAO,CAAC,CAAC,QAAA,EAAS;AACpB;AAIA,SAAS,UAAA,GAAqB;AAE5B,EAAA,IAAI,OAAO,sQAAA,KAAgB,WAAA,IAAgB,WAAyB,YAAA,EAAc;AAChF,IAAA,OAAQ,SAAoB,CAAI,YAAA;AAAA,EAClC;AAEA,EAAA,OAAO,MAAA;AACT;AAEA,IAAM,GAAA,GAAqBA,uBAAM,MAAA,CAAO;AAAA,EACtC,SAAS,UAAA,EAAW;AAAA,EACpB,OAAA,EAAS,EAAE,cAAA,EAAgB,kBAAA;AAC7B,CAAC,CAAA;AAGD,GAAA,CAAI,YAAA,CAAa,OAAA,CAAQ,GAAA,CAAI,CAAC,MAAA,KAAW;AACvC,EAAA,MAAM,QAAQ,QAAA,EAAS;AACvB,EAAA,IAAI,KAAA,EAAO;AACT,IAAA,MAAA,CAAO,OAAA,CAAQ,aAAA,GAAgB,CAAA,OAAA,EAAU,KAAK,CAAA,CAAA;AAAA,EAChD;AACA,EAAA,OAAO,MAAA;AACT,CAAC,CAAA;AAGD,GAAA,CAAI,aAAa,QAAA,CAAS,GAAA;AAAA,EACxB,CAAC,QAAA,
|
|
1
|
+
{"version":3,"sources":["../../src/client/index.ts"],"names":["axios"],"mappings":";;;;;;;;;;;;AAeA,IAAM,SAAA,GAAY,OAAA;AAEX,SAAS,SAAS,KAAA,EAAqB;AAC5C,EAAA,IAAI,OAAO,iBAAiB,WAAA,EAAa;AACvC,IAAA,YAAA,CAAa,OAAA,CAAQ,WAAW,KAAK,CAAA;AAAA,EACvC;AACF;AAEO,SAAS,QAAA,GAA0B;AACxC,EAAA,IAAI,OAAO,iBAAiB,WAAA,EAAa;AACvC,IAAA,OAAO,YAAA,CAAa,QAAQ,SAAS,CAAA;AAAA,EACvC;AACA,EAAA,OAAO,IAAA;AACT;AAEO,SAAS,UAAA,GAAmB;AACjC,EAAA,IAAI,OAAO,iBAAiB,WAAA,EAAa;AACvC,IAAA,YAAA,CAAa,WAAW,SAAS,CAAA;AAAA,EACnC;AACF;AAEO,SAAS,eAAA,GAA2B;AACzC,EAAA,OAAO,CAAC,CAAC,QAAA,EAAS;AACpB;AAIA,SAAS,UAAA,GAAqB;AAE5B,EAAA,IAAI,OAAO,sQAAA,KAAgB,WAAA,IAAgB,WAAyB,YAAA,EAAc;AAChF,IAAA,OAAQ,SAAoB,CAAI,YAAA;AAAA,EAClC;AAEA,EAAA,OAAO,MAAA;AACT;AAEA,IAAM,GAAA,GAAqBA,uBAAM,MAAA,CAAO;AAAA,EACtC,SAAS,UAAA,EAAW;AAAA,EACpB,OAAA,EAAS,EAAE,cAAA,EAAgB,kBAAA;AAC7B,CAAC,CAAA;AAGD,GAAA,CAAI,YAAA,CAAa,OAAA,CAAQ,GAAA,CAAI,CAAC,MAAA,KAAW;AACvC,EAAA,MAAM,QAAQ,QAAA,EAAS;AACvB,EAAA,IAAI,KAAA,EAAO;AACT,IAAA,MAAA,CAAO,OAAA,CAAQ,aAAA,GAAgB,CAAA,OAAA,EAAU,KAAK,CAAA,CAAA;AAAA,EAChD;AACA,EAAA,OAAO,MAAA;AACT,CAAC,CAAA;AAGD,GAAA,CAAI,aAAa,QAAA,CAAS,GAAA;AAAA,EACxB,CAAC,aAAa,QAAA,CAAS,IAAA;AAAA,EACvB,CAAC,KAAA,KAAU;AACT,IAAA,IAAI,KAAA,CAAM,QAAA,EAAU,MAAA,KAAW,GAAA,EAAK;AAClC,MAAA,UAAA,EAAW;AACX,MAAA,IAAI,OAAO,WAAW,WAAA,EAAa;AACjC,QAAA,MAAA,CAAO,SAAS,IAAA,GAAO,QAAA;AAAA,MACzB;AAAA,IACF;AACA,IAAA,OAAO,OAAA,CAAQ,OAAO,KAAK,CAAA;AAAA,EAC7B;AACF,CAAA;AAEA,IAAO,cAAA,GAAQ","file":"index.cjs","sourcesContent":["/**\n * @coduckai/sdk/client — Frontend API Client (browser-only)\n *\n * Pre-configured Axios instance with auth interceptor.\n *\n * Usage:\n * import api, { setToken, clearToken } from '@coduckai/sdk/client';\n * const recipes = await api.get('/recipes'); // returns response.data directly\n * setToken(loginData.token);\n */\n\nimport axios, { type AxiosInstance } from 'axios';\n\n// ── Token Management ───────────────────────────────────\n\nconst TOKEN_KEY = 'token';\n\nexport function setToken(token: string): void {\n if (typeof localStorage !== 'undefined') {\n localStorage.setItem(TOKEN_KEY, token);\n }\n}\n\nexport function getToken(): string | null {\n if (typeof localStorage !== 'undefined') {\n return localStorage.getItem(TOKEN_KEY);\n }\n return null;\n}\n\nexport function clearToken(): void {\n if (typeof localStorage !== 'undefined') {\n localStorage.removeItem(TOKEN_KEY);\n }\n}\n\nexport function isAuthenticated(): boolean {\n return !!getToken();\n}\n\n// ── Axios Instance ─────────────────────────────────────\n\nfunction getBaseUrl(): string {\n // Vite: VITE_API_URL\n if (typeof import.meta !== 'undefined' && (import.meta as any).env?.VITE_API_URL) {\n return (import.meta as any).env.VITE_API_URL;\n }\n // Fallback: relative /api\n return '/api';\n}\n\nconst api: AxiosInstance = axios.create({\n baseURL: getBaseUrl(),\n headers: { 'Content-Type': 'application/json' },\n});\n\n// Request interceptor — attach Bearer token\napi.interceptors.request.use((config) => {\n const token = getToken();\n if (token) {\n config.headers.Authorization = `Bearer ${token}`;\n }\n return config;\n});\n\n// Response interceptor — auto-extract .data and handle 401\napi.interceptors.response.use(\n (response) => response.data,\n (error) => {\n if (error.response?.status === 401) {\n clearToken();\n if (typeof window !== 'undefined') {\n window.location.href = '/login';\n }\n }\n return Promise.reject(error);\n }\n);\n\nexport default api;\n"]}
|
package/dist/client/index.d.cts
CHANGED
|
@@ -7,7 +7,7 @@ import { AxiosInstance } from 'axios';
|
|
|
7
7
|
*
|
|
8
8
|
* Usage:
|
|
9
9
|
* import api, { setToken, clearToken } from '@coduckai/sdk/client';
|
|
10
|
-
* const
|
|
10
|
+
* const recipes = await api.get('/recipes'); // returns response.data directly
|
|
11
11
|
* setToken(loginData.token);
|
|
12
12
|
*/
|
|
13
13
|
|
package/dist/client/index.d.ts
CHANGED
|
@@ -7,7 +7,7 @@ import { AxiosInstance } from 'axios';
|
|
|
7
7
|
*
|
|
8
8
|
* Usage:
|
|
9
9
|
* import api, { setToken, clearToken } from '@coduckai/sdk/client';
|
|
10
|
-
* const
|
|
10
|
+
* const recipes = await api.get('/recipes'); // returns response.data directly
|
|
11
11
|
* setToken(loginData.token);
|
|
12
12
|
*/
|
|
13
13
|
|
package/dist/client/index.js
CHANGED
package/dist/client/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/client/index.ts"],"names":[],"mappings":";;;AAeA,IAAM,SAAA,GAAY,OAAA;AAEX,SAAS,SAAS,KAAA,EAAqB;AAC5C,EAAA,IAAI,OAAO,iBAAiB,WAAA,EAAa;AACvC,IAAA,YAAA,CAAa,OAAA,CAAQ,WAAW,KAAK,CAAA;AAAA,EACvC;AACF;AAEO,SAAS,QAAA,GAA0B;AACxC,EAAA,IAAI,OAAO,iBAAiB,WAAA,EAAa;AACvC,IAAA,OAAO,YAAA,CAAa,QAAQ,SAAS,CAAA;AAAA,EACvC;AACA,EAAA,OAAO,IAAA;AACT;AAEO,SAAS,UAAA,GAAmB;AACjC,EAAA,IAAI,OAAO,iBAAiB,WAAA,EAAa;AACvC,IAAA,YAAA,CAAa,WAAW,SAAS,CAAA;AAAA,EACnC;AACF;AAEO,SAAS,eAAA,GAA2B;AACzC,EAAA,OAAO,CAAC,CAAC,QAAA,EAAS;AACpB;AAIA,SAAS,UAAA,GAAqB;AAE5B,EAAA,IAAI,OAAO,MAAA,CAAA,IAAA,KAAgB,WAAA,IAAgB,MAAA,CAAA,IAAA,CAAoB,KAAK,YAAA,EAAc;AAChF,IAAA,OAAQ,YAAoB,GAAA,CAAI,YAAA;AAAA,EAClC;AAEA,EAAA,OAAO,MAAA;AACT;AAEA,IAAM,GAAA,GAAqB,MAAM,MAAA,CAAO;AAAA,EACtC,SAAS,UAAA,EAAW;AAAA,EACpB,OAAA,EAAS,EAAE,cAAA,EAAgB,kBAAA;AAC7B,CAAC,CAAA;AAGD,GAAA,CAAI,YAAA,CAAa,OAAA,CAAQ,GAAA,CAAI,CAAC,MAAA,KAAW;AACvC,EAAA,MAAM,QAAQ,QAAA,EAAS;AACvB,EAAA,IAAI,KAAA,EAAO;AACT,IAAA,MAAA,CAAO,OAAA,CAAQ,aAAA,GAAgB,CAAA,OAAA,EAAU,KAAK,CAAA,CAAA;AAAA,EAChD;AACA,EAAA,OAAO,MAAA;AACT,CAAC,CAAA;AAGD,GAAA,CAAI,aAAa,QAAA,CAAS,GAAA;AAAA,EACxB,CAAC,QAAA,
|
|
1
|
+
{"version":3,"sources":["../../src/client/index.ts"],"names":[],"mappings":";;;AAeA,IAAM,SAAA,GAAY,OAAA;AAEX,SAAS,SAAS,KAAA,EAAqB;AAC5C,EAAA,IAAI,OAAO,iBAAiB,WAAA,EAAa;AACvC,IAAA,YAAA,CAAa,OAAA,CAAQ,WAAW,KAAK,CAAA;AAAA,EACvC;AACF;AAEO,SAAS,QAAA,GAA0B;AACxC,EAAA,IAAI,OAAO,iBAAiB,WAAA,EAAa;AACvC,IAAA,OAAO,YAAA,CAAa,QAAQ,SAAS,CAAA;AAAA,EACvC;AACA,EAAA,OAAO,IAAA;AACT;AAEO,SAAS,UAAA,GAAmB;AACjC,EAAA,IAAI,OAAO,iBAAiB,WAAA,EAAa;AACvC,IAAA,YAAA,CAAa,WAAW,SAAS,CAAA;AAAA,EACnC;AACF;AAEO,SAAS,eAAA,GAA2B;AACzC,EAAA,OAAO,CAAC,CAAC,QAAA,EAAS;AACpB;AAIA,SAAS,UAAA,GAAqB;AAE5B,EAAA,IAAI,OAAO,MAAA,CAAA,IAAA,KAAgB,WAAA,IAAgB,MAAA,CAAA,IAAA,CAAoB,KAAK,YAAA,EAAc;AAChF,IAAA,OAAQ,YAAoB,GAAA,CAAI,YAAA;AAAA,EAClC;AAEA,EAAA,OAAO,MAAA;AACT;AAEA,IAAM,GAAA,GAAqB,MAAM,MAAA,CAAO;AAAA,EACtC,SAAS,UAAA,EAAW;AAAA,EACpB,OAAA,EAAS,EAAE,cAAA,EAAgB,kBAAA;AAC7B,CAAC,CAAA;AAGD,GAAA,CAAI,YAAA,CAAa,OAAA,CAAQ,GAAA,CAAI,CAAC,MAAA,KAAW;AACvC,EAAA,MAAM,QAAQ,QAAA,EAAS;AACvB,EAAA,IAAI,KAAA,EAAO;AACT,IAAA,MAAA,CAAO,OAAA,CAAQ,aAAA,GAAgB,CAAA,OAAA,EAAU,KAAK,CAAA,CAAA;AAAA,EAChD;AACA,EAAA,OAAO,MAAA;AACT,CAAC,CAAA;AAGD,GAAA,CAAI,aAAa,QAAA,CAAS,GAAA;AAAA,EACxB,CAAC,aAAa,QAAA,CAAS,IAAA;AAAA,EACvB,CAAC,KAAA,KAAU;AACT,IAAA,IAAI,KAAA,CAAM,QAAA,EAAU,MAAA,KAAW,GAAA,EAAK;AAClC,MAAA,UAAA,EAAW;AACX,MAAA,IAAI,OAAO,WAAW,WAAA,EAAa;AACjC,QAAA,MAAA,CAAO,SAAS,IAAA,GAAO,QAAA;AAAA,MACzB;AAAA,IACF;AACA,IAAA,OAAO,OAAA,CAAQ,OAAO,KAAK,CAAA;AAAA,EAC7B;AACF,CAAA;AAEA,IAAO,cAAA,GAAQ","file":"index.js","sourcesContent":["/**\n * @coduckai/sdk/client — Frontend API Client (browser-only)\n *\n * Pre-configured Axios instance with auth interceptor.\n *\n * Usage:\n * import api, { setToken, clearToken } from '@coduckai/sdk/client';\n * const recipes = await api.get('/recipes'); // returns response.data directly\n * setToken(loginData.token);\n */\n\nimport axios, { type AxiosInstance } from 'axios';\n\n// ── Token Management ───────────────────────────────────\n\nconst TOKEN_KEY = 'token';\n\nexport function setToken(token: string): void {\n if (typeof localStorage !== 'undefined') {\n localStorage.setItem(TOKEN_KEY, token);\n }\n}\n\nexport function getToken(): string | null {\n if (typeof localStorage !== 'undefined') {\n return localStorage.getItem(TOKEN_KEY);\n }\n return null;\n}\n\nexport function clearToken(): void {\n if (typeof localStorage !== 'undefined') {\n localStorage.removeItem(TOKEN_KEY);\n }\n}\n\nexport function isAuthenticated(): boolean {\n return !!getToken();\n}\n\n// ── Axios Instance ─────────────────────────────────────\n\nfunction getBaseUrl(): string {\n // Vite: VITE_API_URL\n if (typeof import.meta !== 'undefined' && (import.meta as any).env?.VITE_API_URL) {\n return (import.meta as any).env.VITE_API_URL;\n }\n // Fallback: relative /api\n return '/api';\n}\n\nconst api: AxiosInstance = axios.create({\n baseURL: getBaseUrl(),\n headers: { 'Content-Type': 'application/json' },\n});\n\n// Request interceptor — attach Bearer token\napi.interceptors.request.use((config) => {\n const token = getToken();\n if (token) {\n config.headers.Authorization = `Bearer ${token}`;\n }\n return config;\n});\n\n// Response interceptor — auto-extract .data and handle 401\napi.interceptors.response.use(\n (response) => response.data,\n (error) => {\n if (error.response?.status === 401) {\n clearToken();\n if (typeof window !== 'undefined') {\n window.location.href = '/login';\n }\n }\n return Promise.reject(error);\n }\n);\n\nexport default api;\n"]}
|
package/dist/payments/index.cjs
CHANGED
|
@@ -61,7 +61,7 @@ function getWebhookSecret() {
|
|
|
61
61
|
var payments = {
|
|
62
62
|
/**
|
|
63
63
|
* Create a Stripe Checkout Session for one-time payment.
|
|
64
|
-
* Automatically
|
|
64
|
+
* Automatically uses direct charges (stripeAccount) when STRIPE_CONNECTED_ACCOUNT_ID is set.
|
|
65
65
|
*/
|
|
66
66
|
async createCheckout(options) {
|
|
67
67
|
const stripe = getStripeInstance();
|
|
@@ -85,17 +85,18 @@ var payments = {
|
|
|
85
85
|
...options.customerEmail && { customer_email: options.customerEmail },
|
|
86
86
|
...options.metadata && { metadata: options.metadata }
|
|
87
87
|
};
|
|
88
|
-
if (connectedAccountId) {
|
|
88
|
+
if (connectedAccountId && options.applicationFeeAmount) {
|
|
89
89
|
params.payment_intent_data = {
|
|
90
|
-
|
|
90
|
+
application_fee_amount: options.applicationFeeAmount
|
|
91
91
|
};
|
|
92
92
|
}
|
|
93
|
-
const
|
|
93
|
+
const requestOptions = connectedAccountId ? { stripeAccount: connectedAccountId } : void 0;
|
|
94
|
+
const session = await stripe.checkout.sessions.create(params, requestOptions);
|
|
94
95
|
return { url: session.url, sessionId: session.id };
|
|
95
96
|
},
|
|
96
97
|
/**
|
|
97
98
|
* Create a Stripe Checkout Session for subscriptions.
|
|
98
|
-
* Automatically
|
|
99
|
+
* Automatically uses direct charges (stripeAccount) when STRIPE_CONNECTED_ACCOUNT_ID is set.
|
|
99
100
|
*/
|
|
100
101
|
async createSubscription(options) {
|
|
101
102
|
const stripe = getStripeInstance();
|
|
@@ -108,16 +109,17 @@ var payments = {
|
|
|
108
109
|
...options.customerEmail && { customer_email: options.customerEmail },
|
|
109
110
|
...options.metadata && { metadata: options.metadata }
|
|
110
111
|
};
|
|
111
|
-
if (options.trialDays || connectedAccountId) {
|
|
112
|
+
if (options.trialDays || connectedAccountId && options.applicationFeePercent) {
|
|
112
113
|
params.subscription_data = {};
|
|
113
114
|
if (options.trialDays) {
|
|
114
115
|
params.subscription_data.trial_period_days = options.trialDays;
|
|
115
116
|
}
|
|
116
|
-
if (connectedAccountId) {
|
|
117
|
-
params.subscription_data.
|
|
117
|
+
if (connectedAccountId && options.applicationFeePercent) {
|
|
118
|
+
params.subscription_data.application_fee_percent = options.applicationFeePercent;
|
|
118
119
|
}
|
|
119
120
|
}
|
|
120
|
-
const
|
|
121
|
+
const requestOptions = connectedAccountId ? { stripeAccount: connectedAccountId } : void 0;
|
|
122
|
+
const session = await stripe.checkout.sessions.create(params, requestOptions);
|
|
121
123
|
return { url: session.url, sessionId: session.id };
|
|
122
124
|
},
|
|
123
125
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/internal/env.ts","../../src/internal/config.ts","../../src/payments/index.ts"],"names":["Stripe"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Environment variable helpers\n */\n\nexport function getEnv(key: string, fallback?: string): string | undefined {\n return process.env[key] || fallback;\n}\n\nexport function requireEnv(key: string): string {\n const val = process.env[key];\n if (!val) {\n throw new Error(`@coduckai/sdk: Missing required environment variable: ${key}`);\n }\n return val;\n}\n\nexport function isServer(): boolean {\n return typeof window === 'undefined';\n}\n\nexport function assertServer(moduleName: string): void {\n if (!isServer()) {\n throw new Error(\n `@coduckai/sdk/${moduleName} is server-only. Use @coduckai/sdk/client for browser code.`\n );\n }\n}\n","/**\n * Global SDK configuration\n *\n * CoDuck apps use env vars automatically — no configure() needed.\n * Standalone usage can call configure() to override.\n */\n\nexport interface SDKConfig {\n auth?: {\n jwtSecret?: string;\n jwtExpiresIn?: string;\n bcryptRounds?: number;\n };\n db?: {\n connectionString?: string;\n };\n client?: {\n baseUrl?: string;\n tokenKey?: string;\n };\n payments?: {\n stripeSecretKey?: string;\n connectedAccountId?: string;\n webhookSecret?: string;\n };\n ai?: {\n provider?: 'openai' | 'anthropic';\n apiKey?: string;\n };\n}\n\nlet globalConfig: SDKConfig = {};\n\nexport function setConfig(config: SDKConfig): void {\n globalConfig = { ...globalConfig, ...config };\n}\n\nexport function getConfig(): SDKConfig {\n return globalConfig;\n}\n","/**\n * @coduckai/sdk/payments — Stripe Payments (server-only)\n *\n * Wraps Stripe SDK with automatic Connect destination charges.\n * Auto-reads STRIPE_SECRET_KEY, STRIPE_CONNECTED_ACCOUNT_ID, STRIPE_WEBHOOK_SECRET from env.\n */\n\nimport { assertServer } from '../internal/env';\nimport { getConfig } from '../internal/config';\nimport Stripe from 'stripe';\n\nassertServer('payments');\n\n// ---------------------------------------------------------------------------\n// Lazy singleton Stripe instance\n// ---------------------------------------------------------------------------\n\nlet stripeInstance: Stripe | null = null;\n\nfunction getStripeInstance(): Stripe {\n if (stripeInstance) return stripeInstance;\n\n const config = getConfig();\n const secretKey = config.payments?.stripeSecretKey || process.env.STRIPE_SECRET_KEY;\n\n if (!secretKey) {\n throw new Error(\n '@coduckai/sdk/payments: STRIPE_SECRET_KEY is required. Set the env var or call configure().'\n );\n }\n\n stripeInstance = new Stripe(secretKey);\n return stripeInstance;\n}\n\nfunction getConnectedAccountId(): string | undefined {\n const config = getConfig();\n return config.payments?.connectedAccountId || process.env.STRIPE_CONNECTED_ACCOUNT_ID || undefined;\n}\n\nfunction getWebhookSecret(): string {\n const config = getConfig();\n const secret = config.payments?.webhookSecret || process.env.STRIPE_WEBHOOK_SECRET;\n if (!secret) {\n throw new Error(\n '@coduckai/sdk/payments: STRIPE_WEBHOOK_SECRET is required for webhook handling.'\n );\n }\n return secret;\n}\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface CheckoutItem {\n name: string;\n /** Price in dollars (e.g. 29.99) */\n price: number;\n quantity?: number;\n description?: string;\n image?: string;\n}\n\nexport interface CreateCheckoutOptions {\n items: CheckoutItem[];\n successUrl: string;\n cancelUrl: string;\n customerEmail?: string;\n metadata?: Record<string, string>;\n}\n\nexport interface CreateSubscriptionOptions {\n priceId: string;\n successUrl: string;\n cancelUrl: string;\n customerEmail?: string;\n trialDays?: number;\n metadata?: Record<string, string>;\n}\n\nexport interface CheckoutResult {\n url: string;\n sessionId: string;\n}\n\nexport interface WebhookHandlers {\n onCheckoutComplete?: (session: Stripe.Checkout.Session) => Promise<void> | void;\n onSubscriptionCreated?: (subscription: Stripe.Subscription) => Promise<void> | void;\n onSubscriptionUpdated?: (subscription: Stripe.Subscription) => Promise<void> | void;\n onSubscriptionDeleted?: (subscription: Stripe.Subscription) => Promise<void> | void;\n onPaymentSucceeded?: (invoice: Stripe.Invoice) => Promise<void> | void;\n onPaymentFailed?: (invoice: Stripe.Invoice) => Promise<void> | void;\n onChargeRefunded?: (charge: Stripe.Charge) => Promise<void> | void;\n}\n\n// ---------------------------------------------------------------------------\n// Payments API\n// ---------------------------------------------------------------------------\n\nexport const payments = {\n /**\n * Create a Stripe Checkout Session for one-time payment.\n * Automatically includes destination charges when STRIPE_CONNECTED_ACCOUNT_ID is set.\n */\n async createCheckout(options: CreateCheckoutOptions): Promise<CheckoutResult> {\n const stripe = getStripeInstance();\n const connectedAccountId = getConnectedAccountId();\n\n const params: Stripe.Checkout.SessionCreateParams = {\n mode: 'payment',\n line_items: options.items.map(item => ({\n price_data: {\n currency: 'usd',\n product_data: {\n name: item.name,\n ...(item.description && { description: item.description }),\n ...(item.image && { images: [item.image] }),\n },\n unit_amount: Math.round(item.price * 100),\n },\n quantity: item.quantity || 1,\n })),\n success_url: options.successUrl,\n cancel_url: options.cancelUrl,\n ...(options.customerEmail && { customer_email: options.customerEmail }),\n ...(options.metadata && { metadata: options.metadata }),\n };\n\n if (connectedAccountId) {\n params.payment_intent_data = {\n transfer_data: { destination: connectedAccountId },\n };\n }\n\n const session = await stripe.checkout.sessions.create(params);\n\n return { url: session.url!, sessionId: session.id };\n },\n\n /**\n * Create a Stripe Checkout Session for subscriptions.\n * Automatically includes destination charges when STRIPE_CONNECTED_ACCOUNT_ID is set.\n */\n async createSubscription(options: CreateSubscriptionOptions): Promise<CheckoutResult> {\n const stripe = getStripeInstance();\n const connectedAccountId = getConnectedAccountId();\n\n const params: Stripe.Checkout.SessionCreateParams = {\n mode: 'subscription',\n line_items: [{ price: options.priceId, quantity: 1 }],\n success_url: options.successUrl,\n cancel_url: options.cancelUrl,\n ...(options.customerEmail && { customer_email: options.customerEmail }),\n ...(options.metadata && { metadata: options.metadata }),\n };\n\n if (options.trialDays || connectedAccountId) {\n params.subscription_data = {};\n if (options.trialDays) {\n params.subscription_data.trial_period_days = options.trialDays;\n }\n if (connectedAccountId) {\n params.subscription_data.transfer_data = { destination: connectedAccountId };\n }\n }\n\n const session = await stripe.checkout.sessions.create(params);\n\n return { url: session.url!, sessionId: session.id };\n },\n\n /**\n * Handle Stripe webhook events with typed handlers.\n * Verifies the webhook signature and dispatches to your handler callbacks.\n */\n async handleWebhook(req: any, handlers: WebhookHandlers): Promise<void> {\n const stripe = getStripeInstance();\n const webhookSecret = getWebhookSecret();\n\n const sig = req.headers['stripe-signature'];\n const event = stripe.webhooks.constructEvent(req.body, sig, webhookSecret);\n\n switch (event.type) {\n case 'checkout.session.completed':\n await handlers.onCheckoutComplete?.(event.data.object as Stripe.Checkout.Session);\n break;\n case 'customer.subscription.created':\n await handlers.onSubscriptionCreated?.(event.data.object as Stripe.Subscription);\n break;\n case 'customer.subscription.updated':\n await handlers.onSubscriptionUpdated?.(event.data.object as Stripe.Subscription);\n break;\n case 'customer.subscription.deleted':\n await handlers.onSubscriptionDeleted?.(event.data.object as Stripe.Subscription);\n break;\n case 'invoice.payment_succeeded':\n await handlers.onPaymentSucceeded?.(event.data.object as Stripe.Invoice);\n break;\n case 'invoice.payment_failed':\n await handlers.onPaymentFailed?.(event.data.object as Stripe.Invoice);\n break;\n case 'charge.refunded':\n await handlers.onChargeRefunded?.(event.data.object as Stripe.Charge);\n break;\n }\n },\n\n /**\n * Express middleware for webhook routes.\n * Applies express.raw() body parser — mount BEFORE any json() middleware.\n */\n webhookMiddleware(): any {\n try {\n const express = require('express');\n return express.raw({ type: 'application/json' });\n } catch {\n return (_req: any, _res: any, next: any) => next();\n }\n },\n\n /**\n * Get the underlying Stripe instance for advanced usage.\n */\n getStripe(): Stripe {\n return getStripeInstance();\n },\n};\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/internal/env.ts","../../src/internal/config.ts","../../src/payments/index.ts"],"names":["Stripe"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Environment variable helpers\n */\n\nexport function getEnv(key: string, fallback?: string): string | undefined {\n return process.env[key] || fallback;\n}\n\nexport function requireEnv(key: string): string {\n const val = process.env[key];\n if (!val) {\n throw new Error(`@coduckai/sdk: Missing required environment variable: ${key}`);\n }\n return val;\n}\n\nexport function isServer(): boolean {\n return typeof window === 'undefined';\n}\n\nexport function assertServer(moduleName: string): void {\n if (!isServer()) {\n throw new Error(\n `@coduckai/sdk/${moduleName} is server-only. Use @coduckai/sdk/client for browser code.`\n );\n }\n}\n","/**\n * Global SDK configuration\n *\n * CoDuck apps use env vars automatically — no configure() needed.\n * Standalone usage can call configure() to override.\n */\n\nexport interface SDKConfig {\n auth?: {\n jwtSecret?: string;\n jwtExpiresIn?: string;\n bcryptRounds?: number;\n };\n db?: {\n connectionString?: string;\n };\n client?: {\n baseUrl?: string;\n tokenKey?: string;\n };\n payments?: {\n stripeSecretKey?: string;\n connectedAccountId?: string;\n webhookSecret?: string;\n };\n ai?: {\n provider?: 'openai' | 'anthropic';\n apiKey?: string;\n };\n}\n\nlet globalConfig: SDKConfig = {};\n\nexport function setConfig(config: SDKConfig): void {\n globalConfig = { ...globalConfig, ...config };\n}\n\nexport function getConfig(): SDKConfig {\n return globalConfig;\n}\n","/**\n * @coduckai/sdk/payments — Stripe Payments (server-only)\n *\n * Wraps Stripe SDK with automatic Connect direct charges via stripeAccount header.\n * Auto-reads STRIPE_SECRET_KEY, STRIPE_CONNECTED_ACCOUNT_ID, STRIPE_WEBHOOK_SECRET from env.\n */\n\nimport { assertServer } from '../internal/env';\nimport { getConfig } from '../internal/config';\nimport Stripe from 'stripe';\n\nassertServer('payments');\n\n// ---------------------------------------------------------------------------\n// Lazy singleton Stripe instance\n// ---------------------------------------------------------------------------\n\nlet stripeInstance: Stripe | null = null;\n\nfunction getStripeInstance(): Stripe {\n if (stripeInstance) return stripeInstance;\n\n const config = getConfig();\n const secretKey = config.payments?.stripeSecretKey || process.env.STRIPE_SECRET_KEY;\n\n if (!secretKey) {\n throw new Error(\n '@coduckai/sdk/payments: STRIPE_SECRET_KEY is required. Set the env var or call configure().'\n );\n }\n\n stripeInstance = new Stripe(secretKey);\n return stripeInstance;\n}\n\nfunction getConnectedAccountId(): string | undefined {\n const config = getConfig();\n return config.payments?.connectedAccountId || process.env.STRIPE_CONNECTED_ACCOUNT_ID || undefined;\n}\n\nfunction getWebhookSecret(): string {\n const config = getConfig();\n const secret = config.payments?.webhookSecret || process.env.STRIPE_WEBHOOK_SECRET;\n if (!secret) {\n throw new Error(\n '@coduckai/sdk/payments: STRIPE_WEBHOOK_SECRET is required for webhook handling.'\n );\n }\n return secret;\n}\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface CheckoutItem {\n name: string;\n /** Price in dollars (e.g. 29.99) */\n price: number;\n quantity?: number;\n description?: string;\n image?: string;\n}\n\nexport interface CreateCheckoutOptions {\n items: CheckoutItem[];\n successUrl: string;\n cancelUrl: string;\n customerEmail?: string;\n metadata?: Record<string, string>;\n /** Application fee in cents charged on top of the payment (Connect only) */\n applicationFeeAmount?: number;\n}\n\nexport interface CreateSubscriptionOptions {\n priceId: string;\n successUrl: string;\n cancelUrl: string;\n customerEmail?: string;\n trialDays?: number;\n metadata?: Record<string, string>;\n /** Application fee percentage for recurring charges (0-100, Connect only) */\n applicationFeePercent?: number;\n}\n\nexport interface CheckoutResult {\n url: string;\n sessionId: string;\n}\n\nexport interface WebhookHandlers {\n onCheckoutComplete?: (session: Stripe.Checkout.Session) => Promise<void> | void;\n onSubscriptionCreated?: (subscription: Stripe.Subscription) => Promise<void> | void;\n onSubscriptionUpdated?: (subscription: Stripe.Subscription) => Promise<void> | void;\n onSubscriptionDeleted?: (subscription: Stripe.Subscription) => Promise<void> | void;\n onPaymentSucceeded?: (invoice: Stripe.Invoice) => Promise<void> | void;\n onPaymentFailed?: (invoice: Stripe.Invoice) => Promise<void> | void;\n onChargeRefunded?: (charge: Stripe.Charge) => Promise<void> | void;\n}\n\n// ---------------------------------------------------------------------------\n// Payments API\n// ---------------------------------------------------------------------------\n\nexport const payments = {\n /**\n * Create a Stripe Checkout Session for one-time payment.\n * Automatically uses direct charges (stripeAccount) when STRIPE_CONNECTED_ACCOUNT_ID is set.\n */\n async createCheckout(options: CreateCheckoutOptions): Promise<CheckoutResult> {\n const stripe = getStripeInstance();\n const connectedAccountId = getConnectedAccountId();\n\n const params: Stripe.Checkout.SessionCreateParams = {\n mode: 'payment',\n line_items: options.items.map(item => ({\n price_data: {\n currency: 'usd',\n product_data: {\n name: item.name,\n ...(item.description && { description: item.description }),\n ...(item.image && { images: [item.image] }),\n },\n unit_amount: Math.round(item.price * 100),\n },\n quantity: item.quantity || 1,\n })),\n success_url: options.successUrl,\n cancel_url: options.cancelUrl,\n ...(options.customerEmail && { customer_email: options.customerEmail }),\n ...(options.metadata && { metadata: options.metadata }),\n };\n\n if (connectedAccountId && options.applicationFeeAmount) {\n params.payment_intent_data = {\n application_fee_amount: options.applicationFeeAmount,\n };\n }\n\n const requestOptions: Stripe.RequestOptions | undefined = connectedAccountId\n ? { stripeAccount: connectedAccountId }\n : undefined;\n\n const session = await stripe.checkout.sessions.create(params, requestOptions);\n\n return { url: session.url!, sessionId: session.id };\n },\n\n /**\n * Create a Stripe Checkout Session for subscriptions.\n * Automatically uses direct charges (stripeAccount) when STRIPE_CONNECTED_ACCOUNT_ID is set.\n */\n async createSubscription(options: CreateSubscriptionOptions): Promise<CheckoutResult> {\n const stripe = getStripeInstance();\n const connectedAccountId = getConnectedAccountId();\n\n const params: Stripe.Checkout.SessionCreateParams = {\n mode: 'subscription',\n line_items: [{ price: options.priceId, quantity: 1 }],\n success_url: options.successUrl,\n cancel_url: options.cancelUrl,\n ...(options.customerEmail && { customer_email: options.customerEmail }),\n ...(options.metadata && { metadata: options.metadata }),\n };\n\n if (options.trialDays || (connectedAccountId && options.applicationFeePercent)) {\n params.subscription_data = {};\n if (options.trialDays) {\n params.subscription_data.trial_period_days = options.trialDays;\n }\n if (connectedAccountId && options.applicationFeePercent) {\n params.subscription_data.application_fee_percent = options.applicationFeePercent;\n }\n }\n\n const requestOptions: Stripe.RequestOptions | undefined = connectedAccountId\n ? { stripeAccount: connectedAccountId }\n : undefined;\n\n const session = await stripe.checkout.sessions.create(params, requestOptions);\n\n return { url: session.url!, sessionId: session.id };\n },\n\n /**\n * Handle Stripe webhook events with typed handlers.\n * Verifies the webhook signature and dispatches to your handler callbacks.\n */\n async handleWebhook(req: any, handlers: WebhookHandlers): Promise<void> {\n const stripe = getStripeInstance();\n const webhookSecret = getWebhookSecret();\n\n const sig = req.headers['stripe-signature'];\n const event = stripe.webhooks.constructEvent(req.body, sig, webhookSecret);\n\n switch (event.type) {\n case 'checkout.session.completed':\n await handlers.onCheckoutComplete?.(event.data.object as Stripe.Checkout.Session);\n break;\n case 'customer.subscription.created':\n await handlers.onSubscriptionCreated?.(event.data.object as Stripe.Subscription);\n break;\n case 'customer.subscription.updated':\n await handlers.onSubscriptionUpdated?.(event.data.object as Stripe.Subscription);\n break;\n case 'customer.subscription.deleted':\n await handlers.onSubscriptionDeleted?.(event.data.object as Stripe.Subscription);\n break;\n case 'invoice.payment_succeeded':\n await handlers.onPaymentSucceeded?.(event.data.object as Stripe.Invoice);\n break;\n case 'invoice.payment_failed':\n await handlers.onPaymentFailed?.(event.data.object as Stripe.Invoice);\n break;\n case 'charge.refunded':\n await handlers.onChargeRefunded?.(event.data.object as Stripe.Charge);\n break;\n }\n },\n\n /**\n * Express middleware for webhook routes.\n * Applies express.raw() body parser — mount BEFORE any json() middleware.\n */\n webhookMiddleware(): any {\n try {\n const express = require('express');\n return express.raw({ type: 'application/json' });\n } catch {\n return (_req: any, _res: any, next: any) => next();\n }\n },\n\n /**\n * Get the underlying Stripe instance for advanced usage.\n */\n getStripe(): Stripe {\n return getStripeInstance();\n },\n};\n"]}
|
|
@@ -3,7 +3,7 @@ import Stripe from 'stripe';
|
|
|
3
3
|
/**
|
|
4
4
|
* @coduckai/sdk/payments — Stripe Payments (server-only)
|
|
5
5
|
*
|
|
6
|
-
* Wraps Stripe SDK with automatic Connect
|
|
6
|
+
* Wraps Stripe SDK with automatic Connect direct charges via stripeAccount header.
|
|
7
7
|
* Auto-reads STRIPE_SECRET_KEY, STRIPE_CONNECTED_ACCOUNT_ID, STRIPE_WEBHOOK_SECRET from env.
|
|
8
8
|
*/
|
|
9
9
|
|
|
@@ -21,6 +21,8 @@ interface CreateCheckoutOptions {
|
|
|
21
21
|
cancelUrl: string;
|
|
22
22
|
customerEmail?: string;
|
|
23
23
|
metadata?: Record<string, string>;
|
|
24
|
+
/** Application fee in cents charged on top of the payment (Connect only) */
|
|
25
|
+
applicationFeeAmount?: number;
|
|
24
26
|
}
|
|
25
27
|
interface CreateSubscriptionOptions {
|
|
26
28
|
priceId: string;
|
|
@@ -29,6 +31,8 @@ interface CreateSubscriptionOptions {
|
|
|
29
31
|
customerEmail?: string;
|
|
30
32
|
trialDays?: number;
|
|
31
33
|
metadata?: Record<string, string>;
|
|
34
|
+
/** Application fee percentage for recurring charges (0-100, Connect only) */
|
|
35
|
+
applicationFeePercent?: number;
|
|
32
36
|
}
|
|
33
37
|
interface CheckoutResult {
|
|
34
38
|
url: string;
|
|
@@ -46,12 +50,12 @@ interface WebhookHandlers {
|
|
|
46
50
|
declare const payments: {
|
|
47
51
|
/**
|
|
48
52
|
* Create a Stripe Checkout Session for one-time payment.
|
|
49
|
-
* Automatically
|
|
53
|
+
* Automatically uses direct charges (stripeAccount) when STRIPE_CONNECTED_ACCOUNT_ID is set.
|
|
50
54
|
*/
|
|
51
55
|
createCheckout(options: CreateCheckoutOptions): Promise<CheckoutResult>;
|
|
52
56
|
/**
|
|
53
57
|
* Create a Stripe Checkout Session for subscriptions.
|
|
54
|
-
* Automatically
|
|
58
|
+
* Automatically uses direct charges (stripeAccount) when STRIPE_CONNECTED_ACCOUNT_ID is set.
|
|
55
59
|
*/
|
|
56
60
|
createSubscription(options: CreateSubscriptionOptions): Promise<CheckoutResult>;
|
|
57
61
|
/**
|
package/dist/payments/index.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ import Stripe from 'stripe';
|
|
|
3
3
|
/**
|
|
4
4
|
* @coduckai/sdk/payments — Stripe Payments (server-only)
|
|
5
5
|
*
|
|
6
|
-
* Wraps Stripe SDK with automatic Connect
|
|
6
|
+
* Wraps Stripe SDK with automatic Connect direct charges via stripeAccount header.
|
|
7
7
|
* Auto-reads STRIPE_SECRET_KEY, STRIPE_CONNECTED_ACCOUNT_ID, STRIPE_WEBHOOK_SECRET from env.
|
|
8
8
|
*/
|
|
9
9
|
|
|
@@ -21,6 +21,8 @@ interface CreateCheckoutOptions {
|
|
|
21
21
|
cancelUrl: string;
|
|
22
22
|
customerEmail?: string;
|
|
23
23
|
metadata?: Record<string, string>;
|
|
24
|
+
/** Application fee in cents charged on top of the payment (Connect only) */
|
|
25
|
+
applicationFeeAmount?: number;
|
|
24
26
|
}
|
|
25
27
|
interface CreateSubscriptionOptions {
|
|
26
28
|
priceId: string;
|
|
@@ -29,6 +31,8 @@ interface CreateSubscriptionOptions {
|
|
|
29
31
|
customerEmail?: string;
|
|
30
32
|
trialDays?: number;
|
|
31
33
|
metadata?: Record<string, string>;
|
|
34
|
+
/** Application fee percentage for recurring charges (0-100, Connect only) */
|
|
35
|
+
applicationFeePercent?: number;
|
|
32
36
|
}
|
|
33
37
|
interface CheckoutResult {
|
|
34
38
|
url: string;
|
|
@@ -46,12 +50,12 @@ interface WebhookHandlers {
|
|
|
46
50
|
declare const payments: {
|
|
47
51
|
/**
|
|
48
52
|
* Create a Stripe Checkout Session for one-time payment.
|
|
49
|
-
* Automatically
|
|
53
|
+
* Automatically uses direct charges (stripeAccount) when STRIPE_CONNECTED_ACCOUNT_ID is set.
|
|
50
54
|
*/
|
|
51
55
|
createCheckout(options: CreateCheckoutOptions): Promise<CheckoutResult>;
|
|
52
56
|
/**
|
|
53
57
|
* Create a Stripe Checkout Session for subscriptions.
|
|
54
|
-
* Automatically
|
|
58
|
+
* Automatically uses direct charges (stripeAccount) when STRIPE_CONNECTED_ACCOUNT_ID is set.
|
|
55
59
|
*/
|
|
56
60
|
createSubscription(options: CreateSubscriptionOptions): Promise<CheckoutResult>;
|
|
57
61
|
/**
|
package/dist/payments/index.js
CHANGED
|
@@ -55,7 +55,7 @@ function getWebhookSecret() {
|
|
|
55
55
|
var payments = {
|
|
56
56
|
/**
|
|
57
57
|
* Create a Stripe Checkout Session for one-time payment.
|
|
58
|
-
* Automatically
|
|
58
|
+
* Automatically uses direct charges (stripeAccount) when STRIPE_CONNECTED_ACCOUNT_ID is set.
|
|
59
59
|
*/
|
|
60
60
|
async createCheckout(options) {
|
|
61
61
|
const stripe = getStripeInstance();
|
|
@@ -79,17 +79,18 @@ var payments = {
|
|
|
79
79
|
...options.customerEmail && { customer_email: options.customerEmail },
|
|
80
80
|
...options.metadata && { metadata: options.metadata }
|
|
81
81
|
};
|
|
82
|
-
if (connectedAccountId) {
|
|
82
|
+
if (connectedAccountId && options.applicationFeeAmount) {
|
|
83
83
|
params.payment_intent_data = {
|
|
84
|
-
|
|
84
|
+
application_fee_amount: options.applicationFeeAmount
|
|
85
85
|
};
|
|
86
86
|
}
|
|
87
|
-
const
|
|
87
|
+
const requestOptions = connectedAccountId ? { stripeAccount: connectedAccountId } : void 0;
|
|
88
|
+
const session = await stripe.checkout.sessions.create(params, requestOptions);
|
|
88
89
|
return { url: session.url, sessionId: session.id };
|
|
89
90
|
},
|
|
90
91
|
/**
|
|
91
92
|
* Create a Stripe Checkout Session for subscriptions.
|
|
92
|
-
* Automatically
|
|
93
|
+
* Automatically uses direct charges (stripeAccount) when STRIPE_CONNECTED_ACCOUNT_ID is set.
|
|
93
94
|
*/
|
|
94
95
|
async createSubscription(options) {
|
|
95
96
|
const stripe = getStripeInstance();
|
|
@@ -102,16 +103,17 @@ var payments = {
|
|
|
102
103
|
...options.customerEmail && { customer_email: options.customerEmail },
|
|
103
104
|
...options.metadata && { metadata: options.metadata }
|
|
104
105
|
};
|
|
105
|
-
if (options.trialDays || connectedAccountId) {
|
|
106
|
+
if (options.trialDays || connectedAccountId && options.applicationFeePercent) {
|
|
106
107
|
params.subscription_data = {};
|
|
107
108
|
if (options.trialDays) {
|
|
108
109
|
params.subscription_data.trial_period_days = options.trialDays;
|
|
109
110
|
}
|
|
110
|
-
if (connectedAccountId) {
|
|
111
|
-
params.subscription_data.
|
|
111
|
+
if (connectedAccountId && options.applicationFeePercent) {
|
|
112
|
+
params.subscription_data.application_fee_percent = options.applicationFeePercent;
|
|
112
113
|
}
|
|
113
114
|
}
|
|
114
|
-
const
|
|
115
|
+
const requestOptions = connectedAccountId ? { stripeAccount: connectedAccountId } : void 0;
|
|
116
|
+
const session = await stripe.checkout.sessions.create(params, requestOptions);
|
|
115
117
|
return { url: session.url, sessionId: session.id };
|
|
116
118
|
},
|
|
117
119
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/internal/env.ts","../../src/internal/config.ts","../../src/payments/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Environment variable helpers\n */\n\nexport function getEnv(key: string, fallback?: string): string | undefined {\n return process.env[key] || fallback;\n}\n\nexport function requireEnv(key: string): string {\n const val = process.env[key];\n if (!val) {\n throw new Error(`@coduckai/sdk: Missing required environment variable: ${key}`);\n }\n return val;\n}\n\nexport function isServer(): boolean {\n return typeof window === 'undefined';\n}\n\nexport function assertServer(moduleName: string): void {\n if (!isServer()) {\n throw new Error(\n `@coduckai/sdk/${moduleName} is server-only. Use @coduckai/sdk/client for browser code.`\n );\n }\n}\n","/**\n * Global SDK configuration\n *\n * CoDuck apps use env vars automatically — no configure() needed.\n * Standalone usage can call configure() to override.\n */\n\nexport interface SDKConfig {\n auth?: {\n jwtSecret?: string;\n jwtExpiresIn?: string;\n bcryptRounds?: number;\n };\n db?: {\n connectionString?: string;\n };\n client?: {\n baseUrl?: string;\n tokenKey?: string;\n };\n payments?: {\n stripeSecretKey?: string;\n connectedAccountId?: string;\n webhookSecret?: string;\n };\n ai?: {\n provider?: 'openai' | 'anthropic';\n apiKey?: string;\n };\n}\n\nlet globalConfig: SDKConfig = {};\n\nexport function setConfig(config: SDKConfig): void {\n globalConfig = { ...globalConfig, ...config };\n}\n\nexport function getConfig(): SDKConfig {\n return globalConfig;\n}\n","/**\n * @coduckai/sdk/payments — Stripe Payments (server-only)\n *\n * Wraps Stripe SDK with automatic Connect destination charges.\n * Auto-reads STRIPE_SECRET_KEY, STRIPE_CONNECTED_ACCOUNT_ID, STRIPE_WEBHOOK_SECRET from env.\n */\n\nimport { assertServer } from '../internal/env';\nimport { getConfig } from '../internal/config';\nimport Stripe from 'stripe';\n\nassertServer('payments');\n\n// ---------------------------------------------------------------------------\n// Lazy singleton Stripe instance\n// ---------------------------------------------------------------------------\n\nlet stripeInstance: Stripe | null = null;\n\nfunction getStripeInstance(): Stripe {\n if (stripeInstance) return stripeInstance;\n\n const config = getConfig();\n const secretKey = config.payments?.stripeSecretKey || process.env.STRIPE_SECRET_KEY;\n\n if (!secretKey) {\n throw new Error(\n '@coduckai/sdk/payments: STRIPE_SECRET_KEY is required. Set the env var or call configure().'\n );\n }\n\n stripeInstance = new Stripe(secretKey);\n return stripeInstance;\n}\n\nfunction getConnectedAccountId(): string | undefined {\n const config = getConfig();\n return config.payments?.connectedAccountId || process.env.STRIPE_CONNECTED_ACCOUNT_ID || undefined;\n}\n\nfunction getWebhookSecret(): string {\n const config = getConfig();\n const secret = config.payments?.webhookSecret || process.env.STRIPE_WEBHOOK_SECRET;\n if (!secret) {\n throw new Error(\n '@coduckai/sdk/payments: STRIPE_WEBHOOK_SECRET is required for webhook handling.'\n );\n }\n return secret;\n}\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface CheckoutItem {\n name: string;\n /** Price in dollars (e.g. 29.99) */\n price: number;\n quantity?: number;\n description?: string;\n image?: string;\n}\n\nexport interface CreateCheckoutOptions {\n items: CheckoutItem[];\n successUrl: string;\n cancelUrl: string;\n customerEmail?: string;\n metadata?: Record<string, string>;\n}\n\nexport interface CreateSubscriptionOptions {\n priceId: string;\n successUrl: string;\n cancelUrl: string;\n customerEmail?: string;\n trialDays?: number;\n metadata?: Record<string, string>;\n}\n\nexport interface CheckoutResult {\n url: string;\n sessionId: string;\n}\n\nexport interface WebhookHandlers {\n onCheckoutComplete?: (session: Stripe.Checkout.Session) => Promise<void> | void;\n onSubscriptionCreated?: (subscription: Stripe.Subscription) => Promise<void> | void;\n onSubscriptionUpdated?: (subscription: Stripe.Subscription) => Promise<void> | void;\n onSubscriptionDeleted?: (subscription: Stripe.Subscription) => Promise<void> | void;\n onPaymentSucceeded?: (invoice: Stripe.Invoice) => Promise<void> | void;\n onPaymentFailed?: (invoice: Stripe.Invoice) => Promise<void> | void;\n onChargeRefunded?: (charge: Stripe.Charge) => Promise<void> | void;\n}\n\n// ---------------------------------------------------------------------------\n// Payments API\n// ---------------------------------------------------------------------------\n\nexport const payments = {\n /**\n * Create a Stripe Checkout Session for one-time payment.\n * Automatically includes destination charges when STRIPE_CONNECTED_ACCOUNT_ID is set.\n */\n async createCheckout(options: CreateCheckoutOptions): Promise<CheckoutResult> {\n const stripe = getStripeInstance();\n const connectedAccountId = getConnectedAccountId();\n\n const params: Stripe.Checkout.SessionCreateParams = {\n mode: 'payment',\n line_items: options.items.map(item => ({\n price_data: {\n currency: 'usd',\n product_data: {\n name: item.name,\n ...(item.description && { description: item.description }),\n ...(item.image && { images: [item.image] }),\n },\n unit_amount: Math.round(item.price * 100),\n },\n quantity: item.quantity || 1,\n })),\n success_url: options.successUrl,\n cancel_url: options.cancelUrl,\n ...(options.customerEmail && { customer_email: options.customerEmail }),\n ...(options.metadata && { metadata: options.metadata }),\n };\n\n if (connectedAccountId) {\n params.payment_intent_data = {\n transfer_data: { destination: connectedAccountId },\n };\n }\n\n const session = await stripe.checkout.sessions.create(params);\n\n return { url: session.url!, sessionId: session.id };\n },\n\n /**\n * Create a Stripe Checkout Session for subscriptions.\n * Automatically includes destination charges when STRIPE_CONNECTED_ACCOUNT_ID is set.\n */\n async createSubscription(options: CreateSubscriptionOptions): Promise<CheckoutResult> {\n const stripe = getStripeInstance();\n const connectedAccountId = getConnectedAccountId();\n\n const params: Stripe.Checkout.SessionCreateParams = {\n mode: 'subscription',\n line_items: [{ price: options.priceId, quantity: 1 }],\n success_url: options.successUrl,\n cancel_url: options.cancelUrl,\n ...(options.customerEmail && { customer_email: options.customerEmail }),\n ...(options.metadata && { metadata: options.metadata }),\n };\n\n if (options.trialDays || connectedAccountId) {\n params.subscription_data = {};\n if (options.trialDays) {\n params.subscription_data.trial_period_days = options.trialDays;\n }\n if (connectedAccountId) {\n params.subscription_data.transfer_data = { destination: connectedAccountId };\n }\n }\n\n const session = await stripe.checkout.sessions.create(params);\n\n return { url: session.url!, sessionId: session.id };\n },\n\n /**\n * Handle Stripe webhook events with typed handlers.\n * Verifies the webhook signature and dispatches to your handler callbacks.\n */\n async handleWebhook(req: any, handlers: WebhookHandlers): Promise<void> {\n const stripe = getStripeInstance();\n const webhookSecret = getWebhookSecret();\n\n const sig = req.headers['stripe-signature'];\n const event = stripe.webhooks.constructEvent(req.body, sig, webhookSecret);\n\n switch (event.type) {\n case 'checkout.session.completed':\n await handlers.onCheckoutComplete?.(event.data.object as Stripe.Checkout.Session);\n break;\n case 'customer.subscription.created':\n await handlers.onSubscriptionCreated?.(event.data.object as Stripe.Subscription);\n break;\n case 'customer.subscription.updated':\n await handlers.onSubscriptionUpdated?.(event.data.object as Stripe.Subscription);\n break;\n case 'customer.subscription.deleted':\n await handlers.onSubscriptionDeleted?.(event.data.object as Stripe.Subscription);\n break;\n case 'invoice.payment_succeeded':\n await handlers.onPaymentSucceeded?.(event.data.object as Stripe.Invoice);\n break;\n case 'invoice.payment_failed':\n await handlers.onPaymentFailed?.(event.data.object as Stripe.Invoice);\n break;\n case 'charge.refunded':\n await handlers.onChargeRefunded?.(event.data.object as Stripe.Charge);\n break;\n }\n },\n\n /**\n * Express middleware for webhook routes.\n * Applies express.raw() body parser — mount BEFORE any json() middleware.\n */\n webhookMiddleware(): any {\n try {\n const express = require('express');\n return express.raw({ type: 'application/json' });\n } catch {\n return (_req: any, _res: any, next: any) => next();\n }\n },\n\n /**\n * Get the underlying Stripe instance for advanced usage.\n */\n getStripe(): Stripe {\n return getStripeInstance();\n },\n};\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/internal/env.ts","../../src/internal/config.ts","../../src/payments/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Environment variable helpers\n */\n\nexport function getEnv(key: string, fallback?: string): string | undefined {\n return process.env[key] || fallback;\n}\n\nexport function requireEnv(key: string): string {\n const val = process.env[key];\n if (!val) {\n throw new Error(`@coduckai/sdk: Missing required environment variable: ${key}`);\n }\n return val;\n}\n\nexport function isServer(): boolean {\n return typeof window === 'undefined';\n}\n\nexport function assertServer(moduleName: string): void {\n if (!isServer()) {\n throw new Error(\n `@coduckai/sdk/${moduleName} is server-only. Use @coduckai/sdk/client for browser code.`\n );\n }\n}\n","/**\n * Global SDK configuration\n *\n * CoDuck apps use env vars automatically — no configure() needed.\n * Standalone usage can call configure() to override.\n */\n\nexport interface SDKConfig {\n auth?: {\n jwtSecret?: string;\n jwtExpiresIn?: string;\n bcryptRounds?: number;\n };\n db?: {\n connectionString?: string;\n };\n client?: {\n baseUrl?: string;\n tokenKey?: string;\n };\n payments?: {\n stripeSecretKey?: string;\n connectedAccountId?: string;\n webhookSecret?: string;\n };\n ai?: {\n provider?: 'openai' | 'anthropic';\n apiKey?: string;\n };\n}\n\nlet globalConfig: SDKConfig = {};\n\nexport function setConfig(config: SDKConfig): void {\n globalConfig = { ...globalConfig, ...config };\n}\n\nexport function getConfig(): SDKConfig {\n return globalConfig;\n}\n","/**\n * @coduckai/sdk/payments — Stripe Payments (server-only)\n *\n * Wraps Stripe SDK with automatic Connect direct charges via stripeAccount header.\n * Auto-reads STRIPE_SECRET_KEY, STRIPE_CONNECTED_ACCOUNT_ID, STRIPE_WEBHOOK_SECRET from env.\n */\n\nimport { assertServer } from '../internal/env';\nimport { getConfig } from '../internal/config';\nimport Stripe from 'stripe';\n\nassertServer('payments');\n\n// ---------------------------------------------------------------------------\n// Lazy singleton Stripe instance\n// ---------------------------------------------------------------------------\n\nlet stripeInstance: Stripe | null = null;\n\nfunction getStripeInstance(): Stripe {\n if (stripeInstance) return stripeInstance;\n\n const config = getConfig();\n const secretKey = config.payments?.stripeSecretKey || process.env.STRIPE_SECRET_KEY;\n\n if (!secretKey) {\n throw new Error(\n '@coduckai/sdk/payments: STRIPE_SECRET_KEY is required. Set the env var or call configure().'\n );\n }\n\n stripeInstance = new Stripe(secretKey);\n return stripeInstance;\n}\n\nfunction getConnectedAccountId(): string | undefined {\n const config = getConfig();\n return config.payments?.connectedAccountId || process.env.STRIPE_CONNECTED_ACCOUNT_ID || undefined;\n}\n\nfunction getWebhookSecret(): string {\n const config = getConfig();\n const secret = config.payments?.webhookSecret || process.env.STRIPE_WEBHOOK_SECRET;\n if (!secret) {\n throw new Error(\n '@coduckai/sdk/payments: STRIPE_WEBHOOK_SECRET is required for webhook handling.'\n );\n }\n return secret;\n}\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface CheckoutItem {\n name: string;\n /** Price in dollars (e.g. 29.99) */\n price: number;\n quantity?: number;\n description?: string;\n image?: string;\n}\n\nexport interface CreateCheckoutOptions {\n items: CheckoutItem[];\n successUrl: string;\n cancelUrl: string;\n customerEmail?: string;\n metadata?: Record<string, string>;\n /** Application fee in cents charged on top of the payment (Connect only) */\n applicationFeeAmount?: number;\n}\n\nexport interface CreateSubscriptionOptions {\n priceId: string;\n successUrl: string;\n cancelUrl: string;\n customerEmail?: string;\n trialDays?: number;\n metadata?: Record<string, string>;\n /** Application fee percentage for recurring charges (0-100, Connect only) */\n applicationFeePercent?: number;\n}\n\nexport interface CheckoutResult {\n url: string;\n sessionId: string;\n}\n\nexport interface WebhookHandlers {\n onCheckoutComplete?: (session: Stripe.Checkout.Session) => Promise<void> | void;\n onSubscriptionCreated?: (subscription: Stripe.Subscription) => Promise<void> | void;\n onSubscriptionUpdated?: (subscription: Stripe.Subscription) => Promise<void> | void;\n onSubscriptionDeleted?: (subscription: Stripe.Subscription) => Promise<void> | void;\n onPaymentSucceeded?: (invoice: Stripe.Invoice) => Promise<void> | void;\n onPaymentFailed?: (invoice: Stripe.Invoice) => Promise<void> | void;\n onChargeRefunded?: (charge: Stripe.Charge) => Promise<void> | void;\n}\n\n// ---------------------------------------------------------------------------\n// Payments API\n// ---------------------------------------------------------------------------\n\nexport const payments = {\n /**\n * Create a Stripe Checkout Session for one-time payment.\n * Automatically uses direct charges (stripeAccount) when STRIPE_CONNECTED_ACCOUNT_ID is set.\n */\n async createCheckout(options: CreateCheckoutOptions): Promise<CheckoutResult> {\n const stripe = getStripeInstance();\n const connectedAccountId = getConnectedAccountId();\n\n const params: Stripe.Checkout.SessionCreateParams = {\n mode: 'payment',\n line_items: options.items.map(item => ({\n price_data: {\n currency: 'usd',\n product_data: {\n name: item.name,\n ...(item.description && { description: item.description }),\n ...(item.image && { images: [item.image] }),\n },\n unit_amount: Math.round(item.price * 100),\n },\n quantity: item.quantity || 1,\n })),\n success_url: options.successUrl,\n cancel_url: options.cancelUrl,\n ...(options.customerEmail && { customer_email: options.customerEmail }),\n ...(options.metadata && { metadata: options.metadata }),\n };\n\n if (connectedAccountId && options.applicationFeeAmount) {\n params.payment_intent_data = {\n application_fee_amount: options.applicationFeeAmount,\n };\n }\n\n const requestOptions: Stripe.RequestOptions | undefined = connectedAccountId\n ? { stripeAccount: connectedAccountId }\n : undefined;\n\n const session = await stripe.checkout.sessions.create(params, requestOptions);\n\n return { url: session.url!, sessionId: session.id };\n },\n\n /**\n * Create a Stripe Checkout Session for subscriptions.\n * Automatically uses direct charges (stripeAccount) when STRIPE_CONNECTED_ACCOUNT_ID is set.\n */\n async createSubscription(options: CreateSubscriptionOptions): Promise<CheckoutResult> {\n const stripe = getStripeInstance();\n const connectedAccountId = getConnectedAccountId();\n\n const params: Stripe.Checkout.SessionCreateParams = {\n mode: 'subscription',\n line_items: [{ price: options.priceId, quantity: 1 }],\n success_url: options.successUrl,\n cancel_url: options.cancelUrl,\n ...(options.customerEmail && { customer_email: options.customerEmail }),\n ...(options.metadata && { metadata: options.metadata }),\n };\n\n if (options.trialDays || (connectedAccountId && options.applicationFeePercent)) {\n params.subscription_data = {};\n if (options.trialDays) {\n params.subscription_data.trial_period_days = options.trialDays;\n }\n if (connectedAccountId && options.applicationFeePercent) {\n params.subscription_data.application_fee_percent = options.applicationFeePercent;\n }\n }\n\n const requestOptions: Stripe.RequestOptions | undefined = connectedAccountId\n ? { stripeAccount: connectedAccountId }\n : undefined;\n\n const session = await stripe.checkout.sessions.create(params, requestOptions);\n\n return { url: session.url!, sessionId: session.id };\n },\n\n /**\n * Handle Stripe webhook events with typed handlers.\n * Verifies the webhook signature and dispatches to your handler callbacks.\n */\n async handleWebhook(req: any, handlers: WebhookHandlers): Promise<void> {\n const stripe = getStripeInstance();\n const webhookSecret = getWebhookSecret();\n\n const sig = req.headers['stripe-signature'];\n const event = stripe.webhooks.constructEvent(req.body, sig, webhookSecret);\n\n switch (event.type) {\n case 'checkout.session.completed':\n await handlers.onCheckoutComplete?.(event.data.object as Stripe.Checkout.Session);\n break;\n case 'customer.subscription.created':\n await handlers.onSubscriptionCreated?.(event.data.object as Stripe.Subscription);\n break;\n case 'customer.subscription.updated':\n await handlers.onSubscriptionUpdated?.(event.data.object as Stripe.Subscription);\n break;\n case 'customer.subscription.deleted':\n await handlers.onSubscriptionDeleted?.(event.data.object as Stripe.Subscription);\n break;\n case 'invoice.payment_succeeded':\n await handlers.onPaymentSucceeded?.(event.data.object as Stripe.Invoice);\n break;\n case 'invoice.payment_failed':\n await handlers.onPaymentFailed?.(event.data.object as Stripe.Invoice);\n break;\n case 'charge.refunded':\n await handlers.onChargeRefunded?.(event.data.object as Stripe.Charge);\n break;\n }\n },\n\n /**\n * Express middleware for webhook routes.\n * Applies express.raw() body parser — mount BEFORE any json() middleware.\n */\n webhookMiddleware(): any {\n try {\n const express = require('express');\n return express.raw({ type: 'application/json' });\n } catch {\n return (_req: any, _res: any, next: any) => next();\n }\n },\n\n /**\n * Get the underlying Stripe instance for advanced usage.\n */\n getStripe(): Stripe {\n return getStripeInstance();\n },\n};\n"]}
|