@dxos/echo-pipeline 0.8.4-main.dedc0f3 → 0.8.4-main.e098934

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.
@@ -111,6 +111,30 @@ var filterMatchObjectJSON = (filter, obj) => {
111
111
  return false;
112
112
  }
113
113
  };
114
+ var structuralMatch = (filterObj, targetObj, strict = true) => {
115
+ if (typeof filterObj !== "object" || filterObj === null) {
116
+ return filterObj === targetObj;
117
+ }
118
+ if (typeof targetObj !== "object" || targetObj === null) {
119
+ return false;
120
+ }
121
+ const filterKeys = Object.keys(filterObj);
122
+ const targetKeys = Object.keys(targetObj);
123
+ if (strict && filterKeys.length !== targetKeys.length) {
124
+ return false;
125
+ }
126
+ return filterKeys.every((key) => {
127
+ if (!(key in targetObj)) {
128
+ return false;
129
+ }
130
+ const filterValue = filterObj[key];
131
+ const targetValue = targetObj[key];
132
+ if (typeof filterValue === "object" && filterValue !== null) {
133
+ return structuralMatch(filterValue, targetValue);
134
+ }
135
+ return filterValue === targetValue;
136
+ });
137
+ };
114
138
  var filterMatchValue = (filter, value) => {
115
139
  switch (filter.type) {
116
140
  case "compare": {
@@ -134,12 +158,38 @@ var filterMatchValue = (filter, value) => {
134
158
  return value < compareValue;
135
159
  case "lte":
136
160
  return value <= compareValue;
161
+ default:
162
+ return false;
137
163
  }
138
- break;
164
+ }
165
+ case "object": {
166
+ if (typeof value !== "object" || value === null) {
167
+ return false;
168
+ }
169
+ if (filter.props) {
170
+ for (const [key, valueFilter] of Object.entries(filter.props)) {
171
+ const nestedValue = value[key];
172
+ if (!filterMatchValue(valueFilter, nestedValue)) {
173
+ return false;
174
+ }
175
+ }
176
+ }
177
+ return true;
139
178
  }
140
179
  case "in": {
141
180
  return filter.values.includes(value);
142
181
  }
182
+ case "contains": {
183
+ if (!Array.isArray(value)) {
184
+ return false;
185
+ }
186
+ return value.some((element) => {
187
+ if (typeof filter.value === "object" && filter.value !== null && !Array.isArray(filter.value)) {
188
+ return structuralMatch(filter.value, element);
189
+ }
190
+ return element === filter.value;
191
+ });
192
+ }
143
193
  case "range": {
144
194
  return value >= filter.from && value <= filter.to;
145
195
  }
@@ -179,4 +229,4 @@ export {
179
229
  filterMatchObjectJSON,
180
230
  filterMatchValue
181
231
  };
182
- //# sourceMappingURL=chunk-MBMJB3V7.mjs.map
232
+ //# sourceMappingURL=chunk-KQYT6ADL.mjs.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/filter/filter-match.ts"],
4
- "sourcesContent": ["//\n// Copyright 2025 DXOS.org\n//\n\nimport { type ObjectStructure, type QueryAST, decodeReference, isEncodedReference } from '@dxos/echo-protocol';\nimport { EXPANDO_TYPENAME, type ObjectJSON } from '@dxos/echo-schema';\nimport { DXN, type ObjectId, type SpaceId } from '@dxos/keys';\n\nexport type MatchedObject = {\n id: ObjectId;\n spaceId: SpaceId;\n doc: ObjectStructure;\n};\n\n/**\n * Matches an object against a filter AST.\n * @param obj object structure as stored in automerge.\n */\nexport const filterMatchObject = (filter: QueryAST.Filter, obj: MatchedObject): boolean => {\n switch (filter.type) {\n case 'object': {\n // Check typename if specified\n if (filter.typename !== null) {\n // TODO(dmaretskyi): `system` is missing in some cases.\n if (!obj.doc.system?.type?.['/']) {\n // Objects with no type are considered to be expando objects\n const expectedDXN = DXN.parse(filter.typename).asTypeDXN();\n if (expectedDXN?.type !== EXPANDO_TYPENAME) {\n return false;\n }\n } else {\n const actualDXN = DXN.parse(obj.doc.system.type['/']);\n const expectedDXN = DXN.parse(filter.typename);\n\n if (!compareTypename(expectedDXN, actualDXN)) {\n return false;\n }\n }\n }\n\n // Check IDs if specified\n if (filter.id && filter.id.length > 0 && !filter.id.includes(obj.id)) {\n return false;\n }\n\n // Check properties\n if (filter.props) {\n for (const [key, valueFilter] of Object.entries(filter.props)) {\n const value = obj.doc.data[key];\n if (!filterMatchValue(valueFilter, value)) {\n return false;\n }\n }\n }\n\n // Check foreign keys if specified\n if (filter.foreignKeys && filter.foreignKeys.length > 0) {\n const hasMatchingKey = filter.foreignKeys.some((filterKey) =>\n obj.doc.meta.keys.some((objKey) => objKey.source === filterKey.source && objKey.id === filterKey.id),\n );\n if (!hasMatchingKey) {\n return false;\n }\n }\n\n return true;\n }\n\n case 'text-search': {\n // TODO: Implement text search\n return false;\n }\n\n case 'not': {\n return !filterMatchObject(filter.filter, obj);\n }\n\n case 'and': {\n return filter.filters.every((f) => filterMatchObject(f, obj));\n }\n\n case 'or': {\n return filter.filters.some((f) => filterMatchObject(f, obj));\n }\n\n default:\n return false;\n }\n};\n\nexport const filterMatchObjectJSON = (filter: QueryAST.Filter, obj: ObjectJSON): boolean => {\n switch (filter.type) {\n case 'object': {\n // Check typename if specified\n if (filter.typename !== null) {\n // TODO(dmaretskyi): `system` is missing in some cases.\n if (!obj['@type']) {\n // Objects with no type are considered to be expando objects\n const expectedDXN = DXN.parse(filter.typename).asTypeDXN();\n if (expectedDXN?.type !== EXPANDO_TYPENAME) {\n return false;\n }\n } else {\n const actualDXN = DXN.parse(obj['@type']);\n const expectedDXN = DXN.parse(filter.typename);\n\n if (!compareTypename(expectedDXN, actualDXN)) {\n return false;\n }\n }\n }\n\n // Check IDs if specified\n if (filter.id && filter.id.length > 0 && !filter.id.includes(obj.id)) {\n return false;\n }\n\n // Check properties\n if (filter.props) {\n for (const [key, valueFilter] of Object.entries(filter.props)) {\n if (key.startsWith('@')) {\n // ignore meta properties\n continue;\n }\n const value = (obj as any)[key];\n if (!filterMatchValue(valueFilter, value)) {\n return false;\n }\n }\n }\n\n // Check foreign keys if specified\n if (filter.foreignKeys && filter.foreignKeys.length > 0) {\n const hasMatchingKey = filter.foreignKeys.some((filterKey) =>\n obj['@meta']?.keys?.some((objKey) => objKey.source === filterKey.source && objKey.id === filterKey.id),\n );\n if (!hasMatchingKey) {\n return false;\n }\n }\n\n return true;\n }\n\n case 'text-search': {\n // TODO: Implement text search\n return false;\n }\n\n case 'not': {\n return !filterMatchObjectJSON(filter.filter, obj);\n }\n\n case 'and': {\n return filter.filters.every((f) => filterMatchObjectJSON(f, obj));\n }\n\n case 'or': {\n return filter.filters.some((f) => filterMatchObjectJSON(f, obj));\n }\n\n default:\n return false;\n }\n};\n\nexport const filterMatchValue = (filter: QueryAST.Filter, value: unknown): boolean => {\n switch (filter.type) {\n case 'compare': {\n const compareValue = filter.value as any;\n switch (filter.operator) {\n case 'eq':\n if (isEncodedReference(compareValue)) {\n if (!isEncodedReference(value)) {\n return false;\n }\n return DXN.equals(decodeReference(value).toDXN(), decodeReference(compareValue).toDXN());\n }\n return value === compareValue;\n case 'neq':\n return value !== compareValue;\n case 'gt':\n return (value as any) > compareValue;\n case 'gte':\n return (value as any) >= compareValue;\n case 'lt':\n return (value as any) < compareValue;\n case 'lte':\n return (value as any) <= compareValue;\n }\n break;\n }\n case 'in': {\n return filter.values.includes(value);\n }\n case 'range': {\n return (value as any) >= filter.from && (value as any) <= filter.to;\n }\n case 'not': {\n return !filterMatchValue(filter.filter, value);\n }\n case 'and': {\n return filter.filters.every((f) => filterMatchValue(f, value));\n }\n case 'or': {\n return filter.filters.some((f) => filterMatchValue(f, value));\n }\n default:\n return false;\n }\n};\n\n/**\n * Compares typename DXNs.\n * @returns true if they match\n *\n * Compares typename string.\n * Missing version (on either actual or expected) matches any version.\n * non `type` DXNs are compared exactly.\n *\n * Examples: (expected) (actual)\n *\n * dxn:type:example.org/type/Task !== dxn:type:example.org/type/Contact\n * dxn:type:example.org/type/Task === dxn:type:example.org/type/Task\n * dxn:type:example.org/type/Task:0.1.0 !== dxn:type:example.org/type/Task:0.2.0\n * dxn:type:example.org/type/Task === dxn:type:example.org/type/Task:0.1.0\n * dxn:type:example.org/type/Task:0.1.0 === dxn:type:example.org/type/Task\n *\n */\nconst compareTypename = (expectedDXN: DXN, actualDXN: DXN): boolean => {\n const expectedTypeDXN = expectedDXN.asTypeDXN();\n if (expectedTypeDXN) {\n const actualTypeDXN = actualDXN.asTypeDXN();\n if (!actualTypeDXN) {\n return false;\n }\n if (\n actualTypeDXN.type !== expectedTypeDXN.type ||\n (expectedTypeDXN.version !== undefined &&\n actualTypeDXN.version !== undefined &&\n actualTypeDXN.version !== expectedTypeDXN.version)\n ) {\n return false;\n }\n } else {\n if (!DXN.equals(actualDXN, expectedDXN)) {\n return false;\n }\n }\n return true;\n};\n"],
5
- "mappings": "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",
6
- "names": ["decodeReference", "isEncodedReference", "EXPANDO_TYPENAME", "DXN", "filterMatchObject", "filter", "obj", "type", "typename", "doc", "system", "expectedDXN", "DXN", "parse", "asTypeDXN", "EXPANDO_TYPENAME", "actualDXN", "compareTypename", "id", "length", "includes", "props", "key", "valueFilter", "Object", "entries", "value", "data", "filterMatchValue", "foreignKeys", "hasMatchingKey", "some", "filterKey", "meta", "keys", "objKey", "source", "filters", "every", "f", "filterMatchObjectJSON", "startsWith", "compareValue", "operator", "isEncodedReference", "equals", "decodeReference", "toDXN", "values", "from", "to", "expectedTypeDXN", "actualTypeDXN", "version", "undefined"]
4
+ "sourcesContent": ["//\n// Copyright 2025 DXOS.org\n//\n\nimport { type ObjectStructure, type QueryAST, decodeReference, isEncodedReference } from '@dxos/echo-protocol';\nimport { EXPANDO_TYPENAME, type ObjectJSON } from '@dxos/echo-schema';\nimport { DXN, type ObjectId, type SpaceId } from '@dxos/keys';\n\nexport type MatchedObject = {\n id: ObjectId;\n spaceId: SpaceId;\n doc: ObjectStructure;\n};\n\n/**\n * Matches an object against a filter AST.\n * @param obj object structure as stored in automerge.\n */\nexport const filterMatchObject = (filter: QueryAST.Filter, obj: MatchedObject): boolean => {\n switch (filter.type) {\n case 'object': {\n // Check typename if specified\n if (filter.typename !== null) {\n // TODO(dmaretskyi): `system` is missing in some cases.\n if (!obj.doc.system?.type?.['/']) {\n // Objects with no type are considered to be expando objects\n const expectedDXN = DXN.parse(filter.typename).asTypeDXN();\n if (expectedDXN?.type !== EXPANDO_TYPENAME) {\n return false;\n }\n } else {\n const actualDXN = DXN.parse(obj.doc.system.type['/']);\n const expectedDXN = DXN.parse(filter.typename);\n\n if (!compareTypename(expectedDXN, actualDXN)) {\n return false;\n }\n }\n }\n\n // Check IDs if specified\n if (filter.id && filter.id.length > 0 && !filter.id.includes(obj.id)) {\n return false;\n }\n\n // Check properties\n if (filter.props) {\n for (const [key, valueFilter] of Object.entries(filter.props)) {\n const value = obj.doc.data[key];\n if (!filterMatchValue(valueFilter, value)) {\n return false;\n }\n }\n }\n\n // Check foreign keys if specified\n if (filter.foreignKeys && filter.foreignKeys.length > 0) {\n const hasMatchingKey = filter.foreignKeys.some((filterKey) =>\n obj.doc.meta.keys.some((objKey) => objKey.source === filterKey.source && objKey.id === filterKey.id),\n );\n if (!hasMatchingKey) {\n return false;\n }\n }\n\n return true;\n }\n\n case 'text-search': {\n // TODO: Implement text search\n return false;\n }\n\n case 'not': {\n return !filterMatchObject(filter.filter, obj);\n }\n\n case 'and': {\n return filter.filters.every((f) => filterMatchObject(f, obj));\n }\n\n case 'or': {\n return filter.filters.some((f) => filterMatchObject(f, obj));\n }\n\n default:\n return false;\n }\n};\n\nexport const filterMatchObjectJSON = (filter: QueryAST.Filter, obj: ObjectJSON): boolean => {\n switch (filter.type) {\n case 'object': {\n // Check typename if specified\n if (filter.typename !== null) {\n // TODO(dmaretskyi): `system` is missing in some cases.\n if (!obj['@type']) {\n // Objects with no type are considered to be expando objects\n const expectedDXN = DXN.parse(filter.typename).asTypeDXN();\n if (expectedDXN?.type !== EXPANDO_TYPENAME) {\n return false;\n }\n } else {\n const actualDXN = DXN.parse(obj['@type']);\n const expectedDXN = DXN.parse(filter.typename);\n\n if (!compareTypename(expectedDXN, actualDXN)) {\n return false;\n }\n }\n }\n\n // Check IDs if specified\n if (filter.id && filter.id.length > 0 && !filter.id.includes(obj.id)) {\n return false;\n }\n\n // Check properties\n if (filter.props) {\n for (const [key, valueFilter] of Object.entries(filter.props)) {\n if (key.startsWith('@')) {\n // ignore meta properties\n continue;\n }\n const value = (obj as any)[key];\n if (!filterMatchValue(valueFilter, value)) {\n return false;\n }\n }\n }\n\n // Check foreign keys if specified\n if (filter.foreignKeys && filter.foreignKeys.length > 0) {\n const hasMatchingKey = filter.foreignKeys.some((filterKey) =>\n obj['@meta']?.keys?.some((objKey) => objKey.source === filterKey.source && objKey.id === filterKey.id),\n );\n if (!hasMatchingKey) {\n return false;\n }\n }\n\n return true;\n }\n\n case 'text-search': {\n // TODO: Implement text search\n return false;\n }\n\n case 'not': {\n return !filterMatchObjectJSON(filter.filter, obj);\n }\n\n case 'and': {\n return filter.filters.every((f) => filterMatchObjectJSON(f, obj));\n }\n\n case 'or': {\n return filter.filters.some((f) => filterMatchObjectJSON(f, obj));\n }\n\n default:\n return false;\n }\n};\n\n/**\n * Performs structural matching between a filter object and a target object.\n * This handles nested object comparison for array matching scenarios.\n */\n// TODO(wittjosiah): Add ast support for non-strict matching.\nconst structuralMatch = (filterObj: any, targetObj: any, strict = true): boolean => {\n if (typeof filterObj !== 'object' || filterObj === null) {\n return filterObj === targetObj;\n }\n\n if (typeof targetObj !== 'object' || targetObj === null) {\n return false;\n }\n\n // Prohibit extra keys in targetObj.\n const filterKeys = Object.keys(filterObj);\n const targetKeys = Object.keys(targetObj);\n if (strict && filterKeys.length !== targetKeys.length) {\n return false;\n }\n\n return filterKeys.every((key) => {\n if (!(key in targetObj)) {\n return false;\n }\n const filterValue = filterObj[key];\n const targetValue = targetObj[key];\n\n if (typeof filterValue === 'object' && filterValue !== null) {\n return structuralMatch(filterValue, targetValue);\n }\n\n return filterValue === targetValue;\n });\n};\n\nexport const filterMatchValue = (filter: QueryAST.Filter, value: unknown): boolean => {\n switch (filter.type) {\n case 'compare': {\n const compareValue = filter.value as any;\n switch (filter.operator) {\n case 'eq':\n if (isEncodedReference(compareValue)) {\n if (!isEncodedReference(value)) {\n return false;\n }\n return DXN.equals(decodeReference(value).toDXN(), decodeReference(compareValue).toDXN());\n }\n return value === compareValue;\n case 'neq':\n return value !== compareValue;\n case 'gt':\n return (value as any) > compareValue;\n case 'gte':\n return (value as any) >= compareValue;\n case 'lt':\n return (value as any) < compareValue;\n case 'lte':\n return (value as any) <= compareValue;\n default:\n return false;\n }\n }\n case 'object': {\n // Handle nested object filters for property matching\n if (typeof value !== 'object' || value === null) {\n return false;\n }\n\n // Check properties\n if (filter.props) {\n for (const [key, valueFilter] of Object.entries(filter.props)) {\n const nestedValue = (value as any)[key];\n if (!filterMatchValue(valueFilter, nestedValue)) {\n return false;\n }\n }\n }\n\n return true;\n }\n case 'in': {\n return filter.values.includes(value);\n }\n case 'contains': {\n if (!Array.isArray(value)) {\n return false;\n }\n\n return value.some((element) => {\n if (typeof filter.value === 'object' && filter.value !== null && !Array.isArray(filter.value)) {\n return structuralMatch(filter.value, element);\n }\n\n return element === filter.value;\n });\n }\n case 'range': {\n return (value as any) >= filter.from && (value as any) <= filter.to;\n }\n case 'not': {\n return !filterMatchValue(filter.filter, value);\n }\n case 'and': {\n return filter.filters.every((f) => filterMatchValue(f, value));\n }\n case 'or': {\n return filter.filters.some((f) => filterMatchValue(f, value));\n }\n default:\n return false;\n }\n};\n\n/**\n * Compares typename DXNs.\n * @returns true if they match\n *\n * Compares typename string.\n * Missing version (on either actual or expected) matches any version.\n * non `type` DXNs are compared exactly.\n *\n * Examples: (expected) (actual)\n *\n * dxn:type:example.org/type/Task !== dxn:type:example.org/type/Contact\n * dxn:type:example.org/type/Task === dxn:type:example.org/type/Task\n * dxn:type:example.org/type/Task:0.1.0 !== dxn:type:example.org/type/Task:0.2.0\n * dxn:type:example.org/type/Task === dxn:type:example.org/type/Task:0.1.0\n * dxn:type:example.org/type/Task:0.1.0 === dxn:type:example.org/type/Task\n *\n */\nconst compareTypename = (expectedDXN: DXN, actualDXN: DXN): boolean => {\n const expectedTypeDXN = expectedDXN.asTypeDXN();\n if (expectedTypeDXN) {\n const actualTypeDXN = actualDXN.asTypeDXN();\n if (!actualTypeDXN) {\n return false;\n }\n if (\n actualTypeDXN.type !== expectedTypeDXN.type ||\n (expectedTypeDXN.version !== undefined &&\n actualTypeDXN.version !== undefined &&\n actualTypeDXN.version !== expectedTypeDXN.version)\n ) {\n return false;\n }\n } else {\n if (!DXN.equals(actualDXN, expectedDXN)) {\n return false;\n }\n }\n return true;\n};\n"],
5
+ "mappings": ";;;AAIA,SAA8CA,iBAAiBC,0BAA0B;AACzF,SAASC,wBAAyC;AAClD,SAASC,WAAwC;AAY1C,IAAMC,oBAAoB,CAACC,QAAyBC,QAAAA;AACzD,UAAQD,OAAOE,MAAI;IACjB,KAAK,UAAU;AAEb,UAAIF,OAAOG,aAAa,MAAM;AAE5B,YAAI,CAACF,IAAIG,IAAIC,QAAQH,OAAO,GAAA,GAAM;AAEhC,gBAAMI,cAAcC,IAAIC,MAAMR,OAAOG,QAAQ,EAAEM,UAAS;AACxD,cAAIH,aAAaJ,SAASQ,kBAAkB;AAC1C,mBAAO;UACT;QACF,OAAO;AACL,gBAAMC,YAAYJ,IAAIC,MAAMP,IAAIG,IAAIC,OAAOH,KAAK,GAAA,CAAI;AACpD,gBAAMI,cAAcC,IAAIC,MAAMR,OAAOG,QAAQ;AAE7C,cAAI,CAACS,gBAAgBN,aAAaK,SAAAA,GAAY;AAC5C,mBAAO;UACT;QACF;MACF;AAGA,UAAIX,OAAOa,MAAMb,OAAOa,GAAGC,SAAS,KAAK,CAACd,OAAOa,GAAGE,SAASd,IAAIY,EAAE,GAAG;AACpE,eAAO;MACT;AAGA,UAAIb,OAAOgB,OAAO;AAChB,mBAAW,CAACC,KAAKC,WAAAA,KAAgBC,OAAOC,QAAQpB,OAAOgB,KAAK,GAAG;AAC7D,gBAAMK,QAAQpB,IAAIG,IAAIkB,KAAKL,GAAAA;AAC3B,cAAI,CAACM,iBAAiBL,aAAaG,KAAAA,GAAQ;AACzC,mBAAO;UACT;QACF;MACF;AAGA,UAAIrB,OAAOwB,eAAexB,OAAOwB,YAAYV,SAAS,GAAG;AACvD,cAAMW,iBAAiBzB,OAAOwB,YAAYE,KAAK,CAACC,cAC9C1B,IAAIG,IAAIwB,KAAKC,KAAKH,KAAK,CAACI,WAAWA,OAAOC,WAAWJ,UAAUI,UAAUD,OAAOjB,OAAOc,UAAUd,EAAE,CAAA;AAErG,YAAI,CAACY,gBAAgB;AACnB,iBAAO;QACT;MACF;AAEA,aAAO;IACT;IAEA,KAAK,eAAe;AAElB,aAAO;IACT;IAEA,KAAK,OAAO;AACV,aAAO,CAAC1B,kBAAkBC,OAAOA,QAAQC,GAAAA;IAC3C;IAEA,KAAK,OAAO;AACV,aAAOD,OAAOgC,QAAQC,MAAM,CAACC,MAAMnC,kBAAkBmC,GAAGjC,GAAAA,CAAAA;IAC1D;IAEA,KAAK,MAAM;AACT,aAAOD,OAAOgC,QAAQN,KAAK,CAACQ,MAAMnC,kBAAkBmC,GAAGjC,GAAAA,CAAAA;IACzD;IAEA;AACE,aAAO;EACX;AACF;AAEO,IAAMkC,wBAAwB,CAACnC,QAAyBC,QAAAA;AAC7D,UAAQD,OAAOE,MAAI;IACjB,KAAK,UAAU;AAEb,UAAIF,OAAOG,aAAa,MAAM;AAE5B,YAAI,CAACF,IAAI,OAAA,GAAU;AAEjB,gBAAMK,cAAcC,IAAIC,MAAMR,OAAOG,QAAQ,EAAEM,UAAS;AACxD,cAAIH,aAAaJ,SAASQ,kBAAkB;AAC1C,mBAAO;UACT;QACF,OAAO;AACL,gBAAMC,YAAYJ,IAAIC,MAAMP,IAAI,OAAA,CAAQ;AACxC,gBAAMK,cAAcC,IAAIC,MAAMR,OAAOG,QAAQ;AAE7C,cAAI,CAACS,gBAAgBN,aAAaK,SAAAA,GAAY;AAC5C,mBAAO;UACT;QACF;MACF;AAGA,UAAIX,OAAOa,MAAMb,OAAOa,GAAGC,SAAS,KAAK,CAACd,OAAOa,GAAGE,SAASd,IAAIY,EAAE,GAAG;AACpE,eAAO;MACT;AAGA,UAAIb,OAAOgB,OAAO;AAChB,mBAAW,CAACC,KAAKC,WAAAA,KAAgBC,OAAOC,QAAQpB,OAAOgB,KAAK,GAAG;AAC7D,cAAIC,IAAImB,WAAW,GAAA,GAAM;AAEvB;UACF;AACA,gBAAMf,QAASpB,IAAYgB,GAAAA;AAC3B,cAAI,CAACM,iBAAiBL,aAAaG,KAAAA,GAAQ;AACzC,mBAAO;UACT;QACF;MACF;AAGA,UAAIrB,OAAOwB,eAAexB,OAAOwB,YAAYV,SAAS,GAAG;AACvD,cAAMW,iBAAiBzB,OAAOwB,YAAYE,KAAK,CAACC,cAC9C1B,IAAI,OAAA,GAAU4B,MAAMH,KAAK,CAACI,WAAWA,OAAOC,WAAWJ,UAAUI,UAAUD,OAAOjB,OAAOc,UAAUd,EAAE,CAAA;AAEvG,YAAI,CAACY,gBAAgB;AACnB,iBAAO;QACT;MACF;AAEA,aAAO;IACT;IAEA,KAAK,eAAe;AAElB,aAAO;IACT;IAEA,KAAK,OAAO;AACV,aAAO,CAACU,sBAAsBnC,OAAOA,QAAQC,GAAAA;IAC/C;IAEA,KAAK,OAAO;AACV,aAAOD,OAAOgC,QAAQC,MAAM,CAACC,MAAMC,sBAAsBD,GAAGjC,GAAAA,CAAAA;IAC9D;IAEA,KAAK,MAAM;AACT,aAAOD,OAAOgC,QAAQN,KAAK,CAACQ,MAAMC,sBAAsBD,GAAGjC,GAAAA,CAAAA;IAC7D;IAEA;AACE,aAAO;EACX;AACF;AAOA,IAAMoC,kBAAkB,CAACC,WAAgBC,WAAgBC,SAAS,SAAI;AACpE,MAAI,OAAOF,cAAc,YAAYA,cAAc,MAAM;AACvD,WAAOA,cAAcC;EACvB;AAEA,MAAI,OAAOA,cAAc,YAAYA,cAAc,MAAM;AACvD,WAAO;EACT;AAGA,QAAME,aAAatB,OAAOU,KAAKS,SAAAA;AAC/B,QAAMI,aAAavB,OAAOU,KAAKU,SAAAA;AAC/B,MAAIC,UAAUC,WAAW3B,WAAW4B,WAAW5B,QAAQ;AACrD,WAAO;EACT;AAEA,SAAO2B,WAAWR,MAAM,CAAChB,QAAAA;AACvB,QAAI,EAAEA,OAAOsB,YAAY;AACvB,aAAO;IACT;AACA,UAAMI,cAAcL,UAAUrB,GAAAA;AAC9B,UAAM2B,cAAcL,UAAUtB,GAAAA;AAE9B,QAAI,OAAO0B,gBAAgB,YAAYA,gBAAgB,MAAM;AAC3D,aAAON,gBAAgBM,aAAaC,WAAAA;IACtC;AAEA,WAAOD,gBAAgBC;EACzB,CAAA;AACF;AAEO,IAAMrB,mBAAmB,CAACvB,QAAyBqB,UAAAA;AACxD,UAAQrB,OAAOE,MAAI;IACjB,KAAK,WAAW;AACd,YAAM2C,eAAe7C,OAAOqB;AAC5B,cAAQrB,OAAO8C,UAAQ;QACrB,KAAK;AACH,cAAIC,mBAAmBF,YAAAA,GAAe;AACpC,gBAAI,CAACE,mBAAmB1B,KAAAA,GAAQ;AAC9B,qBAAO;YACT;AACA,mBAAOd,IAAIyC,OAAOC,gBAAgB5B,KAAAA,EAAO6B,MAAK,GAAID,gBAAgBJ,YAAAA,EAAcK,MAAK,CAAA;UACvF;AACA,iBAAO7B,UAAUwB;QACnB,KAAK;AACH,iBAAOxB,UAAUwB;QACnB,KAAK;AACH,iBAAQxB,QAAgBwB;QAC1B,KAAK;AACH,iBAAQxB,SAAiBwB;QAC3B,KAAK;AACH,iBAAQxB,QAAgBwB;QAC1B,KAAK;AACH,iBAAQxB,SAAiBwB;QAC3B;AACE,iBAAO;MACX;IACF;IACA,KAAK,UAAU;AAEb,UAAI,OAAOxB,UAAU,YAAYA,UAAU,MAAM;AAC/C,eAAO;MACT;AAGA,UAAIrB,OAAOgB,OAAO;AAChB,mBAAW,CAACC,KAAKC,WAAAA,KAAgBC,OAAOC,QAAQpB,OAAOgB,KAAK,GAAG;AAC7D,gBAAMmC,cAAe9B,MAAcJ,GAAAA;AACnC,cAAI,CAACM,iBAAiBL,aAAaiC,WAAAA,GAAc;AAC/C,mBAAO;UACT;QACF;MACF;AAEA,aAAO;IACT;IACA,KAAK,MAAM;AACT,aAAOnD,OAAOoD,OAAOrC,SAASM,KAAAA;IAChC;IACA,KAAK,YAAY;AACf,UAAI,CAACgC,MAAMC,QAAQjC,KAAAA,GAAQ;AACzB,eAAO;MACT;AAEA,aAAOA,MAAMK,KAAK,CAAC6B,YAAAA;AACjB,YAAI,OAAOvD,OAAOqB,UAAU,YAAYrB,OAAOqB,UAAU,QAAQ,CAACgC,MAAMC,QAAQtD,OAAOqB,KAAK,GAAG;AAC7F,iBAAOgB,gBAAgBrC,OAAOqB,OAAOkC,OAAAA;QACvC;AAEA,eAAOA,YAAYvD,OAAOqB;MAC5B,CAAA;IACF;IACA,KAAK,SAAS;AACZ,aAAQA,SAAiBrB,OAAOwD,QAASnC,SAAiBrB,OAAOyD;IACnE;IACA,KAAK,OAAO;AACV,aAAO,CAAClC,iBAAiBvB,OAAOA,QAAQqB,KAAAA;IAC1C;IACA,KAAK,OAAO;AACV,aAAOrB,OAAOgC,QAAQC,MAAM,CAACC,MAAMX,iBAAiBW,GAAGb,KAAAA,CAAAA;IACzD;IACA,KAAK,MAAM;AACT,aAAOrB,OAAOgC,QAAQN,KAAK,CAACQ,MAAMX,iBAAiBW,GAAGb,KAAAA,CAAAA;IACxD;IACA;AACE,aAAO;EACX;AACF;AAmBA,IAAMT,kBAAkB,CAACN,aAAkBK,cAAAA;AACzC,QAAM+C,kBAAkBpD,YAAYG,UAAS;AAC7C,MAAIiD,iBAAiB;AACnB,UAAMC,gBAAgBhD,UAAUF,UAAS;AACzC,QAAI,CAACkD,eAAe;AAClB,aAAO;IACT;AACA,QACEA,cAAczD,SAASwD,gBAAgBxD,QACtCwD,gBAAgBE,YAAYC,UAC3BF,cAAcC,YAAYC,UAC1BF,cAAcC,YAAYF,gBAAgBE,SAC5C;AACA,aAAO;IACT;EACF,OAAO;AACL,QAAI,CAACrD,IAAIyC,OAAOrC,WAAWL,WAAAA,GAAc;AACvC,aAAO;IACT;EACF;AACA,SAAO;AACT;",
6
+ "names": ["decodeReference", "isEncodedReference", "EXPANDO_TYPENAME", "DXN", "filterMatchObject", "filter", "obj", "type", "typename", "doc", "system", "expectedDXN", "DXN", "parse", "asTypeDXN", "EXPANDO_TYPENAME", "actualDXN", "compareTypename", "id", "length", "includes", "props", "key", "valueFilter", "Object", "entries", "value", "data", "filterMatchValue", "foreignKeys", "hasMatchingKey", "some", "filterKey", "meta", "keys", "objKey", "source", "filters", "every", "f", "filterMatchObjectJSON", "startsWith", "structuralMatch", "filterObj", "targetObj", "strict", "filterKeys", "targetKeys", "filterValue", "targetValue", "compareValue", "operator", "isEncodedReference", "equals", "decodeReference", "toDXN", "nestedValue", "values", "Array", "isArray", "element", "from", "to", "expectedTypeDXN", "actualTypeDXN", "version", "undefined"]
7
7
  }
@@ -3,7 +3,7 @@ import {
3
3
  filterMatchObject,
4
4
  filterMatchObjectJSON,
5
5
  filterMatchValue
6
- } from "../chunk-MBMJB3V7.mjs";
6
+ } from "../chunk-KQYT6ADL.mjs";
7
7
  import "../chunk-CGS2ULMK.mjs";
