@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.
Files changed (38) hide show
  1. package/README.md +16 -16
  2. package/changelog.json +22 -0
  3. package/dist/admin/admin-files.json +7 -7
  4. package/dist/admin/assets/{chartsImpl-B45AAqnr.js → chartsImpl-aBuZ1X4W.js} +1 -1
  5. package/dist/admin/assets/firebase-BG1GpyBB.js +2 -0
  6. package/dist/admin/assets/{gitJson-CAUSxl8d.js → gitJson-DzX3eZ2P.js} +1 -1
  7. package/dist/admin/assets/{index-ChFauO8y.js → index-DLy5RpPl.js} +5 -5
  8. package/dist/admin/assets/{lucide-react.min--rznIkmQ.js → lucide-react.min-BgcmukkH.js} +1 -1
  9. package/dist/admin/assets/{sdk-DgzLACmL.js → sdk-DtP9zqdi.js} +1 -1
  10. package/dist/admin/index.html +1 -1
  11. package/dist/agent/agentcrm.mjs +70 -12
  12. package/dist/agent/chunks/api-Dwb4xz1k.mjs +27 -0
  13. package/dist/agent/chunks/{firebase-DxGVQV9E.mjs → firebase-DWR0K1OC.mjs} +53 -27
  14. package/dist/agent/chunks/{hosting-Bme7LxPc.mjs → hosting-Dnn1k3cV.mjs} +1 -1
  15. package/dist/agent/chunks/{index-DUSdTBkz.mjs → index-CNXq2Yk_.mjs} +1 -24
  16. package/dist/agent/chunks/index-Dio0aBWA.mjs +6920 -0
  17. package/dist/agent/chunks/{index-CRkw3_iF.mjs → index-DtCezG4R.mjs} +1 -1
  18. package/dist/agent/chunks/{install-CbpD_7gd.mjs → install-Bp-CwDVC.mjs} +13 -4
  19. package/dist/agent/chunks/{sdk-whvfg786.mjs → sdk-CYgNyuoK.mjs} +132 -7005
  20. package/dist/version.json +1 -1
  21. package/package.json +1 -1
  22. package/plugin/.claude-plugin/plugin.json +1 -1
  23. package/plugin/skills/agentcrm-admin/SKILL.md +67 -67
  24. package/plugin/skills/agentcrm-admin/references/records.md +5 -5
  25. package/plugin/skills/agentcrm-admin/references/schema.md +19 -19
  26. package/plugin/skills/agentcrm-extensions/SKILL.md +8 -8
  27. package/plugin/skills/agentcrm-extensions/references/module-recipes.md +2 -2
  28. package/plugin/skills/agentcrm-extensions/references/testing.md +14 -14
  29. package/plugin/skills/agentcrm-extensions/references/theme-recipes.md +3 -3
  30. package/plugin/skills/agentcrm-install/SKILL.md +13 -13
  31. package/plugin/skills/agentcrm-install/references/firebase.md +1 -1
  32. package/plugin/skills/agentcrm-install/references/github.md +1 -1
  33. package/plugin/skills/agentcrm-install/references/mcp.md +2 -2
  34. package/plugin/skills/agentcrm-install/references/plans.md +1 -1
  35. package/plugin/skills/agentcrm-install/references/s3.md +1 -1
  36. package/plugin/skills/agentcrm-manage/SKILL.md +15 -15
  37. package/plugin/skills/agentcrm-sales/SKILL.md +18 -18
  38. package/dist/admin/assets/firebase-C1x_l9P9.js +0 -2
@@ -1,4 +1,4 @@
1
- import{b as $v,g as eg}from"./index-ChFauO8y.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:{}};/**
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-ChFauO8y.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-C1x_l9P9.js";var oo=typeof globalThis<"u"?globalThis:typeof window<"u"?window:typeof global<"u"?global:typeof self<"u"?self:{};/** @license
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
@@ -120,7 +120,7 @@
120
120
  }
121
121
  }
122
122
  </script>
123
- <script type="module" crossorigin src="./assets/index-ChFauO8y.js"></script>
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>
@@ -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.1";
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-Bme7LxPc.mjs");
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
- const { createDataStore } = await import("./chunks/index-CRkw3_iF.mjs");
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-Bme7LxPc.mjs");
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-Bme7LxPc.mjs");
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-Bme7LxPc.mjs");
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-Bme7LxPc.mjs");
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-CbpD_7gd.mjs");
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-CbpD_7gd.mjs");
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
- distRoot as i,
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-whvfg786.mjs").then((n) => n.s).then((m) => m.createSdkFirebaseApi(config.firebase));
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
- async function createFirebaseStore(config, _opts = {}) {
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, i as distRoot } from "../agentcrm.mjs";
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 "./sdk-whvfg786.mjs";
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