@coduckai/sdk 0.1.0

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.
Files changed (49) hide show
  1. package/dist/ai/index.cjs +32 -0
  2. package/dist/ai/index.cjs.map +1 -0
  3. package/dist/ai/index.d.cts +14 -0
  4. package/dist/ai/index.d.ts +14 -0
  5. package/dist/ai/index.js +30 -0
  6. package/dist/ai/index.js.map +1 -0
  7. package/dist/auth/index.cjs +139 -0
  8. package/dist/auth/index.cjs.map +1 -0
  9. package/dist/auth/index.d.cts +56 -0
  10. package/dist/auth/index.d.ts +56 -0
  11. package/dist/auth/index.js +132 -0
  12. package/dist/auth/index.js.map +1 -0
  13. package/dist/client/index.cjs +70 -0
  14. package/dist/client/index.cjs.map +1 -0
  15. package/dist/client/index.d.cts +20 -0
  16. package/dist/client/index.d.ts +20 -0
  17. package/dist/client/index.js +57 -0
  18. package/dist/client/index.js.map +1 -0
  19. package/dist/db/index.cjs +126 -0
  20. package/dist/db/index.cjs.map +1 -0
  21. package/dist/db/index.d.cts +62 -0
  22. package/dist/db/index.d.ts +62 -0
  23. package/dist/db/index.js +120 -0
  24. package/dist/db/index.js.map +1 -0
  25. package/dist/email/index.cjs +29 -0
  26. package/dist/email/index.cjs.map +1 -0
  27. package/dist/email/index.d.cts +11 -0
  28. package/dist/email/index.d.ts +11 -0
  29. package/dist/email/index.js +27 -0
  30. package/dist/email/index.js.map +1 -0
  31. package/dist/index.cjs +20 -0
  32. package/dist/index.cjs.map +1 -0
  33. package/dist/index.d.cts +32 -0
  34. package/dist/index.d.ts +32 -0
  35. package/dist/index.js +17 -0
  36. package/dist/index.js.map +1 -0
  37. package/dist/payments/index.cjs +32 -0
  38. package/dist/payments/index.cjs.map +1 -0
  39. package/dist/payments/index.d.cts +14 -0
  40. package/dist/payments/index.d.ts +14 -0
  41. package/dist/payments/index.js +30 -0
  42. package/dist/payments/index.js.map +1 -0
  43. package/dist/storage/index.cjs +31 -0
  44. package/dist/storage/index.cjs.map +1 -0
  45. package/dist/storage/index.d.cts +13 -0
  46. package/dist/storage/index.d.ts +13 -0
  47. package/dist/storage/index.js +29 -0
  48. package/dist/storage/index.js.map +1 -0
  49. package/package.json +93 -0
