@revealui/core 0.5.6 → 0.7.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.
- package/README.md +1 -1
- package/dist/api/compression.d.ts +3 -4
- package/dist/api/compression.d.ts.map +1 -1
- package/dist/api/compression.js +1 -2
- package/dist/api/rate-limit.d.ts +10 -11
- package/dist/api/rate-limit.d.ts.map +1 -1
- package/dist/api/rate-limit.js +9 -16
- package/dist/api/response-cache.d.ts +8 -9
- package/dist/api/response-cache.d.ts.map +1 -1
- package/dist/api/response-cache.js +2 -3
- package/dist/client/admin/layout.d.ts.map +1 -1
- package/dist/client/admin/layout.js +1 -3
- package/dist/client/admin/utils/apiClient.d.ts.map +1 -1
- package/dist/client/admin/utils/apiClient.js +16 -1
- package/dist/client/richtext/index.d.ts.map +1 -1
- package/dist/client/richtext/index.js +0 -1
- package/dist/collections/operations/create.d.ts.map +1 -1
- package/dist/collections/operations/create.js +23 -5
- package/dist/database/universal-postgres.d.ts +14 -0
- package/dist/database/universal-postgres.d.ts.map +1 -1
- package/dist/database/universal-postgres.js +97 -0
- package/dist/fieldTraversal.d.ts +1 -1
- package/dist/fieldTraversal.d.ts.map +1 -1
- package/dist/generated/types/admin.d.ts +2 -2
- package/dist/generated/types/admin.d.ts.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -2
- package/dist/instance/methods/create.d.ts.map +1 -1
- package/dist/instance/methods/create.js +3 -2
- package/dist/license-encryption.d.ts +11 -2
- package/dist/license-encryption.d.ts.map +1 -1
- package/dist/license-encryption.js +77 -22
- package/dist/license.d.ts +106 -8
- package/dist/license.d.ts.map +1 -1
- package/dist/license.js +243 -35
- package/dist/nextjs/index.d.ts +0 -1
- package/dist/nextjs/index.d.ts.map +1 -1
- package/dist/nextjs/index.js +7 -2
- package/dist/nextjs/withRevealUI.d.ts +29 -1
- package/dist/nextjs/withRevealUI.d.ts.map +1 -1
- package/dist/observability/logger.d.ts +0 -4
- package/dist/observability/logger.d.ts.map +1 -1
- package/dist/observability/logger.js +2 -29
- package/dist/observability/metrics.d.ts +25 -0
- package/dist/observability/metrics.d.ts.map +1 -1
- package/dist/observability/metrics.js +26 -0
- package/dist/revealui.d.ts +0 -5
- package/dist/revealui.d.ts.map +1 -1
- package/dist/revealui.js +0 -10
- package/dist/revforge-license.d.ts +60 -0
- package/dist/revforge-license.d.ts.map +1 -0
- package/dist/revforge-license.js +74 -0
- package/dist/richtext/exports/server/rsc.d.ts +2 -17
- package/dist/richtext/exports/server/rsc.d.ts.map +1 -1
- package/dist/richtext/exports/server/rsc.js +9 -54
- package/dist/types/index.d.ts +1 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/{legacy.d.ts → internal.d.ts} +1 -1
- package/dist/types/internal.d.ts.map +1 -0
- package/dist/types/runtime.d.ts +12 -0
- package/dist/types/runtime.d.ts.map +1 -1
- package/dist/utils/api-wrapper.d.ts +4 -6
- package/dist/utils/api-wrapper.d.ts.map +1 -1
- package/dist/utils/api-wrapper.js +8 -10
- package/package.json +71 -24
- package/dist/types/legacy.d.ts.map +0 -1
- /package/dist/types/{legacy.js → internal.js} +0 -0
package/dist/license.d.ts
CHANGED
|
@@ -1,13 +1,57 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* License validation for RevealUI Pro/Enterprise tiers.
|
|
3
3
|
*
|
|
4
|
+
* Edge-compatible: uses the Web Crypto API (`crypto.subtle`) and `jose`
|
|
5
|
+
* exclusively. Safe to import from any runtime (Node, Edge, browser,
|
|
6
|
+
* Workers). No `node:crypto` or filesystem dependencies.
|
|
7
|
+
*
|
|
4
8
|
* @dependencies
|
|
5
|
-
* - jose - JWT
|
|
9
|
+
* - jose - JWT signing/verification (Web Crypto API)
|
|
6
10
|
* - zod - Schema validation for license payloads
|
|
7
11
|
*/
|
|
8
12
|
import { z } from 'zod';
|
|
9
13
|
/** Available license tiers */
|
|
10
14
|
export type LicenseTier = 'free' | 'pro' | 'max' | 'enterprise';
|
|
15
|
+
/**
|
|
16
|
+
* License operating mode — determines how the system behaves when license
|
|
17
|
+
* checks encounter various failure conditions.
|
|
18
|
+
*
|
|
19
|
+
* - active: License is valid and current
|
|
20
|
+
* - grace: License has an issue but is within a grace period (still allowed)
|
|
21
|
+
* - read-only: Perpetual support lapsed past grace — reads allowed, writes blocked
|
|
22
|
+
* - expired: Grace period exhausted — degraded to free tier
|
|
23
|
+
* - invalid: Signature invalid or tampered — hard fail
|
|
24
|
+
* - missing: No license configured — free tier
|
|
25
|
+
*/
|
|
26
|
+
export type LicenseMode = 'active' | 'grace' | 'read-only' | 'expired' | 'invalid' | 'missing';
|
|
27
|
+
/** Detailed result from license status check */
|
|
28
|
+
export interface LicenseCheckResult {
|
|
29
|
+
/** Whether the requested action is allowed */
|
|
30
|
+
allowed: boolean;
|
|
31
|
+
/** Current effective tier */
|
|
32
|
+
tier: LicenseTier;
|
|
33
|
+
/** Operating mode */
|
|
34
|
+
mode: LicenseMode;
|
|
35
|
+
/** Human-readable reason for the current mode */
|
|
36
|
+
reason?: string;
|
|
37
|
+
/** Milliseconds remaining in grace period (undefined if not in grace) */
|
|
38
|
+
graceRemainingMs?: number;
|
|
39
|
+
/** Whether writes should be blocked (read-only mode for lapsed perpetual) */
|
|
40
|
+
readOnly: boolean;
|
|
41
|
+
}
|
|
42
|
+
/** Grace period configuration (in days). Overridable via env for testing. */
|
|
43
|
+
export interface GracePeriodConfig {
|
|
44
|
+
/** Days after subscription expiry before degrading to free (default: 3) */
|
|
45
|
+
subscriptionDays: number;
|
|
46
|
+
/** Days after perpetual support lapse before read-only mode (default: 30) */
|
|
47
|
+
perpetualDays: number;
|
|
48
|
+
/** Days of cached-license grace when infra is unreachable (default: 7) */
|
|
49
|
+
infraDays: number;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Configure grace period durations. Useful for testing.
|
|
53
|
+
*/
|
|
54
|
+
export declare function configureGracePeriods(overrides: Partial<GracePeriodConfig>): void;
|
|
11
55
|
/** Decoded license payload schema */
|
|
12
56
|
declare const licensePayloadSchema: z.ZodObject<{
|
|
13
57
|
tier: z.ZodEnum<{
|
|
@@ -16,6 +60,7 @@ declare const licensePayloadSchema: z.ZodObject<{
|
|
|
16
60
|
enterprise: "enterprise";
|
|
17
61
|
}>;
|
|
18
62
|
customerId: z.ZodString;
|
|
63
|
+
jti: z.ZodString;
|
|
19
64
|
domains: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
20
65
|
maxSites: z.ZodOptional<z.ZodNumber>;
|
|
21
66
|
maxUsers: z.ZodOptional<z.ZodNumber>;
|
|
@@ -26,9 +71,30 @@ declare const licensePayloadSchema: z.ZodObject<{
|
|
|
26
71
|
export type LicensePayload = z.infer<typeof licensePayloadSchema>;
|
|
27
72
|
/** License cache TTL configuration */
|
|
28
73
|
export interface LicenseCacheConfig {
|
|
29
|
-
/** Cache TTL in milliseconds (default:
|
|
74
|
+
/** Cache TTL in milliseconds (default: 15 seconds) */
|
|
30
75
|
ttlMs: number;
|
|
31
76
|
}
|
|
77
|
+
/**
|
|
78
|
+
* Hard cap on cache TTL. Any env override exceeding this is clamped + warned.
|
|
79
|
+
* Revoked licenses must not stay cached longer than this, regardless of
|
|
80
|
+
* operator misconfiguration. 15 minutes balances revocation responsiveness
|
|
81
|
+
* against DB load for high-traffic deployments.
|
|
82
|
+
*
|
|
83
|
+
* Tracked by MASTER_PLAN §CR-8 CR8-P1-05.
|
|
84
|
+
*/
|
|
85
|
+
export declare const MAX_LICENSE_CACHE_TTL_MS: number;
|
|
86
|
+
/**
|
|
87
|
+
* Parse and validate the `LICENSE_CACHE_TTL_MS` env value.
|
|
88
|
+
*
|
|
89
|
+
* Rules:
|
|
90
|
+
* - Unset / non-numeric / non-positive → `DEFAULT_TTL_MS` (15s)
|
|
91
|
+
* - Above `MAX_LICENSE_CACHE_TTL_MS` → clamped to cap, warning emitted
|
|
92
|
+
* - Otherwise → parsed value
|
|
93
|
+
*
|
|
94
|
+
* Exported for unit testing. Production code uses the module-load-time
|
|
95
|
+
* evaluation in `DEFAULT_CACHE_CONFIG` below.
|
|
96
|
+
*/
|
|
97
|
+
export declare function parseLicenseCacheTtlEnv(envValue: string | undefined): number;
|
|
32
98
|
/**
|
|
33
99
|
* Configure the license cache TTL.
|
|
34
100
|
* Useful for tests (short TTL) or deployments needing faster revocation detection.
|
|
@@ -37,13 +103,26 @@ export declare function configureLicenseCache(overrides: Partial<LicenseCacheCon
|
|
|
37
103
|
/**
|
|
38
104
|
* Computes a deterministic Key ID (kid) from a public key PEM string.
|
|
39
105
|
* Returns the first 8 characters of the SHA-256 hex digest of the PEM.
|
|
106
|
+
*
|
|
107
|
+
* Async because it uses `crypto.subtle.digest` for full edge compatibility.
|
|
40
108
|
*/
|
|
41
|
-
export declare function computeKeyId(publicKeyPem: string): string
|
|
109
|
+
export declare function computeKeyId(publicKeyPem: string): Promise<string>;
|
|
42
110
|
/**
|
|
43
111
|
* Validates a license key JWT and returns the decoded payload.
|
|
44
112
|
* Returns null if the key is invalid, expired, or missing.
|
|
113
|
+
*
|
|
114
|
+
* Phase 1 audit B-2: when `expectedCustomerId` is supplied, the JWT's
|
|
115
|
+
* `customerId` claim must match exactly — otherwise the token is rejected
|
|
116
|
+
* even when the signature + iss + aud + exp are all valid. This binds a
|
|
117
|
+
* license to its purchaser. Forge mode uses this against the env-configured
|
|
118
|
+
* `REVEALUI_LICENSED_CUSTOMER_ID`. Hosted mode (where the deployment IS the
|
|
119
|
+
* customer) leaves it undefined.
|
|
120
|
+
*
|
|
121
|
+
* Note: `nbf` and `exp` are enforced automatically by jose.jwtVerify against
|
|
122
|
+
* `currentDate` (defaults to now). `iss` and `aud` are enforced via the
|
|
123
|
+
* options below. Signature is enforced via the public key.
|
|
45
124
|
*/
|
|
46
|
-
export declare function validateLicenseKey(licenseKey: string, publicKey: string): Promise<LicensePayload | null>;
|
|
125
|
+
export declare function validateLicenseKey(licenseKey: string, publicKey: string, expectedCustomerId?: string): Promise<LicensePayload | null>;
|
|
47
126
|
/**
|
|
48
127
|
* Initialize the license system. Call once at application startup.
|
|
49
128
|
* Reads REVEALUI_LICENSE_KEY and REVEALUI_LICENSE_PUBLIC_KEY from environment.
|
|
@@ -63,8 +142,24 @@ export declare function getLicensePayload(): LicensePayload | null;
|
|
|
63
142
|
/**
|
|
64
143
|
* Checks whether the current license is at least the given tier.
|
|
65
144
|
* Also validates that the license has not expired (checks JWT exp claim).
|
|
145
|
+
*
|
|
146
|
+
* Subscription grace: if the JWT has expired but is within the configured
|
|
147
|
+
* grace period (default 3 days), access is still allowed. Use
|
|
148
|
+
* `getLicenseStatus()` to check whether the license is in grace.
|
|
66
149
|
*/
|
|
67
150
|
export declare function isLicensed(requiredTier: LicenseTier): boolean;
|
|
151
|
+
/**
|
|
152
|
+
* Returns the full license status including mode, grace state, and read-only flag.
|
|
153
|
+
*
|
|
154
|
+
* Use this for UI decisions (banners, warnings) and API response headers.
|
|
155
|
+
* For simple gate checks, `isLicensed()` is sufficient.
|
|
156
|
+
*/
|
|
157
|
+
export declare function getLicenseStatus(requiredTier?: LicenseTier): LicenseCheckResult;
|
|
158
|
+
/**
|
|
159
|
+
* Returns the configured grace period durations.
|
|
160
|
+
* Useful for API response headers and customer-facing documentation.
|
|
161
|
+
*/
|
|
162
|
+
export declare function getGraceConfig(): Readonly<GracePeriodConfig>;
|
|
68
163
|
/**
|
|
69
164
|
* Returns the maximum number of sites allowed by the current license.
|
|
70
165
|
*/
|
|
@@ -80,17 +175,20 @@ export declare function getMaxUsers(): number;
|
|
|
80
175
|
export declare function getMaxAgentTasks(): number;
|
|
81
176
|
/**
|
|
82
177
|
* Generates a signed license key JWT.
|
|
83
|
-
*
|
|
178
|
+
* Server-only in practice (requires the private key) but edge-compatible —
|
|
179
|
+
* `jose.importPKCS8` and `SignJWT` both run on Web Crypto.
|
|
84
180
|
*
|
|
85
181
|
* @param payload - License payload (tier, customerId, limits, perpetual flag)
|
|
86
|
-
* @param privateKey -
|
|
182
|
+
* @param privateKey - Ed25519 private key (PEM format)
|
|
87
183
|
* @param expiresInSeconds - JWT expiration in seconds. Pass null for perpetual
|
|
88
184
|
* licenses (no exp claim). Defaults to 1 year for subscription licenses.
|
|
89
|
-
* @param publicKey -
|
|
185
|
+
* @param publicKey - Ed25519 public key (PEM format). When provided, a `kid`
|
|
90
186
|
* claim is added to the JWT header for forward-compatible key rotation.
|
|
91
187
|
* @returns Signed JWT string
|
|
92
188
|
*/
|
|
93
|
-
export declare function generateLicenseKey(payload: Omit<LicensePayload, 'iat' | 'exp'
|
|
189
|
+
export declare function generateLicenseKey(payload: Omit<LicensePayload, 'iat' | 'exp' | 'jti'> & {
|
|
190
|
+
jti?: string;
|
|
191
|
+
}, privateKey: string, expiresInSeconds?: number | null, publicKey?: string): Promise<string>;
|
|
94
192
|
/**
|
|
95
193
|
* Reset license state. Primarily for testing.
|
|
96
194
|
*/
|
package/dist/license.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"license.d.ts","sourceRoot":"","sources":["../src/license.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"license.d.ts","sourceRoot":"","sources":["../src/license.ts"],"names":[],"mappings":"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"}
|
package/dist/license.js
CHANGED
|
@@ -1,21 +1,56 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* License validation for RevealUI Pro/Enterprise tiers.
|
|
3
3
|
*
|
|
4
|
+
* Edge-compatible: uses the Web Crypto API (`crypto.subtle`) and `jose`
|
|
5
|
+
* exclusively. Safe to import from any runtime (Node, Edge, browser,
|
|
6
|
+
* Workers). No `node:crypto` or filesystem dependencies.
|
|
7
|
+
*
|
|
4
8
|
* @dependencies
|
|
5
|
-
* - jose - JWT
|
|
9
|
+
* - jose - JWT signing/verification (Web Crypto API)
|
|
6
10
|
* - zod - Schema validation for license payloads
|
|
7
11
|
*/
|
|
8
|
-
|
|
9
|
-
|
|
12
|
+
// jose is imported lazily inside async functions to avoid Turbopack's
|
|
13
|
+
// async module initialization ordering issue (see #399). Top-level
|
|
14
|
+
// import of jose triggers an asyncModule wrapper that can race with
|
|
15
|
+
// other modules in the auth route bundle during page data collection.
|
|
10
16
|
import { z } from 'zod';
|
|
11
17
|
import { decryptLicenseKey } from './license-encryption.js';
|
|
12
18
|
import { logger } from './utils/logger.js';
|
|
19
|
+
async function getJose() {
|
|
20
|
+
return await import('jose');
|
|
21
|
+
}
|
|
22
|
+
/** JWT issuer and audience for license tokens — prevents cross-environment replay */
|
|
23
|
+
const LICENSE_ISSUER = process.env.REVEALUI_LICENSE_ISSUER ?? 'https://revealui.com';
|
|
24
|
+
const LICENSE_AUDIENCE = process.env.REVEALUI_LICENSE_AUDIENCE ?? 'revealui-license';
|
|
25
|
+
const DEFAULT_GRACE = {
|
|
26
|
+
subscriptionDays: parseEnvInt('LICENSE_GRACE_SUBSCRIPTION_DAYS', 3),
|
|
27
|
+
perpetualDays: parseEnvInt('LICENSE_GRACE_PERPETUAL_DAYS', 30),
|
|
28
|
+
infraDays: parseEnvInt('LICENSE_GRACE_INFRA_DAYS', 7),
|
|
29
|
+
};
|
|
30
|
+
function parseEnvInt(key, fallback) {
|
|
31
|
+
const val = process.env[key];
|
|
32
|
+
if (val) {
|
|
33
|
+
const parsed = Number.parseInt(val, 10);
|
|
34
|
+
if (Number.isFinite(parsed) && parsed >= 0)
|
|
35
|
+
return parsed;
|
|
36
|
+
}
|
|
37
|
+
return fallback;
|
|
38
|
+
}
|
|
39
|
+
let graceConfig = { ...DEFAULT_GRACE };
|
|
40
|
+
/**
|
|
41
|
+
* Configure grace period durations. Useful for testing.
|
|
42
|
+
*/
|
|
43
|
+
export function configureGracePeriods(overrides) {
|
|
44
|
+
graceConfig = { ...DEFAULT_GRACE, ...overrides };
|
|
45
|
+
}
|
|
13
46
|
/** Decoded license payload schema */
|
|
14
47
|
const licensePayloadSchema = z.object({
|
|
15
48
|
/** License tier */
|
|
16
49
|
tier: z.enum(['pro', 'max', 'enterprise']),
|
|
17
|
-
/** Organization or customer ID */
|
|
18
|
-
customerId: z.string(),
|
|
50
|
+
/** Organization or customer ID — must be non-empty; used to bind the token to a specific customer */
|
|
51
|
+
customerId: z.string().min(1),
|
|
52
|
+
/** JWT ID — used for per-token revocation; every issued token must carry one */
|
|
53
|
+
jti: z.string().min(1),
|
|
19
54
|
/** Licensed domain(s) */
|
|
20
55
|
domains: z.array(z.string()).optional(),
|
|
21
56
|
/** Maximum number of sites allowed */
|
|
@@ -34,16 +69,40 @@ const licensePayloadSchema = z.object({
|
|
|
34
69
|
exp: z.number().optional(),
|
|
35
70
|
});
|
|
36
71
|
const DEFAULT_TTL_MS = 15_000; // 15 seconds - revoked licenses lose access quickly
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
72
|
+
/**
|
|
73
|
+
* Hard cap on cache TTL. Any env override exceeding this is clamped + warned.
|
|
74
|
+
* Revoked licenses must not stay cached longer than this, regardless of
|
|
75
|
+
* operator misconfiguration. 15 minutes balances revocation responsiveness
|
|
76
|
+
* against DB load for high-traffic deployments.
|
|
77
|
+
*
|
|
78
|
+
* Tracked by MASTER_PLAN §CR-8 CR8-P1-05.
|
|
79
|
+
*/
|
|
80
|
+
export const MAX_LICENSE_CACHE_TTL_MS = 15 * 60 * 1000;
|
|
81
|
+
/**
|
|
82
|
+
* Parse and validate the `LICENSE_CACHE_TTL_MS` env value.
|
|
83
|
+
*
|
|
84
|
+
* Rules:
|
|
85
|
+
* - Unset / non-numeric / non-positive → `DEFAULT_TTL_MS` (15s)
|
|
86
|
+
* - Above `MAX_LICENSE_CACHE_TTL_MS` → clamped to cap, warning emitted
|
|
87
|
+
* - Otherwise → parsed value
|
|
88
|
+
*
|
|
89
|
+
* Exported for unit testing. Production code uses the module-load-time
|
|
90
|
+
* evaluation in `DEFAULT_CACHE_CONFIG` below.
|
|
91
|
+
*/
|
|
92
|
+
export function parseLicenseCacheTtlEnv(envValue) {
|
|
93
|
+
if (!envValue)
|
|
94
|
+
return DEFAULT_TTL_MS;
|
|
95
|
+
const parsed = Number.parseInt(envValue, 10);
|
|
96
|
+
if (!Number.isFinite(parsed) || parsed <= 0)
|
|
45
97
|
return DEFAULT_TTL_MS;
|
|
46
|
-
|
|
98
|
+
if (parsed > MAX_LICENSE_CACHE_TTL_MS) {
|
|
99
|
+
logger.warn(`LICENSE_CACHE_TTL_MS=${parsed} exceeds the ${MAX_LICENSE_CACHE_TTL_MS}ms (15-minute) cap; using ${MAX_LICENSE_CACHE_TTL_MS}. Longer TTLs extend the window where revoked licenses retain access and are not permitted.`);
|
|
100
|
+
return MAX_LICENSE_CACHE_TTL_MS;
|
|
101
|
+
}
|
|
102
|
+
return parsed;
|
|
103
|
+
}
|
|
104
|
+
const DEFAULT_CACHE_CONFIG = {
|
|
105
|
+
ttlMs: parseLicenseCacheTtlEnv(process.env.LICENSE_CACHE_TTL_MS),
|
|
47
106
|
};
|
|
48
107
|
let cacheConfig = { ...DEFAULT_CACHE_CONFIG };
|
|
49
108
|
let cachedAt = 0;
|
|
@@ -58,6 +117,7 @@ let cachedState = {
|
|
|
58
117
|
tier: 'free',
|
|
59
118
|
payload: null,
|
|
60
119
|
validatedAt: null,
|
|
120
|
+
keyPresentButInvalid: false,
|
|
61
121
|
};
|
|
62
122
|
/**
|
|
63
123
|
* The public key used to verify license JWTs.
|
|
@@ -73,7 +133,7 @@ function getPublicKey() {
|
|
|
73
133
|
* Reads the license key from environment.
|
|
74
134
|
* Supports encrypted keys (enc:iv:ciphertext:tag format) via REVEALUI_LICENSE_ENCRYPTION_KEY.
|
|
75
135
|
*/
|
|
76
|
-
function getLicenseKey() {
|
|
136
|
+
async function getLicenseKey() {
|
|
77
137
|
const raw = process.env.REVEALUI_LICENSE_KEY ?? null;
|
|
78
138
|
if (!raw)
|
|
79
139
|
return null;
|
|
@@ -82,31 +142,67 @@ function getLicenseKey() {
|
|
|
82
142
|
/**
|
|
83
143
|
* Computes a deterministic Key ID (kid) from a public key PEM string.
|
|
84
144
|
* Returns the first 8 characters of the SHA-256 hex digest of the PEM.
|
|
145
|
+
*
|
|
146
|
+
* Async because it uses `crypto.subtle.digest` for full edge compatibility.
|
|
85
147
|
*/
|
|
86
|
-
export function computeKeyId(publicKeyPem) {
|
|
87
|
-
|
|
148
|
+
export async function computeKeyId(publicKeyPem) {
|
|
149
|
+
const encoded = new TextEncoder().encode(publicKeyPem);
|
|
150
|
+
const digest = new Uint8Array(await crypto.subtle.digest('SHA-256', encoded));
|
|
151
|
+
let hex = '';
|
|
152
|
+
// Only the first 4 bytes (8 hex chars) — enough to identify rotated keys.
|
|
153
|
+
for (const b of digest.subarray(0, 4)) {
|
|
154
|
+
hex += b.toString(16).padStart(2, '0');
|
|
155
|
+
}
|
|
156
|
+
return hex;
|
|
88
157
|
}
|
|
89
158
|
/**
|
|
90
159
|
* Validates a license key JWT and returns the decoded payload.
|
|
91
160
|
* Returns null if the key is invalid, expired, or missing.
|
|
161
|
+
*
|
|
162
|
+
* Phase 1 audit B-2: when `expectedCustomerId` is supplied, the JWT's
|
|
163
|
+
* `customerId` claim must match exactly — otherwise the token is rejected
|
|
164
|
+
* even when the signature + iss + aud + exp are all valid. This binds a
|
|
165
|
+
* license to its purchaser. Forge mode uses this against the env-configured
|
|
166
|
+
* `REVEALUI_LICENSED_CUSTOMER_ID`. Hosted mode (where the deployment IS the
|
|
167
|
+
* customer) leaves it undefined.
|
|
168
|
+
*
|
|
169
|
+
* Note: `nbf` and `exp` are enforced automatically by jose.jwtVerify against
|
|
170
|
+
* `currentDate` (defaults to now). `iss` and `aud` are enforced via the
|
|
171
|
+
* options below. Signature is enforced via the public key.
|
|
92
172
|
*/
|
|
93
|
-
export async function validateLicenseKey(licenseKey, publicKey) {
|
|
173
|
+
export async function validateLicenseKey(licenseKey, publicKey, expectedCustomerId) {
|
|
94
174
|
try {
|
|
175
|
+
const jose = await getJose();
|
|
95
176
|
// Extract kid from JWT header for forward-compatible key rotation
|
|
96
|
-
const header = decodeProtectedHeader(licenseKey);
|
|
97
|
-
const expectedKid = computeKeyId(publicKey);
|
|
177
|
+
const header = jose.decodeProtectedHeader(licenseKey);
|
|
178
|
+
const expectedKid = await computeKeyId(publicKey);
|
|
98
179
|
if (header.kid && header.kid !== expectedKid) {
|
|
99
180
|
logger.warn(`JWT kid mismatch: token has "${header.kid}", current key is "${expectedKid}". ` +
|
|
100
181
|
'Token may have been signed with a rotated key.');
|
|
101
182
|
}
|
|
102
|
-
const key = await importSPKI(publicKey, '
|
|
103
|
-
|
|
104
|
-
|
|
183
|
+
const key = await jose.importSPKI(publicKey, 'EdDSA');
|
|
184
|
+
// Accept tokens expired within the subscription grace window so the
|
|
185
|
+
// payload is available for grace-period calculations in isLicensed().
|
|
186
|
+
const { payload } = await jose.jwtVerify(licenseKey, key, {
|
|
187
|
+
algorithms: ['EdDSA'],
|
|
188
|
+
clockTolerance: graceConfig.subscriptionDays * 86_400,
|
|
189
|
+
issuer: LICENSE_ISSUER,
|
|
190
|
+
audience: LICENSE_AUDIENCE,
|
|
105
191
|
});
|
|
106
192
|
const result = licensePayloadSchema.safeParse(payload);
|
|
107
193
|
if (!result.success) {
|
|
108
194
|
return null;
|
|
109
195
|
}
|
|
196
|
+
// Phase 1 audit B-2: customerId binding. If the caller supplied an
|
|
197
|
+
// expectation, the JWT's customerId must match exactly. This prevents
|
|
198
|
+
// a leaked JWT from one customer being used to license another's
|
|
199
|
+
// deployment (Forge customer-binding) or a leaked stamping-time JWT
|
|
200
|
+
// being replayed against a deployment expecting a different customer.
|
|
201
|
+
if (expectedCustomerId !== undefined && result.data.customerId !== expectedCustomerId) {
|
|
202
|
+
logger.warn(`License customerId mismatch: token has "${result.data.customerId}", ` +
|
|
203
|
+
`deployment expects "${expectedCustomerId}". Token rejected.`);
|
|
204
|
+
return null;
|
|
205
|
+
}
|
|
110
206
|
return result.data;
|
|
111
207
|
}
|
|
112
208
|
catch {
|
|
@@ -120,16 +216,27 @@ export async function validateLicenseKey(licenseKey, publicKey) {
|
|
|
120
216
|
* @returns The resolved license tier
|
|
121
217
|
*/
|
|
122
218
|
export async function initializeLicense() {
|
|
123
|
-
const licenseKey = getLicenseKey();
|
|
219
|
+
const licenseKey = await getLicenseKey();
|
|
124
220
|
const publicKey = getPublicKey();
|
|
125
221
|
if (!(licenseKey && publicKey)) {
|
|
126
|
-
cachedState = {
|
|
222
|
+
cachedState = {
|
|
223
|
+
tier: 'free',
|
|
224
|
+
payload: null,
|
|
225
|
+
validatedAt: Date.now(),
|
|
226
|
+
keyPresentButInvalid: false,
|
|
227
|
+
};
|
|
127
228
|
cachedAt = Date.now();
|
|
128
229
|
return 'free';
|
|
129
230
|
}
|
|
130
231
|
const payload = await validateLicenseKey(licenseKey, publicKey);
|
|
131
232
|
if (!payload) {
|
|
132
|
-
|
|
233
|
+
// Key was present but failed validation (expired beyond grace, invalid signature, etc.)
|
|
234
|
+
cachedState = {
|
|
235
|
+
tier: 'free',
|
|
236
|
+
payload: null,
|
|
237
|
+
validatedAt: Date.now(),
|
|
238
|
+
keyPresentButInvalid: true,
|
|
239
|
+
};
|
|
133
240
|
cachedAt = Date.now();
|
|
134
241
|
return 'free';
|
|
135
242
|
}
|
|
@@ -137,6 +244,7 @@ export async function initializeLicense() {
|
|
|
137
244
|
tier: payload.tier,
|
|
138
245
|
payload,
|
|
139
246
|
validatedAt: Date.now(),
|
|
247
|
+
keyPresentButInvalid: false,
|
|
140
248
|
};
|
|
141
249
|
cachedAt = Date.now();
|
|
142
250
|
// Clamp cache TTL to license expiry so revoked licenses don't survive the full TTL
|
|
@@ -154,7 +262,7 @@ export async function initializeLicense() {
|
|
|
154
262
|
*/
|
|
155
263
|
function evictStaleCache() {
|
|
156
264
|
if (cachedAt > 0 && Date.now() - cachedAt > cacheConfig.ttlMs) {
|
|
157
|
-
cachedState = { tier: 'free', payload: null, validatedAt: null };
|
|
265
|
+
cachedState = { tier: 'free', payload: null, validatedAt: null, keyPresentButInvalid: false };
|
|
158
266
|
cachedAt = 0;
|
|
159
267
|
}
|
|
160
268
|
}
|
|
@@ -176,6 +284,10 @@ export function getLicensePayload() {
|
|
|
176
284
|
/**
|
|
177
285
|
* Checks whether the current license is at least the given tier.
|
|
178
286
|
* Also validates that the license has not expired (checks JWT exp claim).
|
|
287
|
+
*
|
|
288
|
+
* Subscription grace: if the JWT has expired but is within the configured
|
|
289
|
+
* grace period (default 3 days), access is still allowed. Use
|
|
290
|
+
* `getLicenseStatus()` to check whether the license is in grace.
|
|
179
291
|
*/
|
|
180
292
|
export function isLicensed(requiredTier) {
|
|
181
293
|
evictStaleCache();
|
|
@@ -192,11 +304,90 @@ export function isLicensed(requiredTier) {
|
|
|
192
304
|
if (!cachedState.payload?.perpetual && cachedState.payload?.exp) {
|
|
193
305
|
const nowSeconds = Math.floor(Date.now() / 1000);
|
|
194
306
|
if (cachedState.payload.exp < nowSeconds) {
|
|
307
|
+
// Expired — check subscription grace period
|
|
308
|
+
const graceEndSeconds = cachedState.payload.exp + graceConfig.subscriptionDays * 86_400;
|
|
309
|
+
if (nowSeconds < graceEndSeconds) {
|
|
310
|
+
// Within grace — still allowed, but callers should check getLicenseStatus()
|
|
311
|
+
return tierRank[cachedState.tier] >= tierRank[requiredTier];
|
|
312
|
+
}
|
|
195
313
|
return false;
|
|
196
314
|
}
|
|
197
315
|
}
|
|
198
316
|
return tierRank[cachedState.tier] >= tierRank[requiredTier];
|
|
199
317
|
}
|
|
318
|
+
/**
|
|
319
|
+
* Returns the full license status including mode, grace state, and read-only flag.
|
|
320
|
+
*
|
|
321
|
+
* Use this for UI decisions (banners, warnings) and API response headers.
|
|
322
|
+
* For simple gate checks, `isLicensed()` is sufficient.
|
|
323
|
+
*/
|
|
324
|
+
export function getLicenseStatus(requiredTier = 'pro') {
|
|
325
|
+
evictStaleCache();
|
|
326
|
+
const tierRank = {
|
|
327
|
+
free: 0,
|
|
328
|
+
pro: 1,
|
|
329
|
+
max: 2,
|
|
330
|
+
enterprise: 3,
|
|
331
|
+
};
|
|
332
|
+
// No license configured — or key was present but failed validation
|
|
333
|
+
if (!cachedState.payload) {
|
|
334
|
+
if (cachedState.keyPresentButInvalid) {
|
|
335
|
+
return {
|
|
336
|
+
allowed: requiredTier === 'free',
|
|
337
|
+
tier: 'free',
|
|
338
|
+
mode: 'expired',
|
|
339
|
+
reason: 'License key failed validation (expired beyond grace or invalid)',
|
|
340
|
+
readOnly: false,
|
|
341
|
+
};
|
|
342
|
+
}
|
|
343
|
+
return {
|
|
344
|
+
allowed: requiredTier === 'free',
|
|
345
|
+
tier: 'free',
|
|
346
|
+
mode: 'missing',
|
|
347
|
+
reason: 'No license configured',
|
|
348
|
+
readOnly: false,
|
|
349
|
+
};
|
|
350
|
+
}
|
|
351
|
+
const nowSeconds = Math.floor(Date.now() / 1000);
|
|
352
|
+
// Check subscription expiry + grace
|
|
353
|
+
if (!cachedState.payload.perpetual && cachedState.payload.exp) {
|
|
354
|
+
if (cachedState.payload.exp < nowSeconds) {
|
|
355
|
+
const graceEndSeconds = cachedState.payload.exp + graceConfig.subscriptionDays * 86_400;
|
|
356
|
+
if (nowSeconds < graceEndSeconds) {
|
|
357
|
+
const graceRemainingMs = (graceEndSeconds - nowSeconds) * 1000;
|
|
358
|
+
return {
|
|
359
|
+
allowed: tierRank[cachedState.tier] >= tierRank[requiredTier],
|
|
360
|
+
tier: cachedState.tier,
|
|
361
|
+
mode: 'grace',
|
|
362
|
+
reason: `Subscription expired, ${Math.ceil(graceRemainingMs / 86_400_000)}-day grace remaining`,
|
|
363
|
+
graceRemainingMs,
|
|
364
|
+
readOnly: false,
|
|
365
|
+
};
|
|
366
|
+
}
|
|
367
|
+
return {
|
|
368
|
+
allowed: requiredTier === 'free',
|
|
369
|
+
tier: 'free',
|
|
370
|
+
mode: 'expired',
|
|
371
|
+
reason: 'Subscription expired and grace period exhausted',
|
|
372
|
+
readOnly: false,
|
|
373
|
+
};
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
// Active license
|
|
377
|
+
return {
|
|
378
|
+
allowed: tierRank[cachedState.tier] >= tierRank[requiredTier],
|
|
379
|
+
tier: cachedState.tier,
|
|
380
|
+
mode: 'active',
|
|
381
|
+
readOnly: false,
|
|
382
|
+
};
|
|
383
|
+
}
|
|
384
|
+
/**
|
|
385
|
+
* Returns the configured grace period durations.
|
|
386
|
+
* Useful for API response headers and customer-facing documentation.
|
|
387
|
+
*/
|
|
388
|
+
export function getGraceConfig() {
|
|
389
|
+
return graceConfig;
|
|
390
|
+
}
|
|
200
391
|
/**
|
|
201
392
|
* Returns the maximum number of sites allowed by the current license.
|
|
202
393
|
*/
|
|
@@ -239,24 +430,41 @@ export function getMaxAgentTasks() {
|
|
|
239
430
|
}
|
|
240
431
|
/**
|
|
241
432
|
* Generates a signed license key JWT.
|
|
242
|
-
*
|
|
433
|
+
* Server-only in practice (requires the private key) but edge-compatible —
|
|
434
|
+
* `jose.importPKCS8` and `SignJWT` both run on Web Crypto.
|
|
243
435
|
*
|
|
244
436
|
* @param payload - License payload (tier, customerId, limits, perpetual flag)
|
|
245
|
-
* @param privateKey -
|
|
437
|
+
* @param privateKey - Ed25519 private key (PEM format)
|
|
246
438
|
* @param expiresInSeconds - JWT expiration in seconds. Pass null for perpetual
|
|
247
439
|
* licenses (no exp claim). Defaults to 1 year for subscription licenses.
|
|
248
|
-
* @param publicKey -
|
|
440
|
+
* @param publicKey - Ed25519 public key (PEM format). When provided, a `kid`
|
|
249
441
|
* claim is added to the JWT header for forward-compatible key rotation.
|
|
250
442
|
* @returns Signed JWT string
|
|
251
443
|
*/
|
|
252
444
|
export async function generateLicenseKey(payload, privateKey, expiresInSeconds = 365 * 24 * 60 * 60, publicKey) {
|
|
253
|
-
const
|
|
254
|
-
const
|
|
255
|
-
const
|
|
445
|
+
const jose = await getJose();
|
|
446
|
+
const key = await jose.importPKCS8(privateKey, 'EdDSA');
|
|
447
|
+
const kid = publicKey ? await computeKeyId(publicKey) : undefined;
|
|
448
|
+
const header = { alg: 'EdDSA' };
|
|
256
449
|
if (kid) {
|
|
257
450
|
header.kid = kid;
|
|
258
451
|
}
|
|
259
|
-
|
|
452
|
+
// Phase 1 audit B-2: every issued token carries a `jti` so it can be
|
|
453
|
+
// individually revoked without rotating the vendor key. Auto-generate
|
|
454
|
+
// when caller doesn't supply one (the common case).
|
|
455
|
+
const jti = payload.jti ?? crypto.randomUUID();
|
|
456
|
+
// Strip the optional jti from the spread so jose.setJti() is the single
|
|
457
|
+
// source of the claim (avoids a duplicate field in the payload).
|
|
458
|
+
const { jti: _ignoredJti, ...rest } = payload;
|
|
459
|
+
const builder = new jose.SignJWT({ ...rest })
|
|
460
|
+
.setProtectedHeader(header)
|
|
461
|
+
.setIssuedAt()
|
|
462
|
+
// Phase 1 audit B-2: enforce nbf so tokens cannot be replayed pre-issue
|
|
463
|
+
// by a clock-skewed client.
|
|
464
|
+
.setNotBefore('0s')
|
|
465
|
+
.setJti(jti)
|
|
466
|
+
.setIssuer(LICENSE_ISSUER)
|
|
467
|
+
.setAudience(LICENSE_AUDIENCE);
|
|
260
468
|
if (expiresInSeconds !== null) {
|
|
261
469
|
builder.setExpirationTime(`${expiresInSeconds}s`);
|
|
262
470
|
}
|
|
@@ -266,6 +474,6 @@ export async function generateLicenseKey(payload, privateKey, expiresInSeconds =
|
|
|
266
474
|
* Reset license state. Primarily for testing.
|
|
267
475
|
*/
|
|
268
476
|
export function resetLicenseState() {
|
|
269
|
-
cachedState = { tier: 'free', payload: null, validatedAt: null };
|
|
477
|
+
cachedState = { tier: 'free', payload: null, validatedAt: null, keyPresentButInvalid: false };
|
|
270
478
|
cachedAt = 0;
|
|
271
479
|
}
|
package/dist/nextjs/index.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/nextjs/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/nextjs/index.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC7C,YAAY,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC"}
|
package/dist/nextjs/index.js
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
-
// RevealUI Next.js integration
|
|
1
|
+
// RevealUI Next.js runtime integration.
|
|
2
|
+
//
|
|
3
|
+
// This barrel is intentionally runtime-only. `withRevealUI` is NOT re-exported
|
|
4
|
+
// here because it pulls in `node:fs` + `node:path` at module load, which Next's
|
|
5
|
+
// NFT tracer then attributes to every route that transitively imports this
|
|
6
|
+
// barrel (even via type-only paths). Config-time consumers should import it
|
|
7
|
+
// directly from `@revealui/core/nextjs/withRevealUI`.
|
|
2
8
|
export { getRevealUI } from './utilities.js';
|
|
3
|
-
export { withRevealUI } from './withRevealUI.js';
|
|
@@ -1,4 +1,31 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Subset of Next.js config shape used by withRevealUI.
|
|
3
|
+
* Defined locally to avoid requiring `next` as a dependency of @revealui/core.
|
|
4
|
+
* Consumers pass their full NextConfig through; we only access these fields.
|
|
5
|
+
*/
|
|
6
|
+
interface NextConfig {
|
|
7
|
+
env?: Record<string, string | undefined>;
|
|
8
|
+
webpack?: (config: Record<string, unknown>, context: {
|
|
9
|
+
isServer: boolean;
|
|
10
|
+
dev: boolean;
|
|
11
|
+
dir: string;
|
|
12
|
+
[key: string]: unknown;
|
|
13
|
+
}) => Record<string, unknown>;
|
|
14
|
+
turbopack?: {
|
|
15
|
+
resolveAlias?: Record<string, string>;
|
|
16
|
+
};
|
|
17
|
+
headers?: () => Promise<Array<{
|
|
18
|
+
source: string;
|
|
19
|
+
headers: Array<{
|
|
20
|
+
key: string;
|
|
21
|
+
value: string;
|
|
22
|
+
}>;
|
|
23
|
+
}>>;
|
|
24
|
+
images?: {
|
|
25
|
+
remotePatterns?: Array<Record<string, unknown>>;
|
|
26
|
+
};
|
|
27
|
+
[key: string]: unknown;
|
|
28
|
+
}
|
|
2
29
|
export interface WithRevealUIOptions {
|
|
3
30
|
/** Path to the RevealUI config file (relative to Next.js project root) */
|
|
4
31
|
configPath?: string;
|
|
@@ -17,4 +44,5 @@ export interface WithRevealUIOptions {
|
|
|
17
44
|
* The alias works with both Webpack (Next.js < 15) and Turbopack (Next.js 16+).
|
|
18
45
|
*/
|
|
19
46
|
export declare function withRevealUI(nextConfig?: NextConfig, options?: WithRevealUIOptions): NextConfig;
|
|
47
|
+
export {};
|
|
20
48
|
//# sourceMappingURL=withRevealUI.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"withRevealUI.d.ts","sourceRoot":"","sources":["../../src/nextjs/withRevealUI.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"withRevealUI.d.ts","sourceRoot":"","sources":["../../src/nextjs/withRevealUI.ts"],"names":[],"mappings":"AAIA;;;;GAIG;AACH,UAAU,UAAU;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;IACzC,OAAO,CAAC,EAAE,CACR,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,OAAO,EAAE;QAAE,QAAQ,EAAE,OAAO,CAAC;QAAC,GAAG,EAAE,OAAO,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,KAC9E,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC7B,SAAS,CAAC,EAAE;QAAE,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAE,CAAC;IACtD,OAAO,CAAC,EAAE,MAAM,OAAO,CACrB,KAAK,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,KAAK,CAAC;YAAE,GAAG,EAAE,MAAM,CAAC;YAAC,KAAK,EAAE,MAAM,CAAA;SAAE,CAAC,CAAA;KAAE,CAAC,CAC1E,CAAC;IACF,MAAM,CAAC,EAAE;QAAE,cAAc,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAA;KAAE,CAAC;IAC7D,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAOD,MAAM,WAAW,mBAAmB;IAClC,0EAA0E;IAC1E,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,iCAAiC;IACjC,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,uBAAuB;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,qBAAqB;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAC1B,UAAU,GAAE,UAAe,EAC3B,OAAO,GAAE,mBAAwB,GAChC,UAAU,CAgMZ"}
|