@actuate-media/cms-core 0.90.0 → 0.91.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 (88) hide show
  1. package/CHANGELOG.md +69 -0
  2. package/dist/actions.d.ts +31 -1
  3. package/dist/actions.d.ts.map +1 -1
  4. package/dist/actions.js +76 -21
  5. package/dist/actions.js.map +1 -1
  6. package/dist/api/route-helpers.d.ts +4 -1
  7. package/dist/api/route-helpers.d.ts.map +1 -1
  8. package/dist/api/route-helpers.js +2 -2
  9. package/dist/api/route-helpers.js.map +1 -1
  10. package/dist/api/routes/documents.d.ts.map +1 -1
  11. package/dist/api/routes/documents.js +4 -1
  12. package/dist/api/routes/documents.js.map +1 -1
  13. package/dist/api/routes/media.d.ts.map +1 -1
  14. package/dist/api/routes/media.js +10 -0
  15. package/dist/api/routes/media.js.map +1 -1
  16. package/dist/api/routes/url-resolution.d.ts.map +1 -1
  17. package/dist/api/routes/url-resolution.js +4 -1
  18. package/dist/api/routes/url-resolution.js.map +1 -1
  19. package/dist/config/index.d.ts +16 -0
  20. package/dist/config/index.d.ts.map +1 -1
  21. package/dist/config/index.js +59 -2
  22. package/dist/config/index.js.map +1 -1
  23. package/dist/config/runtime.d.ts +8 -0
  24. package/dist/config/runtime.d.ts.map +1 -1
  25. package/dist/config/runtime.js.map +1 -1
  26. package/dist/config/types.d.ts +35 -4
  27. package/dist/config/types.d.ts.map +1 -1
  28. package/dist/index.d.ts +3 -1
  29. package/dist/index.d.ts.map +1 -1
  30. package/dist/index.js +1 -0
  31. package/dist/index.js.map +1 -1
  32. package/dist/media/usage-sync.d.ts +37 -0
  33. package/dist/media/usage-sync.d.ts.map +1 -0
  34. package/dist/media/usage-sync.js +234 -0
  35. package/dist/media/usage-sync.js.map +1 -0
  36. package/dist/realtime/comments.d.ts +1 -1
  37. package/dist/realtime/comments.js +1 -1
  38. package/dist/realtime/notifications.d.ts +1 -1
  39. package/dist/realtime/notifications.js +1 -1
  40. package/dist/realtime/persistence.d.ts +1 -1
  41. package/dist/search/index.d.ts.map +1 -1
  42. package/dist/search/index.js +58 -35
  43. package/dist/search/index.js.map +1 -1
  44. package/generated/browser.ts +229 -0
  45. package/generated/client.ts +253 -0
  46. package/generated/commonInputTypes.ts +1024 -0
  47. package/generated/enums.ts +211 -0
  48. package/generated/internal/class.ts +547 -0
  49. package/generated/internal/prismaNamespace.ts +4596 -0
  50. package/generated/internal/prismaNamespaceBrowser.ts +1188 -0
  51. package/generated/models/AiCrawlerHit.ts +1275 -0
  52. package/generated/models/ApiKey.ts +1559 -0
  53. package/generated/models/ApiRequestMetric.ts +1390 -0
  54. package/generated/models/AuditLog.ts +1215 -0
  55. package/generated/models/BackupRecord.ts +1259 -0
  56. package/generated/models/ContentIssue.ts +1496 -0
  57. package/generated/models/ContentLock.ts +1481 -0
  58. package/generated/models/ContentTemplate.ts +1425 -0
  59. package/generated/models/Document.ts +3486 -0
  60. package/generated/models/Folder.ts +1905 -0
  61. package/generated/models/FormSchemaVersion.ts +1265 -0
  62. package/generated/models/FormSubmission.ts +2105 -0
  63. package/generated/models/FormSubmissionFile.ts +1615 -0
  64. package/generated/models/FormWebhook.ts +1371 -0
  65. package/generated/models/InAppNotification.ts +1466 -0
  66. package/generated/models/Invite.ts +1393 -0
  67. package/generated/models/Media.ts +2887 -0
  68. package/generated/models/MediaUsage.ts +1488 -0
  69. package/generated/models/OAuthAccount.ts +1472 -0
  70. package/generated/models/PageTemplate.ts +1271 -0
  71. package/generated/models/PasswordResetToken.ts +1396 -0
  72. package/generated/models/Redirect.ts +1501 -0
  73. package/generated/models/Redirect404Hit.ts +1266 -0
  74. package/generated/models/RedirectSuggestion.ts +1344 -0
  75. package/generated/models/SavedSection.ts +1315 -0
  76. package/generated/models/ScriptTag.ts +1453 -0
  77. package/generated/models/SeoAuditRun.ts +1745 -0
  78. package/generated/models/SeoIssue.ts +2047 -0
  79. package/generated/models/Session.ts +1501 -0
  80. package/generated/models/Site.ts +1215 -0
  81. package/generated/models/User.ts +4558 -0
  82. package/generated/models/Version.ts +1520 -0
  83. package/generated/models/WebhookDeliveryLog.ts +1656 -0
  84. package/generated/models/WebhookEndpoint.ts +1433 -0
  85. package/generated/models/WorkflowState.ts +1523 -0
  86. package/generated/models.ts +46 -0
  87. package/package.json +10 -3
  88. package/{prisma → schema-fragments}/cms-schema.prisma +15 -2
