@revealui/core 0.11.1 → 0.12.1

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 (69) hide show
  1. package/README.md +2 -3
  2. package/dist/api/rest.js +4 -4
  3. package/dist/client/admin/utils/csrf.d.ts +9 -6
  4. package/dist/client/admin/utils/csrf.d.ts.map +1 -1
  5. package/dist/client/admin/utils/csrf.js +9 -6
  6. package/dist/collections/operations/fieldValidation.d.ts +5 -16
  7. package/dist/collections/operations/fieldValidation.d.ts.map +1 -1
  8. package/dist/collections/operations/fieldValidation.js +5 -20
  9. package/dist/collections/operations/update.d.ts.map +1 -1
  10. package/dist/collections/operations/update.js +4 -2
  11. package/dist/database/safe-parse.js +3 -3
  12. package/dist/database/universal-postgres.d.ts.map +1 -1
  13. package/dist/database/universal-postgres.js +10 -13
  14. package/dist/deployment-mode.d.ts +44 -0
  15. package/dist/deployment-mode.d.ts.map +1 -0
  16. package/dist/deployment-mode.js +58 -0
  17. package/dist/error-handling/error-boundary.d.ts +16 -2
  18. package/dist/error-handling/error-boundary.d.ts.map +1 -1
  19. package/dist/error-handling/error-boundary.js +18 -3
  20. package/dist/error-handling/error-reporter.d.ts +1 -1
  21. package/dist/error-handling/error-reporter.d.ts.map +1 -1
  22. package/dist/error-handling/error-reporter.js +6 -2
  23. package/dist/error-handling/index.d.ts +1 -1
  24. package/dist/error-handling/index.d.ts.map +1 -1
  25. package/dist/error-handling/index.js +1 -1
  26. package/dist/index.d.ts.map +1 -1
  27. package/dist/index.js +4 -2
  28. package/dist/instance/logger.d.ts +18 -7
  29. package/dist/instance/logger.d.ts.map +1 -1
  30. package/dist/instance/logger.js +66 -17
  31. package/dist/license/mint-client.d.ts +72 -0
  32. package/dist/license/mint-client.d.ts.map +1 -0
  33. package/dist/license/mint-client.js +175 -0
  34. package/dist/license.d.ts +109 -0
  35. package/dist/license.d.ts.map +1 -1
  36. package/dist/license.js +153 -6
  37. package/dist/observability/index.d.ts +5 -2
  38. package/dist/observability/index.d.ts.map +1 -1
  39. package/dist/observability/index.js +5 -2
  40. package/dist/observability/logger.d.ts +5 -3
  41. package/dist/observability/logger.d.ts.map +1 -1
  42. package/dist/observability/logger.js +5 -3
  43. package/dist/relationships/analyzer.js +2 -2
  44. package/dist/revforge-license.d.ts +9 -0
  45. package/dist/revforge-license.d.ts.map +1 -1
  46. package/dist/revforge-license.js +12 -2
  47. package/dist/storage/object-storage.d.ts.map +1 -1
  48. package/dist/storage/object-storage.js +3 -3
  49. package/dist/utils/errors.d.ts +16 -4
  50. package/dist/utils/errors.d.ts.map +1 -1
  51. package/dist/utils/errors.js +14 -2
  52. package/dist/utils/json-parsing.d.ts.map +1 -1
  53. package/dist/utils/json-parsing.js +4 -2
  54. package/dist/utils/logger-client.d.ts +6 -27
  55. package/dist/utils/logger-client.d.ts.map +1 -1
  56. package/dist/utils/logger-client.js +5 -51
  57. package/dist/utils/logger-server.d.ts +16 -20
  58. package/dist/utils/logger-server.d.ts.map +1 -1
  59. package/dist/utils/logger-server.js +40 -53
  60. package/dist/utils/logger.d.ts +7 -9
  61. package/dist/utils/logger.d.ts.map +1 -1
  62. package/dist/utils/logger.js +6 -8
  63. package/package.json +154 -76
  64. package/dist/caching/index.d.ts +0 -6
  65. package/dist/caching/index.d.ts.map +0 -1
  66. package/dist/caching/index.js +0 -5
  67. package/dist/observability/tracing.d.ts +0 -149
  68. package/dist/observability/tracing.d.ts.map +0 -1
  69. package/dist/observability/tracing.js +0 -380
package/dist/license.js CHANGED
@@ -15,7 +15,7 @@
15
15
  // other modules in the auth route bundle during page data collection.
16
16
  import { z } from 'zod';
17
17
  import { decryptLicenseKey } from './license-encryption.js';
18
- import { logger } from './utils/logger.js';
18
+ import { logger } from './observability/logger.js';
19
19
  async function getJose() {
20
20
  return await import('jose');
21
21
  }
