@surf-ai/sdk 0.1.6-beta → 1.0.0-alpha.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.
@@ -1,26 +1,35 @@
1
1
  import {
2
2
  __require,
3
3
  get,
4
- post
5
- } from "../chunk-J4OMYO3F.js";
4
+ post,
5
+ readAdminApiKey
6
+ } from "../chunk-4NA3GKVD.js";
6
7
 
7
8
  // src/server/runtime.ts
8
9
  import express from "express";
9
10
  import cors from "cors";
10
11
  import fs from "fs";
11
12
  import path from "path";
12
- import { createProxyMiddleware, responseInterceptor } from "http-proxy-middleware";
13
13
  import { Cron } from "croner";
14
+ function requireBearerAuth(req, res, next) {
15
+ const apiKey = readAdminApiKey();
16
+ if (!apiKey) {
17
+ return res.status(503).json({ error: "SURF_API_KEY is not configured" });
18
+ }
19
+ if (req.headers.authorization !== `Bearer ${apiKey}`) {
20
+ return res.status(401).json({ error: "Unauthorized" });
21
+ }
22
+ next();
23
+ }
14
24
  function createServer(options = {}) {
15
- const port = options.port || parseInt(process.env.PORT || "3001", 10);
25
+ const port = options.port ?? (process.env.PORT ? Number.parseInt(process.env.PORT, 10) : void 0);
26
+ if (!Number.isInteger(port)) {
27
+ throw new Error("createServer requires a port via options.port or process.env.PORT");
28
+ }
16
29
  const routesDir = options.routesDir || path.join(process.cwd(), "routes");
17
30
  const cronDir = options.cronDir || process.cwd();
18
- const enableProxy = options.proxy !== false;
19
31
  const app = express();
20
32
  app.use(cors());
21
- if (enableProxy) {
22
- setupProxy(app, port);
23
- }
24
33
  app.use(express.json());
25
34
  app.get("/api/health", (_req, res) => {
26
35
  res.json({ status: "ok" });
@@ -30,12 +39,13 @@ function createServer(options = {}) {
30
39
  if (!file.endsWith(".js") && !file.endsWith(".ts")) continue;
31
40
  const name = file.replace(/\.(js|ts)$/, "");
32
41
  try {
33
- const route = __require(path.join(routesDir, file));
34
- const handler = route.default || route;
42
+ const handler = __require(path.join(routesDir, file));
35
43
  if (typeof handler === "function") {
36
44
  app.use(`/api/${name}`, handler);
37
45
  console.log(`Route registered: /api/${name}`);
46
+ continue;
38
47
  }
48
+ throw new Error(`Route module must export a handler function via module.exports`);
39
49
  } catch (err) {
40
50
  console.error(`Failed to load route ${file}: ${err.message}`);
41
51
  }
@@ -59,51 +69,6 @@ function createServer(options = {}) {
59
69
  }
60
70
  };
61
71
  }
62
- function env(surfName, legacyName) {
63
- return process.env[surfName] || process.env[legacyName];
64
- }
65
- function setupProxy(app, port) {
66
- const gatewayUrl = env("SURF_DEPLOYED_GATEWAY_URL", "GATEWAY_URL");
67
- const appToken = env("SURF_DEPLOYED_APP_TOKEN", "APP_TOKEN");
68
- const proxyBase = env("SURF_SANDBOX_PROXY_BASE", "DATA_PROXY_BASE");
69
- const isDeployed = Boolean(gatewayUrl && appToken);
70
- const bufferResponse = responseInterceptor(async (buf) => buf);
71
- if (isDeployed) {
72
- app.use("/proxy", createProxyMiddleware({
73
- target: gatewayUrl,
74
- changeOrigin: true,
75
- selfHandleResponse: true,
76
- pathRewrite: (p) => "/gateway/v1" + p,
77
- headers: {
78
- Authorization: `Bearer ${appToken}`,
79
- "Accept-Encoding": "identity"
80
- },
81
- on: { proxyRes: bufferResponse }
82
- }));
83
- const loopback = `http://127.0.0.1:${port}/proxy`;
84
- process.env.SURF_SANDBOX_PROXY_BASE = loopback;
85
- process.env.DATA_PROXY_BASE = loopback;
86
- } else if (proxyBase) {
87
- const target = proxyBase.replace(/\/proxy$/, "");
88
- app.use(createProxyMiddleware({
89
- target,
90
- changeOrigin: true,
91
- pathFilter: "/proxy",
92
- on: {
93
- proxyReq: (proxyReq, req) => {
94
- console.log(`[proxy] >> ${req.method} ${req.originalUrl}`);
95
- },
96
- proxyRes: (proxyRes, req) => {
97
- console.log(`[proxy] << ${proxyRes.statusCode} ${req.method} ${req.originalUrl}`);
98
- },
99
- error: (err, req, res) => {
100
- console.error(`[proxy] !! ${req.method} ${req.originalUrl} error: ${err.message}`);
101
- if (!res.headersSent) res.status(502).json({ error: err.message });
102
- }
103
- }
104
- }));
105
- }
106
- }
107
72
  var schemaSync = { run: async () => {
108
73
  }, watch: () => {
109
74
  } };
@@ -143,7 +108,7 @@ function setupSchemaSync(app, schemaDir) {
143
108
  (t) => t && typeof t === "object" && /* @__PURE__ */ Symbol.for("drizzle:Name") in t
144
109
  );
145
110
  if (tables.length === 0) return;
146
- const { get: dbGet, post: dbPost } = await import("../client-3YMIRPDV.js");
111
+ const { get: dbGet, post: dbPost } = await import("../client-Z45B2GYT.js");
147
112
  await dbPost("db/provision");
148
113
  const existing = (await dbGet("db/tables")).map((t) => t.name);
149
114
  const missing = tables.filter((t) => !existing.includes(getTableConfig(t).name));
@@ -207,7 +172,7 @@ function setupSchemaSync(app, schemaDir) {
207
172
  }
208
173
  console.error("DB schema sync failed after all retries");
209
174
  }
210
- app.post("/api/__sync-schema", async (_req, res) => {
175
+ app.post("/api/__sync-schema", requireBearerAuth, async (_req, res) => {
211
176
  try {
212
177
  await syncWithRetry(2, 1500);
213
178
  res.json({ ok: true });
@@ -311,16 +276,7 @@ function setupCron(app, cronDir) {
311
276
  console.log(`Cron registered: [${task.id}] ${task.name} (${task.schedule})`);
312
277
  }
313
278
  }
314
- const envFn = (s, l) => process.env[s] || process.env[l];
315
- app.use("/api/cron", (req, res, next) => {
316
- const appToken = envFn("SURF_DEPLOYED_APP_TOKEN", "APP_TOKEN");
317
- if (!appToken) return next();
318
- const auth = req.headers.authorization;
319
- if (!auth || auth !== `Bearer ${appToken}`) {
320
- return res.status(401).json({ error: "Unauthorized" });
321
- }
322
- next();
323
- });
279
+ app.use("/api/cron", requireBearerAuth);
324
280
  app.get("/api/cron", (_req, res) => {
325
281
  res.json(cronTasks.map((t) => {
326
282
  const state = cronState.get(t.id) || { lastRunAt: null, lastStatus: null, lastError: null };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@surf-ai/sdk",
3
- "version": "0.1.6-beta",
4
- "description": "Surf platform SDK — data API client, server runtime, React hooks, and database helpers",
3
+ "version": "1.0.0-alpha.0",
4
+ "description": "Surf platform SDK — data API client, server runtime, and database helpers",
5
5
  "type": "module",
6
6
  "exports": {
7
7
  "./server": {
@@ -9,20 +9,14 @@
9
9
  "import": "./dist/server/index.js",
10
10
  "require": "./dist/server/index.cjs"
11
11
  },
12
- "./react": {
13
- "types": "./dist/react/index.d.ts",
14
- "import": "./dist/react/index.js"
15
- },
16
12
  "./db": {
17
13
  "types": "./dist/db/index.d.ts",
18
14
  "import": "./dist/db/index.js",
19
15
  "require": "./dist/db/index.cjs"
20
- },
21
- "./theme.css": "./src/theme/index.css"
16
+ }
22
17
  },
23
18
  "files": [
24
- "dist",
25
- "src/theme"
19
+ "dist"
26
20
  ],
27
21
  "scripts": {
28
22
  "build": "tsup",
@@ -33,30 +27,13 @@
33
27
  "dependencies": {
34
28
  "express": "^4.22.0",
35
29
  "cors": "^2.8.5",
36
- "http-proxy-middleware": "^3.0.0",
37
30
  "croner": "^9.0.0",
38
- "drizzle-orm": "^0.44.0",
39
- "@tanstack/react-query": "^5.94.0",
40
- "clsx": "^2.1.0",
41
- "tailwind-merge": "^2.6.0"
42
- },
43
- "peerDependencies": {
44
- "react": "^19.0.0",
45
- "react-dom": "^19.0.0"
46
- },
47
- "peerDependenciesMeta": {
48
- "react": {
49
- "optional": true
50
- },
51
- "react-dom": {
52
- "optional": true
53
- }
31
+ "drizzle-orm": "^0.44.0"
54
32
  },
55
33
  "devDependencies": {
56
34
  "tsup": "^8.0.0",
57
35
  "typescript": "^5.9.0",
58
36
  "@types/express": "^5.0.0",
59
- "@types/cors": "^2.8.0",
60
- "@types/react": "^19.0.0"
37
+ "@types/cors": "^2.8.0"
61
38
  }
62
39
  }
@@ -1,70 +0,0 @@
1
- var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
2
- get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
3
- }) : x)(function(x) {
4
- if (typeof require !== "undefined") return require.apply(this, arguments);
5
- throw Error('Dynamic require of "' + x + '" is not supported');
6
- });
7
-
8
- // src/data/client.ts
9
- var DEFAULT_PUBLIC_URL = "https://api.ask.surf/gateway/v1";
10
- function env(surfName, legacyName) {
11
- return process.env[surfName] || process.env[legacyName];
12
- }
13
- function resolveConfig() {
14
- const proxyBase = env("SURF_SANDBOX_PROXY_BASE", "DATA_PROXY_BASE");
15
- if (proxyBase) {
16
- return { baseUrl: proxyBase, headers: {} };
17
- }
18
- const gatewayUrl = env("SURF_DEPLOYED_GATEWAY_URL", "GATEWAY_URL");
19
- const appToken = env("SURF_DEPLOYED_APP_TOKEN", "APP_TOKEN");
20
- if (gatewayUrl && appToken) {
21
- return {
22
- baseUrl: `${gatewayUrl.replace(/\/$/, "")}/gateway/v1`,
23
- headers: { Authorization: `Bearer ${appToken}` }
24
- };
25
- }
26
- return { baseUrl: DEFAULT_PUBLIC_URL, headers: {} };
27
- }
28
- function normalizePath(path) {
29
- return String(path || "").replace(/^\/+/, "").replace(/^(?:proxy\/)+/, "");
30
- }
31
- async function fetchJson(url, init, retries = 1) {
32
- for (let attempt = 0; attempt <= retries; attempt++) {
33
- const res = await fetch(url, init);
34
- if (!res.ok) {
35
- const text2 = await res.text();
36
- throw new Error(`API error ${res.status}: ${text2.slice(0, 200)}`);
37
- }
38
- const text = await res.text();
39
- if (text) return JSON.parse(text);
40
- if (attempt < retries) await new Promise((r) => setTimeout(r, 1e3));
41
- }
42
- throw new Error(`Empty response from ${url}`);
43
- }
44
- async function get(path, params) {
45
- const config = resolveConfig();
46
- const cleaned = {};
47
- if (params) {
48
- for (const [k, v] of Object.entries(params)) {
49
- if (v != null) cleaned[k] = String(v);
50
- }
51
- }
52
- const qs = Object.keys(cleaned).length ? "?" + new URLSearchParams(cleaned).toString() : "";
53
- return fetchJson(`${config.baseUrl}/${normalizePath(path)}${qs}`, {
54
- headers: config.headers
55
- });
56
- }
57
- async function post(path, body) {
58
- const config = resolveConfig();
59
- return fetchJson(`${config.baseUrl}/${normalizePath(path)}`, {
60
- method: "POST",
61
- headers: { ...config.headers, "Content-Type": "application/json" },
62
- body: body ? JSON.stringify(body) : void 0
63
- });
64
- }
65
-
66
- export {
67
- __require,
68
- get,
69
- post
70
- };