@zerotal/core 1.0.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.
Files changed (201) hide show
  1. package/CHANGELOG.md +79 -0
  2. package/LICENSE +21 -0
  3. package/README.md +128 -0
  4. package/package.json +72 -0
  5. package/src/application/Application.ts +1671 -0
  6. package/src/application/BootDoctor.ts +108 -0
  7. package/src/application/DevErrorPage.ts +567 -0
  8. package/src/application/ExceptionHandler.ts +183 -0
  9. package/src/application/currentApp.ts +73 -0
  10. package/src/assets/assets.ts +79 -0
  11. package/src/assets/index.ts +16 -0
  12. package/src/auth/AuthenticatedUser.ts +18 -0
  13. package/src/build/PackageLinter.ts +146 -0
  14. package/src/build/PackageScaffold.ts +127 -0
  15. package/src/build/codemod.ts +64 -0
  16. package/src/build/index.ts +12 -0
  17. package/src/command/Command.ts +254 -0
  18. package/src/command/CommandRunner.ts +593 -0
  19. package/src/command/OutputWriter.ts +61 -0
  20. package/src/command/builtin/CompileCommand.ts +46 -0
  21. package/src/command/builtin/CssBuildCommand.ts +71 -0
  22. package/src/command/builtin/KeyGenerateCommand.ts +58 -0
  23. package/src/command/builtin/LintPackagesCommand.ts +72 -0
  24. package/src/command/builtin/MakeCommandCommand.ts +85 -0
  25. package/src/command/builtin/MakeControllerCommand.ts +95 -0
  26. package/src/command/builtin/MakeEventCommand.ts +85 -0
  27. package/src/command/builtin/MakeJobCommand.ts +53 -0
  28. package/src/command/builtin/MakeListenerCommand.ts +35 -0
  29. package/src/command/builtin/MakeMiddlewareCommand.ts +63 -0
  30. package/src/command/builtin/MakeNotificationCommand.ts +48 -0
  31. package/src/command/builtin/MakeObserverCommand.ts +78 -0
  32. package/src/command/builtin/MakePackageCommand.ts +45 -0
  33. package/src/command/builtin/MakePolicyCommand.ts +66 -0
  34. package/src/command/builtin/MakeProviderCommand.ts +75 -0
  35. package/src/command/builtin/MakeRequestCommand.ts +47 -0
  36. package/src/command/builtin/MakeResourceCommand.ts +61 -0
  37. package/src/command/builtin/MakeTestCommand.ts +120 -0
  38. package/src/command/builtin/ReloadCommand.ts +52 -0
  39. package/src/command/builtin/ReplCommand.ts +174 -0
  40. package/src/command/builtin/RouteListCommand.ts +188 -0
  41. package/src/command/builtin/ServeCommand.ts +321 -0
  42. package/src/command/builtin/StartCommand.ts +3 -0
  43. package/src/command/builtin/StatusCommand.ts +71 -0
  44. package/src/command/builtin/TestCommand.ts +172 -0
  45. package/src/command/builtin/WorkerCommand.ts +27 -0
  46. package/src/command/builtin/index.ts +53 -0
  47. package/src/command/scaffold/worker.ts.txt +12 -0
  48. package/src/command/scaffold/zerotal.ts.txt +26 -0
  49. package/src/command/startZerotal.ts +55 -0
  50. package/src/config/AppConfig.ts +253 -0
  51. package/src/config/ConfigLoader.ts +117 -0
  52. package/src/config/ConfigManager.ts +169 -0
  53. package/src/config/index.ts +46 -0
  54. package/src/config/registry.ts +59 -0
  55. package/src/config/validation.ts +117 -0
  56. package/src/container/Container.ts +606 -0
  57. package/src/container/ContextualBindingBuilder.ts +57 -0
  58. package/src/container/ScopedResolver.ts +117 -0
  59. package/src/container/index.ts +32 -0
  60. package/src/container/inject.ts +55 -0
  61. package/src/container/types.ts +71 -0
  62. package/src/context/RequestContext.ts +91 -0
  63. package/src/contracts/auth.ts +24 -0
  64. package/src/contracts/index.ts +23 -0
  65. package/src/contracts/session.ts +70 -0
  66. package/src/contracts/transaction.ts +26 -0
  67. package/src/conventions/ConventionLoader.ts +128 -0
  68. package/src/conventions/builtinConcerns.ts +131 -0
  69. package/src/crypt/Crypt.ts +141 -0
  70. package/src/crypt/URLSigner.ts +96 -0
  71. package/src/datetime/Carbon.ts +1396 -0
  72. package/src/datetime/CarbonInterval.ts +421 -0
  73. package/src/datetime/clock.ts +28 -0
  74. package/src/datetime/index.ts +23 -0
  75. package/src/datetime/temporal-shim.ts +1 -0
  76. package/src/dev/BuildOutput.ts +131 -0
  77. package/src/dev/CssPlugins.ts +184 -0
  78. package/src/dev/DevBuildHook.ts +74 -0
  79. package/src/dev/DevOrchestrator.ts +213 -0
  80. package/src/dev/DevReloadMiddleware.ts +101 -0
  81. package/src/dev/DevReloadServer.ts +85 -0
  82. package/src/dev/DevWsServer.ts +45 -0
  83. package/src/dev/index.ts +19 -0
  84. package/src/dev/reloadClient.ts +39 -0
  85. package/src/env/Def.ts +232 -0
  86. package/src/env/EnvSchema.ts +105 -0
  87. package/src/env/index.ts +34 -0
  88. package/src/env/t.ts +128 -0
  89. package/src/errors/ConfigError.ts +12 -0
  90. package/src/errors/ContainerErrors.ts +143 -0
  91. package/src/errors/HttpError.ts +127 -0
  92. package/src/errors/ValidationError.ts +19 -0
  93. package/src/errors/ZerotalError.ts +25 -0
  94. package/src/errors/index.ts +46 -0
  95. package/src/events/CallQueuedListener.ts +66 -0
  96. package/src/events/Emitter.ts +280 -0
  97. package/src/events/EventFake.ts +160 -0
  98. package/src/events/FrameworkEvents.ts +252 -0
  99. package/src/facade/Facade.ts +101 -0
  100. package/src/facade/facades/App.ts +155 -0
  101. package/src/facade/facades/Artisan.ts +63 -0
  102. package/src/facade/facades/Config.ts +21 -0
  103. package/src/facade/facades/Events.ts +19 -0
  104. package/src/facade/facades/index.ts +28 -0
  105. package/src/global.d.ts +9 -0
  106. package/src/hash/Hash.ts +60 -0
  107. package/src/health/Health.ts +221 -0
  108. package/src/health/index.ts +27 -0
  109. package/src/helpers/Collection.ts +435 -0
  110. package/src/helpers/config.ts +59 -0
  111. package/src/helpers/fluent.ts +52 -0
  112. package/src/helpers/html.ts +11 -0
  113. package/src/helpers/index.ts +266 -0
  114. package/src/helpers/make.ts +35 -0
  115. package/src/helpers/markdown.ts +73 -0
  116. package/src/helpers/pageElements.ts +27 -0
  117. package/src/helpers/request.ts +62 -0
  118. package/src/helpers/response.ts +411 -0
  119. package/src/helpers/str.ts +208 -0
  120. package/src/http/Http.ts +298 -0
  121. package/src/http/HttpClient.ts +289 -0
  122. package/src/http/Resource.ts +171 -0
  123. package/src/http/UploadedFile.ts +204 -0
  124. package/src/http/Uri.ts +490 -0
  125. package/src/http/index.ts +46 -0
  126. package/src/http/negotiate.ts +213 -0
  127. package/src/http/originGuard.ts +76 -0
  128. package/src/http/sniffContentType.ts +105 -0
  129. package/src/http/url.ts +204 -0
  130. package/src/http/withHeaders.ts +24 -0
  131. package/src/index.ts +250 -0
  132. package/src/lock/LockManager.ts +228 -0
  133. package/src/lock/config.ts +49 -0
  134. package/src/lock/drivers/LockDriver.ts +32 -0
  135. package/src/lock/drivers/MemoryLockDriver.ts +52 -0
  136. package/src/lock/drivers/RedisLockDriver.ts +58 -0
  137. package/src/lock/drivers/SqliteLockDriver.ts +85 -0
  138. package/src/lock/errors.ts +20 -0
  139. package/src/lock/facades/Lock.ts +114 -0
  140. package/src/lock/index.ts +53 -0
  141. package/src/logger/Log.ts +35 -0
  142. package/src/logger/LogManager.ts +430 -0
  143. package/src/logger/LoggerMiddleware.ts +125 -0
  144. package/src/logger/channels/ConsoleChannel.ts +139 -0
  145. package/src/logger/channels/DailyChannel.ts +74 -0
  146. package/src/logger/channels/NullChannel.ts +17 -0
  147. package/src/logger/channels/SingleChannel.ts +34 -0
  148. package/src/logger/channels/StackChannel.ts +29 -0
  149. package/src/logger/config.ts +90 -0
  150. package/src/logger/format.ts +96 -0
  151. package/src/logger/frameworkLog.ts +93 -0
  152. package/src/logger/index.ts +68 -0
  153. package/src/logger/renderTable.ts +111 -0
  154. package/src/logger/types.ts +212 -0
  155. package/src/macros/config.macro.ts +50 -0
  156. package/src/metrics/HttpMetrics.ts +114 -0
  157. package/src/metrics/index.ts +18 -0
  158. package/src/middleware/BaseMiddleware.ts +72 -0
  159. package/src/middleware/CorsMiddleware.ts +152 -0
  160. package/src/middleware/RateLimiter.ts +255 -0
  161. package/src/middleware/SecureHeadersMiddleware.ts +127 -0
  162. package/src/middleware/ThrottleMiddleware.ts +252 -0
  163. package/src/middleware/WebhookMiddleware.ts +204 -0
  164. package/src/pipeline/ContextRegistry.ts +42 -0
  165. package/src/pipeline/HttpContext.ts +865 -0
  166. package/src/pipeline/Pipeline.ts +150 -0
  167. package/src/pipeline/currentPage.ts +46 -0
  168. package/src/pipeline/types.ts +80 -0
  169. package/src/provider/LockProvider.ts +64 -0
  170. package/src/provider/LogProvider.ts +137 -0
  171. package/src/provider/ServiceProvider.ts +84 -0
  172. package/src/provider/StorageProvider.ts +45 -0
  173. package/src/router/FileRouter.ts +526 -0
  174. package/src/router/Route.ts +76 -0
  175. package/src/router/RouteHandler.ts +335 -0
  176. package/src/router/Router.ts +1247 -0
  177. package/src/router/domain.ts +65 -0
  178. package/src/security/index.ts +22 -0
  179. package/src/storage/FakeDisk.ts +233 -0
  180. package/src/storage/StorageFilesMiddleware.ts +150 -0
  181. package/src/storage/StorageManager.ts +173 -0
  182. package/src/storage/config.ts +47 -0
  183. package/src/storage/drivers/LocalDriver.ts +138 -0
  184. package/src/storage/drivers/S3Driver.ts +169 -0
  185. package/src/storage/errors.ts +135 -0
  186. package/src/storage/facades/Storage.ts +3 -0
  187. package/src/storage/global.d.ts +7 -0
  188. package/src/storage/index.ts +22 -0
  189. package/src/storage/root.ts +59 -0
  190. package/src/storage/types.ts +104 -0
  191. package/src/support/appKey.ts +38 -0
  192. package/src/support/cookie.ts +72 -0
  193. package/src/support/crypto.ts +52 -0
  194. package/src/support/deepMerge.ts +117 -0
  195. package/src/support/env.ts +71 -0
  196. package/src/support/network.ts +79 -0
  197. package/src/support/port.ts +197 -0
  198. package/src/support/str.ts +122 -0
  199. package/src/view/FileRouteResolver.ts +59 -0
  200. package/src/view/index.ts +144 -0
  201. package/src/view/jsx-runtime.ts +233 -0
