react-native-nitro-logger 0.1.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 (205) hide show
  1. package/LICENSE +20 -0
  2. package/NitroLogger.podspec +29 -0
  3. package/README.md +214 -0
  4. package/android/CMakeLists.txt +24 -0
  5. package/android/build.gradle +124 -0
  6. package/android/src/main/AndroidManifest.xml +2 -0
  7. package/android/src/main/cpp/cpp-adapter.cpp +11 -0
  8. package/android/src/main/java/com/margelo/nitro/nitrologger/AndroidPlatformIo.kt +100 -0
  9. package/android/src/main/java/com/margelo/nitro/nitrologger/HybridFileSink.kt +292 -0
  10. package/android/src/main/java/com/margelo/nitro/nitrologger/HybridNativeConsoleSink.kt +23 -0
  11. package/android/src/main/java/com/margelo/nitro/nitrologger/LogFileWriter.kt +1328 -0
  12. package/android/src/main/java/com/margelo/nitro/nitrologger/LogRotationPolicy.kt +186 -0
  13. package/android/src/main/java/com/margelo/nitro/nitrologger/LogSecureFile.kt +80 -0
  14. package/android/src/main/java/com/margelo/nitro/nitrologger/LogWriterRegistry.kt +420 -0
  15. package/android/src/main/java/com/margelo/nitro/nitrologger/NativeConsoleWriter.kt +237 -0
  16. package/android/src/main/java/com/margelo/nitro/nitrologger/NitroLoggerPackage.kt +22 -0
  17. package/android/src/main/java/com/margelo/nitro/nitrologger/PlatformIo.kt +165 -0
  18. package/docs/PARITY.md +330 -0
  19. package/docs/PRIVACY.md +341 -0
  20. package/eslint-plugin/README.md +238 -0
  21. package/eslint-plugin/index.js +62 -0
  22. package/eslint-plugin/rules/literal-subsystem.js +102 -0
  23. package/eslint-plugin/rules/no-computed-metadata-key.js +174 -0
  24. package/eslint-plugin/rules/no-derived-correlation.js +171 -0
  25. package/eslint-plugin/rules/no-dynamic-message.js +60 -0
  26. package/eslint-plugin/shared.js +1948 -0
  27. package/ios/Gzip.swift +203 -0
  28. package/ios/HybridFileSink.swift +291 -0
  29. package/ios/HybridNativeConsoleSink.swift +20 -0
  30. package/ios/LogFileWriter.swift +1280 -0
  31. package/ios/LogSecureFile.swift +296 -0
  32. package/ios/LogWriterRegistry.swift +444 -0
  33. package/ios/NativeConsoleWriter.swift +180 -0
  34. package/lib/module/Logger.js +381 -0
  35. package/lib/module/Logger.js.map +1 -0
  36. package/lib/module/ScopedLogger.js +70 -0
  37. package/lib/module/ScopedLogger.js.map +1 -0
  38. package/lib/module/config.js +23 -0
  39. package/lib/module/config.js.map +1 -0
  40. package/lib/module/destinations/Batcher.js +647 -0
  41. package/lib/module/destinations/Batcher.js.map +1 -0
  42. package/lib/module/destinations/ConsoleDestination.js +51 -0
  43. package/lib/module/destinations/ConsoleDestination.js.map +1 -0
  44. package/lib/module/destinations/FileDestination.js +360 -0
  45. package/lib/module/destinations/FileDestination.js.map +1 -0
  46. package/lib/module/destinations/NativeConsoleDestination.js +170 -0
  47. package/lib/module/destinations/NativeConsoleDestination.js.map +1 -0
  48. package/lib/module/destinations/types.js +4 -0
  49. package/lib/module/destinations/types.js.map +1 -0
  50. package/lib/module/formatters/DefaultFormatter.js +136 -0
  51. package/lib/module/formatters/DefaultFormatter.js.map +1 -0
  52. package/lib/module/formatters/JsonLinesFormatter.js +162 -0
  53. package/lib/module/formatters/JsonLinesFormatter.js.map +1 -0
  54. package/lib/module/formatters/timestamp.js +15 -0
  55. package/lib/module/formatters/timestamp.js.map +1 -0
  56. package/lib/module/formatters/types.js +4 -0
  57. package/lib/module/formatters/types.js.map +1 -0
  58. package/lib/module/index.js +31 -0
  59. package/lib/module/index.js.map +1 -0
  60. package/lib/module/integrations/appState.js +81 -0
  61. package/lib/module/integrations/appState.js.map +1 -0
  62. package/lib/module/integrations/errorHandler.js +166 -0
  63. package/lib/module/integrations/errorHandler.js.map +1 -0
  64. package/lib/module/integrations/sanitizeError.js +238 -0
  65. package/lib/module/integrations/sanitizeError.js.map +1 -0
  66. package/lib/module/levels.js +35 -0
  67. package/lib/module/levels.js.map +1 -0
  68. package/lib/module/metadata.js +52 -0
  69. package/lib/module/metadata.js.map +1 -0
  70. package/lib/module/package.json +1 -0
  71. package/lib/module/privacy.js +349 -0
  72. package/lib/module/privacy.js.map +1 -0
  73. package/lib/module/specs/FileSink.nitro.js +4 -0
  74. package/lib/module/specs/FileSink.nitro.js.map +1 -0
  75. package/lib/module/specs/NativeConsoleSink.nitro.js +4 -0
  76. package/lib/module/specs/NativeConsoleSink.nitro.js.map +1 -0
  77. package/lib/module/types.js +4 -0
  78. package/lib/module/types.js.map +1 -0
  79. package/lib/module/utf8.js +42 -0
  80. package/lib/module/utf8.js.map +1 -0
  81. package/lib/typescript/package.json +1 -0
  82. package/lib/typescript/src/Logger.d.ts +122 -0
  83. package/lib/typescript/src/Logger.d.ts.map +1 -0
  84. package/lib/typescript/src/ScopedLogger.d.ts +36 -0
  85. package/lib/typescript/src/ScopedLogger.d.ts.map +1 -0
  86. package/lib/typescript/src/config.d.ts +12 -0
  87. package/lib/typescript/src/config.d.ts.map +1 -0
  88. package/lib/typescript/src/destinations/Batcher.d.ts +244 -0
  89. package/lib/typescript/src/destinations/Batcher.d.ts.map +1 -0
  90. package/lib/typescript/src/destinations/ConsoleDestination.d.ts +27 -0
  91. package/lib/typescript/src/destinations/ConsoleDestination.d.ts.map +1 -0
  92. package/lib/typescript/src/destinations/FileDestination.d.ts +200 -0
  93. package/lib/typescript/src/destinations/FileDestination.d.ts.map +1 -0
  94. package/lib/typescript/src/destinations/NativeConsoleDestination.d.ts +86 -0
  95. package/lib/typescript/src/destinations/NativeConsoleDestination.d.ts.map +1 -0
  96. package/lib/typescript/src/destinations/types.d.ts +19 -0
  97. package/lib/typescript/src/destinations/types.d.ts.map +1 -0
  98. package/lib/typescript/src/formatters/DefaultFormatter.d.ts +22 -0
  99. package/lib/typescript/src/formatters/DefaultFormatter.d.ts.map +1 -0
  100. package/lib/typescript/src/formatters/JsonLinesFormatter.d.ts +73 -0
  101. package/lib/typescript/src/formatters/JsonLinesFormatter.d.ts.map +1 -0
  102. package/lib/typescript/src/formatters/timestamp.d.ts +6 -0
  103. package/lib/typescript/src/formatters/timestamp.d.ts.map +1 -0
  104. package/lib/typescript/src/formatters/types.d.ts +27 -0
  105. package/lib/typescript/src/formatters/types.d.ts.map +1 -0
  106. package/lib/typescript/src/index.d.ts +34 -0
  107. package/lib/typescript/src/index.d.ts.map +1 -0
  108. package/lib/typescript/src/integrations/appState.d.ts +33 -0
  109. package/lib/typescript/src/integrations/appState.d.ts.map +1 -0
  110. package/lib/typescript/src/integrations/errorHandler.d.ts +55 -0
  111. package/lib/typescript/src/integrations/errorHandler.d.ts.map +1 -0
  112. package/lib/typescript/src/integrations/sanitizeError.d.ts +89 -0
  113. package/lib/typescript/src/integrations/sanitizeError.d.ts.map +1 -0
  114. package/lib/typescript/src/levels.d.ts +9 -0
  115. package/lib/typescript/src/levels.d.ts.map +1 -0
  116. package/lib/typescript/src/metadata.d.ts +23 -0
  117. package/lib/typescript/src/metadata.d.ts.map +1 -0
  118. package/lib/typescript/src/privacy.d.ts +103 -0
  119. package/lib/typescript/src/privacy.d.ts.map +1 -0
  120. package/lib/typescript/src/specs/FileSink.nitro.d.ts +131 -0
  121. package/lib/typescript/src/specs/FileSink.nitro.d.ts.map +1 -0
  122. package/lib/typescript/src/specs/NativeConsoleSink.nitro.d.ts +21 -0
  123. package/lib/typescript/src/specs/NativeConsoleSink.nitro.d.ts.map +1 -0
  124. package/lib/typescript/src/types.d.ts +37 -0
  125. package/lib/typescript/src/types.d.ts.map +1 -0
  126. package/lib/typescript/src/utf8.d.ts +15 -0
  127. package/lib/typescript/src/utf8.d.ts.map +1 -0
  128. package/nitro.json +33 -0
  129. package/nitrogen/generated/android/c++/JAppendResult.hpp +79 -0
  130. package/nitrogen/generated/android/c++/JClearOutcome.hpp +88 -0
  131. package/nitrogen/generated/android/c++/JFlushOutcome.hpp +81 -0
  132. package/nitrogen/generated/android/c++/JHybridFileSinkSpec.cpp +120 -0
  133. package/nitrogen/generated/android/c++/JHybridFileSinkSpec.hpp +69 -0
  134. package/nitrogen/generated/android/c++/JHybridNativeConsoleSinkSpec.cpp +71 -0
  135. package/nitrogen/generated/android/c++/JHybridNativeConsoleSinkSpec.hpp +64 -0
  136. package/nitrogen/generated/android/c++/JRejectReason.hpp +64 -0
  137. package/nitrogen/generated/android/c++/JRotationConfig.hpp +77 -0
  138. package/nitrogen/generated/android/c++/JSinkStatus.hpp +69 -0
  139. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrologger/AppendResult.kt +76 -0
  140. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrologger/ClearOutcome.kt +66 -0
  141. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrologger/FlushOutcome.kt +81 -0
  142. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrologger/HybridFileSinkSpec.kt +80 -0
  143. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrologger/HybridNativeConsoleSinkSpec.kt +58 -0
  144. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrologger/RejectReason.kt +25 -0
  145. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrologger/RotationConfig.kt +76 -0
  146. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrologger/SinkStatus.kt +66 -0
  147. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrologger/nitrologgerOnLoad.kt +35 -0
  148. package/nitrogen/generated/android/nitrologger+autolinking.cmake +83 -0
  149. package/nitrogen/generated/android/nitrologger+autolinking.gradle +27 -0
  150. package/nitrogen/generated/android/nitrologgerOnLoad.cpp +70 -0
  151. package/nitrogen/generated/android/nitrologgerOnLoad.hpp +34 -0
  152. package/nitrogen/generated/ios/NitroLogger+autolinking.rb +62 -0
  153. package/nitrogen/generated/ios/NitroLogger-Swift-Cxx-Bridge.cpp +50 -0
  154. package/nitrogen/generated/ios/NitroLogger-Swift-Cxx-Bridge.hpp +216 -0
  155. package/nitrogen/generated/ios/NitroLogger-Swift-Cxx-Umbrella.hpp +69 -0
  156. package/nitrogen/generated/ios/NitroLoggerAutolinking.mm +41 -0
  157. package/nitrogen/generated/ios/NitroLoggerAutolinking.swift +38 -0
  158. package/nitrogen/generated/ios/c++/HybridFileSinkSpecSwift.cpp +11 -0
  159. package/nitrogen/generated/ios/c++/HybridFileSinkSpecSwift.hpp +150 -0
  160. package/nitrogen/generated/ios/c++/HybridNativeConsoleSinkSpecSwift.cpp +11 -0
  161. package/nitrogen/generated/ios/c++/HybridNativeConsoleSinkSpecSwift.hpp +87 -0
  162. package/nitrogen/generated/ios/swift/AppendResult.swift +60 -0
  163. package/nitrogen/generated/ios/swift/ClearOutcome.swift +50 -0
  164. package/nitrogen/generated/ios/swift/FlushOutcome.swift +59 -0
  165. package/nitrogen/generated/ios/swift/HybridFileSinkSpec.swift +61 -0
  166. package/nitrogen/generated/ios/swift/HybridFileSinkSpec_cxx.swift +227 -0
  167. package/nitrogen/generated/ios/swift/HybridNativeConsoleSinkSpec.swift +56 -0
  168. package/nitrogen/generated/ios/swift/HybridNativeConsoleSinkSpec_cxx.swift +148 -0
  169. package/nitrogen/generated/ios/swift/RejectReason.swift +48 -0
  170. package/nitrogen/generated/ios/swift/RotationConfig.swift +93 -0
  171. package/nitrogen/generated/ios/swift/SinkStatus.swift +44 -0
  172. package/nitrogen/generated/shared/c++/AppendResult.hpp +105 -0
  173. package/nitrogen/generated/shared/c++/ClearOutcome.hpp +96 -0
  174. package/nitrogen/generated/shared/c++/FlushOutcome.hpp +107 -0
  175. package/nitrogen/generated/shared/c++/HybridFileSinkSpec.cpp +28 -0
  176. package/nitrogen/generated/shared/c++/HybridFileSinkSpec.hpp +84 -0
  177. package/nitrogen/generated/shared/c++/HybridNativeConsoleSinkSpec.cpp +22 -0
  178. package/nitrogen/generated/shared/c++/HybridNativeConsoleSinkSpec.hpp +64 -0
  179. package/nitrogen/generated/shared/c++/RejectReason.hpp +84 -0
  180. package/nitrogen/generated/shared/c++/RotationConfig.hpp +103 -0
  181. package/nitrogen/generated/shared/c++/SinkStatus.hpp +95 -0
  182. package/package.json +151 -0
  183. package/src/Logger.ts +417 -0
  184. package/src/ScopedLogger.ts +94 -0
  185. package/src/config.ts +25 -0
  186. package/src/destinations/Batcher.ts +805 -0
  187. package/src/destinations/ConsoleDestination.ts +60 -0
  188. package/src/destinations/FileDestination.ts +473 -0
  189. package/src/destinations/NativeConsoleDestination.ts +220 -0
  190. package/src/destinations/types.ts +19 -0
  191. package/src/formatters/DefaultFormatter.ts +150 -0
  192. package/src/formatters/JsonLinesFormatter.ts +195 -0
  193. package/src/formatters/timestamp.ts +12 -0
  194. package/src/formatters/types.ts +29 -0
  195. package/src/index.tsx +106 -0
  196. package/src/integrations/appState.ts +111 -0
  197. package/src/integrations/errorHandler.ts +223 -0
  198. package/src/integrations/sanitizeError.ts +287 -0
  199. package/src/levels.ts +35 -0
  200. package/src/metadata.ts +52 -0
  201. package/src/privacy.ts +389 -0
  202. package/src/specs/FileSink.nitro.ts +144 -0
  203. package/src/specs/NativeConsoleSink.nitro.ts +21 -0
  204. package/src/types.ts +45 -0
  205. package/src/utf8.ts +39 -0
