@studioindia/designx 1.0.2 → 1.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.
package/server.cjs CHANGED
@@ -46216,7 +46216,7 @@ var __dirname = import_node_path.default.dirname(__filename);
46216
46216
  var app = (0, import_express.default)();
46217
46217
  var IS_PROD = process.env.NODE_ENV === "production";
46218
46218
  var PORT = parseInt(process.env.PORT ?? "3001", 10);
46219
- var DESIGNX_DATA_DIR = process.env.DESIGNX_DATA_DIR ?? import_node_path.default.join((0, import_node_os.homedir)(), ".designx");
46219
+ var DESIGNX_DATA_DIR = process.env.DESIGNX_DATA_DIR ?? import_node_path.default.join((0, import_node_os.homedir)(), "DesignX");
46220
46220
  var DIST_DIR = import_node_path.default.join(__dirname, IS_PROD ? "dist" : "../dist");
46221
46221
  var COPILOT_API_URL = "https://api.githubcopilot.com";
46222
46222
  var AUTO_PINNED_MODEL = "claude-sonnet-4.6";
@@ -47727,6 +47727,276 @@ app.get("/api/data/projects/:slug/export", (req, res) => {
47727
47727
  res.status(500).json({ error: String(err) });
47728
47728
  }
47729
47729
  });
