@revealui/core 0.6.0 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/README.md +2 -2
  2. package/dist/api/rate-limit.d.ts.map +1 -1
  3. package/dist/api/rate-limit.js +8 -14
  4. package/dist/client/admin/utils/apiClient.d.ts.map +1 -1
  5. package/dist/client/admin/utils/apiClient.js +16 -1
  6. package/dist/client/richtext/index.d.ts.map +1 -1
  7. package/dist/client/richtext/index.js +0 -1
  8. package/dist/collections/operations/create.d.ts.map +1 -1
  9. package/dist/collections/operations/create.js +23 -5
  10. package/dist/collections/operations/delete.d.ts +2 -4
  11. package/dist/collections/operations/delete.d.ts.map +1 -1
  12. package/dist/collections/operations/delete.js +21 -4
  13. package/dist/collections/operations/findById.d.ts.map +1 -1
  14. package/dist/collections/operations/findById.js +18 -3
  15. package/dist/collections/operations/update.d.ts.map +1 -1
  16. package/dist/collections/operations/update.js +21 -4
  17. package/dist/database/universal-postgres.d.ts +14 -0
  18. package/dist/database/universal-postgres.d.ts.map +1 -1
  19. package/dist/database/universal-postgres.js +97 -0
  20. package/dist/fieldTraversal.d.ts +1 -1
  21. package/dist/fieldTraversal.d.ts.map +1 -1
  22. package/dist/instance/methods/create.d.ts.map +1 -1
  23. package/dist/instance/methods/create.js +3 -2
  24. package/dist/license.d.ts +40 -5
  25. package/dist/license.d.ts.map +1 -1
  26. package/dist/license.js +88 -22
  27. package/dist/observability/metrics.d.ts +15 -0
  28. package/dist/observability/metrics.d.ts.map +1 -1
  29. package/dist/observability/metrics.js +21 -0
  30. package/dist/revforge-license.d.ts +60 -0
  31. package/dist/revforge-license.d.ts.map +1 -0
  32. package/dist/revforge-license.js +74 -0
  33. package/dist/richtext/exports/server/rsc.d.ts +1 -1
  34. package/dist/richtext/exports/server/rsc.d.ts.map +1 -1
  35. package/dist/richtext/exports/server/rsc.js +7 -2
  36. package/dist/security/index.d.ts +9 -2
  37. package/dist/security/index.d.ts.map +1 -1
  38. package/dist/security/index.js +9 -2
  39. package/dist/storage/_helpers.d.ts +14 -0
  40. package/dist/storage/_helpers.d.ts.map +1 -0
  41. package/dist/storage/_helpers.js +40 -0
  42. package/dist/storage/index.d.ts +16 -0
  43. package/dist/storage/index.d.ts.map +1 -1
  44. package/dist/storage/index.js +43 -1
  45. package/dist/storage/mock.d.ts +39 -0
  46. package/dist/storage/mock.d.ts.map +1 -0
  47. package/dist/storage/mock.js +91 -0
  48. package/dist/storage/r2.d.ts +13 -0
  49. package/dist/storage/r2.d.ts.map +1 -0
  50. package/dist/storage/r2.js +117 -0
  51. package/dist/storage/types.d.ts +110 -0
  52. package/dist/storage/types.d.ts.map +1 -0
  53. package/dist/storage/types.js +16 -0
  54. package/dist/types/index.d.ts +1 -1
  55. package/dist/types/index.d.ts.map +1 -1
  56. package/dist/types/{legacy.d.ts → internal.d.ts} +1 -1
  57. package/dist/types/internal.d.ts.map +1 -0
  58. package/dist/types/runtime.d.ts +12 -0
  59. package/dist/types/runtime.d.ts.map +1 -1
  60. package/dist/utils/api-wrapper.d.ts.map +1 -1
  61. package/dist/utils/api-wrapper.js +2 -1
  62. package/package.json +33 -24
  63. package/dist/types/legacy.d.ts.map +0 -1
  64. /package/dist/types/{legacy.js → internal.js} +0 -0