@@ -0,0 +1,32 @@
1
+ 'use strict';
2
+
3
+ // src/internal/env.ts
4
+ function isServer() {
5
+ return typeof window === "undefined";
6
+ }
7
+ function assertServer(moduleName) {
8
+ if (!isServer()) {
9
+ throw new Error(
10
+ `@coduckai/sdk/${moduleName} is server-only. Use @coduckai/sdk/client for browser code.`
11
+ );
12
+ }
13
+ }
14
+
15
+ // src/ai/index.ts
16
+ assertServer("ai");
17
+ var ai = {
18
+ chat: notImplemented("ai.chat"),
19
+ streamChat: notImplemented("ai.streamChat"),
20
+ streamToSSE: notImplemented("ai.streamToSSE"),
21
+ generateImage: notImplemented("ai.generateImage"),
22
+ getProvider: notImplemented("ai.getProvider")
23
+ };
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
+
30
+ exports.ai = ai;
31
+ //# sourceMappingURL=index.cjs.map
32
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/internal/env.ts","../../src/ai/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,IAAI,CAAA;AAEV,IAAM,EAAA,GAAK;AAAA,EAChB,IAAA,EAAM,eAAe,SAAS,CAAA;AAAA,EAC9B,UAAA,EAAY,eAAe,eAAe,CAAA;AAAA,EAC1C,WAAA,EAAa,eAAe,gBAAgB,CAAA;AAAA,EAC5C,aAAA,EAAe,eAAe,kBAAkB,CAAA;AAAA,EAChD,WAAA,EAAa,eAAe,gBAAgB;AAC9C;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/ai — AI Providers (server-only)\n *\n * Coming in v0.2.0. Unified interface for OpenAI + Anthropic.\n */\n\nimport { assertServer } from '../internal/env';\nassertServer('ai');\n\nexport const ai = {\n chat: notImplemented('ai.chat'),\n streamChat: notImplemented('ai.streamChat'),\n streamToSSE: notImplemented('ai.streamToSSE'),\n generateImage: notImplemented('ai.generateImage'),\n getProvider: notImplemented('ai.getProvider'),\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"]}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * @coduckai/sdk/ai — AI Providers (server-only)
3
+ *
4
+ * Coming in v0.2.0. Unified interface for OpenAI + Anthropic.
5
+ */
6
+ declare const ai: {
7
+ chat: () => never;
8
+ streamChat: () => never;
9
+ streamToSSE: () => never;
10
+ generateImage: () => never;
11
+ getProvider: () => never;
12
+ };
13
+
14
+ export { ai };
@@ -0,0 +1,14 @@
1
+ /**
2
+ * @coduckai/sdk/ai — AI Providers (server-only)
3
+ *
4
+ * Coming in v0.2.0. Unified interface for OpenAI + Anthropic.
5
+ */
6
+ declare const ai: {
7
+ chat: () => never;
8
+ streamChat: () => never;
9
+ streamToSSE: () => never;
10
+ generateImage: () => never;
11
+ getProvider: () => never;
12
+ };
13
+
14
+ export { ai };
@@ -0,0 +1,30 @@
1
+ // src/internal/env.ts
2
+ function isServer() {
3
+ return typeof window === "undefined";
4
+ }
5
+ function assertServer(moduleName) {
6
+ if (!isServer()) {
7
+ throw new Error(
8
+ `@coduckai/sdk/${moduleName} is server-only. Use @coduckai/sdk/client for browser code.`
9
+ );
10
+ }
11
+ }
12
+
13
+ // src/ai/index.ts
14
+ assertServer("ai");
15
+ var ai = {
16
+ chat: notImplemented("ai.chat"),
17
+ streamChat: notImplemented("ai.streamChat"),
18
+ streamToSSE: notImplemented("ai.streamToSSE"),
19
+ generateImage: notImplemented("ai.generateImage"),
20
+ getProvider: notImplemented("ai.getProvider")
21
+ };
22
+ function notImplemented(name) {
23
+ return () => {
24
+ throw new Error(`@coduckai/sdk: ${name}() is not yet implemented. Coming in v0.2.0.`);
25
+ };
26
+ }
27
+
28
+ export { ai };
29
+ //# sourceMappingURL=index.js.map
30
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/internal/env.ts","../../src/ai/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,IAAI,CAAA;AAEV,IAAM,EAAA,GAAK;AAAA,EAChB,IAAA,EAAM,eAAe,SAAS,CAAA;AAAA,EAC9B,UAAA,EAAY,eAAe,eAAe,CAAA;AAAA,EAC1C,WAAA,EAAa,eAAe,gBAAgB,CAAA;AAAA,EAC5C,aAAA,EAAe,eAAe,kBAAkB,CAAA;AAAA,EAChD,WAAA,EAAa,eAAe,gBAAgB;AAC9C;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.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 * @coduckai/sdk/ai — AI Providers (server-only)\n *\n * Coming in v0.2.0. Unified interface for OpenAI + Anthropic.\n */\n\nimport { assertServer } from '../internal/env';\nassertServer('ai');\n\nexport const ai = {\n chat: notImplemented('ai.chat'),\n streamChat: notImplemented('ai.streamChat'),\n streamToSSE: notImplemented('ai.streamToSSE'),\n generateImage: notImplemented('ai.generateImage'),\n getProvider: notImplemented('ai.getProvider'),\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"]}
@@ -0,0 +1,139 @@
1
+ 'use strict';
2
+
3
+ var bcrypt = require('bcrypt');
4
+ var jwt = require('jsonwebtoken');
5
+
6
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
7
+
8
+ var bcrypt__default = /*#__PURE__*/_interopDefault(bcrypt);
9
+ var jwt__default = /*#__PURE__*/_interopDefault(jwt);
10
+
11
+ // src/internal/env.ts
12
+ function getEnv(key, fallback) {
13
+ return process.env[key] || fallback;
14
+ }
15
+ function isServer() {
16
+ return typeof window === "undefined";
17
+ }
18
+ function assertServer(moduleName) {
19
+ if (!isServer()) {
20
+ throw new Error(
21
+ `@coduckai/sdk/${moduleName} is server-only. Use @coduckai/sdk/client for browser code.`
22
+ );
23
+ }
24
+ }
25
+
26
+ // src/internal/config.ts
27
+ var globalConfig = {};
28
+ function getConfig() {
29
+ return globalConfig;
30
+ }
31
+ assertServer("auth");
32
+ function getSecret() {
33
+ const config = getConfig();
34
+ const secret = config.auth?.jwtSecret || getEnv("JWT_SECRET");
35
+ if (!secret) {
36
+ throw new Error("@coduckai/sdk/auth: JWT_SECRET environment variable is required");
37
+ }
38
+ return secret;
39
+ }
40
+ function getExpiresIn() {
41
+ const config = getConfig();
42
+ return config.auth?.jwtExpiresIn || getEnv("JWT_EXPIRES_IN") || "7d";
43
+ }
44
+ function getRounds() {
45
+ const config = getConfig();
46
+ return config.auth?.bcryptRounds || 12;
47
+ }
48
+ var auth = {
49
+ /**
50
+ * Hash a plaintext password
51
+ */
52
+ async hashPassword(plaintext) {
53
+ return bcrypt__default.default.hash(plaintext, getRounds());
54
+ },
55
+ /**
56
+ * Verify a plaintext password against a hash
57
+ */
58
+ async verifyPassword(plaintext, hash) {
59
+ return bcrypt__default.default.compare(plaintext, hash);
60
+ },
61
+ /**
62
+ * Generate a signed JWT token
63
+ */
64
+ generateToken(payload, expiresIn) {
65
+ const secret = getSecret();
66
+ const options = {};
67
+ const exp = expiresIn || getExpiresIn();
68
+ if (typeof exp === "number") {
69
+ options.expiresIn = exp;
70
+ } else {
71
+ options.expiresIn = exp;
72
+ }
73
+ return jwt__default.default.sign(payload, secret, options);
74
+ },
75
+ /**
76
+ * Verify and decode a JWT token
77
+ */
78
+ verifyToken(token) {
79
+ return jwt__default.default.verify(token, getSecret());
80
+ },
81
+ /**
82
+ * Refresh a token — verifies the old one, issues a new one
83
+ */
84
+ refreshToken(token) {
85
+ const payload = auth.verifyToken(token);
86
+ const { iat, exp, ...data } = payload;
87
+ return auth.generateToken(data);
88
+ },
89
+ /**
90
+ * Express middleware — verifies Bearer token, sets req.user
91
+ * Responds with 401 if token is missing or invalid
92
+ */
93
+ authenticate() {
94
+ return (req, res, next) => {
95
+ const header = req.headers.authorization;
96
+ if (!header || !header.startsWith("Bearer ")) {
97
+ res.status(401).json({ error: "Authentication required" });
98
+ return;
99
+ }
100
+ try {
101
+ const token = header.slice(7);
102
+ req.user = auth.verifyToken(token);
103
+ next();
104
+ } catch {
105
+ res.status(401).json({ error: "Invalid or expired token" });
106
+ }
107
+ };
108
+ },
109
+ /**
110
+ * Express middleware — sets req.user if token present, continues regardless
111
+ */
112
+ optionalAuth() {
113
+ return (req, _res, next) => {
114
+ const header = req.headers.authorization;
115
+ if (header && header.startsWith("Bearer ")) {
116
+ try {
117
+ const token = header.slice(7);
118
+ req.user = auth.verifyToken(token);
119
+ } catch {
120
+ }
121
+ }
122
+ next();
123
+ };
124
+ },
125
+ /**
126
+ * Get the authenticated user from the request (throws if not present)
127
+ */
128
+ getUser(req) {
129
+ const user = req.user;
130
+ if (!user) {
131
+ throw new Error("No authenticated user on request. Use auth.authenticate() middleware first.");
132
+ }
133
+ return user;
134
+ }
135
+ };
136
+
137
+ exports.auth = auth;
138
+ //# sourceMappingURL=index.cjs.map
139
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
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}\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"]}
@@ -0,0 +1,56 @@
1
+ import { RequestHandler, Request } from 'express';
2
+
3
+ /**
4
+ * @coduckai/sdk/auth — Authentication module (server-only)
5
+ *
6
+ * Wraps bcrypt + jsonwebtoken. Drop-in replacement for hand-rolled auth.
7
+ *
8
+ * Usage:
9
+ * import { auth } from '@coduckai/sdk/auth';
10
+ * const hash = await auth.hashPassword('secret');
11
+ * const token = auth.generateToken({ id: 1, email: 'user@test.com' });
12
+ * router.get('/me', auth.authenticate(), handler);
13
+ */
14
+
15
+ interface TokenPayload {
16
+ id: number;
17
+ email: string;
18
+ [key: string]: unknown;
19
+ }
20
+ declare const auth: {
21
+ /**
22
+ * Hash a plaintext password
23
+ */
24
+ hashPassword(plaintext: string): Promise<string>;
25
+ /**
26
+ * Verify a plaintext password against a hash
27
+ */
28
+ verifyPassword(plaintext: string, hash: string): Promise<boolean>;
29
+ /**
30
+ * Generate a signed JWT token
31
+ */
32
+ generateToken(payload: TokenPayload, expiresIn?: string | number): string;
33
+ /**
34
+ * Verify and decode a JWT token
35
+ */
36
+ verifyToken(token: string): TokenPayload;
37
+ /**
38
+ * Refresh a token — verifies the old one, issues a new one
39
+ */
40
+ refreshToken(token: string): string;
41
+ /**
42
+ * Express middleware — verifies Bearer token, sets req.user
43
+ * Responds with 401 if token is missing or invalid
44
+ */
45
+ authenticate(): RequestHandler;
46
+ /**
47
+ * Express middleware — sets req.user if token present, continues regardless
48
+ */
49
+ optionalAuth(): RequestHandler;
50
+ /**
51
+ * Get the authenticated user from the request (throws if not present)
52
+ */
53
+ getUser(req: Request): TokenPayload;
54
+ };
55
+
56
+ export { type TokenPayload, auth };
@@ -0,0 +1,56 @@
1
+ import { RequestHandler, Request } from 'express';
2
+
3
+ /**
4
+ * @coduckai/sdk/auth — Authentication module (server-only)
5
+ *
6
+ * Wraps bcrypt + jsonwebtoken. Drop-in replacement for hand-rolled auth.
7
+ *
8
+ * Usage:
9
+ * import { auth } from '@coduckai/sdk/auth';
10
+ * const hash = await auth.hashPassword('secret');
11
+ * const token = auth.generateToken({ id: 1, email: 'user@test.com' });
12
+ * router.get('/me', auth.authenticate(), handler);
13
+ */
14
+
15
+ interface TokenPayload {
16
+ id: number;
17
+ email: string;
18
+ [key: string]: unknown;
19
+ }
20
+ declare const auth: {
21
+ /**
22
+ * Hash a plaintext password
23
+ */
24
+ hashPassword(plaintext: string): Promise<string>;
25
+ /**
26
+ * Verify a plaintext password against a hash
27
+ */
28
+ verifyPassword(plaintext: string, hash: string): Promise<boolean>;
29
+ /**
30
+ * Generate a signed JWT token
31
+ */
32
+ generateToken(payload: TokenPayload, expiresIn?: string | number): string;
33
+ /**
34
+ * Verify and decode a JWT token
35
+ */
36
+ verifyToken(token: string): TokenPayload;
37
+ /**
38
+ * Refresh a token — verifies the old one, issues a new one
39
+ */
40
+ refreshToken(token: string): string;
41
+ /**
42
+ * Express middleware — verifies Bearer token, sets req.user
43
+ * Responds with 401 if token is missing or invalid
44
+ */
45
+ authenticate(): RequestHandler;
46
+ /**
47
+ * Express middleware — sets req.user if token present, continues regardless
48
+ */
49
+ optionalAuth(): RequestHandler;
50
+ /**
51
+ * Get the authenticated user from the request (throws if not present)
52
+ */
53
+ getUser(req: Request): TokenPayload;
54
+ };
55
+
56
+ export { type TokenPayload, auth };
@@ -0,0 +1,132 @@
1
+ import bcrypt from 'bcrypt';
2
+ import jwt from 'jsonwebtoken';
3
+
4
+ // src/internal/env.ts
5
+ function getEnv(key, fallback) {
6
+ return process.env[key] || fallback;
7
+ }
8
+ function isServer() {
9
+ return typeof window === "undefined";
10
+ }
11
+ function assertServer(moduleName) {
12
+ if (!isServer()) {
13
+ throw new Error(
14
+ `@coduckai/sdk/${moduleName} is server-only. Use @coduckai/sdk/client for browser code.`
15
+ );
16
+ }
17
+ }
18
+
19
+ // src/internal/config.ts
20
+ var globalConfig = {};
21
+ function getConfig() {
22
+ return globalConfig;
23
+ }
24
+ assertServer("auth");
25
+ function getSecret() {
26
+ const config = getConfig();
27
+ const secret = config.auth?.jwtSecret || getEnv("JWT_SECRET");
28
+ if (!secret) {
29
+ throw new Error("@coduckai/sdk/auth: JWT_SECRET environment variable is required");
30
+ }
31
+ return secret;
32
+ }
33
+ function getExpiresIn() {
34
+ const config = getConfig();
35
+ return config.auth?.jwtExpiresIn || getEnv("JWT_EXPIRES_IN") || "7d";
36
+ }
37
+ function getRounds() {
38
+ const config = getConfig();
39
+ return config.auth?.bcryptRounds || 12;
40
+ }
41
+ var auth = {
42
+ /**
43
+ * Hash a plaintext password
44
+ */
45
+ async hashPassword(plaintext) {
46
+ return bcrypt.hash(plaintext, getRounds());
47
+ },
48
+ /**
49
+ * Verify a plaintext password against a hash
50
+ */
51
+ async verifyPassword(plaintext, hash) {
52
+ return bcrypt.compare(plaintext, hash);
53
+ },
54
+ /**
55
+ * Generate a signed JWT token
56
+ */
57
+ generateToken(payload, expiresIn) {
58
+ const secret = getSecret();
59
+ const options = {};
60
+ const exp = expiresIn || getExpiresIn();
61
+ if (typeof exp === "number") {
62
+ options.expiresIn = exp;
63
+ } else {
64
+ options.expiresIn = exp;
65
+ }
66
+ return jwt.sign(payload, secret, options);
67
+ },
68
+ /**
69
+ * Verify and decode a JWT token
70
+ */
71
+ verifyToken(token) {
72
+ return jwt.verify(token, getSecret());
73
+ },
74
+ /**
75
+ * Refresh a token — verifies the old one, issues a new one
76
+ */
77
+ refreshToken(token) {
78
+ const payload = auth.verifyToken(token);
79
+ const { iat, exp, ...data } = payload;
80
+ return auth.generateToken(data);
81
+ },
82
+ /**
83
+ * Express middleware — verifies Bearer token, sets req.user
84
+ * Responds with 401 if token is missing or invalid
85
+ */
86
+ authenticate() {
87
+ return (req, res, next) => {
88
+ const header = req.headers.authorization;
89
+ if (!header || !header.startsWith("Bearer ")) {
90
+ res.status(401).json({ error: "Authentication required" });
91
+ return;
92
+ }
93
+ try {
94
+ const token = header.slice(7);
95
+ req.user = auth.verifyToken(token);
96
+ next();
97
+ } catch {
98
+ res.status(401).json({ error: "Invalid or expired token" });
99
+ }
100
+ };
101
+ },
102
+ /**
103
+ * Express middleware — sets req.user if token present, continues regardless
104
+ */
105
+ optionalAuth() {
106
+ return (req, _res, next) => {
107
+ const header = req.headers.authorization;
108
+ if (header && header.startsWith("Bearer ")) {
109
+ try {
110
+ const token = header.slice(7);
111
+ req.user = auth.verifyToken(token);
112
+ } catch {
113
+ }
114
+ }
115
+ next();
116
+ };
117
+ },
118
+ /**
119
+ * Get the authenticated user from the request (throws if not present)
120
+ */
121
+ getUser(req) {
122
+ const user = req.user;
123
+ if (!user) {
124
+ throw new Error("No authenticated user on request. Use auth.authenticate() middleware first.");
125
+ }
126
+ return user;
127
+ }
128
+ };
129
+
130
+ export { auth };
131
+ //# sourceMappingURL=index.js.map
132
+ //# sourceMappingURL=index.js.map
@@ -0,0 +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;;;ACJA,IAAI,eAA0B,EAAC;AAMxB,SAAS,SAAA,GAAuB;AACrC,EAAA,OAAO,YAAA;AACT;ACfA,YAAA,CAAa,MAAM,CAAA;AAoBnB,SAAS,SAAA,GAAoB;AAC3B,EAAA,MAAM,SAAS,SAAA,EAAU;AACzB,EAAA,MAAM,MAAA,GAAS,MAAA,CAAO,IAAA,EAAM,SAAA,IAAa,OAAO,YAAY,CAAA;AAC5D,EAAA,IAAI,CAAC,MAAA,EAAQ;AACX,IAAA,MAAM,IAAI,MAAM,iEAAiE,CAAA;AAAA,EACnF;AACA,EAAA,OAAO,MAAA;AACT;AAEA,SAAS,YAAA,GAAuB;AAC9B,EAAA,MAAM,SAAS,SAAA,EAAU;AACzB,EAAA,OAAO,MAAA,CAAO,IAAA,EAAM,YAAA,IAAgB,MAAA,CAAO,gBAAgB,CAAA,IAAK,IAAA;AAClE;AAEA,SAAS,SAAA,GAAoB;AAC3B,EAAA,MAAM,SAAS,SAAA,EAAU;AACzB,EAAA,OAAO,MAAA,CAAO,MAAM,YAAA,IAAgB,EAAA;AACtC;AAIO,IAAM,IAAA,GAAO;AAAA;AAAA;AAAA;AAAA,EAIlB,MAAM,aAAa,SAAA,EAAoC;AACrD,IAAA,OAAO,MAAA,CAAO,IAAA,CAAK,SAAA,EAAW,SAAA,EAAW,CAAA;AAAA,EAC3C,CAAA;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,cAAA,CAAe,SAAA,EAAmB,IAAA,EAAgC;AACtE,IAAA,OAAO,MAAA,CAAO,OAAA,CAAQ,SAAA,EAAW,IAAI,CAAA;AAAA,EACvC,CAAA;AAAA;AAAA;AAAA;AAAA,EAKA,aAAA,CAAc,SAAuB,SAAA,EAAqC;AACxE,IAAA,MAAM,SAAS,SAAA,EAAU;AACzB,IAAA,MAAM,UAA2B,EAAC;AAClC,IAAA,MAAM,GAAA,GAAM,aAAa,YAAA,EAAa;AACtC,IAAA,IAAI,OAAO,QAAQ,QAAA,EAAU;AAC3B,MAAA,OAAA,CAAQ,SAAA,GAAY,GAAA;AAAA,IACtB,CAAA,MAAO;AACL,MAAA,OAAA,CAAQ,SAAA,GAAY,GAAA;AAAA,IACtB;AACA,IAAA,OAAO,GAAA,CAAI,IAAA,CAAK,OAAA,EAAS,MAAA,EAAQ,OAAO,CAAA;AAAA,EAC1C,CAAA;AAAA;AAAA;AAAA;AAAA,EAKA,YAAY,KAAA,EAA6B;AACvC,IAAA,OAAO,GAAA,CAAI,MAAA,CAAO,KAAA,EAAO,SAAA,EAAW,CAAA;AAAA,EACtC,CAAA;AAAA;AAAA;AAAA;AAAA,EAKA,aAAa,KAAA,EAAuB;AAClC,IAAA,MAAM,OAAA,GAAU,IAAA,CAAK,WAAA,CAAY,KAAK,CAAA;AAEtC,IAAA,MAAM,EAAE,GAAA,EAAK,GAAA,EAAK,GAAG,MAAK,GAAI,OAAA;AAC9B,IAAA,OAAO,IAAA,CAAK,cAAc,IAAoB,CAAA;AAAA,EAChD,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,YAAA,GAA+B;AAC7B,IAAA,OAAO,CAAC,GAAA,EAAc,GAAA,EAAe,IAAA,KAA6B;AAChE,MAAA,MAAM,MAAA,GAAS,IAAI,OAAA,CAAQ,aAAA;AAC3B,MAAA,IAAI,CAAC,MAAA,IAAU,CAAC,MAAA,CAAO,UAAA,CAAW,SAAS,CAAA,EAAG;AAC5C,QAAA,GAAA,CAAI,OAAO,GAAG,CAAA,CAAE,KAAK,EAAE,KAAA,EAAO,2BAA2B,CAAA;AACzD,QAAA;AAAA,MACF;AAEA,MAAA,IAAI;AACF,QAAA,MAAM,KAAA,GAAQ,MAAA,CAAO,KAAA,CAAM,CAAC,CAAA;AAC5B,QAAC,GAAA,CAA6B,IAAA,GAAO,IAAA,CAAK,WAAA,CAAY,KAAK,CAAA;AAC3D,QAAA,IAAA,EAAK;AAAA,MACP,CAAA,CAAA,MAAQ;AACN,QAAA,GAAA,CAAI,OAAO,GAAG,CAAA,CAAE,KAAK,EAAE,KAAA,EAAO,4BAA4B,CAAA;AAAA,MAC5D;AAAA,IACF,CAAA;AAAA,EACF,CAAA;AAAA;AAAA;AAAA;AAAA,EAKA,YAAA,GAA+B;AAC7B,IAAA,OAAO,CAAC,GAAA,EAAc,IAAA,EAAgB,IAAA,KAA6B;AACjE,MAAA,MAAM,MAAA,GAAS,IAAI,OAAA,CAAQ,aAAA;AAC3B,MAAA,IAAI,MAAA,IAAU,MAAA,CAAO,UAAA,CAAW,SAAS,CAAA,EAAG;AAC1C,QAAA,IAAI;AACF,UAAA,MAAM,KAAA,GAAQ,MAAA,CAAO,KAAA,CAAM,CAAC,CAAA;AAC5B,UAAC,GAAA,CAA6B,IAAA,GAAO,IAAA,CAAK,WAAA,CAAY,KAAK,CAAA;AAAA,QAC7D,CAAA,CAAA,MAAQ;AAAA,QAER;AAAA,MACF;AACA,MAAA,IAAA,EAAK;AAAA,IACP,CAAA;AAAA,EACF,CAAA;AAAA;AAAA;AAAA;AAAA,EAKA,QAAQ,GAAA,EAA4B;AAClC,IAAA,MAAM,OAAQ,GAAA,CAA6B,IAAA;AAC3C,IAAA,IAAI,CAAC,IAAA,EAAM;AACT,MAAA,MAAM,IAAI,MAAM,6EAA6E,CAAA;AAAA,IAC/F;AACA,IAAA,OAAO,IAAA;AAAA,EACT;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}\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"]}
@@ -0,0 +1,70 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var axios = require('axios');
6
+
7
+ var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
8
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
9
+
10
+ var axios__default = /*#__PURE__*/_interopDefault(axios);
11
+
12
+ // src/client/index.ts
13
+ var TOKEN_KEY = "token";
14
+ function setToken(token) {
15
+ if (typeof localStorage !== "undefined") {
16
+ localStorage.setItem(TOKEN_KEY, token);
17
+ }
18
+ }
19
+ function getToken() {
20
+ if (typeof localStorage !== "undefined") {
21
+ return localStorage.getItem(TOKEN_KEY);
22
+ }
23
+ return null;
24
+ }
25
+ function clearToken() {
26
+ if (typeof localStorage !== "undefined") {
27
+ localStorage.removeItem(TOKEN_KEY);
28
+ }
29
+ }
30
+ function isAuthenticated() {
31
+ return !!getToken();
32
+ }
33
+ function getBaseUrl() {
34
+ if (typeof ({ url: (typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)) }) !== "undefined" && undefined?.VITE_API_URL) {
35
+ return undefined.VITE_API_URL;
36
+ }
37
+ return "/api";
38
+ }
39
+ var api = axios__default.default.create({
40
+ baseURL: getBaseUrl(),
41
+ headers: { "Content-Type": "application/json" }
42
+ });
43
+ api.interceptors.request.use((config) => {
44
+ const token = getToken();
45
+ if (token) {
46
+ config.headers.Authorization = `Bearer ${token}`;
47
+ }
48
+ return config;
49
+ });
50
+ api.interceptors.response.use(
51
+ (response) => response,
52
+ (error) => {
53
+ if (error.response?.status === 401) {
54
+ clearToken();
55
+ if (typeof window !== "undefined") {
56
+ window.location.href = "/login";
57
+ }
58
+ }
59
+ return Promise.reject(error);
60
+ }
61
+ );
62
+ var client_default = api;
63
+
64
+ exports.clearToken = clearToken;
65
+ exports.default = client_default;
66
+ exports.getToken = getToken;
67
+ exports.isAuthenticated = isAuthenticated;
68
+ exports.setToken = setToken;
69
+ //# sourceMappingURL=index.cjs.map
70
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +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,KAAa,QAAA;AAAA,EACd,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 { data } = await api.get('/recipes');\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 — handle 401\napi.interceptors.response.use(\n (response) => response,\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"]}
@@ -0,0 +1,20 @@
1
+ import { AxiosInstance } from 'axios';
2
+
3
+ /**
4
+ * @coduckai/sdk/client — Frontend API Client (browser-only)
5
+ *
6
+ * Pre-configured Axios instance with auth interceptor.
7
+ *
8
+ * Usage:
9
+ * import api, { setToken, clearToken } from '@coduckai/sdk/client';
10
+ * const { data } = await api.get('/recipes');
11
+ * setToken(loginData.token);
12
+ */
13
+
14
+ declare function setToken(token: string): void;
15
+ declare function getToken(): string | null;
16
+ declare function clearToken(): void;
17
+ declare function isAuthenticated(): boolean;
18
+ declare const api: AxiosInstance;
19
+
20
+ export { clearToken, api as default, getToken, isAuthenticated, setToken };
@@ -0,0 +1,20 @@
1
+ import { AxiosInstance } from 'axios';
2
+
3
+ /**
4
+ * @coduckai/sdk/client — Frontend API Client (browser-only)
5
+ *
6
+ * Pre-configured Axios instance with auth interceptor.
7
+ *
8
+ * Usage:
9
+ * import api, { setToken, clearToken } from '@coduckai/sdk/client';
10
+ * const { data } = await api.get('/recipes');
11
+ * setToken(loginData.token);
12
+ */
13
+
14
+ declare function setToken(token: string): void;
15
+ declare function getToken(): string | null;
16
+ declare function clearToken(): void;
17
+ declare function isAuthenticated(): boolean;
18
+ declare const api: AxiosInstance;
19
+
20
+ export { clearToken, api as default, getToken, isAuthenticated, setToken };