@@ -127,6 +127,20 @@ let cachedState = {
127
127
  export function normalizePem(raw) {
128
128
  return raw.split('\\n').join('\n');
129
129
  }
130
+ /**
131
+ * Read a PEM from `env[name]` (defaults to `process.env`), trim, and normalize
132
+ * escaped newlines. Returns `undefined` when missing or blank after trim.
133
+ * Canonical helper for the former 8+ copy-pasted license/webhook PEM unescapes (GAP-396).
134
+ */
135
+ export function readPemEnv(name, env = process.env) {
136
+ const raw = env[name];
137
+ if (raw === undefined)
138
+ return undefined;
139
+ const trimmed = raw.trim();
140
+ if (trimmed.length === 0)
141
+ return undefined;
142
+ return normalizePem(trimmed);
143
+ }
130
144
  /**
131
145
  * The ordered public-key candidates used to verify license JWTs.
132
146
  *
@@ -204,6 +218,47 @@ export async function computeKeyId(publicKeyPem) {
204
218
  * options below. Signature is enforced via the public key.
205
219
  */
206
220
  export async function validateLicenseKey(licenseKey, publicKey, expectedCustomerId) {
221
+ // Accept tokens expired within the subscription grace window so the payload
222
+ // is available for grace-period calculations in isLicensed().
223
+ return verifyAndParseLicenseJwt(licenseKey, publicKey, graceConfig.subscriptionDays * 86_400, expectedCustomerId);
224
+ }
225
+ /**
226
+ * How far past `exp` a license JWT is still accepted by the refresh endpoint
227
+ * (GAP-287 PR-1). Ratified by the owner 2026-07-18 at 30 days.
228
+ *
229
+ * Deliberately wider than the subscription validation grace
230
+ * (`LICENSE_GRACE_SUBSCRIPTION_DAYS`, default 3): the validation grace answers
231
+ * "may you still run", the refresh-accept window answers "may you still fetch
232
+ * your renewal". A customer returning from a month away should still be able to
233
+ * pull their current key rather than being bricked. Beyond this window the
234
+ * refresh path refuses and re-delivery goes through the authenticated admin
235
+ * account page.
236
+ */
237
+ export const REFRESH_ACCEPT_DAYS = 30;
238
+ /**
239
+ * Refresh-path validator (GAP-287 PR-1). Verifies a presented license JWT for
240
+ * `POST /api/license/refresh`, accepting a token whose `exp` is past by at most
241
+ * `refreshAcceptDays` (default {@link REFRESH_ACCEPT_DAYS}).
242
+ *
243
+ * It reuses the SAME ordered multi-key verification (GAP-259 rotation
244
+ * composition) and payload schema as {@link validateLicenseKey}, so a token
245
+ * minted under the outgoing private key during a dual-key rotation window still
246
+ * verifies. It performs NO `customerId` binding: the refresh endpoint trusts
247
+ * the token's `customerId` claim and then independently requires an ACTIVE
248
+ * license row for it. This function only proves possession of a recently-valid
249
+ * signed key. It never mints and never grants entitlement on its own.
250
+ */
251
+ export async function validateLicenseKeyForRefresh(licenseKey, publicKey, refreshAcceptDays = REFRESH_ACCEPT_DAYS) {
252
+ return verifyAndParseLicenseJwt(licenseKey, publicKey, refreshAcceptDays * 86_400);
253
+ }
254
+ /**
255
+ * Shared verify + parse path for {@link validateLicenseKey} and
256
+ * {@link validateLicenseKeyForRefresh}. The ONLY behavioral difference between
257
+ * the two callers is `clockToleranceSeconds` — how far past `exp` a token is
258
+ * still accepted — so the rotation-aware multi-key loop and the payload schema
259
+ * live in exactly one place.
260
+ */
261
+ async function verifyAndParseLicenseJwt(licenseKey, publicKey, clockToleranceSeconds, expectedCustomerId) {
207
262
  const candidates = typeof publicKey === 'string' ? [publicKey] : [...publicKey];
208
263
  if (candidates.length === 0)
209
264
  return null;
@@ -218,11 +273,9 @@ export async function validateLicenseKey(licenseKey, publicKey, expectedCustomer
218
273
  for (const candidate of ordered) {
219
274
  try {
220
275
  const key = await jose.importSPKI(candidate, 'EdDSA');
221
- // Accept tokens expired within the subscription grace window so the
222
- // payload is available for grace-period calculations in isLicensed().
223
276
  const { payload } = await jose.jwtVerify(licenseKey, key, {
224
277
  algorithms: ['EdDSA'],
225
- clockTolerance: graceConfig.subscriptionDays * 86_400,
278
+ clockTolerance: clockToleranceSeconds,
226
279
  issuer: LICENSE_ISSUER,
227
280
  audience: LICENSE_AUDIENCE,
228
281
  });
@@ -232,7 +285,7 @@ export async function validateLicenseKey(licenseKey, publicKey, expectedCustomer
232
285
  }
233
286
  catch {
234
287
  // This candidate did not verify (wrong key, malformed PEM, bad
235
- // iss/aud, or expired beyond grace) — try the next before giving up.
288
+ // iss/aud, or expired beyond tolerance) — try the next before giving up.
236
289
  }
237
290
  }
238
291
  if (!verified) {
@@ -617,6 +670,100 @@ export function getMaxAgentTasks() {
617
670
  return 10_000;
618
671
  return 1_000;
619
672
  }
673
+ /**
674
+ * Default subscription license JWT lifetime (seconds) — one year. Used as the
675
+ * fallback when a subscription's billing period is unavailable at mint time (an
676
+ * abnormal Stripe shape) so a period-bound token is never SHORTER than the
677
+ * pre-GAP-287 behavior, and as the default lifetime for {@link generateLicenseKey}
678
+ * when no explicit value is passed.
679
+ */
680
+ export const DEFAULT_SUBSCRIPTION_TTL_SECONDS = 365 * 24 * 60 * 60;
681
+ /**
682
+ * Slack added to a hosted subscription's `current_period_end` when deriving the
683
+ * license JWT `exp` (GAP-287 PR-2). Ratified by the owner 2026-07-18 at 7 days.
684
+ *
685
+ * The token's lifetime equals what billing has actually granted plus this slack.
686
+ * The slack must cover the Stripe dunning/retry window so a card that recovers
687
+ * on retry never presents a lapsed key. Renewals advance the exp each billing
688
+ * cycle by re-minting on `invoice.payment_succeeded`.
689
+ */
690
+ export const RENEWAL_SLACK_DAYS = 7;
691
+ export const RENEWAL_SLACK_SECONDS = RENEWAL_SLACK_DAYS * 24 * 60 * 60;
692
+ /**
693
+ * Default lifetime, in days, for a license JWT minted by the admin
694
+ * `POST /generate` manual-mint endpoint when the caller does not supply an
695
+ * explicit `expiresInDays` (GAP-287 PR-3). Ratified by the owner 2026-07-18 at
696
+ * 90, down from the prior flat 365-day default: this is an operator tool, and
697
+ * a short default nudges the right renewal habit for manually-issued keys. An
698
+ * explicit `expiresInDays` on the request is always honored unchanged.
699
+ */
700
+ export const DEFAULT_MANUAL_MINT_DAYS = 90;
701
+ /**
702
+ * Derives the relative `expiresInSeconds` argument for {@link generateLicenseKey}
703
+ * at the hosted subscription mint sites (GAP-287 PR-2): the token should expire
704
+ * at `periodEnd + RENEWAL_SLACK_SECONDS`. Because generateLicenseKey interprets a
705
+ * numeric lifetime relative to issue time, this returns that absolute bound minus
706
+ * now.
707
+ *
708
+ * Falls back to {@link DEFAULT_SUBSCRIPTION_TTL_SECONDS} when `periodEnd` is
709
+ * absent (a subscription with no billing period) so an unexpected Stripe shape
710
+ * never mints a shorter-than-before token. Never returns a non-positive lifetime:
711
+ * a period end already in the past floors at one second, leaving expiry to the
712
+ * validation grace + refresh window rather than minting an already-invalid token.
713
+ */
714
+ export function subscriptionLicenseExpiresInSeconds(periodEnd, nowMs = Date.now()) {
715
+ if (!periodEnd)
716
+ return DEFAULT_SUBSCRIPTION_TTL_SECONDS;
717
+ const boundMs = periodEnd.getTime() + RENEWAL_SLACK_SECONDS * 1000;
718
+ return Math.max(1, Math.floor((boundMs - nowMs) / 1000));
719
+ }
720
+ /**
721
+ * Absolute epoch-second bound `periodEnd + RENEWAL_SLACK_SECONDS` a hosted
722
+ * subscription key should reach (GAP-287 PR-2). The renewal cadence re-mints IFF
723
+ * the stored key's `exp` is below this bound, so the comparison uses this
724
+ * absolute form while the mint uses the relative
725
+ * {@link subscriptionLicenseExpiresInSeconds}.
726
+ */
727
+ export function subscriptionExpBound(periodEnd) {
728
+ return Math.floor(periodEnd.getTime() / 1000) + RENEWAL_SLACK_SECONDS;
729
+ }
730
+ /**
731
+ * Idempotency tolerance for the renewal re-mint decision (fast-follow from the
732
+ * non-blocking finding on the #1978 guardrail-2 verdict). `subscriptionLicenseExpiresInSeconds`
733
+ * floors its relative TTL to whole seconds and the JWT signer floors `exp` to
734
+ * `iat + expiresInSeconds` at its own second granularity, so the `exp` actually
735
+ * persisted for a subscription key can land exactly 1s below
736
+ * {@link subscriptionExpBound}'s value even though the mint targeted that bound.
737
+ * Without this tolerance a duplicate/retried `invoice.payment_succeeded` lands on
738
+ * that 1s gap and re-enters the re-mint path instead of no-opping.
739
+ */
740
+ export const RENEWAL_IDEMPOTENCY_TOLERANCE_SECONDS = 1;
741
+ /**
742
+ * True when a stored license `exp` already covers the renewal bound, within the
743
+ * {@link RENEWAL_IDEMPOTENCY_TOLERANCE_SECONDS} idempotency tolerance - i.e. the
744
+ * renewal re-mint should be SKIPPED. `null` (perpetual token, or an undecodable
745
+ * key) never covers, so the caller falls through to re-mint.
746
+ */
747
+ export function coversRenewalBound(storedExp, newBound) {
748
+ return storedExp !== null && storedExp >= newBound - RENEWAL_IDEMPOTENCY_TOLERANCE_SECONDS;
749
+ }
750
+ /**
751
+ * Reads the `exp` (epoch seconds) claim from a license JWT WITHOUT verifying its
752
+ * signature. Internal use only, for the GAP-287 PR-2 renewal cadence: the token
753
+ * comes from our OWN store and the caller needs only its expiry to decide whether
754
+ * to re-mint — never as an authentication or entitlement decision. Returns null
755
+ * for a perpetual token (no exp claim) or one that cannot be decoded.
756
+ */
757
+ export async function readLicenseExp(licenseKey) {
758
+ try {
759
+ const jose = await getJose();
760
+ const payload = jose.decodeJwt(licenseKey);
761
+ return typeof payload.exp === 'number' ? payload.exp : null;
762
+ }
763
+ catch {
764
+ return null;
765
+ }
766
+ }
620
767
  /**
621
768
  * Generates a signed license key JWT.
622
769
  * Server-only in practice (requires the private key) but edge-compatible —
@@ -630,7 +777,7 @@ export function getMaxAgentTasks() {
630
777
  * claim is added to the JWT header for forward-compatible key rotation.
631
778
  * @returns Signed JWT string
632
779
  */
633
- export async function generateLicenseKey(payload, privateKey, expiresInSeconds = 365 * 24 * 60 * 60, publicKey) {
780
+ export async function generateLicenseKey(payload, privateKey, expiresInSeconds = DEFAULT_SUBSCRIPTION_TTL_SECONDS, publicKey) {
634
781
  const jose = await getJose();
635
782
  const key = await jose.importPKCS8(privateKey, 'EdDSA');
636
783
  const kid = publicKey ? await computeKeyId(publicKey) : undefined;
@@ -2,11 +2,14 @@
2
2
  * Observability Module
3
3
  *
4
4
  * Centralized exports for observability functionality including logging,
5
- * metrics, tracing, alerts, and health checks.
5
+ * metrics, alerts, and health checks.
6
+ *
7
+ * In-memory `TracingSystem` was removed (fleet-redundancy C11, 2026-07-23):
8
+ * unmounted, tests-only, zero app consumers. Prefer OpenTelemetry when
9
+ * distributed tracing is wired.
6
10
  */
7
11
  export * from './alerts.js';
8
12
  export * from './health-check.js';
9
13
  export * from './logger.js';
10
14
  export * from './metrics.js';
11
- export * from './tracing.js';
12
15
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/observability/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,cAAc,aAAa,CAAC;AAC5B,cAAc,mBAAmB,CAAC;AAClC,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,cAAc,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/observability/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,cAAc,aAAa,CAAC;AAC5B,cAAc,mBAAmB,CAAC;AAClC,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC"}
@@ -2,10 +2,13 @@
2
2
  * Observability Module
3
3
  *
4
4
  * Centralized exports for observability functionality including logging,
5
- * metrics, tracing, alerts, and health checks.
5
+ * metrics, alerts, and health checks.
6
+ *
7
+ * In-memory `TracingSystem` was removed (fleet-redundancy C11, 2026-07-23):
8
+ * unmounted, tests-only, zero app consumers. Prefer OpenTelemetry when
9
+ * distributed tracing is wired.
6
10
  */
7
11
  export * from './alerts.js';
8
12
  export * from './health-check.js';
9
13
  export * from './logger.js';
10
14
  export * from './metrics.js';
11
- export * from './tracing.js';
@@ -1,8 +1,10 @@
1
1
  /**
2
- * Structured Logging Infrastructure
2
+ * Structured Logging Infrastructure (canonical core facade)
3
3
  *
4
- * Re-exports from @revealui/utils to maintain backward compatibility.
5
- * The actual implementation has been moved to @revealui/utils to break circular dependencies.
4
+ * Preferred import for packages that already depend on `@revealui/core`
5
+ * (ADR-008). Re-exports `@revealui/utils/logger` and adds core-only helpers
6
+ * (`createRequestLogger`, `logPerformance`, …). Leaf packages without a core
7
+ * dependency should import `@revealui/utils/logger` directly.
6
8
  */
7
9
  export type { LogContext, LogEntry, LoggerConfig, LogLevel, } from '@revealui/utils/logger';
8
10
  export { createLogger, Logger, logAudit, logError, logger, logQuery, } from '@revealui/utils/logger';
@@ -1 +1 @@
1
- {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/observability/logger.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,YAAY,EACV,UAAU,EACV,QAAQ,EACR,YAAY,EACZ,QAAQ,GACT,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EACL,YAAY,EACZ,MAAM,EACN,QAAQ,EACR,QAAQ,EACR,MAAM,EACN,QAAQ,GACT,MAAM,wBAAwB,CAAC;AAKhC;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,GAAG,OAAO,EAAE,SAAS,GAAG,OAAO,EACzE,OAAO,GAAE;IAAE,WAAW,CAAC,EAAE,OAAO,CAAC;IAAC,cAAc,CAAC,EAAE,OAAO,CAAA;CAAO,IAG/D,SAAS,QAAQ,GAAG;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE;QACR,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAC;QACrC,OAAO,CAAC,EAAE,MAAM,QAAQ,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;KAC5C,CAAC;CACH,EACD,MAAM,MAAM,OAAO,CAAC,SAAS,CAAC,KAC7B,OAAO,CAAC,SAAS,CAAC,CA6CtB;AAED;;GAEG;AACH,wBAAgB,cAAc,CAC5B,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAChC,IAAI,CASN;AAED;;GAEG;AACH,wBAAgB,UAAU,CACxB,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAChC,IAAI,CAgBN;AAED;;GAEG;AACH,wBAAgB,QAAQ,CACtB,SAAS,EAAE,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,QAAQ,EAC5C,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAChC,IAAI,CAMN;AAED;;GAEG;AACH,wBAAgB,aAAa,CAC3B,MAAM,EAAE,MAAM,EACd,MAAM,CAAC,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAChC,IAAI,CAMN;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAKrF"}
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/observability/logger.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAMH,YAAY,EACV,UAAU,EACV,QAAQ,EACR,YAAY,EACZ,QAAQ,GACT,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EACL,YAAY,EACZ,MAAM,EACN,QAAQ,EACR,QAAQ,EACR,MAAM,EACN,QAAQ,GACT,MAAM,wBAAwB,CAAC;AAKhC;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,GAAG,OAAO,EAAE,SAAS,GAAG,OAAO,EACzE,OAAO,GAAE;IAAE,WAAW,CAAC,EAAE,OAAO,CAAC;IAAC,cAAc,CAAC,EAAE,OAAO,CAAA;CAAO,IAG/D,SAAS,QAAQ,GAAG;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE;QACR,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAC;QACrC,OAAO,CAAC,EAAE,MAAM,QAAQ,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;KAC5C,CAAC;CACH,EACD,MAAM,MAAM,OAAO,CAAC,SAAS,CAAC,KAC7B,OAAO,CAAC,SAAS,CAAC,CA6CtB;AAED;;GAEG;AACH,wBAAgB,cAAc,CAC5B,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAChC,IAAI,CASN;AAED;;GAEG;AACH,wBAAgB,UAAU,CACxB,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAChC,IAAI,CAgBN;AAED;;GAEG;AACH,wBAAgB,QAAQ,CACtB,SAAS,EAAE,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,QAAQ,EAC5C,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAChC,IAAI,CAMN;AAED;;GAEG;AACH,wBAAgB,aAAa,CAC3B,MAAM,EAAE,MAAM,EACd,MAAM,CAAC,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAChC,IAAI,CAMN;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAKrF"}
@@ -1,8 +1,10 @@
1
1
  /**
2
- * Structured Logging Infrastructure
2
+ * Structured Logging Infrastructure (canonical core facade)
3
3
  *
4
- * Re-exports from @revealui/utils to maintain backward compatibility.
5
- * The actual implementation has been moved to @revealui/utils to break circular dependencies.
4
+ * Preferred import for packages that already depend on `@revealui/core`
5
+ * (ADR-008). Re-exports `@revealui/utils/logger` and adds core-only helpers
6
+ * (`createRequestLogger`, `logPerformance`, …). Leaf packages without a core
7
+ * dependency should import `@revealui/utils/logger` directly.
6
8
  */
7
9
  // Import logger for internal use
8
10
  import { logger as utilsLogger } from '@revealui/utils/logger';
@@ -1,4 +1,4 @@
1
- import { defaultLogger } from '../instance/logger.js';
1
+ import { logger } from '../observability/logger.js';
2
2
  /**
3
3
  * Analyzes a collection or global configuration and extracts all relationship fields
4
4
  * with their storage metadata for proper query building.
@@ -51,7 +51,7 @@ export function getRelationshipFields(config, collectionSlug) {
51
51
  const validation = validateRelationshipMetadata(relationships);
52
52
  if (!validation.valid) {
53
53
  for (const error of validation.errors) {
54
- defaultLogger.warn(`[RelationshipAnalyzer] ${error}`);
54
+ logger.warn(`[RelationshipAnalyzer] ${error}`);
55
55
  }
56
56
  }
57
57
  return relationships;
@@ -14,6 +14,15 @@ import { type LicensePayload } from './license.js';
14
14
  export declare const SLUG_PATTERN: RegExp;
15
15
  export declare const VALID_REVFORGE_TIERS: readonly ["pro", "max", "enterprise"];
16
16
  export type RevForgeTier = (typeof VALID_REVFORGE_TIERS)[number];
17
+ /**
18
+ * Default lifetime, in days, for a RevForge kit license JWT when neither
19
+ * `expiresInDays` nor `perpetual` is supplied (GAP-287 PR-3). Ratified by the
20
+ * owner 2026-07-18: stays at 365 (no behavior change), matching the annual
21
+ * kit contract — the renewal path already exists via the GAP-316
22
+ * `stamp.sh --license-only` re-mint. This constant only names the value that
23
+ * was previously an inline literal.
24
+ */
25
+ export declare const DEFAULT_KIT_MINT_DAYS = 365;
17
26
  export interface IssueRevForgeLicenseOptions {
18
27
  /** Customer slug; becomes the JWT customerId. Must match SLUG_PATTERN. */
19
28
  slug: string;
@@ -1 +1 @@
1
- {"version":3,"file":"revforge-license.d.ts","sourceRoot":"","sources":["../src/revforge-license.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAsB,KAAK,cAAc,EAAsB,MAAM,cAAc,CAAC;AAE3F,eAAO,MAAM,YAAY,QAAyB,CAAC;AAEnD,eAAO,MAAM,oBAAoB,uCAAwC,CAAC;AAC1E,MAAM,MAAM,YAAY,GAAG,CAAC,OAAO,oBAAoB,CAAC,CAAC,MAAM,CAAC,CAAC;AAEjE,MAAM,WAAW,2BAA2B;IAC1C,0EAA0E;IAC1E,IAAI,EAAE,MAAM,CAAC;IACb,qCAAqC;IACrC,IAAI,EAAE,YAAY,CAAC;IACnB,6FAA6F;IAC7F,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,6FAA6F;IAC7F,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,kCAAkC;IAClC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,kCAAkC;IAClC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,oCAAoC;IACpC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,MAAM,WAAW,0BAA0B;IACzC,gEAAgE;IAChE,UAAU,EAAE,MAAM,CAAC;IACnB,0DAA0D;IAC1D,UAAU,EAAE,MAAM,CAAC;IACnB,gCAAgC;IAChC,IAAI,EAAE,YAAY,CAAC;IACnB,0DAA0D;IAC1D,SAAS,EAAE,OAAO,CAAC;IACnB,sCAAsC;IACtC,QAAQ,EAAE,MAAM,CAAC;IACjB,uDAAuD;IACvD,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,oFAAoF;IACpF,OAAO,EAAE,IAAI,CAAC,cAAc,EAAE,KAAK,GAAG,KAAK,GAAG,KAAK,CAAC,CAAC;CACtD;AAED;;;;;;;;GAQG;AACH,wBAAsB,oBAAoB,CACxC,IAAI,EAAE,2BAA2B,EACjC,IAAI,EAAE;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GAC9C,OAAO,CAAC,0BAA0B,CAAC,CAuFrC"}
1
+ {"version":3,"file":"revforge-license.d.ts","sourceRoot":"","sources":["../src/revforge-license.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAsB,KAAK,cAAc,EAAsB,MAAM,cAAc,CAAC;AAE3F,eAAO,MAAM,YAAY,QAAyB,CAAC;AAEnD,eAAO,MAAM,oBAAoB,uCAAwC,CAAC;AAC1E,MAAM,MAAM,YAAY,GAAG,CAAC,OAAO,oBAAoB,CAAC,CAAC,MAAM,CAAC,CAAC;AAEjE;;;;;;;GAOG;AACH,eAAO,MAAM,qBAAqB,MAAM,CAAC;AAEzC,MAAM,WAAW,2BAA2B;IAC1C,0EAA0E;IAC1E,IAAI,EAAE,MAAM,CAAC;IACb,qCAAqC;IACrC,IAAI,EAAE,YAAY,CAAC;IACnB,6FAA6F;IAC7F,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,6FAA6F;IAC7F,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,kCAAkC;IAClC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,kCAAkC;IAClC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,oCAAoC;IACpC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,MAAM,WAAW,0BAA0B;IACzC,gEAAgE;IAChE,UAAU,EAAE,MAAM,CAAC;IACnB,0DAA0D;IAC1D,UAAU,EAAE,MAAM,CAAC;IACnB,gCAAgC;IAChC,IAAI,EAAE,YAAY,CAAC;IACnB,0DAA0D;IAC1D,SAAS,EAAE,OAAO,CAAC;IACnB,sCAAsC;IACtC,QAAQ,EAAE,MAAM,CAAC;IACjB,uDAAuD;IACvD,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,oFAAoF;IACpF,OAAO,EAAE,IAAI,CAAC,cAAc,EAAE,KAAK,GAAG,KAAK,GAAG,KAAK,CAAC,CAAC;CACtD;AAED;;;;;;;;GAQG;AACH,wBAAsB,oBAAoB,CACxC,IAAI,EAAE,2BAA2B,EACjC,IAAI,EAAE;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GAC9C,OAAO,CAAC,0BAA0B,CAAC,CAwFrC"}
@@ -13,6 +13,15 @@
13
13
  import { generateLicenseKey, validateLicenseKey } from './license.js';
14
14
  export const SLUG_PATTERN = /^[a-z0-9][a-z0-9-]*$/;
15
15
  export const VALID_REVFORGE_TIERS = ['pro', 'max', 'enterprise'];
16
+ /**
17
+ * Default lifetime, in days, for a RevForge kit license JWT when neither
18
+ * `expiresInDays` nor `perpetual` is supplied (GAP-287 PR-3). Ratified by the
19
+ * owner 2026-07-18: stays at 365 (no behavior change), matching the annual
20
+ * kit contract — the renewal path already exists via the GAP-316
21
+ * `stamp.sh --license-only` re-mint. This constant only names the value that
22
+ * was previously an inline literal.
23
+ */
24
+ export const DEFAULT_KIT_MINT_DAYS = 365;
16
25
  /**
17
26
  * Issue a signed RevForge license JWT for a paying customer.
18
27
  *
@@ -55,12 +64,13 @@ export async function issueRevForgeLicense(opts, keys) {
55
64
  ...(opts.domains && opts.domains.length > 0 ? { domains: opts.domains } : {}),
56
65
  };
57
66
  // Perpetual: pass null to omit exp claim. Otherwise translate days → seconds.
58
- // Default (neither flag): 365-day subscription, matching generateLicenseKey's default.
67
+ // Default (neither flag): DEFAULT_KIT_MINT_DAYS (GAP-287 PR-3 named constant;
68
+ // value unchanged at 365).
59
69
  const expiresInSeconds = opts.perpetual
60
70
  ? null
61
71
  : opts.expiresInDays !== undefined
62
72
  ? opts.expiresInDays * 24 * 60 * 60
63
- : 365 * 24 * 60 * 60;
73
+ : DEFAULT_KIT_MINT_DAYS * 24 * 60 * 60;
64
74
  const issuedAtMs = Date.now();
65
75
  const licenseKey = await generateLicenseKey(payload, keys.privateKey, expiresInSeconds, keys.publicKey);
66
76
  // Pair-match guard: prove the supplied public key can verify the JWT we just
@@ -1 +1 @@
1
- {"version":3,"file":"object-storage.d.ts","sourceRoot":"","sources":["../../src/storage/object-storage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAGH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAElD,MAAM,WAAW,mBAAmB;IAClC,2FAA2F;IAC3F,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,kEAAkE;IAClE,WAAW,CAAC,EAAE;QACZ,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;KACxB,CAAC;IACF;;;;;;OAMG;IACH,eAAe,EAAE,MAAM,eAAe,CAAC;IACvC,8DAA8D;IAC9D,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,mBAAmB,GAAG,MAAM,CAiGjE"}
1
+ {"version":3,"file":"object-storage.d.ts","sourceRoot":"","sources":["../../src/storage/object-storage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAGH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAElD,MAAM,WAAW,mBAAmB;IAClC,2FAA2F;IAC3F,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,kEAAkE;IAClE,WAAW,CAAC,EAAE;QACZ,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;KACxB,CAAC;IACF;;;;;;OAMG;IACH,eAAe,EAAE,MAAM,eAAe,CAAC;IACvC,8DAA8D;IAC9D,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,mBAAmB,GAAG,MAAM,CAuGjE"}
@@ -17,7 +17,7 @@
17
17
  * WARNING: This module is server-only.
18
18
  * Do NOT import in client-side code or edge runtime.
19
19
  */
20
- import { defaultLogger } from '../instance/logger.js';
20
+ import { logger } from '../observability/logger.js';
21
21
  export function objectStorage(config) {
22
22
  const prefix = config.prefix || 'uploads';
23
23
  // Memoize the provider so the underlying client (S3 / Blob) is constructed
@@ -71,7 +71,7 @@ export function objectStorage(config) {
71
71
  };
72
72
  }
73
73
  catch (error) {
74
- defaultLogger.error('Object storage upload error:', error);
74
+ logger.error('Object storage upload error', error instanceof Error ? error : new Error(String(error)));
75
75
  throw error;
76
76
  }
77
77
  },
@@ -86,7 +86,7 @@ export function objectStorage(config) {
86
86
  await getProvider().del(keyOrUrl);
87
87
  }
88
88
  catch (error) {
89
- defaultLogger.error('Object storage delete error:', error);
89
+ logger.error('Object storage delete error', error instanceof Error ? error : new Error(String(error)));
90
90
  throw error;
91
91
  }
92
92
  },
@@ -14,14 +14,26 @@ export declare class ApplicationError extends Error {
14
14
  constructor(message: string, code: string, statusCode?: number, context?: Record<string, unknown> | undefined);
15
15
  }
16
16
  /**
17
- * Validation Error
18
- * Use for input validation failures, schema validation failures
17
+ * Validation Error (canonical domain / API / field-ingress class)
18
+ *
19
+ * Single source for server-side validation failures. Carries HTTP 400 via
20
+ * `status` / `statusCode` so REST and middleware treat field-ingress and
21
+ * API validation the same. Distinct from `ClientValidationError` in the
22
+ * React error-boundary module (client form field map).
23
+ *
24
+ * Always branch with `instanceof ValidationError` — never `name ===
25
+ * 'ValidationError'`, which false-positives against other classes that
26
+ * historically shared the same name.
19
27
  */
20
28
  export declare class ValidationError extends Error {
21
29
  field: string;
22
- value: unknown;
30
+ value?: unknown | undefined;
23
31
  context?: Record<string, unknown> | undefined;
24
- constructor(message: string, field: string, value: unknown, context?: Record<string, unknown> | undefined);
32
+ /** HTTP status for transports that read `error.status` (e.g. rest.ts). */
33
+ readonly status = 400;
34
+ /** Alias for handlers that read `statusCode`. */
35
+ readonly statusCode = 400;
36
+ constructor(message: string, field: string, value?: unknown | undefined, context?: Record<string, unknown> | undefined);
25
37
  }
26
38
  /**
27
39
  * Database Error
@@ -1 +1 @@
1
- {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/utils/errors.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/utils/errors.ts"],"names":[],"mappings":"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"}
@@ -22,13 +22,25 @@ export class ApplicationError extends Error {
22
22
  }
23
23
  }
24
24
  /**
25
- * Validation Error
26
- * Use for input validation failures, schema validation failures
25
+ * Validation Error (canonical domain / API / field-ingress class)
26
+ *
27
+ * Single source for server-side validation failures. Carries HTTP 400 via
28
+ * `status` / `statusCode` so REST and middleware treat field-ingress and
29
+ * API validation the same. Distinct from `ClientValidationError` in the
30
+ * React error-boundary module (client form field map).
31
+ *
32
+ * Always branch with `instanceof ValidationError` — never `name ===
33
+ * 'ValidationError'`, which false-positives against other classes that
34
+ * historically shared the same name.
27
35
  */
28
36
  export class ValidationError extends Error {
29
37
  field;
30
38
  value;
31
39
  context;
40
+ /** HTTP status for transports that read `error.status` (e.g. rest.ts). */
41
+ status = 400;
42
+ /** Alias for handlers that read `statusCode`. */
43
+ statusCode = 400;
32
44
  constructor(message, field, value, context) {
33
45
  super(message);
34
46
  this.field = field;
@@ -1 +1 @@
1
- {"version":3,"file":"json-parsing.d.ts","sourceRoot":"","sources":["../../src/utils/json-parsing.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAExD;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAetD;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,qBAAqB,CACnC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC5B,SAAS,CAAC,EAAE,MAAM,GACjB,cAAc,CA2DhB;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,cAAc,EAAE,GAAG,CAAC,MAAM,CAAC,GAC1B,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAUzB;AAED;;;;;;;;GAQG;AACH,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CASjE"}
1
+ {"version":3,"file":"json-parsing.d.ts","sourceRoot":"","sources":["../../src/utils/json-parsing.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAExD;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAetD;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,qBAAqB,CACnC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC5B,SAAS,CAAC,EAAE,MAAM,GACjB,cAAc,CA6DhB;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,cAAc,EAAE,GAAG,CAAC,MAAM,CAAC,GAC1B,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAUzB;AAED;;;;;;;;GAQG;AACH,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CASjE"}
@@ -4,7 +4,7 @@
4
4
  * Utilities for serializing and deserializing JSON fields in database operations.
5
5
  * Handles the _json column pattern used for storing complex field types.
6
6
  */
7
- import { defaultLogger } from '../instance/logger.js';
7
+ import { logger } from '../observability/logger.js';
8
8
  /**
9
9
  * Parse a JSON field value safely
10
10
  *
@@ -67,7 +67,9 @@ export function deserializeJsonFields(doc, tableName) {
67
67
  }
68
68
  catch (error) {
69
69
  // Invalid JSON - log for debugging but continue
70
- defaultLogger.warn(`Failed to parse _json in ${tableName || 'unknown'}:`, error);
70
+ logger.warn(`Failed to parse _json in ${tableName || 'unknown'}`, {
71
+ error: error instanceof Error ? { message: error.message, name: error.name } : error,
72
+ });
71
73
  }
72
74
  }
73
75
  // Remove _json from result (internal column)
@@ -1,32 +1,11 @@
1
1
  /**
2
- * Client-Safe Logger
2
+ * Client-safe logger entry (ADR-008 D4)
3
3
  *
4
- * Production-safe logging utility that works in both client and server contexts.
5
- * Does not depend on Node.js APIs (no async_hooks, no crypto).
6
- * Info/warn messages are no-ops in production to avoid console pollution.
4
+ * Re-exports `@revealui/utils/logger` (no Node async_hooks). Prefer
5
+ * `@revealui/core/observability/logger` for packages that already depend on core.
7
6
  *
8
- * NOTE: No 'use client' directive here. This is a plain utility module, not a
9
- * React component. Adding 'use client' causes Next.js to create a reference
10
- * proxy when imported from server code (API routes), stripping all methods.
7
+ * Package export: `@revealui/core/utils/logger/client`
11
8
  */
12
- export type LogLevel = 'debug' | 'info' | 'warn' | 'error';
13
- export interface LogContext {
14
- [key: string]: unknown;
15
- }
16
- export interface Logger {
17
- debug(message: string, context?: LogContext): void;
18
- info(message: string, context?: LogContext): void;
19
- warn(message: string, context?: LogContext): void;
20
- error(message: string, context?: LogContext): void;
21
- }
22
- /**
23
- * Create a client-safe logger instance
24
- *
25
- * @returns Logger instance safe for client-side use
26
- */
27
- export declare function createLogger(): Logger;
28
- /**
29
- * Default client-safe logger instance
30
- */
31
- export declare const logger: Logger;
9
+ export type { LogContext, LogEntry, LoggerConfig, LogLevel, } from '@revealui/utils/logger';
10
+ export { createLogger, Logger, logAudit, logError, logger, logQuery, } from '@revealui/utils/logger';
32
11
  //# sourceMappingURL=logger-client.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"logger-client.d.ts","sourceRoot":"","sources":["../../src/utils/logger-client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AAE3D,MAAM,WAAW,UAAU;IACzB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,MAAM;IACrB,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,UAAU,GAAG,IAAI,CAAC;IACnD,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,UAAU,GAAG,IAAI,CAAC;IAClD,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,UAAU,GAAG,IAAI,CAAC;IAClD,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,UAAU,GAAG,IAAI,CAAC;CACpD;AAyCD;;;;GAIG;AACH,wBAAgB,YAAY,IAAI,MAAM,CAErC;AAED;;GAEG;AACH,eAAO,MAAM,MAAM,QAAiB,CAAC"}
1
+ {"version":3,"file":"logger-client.d.ts","sourceRoot":"","sources":["../../src/utils/logger-client.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,YAAY,EACV,UAAU,EACV,QAAQ,EACR,YAAY,EACZ,QAAQ,GACT,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EACL,YAAY,EACZ,MAAM,EACN,QAAQ,EACR,QAAQ,EACR,MAAM,EACN,QAAQ,GACT,MAAM,wBAAwB,CAAC"}
@@ -1,55 +1,9 @@
1
1
  /**
2
- * Client-Safe Logger
2
+ * Client-safe logger entry (ADR-008 D4)
3
3
  *
4
- * Production-safe logging utility that works in both client and server contexts.
5
- * Does not depend on Node.js APIs (no async_hooks, no crypto).
6
- * Info/warn messages are no-ops in production to avoid console pollution.
4
+ * Re-exports `@revealui/utils/logger` (no Node async_hooks). Prefer
5
+ * `@revealui/core/observability/logger` for packages that already depend on core.
7
6
  *
8
- * NOTE: No 'use client' directive here. This is a plain utility module, not a
9
- * React component. Adding 'use client' causes Next.js to create a reference
10
- * proxy when imported from server code (API routes), stripping all methods.
7
+ * Package export: `@revealui/core/utils/logger/client`
11
8
  */
12
- /**
13
- * Client-safe logger implementation
14
- * Simple console-based logging without Node.js dependencies
15
- */
16
- class ClientLogger {
17
- formatMessage(level, message, context) {
18
- const timestamp = new Date().toISOString();
19
- const prefix = `[${timestamp}] [RevealUI] [${level.toUpperCase()}]`;
20
- if (context && Object.keys(context).length > 0) {
21
- return `${prefix} ${message} ${JSON.stringify(context)}`;
22
- }
23
- return `${prefix} ${message}`;
24
- }
25
- debug(message, context) {
26
- if (process.env.NODE_ENV !== 'production') {
27
- console.debug(this.formatMessage('debug', message, context));
28
- }
29
- }
30
- info(message, context) {
31
- if (process.env.NODE_ENV !== 'production') {
32
- console.info(this.formatMessage('info', message, context));
33
- }
34
- }
35
- warn(message, context) {
36
- if (process.env.NODE_ENV !== 'production') {
37
- console.warn(this.formatMessage('warn', message, context));
38
- }
39
- }
40
- error(message, context) {
41
- console.error(this.formatMessage('error', message, context));
42
- }
43
- }
44
- /**
45
- * Create a client-safe logger instance
46
- *
47
- * @returns Logger instance safe for client-side use
48
- */
49
- export function createLogger() {
50
- return new ClientLogger();
51
- }
52
- /**
53
- * Default client-safe logger instance
54
- */
55
- export const logger = createLogger();
9
+ export { createLogger, Logger, logAudit, logError, logger, logQuery, } from '@revealui/utils/logger';