@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.
- package/README.md +86 -375
- package/dist/chunk-4NA3GKVD.js +100 -0
- package/dist/{client-3YMIRPDV.js → client-Z45B2GYT.js} +1 -1
- package/dist/db/index.cjs +62 -36
- package/dist/db/index.d.cts +2 -2
- package/dist/db/index.d.ts +2 -2
- package/dist/db/index.js +62 -36
- package/dist/server/index.cjs +101 -104
- package/dist/server/index.d.cts +9 -15
- package/dist/server/index.d.ts +9 -15
- package/dist/server/index.js +23 -67
- package/package.json +6 -29
- package/dist/chunk-J4OMYO3F.js +0 -70
- package/dist/react/index.d.ts +0 -3650
- package/dist/react/index.js +0 -1175
- package/src/theme/index.css +0 -314
package/dist/db/index.cjs
CHANGED
|
@@ -28,28 +28,49 @@ __export(db_exports, {
|
|
|
28
28
|
});
|
|
29
29
|
module.exports = __toCommonJS(db_exports);
|
|
30
30
|
|
|
31
|
-
// src/
|
|
32
|
-
var
|
|
33
|
-
function
|
|
34
|
-
return
|
|
35
|
-
}
|
|
36
|
-
function
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
headers: { Authorization: `Bearer ${appToken}` }
|
|
47
|
-
};
|
|
31
|
+
// src/core/config.ts
|
|
32
|
+
var DEFAULT_API_BASE_URL = "https://api.ask.surf/gateway/v1";
|
|
33
|
+
function trimTrailingSlashes(value) {
|
|
34
|
+
return String(value || "").replace(/\/+$/, "");
|
|
35
|
+
}
|
|
36
|
+
function readSurfApiConfig() {
|
|
37
|
+
return {
|
|
38
|
+
baseUrl: trimTrailingSlashes(process.env.SURF_API_BASE_URL || DEFAULT_API_BASE_URL),
|
|
39
|
+
apiKey: process.env.SURF_API_KEY
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
function requireSurfApiConfig() {
|
|
43
|
+
const config = readSurfApiConfig();
|
|
44
|
+
if (!config.apiKey) {
|
|
45
|
+
throw new Error("SURF_API_KEY is required");
|
|
48
46
|
}
|
|
49
|
-
return { baseUrl:
|
|
47
|
+
return { baseUrl: config.baseUrl, apiKey: config.apiKey };
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// src/core/transport.ts
|
|
51
|
+
function sleep(ms) {
|
|
52
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
50
53
|
}
|
|
51
54
|
function normalizePath(path) {
|
|
52
|
-
return String(path || "").replace(/^\/+/, "")
|
|
55
|
+
return String(path || "").replace(/^\/+/, "");
|
|
56
|
+
}
|
|
57
|
+
function buildUrl(path, params) {
|
|
58
|
+
const { baseUrl } = requireSurfApiConfig();
|
|
59
|
+
const url = new URL(`${baseUrl}/${normalizePath(path)}`);
|
|
60
|
+
if (params) {
|
|
61
|
+
for (const [key, value] of Object.entries(params)) {
|
|
62
|
+
if (value != null) {
|
|
63
|
+
url.searchParams.set(key, String(value));
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return url.toString();
|
|
68
|
+
}
|
|
69
|
+
function buildHeaders(extra) {
|
|
70
|
+
const { apiKey } = requireSurfApiConfig();
|
|
71
|
+
const headers = new Headers(extra);
|
|
72
|
+
headers.set("Authorization", `Bearer ${apiKey}`);
|
|
73
|
+
return headers;
|
|
53
74
|
}
|
|
54
75
|
async function fetchJson(url, init, retries = 1) {
|
|
55
76
|
for (let attempt = 0; attempt <= retries; attempt++) {
|
|
@@ -59,33 +80,38 @@ async function fetchJson(url, init, retries = 1) {
|
|
|
59
80
|
throw new Error(`API error ${res.status}: ${text2.slice(0, 200)}`);
|
|
60
81
|
}
|
|
61
82
|
const text = await res.text();
|
|
62
|
-
if (text)
|
|
63
|
-
|
|
83
|
+
if (text) {
|
|
84
|
+
return JSON.parse(text);
|
|
85
|
+
}
|
|
86
|
+
if (attempt < retries) {
|
|
87
|
+
await sleep(1e3);
|
|
88
|
+
}
|
|
64
89
|
}
|
|
65
90
|
throw new Error(`Empty response from ${url}`);
|
|
66
91
|
}
|
|
67
|
-
async function
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
if (params) {
|
|
71
|
-
for (const [k, v] of Object.entries(params)) {
|
|
72
|
-
if (v != null) cleaned[k] = String(v);
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
const qs = Object.keys(cleaned).length ? "?" + new URLSearchParams(cleaned).toString() : "";
|
|
76
|
-
return fetchJson(`${config.baseUrl}/${normalizePath(path)}${qs}`, {
|
|
77
|
-
headers: config.headers
|
|
92
|
+
async function getJson(path, params) {
|
|
93
|
+
return fetchJson(buildUrl(path, params), {
|
|
94
|
+
headers: buildHeaders()
|
|
78
95
|
});
|
|
79
96
|
}
|
|
80
|
-
async function
|
|
81
|
-
|
|
82
|
-
return fetchJson(`${config.baseUrl}/${normalizePath(path)}`, {
|
|
97
|
+
async function postJson(path, body) {
|
|
98
|
+
return fetchJson(buildUrl(path), {
|
|
83
99
|
method: "POST",
|
|
84
|
-
headers: {
|
|
100
|
+
headers: buildHeaders({
|
|
101
|
+
"Content-Type": "application/json"
|
|
102
|
+
}),
|
|
85
103
|
body: body ? JSON.stringify(body) : void 0
|
|
86
104
|
});
|
|
87
105
|
}
|
|
88
106
|
|
|
107
|
+
// src/data/client.ts
|
|
108
|
+
async function get(path, params) {
|
|
109
|
+
return getJson(path, params);
|
|
110
|
+
}
|
|
111
|
+
async function post(path, body) {
|
|
112
|
+
return postJson(path, body);
|
|
113
|
+
}
|
|
114
|
+
|
|
89
115
|
// src/db/index.ts
|
|
90
116
|
async function dbProvision() {
|
|
91
117
|
return post("db/provision");
|
package/dist/db/index.d.cts
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* const result = await dbQuery('SELECT * FROM users WHERE id = $1', [userId])
|
|
14
14
|
*/
|
|
15
15
|
/**
|
|
16
|
-
* Provision a database for the current user via
|
|
16
|
+
* Provision a database for the current user via db/provision.
|
|
17
17
|
* Returns connection metadata. Neon auto-creates the DB if it doesn't exist.
|
|
18
18
|
*/
|
|
19
19
|
declare function dbProvision(): Promise<{
|
|
@@ -23,7 +23,7 @@ declare function dbProvision(): Promise<{
|
|
|
23
23
|
password: string;
|
|
24
24
|
}>;
|
|
25
25
|
/**
|
|
26
|
-
* Execute a SQL query via
|
|
26
|
+
* Execute a SQL query via db/query.
|
|
27
27
|
* Uses pg-proxy driver under the hood — Drizzle ORM calls this automatically.
|
|
28
28
|
*
|
|
29
29
|
* @param options.arrayMode - When true, rows are returned as positional arrays
|
package/dist/db/index.d.ts
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* const result = await dbQuery('SELECT * FROM users WHERE id = $1', [userId])
|
|
14
14
|
*/
|
|
15
15
|
/**
|
|
16
|
-
* Provision a database for the current user via
|
|
16
|
+
* Provision a database for the current user via db/provision.
|
|
17
17
|
* Returns connection metadata. Neon auto-creates the DB if it doesn't exist.
|
|
18
18
|
*/
|
|
19
19
|
declare function dbProvision(): Promise<{
|
|
@@ -23,7 +23,7 @@ declare function dbProvision(): Promise<{
|
|
|
23
23
|
password: string;
|
|
24
24
|
}>;
|
|
25
25
|
/**
|
|
26
|
-
* Execute a SQL query via
|
|
26
|
+
* Execute a SQL query via db/query.
|
|
27
27
|
* Uses pg-proxy driver under the hood — Drizzle ORM calls this automatically.
|
|
28
28
|
*
|
|
29
29
|
* @param options.arrayMode - When true, rows are returned as positional arrays
|
package/dist/db/index.js
CHANGED
|
@@ -1,25 +1,46 @@
|
|
|
1
|
-
// src/
|
|
2
|
-
var
|
|
3
|
-
function
|
|
4
|
-
return
|
|
5
|
-
}
|
|
6
|
-
function
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
headers: { Authorization: `Bearer ${appToken}` }
|
|
17
|
-
};
|
|
1
|
+
// src/core/config.ts
|
|
2
|
+
var DEFAULT_API_BASE_URL = "https://api.ask.surf/gateway/v1";
|
|
3
|
+
function trimTrailingSlashes(value) {
|
|
4
|
+
return String(value || "").replace(/\/+$/, "");
|
|
5
|
+
}
|
|
6
|
+
function readSurfApiConfig() {
|
|
7
|
+
return {
|
|
8
|
+
baseUrl: trimTrailingSlashes(process.env.SURF_API_BASE_URL || DEFAULT_API_BASE_URL),
|
|
9
|
+
apiKey: process.env.SURF_API_KEY
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
function requireSurfApiConfig() {
|
|
13
|
+
const config = readSurfApiConfig();
|
|
14
|
+
if (!config.apiKey) {
|
|
15
|
+
throw new Error("SURF_API_KEY is required");
|
|
18
16
|
}
|
|
19
|
-
return { baseUrl:
|
|
17
|
+
return { baseUrl: config.baseUrl, apiKey: config.apiKey };
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// src/core/transport.ts
|
|
21
|
+
function sleep(ms) {
|
|
22
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
20
23
|
}
|
|
21
24
|
function normalizePath(path) {
|
|
22
|
-
return String(path || "").replace(/^\/+/, "")
|
|
25
|
+
return String(path || "").replace(/^\/+/, "");
|
|
26
|
+
}
|
|
27
|
+
function buildUrl(path, params) {
|
|
28
|
+
const { baseUrl } = requireSurfApiConfig();
|
|
29
|
+
const url = new URL(`${baseUrl}/${normalizePath(path)}`);
|
|
30
|
+
if (params) {
|
|
31
|
+
for (const [key, value] of Object.entries(params)) {
|
|
32
|
+
if (value != null) {
|
|
33
|
+
url.searchParams.set(key, String(value));
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return url.toString();
|
|
38
|
+
}
|
|
39
|
+
function buildHeaders(extra) {
|
|
40
|
+
const { apiKey } = requireSurfApiConfig();
|
|
41
|
+
const headers = new Headers(extra);
|
|
42
|
+
headers.set("Authorization", `Bearer ${apiKey}`);
|
|
43
|
+
return headers;
|
|
23
44
|
}
|
|
24
45
|
async function fetchJson(url, init, retries = 1) {
|
|
25
46
|
for (let attempt = 0; attempt <= retries; attempt++) {
|
|
@@ -29,33 +50,38 @@ async function fetchJson(url, init, retries = 1) {
|
|
|
29
50
|
throw new Error(`API error ${res.status}: ${text2.slice(0, 200)}`);
|
|
30
51
|
}
|
|
31
52
|
const text = await res.text();
|
|
32
|
-
if (text)
|
|
33
|
-
|
|
53
|
+
if (text) {
|
|
54
|
+
return JSON.parse(text);
|
|
55
|
+
}
|
|
56
|
+
if (attempt < retries) {
|
|
57
|
+
await sleep(1e3);
|
|
58
|
+
}
|
|
34
59
|
}
|
|
35
60
|
throw new Error(`Empty response from ${url}`);
|
|
36
61
|
}
|
|
37
|
-
async function
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
if (params) {
|
|
41
|
-
for (const [k, v] of Object.entries(params)) {
|
|
42
|
-
if (v != null) cleaned[k] = String(v);
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
const qs = Object.keys(cleaned).length ? "?" + new URLSearchParams(cleaned).toString() : "";
|
|
46
|
-
return fetchJson(`${config.baseUrl}/${normalizePath(path)}${qs}`, {
|
|
47
|
-
headers: config.headers
|
|
62
|
+
async function getJson(path, params) {
|
|
63
|
+
return fetchJson(buildUrl(path, params), {
|
|
64
|
+
headers: buildHeaders()
|
|
48
65
|
});
|
|
49
66
|
}
|
|
50
|
-
async function
|
|
51
|
-
|
|
52
|
-
return fetchJson(`${config.baseUrl}/${normalizePath(path)}`, {
|
|
67
|
+
async function postJson(path, body) {
|
|
68
|
+
return fetchJson(buildUrl(path), {
|
|
53
69
|
method: "POST",
|
|
54
|
-
headers: {
|
|
70
|
+
headers: buildHeaders({
|
|
71
|
+
"Content-Type": "application/json"
|
|
72
|
+
}),
|
|
55
73
|
body: body ? JSON.stringify(body) : void 0
|
|
56
74
|
});
|
|
57
75
|
}
|
|
58
76
|
|
|
77
|
+
// src/data/client.ts
|
|
78
|
+
async function get(path, params) {
|
|
79
|
+
return getJson(path, params);
|
|
80
|
+
}
|
|
81
|
+
async function post(path, body) {
|
|
82
|
+
return postJson(path, body);
|
|
83
|
+
}
|
|
84
|
+
|
|
59
85
|
// src/db/index.ts
|
|
60
86
|
async function dbProvision() {
|
|
61
87
|
return post("db/provision");
|
package/dist/server/index.cjs
CHANGED
|
@@ -30,32 +30,58 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
30
30
|
));
|
|
31
31
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
32
32
|
|
|
33
|
-
// src/
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
33
|
+
// src/core/config.ts
|
|
34
|
+
function trimTrailingSlashes(value) {
|
|
35
|
+
return String(value || "").replace(/\/+$/, "");
|
|
36
|
+
}
|
|
37
|
+
function readSurfApiConfig() {
|
|
38
|
+
return {
|
|
39
|
+
baseUrl: trimTrailingSlashes(process.env.SURF_API_BASE_URL || DEFAULT_API_BASE_URL),
|
|
40
|
+
apiKey: process.env.SURF_API_KEY
|
|
41
|
+
};
|
|
41
42
|
}
|
|
42
|
-
function
|
|
43
|
-
const
|
|
44
|
-
if (
|
|
45
|
-
|
|
43
|
+
function requireSurfApiConfig() {
|
|
44
|
+
const config = readSurfApiConfig();
|
|
45
|
+
if (!config.apiKey) {
|
|
46
|
+
throw new Error("SURF_API_KEY is required");
|
|
46
47
|
}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
48
|
+
return { baseUrl: config.baseUrl, apiKey: config.apiKey };
|
|
49
|
+
}
|
|
50
|
+
function readAdminApiKey() {
|
|
51
|
+
return process.env.SURF_API_KEY;
|
|
52
|
+
}
|
|
53
|
+
var DEFAULT_API_BASE_URL;
|
|
54
|
+
var init_config = __esm({
|
|
55
|
+
"src/core/config.ts"() {
|
|
56
|
+
"use strict";
|
|
57
|
+
DEFAULT_API_BASE_URL = "https://api.ask.surf/gateway/v1";
|
|
54
58
|
}
|
|
55
|
-
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
// src/core/transport.ts
|
|
62
|
+
function sleep(ms) {
|
|
63
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
56
64
|
}
|
|
57
65
|
function normalizePath(path2) {
|
|
58
|
-
return String(path2 || "").replace(/^\/+/, "")
|
|
66
|
+
return String(path2 || "").replace(/^\/+/, "");
|
|
67
|
+
}
|
|
68
|
+
function buildUrl(path2, params) {
|
|
69
|
+
const { baseUrl } = requireSurfApiConfig();
|
|
70
|
+
const url = new URL(`${baseUrl}/${normalizePath(path2)}`);
|
|
71
|
+
if (params) {
|
|
72
|
+
for (const [key, value] of Object.entries(params)) {
|
|
73
|
+
if (value != null) {
|
|
74
|
+
url.searchParams.set(key, String(value));
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return url.toString();
|
|
79
|
+
}
|
|
80
|
+
function buildHeaders(extra) {
|
|
81
|
+
const { apiKey } = requireSurfApiConfig();
|
|
82
|
+
const headers = new Headers(extra);
|
|
83
|
+
headers.set("Authorization", `Bearer ${apiKey}`);
|
|
84
|
+
return headers;
|
|
59
85
|
}
|
|
60
86
|
async function fetchJson(url, init, retries = 1) {
|
|
61
87
|
for (let attempt = 0; attempt <= retries; attempt++) {
|
|
@@ -65,37 +91,52 @@ async function fetchJson(url, init, retries = 1) {
|
|
|
65
91
|
throw new Error(`API error ${res.status}: ${text2.slice(0, 200)}`);
|
|
66
92
|
}
|
|
67
93
|
const text = await res.text();
|
|
68
|
-
if (text)
|
|
69
|
-
|
|
94
|
+
if (text) {
|
|
95
|
+
return JSON.parse(text);
|
|
96
|
+
}
|
|
97
|
+
if (attempt < retries) {
|
|
98
|
+
await sleep(1e3);
|
|
99
|
+
}
|
|
70
100
|
}
|
|
71
101
|
throw new Error(`Empty response from ${url}`);
|
|
72
102
|
}
|
|
73
|
-
async function
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
if (params) {
|
|
77
|
-
for (const [k, v] of Object.entries(params)) {
|
|
78
|
-
if (v != null) cleaned[k] = String(v);
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
const qs = Object.keys(cleaned).length ? "?" + new URLSearchParams(cleaned).toString() : "";
|
|
82
|
-
return fetchJson(`${config.baseUrl}/${normalizePath(path2)}${qs}`, {
|
|
83
|
-
headers: config.headers
|
|
103
|
+
async function getJson(path2, params) {
|
|
104
|
+
return fetchJson(buildUrl(path2, params), {
|
|
105
|
+
headers: buildHeaders()
|
|
84
106
|
});
|
|
85
107
|
}
|
|
86
|
-
async function
|
|
87
|
-
|
|
88
|
-
return fetchJson(`${config.baseUrl}/${normalizePath(path2)}`, {
|
|
108
|
+
async function postJson(path2, body) {
|
|
109
|
+
return fetchJson(buildUrl(path2), {
|
|
89
110
|
method: "POST",
|
|
90
|
-
headers: {
|
|
111
|
+
headers: buildHeaders({
|
|
112
|
+
"Content-Type": "application/json"
|
|
113
|
+
}),
|
|
91
114
|
body: body ? JSON.stringify(body) : void 0
|
|
92
115
|
});
|
|
93
116
|
}
|
|
94
|
-
var
|
|
117
|
+
var init_transport = __esm({
|
|
118
|
+
"src/core/transport.ts"() {
|
|
119
|
+
"use strict";
|
|
120
|
+
init_config();
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
// src/data/client.ts
|
|
125
|
+
var client_exports = {};
|
|
126
|
+
__export(client_exports, {
|
|
127
|
+
get: () => get,
|
|
128
|
+
post: () => post
|
|
129
|
+
});
|
|
130
|
+
async function get(path2, params) {
|
|
131
|
+
return getJson(path2, params);
|
|
132
|
+
}
|
|
133
|
+
async function post(path2, body) {
|
|
134
|
+
return postJson(path2, body);
|
|
135
|
+
}
|
|
95
136
|
var init_client = __esm({
|
|
96
137
|
"src/data/client.ts"() {
|
|
97
138
|
"use strict";
|
|
98
|
-
|
|
139
|
+
init_transport();
|
|
99
140
|
}
|
|
100
141
|
});
|
|
101
142
|
|
|
@@ -112,18 +153,27 @@ var import_express = __toESM(require("express"), 1);
|
|
|
112
153
|
var import_cors = __toESM(require("cors"), 1);
|
|
113
154
|
var import_fs = __toESM(require("fs"), 1);
|
|
114
155
|
var import_path = __toESM(require("path"), 1);
|
|
115
|
-
var import_http_proxy_middleware = require("http-proxy-middleware");
|
|
116
156
|
var import_croner = require("croner");
|
|
157
|
+
init_config();
|
|
158
|
+
function requireBearerAuth(req, res, next) {
|
|
159
|
+
const apiKey = readAdminApiKey();
|
|
160
|
+
if (!apiKey) {
|
|
161
|
+
return res.status(503).json({ error: "SURF_API_KEY is not configured" });
|
|
162
|
+
}
|
|
163
|
+
if (req.headers.authorization !== `Bearer ${apiKey}`) {
|
|
164
|
+
return res.status(401).json({ error: "Unauthorized" });
|
|
165
|
+
}
|
|
166
|
+
next();
|
|
167
|
+
}
|
|
117
168
|
function createServer(options = {}) {
|
|
118
|
-
const port = options.port
|
|
169
|
+
const port = options.port ?? (process.env.PORT ? Number.parseInt(process.env.PORT, 10) : void 0);
|
|
170
|
+
if (!Number.isInteger(port)) {
|
|
171
|
+
throw new Error("createServer requires a port via options.port or process.env.PORT");
|
|
172
|
+
}
|
|
119
173
|
const routesDir = options.routesDir || import_path.default.join(process.cwd(), "routes");
|
|
120
174
|
const cronDir = options.cronDir || process.cwd();
|
|
121
|
-
const enableProxy = options.proxy !== false;
|
|
122
175
|
const app = (0, import_express.default)();
|
|
123
176
|
app.use((0, import_cors.default)());
|
|
124
|
-
if (enableProxy) {
|
|
125
|
-
setupProxy(app, port);
|
|
126
|
-
}
|
|
127
177
|
app.use(import_express.default.json());
|
|
128
178
|
app.get("/api/health", (_req, res) => {
|
|
129
179
|
res.json({ status: "ok" });
|
|
@@ -133,12 +183,13 @@ function createServer(options = {}) {
|
|
|
133
183
|
if (!file.endsWith(".js") && !file.endsWith(".ts")) continue;
|
|
134
184
|
const name = file.replace(/\.(js|ts)$/, "");
|
|
135
185
|
try {
|
|
136
|
-
const
|
|
137
|
-
const handler = route.default || route;
|
|
186
|
+
const handler = require(import_path.default.join(routesDir, file));
|
|
138
187
|
if (typeof handler === "function") {
|
|
139
188
|
app.use(`/api/${name}`, handler);
|
|
140
189
|
console.log(`Route registered: /api/${name}`);
|
|
190
|
+
continue;
|
|
141
191
|
}
|
|
192
|
+
throw new Error(`Route module must export a handler function via module.exports`);
|
|
142
193
|
} catch (err) {
|
|
143
194
|
console.error(`Failed to load route ${file}: ${err.message}`);
|
|
144
195
|
}
|
|
@@ -162,51 +213,6 @@ function createServer(options = {}) {
|
|
|
162
213
|
}
|
|
163
214
|
};
|
|
164
215
|
}
|
|
165
|
-
function env2(surfName, legacyName) {
|
|
166
|
-
return process.env[surfName] || process.env[legacyName];
|
|
167
|
-
}
|
|
168
|
-
function setupProxy(app, port) {
|
|
169
|
-
const gatewayUrl = env2("SURF_DEPLOYED_GATEWAY_URL", "GATEWAY_URL");
|
|
170
|
-
const appToken = env2("SURF_DEPLOYED_APP_TOKEN", "APP_TOKEN");
|
|
171
|
-
const proxyBase = env2("SURF_SANDBOX_PROXY_BASE", "DATA_PROXY_BASE");
|
|
172
|
-
const isDeployed = Boolean(gatewayUrl && appToken);
|
|
173
|
-
const bufferResponse = (0, import_http_proxy_middleware.responseInterceptor)(async (buf) => buf);
|
|
174
|
-
if (isDeployed) {
|
|
175
|
-
app.use("/proxy", (0, import_http_proxy_middleware.createProxyMiddleware)({
|
|
176
|
-
target: gatewayUrl,
|
|
177
|
-
changeOrigin: true,
|
|
178
|
-
selfHandleResponse: true,
|
|
179
|
-
pathRewrite: (p) => "/gateway/v1" + p,
|
|
180
|
-
headers: {
|
|
181
|
-
Authorization: `Bearer ${appToken}`,
|
|
182
|
-
"Accept-Encoding": "identity"
|
|
183
|
-
},
|
|
184
|
-
on: { proxyRes: bufferResponse }
|
|
185
|
-
}));
|
|
186
|
-
const loopback = `http://127.0.0.1:${port}/proxy`;
|
|
187
|
-
process.env.SURF_SANDBOX_PROXY_BASE = loopback;
|
|
188
|
-
process.env.DATA_PROXY_BASE = loopback;
|
|
189
|
-
} else if (proxyBase) {
|
|
190
|
-
const target = proxyBase.replace(/\/proxy$/, "");
|
|
191
|
-
app.use((0, import_http_proxy_middleware.createProxyMiddleware)({
|
|
192
|
-
target,
|
|
193
|
-
changeOrigin: true,
|
|
194
|
-
pathFilter: "/proxy",
|
|
195
|
-
on: {
|
|
196
|
-
proxyReq: (proxyReq, req) => {
|
|
197
|
-
console.log(`[proxy] >> ${req.method} ${req.originalUrl}`);
|
|
198
|
-
},
|
|
199
|
-
proxyRes: (proxyRes, req) => {
|
|
200
|
-
console.log(`[proxy] << ${proxyRes.statusCode} ${req.method} ${req.originalUrl}`);
|
|
201
|
-
},
|
|
202
|
-
error: (err, req, res) => {
|
|
203
|
-
console.error(`[proxy] !! ${req.method} ${req.originalUrl} error: ${err.message}`);
|
|
204
|
-
if (!res.headersSent) res.status(502).json({ error: err.message });
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
}));
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
216
|
var schemaSync = { run: async () => {
|
|
211
217
|
}, watch: () => {
|
|
212
218
|
} };
|
|
@@ -310,7 +316,7 @@ function setupSchemaSync(app, schemaDir) {
|
|
|
310
316
|
}
|
|
311
317
|
console.error("DB schema sync failed after all retries");
|
|
312
318
|
}
|
|
313
|
-
app.post("/api/__sync-schema", async (_req, res) => {
|
|
319
|
+
app.post("/api/__sync-schema", requireBearerAuth, async (_req, res) => {
|
|
314
320
|
try {
|
|
315
321
|
await syncWithRetry(2, 1500);
|
|
316
322
|
res.json({ ok: true });
|
|
@@ -414,16 +420,7 @@ function setupCron(app, cronDir) {
|
|
|
414
420
|
console.log(`Cron registered: [${task.id}] ${task.name} (${task.schedule})`);
|
|
415
421
|
}
|
|
416
422
|
}
|
|
417
|
-
|
|
418
|
-
app.use("/api/cron", (req, res, next) => {
|
|
419
|
-
const appToken = envFn("SURF_DEPLOYED_APP_TOKEN", "APP_TOKEN");
|
|
420
|
-
if (!appToken) return next();
|
|
421
|
-
const auth = req.headers.authorization;
|
|
422
|
-
if (!auth || auth !== `Bearer ${appToken}`) {
|
|
423
|
-
return res.status(401).json({ error: "Unauthorized" });
|
|
424
|
-
}
|
|
425
|
-
next();
|
|
426
|
-
});
|
|
423
|
+
app.use("/api/cron", requireBearerAuth);
|
|
427
424
|
app.get("/api/cron", (_req, res) => {
|
|
428
425
|
res.json(cronTasks.map((t) => {
|
|
429
426
|
const state = cronState.get(t.id) || { lastRunAt: null, lastStatus: null, lastError: null };
|
package/dist/server/index.d.cts
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import express from 'express';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* Express server runtime — replaces scaffold server.js
|
|
4
|
+
* Express server runtime — replaces scaffold server.js.
|
|
5
5
|
*
|
|
6
6
|
* Handles:
|
|
7
|
-
* - /proxy/* passthrough (env-aware: sandbox → OutboundProxy, deployed → hermod)
|
|
8
7
|
* - Auto-loading routes from routes/*.js → /api/{name}
|
|
9
8
|
* - Cron job system from cron.json
|
|
10
9
|
* - DB schema sync on startup
|
|
@@ -12,18 +11,16 @@ import express from 'express';
|
|
|
12
11
|
*/
|
|
13
12
|
|
|
14
13
|
interface ServerOptions {
|
|
15
|
-
/** Port to listen on
|
|
14
|
+
/** Port to listen on. Falls back to the PORT env var when omitted. */
|
|
16
15
|
port?: number;
|
|
17
16
|
/** Directory containing route files (default: ./routes) */
|
|
18
17
|
routesDir?: string;
|
|
19
18
|
/** Directory containing cron.json (default: .) */
|
|
20
19
|
cronDir?: string;
|
|
21
|
-
/** Enable /proxy/* passthrough (default: true) */
|
|
22
|
-
proxy?: boolean;
|
|
23
20
|
}
|
|
24
21
|
declare function createServer(options?: ServerOptions): {
|
|
25
22
|
app: express.Express;
|
|
26
|
-
port: number;
|
|
23
|
+
port: number | undefined;
|
|
27
24
|
start(): Promise<void>;
|
|
28
25
|
};
|
|
29
26
|
|
|
@@ -3454,17 +3451,14 @@ interface V2PolymarketVolumeChartParams {
|
|
|
3454
3451
|
}
|
|
3455
3452
|
|
|
3456
3453
|
/**
|
|
3457
|
-
*
|
|
3454
|
+
* 1.0 data API client.
|
|
3458
3455
|
*
|
|
3459
|
-
* Reads
|
|
3460
|
-
* -
|
|
3461
|
-
* -
|
|
3462
|
-
* - Neither → public (api.ask.surf, caller provides own auth)
|
|
3456
|
+
* Reads:
|
|
3457
|
+
* - SURF_API_BASE_URL (default: https://api.asksurf.ai/gateway/v1)
|
|
3458
|
+
* - SURF_API_KEY (required)
|
|
3463
3459
|
*
|
|
3464
|
-
*
|
|
3465
|
-
*
|
|
3466
|
-
* GATEWAY_URL → SURF_DEPLOYED_GATEWAY_URL
|
|
3467
|
-
* APP_TOKEN → SURF_DEPLOYED_APP_TOKEN
|
|
3460
|
+
* All requests are sent directly to the configured API base URL using
|
|
3461
|
+
* Authorization: Bearer <SURF_API_KEY>.
|
|
3468
3462
|
*/
|
|
3469
3463
|
/** Low-level GET — escape hatch for endpoints not yet in the SDK. */
|
|
3470
3464
|
declare function get<T = any>(path: string, params?: Record<string, any>): Promise<T>;
|
package/dist/server/index.d.ts
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import express from 'express';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* Express server runtime — replaces scaffold server.js
|
|
4
|
+
* Express server runtime — replaces scaffold server.js.
|
|
5
5
|
*
|
|
6
6
|
* Handles:
|
|
7
|
-
* - /proxy/* passthrough (env-aware: sandbox → OutboundProxy, deployed → hermod)
|
|
8
7
|
* - Auto-loading routes from routes/*.js → /api/{name}
|
|
9
8
|
* - Cron job system from cron.json
|
|
10
9
|
* - DB schema sync on startup
|
|
@@ -12,18 +11,16 @@ import express from 'express';
|
|
|
12
11
|
*/
|
|
13
12
|
|
|
14
13
|
interface ServerOptions {
|
|
15
|
-
/** Port to listen on
|
|
14
|
+
/** Port to listen on. Falls back to the PORT env var when omitted. */
|
|
16
15
|
port?: number;
|
|
17
16
|
/** Directory containing route files (default: ./routes) */
|
|
18
17
|
routesDir?: string;
|
|
19
18
|
/** Directory containing cron.json (default: .) */
|
|
20
19
|
cronDir?: string;
|
|
21
|
-
/** Enable /proxy/* passthrough (default: true) */
|
|
22
|
-
proxy?: boolean;
|
|
23
20
|
}
|
|
24
21
|
declare function createServer(options?: ServerOptions): {
|
|
25
22
|
app: express.Express;
|
|
26
|
-
port: number;
|
|
23
|
+
port: number | undefined;
|
|
27
24
|
start(): Promise<void>;
|
|
28
25
|
};
|
|
29
26
|
|
|
@@ -3454,17 +3451,14 @@ interface V2PolymarketVolumeChartParams {
|
|
|
3454
3451
|
}
|
|
3455
3452
|
|
|
3456
3453
|
/**
|
|
3457
|
-
*
|
|
3454
|
+
* 1.0 data API client.
|
|
3458
3455
|
*
|
|
3459
|
-
* Reads
|
|
3460
|
-
* -
|
|
3461
|
-
* -
|
|
3462
|
-
* - Neither → public (api.ask.surf, caller provides own auth)
|
|
3456
|
+
* Reads:
|
|
3457
|
+
* - SURF_API_BASE_URL (default: https://api.asksurf.ai/gateway/v1)
|
|
3458
|
+
* - SURF_API_KEY (required)
|
|
3463
3459
|
*
|
|
3464
|
-
*
|
|
3465
|
-
*
|
|
3466
|
-
* GATEWAY_URL → SURF_DEPLOYED_GATEWAY_URL
|
|
3467
|
-
* APP_TOKEN → SURF_DEPLOYED_APP_TOKEN
|
|
3460
|
+
* All requests are sent directly to the configured API base URL using
|
|
3461
|
+
* Authorization: Bearer <SURF_API_KEY>.
|
|
3468
3462
|
*/
|
|
3469
3463
|
/** Low-level GET — escape hatch for endpoints not yet in the SDK. */
|
|
3470
3464
|
declare function get<T = any>(path: string, params?: Record<string, any>): Promise<T>;
|