@@ -0,0 +1,85 @@
1
+ import { Database } from "bun:sqlite";
2
+ import type { LockDriver } from "./LockDriver.ts";
3
+
4
+ /**
5
+ * SQLite-backed lock driver.
6
+ *
7
+ * Suitable for single-server deployments that need locks to survive process
8
+ * restarts. Backed by `bun:sqlite` — fully synchronous under the hood so
9
+ * every acquire/release is a single atomic statement.
10
+ *
11
+ * Use `:memory:` as the path for in-process persistence across tests
12
+ * without touching the filesystem.
13
+ *
14
+ * @category Configuration
15
+ */
16
+ export class SqliteLockDriver implements LockDriver {
17
+ private readonly _db: Database;
18
+
19
+ constructor(path = ":memory:") {
20
+ this._db = new Database(path);
21
+ this._db.exec(`
22
+ CREATE TABLE IF NOT EXISTS zerotal_locks (
23
+ key TEXT PRIMARY KEY,
24
+ owner TEXT NOT NULL,
25
+ expires_at INTEGER NOT NULL
26
+ )
27
+ `);
28
+ }
29
+
30
+ async acquire(key: string, owner: string, ttlSeconds: number): Promise<boolean> {
31
+ const now = Date.now();
32
+ const expiresAt = now + ttlSeconds * 1000;
33
+
34
+ // Purge any expired record for this key so INSERT can succeed
35
+ this._db.prepare("DELETE FROM zerotal_locks WHERE key = ? AND expires_at <= ?").run(key, now);
36
+
37
+ // If the lock is already held by this owner, refresh the TTL
38
+ const existing = this._db
39
+ .prepare<{ owner: string }, string>("SELECT owner FROM zerotal_locks WHERE key = ?")
40
+ .get(key);
41
+
42
+ if (existing) {
43
+ if (existing.owner === owner) {
44
+ this._db
45
+ .prepare("UPDATE zerotal_locks SET expires_at = ? WHERE key = ?")
46
+ .run(expiresAt, key);
47
+ return true;
48
+ }
49
+ return false; // held by another owner
50
+ }
51
+
52
+ try {
53
+ this._db
54
+ .prepare("INSERT INTO zerotal_locks (key, owner, expires_at) VALUES (?, ?, ?)")
55
+ .run(key, owner, expiresAt);
56
+ return true;
57
+ } catch {
58
+ return false;
59
+ }
60
+ }
61
+
62
+ async release(key: string, owner: string): Promise<boolean> {
63
+ const result = this._db
64
+ .prepare("DELETE FROM zerotal_locks WHERE key = ? AND owner = ?")
65
+ .run(key, owner);
66
+ return result.changes > 0;
67
+ }
68
+
69
+ async forceRelease(key: string): Promise<void> {
70
+ this._db.prepare("DELETE FROM zerotal_locks WHERE key = ?").run(key);
71
+ }
72
+
73
+ async exists(key: string): Promise<boolean> {
74
+ const row = this._db
75
+ .prepare<{ 1: number }, [string, number]>(
76
+ "SELECT 1 FROM zerotal_locks WHERE key = ? AND expires_at > ?",
77
+ )
78
+ .get(key, Date.now());
79
+ return row !== null;
80
+ }
81
+
82
+ dispose(): void {
83
+ this._db.close();
84
+ }
85
+ }
@@ -0,0 +1,20 @@
1
+ import { ZerotalError } from "../errors/index.ts";
2
+
3
+ /**
4
+ * Thrown when a lock cannot be acquired: immediately by
5
+ * {@link LockManager.try | try}/{@link Lock.try | Lock.try} when the key is
6
+ * busy, or by {@link LockManager.block | block}/{@link Lock.block | Lock.block}
7
+ * when the wait timeout elapses. Carries the contended {@link key} and maps to
8
+ * HTTP 409 (code `E_LOCK_NOT_ACQUIRED`).
9
+ *
10
+ * @category Acquiring
11
+ */
12
+ export class LockNotAcquiredError extends ZerotalError {
13
+ /** The lock key that could not be acquired. */
14
+ readonly key: string;
15
+
16
+ constructor(key: string) {
17
+ super(`[Zerotal Lock] Could not acquire lock for key: "${key}"`, "E_LOCK_NOT_ACQUIRED", 409);
18
+ this.key = key;
19
+ }
20
+ }
@@ -0,0 +1,114 @@
1
+ import { currentApp } from "../../application/currentApp.ts";
2
+ import { ZerotalError } from "../../errors/index.ts";
3
+ import type { LockManager, ManagedLock, BlockOptions } from "../LockManager.ts";
4
+ import { LockNotAcquiredError } from "../errors.ts";
5
+
6
+ /**
7
+ * Resolve the live LockManager from the application container on every call.
8
+ * The container is the single source of truth — the facade caches nothing and
9
+ * holds no module-level state.
10
+ */
11
+ function _manager(): LockManager {
12
+ try {
13
+ return currentApp().container.makeSync("lock");
14
+ } catch {
15
+ throw new ZerotalError(
16
+ "[Zerotal Lock] Lock facade unavailable — register LockProvider in your application.",
17
+ "E_LOCK_FACADE_UNAVAILABLE",
18
+ 500,
19
+ );
20
+ }
21
+ }
22
+
23
+ /**
24
+ * Static facade over the container-bound {@link LockManager}.
25
+ *
26
+ * Resolves the live `lock` singleton on every call and forwards to the
27
+ * manager, so it exposes the same three usage styles: {@link Lock.try | try}
28
+ * (fail fast), {@link Lock.block | block} (wait for the lock), and
29
+ * {@link Lock.make | make} (a manual {@link ManagedLock} handle). Requires
30
+ * {@link LockProvider} to be registered.
31
+ *
32
+ * @category Acquiring
33
+ *
34
+ * @example
35
+ * ```ts
36
+ * // Fail-fast — throws immediately if the lock is busy
37
+ * await Lock.try('invoice:123', 10, async () => {
38
+ * await processInvoice(123);
39
+ * });
40
+ *
41
+ * // Blocking — waits up to 30s for the lock
42
+ * await Lock.block('invoice:123', 10, async () => {
43
+ * await processInvoice(123);
44
+ * }, { timeout: 30 });
45
+ *
46
+ * // Manual handle for complex flows
47
+ * const handle = Lock.make('payment:456', 15);
48
+ * if (await handle.acquire()) {
49
+ * try {
50
+ * await capturePayment(456);
51
+ * } finally {
52
+ * await handle.release();
53
+ * }
54
+ * }
55
+ * ```
56
+ */
57
+ export class Lock {
58
+ /**
59
+ * Create a named lock handle for manual acquire/release flows.
60
+ * Does NOT acquire the lock — call `.acquire()` or `.block()` explicitly.
61
+ *
62
+ * @param key - Logical lock name.
63
+ * @param ttlSeconds - Lock time-to-live in seconds.
64
+ * @throws {ZerotalError} (code `E_LOCK_FACADE_UNAVAILABLE`) if {@link LockProvider} is not registered.
65
+ * @category Acquiring
66
+ */
67
+ static make(key: string, ttlSeconds: number): ManagedLock {
68
+ return _manager().lock(key, ttlSeconds);
69
+ }
70
+
71
+ /**
72
+ * Acquire the lock exactly once, run `callback`, then release — always,
73
+ * even if `callback` throws.
74
+ *
75
+ * @param key - Logical lock name.
76
+ * @param ttlSeconds - Lock time-to-live in seconds.
77
+ * @param callback - Critical section to run while the lock is held.
78
+ * @returns The value returned by `callback`.
79
+ * @throws {LockNotAcquiredError} Immediately, if the lock is busy.
80
+ * @category Acquiring
81
+ */
82
+ static async try<T>(key: string, ttlSeconds: number, callback: () => Promise<T> | T): Promise<T> {
83
+ return _manager().try(key, ttlSeconds, callback);
84
+ }
85
+
86
+ /**
87
+ * Wait until the lock is free (up to `options.timeout` seconds), run
88
+ * `callback`, then release — always, even if `callback` throws.
89
+ *
90
+ * @param key - Logical lock name.
91
+ * @param ttlSeconds - Lock time-to-live in seconds.
92
+ * @param callback - Critical section to run while the lock is held.
93
+ * @param options - Wait {@link BlockOptions.timeout | timeout} and poll interval.
94
+ * @returns The value returned by `callback`.
95
+ * @throws {LockNotAcquiredError} If the timeout elapses before the lock is acquired.
96
+ * @category Acquiring
97
+ */
98
+ static async block<T>(
99
+ key: string,
100
+ ttlSeconds: number,
101
+ callback: () => Promise<T> | T,
102
+ options?: BlockOptions,
103
+ ): Promise<T> {
104
+ return _manager().block(key, ttlSeconds, callback, options);
105
+ }
106
+
107
+ /**
108
+ * The {@link LockNotAcquiredError} class, re-exported for convenience in
109
+ * `catch` blocks (`err instanceof Lock.NotAcquired`).
110
+ *
111
+ * @category Acquiring
112
+ */
113
+ static readonly NotAcquired = LockNotAcquiredError;
114
+ }
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Distributed mutual-exclusion locks for Zerotal applications.
3
+ *
4
+ * A named lock guarantees that at most one holder runs a critical section at a
5
+ * time — across processes and servers when backed by the Redis or SQLite
6
+ * driver, or in-process with the default memory driver. Every lock carries a
7
+ * TTL so a crashed holder cannot deadlock the key, and release is owner-guarded
8
+ * so a holder whose lock already expired can never release a newer holder's
9
+ * lock. Reach the container-bound manager through the {@link Lock} facade;
10
+ * configure the backend with {@link LockConfig}.
11
+ *
12
+ * @example
13
+ * ```ts
14
+ * import { Lock } from "@zerotal/core/lock";
15
+ *
16
+ * // Fail fast: throw LockNotAcquiredError immediately if the key is busy.
17
+ * await Lock.try("invoice:123", 10, async () => {
18
+ * await processInvoice(123);
19
+ * });
20
+ *
21
+ * // Blocking: wait up to 30s for the key to free, holding it for 10s (TTL).
22
+ * await Lock.block("invoice:123", 10, async () => {
23
+ * await processInvoice(123);
24
+ * }, { timeout: 30 });
25
+ *
26
+ * // Manual handle for flows that span multiple steps.
27
+ * const handle = Lock.make("payment:456", 15);
28
+ * if (await handle.acquire()) {
29
+ * try {
30
+ * await capturePayment(456);
31
+ * } finally {
32
+ * await handle.release();
33
+ * }
34
+ * }
35
+ * ```
36
+ *
37
+ * @packageDocumentation
38
+ */
39
+
40
+ export { LockManager, ManagedLock } from "./LockManager.ts";
41
+ export type { BlockOptions } from "./LockManager.ts";
42
+
43
+ export { Lock } from "./facades/Lock.ts";
44
+ export { LockProvider } from "../provider/LockProvider.ts";
45
+ export { LockConfig } from "./config.ts";
46
+ export type { LockConfigShape } from "./config.ts";
47
+ export { LockNotAcquiredError } from "./errors.ts";
48
+
49
+ // Drivers — exported for custom driver registration and direct instantiation
50
+ export type { LockDriver } from "./drivers/LockDriver.ts";
51
+ export { MemoryLockDriver } from "./drivers/MemoryLockDriver.ts";
52
+ export { SqliteLockDriver } from "./drivers/SqliteLockDriver.ts";
53
+ export { RedisLockDriver } from "./drivers/RedisLockDriver.ts";
@@ -0,0 +1,35 @@
1
+ import { createFacade } from "../facade/Facade.ts";
2
+
3
+ /**
4
+ * Static facade over the container-bound {@link LogManager}.
5
+ *
6
+ * Every access resolves the live `log` singleton, so `Log` exposes the full
7
+ * {@link LogManager} surface: the five level methods
8
+ * ({@link LogManager.debug | debug}/{@link LogManager.info | info}/
9
+ * {@link LogManager.warn | warn}/{@link LogManager.error | error}/
10
+ * {@link LogManager.fatal | fatal}) on the default channel, plus
11
+ * {@link LogManager.channel | channel} and
12
+ * {@link LogManager.withContext | withContext}. Available after the application
13
+ * has booted (the facade throws if accessed at module scope before boot).
14
+ *
15
+ * @category Logging
16
+ *
17
+ * @example
18
+ * ```ts
19
+ * import { Log } from "@zerotal/core/logger";
20
+ *
21
+ * // Level + structured context.
22
+ * Log.info("Order placed", { orderId: 99, total: 42.5 });
23
+ *
24
+ * // Attach an error — its message and stack are captured onto the entry.
25
+ * Log.error("Charge failed", { orderId: 99 }, err);
26
+ *
27
+ * // Contextual logging: shared fields merged into every subsequent entry.
28
+ * const scoped = Log.withContext({ tenant: "acme" });
29
+ * scoped.warn("Quota nearly exhausted", { pct: 92 });
30
+ *
31
+ * // Target a specific configured channel.
32
+ * Log.channel("daily").info("Persisted to today's rotating file");
33
+ * ```
34
+ */
35
+ export const Log = createFacade("log");