@murumets-ee/entity 0.1.6 → 0.2.1

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.
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../src/admin-config.ts","../src/fields/base.ts","../src/types/infer.ts","../src/behaviors/types.ts","../src/behaviors/auditable.ts","../src/behaviors/hierarchical.ts","../src/behaviors/publishable.ts","../src/behaviors/revisionable.ts","../src/behaviors/sluggable.ts","../src/fields/builders.ts","../src/behaviors/timestamped.ts","../src/behaviors/index.ts","../src/count-cache.ts","../src/count-estimate.ts","../src/cursor.ts","../src/define-entity.ts","../src/refs/find-usages.ts","../src/refs/errors.ts","../src/schema-generator.ts"],"mappings":"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"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/admin-config.ts","../src/fields/base.ts","../src/types/infer.ts","../src/behaviors/types.ts","../src/behaviors/auditable.ts","../src/behaviors/hierarchical.ts","../src/behaviors/publishable.ts","../src/behaviors/revisionable.ts","../src/behaviors/sluggable.ts","../src/fields/builders.ts","../src/behaviors/timestamped.ts","../src/behaviors/index.ts","../src/count-cache.ts","../src/count-estimate.ts","../src/cursor.ts","../src/define-entity.ts","../src/refs/find-usages.ts","../src/refs/errors.ts","../src/schema-generator.ts"],"mappings":"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"}
package/dist/index.mjs CHANGED
@@ -1,65 +1,2 @@
1
- import{and as e,eq as t,gt as n,lt as r,or as i,sql as a}from"drizzle-orm";import{boolean as o,doublePrecision as s,index as c,integer as l,jsonb as u,pgTable as d,text as f,timestamp as p,unique as m,uuid as h,varchar as g}from"drizzle-orm/pg-core";const _={id:e=>({type:`id`,required:!0,indexed:!0,...e}),text:e=>({type:`text`,...e}),number:e=>({type:`number`,...e}),boolean:e=>({type:`boolean`,default:!1,...e}),date:e=>({type:`date`,...e}),select:e=>({type:`select`,...e}),reference:e=>({type:`reference`,cardinality:`one`,onDelete:`set-null`,...e}),media:e=>({type:`media`,...e}),richtext:e=>({type:`richtext`,...e}),slug:e=>({type:`slug`,unique:!0,indexed:!0,...e}),json:e=>({type:`json`,...e}),blocks:e=>({type:`blocks`,...e})};async function v(){try{return(await import([`@murumets-ee`,`core`].join(`/`))).getCurrentUser()?.id}catch{return}}function y(){return{name:`auditable`,fields:{createdBy:_.text(),updatedBy:_.text(),createdAt:_.date({indexed:!0}),updatedAt:_.date({indexed:!0})},hooks:{beforeCreate:async e=>{e.createdAt=new Date,e.updatedAt=new Date;let t=await v();return t&&(e.createdBy=t,e.updatedBy=t),e},beforeUpdate:async(e,t)=>{t.updatedAt=new Date;let n=await v();return n&&(t.updatedBy=n),t}}}}function b(e){return{name:`hierarchical`,fields:{parentId:_.reference({entity:`_self`,required:!1}),path:_.text({indexed:!0,maxLength:2048}),depth:_.number({integer:!0,default:0,indexed:!0})},hooks:{beforeCreate:async e=>(e.parentId||(e.depth=0),e)}}}function x(){return{name:`publishable`,fields:{status:_.select({options:[`draft`,`published`],default:`draft`,indexed:!0}),publishedAt:_.date({indexed:!0})},hooks:{beforeUpdate:async(e,t)=>(t.status===`published`&&!t.publishedAt&&(t.publishedAt=new Date),t)}}}function S(){return{name:`revisionable`,fields:{_version:_.number({required:!0,default:1,integer:!0})},hooks:{beforeCreate:async e=>(e._version=1,e),beforeUpdate:async(e,t)=>(t._version=(Number(t._version)||0)+1,t)}}}function C(e){return e.toLowerCase().trim().replace(/[^\w\s-]/g,``).replace(/[\s_-]+/g,`-`).replace(/^-+|-+$/g,``)}function w(e,t){return{name:`sluggable`,fields:{slug:_.slug({from:e,...t?.translatable?{translatable:!0}:{}})},hooks:{beforeCreate:async t=>(!t.slug&&t[e]&&(t.slug=C(String(t[e]))),t),beforeUpdate:async(t,n)=>(n[e]&&!n.slug&&(n.slug=C(String(n[e]))),n)}}}function T(){return{name:`timestamped`,fields:{createdAt:_.date({indexed:!0}),updatedAt:_.date({indexed:!0})},hooks:{beforeCreate:async e=>(e.createdAt=new Date,e.updatedAt=new Date,e),beforeUpdate:async(e,t)=>(t.updatedAt=new Date,t)}}}const E={publishable:x,auditable:y,sluggable:w,revisionable:S,hierarchical:b,timestamped:T};var D=class{cache=new Map;ttlMs;constructor(e=5e3){this.ttlMs=e}get(e){let t=this.cache.get(e);if(!t||Date.now()>t.expiresAt){t&&this.cache.delete(e);return}return t.count}set(e,t){this.cache.set(e,{count:t,expiresAt:Date.now()+this.ttlMs})}invalidate(e){for(let t of this.cache.keys())t.startsWith(e)&&this.cache.delete(t)}prune(){let e=Date.now();for(let[t,n]of this.cache.entries())e>n.expiresAt&&this.cache.delete(t)}clear(){this.cache.clear()}get size(){return this.cache.size}};async function O(e,t){let n=await e.execute(a`SELECT reltuples::bigint AS estimate FROM pg_class WHERE relname = ${t}`),r=(Array.isArray(n)?n:n.rows??[])[0],i=Number(r?.estimate??0);return i>0?i:0}const k=/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;function A(e,t,n){let r={field:t,value:e[t],direction:n,id:e.id};return btoa(JSON.stringify(r))}function j(e){try{let t=atob(e),n=JSON.parse(t);if(typeof n!=`object`||!n)return null;let r=n;return typeof r.field!=`string`||!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(r.field)||typeof r.value!=`string`&&typeof r.value!=`number`||r.direction!==`asc`&&r.direction!==`desc`||r.id!==void 0&&(typeof r.id!=`string`||!k.test(r.id))?null:{field:r.field,value:r.value,direction:r.direction,id:r.id}}catch{return null}}function M(a,o){let s=a[o.field];if(!s)return null;let c=o.direction===`desc`?r:n,l=c(s,o.value);if(!o.id)return l;let u=a.id;if(!u)return l;let d=c(u,o.id);return i(l,e(t(s,o.value),d))}function N(e){let t={},n={};for(let r of e.behaviors||[]){if(r.fields)for(let[e,n]of Object.entries(r.fields)){if(t[e]){console.warn(`Field '${e}' from behavior '${r.name}' conflicts with existing field. Skipping.`);continue}t[e]=n}if(r.hooks)for(let[e,t]of Object.entries(r.hooks)){let r=e;if(t){let e=n[r];if(e){let i=e,a=t;n[r]=async(...e)=>{let t=await i(...e);if(t!==void 0){let n=[...e];return n[n.length-1]=t,await a(...n)}return await a(...e)}}else n[r]=t}}}let r={id:_.id(),...t,...e.fields};for(let[,e]of Object.entries(r))e.type===`slug`&&!e.translatable&&r[e.from]?.translatable&&(e.translatable=!0);return{...e,allFields:r,hooks:n}}var P=class extends Error{entityName;entityId;usages;constructor(e,t,n){let r=n.length;super(`Cannot delete ${e} '${t}': referenced by ${r} other entit${r===1?`y`:`ies`}`),this.name=`ReferencedEntityError`,this.entityName=e,this.entityId=t,this.usages=n}};function F(e,t,n){let r=n?.nullable??!1;switch(t.type){case`id`:return h(e).primaryKey().defaultRandom();case`text`:if(t.maxLength&&t.maxLength<=255){let n=g(e,{length:t.maxLength});return t.unique&&(n=n.unique()),!r&&t.required&&(n=n.notNull()),!r&&t.default!==void 0&&(n=n.default(t.default)),n}else{let n=f(e);return t.unique&&(n=n.unique()),!r&&t.required&&(n=n.notNull()),!r&&t.default!==void 0&&(n=n.default(t.default)),n}case`number`:{let n=t.integer?l(e):s(e);return!r&&t.required&&(n=n.notNull()),!r&&t.default!==void 0&&(n=n.default(t.default)),n}case`boolean`:{let n=o(e);if(!r&&t.required&&(n=n.notNull()),!r){let e=t.default===void 0?!1:t.default;n=n.default(e)}return n}case`date`:{let n=p(e,{withTimezone:!0});return!r&&t.required&&(n=n.notNull()),!r&&t.default!==void 0&&(n=n.default(t.default)),n}case`select`:{let n=g(e,{length:100});return!r&&t.required&&(n=n.notNull()),!r&&t.default!==void 0&&(n=n.default(t.default)),n}case`reference`:{if(t.cardinality===`many`)return h(e).array();let n=h(e);return!r&&t.required&&(n=n.notNull()),n}case`media`:{let n=h(e);return!r&&t.required&&(n=n.notNull()),n}case`slug`:{let n=g(e,{length:255});return t.unique&&!r&&(n=n.unique()),!r&&t.required&&(n=n.notNull()),n}case`richtext`:{let n=f(e);return!r&&t.required&&(n=n.notNull()),n}case`json`:return u(e);default:return f(e)}}function I(e,t,n){let r=n?.nullable??!1;switch(t.type){case`id`:return`id: uuid('id').primaryKey().defaultRandom()`;case`text`:{let n=t.maxLength,i=n&&n<=255?`varchar('${e}', { length: ${n} })`:`text('${e}')`;return t.unique&&(i+=`.unique()`),!r&&t.required&&(i+=`.notNull()`),!r&&t.default&&(i+=`.default('${t.default}')`),`${e}: ${i}`}case`number`:{let n=t.integer?`integer('${e}')`:`doublePrecision('${e}')`;return!r&&t.required&&(n+=`.notNull()`),!r&&t.default!==void 0&&(n+=`.default(${t.default})`),`${e}: ${n}`}case`boolean`:return r?`${e}: boolean('${e}')`:`${e}: boolean('${e}').default(${t.default??!1})`;case`date`:{let n=`timestamp('${e}', { withTimezone: true })`;return!r&&t.required&&(n+=`.notNull()`),`${e}: ${n}`}case`reference`:{if(t.cardinality===`many`)return`${e}: uuid('${e}').array()`;let n=`uuid('${e}')`;return!r&&t.required&&(n+=`.notNull()`),`${e}: ${n}`}case`media`:{let n=`uuid('${e}')`;return!r&&t.required&&(n+=`.notNull()`),`${e}: ${n}`}case`slug`:{let n=`varchar('${e}', { length: 255 })`;return t.unique&&!r&&(n+=`.unique()`),!r&&t.required&&(n+=`.notNull()`),`${e}: ${n}`}case`select`:{let n=`varchar('${e}', { length: 100 })`;return!r&&t.required&&(n+=`.notNull()`),!r&&t.default&&(n+=`.default('${t.default}')`),`${e}: ${n}`}case`richtext`:{let n=`text('${e}')`;return!r&&t.required&&(n+=`.notNull()`),`${e}: ${n}`}case`json`:return`${e}: jsonb('${e}')`;default:return`${e}: text('${e}')`}}function L(e){let t=e.name,n={};for(let[t,r]of Object.entries(e.allFields))r.type!==`blocks`&&(n[t]=F(t,r));(e.scope===`team`||e.scope===`user`)&&(n._scopeId=h(`_scope_id`));let r=Object.entries(e.allFields).filter(([e,t])=>t.type!==`blocks`&&t.type!==`id`&&t.indexed&&!t.unique),i=e.behaviors?.some(e=>e.name===`publishable`)??!1;return r.length===0&&!i?d(t,n):d(t,n,e=>{let n={};for(let[i]of r)n[`idx_${t}_${i}`]=c(`idx_${t}_${i}`).on(e[i]);return i&&e.status&&e.createdAt&&(n[`idx_${t}_status_created`]=c(`idx_${t}_status_created`).on(e.status,e.createdAt)),n})}function R(e){let t=e.name,n=[],r=Object.entries(e.allFields).filter(([e,t])=>t.type!==`blocks`&&t.type!==`id`&&t.indexed&&!t.unique),i=e.behaviors?.some(e=>e.name===`publishable`)??!1,a=r.length>0||i;n.push(`export const ${t} = pgTable('${t}', {`);for(let[t,r]of Object.entries(e.allFields)){if(r.type===`blocks`)continue;let e=I(t,r);n.push(` ${e},`)}if((e.scope===`team`||e.scope===`user`)&&n.push(` _scopeId: uuid('_scope_id'),`),a){n.push(`}, (table) => ({`);for(let[e]of r)n.push(` idx_${t}_${e}: index('idx_${t}_${e}').on(table.${e}),`);i&&n.push(` idx_${t}_status_created: index('idx_${t}_status_created').on(table.status, table.createdAt),`),n.push(`}))`)}else n.push(`)`);return n.join(`
2
- `)}function z(e){let t=Object.entries(e.allFields).filter(([e,t])=>t.translatable);if(t.length===0)return null;let n=`${e.name}_translations`,r={id:h(`id`).primaryKey().defaultRandom(),entityId:h(`entity_id`).notNull(),locale:g(`locale`,{length:10}).notNull()},i=t.some(([e,t])=>t.type===`slug`);for(let[e,n]of t)r[e]=F(e,n,{nullable:!0});return d(n,r,e=>({uniqueEntityLocale:m().on(e.entityId,e.locale),...i&&e.slug?{uniqueSlugLocale:m().on(e.slug,e.locale)}:{}}))}function B(e){let t=Object.entries(e.allFields).filter(([e,t])=>t.translatable);if(t.length===0)return null;let n=`${e.name}_translations`,r=e.name,i=[];i.push(`export const ${n} = pgTable('${n}', {`),i.push(` id: uuid('id').primaryKey().defaultRandom(),`),i.push(` entityId: uuid('entity_id').notNull().references(() => ${r}.id, { onDelete: 'cascade' }),`),i.push(` locale: varchar('locale', { length: 10 }).notNull(),`);for(let[e,n]of t){let t=I(e,n,{nullable:!0});i.push(` ${t},`)}let a=t.some(([e,t])=>t.type===`slug`);return i.push(`}, (table) => ({`),i.push(` uniqueEntityLocale: unique().on(table.entityId, table.locale), // One translation per locale`),a&&i.push(` uniqueSlugLocale: unique().on(table.slug, table.locale), // Per-locale slug uniqueness`),i.push(`}))`),i.join(`
3
- `)}function V(e){return Object.values(e.allFields).some(e=>e.type===`blocks`)}function H(e){if(!V(e))return null;let t=`${e.name}_layout`;return d(t,{id:h(`id`).primaryKey().defaultRandom(),entityId:h(`entity_id`).notNull(),fieldName:g(`field_name`,{length:100}).notNull(),blockType:g(`block_type`,{length:100}).notNull(),sortOrder:l(`sort_order`).notNull().default(0),data:u(`data`),locale:g(`locale`,{length:10})},e=>({idx_entity_locale_sort:c(`idx_${t}_entity_locale_sort`).on(e.entityId,e.locale,e.sortOrder)}))}function U(e){return e.behaviors?.some(e=>e.name===`versionable`)??!1}function W(e){if(!(e.behaviors?.some(e=>e.name===`publishable`)??!1))return!1;let t=e.allFields;return Object.values(t).some(e=>e.translatable)}function G(e){let t=e.name,n=`${t}_locale_status`;return`export const ${n} = pgTable('${n}', {
4
- id: uuid('id').primaryKey().defaultRandom(),
5
- entityId: uuid('entity_id').notNull().references(() => ${t}.id, { onDelete: 'cascade' }),
6
- locale: varchar('locale', { length: 10 }).notNull(),
7
- status: varchar('status', { length: 20 }).notNull().default('draft'),
8
- publishedAt: timestamp('published_at', { withTimezone: true }),
9
- }, (table) => ({
10
- uniqueEntityLocale: unique().on(table.entityId, table.locale),
11
- }))`}function K(e){return e.behaviors?.some(e=>e.name===`publishable`)??!1}function q(e){let t=e.name,n=`${t}_drafts`;return`export const ${n} = pgTable('${n}', {
12
- id: uuid('id').primaryKey().defaultRandom(),
13
- entityId: uuid('entity_id').notNull().references(() => ${t}.id, { onDelete: 'cascade' }),
14
- locale: varchar('locale', { length: 10 }).notNull().default('_'),
15
- data: jsonb('data').notNull(),
16
- createdBy: varchar('created_by', { length: 255 }).notNull(),
17
- createdByName: varchar('created_by_name', { length: 255 }),
18
- createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
19
- updatedAt: timestamp('updated_at', { withTimezone: true }).notNull().defaultNow(),
20
- }, (table) => ({
21
- uniqueEntityLocale: unique().on(table.entityId, table.locale),
22
- }))`}function J(){return`export const toolkit_content_locks = pgTable('toolkit_content_locks', {
23
- id: uuid('id').primaryKey().defaultRandom(),
24
- entityType: varchar('entity_type', { length: 100 }).notNull(),
25
- entityId: varchar('entity_id', { length: 255 }).notNull(),
26
- locale: varchar('locale', { length: 10 }).notNull().default('_'),
27
- lockedBy: varchar('locked_by', { length: 255 }).notNull(),
28
- lockedByName: varchar('locked_by_name', { length: 255 }),
29
- lockedAt: timestamp('locked_at', { withTimezone: true }).notNull().defaultNow(),
30
- expiresAt: timestamp('expires_at', { withTimezone: true }).notNull(),
31
- }, (table) => ({
32
- uniqueEntityLock: unique().on(table.entityType, table.entityId, table.locale),
33
- }))`}function Y(e){let t=e.allFields;return Object.values(t).some(e=>e.type!==`blocks`||e.localized?!1:e.blocks?.some(e=>Object.values(e.fields).some(e=>e.translatable)))}function X(e){let t=e.name,n=`${t}_layout`;return`export const ${n} = pgTable('${n}', {
34
- id: uuid('id').primaryKey().defaultRandom(),
35
- entityId: uuid('entity_id').notNull().references(() => ${t}.id, { onDelete: 'cascade' }),
36
- fieldName: varchar('field_name', { length: 100 }).notNull(),
37
- blockType: varchar('block_type', { length: 100 }).notNull(),
38
- sortOrder: integer('sort_order').notNull().default(0),
39
- data: jsonb('data'),
40
- locale: varchar('locale', { length: 10 }),
41
- }, (table) => ({
42
- idx_entity_locale_sort: index('idx_${n}_entity_locale_sort').on(table.entityId, table.locale, table.sortOrder),
43
- }))`}function Z(e){let t=e.name,n=`${t}_layout_translations`;return`export const ${n} = pgTable('${n}', {
44
- id: uuid('id').primaryKey().defaultRandom(),
45
- layoutId: uuid('layout_id').notNull().references(() => ${`${t}_layout`}.id, { onDelete: 'cascade' }),
46
- locale: varchar('locale', { length: 10 }).notNull(),
47
- fields: jsonb('fields').notNull(),
48
- }, (table) => ({
49
- uniqueLayoutLocale: unique().on(table.layoutId, table.locale),
50
- }))`}function Q(e){let t=e.name,n=`${t}_versions`;return`export const ${n} = pgTable('${n}', {
51
- id: uuid('id').primaryKey().defaultRandom(),
52
- entityId: uuid('entity_id').notNull().references(() => ${t}.id, { onDelete: 'cascade' }),
53
- version: integer('version').notNull(),
54
- locale: varchar('locale', { length: 10 }).notNull().default('_'),
55
- data: jsonb('data').notNull(),
56
- delta: jsonb('delta'),
57
- status: varchar('status', { length: 20 }),
58
- createdBy: varchar('created_by', { length: 255 }),
59
- createdByName: varchar('created_by_name', { length: 255 }),
60
- createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
61
- isAutosave: boolean('is_autosave').notNull().default(false),
62
- }, (table) => ({
63
- uniqueEntityVersionLocale: unique().on(table.entityId, table.version, table.locale),
64
- }))`}function $(e){let t=Object.values(e.allFields).filter(e=>e.type===`blocks`&&!(`localized`in e&&e.localized));return t.length===0||!t.some(e=>e.type===`blocks`?e.blocks.some(e=>Object.values(e.fields).some(e=>e.translatable)):!1)?null:d(`${e.name}_layout_translations`,{id:h(`id`).primaryKey().defaultRandom(),layoutId:h(`layout_id`).notNull(),locale:g(`locale`,{length:10}).notNull(),fields:u(`fields`).notNull()},e=>({uniqueLayoutLocale:m().on(e.layoutId,e.locale)}))}export{D as CountCache,P as ReferencedEntityError,y as auditable,E as behavior,M as buildCursorCondition,j as decodeCursor,N as defineEntity,A as encodeCursor,O as estimateRowCount,_ as field,J as generateContentLocksCode,q as generateDraftsCode,X as generateLayoutCode,H as generateLayoutSchema,Z as generateLayoutTranslationCode,$ as generateLayoutTranslationSchema,G as generateLocaleStatusCode,L as generateSchema,R as generateSchemaCode,z as generateTranslationSchema,B as generateTranslationSchemaCode,Q as generateVersionsCode,V as hasBlocksFields,Y as hasTranslatableBlocks,b as hierarchical,K as isPublishable,U as isVersionable,W as needsLocaleStatus,x as publishable,S as revisionable,w as sluggable,C as slugify,T as timestamped};
1
+ import{and as e,eq as t,gt as n,lt as r,or as i,sql as a}from"drizzle-orm";import{boolean as o,doublePrecision as s,index as c,integer as l,jsonb as u,pgTable as d,text as f,timestamp as p,unique as m,uuid as h,varchar as g}from"drizzle-orm/pg-core";const _={id:e=>({type:`id`,required:!0,indexed:!0,...e}),text:e=>({type:`text`,...e}),number:e=>({type:`number`,...e}),boolean:e=>({type:`boolean`,default:!1,...e}),date:e=>({type:`date`,...e}),select:e=>({type:`select`,...e}),reference:e=>({type:`reference`,cardinality:`one`,onDelete:`set-null`,...e}),media:e=>({type:`media`,...e}),richtext:e=>({type:`richtext`,...e}),slug:e=>({type:`slug`,unique:!0,indexed:!0,...e}),json:e=>({type:`json`,...e}),blocks:e=>({type:`blocks`,...e})};async function v(){try{return(await import([`@murumets-ee`,`core`].join(`/`))).getCurrentUser()?.id}catch{return}}function y(){return{name:`auditable`,fields:{createdBy:_.text(),updatedBy:_.text(),createdAt:_.date({indexed:!0}),updatedAt:_.date({indexed:!0})},hooks:{beforeCreate:async e=>{e.createdAt=new Date,e.updatedAt=new Date;let t=await v();return t&&(e.createdBy=t,e.updatedBy=t),e},beforeUpdate:async(e,t)=>{t.updatedAt=new Date;let n=await v();return n&&(t.updatedBy=n),t}}}}function b(e){return{name:`hierarchical`,fields:{parentId:_.reference({entity:`_self`,required:!1}),path:_.text({indexed:!0,maxLength:2048}),depth:_.number({integer:!0,default:0,indexed:!0})},hooks:{beforeCreate:async e=>(e.parentId||(e.depth=0),e)}}}function x(){return{name:`publishable`,fields:{status:_.select({options:[`draft`,`published`],default:`draft`,indexed:!0}),publishedAt:_.date({indexed:!0})},hooks:{beforeUpdate:async(e,t)=>(t.status===`published`&&!t.publishedAt&&(t.publishedAt=new Date),t)}}}function S(){return{name:`revisionable`,fields:{_version:_.number({required:!0,default:1,integer:!0})},hooks:{beforeCreate:async e=>(e._version=1,e),beforeUpdate:async(e,t)=>(t._version=(Number(t._version)||0)+1,t)}}}function C(e){return e.toLowerCase().trim().replace(/[^\w\s-]/g,``).replace(/[\s_-]+/g,`-`).replace(/^-+|-+$/g,``)}function w(e,t){return{name:`sluggable`,fields:{slug:_.slug({from:e,...t?.translatable?{translatable:!0}:{}})},hooks:{beforeCreate:async t=>(!t.slug&&t[e]&&(t.slug=C(String(t[e]))),t),beforeUpdate:async(t,n)=>(n[e]&&!n.slug&&(n.slug=C(String(n[e]))),n)}}}function T(){return{name:`timestamped`,fields:{createdAt:_.date({indexed:!0}),updatedAt:_.date({indexed:!0})},hooks:{beforeCreate:async e=>(e.createdAt=new Date,e.updatedAt=new Date,e),beforeUpdate:async(e,t)=>(t.updatedAt=new Date,t)}}}const E={publishable:x,auditable:y,sluggable:w,revisionable:S,hierarchical:b,timestamped:T};var D=class{cache=new Map;ttlMs;constructor(e=5e3){this.ttlMs=e}get(e){let t=this.cache.get(e);if(!t||Date.now()>t.expiresAt){t&&this.cache.delete(e);return}return t.count}set(e,t){this.cache.set(e,{count:t,expiresAt:Date.now()+this.ttlMs})}invalidate(e){for(let t of this.cache.keys())t.startsWith(e)&&this.cache.delete(t)}prune(){let e=Date.now();for(let[t,n]of this.cache.entries())e>n.expiresAt&&this.cache.delete(t)}clear(){this.cache.clear()}get size(){return this.cache.size}};async function O(e,t){let n=await e.execute(a`SELECT reltuples::bigint AS estimate FROM pg_class WHERE relname = ${t}`),r=(Array.isArray(n)?n:n.rows??[])[0],i=Number(r?.estimate??0);return i>0?i:0}const k=/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;function A(e,t,n){let r={field:t,value:e[t],direction:n,id:e.id};return btoa(JSON.stringify(r))}function j(e){try{let t=atob(e),n=JSON.parse(t);if(typeof n!=`object`||!n)return null;let r=n;return typeof r.field!=`string`||!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(r.field)||typeof r.value!=`string`&&typeof r.value!=`number`||r.direction!==`asc`&&r.direction!==`desc`||r.id!==void 0&&(typeof r.id!=`string`||!k.test(r.id))?null:{field:r.field,value:r.value,direction:r.direction,id:r.id}}catch{return null}}function M(a,o){let s=a[o.field];if(!s)return null;let c=o.direction===`desc`?r:n,l=c(s,o.value);if(!o.id)return l;let u=a.id;if(!u)return l;let d=c(u,o.id);return i(l,e(t(s,o.value),d))}function N(e){let t={},n={};for(let r of e.behaviors||[]){if(r.fields)for(let[e,n]of Object.entries(r.fields)){if(t[e]){console.warn(`Field '${e}' from behavior '${r.name}' conflicts with existing field. Skipping.`);continue}t[e]=n}if(r.hooks)for(let[e,t]of Object.entries(r.hooks)){let r=e;if(t){let e=n[r];if(e){let i=e,a=t;n[r]=async(...e)=>{let t=await i(...e);if(t!==void 0){let n=[...e];return n[n.length-1]=t,await a(...n)}return await a(...e)}}else n[r]=t}}}let r={id:_.id(),...t,...e.fields};for(let[,e]of Object.entries(r))e.type===`slug`&&!e.translatable&&r[e.from]?.translatable&&(e.translatable=!0);return{...e,allFields:r,hooks:n}}var P=class extends Error{entityName;entityId;usages;constructor(e,t,n){let r=n.length;super(`Cannot delete ${e} '${t}': referenced by ${r} other entit${r===1?`y`:`ies`}`),this.name=`ReferencedEntityError`,this.entityName=e,this.entityId=t,this.usages=n}};function F(e,t,n){let r=n?.nullable??!1;switch(t.type){case`id`:return h(e).primaryKey().defaultRandom();case`text`:if(t.maxLength&&t.maxLength<=255){let n=g(e,{length:t.maxLength});return t.unique&&(n=n.unique()),!r&&t.required&&(n=n.notNull()),!r&&t.default!==void 0&&(n=n.default(t.default)),n}else{let n=f(e);return t.unique&&(n=n.unique()),!r&&t.required&&(n=n.notNull()),!r&&t.default!==void 0&&(n=n.default(t.default)),n}case`number`:{let n=t.integer?l(e):s(e);return!r&&t.required&&(n=n.notNull()),!r&&t.default!==void 0&&(n=n.default(t.default)),n}case`boolean`:{let n=o(e);if(!r&&t.required&&(n=n.notNull()),!r){let e=t.default===void 0?!1:t.default;n=n.default(e)}return n}case`date`:{let n=p(e,{withTimezone:!0});return!r&&t.required&&(n=n.notNull()),!r&&t.default!==void 0&&(n=n.default(t.default)),n}case`select`:{let n=g(e,{length:100});return!r&&t.required&&(n=n.notNull()),!r&&t.default!==void 0&&(n=n.default(t.default)),n}case`reference`:{if(t.cardinality===`many`)return h(e).array();let n=h(e);return!r&&t.required&&(n=n.notNull()),n}case`media`:{let n=h(e);return!r&&t.required&&(n=n.notNull()),n}case`slug`:{let n=g(e,{length:255});return t.unique&&!r&&(n=n.unique()),!r&&t.required&&(n=n.notNull()),n}case`richtext`:{let n=f(e);return!r&&t.required&&(n=n.notNull()),n}case`json`:return u(e);default:return f(e)}}function I(e){let t=e.name,n={};for(let[t,r]of Object.entries(e.allFields))r.type!==`blocks`&&(n[t]=F(t,r));(e.scope===`team`||e.scope===`user`)&&(n._scopeId=h(`_scope_id`));let r=Object.entries(e.allFields).filter(([e,t])=>t.type!==`blocks`&&t.type!==`id`&&t.indexed&&!t.unique),i=e.behaviors?.some(e=>e.name===`publishable`)??!1;return r.length===0&&!i?d(t,n):d(t,n,e=>{let n={};for(let[i]of r)n[`idx_${t}_${i}`]=c(`idx_${t}_${i}`).on(e[i]);return i&&e.status&&e.createdAt&&(n[`idx_${t}_status_created`]=c(`idx_${t}_status_created`).on(e.status,e.createdAt)),n})}function L(e,t){let n=Object.entries(e.allFields).filter(([e,t])=>t.translatable);if(n.length===0)return null;let r=`${e.name}_translations`,i=t?h(`entity_id`).notNull().references(()=>t.id,{onDelete:`cascade`}):h(`entity_id`).notNull(),a={id:h(`id`).primaryKey().defaultRandom(),entityId:i,locale:g(`locale`,{length:10}).notNull()},o=n.some(([e,t])=>t.type===`slug`);for(let[e,t]of n)a[e]=F(e,t,{nullable:!0});return d(r,a,e=>({uniqueEntityLocale:m().on(e.entityId,e.locale),...o&&e.slug?{uniqueSlugLocale:m().on(e.slug,e.locale)}:{}}))}function R(e){return Object.values(e.allFields).some(e=>e.type===`blocks`)}function z(e,t){if(!R(e))return null;let n=`${e.name}_layout`,r=t?h(`entity_id`).notNull().references(()=>t.id,{onDelete:`cascade`}):h(`entity_id`).notNull();return d(n,{id:h(`id`).primaryKey().defaultRandom(),entityId:r,fieldName:g(`field_name`,{length:100}).notNull(),blockType:g(`block_type`,{length:100}).notNull(),sortOrder:l(`sort_order`).notNull().default(0),data:u(`data`),locale:g(`locale`,{length:10})},e=>({idx_entity_locale_sort:c(`idx_${n}_entity_locale_sort`).on(e.entityId,e.locale,e.sortOrder)}))}function B(e){return e.behaviors?.some(e=>e.name===`versionable`)??!1}function V(e){if(!(e.behaviors?.some(e=>e.name===`publishable`)??!1))return!1;let t=e.allFields;return Object.values(t).some(e=>e.translatable)}function H(e){return e.behaviors?.some(e=>e.name===`publishable`)??!1}function U(e,t){return d(`${e.name}_locale_status`,{id:h(`id`).primaryKey().defaultRandom(),entityId:h(`entity_id`).notNull().references(()=>t.id,{onDelete:`cascade`}),locale:g(`locale`,{length:10}).notNull(),status:g(`status`,{length:20}).notNull().default(`draft`),publishedAt:p(`published_at`,{withTimezone:!0})},e=>({uniqueEntityLocale:m().on(e.entityId,e.locale)}))}function W(e,t){return d(`${e.name}_drafts`,{id:h(`id`).primaryKey().defaultRandom(),entityId:h(`entity_id`).notNull().references(()=>t.id,{onDelete:`cascade`}),locale:g(`locale`,{length:10}).notNull().default(`_`),data:u(`data`).notNull(),createdBy:g(`created_by`,{length:255}).notNull(),createdByName:g(`created_by_name`,{length:255}),createdAt:p(`created_at`,{withTimezone:!0}).notNull().defaultNow(),updatedAt:p(`updated_at`,{withTimezone:!0}).notNull().defaultNow()},e=>({uniqueEntityLocale:m().on(e.entityId,e.locale)}))}function G(e,t){return d(`${e.name}_versions`,{id:h(`id`).primaryKey().defaultRandom(),entityId:h(`entity_id`).notNull().references(()=>t.id,{onDelete:`cascade`}),version:l(`version`).notNull(),locale:g(`locale`,{length:10}).notNull().default(`_`),data:u(`data`).notNull(),delta:u(`delta`),status:g(`status`,{length:20}),createdBy:g(`created_by`,{length:255}),createdByName:g(`created_by_name`,{length:255}),createdAt:p(`created_at`,{withTimezone:!0}).notNull().defaultNow(),isAutosave:o(`is_autosave`).notNull().default(!1)},e=>({uniqueEntityVersionLocale:m().on(e.entityId,e.version,e.locale)}))}function K(){return d(`toolkit_content_locks`,{id:h(`id`).primaryKey().defaultRandom(),entityType:g(`entity_type`,{length:100}).notNull(),entityId:g(`entity_id`,{length:255}).notNull(),locale:g(`locale`,{length:10}).notNull().default(`_`),lockedBy:g(`locked_by`,{length:255}).notNull(),lockedByName:g(`locked_by_name`,{length:255}),lockedAt:p(`locked_at`,{withTimezone:!0}).notNull().defaultNow(),expiresAt:p(`expires_at`,{withTimezone:!0}).notNull()},e=>({uniqueEntityLock:m().on(e.entityType,e.entityId,e.locale)}))}function q(e){let t=e.allFields;return Object.values(t).some(e=>e.type!==`blocks`||e.localized?!1:e.blocks?.some(e=>Object.values(e.fields).some(e=>e.translatable)))}function J(e,t){let n=Object.values(e.allFields).filter(e=>e.type===`blocks`&&!(`localized`in e&&e.localized));if(n.length===0||!n.some(e=>e.type===`blocks`?e.blocks.some(e=>Object.values(e.fields).some(e=>e.translatable)):!1))return null;let r=`${e.name}_layout_translations`,i=t?h(`layout_id`).notNull().references(()=>t.id,{onDelete:`cascade`}):h(`layout_id`).notNull();return d(r,{id:h(`id`).primaryKey().defaultRandom(),layoutId:i,locale:g(`locale`,{length:10}).notNull(),fields:u(`fields`).notNull()},e=>({uniqueLayoutLocale:m().on(e.layoutId,e.locale)}))}function Y(e){let t={},n=!1;for(let r of e){let e=I(r);t[r.name]=e;let i=L(r,e);if(i&&(t[`${r.name}_translations`]=i),R(r)){let n=z(r,e);if(n){t[`${r.name}_layout`]=n;let e=J(r,n);e&&(t[`${r.name}_layout_translations`]=e)}}B(r)&&(t[`${r.name}_versions`]=G(r,e)),V(r)&&(t[`${r.name}_locale_status`]=U(r,e)),H(r)&&(t[`${r.name}_drafts`]=W(r,e),n=!0)}return n&&(t.toolkit_content_locks=K()),t}export{D as CountCache,P as ReferencedEntityError,y as auditable,E as behavior,M as buildCursorCondition,Y as buildEntitySchemaMap,j as decodeCursor,N as defineEntity,A as encodeCursor,O as estimateRowCount,_ as field,K as generateContentLocksSchema,W as generateDraftsSchema,z as generateLayoutSchema,J as generateLayoutTranslationSchema,U as generateLocaleStatusSchema,I as generateSchema,L as generateTranslationSchema,G as generateVersionsSchema,R as hasBlocksFields,q as hasTranslatableBlocks,b as hierarchical,H as isPublishable,B as isVersionable,V as needsLocaleStatus,x as publishable,S as revisionable,w as sluggable,C as slugify,T as timestamped};
65
2
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../src/fields/builders.ts","../src/behaviors/auditable.ts","../src/behaviors/hierarchical.ts","../src/behaviors/publishable.ts","../src/behaviors/revisionable.ts","../src/behaviors/sluggable.ts","../src/behaviors/timestamped.ts","../src/behaviors/index.ts","../src/count-cache.ts","../src/count-estimate.ts","../src/cursor.ts","../src/define-entity.ts","../src/refs/errors.ts","../src/schema-generator.ts"],"sourcesContent":["/**\n * Fluent API for building field definitions\n * Provides type-safe field builders with sensible defaults.\n *\n * Each builder uses a `const` generic parameter on the config to preserve\n * literal types (e.g., `required: true` stays `true`, not `boolean`).\n * This enables compile-time type inference in the entity system.\n */\n\nimport type {\n BlockDefinitionRef,\n BlocksField,\n BooleanField,\n DateField,\n IdField,\n JsonField,\n MediaField,\n NumberField,\n ReferenceField,\n RichTextField,\n SelectField,\n SlugField,\n TextField,\n} from './base.js'\n\nexport const field = {\n /**\n * ID field (auto-added to every entity)\n */\n // biome-ignore lint/complexity/noBannedTypes: {} is correct as empty generic default\n id: <const C extends Partial<IdField> = {}>(config?: C): IdField & C =>\n ({\n type: 'id',\n required: true,\n indexed: true,\n ...config,\n }) as IdField & C,\n\n /**\n * Text field\n */\n // biome-ignore lint/complexity/noBannedTypes: {} is correct as empty generic default\n text: <const C extends Partial<TextField> = {}>(config?: C): TextField & C =>\n ({\n type: 'text',\n ...config,\n }) as TextField & C,\n\n /**\n * Number field\n */\n // biome-ignore lint/complexity/noBannedTypes: {} is correct as empty generic default\n number: <const C extends Partial<NumberField> = {}>(config?: C): NumberField & C =>\n ({\n type: 'number',\n ...config,\n }) as NumberField & C,\n\n /**\n * Boolean field\n */\n // biome-ignore lint/complexity/noBannedTypes: {} is correct as empty generic default\n boolean: <const C extends Partial<BooleanField> = {}>(config?: C): BooleanField & C =>\n ({\n type: 'boolean',\n default: false,\n ...config,\n }) as BooleanField & C,\n\n /**\n * Date field\n */\n // biome-ignore lint/complexity/noBannedTypes: {} is correct as empty generic default\n date: <const C extends Partial<DateField> = {}>(config?: C): DateField & C =>\n ({\n type: 'date',\n ...config,\n }) as DateField & C,\n\n /**\n * Select field (enum)\n * Preserves literal option types for type inference.\n * e.g. field.select({ options: ['news', 'tutorial'] }) infers 'news' | 'tutorial'\n */\n select: <\n const O extends readonly string[],\n // biome-ignore lint/complexity/noBannedTypes: {} is correct as empty generic default\n const C extends Omit<Partial<SelectField>, 'options'> = {},\n >(\n config: { options: O } & C,\n ): SelectField & { options: O } & C =>\n ({\n type: 'select',\n ...config,\n }) as SelectField & { options: O } & C,\n\n /**\n * Reference field (foreign key to another entity)\n * Preserves literal cardinality to distinguish string vs string[] in inferred types.\n */\n reference: <\n C extends 'one' | 'many' = 'one',\n // biome-ignore lint/complexity/noBannedTypes: {} is correct as empty generic default\n const R extends Partial<Omit<ReferenceField, 'entity' | 'cardinality'>> = {},\n >(\n config: { entity: string; cardinality?: C } & R,\n ): ReferenceField & { cardinality: C } & R =>\n ({\n type: 'reference',\n cardinality: 'one' as C,\n onDelete: 'set-null',\n ...config,\n }) as ReferenceField & { cardinality: C } & R,\n\n /**\n * Media field (file upload)\n */\n // biome-ignore lint/complexity/noBannedTypes: {} is correct as empty generic default\n media: <const C extends Partial<MediaField> = {}>(config?: C): MediaField & C =>\n ({\n type: 'media',\n ...config,\n }) as MediaField & C,\n\n /**\n * Rich text field (WYSIWYG editor)\n */\n // biome-ignore lint/complexity/noBannedTypes: {} is correct as empty generic default\n richtext: <const C extends Partial<RichTextField> = {}>(config?: C): RichTextField & C =>\n ({\n type: 'richtext',\n ...config,\n }) as RichTextField & C,\n\n /**\n * Slug field (URL-safe string, auto-generated from source field)\n */\n // biome-ignore lint/complexity/noBannedTypes: {} is correct as empty generic default\n slug: <const C extends Partial<SlugField> = {}>(\n config: Pick<SlugField, 'from'> & C,\n ): SlugField & C =>\n ({\n type: 'slug',\n unique: true,\n indexed: true,\n ...config,\n }) as SlugField & C,\n\n /**\n * JSON field (arbitrary JSON data, stored as JSONB)\n */\n // biome-ignore lint/complexity/noBannedTypes: {} is correct as empty generic default\n json: <const C extends Partial<JsonField> = {}>(config?: C): JsonField & C =>\n ({\n type: 'json',\n ...config,\n }) as JsonField & C,\n\n /**\n * Blocks field — ordered array of typed content blocks\n * Preserves literal block tuple type for discriminated union inference.\n */\n blocks: <const B extends readonly BlockDefinitionRef[]>(config: {\n blocks: B\n min?: number\n max?: number\n localized?: boolean\n }): BlocksField & { blocks: B } =>\n ({\n type: 'blocks' as const,\n ...config,\n }) as BlocksField & { blocks: B },\n}\n","/**\n * Auditable behavior\n * Adds createdBy, updatedBy, createdAt, updatedAt fields + auto-set logic.\n *\n * When @murumets-ee/core is available (i.e. running inside createApp), the hooks\n * automatically populate createdBy/updatedBy from the RequestContext.\n */\n\nimport { field } from '../fields/builders.js'\nimport type { AuditableFields } from '../types/infer.js'\nimport type { Behavior } from './types.js'\n\n/**\n * Try to get the current user ID from @murumets-ee/core's RequestContext.\n * Returns undefined if @murumets-ee/core isn't loaded or no user is in context.\n *\n * Uses a dynamic import string indirection to avoid TypeScript resolving\n * @murumets-ee/core at compile time (which would create a circular dep: entity → core → entity).\n */\nasync function getCurrentUserId(): Promise<string | undefined> {\n try {\n // Module name built at runtime so TypeScript doesn't try to resolve it during DTS emit\n const moduleName = ['@murumets-ee', 'core'].join('/')\n const core = await (import(moduleName) as Promise<{\n getCurrentUser: () => { id: string } | undefined\n }>)\n return core.getCurrentUser()?.id\n } catch {\n return undefined\n }\n}\n\nexport function auditable(): Behavior<AuditableFields> {\n return {\n name: 'auditable',\n fields: {\n createdBy: field.text(),\n updatedBy: field.text(),\n createdAt: field.date({ indexed: true }),\n updatedAt: field.date({ indexed: true }),\n },\n hooks: {\n beforeCreate: async (data) => {\n data.createdAt = new Date()\n data.updatedAt = new Date()\n const userId = await getCurrentUserId()\n if (userId) {\n data.createdBy = userId\n data.updatedBy = userId\n }\n return data\n },\n beforeUpdate: async (_id, data) => {\n data.updatedAt = new Date()\n const userId = await getCurrentUserId()\n if (userId) {\n data.updatedBy = userId\n }\n return data\n },\n },\n }\n}\n","/**\n * Hierarchical behavior\n * Adds parentId, path, depth fields for materialized path tree structures.\n *\n * Path format: /uuid1/uuid2/uuid3\n * - Root items: /{ownId}\n * - Children: /{rootId}/.../{parentId}/{ownId}\n *\n * The behavior declares fields and sets safe defaults in hooks.\n * Heavy lifting (path computation, circular ref validation, descendant cascading)\n * is done by TaxonomyClient which has DB access.\n */\n\nimport { field } from '../fields/builders.js'\nimport type { HierarchicalFields } from '../types/infer.js'\nimport type { Behavior } from './types.js'\n\nexport interface HierarchicalOptions {\n /**\n * What happens when deleting a node that has children.\n * - 'restrict': Prevent deletion (default)\n * - 'cascade': Delete all descendants\n * - 'reparent': Move children to the deleted node's parent\n */\n onDelete?: 'restrict' | 'cascade' | 'reparent'\n}\n\nexport function hierarchical(_options?: HierarchicalOptions): Behavior<HierarchicalFields> {\n return {\n name: 'hierarchical',\n fields: {\n parentId: field.reference({ entity: '_self', required: false }),\n path: field.text({ indexed: true, maxLength: 2048 }),\n depth: field.number({ integer: true, default: 0, indexed: true }),\n },\n hooks: {\n beforeCreate: async (data) => {\n // Set defaults for root-level items.\n // TaxonomyClient overrides these after insert when it has the ID.\n if (!data.parentId) {\n data.depth = 0\n }\n return data\n },\n },\n }\n}\n","/**\n * Publishable behavior\n * Adds status (draft/published) and publishedAt fields + auto-set logic\n */\n\nimport { field } from '../fields/builders.js'\nimport type { PublishableFields } from '../types/infer.js'\nimport type { Behavior } from './types.js'\n\nexport function publishable(): Behavior<PublishableFields> {\n return {\n name: 'publishable',\n fields: {\n status: field.select({\n options: ['draft', 'published'] as const,\n default: 'draft',\n indexed: true,\n }),\n publishedAt: field.date({ indexed: true }),\n },\n hooks: {\n beforeUpdate: async (_id, data) => {\n // Auto-set publishedAt when status changes to published (if not already set)\n if (data.status === 'published' && !data.publishedAt) {\n data.publishedAt = new Date()\n }\n return data\n },\n },\n }\n}\n","/**\n * Revisionable behavior\n * Adds _version field + auto-increment on update\n */\n\nimport { field } from '../fields/builders.js'\nimport type { RevisionableFields } from '../types/infer.js'\nimport type { Behavior } from './types.js'\n\nexport function revisionable(): Behavior<RevisionableFields> {\n return {\n name: 'revisionable',\n fields: {\n _version: field.number({ required: true, default: 1, integer: true }),\n },\n hooks: {\n beforeCreate: async (data) => {\n data._version = 1\n return data\n },\n beforeUpdate: async (_id, data) => {\n // Increment version on every update\n data._version = (Number(data._version) || 0) + 1\n return data\n },\n },\n }\n}\n","/**\n * Sluggable behavior\n * Adds slug field + auto-generation from source field\n */\n\nimport { field } from '../fields/builders.js'\nimport type { SluggableFields } from '../types/infer.js'\nimport type { Behavior } from './types.js'\n\nexport interface SluggableOptions {\n /** Make the slug translatable — each locale gets its own slug. Default: false */\n translatable?: boolean\n}\n\n/**\n * Convert text to URL-safe slug\n */\nexport function slugify(text: string): string {\n return text\n .toLowerCase()\n .trim()\n .replace(/[^\\w\\s-]/g, '') // Remove non-word chars except spaces and hyphens\n .replace(/[\\s_-]+/g, '-') // Replace spaces, underscores with single hyphen\n .replace(/^-+|-+$/g, '') // Remove leading/trailing hyphens\n}\n\nexport function sluggable(\n sourceField: string,\n options?: SluggableOptions,\n): Behavior<SluggableFields> {\n return {\n name: 'sluggable',\n fields: {\n slug: field.slug({\n from: sourceField,\n ...(options?.translatable ? { translatable: true } : {}),\n }),\n },\n hooks: {\n beforeCreate: async (data) => {\n // Auto-generate slug from source field if not provided\n if (!data.slug && data[sourceField]) {\n data.slug = slugify(String(data[sourceField]))\n }\n return data\n },\n beforeUpdate: async (_id, data) => {\n // Re-generate slug if source field changed and slug not manually set\n if (data[sourceField] && !data.slug) {\n data.slug = slugify(String(data[sourceField]))\n }\n return data\n },\n },\n }\n}\n","/**\n * Timestamped behavior\n * Adds createdAt and updatedAt fields with auto-set logic.\n * Lighter alternative to auditable() when you don't need createdBy/updatedBy tracking.\n */\n\nimport { field } from '../fields/builders.js'\nimport type { Behavior } from './types.js'\n\nexport type TimestampedFields = {\n createdAt: ReturnType<typeof field.date>\n updatedAt: ReturnType<typeof field.date>\n}\n\nexport function timestamped(): Behavior<TimestampedFields> {\n return {\n name: 'timestamped',\n fields: {\n createdAt: field.date({ indexed: true }),\n updatedAt: field.date({ indexed: true }),\n },\n hooks: {\n beforeCreate: async (data) => {\n data.createdAt = new Date()\n data.updatedAt = new Date()\n return data\n },\n beforeUpdate: async (_id, data) => {\n data.updatedAt = new Date()\n return data\n },\n },\n }\n}\n","/**\n * Behavior exports\n * All behaviors are exported under the `behavior` namespace\n */\n\nimport { auditable } from './auditable.js'\nimport { hierarchical } from './hierarchical.js'\nimport { publishable } from './publishable.js'\nimport { revisionable } from './revisionable.js'\nimport { sluggable } from './sluggable.js'\nimport { timestamped } from './timestamped.js'\n\nexport { publishable, auditable, sluggable, revisionable, hierarchical, timestamped }\nexport type { SluggableOptions } from './sluggable.js'\nexport { slugify } from './sluggable.js'\nexport type { Behavior, BehaviorFactory } from './types.js'\n\n/**\n * Behavior namespace for fluent API\n */\nexport const behavior = {\n publishable,\n auditable,\n sluggable,\n revisionable,\n hierarchical,\n timestamped,\n}\n","/**\n * In-memory TTL cache for COUNT(*) query results.\n *\n * Reduces database load on paginated list pages where the total count\n * is recalculated on every pagination/sort/search interaction. The cache\n * is per-process (not shared across workers) with a short TTL (default 5s)\n * so counts are at most a few seconds stale.\n *\n * Cache keys include the entity name + serialized WHERE clause, so filtered\n * and unfiltered counts are cached independently.\n */\n\n/**\n * Interface for count cache implementations.\n * Used in client configs to avoid TypeScript private-field structural incompatibility\n * across separate .d.ts files.\n */\nexport interface CountCacheLike {\n get(key: string): number | undefined\n set(key: string, count: number): void\n invalidate(prefix: string): void\n}\n\ninterface CountCacheEntry {\n count: number\n expiresAt: number\n}\n\nexport class CountCache implements CountCacheLike {\n private cache = new Map<string, CountCacheEntry>()\n private ttlMs: number\n\n constructor(ttlMs = 5000) {\n this.ttlMs = ttlMs\n }\n\n /**\n * Get a cached count. Returns undefined on miss or expired entry.\n */\n get(key: string): number | undefined {\n const entry = this.cache.get(key)\n if (!entry || Date.now() > entry.expiresAt) {\n if (entry) this.cache.delete(key)\n return undefined\n }\n return entry.count\n }\n\n /**\n * Cache a count result with the configured TTL.\n */\n set(key: string, count: number): void {\n this.cache.set(key, { count, expiresAt: Date.now() + this.ttlMs })\n }\n\n /**\n * Invalidate all cache entries whose key starts with the given prefix.\n * Typically called with the entity name after mutations (create/update/delete).\n */\n invalidate(prefix: string): void {\n for (const key of this.cache.keys()) {\n if (key.startsWith(prefix)) {\n this.cache.delete(key)\n }\n }\n }\n\n /**\n * Remove all expired entries. Useful for periodic cleanup in long-running processes.\n */\n prune(): void {\n const now = Date.now()\n for (const [key, entry] of this.cache.entries()) {\n if (now > entry.expiresAt) {\n this.cache.delete(key)\n }\n }\n }\n\n /**\n * Clear the entire cache.\n */\n clear(): void {\n this.cache.clear()\n }\n\n /**\n * Number of entries currently in the cache (including expired ones not yet pruned).\n */\n get size(): number {\n return this.cache.size\n }\n}\n","/**\n * Postgres row count estimation using pg_class statistics.\n *\n * For unfiltered counts on large tables, querying `pg_class.reltuples`\n * is effectively instant (no table scan) and returns a good approximation\n * that is updated by VACUUM and ANALYZE. This is suitable for pagination\n * totals where exact precision is not critical.\n *\n * SECURITY: The table name is NOT interpolated into SQL — it is passed as a\n * parameterized value to the `relname = $1` comparison. This prevents SQL injection.\n */\n\nimport { sql } from 'drizzle-orm'\nimport type { PostgresJsDatabase } from 'drizzle-orm/postgres-js'\n\n/**\n * Estimate the total row count for a table using Postgres statistics.\n *\n * Returns the approximate row count from `pg_class.reltuples`, which is\n * updated by VACUUM/ANALYZE. Returns 0 if the table is not found or\n * statistics are not yet available (e.g., freshly created table).\n *\n * @param db - Drizzle Postgres database instance\n * @param tableName - The Postgres table name (without schema prefix)\n * @returns Estimated row count (non-negative integer)\n */\nexport async function estimateRowCount(db: PostgresJsDatabase, tableName: string): Promise<number> {\n const result = await db.execute(\n sql`SELECT reltuples::bigint AS estimate FROM pg_class WHERE relname = ${tableName}`,\n )\n\n const rows = Array.isArray(result) ? result : ((result as { rows?: unknown[] }).rows ?? [])\n const row = rows[0] as { estimate?: string | number } | undefined\n const estimate = Number(row?.estimate ?? 0)\n\n // reltuples can be -1 for tables that have never been analyzed\n return estimate > 0 ? estimate : 0\n}\n","/**\n * Cursor-based (keyset) pagination utilities.\n *\n * Cursor pagination avoids the performance cliff of OFFSET at scale (1M+ rows).\n * Instead of `OFFSET N`, it uses a WHERE condition:\n * `WHERE (sortField < lastValue) OR (sortField = lastValue AND id < lastId)`\n * which Postgres can serve from an index in constant time.\n *\n * The cursor is opaque to the client — base64-encoded JSON.\n *\n * Security:\n * - `field` must be whitelisted against the entity's actual fields\n * - `id` must be a valid UUID\n * - `value` is parameterized (never interpolated into SQL)\n * - Malformed cursors return null (caller returns 400)\n */\n\nimport { and, eq, gt, lt, or, type SQL } from 'drizzle-orm'\nimport type { PgTableWithColumns } from 'drizzle-orm/pg-core'\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/** Cursor input for keyset pagination. */\nexport interface CursorInput {\n /** Sort field name (e.g. 'createdAt'). Must be a real column on the entity. */\n field: string\n /** Last seen value of the sort field. */\n value: string | number\n /** Sort direction — must match the ORDER BY direction. */\n direction: 'asc' | 'desc'\n /** Tie-breaker: last seen entity ID. Required for non-unique sort fields. */\n id?: string\n}\n\n/** Decoded cursor (internal, after validation). */\ninterface DecodedCursor {\n field: string\n value: string | number\n direction: 'asc' | 'desc'\n id?: string\n}\n\n// ---------------------------------------------------------------------------\n// UUID validation (same format used throughout the toolkit)\n// ---------------------------------------------------------------------------\n\nconst UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i\n\n// ---------------------------------------------------------------------------\n// Encode / decode\n// ---------------------------------------------------------------------------\n\n/**\n * Encode a cursor for API transport (base64url).\n * Built from the last item in a result set.\n */\nexport function encodeCursor(\n item: Record<string, unknown>,\n sortField: string,\n direction: 'asc' | 'desc',\n): string {\n const payload: CursorInput = {\n field: sortField,\n value: item[sortField] as string | number,\n direction,\n id: item.id as string | undefined,\n }\n return btoa(JSON.stringify(payload))\n}\n\n/**\n * Decode and validate a cursor string from query params.\n * Returns null if the cursor is malformed, tampered, or invalid.\n *\n * Security: the `field` value is NOT validated here — the caller must\n * whitelist it against the entity's actual columns.\n */\nexport function decodeCursor(encoded: string): DecodedCursor | null {\n try {\n const json = atob(encoded)\n const parsed: unknown = JSON.parse(json)\n\n if (typeof parsed !== 'object' || parsed === null) return null\n const obj = parsed as Record<string, unknown>\n\n // Validate field\n if (typeof obj.field !== 'string' || !/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(obj.field)) {\n return null\n }\n\n // Validate value (string or number)\n if (typeof obj.value !== 'string' && typeof obj.value !== 'number') {\n return null\n }\n\n // Validate direction\n if (obj.direction !== 'asc' && obj.direction !== 'desc') {\n return null\n }\n\n // Validate id (optional, must be UUID if present)\n if (obj.id !== undefined) {\n if (typeof obj.id !== 'string' || !UUID_RE.test(obj.id)) {\n return null\n }\n }\n\n return {\n field: obj.field,\n value: obj.value,\n direction: obj.direction,\n id: obj.id as string | undefined,\n }\n } catch {\n return null\n }\n}\n\n// ---------------------------------------------------------------------------\n// SQL condition builder\n// ---------------------------------------------------------------------------\n\n/**\n * Build the keyset WHERE condition from a decoded cursor.\n *\n * For DESC: `WHERE (field < value) OR (field = value AND id < cursorId)`\n * For ASC: `WHERE (field > value) OR (field = value AND id > cursorId)`\n *\n * The caller must verify that `cursor.field` exists on the table before calling.\n *\n * @param table - Drizzle table with columns\n * @param cursor - Decoded and validated cursor\n * @returns SQL condition, or null if the field doesn't exist on the table\n */\nexport function buildCursorCondition(\n // biome-ignore lint/suspicious/noExplicitAny: dynamic table columns require PgTableWithColumns<any> for property access\n table: PgTableWithColumns<any>,\n cursor: DecodedCursor,\n): SQL | null {\n const column = table[cursor.field]\n if (!column) return null\n\n const isDesc = cursor.direction === 'desc'\n const compare = isDesc ? lt : gt\n\n // Primary condition: sort field passes the cursor value\n const fieldCondition = compare(column, cursor.value)\n\n // Without tie-breaker ID, use simple comparison\n if (!cursor.id) {\n return fieldCondition\n }\n\n // With tie-breaker: (field < value) OR (field = value AND id < cursorId)\n const idColumn = table.id\n if (!idColumn) return fieldCondition\n\n const idCondition = compare(idColumn, cursor.id)\n return or(fieldCondition, and(eq(column, cursor.value), idCondition))!\n}\n","/**\n * Entity definition API\n * The core function for defining entities with full type inference.\n *\n * The generic parameters are inferred from the call site:\n * - F is inferred from `definition.fields`\n * - B is inferred from `definition.behaviors` (as a tuple)\n *\n * The returned Entity carries the complete field map:\n * { id: IdField } & BehaviorFields & UserFields\n */\n\nimport type { EntityAdminConfig } from './admin-config.js'\nimport type { Behavior } from './behaviors/types.js'\nimport type { FieldConfig, IdField } from './fields/base.js'\nimport { field } from './fields/builders.js'\n\n/**\n * Entity definition input (without behaviors — behaviors are typed separately\n * on the `defineEntity` function to enable tuple inference).\n *\n * @typeParam F - The literal field map. Inferred automatically from the call site.\n */\nexport interface EntityDefinition<\n F extends Record<string, FieldConfig> = Record<string, FieldConfig>,\n> {\n name: string\n kind?: 'collection' | 'singleton'\n fields: F\n scope?: 'global' | 'team' | 'user'\n access?: {\n view?: string\n create?: string\n update?: string\n delete?: string\n }\n /** Admin UI configuration — controls sidebar, list, and form display */\n admin?: EntityAdminConfig\n}\n\n/**\n * Full input for defineEntity (fields + behaviors + other config).\n * Behaviors are typed as a tuple `B` for type extraction.\n */\nexport type EntityInput<\n F extends Record<string, FieldConfig> = Record<string, FieldConfig>,\n B extends Behavior[] = Behavior[],\n> = EntityDefinition<F> & { behaviors?: B }\n\n/**\n * A fully resolved entity with merged behavior fields.\n * @typeParam AllFields - The complete field map (id + behaviors + user fields).\n */\nexport interface Entity<\n AllFields extends Record<string, FieldConfig> = Record<string, FieldConfig>,\n> {\n name: string\n kind?: 'collection' | 'singleton'\n fields: Record<string, FieldConfig>\n behaviors?: Behavior[]\n scope?: 'global' | 'team' | 'user'\n access?: {\n view?: string\n create?: string\n update?: string\n delete?: string\n }\n /** Admin UI configuration — controls sidebar, list, and form display */\n admin?: EntityAdminConfig\n allFields: AllFields\n hooks: Behavior['hooks']\n}\n\n/**\n * Extract and intersect behavior field types from a behaviors tuple.\n * Walks the tuple recursively (depth bounded by number of behaviors, max ~5).\n */\ntype ExtractBehaviorFields<B extends Behavior[]> = B extends [\n Behavior<infer F1>,\n ...infer Rest extends Behavior[],\n]\n ? F1 & ExtractBehaviorFields<Rest>\n : // biome-ignore lint/complexity/noBannedTypes: empty object is correct for base case of intersection\n {}\n\n/**\n * Define an entity with full type inference.\n *\n * @example\n * const Article = defineEntity({\n * name: 'article',\n * fields: {\n * title: field.text({ required: true }),\n * featured: field.boolean(),\n * },\n * behaviors: [publishable(), auditable()],\n * })\n *\n * type ArticleDTO = InferEntity<typeof Article>\n * // { id: string; title: string; featured?: boolean | null; status?: ...; createdAt?: ...; }\n */\nexport function defineEntity<\n F extends Record<string, FieldConfig>,\n const B extends Behavior[] = [],\n>(\n definition: EntityDefinition<F> & { behaviors?: B },\n): Entity<{ id: IdField } & ExtractBehaviorFields<B> & F> {\n // Merge behavior fields into main fields\n const behaviorFields: Record<string, FieldConfig> = {}\n const hooks: NonNullable<Behavior['hooks']> = {}\n\n for (const behavior of definition.behaviors || []) {\n // Merge fields from behavior\n if (behavior.fields) {\n for (const [fieldName, fieldConfig] of Object.entries(behavior.fields)) {\n if (behaviorFields[fieldName]) {\n console.warn(\n `Field '${fieldName}' from behavior '${behavior.name}' conflicts with existing field. Skipping.`,\n )\n continue\n }\n behaviorFields[fieldName] = fieldConfig\n }\n }\n\n // Merge hooks from behavior\n if (behavior.hooks) {\n for (const [hookName, hookFn] of Object.entries(behavior.hooks)) {\n const typedHookName = hookName as keyof NonNullable<Behavior['hooks']>\n\n if (hookFn) {\n const existingHook = hooks[typedHookName]\n\n if (existingHook) {\n // Chain hooks: execute existing first, then new one\n const previousHook = existingHook as (...args: unknown[]) => Promise<unknown>\n const currentHook = hookFn as (...args: unknown[]) => Promise<unknown>\n\n const chainedHook = async (...args: unknown[]) => {\n const result = await previousHook(...args)\n if (result !== undefined) {\n // Hook returned modified data — replace last arg (the data param),\n // keep leading args (e.g. id) intact for hooks like beforeUpdate(id, data)\n const nextArgs = [...args]\n nextArgs[nextArgs.length - 1] = result\n return await currentHook(...nextArgs)\n }\n return await currentHook(...args)\n }\n // biome-ignore lint/suspicious/noExplicitAny: dynamic dispatch over heterogeneous hook signatures\n hooks[typedHookName] = chainedHook as any\n } else {\n // biome-ignore lint/suspicious/noExplicitAny: dynamic dispatch over heterogeneous hook signatures\n hooks[typedHookName] = hookFn as any\n }\n }\n }\n }\n }\n\n // Build complete field set\n // Order: id (always first) → behavior fields → user-defined fields\n const allFields: Record<string, FieldConfig> = {\n id: field.id(), // Every entity gets an ID\n ...behaviorFields,\n ...definition.fields,\n }\n\n // Auto-infer translatable slugs: if a slug field's source field is translatable,\n // the slug should be translatable too (each locale gets its own URL-safe slug).\n for (const [, fieldConfig] of Object.entries(allFields)) {\n if (\n fieldConfig.type === 'slug' &&\n !fieldConfig.translatable &&\n allFields[fieldConfig.from]?.translatable\n ) {\n fieldConfig.translatable = true\n }\n }\n\n // The cast through `unknown` is safe: runtime merge order (id + behaviors + user fields)\n // exactly mirrors the type-level intersection. TypeScript cannot verify imperative\n // Object.entries() loops produce the same result as a type-level intersection,\n // so we cast at this single auditable boundary.\n return {\n ...definition,\n allFields,\n hooks,\n } as unknown as Entity<{ id: IdField } & ExtractBehaviorFields<B> & F>\n}\n","/**\n * Error thrown when attempting to delete an entity that is still referenced.\n */\n\nimport type { EntityUsage } from './find-usages.js'\n\nexport class ReferencedEntityError extends Error {\n public readonly entityName: string\n public readonly entityId: string\n public readonly usages: EntityUsage[]\n\n constructor(entityName: string, entityId: string, usages: EntityUsage[]) {\n const count = usages.length\n super(\n `Cannot delete ${entityName} '${entityId}': referenced by ${count} other entit${count === 1 ? 'y' : 'ies'}`,\n )\n this.name = 'ReferencedEntityError'\n this.entityName = entityName\n this.entityId = entityId\n this.usages = usages\n }\n}\n","/**\n * Schema generator\n * Converts entity definitions to Drizzle schemas.\n * Every field gets its own Postgres column — no JSONB blobs.\n */\n\nimport type { PgColumnBuilderBase } from 'drizzle-orm/pg-core'\nimport {\n boolean,\n doublePrecision,\n index,\n integer,\n jsonb,\n pgTable,\n text,\n timestamp,\n unique,\n uuid,\n varchar,\n} from 'drizzle-orm/pg-core'\nimport type { Entity } from './define-entity.js'\nimport type { FieldConfig } from './fields/base.js'\n\n/**\n * Convert a field config to a Drizzle column.\n *\n * @param nullable - When true, skips notNull and default constraints.\n * Used for translation table columns (translations are partial overrides).\n */\nexport function fieldToColumn(\n fieldName: string,\n fieldConfig: FieldConfig,\n options?: { nullable?: boolean },\n): PgColumnBuilderBase {\n const nullable = options?.nullable ?? false\n\n switch (fieldConfig.type) {\n case 'id':\n return uuid(fieldName).primaryKey().defaultRandom()\n\n case 'text':\n if (fieldConfig.maxLength && fieldConfig.maxLength <= 255) {\n let column = varchar(fieldName, { length: fieldConfig.maxLength })\n if (fieldConfig.unique) column = column.unique()\n if (!nullable && fieldConfig.required) column = column.notNull()\n if (!nullable && fieldConfig.default !== undefined)\n column = column.default(fieldConfig.default as string)\n return column\n } else {\n let column = text(fieldName)\n if (fieldConfig.unique) column = column.unique()\n if (!nullable && fieldConfig.required) column = column.notNull()\n if (!nullable && fieldConfig.default !== undefined)\n column = column.default(fieldConfig.default as string)\n return column\n }\n\n case 'number': {\n let numColumn = fieldConfig.integer ? integer(fieldName) : doublePrecision(fieldName)\n if (!nullable && fieldConfig.required) numColumn = numColumn.notNull()\n if (!nullable && fieldConfig.default !== undefined)\n numColumn = numColumn.default(fieldConfig.default as number)\n return numColumn\n }\n\n case 'boolean': {\n let boolColumn = boolean(fieldName)\n if (!nullable && fieldConfig.required) boolColumn = boolColumn.notNull()\n if (!nullable) {\n const boolDefault =\n fieldConfig.default !== undefined ? (fieldConfig.default as boolean) : false\n boolColumn = boolColumn.default(boolDefault)\n }\n return boolColumn\n }\n\n case 'date': {\n let dateColumn = timestamp(fieldName, { withTimezone: true })\n if (!nullable && fieldConfig.required) dateColumn = dateColumn.notNull()\n if (!nullable && fieldConfig.default !== undefined)\n dateColumn = dateColumn.default(fieldConfig.default as Date)\n return dateColumn\n }\n\n case 'select': {\n let selectColumn = varchar(fieldName, { length: 100 })\n if (!nullable && fieldConfig.required) selectColumn = selectColumn.notNull()\n if (!nullable && fieldConfig.default !== undefined)\n selectColumn = selectColumn.default(fieldConfig.default as string)\n return selectColumn\n }\n\n case 'reference': {\n if (fieldConfig.cardinality === 'many') {\n return uuid(fieldName).array()\n }\n let refColumn = uuid(fieldName)\n if (!nullable && fieldConfig.required) refColumn = refColumn.notNull()\n return refColumn\n }\n\n case 'media': {\n let mediaColumn = uuid(fieldName)\n if (!nullable && fieldConfig.required) mediaColumn = mediaColumn.notNull()\n return mediaColumn\n }\n\n case 'slug': {\n let slugColumn = varchar(fieldName, { length: 255 })\n // For translation tables (nullable=true), skip per-column unique —\n // translatable slugs use composite UNIQUE(slug, locale) at table level instead.\n if (fieldConfig.unique && !nullable) slugColumn = slugColumn.unique()\n if (!nullable && fieldConfig.required) slugColumn = slugColumn.notNull()\n return slugColumn\n }\n\n case 'richtext': {\n // TipTap HTML strings stored as text\n let rtColumn = text(fieldName)\n if (!nullable && fieldConfig.required) rtColumn = rtColumn.notNull()\n return rtColumn\n }\n\n case 'json':\n return jsonb(fieldName)\n\n default:\n return text(fieldName)\n }\n}\n\n/**\n * Generate TypeScript code string for a single column.\n *\n * @param nullable - When true, skips notNull and default constraints.\n */\nfunction generateColumnCode(\n fieldName: string,\n fieldConfig: FieldConfig,\n options?: { nullable?: boolean },\n): string {\n const nullable = options?.nullable ?? false\n\n switch (fieldConfig.type) {\n case 'id':\n return `id: uuid('id').primaryKey().defaultRandom()`\n\n case 'text': {\n const maxLen = fieldConfig.maxLength\n let textCol =\n maxLen && maxLen <= 255 ? `varchar('${fieldName}', { length: ${maxLen} })` : `text('${fieldName}')`\n if (fieldConfig.unique) textCol += `.unique()`\n if (!nullable && fieldConfig.required) textCol += `.notNull()`\n if (!nullable && fieldConfig.default) textCol += `.default('${fieldConfig.default}')`\n return `${fieldName}: ${textCol}`\n }\n\n case 'number': {\n let numCol = fieldConfig.integer\n ? `integer('${fieldName}')`\n : `doublePrecision('${fieldName}')`\n if (!nullable && fieldConfig.required) numCol += `.notNull()`\n if (!nullable && fieldConfig.default !== undefined)\n numCol += `.default(${fieldConfig.default})`\n return `${fieldName}: ${numCol}`\n }\n\n case 'boolean': {\n if (nullable) {\n return `${fieldName}: boolean('${fieldName}')`\n }\n const boolDefault = fieldConfig.default ?? false\n return `${fieldName}: boolean('${fieldName}').default(${boolDefault})`\n }\n\n case 'date': {\n let dateCol = `timestamp('${fieldName}', { withTimezone: true })`\n if (!nullable && fieldConfig.required) dateCol += `.notNull()`\n return `${fieldName}: ${dateCol}`\n }\n\n case 'reference': {\n if (fieldConfig.cardinality === 'many') {\n return `${fieldName}: uuid('${fieldName}').array()`\n }\n let refCol = `uuid('${fieldName}')`\n if (!nullable && fieldConfig.required) refCol += `.notNull()`\n return `${fieldName}: ${refCol}`\n }\n\n case 'media': {\n let mediaCol = `uuid('${fieldName}')`\n if (!nullable && fieldConfig.required) mediaCol += `.notNull()`\n return `${fieldName}: ${mediaCol}`\n }\n\n case 'slug': {\n let slugCol = `varchar('${fieldName}', { length: 255 })`\n if (fieldConfig.unique && !nullable) slugCol += `.unique()`\n if (!nullable && fieldConfig.required) slugCol += `.notNull()`\n return `${fieldName}: ${slugCol}`\n }\n\n case 'select': {\n let selectCol = `varchar('${fieldName}', { length: 100 })`\n if (!nullable && fieldConfig.required) selectCol += `.notNull()`\n if (!nullable && fieldConfig.default) selectCol += `.default('${fieldConfig.default}')`\n return `${fieldName}: ${selectCol}`\n }\n\n case 'richtext': {\n let rtCol = `text('${fieldName}')`\n if (!nullable && fieldConfig.required) rtCol += `.notNull()`\n return `${fieldName}: ${rtCol}`\n }\n\n case 'json':\n return `${fieldName}: jsonb('${fieldName}')`\n\n default:\n return `${fieldName}: text('${fieldName}')`\n }\n}\n\n/**\n * Generate a runtime Drizzle schema from an entity definition.\n * Every field becomes its own column — no JSONB.\n */\nexport function generateSchema(entity: Entity) {\n const tableName = entity.name\n const columns: Record<string, PgColumnBuilderBase> = {}\n\n for (const [fieldName, fieldConfig] of Object.entries(entity.allFields)) {\n if (fieldConfig.type === 'blocks') continue // stored in layout table\n columns[fieldName] = fieldToColumn(fieldName, fieldConfig)\n }\n\n if (entity.scope === 'team' || entity.scope === 'user') {\n columns._scopeId = uuid('_scope_id')\n }\n\n // Collect fields that need indexes (skip id/unique — they already have btree indexes)\n const indexedFields = Object.entries(entity.allFields).filter(\n ([_, config]) =>\n config.type !== 'blocks' && config.type !== 'id' && config.indexed && !config.unique,\n )\n\n const isPublishableEntity = entity.behaviors?.some((b) => b.name === 'publishable') ?? false\n\n if (indexedFields.length === 0 && !isPublishableEntity) {\n return pgTable(tableName, columns)\n }\n\n return pgTable(tableName, columns, (table) => {\n // biome-ignore lint/suspicious/noExplicitAny: dynamic table columns from pgTable callback\n const constraints: Record<string, any> = {}\n\n for (const [fieldName] of indexedFields) {\n constraints[`idx_${tableName}_${fieldName}`] = index(`idx_${tableName}_${fieldName}`).on(\n table[fieldName],\n )\n }\n\n // Composite index for publishable entities: status + createdAt (most common list query)\n if (isPublishableEntity && table.status && table.createdAt) {\n constraints[`idx_${tableName}_status_created`] = index(`idx_${tableName}_status_created`).on(\n table.status,\n table.createdAt,\n )\n }\n\n return constraints\n })\n}\n\n/**\n * Generate TypeScript code string for an entity schema.\n * Every field becomes its own column — no JSONB.\n */\nexport function generateSchemaCode(entity: Entity): string {\n const tableName = entity.name\n const lines: string[] = []\n\n // Collect fields that need indexes (skip id/unique — they already have btree indexes)\n const indexedFields = Object.entries(entity.allFields).filter(\n ([_, config]) =>\n config.type !== 'blocks' && config.type !== 'id' && config.indexed && !config.unique,\n )\n\n const isPublishableEntity = entity.behaviors?.some((b) => b.name === 'publishable') ?? false\n const needsIndexes = indexedFields.length > 0 || isPublishableEntity\n\n lines.push(`export const ${tableName} = pgTable('${tableName}', {`)\n\n for (const [fieldName, fieldConfig] of Object.entries(entity.allFields)) {\n if (fieldConfig.type === 'blocks') continue // stored in layout table\n const columnCode = generateColumnCode(fieldName, fieldConfig)\n lines.push(` ${columnCode},`)\n }\n\n if (entity.scope === 'team' || entity.scope === 'user') {\n lines.push(` _scopeId: uuid('_scope_id'),`)\n }\n\n if (needsIndexes) {\n lines.push(`}, (table) => ({`)\n\n for (const [fieldName] of indexedFields) {\n lines.push(\n ` idx_${tableName}_${fieldName}: index('idx_${tableName}_${fieldName}').on(table.${fieldName}),`,\n )\n }\n\n // Composite index for publishable entities: status + createdAt\n if (isPublishableEntity) {\n lines.push(\n ` idx_${tableName}_status_created: index('idx_${tableName}_status_created').on(table.status, table.createdAt),`,\n )\n }\n\n lines.push(`}))`)\n } else {\n lines.push(`)`)\n }\n\n return lines.join('\\n')\n}\n\n/**\n * Generate runtime translation table schema.\n * Each translatable field gets its own nullable column.\n */\nexport function generateTranslationSchema(entity: Entity) {\n const translatableFields = Object.entries(entity.allFields).filter(\n ([_, config]) => config.translatable,\n )\n\n if (translatableFields.length === 0) return null\n\n const tableName = `${entity.name}_translations`\n const columns: Record<string, PgColumnBuilderBase> = {\n id: uuid('id').primaryKey().defaultRandom(),\n entityId: uuid('entity_id').notNull(),\n locale: varchar('locale', { length: 10 }).notNull(),\n }\n\n const hasTranslatableSlug = translatableFields.some(([_, config]) => config.type === 'slug')\n\n for (const [fieldName, fieldConfig] of translatableFields) {\n columns[fieldName] = fieldToColumn(fieldName, fieldConfig, { nullable: true })\n }\n\n return pgTable(tableName, columns, (table) => ({\n uniqueEntityLocale: unique().on(table.entityId, table.locale),\n // Per-locale slug uniqueness: no two entities can share the same slug in the same locale\n ...(hasTranslatableSlug && table.slug\n ? { uniqueSlugLocale: unique().on(table.slug, table.locale) }\n : {}),\n }))\n}\n\n/**\n * Generate TypeScript code string for a translation table.\n * Each translatable field gets its own nullable column.\n */\nexport function generateTranslationSchemaCode(entity: Entity): string | null {\n const translatableFields = Object.entries(entity.allFields).filter(\n ([_, config]) => config.translatable,\n )\n\n if (translatableFields.length === 0) return null\n\n const tableName = `${entity.name}_translations`\n const entityTableName = entity.name\n const lines: string[] = []\n\n lines.push(`export const ${tableName} = pgTable('${tableName}', {`)\n lines.push(` id: uuid('id').primaryKey().defaultRandom(),`)\n lines.push(\n ` entityId: uuid('entity_id').notNull().references(() => ${entityTableName}.id, { onDelete: 'cascade' }),`,\n )\n lines.push(` locale: varchar('locale', { length: 10 }).notNull(),`)\n\n for (const [fieldName, fieldConfig] of translatableFields) {\n const columnCode = generateColumnCode(fieldName, fieldConfig, { nullable: true })\n lines.push(` ${columnCode},`)\n }\n\n const hasTranslatableSlug = translatableFields.some(([_, config]) => config.type === 'slug')\n\n lines.push(`}, (table) => ({`)\n lines.push(\n ` uniqueEntityLocale: unique().on(table.entityId, table.locale), // One translation per locale`,\n )\n if (hasTranslatableSlug) {\n lines.push(\n ` uniqueSlugLocale: unique().on(table.slug, table.locale), // Per-locale slug uniqueness`,\n )\n }\n lines.push(`}))`)\n\n return lines.join('\\n')\n}\n\n/**\n * Check if an entity has any blocks fields\n */\nexport function hasBlocksFields(entity: Entity): boolean {\n return Object.values(entity.allFields).some((f) => f.type === 'blocks')\n}\n\n/**\n * Generate layout table schema for entities with blocks fields.\n * Stores block instances in a separate table with ordering.\n *\n * When blocks field has localized: false (default), locale is NULL (shared layout).\n * When blocks field has localized: true, locale is set per-locale.\n */\nexport function generateLayoutSchema(entity: Entity) {\n if (!hasBlocksFields(entity)) return null\n\n const tableName = `${entity.name}_layout`\n\n return pgTable(\n tableName,\n {\n id: uuid('id').primaryKey().defaultRandom(),\n entityId: uuid('entity_id').notNull(),\n fieldName: varchar('field_name', { length: 100 }).notNull(),\n blockType: varchar('block_type', { length: 100 }).notNull(),\n sortOrder: integer('sort_order').notNull().default(0),\n data: jsonb('data'),\n locale: varchar('locale', { length: 10 }),\n },\n (table) => ({\n // Covers: WHERE entity_id IN (...) AND locale IS NULL ORDER BY sort_order\n idx_entity_locale_sort: index(`idx_${tableName}_entity_locale_sort`).on(\n table.entityId,\n table.locale,\n table.sortOrder,\n ),\n }),\n )\n}\n\n/**\n * Check if an entity has the versionable behavior\n */\nexport function isVersionable(entity: Entity): boolean {\n return entity.behaviors?.some((b) => b.name === 'versionable') ?? false\n}\n\n/**\n * Check if an entity needs a per-locale publish status table.\n * Requires both publishable() behavior AND at least one translatable field.\n */\nexport function needsLocaleStatus(entity: Entity): boolean {\n const isPublishable = entity.behaviors?.some((b) => b.name === 'publishable') ?? false\n if (!isPublishable) return false\n const allFields = entity.allFields as Record<string, { translatable?: boolean }>\n return Object.values(allFields).some((f) => f.translatable)\n}\n\n/**\n * Generate TypeScript code string for a per-locale publish status table.\n */\nexport function generateLocaleStatusCode(entity: Entity): string {\n const name = entity.name\n const varName = `${name}_locale_status`\n return `export const ${varName} = pgTable('${varName}', {\n id: uuid('id').primaryKey().defaultRandom(),\n entityId: uuid('entity_id').notNull().references(() => ${name}.id, { onDelete: 'cascade' }),\n locale: varchar('locale', { length: 10 }).notNull(),\n status: varchar('status', { length: 20 }).notNull().default('draft'),\n publishedAt: timestamp('published_at', { withTimezone: true }),\n}, (table) => ({\n uniqueEntityLocale: unique().on(table.entityId, table.locale),\n}))`\n}\n\n/**\n * Check if an entity is publishable (has publishable() behavior).\n */\nexport function isPublishable(entity: Entity): boolean {\n return entity.behaviors?.some((b) => b.name === 'publishable') ?? false\n}\n\n/**\n * Generate TypeScript code string for a drafts overlay table.\n */\nexport function generateDraftsCode(entity: Entity): string {\n const name = entity.name\n const varName = `${name}_drafts`\n return `export const ${varName} = pgTable('${varName}', {\n id: uuid('id').primaryKey().defaultRandom(),\n entityId: uuid('entity_id').notNull().references(() => ${name}.id, { onDelete: 'cascade' }),\n locale: varchar('locale', { length: 10 }).notNull().default('_'),\n data: jsonb('data').notNull(),\n createdBy: varchar('created_by', { length: 255 }).notNull(),\n createdByName: varchar('created_by_name', { length: 255 }),\n createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),\n updatedAt: timestamp('updated_at', { withTimezone: true }).notNull().defaultNow(),\n}, (table) => ({\n uniqueEntityLocale: unique().on(table.entityId, table.locale),\n}))`\n}\n\n/**\n * Generate TypeScript code string for the shared content locks table.\n */\nexport function generateContentLocksCode(): string {\n return `export const toolkit_content_locks = pgTable('toolkit_content_locks', {\n id: uuid('id').primaryKey().defaultRandom(),\n entityType: varchar('entity_type', { length: 100 }).notNull(),\n entityId: varchar('entity_id', { length: 255 }).notNull(),\n locale: varchar('locale', { length: 10 }).notNull().default('_'),\n lockedBy: varchar('locked_by', { length: 255 }).notNull(),\n lockedByName: varchar('locked_by_name', { length: 255 }),\n lockedAt: timestamp('locked_at', { withTimezone: true }).notNull().defaultNow(),\n expiresAt: timestamp('expires_at', { withTimezone: true }).notNull(),\n}, (table) => ({\n uniqueEntityLock: unique().on(table.entityType, table.entityId, table.locale),\n}))`\n}\n\n/**\n * Check if an entity has blocks fields with translatable block content (non-localized mode).\n */\nexport function hasTranslatableBlocks(entity: Entity): boolean {\n const allFields = entity.allFields as Record<\n string,\n {\n type: string\n localized?: boolean\n blocks?: Array<{ fields: Record<string, { translatable?: boolean }> }>\n }\n >\n return Object.values(allFields).some((f) => {\n if (f.type !== 'blocks') return false\n if (f.localized) return false\n return f.blocks?.some((block) => Object.values(block.fields).some((bf) => bf.translatable))\n })\n}\n\n/**\n * Generate TypeScript code string for a layout table (blocks storage).\n */\nexport function generateLayoutCode(entity: Entity): string {\n const name = entity.name\n const varName = `${name}_layout`\n return `export const ${varName} = pgTable('${varName}', {\n id: uuid('id').primaryKey().defaultRandom(),\n entityId: uuid('entity_id').notNull().references(() => ${name}.id, { onDelete: 'cascade' }),\n fieldName: varchar('field_name', { length: 100 }).notNull(),\n blockType: varchar('block_type', { length: 100 }).notNull(),\n sortOrder: integer('sort_order').notNull().default(0),\n data: jsonb('data'),\n locale: varchar('locale', { length: 10 }),\n}, (table) => ({\n idx_entity_locale_sort: index('idx_${varName}_entity_locale_sort').on(table.entityId, table.locale, table.sortOrder),\n}))`\n}\n\n/**\n * Generate TypeScript code string for a layout translation table.\n */\nexport function generateLayoutTranslationCode(entity: Entity): string {\n const name = entity.name\n const varName = `${name}_layout_translations`\n const layoutVar = `${name}_layout`\n return `export const ${varName} = pgTable('${varName}', {\n id: uuid('id').primaryKey().defaultRandom(),\n layoutId: uuid('layout_id').notNull().references(() => ${layoutVar}.id, { onDelete: 'cascade' }),\n locale: varchar('locale', { length: 10 }).notNull(),\n fields: jsonb('fields').notNull(),\n}, (table) => ({\n uniqueLayoutLocale: unique().on(table.layoutId, table.locale),\n}))`\n}\n\n/**\n * Generate TypeScript code string for a versions table.\n */\nexport function generateVersionsCode(entity: Entity): string {\n const name = entity.name\n const varName = `${name}_versions`\n return `export const ${varName} = pgTable('${varName}', {\n id: uuid('id').primaryKey().defaultRandom(),\n entityId: uuid('entity_id').notNull().references(() => ${name}.id, { onDelete: 'cascade' }),\n version: integer('version').notNull(),\n locale: varchar('locale', { length: 10 }).notNull().default('_'),\n data: jsonb('data').notNull(),\n delta: jsonb('delta'),\n status: varchar('status', { length: 20 }),\n createdBy: varchar('created_by', { length: 255 }),\n createdByName: varchar('created_by_name', { length: 255 }),\n createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),\n isAutosave: boolean('is_autosave').notNull().default(false),\n}, (table) => ({\n uniqueEntityVersionLocale: unique().on(table.entityId, table.version, table.locale),\n}))`\n}\n\n/**\n * Generate layout translation table for non-localized blocks with translatable fields.\n */\nexport function generateLayoutTranslationSchema(entity: Entity) {\n const blocksFields = Object.values(entity.allFields).filter(\n (f) => f.type === 'blocks' && !('localized' in f && f.localized),\n )\n\n if (blocksFields.length === 0) return null\n\n const hasTranslatableBlockFields = blocksFields.some((bf) => {\n if (bf.type !== 'blocks') return false\n return bf.blocks.some((block) => Object.values(block.fields).some((f) => f.translatable))\n })\n\n if (!hasTranslatableBlockFields) return null\n\n const tableName = `${entity.name}_layout_translations`\n\n return pgTable(\n tableName,\n {\n id: uuid('id').primaryKey().defaultRandom(),\n layoutId: uuid('layout_id').notNull(),\n locale: varchar('locale', { length: 10 }).notNull(),\n fields: jsonb('fields').notNull(),\n },\n (table) => ({\n uniqueLayoutLocale: unique().on(table.layoutId, table.locale),\n }),\n )\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../src/fields/builders.ts","../src/behaviors/auditable.ts","../src/behaviors/hierarchical.ts","../src/behaviors/publishable.ts","../src/behaviors/revisionable.ts","../src/behaviors/sluggable.ts","../src/behaviors/timestamped.ts","../src/behaviors/index.ts","../src/count-cache.ts","../src/count-estimate.ts","../src/cursor.ts","../src/define-entity.ts","../src/refs/errors.ts","../src/schema-generator.ts"],"sourcesContent":["/**\n * Fluent API for building field definitions\n * Provides type-safe field builders with sensible defaults.\n *\n * Each builder uses a `const` generic parameter on the config to preserve\n * literal types (e.g., `required: true` stays `true`, not `boolean`).\n * This enables compile-time type inference in the entity system.\n */\n\nimport type {\n BlockDefinitionRef,\n BlocksField,\n BooleanField,\n DateField,\n IdField,\n JsonField,\n MediaField,\n NumberField,\n ReferenceField,\n RichTextField,\n SelectField,\n SlugField,\n TextField,\n} from './base.js'\n\nexport const field = {\n /**\n * ID field (auto-added to every entity)\n */\n // biome-ignore lint/complexity/noBannedTypes: {} is correct as empty generic default\n id: <const C extends Partial<IdField> = {}>(config?: C): IdField & C =>\n ({\n type: 'id',\n required: true,\n indexed: true,\n ...config,\n }) as IdField & C,\n\n /**\n * Text field\n */\n // biome-ignore lint/complexity/noBannedTypes: {} is correct as empty generic default\n text: <const C extends Partial<TextField> = {}>(config?: C): TextField & C =>\n ({\n type: 'text',\n ...config,\n }) as TextField & C,\n\n /**\n * Number field\n */\n // biome-ignore lint/complexity/noBannedTypes: {} is correct as empty generic default\n number: <const C extends Partial<NumberField> = {}>(config?: C): NumberField & C =>\n ({\n type: 'number',\n ...config,\n }) as NumberField & C,\n\n /**\n * Boolean field\n */\n // biome-ignore lint/complexity/noBannedTypes: {} is correct as empty generic default\n boolean: <const C extends Partial<BooleanField> = {}>(config?: C): BooleanField & C =>\n ({\n type: 'boolean',\n default: false,\n ...config,\n }) as BooleanField & C,\n\n /**\n * Date field\n */\n // biome-ignore lint/complexity/noBannedTypes: {} is correct as empty generic default\n date: <const C extends Partial<DateField> = {}>(config?: C): DateField & C =>\n ({\n type: 'date',\n ...config,\n }) as DateField & C,\n\n /**\n * Select field (enum)\n * Preserves literal option types for type inference.\n * e.g. field.select({ options: ['news', 'tutorial'] }) infers 'news' | 'tutorial'\n */\n select: <\n const O extends readonly string[],\n // biome-ignore lint/complexity/noBannedTypes: {} is correct as empty generic default\n const C extends Omit<Partial<SelectField>, 'options'> = {},\n >(\n config: { options: O } & C,\n ): SelectField & { options: O } & C =>\n ({\n type: 'select',\n ...config,\n }) as SelectField & { options: O } & C,\n\n /**\n * Reference field (foreign key to another entity)\n * Preserves literal cardinality to distinguish string vs string[] in inferred types.\n */\n reference: <\n C extends 'one' | 'many' = 'one',\n // biome-ignore lint/complexity/noBannedTypes: {} is correct as empty generic default\n const R extends Partial<Omit<ReferenceField, 'entity' | 'cardinality'>> = {},\n >(\n config: { entity: string; cardinality?: C } & R,\n ): ReferenceField & { cardinality: C } & R =>\n ({\n type: 'reference',\n cardinality: 'one' as C,\n onDelete: 'set-null',\n ...config,\n }) as ReferenceField & { cardinality: C } & R,\n\n /**\n * Media field (file upload)\n */\n // biome-ignore lint/complexity/noBannedTypes: {} is correct as empty generic default\n media: <const C extends Partial<MediaField> = {}>(config?: C): MediaField & C =>\n ({\n type: 'media',\n ...config,\n }) as MediaField & C,\n\n /**\n * Rich text field (WYSIWYG editor)\n */\n // biome-ignore lint/complexity/noBannedTypes: {} is correct as empty generic default\n richtext: <const C extends Partial<RichTextField> = {}>(config?: C): RichTextField & C =>\n ({\n type: 'richtext',\n ...config,\n }) as RichTextField & C,\n\n /**\n * Slug field (URL-safe string, auto-generated from source field)\n */\n // biome-ignore lint/complexity/noBannedTypes: {} is correct as empty generic default\n slug: <const C extends Partial<SlugField> = {}>(\n config: Pick<SlugField, 'from'> & C,\n ): SlugField & C =>\n ({\n type: 'slug',\n unique: true,\n indexed: true,\n ...config,\n }) as SlugField & C,\n\n /**\n * JSON field (arbitrary JSON data, stored as JSONB)\n */\n // biome-ignore lint/complexity/noBannedTypes: {} is correct as empty generic default\n json: <const C extends Partial<JsonField> = {}>(config?: C): JsonField & C =>\n ({\n type: 'json',\n ...config,\n }) as JsonField & C,\n\n /**\n * Blocks field — ordered array of typed content blocks\n * Preserves literal block tuple type for discriminated union inference.\n */\n blocks: <const B extends readonly BlockDefinitionRef[]>(config: {\n blocks: B\n min?: number\n max?: number\n localized?: boolean\n }): BlocksField & { blocks: B } =>\n ({\n type: 'blocks' as const,\n ...config,\n }) as BlocksField & { blocks: B },\n}\n","/**\n * Auditable behavior\n * Adds createdBy, updatedBy, createdAt, updatedAt fields + auto-set logic.\n *\n * When @murumets-ee/core is available (i.e. running inside createApp), the hooks\n * automatically populate createdBy/updatedBy from the RequestContext.\n */\n\nimport { field } from '../fields/builders.js'\nimport type { AuditableFields } from '../types/infer.js'\nimport type { Behavior } from './types.js'\n\n/**\n * Try to get the current user ID from @murumets-ee/core's RequestContext.\n * Returns undefined if @murumets-ee/core isn't loaded or no user is in context.\n *\n * Uses a dynamic import string indirection to avoid TypeScript resolving\n * @murumets-ee/core at compile time (which would create a circular dep: entity → core → entity).\n */\nasync function getCurrentUserId(): Promise<string | undefined> {\n try {\n // Module name built at runtime so TypeScript doesn't try to resolve it during DTS emit\n const moduleName = ['@murumets-ee', 'core'].join('/')\n const core = await (import(moduleName) as Promise<{\n getCurrentUser: () => { id: string } | undefined\n }>)\n return core.getCurrentUser()?.id\n } catch {\n return undefined\n }\n}\n\nexport function auditable(): Behavior<AuditableFields> {\n return {\n name: 'auditable',\n fields: {\n createdBy: field.text(),\n updatedBy: field.text(),\n createdAt: field.date({ indexed: true }),\n updatedAt: field.date({ indexed: true }),\n },\n hooks: {\n beforeCreate: async (data) => {\n data.createdAt = new Date()\n data.updatedAt = new Date()\n const userId = await getCurrentUserId()\n if (userId) {\n data.createdBy = userId\n data.updatedBy = userId\n }\n return data\n },\n beforeUpdate: async (_id, data) => {\n data.updatedAt = new Date()\n const userId = await getCurrentUserId()\n if (userId) {\n data.updatedBy = userId\n }\n return data\n },\n },\n }\n}\n","/**\n * Hierarchical behavior\n * Adds parentId, path, depth fields for materialized path tree structures.\n *\n * Path format: /uuid1/uuid2/uuid3\n * - Root items: /{ownId}\n * - Children: /{rootId}/.../{parentId}/{ownId}\n *\n * The behavior declares fields and sets safe defaults in hooks.\n * Heavy lifting (path computation, circular ref validation, descendant cascading)\n * is done by TaxonomyClient which has DB access.\n */\n\nimport { field } from '../fields/builders.js'\nimport type { HierarchicalFields } from '../types/infer.js'\nimport type { Behavior } from './types.js'\n\nexport interface HierarchicalOptions {\n /**\n * What happens when deleting a node that has children.\n * - 'restrict': Prevent deletion (default)\n * - 'cascade': Delete all descendants\n * - 'reparent': Move children to the deleted node's parent\n */\n onDelete?: 'restrict' | 'cascade' | 'reparent'\n}\n\nexport function hierarchical(_options?: HierarchicalOptions): Behavior<HierarchicalFields> {\n return {\n name: 'hierarchical',\n fields: {\n parentId: field.reference({ entity: '_self', required: false }),\n path: field.text({ indexed: true, maxLength: 2048 }),\n depth: field.number({ integer: true, default: 0, indexed: true }),\n },\n hooks: {\n beforeCreate: async (data) => {\n // Set defaults for root-level items.\n // TaxonomyClient overrides these after insert when it has the ID.\n if (!data.parentId) {\n data.depth = 0\n }\n return data\n },\n },\n }\n}\n","/**\n * Publishable behavior\n * Adds status (draft/published) and publishedAt fields + auto-set logic\n */\n\nimport { field } from '../fields/builders.js'\nimport type { PublishableFields } from '../types/infer.js'\nimport type { Behavior } from './types.js'\n\nexport function publishable(): Behavior<PublishableFields> {\n return {\n name: 'publishable',\n fields: {\n status: field.select({\n options: ['draft', 'published'] as const,\n default: 'draft',\n indexed: true,\n }),\n publishedAt: field.date({ indexed: true }),\n },\n hooks: {\n beforeUpdate: async (_id, data) => {\n // Auto-set publishedAt when status changes to published (if not already set)\n if (data.status === 'published' && !data.publishedAt) {\n data.publishedAt = new Date()\n }\n return data\n },\n },\n }\n}\n","/**\n * Revisionable behavior\n * Adds _version field + auto-increment on update\n */\n\nimport { field } from '../fields/builders.js'\nimport type { RevisionableFields } from '../types/infer.js'\nimport type { Behavior } from './types.js'\n\nexport function revisionable(): Behavior<RevisionableFields> {\n return {\n name: 'revisionable',\n fields: {\n _version: field.number({ required: true, default: 1, integer: true }),\n },\n hooks: {\n beforeCreate: async (data) => {\n data._version = 1\n return data\n },\n beforeUpdate: async (_id, data) => {\n // Increment version on every update\n data._version = (Number(data._version) || 0) + 1\n return data\n },\n },\n }\n}\n","/**\n * Sluggable behavior\n * Adds slug field + auto-generation from source field\n */\n\nimport { field } from '../fields/builders.js'\nimport type { SluggableFields } from '../types/infer.js'\nimport type { Behavior } from './types.js'\n\nexport interface SluggableOptions {\n /** Make the slug translatable — each locale gets its own slug. Default: false */\n translatable?: boolean\n}\n\n/**\n * Convert text to URL-safe slug\n */\nexport function slugify(text: string): string {\n return text\n .toLowerCase()\n .trim()\n .replace(/[^\\w\\s-]/g, '') // Remove non-word chars except spaces and hyphens\n .replace(/[\\s_-]+/g, '-') // Replace spaces, underscores with single hyphen\n .replace(/^-+|-+$/g, '') // Remove leading/trailing hyphens\n}\n\nexport function sluggable(\n sourceField: string,\n options?: SluggableOptions,\n): Behavior<SluggableFields> {\n return {\n name: 'sluggable',\n fields: {\n slug: field.slug({\n from: sourceField,\n ...(options?.translatable ? { translatable: true } : {}),\n }),\n },\n hooks: {\n beforeCreate: async (data) => {\n // Auto-generate slug from source field if not provided\n if (!data.slug && data[sourceField]) {\n data.slug = slugify(String(data[sourceField]))\n }\n return data\n },\n beforeUpdate: async (_id, data) => {\n // Re-generate slug if source field changed and slug not manually set\n if (data[sourceField] && !data.slug) {\n data.slug = slugify(String(data[sourceField]))\n }\n return data\n },\n },\n }\n}\n","/**\n * Timestamped behavior\n * Adds createdAt and updatedAt fields with auto-set logic.\n * Lighter alternative to auditable() when you don't need createdBy/updatedBy tracking.\n */\n\nimport { field } from '../fields/builders.js'\nimport type { Behavior } from './types.js'\n\nexport type TimestampedFields = {\n createdAt: ReturnType<typeof field.date>\n updatedAt: ReturnType<typeof field.date>\n}\n\nexport function timestamped(): Behavior<TimestampedFields> {\n return {\n name: 'timestamped',\n fields: {\n createdAt: field.date({ indexed: true }),\n updatedAt: field.date({ indexed: true }),\n },\n hooks: {\n beforeCreate: async (data) => {\n data.createdAt = new Date()\n data.updatedAt = new Date()\n return data\n },\n beforeUpdate: async (_id, data) => {\n data.updatedAt = new Date()\n return data\n },\n },\n }\n}\n","/**\n * Behavior exports\n * All behaviors are exported under the `behavior` namespace\n */\n\nimport { auditable } from './auditable.js'\nimport { hierarchical } from './hierarchical.js'\nimport { publishable } from './publishable.js'\nimport { revisionable } from './revisionable.js'\nimport { sluggable } from './sluggable.js'\nimport { timestamped } from './timestamped.js'\n\nexport { publishable, auditable, sluggable, revisionable, hierarchical, timestamped }\nexport type { SluggableOptions } from './sluggable.js'\nexport { slugify } from './sluggable.js'\nexport type { Behavior, BehaviorFactory } from './types.js'\n\n/**\n * Behavior namespace for fluent API\n */\nexport const behavior = {\n publishable,\n auditable,\n sluggable,\n revisionable,\n hierarchical,\n timestamped,\n}\n","/**\n * In-memory TTL cache for COUNT(*) query results.\n *\n * Reduces database load on paginated list pages where the total count\n * is recalculated on every pagination/sort/search interaction. The cache\n * is per-process (not shared across workers) with a short TTL (default 5s)\n * so counts are at most a few seconds stale.\n *\n * Cache keys include the entity name + serialized WHERE clause, so filtered\n * and unfiltered counts are cached independently.\n */\n\n/**\n * Interface for count cache implementations.\n * Used in client configs to avoid TypeScript private-field structural incompatibility\n * across separate .d.ts files.\n */\nexport interface CountCacheLike {\n get(key: string): number | undefined\n set(key: string, count: number): void\n invalidate(prefix: string): void\n}\n\ninterface CountCacheEntry {\n count: number\n expiresAt: number\n}\n\nexport class CountCache implements CountCacheLike {\n private cache = new Map<string, CountCacheEntry>()\n private ttlMs: number\n\n constructor(ttlMs = 5000) {\n this.ttlMs = ttlMs\n }\n\n /**\n * Get a cached count. Returns undefined on miss or expired entry.\n */\n get(key: string): number | undefined {\n const entry = this.cache.get(key)\n if (!entry || Date.now() > entry.expiresAt) {\n if (entry) this.cache.delete(key)\n return undefined\n }\n return entry.count\n }\n\n /**\n * Cache a count result with the configured TTL.\n */\n set(key: string, count: number): void {\n this.cache.set(key, { count, expiresAt: Date.now() + this.ttlMs })\n }\n\n /**\n * Invalidate all cache entries whose key starts with the given prefix.\n * Typically called with the entity name after mutations (create/update/delete).\n */\n invalidate(prefix: string): void {\n for (const key of this.cache.keys()) {\n if (key.startsWith(prefix)) {\n this.cache.delete(key)\n }\n }\n }\n\n /**\n * Remove all expired entries. Useful for periodic cleanup in long-running processes.\n */\n prune(): void {\n const now = Date.now()\n for (const [key, entry] of this.cache.entries()) {\n if (now > entry.expiresAt) {\n this.cache.delete(key)\n }\n }\n }\n\n /**\n * Clear the entire cache.\n */\n clear(): void {\n this.cache.clear()\n }\n\n /**\n * Number of entries currently in the cache (including expired ones not yet pruned).\n */\n get size(): number {\n return this.cache.size\n }\n}\n","/**\n * Postgres row count estimation using pg_class statistics.\n *\n * For unfiltered counts on large tables, querying `pg_class.reltuples`\n * is effectively instant (no table scan) and returns a good approximation\n * that is updated by VACUUM and ANALYZE. This is suitable for pagination\n * totals where exact precision is not critical.\n *\n * SECURITY: The table name is NOT interpolated into SQL — it is passed as a\n * parameterized value to the `relname = $1` comparison. This prevents SQL injection.\n */\n\nimport { sql } from 'drizzle-orm'\nimport type { PostgresJsDatabase } from 'drizzle-orm/postgres-js'\n\n/**\n * Estimate the total row count for a table using Postgres statistics.\n *\n * Returns the approximate row count from `pg_class.reltuples`, which is\n * updated by VACUUM/ANALYZE. Returns 0 if the table is not found or\n * statistics are not yet available (e.g., freshly created table).\n *\n * @param db - Drizzle Postgres database instance\n * @param tableName - The Postgres table name (without schema prefix)\n * @returns Estimated row count (non-negative integer)\n */\nexport async function estimateRowCount(db: PostgresJsDatabase, tableName: string): Promise<number> {\n const result = await db.execute(\n sql`SELECT reltuples::bigint AS estimate FROM pg_class WHERE relname = ${tableName}`,\n )\n\n const rows = Array.isArray(result) ? result : ((result as { rows?: unknown[] }).rows ?? [])\n const row = rows[0] as { estimate?: string | number } | undefined\n const estimate = Number(row?.estimate ?? 0)\n\n // reltuples can be -1 for tables that have never been analyzed\n return estimate > 0 ? estimate : 0\n}\n","/**\n * Cursor-based (keyset) pagination utilities.\n *\n * Cursor pagination avoids the performance cliff of OFFSET at scale (1M+ rows).\n * Instead of `OFFSET N`, it uses a WHERE condition:\n * `WHERE (sortField < lastValue) OR (sortField = lastValue AND id < lastId)`\n * which Postgres can serve from an index in constant time.\n *\n * The cursor is opaque to the client — base64-encoded JSON.\n *\n * Security:\n * - `field` must be whitelisted against the entity's actual fields\n * - `id` must be a valid UUID\n * - `value` is parameterized (never interpolated into SQL)\n * - Malformed cursors return null (caller returns 400)\n */\n\nimport { and, eq, gt, lt, or, type SQL } from 'drizzle-orm'\nimport type { PgTableWithColumns } from 'drizzle-orm/pg-core'\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/** Cursor input for keyset pagination. */\nexport interface CursorInput {\n /** Sort field name (e.g. 'createdAt'). Must be a real column on the entity. */\n field: string\n /** Last seen value of the sort field. */\n value: string | number\n /** Sort direction — must match the ORDER BY direction. */\n direction: 'asc' | 'desc'\n /** Tie-breaker: last seen entity ID. Required for non-unique sort fields. */\n id?: string\n}\n\n/** Decoded cursor (internal, after validation). */\ninterface DecodedCursor {\n field: string\n value: string | number\n direction: 'asc' | 'desc'\n id?: string\n}\n\n// ---------------------------------------------------------------------------\n// UUID validation (same format used throughout the toolkit)\n// ---------------------------------------------------------------------------\n\nconst UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i\n\n// ---------------------------------------------------------------------------\n// Encode / decode\n// ---------------------------------------------------------------------------\n\n/**\n * Encode a cursor for API transport (base64url).\n * Built from the last item in a result set.\n */\nexport function encodeCursor(\n item: Record<string, unknown>,\n sortField: string,\n direction: 'asc' | 'desc',\n): string {\n const payload: CursorInput = {\n field: sortField,\n value: item[sortField] as string | number,\n direction,\n id: item.id as string | undefined,\n }\n return btoa(JSON.stringify(payload))\n}\n\n/**\n * Decode and validate a cursor string from query params.\n * Returns null if the cursor is malformed, tampered, or invalid.\n *\n * Security: the `field` value is NOT validated here — the caller must\n * whitelist it against the entity's actual columns.\n */\nexport function decodeCursor(encoded: string): DecodedCursor | null {\n try {\n const json = atob(encoded)\n const parsed: unknown = JSON.parse(json)\n\n if (typeof parsed !== 'object' || parsed === null) return null\n const obj = parsed as Record<string, unknown>\n\n // Validate field\n if (typeof obj.field !== 'string' || !/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(obj.field)) {\n return null\n }\n\n // Validate value (string or number)\n if (typeof obj.value !== 'string' && typeof obj.value !== 'number') {\n return null\n }\n\n // Validate direction\n if (obj.direction !== 'asc' && obj.direction !== 'desc') {\n return null\n }\n\n // Validate id (optional, must be UUID if present)\n if (obj.id !== undefined) {\n if (typeof obj.id !== 'string' || !UUID_RE.test(obj.id)) {\n return null\n }\n }\n\n return {\n field: obj.field,\n value: obj.value,\n direction: obj.direction,\n id: obj.id as string | undefined,\n }\n } catch {\n return null\n }\n}\n\n// ---------------------------------------------------------------------------\n// SQL condition builder\n// ---------------------------------------------------------------------------\n\n/**\n * Build the keyset WHERE condition from a decoded cursor.\n *\n * For DESC: `WHERE (field < value) OR (field = value AND id < cursorId)`\n * For ASC: `WHERE (field > value) OR (field = value AND id > cursorId)`\n *\n * The caller must verify that `cursor.field` exists on the table before calling.\n *\n * @param table - Drizzle table with columns\n * @param cursor - Decoded and validated cursor\n * @returns SQL condition, or null if the field doesn't exist on the table\n */\nexport function buildCursorCondition(\n // biome-ignore lint/suspicious/noExplicitAny: dynamic table columns require PgTableWithColumns<any> for property access\n table: PgTableWithColumns<any>,\n cursor: DecodedCursor,\n): SQL | null {\n const column = table[cursor.field]\n if (!column) return null\n\n const isDesc = cursor.direction === 'desc'\n const compare = isDesc ? lt : gt\n\n // Primary condition: sort field passes the cursor value\n const fieldCondition = compare(column, cursor.value)\n\n // Without tie-breaker ID, use simple comparison\n if (!cursor.id) {\n return fieldCondition\n }\n\n // With tie-breaker: (field < value) OR (field = value AND id < cursorId)\n const idColumn = table.id\n if (!idColumn) return fieldCondition\n\n const idCondition = compare(idColumn, cursor.id)\n return or(fieldCondition, and(eq(column, cursor.value), idCondition))!\n}\n","/**\n * Entity definition API\n * The core function for defining entities with full type inference.\n *\n * The generic parameters are inferred from the call site:\n * - F is inferred from `definition.fields`\n * - B is inferred from `definition.behaviors` (as a tuple)\n *\n * The returned Entity carries the complete field map:\n * { id: IdField } & BehaviorFields & UserFields\n */\n\nimport type { EntityAdminConfig } from './admin-config.js'\nimport type { Behavior } from './behaviors/types.js'\nimport type { FieldConfig, IdField } from './fields/base.js'\nimport { field } from './fields/builders.js'\n\n/**\n * Entity definition input (without behaviors — behaviors are typed separately\n * on the `defineEntity` function to enable tuple inference).\n *\n * @typeParam F - The literal field map. Inferred automatically from the call site.\n */\nexport interface EntityDefinition<\n F extends Record<string, FieldConfig> = Record<string, FieldConfig>,\n> {\n name: string\n kind?: 'collection' | 'singleton'\n fields: F\n scope?: 'global' | 'team' | 'user'\n access?: {\n view?: string\n create?: string\n update?: string\n delete?: string\n }\n /** Admin UI configuration — controls sidebar, list, and form display */\n admin?: EntityAdminConfig\n}\n\n/**\n * Full input for defineEntity (fields + behaviors + other config).\n * Behaviors are typed as a tuple `B` for type extraction.\n */\nexport type EntityInput<\n F extends Record<string, FieldConfig> = Record<string, FieldConfig>,\n B extends Behavior[] = Behavior[],\n> = EntityDefinition<F> & { behaviors?: B }\n\n/**\n * A fully resolved entity with merged behavior fields.\n * @typeParam AllFields - The complete field map (id + behaviors + user fields).\n */\nexport interface Entity<\n AllFields extends Record<string, FieldConfig> = Record<string, FieldConfig>,\n> {\n name: string\n kind?: 'collection' | 'singleton'\n fields: Record<string, FieldConfig>\n behaviors?: Behavior[]\n scope?: 'global' | 'team' | 'user'\n access?: {\n view?: string\n create?: string\n update?: string\n delete?: string\n }\n /** Admin UI configuration — controls sidebar, list, and form display */\n admin?: EntityAdminConfig\n allFields: AllFields\n hooks: Behavior['hooks']\n}\n\n/**\n * Extract and intersect behavior field types from a behaviors tuple.\n * Walks the tuple recursively (depth bounded by number of behaviors, max ~5).\n */\ntype ExtractBehaviorFields<B extends Behavior[]> = B extends [\n Behavior<infer F1>,\n ...infer Rest extends Behavior[],\n]\n ? F1 & ExtractBehaviorFields<Rest>\n : // biome-ignore lint/complexity/noBannedTypes: empty object is correct for base case of intersection\n {}\n\n/**\n * Define an entity with full type inference.\n *\n * @example\n * const Article = defineEntity({\n * name: 'article',\n * fields: {\n * title: field.text({ required: true }),\n * featured: field.boolean(),\n * },\n * behaviors: [publishable(), auditable()],\n * })\n *\n * type ArticleDTO = InferEntity<typeof Article>\n * // { id: string; title: string; featured?: boolean | null; status?: ...; createdAt?: ...; }\n */\nexport function defineEntity<\n F extends Record<string, FieldConfig>,\n const B extends Behavior[] = [],\n>(\n definition: EntityDefinition<F> & { behaviors?: B },\n): Entity<{ id: IdField } & ExtractBehaviorFields<B> & F> {\n // Merge behavior fields into main fields\n const behaviorFields: Record<string, FieldConfig> = {}\n const hooks: NonNullable<Behavior['hooks']> = {}\n\n for (const behavior of definition.behaviors || []) {\n // Merge fields from behavior\n if (behavior.fields) {\n for (const [fieldName, fieldConfig] of Object.entries(behavior.fields)) {\n if (behaviorFields[fieldName]) {\n console.warn(\n `Field '${fieldName}' from behavior '${behavior.name}' conflicts with existing field. Skipping.`,\n )\n continue\n }\n behaviorFields[fieldName] = fieldConfig\n }\n }\n\n // Merge hooks from behavior\n if (behavior.hooks) {\n for (const [hookName, hookFn] of Object.entries(behavior.hooks)) {\n const typedHookName = hookName as keyof NonNullable<Behavior['hooks']>\n\n if (hookFn) {\n const existingHook = hooks[typedHookName]\n\n if (existingHook) {\n // Chain hooks: execute existing first, then new one\n const previousHook = existingHook as (...args: unknown[]) => Promise<unknown>\n const currentHook = hookFn as (...args: unknown[]) => Promise<unknown>\n\n const chainedHook = async (...args: unknown[]) => {\n const result = await previousHook(...args)\n if (result !== undefined) {\n // Hook returned modified data — replace last arg (the data param),\n // keep leading args (e.g. id) intact for hooks like beforeUpdate(id, data)\n const nextArgs = [...args]\n nextArgs[nextArgs.length - 1] = result\n return await currentHook(...nextArgs)\n }\n return await currentHook(...args)\n }\n // biome-ignore lint/suspicious/noExplicitAny: dynamic dispatch over heterogeneous hook signatures\n hooks[typedHookName] = chainedHook as any\n } else {\n // biome-ignore lint/suspicious/noExplicitAny: dynamic dispatch over heterogeneous hook signatures\n hooks[typedHookName] = hookFn as any\n }\n }\n }\n }\n }\n\n // Build complete field set\n // Order: id (always first) → behavior fields → user-defined fields\n const allFields: Record<string, FieldConfig> = {\n id: field.id(), // Every entity gets an ID\n ...behaviorFields,\n ...definition.fields,\n }\n\n // Auto-infer translatable slugs: if a slug field's source field is translatable,\n // the slug should be translatable too (each locale gets its own URL-safe slug).\n for (const [, fieldConfig] of Object.entries(allFields)) {\n if (\n fieldConfig.type === 'slug' &&\n !fieldConfig.translatable &&\n allFields[fieldConfig.from]?.translatable\n ) {\n fieldConfig.translatable = true\n }\n }\n\n // The cast through `unknown` is safe: runtime merge order (id + behaviors + user fields)\n // exactly mirrors the type-level intersection. TypeScript cannot verify imperative\n // Object.entries() loops produce the same result as a type-level intersection,\n // so we cast at this single auditable boundary.\n return {\n ...definition,\n allFields,\n hooks,\n } as unknown as Entity<{ id: IdField } & ExtractBehaviorFields<B> & F>\n}\n","/**\n * Error thrown when attempting to delete an entity that is still referenced.\n */\n\nimport type { EntityUsage } from './find-usages.js'\n\nexport class ReferencedEntityError extends Error {\n public readonly entityName: string\n public readonly entityId: string\n public readonly usages: EntityUsage[]\n\n constructor(entityName: string, entityId: string, usages: EntityUsage[]) {\n const count = usages.length\n super(\n `Cannot delete ${entityName} '${entityId}': referenced by ${count} other entit${count === 1 ? 'y' : 'ies'}`,\n )\n this.name = 'ReferencedEntityError'\n this.entityName = entityName\n this.entityId = entityId\n this.usages = usages\n }\n}\n","/**\n * Schema generator\n * Converts entity definitions to Drizzle schemas.\n * Every field gets its own Postgres column — no JSONB blobs.\n */\n\nimport type { PgColumnBuilderBase, PgTable } from 'drizzle-orm/pg-core'\nimport {\n boolean,\n doublePrecision,\n index,\n integer,\n jsonb,\n pgTable,\n text,\n timestamp,\n unique,\n uuid,\n varchar,\n} from 'drizzle-orm/pg-core'\nimport type { Entity } from './define-entity.js'\nimport type { FieldConfig } from './fields/base.js'\n\n// biome-ignore lint/suspicious/noExplicitAny: PgTable<any> is the drizzle convention for parametric tables\ntype AnyTable = PgTable<any>\n\n/**\n * Convert a field config to a Drizzle column.\n *\n * @param nullable - When true, skips notNull and default constraints.\n * Used for translation table columns (translations are partial overrides).\n */\nexport function fieldToColumn(\n fieldName: string,\n fieldConfig: FieldConfig,\n options?: { nullable?: boolean },\n): PgColumnBuilderBase {\n const nullable = options?.nullable ?? false\n\n switch (fieldConfig.type) {\n case 'id':\n return uuid(fieldName).primaryKey().defaultRandom()\n\n case 'text':\n if (fieldConfig.maxLength && fieldConfig.maxLength <= 255) {\n let column = varchar(fieldName, { length: fieldConfig.maxLength })\n if (fieldConfig.unique) column = column.unique()\n if (!nullable && fieldConfig.required) column = column.notNull()\n if (!nullable && fieldConfig.default !== undefined)\n column = column.default(fieldConfig.default as string)\n return column\n } else {\n let column = text(fieldName)\n if (fieldConfig.unique) column = column.unique()\n if (!nullable && fieldConfig.required) column = column.notNull()\n if (!nullable && fieldConfig.default !== undefined)\n column = column.default(fieldConfig.default as string)\n return column\n }\n\n case 'number': {\n let numColumn = fieldConfig.integer ? integer(fieldName) : doublePrecision(fieldName)\n if (!nullable && fieldConfig.required) numColumn = numColumn.notNull()\n if (!nullable && fieldConfig.default !== undefined)\n numColumn = numColumn.default(fieldConfig.default as number)\n return numColumn\n }\n\n case 'boolean': {\n let boolColumn = boolean(fieldName)\n if (!nullable && fieldConfig.required) boolColumn = boolColumn.notNull()\n if (!nullable) {\n const boolDefault =\n fieldConfig.default !== undefined ? (fieldConfig.default as boolean) : false\n boolColumn = boolColumn.default(boolDefault)\n }\n return boolColumn\n }\n\n case 'date': {\n let dateColumn = timestamp(fieldName, { withTimezone: true })\n if (!nullable && fieldConfig.required) dateColumn = dateColumn.notNull()\n if (!nullable && fieldConfig.default !== undefined)\n dateColumn = dateColumn.default(fieldConfig.default as Date)\n return dateColumn\n }\n\n case 'select': {\n let selectColumn = varchar(fieldName, { length: 100 })\n if (!nullable && fieldConfig.required) selectColumn = selectColumn.notNull()\n if (!nullable && fieldConfig.default !== undefined)\n selectColumn = selectColumn.default(fieldConfig.default as string)\n return selectColumn\n }\n\n case 'reference': {\n if (fieldConfig.cardinality === 'many') {\n return uuid(fieldName).array()\n }\n let refColumn = uuid(fieldName)\n if (!nullable && fieldConfig.required) refColumn = refColumn.notNull()\n return refColumn\n }\n\n case 'media': {\n let mediaColumn = uuid(fieldName)\n if (!nullable && fieldConfig.required) mediaColumn = mediaColumn.notNull()\n return mediaColumn\n }\n\n case 'slug': {\n let slugColumn = varchar(fieldName, { length: 255 })\n // For translation tables (nullable=true), skip per-column unique —\n // translatable slugs use composite UNIQUE(slug, locale) at table level instead.\n if (fieldConfig.unique && !nullable) slugColumn = slugColumn.unique()\n if (!nullable && fieldConfig.required) slugColumn = slugColumn.notNull()\n return slugColumn\n }\n\n case 'richtext': {\n // TipTap HTML strings stored as text\n let rtColumn = text(fieldName)\n if (!nullable && fieldConfig.required) rtColumn = rtColumn.notNull()\n return rtColumn\n }\n\n case 'json':\n return jsonb(fieldName)\n\n default:\n return text(fieldName)\n }\n}\n\n/**\n * Generate a runtime Drizzle schema from an entity definition.\n * Every field becomes its own column — no JSONB.\n */\nexport function generateSchema(entity: Entity) {\n const tableName = entity.name\n const columns: Record<string, PgColumnBuilderBase> = {}\n\n for (const [fieldName, fieldConfig] of Object.entries(entity.allFields)) {\n if (fieldConfig.type === 'blocks') continue // stored in layout table\n columns[fieldName] = fieldToColumn(fieldName, fieldConfig)\n }\n\n if (entity.scope === 'team' || entity.scope === 'user') {\n columns._scopeId = uuid('_scope_id')\n }\n\n // Collect fields that need indexes (skip id/unique — they already have btree indexes)\n const indexedFields = Object.entries(entity.allFields).filter(\n ([_, config]) =>\n config.type !== 'blocks' && config.type !== 'id' && config.indexed && !config.unique,\n )\n\n const isPublishableEntity = entity.behaviors?.some((b) => b.name === 'publishable') ?? false\n\n if (indexedFields.length === 0 && !isPublishableEntity) {\n return pgTable(tableName, columns)\n }\n\n return pgTable(tableName, columns, (table) => {\n // biome-ignore lint/suspicious/noExplicitAny: dynamic table columns from pgTable callback\n const constraints: Record<string, any> = {}\n\n for (const [fieldName] of indexedFields) {\n constraints[`idx_${tableName}_${fieldName}`] = index(`idx_${tableName}_${fieldName}`).on(\n table[fieldName],\n )\n }\n\n // Composite index for publishable entities: status + createdAt (most common list query)\n if (isPublishableEntity && table.status && table.createdAt) {\n constraints[`idx_${tableName}_status_created`] = index(`idx_${tableName}_status_created`).on(\n table.status,\n table.createdAt,\n )\n }\n\n return constraints\n })\n}\n\n/**\n * Generate runtime translation table schema.\n * Each translatable field gets its own nullable column.\n *\n * When `parent` is provided, `entityId` gets a `.references()` FK — used\n * by `lumi migrate` so generated SQL includes `REFERENCES parent(id) ON\n * DELETE CASCADE`. Callers that only need the table shape for query\n * building (core/app.ts, content/plugin.ts) can omit `parent`.\n */\nexport function generateTranslationSchema(entity: Entity, parent?: AnyTable) {\n const translatableFields = Object.entries(entity.allFields).filter(\n ([_, config]) => config.translatable,\n )\n\n if (translatableFields.length === 0) return null\n\n const tableName = `${entity.name}_translations`\n const entityIdCol = parent\n ? uuid('entity_id')\n .notNull()\n // biome-ignore lint/suspicious/noExplicitAny: parent is dynamically typed\n .references(() => (parent as any).id, { onDelete: 'cascade' })\n : uuid('entity_id').notNull()\n const columns: Record<string, PgColumnBuilderBase> = {\n id: uuid('id').primaryKey().defaultRandom(),\n entityId: entityIdCol,\n locale: varchar('locale', { length: 10 }).notNull(),\n }\n\n const hasTranslatableSlug = translatableFields.some(([_, config]) => config.type === 'slug')\n\n for (const [fieldName, fieldConfig] of translatableFields) {\n columns[fieldName] = fieldToColumn(fieldName, fieldConfig, { nullable: true })\n }\n\n return pgTable(tableName, columns, (table) => ({\n uniqueEntityLocale: unique().on(table.entityId, table.locale),\n // Per-locale slug uniqueness: no two entities can share the same slug in the same locale\n ...(hasTranslatableSlug && table.slug\n ? { uniqueSlugLocale: unique().on(table.slug, table.locale) }\n : {}),\n }))\n}\n\n/**\n * Check if an entity has any blocks fields\n */\nexport function hasBlocksFields(entity: Entity): boolean {\n return Object.values(entity.allFields).some((f) => f.type === 'blocks')\n}\n\n/**\n * Generate layout table schema for entities with blocks fields.\n * Stores block instances in a separate table with ordering.\n *\n * When blocks field has localized: false (default), locale is NULL (shared layout).\n * When blocks field has localized: true, locale is set per-locale.\n *\n * `parent` is optional — when provided, emits a `.references()` FK (for\n * migration generation); query-runtime callers can omit it.\n */\nexport function generateLayoutSchema(entity: Entity, parent?: AnyTable) {\n if (!hasBlocksFields(entity)) return null\n\n const tableName = `${entity.name}_layout`\n const entityIdCol = parent\n ? uuid('entity_id')\n .notNull()\n // biome-ignore lint/suspicious/noExplicitAny: parent is dynamically typed\n .references(() => (parent as any).id, { onDelete: 'cascade' })\n : uuid('entity_id').notNull()\n\n return pgTable(\n tableName,\n {\n id: uuid('id').primaryKey().defaultRandom(),\n entityId: entityIdCol,\n fieldName: varchar('field_name', { length: 100 }).notNull(),\n blockType: varchar('block_type', { length: 100 }).notNull(),\n sortOrder: integer('sort_order').notNull().default(0),\n data: jsonb('data'),\n locale: varchar('locale', { length: 10 }),\n },\n (table) => ({\n // Covers: WHERE entity_id IN (...) AND locale IS NULL ORDER BY sort_order\n idx_entity_locale_sort: index(`idx_${tableName}_entity_locale_sort`).on(\n table.entityId,\n table.locale,\n table.sortOrder,\n ),\n }),\n )\n}\n\n/**\n * Check if an entity has the versionable behavior\n */\nexport function isVersionable(entity: Entity): boolean {\n return entity.behaviors?.some((b) => b.name === 'versionable') ?? false\n}\n\n/**\n * Check if an entity needs a per-locale publish status table.\n * Requires both publishable() behavior AND at least one translatable field.\n */\nexport function needsLocaleStatus(entity: Entity): boolean {\n const isPublishable = entity.behaviors?.some((b) => b.name === 'publishable') ?? false\n if (!isPublishable) return false\n const allFields = entity.allFields as Record<string, { translatable?: boolean }>\n return Object.values(allFields).some((f) => f.translatable)\n}\n\n/**\n * Check if an entity is publishable (has publishable() behavior).\n */\nexport function isPublishable(entity: Entity): boolean {\n return entity.behaviors?.some((b) => b.name === 'publishable') ?? false\n}\n\n// ---------------------------------------------------------------------------\n// Runtime generators for infrastructure tables attached to an entity.\n//\n// Each one takes the parent entity's runtime `pgTable` so the\n// `.references()` FK is wired. These replace the old `generate*Code()`\n// string helpers that produced source lines to be concatenated into\n// `generated/schema.ts`.\n// ---------------------------------------------------------------------------\n\n/** Per-locale publish status table for publishable + translatable entities. */\nexport function generateLocaleStatusSchema(entity: Entity, parent: AnyTable) {\n const tableName = `${entity.name}_locale_status`\n return pgTable(\n tableName,\n {\n id: uuid('id').primaryKey().defaultRandom(),\n entityId: uuid('entity_id')\n .notNull()\n // biome-ignore lint/suspicious/noExplicitAny: parent is dynamically typed\n .references(() => (parent as any).id, { onDelete: 'cascade' }),\n locale: varchar('locale', { length: 10 }).notNull(),\n status: varchar('status', { length: 20 }).notNull().default('draft'),\n publishedAt: timestamp('published_at', { withTimezone: true }),\n },\n (table) => ({\n uniqueEntityLocale: unique().on(table.entityId, table.locale),\n }),\n )\n}\n\n/** Drafts overlay table for publishable entities. */\nexport function generateDraftsSchema(entity: Entity, parent: AnyTable) {\n const tableName = `${entity.name}_drafts`\n return pgTable(\n tableName,\n {\n id: uuid('id').primaryKey().defaultRandom(),\n entityId: uuid('entity_id')\n .notNull()\n // biome-ignore lint/suspicious/noExplicitAny: parent is dynamically typed\n .references(() => (parent as any).id, { onDelete: 'cascade' }),\n locale: varchar('locale', { length: 10 }).notNull().default('_'),\n data: jsonb('data').notNull(),\n createdBy: varchar('created_by', { length: 255 }).notNull(),\n createdByName: varchar('created_by_name', { length: 255 }),\n createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),\n updatedAt: timestamp('updated_at', { withTimezone: true }).notNull().defaultNow(),\n },\n (table) => ({\n uniqueEntityLocale: unique().on(table.entityId, table.locale),\n }),\n )\n}\n\n/** Versions history table for versionable entities. */\nexport function generateVersionsSchema(entity: Entity, parent: AnyTable) {\n const tableName = `${entity.name}_versions`\n return pgTable(\n tableName,\n {\n id: uuid('id').primaryKey().defaultRandom(),\n entityId: uuid('entity_id')\n .notNull()\n // biome-ignore lint/suspicious/noExplicitAny: parent is dynamically typed\n .references(() => (parent as any).id, { onDelete: 'cascade' }),\n version: integer('version').notNull(),\n locale: varchar('locale', { length: 10 }).notNull().default('_'),\n data: jsonb('data').notNull(),\n delta: jsonb('delta'),\n status: varchar('status', { length: 20 }),\n createdBy: varchar('created_by', { length: 255 }),\n createdByName: varchar('created_by_name', { length: 255 }),\n createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),\n isAutosave: boolean('is_autosave').notNull().default(false),\n },\n (table) => ({\n uniqueEntityVersionLocale: unique().on(table.entityId, table.version, table.locale),\n }),\n )\n}\n\n/**\n * Shared content locks table — one per project, independent of any entity.\n * Included exactly once in `buildRuntimeSchema()` when any entity is publishable.\n */\nexport function generateContentLocksSchema() {\n return pgTable(\n 'toolkit_content_locks',\n {\n id: uuid('id').primaryKey().defaultRandom(),\n entityType: varchar('entity_type', { length: 100 }).notNull(),\n entityId: varchar('entity_id', { length: 255 }).notNull(),\n locale: varchar('locale', { length: 10 }).notNull().default('_'),\n lockedBy: varchar('locked_by', { length: 255 }).notNull(),\n lockedByName: varchar('locked_by_name', { length: 255 }),\n lockedAt: timestamp('locked_at', { withTimezone: true }).notNull().defaultNow(),\n expiresAt: timestamp('expires_at', { withTimezone: true }).notNull(),\n },\n (table) => ({\n uniqueEntityLock: unique().on(table.entityType, table.entityId, table.locale),\n }),\n )\n}\n\n/**\n * Check if an entity has blocks fields with translatable block content (non-localized mode).\n */\nexport function hasTranslatableBlocks(entity: Entity): boolean {\n const allFields = entity.allFields as Record<\n string,\n {\n type: string\n localized?: boolean\n blocks?: Array<{ fields: Record<string, { translatable?: boolean }> }>\n }\n >\n return Object.values(allFields).some((f) => {\n if (f.type !== 'blocks') return false\n if (f.localized) return false\n return f.blocks?.some((block) => Object.values(block.fields).some((bf) => bf.translatable))\n })\n}\n\n/**\n * Generate layout translation table for non-localized blocks with translatable fields.\n *\n * `layoutParent` is optional — when provided, emits a `.references()` FK\n * pointing at the corresponding `{entity}_layout` table (for migration\n * generation).\n */\nexport function generateLayoutTranslationSchema(entity: Entity, layoutParent?: AnyTable) {\n const blocksFields = Object.values(entity.allFields).filter(\n (f) => f.type === 'blocks' && !('localized' in f && f.localized),\n )\n\n if (blocksFields.length === 0) return null\n\n const hasTranslatableBlockFields = blocksFields.some((bf) => {\n if (bf.type !== 'blocks') return false\n return bf.blocks.some((block) => Object.values(block.fields).some((f) => f.translatable))\n })\n\n if (!hasTranslatableBlockFields) return null\n\n const tableName = `${entity.name}_layout_translations`\n const layoutIdCol = layoutParent\n ? uuid('layout_id')\n .notNull()\n // biome-ignore lint/suspicious/noExplicitAny: parent is dynamically typed\n .references(() => (layoutParent as any).id, { onDelete: 'cascade' })\n : uuid('layout_id').notNull()\n\n return pgTable(\n tableName,\n {\n id: uuid('id').primaryKey().defaultRandom(),\n layoutId: layoutIdCol,\n locale: varchar('locale', { length: 10 }).notNull(),\n fields: jsonb('fields').notNull(),\n },\n (table) => ({\n uniqueLayoutLocale: unique().on(table.layoutId, table.locale),\n }),\n )\n}\n\n/**\n * Build the full runtime schema map for a list of entities.\n *\n * Returns a `Record<string, PgTable>` suitable for feeding into\n * `drizzle-kit/api`'s `generateDrizzleJson()`. Includes every table\n * that would have been emitted into `generated/schema.ts` by the old\n * codegen pipeline: main entity, translations, layout, layout\n * translations, versions, drafts, locale status, and the shared\n * content locks table.\n *\n * This is the single entry point used by `lumi migrate` — plugin\n * internal tables are added separately by reading each plugin's\n * `tables` field.\n */\nexport function buildEntitySchemaMap(entities: Entity[]): Record<string, AnyTable> {\n const schema: Record<string, AnyTable> = {}\n let hasAnyPublishable = false\n\n for (const entity of entities) {\n const main = generateSchema(entity)\n schema[entity.name] = main\n\n const translations = generateTranslationSchema(entity, main)\n if (translations) schema[`${entity.name}_translations`] = translations\n\n if (hasBlocksFields(entity)) {\n const layout = generateLayoutSchema(entity, main)\n if (layout) {\n schema[`${entity.name}_layout`] = layout\n const layoutTrans = generateLayoutTranslationSchema(entity, layout)\n if (layoutTrans) schema[`${entity.name}_layout_translations`] = layoutTrans\n }\n }\n\n if (isVersionable(entity)) {\n schema[`${entity.name}_versions`] = generateVersionsSchema(entity, main)\n }\n if (needsLocaleStatus(entity)) {\n schema[`${entity.name}_locale_status`] = generateLocaleStatusSchema(entity, main)\n }\n if (isPublishable(entity)) {\n schema[`${entity.name}_drafts`] = generateDraftsSchema(entity, main)\n hasAnyPublishable = true\n }\n }\n\n if (hasAnyPublishable) {\n schema.toolkit_content_locks = generateContentLocksSchema()\n }\n\n return schema\n}\n"],"mappings":"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"}
@@ -76,6 +76,23 @@ interface EntityAdminConfig {
76
76
  disableCreate?: boolean;
77
77
  /** Order within sidebar group. Default: 0 */
78
78
  sortOrder?: number;
79
+ /**
80
+ * Hide the entity from BOTH dashboard and sidebar.
81
+ * Use for system entities that should not appear in any UI.
82
+ * Shorthand for `hideFromMenu: true` + `hideFromDashboard: true`.
83
+ */
84
+ hidden?: boolean;
85
+ /**
86
+ * Hide from sidebar menu only. Entity remains accessible via dashboard, direct URL,
87
+ * and the entity API. Use for storage models accessed through specialized UI
88
+ * (e.g., Ticket entities accessed via the inbox/board, not as a CRUD table).
89
+ */
90
+ hideFromMenu?: boolean;
91
+ /**
92
+ * Hide from dashboard widget grid only. Entity still appears in sidebar.
93
+ * Use for entities that don't have meaningful counts/stats to show.
94
+ */
95
+ hideFromDashboard?: boolean;
79
96
  }
80
97
  //#endregion
81
98
  //#region src/fields/base.d.ts
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../../src/count-cache.ts","../../src/cursor.ts","../../src/admin-config.ts","../../src/fields/base.ts","../../src/behaviors/types.ts","../../src/define-entity.ts","../../src/types/infer.ts","../../src/types/logger.ts","../../src/query/client.ts"],"mappings":"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"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../../src/count-cache.ts","../../src/cursor.ts","../../src/admin-config.ts","../../src/fields/base.ts","../../src/behaviors/types.ts","../../src/define-entity.ts","../../src/types/infer.ts","../../src/types/logger.ts","../../src/query/client.ts"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@murumets-ee/entity",
3
- "version": "0.1.6",
3
+ "version": "0.2.1",
4
4
  "license": "Elastic-2.0",
5
5
  "type": "module",
6
6
  "exports": {
@@ -28,7 +28,7 @@
28
28
  "drizzle-orm": "^0.45.1",
29
29
  "zod": "^3.24.1",
30
30
  "server-only": "^0.0.1",
31
- "@murumets-ee/db": "0.1.5"
31
+ "@murumets-ee/db": "0.2.0"
32
32
  },
33
33
  "devDependencies": {
34
34
  "tsdown": "^0.21.7",