@@ -0,0 +1,381 @@
1
+ "use strict";
2
+
3
+ import { ConsoleDestination } from "./destinations/ConsoleDestination.js";
4
+ import { resolveSubsystemLevel } from "./config.js";
5
+ import { levelAtLeast } from "./levels.js";
6
+ import { buildCatalog, normalizePrivacyDefault, redactMetadata } from "./privacy.js";
7
+ import { ScopedLogger } from "./ScopedLogger.js";
8
+ /** A destination is cut off after this many consecutive write failures. */
9
+ const MAX_CONSECUTIVE_FAILURES = 5;
10
+
11
+ /**
12
+ * A registered destination plus the label captured once, at registration.
13
+ * The label is never re-read afterwards: a getter that succeeds during
14
+ * registration and throws later would otherwise break removal, and failure
15
+ * accounting needs a stable key or a misbehaving destination can never be
16
+ * disabled.
17
+ */
18
+
19
+ /**
20
+ * The logger. Access through the `Log` singleton.
21
+ *
22
+ * Everything runs on the JS thread, so unlike the Swift original there is no
23
+ * lock or config-snapshot machinery — plain fields mutated by the fluent
24
+ * methods are safe by construction.
25
+ *
26
+ * Pipeline per message: resolve effective level (exact subsystem → parent
27
+ * walk → global) → collect destinations passing isEnabled AND minimumLevel →
28
+ * return BEFORE evaluating a lazy message when none remain → evaluate once,
29
+ * guarded → prepare metadata (redaction seam; M2 adds privacy wrappers) →
30
+ * freeze → fan out with per-destination isolation.
31
+ *
32
+ * Destinations are treated as untrusted: every property read and call is
33
+ * guarded so one faulty implementation can neither crash the app nor starve
34
+ * its siblings.
35
+ */
36
+ export class Logger {
37
+ globalMinimum = 'debug';
38
+ subsystemLevels = new Map();
39
+ registrations = defaultRegistrations();
40
+
41
+ /** Consecutive write-failure counts per destination label. */
42
+ failureCounts = new Map();
43
+ disabledLabels = new Set();
44
+
45
+ // Privacy state. Every transition tightens; nothing here can be loosened
46
+ // at runtime, so a compromised or careless call site cannot turn redaction
47
+ // off in a shipped build.
48
+ privacyDefaultValue = 'public';
49
+ privacyDefaultLocked = false;
50
+ redactAll = false;
51
+ // ── Privacy ─────────────────────────────────────────────────────────────
52
+
53
+ /**
54
+ * Choose how bare (unmarked) metadata values are treated.
55
+ *
56
+ * `'public'` — the OSS default — renders them. `'private'` redacts every
57
+ * bare value outside dev builds unless wrapped in `pub()`, so a forgotten
58
+ * wrapper hides data instead of leaking it. Apps handling PHI set
59
+ * `'private'` in their entry point.
60
+ *
61
+ * First call wins; later calls may only tighten (`'public'` → `'private'`).
62
+ * A request to loosen is ignored, not obeyed. Anything that is not exactly
63
+ * `'public'` or `'private'` — a JS caller, JSON config, an `any` — resolves
64
+ * to `'private'`: ambiguity must never resolve toward disclosure.
65
+ *
66
+ * `'private'` also makes the metadata key catalog mandatory — see
67
+ * {@link metadataKeyCatalog}.
68
+ */
69
+ privacyDefault(value) {
70
+ const normalized = normalizePrivacyDefault(value);
71
+ if (!this.privacyDefaultLocked) {
72
+ this.privacyDefaultValue = normalized;
73
+ this.privacyDefaultLocked = true;
74
+ } else if (normalized === 'private') {
75
+ this.privacyDefaultValue = 'private';
76
+ }
77
+ return this;
78
+ }
79
+
80
+ /** Redact every metadata value from here on, marked or not, dev or not.
81
+ * One-way: there is no call that undoes it. */
82
+ redactAllMetadata() {
83
+ this.redactAll = true;
84
+ return this;
85
+ }
86
+
87
+ /**
88
+ * Restrict metadata to an approved set of keys; anything else is dropped
89
+ * and counted. Rejecting computed keys is not enough on its own — a
90
+ * literal key like `patient123` is still PHI — so the catalog checks exact
91
+ * membership at runtime.
92
+ *
93
+ * Tighten-only: repeat calls intersect with the existing catalog rather
94
+ * than replacing it. Mandatory under a `'private'` privacy default, where
95
+ * an unconfigured catalog approves nothing and all metadata drops.
96
+ *
97
+ * Input is not trusted: a non-iterable, a throwing iterator, a non-string
98
+ * or malformed entry, or an over-long iterable all yield an empty catalog
99
+ * rather than an exception or a hung JS thread.
100
+ */
101
+ metadataKeyCatalog(keys) {
102
+ const incoming = buildCatalog(keys);
103
+ if (this.keyCatalog === undefined) {
104
+ this.keyCatalog = incoming;
105
+ } else {
106
+ const intersection = new Set();
107
+ for (const key of this.keyCatalog) {
108
+ if (incoming.has(key)) intersection.add(key);
109
+ }
110
+ this.keyCatalog = intersection;
111
+ }
112
+ return this;
113
+ }
114
+ privacySettings() {
115
+ return {
116
+ privacyDefault: this.privacyDefaultValue,
117
+ redactAll: this.redactAll,
118
+ keyCatalog: this.keyCatalog
119
+ };
120
+ }
121
+
122
+ // ── Fluent configuration ────────────────────────────────────────────────
123
+
124
+ /** Global minimum level; messages below it are discarded. Default 'debug'. */
125
+ minimumLevel(level) {
126
+ this.globalMinimum = level;
127
+ return this;
128
+ }
129
+
130
+ /** Minimum level for a dot-hierarchical subsystem (`network` covers
131
+ * `network.api` unless the child sets its own). */
132
+ subsystem(name, level) {
133
+ this.subsystemLevels.set(name, level);
134
+ return this;
135
+ }
136
+ resetSubsystem(name) {
137
+ this.subsystemLevels.delete(name);
138
+ return this;
139
+ }
140
+
141
+ /** Toggle console printing. The console destination's test sink, when set,
142
+ * keeps receiving lines regardless. */
143
+ consoleLogging(enabled) {
144
+ for (const {
145
+ destination
146
+ } of this.registrations) {
147
+ if (destination instanceof ConsoleDestination) {
148
+ destination.printEnabled = enabled;
149
+ }
150
+ }
151
+ return this;
152
+ }
153
+
154
+ /**
155
+ * Register a destination. A *different* destination already holding the
156
+ * same label is flushed, disposed, and replaced; re-adding an instance
157
+ * that is already registered is a no-op, because disposing and re-pushing
158
+ * the same object would leave a live destination in a closed state.
159
+ */
160
+ addDestination(destination) {
161
+ // Identity first: an already-registered instance must not have its label
162
+ // getter touched again, or the capture-once invariant leaks right here.
163
+ if (this.registrations.some(r => r.destination === destination)) {
164
+ return this;
165
+ }
166
+ let label;
167
+ try {
168
+ label = destination.label;
169
+ } catch {
170
+ warnFixed('[Logger] a destination was rejected: its label could not be read');
171
+ return this;
172
+ }
173
+ if (typeof label !== 'string') {
174
+ warnFixed('[Logger] a destination was rejected: its label is not a string');
175
+ return this;
176
+ }
177
+ this.removeDestination(label);
178
+ this.registrations.push({
179
+ destination,
180
+ label
181
+ });
182
+ return this;
183
+ }
184
+ removeDestination(label) {
185
+ const index = this.registrations.findIndex(r => r.label === label);
186
+ if (index >= 0) {
187
+ const removed = this.registrations.splice(index, 1)[0];
188
+ // Guarded separately: a failing flush must not skip dispose, or the
189
+ // removed destination leaks timers/handles it will never release.
190
+ try {
191
+ removed.destination.flush();
192
+ } catch {
193
+ // a failing flush must not break reconfiguration
194
+ }
195
+ try {
196
+ removed.destination.dispose();
197
+ } catch {
198
+ // a failing dispose must not break reconfiguration
199
+ }
200
+ }
201
+ this.failureCounts.delete(label);
202
+ this.disabledLabels.delete(label);
203
+ return this;
204
+ }
205
+
206
+ /** Drain every destination synchronously (bounded per destination). */
207
+ flush(deadlineMs = 2000) {
208
+ for (const {
209
+ destination
210
+ } of this.registrations) {
211
+ try {
212
+ destination.flush(deadlineMs);
213
+ } catch {
214
+ // isolation: one failing flush must not stop the others
215
+ }
216
+ }
217
+ }
218
+
219
+ // ── Scopes & correlation ────────────────────────────────────────────────
220
+
221
+ /** Short-lived random correlation ID — the encouraged way to correlate.
222
+ * Never derive correlation IDs from patient/visit/record identifiers. */
223
+ newCorrelationId() {
224
+ return Math.random().toString(36).slice(2, 10);
225
+ }
226
+
227
+ /** A scoped logger tagging every message with a correlation ID, optional
228
+ * subsystem, and default metadata. Omit `correlation` to auto-generate. */
229
+ scoped(correlation, subsystem, metadata) {
230
+ return new ScopedLogger(this, correlation ?? this.newCorrelationId(), subsystem, metadata);
231
+ }
232
+
233
+ // ── Logging ─────────────────────────────────────────────────────────────
234
+
235
+ log(message, options) {
236
+ this.logMessage(message, options);
237
+ }
238
+ verbose(message, metadata, subsystem) {
239
+ this.logMessage(message, {
240
+ level: 'verbose',
241
+ metadata,
242
+ subsystem
243
+ });
244
+ }
245
+ debug(message, metadata, subsystem) {
246
+ this.logMessage(message, {
247
+ level: 'debug',
248
+ metadata,
249
+ subsystem
250
+ });
251
+ }
252
+ info(message, metadata, subsystem) {
253
+ this.logMessage(message, {
254
+ level: 'info',
255
+ metadata,
256
+ subsystem
257
+ });
258
+ }
259
+ warning(message, metadata, subsystem) {
260
+ this.logMessage(message, {
261
+ level: 'warning',
262
+ metadata,
263
+ subsystem
264
+ });
265
+ }
266
+ error(message, metadata, subsystem) {
267
+ this.logMessage(message, {
268
+ level: 'error',
269
+ metadata,
270
+ subsystem
271
+ });
272
+ }
273
+
274
+ /** Marks incomplete work; highest severity so it always surfaces. */
275
+ todo(message, metadata, subsystem) {
276
+ this.logMessage(message, {
277
+ level: 'todo',
278
+ metadata,
279
+ subsystem
280
+ });
281
+ }
282
+
283
+ /** Integration entry point (ScopedLogger, error handler, bridges). */
284
+ logMessage(message, options) {
285
+ const level = options?.level ?? 'info';
286
+ const subsystem = options?.subsystem;
287
+ const effectiveMinimum = (subsystem !== undefined ? resolveSubsystemLevel(this.subsystemLevels, subsystem) : undefined) ?? this.globalMinimum;
288
+ if (!levelAtLeast(level, effectiveMinimum)) return;
289
+
290
+ // Eligibility BEFORE message evaluation: a lazy thunk must not run when
291
+ // nothing will receive the entry. isEnabled/minimumLevel may be throwing
292
+ // getters, so each read is isolated and charged to the stable label.
293
+ const eligible = [];
294
+ for (const registration of this.registrations) {
295
+ const {
296
+ destination,
297
+ label
298
+ } = registration;
299
+ if (this.disabledLabels.has(label)) continue;
300
+ try {
301
+ if (!destination.isEnabled) continue;
302
+ if (destination.minimumLevel !== undefined && !levelAtLeast(level, destination.minimumLevel)) {
303
+ continue;
304
+ }
305
+ } catch {
306
+ this.noteFailure(label);
307
+ continue;
308
+ }
309
+ eligible.push(registration);
310
+ }
311
+ if (eligible.length === 0) return;
312
+ let text;
313
+ try {
314
+ text = typeof message === 'function' ? message() : message;
315
+ } catch {
316
+ // Payload-free by design: the thrown value could contain anything.
317
+ text = '[Logger] message thunk threw';
318
+ }
319
+
320
+ // Frozen: the same entry fans out to every destination, so a mutating
321
+ // destination must not change what its siblings receive. Every field is
322
+ // a primitive or a frozen null-prototype object, so freezing the entry
323
+ // is enough — nothing reachable from it is mutable.
324
+ const entry = Object.freeze({
325
+ timestamp: Date.now(),
326
+ level,
327
+ message: text,
328
+ metadata: redactMetadata(options?.scopeMetadata, options?.metadata, this.privacySettings()),
329
+ correlation: options?.correlation,
330
+ subsystem
331
+ });
332
+ for (const {
333
+ destination,
334
+ label
335
+ } of eligible) {
336
+ try {
337
+ destination.write(entry);
338
+ this.failureCounts.delete(label);
339
+ } catch {
340
+ this.noteFailure(label);
341
+ }
342
+ }
343
+ }
344
+
345
+ /** Count a consecutive failure; disable the destination at the threshold.
346
+ * The diagnostic is fixed text — labels are caller-controlled, so including
347
+ * one would break the payload-free contract and invite log injection. */
348
+ noteFailure(label) {
349
+ const failures = (this.failureCounts.get(label) ?? 0) + 1;
350
+ this.failureCounts.set(label, failures);
351
+ if (failures >= MAX_CONSECUTIVE_FAILURES) {
352
+ this.disabledLabels.add(label);
353
+ warnFixed('[Logger] a destination was disabled after repeated write failures');
354
+ }
355
+ }
356
+
357
+ // Deliberately no reset/reconfigure hook. Such a method would be a public
358
+ // runtime path to loosen every privacy control on the `Log` singleton, and
359
+ // an `@internal` tag does not remove a method from a JS build. Tests
360
+ // construct their own `new Logger()` instead.
361
+ }
362
+ function defaultRegistrations() {
363
+ const console_ = new ConsoleDestination();
364
+ return [{
365
+ destination: console_,
366
+ label: console_.label
367
+ }];
368
+ }
369
+
370
+ /** Fixed-text diagnostic; never interpolates caller-controlled data. */
371
+ function warnFixed(message) {
372
+ try {
373
+ console.warn(message);
374
+ } catch {
375
+ // nothing left to report to
376
+ }
377
+ }
378
+
379
+ /** Global shorthand, mirroring SwiftLogger's `Log`. */
380
+ export const Log = new Logger();
381
+ //# sourceMappingURL=Logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["ConsoleDestination","resolveSubsystemLevel","levelAtLeast","buildCatalog","normalizePrivacyDefault","redactMetadata","ScopedLogger","MAX_CONSECUTIVE_FAILURES","Logger","globalMinimum","subsystemLevels","Map","registrations","defaultRegistrations","failureCounts","disabledLabels","Set","privacyDefaultValue","privacyDefaultLocked","redactAll","privacyDefault","value","normalized","redactAllMetadata","metadataKeyCatalog","keys","incoming","keyCatalog","undefined","intersection","key","has","add","privacySettings","minimumLevel","level","subsystem","name","set","resetSubsystem","delete","consoleLogging","enabled","destination","printEnabled","addDestination","some","r","label","warnFixed","removeDestination","push","index","findIndex","removed","splice","flush","dispose","deadlineMs","newCorrelationId","Math","random","toString","slice","scoped","correlation","metadata","log","message","options","logMessage","verbose","debug","info","warning","error","todo","effectiveMinimum","eligible","registration","isEnabled","noteFailure","length","text","entry","Object","freeze","timestamp","Date","now","scopeMetadata","write","failures","get","console_","console","warn","Log"],"sourceRoot":"../../src","sources":["Logger.ts"],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,70 @@
1
+ "use strict";
2
+
3
+ import { safeSnapshotMetadata } from "./metadata.js";
4
+
5
+ /**
6
+ * A lightweight logger that tags every message with a correlation ID,
7
+ * optional default subsystem, and default metadata. Direct port of
8
+ * SwiftLogger's ScopedLogger: immutable, delegates all work to the parent
9
+ * Logger, nests.
10
+ *
11
+ * Metadata semantics: the scope's metadata merges into every message;
12
+ * call-site keys win on collision (a message reporting `state: 'failed'`
13
+ * must not be masked by the scope's `state: 'running'`). Child scopes merge
14
+ * into — never replace — the parent's metadata.
15
+ */
16
+ export class ScopedLogger {
17
+ /** Frozen snapshot taken at construction — mutating the object the caller
18
+ * passed in (or this field) after the fact must not change future logs,
19
+ * matching SwiftLogger's value semantics. */
20
+
21
+ constructor(logger, correlation, subsystem, metadata) {
22
+ this.logger = logger;
23
+ this.correlation = correlation;
24
+ this.subsystem = subsystem;
25
+ const snapshot = safeSnapshotMetadata(metadata);
26
+ this.metadata = snapshot ? Object.freeze(snapshot) : undefined;
27
+ }
28
+ log(message, level = 'info', metadata) {
29
+ this.logger.logMessage(message, {
30
+ level,
31
+ subsystem: this.subsystem,
32
+ // Handed over unmerged: redaction settles precedence per key and
33
+ // validates the winner BEFORE reading it, so a getter behind a
34
+ // rejected key — or one the call site overrode — never runs. Merging
35
+ // here would read every value first and defeat that.
36
+ scopeMetadata: this.metadata,
37
+ metadata,
38
+ correlation: this.correlation
39
+ });
40
+ }
41
+ verbose(message, metadata) {
42
+ this.log(message, 'verbose', metadata);
43
+ }
44
+ debug(message, metadata) {
45
+ this.log(message, 'debug', metadata);
46
+ }
47
+ info(message, metadata) {
48
+ this.log(message, 'info', metadata);
49
+ }
50
+ warning(message, metadata) {
51
+ this.log(message, 'warning', metadata);
52
+ }
53
+ error(message, metadata) {
54
+ this.log(message, 'error', metadata);
55
+ }
56
+ todo(message, metadata) {
57
+ this.log(message, 'todo', metadata);
58
+ }
59
+
60
+ /** Child scope: inherits this scope's subsystem unless overridden, merges
61
+ * metadata (child keys win). The merge happens at construction, like any
62
+ * scope snapshot — both sides are materialized here so later mutation of
63
+ * the caller's object cannot change what the child reports. */
64
+ scoped(correlation, subsystem, metadata) {
65
+ const child = safeSnapshotMetadata(metadata);
66
+ const merged = this.metadata ? Object.assign(Object.create(null), this.metadata, child) : child;
67
+ return new ScopedLogger(this.logger, correlation, subsystem ?? this.subsystem, merged);
68
+ }
69
+ }
70
+ //# sourceMappingURL=ScopedLogger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["safeSnapshotMetadata","ScopedLogger","constructor","logger","correlation","subsystem","metadata","snapshot","Object","freeze","undefined","log","message","level","logMessage","scopeMetadata","verbose","debug","info","warning","error","todo","scoped","child","merged","assign","create"],"sourceRoot":"../../src","sources":["ScopedLogger.ts"],"mappings":";;AAEA,SAASA,oBAAoB,QAAQ,eAAY;;AAEjD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,MAAMC,YAAY,CAAC;EACxB;AACF;AACA;;EAGEC,WAAWA,CACQC,MAAc,EACtBC,WAAmB,EACnBC,SAAkB,EAC3BC,QAAsB,EACtB;IAAA,KAJiBH,MAAc,GAAdA,MAAc;IAAA,KACtBC,WAAmB,GAAnBA,WAAmB;IAAA,KACnBC,SAAkB,GAAlBA,SAAkB;IAG3B,MAAME,QAAQ,GAAGP,oBAAoB,CAACM,QAAQ,CAAC;IAC/C,IAAI,CAACA,QAAQ,GAAGC,QAAQ,GAAGC,MAAM,CAACC,MAAM,CAACF,QAAQ,CAAC,GAAGG,SAAS;EAChE;EAEAC,GAAGA,CACDC,OAAoB,EACpBC,KAAe,GAAG,MAAM,EACxBP,QAAsB,EAChB;IACN,IAAI,CAACH,MAAM,CAACW,UAAU,CAACF,OAAO,EAAE;MAC9BC,KAAK;MACLR,SAAS,EAAE,IAAI,CAACA,SAAS;MACzB;MACA;MACA;MACA;MACAU,aAAa,EAAE,IAAI,CAACT,QAAQ;MAC5BA,QAAQ;MACRF,WAAW,EAAE,IAAI,CAACA;IACpB,CAAC,CAAC;EACJ;EAEAY,OAAOA,CAACJ,OAAoB,EAAEN,QAAsB,EAAQ;IAC1D,IAAI,CAACK,GAAG,CAACC,OAAO,EAAE,SAAS,EAAEN,QAAQ,CAAC;EACxC;EAEAW,KAAKA,CAACL,OAAoB,EAAEN,QAAsB,EAAQ;IACxD,IAAI,CAACK,GAAG,CAACC,OAAO,EAAE,OAAO,EAAEN,QAAQ,CAAC;EACtC;EAEAY,IAAIA,CAACN,OAAoB,EAAEN,QAAsB,EAAQ;IACvD,IAAI,CAACK,GAAG,CAACC,OAAO,EAAE,MAAM,EAAEN,QAAQ,CAAC;EACrC;EAEAa,OAAOA,CAACP,OAAoB,EAAEN,QAAsB,EAAQ;IAC1D,IAAI,CAACK,GAAG,CAACC,OAAO,EAAE,SAAS,EAAEN,QAAQ,CAAC;EACxC;EAEAc,KAAKA,CAACR,OAAoB,EAAEN,QAAsB,EAAQ;IACxD,IAAI,CAACK,GAAG,CAACC,OAAO,EAAE,OAAO,EAAEN,QAAQ,CAAC;EACtC;EAEAe,IAAIA,CAACT,OAAoB,EAAEN,QAAsB,EAAQ;IACvD,IAAI,CAACK,GAAG,CAACC,OAAO,EAAE,MAAM,EAAEN,QAAQ,CAAC;EACrC;;EAEA;AACF;AACA;AACA;EACEgB,MAAMA,CACJlB,WAAmB,EACnBC,SAAkB,EAClBC,QAAsB,EACR;IACd,MAAMiB,KAAK,GAAGvB,oBAAoB,CAACM,QAAQ,CAAC;IAC5C,MAAMkB,MAAM,GAAG,IAAI,CAAClB,QAAQ,GACxBE,MAAM,CAACiB,MAAM,CAACjB,MAAM,CAACkB,MAAM,CAAC,IAAI,CAAC,EAAiB,IAAI,CAACpB,QAAQ,EAAEiB,KAAK,CAAC,GACvEA,KAAK;IACT,OAAO,IAAItB,YAAY,CACrB,IAAI,CAACE,MAAM,EACXC,WAAW,EACXC,SAAS,IAAI,IAAI,CAACA,SAAS,EAC3BmB,MACF,CAAC;EACH;AACF","ignoreList":[]}
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+
3
+ /**
4
+ * Resolves the effective minimum level for a subsystem by walking the
5
+ * dot-separated hierarchy: exact match, then each parent (`a.b.c` → `a.b` →
6
+ * `a`), then undefined so the caller falls back to the global minimum.
7
+ * Direct port of SwiftLogger's LoggerConfiguration.resolveSubsystemLevel.
8
+ *
9
+ * Single-threaded JS means no snapshot/locking machinery — a plain Map
10
+ * mutated by the fluent config methods is safe.
11
+ */
12
+ export function resolveSubsystemLevel(subsystemLevels, name) {
13
+ if (subsystemLevels.size === 0) return undefined;
14
+ let current = name;
15
+ for (;;) {
16
+ const level = subsystemLevels.get(current);
17
+ if (level !== undefined) return level;
18
+ const dot = current.lastIndexOf('.');
19
+ if (dot < 0) return undefined;
20
+ current = current.slice(0, dot);
21
+ }
22
+ }
23
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["resolveSubsystemLevel","subsystemLevels","name","size","undefined","current","level","get","dot","lastIndexOf","slice"],"sourceRoot":"../../src","sources":["config.ts"],"mappings":";;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASA,qBAAqBA,CACnCC,eAA8C,EAC9CC,IAAY,EACU;EACtB,IAAID,eAAe,CAACE,IAAI,KAAK,CAAC,EAAE,OAAOC,SAAS;EAChD,IAAIC,OAAO,GAAGH,IAAI;EAClB,SAAS;IACP,MAAMI,KAAK,GAAGL,eAAe,CAACM,GAAG,CAACF,OAAO,CAAC;IAC1C,IAAIC,KAAK,KAAKF,SAAS,EAAE,OAAOE,KAAK;IACrC,MAAME,GAAG,GAAGH,OAAO,CAACI,WAAW,CAAC,GAAG,CAAC;IACpC,IAAID,GAAG,GAAG,CAAC,EAAE,OAAOJ,SAAS;IAC7BC,OAAO,GAAGA,OAAO,CAACK,KAAK,CAAC,CAAC,EAAEF,GAAG,CAAC;EACjC;AACF","ignoreList":[]}