@fleox-agent-crm/agentcrm 0.0.0-stage → 0.3.0

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.
Files changed (129) hide show
  1. package/LICENSE +143 -0
  2. package/README.md +223 -2
  3. package/changelog.json +57 -0
  4. package/dist/admin/admin-files.json +26 -0
  5. package/dist/admin/assets/chartsImpl-CE2akJat.js +91 -0
  6. package/dist/admin/assets/firebase-BHSUggRo.js +2 -0
  7. package/dist/admin/assets/gitJson-BulGh2KV.js +3 -0
  8. package/dist/admin/assets/index-DidVVK7L.js +1181 -0
  9. package/dist/admin/assets/index-hMXwHSvN.css +1 -0
  10. package/dist/admin/assets/index.esm-BFc7vwnl.js +400 -0
  11. package/dist/admin/assets/index.esm-CtEQZRb1.js +1651 -0
  12. package/dist/admin/assets/index.esm-Dum0J07z.js +16 -0
  13. package/dist/admin/assets/index.esm2017-EOzKbpUS.js +390 -0
  14. package/dist/admin/assets/lucide-react.min-DEDlHCPj.js +6 -0
  15. package/dist/admin/assets/sdk-CnrLnlRo.js +1717 -0
  16. package/dist/admin/config.js +3 -0
  17. package/dist/admin/favicon.svg +1 -0
  18. package/dist/admin/index.html +139 -0
  19. package/dist/admin/runtime/agentcrm-runtime.js +104 -0
  20. package/dist/admin/runtime/lucide-react.js +791 -0
  21. package/dist/admin/runtime/react-dom-client.js +17 -0
  22. package/dist/admin/runtime/react-dom.js +20 -0
  23. package/dist/admin/runtime/react-i18next.js +19 -0
  24. package/dist/admin/runtime/react-jsx-runtime.js +17 -0
  25. package/dist/admin/runtime/react.js +22 -0
  26. package/dist/agent/agentcrm.mjs +3932 -0
  27. package/dist/agent/chunks/_commonjsHelpers-ClciMIcB.mjs +14 -0
  28. package/dist/agent/chunks/activities-Cj_SIOay.mjs +227 -0
  29. package/dist/agent/chunks/api-B6OqNVWp.mjs +97 -0
  30. package/dist/agent/chunks/appearance-BaShelzt.mjs +174 -0
  31. package/dist/agent/chunks/automations-BWrvLqP6.mjs +698 -0
  32. package/dist/agent/chunks/backup-ClSmxmFZ.mjs +103 -0
  33. package/dist/agent/chunks/batch-CVETiJj5.mjs +142 -0
  34. package/dist/agent/chunks/compact-CsFPaAAq.mjs +69 -0
  35. package/dist/agent/chunks/context-CxFfqS4D.mjs +65 -0
  36. package/dist/agent/chunks/core-Dy7vY9H6.mjs +255 -0
  37. package/dist/agent/chunks/dedupe-BepmsaHv.mjs +123 -0
  38. package/dist/agent/chunks/encoding-C9MzdP95.mjs +36 -0
  39. package/dist/agent/chunks/exportCsv-B5hRvkNm.mjs +95 -0
  40. package/dist/agent/chunks/extCheck--7lmVvl7.mjs +193 -0
  41. package/dist/agent/chunks/extPackage-BGl5Oqs8.mjs +115 -0
  42. package/dist/agent/chunks/extScaffold-DqxI7R1e.mjs +320 -0
  43. package/dist/agent/chunks/extensionActions-D2HtpQz4.mjs +48 -0
  44. package/dist/agent/chunks/extensions-BP1k60md.mjs +151 -0
  45. package/dist/agent/chunks/featureRegistry-C9nbVShp.mjs +149 -0
  46. package/dist/agent/chunks/fields-B0bitgmr.mjs +476 -0
  47. package/dist/agent/chunks/files-CjsPJSR6.mjs +158 -0
  48. package/dist/agent/chunks/files-q8Xu5bft.mjs +367 -0
  49. package/dist/agent/chunks/firebase-DxGVQV9E.mjs +454 -0
  50. package/dist/agent/chunks/firebaseRules-iori-s7U.mjs +221 -0
  51. package/dist/agent/chunks/forms-BKU5F9WF.mjs +847 -0
  52. package/dist/agent/chunks/gitJson-fjr8mcHe.mjs +528 -0
  53. package/dist/agent/chunks/hosting-Bme7LxPc.mjs +144 -0
  54. package/dist/agent/chunks/http-Bk9ICb7I.mjs +127 -0
  55. package/dist/agent/chunks/ids-CvnmrMJX.mjs +59 -0
  56. package/dist/agent/chunks/ids-u-noYcy5.mjs +14 -0
  57. package/dist/agent/chunks/importCsv-DmE_sBch.mjs +334 -0
  58. package/dist/agent/chunks/index-B-4W0-P4.mjs +535 -0
  59. package/dist/agent/chunks/index-BM8qeGOb.mjs +2489 -0
  60. package/dist/agent/chunks/index-Bnmav-Oh.mjs +311 -0
  61. package/dist/agent/chunks/index-CRkw3_iF.mjs +147 -0
  62. package/dist/agent/chunks/index-CWrrF1wl.mjs +111 -0
  63. package/dist/agent/chunks/index-DUSdTBkz.mjs +2988 -0
  64. package/dist/agent/chunks/index-RCmo-uld.mjs +26 -0
  65. package/dist/agent/chunks/index-w03ReRs4.mjs +9780 -0
  66. package/dist/agent/chunks/install-CpHoUFtL.mjs +188 -0
  67. package/dist/agent/chunks/jsx-runtime-Ca2uwGDr.mjs +76 -0
  68. package/dist/agent/chunks/loader-C9nm3iwx.mjs +184 -0
  69. package/dist/agent/chunks/lucide-react.min-Bt3gtepY.mjs +64 -0
  70. package/dist/agent/chunks/memory-WNR3VHUJ.mjs +56 -0
  71. package/dist/agent/chunks/migrate-CsClnnN8.mjs +182 -0
  72. package/dist/agent/chunks/modules-CqdVQVJb.mjs +177 -0
  73. package/dist/agent/chunks/nodeImport-BPCt5uMu.mjs +38 -0
  74. package/dist/agent/chunks/package-DWbn3t2R.mjs +194 -0
  75. package/dist/agent/chunks/papaparse-DjBYnQM2.mjs +1285 -0
  76. package/dist/agent/chunks/pipelines-DCdRBNBV.mjs +234 -0
  77. package/dist/agent/chunks/plan-C0TBrU92.mjs +254 -0
  78. package/dist/agent/chunks/pluginRegistry-DyHtlkcr.mjs +83 -0
  79. package/dist/agent/chunks/query-C5nJB_3C.mjs +192 -0
  80. package/dist/agent/chunks/records-DoqiT9xR.mjs +2191 -0
  81. package/dist/agent/chunks/registry-Ceexawxl.mjs +182 -0
  82. package/dist/agent/chunks/registry-DijAKZ24.mjs +431 -0
  83. package/dist/agent/chunks/relations-B9TynBmA.mjs +191 -0
  84. package/dist/agent/chunks/reports-BB59N6ke.mjs +189 -0
  85. package/dist/agent/chunks/runtime-DHo7ZEEO.mjs +14852 -0
  86. package/dist/agent/chunks/runtimeConfig-CCOFg1RM.mjs +250 -0
  87. package/dist/agent/chunks/s3-Dz50-NuA.mjs +903 -0
  88. package/dist/agent/chunks/schema-7-4-qtSS.mjs +203 -0
  89. package/dist/agent/chunks/schema-DlHt2PxI.mjs +367 -0
  90. package/dist/agent/chunks/sdk-whvfg786.mjs +43644 -0
  91. package/dist/agent/chunks/seed-CugPGYZL.mjs +523 -0
  92. package/dist/agent/chunks/server-ISwlDRCN.mjs +242 -0
  93. package/dist/agent/chunks/settings-BtvR_jdm.mjs +76 -0
  94. package/dist/agent/chunks/standardObjects-CheqfDqa.mjs +243 -0
  95. package/dist/agent/chunks/stats-CfeJssSS.mjs +51 -0
  96. package/dist/agent/chunks/store-5gqRSKXg.mjs +122 -0
  97. package/dist/agent/chunks/themes-DPZFv3yc.mjs +43 -0
  98. package/dist/agent/chunks/tools-Bew8lxKx.mjs +844 -0
  99. package/dist/agent/chunks/types-BOy9PUl7.mjs +44 -0
  100. package/dist/agent/chunks/users-DI1BvS0f.mjs +107 -0
  101. package/dist/agent/chunks/utils-DmI8FtXP.mjs +83 -0
  102. package/dist/agent/chunks/views-fO_BM5U_.mjs +109 -0
  103. package/dist/version.json +7 -0
  104. package/package.json +97 -4
  105. package/plugin/.claude-plugin/plugin.json +17 -0
  106. package/plugin/skills/agentcrm-admin/SKILL.md +191 -0
  107. package/plugin/skills/agentcrm-admin/references/appearance.md +26 -0
  108. package/plugin/skills/agentcrm-admin/references/import.md +16 -0
  109. package/plugin/skills/agentcrm-admin/references/records.md +30 -0
  110. package/plugin/skills/agentcrm-admin/references/schema.md +59 -0
  111. package/plugin/skills/agentcrm-extensions/SKILL.md +93 -0
  112. package/plugin/skills/agentcrm-extensions/references/module-recipes.md +213 -0
  113. package/plugin/skills/agentcrm-extensions/references/runtime-api.md +41 -0
  114. package/plugin/skills/agentcrm-extensions/references/testing.md +76 -0
  115. package/plugin/skills/agentcrm-extensions/references/theme-recipes.md +65 -0
  116. package/plugin/skills/agentcrm-install/SKILL.md +116 -0
  117. package/plugin/skills/agentcrm-install/references/firebase.md +18 -0
  118. package/plugin/skills/agentcrm-install/references/github.md +20 -0
  119. package/plugin/skills/agentcrm-install/references/mcp.md +17 -0
  120. package/plugin/skills/agentcrm-install/references/plans.md +45 -0
  121. package/plugin/skills/agentcrm-install/references/s3.md +24 -0
  122. package/plugin/skills/agentcrm-manage/SKILL.md +108 -0
  123. package/plugin/skills/agentcrm-manage/references/cron.md +11 -0
  124. package/plugin/skills/agentcrm-manage/references/doctor.md +18 -0
  125. package/plugin/skills/agentcrm-sales/SKILL.md +92 -0
  126. package/plugin/skills/agentcrm-sales/references/enrichment.md +13 -0
  127. package/plugin/skills/agentcrm-sales/references/playbooks.md +29 -0
  128. package/plugin/skills/agentcrm-sales/references/weekly-report.md +27 -0
  129. package/types/agentcrm-runtime.d.ts +894 -0
