@murumets-ee/content 0.1.1 → 0.1.2
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/package.json +11 -17
- package/dist/blocks/index.cjs +0 -1
- package/dist/blocks/index.d.cts +0 -187
- package/dist/blocks/index.d.ts +0 -187
- package/dist/client.cjs +0 -1
- package/dist/client.d.cts +0 -215
- package/dist/client.d.ts +0 -215
- package/dist/index.cjs +0 -1
- package/dist/index.d.cts +0 -142
- package/dist/index.d.ts +0 -142
- package/dist/lock-service.cjs +0 -1
- package/dist/lock-service.d.cts +0 -61
- package/dist/lock-service.d.ts +0 -61
- package/dist/plugin.cjs +0 -1
- package/dist/plugin.d.cts +0 -33
- package/dist/plugin.d.ts +0 -33
- package/dist/query-client.cjs +0 -1
- package/dist/query-client.d.cts +0 -67
- package/dist/query-client.d.ts +0 -67
- package/dist/types-BYeiE1ie.d.cts +0 -99
- package/dist/types-BYeiE1ie.d.ts +0 -99
- package/dist/types-Cr0ifLn_.d.cts +0 -41
- package/dist/types-Cr0ifLn_.d.ts +0 -41
package/dist/index.d.ts
DELETED
|
@@ -1,142 +0,0 @@
|
|
|
1
|
-
import { Behavior, NumberField, DateField, SelectField, TextField, FieldConfig } from '@murumets-ee/entity';
|
|
2
|
-
import { b as VersionableOptions, B as BlockDefinition } from './types-BYeiE1ie.js';
|
|
3
|
-
export { C as ContentConfig, D as DraftEntry, I as InferBlockData, c as InferBlocksUnion, d as LocaleConfig, e as LockInfo, f as TranslationFieldStatus, a as TranslationReport, T as TranslationStatus, V as VersionEntry } from './types-BYeiE1ie.js';
|
|
4
|
-
import { B as BlockDiffEntry, F as FieldDiff, D as DiffSegment } from './types-Cr0ifLn_.js';
|
|
5
|
-
export { a as BlockDiffStatus, P as PropDiff } from './types-Cr0ifLn_.js';
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Versionable behavior — full version history with snapshots.
|
|
9
|
-
*
|
|
10
|
-
* Extends the concept of revisionable() (which only tracks a counter)
|
|
11
|
-
* with actual version snapshots stored in {entity}_versions table.
|
|
12
|
-
*
|
|
13
|
-
* The behavior itself adds fields + hooks for version tracking.
|
|
14
|
-
* Actual snapshot persistence happens in ContentClient (which has DB access).
|
|
15
|
-
*
|
|
16
|
-
* Options:
|
|
17
|
-
* - maxPerDoc: Maximum versions kept per document (default: 50)
|
|
18
|
-
* - autosave: Enable smart autosave (default: false)
|
|
19
|
-
*/
|
|
20
|
-
|
|
21
|
-
type VersionableFields = {
|
|
22
|
-
_version: NumberField & {
|
|
23
|
-
required: true;
|
|
24
|
-
};
|
|
25
|
-
_versionedAt: DateField;
|
|
26
|
-
};
|
|
27
|
-
declare function versionable(options?: VersionableOptions): Behavior<VersionableFields>;
|
|
28
|
-
/**
|
|
29
|
-
* Extract versionable options from an entity's behaviors
|
|
30
|
-
*/
|
|
31
|
-
declare function getVersionableOptions(behaviors?: Behavior[]): Required<VersionableOptions> | null;
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* Workflowable behavior — editorial workflow with approval gates.
|
|
35
|
-
*
|
|
36
|
-
* Adds workflow status tracking fields to an entity. Works alongside
|
|
37
|
-
* `publishable()` — the workflow status tracks the editorial pipeline,
|
|
38
|
-
* while publishable's `status` remains the public-facing state.
|
|
39
|
-
*
|
|
40
|
-
* Key invariant: `status` can only transition to 'published' when
|
|
41
|
-
* `_workflowStatus === 'approved'` (unless the user has direct `publish`
|
|
42
|
-
* permission, which bypasses the workflow).
|
|
43
|
-
*
|
|
44
|
-
* Workflow states:
|
|
45
|
-
* - draft → in_review (submit for review, requires 'update')
|
|
46
|
-
* - in_review → approved (approve, requires 'publish')
|
|
47
|
-
* - in_review → rejected (reject with note, requires 'publish')
|
|
48
|
-
* - approved → published (publish, requires 'publish')
|
|
49
|
-
* - rejected → in_review (resubmit, requires 'update')
|
|
50
|
-
* - published → draft (unpublish, requires 'publish')
|
|
51
|
-
*/
|
|
52
|
-
|
|
53
|
-
declare const WORKFLOW_STATES: readonly ["draft", "in_review", "approved", "rejected", "published"];
|
|
54
|
-
type WorkflowState = (typeof WORKFLOW_STATES)[number];
|
|
55
|
-
type WorkflowableFields = {
|
|
56
|
-
_workflowStatus: SelectField & {
|
|
57
|
-
required: true;
|
|
58
|
-
};
|
|
59
|
-
_workflowAssignee: TextField;
|
|
60
|
-
_workflowNote: TextField;
|
|
61
|
-
_workflowUpdatedAt: DateField;
|
|
62
|
-
};
|
|
63
|
-
declare function workflowable(): Behavior<WorkflowableFields>;
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
* Block definition API
|
|
67
|
-
*
|
|
68
|
-
* defineBlock() creates a reusable content block with typed fields.
|
|
69
|
-
* Uses `const F` generic to preserve literal field types for inference.
|
|
70
|
-
*
|
|
71
|
-
* Blocks are NOT entities — they lack independent identity, CRUD, and access control.
|
|
72
|
-
* They exist only as embedded data within a parent entity's blocks field.
|
|
73
|
-
*
|
|
74
|
-
* @example
|
|
75
|
-
* const HeroBlock = defineBlock({
|
|
76
|
-
* slug: 'hero',
|
|
77
|
-
* label: 'Hero Section',
|
|
78
|
-
* fields: {
|
|
79
|
-
* heading: field.text({ required: true, translatable: true }),
|
|
80
|
-
* background: field.media({ accept: ['image/*'] }),
|
|
81
|
-
* },
|
|
82
|
-
* })
|
|
83
|
-
*/
|
|
84
|
-
|
|
85
|
-
declare function defineBlock<const F extends Record<string, FieldConfig>>(definition: {
|
|
86
|
-
slug: string;
|
|
87
|
-
label: string;
|
|
88
|
-
fields: F;
|
|
89
|
-
}): BlockDefinition<F>;
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
* Structural diff for Puck block arrays.
|
|
93
|
-
*
|
|
94
|
-
* Blocks are identified by `_id`. The algorithm detects:
|
|
95
|
-
* - Added blocks (new _id in target)
|
|
96
|
-
* - Removed blocks (missing _id in target)
|
|
97
|
-
* - Moved blocks (same _id, different position)
|
|
98
|
-
* - Changed blocks (same _id, different prop values)
|
|
99
|
-
* - Unchanged blocks
|
|
100
|
-
*/
|
|
101
|
-
|
|
102
|
-
/**
|
|
103
|
-
* Compute structural diff between two block arrays.
|
|
104
|
-
*
|
|
105
|
-
* Each block is identified by its `_id` field. Position changes,
|
|
106
|
-
* additions, removals, and prop-level changes are all detected.
|
|
107
|
-
*/
|
|
108
|
-
declare function diffBlocks(fromBlocks: unknown[], toBlocks: unknown[]): BlockDiffEntry[];
|
|
109
|
-
|
|
110
|
-
/**
|
|
111
|
-
* Field-level diff — dispatches to the appropriate diff strategy per field type.
|
|
112
|
-
*/
|
|
113
|
-
|
|
114
|
-
/**
|
|
115
|
-
* Compute diff for a single field, using the field's type to determine
|
|
116
|
-
* the best diff strategy.
|
|
117
|
-
*/
|
|
118
|
-
declare function diffField(fieldName: string, from: unknown, to: unknown, fieldConfig?: FieldConfig): FieldDiff | null;
|
|
119
|
-
/**
|
|
120
|
-
* Diff all fields between two version snapshots.
|
|
121
|
-
* Pass fieldConfigs to get type-aware diffs; without them, types are inferred.
|
|
122
|
-
*/
|
|
123
|
-
declare function diffFields(from: Record<string, unknown>, to: Record<string, unknown>, fieldConfigs?: Record<string, FieldConfig>): FieldDiff[];
|
|
124
|
-
/** Diff two string values and return segments (used by block-diff for string props). */
|
|
125
|
-
declare function diffStringValues(from: unknown, to: unknown): DiffSegment[] | undefined;
|
|
126
|
-
|
|
127
|
-
/**
|
|
128
|
-
* Word-level text diff using a simplified Myers algorithm.
|
|
129
|
-
*
|
|
130
|
-
* Splits text into words (preserving whitespace), computes the longest common
|
|
131
|
-
* subsequence, and returns an array of diff segments.
|
|
132
|
-
*/
|
|
133
|
-
|
|
134
|
-
/**
|
|
135
|
-
* Compute word-level diff between two strings.
|
|
136
|
-
*
|
|
137
|
-
* Uses a simple LCS (dynamic programming) approach which is fine for
|
|
138
|
-
* the text sizes we deal with (entity field values, not source code).
|
|
139
|
-
*/
|
|
140
|
-
declare function diffText(from: string, to: string): DiffSegment[];
|
|
141
|
-
|
|
142
|
-
export { BlockDefinition, BlockDiffEntry, DiffSegment, FieldDiff, VersionableOptions, WORKFLOW_STATES, type WorkflowState, type WorkflowableFields, defineBlock, diffBlocks, diffField, diffFields, diffStringValues, diffText, getVersionableOptions, versionable, workflowable };
|
package/dist/lock-service.cjs
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
"use strict";var m=Object.create;var p=Object.defineProperty;var b=Object.getOwnPropertyDescriptor;var h=Object.getOwnPropertyNames;var f=Object.getPrototypeOf,A=Object.prototype.hasOwnProperty;var T=(n,e)=>{for(var s in e)p(n,s,{get:e[s],enumerable:!0})},y=(n,e,s,c)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of h(e))!A.call(n,i)&&i!==s&&p(n,i,{get:()=>e[i],enumerable:!(c=b(e,i))||c.enumerable});return n};var g=(n,e,s)=>(s=n!=null?m(f(n)):{},y(e||!n||!n.__esModule?p(s,"default",{value:n,enumerable:!0}):s,n)),x=n=>y(p({},"__esModule",{value:!0}),n);var D={};T(D,{LockService:()=>w,createLockService:()=>B});module.exports=x(D);var L=require("server-only"),k=5,w=class{db;constructor(e){this.db=e.db}async getTable(){let{schemaRegistry:e}=await import("@murumets-ee/db");return e.get("toolkit_content_locks")}async acquireLock(e,s,c,i){let{eq:r,and:o,lt:a}=await import("drizzle-orm"),t=await this.getTable();if(!t)return{acquired:!0};let l=new Date,u=new Date(l.getTime()+k*60*1e3);await this.db.delete(t).where(o(r(t.entityType,e),r(t.entityId,s),r(t.locale,c),a(t.expiresAt,l)));let[d]=await this.db.select().from(t).where(o(r(t.entityType,e),r(t.entityId,s),r(t.locale,c))).limit(1);return d?d.lockedBy===i.id?(await this.db.update(t).set({expiresAt:u,lockedAt:l}).where(r(t.id,d.id)),{acquired:!0}):{acquired:!1,lock:{lockedBy:d.lockedBy,lockedByName:d.lockedByName??null,lockedAt:d.lockedAt,expiresAt:d.expiresAt}}:(await this.db.insert(t).values({entityType:e,entityId:s,locale:c,lockedBy:i.id,lockedByName:i.name??null,lockedAt:l,expiresAt:u}),{acquired:!0})}async renewLock(e,s,c,i){let{eq:r,and:o,gte:a}=await import("drizzle-orm"),t=await this.getTable();if(!t)return!0;let l=new Date,u=new Date(l.getTime()+k*60*1e3);return(await this.db.update(t).set({expiresAt:u}).where(o(r(t.entityType,e),r(t.entityId,s),r(t.locale,c),r(t.lockedBy,i),a(t.expiresAt,l))).returning({id:t.id})).length>0}async releaseLock(e,s,c,i){let{eq:r,and:o}=await import("drizzle-orm"),a=await this.getTable();return a?(await this.db.delete(a).where(o(r(a.entityType,e),r(a.entityId,s),r(a.locale,c),r(a.lockedBy,i))).returning({id:a.id})).length>0:!0}async forceReleaseLock(e,s,c){let{eq:i,and:r}=await import("drizzle-orm"),o=await this.getTable();return o?(await this.db.delete(o).where(r(i(o.entityType,e),i(o.entityId,s),i(o.locale,c))).returning({id:o.id})).length>0:!0}async getLock(e,s,c){let{eq:i,and:r,gte:o}=await import("drizzle-orm"),a=await this.getTable();if(!a)return null;let t=new Date,[l]=await this.db.select().from(a).where(r(i(a.entityType,e),i(a.entityId,s),i(a.locale,c),o(a.expiresAt,t))).limit(1);return l?{lockedBy:l.lockedBy,lockedByName:l.lockedByName??null,lockedAt:l.lockedAt,expiresAt:l.expiresAt}:null}};async function B(){let{getApp:n}=await import("@murumets-ee/core"),e=n();return new w({db:e.db.readWrite})}0&&(module.exports={LockService,createLockService});
|
package/dist/lock-service.d.cts
DELETED
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
import { PostgresJsDatabase } from 'drizzle-orm/postgres-js';
|
|
2
|
-
import { e as LockInfo } from './types-BYeiE1ie.cjs';
|
|
3
|
-
import '@murumets-ee/entity';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Content lock service — pessimistic locking for entity editing.
|
|
7
|
-
*
|
|
8
|
-
* Prevents concurrent edit conflicts by allowing only one editor at a time
|
|
9
|
-
* per entity+locale combination. Locks expire after 5 minutes and must
|
|
10
|
-
* be renewed via heartbeat.
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
|
-
interface LockServiceConfig {
|
|
14
|
-
db: PostgresJsDatabase;
|
|
15
|
-
}
|
|
16
|
-
declare class LockService {
|
|
17
|
-
private db;
|
|
18
|
-
constructor(config: LockServiceConfig);
|
|
19
|
-
private getTable;
|
|
20
|
-
/**
|
|
21
|
-
* Acquire a lock on an entity+locale.
|
|
22
|
-
*
|
|
23
|
-
* - Deletes expired locks first
|
|
24
|
-
* - Attempts INSERT; on conflict checks if same user (re-entrant → renew)
|
|
25
|
-
* - Returns { acquired: true } or { acquired: false, lock: LockInfo }
|
|
26
|
-
*/
|
|
27
|
-
acquireLock(entityType: string, entityId: string, locale: string, user: {
|
|
28
|
-
id: string;
|
|
29
|
-
name?: string;
|
|
30
|
-
}): Promise<{
|
|
31
|
-
acquired: true;
|
|
32
|
-
} | {
|
|
33
|
-
acquired: false;
|
|
34
|
-
lock: LockInfo;
|
|
35
|
-
}>;
|
|
36
|
-
/**
|
|
37
|
-
* Renew an existing lock (heartbeat).
|
|
38
|
-
* Only succeeds if the caller holds the lock and it hasn't expired.
|
|
39
|
-
*/
|
|
40
|
-
renewLock(entityType: string, entityId: string, locale: string, userId: string): Promise<boolean>;
|
|
41
|
-
/**
|
|
42
|
-
* Release a lock. Only the lock holder can release their own lock.
|
|
43
|
-
*/
|
|
44
|
-
releaseLock(entityType: string, entityId: string, locale: string, userId: string): Promise<boolean>;
|
|
45
|
-
/**
|
|
46
|
-
* Force-release a lock regardless of who holds it.
|
|
47
|
-
* Admin-only operation — must be audit-logged by the caller.
|
|
48
|
-
*/
|
|
49
|
-
forceReleaseLock(entityType: string, entityId: string, locale: string): Promise<boolean>;
|
|
50
|
-
/**
|
|
51
|
-
* Get the current lock for an entity+locale.
|
|
52
|
-
* Returns null if no lock or lock has expired.
|
|
53
|
-
*/
|
|
54
|
-
getLock(entityType: string, entityId: string, locale: string): Promise<LockInfo | null>;
|
|
55
|
-
}
|
|
56
|
-
/**
|
|
57
|
-
* Factory — creates a LockService using the app's DB connection.
|
|
58
|
-
*/
|
|
59
|
-
declare function createLockService(): Promise<LockService>;
|
|
60
|
-
|
|
61
|
-
export { LockService, type LockServiceConfig, createLockService };
|
package/dist/lock-service.d.ts
DELETED
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
import { PostgresJsDatabase } from 'drizzle-orm/postgres-js';
|
|
2
|
-
import { e as LockInfo } from './types-BYeiE1ie.js';
|
|
3
|
-
import '@murumets-ee/entity';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Content lock service — pessimistic locking for entity editing.
|
|
7
|
-
*
|
|
8
|
-
* Prevents concurrent edit conflicts by allowing only one editor at a time
|
|
9
|
-
* per entity+locale combination. Locks expire after 5 minutes and must
|
|
10
|
-
* be renewed via heartbeat.
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
|
-
interface LockServiceConfig {
|
|
14
|
-
db: PostgresJsDatabase;
|
|
15
|
-
}
|
|
16
|
-
declare class LockService {
|
|
17
|
-
private db;
|
|
18
|
-
constructor(config: LockServiceConfig);
|
|
19
|
-
private getTable;
|
|
20
|
-
/**
|
|
21
|
-
* Acquire a lock on an entity+locale.
|
|
22
|
-
*
|
|
23
|
-
* - Deletes expired locks first
|
|
24
|
-
* - Attempts INSERT; on conflict checks if same user (re-entrant → renew)
|
|
25
|
-
* - Returns { acquired: true } or { acquired: false, lock: LockInfo }
|
|
26
|
-
*/
|
|
27
|
-
acquireLock(entityType: string, entityId: string, locale: string, user: {
|
|
28
|
-
id: string;
|
|
29
|
-
name?: string;
|
|
30
|
-
}): Promise<{
|
|
31
|
-
acquired: true;
|
|
32
|
-
} | {
|
|
33
|
-
acquired: false;
|
|
34
|
-
lock: LockInfo;
|
|
35
|
-
}>;
|
|
36
|
-
/**
|
|
37
|
-
* Renew an existing lock (heartbeat).
|
|
38
|
-
* Only succeeds if the caller holds the lock and it hasn't expired.
|
|
39
|
-
*/
|
|
40
|
-
renewLock(entityType: string, entityId: string, locale: string, userId: string): Promise<boolean>;
|
|
41
|
-
/**
|
|
42
|
-
* Release a lock. Only the lock holder can release their own lock.
|
|
43
|
-
*/
|
|
44
|
-
releaseLock(entityType: string, entityId: string, locale: string, userId: string): Promise<boolean>;
|
|
45
|
-
/**
|
|
46
|
-
* Force-release a lock regardless of who holds it.
|
|
47
|
-
* Admin-only operation — must be audit-logged by the caller.
|
|
48
|
-
*/
|
|
49
|
-
forceReleaseLock(entityType: string, entityId: string, locale: string): Promise<boolean>;
|
|
50
|
-
/**
|
|
51
|
-
* Get the current lock for an entity+locale.
|
|
52
|
-
* Returns null if no lock or lock has expired.
|
|
53
|
-
*/
|
|
54
|
-
getLock(entityType: string, entityId: string, locale: string): Promise<LockInfo | null>;
|
|
55
|
-
}
|
|
56
|
-
/**
|
|
57
|
-
* Factory — creates a LockService using the app's DB connection.
|
|
58
|
-
*/
|
|
59
|
-
declare function createLockService(): Promise<LockService>;
|
|
60
|
-
|
|
61
|
-
export { LockService, type LockServiceConfig, createLockService };
|
package/dist/plugin.cjs
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
"use strict";var P=Object.create;var h=Object.defineProperty;var D=Object.getOwnPropertyDescriptor;var F=Object.getOwnPropertyNames;var O=Object.getPrototypeOf,G=Object.prototype.hasOwnProperty;var p=(t,a)=>()=>(t&&(a=t(t=0)),a);var f=(t,a)=>{for(var e in a)h(t,e,{get:a[e],enumerable:!0})},v=(t,a,e,i)=>{if(a&&typeof a=="object"||typeof a=="function")for(let m of F(a))!G.call(t,m)&&m!==e&&h(t,m,{get:()=>a[m],enumerable:!(i=D(a,m))||i.enumerable});return t};var E=(t,a,e)=>(e=t!=null?P(O(t)):{},v(a||!t||!t.__esModule?h(e,"default",{value:t,enumerable:!0}):e,t)),H=t=>v(h({},"__esModule",{value:!0}),t);var C={};f(C,{generateVersionsSchema:()=>J});function J(t){let a=`${t.name}_versions`;return(0,o.pgTable)(a,{id:(0,o.uuid)("id").primaryKey().defaultRandom(),entityId:(0,o.uuid)("entity_id").notNull(),version:(0,o.integer)("version").notNull(),locale:(0,o.varchar)("locale",{length:10}).notNull().default("_"),data:(0,o.jsonb)("data").notNull(),delta:(0,o.jsonb)("delta"),status:(0,o.varchar)("status",{length:20}),createdBy:(0,o.varchar)("created_by",{length:255}),createdByName:(0,o.varchar)("created_by_name",{length:255}),createdAt:(0,o.timestamp)("created_at",{withTimezone:!0}).notNull().defaultNow(),isAutosave:(0,o.boolean)("is_autosave").notNull().default(!1)},e=>({uniqueEntityVersionLocale:(0,o.unique)().on(e.entityId,e.version,e.locale)}))}var o,L=p(()=>{"use strict";o=require("drizzle-orm/pg-core")});var S={};f(S,{generateLocaleStatusSchema:()=>M});function M(t){let a=`${t.name}_locale_status`;return(0,r.pgTable)(a,{id:(0,r.uuid)("id").primaryKey().defaultRandom(),entityId:(0,r.uuid)("entity_id").notNull(),locale:(0,r.varchar)("locale",{length:10}).notNull(),status:(0,r.varchar)("status",{length:20}).notNull().default("draft"),publishedAt:(0,r.timestamp)("published_at",{withTimezone:!0})},e=>({uniqueEntityLocale:(0,r.unique)().on(e.entityId,e.locale)}))}var r,q=p(()=>{"use strict";r=require("drizzle-orm/pg-core")});var x={};f(x,{generateDraftsSchema:()=>Q});function Q(t){let a=`${t.name}_drafts`;return(0,l.pgTable)(a,{id:(0,l.uuid)("id").primaryKey().defaultRandom(),entityId:(0,l.uuid)("entity_id").notNull(),locale:(0,l.varchar)("locale",{length:10}).notNull().default("_"),data:(0,l.jsonb)("data").notNull(),createdBy:(0,l.varchar)("created_by",{length:255}).notNull(),createdByName:(0,l.varchar)("created_by_name",{length:255}),createdAt:(0,l.timestamp)("created_at",{withTimezone:!0}).notNull().defaultNow(),updatedAt:(0,l.timestamp)("updated_at",{withTimezone:!0}).notNull().defaultNow()},e=>({uniqueEntityLocale:(0,l.unique)().on(e.entityId,e.locale)}))}var l,$=p(()=>{"use strict";l=require("drizzle-orm/pg-core")});var z={};f(z,{toolkitContentLocks:()=>U});var s,U,A=p(()=>{"use strict";s=require("drizzle-orm/pg-core"),U=(0,s.pgTable)("toolkit_content_locks",{id:(0,s.uuid)("id").primaryKey().defaultRandom(),entityType:(0,s.varchar)("entity_type",{length:100}).notNull(),entityId:(0,s.varchar)("entity_id",{length:255}).notNull(),locale:(0,s.varchar)("locale",{length:10}).notNull().default("_"),lockedBy:(0,s.varchar)("locked_by",{length:255}).notNull(),lockedByName:(0,s.varchar)("locked_by_name",{length:255}),lockedAt:(0,s.timestamp)("locked_at",{withTimezone:!0}).notNull().defaultNow(),expiresAt:(0,s.timestamp)("expires_at",{withTimezone:!0}).notNull()},t=>({uniqueEntityLock:(0,s.unique)().on(t.entityType,t.entityId,t.locale)}))});var Y={};f(Y,{content:()=>X,getContentConfig:()=>W});module.exports=H(Y);var g=null;function W(){if(!g)throw new Error("@murumets-ee/content plugin not initialized. Add content() to your plugins array.");return g}function X(t){if(!t.locales||t.locales.length===0)throw new Error("content() requires at least one locale");if(!t.defaultLocale)throw new Error("content() requires a defaultLocale");if(!t.locales.some(e=>e.code===t.defaultLocale))throw new Error(`defaultLocale "${t.defaultLocale}" not found in locales: [${t.locales.map(e=>e.code).join(", ")}]`);return{name:"@murumets-ee/content",init:async e=>{g=t;let{schemaRegistry:i}=await import("@murumets-ee/db"),{generateVersionsSchema:m}=await Promise.resolve().then(()=>(L(),C)),{generateLocaleStatusSchema:B}=await Promise.resolve().then(()=>(q(),S)),{generateDraftsSchema:I}=await Promise.resolve().then(()=>($(),x)),{toolkitContentLocks:j}=await Promise.resolve().then(()=>(A(),z)),{generateLayoutSchema:R,generateLayoutTranslationSchema:V}=await import("@murumets-ee/entity"),_=0,b=0,N=0,w=0;i.has("toolkit_content_locks")||i.register("toolkit_content_locks",j);for(let[d,u]of e.entities){if(u.behaviors?.some(n=>n.name==="versionable")){let n=`${d}_versions`;if(!i.has(n)){let c=m(u);i.register(n,c)}_++}let k=u.allFields;if(Object.values(k).some(n=>n.type==="blocks")){let n=`${d}_layout`;if(!i.has(n)){let y=R(u);y&&i.register(n,y)}let c=`${d}_layout_translations`;if(!i.has(c)){let y=V(u);y&&i.register(c,y)}b++}let T=u.behaviors?.some(n=>n.name==="publishable"),K=Object.values(k).some(n=>n.translatable);if(T&&K){let n=`${d}_locale_status`;if(!i.has(n)){let c=B(u);i.register(n,c)}N++}if(T){let n=`${d}_drafts`;if(!i.has(n)){let c=I(u);i.register(n,c)}w++}}e.logger.info({locales:t.locales.map(d=>d.code),defaultLocale:t.defaultLocale,versionableEntities:_,blockEntities:b,localeStatusEntities:N,draftEntities:w},"Content plugin initialized")}}}0&&(module.exports={content,getContentConfig});
|
package/dist/plugin.d.cts
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import { Plugin } from '@murumets-ee/core';
|
|
2
|
-
import { C as ContentConfig } from './types-BYeiE1ie.cjs';
|
|
3
|
-
import '@murumets-ee/entity';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Content plugin — registers locale configuration and version schemas.
|
|
7
|
-
*
|
|
8
|
-
* Usage:
|
|
9
|
-
* import { content } from '@murumets-ee/content/plugin'
|
|
10
|
-
*
|
|
11
|
-
* export default defineConfig({
|
|
12
|
-
* plugins: [
|
|
13
|
-
* content({
|
|
14
|
-
* locales: [
|
|
15
|
-
* { code: 'en', label: 'English' },
|
|
16
|
-
* { code: 'de', label: 'German' },
|
|
17
|
-
* ],
|
|
18
|
-
* defaultLocale: 'en',
|
|
19
|
-
* }),
|
|
20
|
-
* ],
|
|
21
|
-
* })
|
|
22
|
-
*/
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Get the content configuration. Throws if plugin not initialized.
|
|
26
|
-
*/
|
|
27
|
-
declare function getContentConfig(): ContentConfig;
|
|
28
|
-
/**
|
|
29
|
-
* Content plugin factory.
|
|
30
|
-
*/
|
|
31
|
-
declare function content(config: ContentConfig): Plugin;
|
|
32
|
-
|
|
33
|
-
export { content, getContentConfig };
|
package/dist/plugin.d.ts
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import { Plugin } from '@murumets-ee/core';
|
|
2
|
-
import { C as ContentConfig } from './types-BYeiE1ie.js';
|
|
3
|
-
import '@murumets-ee/entity';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Content plugin — registers locale configuration and version schemas.
|
|
7
|
-
*
|
|
8
|
-
* Usage:
|
|
9
|
-
* import { content } from '@murumets-ee/content/plugin'
|
|
10
|
-
*
|
|
11
|
-
* export default defineConfig({
|
|
12
|
-
* plugins: [
|
|
13
|
-
* content({
|
|
14
|
-
* locales: [
|
|
15
|
-
* { code: 'en', label: 'English' },
|
|
16
|
-
* { code: 'de', label: 'German' },
|
|
17
|
-
* ],
|
|
18
|
-
* defaultLocale: 'en',
|
|
19
|
-
* }),
|
|
20
|
-
* ],
|
|
21
|
-
* })
|
|
22
|
-
*/
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Get the content configuration. Throws if plugin not initialized.
|
|
26
|
-
*/
|
|
27
|
-
declare function getContentConfig(): ContentConfig;
|
|
28
|
-
/**
|
|
29
|
-
* Content plugin factory.
|
|
30
|
-
*/
|
|
31
|
-
declare function content(config: ContentConfig): Plugin;
|
|
32
|
-
|
|
33
|
-
export { content, getContentConfig };
|
package/dist/query-client.cjs
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
"use strict";var g=Object.create;var s=Object.defineProperty;var l=Object.getOwnPropertyDescriptor;var p=Object.getOwnPropertyNames;var c=Object.getPrototypeOf,d=Object.prototype.hasOwnProperty;var m=(e,t)=>{for(var r in t)s(e,r,{get:t[r],enumerable:!0})},u=(e,t,r,i)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of p(t))!d.call(e,n)&&n!==r&&s(e,n,{get:()=>t[n],enumerable:!(i=l(t,n))||i.enumerable});return e};var o=(e,t,r)=>(r=e!=null?g(c(e)):{},u(t||!e||!e.__esModule?s(r,"default",{value:e,enumerable:!0}):r,e)),h=e=>u(s({},"__esModule",{value:!0}),e);var q={};m(q,{ContentQueryClient:()=>y,createContentQueryClient:()=>f});module.exports=h(q);var y=class{entity;db;logger;query=null;constructor(t){this.entity=t.entity,this.db=t.db,this.logger=t.logger}async getQuery(){if(!this.query){let{QueryClient:t}=await import("@murumets-ee/entity/query");this.query=new t({entity:this.entity,db:this.db,logger:this.logger})}return this.query}async findById(t,r){return(await this.getQuery()).findById(t,r)}async findBySlug(t,r){let{schemaRegistry:i}=await import("@murumets-ee/db"),{eq:n}=await import("drizzle-orm"),a=i.get(this.entity.name);return!a||!a.slug?null:(await(await this.getQuery()).findMany({where:n(a.slug,t),limit:1,locale:r?.locale}))[0]??null}async findMany(t){return(await this.getQuery()).findMany(t)}async count(t){return(await this.getQuery()).count(t)}};async function f(e){let{getApp:t}=await import("@murumets-ee/core"),r=t();return new y({entity:e,db:r.db.readOnly,logger:r.logger.child({content:e.name})})}0&&(module.exports={ContentQueryClient,createContentQueryClient});
|
package/dist/query-client.d.cts
DELETED
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
import { Logger } from '@murumets-ee/core';
|
|
2
|
-
import { Entity } from '@murumets-ee/entity';
|
|
3
|
-
import { FindByIdOptions, FindManyOptions, CountOptions } from '@murumets-ee/entity/query';
|
|
4
|
-
import { PostgresJsDatabase } from 'drizzle-orm/postgres-js';
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* ContentQueryClient — read-only content queries, safe for client bundles.
|
|
8
|
-
*
|
|
9
|
-
* Usage:
|
|
10
|
-
* import { createContentQueryClient } from '@murumets-ee/content/query'
|
|
11
|
-
* const pages = createContentQueryClient(Page)
|
|
12
|
-
* const page = await pages.findBySlug('about', { locale: 'de' })
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
interface ContentQueryClientConfig {
|
|
16
|
-
entity: Entity;
|
|
17
|
-
db: PostgresJsDatabase;
|
|
18
|
-
logger?: Logger;
|
|
19
|
-
}
|
|
20
|
-
declare class ContentQueryClient {
|
|
21
|
-
private entity;
|
|
22
|
-
private db;
|
|
23
|
-
private logger?;
|
|
24
|
-
private query;
|
|
25
|
-
constructor(config: ContentQueryClientConfig);
|
|
26
|
-
private getQuery;
|
|
27
|
-
findById(id: string, options?: FindByIdOptions): Promise<({
|
|
28
|
-
id: string;
|
|
29
|
-
} & {} & {
|
|
30
|
-
[x: string]: string | number | boolean | Date | Record<string, unknown> | Record<string, unknown>[] | {
|
|
31
|
-
[key: string]: unknown;
|
|
32
|
-
_block: string;
|
|
33
|
-
_id: string;
|
|
34
|
-
}[] | null | undefined;
|
|
35
|
-
}) | null>;
|
|
36
|
-
/**
|
|
37
|
-
* Find entity by slug — convenience for slug-based lookups.
|
|
38
|
-
*/
|
|
39
|
-
findBySlug(slug: string, options?: {
|
|
40
|
-
locale?: string;
|
|
41
|
-
}): Promise<({
|
|
42
|
-
id: string;
|
|
43
|
-
} & {} & {
|
|
44
|
-
[x: string]: string | number | boolean | Date | Record<string, unknown> | Record<string, unknown>[] | {
|
|
45
|
-
[key: string]: unknown;
|
|
46
|
-
_block: string;
|
|
47
|
-
_id: string;
|
|
48
|
-
}[] | null | undefined;
|
|
49
|
-
}) | null>;
|
|
50
|
-
findMany(options?: FindManyOptions): Promise<({
|
|
51
|
-
id: string;
|
|
52
|
-
} & {} & {
|
|
53
|
-
[x: string]: string | number | boolean | Date | Record<string, unknown> | Record<string, unknown>[] | {
|
|
54
|
-
[key: string]: unknown;
|
|
55
|
-
_block: string;
|
|
56
|
-
_id: string;
|
|
57
|
-
}[] | null | undefined;
|
|
58
|
-
})[]>;
|
|
59
|
-
count(options?: CountOptions): Promise<number>;
|
|
60
|
-
}
|
|
61
|
-
/**
|
|
62
|
-
* Factory — creates a ContentQueryClient for an entity.
|
|
63
|
-
* Must be called after createApp().
|
|
64
|
-
*/
|
|
65
|
-
declare function createContentQueryClient(entity: Entity): Promise<ContentQueryClient>;
|
|
66
|
-
|
|
67
|
-
export { ContentQueryClient, type ContentQueryClientConfig, createContentQueryClient };
|
package/dist/query-client.d.ts
DELETED
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
import { Logger } from '@murumets-ee/core';
|
|
2
|
-
import { Entity } from '@murumets-ee/entity';
|
|
3
|
-
import { FindByIdOptions, FindManyOptions, CountOptions } from '@murumets-ee/entity/query';
|
|
4
|
-
import { PostgresJsDatabase } from 'drizzle-orm/postgres-js';
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* ContentQueryClient — read-only content queries, safe for client bundles.
|
|
8
|
-
*
|
|
9
|
-
* Usage:
|
|
10
|
-
* import { createContentQueryClient } from '@murumets-ee/content/query'
|
|
11
|
-
* const pages = createContentQueryClient(Page)
|
|
12
|
-
* const page = await pages.findBySlug('about', { locale: 'de' })
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
interface ContentQueryClientConfig {
|
|
16
|
-
entity: Entity;
|
|
17
|
-
db: PostgresJsDatabase;
|
|
18
|
-
logger?: Logger;
|
|
19
|
-
}
|
|
20
|
-
declare class ContentQueryClient {
|
|
21
|
-
private entity;
|
|
22
|
-
private db;
|
|
23
|
-
private logger?;
|
|
24
|
-
private query;
|
|
25
|
-
constructor(config: ContentQueryClientConfig);
|
|
26
|
-
private getQuery;
|
|
27
|
-
findById(id: string, options?: FindByIdOptions): Promise<({
|
|
28
|
-
id: string;
|
|
29
|
-
} & {} & {
|
|
30
|
-
[x: string]: string | number | boolean | Date | Record<string, unknown> | Record<string, unknown>[] | {
|
|
31
|
-
[key: string]: unknown;
|
|
32
|
-
_block: string;
|
|
33
|
-
_id: string;
|
|
34
|
-
}[] | null | undefined;
|
|
35
|
-
}) | null>;
|
|
36
|
-
/**
|
|
37
|
-
* Find entity by slug — convenience for slug-based lookups.
|
|
38
|
-
*/
|
|
39
|
-
findBySlug(slug: string, options?: {
|
|
40
|
-
locale?: string;
|
|
41
|
-
}): Promise<({
|
|
42
|
-
id: string;
|
|
43
|
-
} & {} & {
|
|
44
|
-
[x: string]: string | number | boolean | Date | Record<string, unknown> | Record<string, unknown>[] | {
|
|
45
|
-
[key: string]: unknown;
|
|
46
|
-
_block: string;
|
|
47
|
-
_id: string;
|
|
48
|
-
}[] | null | undefined;
|
|
49
|
-
}) | null>;
|
|
50
|
-
findMany(options?: FindManyOptions): Promise<({
|
|
51
|
-
id: string;
|
|
52
|
-
} & {} & {
|
|
53
|
-
[x: string]: string | number | boolean | Date | Record<string, unknown> | Record<string, unknown>[] | {
|
|
54
|
-
[key: string]: unknown;
|
|
55
|
-
_block: string;
|
|
56
|
-
_id: string;
|
|
57
|
-
}[] | null | undefined;
|
|
58
|
-
})[]>;
|
|
59
|
-
count(options?: CountOptions): Promise<number>;
|
|
60
|
-
}
|
|
61
|
-
/**
|
|
62
|
-
* Factory — creates a ContentQueryClient for an entity.
|
|
63
|
-
* Must be called after createApp().
|
|
64
|
-
*/
|
|
65
|
-
declare function createContentQueryClient(entity: Entity): Promise<ContentQueryClient>;
|
|
66
|
-
|
|
67
|
-
export { ContentQueryClient, type ContentQueryClientConfig, createContentQueryClient };
|
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
import { FieldConfig, InferEntityDTO } from '@murumets-ee/entity';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Content package types
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* A block definition — describes a reusable content block's data shape.
|
|
9
|
-
*
|
|
10
|
-
* @typeParam F - The literal field map, inferred from the call site.
|
|
11
|
-
*/
|
|
12
|
-
interface BlockDefinition<F extends Record<string, FieldConfig> = Record<string, FieldConfig>> {
|
|
13
|
-
slug: string;
|
|
14
|
-
label: string;
|
|
15
|
-
fields: F;
|
|
16
|
-
}
|
|
17
|
-
/**
|
|
18
|
-
* Infer the data shape of a single block definition.
|
|
19
|
-
* Produces `{ _block: 'hero'; _id: string; heading: string; ... }`
|
|
20
|
-
*/
|
|
21
|
-
type InferBlockData<B extends BlockDefinition> = B extends BlockDefinition<infer F> ? {
|
|
22
|
-
_block: B['slug'];
|
|
23
|
-
_id: string;
|
|
24
|
-
} & Omit<InferEntityDTO<F>, 'id'> : never;
|
|
25
|
-
/**
|
|
26
|
-
* Infer a discriminated union from a tuple of block definitions.
|
|
27
|
-
*
|
|
28
|
-
* @example
|
|
29
|
-
* type Layout = InferBlocksUnion<typeof [HeroBlock, RichTextBlock]>
|
|
30
|
-
* // = { _block: 'hero'; ... } | { _block: 'richtext'; ... }
|
|
31
|
-
*/
|
|
32
|
-
type InferBlocksUnion<T extends readonly BlockDefinition[]> = {
|
|
33
|
-
[K in keyof T]: T[K] extends BlockDefinition ? InferBlockData<T[K]> : never;
|
|
34
|
-
}[number];
|
|
35
|
-
interface LocaleConfig {
|
|
36
|
-
code: string;
|
|
37
|
-
label: string;
|
|
38
|
-
}
|
|
39
|
-
interface ContentConfig {
|
|
40
|
-
locales: LocaleConfig[];
|
|
41
|
-
defaultLocale: string;
|
|
42
|
-
}
|
|
43
|
-
interface VersionableOptions {
|
|
44
|
-
/** Maximum versions kept per document. Default: 50 */
|
|
45
|
-
maxPerDoc?: number;
|
|
46
|
-
/** Enable autosave (single mutable autosave version). Default: false */
|
|
47
|
-
autosave?: boolean;
|
|
48
|
-
}
|
|
49
|
-
interface VersionEntry {
|
|
50
|
-
id: string;
|
|
51
|
-
entityId: string;
|
|
52
|
-
version: number;
|
|
53
|
-
locale: string;
|
|
54
|
-
data: Record<string, unknown>;
|
|
55
|
-
delta: Record<string, unknown> | null;
|
|
56
|
-
status: string | null;
|
|
57
|
-
createdBy: string | null;
|
|
58
|
-
createdByName: string | null;
|
|
59
|
-
createdAt: Date | string;
|
|
60
|
-
isAutosave: boolean;
|
|
61
|
-
}
|
|
62
|
-
interface TranslationFieldStatus {
|
|
63
|
-
complete: boolean;
|
|
64
|
-
total: number;
|
|
65
|
-
translated: number;
|
|
66
|
-
missing: string[];
|
|
67
|
-
}
|
|
68
|
-
interface TranslationStatus {
|
|
69
|
-
[locale: string]: TranslationFieldStatus;
|
|
70
|
-
}
|
|
71
|
-
interface TranslationReport {
|
|
72
|
-
total: number;
|
|
73
|
-
complete: number;
|
|
74
|
-
partial: number;
|
|
75
|
-
missing: number;
|
|
76
|
-
}
|
|
77
|
-
interface LocalePublishStatus {
|
|
78
|
-
locale: string;
|
|
79
|
-
status: 'draft' | 'published';
|
|
80
|
-
publishedAt: Date | string | null;
|
|
81
|
-
}
|
|
82
|
-
interface DraftEntry {
|
|
83
|
-
id: string;
|
|
84
|
-
entityId: string;
|
|
85
|
-
locale: string;
|
|
86
|
-
data: Record<string, unknown>;
|
|
87
|
-
createdBy: string;
|
|
88
|
-
createdByName: string | null;
|
|
89
|
-
createdAt: Date | string;
|
|
90
|
-
updatedAt: Date | string;
|
|
91
|
-
}
|
|
92
|
-
interface LockInfo {
|
|
93
|
-
lockedBy: string;
|
|
94
|
-
lockedByName: string | null;
|
|
95
|
-
lockedAt: Date | string;
|
|
96
|
-
expiresAt: Date | string;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
export type { BlockDefinition as B, ContentConfig as C, DraftEntry as D, InferBlockData as I, LocalePublishStatus as L, TranslationStatus as T, VersionEntry as V, TranslationReport as a, VersionableOptions as b, InferBlocksUnion as c, LocaleConfig as d, LockInfo as e, TranslationFieldStatus as f };
|