@retinalabsllc/zairusjs 4.0.12 → 4.0.14

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/dist/index.d.mts CHANGED
@@ -454,7 +454,7 @@ interface GifFeatureCardProps {
454
454
  }
455
455
  declare const GifFeatureCard: React.FC<GifFeatureCardProps>;
456
456
 
457
- type AppTypeKey = 'docx' | 'sheets' | 'mail' | 'calendar' | 'drive' | 'audditur' | 'desktop' | 'admin' | 'unknown';
457
+ type AppTypeKey = 'audditur' | 'desktop' | 'admin' | 'unknown';
458
458
  interface NavItem {
459
459
  name: string;
460
460
  path: string;
@@ -712,7 +712,7 @@ interface AgentStat {
712
712
  icon: React.ReactNode;
713
713
  }
714
714
  interface AgentFilePayload {
715
- imageBase64: string;
715
+ file: File;
716
716
  fileName: string;
717
717
  fileType: string;
718
718
  fileSize: number;
package/dist/index.d.ts CHANGED
@@ -454,7 +454,7 @@ interface GifFeatureCardProps {
454
454
  }
455
455
  declare const GifFeatureCard: React.FC<GifFeatureCardProps>;
456
456
 
457
- type AppTypeKey = 'docx' | 'sheets' | 'mail' | 'calendar' | 'drive' | 'audditur' | 'desktop' | 'admin' | 'unknown';
457
+ type AppTypeKey = 'audditur' | 'desktop' | 'admin' | 'unknown';
458
458
  interface NavItem {
459
459
  name: string;
460
460
  path: string;
@@ -712,7 +712,7 @@ interface AgentStat {
712
712
  icon: React.ReactNode;
713
713
  }
714
714
  interface AgentFilePayload {
715
- imageBase64: string;
715
+ file: File;
716
716
  fileName: string;
717
717
  fileType: string;
718
718
  fileSize: number;
package/dist/index.js CHANGED
@@ -1723,13 +1723,8 @@ var import_react37 = require("@hugeicons/react");
1723
1723
  var import_core_free_icons8 = require("@hugeicons/core-free-icons");
1724
1724
  var ButtonSpinner = () => /* @__PURE__ */ import_react36.default.createElement("svg", { className: "animate-spin h-4 w-4 text-neutral-400", xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24" }, /* @__PURE__ */ import_react36.default.createElement("circle", { className: "opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4" }), /* @__PURE__ */ import_react36.default.createElement("path", { className: "opacity-75", fill: "currentColor", d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z" }));
1725
1725
  var ECOSYSTEM_APPS = [
1726
- { id: "desktop", name: "Retina Desktop", description: "Unified AI Workspace", iconSrc: "https://retinalabs.company/assets/images/desktop.avif", url: "https://retinadesktop.com/app" },
1727
- { id: "audditur", name: "Audditur", description: "AI Legal & Compliance", iconSrc: "https://retinalabs.company/assets/images/audditur.avif", url: "https://audditur.retinaapps.com/app" },
1728
- { id: "docx", name: "Retina Docx", description: "Collaborative Word Processing", iconSrc: "https://retinalabs.company/assets/images/docx.avif", url: "https://docx.retinaapps.com/app" },
1729
- { id: "sheets", name: "Retina Sheets", description: "Advanced Spreadsheets", iconSrc: "https://retinalabs.company/assets/images/sheets.avif", url: "https://sheets.retinaapps.com/app" },
1730
- { id: "drive", name: "Retina Drive", description: "Secure Cloud Storage", iconSrc: "https://retinalabs.company/assets/images/drive.avif", url: "https://drive.retinaapps.com/app" },
1731
- { id: "calendar", name: "Retina Calendar", description: "Smart Scheduling", iconSrc: "https://retinalabs.company/assets/images/calendar.avif", url: "https://calendar.retinaapps.com/app" },
1732
- { id: "mail", name: "Retina Mail", description: "Secure Email Inbox", iconSrc: "https://retinalabs.company/assets/images/mail.avif", url: "https://mail.retinaapps.com/app" }
1726
+ { id: "desktop", name: "Retina", description: "Ai Document Editor", iconSrc: "https://retinalabs.company/assets/images/desktop.avif", url: "https://app.retinaapps.com/" },
1727
+ { id: "audditur", name: "Audditur", description: "AI Legal & Compliance", iconSrc: "https://retinalabs.company/assets/images/audditur.avif", url: "https://app.audditur.com/" }
1733
1728
  ];
1734
1729
  var UniversalSidebar = ({
1735
1730
  navItems,
@@ -1757,7 +1752,6 @@ var UniversalSidebar = ({
1757
1752
  interceptMessage = "Are you sure you want to leave? All unsaved changes will be lost."
1758
1753
  }) => {
1759
1754
  const [isCollapsed, setIsCollapsed] = (0, import_react36.useState)(false);
1760
- const [showAppSwitcherDialog, setShowAppSwitcherDialog] = (0, import_react36.useState)(false);
1761
1755
  const [showSwitcherDialog, setShowSwitcherDialog] = (0, import_react36.useState)(false);
1762
1756
  const [showLogoutDialog, setShowLogoutDialog] = (0, import_react36.useState)(false);
1763
1757
  const [isLoggingOut, setIsLoggingOut] = (0, import_react36.useState)(false);
@@ -1820,29 +1814,14 @@ var UniversalSidebar = ({
1820
1814
  ${isCollapsed ? "md:w-16 w-64" : "w-64"}
1821
1815
  `
1822
1816
  },
1823
- /* @__PURE__ */ import_react36.default.createElement("div", { className: `flex items-center shrink-0 p-5 ${isCollapsed && !isMobileOpen ? "justify-center min-h-18" : "justify-between"}` }, /* @__PURE__ */ import_react36.default.createElement(
1824
- "button",
1817
+ /* @__PURE__ */ import_react36.default.createElement("div", { className: `flex items-center shrink-0 p-5 ${isCollapsed && !isMobileOpen ? "justify-center min-h-18" : "justify-between"}` }, /* @__PURE__ */ import_react36.default.createElement("div", { className: `flex items-center gap-3 text-left ${!isCollapsed || isMobileOpen ? "w-full" : ""}` }, currentAppConfig ? /* @__PURE__ */ import_react36.default.createElement(
1818
+ "img",
1825
1819
  {
1826
- onClick: () => setShowAppSwitcherDialog(true),
1827
- className: `flex items-center gap-3 outline-none group text-left ${!isCollapsed || isMobileOpen ? "w-full" : ""}`
1828
- },
1829
- currentAppConfig ? /* @__PURE__ */ import_react36.default.createElement(
1830
- "img",
1831
- {
1832
- src: currentAppConfig.iconSrc,
1833
- alt: currentAppConfig.name,
1834
- className: "w-5 h-5 rounded-md object-contain shrink-0 group-hover:scale-105 transition-transform"
1835
- }
1836
- ) : /* @__PURE__ */ import_react36.default.createElement("div", { className: " rounded-md shrink-0 flex items-center justify-center" }),
1837
- (!isCollapsed || isMobileOpen) && /* @__PURE__ */ import_react36.default.createElement(import_react36.default.Fragment, null, /* @__PURE__ */ import_react36.default.createElement("div", { className: "flex flex-col justify-center min-w-0 pr-2 flex-1" }, /* @__PURE__ */ import_react36.default.createElement("span", { className: "text-[13px] text-black leading-none truncate tracking-wide mb-1 group-hover:opacity-70 transition-opacity" }, title), subtitle && /* @__PURE__ */ import_react36.default.createElement("span", { className: "text-[9px] text-neutral-500 truncate tracking-[0.2em] leading-none " }, subtitle)), /* @__PURE__ */ import_react36.default.createElement(
1838
- import_react37.HugeiconsIcon,
1839
- {
1840
- icon: import_core_free_icons8.CircleArrowDown01Icon,
1841
- size: 20,
1842
- className: "text-neutral-400 shrink-0 group-hover:text-black transition-colors mr-3 ml-auto"
1843
- }
1844
- ))
1845
- ), /* @__PURE__ */ import_react36.default.createElement("div", { className: "md:hidden flex shrink-0" }, /* @__PURE__ */ import_react36.default.createElement(
1820
+ src: currentAppConfig.iconSrc,
1821
+ alt: currentAppConfig.name,
1822
+ className: "w-5 h-5 rounded-md object-contain shrink-0"
1823
+ }
1824
+ ) : /* @__PURE__ */ import_react36.default.createElement("div", { className: " rounded-md shrink-0 flex items-center justify-center" }), (!isCollapsed || isMobileOpen) && /* @__PURE__ */ import_react36.default.createElement("div", { className: "flex flex-col justify-center min-w-0 pr-2 flex-1" }, /* @__PURE__ */ import_react36.default.createElement("span", { className: "text-[13px] text-black leading-none truncate tracking-wide mb-1" }, title), subtitle && /* @__PURE__ */ import_react36.default.createElement("span", { className: "text-[9px] text-neutral-500 truncate tracking-[0.2em] leading-none " }, subtitle))), /* @__PURE__ */ import_react36.default.createElement("div", { className: "md:hidden flex shrink-0" }, /* @__PURE__ */ import_react36.default.createElement(
1846
1825
  "button",
1847
1826
  {
1848
1827
  onClick: closeMobile,
@@ -1908,39 +1887,7 @@ var UniversalSidebar = ({
1908
1887
  /* @__PURE__ */ import_react36.default.createElement(import_react37.HugeiconsIcon, { icon: import_core_free_icons8.SidebarLeft01Icon, size: 18, className: "shrink-0 text-neutral-400" }),
1909
1888
  !isCollapsed && /* @__PURE__ */ import_react36.default.createElement("span", { className: "text-xs" }, "Collapse")
1910
1889
  )))
1911
- ), showAppSwitcherDialog && /* @__PURE__ */ import_react36.default.createElement("div", { className: "fixed inset-0 z-110 flex items-center justify-center p-4 pointer-events-auto" }, /* @__PURE__ */ import_react36.default.createElement(
1912
- "div",
1913
- {
1914
- className: "absolute inset-0 bg-black/30 transition-opacity",
1915
- onClick: () => setShowAppSwitcherDialog(false)
1916
- }
1917
- ), /* @__PURE__ */ import_react36.default.createElement("div", { className: "relative w-full max-w-85 bg-white rounded-2xl flex flex-col overflow-hidden shadow-2xl animate-in zoom-in-95 duration-200" }, /* @__PURE__ */ import_react36.default.createElement("div", { className: "p-5 w-full flex items-center justify-between" }, /* @__PURE__ */ import_react36.default.createElement("div", null, /* @__PURE__ */ import_react36.default.createElement("h3", { className: "text-[15px] text-black tracking-tight " }, "Retina Apps"), /* @__PURE__ */ import_react36.default.createElement("p", { className: "text-[11px] text-neutral-500 tracking-widest mt-0.5 " }, "Switch Applications")), /* @__PURE__ */ import_react36.default.createElement(
1918
- "button",
1919
- {
1920
- onClick: () => setShowAppSwitcherDialog(false),
1921
- className: "w-8 h-8 flex items-center justify-center rounded-full hover:bg-neutral-100 text-neutral-400 transition-colors"
1922
- },
1923
- /* @__PURE__ */ import_react36.default.createElement(import_react37.HugeiconsIcon, { icon: import_core_free_icons8.CancelCircleIcon, size: 18 })
1924
- )), /* @__PURE__ */ import_react36.default.createElement("div", { className: "max-h-[60vh] overflow-y-auto w-full custom-scrollbar p-2" }, ECOSYSTEM_APPS.map((app) => {
1925
- const isActive = currentAppType === app.id;
1926
- return /* @__PURE__ */ import_react36.default.createElement(
1927
- "a",
1928
- {
1929
- key: app.id,
1930
- href: app.url,
1931
- className: `w-full text-left p-3 flex items-center gap-4 rounded-xl transition-all outline-none ${isActive ? " bg-neutral-50" : "hover:bg-neutral-50 border border-transparent"}`
1932
- },
1933
- /* @__PURE__ */ import_react36.default.createElement(
1934
- "img",
1935
- {
1936
- src: app.iconSrc,
1937
- alt: app.name,
1938
- className: "w-5 h-5 object-contain shrink-0"
1939
- }
1940
- ),
1941
- /* @__PURE__ */ import_react36.default.createElement("div", { className: "flex flex-col min-w-0 flex-1" }, /* @__PURE__ */ import_react36.default.createElement("span", { className: "text-[13px] text-black tracking-tight truncate" }, app.name), /* @__PURE__ */ import_react36.default.createElement("span", { className: "text-[11px] text-neutral-500 mt-0.5 truncate leading-snug" }, app.description))
1942
- );
1943
- })))), showSwitcherDialog && showWorkspaceSwitcher && workspaces && workspaces.length > 0 && /* @__PURE__ */ import_react36.default.createElement("div", { className: "fixed inset-0 z-110 flex items-center justify-center p-4 pointer-events-auto" }, /* @__PURE__ */ import_react36.default.createElement(
1890
+ ), showSwitcherDialog && showWorkspaceSwitcher && workspaces && workspaces.length > 0 && /* @__PURE__ */ import_react36.default.createElement("div", { className: "fixed inset-0 z-110 flex items-center justify-center p-4 pointer-events-auto" }, /* @__PURE__ */ import_react36.default.createElement(
1944
1891
  "div",
1945
1892
  {
1946
1893
  className: "absolute inset-0 bg-black/30",
@@ -2946,14 +2893,11 @@ var UniversalAgentConsole = ({
2946
2893
  if (pendingFiles.length === 0 || !selectedApp) return;
2947
2894
  setIsUploading(true);
2948
2895
  try {
2949
- const payloads = await Promise.all(pendingFiles.map(async (file) => {
2950
- const base64data = await new Promise((resolve, reject) => {
2951
- const reader = new FileReader();
2952
- reader.readAsDataURL(file);
2953
- reader.onload = () => resolve(reader.result);
2954
- reader.onerror = (error) => reject(error);
2955
- });
2956
- return { imageBase64: base64data, fileName: file.name, fileType: file.type, fileSize: file.size };
2896
+ const payloads = pendingFiles.map((file) => ({
2897
+ file,
2898
+ fileName: file.name,
2899
+ fileType: file.type,
2900
+ fileSize: file.size
2957
2901
  }));
2958
2902
  const res = await onUploadArchives(selectedApp.id, payloads);
2959
2903
  if (res.success) setPendingFiles([]);
@@ -3995,15 +3939,17 @@ var UniversalRegistrationFlow = ({
3995
3939
  if (optType === "other1") setIsUploadingOther1(true);
3996
3940
  else if (optType === "other2") setIsUploadingOther2(true);
3997
3941
  else if (optType === "other3") setIsUploadingOther3(true);
3998
- const base64data = await getBase64Safe(file);
3999
- const data = await baseApi("upload_document", { imageBase64: base64data, docType: optType });
4000
- if (data.success) {
3942
+ const data = await baseApi("upload_document", { fileName: file.name, contentType: file.type, fileSize: file.size, docType: optType });
3943
+ if (data.success && data.data.uploadUrl) {
3944
+ await fetch(data.data.uploadUrl, { method: "PUT", headers: { "Content-Type": file.type }, body: file });
4001
3945
  const updatedForm = { ...formData };
4002
3946
  const docNum = optType.replace("other", "");
4003
- updatedForm[`otherDoc${docNum}Url`] = data.data.fileUrl || base64data;
3947
+ updatedForm[`otherDoc${docNum}Url`] = data.data.fileUrl;
4004
3948
  updatedForm[`otherDoc${docNum}Meta`] = { fileName: file.name, contentType: file.type, fileSizeInBytes: file.size };
4005
3949
  setFormData(updatedForm);
4006
3950
  saveProgress(updatedForm);
3951
+ } else {
3952
+ throw new Error(data.error || "Failed to secure upload URL.");
4007
3953
  }
4008
3954
  } catch (error) {
4009
3955
  import_react_hot_toast7.default.error(error.message);
@@ -4075,33 +4021,37 @@ var UniversalRegistrationFlow = ({
4075
4021
  const file = e.target.files?.[0];
4076
4022
  if (!file) return;
4077
4023
  try {
4078
- const base64data = await getBase64Safe(file);
4079
4024
  if (docType === "id") {
4080
4025
  setGlobalExtractingId(true);
4081
4026
  setAiTasks([{ id: "1", label: "Document Scanned", status: "success" }, { id: "2", label: `Extracting ID for Member ${memberIndex + 1}...`, status: "loading" }]);
4027
+ const uploadData = await baseApi("upload_document", { fileName: file.name, contentType: file.type, fileSize: file.size, docType: `member_${memberIndex}_id` });
4028
+ if (!uploadData.success) throw new Error(uploadData.error || "Failed to secure upload URL.");
4029
+ await fetch(uploadData.data.uploadUrl, { method: "PUT", headers: { "Content-Type": file.type }, body: file });
4030
+ const base64data = await getBase64Safe(file);
4082
4031
  const data = await baseApi("extract_id", { imageBase64: base64data });
4083
4032
  if (data.success) {
4084
4033
  const updatedMembers = [...formData.members];
4085
- updatedMembers[memberIndex] = { ...updatedMembers[memberIndex], idExtractedData: data.data, idFileUrl: data.data.fileUrl || base64data, idMetadata: { fileName: file.name, contentType: file.type, fileSizeInBytes: file.size } };
4034
+ updatedMembers[memberIndex] = { ...updatedMembers[memberIndex], idExtractedData: data.data, idFileUrl: uploadData.data.fileUrl, idMetadata: { fileName: file.name, contentType: file.type, fileSizeInBytes: file.size } };
4086
4035
  setFormData({ ...formData, members: updatedMembers });
4087
4036
  saveProgress({ ...formData, members: updatedMembers });
4088
4037
  } else import_react_hot_toast7.default.error(data.error || "Uh oh! Something went wrong.");
4089
4038
  } else {
4090
4039
  if (docType === "passport") setGlobalUploadingPassport(true);
4091
4040
  else setGlobalUploadingSignature(true);
4092
- const data = await baseApi("upload_document", { imageBase64: base64data, docType: `member_${memberIndex}_${docType}` });
4093
- if (data.success) {
4041
+ const data = await baseApi("upload_document", { fileName: file.name, contentType: file.type, fileSize: file.size, docType: `member_${memberIndex}_${docType}` });
4042
+ if (data.success && data.data.uploadUrl) {
4043
+ await fetch(data.data.uploadUrl, { method: "PUT", headers: { "Content-Type": file.type }, body: file });
4094
4044
  const updatedMembers = [...formData.members];
4095
4045
  if (docType === "passport") {
4096
- updatedMembers[memberIndex].passportFileUrl = data.data.fileUrl || base64data;
4046
+ updatedMembers[memberIndex].passportFileUrl = data.data.fileUrl;
4097
4047
  updatedMembers[memberIndex].passportMetadata = { fileName: file.name, contentType: file.type, fileSizeInBytes: file.size };
4098
4048
  } else {
4099
- updatedMembers[memberIndex].signatureFileUrl = data.data.fileUrl || base64data;
4049
+ updatedMembers[memberIndex].signatureFileUrl = data.data.fileUrl;
4100
4050
  updatedMembers[memberIndex].signatureMetadata = { fileName: file.name, contentType: file.type, fileSizeInBytes: file.size };
4101
4051
  }
4102
4052
  setFormData({ ...formData, members: updatedMembers });
4103
4053
  saveProgress({ ...formData, members: updatedMembers });
4104
- } else import_react_hot_toast7.default.error(`Failed to upload ${docType}.`);
4054
+ } else import_react_hot_toast7.default.error(`Failed to secure upload URL for ${docType}.`);
4105
4055
  }
4106
4056
  } catch (error) {
4107
4057
  import_react_hot_toast7.default.error(error.message);
@@ -4139,14 +4089,17 @@ var UniversalRegistrationFlow = ({
4139
4089
  const file = e.target.files?.[0];
4140
4090
  if (!file) return;
4141
4091
  try {
4142
- const base64data = await getBase64Safe(file);
4143
4092
  if (docType === "id") {
4144
4093
  setGlobalExtractingId(true);
4145
4094
  setAiTasks([{ id: "1", label: "Document Scanned", status: "success" }, { id: "2", label: "Extracting Identity Data...", status: "loading" }]);
4095
+ const uploadData = await baseApi("upload_document", { fileName: file.name, contentType: file.type, fileSize: file.size, docType });
4096
+ if (!uploadData.success) throw new Error(uploadData.error || "Failed to secure upload URL.");
4097
+ await fetch(uploadData.data.uploadUrl, { method: "PUT", headers: { "Content-Type": file.type }, body: file });
4098
+ const base64data = await getBase64Safe(file);
4146
4099
  const data = await baseApi("extract_id", { imageBase64: base64data });
4147
4100
  if (data.success) {
4148
4101
  setAiTasks([{ id: "1", label: "Document Scanned", status: "success" }, { id: "2", label: "Identity Data Extracted", status: "success" }]);
4149
- const updatedForm = { ...formData, idExtractedData: data.data, idFileUrl: data.data.fileUrl || base64data, idMetadata: { fileName: file.name, contentType: file.type, fileSizeInBytes: file.size } };
4102
+ const updatedForm = { ...formData, idExtractedData: data.data, idFileUrl: uploadData.data.fileUrl, idMetadata: { fileName: file.name, contentType: file.type, fileSizeInBytes: file.size } };
4150
4103
  setFormData(updatedForm);
4151
4104
  saveProgress(updatedForm);
4152
4105
  } else {
@@ -4156,15 +4109,16 @@ var UniversalRegistrationFlow = ({
4156
4109
  } else {
4157
4110
  if (docType === "passport") setGlobalUploadingPassport(true);
4158
4111
  else setGlobalUploadingSignature(true);
4159
- const data = await baseApi("upload_document", { imageBase64: base64data, docType });
4160
- if (data.success) {
4112
+ const data = await baseApi("upload_document", { fileName: file.name, contentType: file.type, fileSize: file.size, docType });
4113
+ if (data.success && data.data.uploadUrl) {
4114
+ await fetch(data.data.uploadUrl, { method: "PUT", headers: { "Content-Type": file.type }, body: file });
4161
4115
  const updatedForm = { ...formData };
4162
4116
  if (docType === "passport") {
4163
- updatedForm.passportFileUrl = data.data.fileUrl || base64data;
4117
+ updatedForm.passportFileUrl = data.data.fileUrl;
4164
4118
  updatedForm.passportMetadata = { fileName: file.name, contentType: file.type, fileSizeInBytes: file.size };
4165
4119
  approveSection("passportApproved", updatedForm);
4166
4120
  } else {
4167
- updatedForm.signatureFileUrl = data.data.fileUrl || base64data;
4121
+ updatedForm.signatureFileUrl = data.data.fileUrl;
4168
4122
  updatedForm.signatureMetadata = { fileName: file.name, contentType: file.type, fileSizeInBytes: file.size };
4169
4123
  approveSection("signatureApproved", updatedForm);
4170
4124
  }
package/dist/index.mjs CHANGED
@@ -1640,18 +1640,12 @@ import {
1640
1640
  UserIcon,
1641
1641
  CheckmarkCircle01Icon,
1642
1642
  LogoutCircle02Icon,
1643
- ArrowLeft01Icon as ArrowLeft01Icon2,
1644
- CircleArrowDown01Icon
1643
+ ArrowLeft01Icon as ArrowLeft01Icon2
1645
1644
  } from "@hugeicons/core-free-icons";
1646
1645
  var ButtonSpinner = () => /* @__PURE__ */ React25.createElement("svg", { className: "animate-spin h-4 w-4 text-neutral-400", xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24" }, /* @__PURE__ */ React25.createElement("circle", { className: "opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4" }), /* @__PURE__ */ React25.createElement("path", { className: "opacity-75", fill: "currentColor", d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z" }));
1647
1646
  var ECOSYSTEM_APPS = [
1648
- { id: "desktop", name: "Retina Desktop", description: "Unified AI Workspace", iconSrc: "https://retinalabs.company/assets/images/desktop.avif", url: "https://retinadesktop.com/app" },
1649
- { id: "audditur", name: "Audditur", description: "AI Legal & Compliance", iconSrc: "https://retinalabs.company/assets/images/audditur.avif", url: "https://audditur.retinaapps.com/app" },
1650
- { id: "docx", name: "Retina Docx", description: "Collaborative Word Processing", iconSrc: "https://retinalabs.company/assets/images/docx.avif", url: "https://docx.retinaapps.com/app" },
1651
- { id: "sheets", name: "Retina Sheets", description: "Advanced Spreadsheets", iconSrc: "https://retinalabs.company/assets/images/sheets.avif", url: "https://sheets.retinaapps.com/app" },
1652
- { id: "drive", name: "Retina Drive", description: "Secure Cloud Storage", iconSrc: "https://retinalabs.company/assets/images/drive.avif", url: "https://drive.retinaapps.com/app" },
1653
- { id: "calendar", name: "Retina Calendar", description: "Smart Scheduling", iconSrc: "https://retinalabs.company/assets/images/calendar.avif", url: "https://calendar.retinaapps.com/app" },
1654
- { id: "mail", name: "Retina Mail", description: "Secure Email Inbox", iconSrc: "https://retinalabs.company/assets/images/mail.avif", url: "https://mail.retinaapps.com/app" }
1647
+ { id: "desktop", name: "Retina", description: "Ai Document Editor", iconSrc: "https://retinalabs.company/assets/images/desktop.avif", url: "https://app.retinaapps.com/" },
1648
+ { id: "audditur", name: "Audditur", description: "AI Legal & Compliance", iconSrc: "https://retinalabs.company/assets/images/audditur.avif", url: "https://app.audditur.com/" }
1655
1649
  ];
1656
1650
  var UniversalSidebar = ({
1657
1651
  navItems,
@@ -1679,7 +1673,6 @@ var UniversalSidebar = ({
1679
1673
  interceptMessage = "Are you sure you want to leave? All unsaved changes will be lost."
1680
1674
  }) => {
1681
1675
  const [isCollapsed, setIsCollapsed] = useState13(false);
1682
- const [showAppSwitcherDialog, setShowAppSwitcherDialog] = useState13(false);
1683
1676
  const [showSwitcherDialog, setShowSwitcherDialog] = useState13(false);
1684
1677
  const [showLogoutDialog, setShowLogoutDialog] = useState13(false);
1685
1678
  const [isLoggingOut, setIsLoggingOut] = useState13(false);
@@ -1742,29 +1735,14 @@ var UniversalSidebar = ({
1742
1735
  ${isCollapsed ? "md:w-16 w-64" : "w-64"}
1743
1736
  `
1744
1737
  },
1745
- /* @__PURE__ */ React25.createElement("div", { className: `flex items-center shrink-0 p-5 ${isCollapsed && !isMobileOpen ? "justify-center min-h-18" : "justify-between"}` }, /* @__PURE__ */ React25.createElement(
1746
- "button",
1738
+ /* @__PURE__ */ React25.createElement("div", { className: `flex items-center shrink-0 p-5 ${isCollapsed && !isMobileOpen ? "justify-center min-h-18" : "justify-between"}` }, /* @__PURE__ */ React25.createElement("div", { className: `flex items-center gap-3 text-left ${!isCollapsed || isMobileOpen ? "w-full" : ""}` }, currentAppConfig ? /* @__PURE__ */ React25.createElement(
1739
+ "img",
1747
1740
  {
1748
- onClick: () => setShowAppSwitcherDialog(true),
1749
- className: `flex items-center gap-3 outline-none group text-left ${!isCollapsed || isMobileOpen ? "w-full" : ""}`
1750
- },
1751
- currentAppConfig ? /* @__PURE__ */ React25.createElement(
1752
- "img",
1753
- {
1754
- src: currentAppConfig.iconSrc,
1755
- alt: currentAppConfig.name,
1756
- className: "w-5 h-5 rounded-md object-contain shrink-0 group-hover:scale-105 transition-transform"
1757
- }
1758
- ) : /* @__PURE__ */ React25.createElement("div", { className: " rounded-md shrink-0 flex items-center justify-center" }),
1759
- (!isCollapsed || isMobileOpen) && /* @__PURE__ */ React25.createElement(React25.Fragment, null, /* @__PURE__ */ React25.createElement("div", { className: "flex flex-col justify-center min-w-0 pr-2 flex-1" }, /* @__PURE__ */ React25.createElement("span", { className: "text-[13px] text-black leading-none truncate tracking-wide mb-1 group-hover:opacity-70 transition-opacity" }, title), subtitle && /* @__PURE__ */ React25.createElement("span", { className: "text-[9px] text-neutral-500 truncate tracking-[0.2em] leading-none " }, subtitle)), /* @__PURE__ */ React25.createElement(
1760
- HugeiconsIcon12,
1761
- {
1762
- icon: CircleArrowDown01Icon,
1763
- size: 20,
1764
- className: "text-neutral-400 shrink-0 group-hover:text-black transition-colors mr-3 ml-auto"
1765
- }
1766
- ))
1767
- ), /* @__PURE__ */ React25.createElement("div", { className: "md:hidden flex shrink-0" }, /* @__PURE__ */ React25.createElement(
1741
+ src: currentAppConfig.iconSrc,
1742
+ alt: currentAppConfig.name,
1743
+ className: "w-5 h-5 rounded-md object-contain shrink-0"
1744
+ }
1745
+ ) : /* @__PURE__ */ React25.createElement("div", { className: " rounded-md shrink-0 flex items-center justify-center" }), (!isCollapsed || isMobileOpen) && /* @__PURE__ */ React25.createElement("div", { className: "flex flex-col justify-center min-w-0 pr-2 flex-1" }, /* @__PURE__ */ React25.createElement("span", { className: "text-[13px] text-black leading-none truncate tracking-wide mb-1" }, title), subtitle && /* @__PURE__ */ React25.createElement("span", { className: "text-[9px] text-neutral-500 truncate tracking-[0.2em] leading-none " }, subtitle))), /* @__PURE__ */ React25.createElement("div", { className: "md:hidden flex shrink-0" }, /* @__PURE__ */ React25.createElement(
1768
1746
  "button",
1769
1747
  {
1770
1748
  onClick: closeMobile,
@@ -1830,39 +1808,7 @@ var UniversalSidebar = ({
1830
1808
  /* @__PURE__ */ React25.createElement(HugeiconsIcon12, { icon: SidebarLeft01Icon, size: 18, className: "shrink-0 text-neutral-400" }),
1831
1809
  !isCollapsed && /* @__PURE__ */ React25.createElement("span", { className: "text-xs" }, "Collapse")
1832
1810
  )))
1833
- ), showAppSwitcherDialog && /* @__PURE__ */ React25.createElement("div", { className: "fixed inset-0 z-110 flex items-center justify-center p-4 pointer-events-auto" }, /* @__PURE__ */ React25.createElement(
1834
- "div",
1835
- {
1836
- className: "absolute inset-0 bg-black/30 transition-opacity",
1837
- onClick: () => setShowAppSwitcherDialog(false)
1838
- }
1839
- ), /* @__PURE__ */ React25.createElement("div", { className: "relative w-full max-w-85 bg-white rounded-2xl flex flex-col overflow-hidden shadow-2xl animate-in zoom-in-95 duration-200" }, /* @__PURE__ */ React25.createElement("div", { className: "p-5 w-full flex items-center justify-between" }, /* @__PURE__ */ React25.createElement("div", null, /* @__PURE__ */ React25.createElement("h3", { className: "text-[15px] text-black tracking-tight " }, "Retina Apps"), /* @__PURE__ */ React25.createElement("p", { className: "text-[11px] text-neutral-500 tracking-widest mt-0.5 " }, "Switch Applications")), /* @__PURE__ */ React25.createElement(
1840
- "button",
1841
- {
1842
- onClick: () => setShowAppSwitcherDialog(false),
1843
- className: "w-8 h-8 flex items-center justify-center rounded-full hover:bg-neutral-100 text-neutral-400 transition-colors"
1844
- },
1845
- /* @__PURE__ */ React25.createElement(HugeiconsIcon12, { icon: CancelCircleIcon, size: 18 })
1846
- )), /* @__PURE__ */ React25.createElement("div", { className: "max-h-[60vh] overflow-y-auto w-full custom-scrollbar p-2" }, ECOSYSTEM_APPS.map((app) => {
1847
- const isActive = currentAppType === app.id;
1848
- return /* @__PURE__ */ React25.createElement(
1849
- "a",
1850
- {
1851
- key: app.id,
1852
- href: app.url,
1853
- className: `w-full text-left p-3 flex items-center gap-4 rounded-xl transition-all outline-none ${isActive ? " bg-neutral-50" : "hover:bg-neutral-50 border border-transparent"}`
1854
- },
1855
- /* @__PURE__ */ React25.createElement(
1856
- "img",
1857
- {
1858
- src: app.iconSrc,
1859
- alt: app.name,
1860
- className: "w-5 h-5 object-contain shrink-0"
1861
- }
1862
- ),
1863
- /* @__PURE__ */ React25.createElement("div", { className: "flex flex-col min-w-0 flex-1" }, /* @__PURE__ */ React25.createElement("span", { className: "text-[13px] text-black tracking-tight truncate" }, app.name), /* @__PURE__ */ React25.createElement("span", { className: "text-[11px] text-neutral-500 mt-0.5 truncate leading-snug" }, app.description))
1864
- );
1865
- })))), showSwitcherDialog && showWorkspaceSwitcher && workspaces && workspaces.length > 0 && /* @__PURE__ */ React25.createElement("div", { className: "fixed inset-0 z-110 flex items-center justify-center p-4 pointer-events-auto" }, /* @__PURE__ */ React25.createElement(
1811
+ ), showSwitcherDialog && showWorkspaceSwitcher && workspaces && workspaces.length > 0 && /* @__PURE__ */ React25.createElement("div", { className: "fixed inset-0 z-110 flex items-center justify-center p-4 pointer-events-auto" }, /* @__PURE__ */ React25.createElement(
1866
1812
  "div",
1867
1813
  {
1868
1814
  className: "absolute inset-0 bg-black/30",
@@ -2898,14 +2844,11 @@ var UniversalAgentConsole = ({
2898
2844
  if (pendingFiles.length === 0 || !selectedApp) return;
2899
2845
  setIsUploading(true);
2900
2846
  try {
2901
- const payloads = await Promise.all(pendingFiles.map(async (file) => {
2902
- const base64data = await new Promise((resolve, reject) => {
2903
- const reader = new FileReader();
2904
- reader.readAsDataURL(file);
2905
- reader.onload = () => resolve(reader.result);
2906
- reader.onerror = (error) => reject(error);
2907
- });
2908
- return { imageBase64: base64data, fileName: file.name, fileType: file.type, fileSize: file.size };
2847
+ const payloads = pendingFiles.map((file) => ({
2848
+ file,
2849
+ fileName: file.name,
2850
+ fileType: file.type,
2851
+ fileSize: file.size
2909
2852
  }));
2910
2853
  const res = await onUploadArchives(selectedApp.id, payloads);
2911
2854
  if (res.success) setPendingFiles([]);
@@ -3988,15 +3931,17 @@ var UniversalRegistrationFlow = ({
3988
3931
  if (optType === "other1") setIsUploadingOther1(true);
3989
3932
  else if (optType === "other2") setIsUploadingOther2(true);
3990
3933
  else if (optType === "other3") setIsUploadingOther3(true);
3991
- const base64data = await getBase64Safe(file);
3992
- const data = await baseApi("upload_document", { imageBase64: base64data, docType: optType });
3993
- if (data.success) {
3934
+ const data = await baseApi("upload_document", { fileName: file.name, contentType: file.type, fileSize: file.size, docType: optType });
3935
+ if (data.success && data.data.uploadUrl) {
3936
+ await fetch(data.data.uploadUrl, { method: "PUT", headers: { "Content-Type": file.type }, body: file });
3994
3937
  const updatedForm = { ...formData };
3995
3938
  const docNum = optType.replace("other", "");
3996
- updatedForm[`otherDoc${docNum}Url`] = data.data.fileUrl || base64data;
3939
+ updatedForm[`otherDoc${docNum}Url`] = data.data.fileUrl;
3997
3940
  updatedForm[`otherDoc${docNum}Meta`] = { fileName: file.name, contentType: file.type, fileSizeInBytes: file.size };
3998
3941
  setFormData(updatedForm);
3999
3942
  saveProgress(updatedForm);
3943
+ } else {
3944
+ throw new Error(data.error || "Failed to secure upload URL.");
4000
3945
  }
4001
3946
  } catch (error) {
4002
3947
  toast6.error(error.message);
@@ -4068,33 +4013,37 @@ var UniversalRegistrationFlow = ({
4068
4013
  const file = e.target.files?.[0];
4069
4014
  if (!file) return;
4070
4015
  try {
4071
- const base64data = await getBase64Safe(file);
4072
4016
  if (docType === "id") {
4073
4017
  setGlobalExtractingId(true);
4074
4018
  setAiTasks([{ id: "1", label: "Document Scanned", status: "success" }, { id: "2", label: `Extracting ID for Member ${memberIndex + 1}...`, status: "loading" }]);
4019
+ const uploadData = await baseApi("upload_document", { fileName: file.name, contentType: file.type, fileSize: file.size, docType: `member_${memberIndex}_id` });
4020
+ if (!uploadData.success) throw new Error(uploadData.error || "Failed to secure upload URL.");
4021
+ await fetch(uploadData.data.uploadUrl, { method: "PUT", headers: { "Content-Type": file.type }, body: file });
4022
+ const base64data = await getBase64Safe(file);
4075
4023
  const data = await baseApi("extract_id", { imageBase64: base64data });
4076
4024
  if (data.success) {
4077
4025
  const updatedMembers = [...formData.members];
4078
- updatedMembers[memberIndex] = { ...updatedMembers[memberIndex], idExtractedData: data.data, idFileUrl: data.data.fileUrl || base64data, idMetadata: { fileName: file.name, contentType: file.type, fileSizeInBytes: file.size } };
4026
+ updatedMembers[memberIndex] = { ...updatedMembers[memberIndex], idExtractedData: data.data, idFileUrl: uploadData.data.fileUrl, idMetadata: { fileName: file.name, contentType: file.type, fileSizeInBytes: file.size } };
4079
4027
  setFormData({ ...formData, members: updatedMembers });
4080
4028
  saveProgress({ ...formData, members: updatedMembers });
4081
4029
  } else toast6.error(data.error || "Uh oh! Something went wrong.");
4082
4030
  } else {
4083
4031
  if (docType === "passport") setGlobalUploadingPassport(true);
4084
4032
  else setGlobalUploadingSignature(true);
4085
- const data = await baseApi("upload_document", { imageBase64: base64data, docType: `member_${memberIndex}_${docType}` });
4086
- if (data.success) {
4033
+ const data = await baseApi("upload_document", { fileName: file.name, contentType: file.type, fileSize: file.size, docType: `member_${memberIndex}_${docType}` });
4034
+ if (data.success && data.data.uploadUrl) {
4035
+ await fetch(data.data.uploadUrl, { method: "PUT", headers: { "Content-Type": file.type }, body: file });
4087
4036
  const updatedMembers = [...formData.members];
4088
4037
  if (docType === "passport") {
4089
- updatedMembers[memberIndex].passportFileUrl = data.data.fileUrl || base64data;
4038
+ updatedMembers[memberIndex].passportFileUrl = data.data.fileUrl;
4090
4039
  updatedMembers[memberIndex].passportMetadata = { fileName: file.name, contentType: file.type, fileSizeInBytes: file.size };
4091
4040
  } else {
4092
- updatedMembers[memberIndex].signatureFileUrl = data.data.fileUrl || base64data;
4041
+ updatedMembers[memberIndex].signatureFileUrl = data.data.fileUrl;
4093
4042
  updatedMembers[memberIndex].signatureMetadata = { fileName: file.name, contentType: file.type, fileSizeInBytes: file.size };
4094
4043
  }
4095
4044
  setFormData({ ...formData, members: updatedMembers });
4096
4045
  saveProgress({ ...formData, members: updatedMembers });
4097
- } else toast6.error(`Failed to upload ${docType}.`);
4046
+ } else toast6.error(`Failed to secure upload URL for ${docType}.`);
4098
4047
  }
4099
4048
  } catch (error) {
4100
4049
  toast6.error(error.message);
@@ -4132,14 +4081,17 @@ var UniversalRegistrationFlow = ({
4132
4081
  const file = e.target.files?.[0];
4133
4082
  if (!file) return;
4134
4083
  try {
4135
- const base64data = await getBase64Safe(file);
4136
4084
  if (docType === "id") {
4137
4085
  setGlobalExtractingId(true);
4138
4086
  setAiTasks([{ id: "1", label: "Document Scanned", status: "success" }, { id: "2", label: "Extracting Identity Data...", status: "loading" }]);
4087
+ const uploadData = await baseApi("upload_document", { fileName: file.name, contentType: file.type, fileSize: file.size, docType });
4088
+ if (!uploadData.success) throw new Error(uploadData.error || "Failed to secure upload URL.");
4089
+ await fetch(uploadData.data.uploadUrl, { method: "PUT", headers: { "Content-Type": file.type }, body: file });
4090
+ const base64data = await getBase64Safe(file);
4139
4091
  const data = await baseApi("extract_id", { imageBase64: base64data });
4140
4092
  if (data.success) {
4141
4093
  setAiTasks([{ id: "1", label: "Document Scanned", status: "success" }, { id: "2", label: "Identity Data Extracted", status: "success" }]);
4142
- const updatedForm = { ...formData, idExtractedData: data.data, idFileUrl: data.data.fileUrl || base64data, idMetadata: { fileName: file.name, contentType: file.type, fileSizeInBytes: file.size } };
4094
+ const updatedForm = { ...formData, idExtractedData: data.data, idFileUrl: uploadData.data.fileUrl, idMetadata: { fileName: file.name, contentType: file.type, fileSizeInBytes: file.size } };
4143
4095
  setFormData(updatedForm);
4144
4096
  saveProgress(updatedForm);
4145
4097
  } else {
@@ -4149,15 +4101,16 @@ var UniversalRegistrationFlow = ({
4149
4101
  } else {
4150
4102
  if (docType === "passport") setGlobalUploadingPassport(true);
4151
4103
  else setGlobalUploadingSignature(true);
4152
- const data = await baseApi("upload_document", { imageBase64: base64data, docType });
4153
- if (data.success) {
4104
+ const data = await baseApi("upload_document", { fileName: file.name, contentType: file.type, fileSize: file.size, docType });
4105
+ if (data.success && data.data.uploadUrl) {
4106
+ await fetch(data.data.uploadUrl, { method: "PUT", headers: { "Content-Type": file.type }, body: file });
4154
4107
  const updatedForm = { ...formData };
4155
4108
  if (docType === "passport") {
4156
- updatedForm.passportFileUrl = data.data.fileUrl || base64data;
4109
+ updatedForm.passportFileUrl = data.data.fileUrl;
4157
4110
  updatedForm.passportMetadata = { fileName: file.name, contentType: file.type, fileSizeInBytes: file.size };
4158
4111
  approveSection("passportApproved", updatedForm);
4159
4112
  } else {
4160
- updatedForm.signatureFileUrl = data.data.fileUrl || base64data;
4113
+ updatedForm.signatureFileUrl = data.data.fileUrl;
4161
4114
  updatedForm.signatureMetadata = { fileName: file.name, contentType: file.type, fileSizeInBytes: file.size };
4162
4115
  approveSection("signatureApproved", updatedForm);
4163
4116
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@retinalabsllc/zairusjs",
3
- "version": "4.0.12",
3
+ "version": "4.0.14",
4
4
  "description": "A perceptive, Ai data driven Next.js UI component library.",
5
5
  "author": "Retina Labs Company",
6
6
  "license": "MIT",