47730
+ var AUTH_FILE = import_node_path.default.join(DESIGNX_DATA_DIR, "auth.json");
47731
+ app.get("/api/auth", (_req, res) => {
47732
+ try {
47733
+ if (!import_node_fs.default.existsSync(AUTH_FILE)) {
47734
+ res.json({});
47735
+ return;
47736
+ }
47737
+ res.json(readJson(AUTH_FILE, {}));
47738
+ } catch {
47739
+ res.json({});
47740
+ }
47741
+ });
47742
+ app.put("/api/auth", (req, res) => {
47743
+ try {
47744
+ writeJson(AUTH_FILE, req.body);
47745
+ try {
47746
+ import_node_fs.default.chmodSync(AUTH_FILE, 384);
47747
+ } catch {
47748
+ }
47749
+ res.json({ ok: true });
47750
+ } catch (err) {
47751
+ res.status(500).json({ error: String(err) });
47752
+ }
47753
+ });
47754
+ app.delete("/api/auth", (_req, res) => {
47755
+ try {
47756
+ if (import_node_fs.default.existsSync(AUTH_FILE)) import_node_fs.default.unlinkSync(AUTH_FILE);
47757
+ res.json({ ok: true });
47758
+ } catch (err) {
47759
+ res.status(500).json({ error: String(err) });
47760
+ }
47761
+ });
47762
+ var TOKEN_STATS_FILE = import_node_path.default.join(KB_JOBS_DIR, "token-stats.json");
47763
+ app.get("/api/data/token-stats", (_req, res) => {
47764
+ try {
47765
+ if (!import_node_fs.default.existsSync(TOKEN_STATS_FILE)) {
47766
+ res.json(null);
47767
+ return;
47768
+ }
47769
+ res.json(readJson(TOKEN_STATS_FILE, null));
47770
+ } catch {
47771
+ res.json(null);
47772
+ }
47773
+ });
47774
+ app.put("/api/data/token-stats", (req, res) => {
47775
+ try {
47776
+ writeJson(TOKEN_STATS_FILE, req.body);
47777
+ res.json({ ok: true });
47778
+ } catch (err) {
47779
+ res.status(500).json({ error: String(err) });
47780
+ }
47781
+ });
47782
+ app.get("/api/kb/:slug/context", (req, res) => {
47783
+ const { slug } = req.params;
47784
+ if (!safeSlug(slug)) {
47785
+ res.status(400).json({ error: "Invalid slug" });
47786
+ return;
47787
+ }
47788
+ try {
47789
+ const uploadDir = import_node_path.default.join(projectDir(slug), "uploads");
47790
+ if (!import_node_fs.default.existsSync(uploadDir)) {
47791
+ res.json({ entries: [], totalChars: 0 });
47792
+ return;
47793
+ }
47794
+ const TEXT_EXTS = /* @__PURE__ */ new Set([
47795
+ ".txt",
47796
+ ".md",
47797
+ ".mdx",
47798
+ ".json",
47799
+ ".yaml",
47800
+ ".yml",
47801
+ ".csv",
47802
+ ".html",
47803
+ ".htm",
47804
+ ".xml",
47805
+ ".js",
47806
+ ".ts",
47807
+ ".jsx",
47808
+ ".tsx",
47809
+ ".py",
47810
+ ".java",
47811
+ ".cs",
47812
+ ".go",
47813
+ ".rs",
47814
+ ".rb",
47815
+ ".php",
47816
+ ".sh",
47817
+ ".bash",
47818
+ ".zsh",
47819
+ ".env",
47820
+ ".conf",
47821
+ ".ini",
47822
+ ".toml"
47823
+ ]);
47824
+ const PER_FILE_CAP = 8e4;
47825
+ const TOTAL_CAP = 2e5;
47826
+ let totalChars = 0;
47827
+ const entries = [];
47828
+ for (const name of import_node_fs.default.readdirSync(uploadDir)) {
47829
+ if (totalChars >= TOTAL_CAP) break;
47830
+ const filePath = import_node_path.default.join(uploadDir, name);
47831
+ if (import_node_fs.default.statSync(filePath).isDirectory()) continue;
47832
+ const ext = import_node_path.default.extname(name).toLowerCase();
47833
+ if (ext && !TEXT_EXTS.has(ext)) continue;
47834
+ try {
47835
+ const raw = import_node_fs.default.readFileSync(filePath, "utf8");
47836
+ const limit = Math.min(PER_FILE_CAP, TOTAL_CAP - totalChars);
47837
+ const truncated = raw.length > limit;
47838
+ const content = truncated ? raw.slice(0, limit) : raw;
47839
+ entries.push({ name, content, truncated });
47840
+ totalChars += content.length;
47841
+ } catch {
47842
+ }
47843
+ }
47844
+ res.json({ entries, totalChars });
47845
+ } catch (err) {
47846
+ res.status(500).json({ error: String(err) });
47847
+ }
47848
+ });
47849
+ app.post("/api/byok/chat", async (req, res) => {
47850
+ const provider = req.headers["x-byok-provider"];
47851
+ const apiKey = req.headers["x-byok-key"];
47852
+ if (typeof provider !== "string" || typeof apiKey !== "string" || !provider || !apiKey) {
47853
+ res.status(400).json({ error: "x-byok-provider and x-byok-key headers required." });
47854
+ return;
47855
+ }
47856
+ if (provider !== "openai" && provider !== "anthropic") {
47857
+ res.status(400).json({ error: 'x-byok-provider must be "openai" or "anthropic".' });
47858
+ return;
47859
+ }
47860
+ const body = req.body;
47861
+ try {
47862
+ if (provider === "openai") {
47863
+ const upstream2 = await fetch("https://api.openai.com/v1/chat/completions", {
47864
+ method: "POST",
47865
+ headers: { "Content-Type": "application/json", Authorization: `Bearer ${apiKey}` },
47866
+ body: JSON.stringify(body),
47867
+ signal: AbortSignal.timeout(12e4)
47868
+ });
47869
+ res.status(upstream2.status);
47870
+ const ct = upstream2.headers.get("content-type");
47871
+ if (ct) res.setHeader("Content-Type", ct);
47872
+ if (!upstream2.body) {
47873
+ res.end();
47874
+ return;
47875
+ }
47876
+ const reader2 = upstream2.body.getReader();
47877
+ while (true) {
47878
+ const { done, value } = await reader2.read();
47879
+ if (done) {
47880
+ res.end();
47881
+ break;
47882
+ }
47883
+ res.write(Buffer.from(value));
47884
+ }
47885
+ return;
47886
+ }
47887
+ const inMessages = body.messages ?? [];
47888
+ const sysMsg = inMessages.find((m) => m.role === "system");
47889
+ const chatMsgs = inMessages.filter((m) => m.role !== "system");
47890
+ const anthropicBody = {
47891
+ model: body.model ?? "claude-3-5-sonnet-20241022",
47892
+ messages: chatMsgs,
47893
+ max_tokens: body.max_tokens ?? 4096,
47894
+ stream: true
47895
+ };
47896
+ if (sysMsg) anthropicBody.system = sysMsg.content;
47897
+ const upstream = await fetch("https://api.anthropic.com/v1/messages", {
47898
+ method: "POST",
47899
+ headers: {
47900
+ "Content-Type": "application/json",
47901
+ "x-api-key": apiKey,
47902
+ "anthropic-version": "2023-06-01"
47903
+ },
47904
+ body: JSON.stringify(anthropicBody)
47905
+ });
47906
+ if (!upstream.ok) {
47907
+ const errText = await upstream.text().catch(() => "");
47908
+ res.status(upstream.status).json({ error: errText.slice(0, 500) });
47909
+ return;
47910
+ }
47911
+ res.setHeader("Content-Type", "text/event-stream");
47912
+ res.setHeader("Cache-Control", "no-cache");
47913
+ res.setHeader("Connection", "keep-alive");
47914
+ if (!upstream.body) {
47915
+ res.end();
47916
+ return;
47917
+ }
47918
+ const reader = upstream.body.getReader();
47919
+ const decoder = new TextDecoder();
47920
+ let sseBuffer = "";
47921
+ const msgId = (0, import_node_crypto.randomUUID)();
47922
+ const modelId = String(body.model ?? "anthropic");
47923
+ while (true) {
47924
+ const { done, value } = await reader.read();
47925
+ if (done) {
47926
+ res.write("data: [DONE]\n\n");
47927
+ res.end();
47928
+ break;
47929
+ }
47930
+ sseBuffer += decoder.decode(value, { stream: true });
47931
+ const lines = sseBuffer.split("\n");
47932
+ sseBuffer = lines.pop() ?? "";
47933
+ for (const line of lines) {
47934
+ if (!line.startsWith("data: ")) continue;
47935
+ const raw = line.slice(6).trim();
47936
+ if (raw === "" || raw === "[DONE]") continue;
47937
+ try {
47938
+ const evt = JSON.parse(raw);
47939
+ if (evt.type === "content_block_delta" && evt.delta?.type === "text_delta" && evt.delta.text) {
47940
+ res.write(`data: ${JSON.stringify({ id: msgId, object: "chat.completion.chunk", model: modelId, choices: [{ index: 0, delta: { content: evt.delta.text }, finish_reason: null }] })}
47941
+
47942
+ `);
47943
+ } else if (evt.type === "message_delta" && evt.usage) {
47944
+ const outTok = evt.usage.output_tokens ?? 0;
47945
+ res.write(`data: ${JSON.stringify({ id: msgId, object: "chat.completion.chunk", model: modelId, choices: [{ index: 0, delta: {}, finish_reason: "stop" }], usage: { prompt_tokens: 0, completion_tokens: outTok, total_tokens: outTok } })}
47946
+
47947
+ `);
47948
+ }
47949
+ } catch {
47950
+ }
47951
+ }
47952
+ }
47953
+ } catch (err) {
47954
+ if (!res.headersSent) {
47955
+ res.status(502).json({ error: err instanceof Error ? err.message : "BYOK request failed." });
47956
+ }
47957
+ }
47958
+ });
47959
+ app.post("/api/byok/test", async (req, res) => {
47960
+ const provider = req.headers["x-byok-provider"];
47961
+ const apiKey = req.headers["x-byok-key"];
47962
+ if (typeof provider !== "string" || typeof apiKey !== "string" || !provider || !apiKey) {
47963
+ res.status(400).json({ ok: false, error: "x-byok-provider and x-byok-key headers required." });
47964
+ return;
47965
+ }
47966
+ try {
47967
+ if (provider === "openai") {
47968
+ const r = await fetch("https://api.openai.com/v1/chat/completions", {
47969
+ method: "POST",
47970
+ headers: { "Content-Type": "application/json", Authorization: `Bearer ${apiKey}` },
47971
+ body: JSON.stringify({ model: "gpt-4o-mini", messages: [{ role: "user", content: "Hi" }], max_tokens: 1, stream: false }),
47972
+ signal: AbortSignal.timeout(1e4)
47973
+ });
47974
+ if (r.ok) {
47975
+ res.json({ ok: true });
47976
+ return;
47977
+ }
47978
+ const t = await r.text().catch(() => "");
47979
+ res.json({ ok: false, error: `OpenAI ${r.status}: ${t.slice(0, 200)}` });
47980
+ } else if (provider === "anthropic") {
47981
+ const r = await fetch("https://api.anthropic.com/v1/messages", {
47982
+ method: "POST",
47983
+ headers: { "Content-Type": "application/json", "x-api-key": apiKey, "anthropic-version": "2023-06-01" },
47984
+ body: JSON.stringify({ model: "claude-3-5-haiku-20241022", messages: [{ role: "user", content: "Hi" }], max_tokens: 1, stream: false }),
47985
+ signal: AbortSignal.timeout(1e4)
47986
+ });
47987
+ if (r.ok) {
47988
+ res.json({ ok: true });
47989
+ return;
47990
+ }
47991
+ const t = await r.text().catch(() => "");
47992
+ res.json({ ok: false, error: `Anthropic ${r.status}: ${t.slice(0, 200)}` });
47993
+ } else {
47994
+ res.status(400).json({ ok: false, error: "Unknown provider." });
47995
+ }
47996
+ } catch (err) {
47997
+ res.json({ ok: false, error: err instanceof Error ? err.message : "Test failed." });
47998
+ }
47999
+ });
47730
48000
  if (IS_PROD) {
47731
48001
  app.use(import_express.default.static(DIST_DIR));
47732
48002
  app.use((_req, res) => {