@diegoaltoworks/chatter 0.11.0 → 0.13.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.
- package/dist/bin/create-apikey.js +193 -0
- package/dist/index.js +34 -22
- package/dist/index.mjs +34 -22
- package/dist/middleware/cors.d.ts +8 -1
- package/dist/middleware/cors.d.ts.map +1 -1
- package/dist/routes/demo.d.ts.map +1 -1
- package/dist/routes/public.d.ts.map +1 -1
- package/dist/types.d.ts +9 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +5 -4
- package/bin/create-apikey.ts +0 -101
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
|
|
4
|
+
// src/auth/apikeys.ts
|
|
5
|
+
var import_node_crypto = require("node:crypto");
|
|
6
|
+
var import_jose = require("jose");
|
|
7
|
+
var ApiKeyManager = class {
|
|
8
|
+
constructor(secret) {
|
|
9
|
+
this.secret = secret;
|
|
10
|
+
if (!secret) {
|
|
11
|
+
throw new Error("API key secret is required");
|
|
12
|
+
}
|
|
13
|
+
this.secretBytes = new TextEncoder().encode(secret);
|
|
14
|
+
}
|
|
15
|
+
secretBytes;
|
|
16
|
+
/**
|
|
17
|
+
* Create a new API key
|
|
18
|
+
*
|
|
19
|
+
* @param options - API key options
|
|
20
|
+
* @returns JWT token string
|
|
21
|
+
*/
|
|
22
|
+
async create(options = {}) {
|
|
23
|
+
const keyId = (0, import_node_crypto.randomUUID)();
|
|
24
|
+
const keyName = options.name || "api-key";
|
|
25
|
+
const expiresIn = options.expiresIn || "365d";
|
|
26
|
+
const expirationMs = this.parseExpiration(expiresIn);
|
|
27
|
+
const expiresAt = new Date(Date.now() + expirationMs);
|
|
28
|
+
const jwt = await new import_jose.SignJWT({
|
|
29
|
+
name: keyName,
|
|
30
|
+
type: "api_key",
|
|
31
|
+
...options.claims
|
|
32
|
+
}).setProtectedHeader({ alg: "HS256" }).setSubject(keyId).setIssuedAt().setExpirationTime(expiresAt).sign(this.secretBytes);
|
|
33
|
+
return jwt;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Verify an API key
|
|
37
|
+
*
|
|
38
|
+
* @param token - JWT token to verify
|
|
39
|
+
* @returns Verification result with payload if valid
|
|
40
|
+
*/
|
|
41
|
+
async verify(token) {
|
|
42
|
+
try {
|
|
43
|
+
const { payload } = await (0, import_jose.jwtVerify)(token, this.secretBytes);
|
|
44
|
+
if (payload.type !== "api_key") {
|
|
45
|
+
return {
|
|
46
|
+
valid: false,
|
|
47
|
+
error: "Token is not an API key"
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
return {
|
|
51
|
+
valid: true,
|
|
52
|
+
payload
|
|
53
|
+
};
|
|
54
|
+
} catch (error) {
|
|
55
|
+
return {
|
|
56
|
+
valid: false,
|
|
57
|
+
error: error instanceof Error ? error.message : "Verification failed"
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Parse expiration string to milliseconds
|
|
63
|
+
*
|
|
64
|
+
* @param expiresIn - Time string (e.g., "1y", "30d", "12h")
|
|
65
|
+
* @returns Milliseconds
|
|
66
|
+
*/
|
|
67
|
+
parseExpiration(expiresIn) {
|
|
68
|
+
const match = expiresIn.match(/^(\d+)([smhdMy])$/);
|
|
69
|
+
if (!match) {
|
|
70
|
+
throw new Error(
|
|
71
|
+
`Invalid expiration format: ${expiresIn}. Supported: s (seconds), m (minutes), h (hours), d (days), M (months), y (years)`
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
const value = Number.parseInt(match[1], 10);
|
|
75
|
+
const unit = match[2];
|
|
76
|
+
switch (unit) {
|
|
77
|
+
case "s":
|
|
78
|
+
return value * 1e3;
|
|
79
|
+
case "m":
|
|
80
|
+
return value * 60 * 1e3;
|
|
81
|
+
case "h":
|
|
82
|
+
return value * 60 * 60 * 1e3;
|
|
83
|
+
case "d":
|
|
84
|
+
return value * 24 * 60 * 60 * 1e3;
|
|
85
|
+
case "M":
|
|
86
|
+
return value * 30 * 24 * 60 * 60 * 1e3;
|
|
87
|
+
// Approximate 30 days
|
|
88
|
+
case "y":
|
|
89
|
+
return value * 365 * 24 * 60 * 60 * 1e3;
|
|
90
|
+
// Approximate 365 days
|
|
91
|
+
default:
|
|
92
|
+
throw new Error(`Unknown time unit: ${unit}`);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Get information about a token without verifying signature
|
|
97
|
+
* Useful for debugging
|
|
98
|
+
*
|
|
99
|
+
* @param token - JWT token
|
|
100
|
+
* @returns Decoded payload (unverified)
|
|
101
|
+
*/
|
|
102
|
+
decode(token) {
|
|
103
|
+
try {
|
|
104
|
+
const parts = token.split(".");
|
|
105
|
+
if (parts.length !== 3) {
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
const payload = JSON.parse(Buffer.from(parts[1], "base64url").toString("utf-8"));
|
|
109
|
+
return payload;
|
|
110
|
+
} catch {
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
// bin/create-apikey.ts
|
|
117
|
+
async function main() {
|
|
118
|
+
const args = process.argv.slice(2);
|
|
119
|
+
const options = {};
|
|
120
|
+
for (let i = 0; i < args.length; i++) {
|
|
121
|
+
if (args[i] === "--name" && args[i + 1]) {
|
|
122
|
+
options.name = args[i + 1];
|
|
123
|
+
i++;
|
|
124
|
+
} else if (args[i] === "--expires-in" && args[i + 1]) {
|
|
125
|
+
options.expiresIn = args[i + 1];
|
|
126
|
+
i++;
|
|
127
|
+
} else if (args[i] === "--help" || args[i] === "-h") {
|
|
128
|
+
console.log(`
|
|
129
|
+
Chatter API Key Generator
|
|
130
|
+
|
|
131
|
+
Usage:
|
|
132
|
+
npx chatter create-apikey [options]
|
|
133
|
+
|
|
134
|
+
Options:
|
|
135
|
+
--name <name> Name/label for the API key (default: "api-key")
|
|
136
|
+
--expires-in <time> Expiration time (default: "365d")
|
|
137
|
+
Formats: s=seconds, m=minutes, h=hours, d=days, M=months, y=years
|
|
138
|
+
Examples: 30d, 12h, 1y, 6M
|
|
139
|
+
|
|
140
|
+
Environment:
|
|
141
|
+
CHATTER_SECRET Required. Secret key for signing JWT tokens
|
|
142
|
+
|
|
143
|
+
Examples:
|
|
144
|
+
npx chatter create-apikey --name "mobile-app" --expires-in 365d
|
|
145
|
+
npx chatter create-apikey --name "test-key" --expires-in 1h
|
|
146
|
+
`);
|
|
147
|
+
process.exit(0);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
const secret = process.env.CHATTER_SECRET;
|
|
151
|
+
if (!secret) {
|
|
152
|
+
console.error("\u274C Error: CHATTER_SECRET environment variable is not set");
|
|
153
|
+
console.error("\n Please set it before running this command:");
|
|
154
|
+
console.error(" export CHATTER_SECRET=your-secret-key-here");
|
|
155
|
+
console.error("\n Or prefix the command:");
|
|
156
|
+
console.error(" CHATTER_SECRET=your-secret npx chatter create-apikey\n");
|
|
157
|
+
process.exit(1);
|
|
158
|
+
}
|
|
159
|
+
const manager = new ApiKeyManager(secret);
|
|
160
|
+
const keyName = options.name || "api-key";
|
|
161
|
+
const expiresIn = options.expiresIn || "365d";
|
|
162
|
+
try {
|
|
163
|
+
const apiKey = await manager.create({
|
|
164
|
+
name: keyName,
|
|
165
|
+
expiresIn
|
|
166
|
+
});
|
|
167
|
+
const payload = manager.decode(apiKey);
|
|
168
|
+
if (!payload) {
|
|
169
|
+
throw new Error("Failed to decode generated API key");
|
|
170
|
+
}
|
|
171
|
+
const expiresAt = new Date((payload.exp || 0) * 1e3);
|
|
172
|
+
const issuedAt = new Date((payload.iat || 0) * 1e3);
|
|
173
|
+
console.log("\n\u2705 API Key generated successfully!\n");
|
|
174
|
+
console.log(` Name: ${keyName}`);
|
|
175
|
+
console.log(` ID: ${payload.sub}`);
|
|
176
|
+
console.log(` Issued: ${issuedAt.toISOString()}`);
|
|
177
|
+
console.log(` Expires: ${expiresAt.toISOString()} (${expiresIn})`);
|
|
178
|
+
console.log(`
|
|
179
|
+
API Key:
|
|
180
|
+
${apiKey}
|
|
181
|
+
`);
|
|
182
|
+
console.log(" Usage:");
|
|
183
|
+
console.log(" curl -X POST https://your-bot.example.com/api/public/chat \\");
|
|
184
|
+
console.log(` -H "x-api-key: ${apiKey.slice(0, 50)}..." \\`);
|
|
185
|
+
console.log(' -H "Content-Type: application/json" \\');
|
|
186
|
+
console.log(` -d '{"message": "Hello"}'`);
|
|
187
|
+
console.log("");
|
|
188
|
+
} catch (error) {
|
|
189
|
+
console.error("\u274C Error creating API key:", error);
|
|
190
|
+
process.exit(1);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
main();
|
package/dist/index.js
CHANGED
|
@@ -7659,22 +7659,38 @@ function resolveStatic(configStaticDir) {
|
|
|
7659
7659
|
}
|
|
7660
7660
|
|
|
7661
7661
|
// src/middleware/cors.ts
|
|
7662
|
-
var
|
|
7663
|
-
|
|
7664
|
-
|
|
7665
|
-
c.header("
|
|
7662
|
+
var ALLOWED_HEADERS = "content-type, x-api-key, authorization";
|
|
7663
|
+
var ALLOWED_METHODS = "POST, GET, OPTIONS";
|
|
7664
|
+
var cors = (allowedOrigins) => async (c, next) => {
|
|
7665
|
+
const requestOrigin = c.req.header("origin");
|
|
7666
|
+
const allowAll = !allowedOrigins || allowedOrigins.length === 0 || allowedOrigins.includes("*");
|
|
7667
|
+
const originHeader = resolveOrigin(requestOrigin, allowedOrigins, allowAll);
|
|
7666
7668
|
if (c.req.method === "OPTIONS") {
|
|
7667
7669
|
return new Response(null, {
|
|
7668
7670
|
status: 204,
|
|
7669
7671
|
headers: {
|
|
7670
|
-
"access-control-allow-origin":
|
|
7671
|
-
"access-control-allow-headers":
|
|
7672
|
-
"access-control-allow-methods":
|
|
7672
|
+
"access-control-allow-origin": originHeader,
|
|
7673
|
+
"access-control-allow-headers": ALLOWED_HEADERS,
|
|
7674
|
+
"access-control-allow-methods": ALLOWED_METHODS,
|
|
7675
|
+
...allowAll ? {} : { vary: "Origin" }
|
|
7673
7676
|
}
|
|
7674
7677
|
});
|
|
7675
7678
|
}
|
|
7679
|
+
c.header("access-control-allow-origin", originHeader);
|
|
7680
|
+
c.header("access-control-allow-headers", ALLOWED_HEADERS);
|
|
7681
|
+
c.header("access-control-allow-methods", ALLOWED_METHODS);
|
|
7682
|
+
if (!allowAll) {
|
|
7683
|
+
c.header("vary", "Origin");
|
|
7684
|
+
}
|
|
7676
7685
|
await next();
|
|
7677
7686
|
};
|
|
7687
|
+
function resolveOrigin(requestOrigin, allowedOrigins, allowAll) {
|
|
7688
|
+
if (allowAll) return "*";
|
|
7689
|
+
if (requestOrigin && allowedOrigins.includes(requestOrigin)) {
|
|
7690
|
+
return requestOrigin;
|
|
7691
|
+
}
|
|
7692
|
+
return allowedOrigins[0];
|
|
7693
|
+
}
|
|
7678
7694
|
|
|
7679
7695
|
// src/routes/demo.ts
|
|
7680
7696
|
var import_hono = require("hono");
|
|
@@ -7784,14 +7800,8 @@ function getActiveSessions() {
|
|
|
7784
7800
|
}
|
|
7785
7801
|
|
|
7786
7802
|
// src/routes/demo.ts
|
|
7787
|
-
function checkDemoOrigin() {
|
|
7788
|
-
const
|
|
7789
|
-
"https://bot.diegoalto.app",
|
|
7790
|
-
"https://diegoalto.co.uk",
|
|
7791
|
-
"http://diegoalto.co.uk",
|
|
7792
|
-
"https://diegoalto.works",
|
|
7793
|
-
"http://diegoalto.works"
|
|
7794
|
-
];
|
|
7803
|
+
function checkDemoOrigin(allowedOrigins) {
|
|
7804
|
+
const allowAll = allowedOrigins.length === 0 || allowedOrigins.includes("*");
|
|
7795
7805
|
return async (c, next) => {
|
|
7796
7806
|
const origin = c.req.header("origin");
|
|
7797
7807
|
const referer = c.req.header("referer");
|
|
@@ -7799,6 +7809,9 @@ function checkDemoOrigin() {
|
|
|
7799
7809
|
if (host.startsWith("localhost:") || host.startsWith("127.0.0.1:")) {
|
|
7800
7810
|
return next();
|
|
7801
7811
|
}
|
|
7812
|
+
if (allowAll) {
|
|
7813
|
+
return next();
|
|
7814
|
+
}
|
|
7802
7815
|
if (origin) {
|
|
7803
7816
|
const allowed = allowedOrigins.some((allowed2) => origin.startsWith(allowed2));
|
|
7804
7817
|
if (allowed) return next();
|
|
@@ -7868,9 +7881,10 @@ function limitDemo() {
|
|
|
7868
7881
|
};
|
|
7869
7882
|
}
|
|
7870
7883
|
function demoRoutes(deps) {
|
|
7871
|
-
const { client, store, prompts } = deps;
|
|
7884
|
+
const { client, store, config: config2, prompts } = deps;
|
|
7872
7885
|
const app = new import_hono.Hono();
|
|
7873
|
-
|
|
7886
|
+
const demoOrigins = config2.server?.allowedOrigins ?? [];
|
|
7887
|
+
app.get("/api/demo/session", checkDemoOrigin(demoOrigins), limitSessionCreation(), (c) => {
|
|
7874
7888
|
const session = createSession({
|
|
7875
7889
|
maxRequests: 20,
|
|
7876
7890
|
ttl: 3600
|
|
@@ -8213,12 +8227,10 @@ function publicRoutes(deps) {
|
|
|
8213
8227
|
const app = new import_hono3.Hono();
|
|
8214
8228
|
const requirePublicKey = createAuthMiddleware(deps);
|
|
8215
8229
|
const { limitPublic: limitPublic2 } = createRateLimiter(config2);
|
|
8230
|
+
const referrerOrigins = config2.server?.allowedOrigins?.length ? config2.server.allowedOrigins.filter((o) => o !== "*") : [config2.bot.publicUrl, "http://localhost:8181", "http://127.0.0.1:8181"];
|
|
8216
8231
|
app.use("/api/public/*", validateSessionKey());
|
|
8217
8232
|
app.use("/api/public/*", requirePublicKey);
|
|
8218
|
-
app.use(
|
|
8219
|
-
"/api/public/*",
|
|
8220
|
-
requireReferrer([config2.bot.publicUrl, "http://localhost:8181", "http://127.0.0.1:8181"])
|
|
8221
|
-
);
|
|
8233
|
+
app.use("/api/public/*", requireReferrer(referrerOrigins));
|
|
8222
8234
|
app.use("/api/public/*", limitPublic2());
|
|
8223
8235
|
app.post("/api/public/chat", async (c) => {
|
|
8224
8236
|
const body = await c.req.json().catch(() => ({}));
|
|
@@ -8292,7 +8304,7 @@ async function createServer(config2) {
|
|
|
8292
8304
|
}
|
|
8293
8305
|
const app = new import_hono4.Hono();
|
|
8294
8306
|
if (config2.server?.cors !== false) {
|
|
8295
|
-
app.use("*", cors());
|
|
8307
|
+
app.use("*", cors(config2.server?.allowedOrigins));
|
|
8296
8308
|
}
|
|
8297
8309
|
app.get("/healthz", (c) => c.text("ok"));
|
|
8298
8310
|
app.get(
|
package/dist/index.mjs
CHANGED
|
@@ -7630,22 +7630,38 @@ function resolveStatic(configStaticDir) {
|
|
|
7630
7630
|
}
|
|
7631
7631
|
|
|
7632
7632
|
// src/middleware/cors.ts
|
|
7633
|
-
var
|
|
7634
|
-
|
|
7635
|
-
|
|
7636
|
-
c.header("
|
|
7633
|
+
var ALLOWED_HEADERS = "content-type, x-api-key, authorization";
|
|
7634
|
+
var ALLOWED_METHODS = "POST, GET, OPTIONS";
|
|
7635
|
+
var cors = (allowedOrigins) => async (c, next) => {
|
|
7636
|
+
const requestOrigin = c.req.header("origin");
|
|
7637
|
+
const allowAll = !allowedOrigins || allowedOrigins.length === 0 || allowedOrigins.includes("*");
|
|
7638
|
+
const originHeader = resolveOrigin(requestOrigin, allowedOrigins, allowAll);
|
|
7637
7639
|
if (c.req.method === "OPTIONS") {
|
|
7638
7640
|
return new Response(null, {
|
|
7639
7641
|
status: 204,
|
|
7640
7642
|
headers: {
|
|
7641
|
-
"access-control-allow-origin":
|
|
7642
|
-
"access-control-allow-headers":
|
|
7643
|
-
"access-control-allow-methods":
|
|
7643
|
+
"access-control-allow-origin": originHeader,
|
|
7644
|
+
"access-control-allow-headers": ALLOWED_HEADERS,
|
|
7645
|
+
"access-control-allow-methods": ALLOWED_METHODS,
|
|
7646
|
+
...allowAll ? {} : { vary: "Origin" }
|
|
7644
7647
|
}
|
|
7645
7648
|
});
|
|
7646
7649
|
}
|
|
7650
|
+
c.header("access-control-allow-origin", originHeader);
|
|
7651
|
+
c.header("access-control-allow-headers", ALLOWED_HEADERS);
|
|
7652
|
+
c.header("access-control-allow-methods", ALLOWED_METHODS);
|
|
7653
|
+
if (!allowAll) {
|
|
7654
|
+
c.header("vary", "Origin");
|
|
7655
|
+
}
|
|
7647
7656
|
await next();
|
|
7648
7657
|
};
|
|
7658
|
+
function resolveOrigin(requestOrigin, allowedOrigins, allowAll) {
|
|
7659
|
+
if (allowAll) return "*";
|
|
7660
|
+
if (requestOrigin && allowedOrigins.includes(requestOrigin)) {
|
|
7661
|
+
return requestOrigin;
|
|
7662
|
+
}
|
|
7663
|
+
return allowedOrigins[0];
|
|
7664
|
+
}
|
|
7649
7665
|
|
|
7650
7666
|
// src/routes/demo.ts
|
|
7651
7667
|
import { Hono } from "hono";
|
|
@@ -7755,14 +7771,8 @@ function getActiveSessions() {
|
|
|
7755
7771
|
}
|
|
7756
7772
|
|
|
7757
7773
|
// src/routes/demo.ts
|
|
7758
|
-
function checkDemoOrigin() {
|
|
7759
|
-
const
|
|
7760
|
-
"https://bot.diegoalto.app",
|
|
7761
|
-
"https://diegoalto.co.uk",
|
|
7762
|
-
"http://diegoalto.co.uk",
|
|
7763
|
-
"https://diegoalto.works",
|
|
7764
|
-
"http://diegoalto.works"
|
|
7765
|
-
];
|
|
7774
|
+
function checkDemoOrigin(allowedOrigins) {
|
|
7775
|
+
const allowAll = allowedOrigins.length === 0 || allowedOrigins.includes("*");
|
|
7766
7776
|
return async (c, next) => {
|
|
7767
7777
|
const origin = c.req.header("origin");
|
|
7768
7778
|
const referer = c.req.header("referer");
|
|
@@ -7770,6 +7780,9 @@ function checkDemoOrigin() {
|
|
|
7770
7780
|
if (host.startsWith("localhost:") || host.startsWith("127.0.0.1:")) {
|
|
7771
7781
|
return next();
|
|
7772
7782
|
}
|
|
7783
|
+
if (allowAll) {
|
|
7784
|
+
return next();
|
|
7785
|
+
}
|
|
7773
7786
|
if (origin) {
|
|
7774
7787
|
const allowed = allowedOrigins.some((allowed2) => origin.startsWith(allowed2));
|
|
7775
7788
|
if (allowed) return next();
|
|
@@ -7839,9 +7852,10 @@ function limitDemo() {
|
|
|
7839
7852
|
};
|
|
7840
7853
|
}
|
|
7841
7854
|
function demoRoutes(deps) {
|
|
7842
|
-
const { client, store, prompts } = deps;
|
|
7855
|
+
const { client, store, config: config2, prompts } = deps;
|
|
7843
7856
|
const app = new Hono();
|
|
7844
|
-
|
|
7857
|
+
const demoOrigins = config2.server?.allowedOrigins ?? [];
|
|
7858
|
+
app.get("/api/demo/session", checkDemoOrigin(demoOrigins), limitSessionCreation(), (c) => {
|
|
7845
7859
|
const session = createSession({
|
|
7846
7860
|
maxRequests: 20,
|
|
7847
7861
|
ttl: 3600
|
|
@@ -8188,12 +8202,10 @@ function publicRoutes(deps) {
|
|
|
8188
8202
|
const app = new Hono3();
|
|
8189
8203
|
const requirePublicKey = createAuthMiddleware(deps);
|
|
8190
8204
|
const { limitPublic: limitPublic2 } = createRateLimiter(config2);
|
|
8205
|
+
const referrerOrigins = config2.server?.allowedOrigins?.length ? config2.server.allowedOrigins.filter((o) => o !== "*") : [config2.bot.publicUrl, "http://localhost:8181", "http://127.0.0.1:8181"];
|
|
8191
8206
|
app.use("/api/public/*", validateSessionKey());
|
|
8192
8207
|
app.use("/api/public/*", requirePublicKey);
|
|
8193
|
-
app.use(
|
|
8194
|
-
"/api/public/*",
|
|
8195
|
-
requireReferrer([config2.bot.publicUrl, "http://localhost:8181", "http://127.0.0.1:8181"])
|
|
8196
|
-
);
|
|
8208
|
+
app.use("/api/public/*", requireReferrer(referrerOrigins));
|
|
8197
8209
|
app.use("/api/public/*", limitPublic2());
|
|
8198
8210
|
app.post("/api/public/chat", async (c) => {
|
|
8199
8211
|
const body = await c.req.json().catch(() => ({}));
|
|
@@ -8267,7 +8279,7 @@ async function createServer(config2) {
|
|
|
8267
8279
|
}
|
|
8268
8280
|
const app = new Hono4();
|
|
8269
8281
|
if (config2.server?.cors !== false) {
|
|
8270
|
-
app.use("*", cors());
|
|
8282
|
+
app.use("*", cors(config2.server?.allowedOrigins));
|
|
8271
8283
|
}
|
|
8272
8284
|
app.get("/healthz", (c) => c.text("ok"));
|
|
8273
8285
|
app.get(
|
|
@@ -1,3 +1,10 @@
|
|
|
1
1
|
import type { Context, Next } from "hono";
|
|
2
|
-
|
|
2
|
+
/**
|
|
3
|
+
* CORS middleware that validates requests against allowed origins.
|
|
4
|
+
*
|
|
5
|
+
* @param allowedOrigins - Array of permitted origins. When the array contains
|
|
6
|
+
* `"*"` (or is empty/undefined), all origins are allowed. Otherwise only
|
|
7
|
+
* the listed origins receive CORS headers.
|
|
8
|
+
*/
|
|
9
|
+
export declare const cors: (allowedOrigins?: string[]) => (c: Context, next: Next) => Promise<Response | undefined>;
|
|
3
10
|
//# sourceMappingURL=cors.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cors.d.ts","sourceRoot":"","sources":["../../src/middleware/cors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"cors.d.ts","sourceRoot":"","sources":["../../src/middleware/cors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAK1C;;;;;;GAMG;AACH,eAAO,MAAM,IAAI,GAAI,iBAAiB,MAAM,EAAE,MAAY,GAAG,OAAO,EAAE,MAAM,IAAI,kCAyB/E,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"demo.d.ts","sourceRoot":"","sources":["../../src/routes/demo.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAI5B,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"demo.d.ts","sourceRoot":"","sources":["../../src/routes/demo.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAI5B,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAsHnD,wBAAgB,UAAU,CAAC,IAAI,EAAE,kBAAkB,8EAqGlD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"public.d.ts","sourceRoot":"","sources":["../../src/routes/public.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAO5B,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AASnD,wBAAgB,YAAY,CAAC,IAAI,EAAE,kBAAkB,
|
|
1
|
+
{"version":3,"file":"public.d.ts","sourceRoot":"","sources":["../../src/routes/public.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAO5B,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AASnD,wBAAgB,YAAY,CAAC,IAAI,EAAE,kBAAkB,8EAkEpD"}
|
package/dist/types.d.ts
CHANGED
|
@@ -121,6 +121,15 @@ export interface ChatterConfig {
|
|
|
121
121
|
port?: number;
|
|
122
122
|
/** Enable CORS. Default: true */
|
|
123
123
|
cors?: boolean;
|
|
124
|
+
/**
|
|
125
|
+
* Allowed origins for CORS and referrer checks.
|
|
126
|
+
* Requests from these domains will be permitted.
|
|
127
|
+
*
|
|
128
|
+
* @example ["https://myapp.com", "https://staging.myapp.com"]
|
|
129
|
+
*
|
|
130
|
+
* When not set, defaults to `["*"]` (all origins allowed).
|
|
131
|
+
*/
|
|
132
|
+
allowedOrigins?: string[];
|
|
124
133
|
};
|
|
125
134
|
/** Custom route handler for advanced use cases */
|
|
126
135
|
customRoutes?: (app: Hono, deps: ServerDependencies) => void;
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@diegoaltoworks/chatter",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.0",
|
|
4
4
|
"description": "Embeddable AI chatbot framework with RAG, authentication, and customizable widgets",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
7
7
|
"types": "./dist/index.d.ts",
|
|
8
8
|
"bin": {
|
|
9
|
-
"chatter": "./bin/create-apikey.
|
|
9
|
+
"chatter": "./dist/bin/create-apikey.js"
|
|
10
10
|
},
|
|
11
11
|
"exports": {
|
|
12
12
|
".": {
|
|
@@ -30,15 +30,16 @@
|
|
|
30
30
|
"require": "./dist/mcp-server.js"
|
|
31
31
|
}
|
|
32
32
|
},
|
|
33
|
-
"files": ["dist", "
|
|
33
|
+
"files": ["dist", "README.md", "LICENSE"],
|
|
34
34
|
"scripts": {
|
|
35
35
|
"dev": "bun --watch src/index.ts",
|
|
36
|
-
"build": "bun run build:clean && bun run build:types && bun run build:esm && bun run build:cjs && bun run build:mcp && bun run build:client && bun run build:copy-client",
|
|
36
|
+
"build": "bun run build:clean && bun run build:types && bun run build:esm && bun run build:cjs && bun run build:mcp && bun run build:bin && bun run build:client && bun run build:copy-client",
|
|
37
37
|
"build:clean": "rm -rf dist",
|
|
38
38
|
"build:types": "tsc --emitDeclarationOnly --outDir dist",
|
|
39
39
|
"build:esm": "esbuild src/index.ts --bundle --format=esm --outfile=dist/index.mjs --external:hono --external:openai --external:@libsql/client --external:jose --platform=node --target=node24",
|
|
40
40
|
"build:cjs": "esbuild src/index.ts --bundle --format=cjs --outfile=dist/index.js --external:hono --external:openai --external:@libsql/client --external:jose --platform=node --target=node24",
|
|
41
41
|
"build:mcp": "esbuild src/mcp-server.ts --bundle --format=esm --outfile=dist/mcp-server.mjs --external:@modelcontextprotocol/sdk --external:openai --external:@libsql/client --external:zod --platform=node --target=node24 && esbuild src/mcp-server.ts --bundle --format=cjs --outfile=dist/mcp-server.js --external:@modelcontextprotocol/sdk --external:openai --external:@libsql/client --external:zod --platform=node --target=node24",
|
|
42
|
+
"build:bin": "esbuild bin/create-apikey.ts --bundle --format=cjs --outfile=dist/bin/create-apikey.js --external:jose --platform=node --target=node18 --banner:js='#!/usr/bin/env node'",
|
|
42
43
|
"build:client": "cd src/client && bun run build",
|
|
43
44
|
"build:copy-client": "mkdir -p dist/static && cp src/client/dist/chatter.js src/client/dist/chatter.css dist/static/",
|
|
44
45
|
"test": "bun test",
|
package/bin/create-apikey.ts
DELETED
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* CLI tool for creating Chatter API keys
|
|
4
|
-
*
|
|
5
|
-
* Usage:
|
|
6
|
-
* npx chatter create-apikey --name "my-key" --expires-in 365d
|
|
7
|
-
* bun run bin/create-apikey.ts --name "test" --expires-in 1y
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
import { ApiKeyManager } from "../src/auth/apikeys";
|
|
11
|
-
|
|
12
|
-
async function main() {
|
|
13
|
-
// Parse command line arguments
|
|
14
|
-
const args = process.argv.slice(2);
|
|
15
|
-
const options: { name?: string; expiresIn?: string } = {};
|
|
16
|
-
|
|
17
|
-
for (let i = 0; i < args.length; i++) {
|
|
18
|
-
if (args[i] === "--name" && args[i + 1]) {
|
|
19
|
-
options.name = args[i + 1];
|
|
20
|
-
i++;
|
|
21
|
-
} else if (args[i] === "--expires-in" && args[i + 1]) {
|
|
22
|
-
options.expiresIn = args[i + 1];
|
|
23
|
-
i++;
|
|
24
|
-
} else if (args[i] === "--help" || args[i] === "-h") {
|
|
25
|
-
console.log(`
|
|
26
|
-
Chatter API Key Generator
|
|
27
|
-
|
|
28
|
-
Usage:
|
|
29
|
-
npx chatter create-apikey [options]
|
|
30
|
-
|
|
31
|
-
Options:
|
|
32
|
-
--name <name> Name/label for the API key (default: "api-key")
|
|
33
|
-
--expires-in <time> Expiration time (default: "365d")
|
|
34
|
-
Formats: s=seconds, m=minutes, h=hours, d=days, M=months, y=years
|
|
35
|
-
Examples: 30d, 12h, 1y, 6M
|
|
36
|
-
|
|
37
|
-
Environment:
|
|
38
|
-
CHATTER_SECRET Required. Secret key for signing JWT tokens
|
|
39
|
-
|
|
40
|
-
Examples:
|
|
41
|
-
npx chatter create-apikey --name "mobile-app" --expires-in 365d
|
|
42
|
-
npx chatter create-apikey --name "test-key" --expires-in 1h
|
|
43
|
-
`);
|
|
44
|
-
process.exit(0);
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// Check for CHATTER_SECRET
|
|
49
|
-
const secret = process.env.CHATTER_SECRET;
|
|
50
|
-
if (!secret) {
|
|
51
|
-
console.error("❌ Error: CHATTER_SECRET environment variable is not set");
|
|
52
|
-
console.error("\n Please set it before running this command:");
|
|
53
|
-
console.error(" export CHATTER_SECRET=your-secret-key-here");
|
|
54
|
-
console.error("\n Or prefix the command:");
|
|
55
|
-
console.error(" CHATTER_SECRET=your-secret npx chatter create-apikey\n");
|
|
56
|
-
process.exit(1);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
// Create API key manager
|
|
60
|
-
const manager = new ApiKeyManager(secret);
|
|
61
|
-
|
|
62
|
-
// Default values
|
|
63
|
-
const keyName = options.name || "api-key";
|
|
64
|
-
const expiresIn = options.expiresIn || "365d";
|
|
65
|
-
|
|
66
|
-
try {
|
|
67
|
-
// Create the API key
|
|
68
|
-
const apiKey = await manager.create({
|
|
69
|
-
name: keyName,
|
|
70
|
-
expiresIn,
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
// Decode to show details (without verification for display)
|
|
74
|
-
const payload = manager.decode(apiKey);
|
|
75
|
-
if (!payload) {
|
|
76
|
-
throw new Error("Failed to decode generated API key");
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
const expiresAt = new Date((payload.exp || 0) * 1000);
|
|
80
|
-
const issuedAt = new Date((payload.iat || 0) * 1000);
|
|
81
|
-
|
|
82
|
-
// Output the result
|
|
83
|
-
console.log("\n✅ API Key generated successfully!\n");
|
|
84
|
-
console.log(` Name: ${keyName}`);
|
|
85
|
-
console.log(` ID: ${payload.sub}`);
|
|
86
|
-
console.log(` Issued: ${issuedAt.toISOString()}`);
|
|
87
|
-
console.log(` Expires: ${expiresAt.toISOString()} (${expiresIn})`);
|
|
88
|
-
console.log(`\n API Key:\n ${apiKey}\n`);
|
|
89
|
-
console.log(" Usage:");
|
|
90
|
-
console.log(" curl -X POST https://your-bot.example.com/api/public/chat \\");
|
|
91
|
-
console.log(` -H "x-api-key: ${apiKey.slice(0, 50)}..." \\`);
|
|
92
|
-
console.log(' -H "Content-Type: application/json" \\');
|
|
93
|
-
console.log(' -d \'{"message": "Hello"}\'');
|
|
94
|
-
console.log("");
|
|
95
|
-
} catch (error) {
|
|
96
|
-
console.error("❌ Error creating API key:", error);
|
|
97
|
-
process.exit(1);
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
main();
|