@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/README.md CHANGED
@@ -17,7 +17,7 @@ Part of the [RevealUI monorepo](https://github.com/RevealUIStudio/revealui) -
17
17
  - **GDPR Compliance** - Consent management, data export, deletion, anonymization, breach reporting
18
18
  - **Observability** - Structured logging, process health monitoring, alert system, graceful shutdown
19
19
  - **Plugins** - Extensible plugin system (form builder, nested docs, redirects)
20
- - **Feature Gating** - Tier-based licensing (free, pro, max, enterprise/Forge) with JWT license keys
20
+ - **Feature Gating** - Tier-based licensing (free, pro, max, enterprise) with JWT license keys
21
21
  - **Database** - PostgreSQL adapters (NeonDB + PGlite for testing), connection pooling, SSL/TLS
22
22
  - **Storage** - Pluggable storage interface (Vercel Blob adapter included)
23
23
 
@@ -159,7 +159,7 @@ pnpm dev
159
159
  - **Not** for standalone UI components - use `@revealui/presentation`
160
160
  - **Not** for raw database queries - use `@revealui/db` directly
161
161
 
162
- ## JOSHUA Alignment
162
+ ## Design Principles
163
163
 
164
164
  - **Sovereign**: Self-hosted runtime engine - no vendor dependency for content management, auth, or storage
165
165
  - **Unified**: One `buildConfig()` call wires collections, globals, plugins, security, and feature gates into a single configuration
@@ -1 +1 @@
1
- {"version":3,"file":"rate-limit.d.ts","sourceRoot":"","sources":["../../src/api/rate-limit.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"rate-limit.d.ts","sourceRoot":"","sources":["../../src/api/rate-limit.ts"],"names":[],"mappings":"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"}
@@ -3,28 +3,22 @@
3
3
  *
4
4
  * Implements rate limiting to prevent API abuse
5
5
  */
6
+ import { getClientIp } from '@revealui/security';
6
7
  import { logger } from '../observability/logger.js';
7
8
  // WARNING: In-memory store - resets on every serverless cold start or process restart.
8
- // This module is NOT used by any app in production (API uses apps/api/src/middleware/rate-limit.ts,
9
+ // This module is NOT used by any app in production (API uses apps/server/src/middleware/rate-limit.ts,
9
10
  // admin uses @revealui/auth/server which is DB-backed). Exported for framework consumers only.
10
11
  // Replace with a database-backed store before using in production.
11
12
  const rateLimitStore = new Map();
12
13
  /**
13
- * Default key generator (by IP address)
14
+ * Default key generator (by IP address).
15
+ *
16
+ * Delegates to `@revealui/security`'s trusted-proxy-aware
17
+ * `getClientIp` so the IP cannot be spoofed via X-Forwarded-For
18
+ * on deployments that configure their proxy trust correctly.
14
19
  */
15
20
  function defaultKeyGenerator(request) {
16
- // Try to get real IP from headers
17
- const forwarded = request.headers.get('x-forwarded-for');
18
- const realIp = request.headers.get('x-real-ip');
19
- if (forwarded) {
20
- const parts = forwarded.split(',');
21
- return parts[0]?.trim() || 'unknown';
22
- }
23
- if (realIp) {
24
- return realIp;
25
- }
26
- // Fallback to unknown (Request doesn't have ip property)
27
- return 'unknown';
21
+ return getClientIp(request);
28
22
  }
29
23
  /**
30
24
  * Check if rate limit exceeded
@@ -1 +1 @@
1
- {"version":3,"file":"apiClient.d.ts","sourceRoot":"","sources":["../../../../src/client/admin/utils/apiClient.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"apiClient.d.ts","sourceRoot":"","sources":["../../../../src/client/admin/utils/apiClient.ts"],"names":[],"mappings":"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"}
@@ -63,8 +63,23 @@ export class APIClient {
63
63
  * Make an authenticated API request
64
64
  */
65
65
  async request(endpoint, options = {}) {
66
+ const Unsafe = new Set(['POST', 'PUT', 'PATCH', 'DELETE']);
67
+ const method = (options.method ?? 'GET').toUpperCase();
68
+ let csrfToken;
69
+ if (Unsafe.has(method) && typeof document !== 'undefined') {
70
+ for (const part of document.cookie.split(';')) {
71
+ const eqIdx = part.indexOf('=');
72
+ if (eqIdx === -1)
73
+ continue;
74
+ if (part.slice(0, eqIdx).trim() === 'revealui-csrf') {
75
+ csrfToken = part.slice(eqIdx + 1).trim() || undefined;
76
+ break;
77
+ }
78
+ }
79
+ }
66
80
  const headers = {
67
81
  'Content-Type': 'application/json',
82
+ ...(csrfToken ? { 'X-CSRF-Token': csrfToken } : {}),
68
83
  ...options.headers,
69
84
  };
70
85
  const url = `${this.baseURL}${endpoint}`;
@@ -72,7 +87,7 @@ export class APIClient {
72
87
  const response = await fetch(url, {
73
88
  ...options,
74
89
  headers,
75
- credentials: 'include', // Include cookies for authentication
90
+ credentials: 'include',
76
91
  });
77
92
  // Handle authentication errors
78
93
  if (response.status === 401) {
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/client/richtext/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/client/richtext/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,EAAE,iBAAiB,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAC5D,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACvD,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAEvD,OAAO,EAAE,eAAe,EAAE,MAAM,uCAAuC,CAAC;AACxE,OAAO,EAAE,eAAe,EAAE,MAAM,uCAAuC,CAAC;AACxE,OAAO,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AACjE,OAAO,EAAE,yBAAyB,EAAE,MAAM,uCAAuC,CAAC;AAClF,OAAO,EAAE,eAAe,EAAE,MAAM,uCAAuC,CAAC;AACxE,OAAO,EAAE,oBAAoB,EAAE,MAAM,qCAAqC,CAAC;AAC3E,OAAO,EAAE,aAAa,EAAE,MAAM,qCAAqC,CAAC;AACpE,OAAO,EAAE,UAAU,EAAE,MAAM,kCAAkC,CAAC;AAC9D,OAAO,EAAE,UAAU,EAAE,MAAM,kCAAkC,CAAC;AAC9D,OAAO,EAAE,cAAc,EAAE,MAAM,sCAAsC,CAAC;AACtE,OAAO,EAAE,cAAc,EAAE,MAAM,sCAAsC,CAAC;AAEtE,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAE5D,OAAO,EAAE,wBAAwB,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AACzE,OAAO,EAAE,kBAAkB,EAAE,MAAM,oCAAoC,CAAC;AACxE,OAAO,EAAE,iBAAiB,EAAE,MAAM,mCAAmC,CAAC;AACtE,YAAY,EAAE,aAAa,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAE/E,OAAO,EACL,gBAAgB,EAChB,YAAY,EACZ,SAAS,EACT,oBAAoB,EACpB,yBAAyB,GAC1B,MAAM,sBAAsB,CAAC;AAC9B,YAAY,EAAE,wBAAwB,EAAE,MAAM,kCAAkC,CAAC;AACjF,OAAO,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AACvE,YAAY,EAAE,0BAA0B,EAAE,MAAM,oCAAoC,CAAC;AACrF,OAAO,EAAE,qBAAqB,EAAE,MAAM,oCAAoC,CAAC;AAC3E,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,YAAY,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAErE,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAC3D,YAAY,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAC/D,OAAO,EAAE,cAAc,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAI3E,eAAO,MAAM,iBAAiB,YAAa,CAAC;AAC5C,eAAO,MAAM,mBAAmB,YAAa,CAAC;AAC9C,eAAO,MAAM,sBAAsB,YAAa,CAAC;AACjD,eAAO,MAAM,0BAA0B,YAAa,CAAC;AACrD,eAAO,MAAM,sBAAsB,YAAa,CAAC;AACjD,eAAO,MAAM,wBAAwB,YAAa,CAAC;AACnD,eAAO,MAAM,uBAAuB,YAAa,CAAC;AAElD,eAAO,MAAM,oBAAoB,YAAa,CAAC;AAC/C,eAAO,MAAM,sBAAsB,YAAa,CAAC;AACjD,eAAO,MAAM,kBAAkB,YAAa,CAAC;AAC7C,eAAO,MAAM,mBAAmB,YAAa,CAAC;AAE9C,eAAO,MAAM,0BAA0B,YAAa,CAAC;AACrD,eAAO,MAAM,wBAAwB,YAAa,CAAC;AACnD,eAAO,MAAM,sBAAsB,YAAa,CAAC;AAEjD,eAAO,MAAM,iBAAiB,YAAa,CAAC;AAC5C,eAAO,MAAM,yBAAyB,YAAa,CAAC;AACpD,eAAO,MAAM,uBAAuB,YAAa,CAAC;AAClD,eAAO,MAAM,mBAAmB,YAAa,CAAC;AAC9C,eAAO,MAAM,2BAA2B,YAAa,CAAC;AAEtD,eAAO,MAAM,0BAA0B,YAAa,CAAC;AACrD,eAAO,MAAM,yBAAyB,YAAa,CAAC;AACpD,eAAO,MAAM,qBAAqB,YAAa,CAAC;AAChD,eAAO,MAAM,mBAAmB,YAAa,CAAC;AAG9C,eAAO,MAAM,4BAA4B,GAAI,OAAO,OAAO,EAAE;;CAAgB,CAAC;AAC9E,eAAO,MAAM,gCAAgC,GAAI,OAAO,OAAO,EAAE;;CAE/D,CAAC;AAGH,MAAM,WAAW,mBAAmB;IAClC,OAAO,CAAC,EAAE,KAAK,CAAC;QACd,SAAS,EAAE,KAAK,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;QACxC,QAAQ,CAAC,EAAE,QAAQ,GAAG,QAAQ,GAAG,KAAK,CAAC;KACxC,CAAC,CAAC;IACH,KAAK,CAAC,EAAE,OAAO,EAAE,CAAC;IAClB,YAAY,CAAC,EAAE;QACb,MAAM,CAAC,EAAE,OAAO,EAAE,CAAC;KACpB,CAAC;IACF,aAAa,CAAC,EAAE;QACd,MAAM,CAAC,EAAE,OAAO,EAAE,CAAC;KACpB,CAAC;IACF,SAAS,CAAC,EAAE;QACV,MAAM,CAAC,EAAE,OAAO,EAAE,CAAC;KACpB,CAAC;CACH;AAED,eAAO,MAAM,mBAAmB,GAAI,QAAQ,mBAAmB,wBAE9D,CAAC;AAGF,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACjC,KAAK,CAAC,EAAE,OAAO,EAAE,CAAC;CACnB;AAGD,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAG7C,MAAM,MAAM,eAAe,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AAIvE,OAAO,EACL,kBAAkB,EAClB,KAAK,4BAA4B,GAClC,MAAM,+BAA+B,CAAC"}
@@ -34,7 +34,6 @@ export { ImagePlugin } from './plugins/ImagePlugin.js';
34
34
  export { PastePlugin } from './plugins/PastePlugin.js';
35
35
  // Toolbar plugins
36
36
  export { ToolbarPlugin } from './plugins/ToolbarPlugin.js';
37
- // Main editor component - production ready
38
37
  export { RichTextEditor, richTextEditorStyles } from './RichTextEditor.js';
39
38
  // Feature client components (implementations coming in Phase 2)
40
39
  // These now return a minimal React component for tree-shaking
@@ -1 +1 @@
1
- {"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../../../src/collections/operations/create.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EACV,wBAAwB,EACxB,sBAAsB,EACtB,mBAAmB,EACnB,cAAc,EAGf,MAAM,sBAAsB,CAAC;AAwC9B,wBAAsB,MAAM,CAC1B,MAAM,EAAE,sBAAsB,EAC9B,EAAE,EAAE,wBAAwB,GAAG,IAAI,EACnC,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,cAAc,CAAC,CA0HzB"}
1
+ {"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../../../src/collections/operations/create.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EACV,wBAAwB,EACxB,sBAAsB,EACtB,mBAAmB,EACnB,cAAc,EAGf,MAAM,sBAAsB,CAAC;AAwC9B,wBAAsB,MAAM,CAC1B,MAAM,EAAE,sBAAsB,EAC9B,EAAE,EAAE,wBAAwB,GAAG,IAAI,EACnC,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,cAAc,CAAC,CA+IzB"}
@@ -111,12 +111,30 @@ export async function create(config, db, options) {
111
111
  return serializeValueForDatabase(data[key]);
112
112
  });
113
113
  const query = insertDocumentQuery(tableName, columns);
114
+ // Wrap INSERT + read-back in a single transaction so both run on the same
115
+ // connection and snapshot. Without this, pooled pg adapters check out a
116
+ // fresh client per `db.query()` call, and the post-insert `findByID` can
117
+ // see a pre-INSERT snapshot — throwing "Document not found in database"
118
+ // even though the row is present (see revealui#383).
119
+ //
120
+ // Adapters without `transaction` (e.g. test mocks, in-memory stores with
121
+ // same-connection visibility like PGlite used directly without our wrapper)
122
+ // fall back to sequential queries.
123
+ if (db.transaction) {
124
+ return await db.transaction(async (tx) => {
125
+ await tx.query(query, [id, ...values]);
126
+ // The create operation has already passed access control above.
127
+ // The read-back must use overrideAccess to avoid a second access
128
+ // check that fails when there's no req context (e.g. bootstrap).
129
+ const createdDoc = await findByID(config, tx, { id, overrideAccess: true });
130
+ if (!createdDoc) {
131
+ throw new Error(`Failed to retrieve created document with id ${id}. Document not found in database.`);
132
+ }
133
+ return createdDoc;
134
+ });
135
+ }
114
136
  await db.query(query, [id, ...values]);
115
- // For SQLite with WAL mode, writes are immediately visible to readers on the same connection
116
- // Return the created document by fetching it from the database
117
- // This ensures we return what was actually stored (with proper JSON deserialization)
118
- // ID is already a string, so use it directly
119
- const createdDoc = await findByID(config, db, { id });
137
+ const createdDoc = await findByID(config, db, { id, overrideAccess: true });
120
138
  if (!createdDoc) {
121
139
  throw new Error(`Failed to retrieve created document with id ${id}. Document not found in database.`);
122
140
  }
@@ -3,8 +3,6 @@
3
3
  *
4
4
  * Deletes a document by ID with access control enforcement.
5
5
  */
6
- import type { DatabaseResult, RevealCollectionConfig, RevealDeleteOptions, RevealDocument } from '../../types/index.js';
7
- export declare function deleteDocument(config: RevealCollectionConfig, db: {
8
- query: (query: string, values?: unknown[]) => Promise<DatabaseResult>;
9
- } | null, options: RevealDeleteOptions): Promise<RevealDocument>;
6
+ import type { QueryableDatabaseAdapter, RevealCollectionConfig, RevealDeleteOptions, RevealDocument } from '../../types/index.js';
7
+ export declare function deleteDocument(config: RevealCollectionConfig, db: QueryableDatabaseAdapter | null, options: RevealDeleteOptions): Promise<RevealDocument>;
10
8
  //# sourceMappingURL=delete.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"delete.d.ts","sourceRoot":"","sources":["../../../src/collections/operations/delete.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EACV,cAAc,EACd,sBAAsB,EACtB,mBAAmB,EACnB,cAAc,EAEf,MAAM,sBAAsB,CAAC;AAoC9B,wBAAsB,cAAc,CAClC,MAAM,EAAE,sBAAsB,EAC9B,EAAE,EAAE;IACF,KAAK,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC,cAAc,CAAC,CAAC;CACvE,GAAG,IAAI,EACR,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,cAAc,CAAC,CAoBzB"}
1
+ {"version":3,"file":"delete.d.ts","sourceRoot":"","sources":["../../../src/collections/operations/delete.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EACV,wBAAwB,EACxB,sBAAsB,EACtB,mBAAmB,EACnB,cAAc,EAGf,MAAM,sBAAsB,CAAC;AAsC9B,wBAAsB,cAAc,CAClC,MAAM,EAAE,sBAAsB,EAC9B,EAAE,EAAE,wBAAwB,GAAG,IAAI,EACnC,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,cAAc,CAAC,CAkCzB"}
@@ -3,6 +3,7 @@
3
3
  *
4
4
  * Deletes a document by ID with access control enforcement.
5
5
  */
6
+ import { find } from './find.js';
6
7
  import { deleteByIdQuery } from './sqlAdapter.js';
7
8
  /**
8
9
  * Evaluate a collection's access.delete function.
@@ -22,16 +23,32 @@ async function evaluateDeleteAccess(config, options) {
22
23
  const result = await deleteAccess({ req, id: options.id });
23
24
  if (result === false)
24
25
  return false;
25
- // Any truthy result (true, WhereClause) = allowed for single-document operations
26
- return !!result;
26
+ if (result === true)
27
+ return true;
28
+ // A WhereClause = row-level access: allowed only for rows matching the filter.
29
+ return result;
27
30
  }
28
31
  export async function deleteDocument(config, db, options) {
29
32
  const { id } = options;
30
33
  // --- Access control enforcement ---
31
- const allowed = await evaluateDeleteAccess(config, options);
32
- if (!allowed) {
34
+ const access = await evaluateDeleteAccess(config, options);
35
+ if (access === false) {
33
36
  throw new Error('Access denied: insufficient permissions to delete this document');
34
37
  }
38
+ if (access !== true) {
39
+ // Row-level access: confirm the target row matches the ownership filter
40
+ // before deleting, so delete() cannot remove a row outside the caller's
41
+ // scope. Reuse find()'s AND-merge; overrideAccess skips re-evaluation.
42
+ const scoped = await find(config, db, {
43
+ where: { and: [{ id: { equals: id } }, access] },
44
+ limit: 1,
45
+ req: options.req,
46
+ overrideAccess: true,
47
+ });
48
+ if (scoped.docs.length === 0) {
49
+ throw new Error('Access denied: insufficient permissions to delete this document');
50
+ }
51
+ }
35
52
  if (db?.query) {
36
53
  // Dynamic collection storage is quarantined in sqlAdapter.ts until this
37
54
  // layer is redesigned around typed tables that Drizzle can model directly.
@@ -1 +1 @@
1
- {"version":3,"file":"findById.d.ts","sourceRoot":"","sources":["../../../src/collections/operations/findById.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EACV,YAAY,EACZ,wBAAwB,EACxB,sBAAsB,EACtB,cAAc,EACd,aAAa,EAEd,MAAM,sBAAsB,CAAC;AAI9B,wBAAsB,QAAQ,CAC5B,MAAM,EAAE,sBAAsB,EAC9B,EAAE,EAAE,wBAAwB,GAAG,IAAI,EACnC,OAAO,EAAE;IACP,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,aAAa,CAAC;IACpB,QAAQ,CAAC,EAAE,YAAY,CAAC;IACxB,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B,GACA,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAwHhC"}
1
+ {"version":3,"file":"findById.d.ts","sourceRoot":"","sources":["../../../src/collections/operations/findById.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EACV,YAAY,EACZ,wBAAwB,EACxB,sBAAsB,EACtB,cAAc,EACd,aAAa,EAGd,MAAM,sBAAsB,CAAC;AAK9B,wBAAsB,QAAQ,CAC5B,MAAM,EAAE,sBAAsB,EAC9B,EAAE,EAAE,wBAAwB,GAAG,IAAI,EACnC,OAAO,EAAE;IACP,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,aAAa,CAAC;IACpB,QAAQ,CAAC,EAAE,YAAY,CAAC;IACxB,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B,GACA,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAsIhC"}
@@ -5,6 +5,7 @@
5
5
  */
6
6
  import { afterRead } from '../../fields/hooks/afterRead/index.js';
7
7
  import { deserializeJsonFields } from '../../utils/json-parsing.js';
8
+ import { find } from './find.js';
8
9
  import { selectByIdQuery } from './sqlAdapter.js';
9
10
  export async function findByID(config, db, options) {
10
11
  const { id, depth = 0, req, populate: populateOption } = options;
@@ -22,9 +23,23 @@ export async function findByID(config, db, options) {
22
23
  const result = await readAccess({ req, id });
23
24
  if (result === false)
24
25
  return null;
25
- // If result is a WhereClause (row-level filter), we fetch the doc first then verify.
26
- // For findByID, we check after fetch whether the doc matches the access filter.
27
- // Boolean true = allow, WhereClause = post-fetch filter (handled below after query).
26
+ if (result !== true) {
27
+ // Row-level access: a WhereClause means "allowed only for rows matching
28
+ // this filter". Confirm THIS row matches before returning it otherwise
29
+ // findByID hands back rows the ownership rule was meant to scope out
30
+ // (cross-tenant / unpublished-draft leakage). Reuse find()'s AND-merge so
31
+ // the filter runs through the same proven path the list view uses (both
32
+ // storage adapters); overrideAccess skips re-evaluating the rule.
33
+ const scoped = await find(config, db, {
34
+ where: { and: [{ id: { equals: id } }, result] },
35
+ limit: 1,
36
+ depth,
37
+ req,
38
+ ...(populateOption !== undefined ? { populate: populateOption } : {}),
39
+ overrideAccess: true,
40
+ });
41
+ return scoped.docs[0] ?? null;
42
+ }
28
43
  }
29
44
  }
30
45
  if (db?.collectionStorage?.findByID) {
@@ -1 +1 @@
1
- {"version":3,"file":"update.d.ts","sourceRoot":"","sources":["../../../src/collections/operations/update.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,KAAK,EACV,wBAAwB,EACxB,sBAAsB,EACtB,cAAc,EAGd,mBAAmB,EACpB,MAAM,sBAAsB,CAAC;AAiF9B,wBAAsB,MAAM,CAC1B,MAAM,EAAE,sBAAsB,EAC9B,EAAE,EAAE,wBAAwB,GAAG,IAAI,EACnC,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,cAAc,CAAC,CAkMzB"}
1
+ {"version":3,"file":"update.d.ts","sourceRoot":"","sources":["../../../src/collections/operations/update.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,KAAK,EACV,wBAAwB,EACxB,sBAAsB,EACtB,cAAc,EAGd,mBAAmB,EAEpB,MAAM,sBAAsB,CAAC;AAmF9B,wBAAsB,MAAM,CAC1B,MAAM,EAAE,sBAAsB,EAC9B,EAAE,EAAE,wBAAwB,GAAG,IAAI,EACnC,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,cAAc,CAAC,CAgNzB"}
@@ -8,6 +8,7 @@ import { defaultLogger } from '../../instance/logger.js';
8
8
  import { collectJsonFields, serializeValueForDatabase } from '../../utils/json-parsing.js';
9
9
  import { flattenFields, isJsonFieldType } from '../../utils/type-guards.js';
10
10
  import { runBeforeFieldHooks } from './fieldHooks.js';
11
+ import { find } from './find.js';
11
12
  import { findByID } from './findById.js';
12
13
  import { checkExistsByIdQuery, selectJsonByIdQuery, updateByIdQuery, updateByIdWithVersionQuery, } from './sqlAdapter.js';
13
14
  /**
@@ -52,16 +53,32 @@ async function evaluateUpdateAccess(config, options) {
52
53
  const result = await updateAccess({ req, id: options.id, data: options.data });
53
54
  if (result === false)
54
55
  return false;
55
- // Any truthy result (true, WhereClause) = allowed for single-document operations
56
- return !!result;
56
+ if (result === true)
57
+ return true;
58
+ // A WhereClause = row-level access: allowed only for rows matching the filter.
59
+ return result;
57
60
  }
58
61
  export async function update(config, db, options) {
59
62
  const { id, data } = options;
60
63
  // --- Access control enforcement ---
61
- const allowed = await evaluateUpdateAccess(config, options);
62
- if (!allowed) {
64
+ const access = await evaluateUpdateAccess(config, options);
65
+ if (access === false) {
63
66
  throw new Error('Access denied: insufficient permissions to update this document');
64
67
  }
68
+ if (access !== true) {
69
+ // Row-level access: confirm the target row matches the ownership filter
70
+ // before mutating, so update() cannot modify a row outside the caller's
71
+ // scope. Reuse find()'s AND-merge; overrideAccess skips re-evaluation.
72
+ const scoped = await find(config, db, {
73
+ where: { and: [{ id: { equals: options.id } }, access] },
74
+ limit: 1,
75
+ req: options.req,
76
+ overrideAccess: true,
77
+ });
78
+ if (scoped.docs.length === 0) {
79
+ throw new Error('Access denied: insufficient permissions to update this document');
80
+ }
81
+ }
65
82
  // Run beforeValidate field hooks before validation so they can transform values.
66
83
  await runBeforeFieldHooks(config, data, 'update', 'beforeValidate', undefined, options.req);
67
84
  // Validate email format if email field is being updated
@@ -30,6 +30,20 @@ export interface UniversalPostgresAdapterConfig {
30
30
  * Force a specific provider (optional, auto-detected if not provided)
31
31
  */
32
32
  provider?: 'neon' | 'supabase' | 'electric';
33
+ /**
34
+ * Shared pg Pool instance. When provided, the adapter uses this pool
35
+ * instead of creating its own. This eliminates dual-pool issues where
36
+ * the CMS adapter and the Drizzle ORM client create separate connections
37
+ * to the same database. Pass the same pool to both systems.
38
+ */
39
+ pool?: import('pg').Pool;
40
+ /**
41
+ * Async factory that returns a shared pg Pool. Called once during
42
+ * initializeConnection. Use this instead of `pool` when the pool
43
+ * source can't be imported at the top level (e.g., Turbopack async
44
+ * module init issues in Next.js).
45
+ */
46
+ poolFactory?: () => Promise<import('pg').Pool | null>;
33
47
  }
34
48
  /**
35
49
  * Creates a universal PostgreSQL adapter that works with Neon, Supabase, and Electric Postgres
@@ -1 +1 @@
1
- {"version":3,"file":"universal-postgres.d.ts","sourceRoot":"","sources":["../../src/database/universal-postgres.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAKH,OAAO,KAAK,EAAE,eAAe,EAAkB,MAAM,mBAAmB,CAAC;AAIzE,MAAM,WAAW,8BAA8B;IAC7C;;;;;;OAMG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,GAAG,UAAU,GAAG,UAAU,CAAC;CAC7C;AAmGD;;GAEG;AACH,wBAAgB,wBAAwB,CACtC,MAAM,GAAE,8BAAmC,GAC1C,eAAe,CAwcjB;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,eAAe,UAAQ,GAAG,IAAI,CAa/D;AAGD,eAAe,wBAAwB,CAAC"}
1
+ {"version":3,"file":"universal-postgres.d.ts","sourceRoot":"","sources":["../../src/database/universal-postgres.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAKH,OAAO,KAAK,EAAE,eAAe,EAA4C,MAAM,mBAAmB,CAAC;AAInG,MAAM,WAAW,8BAA8B;IAC7C;;;;;;OAMG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,GAAG,UAAU,GAAG,UAAU,CAAC;IAC5C;;;;;OAKG;IACH,IAAI,CAAC,EAAE,OAAO,IAAI,EAAE,IAAI,CAAC;IACzB;;;;;OAKG;IACH,WAAW,CAAC,EAAE,MAAM,OAAO,CAAC,OAAO,IAAI,EAAE,IAAI,GAAG,IAAI,CAAC,CAAC;CACvD;AAmGD;;GAEG;AACH,wBAAgB,wBAAwB,CACtC,MAAM,GAAE,8BAAmC,GAC1C,eAAe,CAsjBjB;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,eAAe,UAAQ,GAAG,IAAI,CAa/D;AAGD,eAAe,wBAAwB,CAAC"}
@@ -97,8 +97,64 @@ function detectProvider(connectionString) {
97
97
  */
98
98
  export function universalPostgresAdapter(config = {}) {
99
99
  let queryFn;
100
+ let transactionFn;
100
101
  let provider = 'generic';
102
+ const buildPgTransactionFn = (pool, providerLabel) => {
103
+ return async (fn) => {
104
+ const client = await pool.connect();
105
+ try {
106
+ await client.query('BEGIN');
107
+ const tx = {
108
+ query: async (queryString, values = []) => {
109
+ const result = await client.query(queryString, values);
110
+ return {
111
+ rows: safeParseRevealDocuments(result.rows),
112
+ rowCount: result.rowCount || 0,
113
+ };
114
+ },
115
+ };
116
+ const result = await fn(tx);
117
+ await client.query('COMMIT');
118
+ return result;
119
+ }
120
+ catch (error) {
121
+ try {
122
+ await client.query('ROLLBACK');
123
+ }
124
+ catch (rollbackErr) {
125
+ defaultLogger.error(`${providerLabel} transaction rollback failed after error:`, rollbackErr);
126
+ }
127
+ throw error;
128
+ }
129
+ finally {
130
+ client.release();
131
+ }
132
+ };
133
+ };
101
134
  const initializeConnection = async () => {
135
+ // Fast path: shared pool provided — skip all pool creation and provider detection.
136
+ // The caller (typically revealui.config.ts) passes the same pg.Pool that the
137
+ // Drizzle ORM client uses, eliminating the dual-connection-pool architecture.
138
+ // Resolve shared pool from either direct `pool` or async `poolFactory`
139
+ const sharedPool = config.pool ?? (config.poolFactory ? await config.poolFactory() : null);
140
+ if (sharedPool) {
141
+ provider = 'generic';
142
+ queryFn = async (queryString, values = []) => {
143
+ const client = await sharedPool.connect();
144
+ try {
145
+ const result = await client.query(queryString, values);
146
+ return {
147
+ rows: safeParseRevealDocuments(result.rows),
148
+ rowCount: result.rowCount || 0,
149
+ };
150
+ }
151
+ finally {
152
+ client.release();
153
+ }
154
+ };
155
+ transactionFn = buildPgTransactionFn(sharedPool, 'shared-pool');
156
+ return;
157
+ }
102
158
  // Allow explicit electric provider without a connection string (PGlite local)
103
159
  let connectionString;
104
160
  if (config.provider === 'electric') {
@@ -151,6 +207,7 @@ export function universalPostgresAdapter(config = {}) {
151
207
  throw error;
152
208
  }
153
209
  };
210
+ transactionFn = buildPgTransactionFn(neonPool, 'Neon');
154
211
  break;
155
212
  }
156
213
  case 'supabase': {
@@ -181,6 +238,7 @@ export function universalPostgresAdapter(config = {}) {
181
238
  client.release();
182
239
  }
183
240
  };
241
+ transactionFn = buildPgTransactionFn(pool, 'Supabase (txn-pool)');
184
242
  }
185
243
  else {
186
244
  // Use pg library for session pooling or direct connections (port 5432)
@@ -208,6 +266,7 @@ export function universalPostgresAdapter(config = {}) {
208
266
  throw error;
209
267
  }
210
268
  };
269
+ transactionFn = buildPgTransactionFn(pool, 'Supabase');
211
270
  }
212
271
  break;
213
272
  }
@@ -227,6 +286,23 @@ export function universalPostgresAdapter(config = {}) {
227
286
  rowCount: result.rowCount || 0,
228
287
  };
229
288
  };
289
+ // PGlite ships a native transaction(fn) with its own tx.query — wrap it
290
+ // so the callback sees a QueryableDatabaseAdapter.
291
+ transactionFn = async (fn) => {
292
+ // biome-ignore lint/style/noNonNullAssertion: db is set above in the electric branch
293
+ return await db.transaction(async (pgliteTx) => {
294
+ const tx = {
295
+ query: async (queryString, values = []) => {
296
+ const result = await pgliteTx.query(queryString, values);
297
+ return {
298
+ rows: safeParseRevealDocuments(result.rows),
299
+ rowCount: result.rowCount || 0,
300
+ };
301
+ },
302
+ };
303
+ return await fn(tx);
304
+ });
305
+ };
230
306
  break;
231
307
  }
232
308
  default: {
@@ -257,6 +333,7 @@ export function universalPostgresAdapter(config = {}) {
257
333
  throw error;
258
334
  }
259
335
  };
336
+ transactionFn = buildPgTransactionFn(pool, 'PostgreSQL');
260
337
  break;
261
338
  }
262
339
  }
@@ -333,6 +410,26 @@ export function universalPostgresAdapter(config = {}) {
333
410
  }
334
411
  return queryFn(queryString, values);
335
412
  },
413
+ async transaction(fn) {
414
+ if (!initialized) {
415
+ await initializeConnection();
416
+ initialized = true;
417
+ }
418
+ // Flush pending table creations before opening a transaction so the
419
+ // schema is in place on the same connection we're about to hold.
420
+ const pendingCreations = getWorkerPendingTableCreations();
421
+ if (pendingCreations.length > 0) {
422
+ try {
423
+ await Promise.all(pendingCreations);
424
+ pendingCreations.length = 0;
425
+ }
426
+ catch (error) {
427
+ defaultLogger.error('Failed to create tables before transaction:', error);
428
+ throw error;
429
+ }
430
+ }
431
+ return transactionFn(fn);
432
+ },
336
433
  // Create table schema for PGlite provider
337
434
  // For other providers, tables should be created via migrations
338
435
  createTable: config.provider === 'electric' ||
@@ -6,7 +6,7 @@
6
6
  *
7
7
  * @module @revealui/core/fieldTraversal
8
8
  */
9
- import type { RevealUITraverseFieldsArgs, RevealUITraverseFieldsResult } from './types/legacy.js';
9
+ import type { RevealUITraverseFieldsArgs, RevealUITraverseFieldsResult } from './types/internal.js';
10
10
  /**
11
11
  * Traversal mode determines how fields are processed
12
12
  */
@@ -1 +1 @@
1
- {"version":3,"file":"fieldTraversal.d.ts","sourceRoot":"","sources":["../src/fieldTraversal.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,KAAK,EAAE,0BAA0B,EAAE,4BAA4B,EAAE,MAAM,mBAAmB,CAAC;AAElG;;GAEG;AACH,KAAK,aAAa,GAAG,aAAa,GAAG,WAAW,GAAG,cAAc,GAAG,gBAAgB,CAAC;AAErF;;;;;;;;;GASG;AACH,wBAAsB,kBAAkB,CACtC,IAAI,EAAE,0BAA0B,EAChC,IAAI,EAAE,aAAa,GAClB,OAAO,CAAC,4BAA4B,CAAC,CA4DvC"}
1
+ {"version":3,"file":"fieldTraversal.d.ts","sourceRoot":"","sources":["../src/fieldTraversal.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,KAAK,EAAE,0BAA0B,EAAE,4BAA4B,EAAE,MAAM,qBAAqB,CAAC;AAEpG;;GAEG;AACH,KAAK,aAAa,GAAG,aAAa,GAAG,WAAW,GAAG,cAAc,GAAG,gBAAgB,CAAC;AAErF;;;;;;;;;GASG;AACH,wBAAsB,kBAAkB,CACtC,IAAI,EAAE,0BAA0B,EAChC,IAAI,EAAE,aAAa,GAClB,OAAO,CAAC,4BAA4B,CAAC,CA4DvC"}
@@ -1 +1 @@
1
- {"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../../../src/instance/methods/create.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EAAE,mBAAmB,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAGlG,wBAAsB,MAAM,CAC1B,QAAQ,EAAE,gBAAgB,EAC1B,iBAAiB,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,EACtC,OAAO,EAAE,mBAAmB,GAAG;IAAE,UAAU,EAAE,MAAM,CAAA;CAAE,GACpD,OAAO,CAAC,cAAc,CAAC,CAyCzB"}
1
+ {"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../../../src/instance/methods/create.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EAAE,mBAAmB,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAGlG,wBAAsB,MAAM,CAC1B,QAAQ,EAAE,gBAAgB,EAC1B,iBAAiB,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,EACtC,OAAO,EAAE,mBAAmB,GAAG;IAAE,UAAU,EAAE,MAAM,CAAA;CAAE,GACpD,OAAO,CAAC,cAAc,CAAC,CA0CzB"}
@@ -11,8 +11,9 @@ export async function create(instance, ensureDbConnected, options) {
11
11
  throw new Error(`Collection '${collection}' not found`);
12
12
  }
13
13
  const collectionConfig = instance.config.collections?.find((c) => c.slug === collection);
14
- // Enforce collection-level access control
15
- if (collectionConfig?.access?.create && options.req) {
14
+ // Enforce collection-level access control (skip when overrideAccess is set,
15
+ // matching the low-level create() guard in collections/operations/create.ts)
16
+ if (collectionConfig?.access?.create && options.req && !options.overrideAccess) {
16
17
  const canCreate = await collectionConfig.access.create({
17
18
  req: options.req,
18
19
  data: options.data,