@@ -0,0 +1,234 @@
1
+ import { createLogger } from '../diagnostics/logger.js';
2
+ const logger = createLogger('media-usage');
3
+ let warnedMissingBinding = false;
4
+ /**
5
+ * The MediaUsage join table is a denormalized index (which media each document
6
+ * references). It is maintained inside the document-write/delete transaction,
7
+ * but must never abort the primary write: if the Prisma `mediaUsage` delegate is
8
+ * missing from the client (e.g. a consumer bumped cms-core without regenerating
9
+ * their client, or an older generated client), skip and let `backfillMediaUsage`
10
+ * reconcile later. Real DB errors still propagate and roll the write back.
11
+ */
12
+ function hasMediaUsageDelegate(db) {
13
+ if (typeof db.mediaUsage?.deleteMany === 'function')
14
+ return true;
15
+ if (!warnedMissingBinding) {
16
+ warnedMissingBinding = true;
17
+ logger.warn('mediaUsage delegate unavailable on the DB client — skipping media-usage sync (run `prisma generate`)');
18
+ }
19
+ return false;
20
+ }
21
+ /** Remove every MediaUsage row for a document (e.g. on delete). Tolerates a missing delegate. */
22
+ export async function clearMediaUsageForDocument(db, documentId) {
23
+ if (!hasMediaUsageDelegate(db))
24
+ return;
25
+ await db.mediaUsage.deleteMany({ where: { documentId } });
26
+ }
27
+ const CUID_RE = /^c[a-z0-9]{20,}$/i;
28
+ const OBJECT_ID_RE = /^[a-f0-9]{24}$/i;
29
+ const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
30
+ const HTML_LIKE = /<\/?[a-z][\s\S]*>/i;
31
+ const IMG_SRC_RE = /<img\b[^>]*\ssrc=["']([^"']+)["']/gi;
32
+ const DATA_MEDIA_ID_RE = /data-media-id=["']([^"']+)["']/gi;
33
+ function isMediaId(value) {
34
+ return CUID_RE.test(value) || OBJECT_ID_RE.test(value) || UUID_RE.test(value);
35
+ }
36
+ function isResolvableUrl(value) {
37
+ if (!value || value.startsWith('data:') || value.startsWith('mailto:') || value.startsWith('#')) {
38
+ return false;
39
+ }
40
+ return (value.startsWith('http://') ||
41
+ value.startsWith('https://') ||
42
+ (value.startsWith('/') && !value.startsWith('//')));
43
+ }
44
+ function pushRef(out, fieldPath, partial) {
45
+ if (partial.mediaId || partial.url) {
46
+ out.push({ fieldPath, ...partial });
47
+ }
48
+ }
49
+ /** Extract candidate media IDs and URLs from document JSON with field paths. */
50
+ export function extractMediaReferences(data, pathPrefix = '') {
51
+ const out = [];
52
+ for (const [key, value] of Object.entries(data)) {
53
+ const fieldPath = pathPrefix ? `${pathPrefix}.${key}` : key;
54
+ collectMediaReferences(value, fieldPath, out);
55
+ }
56
+ return out;
57
+ }
58
+ function collectMediaReferences(value, fieldPath, out) {
59
+ if (typeof value === 'string') {
60
+ const trimmed = value.trim();
61
+ if (!trimmed)
62
+ return;
63
+ if (isMediaId(trimmed)) {
64
+ pushRef(out, fieldPath, { mediaId: trimmed });
65
+ return;
66
+ }
67
+ if (HTML_LIKE.test(trimmed)) {
68
+ for (const mediaId of extractMediaIdsFromHtml(trimmed)) {
69
+ pushRef(out, fieldPath, { mediaId });
70
+ }
71
+ for (const url of extractUrlsFromHtml(trimmed)) {
72
+ pushRef(out, fieldPath, { url });
73
+ }
74
+ return;
75
+ }
76
+ if (isResolvableUrl(trimmed)) {
77
+ pushRef(out, fieldPath, { url: trimmed });
78
+ }
79
+ return;
80
+ }
81
+ if (Array.isArray(value)) {
82
+ for (let i = 0; i < value.length; i++) {
83
+ collectMediaReferences(value[i], `${fieldPath}.${i}`, out);
84
+ }
85
+ return;
86
+ }
87
+ if (value && typeof value === 'object') {
88
+ const obj = value;
89
+ const id = obj.id;
90
+ if (typeof id === 'string' && isMediaId(id)) {
91
+ pushRef(out, fieldPath, { mediaId: id });
92
+ }
93
+ const url = obj.url ?? obj.publicUrl ?? obj.src ?? obj.imageUrl;
94
+ if (typeof url === 'string' && isResolvableUrl(url)) {
95
+ pushRef(out, fieldPath, { url });
96
+ }
97
+ for (const [key, nested] of Object.entries(obj)) {
98
+ if (key === 'id' ||
99
+ key === 'url' ||
100
+ key === 'publicUrl' ||
101
+ key === 'src' ||
102
+ key === 'imageUrl') {
103
+ continue;
104
+ }
105
+ collectMediaReferences(nested, `${fieldPath}.${key}`, out);
106
+ }
107
+ }
108
+ }
109
+ function extractMediaIdsFromHtml(html) {
110
+ const ids = new Set();
111
+ for (const re of [DATA_MEDIA_ID_RE]) {
112
+ re.lastIndex = 0;
113
+ let match;
114
+ while ((match = re.exec(html)) !== null) {
115
+ const id = match[1]?.trim();
116
+ if (id && isMediaId(id))
117
+ ids.add(id);
118
+ }
119
+ }
120
+ return [...ids];
121
+ }
122
+ function extractUrlsFromHtml(html) {
123
+ const urls = new Set();
124
+ IMG_SRC_RE.lastIndex = 0;
125
+ let match;
126
+ while ((match = IMG_SRC_RE.exec(html)) !== null) {
127
+ const url = match[1]?.trim();
128
+ if (url && isResolvableUrl(url))
129
+ urls.add(url);
130
+ }
131
+ return [...urls];
132
+ }
133
+ function usageKey(mediaId, fieldPath) {
134
+ return `${mediaId}\0${fieldPath}`;
135
+ }
136
+ /** Resolve extracted refs to existing media IDs (drops unknown IDs/URLs). */
137
+ export async function resolveMediaReferences(db, refs) {
138
+ const byKey = new Map();
139
+ for (const ref of refs) {
140
+ if (ref.mediaId) {
141
+ byKey.set(usageKey(ref.mediaId, ref.fieldPath), {
142
+ mediaId: ref.mediaId,
143
+ fieldPath: ref.fieldPath,
144
+ });
145
+ }
146
+ }
147
+ const urls = [...new Set(refs.map((r) => r.url).filter((u) => Boolean(u)))];
148
+ if (urls.length > 0) {
149
+ const rows = await db.media.findMany({
150
+ where: {
151
+ deletedAt: null,
152
+ OR: [{ publicUrl: { in: urls } }, { storageKey: { in: urls } }],
153
+ },
154
+ select: { id: true, publicUrl: true, storageKey: true },
155
+ });
156
+ const urlToId = new Map();
157
+ for (const row of rows) {
158
+ if (row.publicUrl)
159
+ urlToId.set(row.publicUrl, row.id);
160
+ if (row.storageKey)
161
+ urlToId.set(row.storageKey, row.id);
162
+ }
163
+ for (const ref of refs) {
164
+ if (!ref.url)
165
+ continue;
166
+ const mediaId = urlToId.get(ref.url);
167
+ if (mediaId) {
168
+ byKey.set(usageKey(mediaId, ref.fieldPath), { mediaId, fieldPath: ref.fieldPath });
169
+ }
170
+ }
171
+ }
172
+ const candidateIds = [...byKey.values()].map((u) => u.mediaId);
173
+ if (candidateIds.length === 0)
174
+ return [];
175
+ const existing = await db.media.findMany({
176
+ where: { id: { in: candidateIds }, deletedAt: null },
177
+ select: { id: true },
178
+ });
179
+ const allowed = new Set(existing.map((r) => r.id));
180
+ return [...byKey.values()].filter((u) => allowed.has(u.mediaId));
181
+ }
182
+ /** Replace all MediaUsage rows for a document with the refs found in `data`. */
183
+ export async function syncMediaUsageForDocument(db, documentId, data) {
184
+ if (!hasMediaUsageDelegate(db))
185
+ return;
186
+ const refs = extractMediaReferences(data && typeof data === 'object' ? data : {});
187
+ const resolved = await resolveMediaReferences(db, refs);
188
+ await db.mediaUsage.deleteMany({ where: { documentId } });
189
+ if (resolved.length === 0)
190
+ return;
191
+ await db.mediaUsage.createMany({
192
+ data: resolved.map((row) => ({
193
+ mediaId: row.mediaId,
194
+ documentId,
195
+ fieldPath: row.fieldPath,
196
+ })),
197
+ skipDuplicates: true,
198
+ });
199
+ }
200
+ /** Re-scan all non-deleted documents and rebuild MediaUsage join rows. */
201
+ export async function backfillMediaUsage(db, options = {}) {
202
+ const dryRun = options.dryRun ?? false;
203
+ const batchSize = options.batchSize && options.batchSize > 0 ? options.batchSize : 100;
204
+ const result = { scanned: 0, synced: 0, skipped: 0 };
205
+ let cursor;
206
+ for (;;) {
207
+ const batch = await db.document.findMany({
208
+ where: { deletedAt: null },
209
+ orderBy: { id: 'asc' },
210
+ take: batchSize,
211
+ ...(cursor ? { skip: 1, cursor: { id: cursor } } : {}),
212
+ select: { id: true, data: true },
213
+ });
214
+ if (batch.length === 0)
215
+ break;
216
+ cursor = batch[batch.length - 1].id;
217
+ for (const doc of batch) {
218
+ result.scanned++;
219
+ const data = doc.data && typeof doc.data === 'object' ? doc.data : null;
220
+ if (!data) {
221
+ result.skipped++;
222
+ continue;
223
+ }
224
+ if (!dryRun) {
225
+ await syncMediaUsageForDocument(db, doc.id, data);
226
+ }
227
+ result.synced++;
228
+ }
229
+ if (batch.length < batchSize)
230
+ break;
231
+ }
232
+ return result;
233
+ }
234
+ //# sourceMappingURL=usage-sync.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usage-sync.js","sourceRoot":"","sources":["../../src/media/usage-sync.ts"],"names":[],"mappings":"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"}
@@ -6,7 +6,7 @@
6
6
  * is a thin wrapper that handles auth + JSON envelope; everything else lives
