@stackone/datasync 1.0.1 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -13,6 +13,16 @@ paths and the `datasync-read-handler` Lambda can share one source of truth:
13
13
  - `describeOpenSearchRejection` returns `{ message, parameters, reason }` only; the consumer adds its own transport fields (`error`, `statusCode`), unlike `SyncedQueryRejection.toResponse()` which is complete.
14
14
  - `buildAggregationBody` takes `TranslatedAggregations` from `translateAggs`, not a raw object, so an untranslated aggregation cannot reach the request.
15
15
  - Both body builders accept only translator outputs — `TranslatedQuery`, `TranslatedSource`, `TranslatedSort`, `FullTextQuery` and `TranslatedAggregations` — never raw caller objects.
16
+ - `read-contract` — the wire contract between `unified-cloud-api` and the `datasync-read-handler`
17
+ Lambda: `DataSyncReadEvent`/`DataSyncReadResult` types and a zod schema validating the event's shape
18
+ and per-field bounds. The `skip + pageSize` window is `assertPageWindow`'s job, called separately.
19
+ This package pins `zod@3.25.76` while `unified-cloud-api` uses zod 4; the two are never composed
20
+ across the process boundary (UCA only builds and sends the event, only the Lambda parses it), so a
21
+ future consumer should not try to import and merge this package's zod-3 schema instance with a zod-4 one.
22
+ - `opensearch-client` — `buildClientOptions`, the pure env-driven OpenSearch client construction
23
+ shared by unified-cloud-api and the `datasync-read-handler` Lambda: IAM SigV4, either signed
24
+ directly with the caller's own task/execution role or — only when `OPENSEARCH_MASTER_ROLE_ARN` is
25
+ set — via an assumed master role, or basic auth otherwise.
16
26
  - `errors` — `SyncedQueryRejection`, the framework-free 400 every consumer maps to its own transport.
17
27
 