8
8
  export {
9
9
  filterMatchObject,
@@ -3,7 +3,7 @@ import {
3
3
  filterMatchObject,
4
4
  filterMatchObjectJSON,
5
5
  filterMatchValue
6
- } from "./chunk-MBMJB3V7.mjs";
6
+ } from "./chunk-KQYT6ADL.mjs";
7
7
  import {
8
8
  AuthExtension,
9
9
  AuthStatus,
@@ -2937,6 +2937,8 @@ import { invariant as invariant9 } from "@dxos/invariant";
2937
2937
  import { BaseError } from "@dxos/errors";
2938
2938
  var QueryError = class extends BaseError.extend("QUERY_ERROR") {
2939
2939
  };
2940
+ var InvalidQueryError = class extends QueryError.extend("INVALID_QUERY") {
2941
+ };
2940
2942
 
2941
2943
  // src/query/plan.ts
2942
2944
  (function(QueryPlan2) {
@@ -3011,7 +3013,8 @@ var QueryPlanner = class {
3011
3013
  case "order":
3012
3014
  return this._generateOrderClause(query, context);
3013
3015
  default:
3014
- throw new QueryError(`Unsupported query type: ${query.type}`, {
3016
+ throw new QueryError({
3017
+ message: `Unsupported query type: ${query.type}`,
3015
3018
  context: {
3016
3019
  query: context.originalQuery
3017
3020
  }
@@ -3047,7 +3050,8 @@ var QueryPlanner = class {
3047
3050
  ]);
3048
3051
  }
3049
3052
  if (context.selectionInverted) {
3050
- throw new QueryError("Query too complex", {
3053
+ throw new QueryError({
3054
+ message: "Query too complex",
3051
3055
  context: {
3052
3056
  query: context.originalQuery
3053
3057
  }
@@ -3128,19 +3132,22 @@ var QueryPlanner = class {
3128
3132
  ]);
3129
3133
  }
3130
3134
  case "compare":
3131
- throw new QueryError("Query too complex", {
3135
+ throw new QueryError({
3136
+ message: "Query too complex",
3132
3137
  context: {
3133
3138
  query: context.originalQuery
3134
3139
  }
3135
3140
  });
3136
3141
  case "in":
3137
- throw new QueryError("Query too complex", {
3142
+ throw new QueryError({
3143
+ message: "Query too complex",
3138
3144
  context: {
3139
3145
  query: context.originalQuery
3140
3146
  }
3141
3147
  });
3142
3148
  case "range":
3143
- throw new QueryError("Query too complex", {
3149
+ throw new QueryError({
3150
+ message: "Query too complex",
3144
3151
  context: {
3145
3152
  query: context.originalQuery
3146
3153
  }
@@ -3151,7 +3158,8 @@ var QueryPlanner = class {
3151
3158
  selectionInverted: !context.selectionInverted
3152
3159
  });
3153
3160
  case "and":
3154
- throw new QueryError("Query too complex", {
3161
+ throw new QueryError({
3162
+ message: "Query too complex",
3155
3163
  context: {
3156
3164
  query: context.originalQuery
3157
3165
  }
@@ -3161,7 +3169,7 @@ var QueryPlanner = class {
3161
3169
  const typenames = filter.filters.map((f) => {
3162
3170
  invariant9(f.type === "object" && f.typename !== null, void 0, {
3163
3171
  F: __dxlog_file10,
3164
- L: 195,
3172
+ L: 199,
3165
3173
  S: this,
3166
3174
  A: [
3167
3175
  "f.type === 'object' && f.typename !== null",
@@ -3183,14 +3191,16 @@ var QueryPlanner = class {
3183
3191
  ...this._generateDeletedHandlingSteps(context)
3184
3192
  ]);
3185
3193
  } else {
3186
- throw new QueryError("Query too complex", {
3194
+ throw new QueryError({
3195
+ message: "Query too complex",
3187
3196
  context: {
3188
3197
  query: context.originalQuery
3189
3198
  }
3190
3199
  });
3191
3200
  }
3192
3201
  default:
3193
- throw new QueryError(`Unsupported filter type: ${filter.type}`, {
3202
+ throw new QueryError({
3203
+ message: `Unsupported filter type: ${filter.type}`,
3194
3204
  context: {
3195
3205
  query: context.originalQuery
3196
3206
  }