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.
Files changed (136) hide show
  1. package/dist/api-audits/index.browser.js +116 -0
  2. package/dist/api-audits/index.browser.js.map +1 -0
  3. package/dist/api-audits/index.d.ts +1194 -0
  4. package/dist/api-audits/index.js +674 -0
  5. package/dist/api-audits/index.js.map +1 -0
  6. package/dist/api-notifications/index.d.ts +147 -147
  7. package/dist/api-parameters/index.browser.js +36 -5
  8. package/dist/api-parameters/index.browser.js.map +1 -1
  9. package/dist/api-parameters/index.d.ts +711 -33
  10. package/dist/api-parameters/index.js +831 -17
  11. package/dist/api-parameters/index.js.map +1 -1
  12. package/dist/api-users/index.d.ts +16 -3
  13. package/dist/api-users/index.js +699 -19
  14. package/dist/api-users/index.js.map +1 -1
  15. package/dist/api-verifications/index.js +2 -1
  16. package/dist/api-verifications/index.js.map +1 -1
  17. package/dist/bin/index.js +1 -0
  18. package/dist/bin/index.js.map +1 -1
  19. package/dist/cli/index.d.ts +85 -31
  20. package/dist/cli/index.js +205 -33
  21. package/dist/cli/index.js.map +1 -1
  22. package/dist/command/index.d.ts +67 -6
  23. package/dist/command/index.js +30 -3
  24. package/dist/command/index.js.map +1 -1
  25. package/dist/core/index.browser.js +241 -61
  26. package/dist/core/index.browser.js.map +1 -1
  27. package/dist/core/index.d.ts +170 -90
  28. package/dist/core/index.js +264 -67
  29. package/dist/core/index.js.map +1 -1
  30. package/dist/core/index.native.js +248 -65
  31. package/dist/core/index.native.js.map +1 -1
  32. package/dist/email/index.js +15 -10554
  33. package/dist/email/index.js.map +1 -1
  34. package/dist/logger/index.d.ts +4 -4
  35. package/dist/logger/index.js +77 -72
  36. package/dist/logger/index.js.map +1 -1
  37. package/dist/orm/index.d.ts +5 -1
  38. package/dist/orm/index.js +24 -7
  39. package/dist/orm/index.js.map +1 -1
  40. package/dist/queue/index.d.ts +4 -4
  41. package/dist/redis/index.d.ts +10 -10
  42. package/dist/security/index.d.ts +28 -28
  43. package/dist/server/index.d.ts +10 -1
  44. package/dist/server/index.js +20 -6
  45. package/dist/server/index.js.map +1 -1
  46. package/dist/server-auth/index.d.ts +163 -152
  47. package/dist/server-auth/index.js +40 -10
  48. package/dist/server-auth/index.js.map +1 -1
  49. package/dist/server-cookies/index.js +5 -1
  50. package/dist/server-cookies/index.js.map +1 -1
  51. package/dist/server-links/index.d.ts +33 -33
  52. package/dist/server-security/index.d.ts +9 -9
  53. package/dist/thread/index.js +2 -2
  54. package/dist/thread/index.js.map +1 -1
  55. package/dist/vite/index.d.ts +2 -2
  56. package/dist/vite/index.js +102 -45
  57. package/dist/vite/index.js.map +1 -1
  58. package/dist/websocket/index.browser.js +3 -3
  59. package/dist/websocket/index.browser.js.map +1 -1
  60. package/dist/websocket/index.d.ts +7 -7
  61. package/dist/websocket/index.js +4 -4
  62. package/dist/websocket/index.js.map +1 -1
  63. package/package.json +14 -9
  64. package/src/api-audits/controllers/AuditController.ts +186 -0
  65. package/src/api-audits/entities/audits.ts +132 -0
  66. package/src/api-audits/index.browser.ts +18 -0
  67. package/src/api-audits/index.ts +58 -0
  68. package/src/api-audits/primitives/$audit.ts +159 -0
  69. package/src/api-audits/schemas/auditQuerySchema.ts +23 -0
  70. package/src/api-audits/schemas/auditResourceSchema.ts +9 -0
  71. package/src/api-audits/schemas/createAuditSchema.ts +27 -0
  72. package/src/api-audits/services/AuditService.ts +412 -0
  73. package/src/api-parameters/controllers/ConfigController.ts +324 -0
  74. package/src/api-parameters/entities/parameters.ts +93 -10
  75. package/src/api-parameters/index.ts +43 -4
  76. package/src/api-parameters/primitives/$config.ts +291 -19
  77. package/src/api-parameters/schedulers/ConfigActivationScheduler.ts +30 -0
  78. package/src/api-parameters/services/ConfigStore.ts +491 -0
  79. package/src/api-users/atoms/realmAuthSettingsAtom.ts +19 -0
  80. package/src/api-users/controllers/UserRealmController.ts +0 -2
  81. package/src/api-users/index.ts +2 -0
  82. package/src/api-users/primitives/$userRealm.ts +18 -3
  83. package/src/api-users/providers/UserRealmProvider.ts +6 -3
  84. package/src/api-users/services/RegistrationService.ts +2 -1
  85. package/src/api-users/services/SessionService.ts +4 -0
  86. package/src/api-users/services/UserService.ts +3 -0
  87. package/src/api-verifications/index.ts +7 -1
  88. package/src/bin/index.ts +1 -0
  89. package/src/cli/assets/biomeJson.ts +1 -1
  90. package/src/cli/assets/dummySpecTs.ts +7 -0
  91. package/src/cli/assets/editorconfig.ts +13 -0
  92. package/src/cli/assets/mainTs.ts +14 -0
  93. package/src/cli/commands/BiomeCommands.ts +2 -0
  94. package/src/cli/commands/CoreCommands.ts +28 -9
  95. package/src/cli/commands/VerifyCommands.ts +2 -1
  96. package/src/cli/commands/ViteCommands.ts +8 -9
  97. package/src/cli/services/AlephaCliUtils.ts +214 -23
  98. package/src/command/helpers/Asker.ts +0 -1
  99. package/src/command/primitives/$command.ts +67 -0
  100. package/src/command/providers/CliProvider.ts +39 -8
  101. package/src/core/Alepha.ts +40 -30
  102. package/src/core/helpers/jsonSchemaToTypeBox.ts +307 -0
  103. package/src/core/index.shared.ts +1 -0
  104. package/src/core/index.ts +30 -3
  105. package/src/core/providers/EventManager.ts +1 -1
  106. package/src/core/providers/StateManager.ts +23 -12
  107. package/src/core/providers/TypeProvider.ts +26 -34
  108. package/src/logger/index.ts +8 -6
  109. package/src/logger/primitives/$logger.ts +1 -1
  110. package/src/logger/providers/{SimpleFormatterProvider.ts → PrettyFormatterProvider.ts} +10 -1
  111. package/src/orm/index.ts +6 -0
  112. package/src/orm/services/PgRelationManager.ts +2 -2
  113. package/src/orm/services/PostgresModelBuilder.ts +11 -7
  114. package/src/orm/services/Repository.ts +16 -7
  115. package/src/orm/services/SqliteModelBuilder.ts +10 -0
  116. package/src/server/index.ts +6 -0
  117. package/src/server/primitives/$action.ts +10 -1
  118. package/src/server/providers/ServerBodyParserProvider.ts +11 -5
  119. package/src/server/providers/ServerRouterProvider.ts +13 -7
  120. package/src/server-auth/primitives/$auth.ts +7 -0
  121. package/src/server-auth/providers/ServerAuthProvider.ts +51 -8
  122. package/src/server-cookies/index.ts +2 -1
  123. package/src/thread/primitives/$thread.ts +2 -2
  124. package/src/vite/index.ts +0 -2
  125. package/src/vite/tasks/buildServer.ts +3 -4
  126. package/src/vite/tasks/generateCloudflare.ts +35 -19
  127. package/src/vite/tasks/generateDocker.ts +18 -4
  128. package/src/vite/tasks/generateSitemap.ts +5 -7
  129. package/src/vite/tasks/generateVercel.ts +76 -41
  130. package/src/vite/tasks/runAlepha.ts +16 -1
  131. package/src/websocket/providers/NodeWebSocketServerProvider.ts +3 -11
  132. package/src/websocket/services/WebSocketClient.ts +3 -3
  133. package/dist/cli/dist-BlfFtOk2.js +0 -2770
  134. package/dist/cli/dist-BlfFtOk2.js.map +0 -1
  135. package/src/api-parameters/controllers/ParameterController.ts +0 -45
  136. package/src/api-parameters/services/ParameterStore.ts +0 -23
