alepha 0.13.5 → 0.13.7
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/dist/api-audits/index.browser.js +116 -0
- package/dist/api-audits/index.browser.js.map +1 -0
- package/dist/api-audits/index.d.ts +1194 -0
- package/dist/api-audits/index.js +674 -0
- package/dist/api-audits/index.js.map +1 -0
- package/dist/api-notifications/index.d.ts +147 -147
- package/dist/api-parameters/index.browser.js +36 -5
- package/dist/api-parameters/index.browser.js.map +1 -1
- package/dist/api-parameters/index.d.ts +711 -33
- package/dist/api-parameters/index.js +831 -17
- package/dist/api-parameters/index.js.map +1 -1
- package/dist/api-users/index.d.ts +16 -3
- package/dist/api-users/index.js +699 -19
- package/dist/api-users/index.js.map +1 -1
- package/dist/api-verifications/index.js +2 -1
- package/dist/api-verifications/index.js.map +1 -1
- package/dist/bin/index.js +1 -0
- package/dist/bin/index.js.map +1 -1
- package/dist/cli/index.d.ts +85 -31
- package/dist/cli/index.js +205 -33
- package/dist/cli/index.js.map +1 -1
- package/dist/command/index.d.ts +67 -6
- package/dist/command/index.js +30 -3
- package/dist/command/index.js.map +1 -1
- package/dist/core/index.browser.js +241 -61
- package/dist/core/index.browser.js.map +1 -1
- package/dist/core/index.d.ts +170 -90
- package/dist/core/index.js +264 -67
- package/dist/core/index.js.map +1 -1
- package/dist/core/index.native.js +248 -65
- package/dist/core/index.native.js.map +1 -1
- package/dist/email/index.js +15 -10554
- package/dist/email/index.js.map +1 -1
- package/dist/logger/index.d.ts +4 -4
- package/dist/logger/index.js +77 -72
- package/dist/logger/index.js.map +1 -1
- package/dist/orm/index.d.ts +5 -1
- package/dist/orm/index.js +24 -7
- package/dist/orm/index.js.map +1 -1
- package/dist/queue/index.d.ts +4 -4
- package/dist/redis/index.d.ts +10 -10
- package/dist/security/index.d.ts +28 -28
- package/dist/server/index.d.ts +10 -1
- package/dist/server/index.js +20 -6
- package/dist/server/index.js.map +1 -1
- package/dist/server-auth/index.d.ts +163 -152
- package/dist/server-auth/index.js +40 -10
- package/dist/server-auth/index.js.map +1 -1
- package/dist/server-cookies/index.js +5 -1
- package/dist/server-cookies/index.js.map +1 -1
- package/dist/server-links/index.d.ts +33 -33
- package/dist/server-security/index.d.ts +9 -9
- package/dist/thread/index.js +2 -2
- package/dist/thread/index.js.map +1 -1
- package/dist/vite/index.d.ts +2 -2
- package/dist/vite/index.js +102 -45
- package/dist/vite/index.js.map +1 -1
- package/dist/websocket/index.browser.js +3 -3
- package/dist/websocket/index.browser.js.map +1 -1
- package/dist/websocket/index.d.ts +7 -7
- package/dist/websocket/index.js +4 -4
- package/dist/websocket/index.js.map +1 -1
- package/package.json +14 -9
- package/src/api-audits/controllers/AuditController.ts +186 -0
- package/src/api-audits/entities/audits.ts +132 -0
- package/src/api-audits/index.browser.ts +18 -0
- package/src/api-audits/index.ts +58 -0
- package/src/api-audits/primitives/$audit.ts +159 -0
- package/src/api-audits/schemas/auditQuerySchema.ts +23 -0
- package/src/api-audits/schemas/auditResourceSchema.ts +9 -0
- package/src/api-audits/schemas/createAuditSchema.ts +27 -0
- package/src/api-audits/services/AuditService.ts +412 -0
- package/src/api-parameters/controllers/ConfigController.ts +324 -0
- package/src/api-parameters/entities/parameters.ts +93 -10
- package/src/api-parameters/index.ts +43 -4
- package/src/api-parameters/primitives/$config.ts +291 -19
- package/src/api-parameters/schedulers/ConfigActivationScheduler.ts +30 -0
- package/src/api-parameters/services/ConfigStore.ts +491 -0
- package/src/api-users/atoms/realmAuthSettingsAtom.ts +19 -0
- package/src/api-users/controllers/UserRealmController.ts +0 -2
- package/src/api-users/index.ts +2 -0
- package/src/api-users/primitives/$userRealm.ts +18 -3
- package/src/api-users/providers/UserRealmProvider.ts +6 -3
- package/src/api-users/services/RegistrationService.ts +2 -1
- package/src/api-users/services/SessionService.ts +4 -0
- package/src/api-users/services/UserService.ts +3 -0
- package/src/api-verifications/index.ts +7 -1
- package/src/bin/index.ts +1 -0
- package/src/cli/assets/biomeJson.ts +1 -1
- package/src/cli/assets/dummySpecTs.ts +7 -0
- package/src/cli/assets/editorconfig.ts +13 -0
- package/src/cli/assets/mainTs.ts +14 -0
- package/src/cli/commands/BiomeCommands.ts +2 -0
- package/src/cli/commands/CoreCommands.ts +28 -9
- package/src/cli/commands/VerifyCommands.ts +2 -1
- package/src/cli/commands/ViteCommands.ts +8 -9
- package/src/cli/services/AlephaCliUtils.ts +214 -23
- package/src/command/helpers/Asker.ts +0 -1
- package/src/command/primitives/$command.ts +67 -0
- package/src/command/providers/CliProvider.ts +39 -8
- package/src/core/Alepha.ts +40 -30
- package/src/core/helpers/jsonSchemaToTypeBox.ts +307 -0
- package/src/core/index.shared.ts +1 -0
- package/src/core/index.ts +30 -3
- package/src/core/providers/EventManager.ts +1 -1
- package/src/core/providers/StateManager.ts +23 -12
- package/src/core/providers/TypeProvider.ts +26 -34
- package/src/logger/index.ts +8 -6
- package/src/logger/primitives/$logger.ts +1 -1
- package/src/logger/providers/{SimpleFormatterProvider.ts → PrettyFormatterProvider.ts} +10 -1
- package/src/orm/index.ts +6 -0
- package/src/orm/services/PgRelationManager.ts +2 -2
- package/src/orm/services/PostgresModelBuilder.ts +11 -7
- package/src/orm/services/Repository.ts +16 -7
- package/src/orm/services/SqliteModelBuilder.ts +10 -0
- package/src/server/index.ts +6 -0
- package/src/server/primitives/$action.ts +10 -1
- package/src/server/providers/ServerBodyParserProvider.ts +11 -5
- package/src/server/providers/ServerRouterProvider.ts +13 -7
- package/src/server-auth/primitives/$auth.ts +7 -0
- package/src/server-auth/providers/ServerAuthProvider.ts +51 -8
- package/src/server-cookies/index.ts +2 -1
- package/src/thread/primitives/$thread.ts +2 -2
- package/src/vite/index.ts +0 -2
- package/src/vite/tasks/buildServer.ts +3 -4
- package/src/vite/tasks/generateCloudflare.ts +35 -19
- package/src/vite/tasks/generateDocker.ts +18 -4
- package/src/vite/tasks/generateSitemap.ts +5 -7
- package/src/vite/tasks/generateVercel.ts +76 -41
- package/src/vite/tasks/runAlepha.ts +16 -1
- package/src/websocket/providers/NodeWebSocketServerProvider.ts +3 -11
- package/src/websocket/services/WebSocketClient.ts +3 -3
- package/dist/cli/dist-BlfFtOk2.js +0 -2770
- package/dist/cli/dist-BlfFtOk2.js.map +0 -1
- package/src/api-parameters/controllers/ParameterController.ts +0 -45
- package/src/api-parameters/services/ParameterStore.ts +0 -23
|
@@ -1,17 +1,38 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
$hook,
|
|
3
|
+
$inject,
|
|
4
|
+
createPrimitive,
|
|
5
|
+
KIND,
|
|
6
|
+
Primitive,
|
|
7
|
+
type Static,
|
|
8
|
+
type TObject,
|
|
9
|
+
} from "alepha";
|
|
10
|
+
import { $logger } from "alepha/logger";
|
|
2
11
|
import type { UserAccount } from "alepha/security";
|
|
12
|
+
import { ConfigStore } from "../services/ConfigStore.ts";
|
|
3
13
|
|
|
4
14
|
/**
|
|
5
|
-
* Creates a configuration
|
|
15
|
+
* Creates a versioned configuration primitive for managing application settings.
|
|
6
16
|
*
|
|
7
|
-
* Provides type-safe, versioned configuration with
|
|
8
|
-
*
|
|
17
|
+
* Provides type-safe, versioned configuration with:
|
|
18
|
+
* - Schema validation with auto-migration detection
|
|
19
|
+
* - Default values for initial state
|
|
20
|
+
* - Scheduled activation (FUTURE, NEXT, CURRENT, EXPIRED statuses)
|
|
21
|
+
* - PostgreSQL persistence with full version history
|
|
22
|
+
* - Cross-instance synchronization via topic
|
|
23
|
+
* - Tree view support via dot-notation naming (e.g., "app.features.flags")
|
|
24
|
+
*
|
|
25
|
+
* Integrates with Alepha's atom system for state management:
|
|
26
|
+
* - Uses `alepha.set(atom, value)` for mutations
|
|
27
|
+
* - Listens to `state:mutate` events to detect changes
|
|
28
|
+
* - Auto-persists changes to database
|
|
29
|
+
* - Syncs across instances via topic
|
|
9
30
|
*
|
|
10
31
|
* @example
|
|
11
32
|
* ```ts
|
|
12
33
|
* class AppConfig {
|
|
13
34
|
* features = $config({
|
|
14
|
-
* name: "
|
|
35
|
+
* name: "app.features.flags",
|
|
15
36
|
* schema: t.object({
|
|
16
37
|
* enableBeta: t.boolean(),
|
|
17
38
|
* maxUploadSize: t.number()
|
|
@@ -19,57 +40,283 @@ import type { UserAccount } from "alepha/security";
|
|
|
19
40
|
* default: { enableBeta: false, maxUploadSize: 10485760 }
|
|
20
41
|
* });
|
|
21
42
|
*
|
|
22
|
-
* async
|
|
43
|
+
* async enableBeta() {
|
|
44
|
+
* // Immediate activation
|
|
45
|
+
* await this.features.set({ enableBeta: true, maxUploadSize: 20971520 });
|
|
46
|
+
* }
|
|
47
|
+
*
|
|
48
|
+
* async scheduleBetaRelease() {
|
|
49
|
+
* // Schedule for future activation
|
|
23
50
|
* await this.features.set(
|
|
24
51
|
* { enableBeta: true, maxUploadSize: 20971520 },
|
|
25
|
-
* {
|
|
52
|
+
* { activationDate: new Date('2024-03-01') }
|
|
26
53
|
* );
|
|
27
54
|
* }
|
|
28
55
|
* }
|
|
29
56
|
* ```
|
|
30
57
|
*/
|
|
31
58
|
export interface ConfigPrimitiveOptions<T extends TObject> {
|
|
59
|
+
/**
|
|
60
|
+
* Configuration name using dot notation for tree hierarchy.
|
|
61
|
+
* Examples: "app.features", "app.pricing.tiers", "system.limits"
|
|
62
|
+
*/
|
|
32
63
|
name?: string;
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Human-readable description of the configuration.
|
|
67
|
+
*/
|
|
33
68
|
description?: string;
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* TypeBox schema defining the configuration structure.
|
|
72
|
+
*/
|
|
34
73
|
schema: T;
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Default value used when no configuration exists in database.
|
|
77
|
+
*/
|
|
35
78
|
default: Static<T>;
|
|
36
79
|
}
|
|
37
80
|
|
|
38
81
|
export class ConfigPrimitive<T extends TObject> extends Primitive<
|
|
39
82
|
ConfigPrimitiveOptions<T>
|
|
40
83
|
> {
|
|
41
|
-
|
|
84
|
+
protected readonly log = $logger();
|
|
85
|
+
protected readonly store = $inject(ConfigStore);
|
|
86
|
+
|
|
87
|
+
/** Internal atom key for state management */
|
|
88
|
+
protected atomKey!: string;
|
|
89
|
+
|
|
90
|
+
/** Schema hash for migration detection */
|
|
91
|
+
protected schemaHash!: string;
|
|
92
|
+
|
|
93
|
+
/** Whether we're currently syncing (to avoid loops) */
|
|
94
|
+
protected syncing = false;
|
|
95
|
+
|
|
96
|
+
/** Whether initial load has completed */
|
|
97
|
+
protected loaded = false;
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Configuration name (uses property key if not specified).
|
|
101
|
+
*/
|
|
102
|
+
public get name(): string {
|
|
42
103
|
return this.options.name || this.config.propertyKey;
|
|
43
104
|
}
|
|
44
105
|
|
|
106
|
+
/**
|
|
107
|
+
* The TypeBox schema for this configuration.
|
|
108
|
+
*/
|
|
45
109
|
public get schema(): T {
|
|
46
110
|
return this.options.schema;
|
|
47
111
|
}
|
|
48
112
|
|
|
113
|
+
/**
|
|
114
|
+
* Get the current configuration value.
|
|
115
|
+
*/
|
|
49
116
|
public get current(): Static<T> {
|
|
50
|
-
return
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
return undefined;
|
|
117
|
+
return (
|
|
118
|
+
(this.alepha.store.get(this.atomKey as any) as Static<T>) ??
|
|
119
|
+
this.options.default
|
|
120
|
+
);
|
|
55
121
|
}
|
|
56
122
|
|
|
123
|
+
/**
|
|
124
|
+
* Get a specific field from the current configuration.
|
|
125
|
+
*/
|
|
57
126
|
public get<Key extends keyof Static<T>>(key: Key): Static<T>[Key] {
|
|
58
127
|
return this.current[key];
|
|
59
128
|
}
|
|
60
129
|
|
|
61
130
|
/**
|
|
62
|
-
*
|
|
131
|
+
* Set a new configuration value.
|
|
132
|
+
*
|
|
133
|
+
* @param value - The new configuration value
|
|
134
|
+
* @param options - Optional settings (activation date, creator info, etc.)
|
|
63
135
|
*/
|
|
64
136
|
public async set(
|
|
65
137
|
value: Static<T>,
|
|
66
|
-
options: {
|
|
67
|
-
|
|
68
|
-
|
|
138
|
+
options: SetConfigOptions = {},
|
|
139
|
+
): Promise<void> {
|
|
140
|
+
// Save to database
|
|
141
|
+
await this.store.save(this.name, value, this.schemaHash, {
|
|
142
|
+
activationDate: options.activationDate,
|
|
143
|
+
changeDescription: options.changeDescription,
|
|
144
|
+
tags: options.tags,
|
|
145
|
+
creatorId: options.user?.id,
|
|
146
|
+
creatorName: options.user?.name ?? options.user?.email,
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
// If immediate activation (no future date), update state
|
|
150
|
+
const now = new Date();
|
|
151
|
+
if (!options.activationDate || options.activationDate <= now) {
|
|
152
|
+
this.syncing = true;
|
|
153
|
+
try {
|
|
154
|
+
this.alepha.store.set(this.atomKey as any, value);
|
|
155
|
+
} finally {
|
|
156
|
+
this.syncing = false;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Subscribe to configuration changes.
|
|
163
|
+
*/
|
|
164
|
+
public sub(fn: (curr: Static<T>) => void): () => void {
|
|
165
|
+
return this.alepha.events.on("state:mutate", {
|
|
166
|
+
callback: ({ key, value }) => {
|
|
167
|
+
if (key === this.atomKey) {
|
|
168
|
+
fn(value as Static<T>);
|
|
169
|
+
}
|
|
170
|
+
},
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Reload configuration from database.
|
|
176
|
+
* Called when scheduled config activates or sync message received.
|
|
177
|
+
*/
|
|
178
|
+
public async reload(): Promise<void> {
|
|
179
|
+
const value = await this.store.load<T>(this.name);
|
|
180
|
+
if (value !== null) {
|
|
181
|
+
this.syncing = true;
|
|
182
|
+
try {
|
|
183
|
+
this.alepha.store.set(this.atomKey as any, value, { skipEvents: true });
|
|
184
|
+
} finally {
|
|
185
|
+
this.syncing = false;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Update from sync message (called by ConfigStore).
|
|
192
|
+
* Uses skipEvents to avoid infinite loops.
|
|
193
|
+
*/
|
|
194
|
+
public async updateFromSync(content: unknown): Promise<void> {
|
|
195
|
+
this.syncing = true;
|
|
196
|
+
try {
|
|
197
|
+
this.alepha.store.set(this.atomKey as any, content as Static<T>, {
|
|
198
|
+
skipEvents: true,
|
|
199
|
+
});
|
|
200
|
+
} finally {
|
|
201
|
+
this.syncing = false;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Get version history for this configuration.
|
|
207
|
+
*/
|
|
208
|
+
public async getHistory() {
|
|
209
|
+
return this.store.getHistory(this.name);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Rollback to a specific version.
|
|
214
|
+
*/
|
|
215
|
+
public async rollback(
|
|
216
|
+
version: number,
|
|
217
|
+
options?: SetConfigOptions,
|
|
218
|
+
): Promise<void> {
|
|
219
|
+
await this.store.rollback(this.name, version, {
|
|
220
|
+
changeDescription: options?.changeDescription,
|
|
221
|
+
creatorId: options?.user?.id,
|
|
222
|
+
creatorName: options?.user?.name ?? options?.user?.email,
|
|
223
|
+
});
|
|
224
|
+
await this.reload();
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Hook to load initial value from database on start.
|
|
229
|
+
*/
|
|
230
|
+
protected readonly onStart = $hook({
|
|
231
|
+
on: "start",
|
|
232
|
+
handler: async () => {
|
|
233
|
+
await this.loadInitial();
|
|
69
234
|
},
|
|
70
|
-
)
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Called after primitive creation to initialize.
|
|
239
|
+
*/
|
|
240
|
+
protected onInit(): void {
|
|
241
|
+
// Create unique key for state management
|
|
242
|
+
this.atomKey = `config:${this.name}`;
|
|
243
|
+
|
|
244
|
+
// Calculate schema hash for migration detection
|
|
245
|
+
this.schemaHash = this.calculateSchemaHash();
|
|
246
|
+
|
|
247
|
+
// Register with store
|
|
248
|
+
this.store.register(this);
|
|
249
|
+
|
|
250
|
+
// Set initial default using key-based state
|
|
251
|
+
this.alepha.store.set(this.atomKey as any, this.options.default, {
|
|
252
|
+
skipEvents: true,
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
// Listen for state mutations to detect external changes via alepha.set()
|
|
256
|
+
// Note: state:mutate is not in Hooks interface, so we use events.on() directly
|
|
257
|
+
this.alepha.events.on("state:mutate", {
|
|
258
|
+
caller: this.config.service,
|
|
259
|
+
callback: async ({ key, value, prevValue }) => {
|
|
260
|
+
// Only handle our key
|
|
261
|
+
if (key !== this.atomKey) {
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
// Skip if we're syncing (to avoid infinite loop)
|
|
266
|
+
if (this.syncing) {
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// Skip if value hasn't actually changed
|
|
271
|
+
if (JSON.stringify(value) === JSON.stringify(prevValue)) {
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// Auto-save to database when state is mutated via alepha.set()
|
|
276
|
+
this.log.debug("Config state mutated, persisting to database", {
|
|
277
|
+
name: this.name,
|
|
278
|
+
});
|
|
279
|
+
await this.store.save(this.name, value as Static<T>, this.schemaHash);
|
|
280
|
+
},
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* Load initial value from database.
|
|
286
|
+
*/
|
|
287
|
+
protected async loadInitial(): Promise<void> {
|
|
288
|
+
if (this.loaded) {
|
|
289
|
+
return;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
const value = await this.store.load<T>(this.name);
|
|
293
|
+
|
|
294
|
+
if (value !== null) {
|
|
295
|
+
this.syncing = true;
|
|
296
|
+
try {
|
|
297
|
+
this.alepha.store.set(this.atomKey as any, value, { skipEvents: true });
|
|
298
|
+
} finally {
|
|
299
|
+
this.syncing = false;
|
|
300
|
+
}
|
|
301
|
+
}
|
|
71
302
|
|
|
72
|
-
|
|
303
|
+
this.loaded = true;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* Calculate a hash of the schema for migration detection.
|
|
308
|
+
*/
|
|
309
|
+
protected calculateSchemaHash(): string {
|
|
310
|
+
const schemaJson = JSON.stringify(this.options.schema);
|
|
311
|
+
// Simple hash - in production you might want a proper hash function
|
|
312
|
+
let hash = 0;
|
|
313
|
+
for (let i = 0; i < schemaJson.length; i++) {
|
|
314
|
+
const char = schemaJson.charCodeAt(i);
|
|
315
|
+
hash = (hash << 5) - hash + char;
|
|
316
|
+
hash = hash & hash; // Convert to 32bit integer
|
|
317
|
+
}
|
|
318
|
+
return hash.toString(16);
|
|
319
|
+
}
|
|
73
320
|
}
|
|
74
321
|
|
|
75
322
|
export const $config = <T extends TObject>(
|
|
@@ -77,3 +324,28 @@ export const $config = <T extends TObject>(
|
|
|
77
324
|
) => {
|
|
78
325
|
return createPrimitive(ConfigPrimitive<T>, options);
|
|
79
326
|
};
|
|
327
|
+
|
|
328
|
+
$config[KIND] = ConfigPrimitive;
|
|
329
|
+
|
|
330
|
+
export interface SetConfigOptions {
|
|
331
|
+
/**
|
|
332
|
+
* User making the change (for audit trail).
|
|
333
|
+
*/
|
|
334
|
+
user?: Pick<UserAccount, "id" | "email" | "name">;
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* When this configuration should become active.
|
|
338
|
+
* Default is immediate (now).
|
|
339
|
+
*/
|
|
340
|
+
activationDate?: Date;
|
|
341
|
+
|
|
342
|
+
/**
|
|
343
|
+
* Description of the change.
|
|
344
|
+
*/
|
|
345
|
+
changeDescription?: string;
|
|
346
|
+
|
|
347
|
+
/**
|
|
348
|
+
* Tags for filtering/categorization.
|
|
349
|
+
*/
|
|
350
|
+
tags?: string[];
|
|
351
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { $inject } from "alepha";
|
|
2
|
+
import { $logger } from "alepha/logger";
|
|
3
|
+
import { $scheduler } from "alepha/scheduler";
|
|
4
|
+
import { ConfigStore } from "../services/ConfigStore.ts";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Scheduler that periodically checks for scheduled configurations
|
|
8
|
+
* that should be activated.
|
|
9
|
+
*
|
|
10
|
+
* Runs every minute to check if any NEXT configurations have reached
|
|
11
|
+
* their activation date and need to be promoted to CURRENT.
|
|
12
|
+
*/
|
|
13
|
+
export class ConfigActivationScheduler {
|
|
14
|
+
protected readonly log = $logger();
|
|
15
|
+
protected readonly store = $inject(ConfigStore);
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Check for scheduled configurations every minute.
|
|
19
|
+
*/
|
|
20
|
+
checkActivations = $scheduler({
|
|
21
|
+
name: "config-activation-check",
|
|
22
|
+
description: "Checks for scheduled configurations that should be activated",
|
|
23
|
+
interval: [1, "minute"],
|
|
24
|
+
lock: true,
|
|
25
|
+
handler: async () => {
|
|
26
|
+
this.log.debug("Checking for scheduled config activations");
|
|
27
|
+
await this.store.activateScheduledConfigs();
|
|
28
|
+
},
|
|
29
|
+
});
|
|
30
|
+
}
|