@shiftengineering/folio 0.1.4 → 0.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -26,7 +26,7 @@ This package exports three main features:
26
26
  - `useFolioFiles` - Get files for a project
27
27
  - `useAddFolioProject` - Create new projects
28
28
  - `useAddFolioFiles` - Add files to a project
29
- - `useAddFolioDirectoryWithFiles` - Add directories with files to a project
29
+ - `useAddFolioDirectoriesWithFiles` - Add directories with files to a project
30
30
 
31
31
  ### Basic Setup
32
32
 
@@ -79,8 +79,9 @@ import {
79
79
  useFolioFiles,
80
80
  useAddFolioProject,
81
81
  useAddFolioFiles,
82
- useAddFolioDirectoryWithFiles,
82
+ useAddFolioDirectoriesWithFiles,
83
83
  type DirectoryEntry,
84
+ type MetadataValue,
84
85
  } from "@shiftengineering/folio";
85
86
  import { useState } from "react";
86
87
 
@@ -105,8 +106,8 @@ function FolioProjectManager() {
105
106
  useAddFolioFiles(selectedProjectId);
106
107
 
107
108
  // Add directories with files to a project
108
- const { addDirectoryWithFiles, isAdding: isAddingDirectory } =
109
- useAddFolioDirectoryWithFiles(selectedProjectId);
109
+ const { addDirectoriesWithFiles, isAdding: isAddingDirectory } =
110
+ useAddFolioDirectoriesWithFiles(selectedProjectId);
110
111
 
111
112
  const handleCreateProject = () => {
112
113
  addProject("My New Project");
@@ -117,10 +118,19 @@ function FolioProjectManager() {
117
118
  };
118
119
 
119
120
  const handleAddSingleDirectory = () => {
120
- // Create a metadata map
121
- const metadata = new Map<string, string>();
122
- metadata.set("category", "reports");
123
- metadata.set("owner", "John Doe");
121
+ // Create metadata with nested structure
122
+ const metadata = {
123
+ category: "reports",
124
+ details: {
125
+ owner: "John Doe",
126
+ department: "Finance",
127
+ tags: ["important", "quarterly"],
128
+ },
129
+ status: {
130
+ reviewed: true,
131
+ approvalDate: "2023-10-15"
132
+ }
133
+ };
124
134
 
125
135
  const directoryEntry: DirectoryEntry = {
126
136
  directoryName: "My Documents",
@@ -131,16 +141,32 @@ function FolioProjectManager() {
131
141
  ],
132
142
  };
133
143
 
134
- addDirectoryWithFiles(directoryEntry);
144
+ addDirectoriesWithFiles(directoryEntry);
135
145
  };
136
146
 
137
147
  const handleAddMultipleDirectories = () => {
138
- // Create metadata maps for each directory
139
- const metadata1 = new Map<string, string>();
140
- metadata1.set("category", "reports");
148
+ // Create metadata for each directory with nested structures
149
+ const metadata1 = {
150
+ category: "reports",
151
+ details: {
152
+ owner: "Jane Smith",
153
+ department: "Accounting",
154
+ tags: ["quarterly", "financial"]
155
+ }
156
+ };
141
157
 
142
- const metadata2 = new Map<string, string>();
143
- metadata2.set("category", "contracts");
158
+ const metadata2 = {
159
+ category: "contracts",
160
+ details: {
161
+ owner: "Legal Team",
162
+ priority: "high",
163
+ clients: ["Acme Inc", "Globex Corp"]
164
+ },
165
+ approvalChain: {
166
+ legalApproved: true,
167
+ executiveApproved: false
168
+ }
169
+ };
144
170
 
145
171
  const directories: DirectoryEntry[] = [
146
172
  {
@@ -161,7 +187,7 @@ function FolioProjectManager() {
161
187
  },
162
188
  ];
163
189
 
164
- addDirectoryWithFiles(directories);
190
+ addDirectoriesWithFiles(directories);
165
191
  };
166
192
 
167
193
  if (isProjectsLoading) return <div>Loading projects...</div>;
@@ -294,30 +320,31 @@ Hook for adding files to a project. Files are always created at the root level (
294
320
  | `error` | `Error \| null` | Error object if an error occurred |
295
321
  | `newFiles` | `FolioFile[] \| undefined` | The newly added files if available |
296
322
 
297
- #### `useAddFolioDirectoryWithFiles(projectId?: number)`
323
+ #### `useAddFolioDirectoriesWithFiles(projectId?: number)`
298
324
 
299
325
  Hook for adding one or more directories with files to a project. Directory names must be unique at the root level (duplicates will be silently skipped with a console warning).
300
326
 
301
- | Return Property | Type | Description |
302
- | ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------ |
303
- | `addDirectoryWithFiles` | `(params: DirectoryEntry \| DirectoryEntry[]) => void` | Function to add one or more directories with files |
304
- | `addDirectoryWithFilesAsync` | `(params: DirectoryEntry \| DirectoryEntry[]) => Promise<{ directory: FolioFile \| null; files: FolioFile[] } \| Array<{ directory: FolioFile \| null; files: FolioFile[] }>>` | Async version returning a promise. Returns a single result when given a single directory, or an array of results when given multiple directories |
305
- | `isAdding` | `boolean` | Whether the directories and files are being added |
306
- | `isError` | `boolean` | Whether an error occurred |
307
- | `error` | `Error \| null` | Error object if an error occurred |
308
- | `result` | `{ directory: FolioFile \| null; files: FolioFile[] } \| Array<{ directory: FolioFile \| null; files: FolioFile[] }> \| undefined` | The newly added directories and files. If a directory is null in a result, it means a directory with that name already existed |
327
+ | Return Property | Type | Description |
328
+ | ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------ |
329
+ | `addDirectoriesWithFiles` | `(params: DirectoryEntry \| DirectoryEntry[]) => void` | Function to add one or more directories with files |
330
+ | `addDirectoriesWithFilesAsync` | `(params: DirectoryEntry \| DirectoryEntry[]) => Promise<{ directory: FolioFile \| null; files: FolioFile[] } \| Array<{ directory: FolioFile \| null; files: FolioFile[] }>>` | Async version returning a promise. Returns a single result when given a single directory, or an array of results when given multiple directories |
331
+ | `isAdding` | `boolean` | Whether the directories and files are being added |
332
+ | `isError` | `boolean` | Whether an error occurred |
333
+ | `error` | `Error \| null` | Error object if an error occurred |
334
+ | `result` | `{ directory: FolioFile \| null; files: FolioFile[] } \| Array<{ directory: FolioFile \| null; files: FolioFile[] }> \| undefined` | The newly added directories and files. If a directory is null in a result, it means a directory with that name already existed |
309
335
 
310
336
  ## Types
311
337
 
312
338
  The library exports these TypeScript types:
313
339
 
314
- | Type | Description |
315
- | -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
316
- | `FolioFile` | Represents a file in Folio. Contains properties: `id`, `name`, `blobUrl`, `parentId` (null for root items), and `isDirectory` (boolean) |
317
- | `FolioProject` | Represents a project in Folio |
318
- | `DirectoryEntry` | Represents a directory with metadata and files to be added to Folio. Contains properties: `directoryName`, `directoryMetadata` (Map<string, string>), and `files` |
319
- | `FolioEmbedProps` | Props for the FolioEmbed component |
320
- | `FolioProviderProps` | Props for the FolioProvider component |
340
+ | Type | Description |
341
+ | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
342
+ | `FolioFile` | Represents a file in Folio. Contains properties: `id`, `name`, `blobUrl`, `parentId` (null for root items), and `isDirectory` (boolean) |
343
+ | `FolioProject` | Represents a project in Folio |
344
+ | `MetadataValue` | Represents metadata values that can be nested. Can be a string, number, boolean, null, object, or array of these types |
345
+ | `DirectoryEntry` | Represents a directory with metadata and files to be added to Folio. Contains properties: `directoryName`, `directoryMetadata` (now supports nested objects), and `files` |
346
+ | `FolioEmbedProps` | Props for the FolioEmbed component |
347
+ | `FolioProviderProps` | Props for the FolioProvider component |
321
348
 
322
349
  ## License
323
350
 
@@ -4258,9 +4258,7 @@ function na(t) {
4258
4258
  if (!t) throw new Error("Project ID is required");
4259
4259
  const a = Array.isArray(s) ? s : [s], u = [];
4260
4260
  for (const l of a) {
4261
- const c = JSON.stringify(
4262
- Object.fromEntries(l.directoryMetadata)
4263
- ), d = await e.addDirectoryWithFilesToProject(
4261
+ const c = JSON.stringify(l.directoryMetadata), d = await e.addDirectoryWithFilesToProject(
4264
4262
  t,
4265
4263
  l.directoryName,
4266
4264
  c,
@@ -4275,8 +4273,8 @@ function na(t) {
4275
4273
  }
4276
4274
  });
4277
4275
  return {
4278
- addDirectoryWithFiles: n.mutate,
4279
- addDirectoryWithFilesAsync: n.mutateAsync,
4276
+ addDirectoriesWithFiles: n.mutate,
4277
+ addDirectoriesWithFilesAsync: n.mutateAsync,
4280
4278
  isAdding: n.isPending,
4281
4279
  isError: n.isError,
4282
4280
  error: n.error,
@@ -4286,7 +4284,7 @@ function na(t) {
4286
4284
  export {
4287
4285
  Xo as FolioEmbed,
4288
4286
  Jo as FolioProvider,
4289
- na as useAddFolioDirectoryWithFiles,
4287
+ na as useAddFolioDirectoriesWithFiles,
4290
4288
  ra as useAddFolioFiles,
4291
4289
  ta as useAddFolioProject,
4292
4290
  ea as useFolioFiles,
@@ -31,4 +31,4 @@ React keys must be passed directly to JSX without using spread:
31
31
  background-color: #${e==="up"?d:h};
32
32
  color: ${e==="up"?"black":"white"};
33
33
  padding: 2px;
34
- `;l.push("%c",e==="up"?">>":"<<",r,`#${a}`,`%c${s}%c`,"%O"),c.push(f,`${f}; font-weight: bold;`,`${f}; font-weight: normal;`)}return e==="up"?c.push(n?{input:u,context:t.context}:{input:u}):c.push({input:u,result:t.result,elapsedMs:t.elapsedMs,...n&&{context:t.context}}),{parts:l,args:c}}const Ai=({c:t=console,colorMode:e="css",withContext:r})=>n=>{const s=n.input,a=Fi(s)?Object.fromEntries(s):s,{parts:u,args:l}=xi({...n,colorMode:e,input:a,withContext:r}),c=n.direction==="down"&&n.result&&(n.result instanceof Error||"error"in n.result.result&&n.result.result.error)?"error":"log";t[c].apply(null,[u.join(" ")].concat(l))};function Di(t={}){const{enabled:e=()=>!0}=t,r=t.colorMode??(typeof window>"u"?"ansi":"css"),n=t.withContext??r==="css",{logger:s=Ai({c:t.console,colorMode:r,withContext:n})}=t;return()=>({op:a,next:u})=>Be(l=>{e({...a,direction:"up"})&&s({...a,direction:"up"});const c=Date.now();function d(h){const f=Date.now()-c;e({...a,direction:"down",result:h})&&s({...a,direction:"down",elapsedMs:f,result:h})}return u(a).pipe(Zs({next(h){d(h)},error(h){d(h)}})).subscribe(l)})}const _i=(t,...e)=>typeof t=="function"?t(...e):t;function Ii(){let t,e;return{promise:new Promise((n,s)=>{t=n,e=s}),resolve:t,reject:e}}async function ki(t){const e=await _i(t.url);if(!t.connectionParams)return e;const n=`${e.includes("?")?"&":"?"}connectionParams=1`;return e+n}function ke(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}function ji(t){const{promise:e,resolve:r,reject:n}=Ii();return t.addEventListener("open",()=>{t.removeEventListener("error",n),r()}),t.addEventListener("error",n),e}function qi(t,{intervalMs:e,pongTimeoutMs:r}){let n,s;function a(){n=setTimeout(()=>{t.send("PING"),s=setTimeout(()=>{t.close()},r)},e)}function u(){clearTimeout(n),a()}function l(){clearTimeout(s),u()}t.addEventListener("open",a),t.addEventListener("message",({data:c})=>{clearTimeout(n),a(),c==="PONG"&&l()}),t.addEventListener("close",()=>{clearTimeout(n),clearTimeout(s)})}class Mt{get ws(){return this.wsObservable.get()}set ws(e){this.wsObservable.next(e)}isOpen(){return!!this.ws&&this.ws.readyState===this.WebSocketPonyfill.OPEN}isClosed(){return!!this.ws&&(this.ws.readyState===this.WebSocketPonyfill.CLOSING||this.ws.readyState===this.WebSocketPonyfill.CLOSED)}async open(){if(this.openPromise)return this.openPromise;this.id=++Mt.connectCount;const e=ki(this.urlOptions).then(r=>new this.WebSocketPonyfill(r));this.openPromise=e.then(ji),this.ws=await e,this.ws.addEventListener("message",function({data:r}){r==="PING"&&this.send("PONG")}),this.keepAliveOpts.enabled&&qi(this.ws,this.keepAliveOpts),this.ws.addEventListener("close",()=>{this.ws=null});try{await this.openPromise}finally{this.openPromise=null}}async close(){var e;try{await this.openPromise}finally{(e=this.ws)==null||e.close()}}constructor(e){if(ke(this,"id",++Mt.connectCount),ke(this,"WebSocketPonyfill",void 0),ke(this,"urlOptions",void 0),ke(this,"keepAliveOpts",void 0),ke(this,"wsObservable",ei(null)),ke(this,"openPromise",null),this.WebSocketPonyfill=e.WebSocketPonyfill??WebSocket,!this.WebSocketPonyfill)throw new Error("No WebSocket implementation found - you probably don't want to use this on the server, but if you do you need to pass a `WebSocket`-ponyfill");this.urlOptions=e.urlOptions,this.keepAliveOpts=e.keepAlive}}ke(Mt,"connectCount",0);class Ui{constructor(){this.keyToValue=new Map,this.valueToKey=new Map}set(e,r){this.keyToValue.set(e,r),this.valueToKey.set(r,e)}getByKey(e){return this.keyToValue.get(e)}getByValue(e){return this.valueToKey.get(e)}clear(){this.keyToValue.clear(),this.valueToKey.clear()}}class fn{constructor(e){this.generateIdentifier=e,this.kv=new Ui}register(e,r){this.kv.getByValue(e)||(r||(r=this.generateIdentifier(e)),this.kv.set(r,e))}clear(){this.kv.clear()}getIdentifier(e){return this.kv.getByValue(e)}getValue(e){return this.kv.getByKey(e)}}class Mi extends fn{constructor(){super(e=>e.name),this.classToAllowedProps=new Map}register(e,r){typeof r=="object"?(r.allowProps&&this.classToAllowedProps.set(e,r.allowProps),super.register(e,r.identifier)):super.register(e,r)}getAllowedProps(e){return this.classToAllowedProps.get(e)}}function Ni(t){if("values"in Object)return Object.values(t);const e=[];for(const r in t)t.hasOwnProperty(r)&&e.push(t[r]);return e}function Li(t,e){const r=Ni(t);if("find"in r)return r.find(e);const n=r;for(let s=0;s<n.length;s++){const a=n[s];if(e(a))return a}}function Ge(t,e){Object.entries(t).forEach(([r,n])=>e(n,r))}function Nt(t,e){return t.indexOf(e)!==-1}function hn(t,e){for(let r=0;r<t.length;r++){const n=t[r];if(e(n))return n}}class Qi{constructor(){this.transfomers={}}register(e){this.transfomers[e.name]=e}findApplicable(e){return Li(this.transfomers,r=>r.isApplicable(e))}findByName(e){return this.transfomers[e]}}const $i=t=>Object.prototype.toString.call(t).slice(8,-1),dn=t=>typeof t>"u",Ki=t=>t===null,wt=t=>typeof t!="object"||t===null||t===Object.prototype?!1:Object.getPrototypeOf(t)===null?!0:Object.getPrototypeOf(t)===Object.prototype,cr=t=>wt(t)&&Object.keys(t).length===0,be=t=>Array.isArray(t),Vi=t=>typeof t=="string",zi=t=>typeof t=="number"&&!isNaN(t),Hi=t=>typeof t=="boolean",Wi=t=>t instanceof RegExp,Et=t=>t instanceof Map,Ot=t=>t instanceof Set,yn=t=>$i(t)==="Symbol",Bi=t=>t instanceof Date&&!isNaN(t.valueOf()),Gi=t=>t instanceof Error,pn=t=>typeof t=="number"&&isNaN(t),Yi=t=>Hi(t)||Ki(t)||dn(t)||zi(t)||Vi(t)||yn(t),Ji=t=>typeof t=="bigint",Xi=t=>t===1/0||t===-1/0,Zi=t=>ArrayBuffer.isView(t)&&!(t instanceof DataView),eo=t=>t instanceof URL,mn=t=>t.replace(/\./g,"\\."),lr=t=>t.map(String).map(mn).join("."),Pt=t=>{const e=[];let r="";for(let s=0;s<t.length;s++){let a=t.charAt(s);if(a==="\\"&&t.charAt(s+1)==="."){r+=".",s++;continue}if(a==="."){e.push(r),r="";continue}r+=a}const n=r;return e.push(n),e};function ue(t,e,r,n){return{isApplicable:t,annotation:e,transform:r,untransform:n}}const gn=[ue(dn,"undefined",()=>null,()=>{}),ue(Ji,"bigint",t=>t.toString(),t=>typeof BigInt<"u"?BigInt(t):(console.error("Please add a BigInt polyfill."),t)),ue(Bi,"Date",t=>t.toISOString(),t=>new Date(t)),ue(Gi,"Error",(t,e)=>{const r={name:t.name,message:t.message};return e.allowedErrorProps.forEach(n=>{r[n]=t[n]}),r},(t,e)=>{const r=new Error(t.message);return r.name=t.name,r.stack=t.stack,e.allowedErrorProps.forEach(n=>{r[n]=t[n]}),r}),ue(Wi,"regexp",t=>""+t,t=>{const e=t.slice(1,t.lastIndexOf("/")),r=t.slice(t.lastIndexOf("/")+1);return new RegExp(e,r)}),ue(Ot,"set",t=>[...t.values()],t=>new Set(t)),ue(Et,"map",t=>[...t.entries()],t=>new Map(t)),ue(t=>pn(t)||Xi(t),"number",t=>pn(t)?"NaN":t>0?"Infinity":"-Infinity",Number),ue(t=>t===0&&1/t===-1/0,"number",()=>"-0",Number),ue(eo,"URL",t=>t.toString(),t=>new URL(t))];function Lt(t,e,r,n){return{isApplicable:t,annotation:e,transform:r,untransform:n}}const bn=Lt((t,e)=>yn(t)?!!e.symbolRegistry.getIdentifier(t):!1,(t,e)=>["symbol",e.symbolRegistry.getIdentifier(t)],t=>t.description,(t,e,r)=>{const n=r.symbolRegistry.getValue(e[1]);if(!n)throw new Error("Trying to deserialize unknown symbol");return n}),to=[Int8Array,Uint8Array,Int16Array,Uint16Array,Int32Array,Uint32Array,Float32Array,Float64Array,Uint8ClampedArray].reduce((t,e)=>(t[e.name]=e,t),{}),vn=Lt(Zi,t=>["typed-array",t.constructor.name],t=>[...t],(t,e)=>{const r=to[e[1]];if(!r)throw new Error("Trying to deserialize unknown typed array");return new r(t)});function wn(t,e){return t!=null&&t.constructor?!!e.classRegistry.getIdentifier(t.constructor):!1}const En=Lt(wn,(t,e)=>["class",e.classRegistry.getIdentifier(t.constructor)],(t,e)=>{const r=e.classRegistry.getAllowedProps(t.constructor);if(!r)return{...t};const n={};return r.forEach(s=>{n[s]=t[s]}),n},(t,e,r)=>{const n=r.classRegistry.getValue(e[1]);if(!n)throw new Error(`Trying to deserialize unknown class '${e[1]}' - check https://github.com/blitz-js/superjson/issues/116#issuecomment-773996564`);return Object.assign(Object.create(n.prototype),t)}),On=Lt((t,e)=>!!e.customTransformerRegistry.findApplicable(t),(t,e)=>["custom",e.customTransformerRegistry.findApplicable(t).name],(t,e)=>e.customTransformerRegistry.findApplicable(t).serialize(t),(t,e,r)=>{const n=r.customTransformerRegistry.findByName(e[1]);if(!n)throw new Error("Trying to deserialize unknown custom value");return n.deserialize(t)}),ro=[En,bn,On,vn],Pn=(t,e)=>{const r=hn(ro,s=>s.isApplicable(t,e));if(r)return{value:r.transform(t,e),type:r.annotation(t,e)};const n=hn(gn,s=>s.isApplicable(t,e));if(n)return{value:n.transform(t,e),type:n.annotation}},Rn={};gn.forEach(t=>{Rn[t.annotation]=t});const no=(t,e,r)=>{if(be(e))switch(e[0]){case"symbol":return bn.untransform(t,e,r);case"class":return En.untransform(t,e,r);case"custom":return On.untransform(t,e,r);case"typed-array":return vn.untransform(t,e,r);default:throw new Error("Unknown transformation: "+e)}else{const n=Rn[e];if(!n)throw new Error("Unknown transformation: "+e);return n.untransform(t,r)}},Ye=(t,e)=>{if(e>t.size)throw new Error("index out of bounds");const r=t.keys();for(;e>0;)r.next(),e--;return r.next().value};function Sn(t){if(Nt(t,"__proto__"))throw new Error("__proto__ is not allowed as a property");if(Nt(t,"prototype"))throw new Error("prototype is not allowed as a property");if(Nt(t,"constructor"))throw new Error("constructor is not allowed as a property")}const so=(t,e)=>{Sn(e);for(let r=0;r<e.length;r++){const n=e[r];if(Ot(t))t=Ye(t,+n);else if(Et(t)){const s=+n,a=+e[++r]==0?"key":"value",u=Ye(t,s);switch(a){case"key":t=u;break;case"value":t=t.get(u);break}}else t=t[n]}return t},fr=(t,e,r)=>{if(Sn(e),e.length===0)return r(t);let n=t;for(let a=0;a<e.length-1;a++){const u=e[a];if(be(n)){const l=+u;n=n[l]}else if(wt(n))n=n[u];else if(Ot(n)){const l=+u;n=Ye(n,l)}else if(Et(n)){if(a===e.length-2)break;const c=+u,d=+e[++a]==0?"key":"value",h=Ye(n,c);switch(d){case"key":n=h;break;case"value":n=n.get(h);break}}}const s=e[e.length-1];if(be(n)?n[+s]=r(n[+s]):wt(n)&&(n[s]=r(n[s])),Ot(n)){const a=Ye(n,+s),u=r(a);a!==u&&(n.delete(a),n.add(u))}if(Et(n)){const a=+e[e.length-2],u=Ye(n,a);switch(+s==0?"key":"value"){case"key":{const c=r(u);n.set(c,n.get(u)),c!==u&&n.delete(u);break}case"value":{n.set(u,r(n.get(u)));break}}}return t};function hr(t,e,r=[]){if(!t)return;if(!be(t)){Ge(t,(a,u)=>hr(a,e,[...r,...Pt(u)]));return}const[n,s]=t;s&&Ge(s,(a,u)=>{hr(a,e,[...r,...Pt(u)])}),e(n,r)}function io(t,e,r){return hr(e,(n,s)=>{t=fr(t,s,a=>no(a,n,r))}),t}function oo(t,e){function r(n,s){const a=so(t,Pt(s));n.map(Pt).forEach(u=>{t=fr(t,u,()=>a)})}if(be(e)){const[n,s]=e;n.forEach(a=>{t=fr(t,Pt(a),()=>t)}),s&&Ge(s,r)}else Ge(e,r);return t}const ao=(t,e)=>wt(t)||be(t)||Et(t)||Ot(t)||wn(t,e);function uo(t,e,r){const n=r.get(t);n?n.push(e):r.set(t,[e])}function co(t,e){const r={};let n;return t.forEach(s=>{if(s.length<=1)return;e||(s=s.map(l=>l.map(String)).sort((l,c)=>l.length-c.length));const[a,...u]=s;a.length===0?n=u.map(lr):r[lr(a)]=u.map(lr)}),n?cr(r)?[n]:[n,r]:cr(r)?void 0:r}const Cn=(t,e,r,n,s=[],a=[],u=new Map)=>{const l=Yi(t);if(!l){uo(t,s,e);const m=u.get(t);if(m)return n?{transformedValue:null}:m}if(!ao(t,r)){const m=Pn(t,r),P=m?{transformedValue:m.value,annotations:[m.type]}:{transformedValue:t};return l||u.set(t,P),P}if(Nt(a,t))return{transformedValue:null};const c=Pn(t,r),d=(c==null?void 0:c.value)??t,h=be(d)?[]:{},f={};Ge(d,(m,P)=>{if(P==="__proto__"||P==="constructor"||P==="prototype")throw new Error(`Detected property ${P}. This is a prototype pollution risk, please remove it from your object.`);const v=Cn(m,e,r,n,[...s,P],[...a,t],u);h[P]=v.transformedValue,be(v.annotations)?f[P]=v.annotations:wt(v.annotations)&&Ge(v.annotations,(O,D)=>{f[mn(P)+"."+D]=O})});const p=cr(f)?{transformedValue:h,annotations:c?[c.type]:void 0}:{transformedValue:h,annotations:c?[c.type,f]:f};return l||u.set(t,p),p};function Tn(t){return Object.prototype.toString.call(t).slice(8,-1)}function Fn(t){return Tn(t)==="Array"}function lo(t){if(Tn(t)!=="Object")return!1;const e=Object.getPrototypeOf(t);return!!e&&e.constructor===Object&&e===Object.prototype}function fo(t,e,r,n,s){const a={}.propertyIsEnumerable.call(n,e)?"enumerable":"nonenumerable";a==="enumerable"&&(t[e]=r),s&&a==="nonenumerable"&&Object.defineProperty(t,e,{value:r,enumerable:!1,writable:!0,configurable:!0})}function dr(t,e={}){if(Fn(t))return t.map(s=>dr(s,e));if(!lo(t))return t;const r=Object.getOwnPropertyNames(t),n=Object.getOwnPropertySymbols(t);return[...r,...n].reduce((s,a)=>{if(Fn(e.props)&&!e.props.includes(a))return s;const u=t[a],l=dr(u,e);return fo(s,a,l,t,e.nonenumerable),s},{})}class C{constructor({dedupe:e=!1}={}){this.classRegistry=new Mi,this.symbolRegistry=new fn(r=>r.description??""),this.customTransformerRegistry=new Qi,this.allowedErrorProps=[],this.dedupe=e}serialize(e){const r=new Map,n=Cn(e,r,this,this.dedupe),s={json:n.transformedValue};n.annotations&&(s.meta={...s.meta,values:n.annotations});const a=co(r,this.dedupe);return a&&(s.meta={...s.meta,referentialEqualities:a}),s}deserialize(e){const{json:r,meta:n}=e;let s=dr(r);return n!=null&&n.values&&(s=io(s,n.values,this)),n!=null&&n.referentialEqualities&&(s=oo(s,n.referentialEqualities)),s}stringify(e){return JSON.stringify(this.serialize(e))}parse(e){return this.deserialize(JSON.parse(e))}registerClass(e,r){this.classRegistry.register(e,r)}registerSymbol(e,r){this.symbolRegistry.register(e,r)}registerCustom(e,r){this.customTransformerRegistry.register({name:r,...e})}allowErrorProps(...e){this.allowedErrorProps.push(...e)}}C.defaultInstance=new C,C.serialize=C.defaultInstance.serialize.bind(C.defaultInstance),C.deserialize=C.defaultInstance.deserialize.bind(C.defaultInstance),C.stringify=C.defaultInstance.stringify.bind(C.defaultInstance),C.parse=C.defaultInstance.parse.bind(C.defaultInstance),C.registerClass=C.defaultInstance.registerClass.bind(C.defaultInstance),C.registerSymbol=C.defaultInstance.registerSymbol.bind(C.defaultInstance),C.registerCustom=C.defaultInstance.registerCustom.bind(C.defaultInstance),C.allowErrorProps=C.defaultInstance.allowErrorProps.bind(C.defaultInstance),C.serialize,C.deserialize,C.stringify,C.parse,C.registerClass,C.registerCustom,C.registerSymbol,C.allowErrorProps;const xn=_.createContext(null);function ho(t,e){const r=yi({links:[Di({enabled:s=>process.env.NODE_ENV==="development"&&typeof window<"u"||s.direction==="down"&&s.result instanceof Error}),Ti({url:`${t}/trpc`,headers:()=>({Authorization:`Bearer ${e}`}),transformer:C})]}),n=async(s,a,u=null)=>{const l=a.filter(f=>f.name.toLowerCase().endsWith(".pdf"));if(l.length===0)return{filesToCreate:[]};const c=await r.fileRouter.getFilesByProject.query({projectId:s}),d=l.filter(f=>u===null?!c.some(p=>p.path===f.blobUrl):!c.some(p=>p.path===f.blobUrl&&p.parentId===u));return d.length===0?{filesToCreate:[]}:{filesToCreate:d.map(f=>({projectId:s,mimeType:Dt.PDF,path:f.blobUrl,name:f.name,size:0,metadata:null,isArtifact:!1,summary:null,chunkingStatus:Wt.NOT_CHUNKED,isDirectory:!1,parentId:u}))}};return{getProjectsForUser:async()=>{const s=await r.projectRouter.getAllProjects.query();if(s.length===0){const a=await r.projectRouter.createProject.mutate({name:"Default Project"});return[{name:a.name,id:a.id}]}return s.map(a=>({name:a.name,id:a.id}))},addProjectForUser:async s=>{const a=await r.projectRouter.createProject.mutate({name:s});return{name:a.name,id:a.id}},addFilesToProject:async(s,a)=>{const{filesToCreate:u}=await n(s,a);return u.length===0?[]:(await r.fileRouter.createFiles.mutate({files:u})).map(c=>({blobUrl:c.path,name:c.name,id:c.id,parentId:c.parentId,isDirectory:c.isDirectory}))},getFilesForProject:async s=>(await r.fileRouter.getFilesByProject.query({projectId:s})).map(u=>({blobUrl:u.path,name:u.name,id:u.id,parentId:u.parentId,isDirectory:u.isDirectory})),addDirectoryWithFilesToProject:async(s,a,u,l)=>{if((await r.fileRouter.getFilesByProject.query({projectId:s})).some(m=>m.name===a&&m.isDirectory===!0&&m.parentId===null))return console.warn(`A directory named "${a}" already exists at the root level. Skipping creation.`),{directory:null,files:[]};const h=await r.fileRouter.createFile.mutate({file:{projectId:s,mimeType:Dt.DIRECTORY,path:"",name:a,size:0,metadata:u,isArtifact:!1,isDirectory:!0,parentId:null,summary:null,chunkingStatus:Wt.NOT_CHUNKED}});if(l.length===0)return{directory:{blobUrl:h.path,name:h.name,id:h.id,parentId:h.parentId,isDirectory:h.isDirectory},files:[]};const{filesToCreate:f}=await n(s,l,h.id);if(f.length===0)return{directory:{blobUrl:h.path,name:h.name,id:h.id,parentId:h.parentId,isDirectory:h.isDirectory},files:[]};const p=await r.fileRouter.createFiles.mutate({files:f});return{directory:h?{blobUrl:h.path,name:h.name,id:h.id,parentId:h.parentId,isDirectory:h.isDirectory}:null,files:p.map(m=>({blobUrl:m.path,name:m.name,id:m.id,parentId:m.parentId,isDirectory:m.isDirectory}))}}}}function yo({children:t,host:e="http://localhost",port:r=5174,token:n}){const[s,a]=_.useState(null),u=_.useMemo(()=>new Is({defaultOptions:{queries:{staleTime:30*1e3,refetchOnWindowFocus:!1}}}),[]);return _.useEffect(()=>{const l=`${e}:${r}`,c=ho(l,n);a(c)},[e,r,n]),mt.jsx(Ms,{client:u,children:mt.jsx(xn.Provider,{value:{host:e,port:r,client:s,token:n},children:t})})}function Je(){const t=_.useContext(xn);if(!t)throw new Error("useFolioContext must be used within a FolioProvider");return t}const{useEffect:po,useRef:mo,useState:go}=M;function bo({width:t="100%",height:e="100vh",allow:r="camera; microphone; clipboard-read; clipboard-write; fullscreen",style:n,className:s="",iframeProps:a={}}){const{host:u,port:l,token:c}=Je(),d=mo(null),[h,f]=go();return po(()=>{(()=>{const P=`${`${u}:${l}`}?jwt=${encodeURIComponent(c)}`;f(P)})()},[u,l,c]),h?mt.jsx("div",{className:`folio-embed-container ${s}`,style:{width:t,height:e,overflow:"hidden",...n},children:mt.jsx("iframe",{ref:d,src:h,width:"100%",height:"100%",style:{border:"none",width:"100%",height:"100%",overflow:"auto"},allow:r,allowFullScreen:!0,...a})}):null}function vo(){const{client:t}=Je(),e=Zr({queryKey:["folioProjects"],queryFn:async()=>{if(!t)throw new Error("Folio client not initialized");return t.getProjectsForUser()},enabled:!!t});return{projects:e.data||[],isLoading:e.isLoading,isError:e.isError,error:e.error,refetch:e.refetch}}function wo(t){const{client:e}=Je(),r=Zr({queryKey:["folioFiles",t],queryFn:async()=>{if(!e)throw new Error("Folio client not initialized");if(!t)throw new Error("Project ID is required");return e.getFilesForProject(t)},enabled:!!e&&!!t});return{files:r.data||[],isLoading:r.isLoading,isError:r.isError,error:r.error,refetch:r.refetch}}function Eo(){const{client:t}=Je(),e=bt(),r=ir({mutationFn:async n=>{if(!t)throw new Error("Folio client not initialized");return t.addProjectForUser(n)},onSuccess:()=>{e.invalidateQueries({queryKey:["folioProjects"]})}});return{addProject:r.mutate,addProjectAsync:r.mutateAsync,isAdding:r.isPending,isError:r.isError,error:r.error,newProject:r.data}}function Oo(t){const{client:e}=Je(),r=bt(),n=ir({mutationFn:async s=>{if(!e)throw new Error("Folio client not initialized");if(!t)throw new Error("Project ID is required");return e.addFilesToProject(t,s)},onSuccess:()=>{r.invalidateQueries({queryKey:["folioFiles",t]})}});return{addFiles:n.mutate,addFilesAsync:n.mutateAsync,isAdding:n.isPending,isError:n.isError,error:n.error,newFiles:n.data}}function Po(t){const{client:e}=Je(),r=bt(),n=ir({mutationFn:async s=>{if(!e)throw new Error("Folio client not initialized");if(!t)throw new Error("Project ID is required");const a=Array.isArray(s)?s:[s],u=[];for(const l of a){const c=JSON.stringify(Object.fromEntries(l.directoryMetadata)),d=await e.addDirectoryWithFilesToProject(t,l.directoryName,c,l.files);u.push(d)}return Array.isArray(s)?u:u[0]},onSuccess:()=>{r.invalidateQueries({queryKey:["folioFiles",t]})}});return{addDirectoryWithFiles:n.mutate,addDirectoryWithFilesAsync:n.mutateAsync,isAdding:n.isPending,isError:n.isError,error:n.error,result:n.data}}x.FolioEmbed=bo,x.FolioProvider=yo,x.useAddFolioDirectoryWithFiles=Po,x.useAddFolioFiles=Oo,x.useAddFolioProject=Eo,x.useFolioFiles=wo,x.useFolioProjects=vo,Object.defineProperty(x,Symbol.toStringTag,{value:"Module"})});
34
+ `;l.push("%c",e==="up"?">>":"<<",r,`#${a}`,`%c${s}%c`,"%O"),c.push(f,`${f}; font-weight: bold;`,`${f}; font-weight: normal;`)}return e==="up"?c.push(n?{input:u,context:t.context}:{input:u}):c.push({input:u,result:t.result,elapsedMs:t.elapsedMs,...n&&{context:t.context}}),{parts:l,args:c}}const Ai=({c:t=console,colorMode:e="css",withContext:r})=>n=>{const s=n.input,a=Fi(s)?Object.fromEntries(s):s,{parts:u,args:l}=xi({...n,colorMode:e,input:a,withContext:r}),c=n.direction==="down"&&n.result&&(n.result instanceof Error||"error"in n.result.result&&n.result.result.error)?"error":"log";t[c].apply(null,[u.join(" ")].concat(l))};function Di(t={}){const{enabled:e=()=>!0}=t,r=t.colorMode??(typeof window>"u"?"ansi":"css"),n=t.withContext??r==="css",{logger:s=Ai({c:t.console,colorMode:r,withContext:n})}=t;return()=>({op:a,next:u})=>Be(l=>{e({...a,direction:"up"})&&s({...a,direction:"up"});const c=Date.now();function d(h){const f=Date.now()-c;e({...a,direction:"down",result:h})&&s({...a,direction:"down",elapsedMs:f,result:h})}return u(a).pipe(Zs({next(h){d(h)},error(h){d(h)}})).subscribe(l)})}const _i=(t,...e)=>typeof t=="function"?t(...e):t;function Ii(){let t,e;return{promise:new Promise((n,s)=>{t=n,e=s}),resolve:t,reject:e}}async function ki(t){const e=await _i(t.url);if(!t.connectionParams)return e;const n=`${e.includes("?")?"&":"?"}connectionParams=1`;return e+n}function ke(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}function ji(t){const{promise:e,resolve:r,reject:n}=Ii();return t.addEventListener("open",()=>{t.removeEventListener("error",n),r()}),t.addEventListener("error",n),e}function qi(t,{intervalMs:e,pongTimeoutMs:r}){let n,s;function a(){n=setTimeout(()=>{t.send("PING"),s=setTimeout(()=>{t.close()},r)},e)}function u(){clearTimeout(n),a()}function l(){clearTimeout(s),u()}t.addEventListener("open",a),t.addEventListener("message",({data:c})=>{clearTimeout(n),a(),c==="PONG"&&l()}),t.addEventListener("close",()=>{clearTimeout(n),clearTimeout(s)})}class Mt{get ws(){return this.wsObservable.get()}set ws(e){this.wsObservable.next(e)}isOpen(){return!!this.ws&&this.ws.readyState===this.WebSocketPonyfill.OPEN}isClosed(){return!!this.ws&&(this.ws.readyState===this.WebSocketPonyfill.CLOSING||this.ws.readyState===this.WebSocketPonyfill.CLOSED)}async open(){if(this.openPromise)return this.openPromise;this.id=++Mt.connectCount;const e=ki(this.urlOptions).then(r=>new this.WebSocketPonyfill(r));this.openPromise=e.then(ji),this.ws=await e,this.ws.addEventListener("message",function({data:r}){r==="PING"&&this.send("PONG")}),this.keepAliveOpts.enabled&&qi(this.ws,this.keepAliveOpts),this.ws.addEventListener("close",()=>{this.ws=null});try{await this.openPromise}finally{this.openPromise=null}}async close(){var e;try{await this.openPromise}finally{(e=this.ws)==null||e.close()}}constructor(e){if(ke(this,"id",++Mt.connectCount),ke(this,"WebSocketPonyfill",void 0),ke(this,"urlOptions",void 0),ke(this,"keepAliveOpts",void 0),ke(this,"wsObservable",ei(null)),ke(this,"openPromise",null),this.WebSocketPonyfill=e.WebSocketPonyfill??WebSocket,!this.WebSocketPonyfill)throw new Error("No WebSocket implementation found - you probably don't want to use this on the server, but if you do you need to pass a `WebSocket`-ponyfill");this.urlOptions=e.urlOptions,this.keepAliveOpts=e.keepAlive}}ke(Mt,"connectCount",0);class Ui{constructor(){this.keyToValue=new Map,this.valueToKey=new Map}set(e,r){this.keyToValue.set(e,r),this.valueToKey.set(r,e)}getByKey(e){return this.keyToValue.get(e)}getByValue(e){return this.valueToKey.get(e)}clear(){this.keyToValue.clear(),this.valueToKey.clear()}}class fn{constructor(e){this.generateIdentifier=e,this.kv=new Ui}register(e,r){this.kv.getByValue(e)||(r||(r=this.generateIdentifier(e)),this.kv.set(r,e))}clear(){this.kv.clear()}getIdentifier(e){return this.kv.getByValue(e)}getValue(e){return this.kv.getByKey(e)}}class Mi extends fn{constructor(){super(e=>e.name),this.classToAllowedProps=new Map}register(e,r){typeof r=="object"?(r.allowProps&&this.classToAllowedProps.set(e,r.allowProps),super.register(e,r.identifier)):super.register(e,r)}getAllowedProps(e){return this.classToAllowedProps.get(e)}}function Ni(t){if("values"in Object)return Object.values(t);const e=[];for(const r in t)t.hasOwnProperty(r)&&e.push(t[r]);return e}function Li(t,e){const r=Ni(t);if("find"in r)return r.find(e);const n=r;for(let s=0;s<n.length;s++){const a=n[s];if(e(a))return a}}function Ge(t,e){Object.entries(t).forEach(([r,n])=>e(n,r))}function Nt(t,e){return t.indexOf(e)!==-1}function hn(t,e){for(let r=0;r<t.length;r++){const n=t[r];if(e(n))return n}}class Qi{constructor(){this.transfomers={}}register(e){this.transfomers[e.name]=e}findApplicable(e){return Li(this.transfomers,r=>r.isApplicable(e))}findByName(e){return this.transfomers[e]}}const $i=t=>Object.prototype.toString.call(t).slice(8,-1),dn=t=>typeof t>"u",Ki=t=>t===null,wt=t=>typeof t!="object"||t===null||t===Object.prototype?!1:Object.getPrototypeOf(t)===null?!0:Object.getPrototypeOf(t)===Object.prototype,cr=t=>wt(t)&&Object.keys(t).length===0,be=t=>Array.isArray(t),Vi=t=>typeof t=="string",zi=t=>typeof t=="number"&&!isNaN(t),Hi=t=>typeof t=="boolean",Wi=t=>t instanceof RegExp,Et=t=>t instanceof Map,Ot=t=>t instanceof Set,yn=t=>$i(t)==="Symbol",Bi=t=>t instanceof Date&&!isNaN(t.valueOf()),Gi=t=>t instanceof Error,pn=t=>typeof t=="number"&&isNaN(t),Yi=t=>Hi(t)||Ki(t)||dn(t)||zi(t)||Vi(t)||yn(t),Ji=t=>typeof t=="bigint",Xi=t=>t===1/0||t===-1/0,Zi=t=>ArrayBuffer.isView(t)&&!(t instanceof DataView),eo=t=>t instanceof URL,mn=t=>t.replace(/\./g,"\\."),lr=t=>t.map(String).map(mn).join("."),Pt=t=>{const e=[];let r="";for(let s=0;s<t.length;s++){let a=t.charAt(s);if(a==="\\"&&t.charAt(s+1)==="."){r+=".",s++;continue}if(a==="."){e.push(r),r="";continue}r+=a}const n=r;return e.push(n),e};function ue(t,e,r,n){return{isApplicable:t,annotation:e,transform:r,untransform:n}}const gn=[ue(dn,"undefined",()=>null,()=>{}),ue(Ji,"bigint",t=>t.toString(),t=>typeof BigInt<"u"?BigInt(t):(console.error("Please add a BigInt polyfill."),t)),ue(Bi,"Date",t=>t.toISOString(),t=>new Date(t)),ue(Gi,"Error",(t,e)=>{const r={name:t.name,message:t.message};return e.allowedErrorProps.forEach(n=>{r[n]=t[n]}),r},(t,e)=>{const r=new Error(t.message);return r.name=t.name,r.stack=t.stack,e.allowedErrorProps.forEach(n=>{r[n]=t[n]}),r}),ue(Wi,"regexp",t=>""+t,t=>{const e=t.slice(1,t.lastIndexOf("/")),r=t.slice(t.lastIndexOf("/")+1);return new RegExp(e,r)}),ue(Ot,"set",t=>[...t.values()],t=>new Set(t)),ue(Et,"map",t=>[...t.entries()],t=>new Map(t)),ue(t=>pn(t)||Xi(t),"number",t=>pn(t)?"NaN":t>0?"Infinity":"-Infinity",Number),ue(t=>t===0&&1/t===-1/0,"number",()=>"-0",Number),ue(eo,"URL",t=>t.toString(),t=>new URL(t))];function Lt(t,e,r,n){return{isApplicable:t,annotation:e,transform:r,untransform:n}}const bn=Lt((t,e)=>yn(t)?!!e.symbolRegistry.getIdentifier(t):!1,(t,e)=>["symbol",e.symbolRegistry.getIdentifier(t)],t=>t.description,(t,e,r)=>{const n=r.symbolRegistry.getValue(e[1]);if(!n)throw new Error("Trying to deserialize unknown symbol");return n}),to=[Int8Array,Uint8Array,Int16Array,Uint16Array,Int32Array,Uint32Array,Float32Array,Float64Array,Uint8ClampedArray].reduce((t,e)=>(t[e.name]=e,t),{}),vn=Lt(Zi,t=>["typed-array",t.constructor.name],t=>[...t],(t,e)=>{const r=to[e[1]];if(!r)throw new Error("Trying to deserialize unknown typed array");return new r(t)});function wn(t,e){return t!=null&&t.constructor?!!e.classRegistry.getIdentifier(t.constructor):!1}const En=Lt(wn,(t,e)=>["class",e.classRegistry.getIdentifier(t.constructor)],(t,e)=>{const r=e.classRegistry.getAllowedProps(t.constructor);if(!r)return{...t};const n={};return r.forEach(s=>{n[s]=t[s]}),n},(t,e,r)=>{const n=r.classRegistry.getValue(e[1]);if(!n)throw new Error(`Trying to deserialize unknown class '${e[1]}' - check https://github.com/blitz-js/superjson/issues/116#issuecomment-773996564`);return Object.assign(Object.create(n.prototype),t)}),On=Lt((t,e)=>!!e.customTransformerRegistry.findApplicable(t),(t,e)=>["custom",e.customTransformerRegistry.findApplicable(t).name],(t,e)=>e.customTransformerRegistry.findApplicable(t).serialize(t),(t,e,r)=>{const n=r.customTransformerRegistry.findByName(e[1]);if(!n)throw new Error("Trying to deserialize unknown custom value");return n.deserialize(t)}),ro=[En,bn,On,vn],Pn=(t,e)=>{const r=hn(ro,s=>s.isApplicable(t,e));if(r)return{value:r.transform(t,e),type:r.annotation(t,e)};const n=hn(gn,s=>s.isApplicable(t,e));if(n)return{value:n.transform(t,e),type:n.annotation}},Rn={};gn.forEach(t=>{Rn[t.annotation]=t});const no=(t,e,r)=>{if(be(e))switch(e[0]){case"symbol":return bn.untransform(t,e,r);case"class":return En.untransform(t,e,r);case"custom":return On.untransform(t,e,r);case"typed-array":return vn.untransform(t,e,r);default:throw new Error("Unknown transformation: "+e)}else{const n=Rn[e];if(!n)throw new Error("Unknown transformation: "+e);return n.untransform(t,r)}},Ye=(t,e)=>{if(e>t.size)throw new Error("index out of bounds");const r=t.keys();for(;e>0;)r.next(),e--;return r.next().value};function Sn(t){if(Nt(t,"__proto__"))throw new Error("__proto__ is not allowed as a property");if(Nt(t,"prototype"))throw new Error("prototype is not allowed as a property");if(Nt(t,"constructor"))throw new Error("constructor is not allowed as a property")}const so=(t,e)=>{Sn(e);for(let r=0;r<e.length;r++){const n=e[r];if(Ot(t))t=Ye(t,+n);else if(Et(t)){const s=+n,a=+e[++r]==0?"key":"value",u=Ye(t,s);switch(a){case"key":t=u;break;case"value":t=t.get(u);break}}else t=t[n]}return t},fr=(t,e,r)=>{if(Sn(e),e.length===0)return r(t);let n=t;for(let a=0;a<e.length-1;a++){const u=e[a];if(be(n)){const l=+u;n=n[l]}else if(wt(n))n=n[u];else if(Ot(n)){const l=+u;n=Ye(n,l)}else if(Et(n)){if(a===e.length-2)break;const c=+u,d=+e[++a]==0?"key":"value",h=Ye(n,c);switch(d){case"key":n=h;break;case"value":n=n.get(h);break}}}const s=e[e.length-1];if(be(n)?n[+s]=r(n[+s]):wt(n)&&(n[s]=r(n[s])),Ot(n)){const a=Ye(n,+s),u=r(a);a!==u&&(n.delete(a),n.add(u))}if(Et(n)){const a=+e[e.length-2],u=Ye(n,a);switch(+s==0?"key":"value"){case"key":{const c=r(u);n.set(c,n.get(u)),c!==u&&n.delete(u);break}case"value":{n.set(u,r(n.get(u)));break}}}return t};function hr(t,e,r=[]){if(!t)return;if(!be(t)){Ge(t,(a,u)=>hr(a,e,[...r,...Pt(u)]));return}const[n,s]=t;s&&Ge(s,(a,u)=>{hr(a,e,[...r,...Pt(u)])}),e(n,r)}function io(t,e,r){return hr(e,(n,s)=>{t=fr(t,s,a=>no(a,n,r))}),t}function oo(t,e){function r(n,s){const a=so(t,Pt(s));n.map(Pt).forEach(u=>{t=fr(t,u,()=>a)})}if(be(e)){const[n,s]=e;n.forEach(a=>{t=fr(t,Pt(a),()=>t)}),s&&Ge(s,r)}else Ge(e,r);return t}const ao=(t,e)=>wt(t)||be(t)||Et(t)||Ot(t)||wn(t,e);function uo(t,e,r){const n=r.get(t);n?n.push(e):r.set(t,[e])}function co(t,e){const r={};let n;return t.forEach(s=>{if(s.length<=1)return;e||(s=s.map(l=>l.map(String)).sort((l,c)=>l.length-c.length));const[a,...u]=s;a.length===0?n=u.map(lr):r[lr(a)]=u.map(lr)}),n?cr(r)?[n]:[n,r]:cr(r)?void 0:r}const Cn=(t,e,r,n,s=[],a=[],u=new Map)=>{const l=Yi(t);if(!l){uo(t,s,e);const m=u.get(t);if(m)return n?{transformedValue:null}:m}if(!ao(t,r)){const m=Pn(t,r),P=m?{transformedValue:m.value,annotations:[m.type]}:{transformedValue:t};return l||u.set(t,P),P}if(Nt(a,t))return{transformedValue:null};const c=Pn(t,r),d=(c==null?void 0:c.value)??t,h=be(d)?[]:{},f={};Ge(d,(m,P)=>{if(P==="__proto__"||P==="constructor"||P==="prototype")throw new Error(`Detected property ${P}. This is a prototype pollution risk, please remove it from your object.`);const v=Cn(m,e,r,n,[...s,P],[...a,t],u);h[P]=v.transformedValue,be(v.annotations)?f[P]=v.annotations:wt(v.annotations)&&Ge(v.annotations,(O,D)=>{f[mn(P)+"."+D]=O})});const p=cr(f)?{transformedValue:h,annotations:c?[c.type]:void 0}:{transformedValue:h,annotations:c?[c.type,f]:f};return l||u.set(t,p),p};function Tn(t){return Object.prototype.toString.call(t).slice(8,-1)}function Fn(t){return Tn(t)==="Array"}function lo(t){if(Tn(t)!=="Object")return!1;const e=Object.getPrototypeOf(t);return!!e&&e.constructor===Object&&e===Object.prototype}function fo(t,e,r,n,s){const a={}.propertyIsEnumerable.call(n,e)?"enumerable":"nonenumerable";a==="enumerable"&&(t[e]=r),s&&a==="nonenumerable"&&Object.defineProperty(t,e,{value:r,enumerable:!1,writable:!0,configurable:!0})}function dr(t,e={}){if(Fn(t))return t.map(s=>dr(s,e));if(!lo(t))return t;const r=Object.getOwnPropertyNames(t),n=Object.getOwnPropertySymbols(t);return[...r,...n].reduce((s,a)=>{if(Fn(e.props)&&!e.props.includes(a))return s;const u=t[a],l=dr(u,e);return fo(s,a,l,t,e.nonenumerable),s},{})}class C{constructor({dedupe:e=!1}={}){this.classRegistry=new Mi,this.symbolRegistry=new fn(r=>r.description??""),this.customTransformerRegistry=new Qi,this.allowedErrorProps=[],this.dedupe=e}serialize(e){const r=new Map,n=Cn(e,r,this,this.dedupe),s={json:n.transformedValue};n.annotations&&(s.meta={...s.meta,values:n.annotations});const a=co(r,this.dedupe);return a&&(s.meta={...s.meta,referentialEqualities:a}),s}deserialize(e){const{json:r,meta:n}=e;let s=dr(r);return n!=null&&n.values&&(s=io(s,n.values,this)),n!=null&&n.referentialEqualities&&(s=oo(s,n.referentialEqualities)),s}stringify(e){return JSON.stringify(this.serialize(e))}parse(e){return this.deserialize(JSON.parse(e))}registerClass(e,r){this.classRegistry.register(e,r)}registerSymbol(e,r){this.symbolRegistry.register(e,r)}registerCustom(e,r){this.customTransformerRegistry.register({name:r,...e})}allowErrorProps(...e){this.allowedErrorProps.push(...e)}}C.defaultInstance=new C,C.serialize=C.defaultInstance.serialize.bind(C.defaultInstance),C.deserialize=C.defaultInstance.deserialize.bind(C.defaultInstance),C.stringify=C.defaultInstance.stringify.bind(C.defaultInstance),C.parse=C.defaultInstance.parse.bind(C.defaultInstance),C.registerClass=C.defaultInstance.registerClass.bind(C.defaultInstance),C.registerSymbol=C.defaultInstance.registerSymbol.bind(C.defaultInstance),C.registerCustom=C.defaultInstance.registerCustom.bind(C.defaultInstance),C.allowErrorProps=C.defaultInstance.allowErrorProps.bind(C.defaultInstance),C.serialize,C.deserialize,C.stringify,C.parse,C.registerClass,C.registerCustom,C.registerSymbol,C.allowErrorProps;const xn=_.createContext(null);function ho(t,e){const r=yi({links:[Di({enabled:s=>process.env.NODE_ENV==="development"&&typeof window<"u"||s.direction==="down"&&s.result instanceof Error}),Ti({url:`${t}/trpc`,headers:()=>({Authorization:`Bearer ${e}`}),transformer:C})]}),n=async(s,a,u=null)=>{const l=a.filter(f=>f.name.toLowerCase().endsWith(".pdf"));if(l.length===0)return{filesToCreate:[]};const c=await r.fileRouter.getFilesByProject.query({projectId:s}),d=l.filter(f=>u===null?!c.some(p=>p.path===f.blobUrl):!c.some(p=>p.path===f.blobUrl&&p.parentId===u));return d.length===0?{filesToCreate:[]}:{filesToCreate:d.map(f=>({projectId:s,mimeType:Dt.PDF,path:f.blobUrl,name:f.name,size:0,metadata:null,isArtifact:!1,summary:null,chunkingStatus:Wt.NOT_CHUNKED,isDirectory:!1,parentId:u}))}};return{getProjectsForUser:async()=>{const s=await r.projectRouter.getAllProjects.query();if(s.length===0){const a=await r.projectRouter.createProject.mutate({name:"Default Project"});return[{name:a.name,id:a.id}]}return s.map(a=>({name:a.name,id:a.id}))},addProjectForUser:async s=>{const a=await r.projectRouter.createProject.mutate({name:s});return{name:a.name,id:a.id}},addFilesToProject:async(s,a)=>{const{filesToCreate:u}=await n(s,a);return u.length===0?[]:(await r.fileRouter.createFiles.mutate({files:u})).map(c=>({blobUrl:c.path,name:c.name,id:c.id,parentId:c.parentId,isDirectory:c.isDirectory}))},getFilesForProject:async s=>(await r.fileRouter.getFilesByProject.query({projectId:s})).map(u=>({blobUrl:u.path,name:u.name,id:u.id,parentId:u.parentId,isDirectory:u.isDirectory})),addDirectoryWithFilesToProject:async(s,a,u,l)=>{if((await r.fileRouter.getFilesByProject.query({projectId:s})).some(m=>m.name===a&&m.isDirectory===!0&&m.parentId===null))return console.warn(`A directory named "${a}" already exists at the root level. Skipping creation.`),{directory:null,files:[]};const h=await r.fileRouter.createFile.mutate({file:{projectId:s,mimeType:Dt.DIRECTORY,path:"",name:a,size:0,metadata:u,isArtifact:!1,isDirectory:!0,parentId:null,summary:null,chunkingStatus:Wt.NOT_CHUNKED}});if(l.length===0)return{directory:{blobUrl:h.path,name:h.name,id:h.id,parentId:h.parentId,isDirectory:h.isDirectory},files:[]};const{filesToCreate:f}=await n(s,l,h.id);if(f.length===0)return{directory:{blobUrl:h.path,name:h.name,id:h.id,parentId:h.parentId,isDirectory:h.isDirectory},files:[]};const p=await r.fileRouter.createFiles.mutate({files:f});return{directory:h?{blobUrl:h.path,name:h.name,id:h.id,parentId:h.parentId,isDirectory:h.isDirectory}:null,files:p.map(m=>({blobUrl:m.path,name:m.name,id:m.id,parentId:m.parentId,isDirectory:m.isDirectory}))}}}}function yo({children:t,host:e="http://localhost",port:r=5174,token:n}){const[s,a]=_.useState(null),u=_.useMemo(()=>new Is({defaultOptions:{queries:{staleTime:30*1e3,refetchOnWindowFocus:!1}}}),[]);return _.useEffect(()=>{const l=`${e}:${r}`,c=ho(l,n);a(c)},[e,r,n]),mt.jsx(Ms,{client:u,children:mt.jsx(xn.Provider,{value:{host:e,port:r,client:s,token:n},children:t})})}function Je(){const t=_.useContext(xn);if(!t)throw new Error("useFolioContext must be used within a FolioProvider");return t}const{useEffect:po,useRef:mo,useState:go}=M;function bo({width:t="100%",height:e="100vh",allow:r="camera; microphone; clipboard-read; clipboard-write; fullscreen",style:n,className:s="",iframeProps:a={}}){const{host:u,port:l,token:c}=Je(),d=mo(null),[h,f]=go();return po(()=>{(()=>{const P=`${`${u}:${l}`}?jwt=${encodeURIComponent(c)}`;f(P)})()},[u,l,c]),h?mt.jsx("div",{className:`folio-embed-container ${s}`,style:{width:t,height:e,overflow:"hidden",...n},children:mt.jsx("iframe",{ref:d,src:h,width:"100%",height:"100%",style:{border:"none",width:"100%",height:"100%",overflow:"auto"},allow:r,allowFullScreen:!0,...a})}):null}function vo(){const{client:t}=Je(),e=Zr({queryKey:["folioProjects"],queryFn:async()=>{if(!t)throw new Error("Folio client not initialized");return t.getProjectsForUser()},enabled:!!t});return{projects:e.data||[],isLoading:e.isLoading,isError:e.isError,error:e.error,refetch:e.refetch}}function wo(t){const{client:e}=Je(),r=Zr({queryKey:["folioFiles",t],queryFn:async()=>{if(!e)throw new Error("Folio client not initialized");if(!t)throw new Error("Project ID is required");return e.getFilesForProject(t)},enabled:!!e&&!!t});return{files:r.data||[],isLoading:r.isLoading,isError:r.isError,error:r.error,refetch:r.refetch}}function Eo(){const{client:t}=Je(),e=bt(),r=ir({mutationFn:async n=>{if(!t)throw new Error("Folio client not initialized");return t.addProjectForUser(n)},onSuccess:()=>{e.invalidateQueries({queryKey:["folioProjects"]})}});return{addProject:r.mutate,addProjectAsync:r.mutateAsync,isAdding:r.isPending,isError:r.isError,error:r.error,newProject:r.data}}function Oo(t){const{client:e}=Je(),r=bt(),n=ir({mutationFn:async s=>{if(!e)throw new Error("Folio client not initialized");if(!t)throw new Error("Project ID is required");return e.addFilesToProject(t,s)},onSuccess:()=>{r.invalidateQueries({queryKey:["folioFiles",t]})}});return{addFiles:n.mutate,addFilesAsync:n.mutateAsync,isAdding:n.isPending,isError:n.isError,error:n.error,newFiles:n.data}}function Po(t){const{client:e}=Je(),r=bt(),n=ir({mutationFn:async s=>{if(!e)throw new Error("Folio client not initialized");if(!t)throw new Error("Project ID is required");const a=Array.isArray(s)?s:[s],u=[];for(const l of a){const c=JSON.stringify(l.directoryMetadata),d=await e.addDirectoryWithFilesToProject(t,l.directoryName,c,l.files);u.push(d)}return Array.isArray(s)?u:u[0]},onSuccess:()=>{r.invalidateQueries({queryKey:["folioFiles",t]})}});return{addDirectoriesWithFiles:n.mutate,addDirectoriesWithFilesAsync:n.mutateAsync,isAdding:n.isPending,isError:n.isError,error:n.error,result:n.data}}x.FolioEmbed=bo,x.FolioProvider=yo,x.useAddFolioDirectoriesWithFiles=Po,x.useAddFolioFiles=Oo,x.useAddFolioProject=Eo,x.useFolioFiles=wo,x.useFolioProjects=vo,Object.defineProperty(x,Symbol.toStringTag,{value:"Module"})});
@@ -11,7 +11,12 @@ import { UseMutateFunction } from '@tanstack/react-query';
11
11
  */
12
12
  export declare type DirectoryEntry = {
13
13
  directoryName: string;
14
- directoryMetadata: Map<string, string>;
14
+ /**
15
+ * Metadata for the directory. Can be a nested structure of objects, arrays, and primitive values.
16
+ * Will be automatically converted to a JSON string before sending to the API.
17
+ * Example: { category: "reports", details: { owner: "John", tags: ["important", "tax"] } }
18
+ */
19
+ directoryMetadata: Record<string, MetadataValue>;
15
20
  files: Omit<FolioFile, "id" | "parentId" | "isDirectory">[];
16
21
  };
17
22
 
@@ -91,6 +96,13 @@ export declare interface FolioProviderProps {
91
96
  token: string;
92
97
  }
93
98
 
99
+ /**
100
+ * Type definition for metadata values that can be nested
101
+ */
102
+ declare type MetadataValue = string | number | boolean | null | {
103
+ [key: string]: MetadataValue;
104
+ } | MetadataValue[];
105
+
94
106
  /**
95
107
  * Hook for adding one or more directories with files to a project
96
108
  * @param projectId The ID of the project to add the directories and files to
@@ -102,19 +114,19 @@ export declare interface FolioProviderProps {
102
114
  * - Files are checked for duplicates based on their path and parent directory.
103
115
  * Files with the same path but in different directories are considered unique.
104
116
  * - Only PDF files are accepted and will be filtered automatically.
105
- * - Metadata is provided as a Map<string, string> and will be automatically
117
+ * - Metadata can be a nested structure of objects, arrays, and primitive values, and will be automatically
106
118
  * converted to a JSON string before sending to the API.
107
119
  * - Can add a single directory or multiple directories in one call.
108
120
  */
109
- export declare function useAddFolioDirectoryWithFiles(projectId?: number): {
110
- addDirectoryWithFiles: UseMutateFunction< {
121
+ export declare function useAddFolioDirectoriesWithFiles(projectId?: number): {
122
+ addDirectoriesWithFiles: UseMutateFunction< {
111
123
  directory: FolioFile | null;
112
124
  files: FolioFile[];
113
125
  } | {
114
126
  directory: FolioFile | null;
115
127
  files: FolioFile[];
116
128
  }[], Error, DirectoryEntry | DirectoryEntry[], unknown>;
117
- addDirectoryWithFilesAsync: UseMutateAsyncFunction< {
129
+ addDirectoriesWithFilesAsync: UseMutateAsyncFunction< {
118
130
  directory: FolioFile | null;
119
131
  files: FolioFile[];
120
132
  } | {
@@ -141,7 +153,7 @@ export declare function useAddFolioDirectoryWithFiles(projectId?: number): {
141
153
  * @remarks
142
154
  * Files are always created at the root level (parentId = null) and
143
155
  * are not directories (isDirectory = false). To create directories,
144
- * use the useAddFolioDirectoryWithFiles hook instead.
156
+ * use the useAddFolioDirectoriesWithFiles hook instead.
145
157
  */
146
158
  export declare function useAddFolioFiles(projectId?: number): {
147
159
  addFiles: UseMutateFunction<FolioFile[], Error, Omit<FolioFile, "id" | "isDirectory" | "parentId">[], unknown>;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@shiftengineering/folio",
3
3
  "private": false,
4
- "version": "0.1.4",
4
+ "version": "0.1.6",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "git+https://github.com/ShiftEngineering/folio.git"
@@ -100,7 +100,7 @@
100
100
  "concurrently": "^9.1.2",
101
101
  "date-fns": "^4.1.0",
102
102
  "embla-carousel-react": "^8.5.2",
103
- "esbuild": "^0.24.2",
103
+ "esbuild": "^0.25.0",
104
104
  "eslint": "^9.19.0",
105
105
  "eslint-plugin-react-hooks": "^5.1.0",
106
106
  "eslint-plugin-react-refresh": "^0.4.18",