@actuate-media/cms-core 0.21.0 → 0.23.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 (109) hide show
  1. package/dist/__tests__/actions/document-crud.test.js +74 -2
  2. package/dist/__tests__/actions/document-crud.test.js.map +1 -1
  3. package/dist/__tests__/api/cache-headers.test.d.ts +2 -0
  4. package/dist/__tests__/api/cache-headers.test.d.ts.map +1 -0
  5. package/dist/__tests__/api/cache-headers.test.js +135 -0
  6. package/dist/__tests__/api/cache-headers.test.js.map +1 -0
  7. package/dist/__tests__/api/collections-discovery.test.d.ts +2 -0
  8. package/dist/__tests__/api/collections-discovery.test.d.ts.map +1 -0
  9. package/dist/__tests__/api/collections-discovery.test.js +129 -0
  10. package/dist/__tests__/api/collections-discovery.test.js.map +1 -0
  11. package/dist/__tests__/api/comments-routes.test.d.ts +2 -0
  12. package/dist/__tests__/api/comments-routes.test.d.ts.map +1 -0
  13. package/dist/__tests__/api/comments-routes.test.js +266 -0
  14. package/dist/__tests__/api/comments-routes.test.js.map +1 -0
  15. package/dist/__tests__/api/notifications-routes.test.d.ts +2 -0
  16. package/dist/__tests__/api/notifications-routes.test.d.ts.map +1 -0
  17. package/dist/__tests__/api/notifications-routes.test.js +225 -0
  18. package/dist/__tests__/api/notifications-routes.test.js.map +1 -0
  19. package/dist/__tests__/api/preview-and-scheduling.test.js +53 -0
  20. package/dist/__tests__/api/preview-and-scheduling.test.js.map +1 -1
  21. package/dist/__tests__/fields/relations.test.js +62 -8
  22. package/dist/__tests__/fields/relations.test.js.map +1 -1
  23. package/dist/__tests__/preview-event-bus.test.d.ts +2 -0
  24. package/dist/__tests__/preview-event-bus.test.d.ts.map +1 -0
  25. package/dist/__tests__/preview-event-bus.test.js +89 -0
  26. package/dist/__tests__/preview-event-bus.test.js.map +1 -0
  27. package/dist/__tests__/preview-sse-stream.test.d.ts +2 -0
  28. package/dist/__tests__/preview-sse-stream.test.d.ts.map +1 -0
  29. package/dist/__tests__/preview-sse-stream.test.js +117 -0
  30. package/dist/__tests__/preview-sse-stream.test.js.map +1 -0
  31. package/dist/__tests__/realtime/comments.test.d.ts +2 -0
  32. package/dist/__tests__/realtime/comments.test.d.ts.map +1 -0
  33. package/dist/__tests__/realtime/comments.test.js +508 -0
  34. package/dist/__tests__/realtime/comments.test.js.map +1 -0
  35. package/dist/__tests__/realtime/gateway-ws-integration.test.d.ts +2 -0
  36. package/dist/__tests__/realtime/gateway-ws-integration.test.d.ts.map +1 -0
  37. package/dist/__tests__/realtime/gateway-ws-integration.test.js +170 -0
  38. package/dist/__tests__/realtime/gateway-ws-integration.test.js.map +1 -0
  39. package/dist/__tests__/realtime/gateway.test.d.ts +2 -0
  40. package/dist/__tests__/realtime/gateway.test.d.ts.map +1 -0
  41. package/dist/__tests__/realtime/gateway.test.js +402 -0
  42. package/dist/__tests__/realtime/gateway.test.js.map +1 -0
  43. package/dist/__tests__/realtime/notifications.test.d.ts +2 -0
  44. package/dist/__tests__/realtime/notifications.test.d.ts.map +1 -0
  45. package/dist/__tests__/realtime/notifications.test.js +317 -0
  46. package/dist/__tests__/realtime/notifications.test.js.map +1 -0
  47. package/dist/__tests__/realtime/persistence.test.d.ts +2 -0
  48. package/dist/__tests__/realtime/persistence.test.d.ts.map +1 -0
  49. package/dist/__tests__/realtime/persistence.test.js +124 -0
  50. package/dist/__tests__/realtime/persistence.test.js.map +1 -0
  51. package/dist/__tests__/schema-preview-features.test.d.ts +2 -0
  52. package/dist/__tests__/schema-preview-features.test.d.ts.map +1 -0
  53. package/dist/__tests__/schema-preview-features.test.js +42 -0
  54. package/dist/__tests__/schema-preview-features.test.js.map +1 -0
  55. package/dist/actions.d.ts.map +1 -1
  56. package/dist/actions.js +71 -26
  57. package/dist/actions.js.map +1 -1
  58. package/dist/api/handlers.d.ts.map +1 -1
  59. package/dist/api/handlers.js +772 -188
  60. package/dist/api/handlers.js.map +1 -1
  61. package/dist/cache/__tests__/http.test.d.ts +2 -0
  62. package/dist/cache/__tests__/http.test.d.ts.map +1 -0
  63. package/dist/cache/__tests__/http.test.js +285 -0
  64. package/dist/cache/__tests__/http.test.js.map +1 -0
  65. package/dist/cache/http.d.ts +119 -0
  66. package/dist/cache/http.d.ts.map +1 -0
  67. package/dist/cache/http.js +188 -0
  68. package/dist/cache/http.js.map +1 -0
  69. package/dist/config/types.d.ts +92 -0
  70. package/dist/config/types.d.ts.map +1 -1
  71. package/dist/fields/relations.d.ts.map +1 -1
  72. package/dist/fields/relations.js +43 -11
  73. package/dist/fields/relations.js.map +1 -1
  74. package/dist/index.d.ts +5 -0
  75. package/dist/index.d.ts.map +1 -1
  76. package/dist/index.js +2 -0
  77. package/dist/index.js.map +1 -1
  78. package/dist/page-builder/schema.d.ts +2 -2
  79. package/dist/preview/event-bus.d.ts +39 -0
  80. package/dist/preview/event-bus.d.ts.map +1 -0
  81. package/dist/preview/event-bus.js +73 -0
  82. package/dist/preview/event-bus.js.map +1 -0
  83. package/dist/preview/sse-stream.d.ts +50 -0
  84. package/dist/preview/sse-stream.d.ts.map +1 -0
  85. package/dist/preview/sse-stream.js +120 -0
  86. package/dist/preview/sse-stream.js.map +1 -0
  87. package/dist/realtime/comments.d.ts +217 -0
  88. package/dist/realtime/comments.d.ts.map +1 -0
  89. package/dist/realtime/comments.js +282 -0
  90. package/dist/realtime/comments.js.map +1 -0
  91. package/dist/realtime/gateway.d.ts +107 -0
  92. package/dist/realtime/gateway.d.ts.map +1 -0
  93. package/dist/realtime/gateway.js +215 -0
  94. package/dist/realtime/gateway.js.map +1 -0
  95. package/dist/realtime/index.d.ts +18 -0
  96. package/dist/realtime/index.d.ts.map +1 -0
  97. package/dist/realtime/index.js +18 -0
  98. package/dist/realtime/index.js.map +1 -0
  99. package/dist/realtime/notifications.d.ts +209 -0
  100. package/dist/realtime/notifications.d.ts.map +1 -0
  101. package/dist/realtime/notifications.js +209 -0
  102. package/dist/realtime/notifications.js.map +1 -0
  103. package/dist/realtime/persistence.d.ts +72 -0
  104. package/dist/realtime/persistence.d.ts.map +1 -0
  105. package/dist/realtime/persistence.js +53 -0
  106. package/dist/realtime/persistence.js.map +1 -0
  107. package/package.json +13 -4
  108. package/prisma/cms-schema.prisma +135 -4
  109. package/prisma/schema.prisma +17 -3
