alepha 0.11.9 → 0.11.11
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 +61 -17
- package/dist/index.cjs +17089 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +17088 -0
- package/dist/index.js.map +1 -0
- package/package.json +42 -365
- package/src/assets/biomeJson.ts +33 -0
- package/src/assets/tsconfigJson.ts +18 -0
- package/src/assets/viteConfigTs.ts +14 -0
- package/src/commands/BiomeCommands.ts +41 -0
- package/src/commands/CoreCommands.ts +169 -0
- package/src/commands/DrizzleCommands.ts +228 -0
- package/src/commands/VerifyCommands.ts +44 -0
- package/src/commands/ViteCommands.ts +119 -0
- package/src/index.ts +35 -0
- package/src/services/ProcessRunner.ts +89 -0
- package/src/services/ProjectUtils.ts +508 -0
- package/src/version.ts +7 -0
- package/api/files.cjs +0 -8
- package/api/files.d.ts +0 -438
- package/api/files.js +0 -1
- package/api/jobs.cjs +0 -8
- package/api/jobs.d.ts +0 -327
- package/api/jobs.js +0 -1
- package/api/notifications.cjs +0 -8
- package/api/notifications.d.ts +0 -263
- package/api/notifications.js +0 -1
- package/api/users.cjs +0 -8
- package/api/users.d.ts +0 -923
- package/api/users.js +0 -1
- package/api/verifications.cjs +0 -8
- package/api/verifications.d.ts +0 -1
- package/api/verifications.js +0 -1
- package/batch.cjs +0 -8
- package/batch.d.ts +0 -154
- package/batch.js +0 -1
- package/bucket.cjs +0 -8
- package/bucket.d.ts +0 -520
- package/bucket.js +0 -1
- package/cache/redis.cjs +0 -8
- package/cache/redis.d.ts +0 -40
- package/cache/redis.js +0 -1
- package/cache.cjs +0 -8
- package/cache.d.ts +0 -288
- package/cache.js +0 -1
- package/command.cjs +0 -8
- package/command.d.ts +0 -269
- package/command.js +0 -1
- package/core.cjs +0 -8
- package/core.d.ts +0 -1904
- package/core.js +0 -1
- package/datetime.cjs +0 -8
- package/datetime.d.ts +0 -144
- package/datetime.js +0 -1
- package/devtools.cjs +0 -8
- package/devtools.d.ts +0 -252
- package/devtools.js +0 -1
- package/email.cjs +0 -8
- package/email.d.ts +0 -187
- package/email.js +0 -1
- package/fake.cjs +0 -8
- package/fake.d.ts +0 -73
- package/fake.js +0 -1
- package/file.cjs +0 -8
- package/file.d.ts +0 -528
- package/file.js +0 -1
- package/lock/redis.cjs +0 -8
- package/lock/redis.d.ts +0 -24
- package/lock/redis.js +0 -1
- package/lock.cjs +0 -8
- package/lock.d.ts +0 -552
- package/lock.js +0 -1
- package/logger.cjs +0 -8
- package/logger.d.ts +0 -287
- package/logger.js +0 -1
- package/postgres.cjs +0 -8
- package/postgres.d.ts +0 -2143
- package/postgres.js +0 -1
- package/queue/redis.cjs +0 -8
- package/queue/redis.d.ts +0 -29
- package/queue/redis.js +0 -1
- package/queue.cjs +0 -8
- package/queue.d.ts +0 -760
- package/queue.js +0 -1
- package/react/auth.cjs +0 -8
- package/react/auth.d.ts +0 -504
- package/react/auth.js +0 -1
- package/react/form.cjs +0 -8
- package/react/form.d.ts +0 -211
- package/react/form.js +0 -1
- package/react/head.cjs +0 -8
- package/react/head.d.ts +0 -120
- package/react/head.js +0 -1
- package/react/i18n.cjs +0 -8
- package/react/i18n.d.ts +0 -168
- package/react/i18n.js +0 -1
- package/react.cjs +0 -8
- package/react.d.ts +0 -1263
- package/react.js +0 -1
- package/redis.cjs +0 -8
- package/redis.d.ts +0 -82
- package/redis.js +0 -1
- package/retry.cjs +0 -8
- package/retry.d.ts +0 -162
- package/retry.js +0 -1
- package/router.cjs +0 -8
- package/router.d.ts +0 -45
- package/router.js +0 -1
- package/scheduler.cjs +0 -8
- package/scheduler.d.ts +0 -145
- package/scheduler.js +0 -1
- package/security.cjs +0 -8
- package/security.d.ts +0 -586
- package/security.js +0 -1
- package/server/cache.cjs +0 -8
- package/server/cache.d.ts +0 -163
- package/server/cache.js +0 -1
- package/server/compress.cjs +0 -8
- package/server/compress.d.ts +0 -38
- package/server/compress.js +0 -1
- package/server/cookies.cjs +0 -8
- package/server/cookies.d.ts +0 -144
- package/server/cookies.js +0 -1
- package/server/cors.cjs +0 -8
- package/server/cors.d.ts +0 -45
- package/server/cors.js +0 -1
- package/server/health.cjs +0 -8
- package/server/health.d.ts +0 -58
- package/server/health.js +0 -1
- package/server/helmet.cjs +0 -8
- package/server/helmet.d.ts +0 -98
- package/server/helmet.js +0 -1
- package/server/links.cjs +0 -8
- package/server/links.d.ts +0 -322
- package/server/links.js +0 -1
- package/server/metrics.cjs +0 -8
- package/server/metrics.d.ts +0 -35
- package/server/metrics.js +0 -1
- package/server/multipart.cjs +0 -8
- package/server/multipart.d.ts +0 -42
- package/server/multipart.js +0 -1
- package/server/proxy.cjs +0 -8
- package/server/proxy.d.ts +0 -234
- package/server/proxy.js +0 -1
- package/server/security.cjs +0 -8
- package/server/security.d.ts +0 -92
- package/server/security.js +0 -1
- package/server/static.cjs +0 -8
- package/server/static.d.ts +0 -119
- package/server/static.js +0 -1
- package/server/swagger.cjs +0 -8
- package/server/swagger.d.ts +0 -161
- package/server/swagger.js +0 -1
- package/server.cjs +0 -8
- package/server.d.ts +0 -849
- package/server.js +0 -1
- package/topic/redis.cjs +0 -8
- package/topic/redis.d.ts +0 -42
- package/topic/redis.js +0 -1
- package/topic.cjs +0 -8
- package/topic.d.ts +0 -819
- package/topic.js +0 -1
- package/vite.cjs +0 -8
- package/vite.d.ts +0 -186
- package/vite.js +0 -1
package/lock.d.ts
DELETED
|
@@ -1,552 +0,0 @@
|
|
|
1
|
-
import * as _alepha_core1 from "alepha";
|
|
2
|
-
import { AsyncFn, Descriptor, KIND, Static } from "alepha";
|
|
3
|
-
import * as _alepha_topic0 from "alepha/topic";
|
|
4
|
-
import { TopicProvider } from "alepha/topic";
|
|
5
|
-
import { DateTime, DateTimeProvider, DurationLike, Timeout } from "alepha/datetime";
|
|
6
|
-
import * as _alepha_logger0 from "alepha/logger";
|
|
7
|
-
import * as dayjs_plugin_duration0 from "dayjs/plugin/duration";
|
|
8
|
-
|
|
9
|
-
//#region src/providers/LockProvider.d.ts
|
|
10
|
-
/**
|
|
11
|
-
* Store Provider Interface
|
|
12
|
-
*/
|
|
13
|
-
declare abstract class LockProvider {
|
|
14
|
-
/**
|
|
15
|
-
* Set the string value of a key.
|
|
16
|
-
*
|
|
17
|
-
* @param key The key of the value to set.
|
|
18
|
-
* @param value The value to set.
|
|
19
|
-
* @param nx If set to true, the key will only be set if it does not already exist.
|
|
20
|
-
* @param px Set the specified expire time, in milliseconds.
|
|
21
|
-
*/
|
|
22
|
-
abstract set(key: string, value: string, nx?: boolean, px?: number): Promise<string>;
|
|
23
|
-
/**
|
|
24
|
-
* Remove the specified keys.
|
|
25
|
-
*
|
|
26
|
-
* @param keys The keys to delete.
|
|
27
|
-
*/
|
|
28
|
-
abstract del(...keys: string[]): Promise<void>;
|
|
29
|
-
}
|
|
30
|
-
//#endregion
|
|
31
|
-
//#region src/descriptors/$lock.d.ts
|
|
32
|
-
/**
|
|
33
|
-
* Creates a distributed lock descriptor for ensuring single-instance execution across processes.
|
|
34
|
-
*
|
|
35
|
-
* This descriptor provides a powerful distributed locking mechanism that prevents multiple instances
|
|
36
|
-
* of the same operation from running simultaneously. It's essential for maintaining data consistency
|
|
37
|
-
* and preventing race conditions in distributed applications, scheduled tasks, and critical sections
|
|
38
|
-
* that must execute atomically.
|
|
39
|
-
*
|
|
40
|
-
* **Key Features**
|
|
41
|
-
*
|
|
42
|
-
* - **Distributed Coordination**: Works across multiple processes, servers, and containers
|
|
43
|
-
* - **Automatic Expiration**: Locks expire automatically to prevent deadlocks
|
|
44
|
-
* - **Graceful Handling**: Configurable wait behavior for different use cases
|
|
45
|
-
* - **Grace Periods**: Optional lock extension after completion for additional safety
|
|
46
|
-
* - **Topic Integration**: Uses pub/sub for efficient lock release notifications
|
|
47
|
-
* - **Unique Instance IDs**: Prevents lock conflicts between different instances
|
|
48
|
-
* - **Timeout Management**: Configurable durations with intelligent retry logic
|
|
49
|
-
*
|
|
50
|
-
* **Use Cases**
|
|
51
|
-
*
|
|
52
|
-
* Perfect for ensuring single execution in distributed environments:
|
|
53
|
-
* - Database migrations and schema updates
|
|
54
|
-
* - Scheduled job execution (cron-like tasks)
|
|
55
|
-
* - File processing and batch operations
|
|
56
|
-
* - Critical section protection
|
|
57
|
-
* - Resource initialization and cleanup
|
|
58
|
-
* - Singleton service operations
|
|
59
|
-
* - Cache warming and maintenance tasks
|
|
60
|
-
*
|
|
61
|
-
* @example
|
|
62
|
-
* **Basic lock for scheduled tasks:**
|
|
63
|
-
* ```ts
|
|
64
|
-
* import { $lock } from "alepha/lock";
|
|
65
|
-
*
|
|
66
|
-
* class ScheduledTaskService {
|
|
67
|
-
* dailyReport = $lock({
|
|
68
|
-
* handler: async () => {
|
|
69
|
-
* // This will only run on one server even if multiple servers
|
|
70
|
-
* // trigger the task simultaneously
|
|
71
|
-
* console.log('Generating daily report...');
|
|
72
|
-
*
|
|
73
|
-
* const report = await this.generateDailyReport();
|
|
74
|
-
* await this.sendReportToManagement(report);
|
|
75
|
-
*
|
|
76
|
-
* console.log('Daily report completed');
|
|
77
|
-
* }
|
|
78
|
-
* });
|
|
79
|
-
*
|
|
80
|
-
* async runDailyReport() {
|
|
81
|
-
* // Multiple servers can call this, but only one will execute
|
|
82
|
-
* await this.dailyReport.run();
|
|
83
|
-
* }
|
|
84
|
-
* }
|
|
85
|
-
* ```
|
|
86
|
-
*
|
|
87
|
-
* @example
|
|
88
|
-
* **Migration lock with wait behavior:**
|
|
89
|
-
* ```ts
|
|
90
|
-
* class DatabaseService {
|
|
91
|
-
* migration = $lock({
|
|
92
|
-
* wait: true, // Wait for other instances to complete migration
|
|
93
|
-
* maxDuration: [10, "minutes"], // Migration timeout
|
|
94
|
-
* handler: async (version: string) => {
|
|
95
|
-
* console.log(`Running migration to version ${version}`);
|
|
96
|
-
*
|
|
97
|
-
* const currentVersion = await this.getCurrentSchemaVersion();
|
|
98
|
-
* if (currentVersion >= version) {
|
|
99
|
-
* console.log(`Already at version ${version}, skipping`);
|
|
100
|
-
* return;
|
|
101
|
-
* }
|
|
102
|
-
*
|
|
103
|
-
* await this.runMigrationScripts(version);
|
|
104
|
-
* await this.updateSchemaVersion(version);
|
|
105
|
-
*
|
|
106
|
-
* console.log(`Migration to ${version} completed`);
|
|
107
|
-
* }
|
|
108
|
-
* });
|
|
109
|
-
*
|
|
110
|
-
* async migrateToVersion(version: string) {
|
|
111
|
-
* // All instances will wait for the first one to complete
|
|
112
|
-
* // before continuing with their startup process
|
|
113
|
-
* await this.migration.run(version);
|
|
114
|
-
* }
|
|
115
|
-
* }
|
|
116
|
-
* ```
|
|
117
|
-
*
|
|
118
|
-
* @example
|
|
119
|
-
* **Dynamic lock keys with grace periods:**
|
|
120
|
-
* ```ts
|
|
121
|
-
* class FileProcessor {
|
|
122
|
-
* processFile = $lock({
|
|
123
|
-
* name: (filePath: string) => `file-processing:${filePath}`,
|
|
124
|
-
* wait: false, // Don't wait, skip if already processing
|
|
125
|
-
* maxDuration: [30, "minutes"],
|
|
126
|
-
* gracePeriod: [5, "minutes"], // Keep lock for 5min after completion
|
|
127
|
-
* handler: async (filePath: string) => {
|
|
128
|
-
* console.log(`Processing file: ${filePath}`);
|
|
129
|
-
*
|
|
130
|
-
* try {
|
|
131
|
-
* const fileData = await this.readFile(filePath);
|
|
132
|
-
* const processedData = await this.processData(fileData);
|
|
133
|
-
* await this.saveProcessedData(filePath, processedData);
|
|
134
|
-
* await this.moveToCompleted(filePath);
|
|
135
|
-
*
|
|
136
|
-
* console.log(`File processing completed: ${filePath}`);
|
|
137
|
-
* } catch (error) {
|
|
138
|
-
* console.error(`File processing failed: ${filePath}`, error);
|
|
139
|
-
* await this.moveToError(filePath, error.message);
|
|
140
|
-
* throw error;
|
|
141
|
-
* }
|
|
142
|
-
* }
|
|
143
|
-
* });
|
|
144
|
-
*
|
|
145
|
-
* async processUploadedFile(filePath: string) {
|
|
146
|
-
* // Each file gets its own lock, preventing duplicate processing
|
|
147
|
-
* // Grace period prevents immediate reprocessing of the same file
|
|
148
|
-
* await this.processFile.run(filePath);
|
|
149
|
-
* }
|
|
150
|
-
* }
|
|
151
|
-
* ```
|
|
152
|
-
*
|
|
153
|
-
* @example
|
|
154
|
-
* **Resource initialization with conditional grace periods:**
|
|
155
|
-
* ```ts
|
|
156
|
-
* class CacheService {
|
|
157
|
-
* warmCache = $lock({
|
|
158
|
-
* name: (cacheKey: string) => `cache-warming:${cacheKey}`,
|
|
159
|
-
* wait: true, // Wait for cache to be warmed before continuing
|
|
160
|
-
* maxDuration: [15, "minutes"],
|
|
161
|
-
* gracePeriod: (cacheKey: string) => {
|
|
162
|
-
* // Dynamic grace period based on cache importance
|
|
163
|
-
* const criticalCaches = ['user-sessions', 'product-catalog'];
|
|
164
|
-
* return criticalCaches.includes(cacheKey)
|
|
165
|
-
* ? [30, "minutes"] // Longer grace for critical caches
|
|
166
|
-
* : [5, "minutes"]; // Shorter grace for regular caches
|
|
167
|
-
* },
|
|
168
|
-
* handler: async (cacheKey: string, force: boolean = false) => {
|
|
169
|
-
* console.log(`Warming cache: ${cacheKey}`);
|
|
170
|
-
*
|
|
171
|
-
* if (!force && await this.isCacheWarm(cacheKey)) {
|
|
172
|
-
* console.log(`Cache ${cacheKey} is already warm`);
|
|
173
|
-
* return;
|
|
174
|
-
* }
|
|
175
|
-
*
|
|
176
|
-
* const startTime = Date.now();
|
|
177
|
-
*
|
|
178
|
-
* switch (cacheKey) {
|
|
179
|
-
* case 'user-sessions':
|
|
180
|
-
* await this.warmUserSessionsCache();
|
|
181
|
-
* break;
|
|
182
|
-
* case 'product-catalog':
|
|
183
|
-
* await this.warmProductCatalogCache();
|
|
184
|
-
* break;
|
|
185
|
-
* case 'configuration':
|
|
186
|
-
* await this.warmConfigurationCache();
|
|
187
|
-
* break;
|
|
188
|
-
* default:
|
|
189
|
-
* throw new Error(`Unknown cache key: ${cacheKey}`);
|
|
190
|
-
* }
|
|
191
|
-
*
|
|
192
|
-
* const duration = Date.now() - startTime;
|
|
193
|
-
* console.log(`Cache warming completed for ${cacheKey} in ${duration}ms`);
|
|
194
|
-
*
|
|
195
|
-
* await this.markCacheAsWarm(cacheKey);
|
|
196
|
-
* }
|
|
197
|
-
* });
|
|
198
|
-
*
|
|
199
|
-
* async ensureCacheWarmed(cacheKey: string, force: boolean = false) {
|
|
200
|
-
* // Multiple instances can call this, but cache warming happens only once
|
|
201
|
-
* // All instances wait for completion before proceeding
|
|
202
|
-
* await this.warmCache.run(cacheKey, force);
|
|
203
|
-
* }
|
|
204
|
-
* }
|
|
205
|
-
* ```
|
|
206
|
-
*
|
|
207
|
-
* @example
|
|
208
|
-
* **Critical section protection with custom timeout handling:**
|
|
209
|
-
* ```ts
|
|
210
|
-
* class InventoryService {
|
|
211
|
-
* updateInventory = $lock({
|
|
212
|
-
* name: (productId: string) => `inventory-update:${productId}`,
|
|
213
|
-
* wait: true, // Ensure all inventory updates are sequential
|
|
214
|
-
* maxDuration: [2, "minutes"],
|
|
215
|
-
* gracePeriod: [30, "seconds"], // Brief grace to prevent immediate conflicts
|
|
216
|
-
* handler: async (productId: string, quantity: number, operation: 'add' | 'subtract') => {
|
|
217
|
-
* console.log(`Updating inventory for product ${productId}: ${operation} ${quantity}`);
|
|
218
|
-
*
|
|
219
|
-
* try {
|
|
220
|
-
* // Start transaction for inventory update
|
|
221
|
-
* await this.db.transaction(async (tx) => {
|
|
222
|
-
* const currentInventory = await tx.getInventory(productId);
|
|
223
|
-
*
|
|
224
|
-
* if (operation === 'subtract' && currentInventory.quantity < quantity) {
|
|
225
|
-
* throw new Error(`Insufficient inventory for product ${productId}. Available: ${currentInventory.quantity}, Requested: ${quantity}`);
|
|
226
|
-
* }
|
|
227
|
-
*
|
|
228
|
-
* const newQuantity = operation === 'add'
|
|
229
|
-
* ? currentInventory.quantity + quantity
|
|
230
|
-
* : currentInventory.quantity - quantity;
|
|
231
|
-
*
|
|
232
|
-
* await tx.updateInventory(productId, newQuantity);
|
|
233
|
-
*
|
|
234
|
-
* // Log inventory change for audit
|
|
235
|
-
* await tx.logInventoryChange({
|
|
236
|
-
* productId,
|
|
237
|
-
* operation,
|
|
238
|
-
* quantity,
|
|
239
|
-
* previousQuantity: currentInventory.quantity,
|
|
240
|
-
* newQuantity,
|
|
241
|
-
* timestamp: new Date()
|
|
242
|
-
* });
|
|
243
|
-
*
|
|
244
|
-
* console.log(`Inventory updated for product ${productId}: ${currentInventory.quantity} -> ${newQuantity}`);
|
|
245
|
-
* });
|
|
246
|
-
*
|
|
247
|
-
* // Notify other services about inventory change
|
|
248
|
-
* await this.inventoryChangeNotifier.notify({
|
|
249
|
-
* productId,
|
|
250
|
-
* operation,
|
|
251
|
-
* quantity,
|
|
252
|
-
* timestamp: new Date()
|
|
253
|
-
* });
|
|
254
|
-
*
|
|
255
|
-
* } catch (error) {
|
|
256
|
-
* console.error(`Inventory update failed for product ${productId}`, error);
|
|
257
|
-
* throw error;
|
|
258
|
-
* }
|
|
259
|
-
* }
|
|
260
|
-
* });
|
|
261
|
-
*
|
|
262
|
-
* async addInventory(productId: string, quantity: number) {
|
|
263
|
-
* await this.updateInventory.run(productId, quantity, 'add');
|
|
264
|
-
* }
|
|
265
|
-
*
|
|
266
|
-
* async subtractInventory(productId: string, quantity: number) {
|
|
267
|
-
* await this.updateInventory.run(productId, quantity, 'subtract');
|
|
268
|
-
* }
|
|
269
|
-
* }
|
|
270
|
-
* ```
|
|
271
|
-
*/
|
|
272
|
-
declare const $lock: {
|
|
273
|
-
<TFunc extends AsyncFn>(options: LockDescriptorOptions<TFunc>): LockDescriptor<TFunc>;
|
|
274
|
-
[KIND]: typeof LockDescriptor;
|
|
275
|
-
};
|
|
276
|
-
interface LockDescriptorOptions<TFunc extends AsyncFn> {
|
|
277
|
-
/**
|
|
278
|
-
* The function to execute when the lock is successfully acquired.
|
|
279
|
-
*
|
|
280
|
-
* This function:
|
|
281
|
-
* - Only executes on the instance that successfully acquires the lock
|
|
282
|
-
* - Has exclusive access to the protected resource during execution
|
|
283
|
-
* - Should contain the critical section logic that must not run concurrently
|
|
284
|
-
* - Can be async and perform any operations needed
|
|
285
|
-
* - Will automatically release the lock upon completion or error
|
|
286
|
-
* - Has access to the full Alepha dependency injection container
|
|
287
|
-
*
|
|
288
|
-
* **Handler Design Guidelines**:
|
|
289
|
-
* - Keep critical sections as short as possible to minimize lock contention
|
|
290
|
-
* - Include proper error handling to ensure locks are released
|
|
291
|
-
* - Use timeouts for external operations to prevent deadlocks
|
|
292
|
-
* - Log important operations for debugging and monitoring
|
|
293
|
-
* - Consider idempotency for handlers that might be retried
|
|
294
|
-
*
|
|
295
|
-
* @param ...args - The arguments passed to the lock execution
|
|
296
|
-
* @returns Promise that resolves when the protected operation is complete
|
|
297
|
-
*
|
|
298
|
-
* @example
|
|
299
|
-
* ```ts
|
|
300
|
-
* handler: async (batchId: string) => {
|
|
301
|
-
* console.log(`Processing batch ${batchId} - only one instance will run this`);
|
|
302
|
-
*
|
|
303
|
-
* const batch = await this.getBatchData(batchId);
|
|
304
|
-
* const results = await this.processBatchItems(batch.items);
|
|
305
|
-
* await this.saveBatchResults(batchId, results);
|
|
306
|
-
*
|
|
307
|
-
* console.log(`Batch ${batchId} completed successfully`);
|
|
308
|
-
* }
|
|
309
|
-
* ```
|
|
310
|
-
*/
|
|
311
|
-
handler: TFunc;
|
|
312
|
-
/**
|
|
313
|
-
* Whether the lock should wait for other instances to complete before giving up.
|
|
314
|
-
*
|
|
315
|
-
* **wait = false (default)**:
|
|
316
|
-
* - Non-blocking behavior - if lock is held, immediately return without executing
|
|
317
|
-
* - Perfect for scheduled tasks where you only want one execution per trigger
|
|
318
|
-
* - Use when multiple triggers are acceptable but concurrent execution is not
|
|
319
|
-
* - Examples: periodic cleanup, cron jobs, background maintenance
|
|
320
|
-
*
|
|
321
|
-
* **wait = true**:
|
|
322
|
-
* - Blocking behavior - wait for the current lock holder to finish
|
|
323
|
-
* - All instances will eventually execute (one after another)
|
|
324
|
-
* - Perfect for initialization tasks where all instances need the work completed
|
|
325
|
-
* - Examples: database migrations, cache warming, resource initialization
|
|
326
|
-
*
|
|
327
|
-
* **Trade-offs**:
|
|
328
|
-
* - Non-waiting: Better performance, may miss executions if timing is off
|
|
329
|
-
* - Waiting: Guaranteed execution order, slower overall throughput
|
|
330
|
-
*
|
|
331
|
-
* @default false
|
|
332
|
-
*
|
|
333
|
-
* @example
|
|
334
|
-
* ```ts
|
|
335
|
-
* // Scheduled task - don't wait, just skip if already running
|
|
336
|
-
* scheduledCleanup = $lock({
|
|
337
|
-
* wait: false, // Skip if cleanup already running
|
|
338
|
-
* handler: async () => { } // perform cleanup
|
|
339
|
-
* });
|
|
340
|
-
*
|
|
341
|
-
* // Migration - wait for completion before proceeding
|
|
342
|
-
* migration = $lock({
|
|
343
|
-
* wait: true, // All instances wait for migration to complete
|
|
344
|
-
* handler: async () => { } // perform migration
|
|
345
|
-
* });
|
|
346
|
-
* ```
|
|
347
|
-
*/
|
|
348
|
-
wait?: boolean;
|
|
349
|
-
/**
|
|
350
|
-
* The unique identifier for the lock.
|
|
351
|
-
*
|
|
352
|
-
* Can be either:
|
|
353
|
-
* - **Static string**: A fixed identifier for the lock
|
|
354
|
-
* - **Dynamic function**: A function that generates the lock key based on arguments
|
|
355
|
-
*
|
|
356
|
-
* **Dynamic Lock Keys**:
|
|
357
|
-
* - Enable per-resource locking (e.g., per-user, per-file, per-product)
|
|
358
|
-
* - Allow fine-grained concurrency control
|
|
359
|
-
* - Prevent unnecessary blocking between unrelated operations
|
|
360
|
-
*
|
|
361
|
-
* **Key Design Guidelines**:
|
|
362
|
-
* - Use descriptive names that indicate the protected resource
|
|
363
|
-
* - Include relevant identifiers for dynamic keys
|
|
364
|
-
* - Keep keys reasonably short but unique
|
|
365
|
-
* - Consider using hierarchical naming (e.g., "service:operation:resource")
|
|
366
|
-
*
|
|
367
|
-
* If not provided, defaults to `{serviceName}:{propertyKey}`.
|
|
368
|
-
*
|
|
369
|
-
* @example "user-migration"
|
|
370
|
-
* @example "daily-report-generation"
|
|
371
|
-
* @example (userId: string) => `user-profile-update:${userId}`
|
|
372
|
-
* @example (fileId: string, operation: string) => `file-${operation}:${fileId}`
|
|
373
|
-
*
|
|
374
|
-
* @example
|
|
375
|
-
* ```ts
|
|
376
|
-
* // Static lock key - all instances compete for the same lock
|
|
377
|
-
* globalCleanup = $lock({
|
|
378
|
-
* name: "system-cleanup",
|
|
379
|
-
* handler: async () => { } // perform cleanup
|
|
380
|
-
* });
|
|
381
|
-
*
|
|
382
|
-
* // Dynamic lock key - per-user locks, users don't block each other
|
|
383
|
-
* updateUserProfile = $lock({
|
|
384
|
-
* name: (userId: string) => `user-update:${userId}`,
|
|
385
|
-
* handler: async (userId: string, data: UserData) => {
|
|
386
|
-
* // Only one update per user at a time, but different users can update concurrently
|
|
387
|
-
* }
|
|
388
|
-
* });
|
|
389
|
-
* ```
|
|
390
|
-
*/
|
|
391
|
-
name?: string | ((...args: Parameters<TFunc>) => string);
|
|
392
|
-
/**
|
|
393
|
-
* Maximum duration the lock can be held before it expires automatically.
|
|
394
|
-
*
|
|
395
|
-
* This prevents deadlocks when a process dies while holding a lock or when
|
|
396
|
-
* operations take longer than expected. The lock will be automatically released
|
|
397
|
-
* after this duration, allowing other instances to proceed.
|
|
398
|
-
*
|
|
399
|
-
* **Duration Guidelines**:
|
|
400
|
-
* - Set based on expected operation duration plus safety margin
|
|
401
|
-
* - Too short: Operations may be interrupted by early expiration
|
|
402
|
-
* - Too long: Failed processes block others for extended periods
|
|
403
|
-
* - Consider worst-case scenarios and external dependency timeouts
|
|
404
|
-
*
|
|
405
|
-
* **Typical Values**:
|
|
406
|
-
* - Quick operations: 30 seconds - 2 minutes
|
|
407
|
-
* - Database operations: 5 - 15 minutes
|
|
408
|
-
* - File processing: 10 - 30 minutes
|
|
409
|
-
* - Large migrations: 30 minutes - 2 hours
|
|
410
|
-
*
|
|
411
|
-
* @default [5, "minutes"]
|
|
412
|
-
*
|
|
413
|
-
* @example [30, "seconds"] // Quick operations
|
|
414
|
-
* @example [10, "minutes"] // Database migrations
|
|
415
|
-
* @example [1, "hour"] // Long-running batch jobs
|
|
416
|
-
*
|
|
417
|
-
* @example
|
|
418
|
-
* ```ts
|
|
419
|
-
* quickTask = $lock({
|
|
420
|
-
* maxDuration: [2, "minutes"], // Quick timeout for fast operations
|
|
421
|
-
* handler: async () => { } // perform quick task
|
|
422
|
-
* });
|
|
423
|
-
*
|
|
424
|
-
* heavyProcessing = $lock({
|
|
425
|
-
* maxDuration: [30, "minutes"], // Longer timeout for heavy work
|
|
426
|
-
* handler: async () => { } // perform heavy processing
|
|
427
|
-
* });
|
|
428
|
-
* ```
|
|
429
|
-
*/
|
|
430
|
-
maxDuration?: DurationLike;
|
|
431
|
-
/**
|
|
432
|
-
* Additional time to keep the lock active after the handler completes successfully.
|
|
433
|
-
*
|
|
434
|
-
* This provides a "cooling off" period that can be useful for:
|
|
435
|
-
* - Preventing immediate re-execution of the same operation
|
|
436
|
-
* - Giving time for related systems to process the results
|
|
437
|
-
* - Avoiding race conditions with dependent operations
|
|
438
|
-
* - Providing a buffer for cleanup operations
|
|
439
|
-
*
|
|
440
|
-
* Can be either:
|
|
441
|
-
* - **Static duration**: Fixed grace period for all executions
|
|
442
|
-
* - **Dynamic function**: Grace period determined by execution arguments
|
|
443
|
-
* - **undefined**: No grace period, lock released immediately after completion
|
|
444
|
-
*
|
|
445
|
-
* **Grace Period Use Cases**:
|
|
446
|
-
* - File processing: Prevent immediate reprocessing of uploaded files
|
|
447
|
-
* - Cache updates: Allow time for cache propagation
|
|
448
|
-
* - Batch operations: Prevent overlapping batch processing
|
|
449
|
-
* - External API calls: Respect rate limiting requirements
|
|
450
|
-
*
|
|
451
|
-
* @default undefined (no grace period)
|
|
452
|
-
*
|
|
453
|
-
* @example [5, "minutes"] // Fixed 5-minute grace period
|
|
454
|
-
* @example [30, "seconds"] // Short grace for quick operations
|
|
455
|
-
* @example (userId: string) => userId.startsWith("premium") ? [10, "minutes"] : [2, "minutes"]
|
|
456
|
-
*
|
|
457
|
-
* @example
|
|
458
|
-
* ```ts
|
|
459
|
-
* fileProcessor = $lock({
|
|
460
|
-
* gracePeriod: [10, "minutes"], // Prevent reprocessing same file immediately
|
|
461
|
-
* handler: async (filePath: string) => {
|
|
462
|
-
* await this.processFile(filePath);
|
|
463
|
-
* }
|
|
464
|
-
* });
|
|
465
|
-
*
|
|
466
|
-
* userOperation = $lock({
|
|
467
|
-
* gracePeriod: (userId: string, operation: string) => {
|
|
468
|
-
* // Dynamic grace based on operation type
|
|
469
|
-
* return operation === 'migration' ? [30, "minutes"] : [5, "minutes"];
|
|
470
|
-
* },
|
|
471
|
-
* handler: async (userId: string, operation: string) => {
|
|
472
|
-
* await this.performUserOperation(userId, operation);
|
|
473
|
-
* }
|
|
474
|
-
* });
|
|
475
|
-
* ```
|
|
476
|
-
*/
|
|
477
|
-
gracePeriod?: ((...args: Parameters<TFunc>) => DurationLike | undefined) | DurationLike;
|
|
478
|
-
}
|
|
479
|
-
declare const envSchema: _alepha_core1.TObject<{
|
|
480
|
-
LOCK_PREFIX_KEY: _alepha_core1.TString;
|
|
481
|
-
}>;
|
|
482
|
-
declare module "alepha" {
|
|
483
|
-
interface Env extends Partial<Static<typeof envSchema>> {}
|
|
484
|
-
}
|
|
485
|
-
declare class LockDescriptor<TFunc extends AsyncFn> extends Descriptor<LockDescriptorOptions<TFunc>> {
|
|
486
|
-
protected readonly log: _alepha_logger0.Logger;
|
|
487
|
-
protected readonly provider: LockProvider;
|
|
488
|
-
protected readonly env: {
|
|
489
|
-
LOCK_PREFIX_KEY: string;
|
|
490
|
-
};
|
|
491
|
-
protected readonly dateTimeProvider: DateTimeProvider;
|
|
492
|
-
protected readonly id: `${string}-${string}-${string}-${string}-${string}`;
|
|
493
|
-
readonly maxDuration: dayjs_plugin_duration0.Duration;
|
|
494
|
-
protected readonly topicLockEnd: _alepha_topic0.TopicDescriptor<{
|
|
495
|
-
payload: _alepha_core1.TObject<{
|
|
496
|
-
name: _alepha_core1.TString;
|
|
497
|
-
}>;
|
|
498
|
-
}>;
|
|
499
|
-
run(...args: Parameters<TFunc>): Promise<void>;
|
|
500
|
-
/**
|
|
501
|
-
* Set the lock for the given key.
|
|
502
|
-
*/
|
|
503
|
-
protected lock(key: string): Promise<LockResult>;
|
|
504
|
-
protected setGracePeriod(key: string, lock: LockResult, ...args: Parameters<TFunc>): Promise<void>;
|
|
505
|
-
protected wait(key: string, maxDuration: DurationLike): Promise<void>;
|
|
506
|
-
protected key(...args: Parameters<TFunc>): string;
|
|
507
|
-
protected parse(value: string): LockResult;
|
|
508
|
-
}
|
|
509
|
-
interface LockResult {
|
|
510
|
-
id: string;
|
|
511
|
-
createdAt: DateTime;
|
|
512
|
-
endedAt?: DateTime;
|
|
513
|
-
response?: string;
|
|
514
|
-
}
|
|
515
|
-
//#endregion
|
|
516
|
-
//#region src/providers/LockTopicProvider.d.ts
|
|
517
|
-
declare abstract class LockTopicProvider extends TopicProvider {}
|
|
518
|
-
//#endregion
|
|
519
|
-
//#region src/providers/MemoryLockProvider.d.ts
|
|
520
|
-
/**
|
|
521
|
-
* A simple in-memory store provider.
|
|
522
|
-
*/
|
|
523
|
-
declare class MemoryLockProvider implements LockProvider {
|
|
524
|
-
protected readonly dateTimeProvider: DateTimeProvider;
|
|
525
|
-
protected readonly log: _alepha_logger0.Logger;
|
|
526
|
-
/**
|
|
527
|
-
* The in-memory store.
|
|
528
|
-
*/
|
|
529
|
-
protected store: Record<string, string>;
|
|
530
|
-
/**
|
|
531
|
-
* Timeouts used to expire keys.
|
|
532
|
-
*/
|
|
533
|
-
protected storeTimeout: Record<string, Timeout>;
|
|
534
|
-
set(key: string, value: string, nx?: boolean, px?: number): Promise<string>;
|
|
535
|
-
del(...keys: string[]): Promise<void>;
|
|
536
|
-
private ttl;
|
|
537
|
-
}
|
|
538
|
-
//#endregion
|
|
539
|
-
//#region src/index.d.ts
|
|
540
|
-
/**
|
|
541
|
-
* Lock a resource for a certain period of time.
|
|
542
|
-
*
|
|
543
|
-
* This module provides a memory implementation of the lock provider.
|
|
544
|
-
* You probably want to use an implementation like RedisLockProvider for distributed systems.
|
|
545
|
-
*
|
|
546
|
-
* @see {@link $lock}
|
|
547
|
-
* @module alepha.lock
|
|
548
|
-
*/
|
|
549
|
-
declare const AlephaLock: _alepha_core1.Service<_alepha_core1.Module>;
|
|
550
|
-
//#endregion
|
|
551
|
-
export { $lock, AlephaLock, LockDescriptor, LockDescriptorOptions, LockProvider, LockResult, LockTopicProvider, MemoryLockProvider };
|
|
552
|
-
//# sourceMappingURL=index.d.ts.map
|
package/lock.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from '@alepha/lock'
|
package/logger.cjs
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
var m = require('@alepha/logger');
|
|
3
|
-
Object.keys(m).forEach(function (k) {
|
|
4
|
-
if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
|
|
5
|
-
enumerable: true,
|
|
6
|
-
get: function () { return m[k]; }
|
|
7
|
-
});
|
|
8
|
-
});
|