@@ -0,0 +1,324 @@
1
+ import { $inject, t } from "alepha";
2
+ import { $action } from "alepha/server";
3
+ import type { ParameterStatus } from "../entities/parameters.ts";
4
+ import { ConfigStore } from "../services/ConfigStore.ts";
5
+
6
+ // Define response schemas inline to avoid complex entity schema issues
7
+ const parameterResponseSchema = t.object({
8
+ id: t.uuid(),
9
+ createdAt: t.datetime(),
10
+ updatedAt: t.datetime(),
11
+ name: t.text(),
12
+ content: t.json(),
13
+ schemaHash: t.text(),
14
+ status: t.enum(["expired", "current", "next", "future"]),
15
+ activationDate: t.datetime(),
16
+ expiredAt: t.optional(t.datetime()),
17
+ version: t.integer(),
18
+ changeDescription: t.optional(t.text()),
19
+ tags: t.optional(t.array(t.text())),
20
+ creatorId: t.optional(t.uuid()),
21
+ creatorName: t.optional(t.text()),
22
+ previousContent: t.optional(t.json()),
23
+ migrationLog: t.optional(t.text()),
24
+ });
25
+
26
+ const treeNodeSchema: any = t.object({
27
+ name: t.text(),
28
+ path: t.text(),
29
+ isLeaf: t.boolean(),
30
+ children: t.array(t.any()),
31
+ });
32
+
33
+ /**
34
+ * REST API controller for versioned configuration management.
35
+ *
36
+ * Provides endpoints for:
37
+ * - Listing all configurations (tree view support)
38
+ * - Getting configuration history (all versions)
39
+ * - Getting current/next configuration values
40
+ * - Creating new configuration versions (immediate or scheduled)
41
+ * - Rolling back to previous versions
42
+ * - Activating scheduled versions immediately
43
+ */
44
+ export class ConfigController {
45
+ protected readonly store = $inject(ConfigStore);
46
+
47
+ /**
48
+ * Get tree structure of all configuration names.
49
+ * Useful for admin UI navigation.
50
+ */
51
+ getConfigTree = $action({
52
+ description:
53
+ "Get tree structure of all configuration names for navigation.",
54
+ path: "/configs/tree",
55
+ method: "GET",
56
+ schema: {
57
+ response: t.array(treeNodeSchema),
58
+ },
59
+ handler: async () => {
60
+ return this.store.getConfigTree();
61
+ },
62
+ });
63
+
64
+ /**
65
+ * List all unique configuration names.
66
+ */
67
+ listConfigNames = $action({
68
+ description: "List all unique configuration names.",
69
+ path: "/configs",
70
+ method: "GET",
71
+ schema: {
72
+ response: t.object({
73
+ names: t.array(t.text()),
74
+ }),
75
+ },
76
+ handler: async () => {
77
+ const names = await this.store.getConfigNames();
78
+ return { names };
79
+ },
80
+ });
81
+
82
+ /**
83
+ * Get configurations by status.
84
+ */
85
+ getByStatus = $action({
86
+ description: "Get all configurations with a specific status.",
87
+ path: "/configs/status/:status",
88
+ method: "GET",
89
+ schema: {
90
+ params: t.object({
91
+ status: t.enum(["expired", "current", "next", "future"]),
92
+ }),
93
+ response: t.object({
94
+ configs: t.array(parameterResponseSchema),
95
+ }),
96
+ },
97
+ handler: async ({ params }) => {
98
+ const configs = await this.store.getByStatus(
99
+ params.status as ParameterStatus,
100
+ );
101
+ return { configs };
102
+ },
103
+ });
104
+
105
+ /**
106
+ * Get version history for a specific configuration.
107
+ */
108
+ getHistory = $action({
109
+ description: "Get all versions of a specific configuration.",
110
+ path: "/configs/:name/history",
111
+ method: "GET",
112
+ schema: {
113
+ params: t.object({
114
+ name: t.text({
115
+ description: "Configuration name (e.g., app.features.flags)",
116
+ }),
117
+ }),
118
+ response: t.object({
119
+ versions: t.array(parameterResponseSchema),
120
+ }),
121
+ },
122
+ handler: async ({ params }) => {
123
+ const versions = await this.store.getHistory(params.name);
124
+ return { versions };
125
+ },
126
+ });
127
+
128
+ /**
129
+ * Get current and next values for a configuration.
130
+ * Includes defaultValue and currentValue from the registered primitive
131
+ * even if no versions exist in the database yet.
132
+ */
133
+ getCurrent = $action({
134
+ description: "Get current and next scheduled values for a configuration.",
135
+ path: "/configs/:name",
136
+ method: "GET",
137
+ schema: {
138
+ params: t.object({
139
+ name: t.text({
140
+ description: "Configuration name (e.g., app.features.flags)",
141
+ }),
142
+ }),
143
+ response: t.object({
144
+ current: t.optional(parameterResponseSchema),
145
+ next: t.optional(parameterResponseSchema),
146
+ defaultValue: t.optional(t.json()),
147
+ currentValue: t.optional(t.json()),
148
+ schema: t.optional(t.json()),
149
+ }),
150
+ },
151
+ handler: async ({ params }) => {
152
+ const result = await this.store.getCurrentWithDefault(params.name);
153
+ return {
154
+ current: result.current ?? undefined,
155
+ next: result.next ?? undefined,
156
+ defaultValue: result.defaultValue ?? undefined,
157
+ currentValue: result.currentValue ?? undefined,
158
+ schema: result.schema ?? undefined,
159
+ };
160
+ },
161
+ });
162
+
163
+ /**
164
+ * Get a specific version of a configuration.
165
+ */
166
+ getVersion = $action({
167
+ description: "Get a specific version of a configuration.",
168
+ path: "/configs/:name/versions/:version",
169
+ method: "GET",
170
+ schema: {
171
+ params: t.object({
172
+ name: t.text(),
173
+ version: t.integer(),
174
+ }),
175
+ response: t.object({
176
+ config: t.optional(parameterResponseSchema),
177
+ }),
178
+ },
179
+ handler: async ({ params }) => {
180
+ const config = await this.store.getVersion(params.name, params.version);
181
+ return { config: config ?? undefined };
182
+ },
183
+ });
184
+
185
+ /**
186
+ * Create a new configuration version.
187
+ */
188
+ createVersion = $action({
189
+ description:
190
+ "Create a new version of a configuration (immediate or scheduled).",
191
+ path: "/configs/:name",
192
+ method: "POST",
193
+ schema: {
194
+ params: t.object({
195
+ name: t.text({
196
+ description: "Configuration name (e.g., app.features.flags)",
197
+ }),
198
+ }),
199
+ body: t.object({
200
+ content: t.json({ description: "New configuration content" }),
201
+ schemaHash: t.text({
202
+ description: "Hash of the schema for migration detection",
203
+ }),
204
+ activationDate: t.optional(
205
+ t.datetime({ description: "When to activate (default: now)" }),
206
+ ),
207
+ changeDescription: t.optional(
208
+ t.text({ description: "Description of changes" }),
209
+ ),
210
+ tags: t.optional(t.array(t.text())),
211
+ creatorId: t.optional(t.uuid()),
212
+ creatorName: t.optional(t.text()),
213
+ }),
214
+ response: parameterResponseSchema,
215
+ },
216
+ handler: async ({ params, body }) => {
217
+ return this.store.save(params.name, body.content, body.schemaHash, {
218
+ activationDate: body.activationDate
219
+ ? new Date(body.activationDate)
220
+ : undefined,
221
+ changeDescription: body.changeDescription,
222
+ tags: body.tags,
223
+ creatorId: body.creatorId,
224
+ creatorName: body.creatorName,
225
+ });
226
+ },
227
+ });
228
+
229
+ /**
230
+ * Rollback to a previous version.
231
+ */
232
+ rollback = $action({
233
+ description:
234
+ "Rollback a configuration to a previous version (creates new version with old content).",
235
+ path: "/configs/:name/rollback",
236
+ method: "POST",
237
+ schema: {
238
+ params: t.object({
239
+ name: t.text(),
240
+ }),
241
+ body: t.object({
242
+ targetVersion: t.integer({
243
+ description: "Version number to rollback to",
244
+ }),
245
+ changeDescription: t.optional(t.text()),
246
+ creatorId: t.optional(t.uuid()),
247
+ creatorName: t.optional(t.text()),
248
+ }),
249
+ response: parameterResponseSchema,
250
+ },
251
+ handler: async ({ params, body }) => {
252
+ return this.store.rollback(params.name, body.targetVersion, {
253
+ changeDescription: body.changeDescription,
254
+ creatorId: body.creatorId,
255
+ creatorName: body.creatorName,
256
+ });
257
+ },
258
+ });
259
+
260
+ /**
261
+ * Activate a scheduled version immediately.
262
+ */
263
+ activateNow = $action({
264
+ description: "Activate a future/next configuration version immediately.",
265
+ path: "/configs/:name/activate",
266
+ method: "POST",
267
+ schema: {
268
+ params: t.object({
269
+ name: t.text(),
270
+ }),
271
+ body: t.object({
272
+ version: t.integer({ description: "Version number to activate" }),
273
+ creatorId: t.optional(t.uuid()),
274
+ creatorName: t.optional(t.text()),
275
+ }),
276
+ response: parameterResponseSchema,
277
+ },
278
+ handler: async ({ params, body }) => {
279
+ const target = await this.store.getVersion(params.name, body.version);
280
+ if (!target) {
281
+ throw new Error(
282
+ `Version ${body.version} not found for config ${params.name}`,
283
+ );
284
+ }
285
+
286
+ if (target.status === "current") {
287
+ return target; // Already current
288
+ }
289
+
290
+ if (target.status === "expired") {
291
+ throw new Error(
292
+ "Cannot activate an expired version. Use rollback instead.",
293
+ );
294
+ }
295
+
296
+ // Create new version with same content but immediate activation
297
+ return this.store.save(params.name, target.content, target.schemaHash, {
298
+ changeDescription: `Early activation of version ${body.version}`,
299
+ creatorId: body.creatorId,
300
+ creatorName: body.creatorName,
301
+ });
302
+ },
303
+ });
304
+
305
+ /**
306
+ * Trigger activation check for all scheduled configs.
307
+ * Normally called by a scheduler, but exposed for manual triggering.
308
+ */
309
+ checkScheduled = $action({
310
+ description:
311
+ "Manually trigger activation check for all scheduled configurations.",
312
+ path: "/configs/activate-scheduled",
313
+ method: "POST",
314
+ schema: {
315
+ response: t.object({
316
+ message: t.text(),
317
+ }),
318
+ },
319
+ handler: async () => {
320
+ await this.store.activateScheduledConfigs();
321
+ return { message: "Scheduled configuration activation check completed" };
322
+ },
323
+ });
324
+ }
@@ -1,30 +1,113 @@
1
1
  import { type Static, t } from "alepha";
