titanpl-sdk 2.0.3 → 2.0.4
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 +2 -0
- package/package.json +38 -34
- package/templates/app/app.js +1 -4
- package/templates/server/Cargo.toml +22 -2
- package/templates/server/src/action_management.rs +8 -10
- package/templates/server/src/errors.rs +3 -1
- package/templates/server/src/extensions/builtin.rs +1038 -877
- package/templates/server/src/extensions/external.rs +338 -404
- package/templates/server/src/extensions/mod.rs +580 -448
- package/templates/server/src/extensions/titan_core.js +249 -186
- package/templates/server/src/fast_path.rs +719 -0
- package/templates/server/src/main.rs +370 -169
- package/templates/server/src/runtime.rs +284 -245
- package/templates/server/src/utils.rs +2 -2
- package/templates/titan/bundle.js +259 -264
- package/templates/titan/dev.js +46 -6
- package/templates/titan/error-box.js +277 -268
- package/templates/app/titan.d.ts +0 -87
- package/templates/index.d.ts +0 -249
|
@@ -1,186 +1,249 @@
|
|
|
1
|
-
// Titan Core Runtime JS
|
|
2
|
-
// Safe Bootstrap — runs only once
|
|
3
|
-
if (!globalThis.__TITAN_CORE_LOADED__) {
|
|
4
|
-
globalThis.__TITAN_CORE_LOADED__ = true;
|
|
5
|
-
|
|
6
|
-
globalThis.global = globalThis;
|
|
7
|
-
|
|
8
|
-
// ensure t exists early
|
|
9
|
-
if (!globalThis.t) globalThis.t = {};
|
|
10
|
-
|
|
11
|
-
//
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
};
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
1
|
+
// Titan Core Runtime JS
|
|
2
|
+
// Safe Bootstrap — runs only once
|
|
3
|
+
if (!globalThis.__TITAN_CORE_LOADED__) {
|
|
4
|
+
globalThis.__TITAN_CORE_LOADED__ = true;
|
|
5
|
+
|
|
6
|
+
globalThis.global = globalThis;
|
|
7
|
+
|
|
8
|
+
// ensure t exists early
|
|
9
|
+
if (!globalThis.t) globalThis.t = {};
|
|
10
|
+
|
|
11
|
+
// defineAction identity helper
|
|
12
|
+
globalThis.defineAction = (fn) => {
|
|
13
|
+
if (fn.__titanWrapped) return fn;
|
|
14
|
+
|
|
15
|
+
const wrapped = function (req) {
|
|
16
|
+
const requestId = req.__titan_request_id;
|
|
17
|
+
|
|
18
|
+
if (req.rawBody && req.rawBody.byteLength !== undefined) {
|
|
19
|
+
try {
|
|
20
|
+
const decoder = new TextDecoder();
|
|
21
|
+
const text = decoder.decode(req.rawBody);
|
|
22
|
+
|
|
23
|
+
const contentType =
|
|
24
|
+
(req.headers && req.headers["content-type"]) ||
|
|
25
|
+
(req.headers && req.headers["Content-Type"]) ||
|
|
26
|
+
"";
|
|
27
|
+
|
|
28
|
+
if (contentType.includes("application/json")) {
|
|
29
|
+
req.body = text ? JSON.parse(text) : {};
|
|
30
|
+
} else if (contentType.includes("application/x-www-form-urlencoded")) {
|
|
31
|
+
req.body = Object.fromEntries(new URLSearchParams(text));
|
|
32
|
+
} else {
|
|
33
|
+
req.body = text;
|
|
34
|
+
}
|
|
35
|
+
} catch (e) {
|
|
36
|
+
req.body = {};
|
|
37
|
+
}
|
|
38
|
+
} else {
|
|
39
|
+
req.body = {};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// ===============================
|
|
43
|
+
|
|
44
|
+
const isSuspend = (err) => {
|
|
45
|
+
const msg = err && (err.message || String(err));
|
|
46
|
+
return msg && (msg.includes("__SUSPEND__") || msg.includes("SUSPEND"));
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
try {
|
|
50
|
+
const result = fn(req);
|
|
51
|
+
|
|
52
|
+
if (result && typeof result.then === 'function') {
|
|
53
|
+
result.then(
|
|
54
|
+
(data) => t._finish_request(requestId, data),
|
|
55
|
+
(err) => {
|
|
56
|
+
if (isSuspend(err)) return;
|
|
57
|
+
t._finish_request(requestId, { error: err.message || String(err) });
|
|
58
|
+
}
|
|
59
|
+
);
|
|
60
|
+
} else {
|
|
61
|
+
t._finish_request(requestId, result);
|
|
62
|
+
}
|
|
63
|
+
} catch (err) {
|
|
64
|
+
if (isSuspend(err)) return;
|
|
65
|
+
t._finish_request(requestId, { error: err.message || String(err) });
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
wrapped.__titanWrapped = true;
|
|
70
|
+
return wrapped;
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
// TextDecoder Polyfill
|
|
75
|
+
globalThis.TextDecoder = class TextDecoder {
|
|
76
|
+
decode(buffer) {
|
|
77
|
+
return t.decodeUtf8(buffer);
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
// Titan Environment API
|
|
82
|
+
t.env = t.loadEnv ? t.loadEnv() : {};
|
|
83
|
+
|
|
84
|
+
// Async Proxy Creator
|
|
85
|
+
function createAsyncOp(op) {
|
|
86
|
+
return new Proxy(op, {
|
|
87
|
+
get(target, prop) {
|
|
88
|
+
if (
|
|
89
|
+
prop === "__titanAsync" ||
|
|
90
|
+
prop === "type" ||
|
|
91
|
+
prop === "data" ||
|
|
92
|
+
typeof prop === 'symbol'
|
|
93
|
+
) {
|
|
94
|
+
return target[prop];
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
throw new Error(
|
|
98
|
+
`[Titan Error] Accessed '${String(prop)}' without drift(). `
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Response API (Dual-Signature)
|
|
105
|
+
// Supports TWO calling conventions for compatibility with fast-path parser:
|
|
106
|
+
//
|
|
107
|
+
// Positional (legacy):
|
|
108
|
+
// t.response.json(data, 201, { "X-Custom": "val" })
|
|
109
|
+
//
|
|
110
|
+
// Options object (preferred — matches fast-path syntax):
|
|
111
|
+
// t.response.json(data, { status: 201, headers: { "X-Custom": "val" } })
|
|
112
|
+
//
|
|
113
|
+
// The fast-path scanner parses the source code and expects the options-object
|
|
114
|
+
// form. Using the positional form works at runtime but won't be detected by
|
|
115
|
+
// fast-path. The options-object form works in BOTH paths.
|
|
116
|
+
//
|
|
117
|
+
// Internal helper to normalize the second argument:
|
|
118
|
+
function _parseResponseOpts(secondArg, thirdArg) {
|
|
119
|
+
let status = 200;
|
|
120
|
+
let extraHeaders = {};
|
|
121
|
+
|
|
122
|
+
if (secondArg !== undefined && secondArg !== null && typeof secondArg === 'object') {
|
|
123
|
+
// Options object form: { status: N, headers: {...} }
|
|
124
|
+
status = secondArg.status || 200;
|
|
125
|
+
extraHeaders = secondArg.headers || {};
|
|
126
|
+
// Also merge thirdArg if provided (defensive)
|
|
127
|
+
if (thirdArg && typeof thirdArg === 'object') {
|
|
128
|
+
extraHeaders = { ...extraHeaders, ...thirdArg };
|
|
129
|
+
}
|
|
130
|
+
} else {
|
|
131
|
+
// Positional form: (status, extraHeaders)
|
|
132
|
+
status = secondArg || 200;
|
|
133
|
+
extraHeaders = thirdArg || {};
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
return { status, extraHeaders };
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const titanResponse = {
|
|
140
|
+
json(data, second, third) {
|
|
141
|
+
const { status, extraHeaders } = _parseResponseOpts(second, third);
|
|
142
|
+
return {
|
|
143
|
+
_isResponse: true,
|
|
144
|
+
status,
|
|
145
|
+
headers: { "Content-Type": "application/json", ...extraHeaders },
|
|
146
|
+
body: JSON.stringify(data)
|
|
147
|
+
};
|
|
148
|
+
},
|
|
149
|
+
text(data, second, third) {
|
|
150
|
+
const { status, extraHeaders } = _parseResponseOpts(second, third);
|
|
151
|
+
return {
|
|
152
|
+
_isResponse: true,
|
|
153
|
+
status,
|
|
154
|
+
headers: { "Content-Type": "text/plain", ...extraHeaders },
|
|
155
|
+
body: String(data)
|
|
156
|
+
};
|
|
157
|
+
},
|
|
158
|
+
html(data, second, third) {
|
|
159
|
+
const { status, extraHeaders } = _parseResponseOpts(second, third);
|
|
160
|
+
return {
|
|
161
|
+
_isResponse: true,
|
|
162
|
+
status,
|
|
163
|
+
headers: { "Content-Type": "text/html", ...extraHeaders },
|
|
164
|
+
body: String(data)
|
|
165
|
+
};
|
|
166
|
+
},
|
|
167
|
+
redirect(url, second, third) {
|
|
168
|
+
const { status: rawStatus, extraHeaders } = _parseResponseOpts(second, third);
|
|
169
|
+
// For redirects, default to 302 and ensure 3xx range
|
|
170
|
+
let status = rawStatus;
|
|
171
|
+
if (status < 300 || status >= 400) status = 302;
|
|
172
|
+
return {
|
|
173
|
+
_isResponse: true,
|
|
174
|
+
status,
|
|
175
|
+
headers: { "Location": url, ...extraHeaders },
|
|
176
|
+
redirect: url
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
t.response = titanResponse;
|
|
182
|
+
|
|
183
|
+
// Drift Support
|
|
184
|
+
globalThis.drift = function (value) {
|
|
185
|
+
if (Array.isArray(value)) {
|
|
186
|
+
for (const item of value) {
|
|
187
|
+
if (!item || !item.__titanAsync) {
|
|
188
|
+
throw new Error("drift() array must contain async ops only.");
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
} else if (!value || !value.__titanAsync) {
|
|
192
|
+
throw new Error("drift() must wrap async ops.");
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
return t._drift_call(value);
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
// Safe Wrappers
|
|
199
|
+
|
|
200
|
+
// fetch
|
|
201
|
+
if (t.fetch && !t.fetch.__titanWrapped) {
|
|
202
|
+
const nativeFetch = t.fetch;
|
|
203
|
+
t.fetch = function (...args) {
|
|
204
|
+
return createAsyncOp(nativeFetch(...args));
|
|
205
|
+
};
|
|
206
|
+
t.fetch.__titanWrapped = true;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// db.connect
|
|
210
|
+
// db.connect
|
|
211
|
+
if (t.db && !t.db.__titanWrapped) {
|
|
212
|
+
const nativeDbConnect = t.db.connect;
|
|
213
|
+
|
|
214
|
+
t.db.connect = function (connString, options = {}) {
|
|
215
|
+
const conn = nativeDbConnect(connString, options);
|
|
216
|
+
|
|
217
|
+
if (!conn.query.__titanWrapped) {
|
|
218
|
+
const nativeQuery = conn.query;
|
|
219
|
+
|
|
220
|
+
conn.query = function (sql, params = []) {
|
|
221
|
+
if (typeof sql !== "string" || !sql.trim()) {
|
|
222
|
+
throw new Error("db.query(): SQL string required");
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
if (!Array.isArray(params)) {
|
|
226
|
+
throw new Error("db.query(): params must be array");
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
return createAsyncOp({
|
|
230
|
+
__titanAsync: true,
|
|
231
|
+
type: "db_query",
|
|
232
|
+
data: {
|
|
233
|
+
conn: connString,
|
|
234
|
+
query: sql,
|
|
235
|
+
params
|
|
236
|
+
}
|
|
237
|
+
});
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
conn.query.__titanWrapped = true;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
return conn;
|
|
244
|
+
};
|
|
245
|
+
|
|
246
|
+
t.db.__titanWrapped = true;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
}
|