7
7
  * here so the unit tests don't need a Request loop.
8
8
  *
9
- * Storage shape — see `packages/cms-core/prisma/cms-schema.prisma`,
9
+ * Storage shape — see `packages/cms-core/schema-fragments/cms-schema.prisma`,
10
10
  * model `DocumentComment`. We require only a minimal Prisma surface so the
11
11
  * helpers can be tested against an in-memory fake.
12
12
  *
@@ -6,7 +6,7 @@
6
6
  * is a thin wrapper that handles auth + JSON envelope; everything else lives
7
7
  * here so the unit tests don't need a Request loop.
8
8
  *
9
- * Storage shape — see `packages/cms-core/prisma/cms-schema.prisma`,
9
+ * Storage shape — see `packages/cms-core/schema-fragments/cms-schema.prisma`,
10
10
  * model `DocumentComment`. We require only a minimal Prisma surface so the
11
11
  * helpers can be tested against an in-memory fake.
12
12
  *
@@ -7,7 +7,7 @@
7
7
  * envelope; the comments hook layer (slice 6, `notification-triggers.ts`)
8
8
  * calls these helpers when a comment lifecycle event fires.
9
9
  *
10
- * Storage shape — see `packages/cms-core/prisma/cms-schema.prisma`, model
10
+ * Storage shape — see `packages/cms-core/schema-fragments/cms-schema.prisma`, model
11
11
  * `DocumentNotification`. We require only a minimal Prisma surface so the
