@neat.is/core 0.10.1-dev.20260927 → 0.10.1

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/neatd.js CHANGED
@@ -2,15 +2,15 @@
2
2
  import {
3
3
  reconcileDaemonRecordSync,
4
4
  startDaemon
5
- } from "./chunk-EJPNEEJA.js";
5
+ } from "./chunk-AWIK6T3G.js";
6
6
  import {
7
7
  listProjects,
8
8
  registryPath
9
- } from "./chunk-J3VVEB45.js";
9
+ } from "./chunk-E3YFFIHE.js";
10
10
  import {
11
11
  BindAuthorityError,
12
12
  __require
13
- } from "./chunk-GDGUY4T6.js";
13
+ } from "./chunk-M7CGATVC.js";
14
14
 
15
15
  // src/neatd.ts
16
16
  import { promises as fs } from "fs";
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  reshapeGrpcRequest,
3
3
  startOtelGrpcReceiver
4
- } from "./chunk-ERE47MCR.js";
5
- import "./chunk-GDGUY4T6.js";
4
+ } from "./chunk-5SJHA5ZH.js";
5
+ import "./chunk-M7CGATVC.js";
6
6
  export {
7
7
  reshapeGrpcRequest,
8
8
  startOtelGrpcReceiver
9
9
  };
10
- //# sourceMappingURL=otel-grpc-Y5K4WGWO.js.map
10
+ //# sourceMappingURL=otel-grpc-CU73Y5WT.js.map
package/dist/server.cjs CHANGED
@@ -12787,13 +12787,16 @@ function objectKeys(obj) {
12787
12787
  var MODULAR_WRITES = /* @__PURE__ */ new Set(["addDoc", "setDoc", "updateDoc"]);
12788
12788
  var NAMESPACED_WRITES = /* @__PURE__ */ new Set(["add", "set", "update"]);
12789
12789
  var READ_CLAUSES = /* @__PURE__ */ new Set(["where", "orderBy"]);
12790
- function firestoreEndpointsFromFile(file, serviceDir) {
12790
+ function firestoreEndpointsFromFile(file, serviceDir, imported) {
12791
12791
  const hasClient = FIRESTORE_CLIENT_IMPORT_RE.test(file.content);
12792
12792
  const hasAdmin = FIRESTORE_ADMIN_IMPORT_RE.test(file.content);
12793
- if (!hasClient && !hasAdmin) return [];
12794
- const fileSdk = hasClient && !hasAdmin ? "client" : hasAdmin && !hasClient ? "admin" : null;
12793
+ const importedNames = imported?.names ?? /* @__PURE__ */ new Set();
12794
+ if (!hasClient && !hasAdmin && importedNames.size === 0) return [];
12795
+ const ownSdk = hasClient && !hasAdmin ? "client" : hasAdmin && !hasClient ? "admin" : null;
12796
+ const fileSdk = !hasClient && !hasAdmin ? imported?.sdk ?? null : ownSdk;
12795
12797
  const tree = parseSource3(parserForExt2(import_node_path46.default.extname(file.path)), file.content);
12796
12798
  const clientVars = firestoreClientVars(tree.rootNode);
12799
+ for (const n of importedNames) clientVars.add(n);
12797
12800
  const collLine = /* @__PURE__ */ new Map();
12798
12801
  const writes = /* @__PURE__ */ new Map();
12799
12802
  const reads = /* @__PURE__ */ new Map();
@@ -12904,6 +12907,99 @@ function firestoreEndpointsFromFile(file, serviceDir) {
12904
12907
  }
12905
12908
  return out;
12906
12909
  }
12910
+ function exportedFirestoreClients(root) {
12911
+ const out = /* @__PURE__ */ new Set();
12912
+ const collect = (node) => {
12913
+ if (node.type === "variable_declarator") {
12914
+ const name = node.childForFieldName("name");
12915
+ let value = node.childForFieldName("value");
12916
+ if (value?.type === "await_expression") value = namedChildren(value)[0] ?? null;
12917
+ if (name?.type === "identifier" && isFirestoreClientFactory(value)) out.add(name.text);
12918
+ }
12919
+ for (const c of namedChildren(node)) collect(c);
12920
+ };
12921
+ const walk11 = (node) => {
12922
+ if (node.type === "export_statement") collect(node);
12923
+ else for (const c of namedChildren(node)) walk11(c);
12924
+ };
12925
+ walk11(root);
12926
+ return out;
12927
+ }
12928
+ function namedImportBindings(root) {
12929
+ const out = [];
12930
+ const walk11 = (node) => {
12931
+ if (node.type === "import_statement") {
12932
+ const src = node.childForFieldName("source");
12933
+ const specifier = src ? src.text.slice(1, -1) : "";
12934
+ if (specifier.length > 0) {
12935
+ const stack = [node];
12936
+ while (stack.length > 0) {
12937
+ const n = stack.pop();
12938
+ if (n.type === "import_specifier") {
12939
+ const nameNode = n.childForFieldName("name");
12940
+ const aliasNode = n.childForFieldName("alias");
12941
+ const importedName = nameNode?.text;
12942
+ if (importedName) {
12943
+ out.push({ local: aliasNode?.text ?? importedName, imported: importedName, specifier });
12944
+ }
12945
+ continue;
12946
+ }
12947
+ for (const c of namedChildren(n)) stack.push(c);
12948
+ }
12949
+ }
12950
+ }
12951
+ for (const c of namedChildren(node)) walk11(c);
12952
+ };
12953
+ walk11(root);
12954
+ return out;
12955
+ }
12956
+ function sdkOf(content) {
12957
+ const hasClient = FIRESTORE_CLIENT_IMPORT_RE.test(content);
12958
+ const hasAdmin = FIRESTORE_ADMIN_IMPORT_RE.test(content);
12959
+ return hasClient && !hasAdmin ? "client" : hasAdmin && !hasClient ? "admin" : null;
12960
+ }
12961
+ function parseOrNull(file) {
12962
+ const ext = import_node_path46.default.extname(file.path);
12963
+ if (!(ext in GRAMMAR_BY_EXT)) return null;
12964
+ try {
12965
+ return parseSource3(parserForExt2(ext), file.content).rootNode;
12966
+ } catch {
12967
+ return null;
12968
+ }
12969
+ }
12970
+ async function firestoreCrossFileEndpoints(files, serviceDir) {
12971
+ const registry = /* @__PURE__ */ new Map();
12972
+ for (const f of files) {
12973
+ if (sdkOf(f.content) === null && !FIRESTORE_CLIENT_IMPORT_RE.test(f.content)) continue;
12974
+ const root = parseOrNull(f);
12975
+ if (!root) continue;
12976
+ const names = exportedFirestoreClients(root);
12977
+ if (names.size === 0) continue;
12978
+ registry.set(toPosix(import_node_path46.default.relative(serviceDir, f.path)), { names, sdk: sdkOf(f.content) });
12979
+ }
12980
+ if (registry.size === 0) return [];
12981
+ const out = [];
12982
+ for (const f of files) {
12983
+ const root = parseOrNull(f);
12984
+ if (!root) continue;
12985
+ if (firestoreClientVars(root).size > 0) continue;
12986
+ const bindings = namedImportBindings(root);
12987
+ if (bindings.length === 0) continue;
12988
+ const names = /* @__PURE__ */ new Set();
12989
+ let sdk = null;
12990
+ for (const b of bindings) {
12991
+ const rel = await resolveJsImport(b.specifier, import_node_path46.default.dirname(f.path), serviceDir, null);
12992
+ if (!rel) continue;
12993
+ const entry = registry.get(rel);
12994
+ if (!entry || !entry.names.has(b.imported)) continue;
12995
+ names.add(b.local);
12996
+ sdk ??= entry.sdk;
12997
+ }
12998
+ if (names.size === 0) continue;
12999
+ out.push(...firestoreEndpointsFromFile(f, serviceDir, { names, sdk }));
13000
+ }
13001
+ return out;
13002
+ }
12907
13003
 
12908
13004
  // src/extract/calls/mongoose.ts
12909
13005
  init_cjs_shims();
@@ -15713,6 +15809,7 @@ async function addExternalEndpointEdges(graph, services) {
15713
15809
  recordExtractionError("python socket call extraction", file.path, err);
15714
15810
  }
15715
15811
  }
15812
+ endpoints.push(...await firestoreCrossFileEndpoints(maskedFiles, service.dir));
15716
15813
  endpoints.push(...await mongooseCrossFileEndpoints(maskedFiles, service.dir));
15717
15814
  endpoints.push(...pythonOrmCrossFileEndpoints(maskedFiles, service.dir));
15718
15815
  endpoints.push(...await prismaColumnEndpoints(service.dir));
@@ -17008,6 +17105,9 @@ function stripComments(src) {
17008
17105
  function segmentsFromMatchPath(pathToken) {
17009
17106
  return pathToken.split("/").filter((s) => s.length > 0);
17010
17107
  }
17108
+ function isRecursiveWildcard(seg) {
17109
+ return /^\{[^}]*=\s*\*\*\}$/.test(seg);
17110
+ }
17011
17111
  function collectionKeyFromSegments(segments) {
17012
17112
  let segs = segments;
17013
17113
  if (segs.length >= 3 && segs[0] === "databases" && /^\{.*\}$/.test(segs[1]) && segs[2] === "documents") {
@@ -17020,10 +17120,11 @@ function collectionKeyFromName(name) {
17020
17120
  }
17021
17121
  function fieldsFromCondition(cond) {
17022
17122
  const out = [];
17023
- const callRe = /\b(?:hasAll|hasOnly|hasAny)\s*\(\s*\[([^\]]*)\]\s*\)/g;
17123
+ const callRe = /(!\s*)?\b(?:hasAll|hasOnly|hasAny)\s*\(\s*\[([^\]]*)\]\s*\)/g;
17024
17124
  let m;
17025
17125
  while ((m = callRe.exec(cond)) !== null) {
17026
- const inner = m[1];
17126
+ if (m[1] !== void 0 || isNegatedAt(cond, m.index)) continue;
17127
+ const inner = m[2];
17027
17128
  const litRe = /'([^']*)'|"([^"]*)"/g;
17028
17129
  let lm;
17029
17130
  while ((lm = litRe.exec(inner)) !== null) {
@@ -17033,6 +17134,28 @@ function fieldsFromCondition(cond) {
17033
17134
  }
17034
17135
  return out;
17035
17136
  }
17137
+ function isNegatedAt(cond, idx) {
17138
+ let i = idx - 1;
17139
+ while (i >= 0) {
17140
+ const ch = cond[i];
17141
+ if (ch === ")") {
17142
+ let depth = 1;
17143
+ i--;
17144
+ while (i >= 0 && depth > 0) {
17145
+ if (cond[i] === ")") depth++;
17146
+ else if (cond[i] === "(") depth--;
17147
+ i--;
17148
+ }
17149
+ continue;
17150
+ }
17151
+ if (/[A-Za-z0-9_$.\]['"]/.test(ch) || ch === " ") {
17152
+ i--;
17153
+ continue;
17154
+ }
17155
+ return ch === "!";
17156
+ }
17157
+ return false;
17158
+ }
17036
17159
  function parseFirestoreRules(content) {
17037
17160
  const src = stripComments(content);
17038
17161
  const tokenRe = /match\s+((?:\/(?:\{[^}]*\}|[^\s/{}]+))+)\s*\{|allow\b([^;{}]*);|(\{)|(\})/g;
@@ -17045,7 +17168,8 @@ function parseFirestoreRules(content) {
17045
17168
  while ((m = tokenRe.exec(src)) !== null) {
17046
17169
  if (m[1] !== void 0) {
17047
17170
  depth++;
17048
- matchStack.push({ depth, segs: segmentsFromMatchPath(m[1]) });
17171
+ const segs = segmentsFromMatchPath(m[1]);
17172
+ matchStack.push({ depth, segs, recursive: segs.some(isRecursiveWildcard) });
17049
17173
  continue;
17050
17174
  }
17051
17175
  if (m[2] !== void 0) {
@@ -17056,6 +17180,10 @@ function parseFirestoreRules(content) {
17056
17180
  if (!methods.some((mm) => WRITE_METHODS.has(mm))) continue;
17057
17181
  const key = currentKey();
17058
17182
  if (key.length === 0) continue;
17183
+ if (matchStack.some((f) => f.recursive)) {
17184
+ indeterminate.add(key);
17185
+ continue;
17186
+ }
17059
17187
  const cond = colon === -1 ? "" : body.slice(colon + 1);
17060
17188
  const fields = fieldsFromCondition(cond);
17061
17189
  if (fields.length > 0) {