@fleox-agent-crm/agentcrm 0.3.1 → 0.3.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +16 -16
- package/changelog.json +22 -0
- package/dist/admin/admin-files.json +7 -7
- package/dist/admin/assets/{chartsImpl-B45AAqnr.js → chartsImpl-aBuZ1X4W.js} +1 -1
- package/dist/admin/assets/firebase-BG1GpyBB.js +2 -0
- package/dist/admin/assets/{gitJson-CAUSxl8d.js → gitJson-DzX3eZ2P.js} +1 -1
- package/dist/admin/assets/{index-ChFauO8y.js → index-DLy5RpPl.js} +5 -5
- package/dist/admin/assets/{lucide-react.min--rznIkmQ.js → lucide-react.min-BgcmukkH.js} +1 -1
- package/dist/admin/assets/{sdk-DgzLACmL.js → sdk-DtP9zqdi.js} +1 -1
- package/dist/admin/index.html +1 -1
- package/dist/agent/agentcrm.mjs +70 -12
- package/dist/agent/chunks/api-Dwb4xz1k.mjs +27 -0
- package/dist/agent/chunks/{firebase-DxGVQV9E.mjs → firebase-DWR0K1OC.mjs} +53 -27
- package/dist/agent/chunks/{hosting-Bme7LxPc.mjs → hosting-Dnn1k3cV.mjs} +1 -1
- package/dist/agent/chunks/{index-DUSdTBkz.mjs → index-CNXq2Yk_.mjs} +1 -24
- package/dist/agent/chunks/index-Dio0aBWA.mjs +6920 -0
- package/dist/agent/chunks/{index-CRkw3_iF.mjs → index-DtCezG4R.mjs} +1 -1
- package/dist/agent/chunks/{install-CbpD_7gd.mjs → install-Bp-CwDVC.mjs} +13 -4
- package/dist/agent/chunks/{sdk-whvfg786.mjs → sdk-CYgNyuoK.mjs} +132 -7005
- package/dist/version.json +1 -1
- package/package.json +1 -1
- package/plugin/.claude-plugin/plugin.json +1 -1
- package/plugin/skills/agentcrm-admin/SKILL.md +67 -67
- package/plugin/skills/agentcrm-admin/references/records.md +5 -5
- package/plugin/skills/agentcrm-admin/references/schema.md +19 -19
- package/plugin/skills/agentcrm-extensions/SKILL.md +8 -8
- package/plugin/skills/agentcrm-extensions/references/module-recipes.md +2 -2
- package/plugin/skills/agentcrm-extensions/references/testing.md +14 -14
- package/plugin/skills/agentcrm-extensions/references/theme-recipes.md +3 -3
- package/plugin/skills/agentcrm-install/SKILL.md +13 -13
- package/plugin/skills/agentcrm-install/references/firebase.md +1 -1
- package/plugin/skills/agentcrm-install/references/github.md +1 -1
- package/plugin/skills/agentcrm-install/references/mcp.md +2 -2
- package/plugin/skills/agentcrm-install/references/plans.md +1 -1
- package/plugin/skills/agentcrm-install/references/s3.md +1 -1
- package/plugin/skills/agentcrm-manage/SKILL.md +15 -15
- package/plugin/skills/agentcrm-sales/SKILL.md +18 -18
- package/dist/admin/assets/firebase-C1x_l9P9.js +0 -2
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{b as $v,g as eg}from"./index-
|
|
1
|
+
import{b as $v,g as eg}from"./index-DLy5RpPl.js";function tg(Ge,We){for(var e=0;e<We.length;e++){const h=We[e];if(typeof h!="string"&&!Array.isArray(h)){for(const r in h)if(r!=="default"&&!(r in Ge)){const Te=Object.getOwnPropertyDescriptor(h,r);Te&&Object.defineProperty(Ge,r,Te.get?Te:{enumerable:!0,get:()=>h[r]})}}}return Object.freeze(Object.defineProperty(Ge,Symbol.toStringTag,{value:"Module"}))}var Ze={exports:{}};/**
|
|
2
2
|
* @license lucide-react v0.460.0 - ISC
|
|
3
3
|
*
|
|
4
4
|
* This source code is licensed under the ISC license.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./index.esm-BFc7vwnl.js","./index.esm2017-EOzKbpUS.js"])))=>i.map(i=>d[i]);
|
|
2
|
-
import{_ as Tl}from"./index-
|
|
2
|
+
import{_ as Tl}from"./index-DLy5RpPl.js";import"./index.esm-Dum0J07z.js";import{getAuth as vl,onAuthStateChanged as so,signOut as Il,sendEmailVerification as Al,sendPasswordResetEmail as wl,GoogleAuthProvider as Rl,signInWithPopup as Pl,signInWithEmailAndPassword as Vl}from"./index.esm-CtEQZRb1.js";import{q as kt,e as ua,y as la,u as Is,v as ca,m as Sl,t as Cl,F as bl,w as Dl,x as Nl,L as kl,z as qt,A as xl,B as Ol,S as Ml,i as Fl,C as Ll,r as io,h as Ul,g as ql,n as jl}from"./index.esm2017-EOzKbpUS.js";import{DELETE_FIELD as Bl}from"./firebase-BG1GpyBB.js";var oo=typeof globalThis<"u"?globalThis:typeof window<"u"?window:typeof global<"u"?global:typeof self<"u"?self:{};/** @license
|
|
3
3
|
Copyright The Closure Library Authors.
|
|
4
4
|
SPDX-License-Identifier: Apache-2.0
|
|
5
5
|
*/var Xt,ha;(function(){var r;/** @license
|
package/dist/admin/index.html
CHANGED
|
@@ -120,7 +120,7 @@
|
|
|
120
120
|
}
|
|
121
121
|
}
|
|
122
122
|
</script>
|
|
123
|
-
<script type="module" crossorigin src="./assets/index-
|
|
123
|
+
<script type="module" crossorigin src="./assets/index-DLy5RpPl.js"></script>
|
|
124
124
|
<link rel="stylesheet" crossorigin href="./assets/index-TcjySLVg.css">
|
|
125
125
|
</head>
|
|
126
126
|
<body>
|
package/dist/agent/agentcrm.mjs
CHANGED
|
@@ -6,7 +6,7 @@ const require2 = __acrmRequire(import.meta.url);
|
|
|
6
6
|
const __filename = __acrmPath(import.meta.url);
|
|
7
7
|
const __dirname = __acrmDirname(__filename);
|
|
8
8
|
import { format, parseArgs } from "node:util";
|
|
9
|
-
import { existsSync, readFileSync, statSync, mkdirSync, writeFileSync, chmodSync, renameSync, openSync, writeSync, closeSync, unlinkSync, mkdtempSync, readdirSync, createReadStream } from "node:fs";
|
|
9
|
+
import { existsSync, readFileSync, statSync, mkdirSync, writeFileSync, chmodSync, renameSync, openSync, writeSync, closeSync, unlinkSync, mkdtempSync, rmSync, readdirSync, createReadStream } from "node:fs";
|
|
10
10
|
import { join, resolve, dirname, basename, extname, sep, normalize, isAbsolute } from "node:path";
|
|
11
11
|
import { fileURLToPath } from "node:url";
|
|
12
12
|
import { randomBytes, timingSafeEqual } from "node:crypto";
|
|
@@ -142,7 +142,7 @@ const output = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProper
|
|
|
142
142
|
toCliError
|
|
143
143
|
}, Symbol.toStringTag, { value: "Module" }));
|
|
144
144
|
const name = "@fleox-agent-crm/agentcrm";
|
|
145
|
-
const version = "0.3.
|
|
145
|
+
const version = "0.3.3";
|
|
146
146
|
const type = "module";
|
|
147
147
|
const description = "The static CRM your AI agent can run: a Twenty / HubSpot-style CRM that runs entirely in the browser or headless through the agentcrm CLI, with data on storage you own.";
|
|
148
148
|
const license = "SEE LICENSE IN LICENSE";
|
|
@@ -608,7 +608,7 @@ async function openStore(runtime, opts) {
|
|
|
608
608
|
}
|
|
609
609
|
if (runtime.backend === "journal") {
|
|
610
610
|
if (!opts.dataTarget) throw new CliError("internal", "journal store without a data location");
|
|
611
|
-
const { buildConnector } = await import("./chunks/hosting-
|
|
611
|
+
const { buildConnector } = await import("./chunks/hosting-Dnn1k3cV.mjs");
|
|
612
612
|
const { createJournalStore } = await import("./chunks/index-B-4W0-P4.mjs");
|
|
613
613
|
const { publicSettings, secrets } = rc.splitSecretSettings(opts.dataTarget.settings);
|
|
614
614
|
rc.setConnectorSecrets(runtime, secrets);
|
|
@@ -625,7 +625,11 @@ async function openStore(runtime, opts) {
|
|
|
625
625
|
const token = String(opts.secrets?.token ?? "");
|
|
626
626
|
if (token) rc.setGitToken(runtime.git, token);
|
|
627
627
|
}
|
|
628
|
-
|
|
628
|
+
if (runtime.backend === "firebase" && opts.account && typeof opts.secrets?.email === "string") {
|
|
629
|
+
const { prepareFirebaseSession: prepareFirebaseSession2 } = await Promise.resolve().then(() => firebaseSession);
|
|
630
|
+
await prepareFirebaseSession2(opts.account, runtime.firebase, opts.secrets.email);
|
|
631
|
+
}
|
|
632
|
+
const { createDataStore } = await import("./chunks/index-DtCezG4R.mjs");
|
|
629
633
|
return createDataStore(runtime, { secrets: opts.secrets ?? {}, passphrase: opts.passphrase ?? null, clientId: cliClientId() });
|
|
630
634
|
}
|
|
631
635
|
function siteSecrets(site) {
|
|
@@ -639,7 +643,7 @@ function siteSecrets(site) {
|
|
|
639
643
|
`Store it (\`agentcrm credentials set ${site.runtime.backend === "firebase" ? "firebase" : site.runtime.git.provider}:<name>\`), then \`agentcrm site credentials ${site.alias} --data-credential <account>\`.`
|
|
640
644
|
);
|
|
641
645
|
}
|
|
642
|
-
return { secrets: requireCredential(site.credentials.data).values, passphrase };
|
|
646
|
+
return { secrets: requireCredential(site.credentials.data).values, passphrase, account: site.credentials.data };
|
|
643
647
|
}
|
|
644
648
|
return { passphrase };
|
|
645
649
|
}
|
|
@@ -703,14 +707,14 @@ async function openSession(alias, opts = {}) {
|
|
|
703
707
|
})();
|
|
704
708
|
if (target) {
|
|
705
709
|
const { setStorageConfigSource, registerStorageConnector } = await import("./chunks/registry-DijAKZ24.mjs").then((n) => n.r);
|
|
706
|
-
const { buildConnector } = await import("./chunks/hosting-
|
|
710
|
+
const { buildConnector } = await import("./chunks/hosting-Dnn1k3cV.mjs");
|
|
707
711
|
if (target.connectorId === "local-folder") registerStorageConnector({ id: "local-folder", create: (s) => buildConnector({ connectorId: "local-folder", settings: s }) });
|
|
708
712
|
setStorageConfigSource(async () => target);
|
|
709
713
|
}
|
|
710
714
|
}
|
|
711
715
|
{
|
|
712
716
|
const forms = await import("./chunks/forms-BfuWaQjA.mjs");
|
|
713
|
-
const { buildConnector } = await import("./chunks/hosting-
|
|
717
|
+
const { buildConnector } = await import("./chunks/hosting-Dnn1k3cV.mjs");
|
|
714
718
|
forms.setInboxSourceResolver((_ctx, form) => {
|
|
715
719
|
if (form.inbox.kind !== "s3") return null;
|
|
716
720
|
const settings = form.inbox.settings ?? {};
|
|
@@ -1670,6 +1674,57 @@ function copyToClipboard(text) {
|
|
|
1670
1674
|
}
|
|
1671
1675
|
throw new CliError("no-clipboard", "No clipboard tool found (pbcopy, clip, wl-copy, xclip or xsel).", "Install one, or read the value from ~/.agentcrm/credentials.json yourself.");
|
|
1672
1676
|
}
|
|
1677
|
+
function sessionFile(account) {
|
|
1678
|
+
return homePath("sessions", `${account.replace(/[^a-z0-9._-]+/gi, "_")}.json`);
|
|
1679
|
+
}
|
|
1680
|
+
function forgetFirebaseSession(account) {
|
|
1681
|
+
const f = sessionFile(account);
|
|
1682
|
+
if (existsSync(f)) rmSync(f, { force: true });
|
|
1683
|
+
}
|
|
1684
|
+
function filePersistence(account, email) {
|
|
1685
|
+
const file2 = sessionFile(account);
|
|
1686
|
+
const saved = readJsonFile(file2, null);
|
|
1687
|
+
const items = saved && saved.email === email ? { ...saved.items } : {};
|
|
1688
|
+
const flush = () => {
|
|
1689
|
+
if (Object.keys(items).length) writeJsonFile(file2, { email, items }, 384);
|
|
1690
|
+
else forgetFirebaseSession(account);
|
|
1691
|
+
};
|
|
1692
|
+
return class FileSessionPersistence {
|
|
1693
|
+
static type = "LOCAL";
|
|
1694
|
+
type = "LOCAL";
|
|
1695
|
+
async _isAvailable() {
|
|
1696
|
+
return true;
|
|
1697
|
+
}
|
|
1698
|
+
async _set(key, value) {
|
|
1699
|
+
items[key] = value;
|
|
1700
|
+
flush();
|
|
1701
|
+
}
|
|
1702
|
+
async _get(key) {
|
|
1703
|
+
return items[key] ?? null;
|
|
1704
|
+
}
|
|
1705
|
+
async _remove(key) {
|
|
1706
|
+
delete items[key];
|
|
1707
|
+
flush();
|
|
1708
|
+
}
|
|
1709
|
+
_addListener() {
|
|
1710
|
+
}
|
|
1711
|
+
_removeListener() {
|
|
1712
|
+
}
|
|
1713
|
+
};
|
|
1714
|
+
}
|
|
1715
|
+
async function prepareFirebaseSession(account, options, email) {
|
|
1716
|
+
const { getFirebaseApp } = await import("./chunks/sdk-CYgNyuoK.mjs");
|
|
1717
|
+
const { initializeAuth } = await import("./chunks/index-Dio0aBWA.mjs").then((n) => n.x);
|
|
1718
|
+
try {
|
|
1719
|
+
initializeAuth(getFirebaseApp(options), { persistence: filePersistence(account, email.trim().toLowerCase()) });
|
|
1720
|
+
} catch {
|
|
1721
|
+
}
|
|
1722
|
+
}
|
|
1723
|
+
const firebaseSession = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
1724
|
+
__proto__: null,
|
|
1725
|
+
forgetFirebaseSession,
|
|
1726
|
+
prepareFirebaseSession
|
|
1727
|
+
}, Symbol.toStringTag, { value: "Module" }));
|
|
1673
1728
|
const credentialsCommand = {
|
|
1674
1729
|
name: "credentials",
|
|
1675
1730
|
usage: "credentials <set|list|remove|copy|verify|types> [<type>:<name>] [--from-env VAR[,VAR]] [--from-gh] [--from-aws-profile <name>] [--generate]",
|
|
@@ -1710,6 +1765,7 @@ const credentialsCommand = {
|
|
|
1710
1765
|
const spec = CREDENTIAL_TYPES[type2];
|
|
1711
1766
|
if (action === "remove") {
|
|
1712
1767
|
const removed = removeCredential(account);
|
|
1768
|
+
forgetFirebaseSession(account);
|
|
1713
1769
|
printResult(io, { account, removed }, () => removed ? `Removed ${account}.` : `${account} was not stored.`);
|
|
1714
1770
|
return;
|
|
1715
1771
|
}
|
|
@@ -1759,6 +1815,7 @@ const credentialsCommand = {
|
|
|
1759
1815
|
for (const field of spec.fields) values[field] = await promptHidden(`${field}: `);
|
|
1760
1816
|
}
|
|
1761
1817
|
const saved = setCredential(account, values);
|
|
1818
|
+
forgetFirebaseSession(account);
|
|
1762
1819
|
printResult(io, { account, type: type2, fields: Object.keys(saved.values) }, () => `Stored ${account} (${Object.keys(saved.values).join(", ")}).`);
|
|
1763
1820
|
}
|
|
1764
1821
|
};
|
|
@@ -2538,7 +2595,7 @@ const formsCommand = {
|
|
|
2538
2595
|
const target = s.hostingTarget();
|
|
2539
2596
|
if (!target) usage(`${s.site.alias} has no hosting to publish the form to.`);
|
|
2540
2597
|
if (options.yes !== true) return { needsConfirmation: true, plan: { form: id, path: built.path, hosting: s.site.hosting?.type, bytes: built.html.length } };
|
|
2541
|
-
const { buildConnector } = await import("./chunks/hosting-
|
|
2598
|
+
const { buildConnector } = await import("./chunks/hosting-Dnn1k3cV.mjs");
|
|
2542
2599
|
const connector = buildConnector(target);
|
|
2543
2600
|
const siteUrl = typeof s.site.hosting?.settings.siteUrl === "string" ? s.site.hosting.settings.siteUrl.replace(/\/+$/, "") : "";
|
|
2544
2601
|
return forms.publishForm(s.ctx, id, { put: (input) => connector.put(input), publicUrl: async (path) => siteUrl ? `${siteUrl}/${path}` : connector.publicUrl(path) });
|
|
@@ -2683,7 +2740,7 @@ const deployAdminCommand = {
|
|
|
2683
2740
|
const sites = options.all === true ? listSites().sites.filter((s) => s.hosting) : [resolveSite(strOpt(options, "site"))];
|
|
2684
2741
|
if (!sites.length) throw new CliError("no-sites", "No registered CRM has a hosting.");
|
|
2685
2742
|
installBrowserEnv();
|
|
2686
|
-
const { adminOps, applyOps, buildConnector } = await import("./chunks/hosting-
|
|
2743
|
+
const { adminOps, applyOps, buildConnector } = await import("./chunks/hosting-Dnn1k3cV.mjs");
|
|
2687
2744
|
const { hostingTargetOf: hostingTargetOf2 } = await Promise.resolve().then(() => session);
|
|
2688
2745
|
const plans = [];
|
|
2689
2746
|
for (const site of sites) {
|
|
@@ -2787,7 +2844,7 @@ async function runDoctor(site, opts = {}) {
|
|
|
2787
2844
|
installBrowserEnv();
|
|
2788
2845
|
try {
|
|
2789
2846
|
if (site.runtime.backend === "journal" && site.runtime.journal.connectorId === "git-pages") {
|
|
2790
|
-
const { probeTarget } = await import("./chunks/install-
|
|
2847
|
+
const { probeTarget } = await import("./chunks/install-Bp-CwDVC.mjs");
|
|
2791
2848
|
const { dataTargetOf: dataTargetOf2 } = await Promise.resolve().then(() => session);
|
|
2792
2849
|
const probe = await probeTarget(dataTargetOf2(site), { requireSiteUrl: false, requirePrivate: true });
|
|
2793
2850
|
add(probe.ok ? { id: "data-repo", status: "ok", message: probe.detail } : { id: "data-repo", status: "fail", message: probe.detail, fix: "Make the data repository private and check the token's Contents permission." });
|
|
@@ -2947,7 +3004,7 @@ const installCommand = {
|
|
|
2947
3004
|
const { resolvePlan } = await import("./chunks/plan-BmTat6-T.mjs");
|
|
2948
3005
|
const plan = resolvePlan(readPlan(planPath));
|
|
2949
3006
|
if (getSite(plan.alias)) throw new CliError("site-exists", `A site named "${plan.alias}" is already registered.`, "Use another alias, or `agentcrm site forget` it first.");
|
|
2950
|
-
const { checkPlan, runInstall } = await import("./chunks/install-
|
|
3007
|
+
const { checkPlan, runInstall } = await import("./chunks/install-Bp-CwDVC.mjs");
|
|
2951
3008
|
io.err("Checking access…");
|
|
2952
3009
|
const checks = await checkPlan(plan);
|
|
2953
3010
|
const summary = {
|
|
@@ -4046,7 +4103,8 @@ export {
|
|
|
4046
4103
|
findBackend as f,
|
|
4047
4104
|
getCredential as g,
|
|
4048
4105
|
openStore as h,
|
|
4049
|
-
|
|
4106
|
+
installBrowserEnv as i,
|
|
4107
|
+
distRoot as j,
|
|
4050
4108
|
nodeImportBundle as n,
|
|
4051
4109
|
ownPackageRoot as o,
|
|
4052
4110
|
packageRoot as p,
|
|
@@ -0,0 +1,27 @@
|
|
|
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
|
+
const DELETE_FIELD = Symbol("deleteField");
|
|
8
|
+
function errorCode(err) {
|
|
9
|
+
return err?.code ?? "";
|
|
10
|
+
}
|
|
11
|
+
function isPermissionDenied(err) {
|
|
12
|
+
const code = errorCode(err);
|
|
13
|
+
return code === "permission-denied" || code === "firestore/permission-denied";
|
|
14
|
+
}
|
|
15
|
+
const FIRESTORE_BATCH_LIMIT = 500;
|
|
16
|
+
function chunk(items, size) {
|
|
17
|
+
const out = [];
|
|
18
|
+
for (let i = 0; i < items.length; i += size) out.push(items.slice(i, i + size));
|
|
19
|
+
return out;
|
|
20
|
+
}
|
|
21
|
+
export {
|
|
22
|
+
DELETE_FIELD as D,
|
|
23
|
+
FIRESTORE_BATCH_LIMIT as F,
|
|
24
|
+
chunk as c,
|
|
25
|
+
errorCode as e,
|
|
26
|
+
isPermissionDenied as i
|
|
27
|
+
};
|
|
@@ -7,6 +7,7 @@ const __dirname = __acrmDirname(__filename);
|
|
|
7
7
|
import "./jsx-runtime-Ca2uwGDr.mjs";
|
|
8
8
|
import { r as reactExports } from "./index-Bnmav-Oh.mjs";
|
|
9
9
|
import { c as createStoreCore, p as plainCopy, e as emptySnapshot, n as normalizeDoc } from "./core-Dy7vY9H6.mjs";
|
|
10
|
+
import { i as isPermissionDenied, D as DELETE_FIELD, e as errorCode, c as chunk, F as FIRESTORE_BATCH_LIMIT } from "./api-Dwb4xz1k.mjs";
|
|
10
11
|
import { w as withFileStore, F as FileStoreUnavailableError } from "./index-RCmo-uld.mjs";
|
|
11
12
|
import { COLLECTIONS } from "./types-BOy9PUl7.mjs";
|
|
12
13
|
import { a as assertFileId } from "./ids-u-noYcy5.mjs";
|
|
@@ -16,20 +17,6 @@ function registerAuthAdapter(backend, adapter) {
|
|
|
16
17
|
adapters.set(backend, adapter);
|
|
17
18
|
}
|
|
18
19
|
reactExports.createContext(null);
|
|
19
|
-
const DELETE_FIELD = Symbol("deleteField");
|
|
20
|
-
function errorCode(err) {
|
|
21
|
-
return err?.code ?? "";
|
|
22
|
-
}
|
|
23
|
-
function isPermissionDenied(err) {
|
|
24
|
-
const code = errorCode(err);
|
|
25
|
-
return code === "permission-denied" || code === "firestore/permission-denied";
|
|
26
|
-
}
|
|
27
|
-
const FIRESTORE_BATCH_LIMIT = 500;
|
|
28
|
-
function chunk(items, size) {
|
|
29
|
-
const out = [];
|
|
30
|
-
for (let i = 0; i < items.length; i += size) out.push(items.slice(i, i + size));
|
|
31
|
-
return out;
|
|
32
|
-
}
|
|
33
20
|
const INVITES_COLLECTION = "invites";
|
|
34
21
|
const EXTENSION_CHUNKS_COLLECTION = "extensionChunks";
|
|
35
22
|
const EXTENSION_CHUNK_CHARS = 3e5;
|
|
@@ -272,8 +259,19 @@ function createFirebaseStoreWith(opts) {
|
|
|
272
259
|
return null;
|
|
273
260
|
}
|
|
274
261
|
}
|
|
262
|
+
function getIdentity() {
|
|
263
|
+
if (!identityPromise) {
|
|
264
|
+
identityPromise = resolveIdentity().then((id) => {
|
|
265
|
+
currentIdentity = id;
|
|
266
|
+
if (!id) identityPromise = null;
|
|
267
|
+
return id;
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
return identityPromise;
|
|
271
|
+
}
|
|
275
272
|
async function persist(mutations, before, after) {
|
|
276
273
|
const ops = mutationOps(mutations, before);
|
|
274
|
+
if (!currentIdentity && mutations.some((m) => m.collection === "users")) await getIdentity();
|
|
277
275
|
if (currentIdentity?.role === "admin") ops.push(...inviteOps(mutations, (id) => before.users.get(id) ?? rawUsers.get(id), after));
|
|
278
276
|
for (const part of chunk(ops, FIRESTORE_BATCH_LIMIT)) await api.commit(part);
|
|
279
277
|
for (const m of mutations) {
|
|
@@ -331,16 +329,7 @@ function createFirebaseStoreWith(opts) {
|
|
|
331
329
|
);
|
|
332
330
|
return () => offs.forEach((off) => off());
|
|
333
331
|
},
|
|
334
|
-
identity
|
|
335
|
-
if (!identityPromise) {
|
|
336
|
-
identityPromise = resolveIdentity().then((id) => {
|
|
337
|
-
currentIdentity = id;
|
|
338
|
-
if (!id) identityPromise = null;
|
|
339
|
-
return id;
|
|
340
|
-
});
|
|
341
|
-
}
|
|
342
|
-
return identityPromise;
|
|
343
|
-
},
|
|
332
|
+
identity: getIdentity,
|
|
344
333
|
close() {
|
|
345
334
|
offAuth();
|
|
346
335
|
}
|
|
@@ -410,7 +399,7 @@ function firebaseApiFor(config) {
|
|
|
410
399
|
const key = config.firebase.projectId ?? "default";
|
|
411
400
|
let api = apis.get(key);
|
|
412
401
|
if (!api) {
|
|
413
|
-
api = import("./sdk-
|
|
402
|
+
api = import("./sdk-CYgNyuoK.mjs").then((m) => m.createSdkFirebaseApi(config.firebase));
|
|
414
403
|
apis.set(key, api);
|
|
415
404
|
api.catch(() => apis.delete(key));
|
|
416
405
|
}
|
|
@@ -422,11 +411,46 @@ registerAuthAdapter("firebase", {
|
|
|
422
411
|
await activeApi?.auth.signOut();
|
|
423
412
|
}
|
|
424
413
|
});
|
|
425
|
-
|
|
414
|
+
function loginOf(secrets) {
|
|
415
|
+
const email = typeof secrets?.email === "string" ? secrets.email.trim() : "";
|
|
416
|
+
const password = typeof secrets?.password === "string" ? secrets.password : "";
|
|
417
|
+
return email && password ? { email, password } : null;
|
|
418
|
+
}
|
|
419
|
+
async function signInWithSecrets(api, secrets) {
|
|
420
|
+
const login = loginOf(secrets);
|
|
421
|
+
if (!login) return null;
|
|
422
|
+
const current = await api.auth.currentUser();
|
|
423
|
+
if (current?.email && current.email.toLowerCase() === login.email.toLowerCase()) return current;
|
|
424
|
+
if (current) await api.auth.signOut();
|
|
425
|
+
return api.auth.signInWithPassword(login.email, login.password);
|
|
426
|
+
}
|
|
427
|
+
async function checkFirebaseAccess(api, secrets, projectId) {
|
|
428
|
+
const login = loginOf(secrets);
|
|
429
|
+
if (!login) return { ok: false, detail: "the Firebase login (email + password) is missing", existing: false };
|
|
430
|
+
let user;
|
|
431
|
+
try {
|
|
432
|
+
user = await signInWithSecrets(api, secrets);
|
|
433
|
+
} catch (err) {
|
|
434
|
+
const code = err.code ?? "";
|
|
435
|
+
return { ok: false, detail: `Firebase refused the login of ${login.email} (${code || err.message}): check the address, the password and that Email/Password sign-in is enabled`, existing: false };
|
|
436
|
+
}
|
|
437
|
+
if (!user?.emailVerified) {
|
|
438
|
+
return { ok: false, detail: `${login.email} is not verified yet: open the verification email Firebase sent to it (the rules refuse unverified addresses), then retry`, existing: false };
|
|
439
|
+
}
|
|
440
|
+
try {
|
|
441
|
+
const settings = await api.getDoc("settings", "general");
|
|
442
|
+
return { ok: true, detail: `Firebase project ${projectId}: signed in as ${login.email}, rules accept it${settings ? " — existing CRM: it is kept, only what's missing is seeded" : ""}`, existing: !!settings };
|
|
443
|
+
} catch (err) {
|
|
444
|
+
if (!isPermissionDenied(err)) throw err;
|
|
445
|
+
return { ok: false, detail: `Firestore refused ${login.email}: publish the AgentCRM rules with this address as bootstrap admin (\`agentcrm options --firebase-rules ${login.email}\`), or invite it`, existing: false };
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
async function createFirebaseStore(config, opts = {}) {
|
|
426
449
|
const cfg = config;
|
|
427
450
|
if (!cfg.firebase?.apiKey || !cfg.firebase.projectId) throw new Error("The Firebase web config (apiKey, projectId) is missing.");
|
|
428
451
|
const api = await firebaseApiFor(cfg);
|
|
429
452
|
activeApi = api;
|
|
453
|
+
await signInWithSecrets(api, opts.secrets);
|
|
430
454
|
return createFirebaseStoreWith({ api });
|
|
431
455
|
}
|
|
432
456
|
export {
|
|
@@ -440,6 +464,7 @@ export {
|
|
|
440
464
|
STORAGE_FILES_DIR,
|
|
441
465
|
STORAGE_NOT_ENABLED,
|
|
442
466
|
assembleExtensionDocs,
|
|
467
|
+
checkFirebaseAccess,
|
|
443
468
|
chunk,
|
|
444
469
|
createFirebaseStore,
|
|
445
470
|
createFirebaseStoreWith,
|
|
@@ -450,5 +475,6 @@ export {
|
|
|
450
475
|
inviteOps,
|
|
451
476
|
isFirebaseStore,
|
|
452
477
|
isPermissionDenied,
|
|
453
|
-
mutationOps
|
|
478
|
+
mutationOps,
|
|
479
|
+
signInWithSecrets
|
|
454
480
|
};
|
|
@@ -8,7 +8,7 @@ import { statSync, rmSync, existsSync, unlinkSync, readFileSync, mkdirSync, writ
|
|
|
8
8
|
import { resolve, dirname, sep, join, relative } from "node:path";
|
|
9
9
|
import { buildConfigJsSource } from "./runtimeConfig-CCOFg1RM.mjs";
|
|
10
10
|
import { a as createGitPagesConnector, b as createS3Connector } from "./s3-Dz50-NuA.mjs";
|
|
11
|
-
import { C as CliError, r as readVersionInfo,
|
|
11
|
+
import { C as CliError, r as readVersionInfo, j as distRoot } from "../agentcrm.mjs";
|
|
12
12
|
import { pathToFileURL } from "node:url";
|
|
13
13
|
import "./index-BM8qeGOb.mjs";
|
|
14
14
|
import "./http-Bk9ICb7I.mjs";
|
|
@@ -4,30 +4,7 @@ import { dirname as __acrmDirname } from "node:path";
|
|
|
4
4
|
const require2 = __acrmRequire(import.meta.url);
|
|
5
5
|
const __filename = __acrmPath(import.meta.url);
|
|
6
6
|
const __dirname = __acrmDirname(__filename);
|
|
7
|
-
import { F as FirebaseError, g as getModularInstance, _ as _getProvider, a as getDefaultEmulatorHostnameAndPort, b as getApp, i as isCloudWorkstation, p as pingServer, u as updateEmulatorBanner, c as createMockUserToken, d as _isFirebaseServerApp, e as _registerComponent, C as Component, r as registerVersion, S as SDK_VERSION } from "./
|
|
8
|
-
import "util";
|
|
9
|
-
import "crypto";
|
|
10
|
-
import "process";
|
|
11
|
-
import "tls";
|
|
12
|
-
import "fs";
|
|
13
|
-
import "os";
|
|
14
|
-
import "net";
|
|
15
|
-
import "events";
|
|
16
|
-
import "stream";
|
|
17
|
-
import "./_commonjsHelpers-ClciMIcB.mjs";
|
|
18
|
-
import "path";
|
|
19
|
-
import "http2";
|
|
20
|
-
import "http";
|
|
21
|
-
import "url";
|
|
22
|
-
import "dns";
|
|
23
|
-
import "zlib";
|
|
24
|
-
import "./firebase-DxGVQV9E.mjs";
|
|
25
|
-
import "./jsx-runtime-Ca2uwGDr.mjs";
|
|
26
|
-
import "./index-Bnmav-Oh.mjs";
|
|
27
|
-
import "./core-Dy7vY9H6.mjs";
|
|
28
|
-
import "./types-BOy9PUl7.mjs";
|
|
29
|
-
import "./index-RCmo-uld.mjs";
|
|
30
|
-
import "./ids-u-noYcy5.mjs";
|
|
7
|
+
import { F as FirebaseError, g as getModularInstance, _ as _getProvider, a as getDefaultEmulatorHostnameAndPort, b as getApp, i as isCloudWorkstation, p as pingServer, u as updateEmulatorBanner, c as createMockUserToken, d as _isFirebaseServerApp, e as _registerComponent, C as Component, r as registerVersion, S as SDK_VERSION } from "./index-Dio0aBWA.mjs";
|
|
31
8
|
/**
|
|
32
9
|
* @license
|
|
33
10
|
* Copyright 2017 Google LLC
|