semola 0.5.4 → 0.6.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 +18 -45
- package/dist/chunk-CKQMccvm.cjs +28 -0
- package/dist/lib/api/index.cjs +29 -15
- package/dist/lib/api/index.mjs +30 -16
- package/dist/lib/cache/index.cjs +47 -22
- package/dist/lib/cache/index.d.cts +3 -24
- package/dist/lib/cache/index.d.mts +3 -24
- package/dist/lib/cache/index.mjs +48 -23
- package/dist/lib/cron/index.cjs +117 -117
- package/dist/lib/cron/index.mjs +118 -118
- package/dist/lib/errors/index.d.cts +12 -1
- package/dist/lib/errors/index.d.mts +12 -1
- package/dist/lib/logging/index.cjs +1 -0
- package/dist/lib/orm/index.cjs +1642 -0
- package/dist/lib/orm/index.d.cts +402 -0
- package/dist/lib/orm/index.d.mts +402 -0
- package/dist/lib/orm/index.mjs +1630 -0
- package/dist/lib/prompts/index.cjs +89 -89
- package/dist/lib/prompts/index.d.cts +12 -33
- package/dist/lib/prompts/index.d.mts +12 -33
- package/dist/lib/prompts/index.mjs +89 -90
- package/dist/lib/pubsub/index.cjs +43 -19
- package/dist/lib/pubsub/index.d.cts +3 -18
- package/dist/lib/pubsub/index.d.mts +3 -18
- package/dist/lib/pubsub/index.mjs +44 -20
- package/dist/lib/queue/index.cjs +40 -10
- package/dist/lib/queue/index.d.cts +11 -4
- package/dist/lib/queue/index.d.mts +11 -4
- package/dist/lib/queue/index.mjs +39 -11
- package/dist/lib/workflow/index.cjs +285 -282
- package/dist/lib/workflow/index.d.cts +76 -11
- package/dist/lib/workflow/index.d.mts +76 -11
- package/dist/lib/workflow/index.mjs +278 -284
- package/package.json +11 -1
- package/dist/index-BhGNDjPq.d.mts +0 -13
- package/dist/index-DxSbeGP-.d.cts +0 -13
package/README.md
CHANGED
|
@@ -27,11 +27,11 @@ Type-safe APIs, Redis queues, pub/sub, i18n, caching & auth with tree-shakeable
|
|
|
27
27
|
| **🌍 i18n** | Compile-time validated internationalization | `semola/i18n` |
|
|
28
28
|
| **💾 Cache** | Redis cache wrapper with TTL & automatic serialization | `semola/cache` |
|
|
29
29
|
| **⏰ Cron** | In-memory cron scheduler for periodic task execution | `semola/cron` |
|
|
30
|
-
| **🔁 Workflow** | Durable resumable workflows with
|
|
30
|
+
| **🔁 Workflow** | Durable resumable workflows with retries and hooks | `semola/workflow` |
|
|
31
31
|
| **⚠️ Errors** | Result-based error handling without try/catch | `semola/errors` |
|
|
32
32
|
| **📃 Logging** | A simple logging utility | `semola/logging` |
|
|
33
33
|
| **⌨️ Prompts** | Interactive zero-dependency CLI prompts | `semola/prompts` |
|
|
34
|
-
| **🗄️ ORM** | Type-safe data layer with query APIs
|
|
34
|
+
| **🗄️ ORM** | Type-safe data layer with query APIs | `semola/orm` |
|
|
35
35
|
|
|
36
36
|
---
|
|
37
37
|
|
|
@@ -122,16 +122,14 @@ const pubsub = new PubSub({
|
|
|
122
122
|
});
|
|
123
123
|
|
|
124
124
|
// Subscribe to messages
|
|
125
|
-
const
|
|
125
|
+
const unsubscribe = await pubsub.subscribe((message) => {
|
|
126
126
|
console.log("Received:", message);
|
|
127
127
|
});
|
|
128
128
|
|
|
129
129
|
// Publish a message
|
|
130
130
|
await pubsub.publish({ userId: 123, text: "New alert!" });
|
|
131
131
|
|
|
132
|
-
|
|
133
|
-
await unsubscribeHandler();
|
|
134
|
-
}
|
|
132
|
+
await unsubscribe();
|
|
135
133
|
```
|
|
136
134
|
|
|
137
135
|
### Cache Data with TTL
|
|
@@ -148,8 +146,8 @@ const cache = new Cache({
|
|
|
148
146
|
await cache.set("user:123", { name: "John", age: 30 });
|
|
149
147
|
|
|
150
148
|
// Retrieve data
|
|
151
|
-
const
|
|
152
|
-
|
|
149
|
+
const user = await cache.get("user:123");
|
|
150
|
+
console.log(user);
|
|
153
151
|
```
|
|
154
152
|
|
|
155
153
|
### Schedule Recurring Tasks
|
|
@@ -172,60 +170,35 @@ cleanup.start();
|
|
|
172
170
|
### Query a Database
|
|
173
171
|
|
|
174
172
|
```typescript
|
|
175
|
-
import { createOrm,
|
|
173
|
+
import { createOrm, defineTable, json, string, uuid } from "semola/orm";
|
|
176
174
|
|
|
177
|
-
const users =
|
|
178
|
-
id: uuid("id").primaryKey(),
|
|
175
|
+
const users = defineTable("users", {
|
|
176
|
+
id: uuid("id").primaryKey().notNull(),
|
|
179
177
|
name: string("name").notNull(),
|
|
180
178
|
email: string("email").unique().notNull(),
|
|
179
|
+
metadata: json<{ plan: string }>("metadata"),
|
|
181
180
|
});
|
|
182
181
|
|
|
183
182
|
const db = createOrm({
|
|
184
|
-
|
|
183
|
+
adapter: "sqlite",
|
|
184
|
+
url: ":memory:",
|
|
185
185
|
tables: { users },
|
|
186
186
|
});
|
|
187
187
|
|
|
188
|
-
|
|
189
|
-
const [findErr, rows] = await db.users.findMany({
|
|
188
|
+
const rows = await db.users.findMany({
|
|
190
189
|
where: { name: { contains: "John" } },
|
|
191
190
|
take: 10,
|
|
192
191
|
});
|
|
193
192
|
|
|
194
|
-
|
|
195
|
-
console.error(findErr.type, findErr.message);
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
// Create record (result pattern)
|
|
199
|
-
const [createErr, user] = await db.users.create({
|
|
193
|
+
const user = await db.users.create({
|
|
200
194
|
data: {
|
|
195
|
+
id: "1",
|
|
201
196
|
name: "John Doe",
|
|
202
197
|
email: "john@example.com",
|
|
203
198
|
},
|
|
204
199
|
});
|
|
205
200
|
|
|
206
|
-
|
|
207
|
-
const insertedRows = await db.users.insert({
|
|
208
|
-
data: {
|
|
209
|
-
name: "Jane Doe",
|
|
210
|
-
email: "jane@example.com",
|
|
211
|
-
},
|
|
212
|
-
returning: true,
|
|
213
|
-
});
|
|
214
|
-
|
|
215
|
-
console.log(rows, user, createErr, insertedRows);
|
|
216
|
-
```
|
|
217
|
-
|
|
218
|
-
### Run ORM Migrations
|
|
219
|
-
|
|
220
|
-
```bash
|
|
221
|
-
# create migration from schema diff
|
|
222
|
-
semola orm migrations create add-users
|
|
223
|
-
|
|
224
|
-
# apply pending migrations
|
|
225
|
-
semola orm migrations apply
|
|
226
|
-
|
|
227
|
-
# rollback last applied migration
|
|
228
|
-
semola orm migrations rollback
|
|
201
|
+
console.log(rows, user);
|
|
229
202
|
```
|
|
230
203
|
|
|
231
204
|
### Check Permissions
|
|
@@ -345,14 +318,14 @@ _Higher is better for req/sec, lower is better for latency._
|
|
|
345
318
|
- [Queue](./docs/queue.md) - Redis-backed job queue with timeouts & concurrency
|
|
346
319
|
- [PubSub](./docs/pubsub.md) - Type-safe Redis pub/sub
|
|
347
320
|
- [Cron](./docs/cron.md) - In-memory cron scheduler for periodic task execution
|
|
348
|
-
- [Workflow](./docs/workflow.md) - Durable and resumable workflows with
|
|
321
|
+
- [Workflow](./docs/workflow.md) - Durable and resumable workflows with retries and hooks
|
|
349
322
|
- [Policy](./docs/policy.md) - Policy-based authorization
|
|
350
323
|
- [i18n](./docs/i18n.md) - Type-safe internationalization
|
|
351
324
|
- [Cache](./docs/cache.md) - Redis cache wrapper with TTL
|
|
352
325
|
- [Errors](./docs/errors.md) - Result-based error handling
|
|
353
326
|
- [Logging](./docs/logging.md) - Logging utility
|
|
354
327
|
- [Prompts](./docs/prompts.md) - Interactive CLI prompts
|
|
355
|
-
- [ORM](./docs/orm.md) - Type-safe data layer
|
|
328
|
+
- [ORM](./docs/orm.md) - Type-safe data layer with SQLite support
|
|
356
329
|
|
|
357
330
|
---
|
|
358
331
|
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
//#region \0rolldown/runtime.js
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __copyProps = (to, from, except, desc) => {
|
|
9
|
+
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
10
|
+
key = keys[i];
|
|
11
|
+
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
|
|
12
|
+
get: ((k) => from[k]).bind(null, key),
|
|
13
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
19
|
+
value: mod,
|
|
20
|
+
enumerable: true
|
|
21
|
+
}) : target, mod));
|
|
22
|
+
//#endregion
|
|
23
|
+
Object.defineProperty(exports, "__toESM", {
|
|
24
|
+
enumerable: true,
|
|
25
|
+
get: function() {
|
|
26
|
+
return __toESM;
|
|
27
|
+
}
|
|
28
|
+
});
|
package/dist/lib/api/index.cjs
CHANGED
|
@@ -253,22 +253,36 @@ const generateOpenApiSpec = async (options) => {
|
|
|
253
253
|
return spec;
|
|
254
254
|
};
|
|
255
255
|
//#endregion
|
|
256
|
+
//#region src/lib/api/errors.ts
|
|
257
|
+
var ParseError = class extends Error {
|
|
258
|
+
constructor(message) {
|
|
259
|
+
super(message);
|
|
260
|
+
this.name = "ParseError";
|
|
261
|
+
}
|
|
262
|
+
};
|
|
263
|
+
var ValidationError = class extends Error {
|
|
264
|
+
constructor(message) {
|
|
265
|
+
super(message);
|
|
266
|
+
this.name = "ValidationError";
|
|
267
|
+
}
|
|
268
|
+
};
|
|
269
|
+
//#endregion
|
|
256
270
|
//#region src/lib/api/validation/index.ts
|
|
257
271
|
const validateSchema = async (schema, data) => {
|
|
258
272
|
const result = await schema["~standard"].validate(data);
|
|
259
|
-
if (!result.issues) return
|
|
260
|
-
|
|
273
|
+
if (!result.issues) return result.value;
|
|
274
|
+
throw new ValidationError(result.issues.map((issue) => {
|
|
261
275
|
let path = "unknown";
|
|
262
276
|
if (Array.isArray(issue.path)) path = issue.path.map(String).join(".");
|
|
263
277
|
return `${path}: ${issue.message ?? "validation failed"}`;
|
|
264
278
|
}).join(", "));
|
|
265
279
|
};
|
|
266
280
|
const validateBody = async (req, bodySchema, bodyCache) => {
|
|
267
|
-
if (!bodySchema) return
|
|
268
|
-
if (!(req.headers.get("content-type") ?? "").includes("application/json")) return
|
|
281
|
+
if (!bodySchema) return true;
|
|
282
|
+
if (!(req.headers.get("content-type") ?? "").includes("application/json")) return;
|
|
269
283
|
if (bodyCache?.parsed) return validateSchema(bodySchema, bodyCache.value);
|
|
270
284
|
const [parseError, parsedBody] = await require_lib_errors_index.mightThrow(req.json());
|
|
271
|
-
if (parseError)
|
|
285
|
+
if (parseError) throw new ParseError("Invalid JSON body");
|
|
272
286
|
if (bodyCache) {
|
|
273
287
|
bodyCache.parsed = true;
|
|
274
288
|
bodyCache.value = parsedBody;
|
|
@@ -276,7 +290,7 @@ const validateBody = async (req, bodySchema, bodyCache) => {
|
|
|
276
290
|
return validateSchema(bodySchema, parsedBody);
|
|
277
291
|
};
|
|
278
292
|
const validateQuery = async (req, querySchema) => {
|
|
279
|
-
if (!querySchema) return
|
|
293
|
+
if (!querySchema) return true;
|
|
280
294
|
const qIndex = req.url.indexOf("?");
|
|
281
295
|
if (qIndex === -1) return validateSchema(querySchema, {});
|
|
282
296
|
const hashIndex = req.url.indexOf("#", qIndex + 1);
|
|
@@ -292,7 +306,7 @@ const validateQuery = async (req, querySchema) => {
|
|
|
292
306
|
return validateSchema(querySchema, queryParams);
|
|
293
307
|
};
|
|
294
308
|
const validateHeaders = async (req, headersSchema) => {
|
|
295
|
-
if (!headersSchema) return
|
|
309
|
+
if (!headersSchema) return true;
|
|
296
310
|
const headers = {};
|
|
297
311
|
req.headers.forEach((value, key) => {
|
|
298
312
|
headers[key] = value;
|
|
@@ -300,13 +314,13 @@ const validateHeaders = async (req, headersSchema) => {
|
|
|
300
314
|
return validateSchema(headersSchema, headers);
|
|
301
315
|
};
|
|
302
316
|
const validateCookies = async (req, cookiesSchema) => {
|
|
303
|
-
if (!cookiesSchema) return
|
|
317
|
+
if (!cookiesSchema) return true;
|
|
304
318
|
const cookieHeader = req.headers.get("cookie") ?? "";
|
|
305
319
|
const cookieMap = new Bun.CookieMap(cookieHeader);
|
|
306
320
|
return validateSchema(cookiesSchema, Object.fromEntries(cookieMap));
|
|
307
321
|
};
|
|
308
322
|
const validateParams = async (req, paramsSchema) => {
|
|
309
|
-
if (!paramsSchema) return
|
|
323
|
+
if (!paramsSchema) return true;
|
|
310
324
|
return validateSchema(paramsSchema, req.params);
|
|
311
325
|
};
|
|
312
326
|
//#endregion
|
|
@@ -374,7 +388,7 @@ var Api = class {
|
|
|
374
388
|
};
|
|
375
389
|
const v = {};
|
|
376
390
|
if (schema.body) {
|
|
377
|
-
const [err, val] = await validateBody(req, schema.body, bodyCache);
|
|
391
|
+
const [err, val] = await require_lib_errors_index.mightThrow(validateBody(req, schema.body, bodyCache));
|
|
378
392
|
if (err) return {
|
|
379
393
|
success: false,
|
|
380
394
|
error: err
|
|
@@ -382,7 +396,7 @@ var Api = class {
|
|
|
382
396
|
v.body = val;
|
|
383
397
|
}
|
|
384
398
|
if (schema.query) {
|
|
385
|
-
const [err, val] = await validateQuery(req, schema.query);
|
|
399
|
+
const [err, val] = await require_lib_errors_index.mightThrow(validateQuery(req, schema.query));
|
|
386
400
|
if (err) return {
|
|
387
401
|
success: false,
|
|
388
402
|
error: err
|
|
@@ -390,7 +404,7 @@ var Api = class {
|
|
|
390
404
|
v.query = val;
|
|
391
405
|
}
|
|
392
406
|
if (schema.headers) {
|
|
393
|
-
const [err, val] = await validateHeaders(req, schema.headers);
|
|
407
|
+
const [err, val] = await require_lib_errors_index.mightThrow(validateHeaders(req, schema.headers));
|
|
394
408
|
if (err) return {
|
|
395
409
|
success: false,
|
|
396
410
|
error: err
|
|
@@ -398,7 +412,7 @@ var Api = class {
|
|
|
398
412
|
v.headers = val;
|
|
399
413
|
}
|
|
400
414
|
if (schema.cookies) {
|
|
401
|
-
const [err, val] = await validateCookies(req, schema.cookies);
|
|
415
|
+
const [err, val] = await require_lib_errors_index.mightThrow(validateCookies(req, schema.cookies));
|
|
402
416
|
if (err) return {
|
|
403
417
|
success: false,
|
|
404
418
|
error: err
|
|
@@ -406,7 +420,7 @@ var Api = class {
|
|
|
406
420
|
v.cookies = val;
|
|
407
421
|
}
|
|
408
422
|
if (schema.params) {
|
|
409
|
-
const [err, val] = await validateParams(req, schema.params);
|
|
423
|
+
const [err, val] = await require_lib_errors_index.mightThrow(validateParams(req, schema.params));
|
|
410
424
|
if (err) return {
|
|
411
425
|
success: false,
|
|
412
426
|
error: err
|
|
@@ -433,7 +447,7 @@ var Api = class {
|
|
|
433
447
|
if (!(response.headers.get("content-type") ?? "").includes("application/json")) return response;
|
|
434
448
|
const [parseError, body] = await require_lib_errors_index.mightThrow(response.clone().json());
|
|
435
449
|
if (parseError) return responseHelpers.json(400, { message: "Invalid response body" });
|
|
436
|
-
const [validationError] = await validateSchema(statusSchema, body);
|
|
450
|
+
const [validationError] = await require_lib_errors_index.mightThrow(validateSchema(statusSchema, body));
|
|
437
451
|
if (validationError) return responseHelpers.json(400, { message: validationError.message });
|
|
438
452
|
return response;
|
|
439
453
|
}
|
package/dist/lib/api/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { mightThrow } from "../errors/index.mjs";
|
|
2
2
|
//#region src/lib/api/openapi/index.ts
|
|
3
3
|
const toOpenAPISchema = (schema, io = "input") => ({ schema: schema["~standard"].jsonSchema[io]({ target: "draft-2020-12" }) });
|
|
4
4
|
const getSchemaDescription = (schema) => {
|
|
@@ -252,22 +252,36 @@ const generateOpenApiSpec = async (options) => {
|
|
|
252
252
|
return spec;
|
|
253
253
|
};
|
|
254
254
|
//#endregion
|
|
255
|
+
//#region src/lib/api/errors.ts
|
|
256
|
+
var ParseError = class extends Error {
|
|
257
|
+
constructor(message) {
|
|
258
|
+
super(message);
|
|
259
|
+
this.name = "ParseError";
|
|
260
|
+
}
|
|
261
|
+
};
|
|
262
|
+
var ValidationError = class extends Error {
|
|
263
|
+
constructor(message) {
|
|
264
|
+
super(message);
|
|
265
|
+
this.name = "ValidationError";
|
|
266
|
+
}
|
|
267
|
+
};
|
|
268
|
+
//#endregion
|
|
255
269
|
//#region src/lib/api/validation/index.ts
|
|
256
270
|
const validateSchema = async (schema, data) => {
|
|
257
271
|
const result = await schema["~standard"].validate(data);
|
|
258
|
-
if (!result.issues) return
|
|
259
|
-
|
|
272
|
+
if (!result.issues) return result.value;
|
|
273
|
+
throw new ValidationError(result.issues.map((issue) => {
|
|
260
274
|
let path = "unknown";
|
|
261
275
|
if (Array.isArray(issue.path)) path = issue.path.map(String).join(".");
|
|
262
276
|
return `${path}: ${issue.message ?? "validation failed"}`;
|
|
263
277
|
}).join(", "));
|
|
264
278
|
};
|
|
265
279
|
const validateBody = async (req, bodySchema, bodyCache) => {
|
|
266
|
-
if (!bodySchema) return
|
|
267
|
-
if (!(req.headers.get("content-type") ?? "").includes("application/json")) return
|
|
280
|
+
if (!bodySchema) return true;
|
|
281
|
+
if (!(req.headers.get("content-type") ?? "").includes("application/json")) return;
|
|
268
282
|
if (bodyCache?.parsed) return validateSchema(bodySchema, bodyCache.value);
|
|
269
283
|
const [parseError, parsedBody] = await mightThrow(req.json());
|
|
270
|
-
if (parseError)
|
|
284
|
+
if (parseError) throw new ParseError("Invalid JSON body");
|
|
271
285
|
if (bodyCache) {
|
|
272
286
|
bodyCache.parsed = true;
|
|
273
287
|
bodyCache.value = parsedBody;
|
|
@@ -275,7 +289,7 @@ const validateBody = async (req, bodySchema, bodyCache) => {
|
|
|
275
289
|
return validateSchema(bodySchema, parsedBody);
|
|
276
290
|
};
|
|
277
291
|
const validateQuery = async (req, querySchema) => {
|
|
278
|
-
if (!querySchema) return
|
|
292
|
+
if (!querySchema) return true;
|
|
279
293
|
const qIndex = req.url.indexOf("?");
|
|
280
294
|
if (qIndex === -1) return validateSchema(querySchema, {});
|
|
281
295
|
const hashIndex = req.url.indexOf("#", qIndex + 1);
|
|
@@ -291,7 +305,7 @@ const validateQuery = async (req, querySchema) => {
|
|
|
291
305
|
return validateSchema(querySchema, queryParams);
|
|
292
306
|
};
|
|
293
307
|
const validateHeaders = async (req, headersSchema) => {
|
|
294
|
-
if (!headersSchema) return
|
|
308
|
+
if (!headersSchema) return true;
|
|
295
309
|
const headers = {};
|
|
296
310
|
req.headers.forEach((value, key) => {
|
|
297
311
|
headers[key] = value;
|
|
@@ -299,13 +313,13 @@ const validateHeaders = async (req, headersSchema) => {
|
|
|
299
313
|
return validateSchema(headersSchema, headers);
|
|
300
314
|
};
|
|
301
315
|
const validateCookies = async (req, cookiesSchema) => {
|
|
302
|
-
if (!cookiesSchema) return
|
|
316
|
+
if (!cookiesSchema) return true;
|
|
303
317
|
const cookieHeader = req.headers.get("cookie") ?? "";
|
|
304
318
|
const cookieMap = new Bun.CookieMap(cookieHeader);
|
|
305
319
|
return validateSchema(cookiesSchema, Object.fromEntries(cookieMap));
|
|
306
320
|
};
|
|
307
321
|
const validateParams = async (req, paramsSchema) => {
|
|
308
|
-
if (!paramsSchema) return
|
|
322
|
+
if (!paramsSchema) return true;
|
|
309
323
|
return validateSchema(paramsSchema, req.params);
|
|
310
324
|
};
|
|
311
325
|
//#endregion
|
|
@@ -373,7 +387,7 @@ var Api = class {
|
|
|
373
387
|
};
|
|
374
388
|
const v = {};
|
|
375
389
|
if (schema.body) {
|
|
376
|
-
const [err, val] = await validateBody(req, schema.body, bodyCache);
|
|
390
|
+
const [err, val] = await mightThrow(validateBody(req, schema.body, bodyCache));
|
|
377
391
|
if (err) return {
|
|
378
392
|
success: false,
|
|
379
393
|
error: err
|
|
@@ -381,7 +395,7 @@ var Api = class {
|
|
|
381
395
|
v.body = val;
|
|
382
396
|
}
|
|
383
397
|
if (schema.query) {
|
|
384
|
-
const [err, val] = await validateQuery(req, schema.query);
|
|
398
|
+
const [err, val] = await mightThrow(validateQuery(req, schema.query));
|
|
385
399
|
if (err) return {
|
|
386
400
|
success: false,
|
|
387
401
|
error: err
|
|
@@ -389,7 +403,7 @@ var Api = class {
|
|
|
389
403
|
v.query = val;
|
|
390
404
|
}
|
|
391
405
|
if (schema.headers) {
|
|
392
|
-
const [err, val] = await validateHeaders(req, schema.headers);
|
|
406
|
+
const [err, val] = await mightThrow(validateHeaders(req, schema.headers));
|
|
393
407
|
if (err) return {
|
|
394
408
|
success: false,
|
|
395
409
|
error: err
|
|
@@ -397,7 +411,7 @@ var Api = class {
|
|
|
397
411
|
v.headers = val;
|
|
398
412
|
}
|
|
399
413
|
if (schema.cookies) {
|
|
400
|
-
const [err, val] = await validateCookies(req, schema.cookies);
|
|
414
|
+
const [err, val] = await mightThrow(validateCookies(req, schema.cookies));
|
|
401
415
|
if (err) return {
|
|
402
416
|
success: false,
|
|
403
417
|
error: err
|
|
@@ -405,7 +419,7 @@ var Api = class {
|
|
|
405
419
|
v.cookies = val;
|
|
406
420
|
}
|
|
407
421
|
if (schema.params) {
|
|
408
|
-
const [err, val] = await validateParams(req, schema.params);
|
|
422
|
+
const [err, val] = await mightThrow(validateParams(req, schema.params));
|
|
409
423
|
if (err) return {
|
|
410
424
|
success: false,
|
|
411
425
|
error: err
|
|
@@ -432,7 +446,7 @@ var Api = class {
|
|
|
432
446
|
if (!(response.headers.get("content-type") ?? "").includes("application/json")) return response;
|
|
433
447
|
const [parseError, body] = await mightThrow(response.clone().json());
|
|
434
448
|
if (parseError) return responseHelpers.json(400, { message: "Invalid response body" });
|
|
435
|
-
const [validationError] = await validateSchema(statusSchema, body);
|
|
449
|
+
const [validationError] = await mightThrow(validateSchema(statusSchema, body));
|
|
436
450
|
if (validationError) return responseHelpers.json(400, { message: validationError.message });
|
|
437
451
|
return response;
|
|
438
452
|
}
|
package/dist/lib/cache/index.cjs
CHANGED
|
@@ -1,5 +1,37 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
const require_lib_errors_index = require("../errors/index.cjs");
|
|
3
|
+
//#region src/lib/cache/errors.ts
|
|
4
|
+
var CacheError = class extends Error {
|
|
5
|
+
constructor(message) {
|
|
6
|
+
super(message);
|
|
7
|
+
this.name = "CacheError";
|
|
8
|
+
}
|
|
9
|
+
};
|
|
10
|
+
var InvalidTTLError = class extends Error {
|
|
11
|
+
constructor(message) {
|
|
12
|
+
super(message);
|
|
13
|
+
this.name = "InvalidTTLError";
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
var NotFoundError = class extends Error {
|
|
17
|
+
constructor(message) {
|
|
18
|
+
super(message);
|
|
19
|
+
this.name = "NotFoundError";
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
var SerializationError = class extends Error {
|
|
23
|
+
constructor(message) {
|
|
24
|
+
super(message);
|
|
25
|
+
this.name = "SerializationError";
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
var DeserializationError = class extends Error {
|
|
29
|
+
constructor(message) {
|
|
30
|
+
super(message);
|
|
31
|
+
this.name = "DeserializationError";
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
//#endregion
|
|
3
35
|
//#region src/lib/cache/index.ts
|
|
4
36
|
var Cache = class {
|
|
5
37
|
options;
|
|
@@ -11,41 +43,34 @@ var Cache = class {
|
|
|
11
43
|
this.deserialize = options.deserializer ?? ((raw) => JSON.parse(raw));
|
|
12
44
|
}
|
|
13
45
|
async get(key) {
|
|
14
|
-
if (!this.isEnabled)
|
|
46
|
+
if (!this.isEnabled) throw new NotFoundError(`Key ${key} not found`);
|
|
15
47
|
const resolvedKey = this.resolveKey(key);
|
|
16
48
|
const [error, value] = await require_lib_errors_index.mightThrow(this.options.redis.get(resolvedKey));
|
|
17
|
-
if (error)
|
|
18
|
-
if (value === null || value === void 0)
|
|
49
|
+
if (error) throw new CacheError(`Unable to get value for key ${key}`);
|
|
50
|
+
if (value === null || value === void 0) throw new NotFoundError(`Key ${key} not found`);
|
|
19
51
|
const [deserializeErr, deserialized] = require_lib_errors_index.mightThrowSync(() => this.deserialize(value));
|
|
20
|
-
if (deserializeErr)
|
|
21
|
-
return
|
|
52
|
+
if (deserializeErr) throw new DeserializationError(`Unable to deserialize value for key ${key}`);
|
|
53
|
+
return deserialized;
|
|
22
54
|
}
|
|
23
55
|
async set(key, value) {
|
|
24
|
-
if (!this.isEnabled) return
|
|
56
|
+
if (!this.isEnabled) return value;
|
|
25
57
|
const [serializeErr, serialized] = require_lib_errors_index.mightThrowSync(() => this.serialize(value));
|
|
26
|
-
if (serializeErr)
|
|
27
|
-
if (serialized === null || serialized === void 0)
|
|
58
|
+
if (serializeErr) throw new SerializationError(`Unable to serialize value for key ${key}`);
|
|
59
|
+
if (serialized === null || serialized === void 0) throw new SerializationError(`Unable to serialize value for key ${key}`);
|
|
28
60
|
const [ttlErr, ttl] = require_lib_errors_index.mightThrowSync(() => this.resolveTTL(key, value));
|
|
29
|
-
if (ttlErr)
|
|
30
|
-
if (!this.isTTLValid(ttl))
|
|
61
|
+
if (ttlErr) throw new InvalidTTLError(`Unable to resolve ttl for key ${key}`);
|
|
62
|
+
if (!this.isTTLValid(ttl)) throw new InvalidTTLError(`Unable to save records with ttl equal to ${ttl}`);
|
|
31
63
|
const resolvedKey = this.resolveKey(key);
|
|
32
64
|
const [setError] = await require_lib_errors_index.mightThrow(this.getSetPromise(resolvedKey, serialized, ttl));
|
|
33
|
-
if (setError)
|
|
34
|
-
return
|
|
65
|
+
if (setError) throw new CacheError(`Unable to set value for key ${key}`);
|
|
66
|
+
return value;
|
|
35
67
|
}
|
|
36
68
|
async delete(key) {
|
|
37
|
-
if (!this.isEnabled) return
|
|
69
|
+
if (!this.isEnabled) return 0;
|
|
38
70
|
const resolvedKey = this.resolveKey(key);
|
|
39
71
|
const [error, data] = await require_lib_errors_index.mightThrow(this.options.redis.del(resolvedKey));
|
|
40
|
-
if (error)
|
|
41
|
-
return
|
|
42
|
-
}
|
|
43
|
-
fail(type, message) {
|
|
44
|
-
this.options.onError?.({
|
|
45
|
-
type,
|
|
46
|
-
message
|
|
47
|
-
});
|
|
48
|
-
return require_lib_errors_index.err(type, message);
|
|
72
|
+
if (error) throw new CacheError(`Unable to delete key ${key}`);
|
|
73
|
+
return data;
|
|
49
74
|
}
|
|
50
75
|
get isEnabled() {
|
|
51
76
|
return this.options.enabled !== false;
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
//#region src/lib/cache/types.d.ts
|
|
2
|
-
type CacheError = "CacheError" | "InvalidTTLError" | "NotFoundError";
|
|
3
2
|
type CacheOptions<T> = {
|
|
4
3
|
redis: Bun.RedisClient;
|
|
5
4
|
ttl?: number | ((key: string, value: T) => number);
|
|
@@ -7,10 +6,6 @@ type CacheOptions<T> = {
|
|
|
7
6
|
prefix?: string;
|
|
8
7
|
serializer?: (value: T) => string;
|
|
9
8
|
deserializer?: (raw: string) => T;
|
|
10
|
-
onError?: (error: {
|
|
11
|
-
type: CacheError;
|
|
12
|
-
message: string;
|
|
13
|
-
}) => void;
|
|
14
9
|
};
|
|
15
10
|
//#endregion
|
|
16
11
|
//#region src/lib/cache/index.d.ts
|
|
@@ -19,25 +14,9 @@ declare class Cache<T> {
|
|
|
19
14
|
private serialize;
|
|
20
15
|
private deserialize;
|
|
21
16
|
constructor(options: CacheOptions<T>);
|
|
22
|
-
get(key: string): Promise<
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
}, null] | readonly [{
|
|
26
|
-
readonly type: "CacheError";
|
|
27
|
-
readonly message: string;
|
|
28
|
-
}, null] | readonly [null, T]>;
|
|
29
|
-
set(key: string, value: T): Promise<readonly [{
|
|
30
|
-
readonly type: "CacheError";
|
|
31
|
-
readonly message: string;
|
|
32
|
-
}, null] | readonly [null, T] | readonly [{
|
|
33
|
-
readonly type: "InvalidTTLError";
|
|
34
|
-
readonly message: string;
|
|
35
|
-
}, null]>;
|
|
36
|
-
delete(key: string): Promise<readonly [null, number] | readonly [{
|
|
37
|
-
readonly type: "CacheError";
|
|
38
|
-
readonly message: string;
|
|
39
|
-
}, null]>;
|
|
40
|
-
private fail;
|
|
17
|
+
get(key: string): Promise<T>;
|
|
18
|
+
set(key: string, value: T): Promise<T>;
|
|
19
|
+
delete(key: string): Promise<number>;
|
|
41
20
|
private get isEnabled();
|
|
42
21
|
private resolveKey;
|
|
43
22
|
private resolveTTL;
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
//#region src/lib/cache/types.d.ts
|
|
2
|
-
type CacheError = "CacheError" | "InvalidTTLError" | "NotFoundError";
|
|
3
2
|
type CacheOptions<T> = {
|
|
4
3
|
redis: Bun.RedisClient;
|
|
5
4
|
ttl?: number | ((key: string, value: T) => number);
|
|
@@ -7,10 +6,6 @@ type CacheOptions<T> = {
|
|
|
7
6
|
prefix?: string;
|
|
8
7
|
serializer?: (value: T) => string;
|
|
9
8
|
deserializer?: (raw: string) => T;
|
|
10
|
-
onError?: (error: {
|
|
11
|
-
type: CacheError;
|
|
12
|
-
message: string;
|
|
13
|
-
}) => void;
|
|
14
9
|
};
|
|
15
10
|
//#endregion
|
|
16
11
|
//#region src/lib/cache/index.d.ts
|
|
@@ -19,25 +14,9 @@ declare class Cache<T> {
|
|
|
19
14
|
private serialize;
|
|
20
15
|
private deserialize;
|
|
21
16
|
constructor(options: CacheOptions<T>);
|
|
22
|
-
get(key: string): Promise<
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
}, null] | readonly [{
|
|
26
|
-
readonly type: "CacheError";
|
|
27
|
-
readonly message: string;
|
|
28
|
-
}, null] | readonly [null, T]>;
|
|
29
|
-
set(key: string, value: T): Promise<readonly [{
|
|
30
|
-
readonly type: "CacheError";
|
|
31
|
-
readonly message: string;
|
|
32
|
-
}, null] | readonly [null, T] | readonly [{
|
|
33
|
-
readonly type: "InvalidTTLError";
|
|
34
|
-
readonly message: string;
|
|
35
|
-
}, null]>;
|
|
36
|
-
delete(key: string): Promise<readonly [null, number] | readonly [{
|
|
37
|
-
readonly type: "CacheError";
|
|
38
|
-
readonly message: string;
|
|
39
|
-
}, null]>;
|
|
40
|
-
private fail;
|
|
17
|
+
get(key: string): Promise<T>;
|
|
18
|
+
set(key: string, value: T): Promise<T>;
|
|
19
|
+
delete(key: string): Promise<number>;
|
|
41
20
|
private get isEnabled();
|
|
42
21
|
private resolveKey;
|
|
43
22
|
private resolveTTL;
|