package/dist/license.d.ts CHANGED
@@ -55,11 +55,12 @@ export declare function configureGracePeriods(overrides: Partial<GracePeriodConf
55
55
  /** Decoded license payload schema */
56
56
  declare const licensePayloadSchema: z.ZodObject<{
57
57
  tier: z.ZodEnum<{
58
- pro: "pro";
59
58
  max: "max";
59
+ pro: "pro";
60
60
  enterprise: "enterprise";
61
61
  }>;
62
62
  customerId: z.ZodString;
63
+ jti: z.ZodString;
63
64
  domains: z.ZodOptional<z.ZodArray<z.ZodString>>;
64
65
  maxSites: z.ZodOptional<z.ZodNumber>;
65
66
  maxUsers: z.ZodOptional<z.ZodNumber>;
@@ -73,6 +74,27 @@ export interface LicenseCacheConfig {
73
74
  /** Cache TTL in milliseconds (default: 15 seconds) */
74
75
  ttlMs: number;
75
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;
76
98
  /**
77
99
  * Configure the license cache TTL.
78
100
  * Useful for tests (short TTL) or deployments needing faster revocation detection.
@@ -88,8 +110,19 @@ export declare function computeKeyId(publicKeyPem: string): Promise<string>;
88
110
  /**
89
111
  * Validates a license key JWT and returns the decoded payload.
90
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.
91
124
  */
92
- 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>;
93
126
  /**
94
127
  * Initialize the license system. Call once at application startup.
95
128
  * Reads REVEALUI_LICENSE_KEY and REVEALUI_LICENSE_PUBLIC_KEY from environment.
@@ -146,14 +179,16 @@ export declare function getMaxAgentTasks(): number;
146
179
  * `jose.importPKCS8` and `SignJWT` both run on Web Crypto.
147
180
  *
148
181
  * @param payload - License payload (tier, customerId, limits, perpetual flag)
149
- * @param privateKey - RS256 private key (PEM format)
182
+ * @param privateKey - Ed25519 private key (PEM format)
150
183
  * @param expiresInSeconds - JWT expiration in seconds. Pass null for perpetual
151
184
  * licenses (no exp claim). Defaults to 1 year for subscription licenses.
152
- * @param publicKey - RS256 public key (PEM format). When provided, a `kid`
185
+ * @param publicKey - Ed25519 public key (PEM format). When provided, a `kid`
153
186
  * claim is added to the JWT header for forward-compatible key rotation.
154
187
  * @returns Signed JWT string
155
188
  */
156
- export declare function generateLicenseKey(payload: Omit<LicensePayload, 'iat' | 'exp'>, privateKey: string, expiresInSeconds?: number | null, publicKey?: string): Promise<string>;
189
+ export declare function generateLicenseKey(payload: Omit<LicensePayload, 'iat' | 'exp' | 'jti'> & {
190
+ jti?: string;
191
+ }, privateKey: string, expiresInSeconds?: number | null, publicKey?: string): Promise<string>;
157
192
  /**
158
193
  * Reset license state. Primarily for testing.
159
194
  */
@@ -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
@@ -9,10 +9,16 @@
9
9
  * - jose - JWT signing/verification (Web Crypto API)
10
10
  * - zod - Schema validation for license payloads
11
11
  */
12
- import { decodeProtectedHeader, importPKCS8, importSPKI, jwtVerify, SignJWT } from 'jose';
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.
13
16
  import { z } from 'zod';
14
17
  import { decryptLicenseKey } from './license-encryption.js';
15
18
  import { logger } from './utils/logger.js';
19
+ async function getJose() {
20
+ return await import('jose');
21
+ }
16
22
  /** JWT issuer and audience for license tokens — prevents cross-environment replay */
17
23
  const LICENSE_ISSUER = process.env.REVEALUI_LICENSE_ISSUER ?? 'https://revealui.com';
18
24
  const LICENSE_AUDIENCE = process.env.REVEALUI_LICENSE_AUDIENCE ?? 'revealui-license';
@@ -41,8 +47,10 @@ export function configureGracePeriods(overrides) {
41
47
  const licensePayloadSchema = z.object({
42
48
  /** License tier */
43
49
  tier: z.enum(['pro', 'max', 'enterprise']),
44
- /** Organization or customer ID */
45
- 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),
46
54
  /** Licensed domain(s) */
47
55
  domains: z.array(z.string()).optional(),
48
56
  /** Maximum number of sites allowed */
@@ -61,16 +69,40 @@ const licensePayloadSchema = z.object({
61
69
  exp: z.number().optional(),
62
70
  });
63
71
  const DEFAULT_TTL_MS = 15_000; // 15 seconds - revoked licenses lose access quickly
64
- const DEFAULT_CACHE_CONFIG = {
65
- ttlMs: (() => {
66
- const envTtl = process.env.LICENSE_CACHE_TTL_MS;
67
- if (envTtl) {
68
- const parsed = Number.parseInt(envTtl, 10);
69
- if (Number.isFinite(parsed) && parsed > 0)
70
- return parsed;
71
- }
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)
72
97
  return DEFAULT_TTL_MS;
73
- })(),
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),
74
106
  };
75
107
  let cacheConfig = { ...DEFAULT_CACHE_CONFIG };
76
108
  let cachedAt = 0;
@@ -126,21 +158,33 @@ export async function computeKeyId(publicKeyPem) {
126
158
  /**
127
159
  * Validates a license key JWT and returns the decoded payload.
128
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.
129
172
  */
130
- export async function validateLicenseKey(licenseKey, publicKey) {
173
+ export async function validateLicenseKey(licenseKey, publicKey, expectedCustomerId) {
131
174
  try {
175
+ const jose = await getJose();
132
176
  // Extract kid from JWT header for forward-compatible key rotation
133
- const header = decodeProtectedHeader(licenseKey);
177
+ const header = jose.decodeProtectedHeader(licenseKey);
134
178
  const expectedKid = await computeKeyId(publicKey);
135
179
  if (header.kid && header.kid !== expectedKid) {
136
180
  logger.warn(`JWT kid mismatch: token has "${header.kid}", current key is "${expectedKid}". ` +
137
181
  'Token may have been signed with a rotated key.');
138
182
  }
139
- const key = await importSPKI(publicKey, 'RS256');
183
+ const key = await jose.importSPKI(publicKey, 'EdDSA');
140
184
  // Accept tokens expired within the subscription grace window so the
141
185
  // payload is available for grace-period calculations in isLicensed().
142
- const { payload } = await jwtVerify(licenseKey, key, {
143
- algorithms: ['RS256'],
186
+ const { payload } = await jose.jwtVerify(licenseKey, key, {
187
+ algorithms: ['EdDSA'],
144
188
  clockTolerance: graceConfig.subscriptionDays * 86_400,
145
189
  issuer: LICENSE_ISSUER,
146
190
  audience: LICENSE_AUDIENCE,
@@ -149,6 +193,16 @@ export async function validateLicenseKey(licenseKey, publicKey) {
149
193
  if (!result.success) {
150
194
  return null;
151
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
+ }
152
206
  return result.data;
153
207
  }
154
208
  catch {
@@ -380,23 +434,35 @@ export function getMaxAgentTasks() {
380
434
  * `jose.importPKCS8` and `SignJWT` both run on Web Crypto.
381
435
  *
382
436
  * @param payload - License payload (tier, customerId, limits, perpetual flag)
383
- * @param privateKey - RS256 private key (PEM format)
437
+ * @param privateKey - Ed25519 private key (PEM format)
384
438
  * @param expiresInSeconds - JWT expiration in seconds. Pass null for perpetual
385
439
  * licenses (no exp claim). Defaults to 1 year for subscription licenses.
386
- * @param publicKey - RS256 public key (PEM format). When provided, a `kid`
440
+ * @param publicKey - Ed25519 public key (PEM format). When provided, a `kid`
387
441
  * claim is added to the JWT header for forward-compatible key rotation.
388
442
  * @returns Signed JWT string
389
443
  */
390
444
  export async function generateLicenseKey(payload, privateKey, expiresInSeconds = 365 * 24 * 60 * 60, publicKey) {
391
- const key = await importPKCS8(privateKey, 'RS256');
445
+ const jose = await getJose();
446
+ const key = await jose.importPKCS8(privateKey, 'EdDSA');
392
447
  const kid = publicKey ? await computeKeyId(publicKey) : undefined;
393
- const header = { alg: 'RS256' };
448
+ const header = { alg: 'EdDSA' };
394
449
  if (kid) {
395
450
  header.kid = kid;
396
451
  }
397
- const builder = new SignJWT({ ...payload })
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 })
398
460
  .setProtectedHeader(header)
399
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)
400
466
  .setIssuer(LICENSE_ISSUER)
401
467
  .setAudience(LICENSE_AUDIENCE);
402
468
  if (expiresInSeconds !== null) {
@@ -162,6 +162,9 @@ export declare const appMetrics: {
162
162
  memoryUsage: Gauge;
163
163
  apiCallsTotal: Counter;
164
164
  apiCallDuration: Histogram;
165
+ x402PaymentRequiredTotal: Counter;
166
+ x402PaymentVerifyTotal: Counter;
167
+ x402PaymentVerifyDuration: Histogram;
165
168
  };
166
169
  /**
167
170
  * Track HTTP request
@@ -183,6 +186,18 @@ export declare function trackError(type: string, severity?: 'low' | 'medium' | '
183
186
  * Update active connections
184
187
  */
185
188
  export declare function updateActiveConnections(type: string, delta: number): void;
189
+ /**
190
+ * Track an x402 HTTP 402 emission at a route. Call when the route returns
191
+ * 402 with `X-PAYMENT-REQUIRED`. `currency` is always `'usdc-only'` — USDC on
192
+ * Base is the sole settlement currency.
193
+ */
194
+ export declare function trackX402PaymentRequired(route: string, currency: 'usdc-only'): void;
195
+ /**
196
+ * Track an x402 payment verification. Increments the result counter and
197
+ * observes the duration histogram (latency = Coinbase facilitator round-trip
198
+ * for USDC).
199
+ */
200
+ export declare function trackX402PaymentVerify(route: string, scheme: 'exact', result: 'valid' | 'invalid', durationMs: number): void;
186
201
  /**
187
202
  * Update memory usage
188
203
  */
@@ -1 +1 @@
1
- {"version":3,"file":"metrics.d.ts","sourceRoot":"","sources":["../../src/observability/metrics.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"metrics.d.ts","sourceRoot":"","sources":["../../src/observability/metrics.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,MAAM,UAAU,GAAG,SAAS,GAAG,OAAO,GAAG,WAAW,GAAG,SAAS,CAAC;AAEvE,MAAM,WAAW,YAAY;IAC3B,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;CAChC;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,YAAY,CAAC;CACvB;AAED,MAAM,WAAW,MAAM;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,UAAU,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,eAAgB,SAAQ,MAAM;IAC7C,IAAI,EAAE,WAAW,CAAC;IAClB,OAAO,EAAE,eAAe,EAAE,CAAC;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;CACf;AAED,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,OAAO,CAAkC;IAEjD;;OAEG;IACH,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,EAAE,GAAG,OAAO;IAc/D;;OAEG;IACH,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,EAAE,GAAG,KAAK;IAc3D;;OAEG;IACH,SAAS,CACP,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,MAAM,EAA8D,EAC7E,MAAM,CAAC,EAAE,MAAM,EAAE,GAChB,SAAS;IAiBZ;;OAEG;IACH,UAAU,IAAI,MAAM,EAAE;IAItB;;OAEG;IACH,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAI3C;;OAEG;IACH,KAAK,IAAI,IAAI;IAIb;;OAEG;IACH,gBAAgB,IAAI,MAAM;IA0C1B;;OAEG;IACH,UAAU,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;CAsBtC;AAED;;GAEG;AACH,qBAAa,OAAO;IACN,OAAO,CAAC,MAAM;gBAAN,MAAM,EAAE,MAAM;IAElC;;OAEG;IACH,GAAG,CAAC,KAAK,GAAE,MAAU,EAAE,MAAM,CAAC,EAAE,YAAY,GAAG,IAAI;IAenD;;OAEG;IACH,GAAG,CAAC,MAAM,CAAC,EAAE,YAAY,GAAG,MAAM;IAKlC;;OAEG;IACH,OAAO,CAAC,SAAS;IAIjB;;OAEG;IACH,OAAO,CAAC,WAAW;CAWpB;AAED;;GAEG;AACH,qBAAa,KAAK;IACJ,OAAO,CAAC,MAAM;gBAAN,MAAM,EAAE,MAAM;IAElC;;OAEG;IACH,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,YAAY,GAAG,IAAI;IAe/C;;OAEG;IACH,GAAG,CAAC,KAAK,GAAE,MAAU,EAAE,MAAM,CAAC,EAAE,YAAY,GAAG,IAAI;IAenD;;OAEG;IACH,GAAG,CAAC,KAAK,GAAE,MAAU,EAAE,MAAM,CAAC,EAAE,YAAY,GAAG,IAAI;IAInD;;OAEG;IACH,GAAG,CAAC,MAAM,CAAC,EAAE,YAAY,GAAG,MAAM;IAKlC;;OAEG;IACH,OAAO,CAAC,SAAS;IAIjB;;OAEG;IACH,OAAO,CAAC,WAAW;CAWpB;AAED;;GAEG;AACH,qBAAa,SAAS;IACR,OAAO,CAAC,MAAM;gBAAN,MAAM,EAAE,eAAe;IAE3C;;OAEG;IACH,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,YAAY,GAAG,IAAI;IAoBnD;;OAEG;IACH,UAAU,CAAC,MAAM,CAAC,EAAE,YAAY,GAAG,MAAM,IAAI;IAS7C;;OAEG;IACH,UAAU,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM;IAS7B;;OAEG;IACH,OAAO,IAAI,MAAM;CAIlB;AAED;;GAEG;AACH,eAAO,MAAM,OAAO,kBAAyB,CAAC;AAE9C;;GAEG;AACH,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;CAwFtB,CAAC;AAEF;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,GACf,IAAI,CAGN;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAGrF;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,SAAS,EAAE,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,QAAQ,EAC5C,MAAM,GAAE,SAAS,GAAG,OAAmB,GACtC,IAAI,CAEN;AAED;;GAEG;AACH,wBAAgB,UAAU,CACxB,IAAI,EAAE,MAAM,EACZ,QAAQ,GAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,UAAqB,GAC1D,IAAI,CAEN;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAEzE;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,WAAW,GAAG,IAAI,CAEnF;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,OAAO,EACf,MAAM,EAAE,OAAO,GAAG,SAAS,EAC3B,UAAU,EAAE,MAAM,GACjB,IAAI,CAGN;AAED;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,IAAI,CAQxC;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,UAAU,GAAE,MAAc,GAAG,MAAM,CAAC,OAAO,CAEhF;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,QAAQ,GAAG,OAAO,EAAE,SAAS,GAAG,OAAO,MAE3E,SAAS,QAAQ,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,EACnD,MAAM,MAAM,OAAO,CAAC,SAAS,GAAG;IAAE,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,KACnD,OAAO,CAAC,SAAS,GAAG;IAAE,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAqB5C"}
@@ -355,6 +355,10 @@ export const appMetrics = {
355
355
  'status',
356
356
  ]),
357
357
  apiCallDuration: metrics.histogram('api_call_duration_seconds', 'External API call duration', [0.1, 0.5, 1, 2, 5, 10], ['service']),
358
+ // x402 micropayments (GAP-149 PR 5)
359
+ x402PaymentRequiredTotal: metrics.counter('x402_payment_required_total', 'HTTP 402 Payment Required responses emitted by route + currency advertised', ['route', 'currency']),
360
+ x402PaymentVerifyTotal: metrics.counter('x402_payment_verify_total', 'x402 payment verification attempts by route, scheme, and result', ['route', 'scheme', 'result']),
361
+ x402PaymentVerifyDuration: metrics.histogram('x402_payment_verify_duration_seconds', 'x402 payment verification latency (Coinbase facilitator round-trip for USDC)', [0.05, 0.1, 0.5, 1, 5, 10, 30], ['scheme']),
358
362
  };
359
363
  /**
360
364
  * Track HTTP request
@@ -388,6 +392,23 @@ export function trackError(type, severity = 'medium') {
388
392
  export function updateActiveConnections(type, delta) {
389
393
  appMetrics.activeConnections.inc(delta, { type });
390
394
  }
395
+ /**
396
+ * Track an x402 HTTP 402 emission at a route. Call when the route returns
397
+ * 402 with `X-PAYMENT-REQUIRED`. `currency` is always `'usdc-only'` — USDC on
398
+ * Base is the sole settlement currency.
399
+ */
400
+ export function trackX402PaymentRequired(route, currency) {
401
+ appMetrics.x402PaymentRequiredTotal.inc(1, { route, currency });
402
+ }
403
+ /**
404
+ * Track an x402 payment verification. Increments the result counter and
405
+ * observes the duration histogram (latency = Coinbase facilitator round-trip
406
+ * for USDC).
407
+ */
408
+ export function trackX402PaymentVerify(route, scheme, result, durationMs) {
409
+ appMetrics.x402PaymentVerifyTotal.inc(1, { route, scheme, result });
410
+ appMetrics.x402PaymentVerifyDuration.observe(durationMs / 1000, { scheme });
411
+ }
391
412
  /**
392
413
  * Update memory usage
393
414
  */
@@ -0,0 +1,60 @@
1
+ /**
2
+ * RevForge per-customer license issuance.
3
+ *
4
+ * The Stripe webhook handler (apps/server/src/routes/webhooks.ts) issues licenses
5
+ * for SaaS subscribers. This module is the analogous issuer for self-hosted
6
+ * RevForge customers — paid direct (source-license / sales) and stamped via
7
+ * forge/stamp.sh.
8
+ *
9
+ * Pure function: takes options + Ed25519 keys, returns a signed JWT plus
10
+ * descriptive metadata. The CLI wrapper (scripts/setup/issue-revforge-license.ts)
11
+ * handles argv parsing and reading keys from the environment.
12
+ */
13
+ import { type LicensePayload } from './license.js';
14
+ export declare const SLUG_PATTERN: RegExp;
15
+ export declare const VALID_REVFORGE_TIERS: readonly ["pro", "max", "enterprise"];
16
+ export type RevForgeTier = (typeof VALID_REVFORGE_TIERS)[number];
17
+ export interface IssueRevForgeLicenseOptions {
18
+ /** Customer slug; becomes the JWT customerId. Must match SLUG_PATTERN. */
19
+ slug: string;
20
+ /** Paid tier the license unlocks. */
21
+ tier: RevForgeTier;
22
+ /** JWT expiry in days. Omit for the 365-day default. Mutually exclusive with `perpetual`. */
23
+ expiresInDays?: number;
24
+ /** One-time purchase: omit `exp` claim entirely. Mutually exclusive with `expiresInDays`. */
25
+ perpetual?: boolean;
26
+ /** Override per-tier site cap. */
27
+ maxSites?: number;
28
+ /** Override per-tier user cap. */
29
+ maxUsers?: number;
30
+ /** Allowed deployment hostnames. */
31
+ domains?: string[];
32
+ }
33
+ export interface IssueRevForgeLicenseResult {
34
+ /** Signed EdDSA JWT — the license key the customer installs. */
35
+ licenseKey: string;
36
+ /** Customer identifier embedded in the JWT (the slug). */
37
+ customerId: string;
38
+ /** Tier embedded in the JWT. */
39
+ tier: RevForgeTier;
40
+ /** Whether this is a perpetual license (no exp claim). */
41
+ perpetual: boolean;
42
+ /** ISO-8601 timestamp of issuance. */
43
+ issuedAt: string;
44
+ /** ISO-8601 expiry, or null for perpetual licenses. */
45
+ expiresAt: string | null;
46
+ /** The payload that was signed (without iat/exp/jti; those live inside the JWT). */
47
+ payload: Omit<LicensePayload, 'iat' | 'exp' | 'jti'>;
48
+ }
49
+ /**
50
+ * Issue a signed RevForge license JWT for a paying customer.
51
+ *
52
+ * @throws Error on invalid slug, invalid tier, mutually-exclusive flag combos,
53
+ * or non-positive numeric overrides. The error message names the offending
54
+ * field so callers can surface it directly to the operator.
55
+ */
56
+ export declare function issueRevForgeLicense(opts: IssueRevForgeLicenseOptions, keys: {
57
+ privateKey: string;
58
+ publicKey: string;
59
+ }): Promise<IssueRevForgeLicenseResult>;
60
+ //# sourceMappingURL=revforge-license.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"revforge-license.d.ts","sourceRoot":"","sources":["../src/revforge-license.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAsB,KAAK,cAAc,EAAE,MAAM,cAAc,CAAC;AAEvE,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;;;;;;GAMG;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,CAoErC"}
@@ -0,0 +1,74 @@
1
+ /**
2
+ * RevForge per-customer license issuance.
3
+ *
4
+ * The Stripe webhook handler (apps/server/src/routes/webhooks.ts) issues licenses
5
+ * for SaaS subscribers. This module is the analogous issuer for self-hosted
6
+ * RevForge customers — paid direct (source-license / sales) and stamped via
7
+ * forge/stamp.sh.
8
+ *
9
+ * Pure function: takes options + Ed25519 keys, returns a signed JWT plus
10
+ * descriptive metadata. The CLI wrapper (scripts/setup/issue-revforge-license.ts)
11
+ * handles argv parsing and reading keys from the environment.
12
+ */
13
+ import { generateLicenseKey } from './license.js';
14
+ export const SLUG_PATTERN = /^[a-z0-9][a-z0-9-]*$/;
15
+ export const VALID_REVFORGE_TIERS = ['pro', 'max', 'enterprise'];
16
+ /**
17
+ * Issue a signed RevForge license JWT for a paying customer.
18
+ *
19
+ * @throws Error on invalid slug, invalid tier, mutually-exclusive flag combos,
20
+ * or non-positive numeric overrides. The error message names the offending
21
+ * field so callers can surface it directly to the operator.
22
+ */
23
+ export async function issueRevForgeLicense(opts, keys) {
24
+ if (!SLUG_PATTERN.test(opts.slug)) {
25
+ throw new Error(`Invalid --slug "${opts.slug}": must match ^[a-z0-9][a-z0-9-]*$ (kebab-case, start with letter or digit).`);
26
+ }
27
+ if (!VALID_REVFORGE_TIERS.includes(opts.tier)) {
28
+ throw new Error(`Invalid --tier "${opts.tier}": must be one of ${VALID_REVFORGE_TIERS.join(', ')}.`);
29
+ }
30
+ if (opts.perpetual && opts.expiresInDays !== undefined) {
31
+ throw new Error('--perpetual and --expires-in-days are mutually exclusive.');
32
+ }
33
+ if (opts.expiresInDays !== undefined) {
34
+ if (!Number.isInteger(opts.expiresInDays) || opts.expiresInDays <= 0) {
35
+ throw new Error(`Invalid --expires-in-days "${opts.expiresInDays}": must be a positive integer.`);
36
+ }
37
+ }
38
+ if (opts.maxSites !== undefined && (!Number.isInteger(opts.maxSites) || opts.maxSites <= 0)) {
39
+ throw new Error(`Invalid --max-sites "${opts.maxSites}": must be a positive integer.`);
40
+ }
41
+ if (opts.maxUsers !== undefined && (!Number.isInteger(opts.maxUsers) || opts.maxUsers <= 0)) {
42
+ throw new Error(`Invalid --max-users "${opts.maxUsers}": must be a positive integer.`);
43
+ }
44
+ // jti is auto-generated inside generateLicenseKey when not supplied (per
45
+ // Phase 1 audit B-2 — every issued token carries a unique JWT ID for
46
+ // forward-compatible per-token revocation).
47
+ const payload = {
48
+ tier: opts.tier,
49
+ customerId: opts.slug,
50
+ ...(opts.perpetual ? { perpetual: true } : {}),
51
+ ...(opts.maxSites !== undefined ? { maxSites: opts.maxSites } : {}),
52
+ ...(opts.maxUsers !== undefined ? { maxUsers: opts.maxUsers } : {}),
53
+ ...(opts.domains && opts.domains.length > 0 ? { domains: opts.domains } : {}),
54
+ };
55
+ // Perpetual: pass null to omit exp claim. Otherwise translate days → seconds.
56
+ // Default (neither flag): 365-day subscription, matching generateLicenseKey's default.
57
+ const expiresInSeconds = opts.perpetual
58
+ ? null
59
+ : opts.expiresInDays !== undefined
60
+ ? opts.expiresInDays * 24 * 60 * 60
61
+ : 365 * 24 * 60 * 60;
62
+ const issuedAtMs = Date.now();
63
+ const licenseKey = await generateLicenseKey(payload, keys.privateKey, expiresInSeconds, keys.publicKey);
64
+ const expiresAt = expiresInSeconds === null ? null : new Date(issuedAtMs + expiresInSeconds * 1000).toISOString();
65
+ return {
66
+ licenseKey,
67
+ customerId: opts.slug,
68
+ tier: opts.tier,
69
+ perpetual: opts.perpetual === true,
70
+ issuedAt: new Date(issuedAtMs).toISOString(),
71
+ expiresAt,
72
+ payload,
73
+ };
74
+ }
@@ -4,7 +4,7 @@
4
4
  * Provides server-side rendering components for Lexical content.
5
5
  * Converts Lexical JSON state to React elements without requiring a browser.
6
6
  */
7
- import { isSafeUrl, sanitizeUrl } from '@revealui/security';
7
+ import { isSafeUrl, sanitizeUrl } from '@revealui/security/sanitize';
8
8
  import type { SerializedEditorState, SerializedLexicalNode } from 'lexical';
9
9
  import { type JSX } from 'react';
10
10
  export type { SerializedEditorState };
@@ -1 +1 @@
1
- {"version":3,"file":"rsc.d.ts","sourceRoot":"","sources":["../../../../src/richtext/exports/server/rsc.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"rsc.d.ts","sourceRoot":"","sources":["../../../../src/richtext/exports/server/rsc.tsx"],"names":[],"mappings":"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"}
@@ -5,10 +5,15 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
5
5
  * Provides server-side rendering components for Lexical content.
6
6
  * Converts Lexical JSON state to React elements without requiring a browser.
7
7
  */
8
- import { isSafeUrl, sanitizeUrl } from '@revealui/security';
8
+ // Import from the client-safe ./sanitize subpath, NOT the @revealui/security
9
+ // barrel: the barrel statically re-exports auth.ts/gdpr.ts, whose top-level
10
+ // `import 'node:crypto'` crashes this module's client/RSC bundle (blank render
11
+ // on routes that load rich text, e.g. marketing /blog). ./sanitize imports only
12
+ // parse5 and is browser-safe.
13
+ import { isSafeUrl, sanitizeUrl } from '@revealui/security/sanitize';
9
14
  import { Fragment } from 'react';
10
15
  // URL sanitization is owned by @revealui/security (single source of truth
11
- // for every untrusted-string sink across the Suite). Re-exported here so
16
+ // for every untrusted-string sink across RevFleet). Re-exported here so
12
17
  // existing consumers keep working.
13
18
  export { isSafeUrl, sanitizeUrl };
14
19
  // ============================================
@@ -1,6 +1,13 @@
1
1
  /**
2
- * Security & Compliance - re-exported from @revealui/security
3
- * New code should import directly from '@revealui/security'.
2
+ * Security & Compliance - full server-side surface.
3
+ *
4
+ * Re-exports the client-safe `@revealui/security` barrel AND the server-only
5
+ * `@revealui/security/server` entry (auth/gdpr/audit/ssrf — node: built-ins),
6
+ * so server code can pull any security symbol from one place. Because it
7
+ * re-exports `./server`, THIS entry is server-only: do not import
8
+ * `@revealui/core/security` from client/RSC code (use `@revealui/security` or
9
+ * `@revealui/security/sanitize` there).
4
10
  */
5
11
  export * from '@revealui/security';
12
+ export * from '@revealui/security/server';
6
13
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/security/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,cAAc,oBAAoB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/security/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,cAAc,oBAAoB,CAAC;AACnC,cAAc,2BAA2B,CAAC"}
@@ -1,5 +1,12 @@
1
1
  /**
2
- * Security & Compliance - re-exported from @revealui/security
3
- * New code should import directly from '@revealui/security'.
2
+ * Security & Compliance - full server-side surface.
3
+ *
4
+ * Re-exports the client-safe `@revealui/security` barrel AND the server-only
5
+ * `@revealui/security/server` entry (auth/gdpr/audit/ssrf — node: built-ins),
6
+ * so server code can pull any security symbol from one place. Because it
7
+ * re-exports `./server`, THIS entry is server-only: do not import
8
+ * `@revealui/core/security` from client/RSC code (use `@revealui/security` or
9
+ * `@revealui/security/sanitize` there).
4
10
  */
5
11
  export * from '@revealui/security';
12
+ export * from '@revealui/security/server';
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Internal helpers shared across storage providers.
3
+ *
4
+ * Underscore prefix denotes private-to-storage/; not re-exported from
5
+ * packages/core/src/storage/index.ts.
6
+ *
7
+ * GAP-208 Phase 2a (2026-05-18).
8
+ */
9
+ /**
10
+ * Normalize the four accepted body types into a Uint8Array so providers
11
+ * can compute size + hand a known buffer to their underlying SDKs.
12
+ */
13
+ export declare function toUint8Array(data: Blob | ArrayBuffer | Uint8Array | ReadableStream<Uint8Array>): Promise<Uint8Array>;
14
+ //# sourceMappingURL=_helpers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"_helpers.d.ts","sourceRoot":"","sources":["../../src/storage/_helpers.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH;;;GAGG;AACH,wBAAsB,YAAY,CAChC,IAAI,EAAE,IAAI,GAAG,WAAW,GAAG,UAAU,GAAG,cAAc,CAAC,UAAU,CAAC,GACjE,OAAO,CAAC,UAAU,CAAC,CA0BrB"}
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Internal helpers shared across storage providers.
3
+ *
4
+ * Underscore prefix denotes private-to-storage/; not re-exported from
5
+ * packages/core/src/storage/index.ts.
6
+ *
7
+ * GAP-208 Phase 2a (2026-05-18).
8
+ */
9
+ /**
10
+ * Normalize the four accepted body types into a Uint8Array so providers
11
+ * can compute size + hand a known buffer to their underlying SDKs.
12
+ */
13
+ export async function toUint8Array(data) {
14
+ if (data instanceof Uint8Array) {
15
+ return data;
16
+ }
17
+ if (data instanceof ArrayBuffer) {
18
+ return new Uint8Array(data);
19
+ }
20
+ if (data instanceof Blob) {
21
+ return new Uint8Array(await data.arrayBuffer());
22
+ }
23
+ const reader = data.getReader();
24
+ const chunks = [];
25
+ let total = 0;
26
+ while (true) {
27
+ const { done, value } = await reader.read();
28
+ if (done)
29
+ break;
30
+ chunks.push(value);
31
+ total += value.byteLength;
32
+ }
33
+ const merged = new Uint8Array(total);
34
+ let offset = 0;
35
+ for (const chunk of chunks) {
36
+ merged.set(chunk, offset);
37
+ offset += chunk.byteLength;
38
+ }
39
+ return merged;
40
+ }