@revealui/core 0.14.7 → 0.15.3

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.
@@ -1 +1 @@
1
- {"version":3,"file":"rest.d.ts","sourceRoot":"","sources":["../../src/api/rest.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EACV,MAAM,EACN,YAAY,EAGZ,cAAc,EAGd,YAAY,EACZ,gBAAgB,EAChB,WAAW,EACZ,MAAM,mBAAmB,CAAC;AAE3B,MAAM,WAAW,WAAW,CAAC,CAAC,GAAG,cAAc;IAC7C,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC;IACX,GAAG,CAAC,EAAE,CAAC,CAAC;IACR,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,KAAK,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACrD;AAED,MAAM,WAAW,WAAW;IAC1B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,QAAQ,CAAC,EAAE,YAAY,CAAC;CACzB;AA8aD,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,gBAAgB,GACzB,OAAO,CAAC,QAAQ,CAAC,CAiGnB;AAGD,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,gBAAgB,GACzB;IACD,GAAG,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;IAChE,IAAI,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;IACjE,GAAG,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;IAChE,MAAM,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;IACnE,KAAK,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;IAClE,OAAO,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;CACrE,CAaA"}
1
+ {"version":3,"file":"rest.d.ts","sourceRoot":"","sources":["../../src/api/rest.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EACV,MAAM,EACN,YAAY,EAGZ,cAAc,EAGd,YAAY,EACZ,gBAAgB,EAChB,WAAW,EACZ,MAAM,mBAAmB,CAAC;AAE3B,MAAM,WAAW,WAAW,CAAC,CAAC,GAAG,cAAc;IAC7C,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC;IACX,GAAG,CAAC,EAAE,CAAC,CAAC;IACR,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,KAAK,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACrD;AAED,MAAM,WAAW,WAAW;IAC1B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,QAAQ,CAAC,EAAE,YAAY,CAAC;CACzB;AAuaD,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,gBAAgB,GACzB,OAAO,CAAC,QAAQ,CAAC,CAiGnB;AAGD,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,gBAAgB,GACzB;IACD,GAAG,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;IAChE,IAAI,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;IACjE,GAAG,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;IAChE,MAAM,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;IACnE,KAAK,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;IAClE,OAAO,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;CACrE,CAaA"}
package/dist/api/rest.js CHANGED
@@ -153,8 +153,10 @@ function getCorsOriginsFromConfig(config) {
153
153
  return [];
154
154
  }
155
155
  /**
156
- * Get allowed CORS origin for a request
157
- * Checks config first, then environment variable, then allows all for development
156
+ * Get allowed CORS origin for a request.
157
+ * The allowlist comes from config, then REVEALUI_CORS_ORIGINS.
158
+ * A request origin on that list is returned. A missing list, an empty list,
159
+ * or a non-matching origin returns an empty allow-origin so nothing is granted.
158
160
  */
159
161
  function getAllowedOrigin(request, config) {
160
162
  let allowedOrigins = getCorsOriginsFromConfig(config);
@@ -163,18 +165,10 @@ function getAllowedOrigin(request, config) {
163
165
  allowedOrigins = process.env.REVEALUI_CORS_ORIGINS.split(',').map((s) => s.trim());
164
166
  }
165
167
  const origin = request.headers.get('origin');
166
- // If config has specific origins and request origin matches, use it
167
168
  if (allowedOrigins.length > 0 && origin && allowedOrigins.includes(origin)) {
168
169
  return origin;
169
170
  }
170
- // In development, allow all origins for convenience
171
- // In production, this should never be reached if CORS is properly configured
172
- if (process.env.NODE_ENV === 'development') {
173
- return '*';
174
- }
175
- // In production, if no allowed origins configured, deny all (secure default)
176
- // This prevents accidental exposure in production
177
- return origin || '';
171
+ return '';
178
172
  }
179
173
  /**
180
174
  * Get standard CORS headers for a response
package/dist/license.d.ts CHANGED
@@ -201,6 +201,8 @@ export declare const REFRESH_ACCEPT_DAYS = 30;
201
201
  * the bind succeeds. It never mints and never grants entitlement on its own.
202
202
  */
203
203
  export declare function validateLicenseKeyForRefresh(licenseKey: string, publicKey: string | readonly string[], expectedCustomerId: string, refreshAcceptDays?: number): Promise<LicensePayload | null>;
204
+ /** Authenticated operator containment: validates issuer/signature/customer, not entitlement expiry. */
205
+ export declare function validateLicenseKeyForOperator(licenseKey: string, publicKey: string | readonly string[], expectedCustomerId: string): Promise<LicensePayload | null>;
204
206
  /**
205
207
  * Outcome of a signing-keypair self-test. See {@link selfVerifyLicenseKeypair}.
206
208
  */
@@ -1 +1 @@
1
- {"version":3,"file":"license.d.ts","sourceRoot":"","sources":["../src/license.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"license.d.ts","sourceRoot":"","sources":["../src/license.ts"],"names":[],"mappings":"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"}
package/dist/license.js CHANGED
@@ -281,6 +281,12 @@ export async function validateLicenseKeyForRefresh(licenseKey, publicKey, expect
281
281
  return null;
282
282
  return verifyAndParseLicenseJwt(licenseKey, publicKey, refreshAcceptDays * 86_400, bound);
283
283
  }
284
+ /** Authenticated operator containment: validates issuer/signature/customer, not entitlement expiry. */
285
+ export async function validateLicenseKeyForOperator(licenseKey, publicKey, expectedCustomerId) {
286
+ if (!expectedCustomerId.trim())
287
+ return null;
288
+ return verifyAndParseLicenseJwt(licenseKey, publicKey, 0, expectedCustomerId, true);
289
+ }
284
290
  /**
285
291
  * Shared verify + parse path for {@link validateLicenseKey} and
286
292
  * {@link validateLicenseKeyForRefresh}. The ONLY behavioral difference between
@@ -288,7 +294,7 @@ export async function validateLicenseKeyForRefresh(licenseKey, publicKey, expect
288
294
  * still accepted — so the rotation-aware multi-key loop and the payload schema
289
295
  * live in exactly one place.
290
296
  */
291
- async function verifyAndParseLicenseJwt(licenseKey, publicKey, clockToleranceSeconds, expectedCustomerId) {
297
+ async function verifyAndParseLicenseJwt(licenseKey, publicKey, clockToleranceSeconds, expectedCustomerId, operator = false) {
292
298
  const candidates = typeof publicKey === 'string' ? [publicKey] : [...publicKey];
293
299
  if (candidates.length === 0)
294
300
  return null;
@@ -303,12 +309,27 @@ async function verifyAndParseLicenseJwt(licenseKey, publicKey, clockToleranceSec
303
309
  for (const candidate of ordered) {
304
310
  try {
305
311
  const key = await jose.importSPKI(candidate, 'EdDSA');
306
- const { payload } = await jose.jwtVerify(licenseKey, key, {
307
- algorithms: ['EdDSA'],
308
- clockTolerance: clockToleranceSeconds,
309
- issuer: LICENSE_ISSUER,
310
- audience: LICENSE_AUDIENCE,
311
- });
312
+ let payload;
313
+ if (operator) {
314
+ const verified = await jose.compactVerify(licenseKey, key, { algorithms: ['EdDSA'] });
315
+ const claims = JSON.parse(new TextDecoder().decode(verified.payload));
316
+ if (claims.iss !== LICENSE_ISSUER ||
317
+ !(claims.aud === LICENSE_AUDIENCE ||
318
+ (Array.isArray(claims.aud) && claims.aud.includes(LICENSE_AUDIENCE))) ||
319
+ (claims.nbf !== undefined &&
320
+ (typeof claims.nbf !== 'number' || claims.nbf > Date.now() / 1000))) {
321
+ continue;
322
+ }
323
+ payload = claims;
324
+ }
325
+ else {
326
+ ({ payload } = await jose.jwtVerify(licenseKey, key, {
327
+ algorithms: ['EdDSA'],
328
+ clockTolerance: clockToleranceSeconds,
329
+ issuer: LICENSE_ISSUER,
330
+ audience: LICENSE_AUDIENCE,
331
+ }));
332
+ }
312
333
  verifiedPayload = payload;
313
334
  verified = true;
314
335
  break;
@@ -882,17 +903,18 @@ export async function generateLicenseKey(payload, privateKey, expiresInSeconds =
882
903
  // Strip the optional jti from the spread so jose.setJti() is the single
883
904
  // source of the claim (avoids a duplicate field in the payload).
884
905
  const { jti: _ignoredJti, ...rest } = payload;
906
+ const issuedAt = Math.floor(Date.now() / 1000);
885
907
  const builder = new jose.SignJWT({ ...rest })
886
908
  .setProtectedHeader(header)
887
- .setIssuedAt()
909
+ .setIssuedAt(issuedAt)
888
910
  // Phase 1 audit B-2: enforce nbf so tokens cannot be replayed pre-issue
889
911
  // by a clock-skewed client.
890
- .setNotBefore('0s')
912
+ .setNotBefore(issuedAt)
891
913
  .setJti(jti)
892
914
  .setIssuer(LICENSE_ISSUER)
893
915
  .setAudience(LICENSE_AUDIENCE);
894
916
  if (expiresInSeconds !== null) {
895
- builder.setExpirationTime(`${expiresInSeconds}s`);
917
+ builder.setExpirationTime(issuedAt + expiresInSeconds);
896
918
  }
897
919
  return builder.sign(key);
898
920
  }
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Sentry `environment` for a deploy.
3
+ *
4
+ * `NODE_ENV=production` is set on staging as well as production, so it is not
5
+ * a safe Sentry label. Prefer `SENTRY_ENVIRONMENT` (then `REVEALUI_DEPLOY_ENV`,
6
+ * then `NEXT_PUBLIC_SENTRY_ENVIRONMENT`). When those are unset, derive the
7
+ * label from public hosts. A `*.staging.revealui.com` host is never reported
8
+ * as production. Vercel preview stays `preview`.
9
+ */
10
+ export type SentryEnvironmentName = 'production' | 'staging' | 'preview' | 'development' | 'test';
11
+ /** Non-secret label. Set `SENTRY_ENVIRONMENT=staging` on staging Vercel and Fly. */
12
+ export declare const SENTRY_ENVIRONMENT_VAR = "SENTRY_ENVIRONMENT";
13
+ export interface SentryEnvironmentSource {
14
+ SENTRY_ENVIRONMENT?: string | undefined;
15
+ REVEALUI_DEPLOY_ENV?: string | undefined;
16
+ NEXT_PUBLIC_SENTRY_ENVIRONMENT?: string | undefined;
17
+ NODE_ENV?: string | undefined;
18
+ VERCEL_ENV?: string | undefined;
19
+ REVEALUI_API_URL?: string | undefined;
20
+ NEXT_PUBLIC_API_URL?: string | undefined;
21
+ API_URL?: string | undefined;
22
+ REVEALUI_PUBLIC_SERVER_URL?: string | undefined;
23
+ NEXT_PUBLIC_SERVER_URL?: string | undefined;
24
+ VERCEL_PROJECT_PRODUCTION_URL?: string | undefined;
25
+ VERCEL_URL?: string | undefined;
26
+ SESSION_COOKIE_DOMAIN?: string | undefined;
27
+ PASSKEY_RP_ID?: string | undefined;
28
+ PASSKEY_ORIGIN?: string | undefined;
29
+ CORS_ORIGIN?: string | undefined;
30
+ }
31
+ /**
32
+ * Resolve the Sentry environment label.
33
+ * Staging hosts report `staging`, or `preview` when that explicit label is set.
34
+ * They do not report `production`.
35
+ */
36
+ export declare function resolveSentryEnvironment(env: SentryEnvironmentSource): SentryEnvironmentName;
37
+ //# sourceMappingURL=sentry-environment.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sentry-environment.d.ts","sourceRoot":"","sources":["../src/sentry-environment.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,MAAM,MAAM,qBAAqB,GAAG,YAAY,GAAG,SAAS,GAAG,SAAS,GAAG,aAAa,GAAG,MAAM,CAAC;AAElG,oFAAoF;AACpF,eAAO,MAAM,sBAAsB,uBAAuB,CAAC;AAE3D,MAAM,WAAW,uBAAuB;IACtC,kBAAkB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACxC,mBAAmB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACzC,8BAA8B,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACpD,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,gBAAgB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACtC,mBAAmB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACzC,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B,0BAA0B,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAChD,sBAAsB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5C,6BAA6B,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACnD,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,qBAAqB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3C,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,cAAc,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAClC;AAyED;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,uBAAuB,GAAG,qBAAqB,CAoD5F"}
@@ -0,0 +1,129 @@
1
+ /**
2
+ * Sentry `environment` for a deploy.
3
+ *
4
+ * `NODE_ENV=production` is set on staging as well as production, so it is not
5
+ * a safe Sentry label. Prefer `SENTRY_ENVIRONMENT` (then `REVEALUI_DEPLOY_ENV`,
6
+ * then `NEXT_PUBLIC_SENTRY_ENVIRONMENT`). When those are unset, derive the
7
+ * label from public hosts. A `*.staging.revealui.com` host is never reported
8
+ * as production. Vercel preview stays `preview`.
9
+ */
10
+ import { isStagingRevealHost, normalizeRequestHost } from './session-cookie-domain.js';
11
+ /** Non-secret label. Set `SENTRY_ENVIRONMENT=staging` on staging Vercel and Fly. */
12
+ export const SENTRY_ENVIRONMENT_VAR = 'SENTRY_ENVIRONMENT';
13
+ const HOST_KEYS = [
14
+ 'REVEALUI_API_URL',
15
+ 'NEXT_PUBLIC_API_URL',
16
+ 'API_URL',
17
+ 'REVEALUI_PUBLIC_SERVER_URL',
18
+ 'NEXT_PUBLIC_SERVER_URL',
19
+ 'VERCEL_PROJECT_PRODUCTION_URL',
20
+ 'VERCEL_URL',
21
+ 'SESSION_COOKIE_DOMAIN',
22
+ 'PASSKEY_RP_ID',
23
+ 'PASSKEY_ORIGIN',
24
+ 'CORS_ORIGIN',
25
+ ];
26
+ const PRODUCTION_HOSTS = new Set([
27
+ 'revealui.com',
28
+ 'www.revealui.com',
29
+ 'api.revealui.com',
30
+ 'admin.revealui.com',
31
+ 'docs.revealui.com',
32
+ ]);
33
+ function lockedEnvironment(raw) {
34
+ if (raw == null)
35
+ return null;
36
+ const value = raw.trim().toLowerCase();
37
+ switch (value) {
38
+ case 'production':
39
+ case 'staging':
40
+ case 'preview':
41
+ case 'development':
42
+ case 'test':
43
+ return value;
44
+ default:
45
+ return null;
46
+ }
47
+ }
48
+ function firstLocked(...values) {
49
+ for (const value of values) {
50
+ const locked = lockedEnvironment(value);
51
+ if (locked)
52
+ return locked;
53
+ }
54
+ return null;
55
+ }
56
+ function splitComma(raw) {
57
+ const parts = [];
58
+ let start = 0;
59
+ for (let index = 0; index <= raw.length; index += 1) {
60
+ if (index === raw.length || raw.charCodeAt(index) === 44) {
61
+ const part = raw.slice(start, index).trim();
62
+ if (part.length > 0)
63
+ parts.push(part);
64
+ start = index + 1;
65
+ }
66
+ }
67
+ return parts;
68
+ }
69
+ function collectHosts(env) {
70
+ const hosts = [];
71
+ for (const key of HOST_KEYS) {
72
+ const raw = env[key];
73
+ if (typeof raw !== 'string' || raw.trim().length === 0)
74
+ continue;
75
+ for (const part of splitComma(raw)) {
76
+ const host = normalizeRequestHost(part);
77
+ if (host)
78
+ hosts.push(host);
79
+ }
80
+ }
81
+ return hosts;
82
+ }
83
+ /**
84
+ * Resolve the Sentry environment label.
85
+ * Staging hosts report `staging`, or `preview` when that explicit label is set.
86
+ * They do not report `production`.
87
+ */
88
+ export function resolveSentryEnvironment(env) {
89
+ const hosts = collectHosts(env);
90
+ let stagingHost = false;
91
+ let productionHost = false;
92
+ for (const host of hosts) {
93
+ if (isStagingRevealHost(host))
94
+ stagingHost = true;
95
+ if (PRODUCTION_HOSTS.has(host))
96
+ productionHost = true;
97
+ }
98
+ const explicit = firstLocked(env.SENTRY_ENVIRONMENT, env.REVEALUI_DEPLOY_ENV, env.NEXT_PUBLIC_SENTRY_ENVIRONMENT);
99
+ if (stagingHost) {
100
+ if (explicit === 'staging' ||
101
+ explicit === 'preview' ||
102
+ explicit === 'development' ||
103
+ explicit === 'test') {
104
+ return explicit;
105
+ }
106
+ return 'staging';
107
+ }
108
+ if (explicit)
109
+ return explicit;
110
+ if (productionHost)
111
+ return 'production';
112
+ const vercel = lockedEnvironment(env.VERCEL_ENV);
113
+ if (vercel === 'preview' ||
114
+ vercel === 'development' ||
115
+ vercel === 'test' ||
116
+ vercel === 'staging') {
117
+ return vercel;
118
+ }
119
+ const nodeEnv = lockedEnvironment(env.NODE_ENV);
120
+ if (nodeEnv === 'development' ||
121
+ nodeEnv === 'test' ||
122
+ nodeEnv === 'staging' ||
123
+ nodeEnv === 'preview') {
124
+ return nodeEnv;
125
+ }
126
+ if (nodeEnv === 'production' || vercel === 'production')
127
+ return 'production';
128
+ return 'development';
129
+ }
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Session cookie domain for a request host (GAP-343).
3
+ *
4
+ * Staging hosts always resolve to `staging.revealui.com` so a production
5
+ * `SESSION_COOKIE_DOMAIN` (for example `.revealui.com`) is not attached to
6
+ * the staging subtree. Every other host returns `configuredDomain` unchanged.
7
+ * This function does not read the environment and does not apply the
8
+ * production-only gate. Callers keep that gate.
9
+ */
10
+ /** Cookie Domain attribute for the staging.revealui.com subtree. No leading dot. */
11
+ export declare const STAGING_SESSION_COOKIE_DOMAIN = "staging.revealui.com";
12
+ /**
13
+ * Hostname from a Host or X-Forwarded-Host value.
14
+ * Strips a scheme, path, trailing dot, and numeric port. Uses the first
15
+ * comma-separated entry. Returns null when nothing usable remains.
16
+ * String methods only (no regular expressions).
17
+ */
18
+ export declare function normalizeRequestHost(raw: string | null | undefined): string | null;
19
+ /**
20
+ * True for `staging.revealui.com` and any host under `*.staging.revealui.com`.
21
+ * Label-boundary match: `evilstaging.revealui.com` and
22
+ * `staging.revealui.com.evil.com` are not staging hosts.
23
+ */
24
+ export declare function isStagingRevealHost(requestHost: string | null | undefined): boolean;
25
+ /**
26
+ * Cookie Domain for this request.
27
+ *
28
+ * Staging hosts return `staging.revealui.com` even when `configuredDomain`
29
+ * is the production domain or unset. Every other host, including a missing
30
+ * host, returns `configuredDomain` exactly (including `undefined`).
31
+ */
32
+ export declare function sessionCookieDomainForHost(requestHost: string | null | undefined, configuredDomain: string | undefined): string | undefined;
33
+ /**
34
+ * Public request host. Prefer `Host` so a client-supplied `X-Forwarded-Host`
35
+ * cannot override the host the platform already set. Fall back to
36
+ * `X-Forwarded-Host` only when `Host` is absent.
37
+ */
38
+ export declare function requestHostFromHeaders(getHeader: (name: string) => string | null | undefined): string | null;
39
+ //# sourceMappingURL=session-cookie-domain.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-cookie-domain.d.ts","sourceRoot":"","sources":["../src/session-cookie-domain.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,oFAAoF;AACpF,eAAO,MAAM,6BAA6B,yBAAyB,CAAC;AAEpE;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI,CA0ClF;AAUD;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAKnF;AAED;;;;;;GAMG;AACH,wBAAgB,0BAA0B,CACxC,WAAW,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EACtC,gBAAgB,EAAE,MAAM,GAAG,SAAS,GACnC,MAAM,GAAG,SAAS,CAKpB;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CACpC,SAAS,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,GAAG,SAAS,GACrD,MAAM,GAAG,IAAI,CAMf"}
@@ -0,0 +1,106 @@
1
+ /**
2
+ * Session cookie domain for a request host (GAP-343).
3
+ *
4
+ * Staging hosts always resolve to `staging.revealui.com` so a production
5
+ * `SESSION_COOKIE_DOMAIN` (for example `.revealui.com`) is not attached to
6
+ * the staging subtree. Every other host returns `configuredDomain` unchanged.
7
+ * This function does not read the environment and does not apply the
8
+ * production-only gate. Callers keep that gate.
9
+ */
10
+ /** Cookie Domain attribute for the staging.revealui.com subtree. No leading dot. */
11
+ export const STAGING_SESSION_COOKIE_DOMAIN = 'staging.revealui.com';
12
+ /**
13
+ * Hostname from a Host or X-Forwarded-Host value.
14
+ * Strips a scheme, path, trailing dot, and numeric port. Uses the first
15
+ * comma-separated entry. Returns null when nothing usable remains.
16
+ * String methods only (no regular expressions).
17
+ */
18
+ export function normalizeRequestHost(raw) {
19
+ if (raw == null)
20
+ return null;
21
+ let value = raw.trim().toLowerCase();
22
+ if (value.length === 0)
23
+ return null;
24
+ const comma = value.indexOf(',');
25
+ if (comma !== -1) {
26
+ value = value.slice(0, comma).trim();
27
+ }
28
+ if (value.length === 0)
29
+ return null;
30
+ const scheme = value.indexOf('://');
31
+ if (scheme !== -1) {
32
+ value = value.slice(scheme + 3);
33
+ }
34
+ const slash = value.indexOf('/');
35
+ if (slash !== -1) {
36
+ value = value.slice(0, slash);
37
+ }
38
+ if (value.startsWith('[')) {
39
+ const end = value.indexOf(']');
40
+ if (end === -1)
41
+ return null;
42
+ const bracketed = value.slice(0, end + 1);
43
+ return bracketed.length > 2 ? bracketed : null;
44
+ }
45
+ const colon = value.lastIndexOf(':');
46
+ if (colon !== -1) {
47
+ const port = value.slice(colon + 1);
48
+ if (port.length > 0 && isAllDigits(port)) {
49
+ value = value.slice(0, colon);
50
+ }
51
+ }
52
+ if (value.endsWith('.')) {
53
+ value = value.slice(0, -1);
54
+ }
55
+ if (value.length === 0)
56
+ return null;
57
+ return value;
58
+ }
59
+ function isAllDigits(value) {
60
+ for (let i = 0; i < value.length; i++) {
61
+ const code = value.charCodeAt(i);
62
+ if (code < 48 || code > 57)
63
+ return false;
64
+ }
65
+ return true;
66
+ }
67
+ /**
68
+ * True for `staging.revealui.com` and any host under `*.staging.revealui.com`.
69
+ * Label-boundary match: `evilstaging.revealui.com` and
70
+ * `staging.revealui.com.evil.com` are not staging hosts.
71
+ */
72
+ export function isStagingRevealHost(requestHost) {
73
+ const host = normalizeRequestHost(requestHost);
74
+ if (!host)
75
+ return false;
76
+ if (host === STAGING_SESSION_COOKIE_DOMAIN)
77
+ return true;
78
+ return host.endsWith(`.${STAGING_SESSION_COOKIE_DOMAIN}`);
79
+ }
80
+ /**
81
+ * Cookie Domain for this request.
82
+ *
83
+ * Staging hosts return `staging.revealui.com` even when `configuredDomain`
84
+ * is the production domain or unset. Every other host, including a missing
85
+ * host, returns `configuredDomain` exactly (including `undefined`).
86
+ */
87
+ export function sessionCookieDomainForHost(requestHost, configuredDomain) {
88
+ if (isStagingRevealHost(requestHost)) {
89
+ return STAGING_SESSION_COOKIE_DOMAIN;
90
+ }
91
+ return configuredDomain;
92
+ }
93
+ /**
94
+ * Public request host. Prefer `Host` so a client-supplied `X-Forwarded-Host`
95
+ * cannot override the host the platform already set. Fall back to
96
+ * `X-Forwarded-Host` only when `Host` is absent.
97
+ */
98
+ export function requestHostFromHeaders(getHeader) {
99
+ const host = getHeader('host');
100
+ if (typeof host === 'string' && host.trim().length > 0)
101
+ return host;
102
+ const forwarded = getHeader('x-forwarded-host');
103
+ if (typeof forwarded === 'string' && forwarded.trim().length > 0)
104
+ return forwarded;
105
+ return null;
106
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@revealui/core",
3
- "version": "0.14.7",
3
+ "version": "0.15.3",
4
4
  "description": "RevealUI's runtime engine — admin UI, REST API, auth, rich text, plugin system, and access control. The heart of the open-source platform.",
5
5
  "license": "MIT",
6
6
  "dependencies": {
@@ -23,10 +23,10 @@
23
23
  "pg": "^8.22.0",
24
24
  "yjs": "^13.6.31",
25
25
  "zod": "^4.4.3",
26
- "@revealui/contracts": "0.11.0",
27
- "@revealui/presentation": "0.14.7",
26
+ "@revealui/contracts": "0.13.2",
27
+ "@revealui/presentation": "0.15.2",
28
28
  "@revealui/resilience": "0.2.4",
29
- "@revealui/security": "0.8.2",
29
+ "@revealui/security": "0.10.1",
30
30
  "@revealui/utils": "0.3.6"
31
31
  },
32
32
  "devDependencies": {
@@ -66,6 +66,16 @@
66
66
  "import": "./dist/deployment-mode.js",
67
67
  "default": "./dist/deployment-mode.js"
68
68
  },
69
+ "./session-cookie-domain": {
70
+ "types": "./dist/session-cookie-domain.d.ts",
71
+ "import": "./dist/session-cookie-domain.js",
72
+ "default": "./dist/session-cookie-domain.js"
73
+ },
74
+ "./sentry-environment": {
75
+ "types": "./dist/sentry-environment.d.ts",
76
+ "import": "./dist/sentry-environment.js",
77
+ "default": "./dist/sentry-environment.js"
78
+ },
69
79
  "./margin-governor": {
70
80
  "types": "./dist/margin-governor.d.ts",
71
81
  "import": "./dist/margin-governor.js",