@stackone/datasync 1.0.0 → 1.0.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/index.cjs +1 -1
- package/dist/index.d.cts +1 -4
- package/dist/index.d.mts +1 -4
- package/dist/index.mjs +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e=Object.defineProperty,__name=(t,n)=>e(t,`name`,{value:n,configurable:!0}),SyncedQueryRejection=class extends Error{constructor(e,t){super(e),this.name=`SyncedQueryRejection`,this.details=t}toResponse(){return{...this.details,message:this.message,error:`Bad Request`,statusCode:400}}};const syncedQueryError=(e,t)=>new SyncedQueryRejection(e,t),t=[`term`,`terms`,`range`,`wildcard`,`match`,`match_phrase`,`exists`,`bool`],n=`OpenSearch-style filter (Query DSL) (${t.join(` / `)}) over synced fields. A filter is one clause: an object with exactly one query type, keyed by field name, e.g. {"term": {"<field>": <value>}}, {"terms": {"<field>": [...]}}, {"range": {"<field>": {"gte": ...}}}; combine clauses with {"bool": {"filter": [...], "must_not": [...]}}. Bare {"<field>": <value>} maps are rejected. match / match_phrase do word-level search (string fields only, case-insensitive); wildcard matches patterns (case-sensitive).`;function buildFullTextQuery(e){let t=e.trim();if(t)return{simple_query_string:{query:t,fields:[`data.*.text`]}}}const r=__name(e=>typeof e==`object`&&!!e&&!Array.isArray(e),`isPlainObject`),isScalar=e=>typeof e==`string`||typeof e==`number`||typeof e==`boolean`,isStringOrNumber=e=>typeof e==`string`||typeof e==`number`,isNumeric=e=>typeof e==`number`||typeof e==`string`&&e.trim()!==``&&Number.isFinite(Number(e)),describeValue=e=>e===null?`null`:Array.isArray(e)?`an array`:`a ${typeof e}`,describeAvailableFields=e=>{let t=[...e.keys()];if(t.length===0)return`No fields are queryable for this sync yet`;let n=t.slice(0,50),r=t.length-n.length,i=r>0?`, … and ${r} more`:``;return`Available fields: ${n.join(`, `)}${i}`},resolveField=(e,t,n=`filter`)=>{let r=t.get(e);if(!r)throw syncedQueryError(`Field '${e}' is not available for querying. ${describeAvailableFields(t)}`,{parameter:n,field:e,available_fields:[...t.keys()]});return`data.${r}`},filterError=(e,t)=>syncedQueryError(e,{parameter:`filter`,path:t}),i=new Set([`term`,`terms`,`range`,`wildcard`]),a=new Set([`match`,`match_phrase`]),o=new Set([`must`,`should`,`filter`,`must_not`]),s=new Set([`minimum_should_match`]),c=[`value`,`boost`,`case_insensitive`],l=[`value`,`boost`,`case_insensitive`,`rewrite`],u=[`query`,`operator`,`minimum_should_match`,`fuzziness`,`prefix_length`,`max_expansions`,`zero_terms_query`,`boost`],d=[`query`,`slop`,`zero_terms_query`,`boost`],f=new Set([`gt`,`gte`,`lt`,`lte`]),p=new Set([`format`,`time_zone`]),unsupportedQueryType=(e,n,r)=>{let i=`Supported types: ${t.join(`, `)}`;return n.aliasMap.has(e)?filterError(`'${e}' is a queryable field, not a query type. Wrap it in a clause, e.g. {"term": {"${e}": ...}}. ${i}`,r):filterError(`Unsupported query type '${e}'. ${i}`,r)},assertSupportedOptions=(e,t,n,r)=>{let i=Object.keys(t).find(e=>!n.includes(e));if(i!==void 0)throw filterError(`'${e}' option '${i}' is not supported. Supported: ${n.join(`, `)}`,r)},validateTermValue=(e,t,n)=>{if(!isScalar(t)){if(r(t)&&isScalar(t.value)){assertSupportedOptions(`term`,t,c,n);return}throw filterError(`'term' on '${e}' must be a single string, number or boolean (or {"value": ...}); use 'terms' for a list of values`,n)}},validateTermsValue=(e,t,n)=>{if(!(Array.isArray(t)&&t.every(isScalar)))throw filterError(`'terms' on '${e}' must be an array of values`,n)},validateWildcardValue=(e,t,n,i)=>{if(n!==void 0&&n!==`string`)throw filterError(`'wildcard' is only supported on string fields; '${e}' is not a string field`,i);if(typeof t!=`string`){if(r(t)&&typeof t.value==`string`){assertSupportedOptions(`wildcard`,t,l,i);return}throw filterError(`'wildcard' on '${e}' must be a pattern string (or {"value": "<pattern>"})`,i)}},validateTextValue=(e,t,n,i)=>{if(typeof n!=`string`){if(r(n)&&isScalar(n.query)){assertSupportedOptions(e,n,e===`match`?u:d,i);return}throw filterError(`'${e}' on '${t}' must be a string or a { "query": ... } object`,i)}},validateRangeBound=(e,t,n,r,i)=>{if(!isStringOrNumber(n))throw filterError(`'range' bound '${t}' on '${e}' must be a string or number`,i);if((r===`int`||r===`float`)&&!isNumeric(n))throw filterError(`'range' bound '${t}' on numeric field '${e}' must be a number`,i);if(r===`date`&&typeof n==`boolean`)throw filterError(`'range' bound '${t}' on date field '${e}' must be an ISO date string, date-math expression or epoch millis`,i)},validateRangeValue=(e,t,n,i)=>{if(n===`bool`)throw filterError(`'range' is not supported on boolean field '${e}'`,i);if(!r(t))throw filterError(`'range' on '${e}' must be an object of bounds, e.g. {"gte": ..., "lte": ...}`,i);let a=Object.keys(t);for(let r of a){if(f.has(r)){validateRangeBound(e,r,t[r],n,i);continue}if(p.has(r)){if(n!==void 0&&n!==`date`)throw filterError(`'range' option '${r}' is only supported on date fields; '${e}' is a ${n} field`,i);continue}throw filterError(`'range' operator '${r}' is not supported. Supported: ${[...f].join(`, `)} (plus ${[...p].join(`, `)} on date fields)`,i)}if(!a.some(e=>f.has(e)))throw filterError(`'range' on '${e}' needs at least one bound (${[...f].join(`, `)})`,i)},translateFieldClause=(e,t,n,i)=>{if(!r(t))throw filterError(`'${e}' clause at '${i}' must be an object keyed by field name, e.g. {"${e}": {"<field>": ...}}`,i);let o=Object.keys(t);if(o.length!==1)throw filterError(`'${e}' clause at '${i}' must name exactly one field, got: ${o.join(`, `)||`none`}`,i);let[s]=o,c=t[s],l=`${i}.${s}`,u=resolveField(s,n.aliasMap),d=n.fieldTypes.get(s);if(a.has(e)){if(d!==`string`)throw filterError(`'${e}' is only supported on string fields; '${s}' is not a string field`,l);return validateTextValue(e,s,c,l),{[e]:{[`${u}.text`]:c}}}return e===`term`?validateTermValue(s,c,l):e===`terms`?validateTermsValue(s,c,l):e===`range`?validateRangeValue(s,c,d,l):validateWildcardValue(s,c,d,l),{[e]:{[u]:c}}},translateExists=(e,t,n)=>{if(!r(e)||typeof e.field!=`string`)throw filterError(`'exists' query requires a string 'field'`,n);let i=Object.keys(e).filter(e=>e!==`field`);if(i.length>0)throw filterError(`'exists' only accepts 'field'; unsupported: ${i.join(`, `)}`,n);return{field:resolveField(e.field,t.aliasMap)}},translateBool=(e,t,n,i)=>{if(!r(e))throw filterError(`'bool' clause at '${n}' must be an object of clauses (${[...o].join(`, `)})`,n);let a={};for(let[r,c]of Object.entries(e)){if(o.has(r)){a[r]=(Array.isArray(c)?c:[c]).map((e,a)=>translateNode(e,t,`${n}.${r}[${a}]`,i+1));continue}if(s.has(r)){if(typeof c!=`number`&&typeof c!=`string`)throw filterError(`'bool' option '${r}' must be a number or string`,n);a[r]=c;continue}throw filterError(`'bool' option '${r}' is not supported. Supported: ${[...o,...s].join(`, `)}`,n)}return a},translateNode=(e,t,n,o)=>{if(o>10)throw filterError(`Filter nesting too deep (maximum 10 levels)`,n);if(!r(e))throw filterError(`Filter clause at '${n}' must be an object, got ${describeValue(e)}`,n);let s=Object.keys(e);if(s.length===0)throw filterError(`Filter clause at '${n}' is empty`,n);if(s.length>1)throw filterError(`Filter clause at '${n}' must contain exactly one query type, got: ${s.join(`, `)}. Combine clauses with {"bool": {"filter": [...]}}`,n);let[c]=s,l=e[c],u=`${n}.${c}`;if(c===`bool`)return{bool:translateBool(l,t,u,o)};if(c===`exists`)return{exists:translateExists(l,t,u)};if(i.has(c)||a.has(c))return translateFieldClause(c,l,t,u);throw unsupportedQueryType(c,t,n)},translateQuery=(e,t,n=new Map)=>translateNode(e,{aliasMap:t,fieldTypes:n},`filter`,0);function translateSourceFields(e,t){return e.map(e=>resolveField(e,t,`source`))}const m=new Set([`asc`,`desc`]),h=new Set([`min`,`max`,`sum`,`avg`,`median`]),g=[`order`,`missing`,`mode`],sortError=e=>syncedQueryError(e,{parameter:`sort`}),validateSortOptions=(e,t)=>{let n=sortError(`'sort' order for '${e}' must be "asc" or "desc"`);if(typeof t==`string`){if(!m.has(t))throw n;return}if(!r(t))throw sortError(`'sort' options for '${e}' must be "asc", "desc" or an object like {"order": "desc"}`);let i=Object.keys(t).find(e=>!g.includes(e));if(i!==void 0)throw sortError(`'sort' option '${i}' is not supported. Supported: ${g.join(`, `)}`);if(`order`in t&&!(typeof t.order==`string`&&m.has(t.order)))throw n;if(`mode`in t&&!(typeof t.mode==`string`&&h.has(t.mode)))throw sortError(`'sort' mode for '${e}' must be one of ${[...h].join(`, `)}`)};function translateSortFields(e,t){return e.map(e=>{if(typeof e==`string`)return resolveField(e,t,`sort`);if(r(e)){let n=Object.keys(e);if(n.length!==1)throw sortError(`Each sort entry must reference exactly one field`);let[r]=n,i=resolveField(r,t,`sort`);return validateSortOptions(r,e[r]),{[i]:e[r]}}throw sortError(`Each sort entry must be a field name or a '{ field: order }' object`)})}const _=1e3,v=[`avg`,`sum`,`min`,`max`,`value_count`,`stats`,`extended_stats`,`cardinality`,`percentiles`],y=[`terms`,`date_histogram`,`histogram`,`range`,`date_range`],b=new Set([...v,...y]),x=new Set([`__proto__`,`constructor`,`prototype`]),S=[`int`,`float`],C={avg:{label:`a numeric`,types:S},sum:{label:`a numeric`,types:S},stats:{label:`a numeric`,types:S},extended_stats:{label:`a numeric`,types:S},percentiles:{label:`a numeric`,types:S},histogram:{label:`a numeric`,types:S},range:{label:`a numeric`,types:S},min:{label:`a numeric or date`,types:[...S,`date`]},max:{label:`a numeric or date`,types:[...S,`date`]},date_histogram:{label:`a date`,types:[`date`]},date_range:{label:`a date`,types:[`date`]}},w=[`missing`,`format`],T={avg:w,sum:w,min:w,max:w,value_count:w,stats:w,extended_stats:w,cardinality:[`precision_threshold`,`missing`,`format`],percentiles:[`percents`,`keyed`,`missing`,`format`],terms:[`size`,`missing`,`min_doc_count`,`order`],date_histogram:[`calendar_interval`,`fixed_interval`,`interval`,`offset`,`time_zone`,`format`,`min_doc_count`,`order`,`missing`,`keyed`],histogram:[`interval`,`offset`,`min_doc_count`,`order`,`missing`,`keyed`],range:[`ranges`,`keyed`,`missing`],date_range:[`ranges`,`format`,`time_zone`,`keyed`,`missing`]},E=new Set([`aggs`,`aggregations`]),D={date_histogram:{keys:[`calendar_interval`,`fixed_interval`,`interval`],exactlyOne:!0},histogram:{keys:[`interval`]},range:{keys:[`ranges`]},date_range:{keys:[`ranges`]}};function isPlainObject(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}const O=new Set([`from`,`to`,`key`]);function rangeEntryKeys(e){return Object.keys(e).every(e=>O.has(e))}const aggsError=e=>syncedQueryError(e,{parameter:`aggs`});function assertAggFieldType(e,t,n){let r=C[e],i=n.fieldTypes.get(t);if(!(!r||i===void 0||r.types.includes(i)))throw syncedQueryError(`'${e}' requires ${r.label} field; '${t}' is a ${i} field`,{parameter:`aggs`,field:t})}function translateAggBody(e,t,n){if(!isPlainObject(t))throw aggsError(`Aggregation definition must be an object`);let r=T[e]??[],i={};for(let[a,o]of Object.entries(t)){if(a===`field`){if(typeof o!=`string`)throw aggsError(`Aggregation 'field' must be a string`);i[a]=resolveField(o,n.aliasMap,`aggs`),assertAggFieldType(e,o,n);continue}if(!r.includes(a))throw aggsError(`Aggregation option '${a}' is not supported for '${e}'. Supported: field, ${r.join(`, `)}`);if(a===`size`){if(typeof o!=`number`||!Number.isInteger(o)||o<1)throw aggsError(`Aggregation 'size' must be a positive integer`);if(o>_)throw aggsError(`Aggregation 'size' exceeds the maximum of ${_}`)}if(a===`ranges`){if(!Array.isArray(o)||o.length===0||!o.every(e=>isPlainObject(e)&&rangeEntryKeys(e)))throw aggsError(`Aggregation 'ranges' must be an array of {from, to, key} objects`);if(o.length>100)throw aggsError(`Aggregation 'ranges' exceeds the maximum of 100 entries`)}if(a===`percents`){if(!Array.isArray(o)||o.length===0||!o.every(e=>typeof e==`number`&&Number.isFinite(e)&&e>=0&&e<=100))throw aggsError(`Aggregation 'percents' must be an array of numbers between 0 and 100`);if(o.length>100)throw aggsError(`Aggregation 'percents' exceeds the maximum of 100 entries`)}if(a===`interval`){if(e===`date_histogram`){if(typeof o!=`string`||o.length===0)throw aggsError(`Aggregation 'interval' must be a non-empty string`)}else if(typeof o!=`number`||!Number.isFinite(o)||o<=0)throw aggsError(`Aggregation 'interval' must be a finite number greater than 0`)}if((a===`fixed_interval`||a===`calendar_interval`)&&(typeof o!=`string`||o.length===0))throw aggsError(`Aggregation '${a}' must be a non-empty string`);if(a===`min_doc_count`&&(typeof o!=`number`||!Number.isInteger(o)||o<0))throw aggsError(`Aggregation 'min_doc_count' must be a non-negative integer`);if(a===`keyed`&&typeof o!=`boolean`)throw aggsError(`Aggregation 'keyed' must be a boolean`);i[a]=o}if(!(`field`in t))throw aggsError(`Aggregation '${e}' requires a 'field'`);let a=D[e];if(a){let n=a.keys.filter(e=>e in t);if(a.exactlyOne&&n.length!==1)throw aggsError(`Aggregation '${e}' requires exactly one of: ${a.keys.join(`, `)}`);if(!a.exactlyOne&&n.length===0)throw a.keys.length===1?aggsError(`Aggregation '${e}' requires '${a.keys[0]}'`):aggsError(`Aggregation '${e}' requires one of: ${a.keys.join(`, `)}`)}return i}function translateAggDefinition(e,t,n,r){if(!isPlainObject(t))throw aggsError(`Aggregation definition must be an object`);let i=Object.keys(t).filter(e=>e!==`meta`&&!E.has(e));if(i.length!==1)throw aggsError(`Aggregation '${e}' must define exactly one aggregation type, got${i.length===0?` none`:`: ${i.join(`, `)}`}`);let a={};for(let[e,i]of Object.entries(t)){if(E.has(e)){a[e]=translateAggMap(i,n,r+1);continue}if(e===`meta`){a[e]=i;continue}if(!b.has(e))throw aggsError(`Aggregation type '${e}' is not supported. Supported types: ${[...b].join(`, `)}`);a[e]=translateAggBody(e,i,n)}return a}function translateAggMap(e,t,n){if(n>5)throw aggsError(`Aggregation nesting too deep`);if(!isPlainObject(e))throw aggsError(`Aggregations must be an object`);let r={};for(let[i,a]of Object.entries(e)){if(x.has(i))throw aggsError(`Aggregation name '${i}' is reserved`);if(t.definitions+=1,t.definitions>50)throw aggsError(`Aggregations exceed the maximum of 50 definitions`);r[i]=translateAggDefinition(i,a,t,n)}return r}function translateAggs(e,t,n=new Map){return translateAggMap(e,{aliasMap:t,fieldTypes:n,definitions:0},0)}const k=.9,A=new Set([`__proto__`,`constructor`,`prototype`]),hasForbiddenSegment=e=>e.replace(/\[\]/g,``).split(`.`).some(e=>A.has(e));function processValue(e,t,n,r){if(t!=null&&!(n>=5)){if(Array.isArray(t)){let i=t.filter(e=>e!=null);if(i.length===0)return;let a=i[0];if(typeof a==`object`&&!Array.isArray(a))for(let t of i)processObject(`${e}[]`,t,n+2,r);else r.has(e)||r.set(e,[]),r.get(e)?.push(...i);return}if(typeof t==`object`){processObject(e,t,n+1,r);return}r.has(e)||r.set(e,[]),r.get(e)?.push(t)}}function processObject(e,t,n,r){if(!(n>=5))for(let[i,a]of Object.entries(t))A.has(i)||processValue(e?`${e}.${i}`:i,a,n,r)}function collectFieldValues(e){let t=new Map;for(let n of e)processObject(``,n,0,t);return t}function flattenItem(e){let t=new Map;return flattenObject(``,e,0,t),Object.fromEntries(t)}function flattenValue(e,t,n,r){if(t!=null&&!(n>=5)){if(Array.isArray(t)){if(t.length===0)return;let i=t.find(e=>e!=null);if(typeof i==`object`&&!Array.isArray(i))flattenArrayOfObjects(e,t,n,r);else{let n=t.filter(e=>e!=null);n.length>0&&r.set(e,n)}return}if(typeof t==`object`){flattenObject(e,t,n+1,r);return}r.set(e,t)}}function flattenObject(e,t,n,r){if(!(n>=5))for(let[i,a]of Object.entries(t))A.has(i)||flattenValue(e?`${e}.${i}`:i,a,n,r)}function flattenArrayOfObjects(e,t,n,r){let i=`${e}[]`,a=[],o=[],s=new Set;for(let e of t){if(typeof e!=`object`||!e||Array.isArray(e)){a.push(new Map);continue}let t=new Map;flattenObject(i,e,n+2,t),a.push(t);for(let e of t.keys())s.has(e)||(s.add(e),o.push(e))}for(let e of o){let n=t.map((t,n)=>{let r=a[n].get(e);return r===void 0?null:r});r.set(e,n)}}function unflattenItem(e){let t={},n=new Map;for(let[r,i]of Object.entries(e)){if(hasForbiddenSegment(r)||(r.match(/\[\]/g)??[]).length>5)continue;let e=r.indexOf(`[].`);if(e!==-1){let t=r.substring(0,e),a=r.substring(e+3);n.has(t)||n.set(t,new Map),n.get(t)?.set(a,i);continue}let a=r.split(`.`),o=t;for(let e=0;e<a.length-1;e++){let t=a[e];(!Object.prototype.hasOwnProperty.call(o,t)||typeof o[t]!=`object`||o[t]===null)&&(o[t]={}),o=o[t]}o[a[a.length-1]]=i}for(let[e,r]of n.entries()){let n=0;for(let e of r.values())Array.isArray(e)&&(n=Math.max(n,e.length));let i=[];for(let e=0;e<n;e++){let t={};for(let[n,i]of r.entries())t[n]=Array.isArray(i)?i[e]:i;i.push(unflattenItem(t))}let a=e.split(`.`),o=t;for(let e=0;e<a.length-1;e++){let t=a[e];(!Object.prototype.hasOwnProperty.call(o,t)||typeof o[t]!=`object`||o[t]===null)&&(o[t]={}),o=o[t]}o[a[a.length-1]]=i}return t}const j=/^\d{4}-\d{2}-\d{2}(T\d{2}:\d{2}:\d{2}(\.\d+)?(Z|[+-]\d{2}:\d{2})?)?$/;function isValidCalendarDate(e){let[t,n,r]=e.slice(0,10).split(`-`).map(Number);return n<1||n>12||r<1?!1:r<=new Date(Date.UTC(t,n,0)).getUTCDate()&&!Number.isNaN(Date.parse(e))}function inferPrimitiveType(e){return typeof e==`boolean`?`bool`:typeof e==`number`?Number.isInteger(e)?`int`:`float`:typeof e==`string`?j.test(e)&&isValidCalendarDate(e)?`date`:`string`:null}function determineFieldType(e){let t=e.map(inferPrimitiveType).filter(e=>e!==null);if(t.length===0)return null;let n=t.reduce((e,t)=>(e[t]=(e[t]??0)+1,e),{});if(((n.int??0)+(n.float??0))/t.length>=k)return(n.float??0)>0?`float`:`int`;let r=Object.entries(n).sort((e,t)=>t[1]-e[1])[0];return r[1]/t.length>=k?r[0]:`string`}function findNextAvailableSlot(e,t){let n=1;for(;t.has(`${e}${n}`);)n++;return`${e}${n}`}const M=1e4;function assertPageWindow(e,t){if(e!==void 0&&(!Number.isInteger(e)||e<1))throw syncedQueryError(`page_size ${e} must be an integer of at least 1`,{parameter:`page_size`,min_page_size:1});if(t!==void 0&&(!Number.isInteger(t)||t<0))throw syncedQueryError(`skip ${t} must be an integer of 0 or greater`,{parameter:`skip`,min_skip:0});if(e!==void 0&&e>200)throw syncedQueryError(`page_size ${e} exceeds the maximum of 200`,{parameter:`page_size`,max_page_size:200});let n=(t??0)+(e??100);if(n>1e4)throw syncedQueryError(`skip + page_size (${n}${e===void 0?`, page_size defaulting to 100`:``}) exceeds the maximum result window of ${M}; narrow the filter instead of paging deeper`,{parameter:`skip`,max_result_window:M})}function buildTenantScopeFilter(e){let t=e.ref?[{term:{refs:e.ref}}]:[{term:{account_id:e.accountId}},{term:{params_hash:e.paramsHash}},{term:{last_full_run_id:e.lastFullRunId}}];return[{term:{project_id:e.projectId}},...t,{term:{action_id:e.actionId}}]}function buildSearchBody(e){let t=buildTenantScopeFilter(e.scope);e.additionalQuery&&t.push(e.additionalQuery);let n={filter:t};return e.textQuery&&(n.must=[e.textQuery]),{query:{bool:n},timeout:`10s`,size:e.size??100,from:e.from??0,...e.source?.length&&{_source:e.source},...e.sort?.length&&{sort:e.sort}}}function buildAggregationBody(e){let t=buildTenantScopeFilter(e.scope);return e.additionalQuery&&t.push(e.additionalQuery),e.textQuery&&t.push(e.textQuery),{query:{bool:{filter:t}},size:0,aggregations:e.aggregations,timeout:`10s`}}function isIncompleteResponse(e){let t=e;return t?.timed_out===!0||(t?._shards?.failed??0)>0}const asClientError=e=>typeof e==`object`&&e?e:void 0;function isIndexNotFoundError(e){return asClientError(e)?.meta?.body?.error?.type===`index_not_found_exception`}function isOpenSearchBadRequest(e){return asClientError(e)?.meta?.statusCode===400}function describeOpenSearchRejection(e,t){let n=e.meta?.body?.error,r=n?.root_cause?.[0]?.reason??n?.reason??e.message??`unknown`;return{message:`The search backend rejected the synced query: ${r}. Check the ${t.map(e=>`'${e}'`).join(` and `)} arguments against the queryable fields`,parameters:t,reason:r}}exports.AGGREGATION_TIMEOUT=`10s`,exports.DEFAULT_SYNCED_PAGE_SIZE=100,exports.MAX_SYNCED_PAGE_SIZE=200,exports.MAX_SYNCED_RESULT_WINDOW=M,exports.SEARCH_TIMEOUT=`10s`,exports.SUPPORTED_QUERY_OPERATIONS=t,exports.SYNCED_FILTER_GRAMMAR=n,exports.SYNCED_SEARCH_DESCRIPTION='Free-text search over the record\'s text fields, ranked by relevance. Supports "quoted phrases", +required / -excluded terms, and prefix* — lenient (never errors). Combine with `filter` to narrow; results are relevance-ranked unless an explicit sort is given.',exports.SyncedQueryRejection=SyncedQueryRejection,exports.assertPageWindow=assertPageWindow,exports.buildAggregationBody=buildAggregationBody,exports.buildFullTextQuery=buildFullTextQuery,exports.buildSearchBody=buildSearchBody,exports.buildTenantScopeFilter=buildTenantScopeFilter,exports.collectFieldValues=collectFieldValues,exports.describeOpenSearchRejection=describeOpenSearchRejection,exports.determineFieldType=determineFieldType,exports.findNextAvailableSlot=findNextAvailableSlot,exports.flattenItem=flattenItem,exports.inferPrimitiveType=inferPrimitiveType,exports.isIncompleteResponse=isIncompleteResponse,exports.isIndexNotFoundError=isIndexNotFoundError,exports.isOpenSearchBadRequest=isOpenSearchBadRequest,exports.resolveField=resolveField,exports.syncedQueryError=syncedQueryError,exports.translateAggs=translateAggs,exports.translateQuery=translateQuery,exports.translateSortFields=translateSortFields,exports.translateSourceFields=translateSourceFields,exports.unflattenItem=unflattenItem;
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e=Object.defineProperty,__name=(t,n)=>e(t,`name`,{value:n,configurable:!0}),SyncedQueryRejection=class extends Error{constructor(e,t){super(e),this.name=`SyncedQueryRejection`,this.details=t}toResponse(){return{...this.details,message:this.message,error:`Bad Request`,statusCode:400}}};const syncedQueryError=(e,t)=>new SyncedQueryRejection(e,t),t=[`term`,`terms`,`range`,`wildcard`,`match`,`match_phrase`,`exists`,`bool`],n=`OpenSearch-style filter (Query DSL) (${t.join(` / `)}) over synced fields. A filter is one clause: an object with exactly one query type, keyed by field name, e.g. {"term": {"<field>": <value>}}, {"terms": {"<field>": [...]}}, {"range": {"<field>": {"gte": ...}}}; combine clauses with {"bool": {"filter": [...], "must_not": [...]}}. Bare {"<field>": <value>} maps are rejected. match / match_phrase do word-level search (string fields only, case-insensitive); wildcard matches patterns (case-sensitive).`;function buildFullTextQuery(e){let t=e.trim();if(t)return{simple_query_string:{query:t,fields:[`data.*.text`]}}}const r=__name(e=>typeof e==`object`&&!!e&&!Array.isArray(e),`isPlainObject`),isScalar=e=>typeof e==`string`||typeof e==`number`||typeof e==`boolean`,isStringOrNumber=e=>typeof e==`string`||typeof e==`number`,isNumeric=e=>typeof e==`number`||typeof e==`string`&&e.trim()!==``&&Number.isFinite(Number(e)),describeValue=e=>e===null?`null`:Array.isArray(e)?`an array`:`a ${typeof e}`,describeAvailableFields=e=>{let t=[...e.keys()];if(t.length===0)return`No fields are queryable for this sync yet`;let n=t.slice(0,50),r=t.length-n.length,i=r>0?`, … and ${r} more`:``;return`Available fields: ${n.join(`, `)}${i}`},resolveField=(e,t,n=`filter`)=>{let r=t.get(e);if(!r)throw syncedQueryError(`Field '${e}' is not available for querying. ${describeAvailableFields(t)}`,{parameter:n,field:e,available_fields:[...t.keys()]});return`data.${r}`},filterError=(e,t)=>syncedQueryError(e,{parameter:`filter`,path:t}),i=new Set([`term`,`terms`,`range`,`wildcard`]),a=new Set([`match`,`match_phrase`]),o=new Set([`must`,`should`,`filter`,`must_not`]),s=new Set([`minimum_should_match`]),c=[`value`,`boost`,`case_insensitive`],l=[`value`,`boost`,`case_insensitive`,`rewrite`],u=[`query`,`operator`,`minimum_should_match`,`fuzziness`,`prefix_length`,`max_expansions`,`zero_terms_query`,`boost`],d=[`query`,`slop`,`zero_terms_query`,`boost`],f=new Set([`gt`,`gte`,`lt`,`lte`]),p=new Set([`format`,`time_zone`]),unsupportedQueryType=(e,n,r)=>{let i=`Supported types: ${t.join(`, `)}`;return n.aliasMap.has(e)?filterError(`'${e}' is a queryable field, not a query type. Wrap it in a clause, e.g. {"term": {"${e}": ...}}. ${i}`,r):filterError(`Unsupported query type '${e}'. ${i}`,r)},assertSupportedOptions=(e,t,n,r)=>{let i=Object.keys(t).find(e=>!n.includes(e));if(i!==void 0)throw filterError(`'${e}' option '${i}' is not supported. Supported: ${n.join(`, `)}`,r)},validateTermValue=(e,t,n)=>{if(!isScalar(t)){if(r(t)&&isScalar(t.value)){assertSupportedOptions(`term`,t,c,n);return}throw filterError(`'term' on '${e}' must be a single string, number or boolean (or {"value": ...}); use 'terms' for a list of values`,n)}},validateTermsValue=(e,t,n)=>{if(!(Array.isArray(t)&&t.every(isScalar)))throw filterError(`'terms' on '${e}' must be an array of values`,n)},validateWildcardValue=(e,t,n,i)=>{if(n!==void 0&&n!==`string`)throw filterError(`'wildcard' is only supported on string fields; '${e}' is not a string field`,i);if(typeof t!=`string`){if(r(t)&&typeof t.value==`string`){assertSupportedOptions(`wildcard`,t,l,i);return}throw filterError(`'wildcard' on '${e}' must be a pattern string (or {"value": "<pattern>"})`,i)}},validateTextValue=(e,t,n,i)=>{if(typeof n!=`string`){if(r(n)&&isScalar(n.query)){assertSupportedOptions(e,n,e===`match`?u:d,i);return}throw filterError(`'${e}' on '${t}' must be a string or a { "query": ... } object`,i)}},validateRangeBound=(e,t,n,r,i)=>{if(!isStringOrNumber(n))throw filterError(`'range' bound '${t}' on '${e}' must be a string or number`,i);if((r===`int`||r===`float`)&&!isNumeric(n))throw filterError(`'range' bound '${t}' on numeric field '${e}' must be a number`,i);if(r===`date`&&typeof n==`boolean`)throw filterError(`'range' bound '${t}' on date field '${e}' must be an ISO date string, date-math expression or epoch millis`,i)},validateRangeValue=(e,t,n,i)=>{if(n===`bool`)throw filterError(`'range' is not supported on boolean field '${e}'`,i);if(!r(t))throw filterError(`'range' on '${e}' must be an object of bounds, e.g. {"gte": ..., "lte": ...}`,i);let a=Object.keys(t);for(let r of a){if(f.has(r)){validateRangeBound(e,r,t[r],n,i);continue}if(p.has(r)){if(n!==void 0&&n!==`date`)throw filterError(`'range' option '${r}' is only supported on date fields; '${e}' is a ${n} field`,i);continue}throw filterError(`'range' operator '${r}' is not supported. Supported: ${[...f].join(`, `)} (plus ${[...p].join(`, `)} on date fields)`,i)}if(!a.some(e=>f.has(e)))throw filterError(`'range' on '${e}' needs at least one bound (${[...f].join(`, `)})`,i)},translateFieldClause=(e,t,n,i)=>{if(!r(t))throw filterError(`'${e}' clause at '${i}' must be an object keyed by field name, e.g. {"${e}": {"<field>": ...}}`,i);let o=Object.keys(t);if(o.length!==1)throw filterError(`'${e}' clause at '${i}' must name exactly one field, got: ${o.join(`, `)||`none`}`,i);let[s]=o,c=t[s],l=`${i}.${s}`,u=resolveField(s,n.aliasMap),d=n.fieldTypes.get(s);if(a.has(e)){if(d!==`string`)throw filterError(`'${e}' is only supported on string fields; '${s}' is not a string field`,l);return validateTextValue(e,s,c,l),{[e]:{[`${u}.text`]:c}}}return e===`term`?validateTermValue(s,c,l):e===`terms`?validateTermsValue(s,c,l):e===`range`?validateRangeValue(s,c,d,l):validateWildcardValue(s,c,d,l),{[e]:{[u]:c}}},translateExists=(e,t,n)=>{if(!r(e)||typeof e.field!=`string`)throw filterError(`'exists' query requires a string 'field'`,n);let i=Object.keys(e).filter(e=>e!==`field`);if(i.length>0)throw filterError(`'exists' only accepts 'field'; unsupported: ${i.join(`, `)}`,n);return{field:resolveField(e.field,t.aliasMap)}},translateBool=(e,t,n,i)=>{if(!r(e))throw filterError(`'bool' clause at '${n}' must be an object of clauses (${[...o].join(`, `)})`,n);let a={};for(let[r,c]of Object.entries(e)){if(o.has(r)){a[r]=(Array.isArray(c)?c:[c]).map((e,a)=>translateNode(e,t,`${n}.${r}[${a}]`,i+1));continue}if(s.has(r)){if(typeof c!=`number`&&typeof c!=`string`)throw filterError(`'bool' option '${r}' must be a number or string`,n);a[r]=c;continue}throw filterError(`'bool' option '${r}' is not supported. Supported: ${[...o,...s].join(`, `)}`,n)}return a},translateNode=(e,t,n,o)=>{if(o>10)throw filterError(`Filter nesting too deep (maximum 10 levels)`,n);if(!r(e))throw filterError(`Filter clause at '${n}' must be an object, got ${describeValue(e)}`,n);let s=Object.keys(e);if(s.length===0)throw filterError(`Filter clause at '${n}' is empty`,n);if(s.length>1)throw filterError(`Filter clause at '${n}' must contain exactly one query type, got: ${s.join(`, `)}. Combine clauses with {"bool": {"filter": [...]}}`,n);let[c]=s,l=e[c],u=`${n}.${c}`;if(c===`bool`)return{bool:translateBool(l,t,u,o)};if(c===`exists`)return{exists:translateExists(l,t,u)};if(i.has(c)||a.has(c))return translateFieldClause(c,l,t,u);throw unsupportedQueryType(c,t,n)},translateQuery=(e,t,n=new Map)=>translateNode(e,{aliasMap:t,fieldTypes:n},`filter`,0);function translateSourceFields(e,t){return e.map(e=>resolveField(e,t,`source`))}const m=new Set([`asc`,`desc`]),h=new Set([`min`,`max`,`sum`,`avg`,`median`]),g=[`order`,`missing`,`mode`],sortError=e=>syncedQueryError(e,{parameter:`sort`}),validateSortOptions=(e,t)=>{let n=sortError(`'sort' order for '${e}' must be "asc" or "desc"`);if(typeof t==`string`){if(!m.has(t))throw n;return}if(!r(t))throw sortError(`'sort' options for '${e}' must be "asc", "desc" or an object like {"order": "desc"}`);let i=Object.keys(t).find(e=>!g.includes(e));if(i!==void 0)throw sortError(`'sort' option '${i}' is not supported. Supported: ${g.join(`, `)}`);if(`order`in t&&!(typeof t.order==`string`&&m.has(t.order)))throw n;if(`mode`in t&&!(typeof t.mode==`string`&&h.has(t.mode)))throw sortError(`'sort' mode for '${e}' must be one of ${[...h].join(`, `)}`)};function translateSortFields(e,t){return e.map(e=>{if(typeof e==`string`)return resolveField(e,t,`sort`);if(r(e)){let n=Object.keys(e);if(n.length!==1)throw sortError(`Each sort entry must reference exactly one field`);let[r]=n,i=resolveField(r,t,`sort`);return validateSortOptions(r,e[r]),{[i]:e[r]}}throw sortError(`Each sort entry must be a field name or a '{ field: order }' object`)})}const _=1e3,v=[`avg`,`sum`,`min`,`max`,`value_count`,`stats`,`extended_stats`,`cardinality`,`percentiles`],y=[`terms`,`date_histogram`,`histogram`,`range`,`date_range`],b=new Set([...v,...y]),x=new Set([`__proto__`,`constructor`,`prototype`]),S=[`int`,`float`],C={avg:{label:`a numeric`,types:S},sum:{label:`a numeric`,types:S},stats:{label:`a numeric`,types:S},extended_stats:{label:`a numeric`,types:S},percentiles:{label:`a numeric`,types:S},histogram:{label:`a numeric`,types:S},range:{label:`a numeric`,types:S},min:{label:`a numeric or date`,types:[...S,`date`]},max:{label:`a numeric or date`,types:[...S,`date`]},date_histogram:{label:`a date`,types:[`date`]},date_range:{label:`a date`,types:[`date`]}},w=[`missing`,`format`],T={avg:w,sum:w,min:w,max:w,value_count:w,stats:w,extended_stats:w,cardinality:[`precision_threshold`,`missing`,`format`],percentiles:[`percents`,`keyed`,`missing`,`format`],terms:[`size`,`missing`,`min_doc_count`,`order`],date_histogram:[`calendar_interval`,`fixed_interval`,`interval`,`offset`,`time_zone`,`format`,`min_doc_count`,`order`,`missing`,`keyed`],histogram:[`interval`,`offset`,`min_doc_count`,`order`,`missing`,`keyed`],range:[`ranges`,`keyed`,`missing`],date_range:[`ranges`,`format`,`time_zone`,`keyed`,`missing`]},E=new Set([`aggs`,`aggregations`]),D={date_histogram:{keys:[`calendar_interval`,`fixed_interval`,`interval`],exactlyOne:!0},histogram:{keys:[`interval`]},range:{keys:[`ranges`]},date_range:{keys:[`ranges`]}};function isPlainObject(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}const O=new Set([`from`,`to`,`key`]);function rangeEntryKeys(e){return Object.keys(e).every(e=>O.has(e))}const aggsError=e=>syncedQueryError(e,{parameter:`aggs`});function assertAggFieldType(e,t,n){let r=C[e],i=n.fieldTypes.get(t);if(!(!r||i===void 0||r.types.includes(i)))throw syncedQueryError(`'${e}' requires ${r.label} field; '${t}' is a ${i} field`,{parameter:`aggs`,field:t})}function translateAggBody(e,t,n){if(!isPlainObject(t))throw aggsError(`Aggregation definition must be an object`);let r=T[e]??[],i={};for(let[a,o]of Object.entries(t)){if(a===`field`){if(typeof o!=`string`)throw aggsError(`Aggregation 'field' must be a string`);i[a]=resolveField(o,n.aliasMap,`aggs`),assertAggFieldType(e,o,n);continue}if(!r.includes(a))throw aggsError(`Aggregation option '${a}' is not supported for '${e}'. Supported: field, ${r.join(`, `)}`);if(a===`size`){if(typeof o!=`number`||!Number.isInteger(o)||o<1)throw aggsError(`Aggregation 'size' must be a positive integer`);if(o>_)throw aggsError(`Aggregation 'size' exceeds the maximum of ${_}`)}if(a===`ranges`){if(!Array.isArray(o)||o.length===0||!o.every(e=>isPlainObject(e)&&rangeEntryKeys(e)))throw aggsError(`Aggregation 'ranges' must be an array of {from, to, key} objects`);if(o.length>100)throw aggsError(`Aggregation 'ranges' exceeds the maximum of 100 entries`)}if(a===`percents`){if(!Array.isArray(o)||o.length===0||!o.every(e=>typeof e==`number`&&Number.isFinite(e)&&e>=0&&e<=100))throw aggsError(`Aggregation 'percents' must be an array of numbers between 0 and 100`);if(o.length>100)throw aggsError(`Aggregation 'percents' exceeds the maximum of 100 entries`)}if(a===`interval`){if(e===`date_histogram`){if(typeof o!=`string`||o.length===0)throw aggsError(`Aggregation 'interval' must be a non-empty string`)}else if(typeof o!=`number`||!Number.isFinite(o)||o<=0)throw aggsError(`Aggregation 'interval' must be a finite number greater than 0`)}if((a===`fixed_interval`||a===`calendar_interval`)&&(typeof o!=`string`||o.length===0))throw aggsError(`Aggregation '${a}' must be a non-empty string`);if(a===`min_doc_count`&&(typeof o!=`number`||!Number.isInteger(o)||o<0))throw aggsError(`Aggregation 'min_doc_count' must be a non-negative integer`);if(a===`keyed`&&typeof o!=`boolean`)throw aggsError(`Aggregation 'keyed' must be a boolean`);i[a]=o}if(!(`field`in t))throw aggsError(`Aggregation '${e}' requires a 'field'`);let a=D[e];if(a){let n=a.keys.filter(e=>e in t);if(a.exactlyOne&&n.length!==1)throw aggsError(`Aggregation '${e}' requires exactly one of: ${a.keys.join(`, `)}`);if(!a.exactlyOne&&n.length===0)throw a.keys.length===1?aggsError(`Aggregation '${e}' requires '${a.keys[0]}'`):aggsError(`Aggregation '${e}' requires one of: ${a.keys.join(`, `)}`)}return i}function translateAggDefinition(e,t,n,r){if(!isPlainObject(t))throw aggsError(`Aggregation definition must be an object`);let i=Object.keys(t).filter(e=>e!==`meta`&&!E.has(e));if(i.length!==1)throw aggsError(`Aggregation '${e}' must define exactly one aggregation type, got${i.length===0?` none`:`: ${i.join(`, `)}`}`);let a={};for(let[e,i]of Object.entries(t)){if(E.has(e)){a[e]=translateAggMap(i,n,r+1);continue}if(e===`meta`){a[e]=i;continue}if(!b.has(e))throw aggsError(`Aggregation type '${e}' is not supported. Supported types: ${[...b].join(`, `)}`);a[e]=translateAggBody(e,i,n)}return a}function translateAggMap(e,t,n){if(n>5)throw aggsError(`Aggregation nesting too deep`);if(!isPlainObject(e))throw aggsError(`Aggregations must be an object`);let r={};for(let[i,a]of Object.entries(e)){if(x.has(i))throw aggsError(`Aggregation name '${i}' is reserved`);if(t.definitions+=1,t.definitions>50)throw aggsError(`Aggregations exceed the maximum of 50 definitions`);r[i]=translateAggDefinition(i,a,t,n)}return r}function translateAggs(e,t,n=new Map){return translateAggMap(e,{aliasMap:t,fieldTypes:n,definitions:0},0)}const k=.9,A=new Set([`__proto__`,`constructor`,`prototype`]),hasForbiddenSegment=e=>e.replace(/\[\]/g,``).split(`.`).some(e=>A.has(e));function processValue(e,t,n,r){if(t!=null&&!(n>=5)){if(Array.isArray(t)){let i=t.filter(e=>e!=null);if(i.length===0)return;let a=i[0];if(typeof a==`object`&&!Array.isArray(a))for(let t of i)processObject(`${e}[]`,t,n+2,r);else r.has(e)||r.set(e,[]),r.get(e)?.push(...i);return}if(typeof t==`object`){processObject(e,t,n+1,r);return}r.has(e)||r.set(e,[]),r.get(e)?.push(t)}}function processObject(e,t,n,r){if(!(n>=5))for(let[i,a]of Object.entries(t))A.has(i)||processValue(e?`${e}.${i}`:i,a,n,r)}function collectFieldValues(e){let t=new Map;for(let n of e)processObject(``,n,0,t);return t}function flattenItem(e){let t=new Map;return flattenObject(``,e,0,t),Object.fromEntries(t)}function flattenValue(e,t,n,r){if(t!=null&&!(n>=5)){if(Array.isArray(t)){if(t.length===0)return;let i=t.find(e=>e!=null);if(typeof i==`object`&&!Array.isArray(i))flattenArrayOfObjects(e,t,n,r);else{let n=t.filter(e=>e!=null);n.length>0&&r.set(e,n)}return}if(typeof t==`object`){flattenObject(e,t,n+1,r);return}r.set(e,t)}}function flattenObject(e,t,n,r){if(!(n>=5))for(let[i,a]of Object.entries(t))A.has(i)||flattenValue(e?`${e}.${i}`:i,a,n,r)}function flattenArrayOfObjects(e,t,n,r){let i=`${e}[]`,a=[],o=[],s=new Set;for(let e of t){if(typeof e!=`object`||!e||Array.isArray(e)){a.push(new Map);continue}let t=new Map;flattenObject(i,e,n+2,t),a.push(t);for(let e of t.keys())s.has(e)||(s.add(e),o.push(e))}for(let e of o){let n=t.map((t,n)=>{let r=a[n].get(e);return r===void 0?null:r});r.set(e,n)}}function unflattenItem(e){let t={},n=new Map;for(let[r,i]of Object.entries(e)){if(hasForbiddenSegment(r)||(r.match(/\[\]/g)??[]).length>5)continue;let e=r.indexOf(`[].`);if(e!==-1){let t=r.substring(0,e),a=r.substring(e+3);n.has(t)||n.set(t,new Map),n.get(t)?.set(a,i);continue}let a=r.split(`.`),o=t;for(let e=0;e<a.length-1;e++){let t=a[e];(!Object.prototype.hasOwnProperty.call(o,t)||typeof o[t]!=`object`||o[t]===null)&&(o[t]={}),o=o[t]}o[a[a.length-1]]=i}for(let[e,r]of n.entries()){let n=0;for(let e of r.values())Array.isArray(e)&&(n=Math.max(n,e.length));let i=[];for(let e=0;e<n;e++){let t={};for(let[n,i]of r.entries())t[n]=Array.isArray(i)?i[e]:i;i.push(unflattenItem(t))}let a=e.split(`.`),o=t;for(let e=0;e<a.length-1;e++){let t=a[e];(!Object.prototype.hasOwnProperty.call(o,t)||typeof o[t]!=`object`||o[t]===null)&&(o[t]={}),o=o[t]}o[a[a.length-1]]=i}return t}const j=/^\d{4}-\d{2}-\d{2}(T\d{2}:\d{2}:\d{2}(\.\d+)?(Z|[+-]\d{2}:\d{2})?)?$/;function isValidCalendarDate(e){let[t,n,r]=e.slice(0,10).split(`-`).map(Number);return n<1||n>12||r<1?!1:r<=new Date(Date.UTC(t,n,0)).getUTCDate()&&!Number.isNaN(Date.parse(e))}function inferPrimitiveType(e){return typeof e==`boolean`?`bool`:typeof e==`number`?Number.isInteger(e)?`int`:`float`:typeof e==`string`?j.test(e)&&isValidCalendarDate(e)?`date`:`string`:null}function determineFieldType(e){let t=e.map(inferPrimitiveType).filter(e=>e!==null);if(t.length===0)return null;let n=t.reduce((e,t)=>(e[t]=(e[t]??0)+1,e),{});if(((n.int??0)+(n.float??0))/t.length>=k)return(n.float??0)>0?`float`:`int`;let r=Object.entries(n).sort((e,t)=>t[1]-e[1])[0];return r[1]/t.length>=k?r[0]:`string`}function findNextAvailableSlot(e,t){let n=1;for(;t.has(`${e}${n}`);)n++;return`${e}${n}`}const M=1e4;function assertPageWindow(e,t){if(e!==void 0&&(!Number.isInteger(e)||e<1))throw syncedQueryError(`page_size ${e} must be an integer of at least 1`,{parameter:`page_size`,min_page_size:1});if(t!==void 0&&(!Number.isInteger(t)||t<0))throw syncedQueryError(`skip ${t} must be an integer of 0 or greater`,{parameter:`skip`,min_skip:0});if(e!==void 0&&e>200)throw syncedQueryError(`page_size ${e} exceeds the maximum of 200`,{parameter:`page_size`,max_page_size:200});let n=(t??0)+(e??100);if(n>1e4)throw syncedQueryError(`skip + page_size (${n}${e===void 0?`, page_size defaulting to 100`:``}) exceeds the maximum result window of ${M}; narrow the filter instead of paging deeper`,{parameter:`skip`,max_result_window:M})}function buildTenantScopeFilter(e){return[{term:{project_id:e.projectId}},{term:{refs:e.ref}},{term:{action_id:e.actionId}}]}function buildSearchBody(e){let t=buildTenantScopeFilter(e.scope);e.additionalQuery&&t.push(e.additionalQuery);let n={filter:t};return e.textQuery&&(n.must=[e.textQuery]),{query:{bool:n},timeout:`10s`,size:e.size??100,from:e.from??0,...e.source?.length&&{_source:e.source},...e.sort?.length&&{sort:e.sort}}}function buildAggregationBody(e){let t=buildTenantScopeFilter(e.scope);return e.additionalQuery&&t.push(e.additionalQuery),e.textQuery&&t.push(e.textQuery),{query:{bool:{filter:t}},size:0,aggregations:e.aggregations,timeout:`10s`}}function isIncompleteResponse(e){let t=e;return t?.timed_out===!0||(t?._shards?.failed??0)>0}const asClientError=e=>typeof e==`object`&&e?e:void 0;function isIndexNotFoundError(e){return asClientError(e)?.meta?.body?.error?.type===`index_not_found_exception`}function isOpenSearchBadRequest(e){return asClientError(e)?.meta?.statusCode===400}function describeOpenSearchRejection(e,t){let n=e.meta?.body?.error,r=n?.root_cause?.[0]?.reason??n?.reason??e.message??`unknown`;return{message:`The search backend rejected the synced query: ${r}. Check the ${t.map(e=>`'${e}'`).join(` and `)} arguments against the queryable fields`,parameters:t,reason:r}}exports.AGGREGATION_TIMEOUT=`10s`,exports.DEFAULT_SYNCED_PAGE_SIZE=100,exports.MAX_SYNCED_PAGE_SIZE=200,exports.MAX_SYNCED_RESULT_WINDOW=M,exports.SEARCH_TIMEOUT=`10s`,exports.SUPPORTED_QUERY_OPERATIONS=t,exports.SYNCED_FILTER_GRAMMAR=n,exports.SYNCED_SEARCH_DESCRIPTION='Free-text search over the record\'s text fields, ranked by relevance. Supports "quoted phrases", +required / -excluded terms, and prefix* — lenient (never errors). Combine with `filter` to narrow; results are relevance-ranked unless an explicit sort is given.',exports.SyncedQueryRejection=SyncedQueryRejection,exports.assertPageWindow=assertPageWindow,exports.buildAggregationBody=buildAggregationBody,exports.buildFullTextQuery=buildFullTextQuery,exports.buildSearchBody=buildSearchBody,exports.buildTenantScopeFilter=buildTenantScopeFilter,exports.collectFieldValues=collectFieldValues,exports.describeOpenSearchRejection=describeOpenSearchRejection,exports.determineFieldType=determineFieldType,exports.findNextAvailableSlot=findNextAvailableSlot,exports.flattenItem=flattenItem,exports.inferPrimitiveType=inferPrimitiveType,exports.isIncompleteResponse=isIncompleteResponse,exports.isIndexNotFoundError=isIndexNotFoundError,exports.isOpenSearchBadRequest=isOpenSearchBadRequest,exports.resolveField=resolveField,exports.syncedQueryError=syncedQueryError,exports.translateAggs=translateAggs,exports.translateQuery=translateQuery,exports.translateSortFields=translateSortFields,exports.translateSourceFields=translateSourceFields,exports.unflattenItem=unflattenItem;
|
package/dist/index.d.cts
CHANGED
|
@@ -64,11 +64,8 @@ declare const SEARCH_TIMEOUT = "10s";
|
|
|
64
64
|
declare const AGGREGATION_TIMEOUT = "10s";
|
|
65
65
|
type TenantScope = {
|
|
66
66
|
projectId: number;
|
|
67
|
-
accountId: string;
|
|
68
67
|
actionId: string;
|
|
69
|
-
|
|
70
|
-
lastFullRunId: string;
|
|
71
|
-
ref?: string;
|
|
68
|
+
ref: string;
|
|
72
69
|
};
|
|
73
70
|
declare function buildTenantScopeFilter(scope: TenantScope): Record<string, unknown>[];
|
|
74
71
|
type SearchBodyArgs = {
|
package/dist/index.d.mts
CHANGED
|
@@ -65,11 +65,8 @@ declare const SEARCH_TIMEOUT = "10s";
|
|
|
65
65
|
declare const AGGREGATION_TIMEOUT = "10s";
|
|
66
66
|
type TenantScope = {
|
|
67
67
|
projectId: number;
|
|
68
|
-
accountId: string;
|
|
69
68
|
actionId: string;
|
|
70
|
-
|
|
71
|
-
lastFullRunId: string;
|
|
72
|
-
ref?: string;
|
|
69
|
+
ref: string;
|
|
73
70
|
};
|
|
74
71
|
declare function buildTenantScopeFilter(scope: TenantScope): Record<string, unknown>[];
|
|
75
72
|
type SearchBodyArgs = {
|
package/dist/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{t as e}from"./chunk-BhWHdk3m.mjs";var SyncedQueryRejection=class extends Error{constructor(e,t){super(e),this.name=`SyncedQueryRejection`,this.details=t}toResponse(){return{...this.details,message:this.message,error:`Bad Request`,statusCode:400}}};const syncedQueryError=(e,t)=>new SyncedQueryRejection(e,t),t=[`term`,`terms`,`range`,`wildcard`,`match`,`match_phrase`,`exists`,`bool`],n=`OpenSearch-style filter (Query DSL) (${t.join(` / `)}) over synced fields. A filter is one clause: an object with exactly one query type, keyed by field name, e.g. {"term": {"<field>": <value>}}, {"terms": {"<field>": [...]}}, {"range": {"<field>": {"gte": ...}}}; combine clauses with {"bool": {"filter": [...], "must_not": [...]}}. Bare {"<field>": <value>} maps are rejected. match / match_phrase do word-level search (string fields only, case-insensitive); wildcard matches patterns (case-sensitive).`,r='Free-text search over the record\'s text fields, ranked by relevance. Supports "quoted phrases", +required / -excluded terms, and prefix* — lenient (never errors). Combine with `filter` to narrow; results are relevance-ranked unless an explicit sort is given.';function buildFullTextQuery(e){let t=e.trim();if(t)return{simple_query_string:{query:t,fields:[`data.*.text`]}}}const i=e(e=>typeof e==`object`&&!!e&&!Array.isArray(e),`isPlainObject`),isScalar=e=>typeof e==`string`||typeof e==`number`||typeof e==`boolean`,isStringOrNumber=e=>typeof e==`string`||typeof e==`number`,isNumeric=e=>typeof e==`number`||typeof e==`string`&&e.trim()!==``&&Number.isFinite(Number(e)),describeValue=e=>e===null?`null`:Array.isArray(e)?`an array`:`a ${typeof e}`,describeAvailableFields=e=>{let t=[...e.keys()];if(t.length===0)return`No fields are queryable for this sync yet`;let n=t.slice(0,50),r=t.length-n.length,i=r>0?`, … and ${r} more`:``;return`Available fields: ${n.join(`, `)}${i}`},resolveField=(e,t,n=`filter`)=>{let r=t.get(e);if(!r)throw syncedQueryError(`Field '${e}' is not available for querying. ${describeAvailableFields(t)}`,{parameter:n,field:e,available_fields:[...t.keys()]});return`data.${r}`},filterError=(e,t)=>syncedQueryError(e,{parameter:`filter`,path:t}),a=new Set([`term`,`terms`,`range`,`wildcard`]),o=new Set([`match`,`match_phrase`]),s=new Set([`must`,`should`,`filter`,`must_not`]),c=new Set([`minimum_should_match`]),l=[`value`,`boost`,`case_insensitive`],u=[`value`,`boost`,`case_insensitive`,`rewrite`],d=[`query`,`operator`,`minimum_should_match`,`fuzziness`,`prefix_length`,`max_expansions`,`zero_terms_query`,`boost`],f=[`query`,`slop`,`zero_terms_query`,`boost`],p=new Set([`gt`,`gte`,`lt`,`lte`]),m=new Set([`format`,`time_zone`]),unsupportedQueryType=(e,n,r)=>{let i=`Supported types: ${t.join(`, `)}`;return n.aliasMap.has(e)?filterError(`'${e}' is a queryable field, not a query type. Wrap it in a clause, e.g. {"term": {"${e}": ...}}. ${i}`,r):filterError(`Unsupported query type '${e}'. ${i}`,r)},assertSupportedOptions=(e,t,n,r)=>{let i=Object.keys(t).find(e=>!n.includes(e));if(i!==void 0)throw filterError(`'${e}' option '${i}' is not supported. Supported: ${n.join(`, `)}`,r)},validateTermValue=(e,t,n)=>{if(!isScalar(t)){if(i(t)&&isScalar(t.value)){assertSupportedOptions(`term`,t,l,n);return}throw filterError(`'term' on '${e}' must be a single string, number or boolean (or {"value": ...}); use 'terms' for a list of values`,n)}},validateTermsValue=(e,t,n)=>{if(!(Array.isArray(t)&&t.every(isScalar)))throw filterError(`'terms' on '${e}' must be an array of values`,n)},validateWildcardValue=(e,t,n,r)=>{if(n!==void 0&&n!==`string`)throw filterError(`'wildcard' is only supported on string fields; '${e}' is not a string field`,r);if(typeof t!=`string`){if(i(t)&&typeof t.value==`string`){assertSupportedOptions(`wildcard`,t,u,r);return}throw filterError(`'wildcard' on '${e}' must be a pattern string (or {"value": "<pattern>"})`,r)}},validateTextValue=(e,t,n,r)=>{if(typeof n!=`string`){if(i(n)&&isScalar(n.query)){assertSupportedOptions(e,n,e===`match`?d:f,r);return}throw filterError(`'${e}' on '${t}' must be a string or a { "query": ... } object`,r)}},validateRangeBound=(e,t,n,r,i)=>{if(!isStringOrNumber(n))throw filterError(`'range' bound '${t}' on '${e}' must be a string or number`,i);if((r===`int`||r===`float`)&&!isNumeric(n))throw filterError(`'range' bound '${t}' on numeric field '${e}' must be a number`,i);if(r===`date`&&typeof n==`boolean`)throw filterError(`'range' bound '${t}' on date field '${e}' must be an ISO date string, date-math expression or epoch millis`,i)},validateRangeValue=(e,t,n,r)=>{if(n===`bool`)throw filterError(`'range' is not supported on boolean field '${e}'`,r);if(!i(t))throw filterError(`'range' on '${e}' must be an object of bounds, e.g. {"gte": ..., "lte": ...}`,r);let a=Object.keys(t);for(let i of a){if(p.has(i)){validateRangeBound(e,i,t[i],n,r);continue}if(m.has(i)){if(n!==void 0&&n!==`date`)throw filterError(`'range' option '${i}' is only supported on date fields; '${e}' is a ${n} field`,r);continue}throw filterError(`'range' operator '${i}' is not supported. Supported: ${[...p].join(`, `)} (plus ${[...m].join(`, `)} on date fields)`,r)}if(!a.some(e=>p.has(e)))throw filterError(`'range' on '${e}' needs at least one bound (${[...p].join(`, `)})`,r)},translateFieldClause=(e,t,n,r)=>{if(!i(t))throw filterError(`'${e}' clause at '${r}' must be an object keyed by field name, e.g. {"${e}": {"<field>": ...}}`,r);let a=Object.keys(t);if(a.length!==1)throw filterError(`'${e}' clause at '${r}' must name exactly one field, got: ${a.join(`, `)||`none`}`,r);let[s]=a,c=t[s],l=`${r}.${s}`,u=resolveField(s,n.aliasMap),d=n.fieldTypes.get(s);if(o.has(e)){if(d!==`string`)throw filterError(`'${e}' is only supported on string fields; '${s}' is not a string field`,l);return validateTextValue(e,s,c,l),{[e]:{[`${u}.text`]:c}}}return e===`term`?validateTermValue(s,c,l):e===`terms`?validateTermsValue(s,c,l):e===`range`?validateRangeValue(s,c,d,l):validateWildcardValue(s,c,d,l),{[e]:{[u]:c}}},translateExists=(e,t,n)=>{if(!i(e)||typeof e.field!=`string`)throw filterError(`'exists' query requires a string 'field'`,n);let r=Object.keys(e).filter(e=>e!==`field`);if(r.length>0)throw filterError(`'exists' only accepts 'field'; unsupported: ${r.join(`, `)}`,n);return{field:resolveField(e.field,t.aliasMap)}},translateBool=(e,t,n,r)=>{if(!i(e))throw filterError(`'bool' clause at '${n}' must be an object of clauses (${[...s].join(`, `)})`,n);let a={};for(let[i,o]of Object.entries(e)){if(s.has(i)){a[i]=(Array.isArray(o)?o:[o]).map((e,a)=>translateNode(e,t,`${n}.${i}[${a}]`,r+1));continue}if(c.has(i)){if(typeof o!=`number`&&typeof o!=`string`)throw filterError(`'bool' option '${i}' must be a number or string`,n);a[i]=o;continue}throw filterError(`'bool' option '${i}' is not supported. Supported: ${[...s,...c].join(`, `)}`,n)}return a},translateNode=(e,t,n,r)=>{if(r>10)throw filterError(`Filter nesting too deep (maximum 10 levels)`,n);if(!i(e))throw filterError(`Filter clause at '${n}' must be an object, got ${describeValue(e)}`,n);let s=Object.keys(e);if(s.length===0)throw filterError(`Filter clause at '${n}' is empty`,n);if(s.length>1)throw filterError(`Filter clause at '${n}' must contain exactly one query type, got: ${s.join(`, `)}. Combine clauses with {"bool": {"filter": [...]}}`,n);let[c]=s,l=e[c],u=`${n}.${c}`;if(c===`bool`)return{bool:translateBool(l,t,u,r)};if(c===`exists`)return{exists:translateExists(l,t,u)};if(a.has(c)||o.has(c))return translateFieldClause(c,l,t,u);throw unsupportedQueryType(c,t,n)},translateQuery=(e,t,n=new Map)=>translateNode(e,{aliasMap:t,fieldTypes:n},`filter`,0);function translateSourceFields(e,t){return e.map(e=>resolveField(e,t,`source`))}const h=new Set([`asc`,`desc`]),g=new Set([`min`,`max`,`sum`,`avg`,`median`]),_=[`order`,`missing`,`mode`],sortError=e=>syncedQueryError(e,{parameter:`sort`}),validateSortOptions=(e,t)=>{let n=sortError(`'sort' order for '${e}' must be "asc" or "desc"`);if(typeof t==`string`){if(!h.has(t))throw n;return}if(!i(t))throw sortError(`'sort' options for '${e}' must be "asc", "desc" or an object like {"order": "desc"}`);let r=Object.keys(t).find(e=>!_.includes(e));if(r!==void 0)throw sortError(`'sort' option '${r}' is not supported. Supported: ${_.join(`, `)}`);if(`order`in t&&!(typeof t.order==`string`&&h.has(t.order)))throw n;if(`mode`in t&&!(typeof t.mode==`string`&&g.has(t.mode)))throw sortError(`'sort' mode for '${e}' must be one of ${[...g].join(`, `)}`)};function translateSortFields(e,t){return e.map(e=>{if(typeof e==`string`)return resolveField(e,t,`sort`);if(i(e)){let n=Object.keys(e);if(n.length!==1)throw sortError(`Each sort entry must reference exactly one field`);let[r]=n,i=resolveField(r,t,`sort`);return validateSortOptions(r,e[r]),{[i]:e[r]}}throw sortError(`Each sort entry must be a field name or a '{ field: order }' object`)})}const v=1e3,y=[`avg`,`sum`,`min`,`max`,`value_count`,`stats`,`extended_stats`,`cardinality`,`percentiles`],b=[`terms`,`date_histogram`,`histogram`,`range`,`date_range`],x=new Set([...y,...b]),S=new Set([`__proto__`,`constructor`,`prototype`]),C=[`int`,`float`],w={avg:{label:`a numeric`,types:C},sum:{label:`a numeric`,types:C},stats:{label:`a numeric`,types:C},extended_stats:{label:`a numeric`,types:C},percentiles:{label:`a numeric`,types:C},histogram:{label:`a numeric`,types:C},range:{label:`a numeric`,types:C},min:{label:`a numeric or date`,types:[...C,`date`]},max:{label:`a numeric or date`,types:[...C,`date`]},date_histogram:{label:`a date`,types:[`date`]},date_range:{label:`a date`,types:[`date`]}},T=[`missing`,`format`],E={avg:T,sum:T,min:T,max:T,value_count:T,stats:T,extended_stats:T,cardinality:[`precision_threshold`,`missing`,`format`],percentiles:[`percents`,`keyed`,`missing`,`format`],terms:[`size`,`missing`,`min_doc_count`,`order`],date_histogram:[`calendar_interval`,`fixed_interval`,`interval`,`offset`,`time_zone`,`format`,`min_doc_count`,`order`,`missing`,`keyed`],histogram:[`interval`,`offset`,`min_doc_count`,`order`,`missing`,`keyed`],range:[`ranges`,`keyed`,`missing`],date_range:[`ranges`,`format`,`time_zone`,`keyed`,`missing`]},D=new Set([`aggs`,`aggregations`]),O={date_histogram:{keys:[`calendar_interval`,`fixed_interval`,`interval`],exactlyOne:!0},histogram:{keys:[`interval`]},range:{keys:[`ranges`]},date_range:{keys:[`ranges`]}};function isPlainObject(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}const k=new Set([`from`,`to`,`key`]);function rangeEntryKeys(e){return Object.keys(e).every(e=>k.has(e))}const aggsError=e=>syncedQueryError(e,{parameter:`aggs`});function assertAggFieldType(e,t,n){let r=w[e],i=n.fieldTypes.get(t);if(!(!r||i===void 0||r.types.includes(i)))throw syncedQueryError(`'${e}' requires ${r.label} field; '${t}' is a ${i} field`,{parameter:`aggs`,field:t})}function translateAggBody(e,t,n){if(!isPlainObject(t))throw aggsError(`Aggregation definition must be an object`);let r=E[e]??[],i={};for(let[a,o]of Object.entries(t)){if(a===`field`){if(typeof o!=`string`)throw aggsError(`Aggregation 'field' must be a string`);i[a]=resolveField(o,n.aliasMap,`aggs`),assertAggFieldType(e,o,n);continue}if(!r.includes(a))throw aggsError(`Aggregation option '${a}' is not supported for '${e}'. Supported: field, ${r.join(`, `)}`);if(a===`size`){if(typeof o!=`number`||!Number.isInteger(o)||o<1)throw aggsError(`Aggregation 'size' must be a positive integer`);if(o>v)throw aggsError(`Aggregation 'size' exceeds the maximum of ${v}`)}if(a===`ranges`){if(!Array.isArray(o)||o.length===0||!o.every(e=>isPlainObject(e)&&rangeEntryKeys(e)))throw aggsError(`Aggregation 'ranges' must be an array of {from, to, key} objects`);if(o.length>100)throw aggsError(`Aggregation 'ranges' exceeds the maximum of 100 entries`)}if(a===`percents`){if(!Array.isArray(o)||o.length===0||!o.every(e=>typeof e==`number`&&Number.isFinite(e)&&e>=0&&e<=100))throw aggsError(`Aggregation 'percents' must be an array of numbers between 0 and 100`);if(o.length>100)throw aggsError(`Aggregation 'percents' exceeds the maximum of 100 entries`)}if(a===`interval`){if(e===`date_histogram`){if(typeof o!=`string`||o.length===0)throw aggsError(`Aggregation 'interval' must be a non-empty string`)}else if(typeof o!=`number`||!Number.isFinite(o)||o<=0)throw aggsError(`Aggregation 'interval' must be a finite number greater than 0`)}if((a===`fixed_interval`||a===`calendar_interval`)&&(typeof o!=`string`||o.length===0))throw aggsError(`Aggregation '${a}' must be a non-empty string`);if(a===`min_doc_count`&&(typeof o!=`number`||!Number.isInteger(o)||o<0))throw aggsError(`Aggregation 'min_doc_count' must be a non-negative integer`);if(a===`keyed`&&typeof o!=`boolean`)throw aggsError(`Aggregation 'keyed' must be a boolean`);i[a]=o}if(!(`field`in t))throw aggsError(`Aggregation '${e}' requires a 'field'`);let a=O[e];if(a){let n=a.keys.filter(e=>e in t);if(a.exactlyOne&&n.length!==1)throw aggsError(`Aggregation '${e}' requires exactly one of: ${a.keys.join(`, `)}`);if(!a.exactlyOne&&n.length===0)throw a.keys.length===1?aggsError(`Aggregation '${e}' requires '${a.keys[0]}'`):aggsError(`Aggregation '${e}' requires one of: ${a.keys.join(`, `)}`)}return i}function translateAggDefinition(e,t,n,r){if(!isPlainObject(t))throw aggsError(`Aggregation definition must be an object`);let i=Object.keys(t).filter(e=>e!==`meta`&&!D.has(e));if(i.length!==1)throw aggsError(`Aggregation '${e}' must define exactly one aggregation type, got${i.length===0?` none`:`: ${i.join(`, `)}`}`);let a={};for(let[e,i]of Object.entries(t)){if(D.has(e)){a[e]=translateAggMap(i,n,r+1);continue}if(e===`meta`){a[e]=i;continue}if(!x.has(e))throw aggsError(`Aggregation type '${e}' is not supported. Supported types: ${[...x].join(`, `)}`);a[e]=translateAggBody(e,i,n)}return a}function translateAggMap(e,t,n){if(n>5)throw aggsError(`Aggregation nesting too deep`);if(!isPlainObject(e))throw aggsError(`Aggregations must be an object`);let r={};for(let[i,a]of Object.entries(e)){if(S.has(i))throw aggsError(`Aggregation name '${i}' is reserved`);if(t.definitions+=1,t.definitions>50)throw aggsError(`Aggregations exceed the maximum of 50 definitions`);r[i]=translateAggDefinition(i,a,t,n)}return r}function translateAggs(e,t,n=new Map){return translateAggMap(e,{aliasMap:t,fieldTypes:n,definitions:0},0)}const A=.9,j=new Set([`__proto__`,`constructor`,`prototype`]),hasForbiddenSegment=e=>e.replace(/\[\]/g,``).split(`.`).some(e=>j.has(e));function processValue(e,t,n,r){if(t!=null&&!(n>=5)){if(Array.isArray(t)){let i=t.filter(e=>e!=null);if(i.length===0)return;let a=i[0];if(typeof a==`object`&&!Array.isArray(a))for(let t of i)processObject(`${e}[]`,t,n+2,r);else r.has(e)||r.set(e,[]),r.get(e)?.push(...i);return}if(typeof t==`object`){processObject(e,t,n+1,r);return}r.has(e)||r.set(e,[]),r.get(e)?.push(t)}}function processObject(e,t,n,r){if(!(n>=5))for(let[i,a]of Object.entries(t))j.has(i)||processValue(e?`${e}.${i}`:i,a,n,r)}function collectFieldValues(e){let t=new Map;for(let n of e)processObject(``,n,0,t);return t}function flattenItem(e){let t=new Map;return flattenObject(``,e,0,t),Object.fromEntries(t)}function flattenValue(e,t,n,r){if(t!=null&&!(n>=5)){if(Array.isArray(t)){if(t.length===0)return;let i=t.find(e=>e!=null);if(typeof i==`object`&&!Array.isArray(i))flattenArrayOfObjects(e,t,n,r);else{let n=t.filter(e=>e!=null);n.length>0&&r.set(e,n)}return}if(typeof t==`object`){flattenObject(e,t,n+1,r);return}r.set(e,t)}}function flattenObject(e,t,n,r){if(!(n>=5))for(let[i,a]of Object.entries(t))j.has(i)||flattenValue(e?`${e}.${i}`:i,a,n,r)}function flattenArrayOfObjects(e,t,n,r){let i=`${e}[]`,a=[],o=[],s=new Set;for(let e of t){if(typeof e!=`object`||!e||Array.isArray(e)){a.push(new Map);continue}let t=new Map;flattenObject(i,e,n+2,t),a.push(t);for(let e of t.keys())s.has(e)||(s.add(e),o.push(e))}for(let e of o){let n=t.map((t,n)=>{let r=a[n].get(e);return r===void 0?null:r});r.set(e,n)}}function unflattenItem(e){let t={},n=new Map;for(let[r,i]of Object.entries(e)){if(hasForbiddenSegment(r)||(r.match(/\[\]/g)??[]).length>5)continue;let e=r.indexOf(`[].`);if(e!==-1){let t=r.substring(0,e),a=r.substring(e+3);n.has(t)||n.set(t,new Map),n.get(t)?.set(a,i);continue}let a=r.split(`.`),o=t;for(let e=0;e<a.length-1;e++){let t=a[e];(!Object.prototype.hasOwnProperty.call(o,t)||typeof o[t]!=`object`||o[t]===null)&&(o[t]={}),o=o[t]}o[a[a.length-1]]=i}for(let[e,r]of n.entries()){let n=0;for(let e of r.values())Array.isArray(e)&&(n=Math.max(n,e.length));let i=[];for(let e=0;e<n;e++){let t={};for(let[n,i]of r.entries())t[n]=Array.isArray(i)?i[e]:i;i.push(unflattenItem(t))}let a=e.split(`.`),o=t;for(let e=0;e<a.length-1;e++){let t=a[e];(!Object.prototype.hasOwnProperty.call(o,t)||typeof o[t]!=`object`||o[t]===null)&&(o[t]={}),o=o[t]}o[a[a.length-1]]=i}return t}const M=/^\d{4}-\d{2}-\d{2}(T\d{2}:\d{2}:\d{2}(\.\d+)?(Z|[+-]\d{2}:\d{2})?)?$/;function isValidCalendarDate(e){let[t,n,r]=e.slice(0,10).split(`-`).map(Number);return n<1||n>12||r<1?!1:r<=new Date(Date.UTC(t,n,0)).getUTCDate()&&!Number.isNaN(Date.parse(e))}function inferPrimitiveType(e){return typeof e==`boolean`?`bool`:typeof e==`number`?Number.isInteger(e)?`int`:`float`:typeof e==`string`?M.test(e)&&isValidCalendarDate(e)?`date`:`string`:null}function determineFieldType(e){let t=e.map(inferPrimitiveType).filter(e=>e!==null);if(t.length===0)return null;let n=t.reduce((e,t)=>(e[t]=(e[t]??0)+1,e),{});if(((n.int??0)+(n.float??0))/t.length>=A)return(n.float??0)>0?`float`:`int`;let r=Object.entries(n).sort((e,t)=>t[1]-e[1])[0];return r[1]/t.length>=A?r[0]:`string`}function findNextAvailableSlot(e,t){let n=1;for(;t.has(`${e}${n}`);)n++;return`${e}${n}`}const N=100,P=200,F=1e4;function assertPageWindow(e,t){if(e!==void 0&&(!Number.isInteger(e)||e<1))throw syncedQueryError(`page_size ${e} must be an integer of at least 1`,{parameter:`page_size`,min_page_size:1});if(t!==void 0&&(!Number.isInteger(t)||t<0))throw syncedQueryError(`skip ${t} must be an integer of 0 or greater`,{parameter:`skip`,min_skip:0});if(e!==void 0&&e>200)throw syncedQueryError(`page_size ${e} exceeds the maximum of 200`,{parameter:`page_size`,max_page_size:200});let n=(t??0)+(e??100);if(n>1e4)throw syncedQueryError(`skip + page_size (${n}${e===void 0?`, page_size defaulting to 100`:``}) exceeds the maximum result window of ${F}; narrow the filter instead of paging deeper`,{parameter:`skip`,max_result_window:F})}const I=`10s`,L=`10s`;function buildTenantScopeFilter(e){let t=e.ref?[{term:{refs:e.ref}}]:[{term:{account_id:e.accountId}},{term:{params_hash:e.paramsHash}},{term:{last_full_run_id:e.lastFullRunId}}];return[{term:{project_id:e.projectId}},...t,{term:{action_id:e.actionId}}]}function buildSearchBody(e){let t=buildTenantScopeFilter(e.scope);e.additionalQuery&&t.push(e.additionalQuery);let n={filter:t};return e.textQuery&&(n.must=[e.textQuery]),{query:{bool:n},timeout:`10s`,size:e.size??100,from:e.from??0,...e.source?.length&&{_source:e.source},...e.sort?.length&&{sort:e.sort}}}function buildAggregationBody(e){let t=buildTenantScopeFilter(e.scope);return e.additionalQuery&&t.push(e.additionalQuery),e.textQuery&&t.push(e.textQuery),{query:{bool:{filter:t}},size:0,aggregations:e.aggregations,timeout:`10s`}}function isIncompleteResponse(e){let t=e;return t?.timed_out===!0||(t?._shards?.failed??0)>0}const asClientError=e=>typeof e==`object`&&e?e:void 0;function isIndexNotFoundError(e){return asClientError(e)?.meta?.body?.error?.type===`index_not_found_exception`}function isOpenSearchBadRequest(e){return asClientError(e)?.meta?.statusCode===400}function describeOpenSearchRejection(e,t){let n=e.meta?.body?.error,r=n?.root_cause?.[0]?.reason??n?.reason??e.message??`unknown`;return{message:`The search backend rejected the synced query: ${r}. Check the ${t.map(e=>`'${e}'`).join(` and `)} arguments against the queryable fields`,parameters:t,reason:r}}export{L as AGGREGATION_TIMEOUT,N as DEFAULT_SYNCED_PAGE_SIZE,P as MAX_SYNCED_PAGE_SIZE,F as MAX_SYNCED_RESULT_WINDOW,I as SEARCH_TIMEOUT,t as SUPPORTED_QUERY_OPERATIONS,n as SYNCED_FILTER_GRAMMAR,r as SYNCED_SEARCH_DESCRIPTION,SyncedQueryRejection,assertPageWindow,buildAggregationBody,buildFullTextQuery,buildSearchBody,buildTenantScopeFilter,collectFieldValues,describeOpenSearchRejection,determineFieldType,findNextAvailableSlot,flattenItem,inferPrimitiveType,isIncompleteResponse,isIndexNotFoundError,isOpenSearchBadRequest,resolveField,syncedQueryError,translateAggs,translateQuery,translateSortFields,translateSourceFields,unflattenItem};
|
|
1
|
+
import{t as e}from"./chunk-BhWHdk3m.mjs";var SyncedQueryRejection=class extends Error{constructor(e,t){super(e),this.name=`SyncedQueryRejection`,this.details=t}toResponse(){return{...this.details,message:this.message,error:`Bad Request`,statusCode:400}}};const syncedQueryError=(e,t)=>new SyncedQueryRejection(e,t),t=[`term`,`terms`,`range`,`wildcard`,`match`,`match_phrase`,`exists`,`bool`],n=`OpenSearch-style filter (Query DSL) (${t.join(` / `)}) over synced fields. A filter is one clause: an object with exactly one query type, keyed by field name, e.g. {"term": {"<field>": <value>}}, {"terms": {"<field>": [...]}}, {"range": {"<field>": {"gte": ...}}}; combine clauses with {"bool": {"filter": [...], "must_not": [...]}}. Bare {"<field>": <value>} maps are rejected. match / match_phrase do word-level search (string fields only, case-insensitive); wildcard matches patterns (case-sensitive).`,r='Free-text search over the record\'s text fields, ranked by relevance. Supports "quoted phrases", +required / -excluded terms, and prefix* — lenient (never errors). Combine with `filter` to narrow; results are relevance-ranked unless an explicit sort is given.';function buildFullTextQuery(e){let t=e.trim();if(t)return{simple_query_string:{query:t,fields:[`data.*.text`]}}}const i=e(e=>typeof e==`object`&&!!e&&!Array.isArray(e),`isPlainObject`),isScalar=e=>typeof e==`string`||typeof e==`number`||typeof e==`boolean`,isStringOrNumber=e=>typeof e==`string`||typeof e==`number`,isNumeric=e=>typeof e==`number`||typeof e==`string`&&e.trim()!==``&&Number.isFinite(Number(e)),describeValue=e=>e===null?`null`:Array.isArray(e)?`an array`:`a ${typeof e}`,describeAvailableFields=e=>{let t=[...e.keys()];if(t.length===0)return`No fields are queryable for this sync yet`;let n=t.slice(0,50),r=t.length-n.length,i=r>0?`, … and ${r} more`:``;return`Available fields: ${n.join(`, `)}${i}`},resolveField=(e,t,n=`filter`)=>{let r=t.get(e);if(!r)throw syncedQueryError(`Field '${e}' is not available for querying. ${describeAvailableFields(t)}`,{parameter:n,field:e,available_fields:[...t.keys()]});return`data.${r}`},filterError=(e,t)=>syncedQueryError(e,{parameter:`filter`,path:t}),a=new Set([`term`,`terms`,`range`,`wildcard`]),o=new Set([`match`,`match_phrase`]),s=new Set([`must`,`should`,`filter`,`must_not`]),c=new Set([`minimum_should_match`]),l=[`value`,`boost`,`case_insensitive`],u=[`value`,`boost`,`case_insensitive`,`rewrite`],d=[`query`,`operator`,`minimum_should_match`,`fuzziness`,`prefix_length`,`max_expansions`,`zero_terms_query`,`boost`],f=[`query`,`slop`,`zero_terms_query`,`boost`],p=new Set([`gt`,`gte`,`lt`,`lte`]),m=new Set([`format`,`time_zone`]),unsupportedQueryType=(e,n,r)=>{let i=`Supported types: ${t.join(`, `)}`;return n.aliasMap.has(e)?filterError(`'${e}' is a queryable field, not a query type. Wrap it in a clause, e.g. {"term": {"${e}": ...}}. ${i}`,r):filterError(`Unsupported query type '${e}'. ${i}`,r)},assertSupportedOptions=(e,t,n,r)=>{let i=Object.keys(t).find(e=>!n.includes(e));if(i!==void 0)throw filterError(`'${e}' option '${i}' is not supported. Supported: ${n.join(`, `)}`,r)},validateTermValue=(e,t,n)=>{if(!isScalar(t)){if(i(t)&&isScalar(t.value)){assertSupportedOptions(`term`,t,l,n);return}throw filterError(`'term' on '${e}' must be a single string, number or boolean (or {"value": ...}); use 'terms' for a list of values`,n)}},validateTermsValue=(e,t,n)=>{if(!(Array.isArray(t)&&t.every(isScalar)))throw filterError(`'terms' on '${e}' must be an array of values`,n)},validateWildcardValue=(e,t,n,r)=>{if(n!==void 0&&n!==`string`)throw filterError(`'wildcard' is only supported on string fields; '${e}' is not a string field`,r);if(typeof t!=`string`){if(i(t)&&typeof t.value==`string`){assertSupportedOptions(`wildcard`,t,u,r);return}throw filterError(`'wildcard' on '${e}' must be a pattern string (or {"value": "<pattern>"})`,r)}},validateTextValue=(e,t,n,r)=>{if(typeof n!=`string`){if(i(n)&&isScalar(n.query)){assertSupportedOptions(e,n,e===`match`?d:f,r);return}throw filterError(`'${e}' on '${t}' must be a string or a { "query": ... } object`,r)}},validateRangeBound=(e,t,n,r,i)=>{if(!isStringOrNumber(n))throw filterError(`'range' bound '${t}' on '${e}' must be a string or number`,i);if((r===`int`||r===`float`)&&!isNumeric(n))throw filterError(`'range' bound '${t}' on numeric field '${e}' must be a number`,i);if(r===`date`&&typeof n==`boolean`)throw filterError(`'range' bound '${t}' on date field '${e}' must be an ISO date string, date-math expression or epoch millis`,i)},validateRangeValue=(e,t,n,r)=>{if(n===`bool`)throw filterError(`'range' is not supported on boolean field '${e}'`,r);if(!i(t))throw filterError(`'range' on '${e}' must be an object of bounds, e.g. {"gte": ..., "lte": ...}`,r);let a=Object.keys(t);for(let i of a){if(p.has(i)){validateRangeBound(e,i,t[i],n,r);continue}if(m.has(i)){if(n!==void 0&&n!==`date`)throw filterError(`'range' option '${i}' is only supported on date fields; '${e}' is a ${n} field`,r);continue}throw filterError(`'range' operator '${i}' is not supported. Supported: ${[...p].join(`, `)} (plus ${[...m].join(`, `)} on date fields)`,r)}if(!a.some(e=>p.has(e)))throw filterError(`'range' on '${e}' needs at least one bound (${[...p].join(`, `)})`,r)},translateFieldClause=(e,t,n,r)=>{if(!i(t))throw filterError(`'${e}' clause at '${r}' must be an object keyed by field name, e.g. {"${e}": {"<field>": ...}}`,r);let a=Object.keys(t);if(a.length!==1)throw filterError(`'${e}' clause at '${r}' must name exactly one field, got: ${a.join(`, `)||`none`}`,r);let[s]=a,c=t[s],l=`${r}.${s}`,u=resolveField(s,n.aliasMap),d=n.fieldTypes.get(s);if(o.has(e)){if(d!==`string`)throw filterError(`'${e}' is only supported on string fields; '${s}' is not a string field`,l);return validateTextValue(e,s,c,l),{[e]:{[`${u}.text`]:c}}}return e===`term`?validateTermValue(s,c,l):e===`terms`?validateTermsValue(s,c,l):e===`range`?validateRangeValue(s,c,d,l):validateWildcardValue(s,c,d,l),{[e]:{[u]:c}}},translateExists=(e,t,n)=>{if(!i(e)||typeof e.field!=`string`)throw filterError(`'exists' query requires a string 'field'`,n);let r=Object.keys(e).filter(e=>e!==`field`);if(r.length>0)throw filterError(`'exists' only accepts 'field'; unsupported: ${r.join(`, `)}`,n);return{field:resolveField(e.field,t.aliasMap)}},translateBool=(e,t,n,r)=>{if(!i(e))throw filterError(`'bool' clause at '${n}' must be an object of clauses (${[...s].join(`, `)})`,n);let a={};for(let[i,o]of Object.entries(e)){if(s.has(i)){a[i]=(Array.isArray(o)?o:[o]).map((e,a)=>translateNode(e,t,`${n}.${i}[${a}]`,r+1));continue}if(c.has(i)){if(typeof o!=`number`&&typeof o!=`string`)throw filterError(`'bool' option '${i}' must be a number or string`,n);a[i]=o;continue}throw filterError(`'bool' option '${i}' is not supported. Supported: ${[...s,...c].join(`, `)}`,n)}return a},translateNode=(e,t,n,r)=>{if(r>10)throw filterError(`Filter nesting too deep (maximum 10 levels)`,n);if(!i(e))throw filterError(`Filter clause at '${n}' must be an object, got ${describeValue(e)}`,n);let s=Object.keys(e);if(s.length===0)throw filterError(`Filter clause at '${n}' is empty`,n);if(s.length>1)throw filterError(`Filter clause at '${n}' must contain exactly one query type, got: ${s.join(`, `)}. Combine clauses with {"bool": {"filter": [...]}}`,n);let[c]=s,l=e[c],u=`${n}.${c}`;if(c===`bool`)return{bool:translateBool(l,t,u,r)};if(c===`exists`)return{exists:translateExists(l,t,u)};if(a.has(c)||o.has(c))return translateFieldClause(c,l,t,u);throw unsupportedQueryType(c,t,n)},translateQuery=(e,t,n=new Map)=>translateNode(e,{aliasMap:t,fieldTypes:n},`filter`,0);function translateSourceFields(e,t){return e.map(e=>resolveField(e,t,`source`))}const h=new Set([`asc`,`desc`]),g=new Set([`min`,`max`,`sum`,`avg`,`median`]),_=[`order`,`missing`,`mode`],sortError=e=>syncedQueryError(e,{parameter:`sort`}),validateSortOptions=(e,t)=>{let n=sortError(`'sort' order for '${e}' must be "asc" or "desc"`);if(typeof t==`string`){if(!h.has(t))throw n;return}if(!i(t))throw sortError(`'sort' options for '${e}' must be "asc", "desc" or an object like {"order": "desc"}`);let r=Object.keys(t).find(e=>!_.includes(e));if(r!==void 0)throw sortError(`'sort' option '${r}' is not supported. Supported: ${_.join(`, `)}`);if(`order`in t&&!(typeof t.order==`string`&&h.has(t.order)))throw n;if(`mode`in t&&!(typeof t.mode==`string`&&g.has(t.mode)))throw sortError(`'sort' mode for '${e}' must be one of ${[...g].join(`, `)}`)};function translateSortFields(e,t){return e.map(e=>{if(typeof e==`string`)return resolveField(e,t,`sort`);if(i(e)){let n=Object.keys(e);if(n.length!==1)throw sortError(`Each sort entry must reference exactly one field`);let[r]=n,i=resolveField(r,t,`sort`);return validateSortOptions(r,e[r]),{[i]:e[r]}}throw sortError(`Each sort entry must be a field name or a '{ field: order }' object`)})}const v=1e3,y=[`avg`,`sum`,`min`,`max`,`value_count`,`stats`,`extended_stats`,`cardinality`,`percentiles`],b=[`terms`,`date_histogram`,`histogram`,`range`,`date_range`],x=new Set([...y,...b]),S=new Set([`__proto__`,`constructor`,`prototype`]),C=[`int`,`float`],w={avg:{label:`a numeric`,types:C},sum:{label:`a numeric`,types:C},stats:{label:`a numeric`,types:C},extended_stats:{label:`a numeric`,types:C},percentiles:{label:`a numeric`,types:C},histogram:{label:`a numeric`,types:C},range:{label:`a numeric`,types:C},min:{label:`a numeric or date`,types:[...C,`date`]},max:{label:`a numeric or date`,types:[...C,`date`]},date_histogram:{label:`a date`,types:[`date`]},date_range:{label:`a date`,types:[`date`]}},T=[`missing`,`format`],E={avg:T,sum:T,min:T,max:T,value_count:T,stats:T,extended_stats:T,cardinality:[`precision_threshold`,`missing`,`format`],percentiles:[`percents`,`keyed`,`missing`,`format`],terms:[`size`,`missing`,`min_doc_count`,`order`],date_histogram:[`calendar_interval`,`fixed_interval`,`interval`,`offset`,`time_zone`,`format`,`min_doc_count`,`order`,`missing`,`keyed`],histogram:[`interval`,`offset`,`min_doc_count`,`order`,`missing`,`keyed`],range:[`ranges`,`keyed`,`missing`],date_range:[`ranges`,`format`,`time_zone`,`keyed`,`missing`]},D=new Set([`aggs`,`aggregations`]),O={date_histogram:{keys:[`calendar_interval`,`fixed_interval`,`interval`],exactlyOne:!0},histogram:{keys:[`interval`]},range:{keys:[`ranges`]},date_range:{keys:[`ranges`]}};function isPlainObject(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}const k=new Set([`from`,`to`,`key`]);function rangeEntryKeys(e){return Object.keys(e).every(e=>k.has(e))}const aggsError=e=>syncedQueryError(e,{parameter:`aggs`});function assertAggFieldType(e,t,n){let r=w[e],i=n.fieldTypes.get(t);if(!(!r||i===void 0||r.types.includes(i)))throw syncedQueryError(`'${e}' requires ${r.label} field; '${t}' is a ${i} field`,{parameter:`aggs`,field:t})}function translateAggBody(e,t,n){if(!isPlainObject(t))throw aggsError(`Aggregation definition must be an object`);let r=E[e]??[],i={};for(let[a,o]of Object.entries(t)){if(a===`field`){if(typeof o!=`string`)throw aggsError(`Aggregation 'field' must be a string`);i[a]=resolveField(o,n.aliasMap,`aggs`),assertAggFieldType(e,o,n);continue}if(!r.includes(a))throw aggsError(`Aggregation option '${a}' is not supported for '${e}'. Supported: field, ${r.join(`, `)}`);if(a===`size`){if(typeof o!=`number`||!Number.isInteger(o)||o<1)throw aggsError(`Aggregation 'size' must be a positive integer`);if(o>v)throw aggsError(`Aggregation 'size' exceeds the maximum of ${v}`)}if(a===`ranges`){if(!Array.isArray(o)||o.length===0||!o.every(e=>isPlainObject(e)&&rangeEntryKeys(e)))throw aggsError(`Aggregation 'ranges' must be an array of {from, to, key} objects`);if(o.length>100)throw aggsError(`Aggregation 'ranges' exceeds the maximum of 100 entries`)}if(a===`percents`){if(!Array.isArray(o)||o.length===0||!o.every(e=>typeof e==`number`&&Number.isFinite(e)&&e>=0&&e<=100))throw aggsError(`Aggregation 'percents' must be an array of numbers between 0 and 100`);if(o.length>100)throw aggsError(`Aggregation 'percents' exceeds the maximum of 100 entries`)}if(a===`interval`){if(e===`date_histogram`){if(typeof o!=`string`||o.length===0)throw aggsError(`Aggregation 'interval' must be a non-empty string`)}else if(typeof o!=`number`||!Number.isFinite(o)||o<=0)throw aggsError(`Aggregation 'interval' must be a finite number greater than 0`)}if((a===`fixed_interval`||a===`calendar_interval`)&&(typeof o!=`string`||o.length===0))throw aggsError(`Aggregation '${a}' must be a non-empty string`);if(a===`min_doc_count`&&(typeof o!=`number`||!Number.isInteger(o)||o<0))throw aggsError(`Aggregation 'min_doc_count' must be a non-negative integer`);if(a===`keyed`&&typeof o!=`boolean`)throw aggsError(`Aggregation 'keyed' must be a boolean`);i[a]=o}if(!(`field`in t))throw aggsError(`Aggregation '${e}' requires a 'field'`);let a=O[e];if(a){let n=a.keys.filter(e=>e in t);if(a.exactlyOne&&n.length!==1)throw aggsError(`Aggregation '${e}' requires exactly one of: ${a.keys.join(`, `)}`);if(!a.exactlyOne&&n.length===0)throw a.keys.length===1?aggsError(`Aggregation '${e}' requires '${a.keys[0]}'`):aggsError(`Aggregation '${e}' requires one of: ${a.keys.join(`, `)}`)}return i}function translateAggDefinition(e,t,n,r){if(!isPlainObject(t))throw aggsError(`Aggregation definition must be an object`);let i=Object.keys(t).filter(e=>e!==`meta`&&!D.has(e));if(i.length!==1)throw aggsError(`Aggregation '${e}' must define exactly one aggregation type, got${i.length===0?` none`:`: ${i.join(`, `)}`}`);let a={};for(let[e,i]of Object.entries(t)){if(D.has(e)){a[e]=translateAggMap(i,n,r+1);continue}if(e===`meta`){a[e]=i;continue}if(!x.has(e))throw aggsError(`Aggregation type '${e}' is not supported. Supported types: ${[...x].join(`, `)}`);a[e]=translateAggBody(e,i,n)}return a}function translateAggMap(e,t,n){if(n>5)throw aggsError(`Aggregation nesting too deep`);if(!isPlainObject(e))throw aggsError(`Aggregations must be an object`);let r={};for(let[i,a]of Object.entries(e)){if(S.has(i))throw aggsError(`Aggregation name '${i}' is reserved`);if(t.definitions+=1,t.definitions>50)throw aggsError(`Aggregations exceed the maximum of 50 definitions`);r[i]=translateAggDefinition(i,a,t,n)}return r}function translateAggs(e,t,n=new Map){return translateAggMap(e,{aliasMap:t,fieldTypes:n,definitions:0},0)}const A=.9,j=new Set([`__proto__`,`constructor`,`prototype`]),hasForbiddenSegment=e=>e.replace(/\[\]/g,``).split(`.`).some(e=>j.has(e));function processValue(e,t,n,r){if(t!=null&&!(n>=5)){if(Array.isArray(t)){let i=t.filter(e=>e!=null);if(i.length===0)return;let a=i[0];if(typeof a==`object`&&!Array.isArray(a))for(let t of i)processObject(`${e}[]`,t,n+2,r);else r.has(e)||r.set(e,[]),r.get(e)?.push(...i);return}if(typeof t==`object`){processObject(e,t,n+1,r);return}r.has(e)||r.set(e,[]),r.get(e)?.push(t)}}function processObject(e,t,n,r){if(!(n>=5))for(let[i,a]of Object.entries(t))j.has(i)||processValue(e?`${e}.${i}`:i,a,n,r)}function collectFieldValues(e){let t=new Map;for(let n of e)processObject(``,n,0,t);return t}function flattenItem(e){let t=new Map;return flattenObject(``,e,0,t),Object.fromEntries(t)}function flattenValue(e,t,n,r){if(t!=null&&!(n>=5)){if(Array.isArray(t)){if(t.length===0)return;let i=t.find(e=>e!=null);if(typeof i==`object`&&!Array.isArray(i))flattenArrayOfObjects(e,t,n,r);else{let n=t.filter(e=>e!=null);n.length>0&&r.set(e,n)}return}if(typeof t==`object`){flattenObject(e,t,n+1,r);return}r.set(e,t)}}function flattenObject(e,t,n,r){if(!(n>=5))for(let[i,a]of Object.entries(t))j.has(i)||flattenValue(e?`${e}.${i}`:i,a,n,r)}function flattenArrayOfObjects(e,t,n,r){let i=`${e}[]`,a=[],o=[],s=new Set;for(let e of t){if(typeof e!=`object`||!e||Array.isArray(e)){a.push(new Map);continue}let t=new Map;flattenObject(i,e,n+2,t),a.push(t);for(let e of t.keys())s.has(e)||(s.add(e),o.push(e))}for(let e of o){let n=t.map((t,n)=>{let r=a[n].get(e);return r===void 0?null:r});r.set(e,n)}}function unflattenItem(e){let t={},n=new Map;for(let[r,i]of Object.entries(e)){if(hasForbiddenSegment(r)||(r.match(/\[\]/g)??[]).length>5)continue;let e=r.indexOf(`[].`);if(e!==-1){let t=r.substring(0,e),a=r.substring(e+3);n.has(t)||n.set(t,new Map),n.get(t)?.set(a,i);continue}let a=r.split(`.`),o=t;for(let e=0;e<a.length-1;e++){let t=a[e];(!Object.prototype.hasOwnProperty.call(o,t)||typeof o[t]!=`object`||o[t]===null)&&(o[t]={}),o=o[t]}o[a[a.length-1]]=i}for(let[e,r]of n.entries()){let n=0;for(let e of r.values())Array.isArray(e)&&(n=Math.max(n,e.length));let i=[];for(let e=0;e<n;e++){let t={};for(let[n,i]of r.entries())t[n]=Array.isArray(i)?i[e]:i;i.push(unflattenItem(t))}let a=e.split(`.`),o=t;for(let e=0;e<a.length-1;e++){let t=a[e];(!Object.prototype.hasOwnProperty.call(o,t)||typeof o[t]!=`object`||o[t]===null)&&(o[t]={}),o=o[t]}o[a[a.length-1]]=i}return t}const M=/^\d{4}-\d{2}-\d{2}(T\d{2}:\d{2}:\d{2}(\.\d+)?(Z|[+-]\d{2}:\d{2})?)?$/;function isValidCalendarDate(e){let[t,n,r]=e.slice(0,10).split(`-`).map(Number);return n<1||n>12||r<1?!1:r<=new Date(Date.UTC(t,n,0)).getUTCDate()&&!Number.isNaN(Date.parse(e))}function inferPrimitiveType(e){return typeof e==`boolean`?`bool`:typeof e==`number`?Number.isInteger(e)?`int`:`float`:typeof e==`string`?M.test(e)&&isValidCalendarDate(e)?`date`:`string`:null}function determineFieldType(e){let t=e.map(inferPrimitiveType).filter(e=>e!==null);if(t.length===0)return null;let n=t.reduce((e,t)=>(e[t]=(e[t]??0)+1,e),{});if(((n.int??0)+(n.float??0))/t.length>=A)return(n.float??0)>0?`float`:`int`;let r=Object.entries(n).sort((e,t)=>t[1]-e[1])[0];return r[1]/t.length>=A?r[0]:`string`}function findNextAvailableSlot(e,t){let n=1;for(;t.has(`${e}${n}`);)n++;return`${e}${n}`}const N=100,P=200,F=1e4;function assertPageWindow(e,t){if(e!==void 0&&(!Number.isInteger(e)||e<1))throw syncedQueryError(`page_size ${e} must be an integer of at least 1`,{parameter:`page_size`,min_page_size:1});if(t!==void 0&&(!Number.isInteger(t)||t<0))throw syncedQueryError(`skip ${t} must be an integer of 0 or greater`,{parameter:`skip`,min_skip:0});if(e!==void 0&&e>200)throw syncedQueryError(`page_size ${e} exceeds the maximum of 200`,{parameter:`page_size`,max_page_size:200});let n=(t??0)+(e??100);if(n>1e4)throw syncedQueryError(`skip + page_size (${n}${e===void 0?`, page_size defaulting to 100`:``}) exceeds the maximum result window of ${F}; narrow the filter instead of paging deeper`,{parameter:`skip`,max_result_window:F})}const I=`10s`,L=`10s`;function buildTenantScopeFilter(e){return[{term:{project_id:e.projectId}},{term:{refs:e.ref}},{term:{action_id:e.actionId}}]}function buildSearchBody(e){let t=buildTenantScopeFilter(e.scope);e.additionalQuery&&t.push(e.additionalQuery);let n={filter:t};return e.textQuery&&(n.must=[e.textQuery]),{query:{bool:n},timeout:`10s`,size:e.size??100,from:e.from??0,...e.source?.length&&{_source:e.source},...e.sort?.length&&{sort:e.sort}}}function buildAggregationBody(e){let t=buildTenantScopeFilter(e.scope);return e.additionalQuery&&t.push(e.additionalQuery),e.textQuery&&t.push(e.textQuery),{query:{bool:{filter:t}},size:0,aggregations:e.aggregations,timeout:`10s`}}function isIncompleteResponse(e){let t=e;return t?.timed_out===!0||(t?._shards?.failed??0)>0}const asClientError=e=>typeof e==`object`&&e?e:void 0;function isIndexNotFoundError(e){return asClientError(e)?.meta?.body?.error?.type===`index_not_found_exception`}function isOpenSearchBadRequest(e){return asClientError(e)?.meta?.statusCode===400}function describeOpenSearchRejection(e,t){let n=e.meta?.body?.error,r=n?.root_cause?.[0]?.reason??n?.reason??e.message??`unknown`;return{message:`The search backend rejected the synced query: ${r}. Check the ${t.map(e=>`'${e}'`).join(` and `)} arguments against the queryable fields`,parameters:t,reason:r}}export{L as AGGREGATION_TIMEOUT,N as DEFAULT_SYNCED_PAGE_SIZE,P as MAX_SYNCED_PAGE_SIZE,F as MAX_SYNCED_RESULT_WINDOW,I as SEARCH_TIMEOUT,t as SUPPORTED_QUERY_OPERATIONS,n as SYNCED_FILTER_GRAMMAR,r as SYNCED_SEARCH_DESCRIPTION,SyncedQueryRejection,assertPageWindow,buildAggregationBody,buildFullTextQuery,buildSearchBody,buildTenantScopeFilter,collectFieldValues,describeOpenSearchRejection,determineFieldType,findNextAvailableSlot,flattenItem,inferPrimitiveType,isIncompleteResponse,isIndexNotFoundError,isOpenSearchBadRequest,resolveField,syncedQueryError,translateAggs,translateQuery,translateSortFields,translateSourceFields,unflattenItem};
|