2
2
  import { $entity, pg } from "alepha/orm";
3
3
 
4
+ /**
5
+ * Parameter status values.
6
+ *
7
+ * - EXPIRED: Past version, no longer active
8
+ * - CURRENT: Currently active version
9
+ * - NEXT: Scheduled to become active (closest future date)
10
+ * - FUTURE: Scheduled for activation after NEXT
11
+ */
12
+ export type ParameterStatus = "expired" | "current" | "next" | "future";
13
+
14
+ /**
15
+ * Configuration parameter entity for versioned configuration management.
16
+ *
17
+ * Stores all versions of configuration parameters with:
18
+ * - Automatic status management (expired, current, next, future)
19
+ * - Schema versioning for migrations
20
+ * - Activation scheduling
21
+ * - Audit trail (creator info)
22
+ */
4
23
  export const parameters = $entity({
5
24
  name: "parameters",
6
25
  schema: t.object({
7
26
  id: pg.primaryKey(t.uuid()),
8
-
9
27
  createdAt: pg.createdAt(),
10
-
11
28
  updatedAt: pg.updatedAt(),
12
29
 
13
- name: t.string(),
30
+ /**
31
+ * Configuration name using dot notation for tree hierarchy.
32
+ * Examples: "app.features", "app.pricing.tiers", "system.limits"
33
+ */
34
+ name: t.text(),
14
35
 
36
+ /**
37
+ * The configuration content as JSON.
38
+ */
15
39
  content: t.json(),
16
40
 
17
- tags: t.optional(t.array(t.string())),
41
+ /**
42
+ * Schema version hash for detecting schema changes.
43
+ * Used for auto-migration when schema evolves.
44
+ */
45
+ schemaHash: t.text(),
46
+
47
+ /**
48
+ * Current status of this parameter version.
49
+ */
50
+ status: pg.default(
51
+ t.enum(["expired", "current", "next", "future"]),
52
+ "future",
53
+ ),
54
+
55
+ /**
56
+ * When this version should become active.
57
+ * Default is immediate (now).
58
+ */
59
+ activationDate: t.datetime(),
18
60
 
61
+ /**
62
+ * When this version was deactivated (became expired).
63
+ * Null if still active or scheduled.
64
+ */
65
+ expiredAt: t.optional(t.datetime()),
66
+
67
+ /**
68
+ * Version number for this configuration.
69
+ * Auto-incremented per config name.
70
+ */
71
+ version: t.integer(),
72
+
73
+ /**
74
+ * Optional description of changes in this version.
75
+ */
76
+ changeDescription: t.optional(t.text()),
77
+
78
+ /**
79
+ * Optional tags for filtering/categorization.
80
+ */
81
+ tags: t.optional(t.array(t.text())),
82
+
83
+ /**
84
+ * Creator user ID (if available).
85
+ */
19
86
  creatorId: t.optional(t.uuid()),
20
87
 
21
- creatorName: t.optional(t.string()),
88
+ /**
89
+ * Creator display name for audit trail.
90
+ */
91
+ creatorName: t.optional(t.text()),
92
+
93
+ /**
94
+ * Previous content before this change (for rollback reference).
95
+ */
96
+ previousContent: t.optional(t.json()),
22
97
 
23
- activationDate: t.datetime({
24
- description:
25
- "Optional activation date. Default to now. Must be now or later.",
26
- }),
98
+ /**
99
+ * Migration log if schema changed.
100
+ */
101
+ migrationLog: t.optional(t.text()),
27
102
  }),
103
+ indexes: [
104
+ { columns: ["name", "status"] },
105
+ { columns: ["name", "activationDate"] },
106
+ { columns: ["name", "version"], unique: true },
107
+ { columns: ["status"] },
108
+ { columns: ["activationDate"] },
109
+ ],
28
110
  });
