blendsdk 5.34.0 → 5.35.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 +169 -17
- package/package.json +14 -14
package/README.md
CHANGED
|
@@ -35,20 +35,31 @@ npm install blendsdk
|
|
|
35
35
|
### Web API with Express 5
|
|
36
36
|
|
|
37
37
|
```typescript
|
|
38
|
-
import { WebApplication,
|
|
38
|
+
import { WebApplication, BaseController, RouteDefinition } from "blendsdk/webafx";
|
|
39
|
+
|
|
40
|
+
// Define a controller with routes
|
|
41
|
+
class HelloController extends BaseController {
|
|
42
|
+
routes(): RouteDefinition[] {
|
|
43
|
+
return [
|
|
44
|
+
this.route()
|
|
45
|
+
.get("/hello")
|
|
46
|
+
.handle(async (_req, res) => {
|
|
47
|
+
this.ok(res, { message: "Hello from BlendSDK!" });
|
|
48
|
+
}),
|
|
49
|
+
];
|
|
50
|
+
}
|
|
51
|
+
}
|
|
39
52
|
|
|
53
|
+
// Create the application and register the controller
|
|
40
54
|
const app = new WebApplication({
|
|
41
|
-
|
|
42
|
-
|
|
55
|
+
PORT: 3000,
|
|
56
|
+
ENV_MODE: "development",
|
|
43
57
|
});
|
|
44
58
|
|
|
45
|
-
app.
|
|
46
|
-
RouteBuilder.get("/hello").handler((_req, res) => {
|
|
47
|
-
res.json({ message: "Hello from BlendSDK!" });
|
|
48
|
-
})
|
|
49
|
-
);
|
|
59
|
+
app.registerController("/api", HelloController);
|
|
50
60
|
|
|
51
|
-
await app.start();
|
|
61
|
+
const shutdown = await app.start();
|
|
62
|
+
// Server running → GET /api/hello returns { success: true, data: { message: "Hello from BlendSDK!" } }
|
|
52
63
|
```
|
|
53
64
|
|
|
54
65
|
### SQL Expression Building
|
|
@@ -58,16 +69,157 @@ import { query } from "blendsdk/expression";
|
|
|
58
69
|
|
|
59
70
|
// Build a type-safe WHERE clause
|
|
60
71
|
const filter = query()
|
|
61
|
-
.
|
|
62
|
-
.
|
|
63
|
-
.and()
|
|
64
|
-
.field("age")
|
|
65
|
-
.gte(18);
|
|
72
|
+
.where("status").equals("active")
|
|
73
|
+
.and("age").greaterThanOrEqual(18);
|
|
66
74
|
|
|
67
75
|
// Compile to parameterized SQL
|
|
68
|
-
const { sql,
|
|
69
|
-
// sql: "status
|
|
70
|
-
//
|
|
76
|
+
const { sql, params } = filter.compile();
|
|
77
|
+
// sql: "status = :p1 AND age >= :p2"
|
|
78
|
+
// params: { p1: "active", p2: 18 }
|
|
79
|
+
|
|
80
|
+
// Nested conditions with grouping
|
|
81
|
+
const advanced = query()
|
|
82
|
+
.where("status").equals("active")
|
|
83
|
+
.and(q => q
|
|
84
|
+
.where("age").greaterThan(21)
|
|
85
|
+
.or("verified").equals(true)
|
|
86
|
+
)
|
|
87
|
+
.compile();
|
|
88
|
+
// sql: "status = :p1 AND (age > :p2 OR verified = :p3)"
|
|
89
|
+
// params: { p1: "active", p2: 21, p3: true }
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### CLI Argument Parser
|
|
93
|
+
|
|
94
|
+
```typescript
|
|
95
|
+
import { CommandLineParser } from "blendsdk/cmdline";
|
|
96
|
+
|
|
97
|
+
const cli = new CommandLineParser({ name: "my-cli", version: "1.0.0" });
|
|
98
|
+
|
|
99
|
+
cli.addCommand({
|
|
100
|
+
name: "deploy",
|
|
101
|
+
description: "Deploy the application",
|
|
102
|
+
options: [
|
|
103
|
+
{
|
|
104
|
+
name: "environment",
|
|
105
|
+
short: "e",
|
|
106
|
+
type: "string",
|
|
107
|
+
required: true,
|
|
108
|
+
choices: ["dev", "staging", "production"],
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
name: "verbose",
|
|
112
|
+
short: "v",
|
|
113
|
+
type: "boolean",
|
|
114
|
+
description: "Verbose output",
|
|
115
|
+
},
|
|
116
|
+
],
|
|
117
|
+
handler: async (params) => {
|
|
118
|
+
console.log(`Deploying to ${params.environment}...`);
|
|
119
|
+
},
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
await cli.execute();
|
|
123
|
+
// Usage: my-cli deploy --environment=staging --verbose
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### Database CRUD Operations
|
|
127
|
+
|
|
128
|
+
```typescript
|
|
129
|
+
import { Database } from "blendsdk/dbcore";
|
|
130
|
+
|
|
131
|
+
// Insert with returning clause
|
|
132
|
+
const user = await db
|
|
133
|
+
.insert<{ name: string; email: string }>("users")
|
|
134
|
+
.values({ name: "Alice", email: "alice@example.com" })
|
|
135
|
+
.returning("*")
|
|
136
|
+
.execute();
|
|
137
|
+
|
|
138
|
+
// Update with filter
|
|
139
|
+
await db
|
|
140
|
+
.update<{ name: string }, { id: number }>("users")
|
|
141
|
+
.values({ name: "Bob" })
|
|
142
|
+
.filter({ id: 1 })
|
|
143
|
+
.returning("*")
|
|
144
|
+
.execute();
|
|
145
|
+
|
|
146
|
+
// Delete with expression filter
|
|
147
|
+
await db
|
|
148
|
+
.delete<{ status: string }>("users")
|
|
149
|
+
.filterByExpression(q => q.where("status").equals("inactive"))
|
|
150
|
+
.execute();
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### Caching
|
|
154
|
+
|
|
155
|
+
```typescript
|
|
156
|
+
import { MemoryCacheProvider } from "blendsdk/webafx-cache";
|
|
157
|
+
|
|
158
|
+
const cache = new MemoryCacheProvider({
|
|
159
|
+
rootKey: "MyApp",
|
|
160
|
+
defaultTTL: 300, // 5 minutes
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
// Simple set/get with type safety
|
|
164
|
+
await cache.set("user:1", { name: "Alice", role: "admin" });
|
|
165
|
+
const user = await cache.get<{ name: string; role: string }>("user:1");
|
|
166
|
+
|
|
167
|
+
// Cache-aside pattern (getOrSet)
|
|
168
|
+
const product = await cache.getOrSet(
|
|
169
|
+
"product:42",
|
|
170
|
+
async () => {
|
|
171
|
+
return await fetchProductFromDatabase(42);
|
|
172
|
+
},
|
|
173
|
+
60, // TTL in seconds
|
|
174
|
+
);
|
|
175
|
+
|
|
176
|
+
// Pattern-based deletion
|
|
177
|
+
await cache.deletePattern("user:*"); // Remove all user cache entries
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
### Pub/Sub Messaging
|
|
181
|
+
|
|
182
|
+
```typescript
|
|
183
|
+
import { MemoryPubSubProvider } from "blendsdk/webafx-cache";
|
|
184
|
+
|
|
185
|
+
const pubsub = new MemoryPubSubProvider();
|
|
186
|
+
|
|
187
|
+
// Subscribe to a specific channel with typed messages
|
|
188
|
+
await pubsub.subscribe<{ id: number; total: number }>("order:new", (msg) => {
|
|
189
|
+
console.log(`New order on ${msg.channel}:`, msg.data);
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
// Pattern subscription (wildcard matching)
|
|
193
|
+
await pubsub.psubscribe("order:*", (msg) => {
|
|
194
|
+
console.log(`Order event [${msg.pattern}] on ${msg.channel}`);
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
// Publish returns the number of receivers
|
|
198
|
+
const receiverCount = await pubsub.publish("order:new", { id: 1, total: 99.99 });
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### Internationalization
|
|
202
|
+
|
|
203
|
+
```typescript
|
|
204
|
+
import { Translator } from "blendsdk/i18n";
|
|
205
|
+
|
|
206
|
+
const translator = new Translator({
|
|
207
|
+
defaultLocale: "en",
|
|
208
|
+
catalog: {
|
|
209
|
+
greeting: { en: "Hello ${name}", nl: "Hallo ${name}" },
|
|
210
|
+
farewell: { en: "Goodbye", nl: "Tot ziens" },
|
|
211
|
+
book: {
|
|
212
|
+
en: ["${count} book", "${count} books"],
|
|
213
|
+
nl: ["${count} boek", "${count} boeken"],
|
|
214
|
+
},
|
|
215
|
+
},
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
translator.translate("greeting", "en", { name: "Alice" }); // "Hello Alice"
|
|
219
|
+
translator.translate("greeting", "nl", { name: "Alice" }); // "Hallo Alice"
|
|
220
|
+
translator.translate("book", "en", { count: 1 }); // "1 book"
|
|
221
|
+
translator.translate("book", "en", { count: 5 }); // "5 books"
|
|
222
|
+
translator.translate("farewell", "en_GB"); // "Goodbye" (falls back to "en")
|
|
71
223
|
```
|
|
72
224
|
|
|
73
225
|
### Utilities
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "blendsdk",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.35.0",
|
|
4
4
|
"description": "Enterprise-grade TypeScript SDK for web applications, database operations, caching, pub/sub, email, i18n, and code generation",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
@@ -74,21 +74,21 @@
|
|
|
74
74
|
"prepack": "npm run build"
|
|
75
75
|
},
|
|
76
76
|
"dependencies": {
|
|
77
|
-
"zod": "^4.
|
|
77
|
+
"zod": "^4.3.6"
|
|
78
78
|
},
|
|
79
79
|
"devDependencies": {
|
|
80
|
-
"@blendsdk/stdlib": "5.
|
|
81
|
-
"@blendsdk/cmdline": "5.
|
|
82
|
-
"@blendsdk/expression": "5.
|
|
83
|
-
"@blendsdk/dbcore": "5.
|
|
84
|
-
"@blendsdk/postgresql": "5.
|
|
85
|
-
"@blendsdk/webafx": "5.
|
|
86
|
-
"@blendsdk/webafx-cache": "5.
|
|
87
|
-
"@blendsdk/webafx-mailer": "5.
|
|
88
|
-
"@blendsdk/webafx-auth": "5.
|
|
89
|
-
"@blendsdk/i18n": "5.
|
|
90
|
-
"@blendsdk/webafx-i18n": "5.
|
|
91
|
-
"@blendsdk/codegen": "5.
|
|
80
|
+
"@blendsdk/stdlib": "5.35.0",
|
|
81
|
+
"@blendsdk/cmdline": "5.35.0",
|
|
82
|
+
"@blendsdk/expression": "5.35.0",
|
|
83
|
+
"@blendsdk/dbcore": "5.35.0",
|
|
84
|
+
"@blendsdk/postgresql": "5.35.0",
|
|
85
|
+
"@blendsdk/webafx": "5.35.0",
|
|
86
|
+
"@blendsdk/webafx-cache": "5.35.0",
|
|
87
|
+
"@blendsdk/webafx-mailer": "5.35.0",
|
|
88
|
+
"@blendsdk/webafx-auth": "5.35.0",
|
|
89
|
+
"@blendsdk/i18n": "5.35.0",
|
|
90
|
+
"@blendsdk/webafx-i18n": "5.35.0",
|
|
91
|
+
"@blendsdk/codegen": "5.35.0"
|
|
92
92
|
},
|
|
93
93
|
"peerDependencies": {
|
|
94
94
|
"typescript": "^5.6.0",
|