@stackone/datasync 1.3.0 → 1.4.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
@@ -9,6 +9,19 @@ paths and the `datasync-read-handler` Lambda can share one source of truth:
9
9
  - `query` / `aggregations` — validate and translate the caller-supplied s1query `filter`, `search`,
10
10
  `source`, `sort` and `aggs` into OpenSearch DSL over aliased columns.
11
11
  - `limits` — page bounds shared by every surface.
12
+ - `aggregation-buckets` — keeps a synced aggregation under OpenSearch's `search.max_buckets`, which a
13
+ narrow histogram interval or nested `terms`/`range` can exceed for every tenant on the cluster.
14
+ `needsBucketProbe` says whether the request alone proves it fits; when it does not, run
15
+ `buildBucketProbeBody` (a size-0 search under the same scope and filter), read its response with
16
+ `readBucketProbe(aggs, response.aggregations)`, which throws on a missing or malformed result
17
+ rather than reading it as empty, then `assertAggBucketBudget` rejects anything over
18
+ `MAX_AGG_BUCKETS`.
19
+ `isTooManyBucketsError` recognises, in the thrown error or the returned response, the 503
20
+ OpenSearch still answers if data grew after the probe;
21
+ map it to `tooManyBucketsRejection()` rather than a server error. Send both the probe and the
22
+ aggregation with the client option `ignore: [503]` so it hands that response back instead of retrying it and marking
23
+ the node dead. That option also stops the client throwing, so any other 503 must still be raised as an
24
+ outage: `isTooManyBucketsError` matches on the cause, never the status.
12
25
  - `opensearch` — tenant-scoped search/aggregation body builders and response predicates.
13
26
  - `describeOpenSearchRejection` returns `{ message, parameters, reason }` only; the consumer adds its own transport fields (`error`, `statusCode`), unlike `SyncedQueryRejection.toResponse()` which is complete.