12
12
  * helpers can be tested against an in-memory fake.
13
13
  *
@@ -7,7 +7,7 @@
7
7
  * envelope; the comments hook layer (slice 6, `notification-triggers.ts`)
8
8
  * calls these helpers when a comment lifecycle event fires.
9
9
  *
10
- * Storage shape — see `packages/cms-core/prisma/cms-schema.prisma`, model
10
+ * Storage shape — see `packages/cms-core/schema-fragments/cms-schema.prisma`, model
11
11
  * `DocumentNotification`. We require only a minimal Prisma surface so the
12
12
  * helpers can be tested against an in-memory fake.
13
13
  *
@@ -2,7 +2,7 @@
2
2
  * Prisma-backed `DocumentPersistence` for `@actuate-media/realtime`.
3
3
  *
4
4
  * Reads and writes the `DocumentCRDT` table (see
5
- * `prisma/cms-schema.prisma`). The adapter is intentionally narrow — it only
5
+ * `schema-fragments/cms-schema.prisma`). The adapter is intentionally narrow — it only
6
6
  * implements the two methods declared by the realtime package, so it can be
7
7
  * swapped for an S3 / Redis / Postgres-LO adapter without touching the
8
8
  * gateway code.
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/search/index.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,aAAa;IAC5B,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAED,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,CAAA;IACZ,UAAU,EAAE,MAAM,CAAA;IAClB,OAAO,EAAE,MAAM,CAAA;IACf,KAAK,EAAE,MAAM,CAAA;IACb,UAAU,EAAE,MAAM,EAAE,CAAA;CACrB;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,YAAY,EAAE,CAAA;IACvB,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,MAAM,CAAA;CACjB;AAgBD,+EAA+E;AAC/E,wBAAsB,eAAe,CACnC,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,aAAkB,GAC1B,OAAO,CAAC,cAAc,CAAC,CAkHzB"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/search/index.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,aAAa;IAC5B,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAED,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,CAAA;IACZ,UAAU,EAAE,MAAM,CAAA;IAClB,OAAO,EAAE,MAAM,CAAA;IACf,KAAK,EAAE,MAAM,CAAA;IACb,UAAU,EAAE,MAAM,EAAE,CAAA;CACrB;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,YAAY,EAAE,CAAA;IACvB,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,MAAM,CAAA;CACjB;AAgBD,+EAA+E;AAC/E,wBAAsB,eAAe,CACnC,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,aAAkB,GAC1B,OAAO,CAAC,cAAc,CAAC,CAoIzB"}
@@ -1,4 +1,6 @@
1
1
  import { getDB } from '../db.js';