18
28
  This package uses the tech stack provided by the **Connect Monorepo** global setup. Please check the
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){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;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e=Object.defineProperty,__name=(t,n)=>e(t,`name`,{value:n,configurable:!0});let t=require("@aws-sdk/credential-provider-node"),n=require("@aws-sdk/credential-providers"),r=require("@opensearch-project/opensearch/aws"),i=require("zod");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),a=[`term`,`terms`,`range`,`wildcard`,`match`,`match_phrase`,`exists`,`bool`],o=`OpenSearch-style filter (Query DSL) (${a.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 s=__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}),c=new Set([`term`,`terms`,`range`,`wildcard`]),l=new Set([`match`,`match_phrase`]),u=new Set([`must`,`should`,`filter`,`must_not`]),d=new Set([`minimum_should_match`]),f=[`value`,`boost`,`case_insensitive`],p=[`value`,`boost`,`case_insensitive`,`rewrite`],m=[`query`,`operator`,`minimum_should_match`,`fuzziness`,`prefix_length`,`max_expansions`,`zero_terms_query`,`boost`],h=[`query`,`slop`,`zero_terms_query`,`boost`],g=new Set([`gt`,`gte`,`lt`,`lte`]),_=new Set([`format`,`time_zone`]),unsupportedQueryType=(e,t,n)=>{let r=`Supported types: ${a.join(`, `)}`;return t.aliasMap.has(e)?filterError(`'${e}' is a queryable field, not a query type. Wrap it in a clause, e.g. {"term": {"${e}": ...}}. ${r}`,n):filterError(`Unsupported query type '${e}'. ${r}`,n)},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(s(t)&&isScalar(t.value)){assertSupportedOptions(`term`,t,f,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(s(t)&&typeof t.value==`string`){assertSupportedOptions(`wildcard`,t,p,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(s(n)&&isScalar(n.query)){assertSupportedOptions(e,n,e===`match`?m:h,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(!s(t))throw filterError(`'range' on '${e}' must be an object of bounds, e.g. {"gte": ..., "lte": ...}`,r);let i=Object.keys(t);for(let a of i){if(g.has(a)){validateRangeBound(e,a,t[a],n,r);continue}if(_.has(a)){if(n!==void 0&&n!==`date`)throw filterError(`'range' option '${a}' is only supported on date fields; '${e}' is a ${n} field`,r);continue}throw filterError(`'range' operator '${a}' is not supported. Supported: ${[...g].join(`, `)} (plus ${[..._].join(`, `)} on date fields)`,r)}if(!i.some(e=>g.has(e)))throw filterError(`'range' on '${e}' needs at least one bound (${[...g].join(`, `)})`,r)},translateFieldClause=(e,t,n,r)=>{if(!s(t))throw filterError(`'${e}' clause at '${r}' must be an object keyed by field name, e.g. {"${e}": {"<field>": ...}}`,r);let i=Object.keys(t);if(i.length!==1)throw filterError(`'${e}' clause at '${r}' must name exactly one field, got: ${i.join(`, `)||`none`}`,r);let[a]=i,o=t[a],c=`${r}.${a}`,u=resolveField(a,n.aliasMap),d=n.fieldTypes.get(a);if(l.has(e)){if(d!==`string`)throw filterError(`'${e}' is only supported on string fields; '${a}' is not a string field`,c);return validateTextValue(e,a,o,c),{[e]:{[`${u}.text`]:o}}}return e===`term`?validateTermValue(a,o,c):e===`terms`?validateTermsValue(a,o,c):e===`range`?validateRangeValue(a,o,d,c):validateWildcardValue(a,o,d,c),{[e]:{[u]:o}}},translateExists=(e,t,n)=>{if(!s(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(!s(e))throw filterError(`'bool' clause at '${n}' must be an object of clauses (${[...u].join(`, `)})`,n);let i={};for(let[a,o]of Object.entries(e)){if(u.has(a)){i[a]=(Array.isArray(o)?o:[o]).map((e,i)=>translateNode(e,t,`${n}.${a}[${i}]`,r+1));continue}if(d.has(a)){if(typeof o!=`number`&&typeof o!=`string`)throw filterError(`'bool' option '${a}' must be a number or string`,n);i[a]=o;continue}throw filterError(`'bool' option '${a}' is not supported. Supported: ${[...u,...d].join(`, `)}`,n)}return i},translateNode=(e,t,n,r)=>{if(r>10)throw filterError(`Filter nesting too deep (maximum 10 levels)`,n);if(!s(e))throw filterError(`Filter clause at '${n}' must be an object, got ${describeValue(e)}`,n);let i=Object.keys(e);if(i.length===0)throw filterError(`Filter clause at '${n}' is empty`,n);if(i.length>1)throw filterError(`Filter clause at '${n}' must contain exactly one query type, got: ${i.join(`, `)}. Combine clauses with {"bool": {"filter": [...]}}`,n);let[a]=i,o=e[a],u=`${n}.${a}`;if(a===`bool`)return{bool:translateBool(o,t,u,r)};if(a===`exists`)return{exists:translateExists(o,t,u)};if(c.has(a)||l.has(a))return translateFieldClause(a,o,t,u);throw unsupportedQueryType(a,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 v=new Set([`asc`,`desc`]),y=new Set([`min`,`max`,`sum`,`avg`,`median`]),b=[`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(!v.has(t))throw n;return}if(!s(t))throw sortError(`'sort' options for '${e}' must be "asc", "desc" or an object like {"order": "desc"}`);let r=Object.keys(t).find(e=>!b.includes(e));if(r!==void 0)throw sortError(`'sort' option '${r}' is not supported. Supported: ${b.join(`, `)}`);if(`order`in t&&!(typeof t.order==`string`&&v.has(t.order)))throw n;if(`mode`in t&&!(typeof t.mode==`string`&&y.has(t.mode)))throw sortError(`'sort' mode for '${e}' must be one of ${[...y].join(`, `)}`)};function translateSortFields(e,t){return e.map(e=>{if(typeof e==`string`)return resolveField(e,t,`sort`);if(s(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 x=1e3,S=[`avg`,`sum`,`min`,`max`,`value_count`,`stats`,`extended_stats`,`cardinality`,`percentiles`],C=[`terms`,`date_histogram`,`histogram`,`range`,`date_range`],w=new Set([...S,...C]),T=new Set([`__proto__`,`constructor`,`prototype`]),E=[`int`,`float`],D={avg:{label:`a numeric`,types:E},sum:{label:`a numeric`,types:E},stats:{label:`a numeric`,types:E},extended_stats:{label:`a numeric`,types:E},percentiles:{label:`a numeric`,types:E},histogram:{label:`a numeric`,types:E},range:{label:`a numeric`,types:E},min:{label:`a numeric or date`,types:[...E,`date`]},max:{label:`a numeric or date`,types:[...E,`date`]},date_histogram:{label:`a date`,types:[`date`]},date_range:{label:`a date`,types:[`date`]}},O=[`missing`,`format`],k={avg:O,sum:O,min:O,max:O,value_count:O,stats:O,extended_stats:O,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`]},A=new Set([`aggs`,`aggregations`]),j={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 M=new Set([`from`,`to`,`key`]);function rangeEntryKeys(e){return Object.keys(e).every(e=>M.has(e))}const aggsError=e=>syncedQueryError(e,{parameter:`aggs`});function assertAggFieldType(e,t,n){let r=D[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=k[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>x)throw aggsError(`Aggregation 'size' exceeds the maximum of ${x}`)}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=j[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`&&!A.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(A.has(e)){a[e]=translateAggMap(i,n,r+1);continue}if(e===`meta`){a[e]=i;continue}if(!w.has(e))throw aggsError(`Aggregation type '${e}' is not supported. Supported types: ${[...w].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(T.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 N=.9,P=new Set([`__proto__`,`constructor`,`prototype`]),hasForbiddenSegment=e=>e.replace(/\[\]/g,``).split(`.`).some(e=>P.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))P.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))P.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 F=/^\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`?F.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>=N)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>=N?r[0]:`string`}function findNextAvailableSlot(e,t){let n=1;for(;t.has(`${e}${n}`);)n++;return`${e}${n}`}const I=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 ${I}; narrow the filter instead of paging deeper`,{parameter:`skip`,max_result_window:I})}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}}const L=[`basic`,`iam`],R={fromTemporaryCredentials:n.fromTemporaryCredentials,defaultProvider:t.defaultProvider,awsSigv4Signer:r.AwsSigv4Signer};function buildClientOptions(e,t=R){let n=e.OPENSEARCH_URL;if(!n)throw Error(`OPENSEARCH_URL is required`);let r={rejectUnauthorized:e.OPENSEARCH_SSL_VERIFY!==`false`},i=e.OPENSEARCH_AUTH_MODE;if(i!==void 0&&!L.includes(i))throw Error(`Unsupported OPENSEARCH_AUTH_MODE "${i}" — expected unset, ${L.map(e=>`"${e}"`).join(` or `)}`);if(i===`iam`){let i=e.AWS_REGION;if(!i)throw Error(`OPENSEARCH_AUTH_MODE=iam requires AWS_REGION to be set`);let a=e.OPENSEARCH_MASTER_ROLE_ARN,o=a?t.fromTemporaryCredentials({params:{RoleArn:a,RoleSessionName:e.OPENSEARCH_ROLE_SESSION_NAME??`opensearch-client`}}):t.defaultProvider();return{...t.awsSigv4Signer({region:i,service:`es`,getCredentials:()=>o()}),node:n,ssl:r}}let a=e.OPENSEARCH_USERNAME,o=e.OPENSEARCH_PASSWORD;if(i===`basic`&&!(a&&o))throw Error(`OPENSEARCH_AUTH_MODE=basic requires both OPENSEARCH_USERNAME and OPENSEARCH_PASSWORD`);return{node:n,...a&&o?{auth:{username:a,password:o}}:{},ssl:r}}const z=i.z.enum([`string`,`int`,`float`,`bool`,`date`]),B=i.z.object({field:i.z.string().min(1),alias:i.z.string().min(1),fieldType:z}).strict(),V=i.z.object({requestId:i.z.string().min(1),projectId:i.z.number().int().positive(),actionId:i.z.string().min(1),ref:i.z.string().min(1),connectorKey:i.z.string().min(1),mappings:i.z.array(B),query:i.z.record(i.z.string(),i.z.unknown()).optional(),search:i.z.string().optional(),source:i.z.array(i.z.string()).optional(),sort:i.z.array(i.z.unknown()).optional(),aggs:i.z.record(i.z.string(),i.z.unknown()).optional(),pageSize:i.z.number().int().min(1).max(200).optional(),skip:i.z.number().int().min(0).optional()}).strict();exports.AGGREGATION_TIMEOUT=`10s`,exports.DEFAULT_SYNCED_PAGE_SIZE=100,exports.MAX_SYNCED_PAGE_SIZE=200,exports.MAX_SYNCED_RESULT_WINDOW=I,exports.SEARCH_TIMEOUT=`10s`,exports.SUPPORTED_QUERY_OPERATIONS=a,exports.SYNCED_FILTER_GRAMMAR=o,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.buildClientOptions=buildClientOptions,exports.buildFullTextQuery=buildFullTextQuery,exports.buildSearchBody=buildSearchBody,exports.buildTenantScopeFilter=buildTenantScopeFilter,exports.collectFieldValues=collectFieldValues,exports.dataSyncReadEventSchema=V,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
@@ -1,3 +1,10 @@
1
+ import { defaultProvider } from "@aws-sdk/credential-provider-node";
2
+ import { fromTemporaryCredentials } from "@aws-sdk/credential-providers";
3
+ import { AwsSigv4Signer } from "@opensearch-project/opensearch/aws";
4
+ import { ClientOptions } from "@opensearch-project/opensearch";
5
+ import { z } from "zod";
6
+
7
+ //#region \0rolldown/runtime.js
1
8
  //#endregion
2
9
  //#region src/documents.d.ts
3
10
  type FieldType = 'string' | 'int' | 'float' | 'bool' | 'date';
@@ -109,4 +116,112 @@ declare function describeOpenSearchRejection(error: OpenSearchClientError, param
109
116
  reason: string;
110
117
  };
111
118
  //#endregion
112
- export { AGGREGATION_TIMEOUT, type AggregationBodyArgs, DEFAULT_SYNCED_PAGE_SIZE, type FieldType, type FullTextQuery, MAX_SYNCED_PAGE_SIZE, MAX_SYNCED_RESULT_WINDOW, type OpenSearchClientError, SEARCH_TIMEOUT, SUPPORTED_QUERY_OPERATIONS, SYNCED_FILTER_GRAMMAR, SYNCED_SEARCH_DESCRIPTION, type SearchBodyArgs, type SyncedQueryParameter, SyncedQueryRejection, type SyncedQueryRejectionDetails, type TenantScope, type TranslatedAggregations, type TranslatedQuery, type TranslatedSort, type TranslatedSource, assertPageWindow, buildAggregationBody, buildFullTextQuery, buildSearchBody, buildTenantScopeFilter, collectFieldValues, describeOpenSearchRejection, determineFieldType, findNextAvailableSlot, flattenItem, inferPrimitiveType, isIncompleteResponse, isIndexNotFoundError, isOpenSearchBadRequest, resolveField, syncedQueryError, translateAggs, translateQuery, translateSortFields, translateSourceFields, unflattenItem };
119
+ //#region src/opensearch-client.d.ts
120
+ type OpenSearchClientDeps = {
121
+ fromTemporaryCredentials: typeof fromTemporaryCredentials;
122
+ defaultProvider: typeof defaultProvider;
123
+ awsSigv4Signer: typeof AwsSigv4Signer;
124
+ };
125
+ declare function buildClientOptions(env: NodeJS.ProcessEnv, deps?: OpenSearchClientDeps): ClientOptions;
126
+ //#endregion
127
+ //#region src/read-contract.d.ts
128
+ type DataSyncReadEventMapping = {
129
+ field: string;
130
+ alias: string;
131
+ fieldType: FieldType;
132
+ };
133
+ type DataSyncReadEvent = {
134
+ requestId: string;
135
+ projectId: number;
136
+ actionId: string;
137
+ ref: string;
138
+ connectorKey: string;
139
+ mappings: DataSyncReadEventMapping[];
140
+ query?: Record<string, unknown>;
141
+ search?: string;
142
+ source?: string[];
143
+ sort?: unknown[];
144
+ aggs?: Record<string, unknown>;
145
+ pageSize?: number;
146
+ skip?: number;
147
+ };
148
+ type DataSyncReadSuccess = {
149
+ data: Record<string, unknown>[];
150
+ aggregations?: Record<string, unknown>;
151
+ };
152
+ type DataSyncReadErrorName = 'SyncedQueryRejection' | 'OpenSearchUnavailable';
153
+ type DataSyncReadError = ({
154
+ name: 'SyncedQueryRejection';
155
+ message: string;
156
+ } & SyncedQueryRejectionDetails) | {
157
+ name: 'OpenSearchUnavailable';
158
+ message: string;
159
+ };
160
+ type DataSyncReadResult = DataSyncReadSuccess | {
161
+ error: DataSyncReadError;
162
+ };
163
+ declare const dataSyncReadEventSchema: z.ZodObject<{
164
+ requestId: z.ZodString;
165
+ projectId: z.ZodNumber;
166
+ actionId: z.ZodString;
167
+ ref: z.ZodString;
168
+ connectorKey: z.ZodString;
169
+ mappings: z.ZodArray<z.ZodObject<{
170
+ field: z.ZodString;
171
+ alias: z.ZodString;
172
+ fieldType: z.ZodEnum<["string", "int", "float", "bool", "date"]>;
173
+ }, "strict", z.ZodTypeAny, {
174
+ field: string;
175
+ alias: string;
176
+ fieldType: "string" | "float" | "date" | "int" | "bool";
177
+ }, {
178
+ field: string;
179
+ alias: string;
180
+ fieldType: "string" | "float" | "date" | "int" | "bool";
181
+ }>, "many">;
182
+ query: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
183
+ search: z.ZodOptional<z.ZodString>;
184
+ source: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
185
+ sort: z.ZodOptional<z.ZodArray<z.ZodUnknown, "many">>;
186
+ aggs: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
187
+ pageSize: z.ZodOptional<z.ZodNumber>;
188
+ skip: z.ZodOptional<z.ZodNumber>;
189
+ }, "strict", z.ZodTypeAny, {
190
+ requestId: string;
191
+ projectId: number;
192
+ actionId: string;
193
+ ref: string;
194
+ connectorKey: string;
195
+ mappings: {
196
+ field: string;
197
+ alias: string;
198
+ fieldType: "string" | "float" | "date" | "int" | "bool";
199
+ }[];
200
+ sort?: unknown[] | undefined;
201
+ query?: Record<string, unknown> | undefined;
202
+ search?: string | undefined;
203
+ source?: string[] | undefined;
204
+ aggs?: Record<string, unknown> | undefined;
205
+ pageSize?: number | undefined;
206
+ skip?: number | undefined;
207
+ }, {
208
+ requestId: string;
209
+ projectId: number;
210
+ actionId: string;
211
+ ref: string;
212
+ connectorKey: string;
213
+ mappings: {
214
+ field: string;
215
+ alias: string;
216
+ fieldType: "string" | "float" | "date" | "int" | "bool";
217
+ }[];
218
+ sort?: unknown[] | undefined;
219
+ query?: Record<string, unknown> | undefined;
220
+ search?: string | undefined;
221
+ source?: string[] | undefined;
222
+ aggs?: Record<string, unknown> | undefined;
223
+ pageSize?: number | undefined;
224
+ skip?: number | undefined;
225
+ }>;
226
+ //#endregion
227
+ export { AGGREGATION_TIMEOUT, type AggregationBodyArgs, DEFAULT_SYNCED_PAGE_SIZE, type DataSyncReadError, type DataSyncReadErrorName, type DataSyncReadEvent, type DataSyncReadEventMapping, type DataSyncReadResult, type DataSyncReadSuccess, type FieldType, type FullTextQuery, MAX_SYNCED_PAGE_SIZE, MAX_SYNCED_RESULT_WINDOW, type OpenSearchClientDeps, type OpenSearchClientError, SEARCH_TIMEOUT, SUPPORTED_QUERY_OPERATIONS, SYNCED_FILTER_GRAMMAR, SYNCED_SEARCH_DESCRIPTION, type SearchBodyArgs, type SyncedQueryParameter, SyncedQueryRejection, type SyncedQueryRejectionDetails, type TenantScope, type TranslatedAggregations, type TranslatedQuery, type TranslatedSort, type TranslatedSource, assertPageWindow, buildAggregationBody, buildClientOptions, buildFullTextQuery, buildSearchBody, buildTenantScopeFilter, collectFieldValues, dataSyncReadEventSchema, describeOpenSearchRejection, determineFieldType, findNextAvailableSlot, flattenItem, inferPrimitiveType, isIncompleteResponse, isIndexNotFoundError, isOpenSearchBadRequest, resolveField, syncedQueryError, translateAggs, translateQuery, translateSortFields, translateSourceFields, unflattenItem };
package/dist/index.d.mts CHANGED
@@ -1,4 +1,9 @@
1
1
  import { t as __name } from "./chunk-BhWHdk3m.mjs";
2
+ import { defaultProvider } from "@aws-sdk/credential-provider-node";
3
+ import { fromTemporaryCredentials } from "@aws-sdk/credential-providers";
4
+ import { AwsSigv4Signer } from "@opensearch-project/opensearch/aws";
5
+ import { z } from "zod";
6
+ import { ClientOptions } from "@opensearch-project/opensearch";
2
7
 
3
8
  //#region src/documents.d.ts
4
9
  type FieldType = 'string' | 'int' | 'float' | 'bool' | 'date';
@@ -110,4 +115,112 @@ declare function describeOpenSearchRejection(error: OpenSearchClientError, param
110
115
  reason: string;
111
116
  };
112
117
  //#endregion
113
- export { AGGREGATION_TIMEOUT, type AggregationBodyArgs, DEFAULT_SYNCED_PAGE_SIZE, type FieldType, type FullTextQuery, MAX_SYNCED_PAGE_SIZE, MAX_SYNCED_RESULT_WINDOW, type OpenSearchClientError, SEARCH_TIMEOUT, SUPPORTED_QUERY_OPERATIONS, SYNCED_FILTER_GRAMMAR, SYNCED_SEARCH_DESCRIPTION, type SearchBodyArgs, type SyncedQueryParameter, SyncedQueryRejection, type SyncedQueryRejectionDetails, type TenantScope, type TranslatedAggregations, type TranslatedQuery, type TranslatedSort, type TranslatedSource, assertPageWindow, buildAggregationBody, buildFullTextQuery, buildSearchBody, buildTenantScopeFilter, collectFieldValues, describeOpenSearchRejection, determineFieldType, findNextAvailableSlot, flattenItem, inferPrimitiveType, isIncompleteResponse, isIndexNotFoundError, isOpenSearchBadRequest, resolveField, syncedQueryError, translateAggs, translateQuery, translateSortFields, translateSourceFields, unflattenItem };
118
+ //#region src/opensearch-client.d.ts
119
+ type OpenSearchClientDeps = {
120
+ fromTemporaryCredentials: typeof fromTemporaryCredentials;
121
+ defaultProvider: typeof defaultProvider;
122
+ awsSigv4Signer: typeof AwsSigv4Signer;
123
+ };
124
+ declare function buildClientOptions(env: NodeJS.ProcessEnv, deps?: OpenSearchClientDeps): ClientOptions;
125
+ //#endregion
126
+ //#region src/read-contract.d.ts
127
+ type DataSyncReadEventMapping = {
128
+ field: string;
129
+ alias: string;
130
+ fieldType: FieldType;
131
+ };
132
+ type DataSyncReadEvent = {
133
+ requestId: string;
134
+ projectId: number;
135
+ actionId: string;
136
+ ref: string;
137
+ connectorKey: string;
138
+ mappings: DataSyncReadEventMapping[];
139
+ query?: Record<string, unknown>;
140
+ search?: string;
141
+ source?: string[];
142
+ sort?: unknown[];
143
+ aggs?: Record<string, unknown>;
144
+ pageSize?: number;
145
+ skip?: number;
146
+ };
147
+ type DataSyncReadSuccess = {
148
+ data: Record<string, unknown>[];
149
+ aggregations?: Record<string, unknown>;
150
+ };
151
+ type DataSyncReadErrorName = 'SyncedQueryRejection' | 'OpenSearchUnavailable';
152
+ type DataSyncReadError = ({
153
+ name: 'SyncedQueryRejection';
154
+ message: string;
155
+ } & SyncedQueryRejectionDetails) | {
156
+ name: 'OpenSearchUnavailable';
157
+ message: string;
158
+ };
159
+ type DataSyncReadResult = DataSyncReadSuccess | {
160
+ error: DataSyncReadError;
161
+ };
162
+ declare const dataSyncReadEventSchema: z.ZodObject<{
163
+ requestId: z.ZodString;
164
+ projectId: z.ZodNumber;
165
+ actionId: z.ZodString;
166
+ ref: z.ZodString;
167
+ connectorKey: z.ZodString;
168
+ mappings: z.ZodArray<z.ZodObject<{
169
+ field: z.ZodString;
170
+ alias: z.ZodString;
171
+ fieldType: z.ZodEnum<["string", "int", "float", "bool", "date"]>;
172
+ }, "strict", z.ZodTypeAny, {
173
+ field: string;
174
+ alias: string;
175
+ fieldType: "string" | "float" | "date" | "int" | "bool";
176
+ }, {
177
+ field: string;
178
+ alias: string;
179
+ fieldType: "string" | "float" | "date" | "int" | "bool";
180
+ }>, "many">;
181
+ query: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
182
+ search: z.ZodOptional<z.ZodString>;
183
+ source: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
184
+ sort: z.ZodOptional<z.ZodArray<z.ZodUnknown, "many">>;
185
+ aggs: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
186
+ pageSize: z.ZodOptional<z.ZodNumber>;
187
+ skip: z.ZodOptional<z.ZodNumber>;
188
+ }, "strict", z.ZodTypeAny, {
189
+ requestId: string;
190
+ projectId: number;
191
+ actionId: string;
192
+ ref: string;
193
+ connectorKey: string;
194
+ mappings: {
195
+ field: string;
196
+ alias: string;
197
+ fieldType: "string" | "float" | "date" | "int" | "bool";
198
+ }[];
199
+ sort?: unknown[] | undefined;
200
+ query?: Record<string, unknown> | undefined;
201
+ search?: string | undefined;
202
+ source?: string[] | undefined;
203
+ aggs?: Record<string, unknown> | undefined;
204
+ pageSize?: number | undefined;
205
+ skip?: number | undefined;
206
+ }, {
207
+ requestId: string;
208
+ projectId: number;
209
+ actionId: string;
210
+ ref: string;
211
+ connectorKey: string;
212
+ mappings: {
213
+ field: string;
214
+ alias: string;
215
+ fieldType: "string" | "float" | "date" | "int" | "bool";
216
+ }[];
217
+ sort?: unknown[] | undefined;
218
+ query?: Record<string, unknown> | undefined;
219
+ search?: string | undefined;
220
+ source?: string[] | undefined;
221
+ aggs?: Record<string, unknown> | undefined;
222
+ pageSize?: number | undefined;
223
+ skip?: number | undefined;
224
+ }>;
225
+ //#endregion
226
+ export { AGGREGATION_TIMEOUT, type AggregationBodyArgs, DEFAULT_SYNCED_PAGE_SIZE, type DataSyncReadError, type DataSyncReadErrorName, type DataSyncReadEvent, type DataSyncReadEventMapping, type DataSyncReadResult, type DataSyncReadSuccess, type FieldType, type FullTextQuery, MAX_SYNCED_PAGE_SIZE, MAX_SYNCED_RESULT_WINDOW, type OpenSearchClientDeps, type OpenSearchClientError, SEARCH_TIMEOUT, SUPPORTED_QUERY_OPERATIONS, SYNCED_FILTER_GRAMMAR, SYNCED_SEARCH_DESCRIPTION, type SearchBodyArgs, type SyncedQueryParameter, SyncedQueryRejection, type SyncedQueryRejectionDetails, type TenantScope, type TranslatedAggregations, type TranslatedQuery, type TranslatedSort, type TranslatedSource, assertPageWindow, buildAggregationBody, buildClientOptions, buildFullTextQuery, buildSearchBody, buildTenantScopeFilter, collectFieldValues, dataSyncReadEventSchema, describeOpenSearchRejection, determineFieldType, findNextAvailableSlot, flattenItem, inferPrimitiveType, isIncompleteResponse, isIndexNotFoundError, isOpenSearchBadRequest, resolveField, syncedQueryError, translateAggs, translateQuery, translateSortFields, translateSourceFields, unflattenItem };
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){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};
1
+ import{t as e}from"./chunk-BhWHdk3m.mjs";import{defaultProvider as t}from"@aws-sdk/credential-provider-node";import{fromTemporaryCredentials as n}from"@aws-sdk/credential-providers";import{AwsSigv4Signer as r}from"@opensearch-project/opensearch/aws";import{z as i}from"zod";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),a=[`term`,`terms`,`range`,`wildcard`,`match`,`match_phrase`,`exists`,`bool`],o=`OpenSearch-style filter (Query DSL) (${a.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).`,s='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 c=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}),l=new Set([`term`,`terms`,`range`,`wildcard`]),u=new Set([`match`,`match_phrase`]),d=new Set([`must`,`should`,`filter`,`must_not`]),f=new Set([`minimum_should_match`]),p=[`value`,`boost`,`case_insensitive`],m=[`value`,`boost`,`case_insensitive`,`rewrite`],h=[`query`,`operator`,`minimum_should_match`,`fuzziness`,`prefix_length`,`max_expansions`,`zero_terms_query`,`boost`],g=[`query`,`slop`,`zero_terms_query`,`boost`],_=new Set([`gt`,`gte`,`lt`,`lte`]),v=new Set([`format`,`time_zone`]),unsupportedQueryType=(e,t,n)=>{let r=`Supported types: ${a.join(`, `)}`;return t.aliasMap.has(e)?filterError(`'${e}' is a queryable field, not a query type. Wrap it in a clause, e.g. {"term": {"${e}": ...}}. ${r}`,n):filterError(`Unsupported query type '${e}'. ${r}`,n)},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(c(t)&&isScalar(t.value)){assertSupportedOptions(`term`,t,p,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(c(t)&&typeof t.value==`string`){assertSupportedOptions(`wildcard`,t,m,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(c(n)&&isScalar(n.query)){assertSupportedOptions(e,n,e===`match`?h:g,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(!c(t))throw filterError(`'range' on '${e}' must be an object of bounds, e.g. {"gte": ..., "lte": ...}`,r);let i=Object.keys(t);for(let a of i){if(_.has(a)){validateRangeBound(e,a,t[a],n,r);continue}if(v.has(a)){if(n!==void 0&&n!==`date`)throw filterError(`'range' option '${a}' is only supported on date fields; '${e}' is a ${n} field`,r);continue}throw filterError(`'range' operator '${a}' is not supported. Supported: ${[..._].join(`, `)} (plus ${[...v].join(`, `)} on date fields)`,r)}if(!i.some(e=>_.has(e)))throw filterError(`'range' on '${e}' needs at least one bound (${[..._].join(`, `)})`,r)},translateFieldClause=(e,t,n,r)=>{if(!c(t))throw filterError(`'${e}' clause at '${r}' must be an object keyed by field name, e.g. {"${e}": {"<field>": ...}}`,r);let i=Object.keys(t);if(i.length!==1)throw filterError(`'${e}' clause at '${r}' must name exactly one field, got: ${i.join(`, `)||`none`}`,r);let[a]=i,o=t[a],s=`${r}.${a}`,l=resolveField(a,n.aliasMap),d=n.fieldTypes.get(a);if(u.has(e)){if(d!==`string`)throw filterError(`'${e}' is only supported on string fields; '${a}' is not a string field`,s);return validateTextValue(e,a,o,s),{[e]:{[`${l}.text`]:o}}}return e===`term`?validateTermValue(a,o,s):e===`terms`?validateTermsValue(a,o,s):e===`range`?validateRangeValue(a,o,d,s):validateWildcardValue(a,o,d,s),{[e]:{[l]:o}}},translateExists=(e,t,n)=>{if(!c(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(!c(e))throw filterError(`'bool' clause at '${n}' must be an object of clauses (${[...d].join(`, `)})`,n);let i={};for(let[a,o]of Object.entries(e)){if(d.has(a)){i[a]=(Array.isArray(o)?o:[o]).map((e,i)=>translateNode(e,t,`${n}.${a}[${i}]`,r+1));continue}if(f.has(a)){if(typeof o!=`number`&&typeof o!=`string`)throw filterError(`'bool' option '${a}' must be a number or string`,n);i[a]=o;continue}throw filterError(`'bool' option '${a}' is not supported. Supported: ${[...d,...f].join(`, `)}`,n)}return i},translateNode=(e,t,n,r)=>{if(r>10)throw filterError(`Filter nesting too deep (maximum 10 levels)`,n);if(!c(e))throw filterError(`Filter clause at '${n}' must be an object, got ${describeValue(e)}`,n);let i=Object.keys(e);if(i.length===0)throw filterError(`Filter clause at '${n}' is empty`,n);if(i.length>1)throw filterError(`Filter clause at '${n}' must contain exactly one query type, got: ${i.join(`, `)}. Combine clauses with {"bool": {"filter": [...]}}`,n);let[a]=i,o=e[a],s=`${n}.${a}`;if(a===`bool`)return{bool:translateBool(o,t,s,r)};if(a===`exists`)return{exists:translateExists(o,t,s)};if(l.has(a)||u.has(a))return translateFieldClause(a,o,t,s);throw unsupportedQueryType(a,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 y=new Set([`asc`,`desc`]),b=new Set([`min`,`max`,`sum`,`avg`,`median`]),x=[`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(!y.has(t))throw n;return}if(!c(t))throw sortError(`'sort' options for '${e}' must be "asc", "desc" or an object like {"order": "desc"}`);let r=Object.keys(t).find(e=>!x.includes(e));if(r!==void 0)throw sortError(`'sort' option '${r}' is not supported. Supported: ${x.join(`, `)}`);if(`order`in t&&!(typeof t.order==`string`&&y.has(t.order)))throw n;if(`mode`in t&&!(typeof t.mode==`string`&&b.has(t.mode)))throw sortError(`'sort' mode for '${e}' must be one of ${[...b].join(`, `)}`)};function translateSortFields(e,t){return e.map(e=>{if(typeof e==`string`)return resolveField(e,t,`sort`);if(c(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 S=1e3,C=[`avg`,`sum`,`min`,`max`,`value_count`,`stats`,`extended_stats`,`cardinality`,`percentiles`],w=[`terms`,`date_histogram`,`histogram`,`range`,`date_range`],T=new Set([...C,...w]),E=new Set([`__proto__`,`constructor`,`prototype`]),D=[`int`,`float`],O={avg:{label:`a numeric`,types:D},sum:{label:`a numeric`,types:D},stats:{label:`a numeric`,types:D},extended_stats:{label:`a numeric`,types:D},percentiles:{label:`a numeric`,types:D},histogram:{label:`a numeric`,types:D},range:{label:`a numeric`,types:D},min:{label:`a numeric or date`,types:[...D,`date`]},max:{label:`a numeric or date`,types:[...D,`date`]},date_histogram:{label:`a date`,types:[`date`]},date_range:{label:`a date`,types:[`date`]}},k=[`missing`,`format`],A={avg:k,sum:k,min:k,max:k,value_count:k,stats:k,extended_stats:k,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`]},j=new Set([`aggs`,`aggregations`]),M={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 N=new Set([`from`,`to`,`key`]);function rangeEntryKeys(e){return Object.keys(e).every(e=>N.has(e))}const aggsError=e=>syncedQueryError(e,{parameter:`aggs`});function assertAggFieldType(e,t,n){let r=O[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=A[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>S)throw aggsError(`Aggregation 'size' exceeds the maximum of ${S}`)}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=M[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`&&!j.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(j.has(e)){a[e]=translateAggMap(i,n,r+1);continue}if(e===`meta`){a[e]=i;continue}if(!T.has(e))throw aggsError(`Aggregation type '${e}' is not supported. Supported types: ${[...T].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(E.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 P=.9,F=new Set([`__proto__`,`constructor`,`prototype`]),hasForbiddenSegment=e=>e.replace(/\[\]/g,``).split(`.`).some(e=>F.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))F.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))F.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 I=/^\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`?I.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>=P)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>=P?r[0]:`string`}function findNextAvailableSlot(e,t){let n=1;for(;t.has(`${e}${n}`);)n++;return`${e}${n}`}const L=100,R=200,z=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 ${z}; narrow the filter instead of paging deeper`,{parameter:`skip`,max_result_window:z})}const B=`10s`,V=`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}}const H=[`basic`,`iam`],U={fromTemporaryCredentials:n,defaultProvider:t,awsSigv4Signer:r};function buildClientOptions(e,t=U){let n=e.OPENSEARCH_URL;if(!n)throw Error(`OPENSEARCH_URL is required`);let r={rejectUnauthorized:e.OPENSEARCH_SSL_VERIFY!==`false`},i=e.OPENSEARCH_AUTH_MODE;if(i!==void 0&&!H.includes(i))throw Error(`Unsupported OPENSEARCH_AUTH_MODE "${i}" — expected unset, ${H.map(e=>`"${e}"`).join(` or `)}`);if(i===`iam`){let i=e.AWS_REGION;if(!i)throw Error(`OPENSEARCH_AUTH_MODE=iam requires AWS_REGION to be set`);let a=e.OPENSEARCH_MASTER_ROLE_ARN,o=a?t.fromTemporaryCredentials({params:{RoleArn:a,RoleSessionName:e.OPENSEARCH_ROLE_SESSION_NAME??`opensearch-client`}}):t.defaultProvider();return{...t.awsSigv4Signer({region:i,service:`es`,getCredentials:()=>o()}),node:n,ssl:r}}let a=e.OPENSEARCH_USERNAME,o=e.OPENSEARCH_PASSWORD;if(i===`basic`&&!(a&&o))throw Error(`OPENSEARCH_AUTH_MODE=basic requires both OPENSEARCH_USERNAME and OPENSEARCH_PASSWORD`);return{node:n,...a&&o?{auth:{username:a,password:o}}:{},ssl:r}}const W=i.enum([`string`,`int`,`float`,`bool`,`date`]),G=i.object({field:i.string().min(1),alias:i.string().min(1),fieldType:W}).strict(),K=i.object({requestId:i.string().min(1),projectId:i.number().int().positive(),actionId:i.string().min(1),ref:i.string().min(1),connectorKey:i.string().min(1),mappings:i.array(G),query:i.record(i.string(),i.unknown()).optional(),search:i.string().optional(),source:i.array(i.string()).optional(),sort:i.array(i.unknown()).optional(),aggs:i.record(i.string(),i.unknown()).optional(),pageSize:i.number().int().min(1).max(200).optional(),skip:i.number().int().min(0).optional()}).strict();export{V as AGGREGATION_TIMEOUT,L as DEFAULT_SYNCED_PAGE_SIZE,R as MAX_SYNCED_PAGE_SIZE,z as MAX_SYNCED_RESULT_WINDOW,B as SEARCH_TIMEOUT,a as SUPPORTED_QUERY_OPERATIONS,o as SYNCED_FILTER_GRAMMAR,s as SYNCED_SEARCH_DESCRIPTION,SyncedQueryRejection,assertPageWindow,buildAggregationBody,buildClientOptions,buildFullTextQuery,buildSearchBody,buildTenantScopeFilter,collectFieldValues,K as dataSyncReadEventSchema,describeOpenSearchRejection,determineFieldType,findNextAvailableSlot,flattenItem,inferPrimitiveType,isIncompleteResponse,isIndexNotFoundError,isOpenSearchBadRequest,resolveField,syncedQueryError,translateAggs,translateQuery,translateSortFields,translateSourceFields,unflattenItem};
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@stackone/datasync",
3
- "version": "1.0.1",
4
- "description": "DataSync document model, s1query grammar and OpenSearch query builders",
3
+ "version": "1.2.0",
4
+ "description": "DataSync document model, s1query grammar, OpenSearch query builders and client construction",
5
5
  "main": "dist/index.cjs",
6
6
  "module": "dist/index.mjs",
7
7
  "types": "dist/index.d.cts",
@@ -26,6 +26,17 @@
26
26
  "keywords": [],
27
27
  "author": "StackOne",
28
28
  "license": "ISC",
29
+ "dependencies": {
30
+ "zod": "3.25.76",
31
+ "@aws-sdk/credential-provider-node": "3.901.0",
32
+ "@aws-sdk/credential-providers": "3.901.0"
33
+ },
34
+ "peerDependencies": {
35
+ "@opensearch-project/opensearch": "^3.5.1"
36
+ },
37
+ "devDependencies": {
38
+ "@opensearch-project/opensearch": "3.5.1"
39
+ },
29
40
  "scripts": {
30
41
  "clean": "rimraf dist",
31
42
  "prebuild": "pnpm clean",