14
27
  - `buildAggregationBody` takes `TranslatedAggregations` from `translateAggs`, not a raw object, so an untranslated aggregation cannot reach the request.
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});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(),H=i.z.enum([`filter`,`sort`,`source`,`aggs`,`page_size`,`skip`]),U=i.z.discriminatedUnion(`name`,[i.z.object({name:i.z.literal(`SyncedQueryRejection`),message:i.z.string().min(1),parameter:H}).catchall(i.z.unknown()),i.z.object({name:i.z.literal(`OpenSearchUnavailable`),message:i.z.string().min(1)}).catchall(i.z.unknown())]),W=i.z.union([i.z.object({error:U,data:i.z.never().optional()}),i.z.object({data:i.z.array(i.z.record(i.z.string(),i.z.unknown())),aggregations:i.z.record(i.z.string(),i.z.unknown()).optional(),error:i.z.never().optional()})]);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.dataSyncReadResultSchema=W,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=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 ${a}; narrow the filter instead of paging deeper`,{parameter:`skip`,max_result_window:a})}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 o=5e4,s=6e4,c=60*s,l=24*c,u=new Map([[`minute`,s],[`1m`,s],[`hour`,c],[`1h`,c],[`day`,l-c],[`1d`,l-c],[`week`,7*l-c],[`1w`,7*l-c],[`month`,28*l-c],[`1M`,28*l-c],[`quarter`,89*l],[`1q`,89*l],[`year`,365*l-c],[`1y`,365*l-c]]),d={ms:1,s:1e3,m:s,h:c,d:l},f=/^([1-9]\d*)(ms|s|m|h|d)$/,fixedIntervalMs=e=>{let t=f.exec(e),n=t?Number(t[1])*d[t[2]]:void 0;return n!==void 0&&Number.isSafeInteger(n)?n:void 0},dateIntervalMs=(e,t)=>e===`calendar_interval`?u.get(t):e===`fixed_interval`?fixedIntervalMs(t):u.get(t)??fixedIntervalMs(t),p=/^(\d{4})(?:-(\d{2})(?:-(\d{2})(?:T.*)?)?)?$/,m=/^\d+$/,parseIsoDate=(e,t)=>{let n=Date.parse(e);if(Number.isNaN(n))return;let[r,i,a]=[t[1],t[2]??`1`,t[3]??`1`].map(Number),o=new Date(Date.UTC(r,i-1,a));return o.getUTCMonth()===i-1&&o.getUTCDate()===a?n:void 0},parseMissingDate=e=>{let t=p.exec(e);if(t)return parseIsoDate(e,t);if(m.test(e)){let t=Number(e);return Number.isSafeInteger(t)?t:void 0}},histogramMissingValue=(e,t)=>{if(typeof t==`number`)return Number.isFinite(t)?t:void 0;if(e===`date_histogram`&&typeof t==`string`)return parseMissingDate(t)},h=[`aggs`,`aggregations`],g=[`histogram`,`date_histogram`],_=[`range`,`date_range`],aggTypeOf=e=>Object.keys(e).find(e=>e!==`meta`&&!h.includes(e))??``,subAggsOf=e=>e.aggs??e.aggregations,histogramIntervalMs=(e,t)=>{if(e===`histogram`)return t.interval;let n=[`calendar_interval`,`fixed_interval`,`interval`].find(e=>e in t);return n?dateIntervalMs(n,t[n]):void 0},histogramBuckets=(e,t,n)=>{let r=t.field,i=histogramIntervalMs(e,t);if(!n?.spans.has(r)||i===void 0||!(i>0))return 1/0;let a=n.spans.get(r),o=`missing`in t?histogramMissingValue(e,t.missing):void 0,s=[a?.min,a?.max,o].filter(e=>e!==void 0);return s.length===0?0:Math.floor((Math.max(...s)-Math.min(...s))/i)+2},termsBuckets=(e,t)=>{let n=e.size??10,r=e.min_doc_count===0?void 0:t?.distinctValues.get(e.field);return r===void 0?n:Math.min(n,r+ +(`missing`in e))},ownBuckets=(e,t,n)=>e===`terms`?termsBuckets(t,n):_.includes(e)?t.ranges.length:g.includes(e)?histogramBuckets(e,t,n):0,definitionBuckets=(e,t)=>{let n=aggTypeOf(e),r=ownBuckets(n,e[n],t),i=subAggsOf(e);return i&&r>0?r*(1+mapBuckets(i,t)):r},mapBuckets=(e,t)=>Object.values(e).reduce((e,n)=>e+definitionBuckets(n,t),0),projectAggBuckets=(e,t)=>mapBuckets(e,t),needsBucketProbe=e=>projectAggBuckets(e)>o,collectProbeFields=(e,t)=>{for(let n of Object.values(e)){let e=aggTypeOf(n),r=n[e],i=r.field;if(g.includes(e)&&t.spans.add(i),e===`terms`){let e=r.size??10;t.termsSizes.set(i,Math.max(e,t.termsSizes.get(i)??0))}let a=subAggsOf(n);a&&collectProbeFields(a,t)}return t},probeFieldsOf=e=>collectProbeFields(e,{spans:new Set,termsSizes:new Map}),v=`min:`,y=`max:`,b=`distinct:`,buildBucketProbeBody=e=>{let t=probeFieldsOf(e.aggregations),n=Object.fromEntries([...[...t.spans].flatMap(e=>[[`${v}${e}`,{min:{field:e}}],[`${y}${e}`,{max:{field:e}}]]),...[...t.termsSizes].map(([e,t])=>[`${b}${e}`,{terms:{field:e,size:t}}])]);return buildAggregationBody({...e,aggregations:n})},probeFailure=e=>Error(`Bucket probe returned no usable result for '${e}'`),readSpan=(e,t)=>{let probedValue=t=>e[t]?.value,n=probedValue(`${v}${t}`),r=probedValue(`${y}${t}`);if(Number.isFinite(n)&&Number.isFinite(r))return{min:n,max:r};if(n===null&&r===null)return null;throw probeFailure(t)},readDistinctValues=(e,t)=>{let n=e[`${b}${t}`]?.buckets;if(!Array.isArray(n))throw probeFailure(t);return n.length},readBucketProbe=(e,t)=>{let n=probeFieldsOf(e);return{spans:new Map([...n.spans].map(e=>[e,readSpan(t,e)])),distinctValues:new Map([...n.termsSizes.keys()].map(e=>[e,readDistinctValues(t,e)]))}},assertAggBucketBudget=(e,t)=>{let n=Object.entries(e).map(([e,n])=>[e,definitionBuckets(n,t)]),r=n.reduce((e,[,t])=>e+t,0);if(r<=5e4)return;let[i]=[...n].sort(([,e],[,t])=>t-e)[0];throw syncedQueryError(`Aggregations would create about ${Math.ceil(r)} buckets, mostly from '${i}', above the maximum of ${o}. Use a wider histogram interval, or a smaller terms size or fewer ranges`,{parameter:`aggs`,aggregation:i,max_buckets:o})},hasTooManyBuckets=e=>e!==void 0&&(e.type===`too_many_buckets_exception`||hasTooManyBuckets(e.caused_by)||(e.root_cause??[]).some(hasTooManyBuckets)),isTooManyBucketsError=e=>{if(typeof e!=`object`||!e)return!1;let t=e.meta?.body?.error,n=e.body?.error;return hasTooManyBuckets(t??n)},tooManyBucketsRejection=()=>syncedQueryError(`Aggregations would create more buckets than the search backend allows. Use a wider histogram interval, or a smaller terms size or fewer ranges`,{parameter:`aggs`}),x=[`term`,`terms`,`range`,`wildcard`,`match`,`match_phrase`,`exists`,`bool`],ee=`OpenSearch-style filter (Query DSL) (${x.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`]),w=new Set([`match`,`match_phrase`]),T=new Set([`must`,`should`,`filter`,`must_not`]),E=new Set([`minimum_should_match`]),D=[`value`,`boost`,`case_insensitive`],O=[`value`,`boost`,`case_insensitive`,`rewrite`],k=[`query`,`operator`,`minimum_should_match`,`fuzziness`,`prefix_length`,`max_expansions`,`zero_terms_query`,`boost`],A=[`query`,`slop`,`zero_terms_query`,`boost`],j=new Set([`gt`,`gte`,`lt`,`lte`]),M=new Set([`format`,`time_zone`]),unsupportedQueryType=(e,t,n)=>{let r=`Supported types: ${x.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,D,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,O,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`?k:A,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(j.has(a)){validateRangeBound(e,a,t[a],n,r);continue}if(M.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: ${[...j].join(`, `)} (plus ${[...M].join(`, `)} on date fields)`,r)}if(!i.some(e=>j.has(e)))throw filterError(`'range' on '${e}' needs at least one bound (${[...j].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],s=`${r}.${a}`,c=resolveField(a,n.aliasMap),l=n.fieldTypes.get(a);if(w.has(e)){if(l!==`string`)throw filterError(`'${e}' is only supported on string fields; '${a}' is not a string field`,s);return validateTextValue(e,a,o,s),{[e]:{[`${c}.text`]:o}}}return e===`term`?validateTermValue(a,o,s):e===`terms`?validateTermsValue(a,o,s):e===`range`?validateRangeValue(a,o,l,s):validateWildcardValue(a,o,l,s),{[e]:{[c]: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 (${[...T].join(`, `)})`,n);let i={};for(let[a,o]of Object.entries(e)){if(T.has(a)){i[a]=(Array.isArray(o)?o:[o]).map((e,i)=>translateNode(e,t,`${n}.${a}[${i}]`,r+1));continue}if(E.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: ${[...T,...E].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],s=`${n}.${a}`;if(a===`bool`)return{bool:translateBool(o,t,s,r)};if(a===`exists`)return{exists:translateExists(o,t,s)};if(C.has(a)||w.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 N=new Set([`asc`,`desc`]),P=new Set([`min`,`max`,`sum`,`avg`,`median`]),F=[`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(!N.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=>!F.includes(e));if(r!==void 0)throw sortError(`'sort' option '${r}' is not supported. Supported: ${F.join(`, `)}`);if(`order`in t&&!(typeof t.order==`string`&&N.has(t.order)))throw n;if(`mode`in t&&!(typeof t.mode==`string`&&P.has(t.mode)))throw sortError(`'sort' mode for '${e}' must be one of ${[...P].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 I=1e3,L=[`avg`,`sum`,`min`,`max`,`value_count`,`stats`,`extended_stats`,`cardinality`,`percentiles`],R=[`terms`,`date_histogram`,`histogram`,`range`,`date_range`],z=new Set([...L,...R]),B=new Set([`__proto__`,`constructor`,`prototype`]),V=[`int`,`float`],H={avg:{label:`a numeric`,types:V},sum:{label:`a numeric`,types:V},stats:{label:`a numeric`,types:V},extended_stats:{label:`a numeric`,types:V},percentiles:{label:`a numeric`,types:V},histogram:{label:`a numeric`,types:V},range:{label:`a numeric`,types:V},min:{label:`a numeric or date`,types:[...V,`date`]},max:{label:`a numeric or date`,types:[...V,`date`]},date_histogram:{label:`a date`,types:[`date`]},date_range:{label:`a date`,types:[`date`]}},U=[`missing`,`format`],W={avg:U,sum:U,min:U,max:U,value_count:U,stats:U,extended_stats:U,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`]},G=new Set([`aggs`,`aggregations`]),K={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 q=new Set([`from`,`to`,`key`]);function rangeEntryKeys(e){return Object.keys(e).every(e=>q.has(e))}const J=`a whole-number duration such as 30s, 5m, 12h or 7d`,Y={calendar_interval:`Aggregation 'calendar_interval' must be one of minute, hour, day, week, month, quarter, year (or 1m, 1h, 1d, 1w, 1M, 1q, 1y)`,fixed_interval:`Aggregation 'fixed_interval' must be ${J}`,interval:`Aggregation 'interval' must be a calendar unit or ${J}`},aggsError=e=>syncedQueryError(e,{parameter:`aggs`});function assertAggFieldType(e,t,n){let r=H[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=W[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>I)throw aggsError(`Aggregation 'size' exceeds the maximum of ${I}`)}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`&&e!==`date_histogram`&&(typeof o!=`number`||!Number.isFinite(o)||o<=0))throw aggsError(`Aggregation 'interval' must be a finite number greater than 0`);if(e===`date_histogram`&&(a===`interval`||a===`fixed_interval`||a===`calendar_interval`)&&(typeof o!=`string`||dateIntervalMs(a,o)===void 0))throw aggsError(Y[a]);if(a===`missing`&&(e===`histogram`||e===`date_histogram`)&&histogramMissingValue(e,o)===void 0)throw aggsError(e===`histogram`?`Aggregation 'missing' must be a finite number on 'histogram'`:`Aggregation 'missing' must be an ISO 8601 date or epoch milliseconds on 'date_histogram'`);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=K[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`);if(`aggs`in t&&`aggregations`in t)throw aggsError(`Aggregation '${e}' must use either 'aggs' or 'aggregations', not both`);let i=Object.keys(t).filter(e=>e!==`meta`&&!G.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(G.has(e)){a[e]=translateAggMap(i,n,r+1);continue}if(e===`meta`){a[e]=i;continue}if(!z.has(e))throw aggsError(`Aggregation type '${e}' is not supported. Supported types: ${[...z].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(B.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 X=.9,Z=new Set([`__proto__`,`constructor`,`prototype`]),hasForbiddenSegment=e=>e.replace(/\[\]/g,``).split(`.`).some(e=>Z.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))Z.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))Z.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 Q=/^\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`?Q.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>=X)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>=X?r[0]:`string`}function findNextAvailableSlot(e,t){let n=1;for(;t.has(`${e}${n}`);)n++;return`${e}${n}`}const $=[`basic`,`iam`],te={fromTemporaryCredentials:n.fromTemporaryCredentials,defaultProvider:t.defaultProvider,awsSigv4Signer:r.AwsSigv4Signer};function buildClientOptions(e,t=te){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&&!$.includes(i))throw Error(`Unsupported OPENSEARCH_AUTH_MODE "${i}" — expected unset, ${$.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 ne=i.z.enum([`string`,`int`,`float`,`bool`,`date`]),re=i.z.object({field:i.z.string().min(1),alias:i.z.string().min(1),fieldType:ne}).strict(),ie=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(re),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(),ae=i.z.enum([`filter`,`sort`,`source`,`aggs`,`page_size`,`skip`]),oe=i.z.discriminatedUnion(`name`,[i.z.object({name:i.z.literal(`SyncedQueryRejection`),message:i.z.string().min(1),parameter:ae}).catchall(i.z.unknown()),i.z.object({name:i.z.literal(`OpenSearchUnavailable`),message:i.z.string().min(1)}).catchall(i.z.unknown())]),se=i.z.union([i.z.object({error:oe,data:i.z.never().optional()}),i.z.object({data:i.z.array(i.z.record(i.z.string(),i.z.unknown())),aggregations:i.z.record(i.z.string(),i.z.unknown()).optional(),error:i.z.never().optional()})]);exports.AGGREGATION_TIMEOUT=`10s`,exports.DEFAULT_SYNCED_PAGE_SIZE=100,exports.MAX_AGG_BUCKETS=o,exports.MAX_SYNCED_PAGE_SIZE=200,exports.MAX_SYNCED_RESULT_WINDOW=a,exports.SEARCH_TIMEOUT=`10s`,exports.SUPPORTED_QUERY_OPERATIONS=x,exports.SYNCED_FILTER_GRAMMAR=ee,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.assertAggBucketBudget=assertAggBucketBudget,exports.assertPageWindow=assertPageWindow,exports.buildAggregationBody=buildAggregationBody,exports.buildBucketProbeBody=buildBucketProbeBody,exports.buildClientOptions=buildClientOptions,exports.buildFullTextQuery=buildFullTextQuery,exports.buildSearchBody=buildSearchBody,exports.buildTenantScopeFilter=buildTenantScopeFilter,exports.collectFieldValues=collectFieldValues,exports.dataSyncReadEventSchema=ie,exports.dataSyncReadResultSchema=se,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.isTooManyBucketsError=isTooManyBucketsError,exports.needsBucketProbe=needsBucketProbe,exports.readBucketProbe=readBucketProbe,exports.resolveField=resolveField,exports.syncedQueryError=syncedQueryError,exports.tooManyBucketsRejection=tooManyBucketsRejection,exports.translateAggs=translateAggs,exports.translateQuery=translateQuery,exports.translateSortFields=translateSortFields,exports.translateSourceFields=translateSourceFields,exports.unflattenItem=unflattenItem;
package/dist/index.d.cts CHANGED
@@ -6,6 +6,18 @@ import { z } from "zod";
6
6
 
7
7
  //#region \0rolldown/runtime.js
8
8
  //#endregion
9
+ //#region src/errors.d.ts
10
+ type SyncedQueryParameter = 'filter' | 'sort' | 'source' | 'aggs' | 'page_size' | 'skip';
11
+ type SyncedQueryRejectionDetails = {
12
+ parameter: SyncedQueryParameter;
13
+ } & Record<string, unknown>;
14
+ declare class SyncedQueryRejection extends Error {
15
+ readonly details: SyncedQueryRejectionDetails;
16
+ constructor(message: string, details: SyncedQueryRejectionDetails);
17
+ toResponse(): Record<string, unknown>;
18
+ }
19
+ declare const syncedQueryError: (message: string, details: SyncedQueryRejectionDetails) => SyncedQueryRejection;
20
+ //#endregion
9
21
  //#region src/documents.d.ts
10
22
  type FieldType = 'string' | 'int' | 'float' | 'bool' | 'date';
11
23
  declare function collectFieldValues(items: Record<string, unknown>[]): Map<string, unknown[]>;
@@ -22,24 +34,6 @@ type TranslatedAggregations = Record<string, unknown> & {
22
34
  };
23
35
  declare function translateAggs(aggs: Record<string, unknown>, aliasMap: Map<string, string>, fieldTypes?: Map<string, FieldType>): TranslatedAggregations;
24
36
  //#endregion
25
- //#region src/errors.d.ts
26
- type SyncedQueryParameter = 'filter' | 'sort' | 'source' | 'aggs' | 'page_size' | 'skip';
27
- type SyncedQueryRejectionDetails = {
28
- parameter: SyncedQueryParameter;
29
- } & Record<string, unknown>;
30
- declare class SyncedQueryRejection extends Error {
31
- readonly details: SyncedQueryRejectionDetails;
32
- constructor(message: string, details: SyncedQueryRejectionDetails);
33
- toResponse(): Record<string, unknown>;
34
- }
35
- declare const syncedQueryError: (message: string, details: SyncedQueryRejectionDetails) => SyncedQueryRejection;
36
- //#endregion
37
- //#region src/limits.d.ts
38
- declare const DEFAULT_SYNCED_PAGE_SIZE = 100;
39
- declare const MAX_SYNCED_PAGE_SIZE = 200;
40
- declare const MAX_SYNCED_RESULT_WINDOW = 10000;
41
- declare function assertPageWindow(pageSize: number | undefined, skip: number | undefined): void;
42
- //#endregion
43
37
  //#region src/query.d.ts
44
38
  declare const translatedQuery: unique symbol;
45
39
  declare const translatedSource: unique symbol;
@@ -116,6 +110,28 @@ declare function describeOpenSearchRejection(error: OpenSearchClientError, param
116
110
  reason: string;
117
111
  };
118
112
  //#endregion
113
+ //#region src/aggregation-buckets.d.ts
114
+ declare const MAX_AGG_BUCKETS = 50000;
115
+ type BucketProbeResult = {
116
+ spans: Map<string, {
117
+ min: number;
118
+ max: number;
119
+ } | null>;
120
+ distinctValues: Map<string, number>;
121
+ };
122
+ declare const needsBucketProbe: (aggs: TranslatedAggregations) => boolean;
123
+ declare const buildBucketProbeBody: (args: AggregationBodyArgs) => Record<string, unknown>;
124
+ declare const readBucketProbe: (aggs: TranslatedAggregations, aggregations: Record<string, unknown>) => BucketProbeResult;
125
+ declare const assertAggBucketBudget: (aggs: TranslatedAggregations, probe: BucketProbeResult) => void;
126
+ declare const isTooManyBucketsError: (errorOrResponse: unknown) => boolean;
127
+ declare const tooManyBucketsRejection: () => SyncedQueryRejection;
128
+ //#endregion
129
+ //#region src/limits.d.ts
130
+ declare const DEFAULT_SYNCED_PAGE_SIZE = 100;
131
+ declare const MAX_SYNCED_PAGE_SIZE = 200;
132
+ declare const MAX_SYNCED_RESULT_WINDOW = 10000;
133
+ declare function assertPageWindow(pageSize: number | undefined, skip: number | undefined): void;
134
+ //#endregion
119
135
  //#region src/opensearch-client.d.ts
120
136
  type OpenSearchClientDeps = {
121
137
  fromTemporaryCredentials: typeof fromTemporaryCredentials;
@@ -281,4 +297,4 @@ declare const dataSyncReadResultSchema: z.ZodUnion<[z.ZodObject<{
281
297
  aggregations?: Record<string, unknown> | undefined;
282
298
  }>]>;
283
299
  //#endregion
284
- 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, dataSyncReadResultSchema, describeOpenSearchRejection, determineFieldType, findNextAvailableSlot, flattenItem, inferPrimitiveType, isIncompleteResponse, isIndexNotFoundError, isOpenSearchBadRequest, resolveField, syncedQueryError, translateAggs, translateQuery, translateSortFields, translateSourceFields, unflattenItem };
300
+ export { AGGREGATION_TIMEOUT, type AggregationBodyArgs, type BucketProbeResult, DEFAULT_SYNCED_PAGE_SIZE, type DataSyncReadError, type DataSyncReadErrorName, type DataSyncReadEvent, type DataSyncReadEventMapping, type DataSyncReadResult, type DataSyncReadSuccess, type FieldType, type FullTextQuery, MAX_AGG_BUCKETS, 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, assertAggBucketBudget, assertPageWindow, buildAggregationBody, buildBucketProbeBody, buildClientOptions, buildFullTextQuery, buildSearchBody, buildTenantScopeFilter, collectFieldValues, dataSyncReadEventSchema, dataSyncReadResultSchema, describeOpenSearchRejection, determineFieldType, findNextAvailableSlot, flattenItem, inferPrimitiveType, isIncompleteResponse, isIndexNotFoundError, isOpenSearchBadRequest, isTooManyBucketsError, needsBucketProbe, readBucketProbe, resolveField, syncedQueryError, tooManyBucketsRejection, translateAggs, translateQuery, translateSortFields, translateSourceFields, unflattenItem };
package/dist/index.d.mts CHANGED
@@ -5,6 +5,18 @@ import { AwsSigv4Signer } from "@opensearch-project/opensearch/aws";
5
5
  import { z } from "zod";
6
6
  import { ClientOptions } from "@opensearch-project/opensearch";
7
7
 
8
+ //#region src/errors.d.ts
9
+ type SyncedQueryParameter = 'filter' | 'sort' | 'source' | 'aggs' | 'page_size' | 'skip';
10
+ type SyncedQueryRejectionDetails = {
11
+ parameter: SyncedQueryParameter;
12
+ } & Record<string, unknown>;
13
+ declare class SyncedQueryRejection extends Error {
14
+ readonly details: SyncedQueryRejectionDetails;
15
+ constructor(message: string, details: SyncedQueryRejectionDetails);
16
+ toResponse(): Record<string, unknown>;
17
+ }
18
+ declare const syncedQueryError: (message: string, details: SyncedQueryRejectionDetails) => SyncedQueryRejection;
19
+ //#endregion
8
20
  //#region src/documents.d.ts
9
21
  type FieldType = 'string' | 'int' | 'float' | 'bool' | 'date';
10
22
  declare function collectFieldValues(items: Record<string, unknown>[]): Map<string, unknown[]>;
@@ -21,24 +33,6 @@ type TranslatedAggregations = Record<string, unknown> & {
21
33
  };
22
34
  declare function translateAggs(aggs: Record<string, unknown>, aliasMap: Map<string, string>, fieldTypes?: Map<string, FieldType>): TranslatedAggregations;
23
35
  //#endregion
24
- //#region src/errors.d.ts
25
- type SyncedQueryParameter = 'filter' | 'sort' | 'source' | 'aggs' | 'page_size' | 'skip';
26
- type SyncedQueryRejectionDetails = {
27
- parameter: SyncedQueryParameter;
28
- } & Record<string, unknown>;
29
- declare class SyncedQueryRejection extends Error {
30
- readonly details: SyncedQueryRejectionDetails;
31
- constructor(message: string, details: SyncedQueryRejectionDetails);
32
- toResponse(): Record<string, unknown>;
33
- }
34
- declare const syncedQueryError: (message: string, details: SyncedQueryRejectionDetails) => SyncedQueryRejection;
35
- //#endregion
36
- //#region src/limits.d.ts
37
- declare const DEFAULT_SYNCED_PAGE_SIZE = 100;
38
- declare const MAX_SYNCED_PAGE_SIZE = 200;
39
- declare const MAX_SYNCED_RESULT_WINDOW = 10000;
40
- declare function assertPageWindow(pageSize: number | undefined, skip: number | undefined): void;
41
- //#endregion
42
36
  //#region src/query.d.ts
43
37
  declare const translatedQuery: unique symbol;
44
38
  declare const translatedSource: unique symbol;
@@ -115,6 +109,28 @@ declare function describeOpenSearchRejection(error: OpenSearchClientError, param
115
109
  reason: string;
116
110
  };
117
111
  //#endregion
112
+ //#region src/aggregation-buckets.d.ts
113
+ declare const MAX_AGG_BUCKETS = 50000;
114
+ type BucketProbeResult = {
115
+ spans: Map<string, {
116
+ min: number;
117
+ max: number;
118
+ } | null>;
119
+ distinctValues: Map<string, number>;
120
+ };
121
+ declare const needsBucketProbe: (aggs: TranslatedAggregations) => boolean;
122
+ declare const buildBucketProbeBody: (args: AggregationBodyArgs) => Record<string, unknown>;
123
+ declare const readBucketProbe: (aggs: TranslatedAggregations, aggregations: Record<string, unknown>) => BucketProbeResult;
124
+ declare const assertAggBucketBudget: (aggs: TranslatedAggregations, probe: BucketProbeResult) => void;
125
+ declare const isTooManyBucketsError: (errorOrResponse: unknown) => boolean;
126
+ declare const tooManyBucketsRejection: () => SyncedQueryRejection;
127
+ //#endregion
128
+ //#region src/limits.d.ts
129
+ declare const DEFAULT_SYNCED_PAGE_SIZE = 100;
130
+ declare const MAX_SYNCED_PAGE_SIZE = 200;
131
+ declare const MAX_SYNCED_RESULT_WINDOW = 10000;
132
+ declare function assertPageWindow(pageSize: number | undefined, skip: number | undefined): void;
133
+ //#endregion
118
134
  //#region src/opensearch-client.d.ts
119
135
  type OpenSearchClientDeps = {
120
136
  fromTemporaryCredentials: typeof fromTemporaryCredentials;
@@ -280,4 +296,4 @@ declare const dataSyncReadResultSchema: z.ZodUnion<[z.ZodObject<{
280
296
  aggregations?: Record<string, unknown> | undefined;
281
297
  }>]>;
282
298
  //#endregion
283
- 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, dataSyncReadResultSchema, describeOpenSearchRejection, determineFieldType, findNextAvailableSlot, flattenItem, inferPrimitiveType, isIncompleteResponse, isIndexNotFoundError, isOpenSearchBadRequest, resolveField, syncedQueryError, translateAggs, translateQuery, translateSortFields, translateSourceFields, unflattenItem };
299
+ export { AGGREGATION_TIMEOUT, type AggregationBodyArgs, type BucketProbeResult, DEFAULT_SYNCED_PAGE_SIZE, type DataSyncReadError, type DataSyncReadErrorName, type DataSyncReadEvent, type DataSyncReadEventMapping, type DataSyncReadResult, type DataSyncReadSuccess, type FieldType, type FullTextQuery, MAX_AGG_BUCKETS, 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, assertAggBucketBudget, assertPageWindow, buildAggregationBody, buildBucketProbeBody, buildClientOptions, buildFullTextQuery, buildSearchBody, buildTenantScopeFilter, collectFieldValues, dataSyncReadEventSchema, dataSyncReadResultSchema, describeOpenSearchRejection, determineFieldType, findNextAvailableSlot, flattenItem, inferPrimitiveType, isIncompleteResponse, isIndexNotFoundError, isOpenSearchBadRequest, isTooManyBucketsError, needsBucketProbe, readBucketProbe, resolveField, syncedQueryError, tooManyBucketsRejection, translateAggs, translateQuery, translateSortFields, translateSourceFields, unflattenItem };
package/dist/index.mjs CHANGED
@@ -1 +1 @@
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(),q=i.enum([`filter`,`sort`,`source`,`aggs`,`page_size`,`skip`]),J=i.discriminatedUnion(`name`,[i.object({name:i.literal(`SyncedQueryRejection`),message:i.string().min(1),parameter:q}).catchall(i.unknown()),i.object({name:i.literal(`OpenSearchUnavailable`),message:i.string().min(1)}).catchall(i.unknown())]),Y=i.union([i.object({error:J,data:i.never().optional()}),i.object({data:i.array(i.record(i.string(),i.unknown())),aggregations:i.record(i.string(),i.unknown()).optional(),error:i.never().optional()})]);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,Y as dataSyncReadResultSchema,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=100,o=200,s=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 ${s}; narrow the filter instead of paging deeper`,{parameter:`skip`,max_result_window:s})}const c=`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}}const u=5e4,d=6e4,f=60*d,p=24*f,m=new Map([[`minute`,d],[`1m`,d],[`hour`,f],[`1h`,f],[`day`,p-f],[`1d`,p-f],[`week`,7*p-f],[`1w`,7*p-f],[`month`,28*p-f],[`1M`,28*p-f],[`quarter`,89*p],[`1q`,89*p],[`year`,365*p-f],[`1y`,365*p-f]]),h={ms:1,s:1e3,m:d,h:f,d:p},g=/^([1-9]\d*)(ms|s|m|h|d)$/,fixedIntervalMs=e=>{let t=g.exec(e),n=t?Number(t[1])*h[t[2]]:void 0;return n!==void 0&&Number.isSafeInteger(n)?n:void 0},dateIntervalMs=(e,t)=>e===`calendar_interval`?m.get(t):e===`fixed_interval`?fixedIntervalMs(t):m.get(t)??fixedIntervalMs(t),_=/^(\d{4})(?:-(\d{2})(?:-(\d{2})(?:T.*)?)?)?$/,ee=/^\d+$/,parseIsoDate=(e,t)=>{let n=Date.parse(e);if(Number.isNaN(n))return;let[r,i,a]=[t[1],t[2]??`1`,t[3]??`1`].map(Number),o=new Date(Date.UTC(r,i-1,a));return o.getUTCMonth()===i-1&&o.getUTCDate()===a?n:void 0},parseMissingDate=e=>{let t=_.exec(e);if(t)return parseIsoDate(e,t);if(ee.test(e)){let t=Number(e);return Number.isSafeInteger(t)?t:void 0}},histogramMissingValue=(e,t)=>{if(typeof t==`number`)return Number.isFinite(t)?t:void 0;if(e===`date_histogram`&&typeof t==`string`)return parseMissingDate(t)},v=[`aggs`,`aggregations`],y=[`histogram`,`date_histogram`],te=[`range`,`date_range`],aggTypeOf=e=>Object.keys(e).find(e=>e!==`meta`&&!v.includes(e))??``,subAggsOf=e=>e.aggs??e.aggregations,histogramIntervalMs=(e,t)=>{if(e===`histogram`)return t.interval;let n=[`calendar_interval`,`fixed_interval`,`interval`].find(e=>e in t);return n?dateIntervalMs(n,t[n]):void 0},histogramBuckets=(e,t,n)=>{let r=t.field,i=histogramIntervalMs(e,t);if(!n?.spans.has(r)||i===void 0||!(i>0))return 1/0;let a=n.spans.get(r),o=`missing`in t?histogramMissingValue(e,t.missing):void 0,s=[a?.min,a?.max,o].filter(e=>e!==void 0);return s.length===0?0:Math.floor((Math.max(...s)-Math.min(...s))/i)+2},termsBuckets=(e,t)=>{let n=e.size??10,r=e.min_doc_count===0?void 0:t?.distinctValues.get(e.field);return r===void 0?n:Math.min(n,r+ +(`missing`in e))},ownBuckets=(e,t,n)=>e===`terms`?termsBuckets(t,n):te.includes(e)?t.ranges.length:y.includes(e)?histogramBuckets(e,t,n):0,definitionBuckets=(e,t)=>{let n=aggTypeOf(e),r=ownBuckets(n,e[n],t),i=subAggsOf(e);return i&&r>0?r*(1+mapBuckets(i,t)):r},mapBuckets=(e,t)=>Object.values(e).reduce((e,n)=>e+definitionBuckets(n,t),0),projectAggBuckets=(e,t)=>mapBuckets(e,t),needsBucketProbe=e=>projectAggBuckets(e)>u,collectProbeFields=(e,t)=>{for(let n of Object.values(e)){let e=aggTypeOf(n),r=n[e],i=r.field;if(y.includes(e)&&t.spans.add(i),e===`terms`){let e=r.size??10;t.termsSizes.set(i,Math.max(e,t.termsSizes.get(i)??0))}let a=subAggsOf(n);a&&collectProbeFields(a,t)}return t},probeFieldsOf=e=>collectProbeFields(e,{spans:new Set,termsSizes:new Map}),b=`min:`,x=`max:`,S=`distinct:`,buildBucketProbeBody=e=>{let t=probeFieldsOf(e.aggregations),n=Object.fromEntries([...[...t.spans].flatMap(e=>[[`${b}${e}`,{min:{field:e}}],[`${x}${e}`,{max:{field:e}}]]),...[...t.termsSizes].map(([e,t])=>[`${S}${e}`,{terms:{field:e,size:t}}])]);return buildAggregationBody({...e,aggregations:n})},probeFailure=e=>Error(`Bucket probe returned no usable result for '${e}'`),readSpan=(e,t)=>{let probedValue=t=>e[t]?.value,n=probedValue(`${b}${t}`),r=probedValue(`${x}${t}`);if(Number.isFinite(n)&&Number.isFinite(r))return{min:n,max:r};if(n===null&&r===null)return null;throw probeFailure(t)},readDistinctValues=(e,t)=>{let n=e[`${S}${t}`]?.buckets;if(!Array.isArray(n))throw probeFailure(t);return n.length},readBucketProbe=(e,t)=>{let n=probeFieldsOf(e);return{spans:new Map([...n.spans].map(e=>[e,readSpan(t,e)])),distinctValues:new Map([...n.termsSizes.keys()].map(e=>[e,readDistinctValues(t,e)]))}},assertAggBucketBudget=(e,t)=>{let n=Object.entries(e).map(([e,n])=>[e,definitionBuckets(n,t)]),r=n.reduce((e,[,t])=>e+t,0);if(r<=5e4)return;let[i]=[...n].sort(([,e],[,t])=>t-e)[0];throw syncedQueryError(`Aggregations would create about ${Math.ceil(r)} buckets, mostly from '${i}', above the maximum of ${u}. Use a wider histogram interval, or a smaller terms size or fewer ranges`,{parameter:`aggs`,aggregation:i,max_buckets:u})},hasTooManyBuckets=e=>e!==void 0&&(e.type===`too_many_buckets_exception`||hasTooManyBuckets(e.caused_by)||(e.root_cause??[]).some(hasTooManyBuckets)),isTooManyBucketsError=e=>{if(typeof e!=`object`||!e)return!1;let t=e.meta?.body?.error,n=e.body?.error;return hasTooManyBuckets(t??n)},tooManyBucketsRejection=()=>syncedQueryError(`Aggregations would create more buckets than the search backend allows. Use a wider histogram interval, or a smaller terms size or fewer ranges`,{parameter:`aggs`}),C=[`term`,`terms`,`range`,`wildcard`,`match`,`match_phrase`,`exists`,`bool`],w=`OpenSearch-style filter (Query DSL) (${C.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).`,T='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 E=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}),D=new Set([`term`,`terms`,`range`,`wildcard`]),O=new Set([`match`,`match_phrase`]),k=new Set([`must`,`should`,`filter`,`must_not`]),A=new Set([`minimum_should_match`]),j=[`value`,`boost`,`case_insensitive`],M=[`value`,`boost`,`case_insensitive`,`rewrite`],ne=[`query`,`operator`,`minimum_should_match`,`fuzziness`,`prefix_length`,`max_expansions`,`zero_terms_query`,`boost`],re=[`query`,`slop`,`zero_terms_query`,`boost`],N=new Set([`gt`,`gte`,`lt`,`lte`]),P=new Set([`format`,`time_zone`]),unsupportedQueryType=(e,t,n)=>{let r=`Supported types: ${C.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(E(t)&&isScalar(t.value)){assertSupportedOptions(`term`,t,j,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(E(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(E(n)&&isScalar(n.query)){assertSupportedOptions(e,n,e===`match`?ne:re,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(!E(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(N.has(a)){validateRangeBound(e,a,t[a],n,r);continue}if(P.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: ${[...N].join(`, `)} (plus ${[...P].join(`, `)} on date fields)`,r)}if(!i.some(e=>N.has(e)))throw filterError(`'range' on '${e}' needs at least one bound (${[...N].join(`, `)})`,r)},translateFieldClause=(e,t,n,r)=>{if(!E(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}`,c=resolveField(a,n.aliasMap),l=n.fieldTypes.get(a);if(O.has(e)){if(l!==`string`)throw filterError(`'${e}' is only supported on string fields; '${a}' is not a string field`,s);return validateTextValue(e,a,o,s),{[e]:{[`${c}.text`]:o}}}return e===`term`?validateTermValue(a,o,s):e===`terms`?validateTermsValue(a,o,s):e===`range`?validateRangeValue(a,o,l,s):validateWildcardValue(a,o,l,s),{[e]:{[c]:o}}},translateExists=(e,t,n)=>{if(!E(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(!E(e))throw filterError(`'bool' clause at '${n}' must be an object of clauses (${[...k].join(`, `)})`,n);let i={};for(let[a,o]of Object.entries(e)){if(k.has(a)){i[a]=(Array.isArray(o)?o:[o]).map((e,i)=>translateNode(e,t,`${n}.${a}[${i}]`,r+1));continue}if(A.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: ${[...k,...A].join(`, `)}`,n)}return i},translateNode=(e,t,n,r)=>{if(r>10)throw filterError(`Filter nesting too deep (maximum 10 levels)`,n);if(!E(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(D.has(a)||O.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 F=new Set([`asc`,`desc`]),I=new Set([`min`,`max`,`sum`,`avg`,`median`]),L=[`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(!F.has(t))throw n;return}if(!E(t))throw sortError(`'sort' options for '${e}' must be "asc", "desc" or an object like {"order": "desc"}`);let r=Object.keys(t).find(e=>!L.includes(e));if(r!==void 0)throw sortError(`'sort' option '${r}' is not supported. Supported: ${L.join(`, `)}`);if(`order`in t&&!(typeof t.order==`string`&&F.has(t.order)))throw n;if(`mode`in t&&!(typeof t.mode==`string`&&I.has(t.mode)))throw sortError(`'sort' mode for '${e}' must be one of ${[...I].join(`, `)}`)};function translateSortFields(e,t){return e.map(e=>{if(typeof e==`string`)return resolveField(e,t,`sort`);if(E(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 R=1e3,z=[`avg`,`sum`,`min`,`max`,`value_count`,`stats`,`extended_stats`,`cardinality`,`percentiles`],B=[`terms`,`date_histogram`,`histogram`,`range`,`date_range`],V=new Set([...z,...B]),H=new Set([`__proto__`,`constructor`,`prototype`]),U=[`int`,`float`],W={avg:{label:`a numeric`,types:U},sum:{label:`a numeric`,types:U},stats:{label:`a numeric`,types:U},extended_stats:{label:`a numeric`,types:U},percentiles:{label:`a numeric`,types:U},histogram:{label:`a numeric`,types:U},range:{label:`a numeric`,types:U},min:{label:`a numeric or date`,types:[...U,`date`]},max:{label:`a numeric or date`,types:[...U,`date`]},date_histogram:{label:`a date`,types:[`date`]},date_range:{label:`a date`,types:[`date`]}},G=[`missing`,`format`],K={avg:G,sum:G,min:G,max:G,value_count:G,stats:G,extended_stats:G,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`]},q=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 Y=new Set([`from`,`to`,`key`]);function rangeEntryKeys(e){return Object.keys(e).every(e=>Y.has(e))}const X=`a whole-number duration such as 30s, 5m, 12h or 7d`,ie={calendar_interval:`Aggregation 'calendar_interval' must be one of minute, hour, day, week, month, quarter, year (or 1m, 1h, 1d, 1w, 1M, 1q, 1y)`,fixed_interval:`Aggregation 'fixed_interval' must be ${X}`,interval:`Aggregation 'interval' must be a calendar unit or ${X}`},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=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>R)throw aggsError(`Aggregation 'size' exceeds the maximum of ${R}`)}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`&&e!==`date_histogram`&&(typeof o!=`number`||!Number.isFinite(o)||o<=0))throw aggsError(`Aggregation 'interval' must be a finite number greater than 0`);if(e===`date_histogram`&&(a===`interval`||a===`fixed_interval`||a===`calendar_interval`)&&(typeof o!=`string`||dateIntervalMs(a,o)===void 0))throw aggsError(ie[a]);if(a===`missing`&&(e===`histogram`||e===`date_histogram`)&&histogramMissingValue(e,o)===void 0)throw aggsError(e===`histogram`?`Aggregation 'missing' must be a finite number on 'histogram'`:`Aggregation 'missing' must be an ISO 8601 date or epoch milliseconds on 'date_histogram'`);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`);if(`aggs`in t&&`aggregations`in t)throw aggsError(`Aggregation '${e}' must use either 'aggs' or 'aggregations', not both`);let i=Object.keys(t).filter(e=>e!==`meta`&&!q.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(q.has(e)){a[e]=translateAggMap(i,n,r+1);continue}if(e===`meta`){a[e]=i;continue}if(!V.has(e))throw aggsError(`Aggregation type '${e}' is not supported. Supported types: ${[...V].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(H.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 Z=.9,Q=new Set([`__proto__`,`constructor`,`prototype`]),hasForbiddenSegment=e=>e.replace(/\[\]/g,``).split(`.`).some(e=>Q.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))Q.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))Q.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 ae=/^\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`?ae.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>=Z)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>=Z?r[0]:`string`}function findNextAvailableSlot(e,t){let n=1;for(;t.has(`${e}${n}`);)n++;return`${e}${n}`}const $=[`basic`,`iam`],oe={fromTemporaryCredentials:n,defaultProvider:t,awsSigv4Signer:r};function buildClientOptions(e,t=oe){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&&!$.includes(i))throw Error(`Unsupported OPENSEARCH_AUTH_MODE "${i}" — expected unset, ${$.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 se=i.enum([`string`,`int`,`float`,`bool`,`date`]),ce=i.object({field:i.string().min(1),alias:i.string().min(1),fieldType:se}).strict(),le=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(ce),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(),ue=i.enum([`filter`,`sort`,`source`,`aggs`,`page_size`,`skip`]),de=i.discriminatedUnion(`name`,[i.object({name:i.literal(`SyncedQueryRejection`),message:i.string().min(1),parameter:ue}).catchall(i.unknown()),i.object({name:i.literal(`OpenSearchUnavailable`),message:i.string().min(1)}).catchall(i.unknown())]),fe=i.union([i.object({error:de,data:i.never().optional()}),i.object({data:i.array(i.record(i.string(),i.unknown())),aggregations:i.record(i.string(),i.unknown()).optional(),error:i.never().optional()})]);export{l as AGGREGATION_TIMEOUT,a as DEFAULT_SYNCED_PAGE_SIZE,u as MAX_AGG_BUCKETS,o as MAX_SYNCED_PAGE_SIZE,s as MAX_SYNCED_RESULT_WINDOW,c as SEARCH_TIMEOUT,C as SUPPORTED_QUERY_OPERATIONS,w as SYNCED_FILTER_GRAMMAR,T as SYNCED_SEARCH_DESCRIPTION,SyncedQueryRejection,assertAggBucketBudget,assertPageWindow,buildAggregationBody,buildBucketProbeBody,buildClientOptions,buildFullTextQuery,buildSearchBody,buildTenantScopeFilter,collectFieldValues,le as dataSyncReadEventSchema,fe as dataSyncReadResultSchema,describeOpenSearchRejection,determineFieldType,findNextAvailableSlot,flattenItem,inferPrimitiveType,isIncompleteResponse,isIndexNotFoundError,isOpenSearchBadRequest,isTooManyBucketsError,needsBucketProbe,readBucketProbe,resolveField,syncedQueryError,tooManyBucketsRejection,translateAggs,translateQuery,translateSortFields,translateSourceFields,unflattenItem};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stackone/datasync",
3
- "version": "1.3.0",
3
+ "version": "1.4.0",
4
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",
@@ -28,8 +28,8 @@
28
28
  "license": "ISC",
29
29
  "dependencies": {
30
30
  "zod": "3.25.76",
31
- "@aws-sdk/credential-provider-node": "3.901.0",
32
- "@aws-sdk/credential-providers": "3.901.0"
31
+ "@aws-sdk/credential-provider-node": "3.972.79",
32
+ "@aws-sdk/credential-providers": "3.1057.0"
33
33
  },
34
34
  "peerDependencies": {
35
35
  "@opensearch-project/opensearch": "^3.5.1"