@coduckai/sdk 0.1.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 +179 -10
- package/dist/ai/index.cjs.map +1 -1
- package/dist/ai/index.d.cts +52 -7
- package/dist/ai/index.d.ts +52 -7
- package/dist/ai/index.js +179 -10
- package/dist/ai/index.js.map +1 -1
- package/dist/auth/index.cjs.map +1 -1
- package/dist/auth/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/db/index.cjs.map +1 -1
- package/dist/db/index.js.map +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +9 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js.map +1 -1
- package/dist/payments/index.cjs +159 -11
- package/dist/payments/index.cjs.map +1 -1
- package/dist/payments/index.d.cts +70 -7
- package/dist/payments/index.d.ts +70 -7
- package/dist/payments/index.js +155 -11
- package/dist/payments/index.js.map +1 -1
- package/package.json +29 -7
package/dist/auth/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/internal/env.ts","../../src/internal/config.ts","../../src/auth/index.ts"],"names":["bcrypt","jwt"],"mappings":";;;;;;;;;;;AAIO,SAAS,MAAA,CAAO,KAAa,QAAA,EAAuC;AACzE,EAAA,OAAO,OAAA,CAAQ,GAAA,CAAI,GAAG,CAAA,IAAK,QAAA;AAC7B;AAUO,SAAS,QAAA,GAAoB;AAClC,EAAA,OAAO,OAAO,MAAA,KAAW,WAAA;AAC3B;AAEO,SAAS,aAAa,UAAA,EAA0B;AACrD,EAAA,IAAI,CAAC,UAAS,EAAG;AACf,IAAA,MAAM,IAAI,KAAA;AAAA,MACR,iBAAiB,UAAU,CAAA,2DAAA;AAAA,KAC7B;AAAA,EACF;AACF;;;
|
|
1
|
+
{"version":3,"sources":["../../src/internal/env.ts","../../src/internal/config.ts","../../src/auth/index.ts"],"names":["bcrypt","jwt"],"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/auth — Authentication module (server-only)\n *\n * Wraps bcrypt + jsonwebtoken. Drop-in replacement for hand-rolled auth.\n *\n * Usage:\n * import { auth } from '@coduckai/sdk/auth';\n * const hash = await auth.hashPassword('secret');\n * const token = auth.generateToken({ id: 1, email: 'user@test.com' });\n * router.get('/me', auth.authenticate(), handler);\n */\n\nimport { assertServer, getEnv } from '../internal/env';\nimport { getConfig } from '../internal/config';\n\nassertServer('auth');\n\nimport bcrypt from 'bcrypt';\nimport jwt from 'jsonwebtoken';\nimport type { Request, Response, NextFunction, RequestHandler } from 'express';\n\n// ── Types ──────────────────────────────────────────────\n\nexport interface TokenPayload {\n id: number;\n email: string;\n [key: string]: unknown;\n}\n\ninterface AuthenticatedRequest extends Request {\n user?: TokenPayload;\n}\n\n// ── Internal helpers ───────────────────────────────────\n\nfunction getSecret(): string {\n const config = getConfig();\n const secret = config.auth?.jwtSecret || getEnv('JWT_SECRET');\n if (!secret) {\n throw new Error('@coduckai/sdk/auth: JWT_SECRET environment variable is required');\n }\n return secret;\n}\n\nfunction getExpiresIn(): string {\n const config = getConfig();\n return config.auth?.jwtExpiresIn || getEnv('JWT_EXPIRES_IN') || '7d';\n}\n\nfunction getRounds(): number {\n const config = getConfig();\n return config.auth?.bcryptRounds || 12;\n}\n\n// ── Auth API ───────────────────────────────────────────\n\nexport const auth = {\n /**\n * Hash a plaintext password\n */\n async hashPassword(plaintext: string): Promise<string> {\n return bcrypt.hash(plaintext, getRounds());\n },\n\n /**\n * Verify a plaintext password against a hash\n */\n async verifyPassword(plaintext: string, hash: string): Promise<boolean> {\n return bcrypt.compare(plaintext, hash);\n },\n\n /**\n * Generate a signed JWT token\n */\n generateToken(payload: TokenPayload, expiresIn?: string | number): string {\n const secret = getSecret();\n const options: jwt.SignOptions = {};\n const exp = expiresIn || getExpiresIn();\n if (typeof exp === 'number') {\n options.expiresIn = exp;\n } else {\n options.expiresIn = exp as any;\n }\n return jwt.sign(payload, secret, options);\n },\n\n /**\n * Verify and decode a JWT token\n */\n verifyToken(token: string): TokenPayload {\n return jwt.verify(token, getSecret()) as TokenPayload;\n },\n\n /**\n * Refresh a token — verifies the old one, issues a new one\n */\n refreshToken(token: string): string {\n const payload = auth.verifyToken(token);\n // Strip jwt metadata before re-signing\n const { iat, exp, ...data } = payload as TokenPayload & { iat?: number; exp?: number };\n return auth.generateToken(data as TokenPayload);\n },\n\n /**\n * Express middleware — verifies Bearer token, sets req.user\n * Responds with 401 if token is missing or invalid\n */\n authenticate(): RequestHandler {\n return (req: Request, res: Response, next: NextFunction): void => {\n const header = req.headers.authorization;\n if (!header || !header.startsWith('Bearer ')) {\n res.status(401).json({ error: 'Authentication required' });\n return;\n }\n\n try {\n const token = header.slice(7);\n (req as AuthenticatedRequest).user = auth.verifyToken(token);\n next();\n } catch {\n res.status(401).json({ error: 'Invalid or expired token' });\n }\n };\n },\n\n /**\n * Express middleware — sets req.user if token present, continues regardless\n */\n optionalAuth(): RequestHandler {\n return (req: Request, _res: Response, next: NextFunction): void => {\n const header = req.headers.authorization;\n if (header && header.startsWith('Bearer ')) {\n try {\n const token = header.slice(7);\n (req as AuthenticatedRequest).user = auth.verifyToken(token);\n } catch {\n // Invalid token — proceed without user\n }\n }\n next();\n };\n },\n\n /**\n * Get the authenticated user from the request (throws if not present)\n */\n getUser(req: Request): TokenPayload {\n const user = (req as AuthenticatedRequest).user;\n if (!user) {\n throw new Error('No authenticated user on request. Use auth.authenticate() middleware first.');\n }\n return user;\n },\n};\n"]}
|
package/dist/auth/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/internal/env.ts","../../src/internal/config.ts","../../src/auth/index.ts"],"names":[],"mappings":";;;;AAIO,SAAS,MAAA,CAAO,KAAa,QAAA,EAAuC;AACzE,EAAA,OAAO,OAAA,CAAQ,GAAA,CAAI,GAAG,CAAA,IAAK,QAAA;AAC7B;AAUO,SAAS,QAAA,GAAoB;AAClC,EAAA,OAAO,OAAO,MAAA,KAAW,WAAA;AAC3B;AAEO,SAAS,aAAa,UAAA,EAA0B;AACrD,EAAA,IAAI,CAAC,UAAS,EAAG;AACf,IAAA,MAAM,IAAI,KAAA;AAAA,MACR,iBAAiB,UAAU,CAAA,2DAAA;AAAA,KAC7B;AAAA,EACF;AACF;;;
|
|
1
|
+
{"version":3,"sources":["../../src/internal/env.ts","../../src/internal/config.ts","../../src/auth/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/auth — Authentication module (server-only)\n *\n * Wraps bcrypt + jsonwebtoken. Drop-in replacement for hand-rolled auth.\n *\n * Usage:\n * import { auth } from '@coduckai/sdk/auth';\n * const hash = await auth.hashPassword('secret');\n * const token = auth.generateToken({ id: 1, email: 'user@test.com' });\n * router.get('/me', auth.authenticate(), handler);\n */\n\nimport { assertServer, getEnv } from '../internal/env';\nimport { getConfig } from '../internal/config';\n\nassertServer('auth');\n\nimport bcrypt from 'bcrypt';\nimport jwt from 'jsonwebtoken';\nimport type { Request, Response, NextFunction, RequestHandler } from 'express';\n\n// ── Types ──────────────────────────────────────────────\n\nexport interface TokenPayload {\n id: number;\n email: string;\n [key: string]: unknown;\n}\n\ninterface AuthenticatedRequest extends Request {\n user?: TokenPayload;\n}\n\n// ── Internal helpers ───────────────────────────────────\n\nfunction getSecret(): string {\n const config = getConfig();\n const secret = config.auth?.jwtSecret || getEnv('JWT_SECRET');\n if (!secret) {\n throw new Error('@coduckai/sdk/auth: JWT_SECRET environment variable is required');\n }\n return secret;\n}\n\nfunction getExpiresIn(): string {\n const config = getConfig();\n return config.auth?.jwtExpiresIn || getEnv('JWT_EXPIRES_IN') || '7d';\n}\n\nfunction getRounds(): number {\n const config = getConfig();\n return config.auth?.bcryptRounds || 12;\n}\n\n// ── Auth API ───────────────────────────────────────────\n\nexport const auth = {\n /**\n * Hash a plaintext password\n */\n async hashPassword(plaintext: string): Promise<string> {\n return bcrypt.hash(plaintext, getRounds());\n },\n\n /**\n * Verify a plaintext password against a hash\n */\n async verifyPassword(plaintext: string, hash: string): Promise<boolean> {\n return bcrypt.compare(plaintext, hash);\n },\n\n /**\n * Generate a signed JWT token\n */\n generateToken(payload: TokenPayload, expiresIn?: string | number): string {\n const secret = getSecret();\n const options: jwt.SignOptions = {};\n const exp = expiresIn || getExpiresIn();\n if (typeof exp === 'number') {\n options.expiresIn = exp;\n } else {\n options.expiresIn = exp as any;\n }\n return jwt.sign(payload, secret, options);\n },\n\n /**\n * Verify and decode a JWT token\n */\n verifyToken(token: string): TokenPayload {\n return jwt.verify(token, getSecret()) as TokenPayload;\n },\n\n /**\n * Refresh a token — verifies the old one, issues a new one\n */\n refreshToken(token: string): string {\n const payload = auth.verifyToken(token);\n // Strip jwt metadata before re-signing\n const { iat, exp, ...data } = payload as TokenPayload & { iat?: number; exp?: number };\n return auth.generateToken(data as TokenPayload);\n },\n\n /**\n * Express middleware — verifies Bearer token, sets req.user\n * Responds with 401 if token is missing or invalid\n */\n authenticate(): RequestHandler {\n return (req: Request, res: Response, next: NextFunction): void => {\n const header = req.headers.authorization;\n if (!header || !header.startsWith('Bearer ')) {\n res.status(401).json({ error: 'Authentication required' });\n return;\n }\n\n try {\n const token = header.slice(7);\n (req as AuthenticatedRequest).user = auth.verifyToken(token);\n next();\n } catch {\n res.status(401).json({ error: 'Invalid or expired token' });\n }\n };\n },\n\n /**\n * Express middleware — sets req.user if token present, continues regardless\n */\n optionalAuth(): RequestHandler {\n return (req: Request, _res: Response, next: NextFunction): void => {\n const header = req.headers.authorization;\n if (header && header.startsWith('Bearer ')) {\n try {\n const token = header.slice(7);\n (req as AuthenticatedRequest).user = auth.verifyToken(token);\n } catch {\n // Invalid token — proceed without user\n }\n }\n next();\n };\n },\n\n /**\n * Get the authenticated user from the request (throws if not present)\n */\n getUser(req: Request): TokenPayload {\n const user = (req as AuthenticatedRequest).user;\n if (!user) {\n throw new Error('No authenticated user on request. Use auth.authenticate() middleware first.');\n }\n return user;\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/db/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/internal/env.ts","../../src/internal/config.ts","../../src/db/index.ts"],"names":["pg"],"mappings":";;;;;;;;;AAIO,SAAS,MAAA,CAAO,KAAa,QAAA,EAAuC;AACzE,EAAA,OAAO,OAAA,CAAQ,GAAA,CAAI,GAAG,CAAA,IAAK,QAAA;AAC7B;AAUO,SAAS,QAAA,GAAoB;AAClC,EAAA,OAAO,OAAO,MAAA,KAAW,WAAA;AAC3B;AAEO,SAAS,aAAa,UAAA,EAA0B;AACrD,EAAA,IAAI,CAAC,UAAS,EAAG;AACf,IAAA,MAAM,IAAI,KAAA;AAAA,MACR,iBAAiB,UAAU,CAAA,2DAAA;AAAA,KAC7B;AAAA,EACF;AACF;;;
|
|
1
|
+
{"version":3,"sources":["../../src/internal/env.ts","../../src/internal/config.ts","../../src/db/index.ts"],"names":["pg"],"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/db — Database module (server-only)\n *\n * Wraps pg Pool. Returns rows directly, adds pagination and transactions.\n *\n * Usage:\n * import { db } from '@coduckai/sdk/db';\n * const users = await db.query('SELECT * FROM users WHERE active = $1', [true]);\n * const user = await db.queryOne('SELECT * FROM users WHERE id = $1', [id]);\n */\n\nimport { assertServer, getEnv } from '../internal/env';\nimport { getConfig } from '../internal/config';\n\nassertServer('db');\n\nimport pg from 'pg';\nconst { Pool } = pg;\nimport type { PoolClient, QueryResultRow } from 'pg';\n\n// ── Types ──────────────────────────────────────────────\n\nexport interface PaginationOptions {\n page: number;\n pageSize: number;\n}\n\nexport interface PaginatedResult<T> {\n data: T[];\n total: number;\n page: number;\n pageSize: number;\n totalPages: number;\n}\n\n// ── Pool (lazy singleton) ──────────────────────────────\n\nlet pool: pg.Pool | null = null;\n\nfunction getPool(): pg.Pool {\n if (!pool) {\n const config = getConfig();\n const connectionString = config.db?.connectionString || getEnv('DATABASE_URL');\n if (!connectionString) {\n throw new Error('@coduckai/sdk/db: DATABASE_URL environment variable is required');\n }\n pool = new Pool({ connectionString });\n }\n return pool;\n}\n\n// ── DB API ─────────────────────────────────────────────\n\nexport const db = {\n /**\n * Run a query, returns all rows\n */\n async query<T extends QueryResultRow = QueryResultRow>(\n sql: string,\n params?: unknown[]\n ): Promise<T[]> {\n const result = await getPool().query<T>(sql, params);\n return result.rows;\n },\n\n /**\n * Run a query, returns the first row or null\n */\n async queryOne<T extends QueryResultRow = QueryResultRow>(\n sql: string,\n params?: unknown[]\n ): Promise<T | null> {\n const result = await getPool().query<T>(sql, params);\n return result.rows[0] || null;\n },\n\n /**\n * Run a query that doesn't return rows (INSERT/UPDATE/DELETE)\n */\n async execute(\n sql: string,\n params?: unknown[]\n ): Promise<{ rowCount: number }> {\n const result = await getPool().query(sql, params);\n return { rowCount: result.rowCount ?? 0 };\n },\n\n /**\n * Paginated query — automatically appends LIMIT/OFFSET and runs COUNT\n */\n async paginate<T extends QueryResultRow = QueryResultRow>(\n sql: string,\n params: unknown[],\n options: PaginationOptions\n ): Promise<PaginatedResult<T>> {\n const { page, pageSize } = options;\n const offset = (page - 1) * pageSize;\n\n // Count query — wrap the user's SQL\n const countSql = `SELECT COUNT(*) as total FROM (${sql}) AS _count_query`;\n const countResult = await getPool().query(countSql, params);\n const total = parseInt(countResult.rows[0].total, 10);\n\n // Data query — append LIMIT/OFFSET\n const dataSql = `${sql} LIMIT $${params.length + 1} OFFSET $${params.length + 2}`;\n const dataResult = await getPool().query<T>(dataSql, [...params, pageSize, offset]);\n\n return {\n data: dataResult.rows,\n total,\n page,\n pageSize,\n totalPages: Math.ceil(total / pageSize),\n };\n },\n\n /**\n * Run multiple queries in a transaction. Auto-commits on success, rolls back on error.\n */\n async transaction<T>(fn: (tx: TransactionClient) => Promise<T>): Promise<T> {\n const client = await getPool().connect();\n try {\n await client.query('BEGIN');\n const txClient = createTransactionClient(client);\n const result = await fn(txClient);\n await client.query('COMMIT');\n return result;\n } catch (error) {\n await client.query('ROLLBACK');\n throw error;\n } finally {\n client.release();\n }\n },\n\n /**\n * Get the underlying pg Pool (escape hatch)\n */\n getPool,\n};\n\n// ── Transaction Client ─────────────────────────────────\n\nexport interface TransactionClient {\n query<T extends QueryResultRow = QueryResultRow>(sql: string, params?: unknown[]): Promise<T[]>;\n queryOne<T extends QueryResultRow = QueryResultRow>(sql: string, params?: unknown[]): Promise<T | null>;\n execute(sql: string, params?: unknown[]): Promise<{ rowCount: number }>;\n}\n\nfunction createTransactionClient(client: PoolClient): TransactionClient {\n return {\n async query<T extends QueryResultRow = QueryResultRow>(sql: string, params?: unknown[]): Promise<T[]> {\n const result = await client.query<T>(sql, params);\n return result.rows;\n },\n async queryOne<T extends QueryResultRow = QueryResultRow>(sql: string, params?: unknown[]): Promise<T | null> {\n const result = await client.query<T>(sql, params);\n return result.rows[0] || null;\n },\n async execute(sql: string, params?: unknown[]): Promise<{ rowCount: number }> {\n const result = await client.query(sql, params);\n return { rowCount: result.rowCount ?? 0 };\n },\n };\n}\n"]}
|
package/dist/db/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/internal/env.ts","../../src/internal/config.ts","../../src/db/index.ts"],"names":[],"mappings":";;;AAIO,SAAS,MAAA,CAAO,KAAa,QAAA,EAAuC;AACzE,EAAA,OAAO,OAAA,CAAQ,GAAA,CAAI,GAAG,CAAA,IAAK,QAAA;AAC7B;AAUO,SAAS,QAAA,GAAoB;AAClC,EAAA,OAAO,OAAO,MAAA,KAAW,WAAA;AAC3B;AAEO,SAAS,aAAa,UAAA,EAA0B;AACrD,EAAA,IAAI,CAAC,UAAS,EAAG;AACf,IAAA,MAAM,IAAI,KAAA;AAAA,MACR,iBAAiB,UAAU,CAAA,2DAAA;AAAA,KAC7B;AAAA,EACF;AACF;;;
|
|
1
|
+
{"version":3,"sources":["../../src/internal/env.ts","../../src/internal/config.ts","../../src/db/index.ts"],"names":[],"mappings":";;;AAIO,SAAS,MAAA,CAAO,KAAa,QAAA,EAAuC;AACzE,EAAA,OAAO,OAAA,CAAQ,GAAA,CAAI,GAAG,CAAA,IAAK,QAAA;AAC7B;AAUO,SAAS,QAAA,GAAoB;AAClC,EAAA,OAAO,OAAO,MAAA,KAAW,WAAA;AAC3B;AAEO,SAAS,aAAa,UAAA,EAA0B;AACrD,EAAA,IAAI,CAAC,UAAS,EAAG;AACf,IAAA,MAAM,IAAI,KAAA;AAAA,MACR,iBAAiB,UAAU,CAAA,2DAAA;AAAA,KAC7B;AAAA,EACF;AACF;;;ACKA,IAAI,eAA0B,EAAC;AAMxB,SAAS,SAAA,GAAuB;AACrC,EAAA,OAAO,YAAA;AACT;ACzBA,YAAA,CAAa,IAAI,CAAA;AAGjB,IAAM,EAAE,MAAK,GAAI,EAAA;AAoBjB,IAAI,IAAA,GAAuB,IAAA;AAE3B,SAAS,OAAA,GAAmB;AAC1B,EAAA,IAAI,CAAC,IAAA,EAAM;AACT,IAAA,MAAM,SAAS,SAAA,EAAU;AACzB,IAAA,MAAM,gBAAA,GAAmB,MAAA,CAAO,EAAA,EAAI,gBAAA,IAAoB,OAAO,cAAc,CAAA;AAC7E,IAAA,IAAI,CAAC,gBAAA,EAAkB;AACrB,MAAA,MAAM,IAAI,MAAM,iEAAiE,CAAA;AAAA,IACnF;AACA,IAAA,IAAA,GAAO,IAAI,IAAA,CAAK,EAAE,gBAAA,EAAkB,CAAA;AAAA,EACtC;AACA,EAAA,OAAO,IAAA;AACT;AAIO,IAAM,EAAA,GAAK;AAAA;AAAA;AAAA;AAAA,EAIhB,MAAM,KAAA,CACJ,GAAA,EACA,MAAA,EACc;AACd,IAAA,MAAM,SAAS,MAAM,OAAA,EAAQ,CAAE,KAAA,CAAS,KAAK,MAAM,CAAA;AACnD,IAAA,OAAO,MAAA,CAAO,IAAA;AAAA,EAChB,CAAA;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,QAAA,CACJ,GAAA,EACA,MAAA,EACmB;AACnB,IAAA,MAAM,SAAS,MAAM,OAAA,EAAQ,CAAE,KAAA,CAAS,KAAK,MAAM,CAAA;AACnD,IAAA,OAAO,MAAA,CAAO,IAAA,CAAK,CAAC,CAAA,IAAK,IAAA;AAAA,EAC3B,CAAA;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,OAAA,CACJ,GAAA,EACA,MAAA,EAC+B;AAC/B,IAAA,MAAM,SAAS,MAAM,OAAA,EAAQ,CAAE,KAAA,CAAM,KAAK,MAAM,CAAA;AAChD,IAAA,OAAO,EAAE,QAAA,EAAU,MAAA,CAAO,QAAA,IAAY,CAAA,EAAE;AAAA,EAC1C,CAAA;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,QAAA,CACJ,GAAA,EACA,MAAA,EACA,OAAA,EAC6B;AAC7B,IAAA,MAAM,EAAE,IAAA,EAAM,QAAA,EAAS,GAAI,OAAA;AAC3B,IAAA,MAAM,MAAA,GAAA,CAAU,OAAO,CAAA,IAAK,QAAA;AAG5B,IAAA,MAAM,QAAA,GAAW,kCAAkC,GAAG,CAAA,iBAAA,CAAA;AACtD,IAAA,MAAM,cAAc,MAAM,OAAA,EAAQ,CAAE,KAAA,CAAM,UAAU,MAAM,CAAA;AAC1D,IAAA,MAAM,QAAQ,QAAA,CAAS,WAAA,CAAY,KAAK,CAAC,CAAA,CAAE,OAAO,EAAE,CAAA;AAGpD,IAAA,MAAM,OAAA,GAAU,CAAA,EAAG,GAAG,CAAA,QAAA,EAAW,MAAA,CAAO,SAAS,CAAC,CAAA,SAAA,EAAY,MAAA,CAAO,MAAA,GAAS,CAAC,CAAA,CAAA;AAC/E,IAAA,MAAM,UAAA,GAAa,MAAM,OAAA,EAAQ,CAAE,KAAA,CAAS,OAAA,EAAS,CAAC,GAAG,MAAA,EAAQ,QAAA,EAAU,MAAM,CAAC,CAAA;AAElF,IAAA,OAAO;AAAA,MACL,MAAM,UAAA,CAAW,IAAA;AAAA,MACjB,KAAA;AAAA,MACA,IAAA;AAAA,MACA,QAAA;AAAA,MACA,UAAA,EAAY,IAAA,CAAK,IAAA,CAAK,KAAA,GAAQ,QAAQ;AAAA,KACxC;AAAA,EACF,CAAA;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,YAAe,EAAA,EAAuD;AAC1E,IAAA,MAAM,MAAA,GAAS,MAAM,OAAA,EAAQ,CAAE,OAAA,EAAQ;AACvC,IAAA,IAAI;AACF,MAAA,MAAM,MAAA,CAAO,MAAM,OAAO,CAAA;AAC1B,MAAA,MAAM,QAAA,GAAW,wBAAwB,MAAM,CAAA;AAC/C,MAAA,MAAM,MAAA,GAAS,MAAM,EAAA,CAAG,QAAQ,CAAA;AAChC,MAAA,MAAM,MAAA,CAAO,MAAM,QAAQ,CAAA;AAC3B,MAAA,OAAO,MAAA;AAAA,IACT,SAAS,KAAA,EAAO;AACd,MAAA,MAAM,MAAA,CAAO,MAAM,UAAU,CAAA;AAC7B,MAAA,MAAM,KAAA;AAAA,IACR,CAAA,SAAE;AACA,MAAA,MAAA,CAAO,OAAA,EAAQ;AAAA,IACjB;AAAA,EACF,CAAA;AAAA;AAAA;AAAA;AAAA,EAKA;AACF;AAUA,SAAS,wBAAwB,MAAA,EAAuC;AACtE,EAAA,OAAO;AAAA,IACL,MAAM,KAAA,CAAiD,GAAA,EAAa,MAAA,EAAkC;AACpG,MAAA,MAAM,MAAA,GAAS,MAAM,MAAA,CAAO,KAAA,CAAS,KAAK,MAAM,CAAA;AAChD,MAAA,OAAO,MAAA,CAAO,IAAA;AAAA,IAChB,CAAA;AAAA,IACA,MAAM,QAAA,CAAoD,GAAA,EAAa,MAAA,EAAuC;AAC5G,MAAA,MAAM,MAAA,GAAS,MAAM,MAAA,CAAO,KAAA,CAAS,KAAK,MAAM,CAAA;AAChD,MAAA,OAAO,MAAA,CAAO,IAAA,CAAK,CAAC,CAAA,IAAK,IAAA;AAAA,IAC3B,CAAA;AAAA,IACA,MAAM,OAAA,CAAQ,GAAA,EAAa,MAAA,EAAmD;AAC5E,MAAA,MAAM,MAAA,GAAS,MAAM,MAAA,CAAO,KAAA,CAAM,KAAK,MAAM,CAAA;AAC7C,MAAA,OAAO,EAAE,QAAA,EAAU,MAAA,CAAO,QAAA,IAAY,CAAA,EAAE;AAAA,IAC1C;AAAA,GACF;AACF","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/db — Database module (server-only)\n *\n * Wraps pg Pool. Returns rows directly, adds pagination and transactions.\n *\n * Usage:\n * import { db } from '@coduckai/sdk/db';\n * const users = await db.query('SELECT * FROM users WHERE active = $1', [true]);\n * const user = await db.queryOne('SELECT * FROM users WHERE id = $1', [id]);\n */\n\nimport { assertServer, getEnv } from '../internal/env';\nimport { getConfig } from '../internal/config';\n\nassertServer('db');\n\nimport pg from 'pg';\nconst { Pool } = pg;\nimport type { PoolClient, QueryResultRow } from 'pg';\n\n// ── Types ──────────────────────────────────────────────\n\nexport interface PaginationOptions {\n page: number;\n pageSize: number;\n}\n\nexport interface PaginatedResult<T> {\n data: T[];\n total: number;\n page: number;\n pageSize: number;\n totalPages: number;\n}\n\n// ── Pool (lazy singleton) ──────────────────────────────\n\nlet pool: pg.Pool | null = null;\n\nfunction getPool(): pg.Pool {\n if (!pool) {\n const config = getConfig();\n const connectionString = config.db?.connectionString || getEnv('DATABASE_URL');\n if (!connectionString) {\n throw new Error('@coduckai/sdk/db: DATABASE_URL environment variable is required');\n }\n pool = new Pool({ connectionString });\n }\n return pool;\n}\n\n// ── DB API ─────────────────────────────────────────────\n\nexport const db = {\n /**\n * Run a query, returns all rows\n */\n async query<T extends QueryResultRow = QueryResultRow>(\n sql: string,\n params?: unknown[]\n ): Promise<T[]> {\n const result = await getPool().query<T>(sql, params);\n return result.rows;\n },\n\n /**\n * Run a query, returns the first row or null\n */\n async queryOne<T extends QueryResultRow = QueryResultRow>(\n sql: string,\n params?: unknown[]\n ): Promise<T | null> {\n const result = await getPool().query<T>(sql, params);\n return result.rows[0] || null;\n },\n\n /**\n * Run a query that doesn't return rows (INSERT/UPDATE/DELETE)\n */\n async execute(\n sql: string,\n params?: unknown[]\n ): Promise<{ rowCount: number }> {\n const result = await getPool().query(sql, params);\n return { rowCount: result.rowCount ?? 0 };\n },\n\n /**\n * Paginated query — automatically appends LIMIT/OFFSET and runs COUNT\n */\n async paginate<T extends QueryResultRow = QueryResultRow>(\n sql: string,\n params: unknown[],\n options: PaginationOptions\n ): Promise<PaginatedResult<T>> {\n const { page, pageSize } = options;\n const offset = (page - 1) * pageSize;\n\n // Count query — wrap the user's SQL\n const countSql = `SELECT COUNT(*) as total FROM (${sql}) AS _count_query`;\n const countResult = await getPool().query(countSql, params);\n const total = parseInt(countResult.rows[0].total, 10);\n\n // Data query — append LIMIT/OFFSET\n const dataSql = `${sql} LIMIT $${params.length + 1} OFFSET $${params.length + 2}`;\n const dataResult = await getPool().query<T>(dataSql, [...params, pageSize, offset]);\n\n return {\n data: dataResult.rows,\n total,\n page,\n pageSize,\n totalPages: Math.ceil(total / pageSize),\n };\n },\n\n /**\n * Run multiple queries in a transaction. Auto-commits on success, rolls back on error.\n */\n async transaction<T>(fn: (tx: TransactionClient) => Promise<T>): Promise<T> {\n const client = await getPool().connect();\n try {\n await client.query('BEGIN');\n const txClient = createTransactionClient(client);\n const result = await fn(txClient);\n await client.query('COMMIT');\n return result;\n } catch (error) {\n await client.query('ROLLBACK');\n throw error;\n } finally {\n client.release();\n }\n },\n\n /**\n * Get the underlying pg Pool (escape hatch)\n */\n getPool,\n};\n\n// ── Transaction Client ─────────────────────────────────\n\nexport interface TransactionClient {\n query<T extends QueryResultRow = QueryResultRow>(sql: string, params?: unknown[]): Promise<T[]>;\n queryOne<T extends QueryResultRow = QueryResultRow>(sql: string, params?: unknown[]): Promise<T | null>;\n execute(sql: string, params?: unknown[]): Promise<{ rowCount: number }>;\n}\n\nfunction createTransactionClient(client: PoolClient): TransactionClient {\n return {\n async query<T extends QueryResultRow = QueryResultRow>(sql: string, params?: unknown[]): Promise<T[]> {\n const result = await client.query<T>(sql, params);\n return result.rows;\n },\n async queryOne<T extends QueryResultRow = QueryResultRow>(sql: string, params?: unknown[]): Promise<T | null> {\n const result = await client.query<T>(sql, params);\n return result.rows[0] || null;\n },\n async execute(sql: string, params?: unknown[]): Promise<{ rowCount: number }> {\n const result = await client.query(sql, params);\n return { rowCount: result.rowCount ?? 0 };\n },\n };\n}\n"]}
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/internal/config.ts","../src/index.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"sources":["../src/internal/config.ts","../src/index.ts"],"names":[],"mappings":";;;AA+BA,IAAI,eAA0B,EAAC;AAExB,SAAS,UAAU,MAAA,EAAyB;AACjD,EAAA,YAAA,GAAe,EAAE,GAAG,YAAA,EAAc,GAAG,MAAA,EAAO;AAC9C;AAEO,SAAS,SAAA,GAAuB;AACrC,EAAA,OAAO,YAAA;AACT;;;AC5BO,SAAS,UAAU,MAAA,EAAyB;AACjD,EAAA,SAAA,CAAU,MAAM,CAAA;AAClB","file":"index.cjs","sourcesContent":["/**\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 — CoDuck Platform SDK\n *\n * Zero-config in CoDuck apps (env vars auto-detected).\n * For standalone usage, call configure() first.\n */\n\nimport { setConfig, getConfig, type SDKConfig } from './internal/config';\n\nexport type { SDKConfig };\n\nexport function configure(config: SDKConfig): void {\n setConfig(config);\n}\n\nexport { getConfig };\n"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -17,6 +17,15 @@ interface SDKConfig {
|
|
|
17
17
|
baseUrl?: string;
|
|
18
18
|
tokenKey?: string;
|
|
19
19
|
};
|
|
20
|
+
payments?: {
|
|
21
|
+
stripeSecretKey?: string;
|
|
22
|
+
connectedAccountId?: string;
|
|
23
|
+
webhookSecret?: string;
|
|
24
|
+
};
|
|
25
|
+
ai?: {
|
|
26
|
+
provider?: 'openai' | 'anthropic';
|
|
27
|
+
apiKey?: string;
|
|
28
|
+
};
|
|
20
29
|
}
|
|
21
30
|
declare function getConfig(): SDKConfig;
|
|
22
31
|
|
package/dist/index.d.ts
CHANGED
|
@@ -17,6 +17,15 @@ interface SDKConfig {
|
|
|
17
17
|
baseUrl?: string;
|
|
18
18
|
tokenKey?: string;
|
|
19
19
|
};
|
|
20
|
+
payments?: {
|
|
21
|
+
stripeSecretKey?: string;
|
|
22
|
+
connectedAccountId?: string;
|
|
23
|
+
webhookSecret?: string;
|
|
24
|
+
};
|
|
25
|
+
ai?: {
|
|
26
|
+
provider?: 'openai' | 'anthropic';
|
|
27
|
+
apiKey?: string;
|
|
28
|
+
};
|
|
20
29
|
}
|
|
21
30
|
declare function getConfig(): SDKConfig;
|
|
22
31
|
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/internal/config.ts","../src/index.ts"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"sources":["../src/internal/config.ts","../src/index.ts"],"names":[],"mappings":";AA+BA,IAAI,eAA0B,EAAC;AAExB,SAAS,UAAU,MAAA,EAAyB;AACjD,EAAA,YAAA,GAAe,EAAE,GAAG,YAAA,EAAc,GAAG,MAAA,EAAO;AAC9C;AAEO,SAAS,SAAA,GAAuB;AACrC,EAAA,OAAO,YAAA;AACT;;;AC5BO,SAAS,UAAU,MAAA,EAAyB;AACjD,EAAA,SAAA,CAAU,MAAM,CAAA;AAClB","file":"index.js","sourcesContent":["/**\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 — CoDuck Platform SDK\n *\n * Zero-config in CoDuck apps (env vars auto-detected).\n * For standalone usage, call configure() first.\n */\n\nimport { setConfig, getConfig, type SDKConfig } from './internal/config';\n\nexport type { SDKConfig };\n\nexport function configure(config: SDKConfig): void {\n setConfig(config);\n}\n\nexport { getConfig };\n"]}
|
package/dist/payments/index.cjs
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
var Stripe = require('stripe');
|
|
4
|
+
|
|
5
|
+
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
6
|
+
|
|
7
|
+
var Stripe__default = /*#__PURE__*/_interopDefault(Stripe);
|
|
8
|
+
|
|
9
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
10
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
11
|
+
}) : x)(function(x) {
|
|
12
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
13
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
14
|
+
});
|
|
15
|
+
|
|
3
16
|
// src/internal/env.ts
|
|
4
17
|
function isServer() {
|
|
5
18
|
return typeof window === "undefined";
|
|
@@ -12,20 +25,155 @@ function assertServer(moduleName) {
|
|
|
12
25
|
}
|
|
13
26
|
}
|
|
14
27
|
|
|
15
|
-
// src/
|
|
28
|
+
// src/internal/config.ts
|
|
29
|
+
var globalConfig = {};
|
|
30
|
+
function getConfig() {
|
|
31
|
+
return globalConfig;
|
|
32
|
+
}
|
|
16
33
|
assertServer("payments");
|
|
34
|
+
var stripeInstance = null;
|
|
35
|
+
function getStripeInstance() {
|
|
36
|
+
if (stripeInstance) return stripeInstance;
|
|
37
|
+
const config = getConfig();
|
|
38
|
+
const secretKey = config.payments?.stripeSecretKey || process.env.STRIPE_SECRET_KEY;
|
|
39
|
+
if (!secretKey) {
|
|
40
|
+
throw new Error(
|
|
41
|
+
"@coduckai/sdk/payments: STRIPE_SECRET_KEY is required. Set the env var or call configure()."
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
stripeInstance = new Stripe__default.default(secretKey);
|
|
45
|
+
return stripeInstance;
|
|
46
|
+
}
|
|
47
|
+
function getConnectedAccountId() {
|
|
48
|
+
const config = getConfig();
|
|
49
|
+
return config.payments?.connectedAccountId || process.env.STRIPE_CONNECTED_ACCOUNT_ID || void 0;
|
|
50
|
+
}
|
|
51
|
+
function getWebhookSecret() {
|
|
52
|
+
const config = getConfig();
|
|
53
|
+
const secret = config.payments?.webhookSecret || process.env.STRIPE_WEBHOOK_SECRET;
|
|
54
|
+
if (!secret) {
|
|
55
|
+
throw new Error(
|
|
56
|
+
"@coduckai/sdk/payments: STRIPE_WEBHOOK_SECRET is required for webhook handling."
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
return secret;
|
|
60
|
+
}
|
|
17
61
|
var payments = {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
62
|
+
/**
|
|
63
|
+
* Create a Stripe Checkout Session for one-time payment.
|
|
64
|
+
* Automatically uses direct charges (stripeAccount) when STRIPE_CONNECTED_ACCOUNT_ID is set.
|
|
65
|
+
*/
|
|
66
|
+
async createCheckout(options) {
|
|
67
|
+
const stripe = getStripeInstance();
|
|
68
|
+
const connectedAccountId = getConnectedAccountId();
|
|
69
|
+
const params = {
|
|
70
|
+
mode: "payment",
|
|
71
|
+
line_items: options.items.map((item) => ({
|
|
72
|
+
price_data: {
|
|
73
|
+
currency: "usd",
|
|
74
|
+
product_data: {
|
|
75
|
+
name: item.name,
|
|
76
|
+
...item.description && { description: item.description },
|
|
77
|
+
...item.image && { images: [item.image] }
|
|
78
|
+
},
|
|
79
|
+
unit_amount: Math.round(item.price * 100)
|
|
80
|
+
},
|
|
81
|
+
quantity: item.quantity || 1
|
|
82
|
+
})),
|
|
83
|
+
success_url: options.successUrl,
|
|
84
|
+
cancel_url: options.cancelUrl,
|
|
85
|
+
...options.customerEmail && { customer_email: options.customerEmail },
|
|
86
|
+
...options.metadata && { metadata: options.metadata }
|
|
87
|
+
};
|
|
88
|
+
if (connectedAccountId && options.applicationFeeAmount) {
|
|
89
|
+
params.payment_intent_data = {
|
|
90
|
+
application_fee_amount: options.applicationFeeAmount
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
const requestOptions = connectedAccountId ? { stripeAccount: connectedAccountId } : void 0;
|
|
94
|
+
const session = await stripe.checkout.sessions.create(params, requestOptions);
|
|
95
|
+
return { url: session.url, sessionId: session.id };
|
|
96
|
+
},
|
|
97
|
+
/**
|
|
98
|
+
* Create a Stripe Checkout Session for subscriptions.
|
|
99
|
+
* Automatically uses direct charges (stripeAccount) when STRIPE_CONNECTED_ACCOUNT_ID is set.
|
|
100
|
+
*/
|
|
101
|
+
async createSubscription(options) {
|
|
102
|
+
const stripe = getStripeInstance();
|
|
103
|
+
const connectedAccountId = getConnectedAccountId();
|
|
104
|
+
const params = {
|
|
105
|
+
mode: "subscription",
|
|
106
|
+
line_items: [{ price: options.priceId, quantity: 1 }],
|
|
107
|
+
success_url: options.successUrl,
|
|
108
|
+
cancel_url: options.cancelUrl,
|
|
109
|
+
...options.customerEmail && { customer_email: options.customerEmail },
|
|
110
|
+
...options.metadata && { metadata: options.metadata }
|
|
111
|
+
};
|
|
112
|
+
if (options.trialDays || connectedAccountId && options.applicationFeePercent) {
|
|
113
|
+
params.subscription_data = {};
|
|
114
|
+
if (options.trialDays) {
|
|
115
|
+
params.subscription_data.trial_period_days = options.trialDays;
|
|
116
|
+
}
|
|
117
|
+
if (connectedAccountId && options.applicationFeePercent) {
|
|
118
|
+
params.subscription_data.application_fee_percent = options.applicationFeePercent;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
const requestOptions = connectedAccountId ? { stripeAccount: connectedAccountId } : void 0;
|
|
122
|
+
const session = await stripe.checkout.sessions.create(params, requestOptions);
|
|
123
|
+
return { url: session.url, sessionId: session.id };
|
|
124
|
+
},
|
|
125
|
+
/**
|
|
126
|
+
* Handle Stripe webhook events with typed handlers.
|
|
127
|
+
* Verifies the webhook signature and dispatches to your handler callbacks.
|
|
128
|
+
*/
|
|
129
|
+
async handleWebhook(req, handlers) {
|
|
130
|
+
const stripe = getStripeInstance();
|
|
131
|
+
const webhookSecret = getWebhookSecret();
|
|
132
|
+
const sig = req.headers["stripe-signature"];
|
|
133
|
+
const event = stripe.webhooks.constructEvent(req.body, sig, webhookSecret);
|
|
134
|
+
switch (event.type) {
|
|
135
|
+
case "checkout.session.completed":
|
|
136
|
+
await handlers.onCheckoutComplete?.(event.data.object);
|
|
137
|
+
break;
|
|
138
|
+
case "customer.subscription.created":
|
|
139
|
+
await handlers.onSubscriptionCreated?.(event.data.object);
|
|
140
|
+
break;
|
|
141
|
+
case "customer.subscription.updated":
|
|
142
|
+
await handlers.onSubscriptionUpdated?.(event.data.object);
|
|
143
|
+
break;
|
|
144
|
+
case "customer.subscription.deleted":
|
|
145
|
+
await handlers.onSubscriptionDeleted?.(event.data.object);
|
|
146
|
+
break;
|
|
147
|
+
case "invoice.payment_succeeded":
|
|
148
|
+
await handlers.onPaymentSucceeded?.(event.data.object);
|
|
149
|
+
break;
|
|
150
|
+
case "invoice.payment_failed":
|
|
151
|
+
await handlers.onPaymentFailed?.(event.data.object);
|
|
152
|
+
break;
|
|
153
|
+
case "charge.refunded":
|
|
154
|
+
await handlers.onChargeRefunded?.(event.data.object);
|
|
155
|
+
break;
|
|
156
|
+
}
|
|
157
|
+
},
|
|
158
|
+
/**
|
|
159
|
+
* Express middleware for webhook routes.
|
|
160
|
+
* Applies express.raw() body parser — mount BEFORE any json() middleware.
|
|
161
|
+
*/
|
|
162
|
+
webhookMiddleware() {
|
|
163
|
+
try {
|
|
164
|
+
const express = __require("express");
|
|
165
|
+
return express.raw({ type: "application/json" });
|
|
166
|
+
} catch {
|
|
167
|
+
return (_req, _res, next) => next();
|
|
168
|
+
}
|
|
169
|
+
},
|
|
170
|
+
/**
|
|
171
|
+
* Get the underlying Stripe instance for advanced usage.
|
|
172
|
+
*/
|
|
173
|
+
getStripe() {
|
|
174
|
+
return getStripeInstance();
|
|
175
|
+
}
|
|
23
176
|
};
|
|
24
|
-
function notImplemented(name) {
|
|
25
|
-
return () => {
|
|
26
|
-
throw new Error(`@coduckai/sdk: ${name}() is not yet implemented. Coming in v0.2.0.`);
|
|
27
|
-
};
|
|
28
|
-
}
|
|
29
177
|
|
|
30
178
|
exports.payments = payments;
|
|
31
179
|
//# sourceMappingURL=index.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/internal/env.ts","../../src/payments/index.ts"],"names":[],"mappings":";;;AAgBO,SAAS,QAAA,GAAoB;AAClC,EAAA,OAAO,OAAO,MAAA,KAAW,WAAA;AAC3B;AAEO,SAAS,aAAa,UAAA,EAA0B;AACrD,EAAA,IAAI,CAAC,UAAS,EAAG;AACf,IAAA,MAAM,IAAI,KAAA;AAAA,MACR,iBAAiB,UAAU,CAAA,2DAAA;AAAA,KAC7B;AAAA,EACF;AACF;;;ACnBA,YAAA,CAAa,UAAU,CAAA;AAEhB,IAAM,QAAA,GAAW;AAAA,EACtB,cAAA,EAAgB,eAAe,yBAAyB,CAAA;AAAA,EACxD,kBAAA,EAAoB,eAAe,6BAA6B,CAAA;AAAA,EAChE,aAAA,EAAe,eAAe,wBAAwB,CAAA;AAAA,EACtD,iBAAA,EAAmB,eAAe,4BAA4B,CAAA;AAAA,EAC9D,SAAA,EAAW,eAAe,oBAAoB;AAChD;AAEA,SAAS,eAAe,IAAA,EAAc;AACpC,EAAA,OAAO,MAAM;AACX,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,eAAA,EAAkB,IAAI,CAAA,4CAAA,CAA8C,CAAA;AAAA,EACtF,CAAA;AACF","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 * @coduckai/sdk/payments — Stripe Payments (server-only)\n *\n * Coming in v0.2.0. Wraps Stripe SDK with Connect destination charges.\n */\n\nimport { assertServer } from '../internal/env';\nassertServer('payments');\n\nexport const payments = {\n createCheckout: notImplemented('payments.createCheckout'),\n createSubscription: notImplemented('payments.createSubscription'),\n handleWebhook: notImplemented('payments.handleWebhook'),\n webhookMiddleware: notImplemented('payments.webhookMiddleware'),\n getStripe: notImplemented('payments.getStripe'),\n};\n\nfunction notImplemented(name: string) {\n return () => {\n throw new Error(`@coduckai/sdk: ${name}() is not yet implemented. Coming in v0.2.0.`);\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"]}
|