@lpdjs/firestore-repo-service 2.3.2 → 2.3.3

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.
@@ -29,6 +29,7 @@ interface SyncQueueOptions {
29
29
  declare class SyncQueue {
30
30
  private buffer;
31
31
  private flushing;
32
+ private flushPromise;
32
33
  private timer;
33
34
  private readonly adapter;
34
35
  private readonly tableName;
@@ -43,8 +44,16 @@ declare class SyncQueue {
43
44
  /**
44
45
  * Flush all buffered events to the SQL adapter.
45
46
  * Upserts and deletes are batched separately.
47
+ *
48
+ * Concurrent callers (e.g. several PubSub messages handled in parallel
49
+ * inside the same Cloud Function instance with `concurrency > 1`) all
50
+ * await the same in-flight flush and then trigger a follow-up flush if
51
+ * new events were enqueued in the meantime. This guarantees that every
52
+ * caller's event is persisted before its `await flush()` resolves —
53
+ * which is required for safe PubSub ack semantics.
46
54
  */
47
55
  flush(): Promise<void>;
56
+ private _doFlush;
48
57
  /** Stop the auto-flush timer and flush remaining events. */
49
58
  shutdown(): Promise<void>;
50
59
  }
@@ -29,6 +29,7 @@ interface SyncQueueOptions {
29
29
  declare class SyncQueue {
30
30
  private buffer;
31
31
  private flushing;
32
+ private flushPromise;
32
33
  private timer;
33
34
  private readonly adapter;
34
35
  private readonly tableName;
@@ -43,8 +44,16 @@ declare class SyncQueue {
43
44
  /**
44
45
  * Flush all buffered events to the SQL adapter.
45
46
  * Upserts and deletes are batched separately.
47
+ *
48
+ * Concurrent callers (e.g. several PubSub messages handled in parallel
49
+ * inside the same Cloud Function instance with `concurrency > 1`) all
50
+ * await the same in-flight flush and then trigger a follow-up flush if
51
+ * new events were enqueued in the meantime. This guarantees that every
52
+ * caller's event is persisted before its `await flush()` resolves —
53
+ * which is required for safe PubSub ack semantics.
46
54
  */
47
55
  flush(): Promise<void>;
56
+ private _doFlush;
48
57
  /** Stop the auto-flush timer and flush remaining events. */
49
58
  shutdown(): Promise<void>;
50
59
  }
@@ -81,7 +81,7 @@ ${n}
81
81
  ${d("BigQuery",a.bigquery)}
82
82
  ${d("Pub/Sub",a.pubsub)}
83
83
  ${d("Firestore",a.firestore)}
84
- </div>`);de(w,x);}),async(h,w)=>{await C.handle(h,w);}}var tr="firestore-sync";function nr(e,t){let n=t.ref?.path??void 0;return n?`${n}/{docId}`:(console.warn(`[SyncTriggers] Cannot determine collection path for "${e}". Skipping.`),null)}function Vt(e,t){let{onDocumentCreated:n,onDocumentUpdated:o,onDocumentDeleted:r}=t.deps.firestoreTriggers,s=t.deps.pubsub,l=t?.topicPrefix??tr,u={},c=new Map;function y(C){let h=c.get(C);return h||(h=s.topic(C),c.set(C,h),h)}async function g(C,h){await y(C).publishMessage({json:h});}for(let[C,h]of Object.entries(e)){let w=t?.repos?.[C],v;if(h._isGroup){if(!w?.triggerPath){console.warn(`[SyncTriggers] Skipping collection-group repo "${C}". Provide a triggerPath in the sync repos config for group collections.`);continue}v=w.triggerPath;}else v=w?.triggerPath??nr(C,h);if(!v)continue;let b=h._systemKeys?.[0]??"docId",S=`${l}-${C}`;u[`${C}_onCreate`]=n(v,async p=>{let i=p.data;if(!i)return;let m=i.data();if(!m)return;let a=String(m[b]??i.id),d=Fe(m,{exclude:w?.exclude,columnMap:w?.columnMap}),f={operation:"INSERT",repoName:C,docId:a,data:d,timestamp:new Date().toISOString(),version:Date.now()};await g(S,f);}),u[`${C}_onUpdate`]=o(v,async p=>{let i=p.data?.after;if(!i)return;let m=i.data();if(!m)return;let a=String(m[b]??i.id),d=Fe(m,{exclude:w?.exclude,columnMap:w?.columnMap}),f={operation:"UPSERT",repoName:C,docId:a,data:d,timestamp:new Date().toISOString(),version:Date.now()};await g(S,f);}),u[`${C}_onDelete`]=r(v,async p=>{let i=p.data;if(!i)return;let m=i.data(),a=String(m?.[b]??i.id),d={operation:"DELETE",repoName:C,docId:a,data:null,timestamp:new Date().toISOString(),version:Date.now()};await g(S,d);});}return u}var We=class{constructor(t){this.buffer=[];this.flushing=false;this.timer=null;this.adapter=t.adapter,this.tableName=t.tableName,this.primaryKey=t.primaryKey,this.batchSize=t.batchSize??100,this.onFlushError=t.onFlushError;let n=t.flushIntervalMs??5e3;n>0&&(this.timer=setInterval(()=>{this.flush();},n),typeof this.timer=="object"&&"unref"in this.timer&&this.timer.unref());}get size(){return this.buffer.length}enqueue(...t){this.buffer.push(...t),this.buffer.length>=this.batchSize&&this.flush();}async flush(){if(this.flushing||this.buffer.length===0)return;this.flushing=true;let t=this.buffer.splice(0,this.batchSize);try{let n=new Map,o=[];for(let s of t)if(s.operation==="DELETE")o.push(s.docId),n.delete(s.docId);else if(s.data){let l=n.get(s.docId);if(!l)n.set(s.docId,s.data);else {let u=Number(l[me]??0);Number(s.data[me]??0)>=u&&n.set(s.docId,s.data);}}let r=Array.from(n.values());r.length>0&&await this.adapter.upsertRows(this.tableName,r,this.primaryKey),o.length>0&&await this.adapter.deleteRows(this.tableName,this.primaryKey,o);}catch(n){this.onFlushError?await this.onFlushError(t,n).catch(o=>{console.error(`[SyncQueue] Flush error for ${this.tableName}:`,n),console.error("[SyncQueue] Error handler also failed:",o);}):(this.buffer.unshift(...t),console.error(`[SyncQueue] Flush failed for ${this.tableName}:`,n));}finally{this.flushing=false;}}async shutdown(){this.timer&&(clearInterval(this.timer),this.timer=null),await this.flush();}};var Gt=new Set;async function rr(e,t,n,o,r,s,l){if(Gt.has(e))return;let u=Ge(n,t.dialect,{primaryKey:r,exclude:s,columnMap:l});if(!await t.tableExists(o))await t.createTable({tableName:o,columns:u});else {let y=new Set(await t.getTableColumns(o)),g=u.filter(C=>!y.has(C.name));g.length>0&&await t.addColumns(o,g);}Gt.add(e);}function Jt(e,t){let{deps:n,adapter:o,batchSize:r=100,flushIntervalMs:s=5e3,autoMigrate:l=false,topicPrefix:u="firestore-sync",workerOptions:c,repos:y={}}=t,g=new Map;function C(v,b){let S=g.get(v);if(S)return S;let i=y[v]?.tableName??v,m=async(a,d)=>{console.error(`[SyncWorker] Flush failed for "${v}" (${a.length} events):`,d);try{let f=`${u}-${v}-dlq`,k=n.pubsub.topic(f),[x]=await k.exists();x||(await k.create(),console.info(`[SyncWorker] Created DLQ topic "${f}"`));for(let $ of a)await k.publishMessage({json:$});}catch(f){console.error(`[SyncWorker] Dead-letter publish also failed for ${v}:`,f);}};return S=new We({adapter:o,tableName:i,primaryKey:b,batchSize:r,flushIntervalMs:s,onFlushError:m}),g.set(v,S),S}async function h(v){let{repoName:b}=v,S=e[b];if(!S){console.warn(`[SyncWorker] Unknown repo "${b}", skipping event`);return}let p=S._systemKeys?.[0]??S.documentKey??"docId",i=y[b],m=i?.columnMap,a=m?.[p]??p;if(l){let f=S.schema??void 0;if(f){let k=i?.tableName??b;await rr(b,o,f,k,p,i?.exclude,m);}}let d=C(b,a);v.data&&(v.data[me]=v.version??Date.now()),d.enqueue(v);}function w(v){let b=async S=>{let p=S.data?.message?.json??S.data?.json;if(!p){console.warn("[SyncWorker] Received empty PubSub message");return}await h(p);let i=g.get(p.repoName);i&&await i.flush();};return c?n.pubsubHandler.onMessagePublished({topic:v,...c},b):n.pubsubHandler.onMessagePublished(v,b)}return {handleMessage:h,createHandler:w,queues:g,async shutdown(){let v=[];for(let b of g.values())v.push(b.shutdown());await Promise.all(v);}}}var or="firestore-sync";function Wt(e){if(typeof e!="function")return e;let t=e,n;return new Proxy({},{get(o,r){return n||(n=t()),n[r]},has(o,r){return n||(n=t()),r in n}})}function Qt(e,t){let{deps:n,adapter:o,topicPrefix:r=or,batchSize:s,flushIntervalMs:l,autoMigrate:u,admin:c,workerOptions:y,repos:g}=t,C=Wt(n.pubsub),h=Wt(o),w=Vt(e,{deps:{firestoreTriggers:n.firestoreTriggers,pubsub:C},topicPrefix:r,repos:g}),v=Jt(e,{deps:{pubsubHandler:n.pubsubHandler,pubsub:C},adapter:h,batchSize:s,flushIntervalMs:l,autoMigrate:u,topicPrefix:r,workerOptions:y,repos:g}),b={};for(let i of Object.keys(e))b[`sync_${i}`]=v.createHandler(`${r}-${i}`);let S=null;c&&(S=Kt(e,h,v.queues,v.handleMessage,c,g??{},C,r),b.adminsync=c.onRequest?c.httpsOptions?c.onRequest(c.httpsOptions,S):c.onRequest(S):S);let p={functions:{...w,...b},adminHandler:S,handleMessage:v.handleMessage,queues:v.queues,shutdown:v.shutdown};for(let i of ["adminHandler","handleMessage","queues","shutdown"])Object.defineProperty(p,i,{enumerable:false});return p}je();je();function sr(e){return e.replace(/([A-Z])/g," $1").replace(/_/g," ").replace(/^\s/,"").replace(/^./,t=>t.toUpperCase())}function Xt(e){let t=e,n=true,o=false,r;for(;;){let s=H(t);if(s==="ZodOptional")n=false,t=G(t);else if(s==="ZodNullable")n=false,o=true,t=G(t);else if(s==="ZodDefault")n=false,r=Mt(t),t=G(t);else break}return {inner:t,required:n,nullable:o,defaultValue:r}}function ae(e,t=""){if(H(e)==="ZodObject"){let o=te(e);return Object.entries(o).map(([r,s])=>Yt(t?`${t}.${r}`:r,r,s))}return [Yt(t||"value",t||"value",e)]}function Yt(e,t,n){let{inner:o,required:r,nullable:s,defaultValue:l}=Xt(n),u=H(o),c=sr(t.split(".").pop()??t);switch(u){case "ZodString":{let y=qt(o),g=y.includes("email"),C=y.includes("url");return {name:e,label:c,type:"text",required:r,nullable:s,defaultValue:l,hint:g?"email":C?"url":void 0}}case "ZodNumber":case "ZodBigInt":return {name:e,label:c,type:"number",required:r,nullable:s,defaultValue:l};case "ZodBoolean":return {name:e,label:c,type:"checkbox",required:r,nullable:s,defaultValue:l};case "ZodDate":case "ZodCoerce":return {name:e,label:c,type:"datetime-local",required:r,nullable:s,defaultValue:l};case "ZodEnum":{let y=_e(o);return {name:e,label:c,type:"select",required:r,nullable:s,defaultValue:l,options:y}}case "ZodNativeEnum":{let y=De(o),g=Object.values(y).filter(C=>typeof C=="string");return {name:e,label:c,type:"select",required:r,nullable:s,defaultValue:l,options:g}}case "ZodLiteral":{let y=String(Ve(o)??"");return {name:e,label:c,type:"select",required:r,nullable:s,defaultValue:l,options:[y]}}case "ZodObject":{let y=ae(o,e);return {name:e,label:c,type:"textarea",required:r,nullable:s,defaultValue:l,nested:y,hint:"JSON object"}}case "ZodArray":{let y=Bt(o);if(!y)return {name:e,label:c,type:"textarea",required:r,nullable:s,defaultValue:l,hint:"JSON array"};let{inner:g}=Xt(y),C=H(g),h,w,v;switch(C){case "ZodString":h="text";break;case "ZodNumber":case "ZodBigInt":h="number";break;case "ZodBoolean":h="checkbox";break;case "ZodDate":h="datetime-local";break;case "ZodEnum":h="select",w=_e(g);break;case "ZodNativeEnum":h="select",w=Object.values(De(g)).filter(b=>typeof b=="string");break;case "ZodObject":h="object",v=ae(g);break;default:return {name:e,label:c,type:"textarea",required:r,nullable:s,defaultValue:l,hint:"JSON array"}}return {name:e,label:c,type:"textarea",required:r,nullable:s,defaultValue:l,arrayElementType:h,arrayElementOptions:w,arrayElementFields:v}}default:return {name:e,label:c,type:"textarea",required:r,nullable:s,defaultValue:l,hint:"JSON"}}}function ot(e,t=0){let n=t>0?`ml-${t*4}`:"",o=`field_${e.name.replace(/\./g,"__")}`,r=e.name,s=e.required?" required":"",l=e.defaultValue==="__null__",u=!l&&e.defaultValue!=null?String(e.defaultValue):"",c=e.nullable&&e.type!=="checkbox"?`<span class="flex items-center gap-1 shrink-0">
84
+ </div>`);de(w,x);}),async(h,w)=>{await C.handle(h,w);}}var tr="firestore-sync";function nr(e,t){let n=t.ref?.path??void 0;return n?`${n}/{docId}`:(console.warn(`[SyncTriggers] Cannot determine collection path for "${e}". Skipping.`),null)}function Vt(e,t){let{onDocumentCreated:n,onDocumentUpdated:o,onDocumentDeleted:r}=t.deps.firestoreTriggers,s=t.deps.pubsub,l=t?.topicPrefix??tr,u={},c=new Map;function y(C){let h=c.get(C);return h||(h=s.topic(C),c.set(C,h),h)}async function g(C,h){await y(C).publishMessage({json:h});}for(let[C,h]of Object.entries(e)){let w=t?.repos?.[C],v;if(h._isGroup){if(!w?.triggerPath){console.warn(`[SyncTriggers] Skipping collection-group repo "${C}". Provide a triggerPath in the sync repos config for group collections.`);continue}v=w.triggerPath;}else v=w?.triggerPath??nr(C,h);if(!v)continue;let b=h._systemKeys?.[0]??"docId",S=`${l}-${C}`;u[`${C}_onCreate`]=n(v,async p=>{let i=p.data;if(!i)return;let m=i.data();if(!m)return;let a=String(m[b]??i.id),d=Fe(m,{exclude:w?.exclude,columnMap:w?.columnMap}),f={operation:"INSERT",repoName:C,docId:a,data:d,timestamp:new Date().toISOString(),version:Date.now()};await g(S,f);}),u[`${C}_onUpdate`]=o(v,async p=>{let i=p.data?.after;if(!i)return;let m=i.data();if(!m)return;let a=String(m[b]??i.id),d=Fe(m,{exclude:w?.exclude,columnMap:w?.columnMap}),f={operation:"UPSERT",repoName:C,docId:a,data:d,timestamp:new Date().toISOString(),version:Date.now()};await g(S,f);}),u[`${C}_onDelete`]=r(v,async p=>{let i=p.data;if(!i)return;let m=i.data(),a=String(m?.[b]??i.id),d={operation:"DELETE",repoName:C,docId:a,data:null,timestamp:new Date().toISOString(),version:Date.now()};await g(S,d);});}return u}var We=class{constructor(t){this.buffer=[];this.flushing=false;this.flushPromise=null;this.timer=null;this.adapter=t.adapter,this.tableName=t.tableName,this.primaryKey=t.primaryKey,this.batchSize=t.batchSize??100,this.onFlushError=t.onFlushError;let n=t.flushIntervalMs??5e3;n>0&&(this.timer=setInterval(()=>{this.flush();},n),typeof this.timer=="object"&&"unref"in this.timer&&this.timer.unref());}get size(){return this.buffer.length}enqueue(...t){this.buffer.push(...t),this.buffer.length>=this.batchSize&&this.flush();}async flush(){for(;this.flushing&&this.flushPromise;)await this.flushPromise;this.buffer.length!==0&&(this.flushing=true,this.flushPromise=this._doFlush().finally(()=>{this.flushing=false,this.flushPromise=null;}),await this.flushPromise);}async _doFlush(){let t=this.buffer.splice(0,this.batchSize);try{let n=new Map,o=[];for(let s of t)if(s.operation==="DELETE")o.push(s.docId),n.delete(s.docId);else if(s.data){let l=n.get(s.docId);if(!l)n.set(s.docId,s.data);else {let u=Number(l[me]??0);Number(s.data[me]??0)>=u&&n.set(s.docId,s.data);}}let r=Array.from(n.values());r.length>0&&await this.adapter.upsertRows(this.tableName,r,this.primaryKey),o.length>0&&await this.adapter.deleteRows(this.tableName,this.primaryKey,o);}catch(n){this.onFlushError?await this.onFlushError(t,n):(this.buffer.unshift(...t),console.error(`[SyncQueue] Flush failed for ${this.tableName}:`,n));}}async shutdown(){this.timer&&(clearInterval(this.timer),this.timer=null),await this.flush();}};var Gt=new Set;async function rr(e,t,n,o,r,s,l){if(Gt.has(e))return;let u=Ge(n,t.dialect,{primaryKey:r,exclude:s,columnMap:l});if(!await t.tableExists(o))await t.createTable({tableName:o,columns:u});else {let y=new Set(await t.getTableColumns(o)),g=u.filter(C=>!y.has(C.name));g.length>0&&await t.addColumns(o,g);}Gt.add(e);}function Jt(e,t){let{deps:n,adapter:o,batchSize:r=100,flushIntervalMs:s=5e3,autoMigrate:l=false,topicPrefix:u="firestore-sync",workerOptions:c,repos:y={}}=t,g=new Map;function C(v,b){let S=g.get(v);if(S)return S;let i=y[v]?.tableName??v,m=async(a,d)=>{console.error(`[SyncWorker] Flush failed for "${v}" (${a.length} events):`,d);let f=`${u}-${v}-dlq`,k=n.pubsub.topic(f),[x]=await k.exists();x||(await k.create(),console.info(`[SyncWorker] Created DLQ topic "${f}"`));for(let $ of a)await k.publishMessage({json:$});};return S=new We({adapter:o,tableName:i,primaryKey:b,batchSize:r,flushIntervalMs:s,onFlushError:m}),g.set(v,S),S}async function h(v){let{repoName:b}=v,S=e[b];if(!S){console.warn(`[SyncWorker] Unknown repo "${b}", skipping event`);return}let p=S._systemKeys?.[0]??S.documentKey??"docId",i=y[b],m=i?.columnMap,a=m?.[p]??p;if(l){let f=S.schema??void 0;if(f){let k=i?.tableName??b;await rr(b,o,f,k,p,i?.exclude,m);}}let d=C(b,a);v.data&&(v.data[me]=v.version??Date.now()),d.enqueue(v);}function w(v){let b=async S=>{let p=S.data?.message?.json??S.data?.json;if(!p){console.warn("[SyncWorker] Received empty PubSub message");return}await h(p);let i=g.get(p.repoName);i&&await i.flush();};return c?n.pubsubHandler.onMessagePublished({topic:v,...c},b):n.pubsubHandler.onMessagePublished(v,b)}return {handleMessage:h,createHandler:w,queues:g,async shutdown(){let v=[];for(let b of g.values())v.push(b.shutdown());await Promise.all(v);}}}var or="firestore-sync";function Wt(e){if(typeof e!="function")return e;let t=e,n;return new Proxy({},{get(o,r){return n||(n=t()),n[r]},has(o,r){return n||(n=t()),r in n}})}function Qt(e,t){let{deps:n,adapter:o,topicPrefix:r=or,batchSize:s,flushIntervalMs:l,autoMigrate:u,admin:c,workerOptions:y,repos:g}=t,C=Wt(n.pubsub),h=Wt(o),w=Vt(e,{deps:{firestoreTriggers:n.firestoreTriggers,pubsub:C},topicPrefix:r,repos:g}),v=Jt(e,{deps:{pubsubHandler:n.pubsubHandler,pubsub:C},adapter:h,batchSize:s,flushIntervalMs:l,autoMigrate:u,topicPrefix:r,workerOptions:y,repos:g}),b={};for(let i of Object.keys(e))b[`sync_${i}`]=v.createHandler(`${r}-${i}`);let S=null;c&&(S=Kt(e,h,v.queues,v.handleMessage,c,g??{},C,r),b.adminsync=c.onRequest?c.httpsOptions?c.onRequest(c.httpsOptions,S):c.onRequest(S):S);let p={functions:{...w,...b},adminHandler:S,handleMessage:v.handleMessage,queues:v.queues,shutdown:v.shutdown};for(let i of ["adminHandler","handleMessage","queues","shutdown"])Object.defineProperty(p,i,{enumerable:false});return p}je();je();function sr(e){return e.replace(/([A-Z])/g," $1").replace(/_/g," ").replace(/^\s/,"").replace(/^./,t=>t.toUpperCase())}function Xt(e){let t=e,n=true,o=false,r;for(;;){let s=H(t);if(s==="ZodOptional")n=false,t=G(t);else if(s==="ZodNullable")n=false,o=true,t=G(t);else if(s==="ZodDefault")n=false,r=Mt(t),t=G(t);else break}return {inner:t,required:n,nullable:o,defaultValue:r}}function ae(e,t=""){if(H(e)==="ZodObject"){let o=te(e);return Object.entries(o).map(([r,s])=>Yt(t?`${t}.${r}`:r,r,s))}return [Yt(t||"value",t||"value",e)]}function Yt(e,t,n){let{inner:o,required:r,nullable:s,defaultValue:l}=Xt(n),u=H(o),c=sr(t.split(".").pop()??t);switch(u){case "ZodString":{let y=qt(o),g=y.includes("email"),C=y.includes("url");return {name:e,label:c,type:"text",required:r,nullable:s,defaultValue:l,hint:g?"email":C?"url":void 0}}case "ZodNumber":case "ZodBigInt":return {name:e,label:c,type:"number",required:r,nullable:s,defaultValue:l};case "ZodBoolean":return {name:e,label:c,type:"checkbox",required:r,nullable:s,defaultValue:l};case "ZodDate":case "ZodCoerce":return {name:e,label:c,type:"datetime-local",required:r,nullable:s,defaultValue:l};case "ZodEnum":{let y=_e(o);return {name:e,label:c,type:"select",required:r,nullable:s,defaultValue:l,options:y}}case "ZodNativeEnum":{let y=De(o),g=Object.values(y).filter(C=>typeof C=="string");return {name:e,label:c,type:"select",required:r,nullable:s,defaultValue:l,options:g}}case "ZodLiteral":{let y=String(Ve(o)??"");return {name:e,label:c,type:"select",required:r,nullable:s,defaultValue:l,options:[y]}}case "ZodObject":{let y=ae(o,e);return {name:e,label:c,type:"textarea",required:r,nullable:s,defaultValue:l,nested:y,hint:"JSON object"}}case "ZodArray":{let y=Bt(o);if(!y)return {name:e,label:c,type:"textarea",required:r,nullable:s,defaultValue:l,hint:"JSON array"};let{inner:g}=Xt(y),C=H(g),h,w,v;switch(C){case "ZodString":h="text";break;case "ZodNumber":case "ZodBigInt":h="number";break;case "ZodBoolean":h="checkbox";break;case "ZodDate":h="datetime-local";break;case "ZodEnum":h="select",w=_e(g);break;case "ZodNativeEnum":h="select",w=Object.values(De(g)).filter(b=>typeof b=="string");break;case "ZodObject":h="object",v=ae(g);break;default:return {name:e,label:c,type:"textarea",required:r,nullable:s,defaultValue:l,hint:"JSON array"}}return {name:e,label:c,type:"textarea",required:r,nullable:s,defaultValue:l,arrayElementType:h,arrayElementOptions:w,arrayElementFields:v}}default:return {name:e,label:c,type:"textarea",required:r,nullable:s,defaultValue:l,hint:"JSON"}}}function ot(e,t=0){let n=t>0?`ml-${t*4}`:"",o=`field_${e.name.replace(/\./g,"__")}`,r=e.name,s=e.required?" required":"",l=e.defaultValue==="__null__",u=!l&&e.defaultValue!=null?String(e.defaultValue):"",c=e.nullable&&e.type!=="checkbox"?`<span class="flex items-center gap-1 shrink-0">
85
85
  <input type="hidden" id="${o}__isnull" name="${r}__isnull" value="${l?"1":""}">
86
86
  <label class="flex items-center gap-1 cursor-pointer select-none text-xs text-base-content/40 hover:text-base-content/70 border border-base-300 rounded px-2 py-1">
87
87
  <input type="checkbox" class="checkbox checkbox-xs" ${l?"checked":""}