2
+ /** Hard cap on search page size so a client can't request an unbounded scan. */
3
+ const MAX_SEARCH_PAGE_SIZE = 100;
2
4
  /**
3
5
  * Convert a user query into a Postgres tsquery-compatible string.
4
6
  * Splits on whitespace, strips non-word chars, joins with & for AND matching.
@@ -25,39 +27,35 @@ export async function searchDocuments(query, options = {}) {
25
27
  if (!tsQueryStr) {
26
28
  return { results: [], total: 0, page, pageSize };
27
29
  }
28
- const conditions = [`d."deletedAt" IS NULL`];
29
- const params = [];
30
+ // Filters shared by both the FTS and the ILIKE fallback pass.
31
+ const baseConditions = [`d."deletedAt" IS NULL`];
32
+ const baseParams = [];
30
33
  let paramIdx = 1;
31
34
  // tsquery as a parameter instead of inline interpolation
32
- params.push(tsQueryStr);
35
+ baseParams.push(tsQueryStr);
33
36
  const tsQueryParam = `$${paramIdx++}`;
34
37
  if (collection) {
35
- conditions.push(`d."collection" = $${paramIdx++}`);
36
- params.push(collection);
38
+ baseConditions.push(`d."collection" = $${paramIdx++}`);
39
+ baseParams.push(collection);
37
40
  }
38
41
  if (locale) {
39
- conditions.push(`d."locale" = $${paramIdx++}`);
40
- params.push(locale);
42
+ baseConditions.push(`d."locale" = $${paramIdx++}`);
43
+ baseParams.push(locale);
41
44
  }
42
45
  if (status) {
43
- conditions.push(`d."status"::text = $${paramIdx++}`);
44
- params.push(status);
46
+ baseConditions.push(`d."status"::text = $${paramIdx++}`);
47
+ baseParams.push(status);
45
48
  }
46
- const whereClause = conditions.join(' AND ');
49
+ const baseWhere = baseConditions.join(' AND ');
47
50
  const ftsVector = `to_tsvector('english', COALESCE(d."title", '') || ' ' || COALESCE(d."plainText", ''))`;
48
51
  const ftsCondition = `(${ftsVector} @@ to_tsquery('english', ${tsQueryParam}))`;
49
- const ilikePlaceholder = `$${paramIdx}`;
50
- params.push(`%${sanitized}%`);
51
- paramIdx++;
52
- const fallbackCondition = `(d."title" ILIKE ${ilikePlaceholder} OR d."plainText" ILIKE ${ilikePlaceholder})`;
53
52
  const rankExpr = `ts_rank_cd(${ftsVector}, to_tsquery('english', ${tsQueryParam}))`;
54
53
  const headline = `ts_headline('english', COALESCE(d."plainText", ''), to_tsquery('english', ${tsQueryParam}), 'StartSel=<mark>, StopSel=</mark>, MaxWords=35, MinWords=15, MaxFragments=2')`;
55
- const limitParam = `$${paramIdx++}`;
56
- params.push(pageSize);
57
- const offsetParam = `$${paramIdx++}`;
58
- params.push(offset);
59
- const sql = `
60
- SELECT
54
+ // Clamp pagination so a client can't request an unbounded page (LIMIT/OFFSET
55
+ // were previously taken from the request verbatim).
56
+ const safePageSize = Math.min(Math.max(1, Math.floor(pageSize)), MAX_SEARCH_PAGE_SIZE);
57
+ const safeOffset = Math.max(0, (page - 1) * safePageSize);
58
+ const selectList = `
61
59
  d."id",
62
60
  d."title",
63
61
  d."slug",
@@ -66,27 +64,52 @@ export async function searchDocuments(query, options = {}) {
66
64
  d."updatedAt",
67
65
  ${rankExpr} AS score,
68
66
  ${headline} AS headline,
69
- LEFT(COALESCE(d."plainText", ''), 200) AS excerpt
67
+ LEFT(COALESCE(d."plainText", ''), 200) AS excerpt`;
68
+ // First free placeholder after the base params.
69
+ const nextIdx = paramIdx;
70
+ // Primary query: FTS only. Critically, the WHERE does NOT OR-in an
71
+ // un-indexable ILIKE, so Postgres can use the `idx_actuate_documents_fts`
72
+ // GIN index instead of sequentially scanning every row on each search.
73
+ const ftsRowsSql = `
74
+ SELECT ${selectList}
70
75
  FROM "actuate_documents" d
71
- WHERE ${whereClause}
72
- AND (${ftsCondition} OR ${fallbackCondition})
76
+ WHERE ${baseWhere} AND ${ftsCondition}
73
77
  ORDER BY score DESC, d."updatedAt" DESC
74
- LIMIT ${limitParam}
75
- OFFSET ${offsetParam}
78
+ LIMIT $${nextIdx} OFFSET $${nextIdx + 1}
76
79
  `;
77
- const countSql = `
78
- SELECT COUNT(*)::int AS total
80
+ const ftsCountSql = `SELECT COUNT(*)::int AS total FROM "actuate_documents" d WHERE ${baseWhere} AND ${ftsCondition}`;
81
+ // Substring fallback (ILIKE) only run when FTS matches nothing, so the
82
+ // common path never pays for the sequential scan.
83
+ const ilikeParam = `$${nextIdx}`;
84
+ const ilikeCondition = `(d."title" ILIKE ${ilikeParam} OR d."plainText" ILIKE ${ilikeParam})`;
85
+ const ilikeRowsSql = `
86
+ SELECT ${selectList}
79
87
  FROM "actuate_documents" d
80
- WHERE ${whereClause}
81
- AND (${ftsCondition} OR ${fallbackCondition})
88
+ WHERE ${baseWhere} AND ${ilikeCondition}
89
+ ORDER BY score DESC, d."updatedAt" DESC
90
+ LIMIT $${nextIdx + 1} OFFSET $${nextIdx + 2}
82
91
  `;
83
- const countParams = params.slice(0, -2);
92
+ const ilikeCountSql = `SELECT COUNT(*)::int AS total FROM "actuate_documents" d WHERE ${baseWhere} AND ${ilikeCondition}`;
93
+ const ilikeValue = `%${sanitized}%`;
84
94
  try {
85
- const [rows, countRows] = await Promise.all([
86
- db.$queryRawUnsafe(sql, ...params),
87
- db.$queryRawUnsafe(countSql, ...countParams),
95
+ let rows;
96
+ let total;
97
+ const [ftsRows, ftsCountRows] = await Promise.all([
98
+ db.$queryRawUnsafe(ftsRowsSql, ...baseParams, safePageSize, safeOffset),
99
+ db.$queryRawUnsafe(ftsCountSql, ...baseParams),
88
100
  ]);
89
- const total = countRows[0]?.total ?? 0;
101
+ total = ftsCountRows[0]?.total ?? 0;
102
+ if (total > 0) {
103
+ rows = ftsRows;
104
+ }
105
+ else {
106
+ const [ilikeRows, ilikeCountRows] = await Promise.all([
107
+ db.$queryRawUnsafe(ilikeRowsSql, ...baseParams, ilikeValue, safePageSize, safeOffset),
108
+ db.$queryRawUnsafe(ilikeCountSql, ...baseParams, ilikeValue),
109
+ ]);
110
+ rows = ilikeRows;
111
+ total = ilikeCountRows[0]?.total ?? 0;
112
+ }
90
113
  const results = rows.map((row) => {
91
114
  const headlineText = row.headline ?? '';
92
115
  const highlights = headlineText
@@ -102,7 +125,7 @@ export async function searchDocuments(query, options = {}) {
102
125
  highlights,
103
126
  };
104
127
  });
105
- return { results, total, page, pageSize };
128
+ return { results, total, page, pageSize: safePageSize };
106
129
  }
107
130
  catch {
108
131
  return fallbackSearch(sanitized, options);
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/search/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/search/index.ts"],"names":[],"mappings":"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"}