@murumets-ee/content 0.3.0 → 0.4.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +94 -0
- package/dist/{block-diff-H1AttKiz.mjs → block-diff-BBH6FoFT.mjs} +1 -1
- package/dist/{block-diff-H1AttKiz.mjs.map → block-diff-BBH6FoFT.mjs.map} +1 -1
- package/dist/blocks/index.d.mts +1 -1
- package/dist/blocks/index.mjs +1 -1
- package/dist/client.d.mts +160 -18
- package/dist/client.d.mts.map +1 -1
- package/dist/client.mjs +1 -1
- package/dist/client.mjs.map +1 -1
- package/dist/{define-block-D-7OpIn5.mjs → define-block-DpMPEEdA.mjs} +1 -1
- package/dist/{define-block-D-7OpIn5.mjs.map → define-block-DpMPEEdA.mjs.map} +1 -1
- package/dist/drafts-CyOivEtr.mjs +2 -0
- package/dist/drafts-CyOivEtr.mjs.map +1 -0
- package/dist/index.d.mts +2 -2
- package/dist/index.mjs +1 -1
- package/dist/locale-status-DTyv4wcn.mjs +2 -0
- package/dist/locale-status-DTyv4wcn.mjs.map +1 -0
- package/dist/lock-service.d.mts +3 -4
- package/dist/lock-service.d.mts.map +1 -1
- package/dist/lock-service.mjs +1 -1
- package/dist/lock-service.mjs.map +1 -1
- package/dist/locks-BkO2qMfm.mjs +2 -0
- package/dist/locks-BkO2qMfm.mjs.map +1 -0
- package/dist/plugin.d.mts +1 -1
- package/dist/plugin.mjs +1 -1
- package/dist/plugin.mjs.map +1 -1
- package/dist/query-client.d.mts +80 -14
- package/dist/query-client.d.mts.map +1 -1
- package/dist/query-client.mjs +1 -1
- package/dist/query-client.mjs.map +1 -1
- package/dist/registry-BJSOGFEN.mjs +2 -0
- package/dist/registry-BJSOGFEN.mjs.map +1 -0
- package/dist/rolldown-runtime-DR3Ue2cl.mjs +1 -0
- package/dist/{types-nXbE5Ufa.d.mts → types-COcneY5H.d.mts} +1 -1
- package/dist/{types-nXbE5Ufa.d.mts.map → types-COcneY5H.d.mts.map} +1 -1
- package/dist/{types-wLHyjcWf.d.mts → types-D-ATlx7t.d.mts} +1 -1
- package/dist/{types-wLHyjcWf.d.mts.map → types-D-ATlx7t.d.mts.map} +1 -1
- package/dist/versions-CO6oDyet.mjs +2 -0
- package/dist/versions-CO6oDyet.mjs.map +1 -0
- package/package.json +12 -12
- package/dist/drafts-BYyRdmiT.mjs +0 -2
- package/dist/drafts-BYyRdmiT.mjs.map +0 -1
- package/dist/locale-status-CGttT38v.mjs +0 -2
- package/dist/locale-status-CGttT38v.mjs.map +0 -1
- package/dist/locks-CNxQJieo.mjs +0 -2
- package/dist/locks-CNxQJieo.mjs.map +0 -1
- package/dist/versions-cotph2VG.mjs +0 -2
- package/dist/versions-cotph2VG.mjs.map +0 -1
package/LICENSE
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
Elastic License 2.0 (ELv2)
|
|
2
|
+
|
|
3
|
+
URL: https://www.elastic.co/licensing/elastic-license
|
|
4
|
+
|
|
5
|
+
## Acceptance
|
|
6
|
+
|
|
7
|
+
By using the software, you agree to all of the terms and conditions below.
|
|
8
|
+
|
|
9
|
+
## Copyright License
|
|
10
|
+
|
|
11
|
+
The licensor grants you a non-exclusive, royalty-free, worldwide,
|
|
12
|
+
non-sublicensable, non-transferable license to use, copy, distribute, make
|
|
13
|
+
available, and prepare derivative works of the software, in each case subject
|
|
14
|
+
to the limitations and conditions below.
|
|
15
|
+
|
|
16
|
+
## Limitations
|
|
17
|
+
|
|
18
|
+
You may not provide the software to third parties as a hosted or managed
|
|
19
|
+
service, where the service provides users with access to any substantial set
|
|
20
|
+
of the features or functionality of the software.
|
|
21
|
+
|
|
22
|
+
You may not move, change, disable, or circumvent the license key functionality
|
|
23
|
+
in the software, and you may not remove or obscure any functionality in the
|
|
24
|
+
software that is protected by the license key.
|
|
25
|
+
|
|
26
|
+
You may not alter, remove, or obscure any licensing, copyright, or other
|
|
27
|
+
notices of the licensor in the software. Any use of the licensor's trademarks
|
|
28
|
+
is subject to applicable law.
|
|
29
|
+
|
|
30
|
+
## Patents
|
|
31
|
+
|
|
32
|
+
The licensor grants you a license, under any patent claims the licensor can
|
|
33
|
+
license, or becomes able to license, to make, have made, use, sell, offer for
|
|
34
|
+
sale, import and have imported the software, in each case subject to the
|
|
35
|
+
limitations and conditions in this license. This license does not cover any
|
|
36
|
+
patent claims that you cause to be infringed by modifications or additions to
|
|
37
|
+
the software. If you or your company make any written claim that the software
|
|
38
|
+
infringes or contributes to infringement of any patent, your patent license
|
|
39
|
+
for the software granted under these terms ends immediately. If your company
|
|
40
|
+
makes such a claim, your patent license ends immediately for work on behalf
|
|
41
|
+
of your company.
|
|
42
|
+
|
|
43
|
+
## Notices
|
|
44
|
+
|
|
45
|
+
You must ensure that anyone who gets a copy of any part of the software from
|
|
46
|
+
you also gets a copy of these terms.
|
|
47
|
+
|
|
48
|
+
If you modify the software, you must include in any modified copies of the
|
|
49
|
+
software prominent notices stating that you have modified the software.
|
|
50
|
+
|
|
51
|
+
## No Other Rights
|
|
52
|
+
|
|
53
|
+
These terms do not imply any licenses other than those expressly granted in
|
|
54
|
+
these terms.
|
|
55
|
+
|
|
56
|
+
## Termination
|
|
57
|
+
|
|
58
|
+
If you use the software in violation of these terms, such use is not licensed,
|
|
59
|
+
and your licenses will automatically terminate. If the licensor provides you
|
|
60
|
+
with a notice of your violation, and you cease all violation of this license
|
|
61
|
+
no later than 30 days after you receive that notice, your licenses will be
|
|
62
|
+
reinstated retroactively. However, if you violate these terms after such
|
|
63
|
+
reinstatement, any additional violation of these terms will cause your
|
|
64
|
+
licenses to terminate automatically and permanently.
|
|
65
|
+
|
|
66
|
+
## No Liability
|
|
67
|
+
|
|
68
|
+
As far as the law allows, the software comes as is, without any warranty or
|
|
69
|
+
condition, and the licensor will not be liable to you for any damages arising
|
|
70
|
+
out of these terms or the use or nature of the software, under any kind of
|
|
71
|
+
legal claim.
|
|
72
|
+
|
|
73
|
+
## Definitions
|
|
74
|
+
|
|
75
|
+
The **licensor** is the entity offering these terms, and the **software** is
|
|
76
|
+
the software the licensor makes available under these terms, including any
|
|
77
|
+
portion of it.
|
|
78
|
+
|
|
79
|
+
**you** refers to the individual or entity agreeing to these terms.
|
|
80
|
+
|
|
81
|
+
**your company** is any legal entity, sole proprietorship, or other kind of
|
|
82
|
+
organization that you work for, plus all organizations that have control over,
|
|
83
|
+
are under the control of, or are under common control with that organization.
|
|
84
|
+
**control** means ownership of substantially all the assets of an entity, or
|
|
85
|
+
the power to direct the management and policies of an entity (for example, by
|
|
86
|
+
voting right, contract, or otherwise). Control can be direct or indirect.
|
|
87
|
+
|
|
88
|
+
**your licenses** are all the licenses granted to you for the software under
|
|
89
|
+
these terms.
|
|
90
|
+
|
|
91
|
+
**use** means anything you do with the software requiring one of your
|
|
92
|
+
licenses.
|
|
93
|
+
|
|
94
|
+
**trademark** means trademarks, service marks, and similar rights.
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import{field as e}from"@murumets-ee/entity";const t={maxPerDoc:50,autosave:!1};function n(n){let r={...t,...n};return{name:`versionable`,fields:{_version:e.number({required:!0,default:1,integer:!0}),_versionedAt:e.date()},hooks:{beforeCreate:async e=>(e._version=1,e._versionedAt=new Date,e),beforeUpdate:async(e,t)=>(t._versionedAt=new Date,t)},_versionableOptions:r}}function r(e){return e?e.find(e=>e.name===`versionable`)?._versionableOptions??null:null}function i(e){return e.match(/\S+|\s+/g)??[]}function a(e,t){if(e===t)return e?[{type:`equal`,value:e}]:[];if(!e)return[{type:`add`,value:t}];if(!t)return[{type:`remove`,value:e}];let n=i(e),r=i(t),a=n.length,o=r.length,s=Array.from({length:a+1},()=>Array(o+1).fill(0));for(let e=1;e<=a;e++)for(let t=1;t<=o;t++)n[e-1]===r[t-1]?s[e][t]=s[e-1][t-1]+1:s[e][t]=Math.max(s[e-1][t],s[e][t-1]);let c=[],l=a,u=o,d=[];for(;l>0||u>0;)l>0&&u>0&&n[l-1]===r[u-1]?(d.push({type:`equal`,value:n[l-1]}),l--,u--):u>0&&(l===0||s[l][u-1]>=s[l-1][u])?(d.push({type:`add`,value:r[u-1]}),u--):(d.push({type:`remove`,value:n[l-1]}),l--);d.reverse();for(let e of d){let t=c[c.length-1];t&&t.type===e.type?t.value+=e.value:c.push({...e})}return c}function o(e){return e.replace(/<[^>]*>/g,` `).replace(/\s+/g,` `).trim()}function s(e){return e==null?``:e instanceof Date?e.toISOString():typeof e==`object`?JSON.stringify(e):String(e)}function c(e,t,n,r){if(JSON.stringify(t)===JSON.stringify(n))return null;switch(r?.type??u(t,n)){case`text`:case`slug`:return{field:e,type:`text`,from:t,to:n,segments:a(s(t),s(n))};case`richtext`:return{field:e,type:`richtext`,from:t,to:n,segments:a(o(s(t)),o(s(n)))};case`number`:return{field:e,type:`number`,from:t,to:n};case`boolean`:return{field:e,type:`boolean`,from:t,to:n};case`date`:return{field:e,type:`date`,from:t,to:n};case`select`:return{field:e,type:`select`,from:t,to:n};case`media`:return{field:e,type:`media`,from:t,to:n};case`json`:return{field:e,type:`json`,from:t,to:n};case`blocks`:return{field:e,type:`blocks`,from:t,to:n};default:return{field:e,type:`unknown`,from:t,to:n}}}function l(e,t,n){let r=new Set([...Object.keys(e),...Object.keys(t)]),i=[];for(let a of r){if(a===`id`||a===`createdAt`||a===`updatedAt`)continue;let r=c(a,e[a],t[a],n?.[a]);r&&i.push(r)}return i}function u(e,t){let n=e??t;return typeof n==`number`?`number`:typeof n==`boolean`?`boolean`:n instanceof Date?`date`:typeof n==`string`?/^\d{4}-\d{2}-\d{2}/.test(n)?`date`:`text`:Array.isArray(n)?n.length>0&&typeof n[0]==`object`&&n[0]!==null&&`_block`in n[0]?`blocks`:`json`:typeof n==`object`?`json`:`unknown`}function d(e,t){if(typeof e==`string`||typeof t==`string`)return a(s(e),s(t))}function f(e){return typeof e==`object`&&!!e&&`_block`in e&&`_id`in e&&typeof e._block==`string`&&typeof e._id==`string`}function p(e,t){let n=new Set([...Object.keys(e),...Object.keys(t)]),r=[];for(let i of n){if(i===`_block`||i===`_id`)continue;let n=e[i],a=t[i];JSON.stringify(n)!==JSON.stringify(a)&&r.push({field:i,from:n,to:a,segments:d(n,a)})}return r}function m(e,t){let n=e.filter(f),r=t.filter(f),i=new Map,a=new Map;for(let e=0;e<n.length;e++)i.set(n[e]._id,{block:n[e],index:e});for(let e=0;e<r.length;e++)a.set(r[e]._id,{block:r[e],index:e});let o=[],s=new Set;for(let[e,{block:t,index:n}]of a){s.add(e);let r=i.get(e);if(!r){o.push({blockId:e,blockType:t._block,status:`added`,toIndex:n});continue}let a=r.block,c=r.index,l=p(a,t),u=c!==n;l.length===0&&!u?o.push({blockId:e,blockType:t._block,status:`unchanged`,fromIndex:c,toIndex:n}):l.length>0?o.push({blockId:e,blockType:t._block,status:`changed`,fromIndex:c,toIndex:n,propDiffs:l}):o.push({blockId:e,blockType:t._block,status:`moved`,fromIndex:c,toIndex:n})}for(let[e,{block:t,index:n}]of i)s.has(e)||o.push({blockId:e,blockType:t._block,status:`removed`,fromIndex:n});return o}export{a,d as i,c as n,r as o,l as r,n as s,m as t};
|
|
2
|
-
//# sourceMappingURL=block-diff-
|
|
2
|
+
//# sourceMappingURL=block-diff-BBH6FoFT.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"block-diff-H1AttKiz.mjs","names":[],"sources":["../src/behaviors/versionable.ts","../src/diff/text-diff.ts","../src/diff/field-diff.ts","../src/diff/block-diff.ts"],"sourcesContent":["/**\n * Versionable behavior — full version history with snapshots.\n *\n * Extends the concept of revisionable() (which only tracks a counter)\n * with actual version snapshots stored in {entity}_versions table.\n *\n * The behavior itself adds fields + hooks for version tracking.\n * Actual snapshot persistence happens in ContentClient (which has DB access).\n *\n * Options:\n * - maxPerDoc: Maximum versions kept per document (default: 50)\n * - autosave: Enable smart autosave (default: false)\n */\n\nimport type { Behavior, DateField, NumberField } from '@murumets-ee/entity'\n\nimport { field } from '@murumets-ee/entity'\nimport type { VersionableOptions } from '../types.js'\n\nexport type VersionableFields = {\n _version: NumberField & { required: true }\n _versionedAt: DateField\n}\n\nconst DEFAULT_OPTIONS: Required<VersionableOptions> = {\n maxPerDoc: 50,\n autosave: false,\n}\n\nexport function versionable(options?: VersionableOptions): Behavior<VersionableFields> {\n const opts = { ...DEFAULT_OPTIONS, ...options }\n\n // Attach options to the behavior for ContentClient to read\n const behavior: Behavior<VersionableFields> & {\n _versionableOptions: Required<VersionableOptions>\n } = {\n name: 'versionable',\n fields: {\n _version: field.number({ required: true, default: 1, integer: true }),\n _versionedAt: field.date(),\n },\n hooks: {\n beforeCreate: async (data) => {\n data._version = 1\n data._versionedAt = new Date()\n return data\n },\n beforeUpdate: async (_id, data) => {\n // Only update _versionedAt here. The _version increment is handled by\n // createVersionSnapshot which reads the current version from the DB.\n // The beforeUpdate hook only receives partial data (the PATCH payload),\n // so it can't reliably increment _version without the current value.\n data._versionedAt = new Date()\n return data\n },\n },\n _versionableOptions: opts,\n }\n\n return behavior as Behavior<VersionableFields>\n}\n\n/**\n * Extract versionable options from an entity's behaviors\n */\nexport function getVersionableOptions(behaviors?: Behavior[]): Required<VersionableOptions> | null {\n if (!behaviors) return null\n const vBehavior = behaviors.find((b) => b.name === 'versionable') as\n | (Behavior & { _versionableOptions?: Required<VersionableOptions> })\n | undefined\n return vBehavior?._versionableOptions ?? null\n}\n","/**\n * Word-level text diff using a simplified Myers algorithm.\n *\n * Splits text into words (preserving whitespace), computes the longest common\n * subsequence, and returns an array of diff segments.\n */\n\nimport type { DiffSegment } from './types.js'\n\n/**\n * Split text into tokens — words and whitespace runs — so diffs are\n * human-readable (\"Changed *this* word\") rather than character-level.\n */\nfunction tokenize(text: string): string[] {\n return text.match(/\\S+|\\s+/g) ?? []\n}\n\n/**\n * Compute word-level diff between two strings.\n *\n * Uses a simple LCS (dynamic programming) approach which is fine for\n * the text sizes we deal with (entity field values, not source code).\n */\nexport function diffText(from: string, to: string): DiffSegment[] {\n if (from === to) {\n return from ? [{ type: 'equal', value: from }] : []\n }\n if (!from) {\n return [{ type: 'add', value: to }]\n }\n if (!to) {\n return [{ type: 'remove', value: from }]\n }\n\n const fromTokens = tokenize(from)\n const toTokens = tokenize(to)\n\n // Build LCS table\n const m = fromTokens.length\n const n = toTokens.length\n const dp: number[][] = Array.from({ length: m + 1 }, () => new Array(n + 1).fill(0))\n\n for (let i = 1; i <= m; i++) {\n for (let j = 1; j <= n; j++) {\n if (fromTokens[i - 1] === toTokens[j - 1]) {\n dp[i][j] = dp[i - 1][j - 1] + 1\n } else {\n dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1])\n }\n }\n }\n\n // Backtrack to build diff segments\n const segments: DiffSegment[] = []\n let i = m\n let j = n\n\n // Collect in reverse, then flip\n const reversed: DiffSegment[] = []\n\n while (i > 0 || j > 0) {\n if (i > 0 && j > 0 && fromTokens[i - 1] === toTokens[j - 1]) {\n reversed.push({ type: 'equal', value: fromTokens[i - 1] })\n i--\n j--\n } else if (j > 0 && (i === 0 || dp[i][j - 1] >= dp[i - 1][j])) {\n reversed.push({ type: 'add', value: toTokens[j - 1] })\n j--\n } else {\n reversed.push({ type: 'remove', value: fromTokens[i - 1] })\n i--\n }\n }\n\n reversed.reverse()\n\n // Merge consecutive segments of the same type\n for (const seg of reversed) {\n const last = segments[segments.length - 1]\n if (last && last.type === seg.type) {\n last.value += seg.value\n } else {\n segments.push({ ...seg })\n }\n }\n\n return segments\n}\n","/**\n * Field-level diff — dispatches to the appropriate diff strategy per field type.\n */\n\nimport type { FieldConfig } from '@murumets-ee/entity'\nimport { diffText } from './text-diff.js'\nimport type { DiffSegment, FieldDiff } from './types.js'\n\n/** Strip HTML tags for diffing richtext content as plain text. */\nfunction stripHtml(html: string): string {\n return html\n .replace(/<[^>]*>/g, ' ')\n .replace(/\\s+/g, ' ')\n .trim()\n}\n\n/** Stringify a value for display (dates, objects, etc.). */\nfunction stringify(value: unknown): string {\n if (value === null || value === undefined) return ''\n if (value instanceof Date) return value.toISOString()\n if (typeof value === 'object') return JSON.stringify(value)\n return String(value)\n}\n\n/**\n * Compute diff for a single field, using the field's type to determine\n * the best diff strategy.\n */\nexport function diffField(\n fieldName: string,\n from: unknown,\n to: unknown,\n fieldConfig?: FieldConfig,\n): FieldDiff | null {\n // No change\n if (JSON.stringify(from) === JSON.stringify(to)) return null\n\n const type = fieldConfig?.type ?? inferType(from, to)\n\n switch (type) {\n case 'text':\n case 'slug': {\n const segments = diffText(stringify(from), stringify(to))\n return { field: fieldName, type: 'text', from, to, segments }\n }\n\n case 'richtext': {\n // Diff on stripped HTML so users see word changes, not tag noise\n const segments = diffText(stripHtml(stringify(from)), stripHtml(stringify(to)))\n return { field: fieldName, type: 'richtext', from, to, segments }\n }\n\n case 'number':\n return { field: fieldName, type: 'number', from, to }\n\n case 'boolean':\n return { field: fieldName, type: 'boolean', from, to }\n\n case 'date':\n return { field: fieldName, type: 'date', from, to }\n\n case 'select':\n return { field: fieldName, type: 'select', from, to }\n\n case 'media':\n return { field: fieldName, type: 'media', from, to }\n\n case 'json':\n return { field: fieldName, type: 'json', from, to }\n\n case 'blocks':\n // Blocks are handled separately by block-diff.ts — just mark the field\n return { field: fieldName, type: 'blocks', from, to }\n\n default:\n return { field: fieldName, type: 'unknown', from, to }\n }\n}\n\n/**\n * Diff all fields between two version snapshots.\n * Pass fieldConfigs to get type-aware diffs; without them, types are inferred.\n */\nexport function diffFields(\n from: Record<string, unknown>,\n to: Record<string, unknown>,\n fieldConfigs?: Record<string, FieldConfig>,\n): FieldDiff[] {\n const allKeys = new Set([...Object.keys(from), ...Object.keys(to)])\n const diffs: FieldDiff[] = []\n\n for (const key of allKeys) {\n // Skip internal/auto-generated fields\n if (key === 'id' || key === 'createdAt' || key === 'updatedAt') continue\n\n const diff = diffField(key, from[key], to[key], fieldConfigs?.[key])\n if (diff) diffs.push(diff)\n }\n\n return diffs\n}\n\n/** Best-effort type inference when no FieldConfig is available. */\nfunction inferType(from: unknown, to: unknown): string {\n const val = from ?? to\n if (typeof val === 'number') return 'number'\n if (typeof val === 'boolean') return 'boolean'\n if (val instanceof Date) return 'date'\n if (typeof val === 'string') {\n if (/^\\d{4}-\\d{2}-\\d{2}/.test(val)) return 'date'\n return 'text'\n }\n if (Array.isArray(val)) {\n // Check if it looks like a blocks array\n if (val.length > 0 && typeof val[0] === 'object' && val[0] !== null && '_block' in val[0]) {\n return 'blocks'\n }\n return 'json'\n }\n if (typeof val === 'object') return 'json'\n return 'unknown'\n}\n\n/** Diff two string values and return segments (used by block-diff for string props). */\nexport function diffStringValues(from: unknown, to: unknown): DiffSegment[] | undefined {\n if (typeof from === 'string' || typeof to === 'string') {\n return diffText(stringify(from), stringify(to))\n }\n return undefined\n}\n","/**\n * Structural diff for Puck block arrays.\n *\n * Blocks are identified by `_id`. The algorithm detects:\n * - Added blocks (new _id in target)\n * - Removed blocks (missing _id in target)\n * - Moved blocks (same _id, different position)\n * - Changed blocks (same _id, different prop values)\n * - Unchanged blocks\n */\n\nimport { diffStringValues } from './field-diff.js'\nimport type { BlockDiffEntry, PropDiff } from './types.js'\n\ninterface Block {\n _block: string\n _id: string\n [key: string]: unknown\n}\n\nfunction isBlock(val: unknown): val is Block {\n return (\n typeof val === 'object' &&\n val !== null &&\n '_block' in val &&\n '_id' in val &&\n typeof (val as Block)._block === 'string' &&\n typeof (val as Block)._id === 'string'\n )\n}\n\n/**\n * Diff two prop objects within a single block, returning per-prop diffs.\n */\nfunction diffProps(\n fromProps: Record<string, unknown>,\n toProps: Record<string, unknown>,\n): PropDiff[] {\n const allKeys = new Set([...Object.keys(fromProps), ...Object.keys(toProps)])\n const diffs: PropDiff[] = []\n\n for (const key of allKeys) {\n // Skip block metadata\n if (key === '_block' || key === '_id') continue\n\n const fromVal = fromProps[key]\n const toVal = toProps[key]\n\n if (JSON.stringify(fromVal) !== JSON.stringify(toVal)) {\n diffs.push({\n field: key,\n from: fromVal,\n to: toVal,\n segments: diffStringValues(fromVal, toVal),\n })\n }\n }\n\n return diffs\n}\n\n/**\n * Compute structural diff between two block arrays.\n *\n * Each block is identified by its `_id` field. Position changes,\n * additions, removals, and prop-level changes are all detected.\n */\nexport function diffBlocks(fromBlocks: unknown[], toBlocks: unknown[]): BlockDiffEntry[] {\n const from = fromBlocks.filter(isBlock)\n const to = toBlocks.filter(isBlock)\n\n const fromMap = new Map<string, { block: Block; index: number }>()\n const toMap = new Map<string, { block: Block; index: number }>()\n\n for (let i = 0; i < from.length; i++) {\n fromMap.set(from[i]._id, { block: from[i], index: i })\n }\n for (let i = 0; i < to.length; i++) {\n toMap.set(to[i]._id, { block: to[i], index: i })\n }\n\n const entries: BlockDiffEntry[] = []\n const processedIds = new Set<string>()\n\n // Walk the \"to\" array to preserve target order\n for (const [id, { block: toBlock, index: toIndex }] of toMap) {\n processedIds.add(id)\n const fromEntry = fromMap.get(id)\n\n if (!fromEntry) {\n // Added\n entries.push({\n blockId: id,\n blockType: toBlock._block,\n status: 'added',\n toIndex,\n })\n continue\n }\n\n const fromBlock = fromEntry.block\n const fromIndex = fromEntry.index\n const propDiffs = diffProps(fromBlock, toBlock)\n const moved = fromIndex !== toIndex\n\n if (propDiffs.length === 0 && !moved) {\n entries.push({\n blockId: id,\n blockType: toBlock._block,\n status: 'unchanged',\n fromIndex,\n toIndex,\n })\n } else if (propDiffs.length > 0) {\n entries.push({\n blockId: id,\n blockType: toBlock._block,\n status: 'changed',\n fromIndex,\n toIndex,\n propDiffs,\n })\n } else {\n entries.push({\n blockId: id,\n blockType: toBlock._block,\n status: 'moved',\n fromIndex,\n toIndex,\n })\n }\n }\n\n // Removed blocks (in \"from\" but not in \"to\")\n for (const [id, { block, index }] of fromMap) {\n if (!processedIds.has(id)) {\n entries.push({\n blockId: id,\n blockType: block._block,\n status: 'removed',\n fromIndex: index,\n })\n }\n }\n\n return entries\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"block-diff-BBH6FoFT.mjs","names":[],"sources":["../src/behaviors/versionable.ts","../src/diff/text-diff.ts","../src/diff/field-diff.ts","../src/diff/block-diff.ts"],"sourcesContent":["/**\n * Versionable behavior — full version history with snapshots.\n *\n * Extends the concept of revisionable() (which only tracks a counter)\n * with actual version snapshots stored in {entity}_versions table.\n *\n * The behavior itself adds fields + hooks for version tracking.\n * Actual snapshot persistence happens in ContentClient (which has DB access).\n *\n * Options:\n * - maxPerDoc: Maximum versions kept per document (default: 50)\n * - autosave: Enable smart autosave (default: false)\n */\n\nimport type { Behavior, DateField, NumberField } from '@murumets-ee/entity'\n\nimport { field } from '@murumets-ee/entity'\nimport type { VersionableOptions } from '../types.js'\n\nexport type VersionableFields = {\n _version: NumberField & { required: true }\n _versionedAt: DateField\n}\n\nconst DEFAULT_OPTIONS: Required<VersionableOptions> = {\n maxPerDoc: 50,\n autosave: false,\n}\n\nexport function versionable(options?: VersionableOptions): Behavior<VersionableFields> {\n const opts = { ...DEFAULT_OPTIONS, ...options }\n\n // Attach options to the behavior for ContentClient to read\n const behavior: Behavior<VersionableFields> & {\n _versionableOptions: Required<VersionableOptions>\n } = {\n name: 'versionable',\n fields: {\n _version: field.number({ required: true, default: 1, integer: true }),\n _versionedAt: field.date(),\n },\n hooks: {\n beforeCreate: async (data) => {\n data._version = 1\n data._versionedAt = new Date()\n return data\n },\n beforeUpdate: async (_id, data) => {\n // Only update _versionedAt here. The _version increment is handled by\n // createVersionSnapshot which reads the current version from the DB.\n // The beforeUpdate hook only receives partial data (the PATCH payload),\n // so it can't reliably increment _version without the current value.\n data._versionedAt = new Date()\n return data\n },\n },\n _versionableOptions: opts,\n }\n\n return behavior as Behavior<VersionableFields>\n}\n\n/**\n * Extract versionable options from an entity's behaviors\n */\nexport function getVersionableOptions(behaviors?: Behavior[]): Required<VersionableOptions> | null {\n if (!behaviors) return null\n const vBehavior = behaviors.find((b) => b.name === 'versionable') as\n | (Behavior & { _versionableOptions?: Required<VersionableOptions> })\n | undefined\n return vBehavior?._versionableOptions ?? null\n}\n","/**\n * Word-level text diff using a simplified Myers algorithm.\n *\n * Splits text into words (preserving whitespace), computes the longest common\n * subsequence, and returns an array of diff segments.\n */\n\nimport type { DiffSegment } from './types.js'\n\n/**\n * Split text into tokens — words and whitespace runs — so diffs are\n * human-readable (\"Changed *this* word\") rather than character-level.\n */\nfunction tokenize(text: string): string[] {\n return text.match(/\\S+|\\s+/g) ?? []\n}\n\n/**\n * Compute word-level diff between two strings.\n *\n * Uses a simple LCS (dynamic programming) approach which is fine for\n * the text sizes we deal with (entity field values, not source code).\n */\nexport function diffText(from: string, to: string): DiffSegment[] {\n if (from === to) {\n return from ? [{ type: 'equal', value: from }] : []\n }\n if (!from) {\n return [{ type: 'add', value: to }]\n }\n if (!to) {\n return [{ type: 'remove', value: from }]\n }\n\n const fromTokens = tokenize(from)\n const toTokens = tokenize(to)\n\n // Build LCS table\n const m = fromTokens.length\n const n = toTokens.length\n const dp: number[][] = Array.from({ length: m + 1 }, () => new Array(n + 1).fill(0))\n\n for (let i = 1; i <= m; i++) {\n for (let j = 1; j <= n; j++) {\n if (fromTokens[i - 1] === toTokens[j - 1]) {\n dp[i][j] = dp[i - 1][j - 1] + 1\n } else {\n dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1])\n }\n }\n }\n\n // Backtrack to build diff segments\n const segments: DiffSegment[] = []\n let i = m\n let j = n\n\n // Collect in reverse, then flip\n const reversed: DiffSegment[] = []\n\n while (i > 0 || j > 0) {\n if (i > 0 && j > 0 && fromTokens[i - 1] === toTokens[j - 1]) {\n reversed.push({ type: 'equal', value: fromTokens[i - 1] })\n i--\n j--\n } else if (j > 0 && (i === 0 || dp[i][j - 1] >= dp[i - 1][j])) {\n reversed.push({ type: 'add', value: toTokens[j - 1] })\n j--\n } else {\n reversed.push({ type: 'remove', value: fromTokens[i - 1] })\n i--\n }\n }\n\n reversed.reverse()\n\n // Merge consecutive segments of the same type\n for (const seg of reversed) {\n const last = segments[segments.length - 1]\n if (last && last.type === seg.type) {\n last.value += seg.value\n } else {\n segments.push({ ...seg })\n }\n }\n\n return segments\n}\n","/**\n * Field-level diff — dispatches to the appropriate diff strategy per field type.\n */\n\nimport type { FieldConfig } from '@murumets-ee/entity'\nimport { diffText } from './text-diff.js'\nimport type { DiffSegment, FieldDiff } from './types.js'\n\n/** Strip HTML tags for diffing richtext content as plain text. */\nfunction stripHtml(html: string): string {\n return html\n .replace(/<[^>]*>/g, ' ')\n .replace(/\\s+/g, ' ')\n .trim()\n}\n\n/** Stringify a value for display (dates, objects, etc.). */\nfunction stringify(value: unknown): string {\n if (value === null || value === undefined) return ''\n if (value instanceof Date) return value.toISOString()\n if (typeof value === 'object') return JSON.stringify(value)\n return String(value)\n}\n\n/**\n * Compute diff for a single field, using the field's type to determine\n * the best diff strategy.\n */\nexport function diffField(\n fieldName: string,\n from: unknown,\n to: unknown,\n fieldConfig?: FieldConfig,\n): FieldDiff | null {\n // No change\n if (JSON.stringify(from) === JSON.stringify(to)) return null\n\n const type = fieldConfig?.type ?? inferType(from, to)\n\n switch (type) {\n case 'text':\n case 'slug': {\n const segments = diffText(stringify(from), stringify(to))\n return { field: fieldName, type: 'text', from, to, segments }\n }\n\n case 'richtext': {\n // Diff on stripped HTML so users see word changes, not tag noise\n const segments = diffText(stripHtml(stringify(from)), stripHtml(stringify(to)))\n return { field: fieldName, type: 'richtext', from, to, segments }\n }\n\n case 'number':\n return { field: fieldName, type: 'number', from, to }\n\n case 'boolean':\n return { field: fieldName, type: 'boolean', from, to }\n\n case 'date':\n return { field: fieldName, type: 'date', from, to }\n\n case 'select':\n return { field: fieldName, type: 'select', from, to }\n\n case 'media':\n return { field: fieldName, type: 'media', from, to }\n\n case 'json':\n return { field: fieldName, type: 'json', from, to }\n\n case 'blocks':\n // Blocks are handled separately by block-diff.ts — just mark the field\n return { field: fieldName, type: 'blocks', from, to }\n\n default:\n return { field: fieldName, type: 'unknown', from, to }\n }\n}\n\n/**\n * Diff all fields between two version snapshots.\n * Pass fieldConfigs to get type-aware diffs; without them, types are inferred.\n */\nexport function diffFields(\n from: Record<string, unknown>,\n to: Record<string, unknown>,\n fieldConfigs?: Record<string, FieldConfig>,\n): FieldDiff[] {\n const allKeys = new Set([...Object.keys(from), ...Object.keys(to)])\n const diffs: FieldDiff[] = []\n\n for (const key of allKeys) {\n // Skip internal/auto-generated fields\n if (key === 'id' || key === 'createdAt' || key === 'updatedAt') continue\n\n const diff = diffField(key, from[key], to[key], fieldConfigs?.[key])\n if (diff) diffs.push(diff)\n }\n\n return diffs\n}\n\n/** Best-effort type inference when no FieldConfig is available. */\nfunction inferType(from: unknown, to: unknown): string {\n const val = from ?? to\n if (typeof val === 'number') return 'number'\n if (typeof val === 'boolean') return 'boolean'\n if (val instanceof Date) return 'date'\n if (typeof val === 'string') {\n if (/^\\d{4}-\\d{2}-\\d{2}/.test(val)) return 'date'\n return 'text'\n }\n if (Array.isArray(val)) {\n // Check if it looks like a blocks array\n if (val.length > 0 && typeof val[0] === 'object' && val[0] !== null && '_block' in val[0]) {\n return 'blocks'\n }\n return 'json'\n }\n if (typeof val === 'object') return 'json'\n return 'unknown'\n}\n\n/** Diff two string values and return segments (used by block-diff for string props). */\nexport function diffStringValues(from: unknown, to: unknown): DiffSegment[] | undefined {\n if (typeof from === 'string' || typeof to === 'string') {\n return diffText(stringify(from), stringify(to))\n }\n return undefined\n}\n","/**\n * Structural diff for Puck block arrays.\n *\n * Blocks are identified by `_id`. The algorithm detects:\n * - Added blocks (new _id in target)\n * - Removed blocks (missing _id in target)\n * - Moved blocks (same _id, different position)\n * - Changed blocks (same _id, different prop values)\n * - Unchanged blocks\n */\n\nimport { diffStringValues } from './field-diff.js'\nimport type { BlockDiffEntry, PropDiff } from './types.js'\n\ninterface Block {\n _block: string\n _id: string\n [key: string]: unknown\n}\n\nfunction isBlock(val: unknown): val is Block {\n return (\n typeof val === 'object' &&\n val !== null &&\n '_block' in val &&\n '_id' in val &&\n typeof (val as Block)._block === 'string' &&\n typeof (val as Block)._id === 'string'\n )\n}\n\n/**\n * Diff two prop objects within a single block, returning per-prop diffs.\n */\nfunction diffProps(\n fromProps: Record<string, unknown>,\n toProps: Record<string, unknown>,\n): PropDiff[] {\n const allKeys = new Set([...Object.keys(fromProps), ...Object.keys(toProps)])\n const diffs: PropDiff[] = []\n\n for (const key of allKeys) {\n // Skip block metadata\n if (key === '_block' || key === '_id') continue\n\n const fromVal = fromProps[key]\n const toVal = toProps[key]\n\n if (JSON.stringify(fromVal) !== JSON.stringify(toVal)) {\n diffs.push({\n field: key,\n from: fromVal,\n to: toVal,\n segments: diffStringValues(fromVal, toVal),\n })\n }\n }\n\n return diffs\n}\n\n/**\n * Compute structural diff between two block arrays.\n *\n * Each block is identified by its `_id` field. Position changes,\n * additions, removals, and prop-level changes are all detected.\n */\nexport function diffBlocks(fromBlocks: unknown[], toBlocks: unknown[]): BlockDiffEntry[] {\n const from = fromBlocks.filter(isBlock)\n const to = toBlocks.filter(isBlock)\n\n const fromMap = new Map<string, { block: Block; index: number }>()\n const toMap = new Map<string, { block: Block; index: number }>()\n\n for (let i = 0; i < from.length; i++) {\n fromMap.set(from[i]._id, { block: from[i], index: i })\n }\n for (let i = 0; i < to.length; i++) {\n toMap.set(to[i]._id, { block: to[i], index: i })\n }\n\n const entries: BlockDiffEntry[] = []\n const processedIds = new Set<string>()\n\n // Walk the \"to\" array to preserve target order\n for (const [id, { block: toBlock, index: toIndex }] of toMap) {\n processedIds.add(id)\n const fromEntry = fromMap.get(id)\n\n if (!fromEntry) {\n // Added\n entries.push({\n blockId: id,\n blockType: toBlock._block,\n status: 'added',\n toIndex,\n })\n continue\n }\n\n const fromBlock = fromEntry.block\n const fromIndex = fromEntry.index\n const propDiffs = diffProps(fromBlock, toBlock)\n const moved = fromIndex !== toIndex\n\n if (propDiffs.length === 0 && !moved) {\n entries.push({\n blockId: id,\n blockType: toBlock._block,\n status: 'unchanged',\n fromIndex,\n toIndex,\n })\n } else if (propDiffs.length > 0) {\n entries.push({\n blockId: id,\n blockType: toBlock._block,\n status: 'changed',\n fromIndex,\n toIndex,\n propDiffs,\n })\n } else {\n entries.push({\n blockId: id,\n blockType: toBlock._block,\n status: 'moved',\n fromIndex,\n toIndex,\n })\n }\n }\n\n // Removed blocks (in \"from\" but not in \"to\")\n for (const [id, { block, index }] of fromMap) {\n if (!processedIds.has(id)) {\n entries.push({\n blockId: id,\n blockType: block._block,\n status: 'removed',\n fromIndex: index,\n })\n }\n }\n\n return entries\n}\n"],"mappings":"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"}
|
package/dist/blocks/index.d.mts
CHANGED
package/dist/blocks/index.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{t as e}from"../define-block-
|
|
1
|
+
import{t as e}from"../define-block-DpMPEEdA.mjs";import{field as t}from"@murumets-ee/entity";const n=e({slug:`code`,label:`Code`,fields:{code:t.text({required:!0}),language:t.select({options:[`javascript`,`typescript`,`python`,`html`,`css`,`json`,`bash`,`sql`,`other`]})}}),r=e({slug:`cta`,label:`Call to Action`,fields:{heading:t.text({required:!0,translatable:!0}),description:t.text({translatable:!0}),buttonText:t.text({required:!0,translatable:!0}),buttonLink:t.text({required:!0})}}),i=e({slug:`gallery`,label:`Gallery`,fields:{images:t.reference({entity:`media`,cardinality:`many`}),columns:t.select({options:[`2`,`3`,`4`]})}}),a=e({slug:`hero`,label:`Hero Section`,fields:{heading:t.text({required:!0,translatable:!0}),subheading:t.text({translatable:!0}),background:t.media({accept:[`image/*`]}),alignment:t.select({options:[`left`,`center`,`right`]})}}),o=e({slug:`image`,label:`Image`,fields:{image:t.media({accept:[`image/*`],required:!0}),alt:t.text({translatable:!0}),caption:t.text({translatable:!0})}}),s=e({slug:`quote`,label:`Quote`,fields:{quote:t.text({required:!0,translatable:!0}),attribution:t.text({translatable:!0})}}),c=e({slug:`richtext`,label:`Rich Text`,fields:{content:t.richtext({translatable:!0})}}),l=e({slug:`video`,label:`Video`,fields:{url:t.text({required:!0}),poster:t.media({accept:[`image/*`]}),caption:t.text({translatable:!0})}}),u=[c,o,a,i,r,l,s,n];export{r as CTABlock,n as CodeBlock,i as GalleryBlock,a as HeroBlock,o as ImageBlock,s as QuoteBlock,c as RichTextBlock,l as VideoBlock,u as commonBlocks};
|
|
2
2
|
//# sourceMappingURL=index.mjs.map
|
package/dist/client.d.mts
CHANGED
|
@@ -1,69 +1,177 @@
|
|
|
1
|
-
import { d as TranslationStatus, f as VersionEntry, r as DraftEntry, s as LocalePublishStatus, u as TranslationReport } from "./types-
|
|
2
|
-
import { i as FieldDiff } from "./types-
|
|
1
|
+
import { d as TranslationStatus, f as VersionEntry, r as DraftEntry, s as LocalePublishStatus, u as TranslationReport } from "./types-D-ATlx7t.mjs";
|
|
2
|
+
import { i as FieldDiff } from "./types-COcneY5H.mjs";
|
|
3
3
|
import { Entity, FieldConfig, FieldToTS } from "@murumets-ee/entity";
|
|
4
4
|
import { Logger } from "@murumets-ee/core";
|
|
5
|
-
import { FindManyOptions } from "@murumets-ee/entity/admin";
|
|
6
|
-
import { PostgresJsDatabase } from "drizzle-orm/postgres-js";
|
|
5
|
+
import { AdminClient, FindManyOptions } from "@murumets-ee/entity/admin";
|
|
7
6
|
|
|
8
7
|
//#region src/client.d.ts
|
|
9
8
|
/** Value type that any entity field can hold */
|
|
10
9
|
type EntityFieldValue = FieldToTS<FieldConfig> | null | undefined;
|
|
11
10
|
interface ContentClientConfig {
|
|
11
|
+
admin: AdminClient;
|
|
12
12
|
entity: Entity;
|
|
13
|
-
db: PostgresJsDatabase;
|
|
14
13
|
logger?: Logger;
|
|
15
14
|
}
|
|
16
15
|
declare class ContentClient {
|
|
17
16
|
private entity;
|
|
18
|
-
private db;
|
|
19
|
-
private logger?;
|
|
20
17
|
private admin;
|
|
18
|
+
private logger?;
|
|
21
19
|
private versionableOptions;
|
|
22
20
|
constructor(config: ContentClientConfig);
|
|
23
|
-
|
|
21
|
+
/** Database handle inherited from the injected AdminClient. */
|
|
22
|
+
private get db();
|
|
23
|
+
/** Lazy TableClient for the drafts table. Returns null if the entity has no drafts table. */
|
|
24
|
+
private getDraftsClient;
|
|
25
|
+
/** Lazy TableClient for the versions table. Returns null if the entity has no versions table. */
|
|
26
|
+
private getVersionsClient;
|
|
27
|
+
/** Lazy TableClient for the locale_status table. Returns null if the entity has no locale_status table. */
|
|
28
|
+
private getLocaleStatusClient;
|
|
24
29
|
create(data: Record<string, EntityFieldValue>): Promise<{
|
|
25
30
|
id: string;
|
|
26
31
|
} & {} & {
|
|
27
|
-
[x: string]: string | number | boolean |
|
|
32
|
+
[x: string]: Date | Record<string, unknown>[] | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | /*elided*/any | {
|
|
33
|
+
[key: string]: string | number | boolean | /*elided*/any | /*elided*/any | null;
|
|
34
|
+
} | null)[] | {
|
|
35
|
+
[key: string]: string | number | boolean | (string | number | boolean | /*elided*/any | /*elided*/any | null)[] | /*elided*/any | null;
|
|
36
|
+
} | null)[] | {
|
|
37
|
+
[key: string]: string | number | boolean | (string | number | boolean | (string | number | boolean | /*elided*/any | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null;
|
|
38
|
+
} | null)[] | {
|
|
39
|
+
[key: string]: string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | /*elided*/any | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null;
|
|
40
|
+
} | null)[] | {
|
|
41
|
+
[key: string]: string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | /*elided*/any | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null;
|
|
42
|
+
} | null)[] | {
|
|
43
|
+
[key: string]: string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | /*elided*/any | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null;
|
|
44
|
+
} | null)[] | {
|
|
45
|
+
[key: string]: string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | /*elided*/any | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null;
|
|
46
|
+
} | null)[] | {
|
|
47
|
+
[key: string]: string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | /*elided*/any | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null;
|
|
48
|
+
} | null)[] | {
|
|
49
|
+
[key: string]: string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | /*elided*/any | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null;
|
|
50
|
+
} | null)[] | {
|
|
51
|
+
[key: string]: string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | /*elided*/any | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null;
|
|
52
|
+
} | null)[] | {
|
|
53
|
+
[key: string]: string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | /*elided*/any | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null;
|
|
54
|
+
} | null)[] | {
|
|
55
|
+
[key: string]: string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | /*elided*/any | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null;
|
|
56
|
+
} | null) | {
|
|
28
57
|
[key: string]: unknown;
|
|
29
58
|
_block: string;
|
|
30
59
|
_id: string;
|
|
31
|
-
}[] |
|
|
60
|
+
}[] | undefined;
|
|
32
61
|
}>;
|
|
33
62
|
findById(id: string, options?: {
|
|
34
63
|
locale?: string;
|
|
35
64
|
}): Promise<({
|
|
36
65
|
id: string;
|
|
37
66
|
} & {} & {
|
|
38
|
-
[x: string]: string | number | boolean |
|
|
67
|
+
[x: string]: Date | Record<string, unknown>[] | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | /*elided*/any | {
|
|
68
|
+
[key: string]: string | number | boolean | /*elided*/any | /*elided*/any | null;
|
|
69
|
+
} | null)[] | {
|
|
70
|
+
[key: string]: string | number | boolean | (string | number | boolean | /*elided*/any | /*elided*/any | null)[] | /*elided*/any | null;
|
|
71
|
+
} | null)[] | {
|
|
72
|
+
[key: string]: string | number | boolean | (string | number | boolean | (string | number | boolean | /*elided*/any | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null;
|
|
73
|
+
} | null)[] | {
|
|
74
|
+
[key: string]: string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | /*elided*/any | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null;
|
|
75
|
+
} | null)[] | {
|
|
76
|
+
[key: string]: string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | /*elided*/any | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null;
|
|
77
|
+
} | null)[] | {
|
|
78
|
+
[key: string]: string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | /*elided*/any | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null;
|
|
79
|
+
} | null)[] | {
|
|
80
|
+
[key: string]: string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | /*elided*/any | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null;
|
|
81
|
+
} | null)[] | {
|
|
82
|
+
[key: string]: string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | /*elided*/any | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null;
|
|
83
|
+
} | null)[] | {
|
|
84
|
+
[key: string]: string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | /*elided*/any | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null;
|
|
85
|
+
} | null)[] | {
|
|
86
|
+
[key: string]: string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | /*elided*/any | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null;
|
|
87
|
+
} | null)[] | {
|
|
88
|
+
[key: string]: string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | /*elided*/any | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null;
|
|
89
|
+
} | null)[] | {
|
|
90
|
+
[key: string]: string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | /*elided*/any | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null;
|
|
91
|
+
} | null) | {
|
|
39
92
|
[key: string]: unknown;
|
|
40
93
|
_block: string;
|
|
41
94
|
_id: string;
|
|
42
|
-
}[] |
|
|
95
|
+
}[] | undefined;
|
|
43
96
|
}) | null>;
|
|
44
97
|
findMany(options?: FindManyOptions): Promise<({
|
|
45
98
|
id: string;
|
|
46
99
|
} & {} & {
|
|
47
|
-
[x: string]: string | number | boolean |
|
|
100
|
+
[x: string]: Date | Record<string, unknown>[] | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | /*elided*/any | {
|
|
101
|
+
[key: string]: string | number | boolean | /*elided*/any | /*elided*/any | null;
|
|
102
|
+
} | null)[] | {
|
|
103
|
+
[key: string]: string | number | boolean | (string | number | boolean | /*elided*/any | /*elided*/any | null)[] | /*elided*/any | null;
|
|
104
|
+
} | null)[] | {
|
|
105
|
+
[key: string]: string | number | boolean | (string | number | boolean | (string | number | boolean | /*elided*/any | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null;
|
|
106
|
+
} | null)[] | {
|
|
107
|
+
[key: string]: string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | /*elided*/any | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null;
|
|
108
|
+
} | null)[] | {
|
|
109
|
+
[key: string]: string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | /*elided*/any | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null;
|
|
110
|
+
} | null)[] | {
|
|
111
|
+
[key: string]: string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | /*elided*/any | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null;
|
|
112
|
+
} | null)[] | {
|
|
113
|
+
[key: string]: string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | /*elided*/any | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null;
|
|
114
|
+
} | null)[] | {
|
|
115
|
+
[key: string]: string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | /*elided*/any | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null;
|
|
116
|
+
} | null)[] | {
|
|
117
|
+
[key: string]: string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | /*elided*/any | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null;
|
|
118
|
+
} | null)[] | {
|
|
119
|
+
[key: string]: string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | /*elided*/any | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null;
|
|
120
|
+
} | null)[] | {
|
|
121
|
+
[key: string]: string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | /*elided*/any | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null;
|
|
122
|
+
} | null)[] | {
|
|
123
|
+
[key: string]: string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | /*elided*/any | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null;
|
|
124
|
+
} | null) | {
|
|
48
125
|
[key: string]: unknown;
|
|
49
126
|
_block: string;
|
|
50
127
|
_id: string;
|
|
51
|
-
}[] |
|
|
128
|
+
}[] | undefined;
|
|
52
129
|
})[]>;
|
|
53
130
|
update(id: string, data: Record<string, EntityFieldValue>): Promise<{
|
|
54
131
|
id: string;
|
|
55
132
|
} & {} & {
|
|
56
|
-
[x: string]: string | number | boolean |
|
|
133
|
+
[x: string]: Date | Record<string, unknown>[] | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | /*elided*/any | {
|
|
134
|
+
[key: string]: string | number | boolean | /*elided*/any | /*elided*/any | null;
|
|
135
|
+
} | null)[] | {
|
|
136
|
+
[key: string]: string | number | boolean | (string | number | boolean | /*elided*/any | /*elided*/any | null)[] | /*elided*/any | null;
|
|
137
|
+
} | null)[] | {
|
|
138
|
+
[key: string]: string | number | boolean | (string | number | boolean | (string | number | boolean | /*elided*/any | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null;
|
|
139
|
+
} | null)[] | {
|
|
140
|
+
[key: string]: string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | /*elided*/any | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null;
|
|
141
|
+
} | null)[] | {
|
|
142
|
+
[key: string]: string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | /*elided*/any | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null;
|
|
143
|
+
} | null)[] | {
|
|
144
|
+
[key: string]: string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | /*elided*/any | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null;
|
|
145
|
+
} | null)[] | {
|
|
146
|
+
[key: string]: string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | /*elided*/any | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null;
|
|
147
|
+
} | null)[] | {
|
|
148
|
+
[key: string]: string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | /*elided*/any | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null;
|
|
149
|
+
} | null)[] | {
|
|
150
|
+
[key: string]: string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | /*elided*/any | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null;
|
|
151
|
+
} | null)[] | {
|
|
152
|
+
[key: string]: string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | /*elided*/any | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null;
|
|
153
|
+
} | null)[] | {
|
|
154
|
+
[key: string]: string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | /*elided*/any | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null;
|
|
155
|
+
} | null)[] | {
|
|
156
|
+
[key: string]: string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | /*elided*/any | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null;
|
|
157
|
+
} | null) | {
|
|
57
158
|
[key: string]: unknown;
|
|
58
159
|
_block: string;
|
|
59
160
|
_id: string;
|
|
60
|
-
}[] |
|
|
161
|
+
}[] | undefined;
|
|
61
162
|
}>;
|
|
62
163
|
delete(id: string): Promise<void>;
|
|
63
164
|
saveTranslation(entityId: string, locale: string, translations: Record<string, unknown>): Promise<void>;
|
|
64
165
|
deleteTranslation(entityId: string, locale?: string): Promise<void>;
|
|
65
166
|
/**
|
|
66
167
|
* Copy layout from one locale to another (for localized: true blocks).
|
|
168
|
+
*
|
|
169
|
+
* NOTE: Layout tables are generated in `@murumets-ee/entity` (they need
|
|
170
|
+
* FK references to the parent entity table, which `defineTable` does not
|
|
171
|
+
* currently support). So this method uses direct Drizzle queries against
|
|
172
|
+
* the layout pgTable via `schemaRegistry` — it is the one remaining
|
|
173
|
+
* escape valve in ContentClient. If `defineTable` gains FK support in the
|
|
174
|
+
* future, migrate this to a TableClient pattern like drafts/versions.
|
|
67
175
|
*/
|
|
68
176
|
copyLayout(entityId: string, options: {
|
|
69
177
|
from: string;
|
|
@@ -108,11 +216,35 @@ declare class ContentClient {
|
|
|
108
216
|
restoreVersion(entityId: string, version: number): Promise<{
|
|
109
217
|
id: string;
|
|
110
218
|
} & {} & {
|
|
111
|
-
[x: string]: string | number | boolean |
|
|
219
|
+
[x: string]: Date | Record<string, unknown>[] | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | /*elided*/any | {
|
|
220
|
+
[key: string]: string | number | boolean | /*elided*/any | /*elided*/any | null;
|
|
221
|
+
} | null)[] | {
|
|
222
|
+
[key: string]: string | number | boolean | (string | number | boolean | /*elided*/any | /*elided*/any | null)[] | /*elided*/any | null;
|
|
223
|
+
} | null)[] | {
|
|
224
|
+
[key: string]: string | number | boolean | (string | number | boolean | (string | number | boolean | /*elided*/any | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null;
|
|
225
|
+
} | null)[] | {
|
|
226
|
+
[key: string]: string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | /*elided*/any | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null;
|
|
227
|
+
} | null)[] | {
|
|
228
|
+
[key: string]: string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | /*elided*/any | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null;
|
|
229
|
+
} | null)[] | {
|
|
230
|
+
[key: string]: string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | /*elided*/any | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null;
|
|
231
|
+
} | null)[] | {
|
|
232
|
+
[key: string]: string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | /*elided*/any | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null;
|
|
233
|
+
} | null)[] | {
|
|
234
|
+
[key: string]: string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | /*elided*/any | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null;
|
|
235
|
+
} | null)[] | {
|
|
236
|
+
[key: string]: string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | /*elided*/any | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null;
|
|
237
|
+
} | null)[] | {
|
|
238
|
+
[key: string]: string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | /*elided*/any | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null;
|
|
239
|
+
} | null)[] | {
|
|
240
|
+
[key: string]: string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | /*elided*/any | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null;
|
|
241
|
+
} | null)[] | {
|
|
242
|
+
[key: string]: string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | /*elided*/any | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null)[] | /*elided*/any | null;
|
|
243
|
+
} | null) | {
|
|
112
244
|
[key: string]: unknown;
|
|
113
245
|
_block: string;
|
|
114
246
|
_id: string;
|
|
115
|
-
}[] |
|
|
247
|
+
}[] | undefined;
|
|
116
248
|
}>;
|
|
117
249
|
/**
|
|
118
250
|
* Enforce maxPerDoc retention by deleting oldest versions for a locale.
|
|
@@ -199,6 +331,16 @@ declare class ContentClient {
|
|
|
199
331
|
id: string;
|
|
200
332
|
name?: string;
|
|
201
333
|
}): Promise<void>;
|
|
334
|
+
/**
|
|
335
|
+
* Write the `_version` column on the entity row.
|
|
336
|
+
*
|
|
337
|
+
* KNOWN EXCEPTION: this bypasses AdminClient and goes straight to the
|
|
338
|
+
* entity pgTable via `schemaRegistry` + direct Drizzle. Using
|
|
339
|
+
* `admin.update()` would retrigger the `versionable.beforeUpdate` hook
|
|
340
|
+
* and loop indefinitely. This is the only ContentClient path that still
|
|
341
|
+
* writes to an entity table directly.
|
|
342
|
+
*/
|
|
343
|
+
private writeVersionColumn;
|
|
202
344
|
private saveVersionSnapshot;
|
|
203
345
|
private toDraftEntry;
|
|
204
346
|
private calculateDelta;
|
package/dist/client.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.mts","names":[],"sources":["../src/client.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"client.d.mts","names":[],"sources":["../src/client.ts"],"mappings":"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"}
|
package/dist/client.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{o as e,r as t,t as n}from"./block-diff-H1AttKiz.mjs";import"server-only";var r=class{entity;db;logger;admin=null;versionableOptions;constructor(t){this.entity=t.entity,this.db=t.db,this.logger=t.logger,this.versionableOptions=e(t.entity.behaviors)}async getAdmin(){if(!this.admin){let{AdminClient:e}=await import(`@murumets-ee/entity/admin`);this.admin=new e({entity:this.entity,db:this.db,logger:this.logger})}return this.admin}async create(e){let t=await(await this.getAdmin()).create(e);return this.versionableOptions&&await this.saveVersionSnapshot(t.id,t,null,!1),t}async findById(e,t){return(await this.getAdmin()).findById(e,t)}async findMany(e){return(await this.getAdmin()).findMany(e)}async update(e,t){let n=await this.getAdmin(),r=null;this.versionableOptions&&(r=await n.findById(e));let i=await n.update(e,t);if(this.versionableOptions&&r){let t=this.calculateDelta(r,i),n=await this.saveVersionSnapshot(e,i,t,!1);if(n!==void 0){let{schemaRegistry:t}=await import(`@murumets-ee/db`),{eq:r}=await import(`drizzle-orm`),a=t.get(this.entity.name);a&&(await this.db.update(a).set({_version:n}).where(r(a.id,e)),i._version=n)}await this.pruneVersions(e)}return i}async delete(e){return(await this.getAdmin()).delete(e)}async saveTranslation(e,t,n){return(await this.getAdmin()).saveTranslation(e,t,n)}async deleteTranslation(e,t){return(await this.getAdmin()).deleteTranslation(e,t)}async copyLayout(e,t){let{schemaRegistry:n}=await import(`@murumets-ee/db`),{eq:r,and:i}=await import(`drizzle-orm`),a=n.get(`${this.entity.name}_layout`);if(!a)return;let o=Array.isArray(t.to)?t.to:[t.to],s=await this.db.select().from(a).where(i(r(a.entityId,e),r(a.locale,t.from))).orderBy(a.sortOrder);if(s.length!==0){for(let t of o){await this.db.delete(a).where(i(r(a.entityId,e),r(a.locale,t)));for(let e of s)await this.db.insert(a).values({entityId:e.entityId,fieldName:e.fieldName,blockType:e.blockType,sortOrder:e.sortOrder,data:e.data,locale:t})}this.logger?.debug({entityId:e,from:t.from,to:o},`Layout copied between locales`)}}async getVersions(e,t){let{schemaRegistry:n}=await import(`@murumets-ee/db`),{eq:r,and:i,desc:a}=await import(`drizzle-orm`),o=n.get(`${this.entity.name}_versions`);if(!o)return[];let s=t?.locale??`_`,c=this.db.select().from(o).where(i(r(o.entityId,e),r(o.locale,s))).orderBy(a(o.version)).$dynamic();return t?.limit&&(c=c.limit(t.limit)),t?.offset&&(c=c.offset(t.offset)),c}async getVersion(e,t,n=`_`){let{schemaRegistry:r}=await import(`@murumets-ee/db`),{eq:i,and:a}=await import(`drizzle-orm`),o=r.get(`${this.entity.name}_versions`);return o?(await this.db.select().from(o).where(a(i(o.entityId,e),i(o.version,t),i(o.locale,n))).limit(1))[0]??null:null}async compareVersions(e,r,i,a=`_`){let[o,s]=await Promise.all([this.getVersion(e,r,a),this.getVersion(e,i,a)]);if(!o||!s)return null;let c=o.data,l=s.data,u=this.entity.allFields,d=t(c,l,u);for(let e of d)e.type===`blocks`&&Array.isArray(e.from)&&Array.isArray(e.to)&&(e.blockDiffs=n(e.from,e.to));return{diffs:d,fromVersion:o,toVersion:s}}async compareDraftWithCurrent(e,r=`_`){let i=await this.getDraft(e,r);if(!i)return null;let a=await this.getAdmin(),{getContentConfig:o}=await import(`./plugin.mjs`),s=o().defaultLocale,c=r===`_`?{defaultLocale:s}:{locale:r,defaultLocale:s},l=await a.findById(e,c);if(!l)return null;let u=this.entity.allFields,d={};for(let e of Object.keys(i.data))d[e]=l[e];let f=t(d,i.data,u);for(let e of f)e.type===`blocks`&&Array.isArray(e.from)&&Array.isArray(e.to)&&(e.blockDiffs=n(e.from,e.to));return{diffs:f,current:l,draft:i}}async restoreVersion(e,t){let n=await this.getVersion(e,t);if(!n)throw Error(`Version ${t} not found for entity ${e}`);let{id:r,createdAt:i,createdBy:a,_version:o,_versionedAt:s,...c}=n.data;return(await this.getAdmin()).update(e,c)}async pruneVersions(e,t=`_`){if(!this.versionableOptions)return;let{schemaRegistry:n}=await import(`@murumets-ee/db`),{eq:r,and:i,desc:a,sql:o}=await import(`drizzle-orm`),s=n.get(`${this.entity.name}_versions`);if(!s)return;let c=this.versionableOptions.maxPerDoc,l=await this.db.select({id:s.id}).from(s).where(i(r(s.entityId,e),r(s.locale,t))).orderBy(a(s.version)).limit(c);if(l.length<c)return;let u=l.map(e=>e.id);await this.db.delete(s).where(o`${s.entityId} = ${e} AND ${s.locale} = ${t} AND ${s.id} NOT IN (${o.join(u.map(e=>o`${e}`),o`, `)})`)}async getTranslationStatus(e){let{getContentConfig:t}=await import(`./plugin.mjs`),n=t(),r=Object.entries(this.entity.allFields).filter(([e,t])=>t.translatable).map(([e])=>e);if(r.length===0)return{};let{schemaRegistry:i}=await import(`@murumets-ee/db`),{eq:a}=await import(`drizzle-orm`),o=i.get(`${this.entity.name}_translations`);if(!o)return{};let s=await this.db.select().from(o).where(a(o.entityId,e)),c=new Map;for(let e of s){let t=e,n={};for(let e of r)n[e]=t[e];c.set(t.locale,n)}let l={};for(let e of n.locales){if(e.code===n.defaultLocale)continue;let t=c.get(e.code)??{},i=[];for(let e of r)(t[e]===void 0||t[e]===null)&&i.push(e);let a=r.length-i.length;l[e.code]={complete:i.length===0,total:r.length,translated:a,missing:i}}return l}async getTranslationStatusBatch(e){let t=new Map;if(e.length===0)return t;let{getContentConfig:n}=await import(`./plugin.mjs`),r=n(),i=Object.entries(this.entity.allFields).filter(([e,t])=>t.translatable).map(([e])=>e);if(i.length===0)return t;let{schemaRegistry:a}=await import(`@murumets-ee/db`),{inArray:o}=await import(`drizzle-orm`),s=a.get(`${this.entity.name}_translations`);if(!s)return t;let c=await this.db.select().from(s).where(o(s.entityId,e)),l=new Map;for(let e of c){let t=e,n=t.entityId,r=t.locale,a={};for(let e of i)a[e]=t[e];l.has(n)||l.set(n,new Map),l.get(n).set(r,a)}for(let n of e){let e=l.get(n),a={};for(let t of r.locales){if(t.code===r.defaultLocale)continue;let n=e?.get(t.code)??{},o=[];for(let e of i)(n[e]===void 0||n[e]===null)&&o.push(e);let s=i.length-o.length;a[t.code]={complete:o.length===0,total:i.length,translated:s,missing:o}}t.set(n,a)}return t}async getTranslationReport(e){let{getContentConfig:t}=await import(`./plugin.mjs`),n=t(),r=e?.locale??n.locales.find(e=>e.code!==n.defaultLocale)?.code;if(!r)return{total:0,complete:0,partial:0,missing:0};let i=await(await this.getAdmin()).findMany(),a=0,o=0,s=0;for(let e of i){let t=(await this.getTranslationStatus(e.id))[r];!t||t.translated===0?s++:t.complete?a++:o++}return{total:i.length,complete:a,partial:o,missing:s}}async getLocaleStatus(e){let{schemaRegistry:t}=await import(`@murumets-ee/db`),{eq:n}=await import(`drizzle-orm`),r=t.get(`${this.entity.name}_locale_status`);return r?(await this.db.select().from(r).where(n(r.entityId,e))).map(e=>({locale:e.locale,status:e.status,publishedAt:e.publishedAt??null})):[]}async setLocaleStatus(e,t,n){let{getContentConfig:r}=await import(`./plugin.mjs`);if(t===r().defaultLocale){let t=await this.getAdmin(),r={status:n};n===`published`&&(r.publishedAt=new Date),await t.update(e,r);return}let{schemaRegistry:i}=await import(`@murumets-ee/db`),{eq:a,and:o}=await import(`drizzle-orm`),s=i.get(`${this.entity.name}_locale_status`);if(!s)return;let c=n===`published`?new Date:null,[l]=await this.db.select({id:s.id}).from(s).where(o(a(s.entityId,e),a(s.locale,t))).limit(1);l?await this.db.update(s).set({status:n,publishedAt:c}).where(a(s.id,l.id)):await this.db.insert(s).values({entityId:e,locale:t,status:n,publishedAt:c})}async getLocaleStatusBatch(e){let t=new Map;if(e.length===0)return t;let{schemaRegistry:n}=await import(`@murumets-ee/db`),{inArray:r}=await import(`drizzle-orm`),i=n.get(`${this.entity.name}_locale_status`);if(!i)return t;let a=await this.db.select().from(i).where(r(i.entityId,e));for(let e of a){let n=e.entityId,r=e.locale;t.has(n)||t.set(n,{}),t.get(n)[r]={locale:r,status:e.status,publishedAt:e.publishedAt??null}}return t}async saveDraft(e,t,n=`_`,r){let{schemaRegistry:i}=await import(`@murumets-ee/db`),{eq:a,and:o}=await import(`drizzle-orm`),s=i.get(`${this.entity.name}_drafts`);if(!s)throw Error(`Drafts table not found for entity "${this.entity.name}". Is the content plugin initialized?`);let c=new Date,l=r?.id??``,u=r?.name??null,[d]=await this.db.select().from(s).where(o(a(s.entityId,e),a(s.locale,n))).limit(1);if(d){let[e]=await this.db.update(s).set({data:t,updatedAt:c}).where(a(s.id,d.id)).returning();return this.toDraftEntry(e)}let[f]=await this.db.insert(s).values({entityId:e,locale:n,data:t,createdBy:l,createdByName:u,createdAt:c,updatedAt:c}).returning();return this.toDraftEntry(f)}async getDraft(e,t=`_`){let{schemaRegistry:n}=await import(`@murumets-ee/db`),{eq:r,and:i}=await import(`drizzle-orm`),a=n.get(`${this.entity.name}_drafts`);if(!a)return null;let[o]=await this.db.select().from(a).where(i(r(a.entityId,e),r(a.locale,t))).limit(1);return o?this.toDraftEntry(o):null}async deleteDraft(e,t=`_`){let{schemaRegistry:n}=await import(`@murumets-ee/db`),{eq:r,and:i}=await import(`drizzle-orm`),a=n.get(`${this.entity.name}_drafts`);return a?(await this.db.delete(a).where(i(r(a.entityId,e),r(a.locale,t))).returning({id:a.id})).length>0:!1}async publishDraft(e,t=`_`,n){let r=await this.getDraft(e,t);if(!r)throw Error(`No draft found for entity ${e} locale ${t}`);let i=await this.getAdmin(),a=null;this.versionableOptions&&(a=await i.findById(e));let{id:o,createdAt:s,createdBy:c,_version:l,_versionedAt:u,...d}=r.data,f=await i.update(e,d);return await this.deleteDraft(e,t),this.versionableOptions&&await this.createVersionSnapshot(e,f,a,t,n),f}async hasDraft(e,t=`_`){let{schemaRegistry:n}=await import(`@murumets-ee/db`),{eq:r,and:i}=await import(`drizzle-orm`),a=n.get(`${this.entity.name}_drafts`);if(!a)return!1;let[o]=await this.db.select({id:a.id}).from(a).where(i(r(a.entityId,e),r(a.locale,t))).limit(1);return!!o}async countDrafts(e=`_`){let{schemaRegistry:t}=await import(`@murumets-ee/db`),{eq:n,sql:r}=await import(`drizzle-orm`),i=t.get(`${this.entity.name}_drafts`);if(!i)return 0;let[a]=await this.db.select({count:r`count(*)::int`}).from(i).where(n(i.locale,e));return a?.count??0}async hasDraftBatch(e,t=`_`){let n=new Set;if(e.length===0)return n;let{schemaRegistry:r}=await import(`@murumets-ee/db`),{inArray:i,eq:a,and:o}=await import(`drizzle-orm`),s=r.get(`${this.entity.name}_drafts`);if(!s)return n;let c=await this.db.select({entityId:s.entityId}).from(s).where(o(i(s.entityId,e),a(s.locale,t)));for(let e of c)n.add(e.entityId);return n}async createVersionSnapshot(e,t,n,r,i){if(!this.versionableOptions)return;let a=r??`_`,o=n?this.calculateDelta(n,t):null,s=await this.saveVersionSnapshot(e,t,o,!1,a,i);if(s!==void 0&&a===`_`){let{schemaRegistry:t}=await import(`@murumets-ee/db`),{eq:n}=await import(`drizzle-orm`),r=t.get(this.entity.name);r&&await this.db.update(r).set({_version:s}).where(n(r.id,e))}await this.pruneVersions(e,a)}async saveVersionSnapshot(e,t,n,r,i=`_`,a){let{schemaRegistry:o}=await import(`@murumets-ee/db`),{eq:s,and:c,sql:l}=await import(`drizzle-orm`),u=o.get(`${this.entity.name}_versions`);if(!u)return;let[d]=await this.db.select({maxVersion:l`coalesce(max(${u.version}), 0)`}).from(u).where(c(s(u.entityId,e),s(u.locale,i))),f=(d?.maxVersion??0)+1,p=t.status??null;if(r){let[r]=await this.db.select().from(u).where(c(s(u.entityId,e),s(u.isAutosave,!0),s(u.version,f),s(u.locale,i))).limit(1);if(r)return await this.db.update(u).set({data:t,delta:n,status:p,createdAt:new Date}).where(s(u.id,r.id)),f}return await this.db.insert(u).values({entityId:e,version:f,locale:i,data:t,delta:n,status:p,createdBy:a?.id??t.updatedBy??t.createdBy??null,createdByName:a?.name??null,isAutosave:r}),f}toDraftEntry(e){return{id:e.id,entityId:e.entityId,locale:e.locale,data:e.data,createdBy:e.createdBy,createdByName:e.createdByName??null,createdAt:e.createdAt,updatedAt:e.updatedAt}}calculateDelta(e,t){let n={};for(let r of Object.keys(t))r===`id`||r.startsWith(`_`)||JSON.stringify(e[r])!==JSON.stringify(t[r])&&(n[r]=t[r]);return n}};async function i(e){let{getApp:t}=await import(`@murumets-ee/core`),n=t();return new r({entity:e,db:n.db.readWrite,logger:n.logger.child({content:e.name})})}export{r as ContentClient,i as createContentClient};
|
|
1
|
+
import{o as e,r as t,t as n}from"./block-diff-BBH6FoFT.mjs";import{t as r}from"./registry-BJSOGFEN.mjs";import"server-only";var i=class{entity;admin;logger;versionableOptions;constructor(t){this.entity=t.entity,this.admin=t.admin,this.logger=t.logger,this.versionableOptions=e(t.entity.behaviors)}get db(){return this.admin.getDb()}getDraftsClient(){let{drafts:e}=r(this.entity.name);return e?e.makeClient(this.db):null}getVersionsClient(){let{versions:e}=r(this.entity.name);return e?e.makeClient(this.db):null}getLocaleStatusClient(){let{localeStatus:e}=r(this.entity.name);return e?e.makeClient(this.db):null}async create(e){let t=await this.admin.create(e);return this.versionableOptions&&await this.saveVersionSnapshot(t.id,t,null,!1),t}async findById(e,t){return this.admin.findById(e,t)}async findMany(e){return this.admin.findMany(e)}async update(e,t){let n=this.admin,r=null;this.versionableOptions&&(r=await n.findById(e));let i=await n.update(e,t);if(this.versionableOptions&&r){let t=this.calculateDelta(r,i),n=await this.saveVersionSnapshot(e,i,t,!1);n!==void 0&&(await this.writeVersionColumn(e,n),i._version=n),await this.pruneVersions(e)}return i}async delete(e){return this.admin.delete(e)}async saveTranslation(e,t,n){return this.admin.saveTranslation(e,t,n)}async deleteTranslation(e,t){return this.admin.deleteTranslation(e,t)}async copyLayout(e,t){let{schemaRegistry:n}=await import(`@murumets-ee/db`),{eq:r,and:i}=await import(`drizzle-orm`),a=n.get(`${this.entity.name}_layout`);if(!a)return;let o=Array.isArray(t.to)?t.to:[t.to],s=await this.db.select().from(a).where(i(r(a.entityId,e),r(a.locale,t.from))).orderBy(a.sortOrder);if(s.length!==0){for(let t of o){await this.db.delete(a).where(i(r(a.entityId,e),r(a.locale,t)));for(let e of s)await this.db.insert(a).values({entityId:e.entityId,fieldName:e.fieldName,blockType:e.blockType,sortOrder:e.sortOrder,data:e.data,locale:t})}this.logger?.debug({entityId:e,from:t.from,to:o},`Layout copied between locales`)}}async getVersions(e,t){let n=this.getVersionsClient();return n?await n.findMany({where:{entityId:e,locale:t?.locale??`_`},orderBy:[{column:`version`,dir:`desc`}],...t?.limit===void 0?{}:{limit:t.limit},...t?.offset===void 0?{}:{offset:t.offset}}):[]}async getVersion(e,t,n=`_`){let r=this.getVersionsClient();return r?await r.findOne({entityId:e,version:t,locale:n})??null:null}async compareVersions(e,r,i,a=`_`){let[o,s]=await Promise.all([this.getVersion(e,r,a),this.getVersion(e,i,a)]);if(!o||!s)return null;let c=o.data,l=s.data,u=this.entity.allFields,d=t(c,l,u);for(let e of d)e.type===`blocks`&&Array.isArray(e.from)&&Array.isArray(e.to)&&(e.blockDiffs=n(e.from,e.to));return{diffs:d,fromVersion:o,toVersion:s}}async compareDraftWithCurrent(e,r=`_`){let i=await this.getDraft(e,r);if(!i)return null;let a=this.admin,{getContentConfig:o}=await import(`./plugin.mjs`),s=o().defaultLocale,c=r===`_`?{defaultLocale:s}:{locale:r,defaultLocale:s},l=await a.findById(e,c);if(!l)return null;let u=this.entity.allFields,d={};for(let e of Object.keys(i.data))d[e]=l[e];let f=t(d,i.data,u);for(let e of f)e.type===`blocks`&&Array.isArray(e.from)&&Array.isArray(e.to)&&(e.blockDiffs=n(e.from,e.to));return{diffs:f,current:l,draft:i}}async restoreVersion(e,t){let n=await this.getVersion(e,t);if(!n)throw Error(`Version ${t} not found for entity ${e}`);let{id:r,createdAt:i,createdBy:a,_version:o,_versionedAt:s,...c}=n.data;return this.admin.update(e,c)}async pruneVersions(e,t=`_`){if(!this.versionableOptions)return;let n=this.getVersionsClient();if(!n)return;let r=this.versionableOptions.maxPerDoc,i=await n.findMany({where:{entityId:e,locale:t},orderBy:[{column:`version`,dir:`desc`}],limit:r});if(i.length<r)return;let a=i.map(e=>e.id);await n.deleteMany({entityId:e,locale:t,id:{notIn:a}})}async getTranslationStatus(e){let{getContentConfig:t}=await import(`./plugin.mjs`),n=t(),r=Object.entries(this.entity.allFields).filter(([e,t])=>t.translatable).map(([e])=>e);if(r.length===0)return{};let{schemaRegistry:i}=await import(`@murumets-ee/db`),{eq:a}=await import(`drizzle-orm`),o=i.get(`${this.entity.name}_translations`);if(!o)return{};let s=await this.db.select().from(o).where(a(o.entityId,e)),c=new Map;for(let e of s){let t=e,n={};for(let e of r)n[e]=t[e];c.set(t.locale,n)}let l={};for(let e of n.locales){if(e.code===n.defaultLocale)continue;let t=c.get(e.code)??{},i=[];for(let e of r)(t[e]===void 0||t[e]===null)&&i.push(e);let a=r.length-i.length;l[e.code]={complete:i.length===0,total:r.length,translated:a,missing:i}}return l}async getTranslationStatusBatch(e){let t=new Map;if(e.length===0)return t;let{getContentConfig:n}=await import(`./plugin.mjs`),r=n(),i=Object.entries(this.entity.allFields).filter(([e,t])=>t.translatable).map(([e])=>e);if(i.length===0)return t;let{schemaRegistry:a}=await import(`@murumets-ee/db`),{inArray:o}=await import(`drizzle-orm`),s=a.get(`${this.entity.name}_translations`);if(!s)return t;let c=await this.db.select().from(s).where(o(s.entityId,e)),l=new Map;for(let e of c){let t=e,n=t.entityId,r=t.locale,a={};for(let e of i)a[e]=t[e];l.has(n)||l.set(n,new Map),l.get(n).set(r,a)}for(let n of e){let e=l.get(n),a={};for(let t of r.locales){if(t.code===r.defaultLocale)continue;let n=e?.get(t.code)??{},o=[];for(let e of i)(n[e]===void 0||n[e]===null)&&o.push(e);let s=i.length-o.length;a[t.code]={complete:o.length===0,total:i.length,translated:s,missing:o}}t.set(n,a)}return t}async getTranslationReport(e){let{getContentConfig:t}=await import(`./plugin.mjs`),n=t(),r=e?.locale??n.locales.find(e=>e.code!==n.defaultLocale)?.code;if(!r)return{total:0,complete:0,partial:0,missing:0};let i=await this.admin.findMany(),a=0,o=0,s=0;for(let e of i){let t=(await this.getTranslationStatus(e.id))[r];!t||t.translated===0?s++:t.complete?a++:o++}return{total:i.length,complete:a,partial:o,missing:s}}async getLocaleStatus(e){let t=this.getLocaleStatusClient();return t?(await t.findMany({where:{entityId:e}})).map(e=>({locale:e.locale,status:e.status,publishedAt:e.publishedAt??null})):[]}async setLocaleStatus(e,t,n){let{getContentConfig:r}=await import(`./plugin.mjs`);if(t===r().defaultLocale){let t=this.admin,r={status:n};n===`published`&&(r.publishedAt=new Date),await t.update(e,r);return}let i=this.getLocaleStatusClient();if(!i)return;let a=n===`published`?new Date:null;await i.upsert({entityId:e,locale:t,status:n,publishedAt:a},{target:[`entityId`,`locale`],set:{status:n,publishedAt:a}})}async getLocaleStatusBatch(e){let t=new Map;if(e.length===0)return t;let n=this.getLocaleStatusClient();if(!n)return t;let r=await n.findMany({where:{entityId:{in:e}}});for(let e of r){let n=e.entityId,r=e.locale;t.has(n)||t.set(n,{}),t.get(n)[r]={locale:r,status:e.status,publishedAt:e.publishedAt??null}}return t}async saveDraft(e,t,n=`_`,r){let i=this.getDraftsClient();if(!i)throw Error(`Drafts table not found for entity "${this.entity.name}". Is the content plugin initialized?`);let a=new Date,o=r?.id??``,s=r?.name??null,c=await i.upsert({entityId:e,locale:n,data:t,createdBy:o,createdByName:s,createdAt:a,updatedAt:a},{target:[`entityId`,`locale`],set:{data:t,updatedAt:a}});return this.toDraftEntry(c)}async getDraft(e,t=`_`){let n=this.getDraftsClient();if(!n)return null;let r=await n.findOne({entityId:e,locale:t});return r?this.toDraftEntry(r):null}async deleteDraft(e,t=`_`){let n=this.getDraftsClient();return n?(await n.deleteMany({entityId:e,locale:t})).length>0:!1}async publishDraft(e,t=`_`,n){let r=await this.getDraft(e,t);if(!r)throw Error(`No draft found for entity ${e} locale ${t}`);let i=this.admin,a=null;this.versionableOptions&&(a=await i.findById(e));let{id:o,createdAt:s,createdBy:c,_version:l,_versionedAt:u,...d}=r.data,f=await i.update(e,d);return await this.deleteDraft(e,t),this.versionableOptions&&await this.createVersionSnapshot(e,f,a,t,n),f}async hasDraft(e,t=`_`){let n=this.getDraftsClient();return n?n.exists({entityId:e,locale:t}):!1}async countDrafts(e=`_`){let t=this.getDraftsClient();return t?t.count({locale:e}):0}async hasDraftBatch(e,t=`_`){let n=new Set;if(e.length===0)return n;let r=this.getDraftsClient();if(!r)return n;let i=await r.findMany({where:{entityId:{in:e},locale:t}});for(let e of i)n.add(e.entityId);return n}async createVersionSnapshot(e,t,n,r,i){if(!this.versionableOptions)return;let a=r??`_`,o=n?this.calculateDelta(n,t):null,s=await this.saveVersionSnapshot(e,t,o,!1,a,i);s!==void 0&&a===`_`&&await this.writeVersionColumn(e,s),await this.pruneVersions(e,a)}async writeVersionColumn(e,t){let{schemaRegistry:n}=await import(`@murumets-ee/db`),{eq:r}=await import(`drizzle-orm`),i=n.get(this.entity.name);i&&await this.db.update(i).set({_version:t}).where(r(i.id,e))}async saveVersionSnapshot(e,t,n,r,i=`_`,a){let o=this.getVersionsClient();if(!o)return;let[s]=await o.aggregate({select:{maxVersion:{fn:`max`,column:`version`}},where:{entityId:e,locale:i}}),c=Number(s?.maxVersion??0)+1,l=t.status??null;if(r){let r=await o.findOne({entityId:e,isAutosave:!0,version:c,locale:i});if(r)return await o.update({id:r.id},{data:t,delta:n,status:l,createdAt:new Date}),c}return await o.insert({entityId:e,version:c,locale:i,data:t,delta:n,status:l,createdBy:a?.id??t.updatedBy??t.createdBy??null,createdByName:a?.name??null,isAutosave:r}),c}toDraftEntry(e){return{id:e.id,entityId:e.entityId,locale:e.locale,data:e.data,createdBy:e.createdBy,createdByName:e.createdByName??null,createdAt:e.createdAt,updatedAt:e.updatedAt}}calculateDelta(e,t){let n={};for(let r of Object.keys(t))r===`id`||r.startsWith(`_`)||JSON.stringify(e[r])!==JSON.stringify(t[r])&&(n[r]=t[r]);return n}};async function a(e){let{createAdminClient:t}=await import(`@murumets-ee/core/clients`),{getApp:n}=await import(`@murumets-ee/core`);return new i({admin:t(e),entity:e,logger:n().logger.child({content:e.name})})}export{i as ContentClient,a as createContentClient};
|
|
2
2
|
//# sourceMappingURL=client.mjs.map
|