29
111
 
30
- export type ParameterEntity = Static<typeof parameters.schema>;
112
+ export type Parameter = Static<typeof parameters.schema>;
113
+ export type ParameterInsert = Omit<Parameter, "id" | "createdAt" | "updatedAt">;
@@ -1,21 +1,60 @@
1
1
  import { $module } from "alepha";
2
+ import { ConfigController } from "./controllers/ConfigController.ts";
3
+ import { ConfigActivationScheduler } from "./schedulers/ConfigActivationScheduler.ts";
4
+ import { ConfigStore } from "./services/ConfigStore.ts";
2
5
 
3
6
  // ---------------------------------------------------------------------------------------------------------------------
4
7
 
8
+ // Controller exports
9
+ export * from "./controllers/ConfigController.ts";
10
+ // Entity exports
5
11
  export * from "./entities/parameters.ts";
12
+ // Primitive exports
6
13
  export * from "./primitives/$config.ts";
14
+ // Scheduler exports
15
+ export * from "./schedulers/ConfigActivationScheduler.ts";
16
+ // Service exports
17
+ export * from "./services/ConfigStore.ts";
7
18
 
8
19
  // ---------------------------------------------------------------------------------------------------------------------
9
20
 
10
21
  /**
11
- * Provides parameter management API endpoints for Alepha applications.
22
+ * Provides versioned configuration management for Alepha applications.
12
23
  *
13
- * This module includes configuration parameter storage, retrieval,
14
- * and dynamic application settings management.
24
+ * Features:
25
+ * - Type-safe, versioned configuration with `$config` primitive
26
+ * - Schema validation with auto-migration detection
27
+ * - Scheduled activation (FUTURE, NEXT, CURRENT, EXPIRED statuses)
28
+ * - PostgreSQL persistence with full version history
29
+ * - Cross-instance synchronization via topic
30
+ * - Tree view support via dot-notation naming
31
+ * - REST API for configuration management
32
+ * - Automatic activation scheduler
33
+ *
34
+ * @example
35
+ * ```ts
36
+ * import { Alepha } from "alepha";
37
+ * import { AlephaApiParameters } from "alepha/api-parameters";
38
+ *
39
+ * const alepha = Alepha.create();
40
+ * alepha.with(AlephaApiParameters);
41
+ *
42
+ * // Then use $config in your services:
43
+ * class AppConfig {
44
+ * features = $config({
45
+ * name: "app.features.flags",
46
+ * schema: t.object({
47
+ * enableBeta: t.boolean(),
48
+ * maxUploadSize: t.number()
49
+ * }),
50
+ * default: { enableBeta: false, maxUploadSize: 10485760 }
51
+ * });
52
+ * }
53
+ * ```
15
54
  *
16
55
  * @module alepha.api.parameters
17
56
  */
18
57
  export const AlephaApiParameters = $module({
19
58
  name: "alepha.api.parameters",
20
- services: [],
59
+ services: [ConfigStore, ConfigController, ConfigActivationScheduler],
21
60
  });