@digilogiclabs/platform-core 1.2.0 → 1.3.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 CHANGED
@@ -1,545 +1,583 @@
1
- # @digilogiclabs/platform-core
2
-
3
- > Vendor-agnostic infrastructure abstraction layer for building portable, enterprise-grade applications.
4
-
5
- [![Tests](https://img.shields.io/badge/tests-343%20passing-brightgreen)](./tests)
6
- [![Adapters](https://img.shields.io/badge/adapters-14-blue)](./src/adapters)
7
- [![Interfaces](https://img.shields.io/badge/interfaces-12-blue)](./src/interfaces)
8
-
9
- ## Overview
10
-
11
- Platform Core provides a unified API for common infrastructure services, allowing you to swap providers without changing application code. Build once, deploy anywhere.
12
-
13
- ## Features
14
-
15
- ### Core Infrastructure
16
- - **Database** - Query builder abstraction (PostgreSQL, Supabase, Memory)
17
- - **Cache** - Key-value caching (Redis, Upstash, Memory)
18
- - **Storage** - File storage (S3/MinIO/R2, Supabase Storage, Memory)
19
- - **Email** - Transactional email (SMTP, Resend, Console, Memory)
20
- - **Queue** - Background jobs (BullMQ, Memory)
21
- - **Tracing** - Distributed tracing (OpenTelemetry, Memory, Noop)
22
- - **Health Checks** - Built-in health monitoring for all services
23
-
24
- ### Enterprise Patterns
25
- - **Middleware** - Composable before/after hooks for all operations
26
- - **Hooks** - Lifecycle events for database, cache, email, queue operations
27
- - **Resilience** - Retry, circuit breaker, timeout, bulkhead, fallback patterns
28
- - **Metrics** - Counters, gauges, histograms, timings with tag support
29
-
30
- ## Installation
31
-
32
- ```bash
33
- npm install @digilogiclabs/platform-core
34
- # or
35
- pnpm add @digilogiclabs/platform-core
36
- ```
37
-
38
- ### Optional Peer Dependencies
39
-
40
- Install only the providers you need:
41
-
42
- ```bash
43
- # For Supabase database
44
- pnpm add @supabase/supabase-js
45
-
46
- # For Upstash cache
47
- pnpm add @upstash/redis
48
-
49
- # For S3 storage
50
- pnpm add @aws-sdk/client-s3 @aws-sdk/s3-request-presigner
51
-
52
- # For Resend email
53
- pnpm add resend
54
- ```
55
-
56
- ## Quick Start
57
-
58
- ### Development (Memory Adapters)
59
-
60
- ```typescript
61
- import { createPlatform } from '@digilogiclabs/platform-core';
62
-
63
- // Uses memory adapters by default - no external services needed
64
- const platform = createPlatform();
65
-
66
- // Use the platform
67
- const users = await platform.db.from('users').where('active', '=', true).execute();
68
- await platform.cache.set('user:123', users.data[0], 3600);
69
- await platform.email.send({
70
- to: 'user@example.com',
71
- subject: 'Welcome!',
72
- text: 'Hello from Platform Core',
73
- });
74
- ```
75
-
76
- ### Production (Real Adapters)
77
-
78
- ```typescript
79
- import { createPlatformAsync } from '@digilogiclabs/platform-core';
80
-
81
- // Use environment variables to configure providers
82
- const platform = await createPlatformAsync();
83
-
84
- // Or configure explicitly
85
- const platform = await createPlatformAsync({
86
- database: { provider: 'supabase' },
87
- cache: { provider: 'upstash' },
88
- storage: { provider: 's3' },
89
- email: { provider: 'resend' },
90
- });
91
- ```
92
-
93
- ## Environment Variables
94
-
95
- ```bash
96
- # Provider selection
97
- PLATFORM_DB_PROVIDER=memory|supabase
98
- PLATFORM_CACHE_PROVIDER=memory|upstash
99
- PLATFORM_STORAGE_PROVIDER=memory|s3|minio|r2
100
- PLATFORM_EMAIL_PROVIDER=memory|console|resend
101
- PLATFORM_QUEUE_PROVIDER=memory
102
-
103
- # Supabase
104
- SUPABASE_URL=https://your-project.supabase.co
105
- SUPABASE_ANON_KEY=your-anon-key
106
- SUPABASE_SERVICE_ROLE_KEY=your-service-role-key
107
-
108
- # Upstash
109
- UPSTASH_REDIS_REST_URL=https://your-redis.upstash.io
110
- UPSTASH_REDIS_REST_TOKEN=your-token
111
-
112
- # S3 / MinIO / R2
113
- S3_ENDPOINT=https://s3.amazonaws.com
114
- S3_REGION=us-east-1
115
- S3_ACCESS_KEY_ID=your-key
116
- S3_SECRET_ACCESS_KEY=your-secret
117
- S3_BUCKET=your-bucket
118
- S3_FORCE_PATH_STYLE=false
119
-
120
- # Resend
121
- RESEND_API_KEY=re_your_api_key
122
- EMAIL_FROM=noreply@yourdomain.com
123
- ```
124
-
125
- ## API Reference
126
-
127
- ### Platform
128
-
129
- ```typescript
130
- interface IPlatform {
131
- db: IDatabase;
132
- cache: ICache;
133
- storage: IStorage;
134
- email: IEmail;
135
- queue: IQueue;
136
-
137
- healthCheck(): Promise<PlatformHealthStatus>;
138
- close(): Promise<void>;
139
- }
140
- ```
141
-
142
- ### Database
143
-
144
- ```typescript
145
- // Query builder
146
- const users = await platform.db
147
- .from<User>('users')
148
- .where('active', '=', true)
149
- .orderBy('created_at', 'desc')
150
- .limit(10)
151
- .execute();
152
-
153
- // Insert
154
- await platform.db
155
- .from<User>('users')
156
- .insert({ name: 'John', email: 'john@example.com' })
157
- .execute();
158
-
159
- // Update
160
- await platform.db
161
- .from<User>('users')
162
- .where('id', '=', '123')
163
- .update({ name: 'Jane' })
164
- .execute();
165
-
166
- // Delete
167
- await platform.db
168
- .from<User>('users')
169
- .where('id', '=', '123')
170
- .delete()
171
- .execute();
172
- ```
173
-
174
- ### Cache
175
-
176
- ```typescript
177
- // Basic operations
178
- await platform.cache.set('key', value, 3600); // TTL in seconds
179
- const value = await platform.cache.get<User>('key');
180
- await platform.cache.delete('key');
181
-
182
- // Batch operations
183
- const values = await platform.cache.mget(['key1', 'key2', 'key3']);
184
- await platform.cache.mset([
185
- { key: 'a', value: 1 },
186
- { key: 'b', value: 2, ttl: 60 },
187
- ]);
188
-
189
- // Increment/Decrement
190
- const count = await platform.cache.incr('counter');
191
-
192
- // Pattern delete
193
- await platform.cache.deletePattern('user:*');
194
- ```
195
-
196
- ### Storage
197
-
198
- ```typescript
199
- // Upload
200
- const file = await platform.storage.upload('path/to/file.txt', buffer, {
201
- contentType: 'text/plain',
202
- });
203
-
204
- // Download
205
- const data = await platform.storage.download('path/to/file.txt');
206
-
207
- // Get signed URL
208
- const url = await platform.storage.getSignedUrl('path/to/file.txt', 3600);
209
-
210
- // Delete
211
- await platform.storage.delete('path/to/file.txt');
212
-
213
- // Check existence
214
- const exists = await platform.storage.exists('path/to/file.txt');
215
- ```
216
-
217
- ### Email
218
-
219
- ```typescript
220
- // Send email
221
- const result = await platform.email.send({
222
- to: 'user@example.com',
223
- from: 'noreply@yourdomain.com',
224
- subject: 'Hello',
225
- text: 'Plain text body',
226
- html: '<h1>HTML body</h1>',
227
- });
228
-
229
- // Batch send
230
- const results = await platform.email.sendBatch([
231
- { to: 'a@example.com', subject: 'A', text: 'A' },
232
- { to: 'b@example.com', subject: 'B', text: 'B' },
233
- ]);
234
- ```
235
-
236
- ### Queue
237
-
238
- ```typescript
239
- // Add job
240
- const job = await platform.queue.add('sendEmail', {
241
- userId: '123',
242
- template: 'welcome',
243
- });
244
-
245
- // Process jobs
246
- platform.queue.process(async (job) => {
247
- console.log('Processing:', job.name, job.data);
248
- return { success: true };
249
- });
250
-
251
- // Get job status
252
- const job = await platform.queue.getJob('job_id');
253
- ```
254
-
255
- ### Health Checks
256
-
257
- ```typescript
258
- const health = await platform.healthCheck();
259
-
260
- console.log(health);
261
- // {
262
- // healthy: true,
263
- // services: {
264
- // database: true,
265
- // cache: true,
266
- // storage: true,
267
- // email: true,
268
- // queue: true,
269
- // },
270
- // timestamp: 1701234567890,
271
- // }
272
- ```
273
-
274
- ## Testing
275
-
276
- Use memory adapters for fast, isolated tests:
277
-
278
- ```typescript
279
- import { createPlatform, MemoryDatabase, MemoryCache } from '@digilogiclabs/platform-core';
280
-
281
- describe('MyService', () => {
282
- const platform = createPlatform(); // Uses memory adapters
283
-
284
- beforeEach(async () => {
285
- // Reset state between tests
286
- await platform.close();
287
- });
288
-
289
- it('should create user', async () => {
290
- const result = await platform.db
291
- .from('users')
292
- .insert({ name: 'Test' })
293
- .execute();
294
-
295
- expect(result.data).toHaveLength(1);
296
- });
297
- });
298
- ```
299
-
300
- ## Direct Adapter Usage
301
-
302
- You can also use adapters directly:
303
-
304
- ```typescript
305
- import {
306
- MemoryDatabase,
307
- MemoryCache,
308
- SupabaseDatabase,
309
- UpstashCache,
310
- S3Storage,
311
- ResendEmail,
312
- ConsoleEmail,
313
- } from '@digilogiclabs/platform-core';
314
-
315
- // Create adapters directly
316
- const db = new MemoryDatabase();
317
- const cache = new MemoryCache();
318
- const email = new ConsoleEmail(); // Logs to console
319
- ```
320
-
321
- ## Migration from Direct Provider Usage
322
-
323
- ### Before (Direct Supabase)
324
-
325
- ```typescript
326
- import { createClient } from '@supabase/supabase-js';
327
-
328
- const supabase = createClient(url, key);
329
- const { data } = await supabase.from('users').select('*').eq('active', true);
330
- ```
331
-
332
- ### After (Platform Core)
333
-
334
- ```typescript
335
- import { createPlatformAsync } from '@digilogiclabs/platform-core';
336
-
337
- const platform = await createPlatformAsync();
338
- const result = await platform.db.from('users').where('active', '=', true).execute();
339
- ```
340
-
341
- ## Enterprise Patterns
342
-
343
- ### Middleware
344
-
345
- Compose middleware for cross-cutting concerns:
346
-
347
- ```typescript
348
- import { createMiddlewareChain, createLoggingMiddleware, createMetricsMiddleware } from '@digilogiclabs/platform-core';
349
-
350
- const chain = createMiddlewareChain()
351
- .use(createLoggingMiddleware(logger))
352
- .use(createMetricsMiddleware(metrics))
353
- .use({
354
- name: 'custom',
355
- before: (ctx) => console.log('Before:', ctx.operation),
356
- after: (ctx) => console.log('After:', ctx.operation, ctx.duration + 'ms'),
357
- onError: (ctx, error) => console.error('Error:', error),
358
- });
359
-
360
- // Execute with middleware
361
- const result = await chain.execute(
362
- { service: 'database', operation: 'query', args: { table: 'users' }, logger, startTime: Date.now(), correlationId: 'abc' },
363
- async () => db.from('users').execute()
364
- );
365
- ```
366
-
367
- ### Hooks
368
-
369
- Register lifecycle hooks for platform events:
370
-
371
- ```typescript
372
- import { createHookRegistry } from '@digilogiclabs/platform-core';
373
-
374
- const hooks = createHookRegistry(logger);
375
-
376
- hooks.register({
377
- onReady: () => console.log('Platform ready'),
378
- onShutdown: () => console.log('Shutting down'),
379
- beforeQuery: ({ table, operation }) => console.log(`Query: ${operation} on ${table}`),
380
- afterQuery: ({ table, duration }) => console.log(`Query completed in ${duration}ms`),
381
- onCacheHit: (key, value) => console.log(`Cache hit: ${key}`),
382
- onCacheMiss: (key) => console.log(`Cache miss: ${key}`),
383
- onError: ({ service, operation, error }) => console.error(`Error in ${service}.${operation}:`, error),
384
- });
385
-
386
- // Execute hooks
387
- await hooks.execute('onReady');
388
- await hooks.execute('beforeQuery', { table: 'users', operation: 'select' });
389
- ```
390
-
391
- ### Resilience Patterns
392
-
393
- #### Retry with Exponential Backoff
394
-
395
- ```typescript
396
- import { withRetry, RetryConfigs, RetryPredicates } from '@digilogiclabs/platform-core';
397
-
398
- const result = await withRetry(
399
- () => fetchData(),
400
- {
401
- maxAttempts: 3,
402
- baseDelay: 100,
403
- maxDelay: 5000,
404
- backoffMultiplier: 2,
405
- shouldRetry: RetryPredicates.networkErrors,
406
- }
407
- );
408
-
409
- // Or use presets
410
- const result = await withRetry(() => fetchData(), RetryConfigs.standard);
411
- ```
412
-
413
- #### Circuit Breaker
414
-
415
- ```typescript
416
- import { CircuitBreaker, CircuitBreakerRegistry } from '@digilogiclabs/platform-core';
417
-
418
- const breaker = new CircuitBreaker({
419
- failureThreshold: 5,
420
- resetTimeout: 30000,
421
- halfOpenRequests: 3,
422
- });
423
-
424
- const result = await breaker.execute(() => externalApiCall());
425
-
426
- // Or use a registry for named breakers
427
- const registry = new CircuitBreakerRegistry();
428
- const apiBreaker = registry.get('external-api');
429
- ```
430
-
431
- #### Timeout
432
-
433
- ```typescript
434
- import { withTimeout, TimeoutError } from '@digilogiclabs/platform-core';
435
-
436
- try {
437
- const result = await withTimeout(() => slowOperation(), 5000);
438
- } catch (error) {
439
- if (error instanceof TimeoutError) {
440
- console.log('Operation timed out');
441
- }
442
- }
443
- ```
444
-
445
- #### Bulkhead (Concurrency Isolation)
446
-
447
- ```typescript
448
- import { Bulkhead } from '@digilogiclabs/platform-core';
449
-
450
- const bulkhead = new Bulkhead({
451
- maxConcurrent: 10,
452
- maxQueued: 100,
453
- timeout: 30000,
454
- });
455
-
456
- const result = await bulkhead.execute(() => cpuIntensiveTask());
457
- ```
458
-
459
- #### Fallback
460
-
461
- ```typescript
462
- import { withFallback, FallbackStrategies } from '@digilogiclabs/platform-core';
463
-
464
- // Static fallback
465
- const result = await withFallback(
466
- () => fetchFromApi(),
467
- FallbackStrategies.value({ cached: true, data: [] })
468
- );
469
-
470
- // Dynamic fallback
471
- const result = await withFallback(
472
- () => fetchFromPrimary(),
473
- FallbackStrategies.execute(() => fetchFromSecondary())
474
- );
475
- ```
476
-
477
- ### Metrics
478
-
479
- Track application metrics with a provider-agnostic interface:
480
-
481
- ```typescript
482
- import { MemoryMetrics, createScopedMetrics } from '@digilogiclabs/platform-core';
483
-
484
- const metrics = new MemoryMetrics();
485
-
486
- // Counter
487
- metrics.increment('api.requests', 1, { method: 'GET', path: '/users' });
488
- metrics.decrement('active.connections');
489
-
490
- // Gauge
491
- metrics.gauge('queue.size', 42, { queue: 'emails' });
492
-
493
- // Histogram
494
- metrics.histogram('response.size', 1024, { endpoint: '/api/users' });
495
-
496
- // Timer
497
- const stopTimer = metrics.startTimer('api.request.duration', { method: 'POST' });
498
- // ... do work ...
499
- stopTimer(); // Records duration
500
-
501
- // Timing
502
- metrics.timing('db.query.duration', 42, { table: 'users' });
503
-
504
- // Scoped metrics with prefix
505
- const dbMetrics = createScopedMetrics(metrics, 'database', { service: 'users' });
506
- dbMetrics.timing('query', 50); // Records as 'database.query' with service=users tag
507
-
508
- // Get summary (for testing)
509
- const summary = metrics.getSummary();
510
- console.log(summary.counters, summary.timings);
511
- ```
512
-
513
- ## Local Development
514
-
515
- Start the development infrastructure:
516
-
517
- ```bash
518
- # Start core services (PostgreSQL, Redis, MinIO, MailHog)
519
- ./infrastructure/scripts/dev.sh start
520
-
521
- # Start with observability (adds Prometheus, Grafana)
522
- ./infrastructure/scripts/dev.sh start:obs
523
-
524
- # Start with dev tools (adds PgAdmin, RedisInsight)
525
- ./infrastructure/scripts/dev.sh start:tools
526
-
527
- # Check service health
528
- ./infrastructure/scripts/dev.sh health
529
-
530
- # Connect to databases
531
- ./infrastructure/scripts/dev.sh psql
532
- ./infrastructure/scripts/dev.sh redis-cli
533
- ```
534
-
535
- Service URLs:
536
- - PostgreSQL: `localhost:5432` (user: dll, pass: development)
537
- - Redis: `localhost:6379` (pass: development)
538
- - MinIO: `localhost:9000` (console: 9001)
539
- - MailHog: `localhost:8025` (SMTP: 1025)
540
- - Prometheus: `localhost:9090` (with observability profile)
541
- - Grafana: `localhost:3001` (with observability profile)
542
-
543
- ## License
544
-
545
- MIT
1
+ # @digilogiclabs/platform-core
2
+
3
+ > Vendor-agnostic infrastructure abstraction layer for building portable, enterprise-grade applications.
4
+
5
+ [![Tests](https://img.shields.io/badge/tests-343%20passing-brightgreen)](./tests)
6
+ [![Adapters](https://img.shields.io/badge/adapters-14-blue)](./src/adapters)
7
+ [![Interfaces](https://img.shields.io/badge/interfaces-12-blue)](./src/interfaces)
8
+
9
+ ## Overview
10
+
11
+ Platform Core provides a unified API for common infrastructure services, allowing you to swap providers without changing application code. Build once, deploy anywhere.
12
+
13
+ ## Features
14
+
15
+ ### Core Infrastructure
16
+
17
+ - **Database** - Query builder abstraction (PostgreSQL, Supabase, Memory)
18
+ - **Cache** - Key-value caching (Redis, Upstash, Memory)
19
+ - **Storage** - File storage (S3/MinIO/R2, Supabase Storage, Memory)
20
+ - **Email** - Transactional email (SMTP, Resend, Console, Memory)
21
+ - **Queue** - Background jobs (BullMQ, Memory)
22
+ - **Tracing** - Distributed tracing (OpenTelemetry, Memory, Noop)
23
+ - **Health Checks** - Built-in health monitoring for all services
24
+
25
+ ### Enterprise Patterns
26
+
27
+ - **Middleware** - Composable before/after hooks for all operations
28
+ - **Hooks** - Lifecycle events for database, cache, email, queue operations
29
+ - **Resilience** - Retry, circuit breaker, timeout, bulkhead, fallback patterns
30
+ - **Metrics** - Counters, gauges, histograms, timings with tag support
31
+
32
+ ## Installation
33
+
34
+ ```bash
35
+ npm install @digilogiclabs/platform-core
36
+ # or
37
+ pnpm add @digilogiclabs/platform-core
38
+ ```
39
+
40
+ ### Optional Peer Dependencies
41
+
42
+ Install only the providers you need:
43
+
44
+ ```bash
45
+ # For Supabase database
46
+ pnpm add @supabase/supabase-js
47
+
48
+ # For Upstash cache
49
+ pnpm add @upstash/redis
50
+
51
+ # For S3 storage
52
+ pnpm add @aws-sdk/client-s3 @aws-sdk/s3-request-presigner
53
+
54
+ # For Resend email
55
+ pnpm add resend
56
+ ```
57
+
58
+ ## Quick Start
59
+
60
+ ### Development (Memory Adapters)
61
+
62
+ ```typescript
63
+ import { createPlatform } from "@digilogiclabs/platform-core";
64
+
65
+ // Uses memory adapters by default - no external services needed
66
+ const platform = createPlatform();
67
+
68
+ // Use the platform
69
+ const users = await platform.db
70
+ .from("users")
71
+ .where("active", "=", true)
72
+ .execute();
73
+ await platform.cache.set("user:123", users.data[0], 3600);
74
+ await platform.email.send({
75
+ to: "user@example.com",
76
+ subject: "Welcome!",
77
+ text: "Hello from Platform Core",
78
+ });
79
+ ```
80
+
81
+ ### Production (Real Adapters)
82
+
83
+ ```typescript
84
+ import { createPlatformAsync } from "@digilogiclabs/platform-core";
85
+
86
+ // Use environment variables to configure providers
87
+ const platform = await createPlatformAsync();
88
+
89
+ // Or configure explicitly
90
+ const platform = await createPlatformAsync({
91
+ database: { provider: "supabase" },
92
+ cache: { provider: "upstash" },
93
+ storage: { provider: "s3" },
94
+ email: { provider: "resend" },
95
+ });
96
+ ```
97
+
98
+ ## Environment Variables
99
+
100
+ ```bash
101
+ # Provider selection
102
+ PLATFORM_DB_PROVIDER=memory|supabase
103
+ PLATFORM_CACHE_PROVIDER=memory|upstash
104
+ PLATFORM_STORAGE_PROVIDER=memory|s3|minio|r2
105
+ PLATFORM_EMAIL_PROVIDER=memory|console|resend
106
+ PLATFORM_QUEUE_PROVIDER=memory
107
+
108
+ # Supabase
109
+ SUPABASE_URL=https://your-project.supabase.co
110
+ SUPABASE_ANON_KEY=your-anon-key
111
+ SUPABASE_SERVICE_ROLE_KEY=your-service-role-key
112
+
113
+ # Upstash
114
+ UPSTASH_REDIS_REST_URL=https://your-redis.upstash.io
115
+ UPSTASH_REDIS_REST_TOKEN=your-token
116
+
117
+ # S3 / MinIO / R2
118
+ S3_ENDPOINT=https://s3.amazonaws.com
119
+ S3_REGION=us-east-1
120
+ S3_ACCESS_KEY_ID=your-key
121
+ S3_SECRET_ACCESS_KEY=your-secret
122
+ S3_BUCKET=your-bucket
123
+ S3_FORCE_PATH_STYLE=false
124
+
125
+ # Resend
126
+ RESEND_API_KEY=re_your_api_key
127
+ EMAIL_FROM=noreply@yourdomain.com
128
+ ```
129
+
130
+ ## API Reference
131
+
132
+ ### Platform
133
+
134
+ ```typescript
135
+ interface IPlatform {
136
+ db: IDatabase;
137
+ cache: ICache;
138
+ storage: IStorage;
139
+ email: IEmail;
140
+ queue: IQueue;
141
+
142
+ healthCheck(): Promise<PlatformHealthStatus>;
143
+ close(): Promise<void>;
144
+ }
145
+ ```
146
+
147
+ ### Database
148
+
149
+ ```typescript
150
+ // Query builder
151
+ const users = await platform.db
152
+ .from<User>("users")
153
+ .where("active", "=", true)
154
+ .orderBy("created_at", "desc")
155
+ .limit(10)
156
+ .execute();
157
+
158
+ // Insert
159
+ await platform.db
160
+ .from<User>("users")
161
+ .insert({ name: "John", email: "john@example.com" })
162
+ .execute();
163
+
164
+ // Update
165
+ await platform.db
166
+ .from<User>("users")
167
+ .where("id", "=", "123")
168
+ .update({ name: "Jane" })
169
+ .execute();
170
+
171
+ // Delete
172
+ await platform.db
173
+ .from<User>("users")
174
+ .where("id", "=", "123")
175
+ .delete()
176
+ .execute();
177
+ ```
178
+
179
+ ### Cache
180
+
181
+ ```typescript
182
+ // Basic operations
183
+ await platform.cache.set("key", value, 3600); // TTL in seconds
184
+ const value = await platform.cache.get<User>("key");
185
+ await platform.cache.delete("key");
186
+
187
+ // Batch operations
188
+ const values = await platform.cache.mget(["key1", "key2", "key3"]);
189
+ await platform.cache.mset([
190
+ { key: "a", value: 1 },
191
+ { key: "b", value: 2, ttl: 60 },
192
+ ]);
193
+
194
+ // Increment/Decrement
195
+ const count = await platform.cache.incr("counter");
196
+
197
+ // Pattern delete
198
+ await platform.cache.deletePattern("user:*");
199
+ ```
200
+
201
+ ### Storage
202
+
203
+ ```typescript
204
+ // Upload
205
+ const file = await platform.storage.upload("path/to/file.txt", buffer, {
206
+ contentType: "text/plain",
207
+ });
208
+
209
+ // Download
210
+ const data = await platform.storage.download("path/to/file.txt");
211
+
212
+ // Get signed URL
213
+ const url = await platform.storage.getSignedUrl("path/to/file.txt", 3600);
214
+
215
+ // Delete
216
+ await platform.storage.delete("path/to/file.txt");
217
+
218
+ // Check existence
219
+ const exists = await platform.storage.exists("path/to/file.txt");
220
+ ```
221
+
222
+ ### Email
223
+
224
+ ```typescript
225
+ // Send email
226
+ const result = await platform.email.send({
227
+ to: "user@example.com",
228
+ from: "noreply@yourdomain.com",
229
+ subject: "Hello",
230
+ text: "Plain text body",
231
+ html: "<h1>HTML body</h1>",
232
+ });
233
+
234
+ // Batch send
235
+ const results = await platform.email.sendBatch([
236
+ { to: "a@example.com", subject: "A", text: "A" },
237
+ { to: "b@example.com", subject: "B", text: "B" },
238
+ ]);
239
+ ```
240
+
241
+ ### Queue
242
+
243
+ ```typescript
244
+ // Add job
245
+ const job = await platform.queue.add("sendEmail", {
246
+ userId: "123",
247
+ template: "welcome",
248
+ });
249
+
250
+ // Process jobs
251
+ platform.queue.process(async (job) => {
252
+ console.log("Processing:", job.name, job.data);
253
+ return { success: true };
254
+ });
255
+
256
+ // Get job status
257
+ const job = await platform.queue.getJob("job_id");
258
+ ```
259
+
260
+ ### Health Checks
261
+
262
+ ```typescript
263
+ const health = await platform.healthCheck();
264
+
265
+ console.log(health);
266
+ // {
267
+ // healthy: true,
268
+ // services: {
269
+ // database: true,
270
+ // cache: true,
271
+ // storage: true,
272
+ // email: true,
273
+ // queue: true,
274
+ // },
275
+ // timestamp: 1701234567890,
276
+ // }
277
+ ```
278
+
279
+ ## Testing
280
+
281
+ Use memory adapters for fast, isolated tests:
282
+
283
+ ```typescript
284
+ import {
285
+ createPlatform,
286
+ MemoryDatabase,
287
+ MemoryCache,
288
+ } from "@digilogiclabs/platform-core";
289
+
290
+ describe("MyService", () => {
291
+ const platform = createPlatform(); // Uses memory adapters
292
+
293
+ beforeEach(async () => {
294
+ // Reset state between tests
295
+ await platform.close();
296
+ });
297
+
298
+ it("should create user", async () => {
299
+ const result = await platform.db
300
+ .from("users")
301
+ .insert({ name: "Test" })
302
+ .execute();
303
+
304
+ expect(result.data).toHaveLength(1);
305
+ });
306
+ });
307
+ ```
308
+
309
+ ## Direct Adapter Usage
310
+
311
+ You can also use adapters directly:
312
+
313
+ ```typescript
314
+ import {
315
+ MemoryDatabase,
316
+ MemoryCache,
317
+ SupabaseDatabase,
318
+ UpstashCache,
319
+ S3Storage,
320
+ ResendEmail,
321
+ ConsoleEmail,
322
+ } from "@digilogiclabs/platform-core";
323
+
324
+ // Create adapters directly
325
+ const db = new MemoryDatabase();
326
+ const cache = new MemoryCache();
327
+ const email = new ConsoleEmail(); // Logs to console
328
+ ```
329
+
330
+ ## Migration from Direct Provider Usage
331
+
332
+ ### Before (Direct Supabase)
333
+
334
+ ```typescript
335
+ import { createClient } from "@supabase/supabase-js";
336
+
337
+ const supabase = createClient(url, key);
338
+ const { data } = await supabase.from("users").select("*").eq("active", true);
339
+ ```
340
+
341
+ ### After (Platform Core)
342
+
343
+ ```typescript
344
+ import { createPlatformAsync } from "@digilogiclabs/platform-core";
345
+
346
+ const platform = await createPlatformAsync();
347
+ const result = await platform.db
348
+ .from("users")
349
+ .where("active", "=", true)
350
+ .execute();
351
+ ```
352
+
353
+ ## Enterprise Patterns
354
+
355
+ ### Middleware
356
+
357
+ Compose middleware for cross-cutting concerns:
358
+
359
+ ```typescript
360
+ import {
361
+ createMiddlewareChain,
362
+ createLoggingMiddleware,
363
+ createMetricsMiddleware,
364
+ } from "@digilogiclabs/platform-core";
365
+
366
+ const chain = createMiddlewareChain()
367
+ .use(createLoggingMiddleware(logger))
368
+ .use(createMetricsMiddleware(metrics))
369
+ .use({
370
+ name: "custom",
371
+ before: (ctx) => console.log("Before:", ctx.operation),
372
+ after: (ctx) => console.log("After:", ctx.operation, ctx.duration + "ms"),
373
+ onError: (ctx, error) => console.error("Error:", error),
374
+ });
375
+
376
+ // Execute with middleware
377
+ const result = await chain.execute(
378
+ {
379
+ service: "database",
380
+ operation: "query",
381
+ args: { table: "users" },
382
+ logger,
383
+ startTime: Date.now(),
384
+ correlationId: "abc",
385
+ },
386
+ async () => db.from("users").execute(),
387
+ );
388
+ ```
389
+
390
+ ### Hooks
391
+
392
+ Register lifecycle hooks for platform events:
393
+
394
+ ```typescript
395
+ import { createHookRegistry } from "@digilogiclabs/platform-core";
396
+
397
+ const hooks = createHookRegistry(logger);
398
+
399
+ hooks.register({
400
+ onReady: () => console.log("Platform ready"),
401
+ onShutdown: () => console.log("Shutting down"),
402
+ beforeQuery: ({ table, operation }) =>
403
+ console.log(`Query: ${operation} on ${table}`),
404
+ afterQuery: ({ table, duration }) =>
405
+ console.log(`Query completed in ${duration}ms`),
406
+ onCacheHit: (key, value) => console.log(`Cache hit: ${key}`),
407
+ onCacheMiss: (key) => console.log(`Cache miss: ${key}`),
408
+ onError: ({ service, operation, error }) =>
409
+ console.error(`Error in ${service}.${operation}:`, error),
410
+ });
411
+
412
+ // Execute hooks
413
+ await hooks.execute("onReady");
414
+ await hooks.execute("beforeQuery", { table: "users", operation: "select" });
415
+ ```
416
+
417
+ ### Resilience Patterns
418
+
419
+ #### Retry with Exponential Backoff
420
+
421
+ ```typescript
422
+ import {
423
+ withRetry,
424
+ RetryConfigs,
425
+ RetryPredicates,
426
+ } from "@digilogiclabs/platform-core";
427
+
428
+ const result = await withRetry(() => fetchData(), {
429
+ maxAttempts: 3,
430
+ baseDelay: 100,
431
+ maxDelay: 5000,
432
+ backoffMultiplier: 2,
433
+ shouldRetry: RetryPredicates.networkErrors,
434
+ });
435
+
436
+ // Or use presets
437
+ const result = await withRetry(() => fetchData(), RetryConfigs.standard);
438
+ ```
439
+
440
+ #### Circuit Breaker
441
+
442
+ ```typescript
443
+ import {
444
+ CircuitBreaker,
445
+ CircuitBreakerRegistry,
446
+ } from "@digilogiclabs/platform-core";
447
+
448
+ const breaker = new CircuitBreaker({
449
+ failureThreshold: 5,
450
+ resetTimeout: 30000,
451
+ halfOpenRequests: 3,
452
+ });
453
+
454
+ const result = await breaker.execute(() => externalApiCall());
455
+
456
+ // Or use a registry for named breakers
457
+ const registry = new CircuitBreakerRegistry();
458
+ const apiBreaker = registry.get("external-api");
459
+ ```
460
+
461
+ #### Timeout
462
+
463
+ ```typescript
464
+ import { withTimeout, TimeoutError } from "@digilogiclabs/platform-core";
465
+
466
+ try {
467
+ const result = await withTimeout(() => slowOperation(), 5000);
468
+ } catch (error) {
469
+ if (error instanceof TimeoutError) {
470
+ console.log("Operation timed out");
471
+ }
472
+ }
473
+ ```
474
+
475
+ #### Bulkhead (Concurrency Isolation)
476
+
477
+ ```typescript
478
+ import { Bulkhead } from "@digilogiclabs/platform-core";
479
+
480
+ const bulkhead = new Bulkhead({
481
+ maxConcurrent: 10,
482
+ maxQueued: 100,
483
+ timeout: 30000,
484
+ });
485
+
486
+ const result = await bulkhead.execute(() => cpuIntensiveTask());
487
+ ```
488
+
489
+ #### Fallback
490
+
491
+ ```typescript
492
+ import { withFallback, FallbackStrategies } from "@digilogiclabs/platform-core";
493
+
494
+ // Static fallback
495
+ const result = await withFallback(
496
+ () => fetchFromApi(),
497
+ FallbackStrategies.value({ cached: true, data: [] }),
498
+ );
499
+
500
+ // Dynamic fallback
501
+ const result = await withFallback(
502
+ () => fetchFromPrimary(),
503
+ FallbackStrategies.execute(() => fetchFromSecondary()),
504
+ );
505
+ ```
506
+
507
+ ### Metrics
508
+
509
+ Track application metrics with a provider-agnostic interface:
510
+
511
+ ```typescript
512
+ import {
513
+ MemoryMetrics,
514
+ createScopedMetrics,
515
+ } from "@digilogiclabs/platform-core";
516
+
517
+ const metrics = new MemoryMetrics();
518
+
519
+ // Counter
520
+ metrics.increment("api.requests", 1, { method: "GET", path: "/users" });
521
+ metrics.decrement("active.connections");
522
+
523
+ // Gauge
524
+ metrics.gauge("queue.size", 42, { queue: "emails" });
525
+
526
+ // Histogram
527
+ metrics.histogram("response.size", 1024, { endpoint: "/api/users" });
528
+
529
+ // Timer
530
+ const stopTimer = metrics.startTimer("api.request.duration", {
531
+ method: "POST",
532
+ });
533
+ // ... do work ...
534
+ stopTimer(); // Records duration
535
+
536
+ // Timing
537
+ metrics.timing("db.query.duration", 42, { table: "users" });
538
+
539
+ // Scoped metrics with prefix
540
+ const dbMetrics = createScopedMetrics(metrics, "database", {
541
+ service: "users",
542
+ });
543
+ dbMetrics.timing("query", 50); // Records as 'database.query' with service=users tag
544
+
545
+ // Get summary (for testing)
546
+ const summary = metrics.getSummary();
547
+ console.log(summary.counters, summary.timings);
548
+ ```
549
+
550
+ ## Local Development
551
+
552
+ Start the development infrastructure:
553
+
554
+ ```bash
555
+ # Start core services (PostgreSQL, Redis, MinIO, MailHog)
556
+ ./infrastructure/scripts/dev.sh start
557
+
558
+ # Start with observability (adds Prometheus, Grafana)
559
+ ./infrastructure/scripts/dev.sh start:obs
560
+
561
+ # Start with dev tools (adds PgAdmin, RedisInsight)
562
+ ./infrastructure/scripts/dev.sh start:tools
563
+
564
+ # Check service health
565
+ ./infrastructure/scripts/dev.sh health
566
+
567
+ # Connect to databases
568
+ ./infrastructure/scripts/dev.sh psql
569
+ ./infrastructure/scripts/dev.sh redis-cli
570
+ ```
571
+
572
+ Service URLs:
573
+
574
+ - PostgreSQL: `localhost:5432` (user: dll, pass: development)
575
+ - Redis: `localhost:6379` (pass: development)
576
+ - MinIO: `localhost:9000` (console: 9001)
577
+ - MailHog: `localhost:8025` (SMTP: 1025)
578
+ - Prometheus: `localhost:9090` (with observability profile)
579
+ - Grafana: `localhost:3001` (with observability profile)
580
+
581
+ ## License
582
+
583
+ MIT