@@ -0,0 +1,182 @@
1
+ import { createRequire as __acrmRequire } from "node:module";
2
+ import { fileURLToPath as __acrmPath } from "node:url";
3
+ import { dirname as __acrmDirname } from "node:path";
4
+ const require2 = __acrmRequire(import.meta.url);
5
+ const __filename = __acrmPath(import.meta.url);
6
+ const __dirname = __acrmDirname(__filename);
7
+ import { i as isCompatibleApiVersion } from "./api-B6OqNVWp.mjs";
8
+ import { registerExternalFeature } from "./featureRegistry-C9nbVShp.mjs";
9
+ import { registerAiTool } from "./tools-Bew8lxKx.mjs";
10
+ import { registerAutomationAction } from "./extensionActions-D2HtpQz4.mjs";
11
+ import { plugins } from "./pluginRegistry-DyHtlkcr.mjs";
12
+ import { registerExternalTheme } from "./themes-DPZFv3yc.mjs";
13
+ import "./index-Bnmav-Oh.mjs";
14
+ import "./_commonjsHelpers-ClciMIcB.mjs";
15
+ import "./index-BM8qeGOb.mjs";
16
+ import "./modules-CqdVQVJb.mjs";
17
+ import "./context-CxFfqS4D.mjs";
18
+ import "./settings-BtvR_jdm.mjs";
19
+ import "./store-5gqRSKXg.mjs";
20
+ import "./runtimeConfig-CCOFg1RM.mjs";
21
+ import "./fields-B0bitgmr.mjs";
22
+ import "./query-C5nJB_3C.mjs";
23
+ import "../agentcrm.mjs";
24
+ import "node:util";
25
+ import "node:fs";
26
+ import "node:path";
27
+ import "node:url";
28
+ import "node:crypto";
29
+ import "node:os";
30
+ import "node:child_process";
31
+ import "node:http";
32
+ import "./activities-Cj_SIOay.mjs";
33
+ import "./ids-CvnmrMJX.mjs";
34
+ import "./relations-B9TynBmA.mjs";
35
+ import "./dedupe-BepmsaHv.mjs";
36
+ import "./importCsv-DmE_sBch.mjs";
37
+ import "./papaparse-DjBYnQM2.mjs";
38
+ import "stream";
39
+ import "./utils-DmI8FtXP.mjs";
40
+ import "./records-DoqiT9xR.mjs";
41
+ import "./standardObjects-CheqfDqa.mjs";
42
+ import "./pipelines-DCdRBNBV.mjs";
43
+ import "./reports-BB59N6ke.mjs";
44
+ import "./schema-DlHt2PxI.mjs";
45
+ import "./automations-BWrvLqP6.mjs";
46
+ import "./forms-BKU5F9WF.mjs";
47
+ import "./schema-7-4-qtSS.mjs";
48
+ import "./appearance-BaShelzt.mjs";
49
+ import "./extensions-BP1k60md.mjs";
50
+ import "./package-DWbn3t2R.mjs";
51
+ import "./index-w03ReRs4.mjs";
52
+ import "events";
53
+ import "buffer";
54
+ import "util";
55
+ import "./files-CjsPJSR6.mjs";
56
+ import "./files-q8Xu5bft.mjs";
57
+ import "./index-RCmo-uld.mjs";
58
+ import "./http-Bk9ICb7I.mjs";
59
+ const entries = /* @__PURE__ */ new Map();
60
+ const listeners = /* @__PURE__ */ new Set();
61
+ let snapshot = [];
62
+ function notify() {
63
+ snapshot = [...entries.values()].map((e) => e.state).sort((a, b) => a.id.localeCompare(b.id));
64
+ for (const l of [...listeners]) l();
65
+ }
66
+ function listLoadedExtensions() {
67
+ return snapshot;
68
+ }
69
+ function getLoadedExtension(id) {
70
+ return entries.get(id)?.state;
71
+ }
72
+ function subscribeLoadedExtensions(listener) {
73
+ listeners.add(listener);
74
+ return () => listeners.delete(listener);
75
+ }
76
+ function setExtensionStatus(doc, status, error) {
77
+ const prev = entries.get(doc.id);
78
+ if (prev) prev.dispose();
79
+ entries.set(doc.id, { state: { id: doc.id, kind: doc.kind, version: doc.manifest.version, status, ...error ? { error } : {} }, dispose: () => void 0 });
80
+ notify();
81
+ }
82
+ function deactivateExtension(id) {
83
+ const e = entries.get(id);
84
+ if (!e) return;
85
+ entries.delete(id);
86
+ try {
87
+ e.dispose();
88
+ } catch (err) {
89
+ console.error(`[extensions] dispose of ${id} failed:`, err);
90
+ }
91
+ notify();
92
+ }
93
+ function deactivateAllExtensions() {
94
+ for (const id of [...entries.keys()]) deactivateExtension(id);
95
+ }
96
+ function asDefinition(mod) {
97
+ const m = mod;
98
+ const def = m && typeof m === "object" && "default" in m ? m.default : null;
99
+ return def && typeof def === "object" ? def : null;
100
+ }
101
+ function checkDefinition(doc, def) {
102
+ if (!def) throw new Error("bundle.js has no default export (export default defineModule({...}) / defineTheme({...})).");
103
+ if (def.id !== doc.id) throw new Error(`bundle id "${String(def.id)}" doesn't match manifest id "${doc.id}".`);
104
+ if (!isCompatibleApiVersion(def.apiVersion)) throw new Error(`bundle apiVersion "${String(def.apiVersion)}" is not supported.`);
105
+ }
106
+ function styleInjector(id, css) {
107
+ if (!css || typeof document === "undefined") return () => void 0;
108
+ const el = document.createElement("style");
109
+ el.dataset.agentcrmExtension = id;
110
+ el.textContent = css;
111
+ document.head.appendChild(el);
112
+ return () => el.remove();
113
+ }
114
+ function activateModule(doc, def) {
115
+ const disposers = [];
116
+ const track = (off) => {
117
+ disposers.push(off);
118
+ return off;
119
+ };
120
+ try {
121
+ const m = doc.manifest;
122
+ const feature = {
123
+ routes: [],
124
+ i18n: { en: {} },
125
+ ...def.feature ?? {},
126
+ id: doc.id,
127
+ module: { name: m.name, description: m.description, icon: m.icon ?? "Puzzle", category: m.category ?? "customisation", ...m.dependsOn?.length ? { dependsOn: m.dependsOn } : {} },
128
+ ...def.settingsPage ? { settingsPage: def.settingsPage } : {}
129
+ };
130
+ track(registerExternalFeature(feature));
131
+ for (const tool of def.aiTools ?? []) track(registerAiTool(tool));
132
+ for (const action of def.automationActions ?? []) track(registerAutomationAction(action));
133
+ track(styleInjector(doc.id, doc.files["style.css"]));
134
+ if (typeof def.register === "function") {
135
+ const api = {
136
+ moduleId: doc.id,
137
+ addAction: ((hook, fn, priority) => track(plugins.addAction(hook, fn, priority))),
138
+ addFilter: (hook, fn, priority) => track(plugins.addFilter(hook, fn, priority)),
139
+ registerAiTool: (tool) => track(registerAiTool(tool)),
140
+ registerAutomationAction: (action) => track(registerAutomationAction(action)),
141
+ onDispose: (fn) => void disposers.push(fn)
142
+ };
143
+ const cleanup = def.register(api);
144
+ if (typeof cleanup === "function") disposers.push(cleanup);
145
+ }
146
+ } catch (err) {
147
+ for (const d of disposers.reverse()) d();
148
+ throw err;
149
+ }
150
+ return () => {
151
+ for (const d of disposers.reverse()) {
152
+ try {
153
+ d();
154
+ } catch (err) {
155
+ console.error(`[extensions] cleanup of ${doc.id} failed:`, err);
156
+ }
157
+ }
158
+ };
159
+ }
160
+ function activateTheme(doc, def) {
161
+ if (!def.appearance || typeof def.appearance !== "object") throw new Error("defineTheme({ appearance }) is required.");
162
+ if (typeof def.name !== "string" || !def.name) throw new Error("defineTheme({ name }) is required.");
163
+ const css = [def.css, doc.files["style.css"]].filter(Boolean).join("\n");
164
+ return registerExternalTheme({ id: doc.id, apiVersion: def.apiVersion, name: def.name, ...def.description ? { description: def.description } : {}, appearance: { ...def.appearance }, ...css ? { css } : {} });
165
+ }
166
+ function activateExtension(doc, mod, fingerprint) {
167
+ const def = asDefinition(mod);
168
+ checkDefinition(doc, def);
169
+ deactivateExtension(doc.id);
170
+ const dispose = doc.kind === "theme" ? activateTheme(doc, def) : activateModule(doc, def);
171
+ entries.set(doc.id, { state: { id: doc.id, kind: doc.kind, version: doc.manifest.version, status: "loaded", fingerprint }, dispose });
172
+ notify();
173
+ }
174
+ export {
175
+ activateExtension,
176
+ deactivateAllExtensions,
177
+ deactivateExtension,
178
+ getLoadedExtension,
179
+ listLoadedExtensions,
180
+ setExtensionStatus,
181
+ subscribeLoadedExtensions
182
+ };
@@ -0,0 +1,431 @@
1
+ import { createRequire as __acrmRequire } from "node:module";
2
+ import { fileURLToPath as __acrmPath } from "node:url";
3
+ import { dirname as __acrmDirname } from "node:path";
4
+ const require2 = __acrmRequire(import.meta.url);
5
+ const __filename = __acrmPath(import.meta.url);
6
+ const __dirname = __acrmDirname(__filename);
7
+ import { i as instance } from "./index-BM8qeGOb.mjs";
8
+ import { S as StorageError, t as toast } from "./http-Bk9ICb7I.mjs";
9
+ import "./index-w03ReRs4.mjs";
10
+ import { c as changeToBytes, d as base64ToBytes, a as base64ToUtf8 } from "./encoding-C9MzdP95.mjs";
11
+ import { G as GitConflictError, g as gitPagesFactory, s as s3Factory } from "./s3-Dz50-NuA.mjs";
12
+ const IGNORED = /* @__PURE__ */ new Set([".git", "node_modules", ".DS_Store", "Thumbs.db"]);
13
+ async function ensureFolderPermission(handle, request) {
14
+ const dir = handle;
15
+ const desc = { mode: "readwrite" };
16
+ if (await dir.queryPermission?.(desc) === "granted") return true;
17
+ return false;
18
+ }
19
+ function fingerprint(entries) {
20
+ let h = 2166136261;
21
+ for (const e of entries) {
22
+ const line = `${e.path}\0${e.sha}
23
+ `;
24
+ for (let i = 0; i < line.length; i++) {
25
+ h ^= line.charCodeAt(i);
26
+ h = Math.imul(h, 16777619);
27
+ }
28
+ }
29
+ return `local-${entries.length}-${(h >>> 0).toString(16)}`;
30
+ }
31
+ function createLocalFsTransport(handle) {
32
+ const root = handle;
33
+ const files = /* @__PURE__ */ new Map();
34
+ async function walk(dir, prefix, out) {
35
+ for await (const [name, child] of dir.entries()) {
36
+ if (IGNORED.has(name)) continue;
37
+ const path = prefix + name;
38
+ if (child.kind === "directory") {
39
+ await walk(child, path + "/", out);
40
+ } else {
41
+ const file = await child.getFile();
42
+ files.set(path, child);
43
+ out.push({ path, sha: `${file.size}:${file.lastModified}`, size: file.size });
44
+ }
45
+ }
46
+ }
47
+ async function listTree() {
48
+ files.clear();
49
+ const entries = [];
50
+ await walk(root, "", entries);
51
+ entries.sort((a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0);
52
+ return { headSha: fingerprint(entries), entries };
53
+ }
54
+ async function fileHandle(path) {
55
+ const cached = files.get(path);
56
+ if (cached) return cached;
57
+ const parts = path.split("/");
58
+ let dir = root;
59
+ for (const part of parts.slice(0, -1)) dir = await dir.getDirectoryHandle(part);
60
+ return dir.getFileHandle(parts[parts.length - 1]);
61
+ }
62
+ async function readTexts(entries) {
63
+ const out = /* @__PURE__ */ new Map();
64
+ for (const e of entries) {
65
+ try {
66
+ out.set(e.path, await (await (await fileHandle(e.path)).getFile()).text());
67
+ } catch {
68
+ }
69
+ }
70
+ return out;
71
+ }
72
+ async function readBytes(entry) {
73
+ const file = await (await fileHandle(entry.path)).getFile();
74
+ return new Uint8Array(await file.arrayBuffer());
75
+ }
76
+ async function writeFile(path, bytes) {
77
+ const parts = path.split("/");
78
+ let dir = root;
79
+ for (const part of parts.slice(0, -1)) dir = await dir.getDirectoryHandle(part, { create: true });
80
+ const file = await dir.getFileHandle(parts[parts.length - 1], { create: true });
81
+ const writable = await file.createWritable();
82
+ await writable.write(bytes);
83
+ await writable.close();
84
+ files.set(path, file);
85
+ }
86
+ async function removeFile(path) {
87
+ const parts = path.split("/");
88
+ try {
89
+ let dir = root;
90
+ for (const part of parts.slice(0, -1)) dir = await dir.getDirectoryHandle(part);
91
+ await dir.removeEntry(parts[parts.length - 1]);
92
+ } catch {
93
+ }
94
+ files.delete(path);
95
+ }
96
+ async function commit(changes, opts) {
97
+ if (opts.expectedHeadSha !== void 0) {
98
+ const current = (await listTree()).headSha;
99
+ if (current !== opts.expectedHeadSha) throw new GitConflictError("Folder changed on disk", current);
100
+ }
101
+ for (const change of changes) {
102
+ if (change.type === "delete") await removeFile(change.path);
103
+ else await writeFile(change.path, changeToBytes(change));
104
+ }
105
+ return (await listTree()).headSha;
106
+ }
107
+ return {
108
+ kind: "local",
109
+ label: root.name,
110
+ headSha: async () => (await listTree()).headSha,
111
+ listTree,
112
+ readTexts,
113
+ readBytes,
114
+ commit,
115
+ permissions: async () => ({
116
+ login: "local",
117
+ canWrite: await ensureFolderPermission(handle),
118
+ isAdmin: true
119
+ })
120
+ };
121
+ }
122
+ const DB_NAME = "agentcrm-folder-handles";
123
+ const STORE = "handles";
124
+ function openDb() {
125
+ return new Promise((resolve, reject) => {
126
+ const req = indexedDB.open(DB_NAME, 1);
127
+ req.onupgradeneeded = () => req.result.createObjectStore(STORE);
128
+ req.onsuccess = () => resolve(req.result);
129
+ req.onerror = () => reject(req.error);
130
+ });
131
+ }
132
+ async function loadFolderHandle(key) {
133
+ try {
134
+ const db = await openDb();
135
+ return await new Promise((resolve) => {
136
+ const req = db.transaction(STORE, "readonly").objectStore(STORE).get(key);
137
+ req.onsuccess = () => resolve(req.result ?? null);
138
+ req.onerror = () => resolve(null);
139
+ });
140
+ } catch {
141
+ return null;
142
+ }
143
+ }
144
+ function createKvStore(dbName, storeName = "kv") {
145
+ const memory = /* @__PURE__ */ new Map();
146
+ let dbPromise = null;
147
+ function db() {
148
+ if (!dbPromise) {
149
+ dbPromise = new Promise((resolve) => {
150
+ try {
151
+ if (typeof indexedDB === "undefined") return resolve(null);
152
+ const req = indexedDB.open(dbName, 1);
153
+ req.onupgradeneeded = () => req.result.createObjectStore(storeName);
154
+ req.onsuccess = () => resolve(req.result);
155
+ req.onerror = () => resolve(null);
156
+ req.onblocked = () => resolve(null);
157
+ } catch {
158
+ resolve(null);
159
+ }
160
+ });
161
+ }
162
+ return dbPromise;
163
+ }
164
+ function run(mode, fn) {
165
+ return db().then(
166
+ (d) => new Promise((resolve, reject) => {
167
+ if (!d) return resolve(void 0);
168
+ const tx = d.transaction(storeName, mode);
169
+ const req = fn(tx.objectStore(storeName));
170
+ tx.oncomplete = () => resolve(req ? req.result : void 0);
171
+ tx.onerror = () => reject(tx.error);
172
+ tx.onabort = () => reject(tx.error);
173
+ })
174
+ );
175
+ }
176
+ return {
177
+ async get(key) {
178
+ if (!await db()) return memory.get(key);
179
+ return run("readonly", (s) => s.get(key));
180
+ },
181
+ async set(key, value) {
182
+ if (!await db()) return void memory.set(key, value);
183
+ await run("readwrite", (s) => void s.put(value, key));
184
+ },
185
+ async delete(key) {
186
+ if (!await db()) return void memory.delete(key);
187
+ await run("readwrite", (s) => void s.delete(key));
188
+ },
189
+ async keys() {
190
+ if (!await db()) return [...memory.keys()];
191
+ return (await run("readonly", (s) => s.getAllKeys()) ?? []).map(String);
192
+ },
193
+ async entries() {
194
+ if (!await db()) return [...memory.entries()];
195
+ const out = [];
196
+ await run("readonly", (s) => {
197
+ const req = s.openCursor();
198
+ req.onsuccess = () => {
199
+ const cursor = req.result;
200
+ if (!cursor) return;
201
+ out.push([String(cursor.key), cursor.value]);
202
+ cursor.continue();
203
+ };
204
+ });
205
+ return out;
206
+ },
207
+ async clear() {
208
+ if (!await db()) return void memory.clear();
209
+ await run("readwrite", (s) => void s.clear());
210
+ }
211
+ };
212
+ }
213
+ const mirror = createKvStore("agentcrm-site-mirror", "files");
214
+ function createBrowserMirrorConnector(settings) {
215
+ const siteUrl = (settings.siteUrl ?? "").replace(/\/+$/, "");
216
+ const norm = (path) => path.replace(/^\/+/, "");
217
+ return {
218
+ id: "browser-mirror",
219
+ model: "files",
220
+ capabilities: {
221
+ list: true,
222
+ rename: false,
223
+ renameFolder: false,
224
+ folders: false,
225
+ deletePrefix: true
226
+ },
227
+ async put(input) {
228
+ await mirror.set(norm(input.path), {
229
+ content: input.content,
230
+ encoding: input.encoding === "base64" ? "base64" : "utf-8",
231
+ updatedAt: Date.now()
232
+ });
233
+ },
234
+ async get(path) {
235
+ const file = await mirror.get(norm(path));
236
+ if (!file) throw new StorageError(`File not found: ${path}`, 404);
237
+ return file.encoding === "base64" ? base64ToUtf8(file.content) : file.content;
238
+ },
239
+ async getBytes(path) {
240
+ const file = await mirror.get(norm(path));
241
+ if (!file) return null;
242
+ return file.encoding === "base64" ? base64ToBytes(file.content) : new TextEncoder().encode(file.content);
243
+ },
244
+ delete: (path) => mirror.delete(norm(path)),
245
+ async deletePrefix(path) {
246
+ const prefix = norm(path).replace(/\/+$/, "") + "/";
247
+ for (const key of await mirror.keys()) if (key.startsWith(prefix)) await mirror.delete(key);
248
+ },
249
+ async list(page, perPage) {
250
+ const all = (await mirror.keys()).sort().map((path) => ({ path, type: "file", url: siteUrl ? `${siteUrl}/${path}` : `/${path}` }));
251
+ return { items: all.slice((page - 1) * perPage, page * perPage), page, per_page: perPage, total: all.length };
252
+ },
253
+ async listPrefix(under) {
254
+ const want = norm(under);
255
+ return (await mirror.keys()).filter((k) => k.startsWith(want)).sort();
256
+ },
257
+ async publicUrl(path) {
258
+ return siteUrl ? `${siteUrl}/${norm(path)}` : `/${norm(path)}`;
259
+ }
260
+ };
261
+ }
262
+ const browserMirrorFactory = {
263
+ id: "browser-mirror",
264
+ create: createBrowserMirrorConnector
265
+ };
266
+ const LOCAL_PUBLISH_HANDLE_KEY = "publish-target";
267
+ function createLocalFolderConnector(settings) {
268
+ const siteUrl = (settings.siteUrl ?? "").replace(/\/+$/, "");
269
+ let transport = null;
270
+ async function open() {
271
+ if (transport) return transport;
272
+ const handle = await loadFolderHandle(settings.handleKey || LOCAL_PUBLISH_HANDLE_KEY);
273
+ if (!handle || !await ensureFolderPermission(handle)) {
274
+ const message = instance.t("storage.errors.folderAccess");
275
+ toast.error(message);
276
+ throw new StorageError(message, 403);
277
+ }
278
+ transport = createLocalFsTransport(handle);
279
+ return transport;
280
+ }
281
+ async function entry(path) {
282
+ const tree = await (await open()).listTree();
283
+ return tree.entries.find((e) => e.path === path.replace(/^\/+/, ""));
284
+ }
285
+ return {
286
+ id: "local-folder",
287
+ model: "files",
288
+ capabilities: {
289
+ list: true,
290
+ rename: false,
291
+ renameFolder: false,
292
+ folders: false,
293
+ deletePrefix: true
294
+ },
295
+ async put(input) {
296
+ await (await open()).commit([{ type: "put", ...input, path: input.path.replace(/^\/+/, "") }], { message: "" });
297
+ },
298
+ async get(path) {
299
+ const e = await entry(path);
300
+ const text = e ? (await (await open()).readTexts([e])).get(e.path) : void 0;
301
+ if (text === void 0) throw new StorageError(`File not found: ${path}`, 404);
302
+ return text;
303
+ },
304
+ async getBytes(path) {
305
+ const e = await entry(path);
306
+ return e ? (await open()).readBytes(e) : null;
307
+ },
308
+ async delete(path) {
309
+ await (await open()).commit([{ type: "delete", path: path.replace(/^\/+/, "") }], { message: "" });
310
+ },
311
+ async deletePrefix(path) {
312
+ const t = await open();
313
+ const prefix = path.replace(/^\/+|\/+$/g, "") + "/";
314
+ const doomed = (await t.listTree()).entries.filter((e) => e.path.startsWith(prefix));
315
+ await t.commit(doomed.map((e) => ({ type: "delete", path: e.path })), { message: "" });
316
+ },
317
+ async list(page, perPage) {
318
+ const all = (await (await open()).listTree()).entries.map((e) => ({
319
+ path: e.path,
320
+ type: "file",
321
+ size: e.size,
322
+ url: siteUrl ? `${siteUrl}/${e.path}` : `/${e.path}`
323
+ }));
324
+ return { items: all.slice((page - 1) * perPage, page * perPage), page, per_page: perPage, total: all.length };
325
+ },
326
+ async listPrefix(under) {
327
+ const want = under.replace(/^\/+/, "");
328
+ return (await (await open()).listTree()).entries.map((e) => e.path).filter((p) => p.startsWith(want));
329
+ },
330
+ async publicUrl(path) {
331
+ const clean = path.replace(/^\/+/, "");
332
+ return siteUrl ? `${siteUrl}/${clean}` : `/${clean}`;
333
+ }
334
+ };
335
+ }
336
+ const localFolderFactory = {
337
+ id: "local-folder",
338
+ create: createLocalFolderConnector
339
+ };
340
+ let configSource = async () => null;
341
+ function setStorageConfigSource(source) {
342
+ configSource = source;
343
+ active = null;
344
+ }
345
+ function getStorageConfig() {
346
+ return configSource();
347
+ }
348
+ const DEFAULT_CONNECTOR_ID = "browser-mirror";
349
+ let active = null;
350
+ const connectors = new Map(
351
+ [
352
+ gitPagesFactory,
353
+ s3Factory,
354
+ browserMirrorFactory,
355
+ localFolderFactory
356
+ ].map((e) => [e.id, e])
357
+ );
358
+ function isFactory(entry) {
359
+ return typeof entry.create === "function";
360
+ }
361
+ function registerStorageConnector(entry) {
362
+ connectors.set(entry.id, entry);
363
+ if (active && active.id === entry.id) active = null;
364
+ }
365
+ function defaultConnectorId() {
366
+ return DEFAULT_CONNECTOR_ID;
367
+ }
368
+ function listStorageConnectorIds() {
369
+ return [...connectors.keys()];
370
+ }
371
+ function instantiateStorageConnector(id, settings) {
372
+ const entry = connectors.get(id);
373
+ if (!entry) {
374
+ throw new StorageError(instance.t("storage.errors.unknownConnector", { connector: id }), 501);
375
+ }
376
+ return isFactory(entry) ? entry.create(settings) : entry;
377
+ }
378
+ async function resolveActive() {
379
+ let config = null;
380
+ try {
381
+ config = await getStorageConfig();
382
+ } catch (err) {
383
+ console.warn("[storage] could not read storage config, using the default target:", err);
384
+ }
385
+ const id = config?.connectorId ?? defaultConnectorId();
386
+ try {
387
+ return instantiateStorageConnector(id, config?.settings ?? {});
388
+ } catch (err) {
389
+ toast.error(err.message);
390
+ throw err;
391
+ }
392
+ }
393
+ async function getActiveStorageConnector() {
394
+ if (!active) {
395
+ const connector = resolveActive();
396
+ active = { id: "", connector };
397
+ connector.then(
398
+ (c) => {
399
+ if (active?.connector === connector) active.id = c.id;
400
+ },
401
+ () => {
402
+ if (active?.connector === connector) active = null;
403
+ }
404
+ );
405
+ }
406
+ return active.connector;
407
+ }
408
+ function invalidateActiveStorageConnector() {
409
+ active = null;
410
+ }
411
+ const registry = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
412
+ __proto__: null,
413
+ DEFAULT_CONNECTOR_ID,
414
+ defaultConnectorId,
415
+ getActiveStorageConnector,
416
+ getStorageConfig,
417
+ instantiateStorageConnector,
418
+ invalidateActiveStorageConnector,
419
+ listStorageConnectorIds,
420
+ registerStorageConnector,
421
+ setStorageConfigSource
422
+ }, Symbol.toStringTag, { value: "Module" }));
423
+ export {
424
+ createKvStore as a,
425
+ createLocalFsTransport as c,
426
+ ensureFolderPermission as e,
427
+ getActiveStorageConnector as g,
428
+ instantiateStorageConnector as i,
429
+ loadFolderHandle as l,
430
+ registry as r
431
+ };