@@ -0,0 +1,317 @@
1
+ import { beforeEach, describe, expect, it } from 'vitest';
2
+ import { createNotification, excerptForNotification, extractMentionedUserIds, isNotificationKind, listForUser as listNotificationsForUser, markAllRead as markAllNotificationsRead, markRead as markNotificationRead, unreadCount as notificationsUnreadCount, toNotificationDTO, } from '../../realtime/notifications.js';
3
+ /**
4
+ * In-memory fake of the Prisma `documentNotification` delegate. The
5
+ * production schema lives in `cms-schema.prisma`; this fake mirrors the
6
+ * narrow interface declared in `notifications.ts`.
7
+ */
8
+ function createFakeDB() {
9
+ const rows = [];
10
+ let nextId = 1;
11
+ let now = new Date('2026-01-01T00:00:00.000Z').getTime();
12
+ const advance = () => {
13
+ now += 1000;
14
+ return new Date(now);
15
+ };
16
+ const db = {
17
+ documentNotification: {
18
+ async create({ data }) {
19
+ const row = {
20
+ id: `n-${nextId++}`,
21
+ userId: data.userId,
22
+ kind: data.kind,
23
+ documentId: data.documentId ?? null,
24
+ commentId: data.commentId ?? null,
25
+ payload: data.payload,
26
+ readAt: data.readAt ?? null,
27
+ createdAt: advance(),
28
+ };
29
+ rows.push(row);
30
+ return row;
31
+ },
32
+ async findUnique({ where: { id } }) {
33
+ return rows.find((r) => r.id === id) ?? null;
34
+ },
35
+ async findMany({ where, orderBy, take }) {
36
+ let candidates = rows.filter((r) => r.userId === where.userId);
37
+ if (where.readAt === null)
38
+ candidates = candidates.filter((r) => r.readAt === null);
39
+ candidates = candidates.slice();
40
+ candidates.sort((a, b) => orderBy?.createdAt === 'asc'
41
+ ? a.createdAt.getTime() - b.createdAt.getTime()
42
+ : b.createdAt.getTime() - a.createdAt.getTime());
43
+ return typeof take === 'number' ? candidates.slice(0, take) : candidates;
44
+ },
45
+ async update({ where, data }) {
46
+ const row = rows.find((r) => r.id === where.id);
47
+ if (!row)
48
+ throw new Error('row not found');
49
+ if (data.readAt !== undefined)
50
+ row.readAt = data.readAt;
51
+ return row;
52
+ },
53
+ async updateMany({ where, data }) {
54
+ let count = 0;
55
+ for (const row of rows) {
56
+ if (row.userId !== where.userId)
57
+ continue;
58
+ if (where.readAt === null && row.readAt !== null)
59
+ continue;
60
+ row.readAt = data.readAt;
61
+ count += 1;
62
+ }
63
+ return { count };
64
+ },
65
+ async count({ where }) {
66
+ return rows.filter((r) => r.userId === where.userId && r.readAt === null).length;
67
+ },
68
+ },
69
+ };
70
+ return { db, rows };
71
+ }
72
+ let fake = createFakeDB();
73
+ beforeEach(() => {
74
+ fake = createFakeDB();
75
+ });
76
+ describe('isNotificationKind', () => {
77
+ it('accepts the three known kinds', () => {
78
+ expect(isNotificationKind('comment_reply')).toBe(true);
79
+ expect(isNotificationKind('comment_resolved')).toBe(true);
80
+ expect(isNotificationKind('comment_mention')).toBe(true);
81
+ });
82
+ it('rejects anything else', () => {
83
+ expect(isNotificationKind('unknown')).toBe(false);
84
+ expect(isNotificationKind('')).toBe(false);
85
+ expect(isNotificationKind(null)).toBe(false);
86
+ });
87
+ });
88
+ describe('excerptForNotification', () => {
89
+ it('trims whitespace and collapses runs', () => {
90
+ expect(excerptForNotification(' hello world\n\n! ')).toBe('hello world !');
91
+ });
92
+ it('clips to the max length with an ellipsis', () => {
93
+ const long = 'x'.repeat(200);
94
+ const out = excerptForNotification(long, 50);
95
+ expect(out.length).toBe(50);
96
+ expect(out.endsWith('…')).toBe(true);
97
+ });
98
+ it('leaves short strings alone', () => {
99
+ expect(excerptForNotification('short')).toBe('short');
100
+ });
101
+ });
102
+ describe('extractMentionedUserIds', () => {
103
+ it('returns ids for @<id> tokens', () => {
104
+ expect(extractMentionedUserIds('cc @user_abc and @user_def!')).toEqual(['user_abc', 'user_def']);
105
+ });
106
+ it('deduplicates repeated mentions', () => {
107
+ expect(extractMentionedUserIds('@user_a @user_a @user_a')).toEqual(['user_a']);
108
+ });
109
+ it('ignores too-short tokens', () => {
110
+ expect(extractMentionedUserIds('@a @ab @abc')).toEqual(['abc']);
111
+ });
112
+ it('returns [] for empty / non-string input', () => {
113
+ expect(extractMentionedUserIds('')).toEqual([]);
114
+ expect(extractMentionedUserIds(null)).toEqual([]);
115
+ });
116
+ });
117
+ describe('toNotificationDTO', () => {
118
+ it('re-tags the payload with the kind discriminator', () => {
119
+ const row = {
120
+ id: 'n-1',
121
+ userId: 'u-1',
122
+ kind: 'comment_reply',
123
+ documentId: 'doc-1',
124
+ commentId: 'c-1',
125
+ payload: { actorId: 'u-2', actorName: 'Alice', excerpt: 'hi' },
126
+ readAt: null,
127
+ createdAt: new Date('2026-01-01T00:00:00.000Z'),
128
+ };
129
+ const dto = toNotificationDTO(row);
130
+ expect(dto.payload).toEqual({
131
+ kind: 'comment_reply',
132
+ actorId: 'u-2',
133
+ actorName: 'Alice',
134
+ excerpt: 'hi',
135
+ });
136
+ expect(dto.readAt).toBeNull();
137
+ expect(dto.createdAt).toBe('2026-01-01T00:00:00.000Z');
138
+ });
139
+ });
140
+ describe('createNotification', () => {
141
+ it('persists a comment_reply notification', async () => {
142
+ const out = await createNotification(fake.db, {
143
+ userId: 'u-1',
144
+ commentId: 'c-1',
145
+ documentId: 'doc-1',
146
+ payload: {
147
+ kind: 'comment_reply',
148
+ actorId: 'u-2',
149
+ actorName: 'Alice',
150
+ excerpt: 'hi',
151
+ },
152
+ });
153
+ expect(out.ok).toBe(true);
154
+ if (!out.ok)
155
+ return;
156
+ expect(out.value.kind).toBe('comment_reply');
157
+ expect(fake.rows).toHaveLength(1);
158
+ expect(fake.rows[0].kind).toBe('comment_reply');
159
+ // Kind tag is stripped from the stored payload (lives in the
160
+ // dedicated column).
161
+ expect(fake.rows[0].payload.kind).toBeUndefined();
162
+ });
163
+ it('rejects an unknown kind', async () => {
164
+ const out = await createNotification(fake.db, {
165
+ userId: 'u-1',
166
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
167
+ payload: { kind: 'nonsense', actorId: 'u-2', actorName: 'Alice', excerpt: 'x' },
168
+ });
169
+ expect(out.ok).toBe(false);
170
+ if (out.ok)
171
+ return;
172
+ expect(out.error.code).toBe('validation');
173
+ });
174
+ it('rejects a comment_reply without an excerpt', async () => {
175
+ const out = await createNotification(fake.db, {
176
+ userId: 'u-1',
177
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
178
+ payload: { kind: 'comment_reply', actorId: 'u-2', actorName: 'Alice' },
179
+ });
180
+ expect(out.ok).toBe(false);
181
+ });
182
+ it('rejects a comment_resolved without a rootExcerpt', async () => {
183
+ const out = await createNotification(fake.db, {
184
+ userId: 'u-1',
185
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
186
+ payload: { kind: 'comment_resolved', actorId: 'u-2', actorName: 'Alice' },
187
+ });
188
+ expect(out.ok).toBe(false);
189
+ });
190
+ it('rejects an empty userId', async () => {
191
+ const out = await createNotification(fake.db, {
192
+ userId: '',
193
+ payload: {
194
+ kind: 'comment_reply',
195
+ actorId: 'u-2',
196
+ actorName: 'Alice',
197
+ excerpt: 'hi',
198
+ },
199
+ });
200
+ expect(out.ok).toBe(false);
201
+ });
202
+ });
203
+ describe('listForUser / unreadCount', () => {
204
+ beforeEach(async () => {
205
+ await createNotification(fake.db, {
206
+ userId: 'u-1',
207
+ payload: { kind: 'comment_reply', actorId: 'u-2', actorName: 'A', excerpt: 'a' },
208
+ });
209
+ await createNotification(fake.db, {
210
+ userId: 'u-1',
211
+ payload: { kind: 'comment_reply', actorId: 'u-2', actorName: 'A', excerpt: 'b' },
212
+ });
213
+ await createNotification(fake.db, {
214
+ userId: 'u-2',
215
+ payload: { kind: 'comment_reply', actorId: 'u-1', actorName: 'B', excerpt: 'c' },
216
+ });
217
+ });
218
+ it('returns only the target user notifications, newest first, unread only', async () => {
219
+ const out = await listNotificationsForUser(fake.db, { userId: 'u-1' });
220
+ expect(out.ok).toBe(true);
221
+ if (!out.ok)
222
+ return;
223
+ expect(out.value.map((n) => n.payload.kind === 'comment_resolved' ? n.payload.rootExcerpt : n.payload.excerpt)).toEqual(['b', 'a']);
224
+ });
225
+ it('honours pageSize', async () => {
226
+ const out = await listNotificationsForUser(fake.db, { userId: 'u-1', pageSize: 1 });
227
+ expect(out.ok).toBe(true);
228
+ if (!out.ok)
229
+ return;
230
+ expect(out.value).toHaveLength(1);
231
+ });
232
+ it('clamps pageSize at the upper bound', async () => {
233
+ const out = await listNotificationsForUser(fake.db, {
234
+ userId: 'u-1',
235
+ pageSize: 999999,
236
+ });
237
+ expect(out.ok).toBe(true);
238
+ });
239
+ it('unreadCount matches the count of unread rows', async () => {
240
+ const out = await notificationsUnreadCount(fake.db, 'u-1');
241
+ expect(out.ok).toBe(true);
242
+ if (!out.ok)
243
+ return;
244
+ expect(out.value).toBe(2);
245
+ });
246
+ it('rejects missing userId', async () => {
247
+ expect((await listNotificationsForUser(fake.db, { userId: '' })).ok).toBe(false);
248
+ expect((await notificationsUnreadCount(fake.db, '')).ok).toBe(false);
249
+ });
250
+ });
251
+ describe('markRead', () => {
252
+ it('marks an unread row as read', async () => {
253
+ const created = await createNotification(fake.db, {
254
+ userId: 'u-1',
255
+ payload: { kind: 'comment_reply', actorId: 'u-2', actorName: 'A', excerpt: 'x' },
256
+ });
257
+ if (!created.ok)
258
+ throw new Error('setup failed');
259
+ const out = await markNotificationRead(fake.db, created.value.id, { userId: 'u-1' });
260
+ expect(out.ok).toBe(true);
261
+ if (!out.ok)
262
+ return;
263
+ expect(out.value.readAt).not.toBeNull();
264
+ });
265
+ it('is idempotent — marking an already-read row returns the same DTO', async () => {
266
+ const created = await createNotification(fake.db, {
267
+ userId: 'u-1',
268
+ payload: { kind: 'comment_reply', actorId: 'u-2', actorName: 'A', excerpt: 'x' },
269
+ });
270
+ if (!created.ok)
271
+ throw new Error('setup failed');
272
+ await markNotificationRead(fake.db, created.value.id, { userId: 'u-1' });
273
+ const second = await markNotificationRead(fake.db, created.value.id, { userId: 'u-1' });
274
+ expect(second.ok).toBe(true);
275
+ });
276
+ it("forbids marking another user's notification", async () => {
277
+ const created = await createNotification(fake.db, {
278
+ userId: 'u-1',
279
+ payload: { kind: 'comment_reply', actorId: 'u-2', actorName: 'A', excerpt: 'x' },
280
+ });
281
+ if (!created.ok)
282
+ throw new Error('setup failed');
283
+ const out = await markNotificationRead(fake.db, created.value.id, { userId: 'u-2' });
284
+ expect(out.ok).toBe(false);
285
+ if (out.ok)
286
+ return;
287
+ expect(out.error.code).toBe('forbidden');
288
+ });
289
+ it('returns not_found for an unknown id', async () => {
290
+ const out = await markNotificationRead(fake.db, 'unknown', { userId: 'u-1' });
291
+ expect(out.ok).toBe(false);
292
+ if (out.ok)
293
+ return;
294
+ expect(out.error.code).toBe('not_found');
295
+ });
296
+ });
297
+ describe('markAllRead', () => {
298
+ it('clears the unread queue', async () => {
299
+ for (let i = 0; i < 5; i++) {
300
+ await createNotification(fake.db, {
301
+ userId: 'u-1',
302
+ payload: { kind: 'comment_reply', actorId: 'u-2', actorName: 'A', excerpt: `${i}` },
303
+ });
304
+ }
305
+ const out = await markAllNotificationsRead(fake.db, 'u-1');
306
+ expect(out.ok).toBe(true);
307
+ if (!out.ok)
308
+ return;
309
+ expect(out.value.count).toBe(5);
310
+ const remaining = await notificationsUnreadCount(fake.db, 'u-1');
311
+ expect(remaining.ok && remaining.value).toBe(0);
312
+ });
313
+ it('rejects missing userId', async () => {
314
+ expect((await markAllNotificationsRead(fake.db, '')).ok).toBe(false);
315
+ });
316
+ });
317
+ //# sourceMappingURL=notifications.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"notifications.test.js","sourceRoot":"","sources":["../../../src/__tests__/realtime/notifications.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=persistence.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"persistence.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/realtime/persistence.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,124 @@
1
+ import { describe, expect, it, vi } from 'vitest';
2
+ import * as Y from 'yjs';
3
+ import { createPrismaDocumentPersistence, } from '../../realtime/persistence.js';
4
+ /** Build a minimal mock that records calls and lets tests stub return values. */
5
+ function makeMockDb() {
6
+ const findUnique = vi.fn();
7
+ const upsert = vi.fn(async (args) => ({
8
+ documentId: args.where.documentId,
9
+ version: 1,
10
+ }));
11
+ const db = {
12
+ documentCRDT: { findUnique, upsert },
13
+ };
14
+ return { db, findUnique, upsert };
15
+ }
16
+ function makeYjsState(seed) {
17
+ const doc = new Y.Doc();
18
+ seed(doc);
19
+ const state = Y.encodeStateAsUpdate(doc);
20
+ doc.destroy();
21
+ return state;
22
+ }
23
+ describe('createPrismaDocumentPersistence — load', () => {
24
+ it('returns null when no row exists', async () => {
25
+ const { db, findUnique } = makeMockDb();
26
+ findUnique.mockResolvedValueOnce(null);
27
+ const p = createPrismaDocumentPersistence(db);
28
+ const result = await p.load('doc-1');
29
+ expect(result).toBeNull();
30
+ expect(findUnique).toHaveBeenCalledWith({
31
+ where: { documentId: 'doc-1' },
32
+ select: { state: true },
33
+ });
34
+ });
35
+ it('returns the stored bytes when a row exists', async () => {
36
+ const { db, findUnique } = makeMockDb();
37
+ const stored = makeYjsState((d) => d.getText('t').insert(0, 'hello'));
38
+ findUnique.mockResolvedValueOnce({ state: stored });
39
+ const p = createPrismaDocumentPersistence(db);
40
+ const result = await p.load('doc-1');
41
+ expect(result).not.toBeNull();
42
+ // Round-trip the bytes through Yjs to confirm content survives.
43
+ const doc = new Y.Doc();
44
+ Y.applyUpdate(doc, result);
45
+ expect(doc.getText('t').toString()).toBe('hello');
46
+ doc.destroy();
47
+ });
48
+ it('returns a defensive copy so callers cannot mutate the source', async () => {
49
+ const { db, findUnique } = makeMockDb();
50
+ const stored = new Uint8Array([1, 2, 3]);
51
+ findUnique.mockResolvedValueOnce({ state: stored });
52
+ const p = createPrismaDocumentPersistence(db);
53
+ const result = await p.load('doc-1');
54
+ result[0] = 99;
55
+ expect(stored[0]).toBe(1);
56
+ });
57
+ });
58
+ describe('createPrismaDocumentPersistence — save', () => {
59
+ it('upserts with state + stateVector + version increment', async () => {
60
+ const { db, upsert } = makeMockDb();
61
+ const state = makeYjsState((d) => d.getText('t').insert(0, 'hi'));
62
+ const p = createPrismaDocumentPersistence(db);
63
+ await p.save('doc-1', state);
64
+ expect(upsert).toHaveBeenCalledTimes(1);
65
+ const args = upsert.mock.calls[0][0];
66
+ expect(args.where).toEqual({ documentId: 'doc-1' });
67
+ expect(args.create.documentId).toBe('doc-1');
68
+ expect(args.create.state).toBeInstanceOf(Uint8Array);
69
+ expect(args.create.stateVector).toBeInstanceOf(Uint8Array);
70
+ expect(args.create.version).toBe(1);
71
+ expect(args.update.version).toEqual({ increment: 1 });
72
+ expect(args.update.state).toBeInstanceOf(Uint8Array);
73
+ expect(args.update.stateVector).toBeInstanceOf(Uint8Array);
74
+ });
75
+ it('writes a stateVector that matches the encoded document', async () => {
76
+ const { db, upsert } = makeMockDb();
77
+ const seed = (d) => d.getText('t').insert(0, 'abc');
78
+ const state = makeYjsState(seed);
79
+ const p = createPrismaDocumentPersistence(db);
80
+ await p.save('doc-1', state);
81
+ const writtenStateVector = upsert.mock.calls[0][0].create.stateVector;
82
+ // Reconstruct the expected stateVector from the same state bytes and
83
+ // compare byte-by-byte.
84
+ const verify = new Y.Doc();
85
+ Y.applyUpdate(verify, state);
86
+ const expected = Y.encodeStateVector(verify);
87
+ verify.destroy();
88
+ expect(Array.from(writtenStateVector)).toEqual(Array.from(expected));
89
+ });
90
+ it('honours options.lastUpdatedById when set', async () => {
91
+ const { db, upsert } = makeMockDb();
92
+ const p = createPrismaDocumentPersistence(db, { lastUpdatedById: 'user_42' });
93
+ await p.save('doc-1', makeYjsState((d) => d.getText('t').insert(0, 'x')));
94
+ const args = upsert.mock.calls[0][0];
95
+ expect(args.create.lastUpdatedById).toBe('user_42');
96
+ expect(args.update.lastUpdatedById).toBe('user_42');
97
+ });
98
+ it('defaults lastUpdatedById to null when no option is set', async () => {
99
+ const { db, upsert } = makeMockDb();
100
+ const p = createPrismaDocumentPersistence(db);
101
+ await p.save('doc-1', makeYjsState((d) => d.getText('t').insert(0, 'x')));
102
+ const args = upsert.mock.calls[0][0];
103
+ expect(args.create.lastUpdatedById).toBeNull();
104
+ expect(args.update.lastUpdatedById).toBeNull();
105
+ });
106
+ it('makes a defensive copy of the state bytes', async () => {
107
+ const { db, upsert } = makeMockDb();
108
+ const original = makeYjsState((d) => d.getText('t').insert(0, 'abc'));
109
+ const p = createPrismaDocumentPersistence(db);
110
+ await p.save('doc-1', original);
111
+ const written = upsert.mock.calls[0][0].create.state;
112
+ // Mutating the original after save should not affect the buffer Prisma got.
113
+ const beforeFirst = written[0];
114
+ original[0] = 99;
115
+ expect(written[0]).toBe(beforeFirst);
116
+ });
117
+ it('propagates database errors so the binding can flag them via onError', async () => {
118
+ const { db, upsert } = makeMockDb();
119
+ upsert.mockRejectedValueOnce(new Error('boom'));
120
+ const p = createPrismaDocumentPersistence(db);
121
+ await expect(p.save('doc-1', makeYjsState((d) => d.getText('t').insert(0, 'x')))).rejects.toThrow('boom');
122
+ });
123
+ });
124
+ //# sourceMappingURL=persistence.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"persistence.test.js","sourceRoot":"","sources":["../../../src/__tests__/realtime/persistence.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=schema-preview-features.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema-preview-features.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/schema-preview-features.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,42 @@
1
+ import { readFileSync } from 'node:fs';
2
+ import { fileURLToPath } from 'node:url';
3
+ import { dirname, resolve } from 'node:path';
4
+ import { describe, expect, it } from 'vitest';
5
+ /**
6
+ * Guard against the Phase 5.5 regression where `relationLoadStrategy:
7
+ * 'join'` was added to the dashboard / versions / bench queries
8
+ * without the `relationJoins` Preview-feature flag in the schema.
9
+ * Prisma silently rejects the option as an "Unknown argument" when
10
+ * the flag is missing — for `safeFindMany` callers that surfaces as
11
+ * an empty result and for the versions endpoint as a 500 to the
12
+ * client. Either failure mode is hard to spot without a deliberate
13
+ * bench run, so pin the schema's preview-feature set with a tiny
14
+ * test rather than a code-review-only convention.
15
+ *
16
+ * If the preview-feature set legitimately needs to change, update
17
+ * the assertion below in the same commit — that way the rationale
18
+ * surfaces in the diff.
19
+ */
20
+ describe('Prisma schema preview features', () => {
21
+ const here = dirname(fileURLToPath(import.meta.url));
22
+ const schemaPath = resolve(here, '..', '..', 'prisma', 'schema.prisma');
23
+ const schema = readFileSync(schemaPath, 'utf8');
24
+ it('declares relationJoins so `relationLoadStrategy: "join"` is honoured', () => {
25
+ const match = schema.match(/previewFeatures\s*=\s*\[([^\]]*)\]/);
26
+ expect(match, 'schema.prisma must declare a previewFeatures array').not.toBeNull();
27
+ const features = (match[1] ?? '')
28
+ .split(',')
29
+ .map((s) => s.trim().replace(/^"|"$/g, ''))
30
+ .filter(Boolean);
31
+ expect(features).toContain('relationJoins');
32
+ });
33
+ it('still declares fullTextSearchPostgres (search uses it)', () => {
34
+ const match = schema.match(/previewFeatures\s*=\s*\[([^\]]*)\]/);
35
+ const features = (match[1] ?? '')
36
+ .split(',')
37
+ .map((s) => s.trim().replace(/^"|"$/g, ''))
38
+ .filter(Boolean);
39
+ expect(features).toContain('fullTextSearchPostgres');
40
+ });
41
+ });
42
+ //# sourceMappingURL=schema-preview-features.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema-preview-features.test.js","sourceRoot":"","sources":["../../src/__tests__/schema-preview-features.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AACtC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AACxC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAE5C,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAA;AAE7C;;;;;;;;;;;;;;GAcG;AACH,QAAQ,CAAC,gCAAgC,EAAE,GAAG,EAAE;IAC9C,MAAM,IAAI,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAA;IACpD,MAAM,UAAU,GAAG,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,eAAe,CAAC,CAAA;IACvE,MAAM,MAAM,GAAG,YAAY,CAAC,UAAU,EAAE,MAAM,CAAC,CAAA;IAE/C,EAAE,CAAC,sEAAsE,EAAE,GAAG,EAAE;QAC9E,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,oCAAoC,CAAC,CAAA;QAChE,MAAM,CAAC,KAAK,EAAE,oDAAoD,CAAC,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAA;QAClF,MAAM,QAAQ,GAAG,CAAC,KAAM,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;aAC/B,KAAK,CAAC,GAAG,CAAC;aACV,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;aAC1C,MAAM,CAAC,OAAO,CAAC,CAAA;QAClB,MAAM,CAAC,QAAQ,CAAC,CAAC,SAAS,CAAC,eAAe,CAAC,CAAA;IAC7C,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,wDAAwD,EAAE,GAAG,EAAE;QAChE,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,oCAAoC,CAAC,CAAA;QAChE,MAAM,QAAQ,GAAG,CAAC,KAAM,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;aAC/B,KAAK,CAAC,GAAG,CAAC;aACV,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;aAC1C,MAAM,CAAC,OAAO,CAAC,CAAA;QAClB,MAAM,CAAC,QAAQ,CAAC,CAAC,SAAS,CAAC,wBAAwB,CAAC,CAAA;IACtD,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"actions.d.ts","sourceRoot":"","sources":["../src/actions.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"actions.d.ts","sourceRoot":"","sources":["../src/actions.ts"],"names":[],"mappings":"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"}