@bandeira-tech/b3nd-save 0.8.1 → 0.13.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (161) hide show
  1. package/esm/clients/save-client.d.ts +63 -29
  2. package/esm/clients/save-client.d.ts.map +1 -1
  3. package/esm/clients/save-client.js +148 -68
  4. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/{0.22.0 → 0.25.0}/mod.d.ts +1 -1
  5. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.25.0/mod.d.ts.map +1 -0
  6. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/{0.22.0 → 0.25.0}/src/client-console/client.d.ts.map +1 -1
  7. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/{0.22.0 → 0.25.0}/src/encoding/encoding.d.ts.map +1 -1
  8. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/{0.22.0 → 0.25.0}/src/encrypt/mod.d.ts +1 -0
  9. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.25.0/src/encrypt/mod.d.ts.map +1 -0
  10. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/{0.22.0 → 0.25.0}/src/encrypt/mod.js +1 -0
  11. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.25.0/src/encrypt/utils.d.ts +6 -0
  12. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.25.0/src/encrypt/utils.d.ts.map +1 -0
  13. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.25.0/src/encrypt/utils.js +12 -0
  14. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/{0.22.0 → 0.25.0}/src/functional-client/functional-client.d.ts.map +1 -1
  15. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/{0.22.0 → 0.25.0}/src/match-pattern/match-pattern.d.ts.map +1 -1
  16. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/{0.22.0 → 0.25.0}/src/network/decorators.d.ts.map +1 -1
  17. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/{0.22.0 → 0.25.0}/src/network/network.d.ts.map +1 -1
  18. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/{0.22.0 → 0.25.0}/src/network/peer.d.ts.map +1 -1
  19. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/{0.22.0 → 0.25.0}/src/network/policies/flood.d.ts.map +1 -1
  20. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/{0.22.0 → 0.25.0}/src/network/policies/path-vector.d.ts +3 -1
  21. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.25.0/src/network/policies/path-vector.d.ts.map +1 -0
  22. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/{0.22.0 → 0.25.0}/src/network/policies/path-vector.js +3 -1
  23. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/{0.22.0 → 0.25.0}/src/network/policies/tell-and-read.d.ts.map +1 -1
  24. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/{0.22.0 → 0.25.0}/src/network/types.d.ts.map +1 -1
  25. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/{0.22.0 → 0.25.0}/src/observe-emitter/observe-emitter.d.ts.map +1 -1
  26. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/{0.22.0 → 0.25.0}/src/rig/connection.d.ts +13 -5
  27. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.25.0/src/rig/connection.d.ts.map +1 -0
  28. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/{0.22.0 → 0.25.0}/src/rig/connection.js +1 -1
  29. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/{0.22.0 → 0.25.0}/src/rig/events.d.ts.map +1 -1
  30. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/{0.22.0 → 0.25.0}/src/rig/hooks.d.ts.map +1 -1
  31. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/{0.22.0 → 0.25.0}/src/rig/identity.d.ts.map +1 -1
  32. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/{0.22.0 → 0.25.0}/src/rig/operation-handle.d.ts.map +1 -1
  33. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/{0.22.0 → 0.25.0}/src/rig/reactions.d.ts.map +1 -1
  34. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/{0.22.0 → 0.25.0}/src/rig/rig.d.ts +3 -0
  35. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.25.0/src/rig/rig.d.ts.map +1 -0
  36. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/{0.22.0 → 0.25.0}/src/rig/rig.js +46 -4
  37. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/{0.22.0 → 0.25.0}/src/rig/types.d.ts +4 -4
  38. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.25.0/src/rig/types.d.ts.map +1 -0
  39. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/{0.22.0 → 0.25.0}/src/types/types.d.ts +119 -80
  40. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.25.0/src/types/types.d.ts.map +1 -0
  41. package/esm/dispatch.d.ts +116 -3
  42. package/esm/dispatch.d.ts.map +1 -1
  43. package/esm/dispatch.js +381 -5
  44. package/esm/elasticsearch/store.d.ts +124 -25
  45. package/esm/elasticsearch/store.d.ts.map +1 -1
  46. package/esm/elasticsearch/store.js +451 -92
  47. package/esm/entity-store.d.ts +1 -1
  48. package/esm/errors.d.ts +1 -1
  49. package/esm/errors.js +1 -1
  50. package/esm/fs/mod.d.ts +26 -0
  51. package/esm/fs/mod.d.ts.map +1 -1
  52. package/esm/fs/store.d.ts +100 -23
  53. package/esm/fs/store.d.ts.map +1 -1
  54. package/esm/fs/store.js +250 -66
  55. package/esm/glob.d.ts +114 -0
  56. package/esm/glob.d.ts.map +1 -0
  57. package/esm/glob.js +352 -0
  58. package/esm/identifiers.d.ts +18 -0
  59. package/esm/identifiers.d.ts.map +1 -0
  60. package/esm/identifiers.js +19 -0
  61. package/esm/indexeddb/fields.d.ts +32 -0
  62. package/esm/indexeddb/fields.d.ts.map +1 -0
  63. package/esm/indexeddb/fields.js +51 -0
  64. package/esm/indexeddb/store.d.ts +72 -17
  65. package/esm/indexeddb/store.d.ts.map +1 -1
  66. package/esm/indexeddb/store.js +362 -106
  67. package/esm/ipfs/mod.d.ts +19 -0
  68. package/esm/ipfs/mod.d.ts.map +1 -1
  69. package/esm/ipfs/mod.js +19 -0
  70. package/esm/ipfs/store.d.ts +82 -21
  71. package/esm/ipfs/store.d.ts.map +1 -1
  72. package/esm/ipfs/store.js +269 -68
  73. package/esm/json-fields.d.ts +61 -0
  74. package/esm/json-fields.d.ts.map +1 -0
  75. package/esm/json-fields.js +121 -0
  76. package/esm/localstorage/store.d.ts +89 -21
  77. package/esm/localstorage/store.d.ts.map +1 -1
  78. package/esm/localstorage/store.js +247 -54
  79. package/esm/memory/store.d.ts +35 -4
  80. package/esm/memory/store.d.ts.map +1 -1
  81. package/esm/memory/store.js +69 -47
  82. package/esm/mod.d.ts +2 -0
  83. package/esm/mod.d.ts.map +1 -1
  84. package/esm/mod.js +1 -0
  85. package/esm/mongo/fields.d.ts +53 -0
  86. package/esm/mongo/fields.d.ts.map +1 -0
  87. package/esm/mongo/fields.js +71 -0
  88. package/esm/mongo/mod.d.ts +19 -4
  89. package/esm/mongo/mod.d.ts.map +1 -1
  90. package/esm/mongo/mod.js +4 -2
  91. package/esm/mongo/store.d.ts +114 -25
  92. package/esm/mongo/store.d.ts.map +1 -1
  93. package/esm/mongo/store.js +355 -102
  94. package/esm/postgres/store.d.ts +50 -1
  95. package/esm/postgres/store.d.ts.map +1 -1
  96. package/esm/postgres/store.js +133 -13
  97. package/esm/read.d.ts +54 -7
  98. package/esm/read.d.ts.map +1 -1
  99. package/esm/read.js +141 -16
  100. package/esm/s3/store.d.ts +125 -23
  101. package/esm/s3/store.d.ts.map +1 -1
  102. package/esm/s3/store.js +313 -57
  103. package/esm/sqlite/columns.d.ts +33 -0
  104. package/esm/sqlite/columns.d.ts.map +1 -0
  105. package/esm/sqlite/columns.js +51 -0
  106. package/esm/sqlite/store.d.ts +73 -25
  107. package/esm/sqlite/store.d.ts.map +1 -1
  108. package/esm/sqlite/store.js +411 -107
  109. package/esm/types.d.ts +1 -1
  110. package/esm/url.d.ts +122 -19
  111. package/esm/url.d.ts.map +1 -1
  112. package/esm/url.js +218 -24
  113. package/esm/walk-via-ls.d.ts +122 -0
  114. package/esm/walk-via-ls.d.ts.map +1 -0
  115. package/esm/walk-via-ls.js +178 -0
  116. package/package.json +1 -1
  117. package/esm/byte-entity-shim.d.ts +0 -47
  118. package/esm/byte-entity-shim.d.ts.map +0 -1
  119. package/esm/byte-entity-shim.js +0 -138
  120. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/mod.d.ts.map +0 -1
  121. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/encrypt/mod.d.ts.map +0 -1
  122. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/network/policies/path-vector.d.ts.map +0 -1
  123. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/connection.d.ts.map +0 -1
  124. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/rig.d.ts.map +0 -1
  125. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/rig/types.d.ts.map +0 -1
  126. package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/types/types.d.ts.map +0 -1
  127. /package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/{0.22.0 → 0.25.0}/mod.js +0 -0
  128. /package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/{0.22.0 → 0.25.0}/src/client-console/client.d.ts +0 -0
  129. /package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/{0.22.0 → 0.25.0}/src/client-console/client.js +0 -0
  130. /package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/{0.22.0 → 0.25.0}/src/encoding/encoding.d.ts +0 -0
  131. /package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/{0.22.0 → 0.25.0}/src/encoding/encoding.js +0 -0
  132. /package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/{0.22.0 → 0.25.0}/src/functional-client/functional-client.d.ts +0 -0
  133. /package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/{0.22.0 → 0.25.0}/src/functional-client/functional-client.js +0 -0
  134. /package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/{0.22.0 → 0.25.0}/src/match-pattern/match-pattern.d.ts +0 -0
  135. /package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/{0.22.0 → 0.25.0}/src/match-pattern/match-pattern.js +0 -0
  136. /package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/{0.22.0 → 0.25.0}/src/network/decorators.d.ts +0 -0
  137. /package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/{0.22.0 → 0.25.0}/src/network/decorators.js +0 -0
  138. /package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/{0.22.0 → 0.25.0}/src/network/network.d.ts +0 -0
  139. /package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/{0.22.0 → 0.25.0}/src/network/network.js +0 -0
  140. /package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/{0.22.0 → 0.25.0}/src/network/peer.d.ts +0 -0
  141. /package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/{0.22.0 → 0.25.0}/src/network/peer.js +0 -0
  142. /package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/{0.22.0 → 0.25.0}/src/network/policies/flood.d.ts +0 -0
  143. /package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/{0.22.0 → 0.25.0}/src/network/policies/flood.js +0 -0
  144. /package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/{0.22.0 → 0.25.0}/src/network/policies/tell-and-read.d.ts +0 -0
  145. /package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/{0.22.0 → 0.25.0}/src/network/policies/tell-and-read.js +0 -0
  146. /package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/{0.22.0 → 0.25.0}/src/network/types.d.ts +0 -0
  147. /package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/{0.22.0 → 0.25.0}/src/network/types.js +0 -0
  148. /package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/{0.22.0 → 0.25.0}/src/observe-emitter/observe-emitter.d.ts +0 -0
  149. /package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/{0.22.0 → 0.25.0}/src/observe-emitter/observe-emitter.js +0 -0
  150. /package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/{0.22.0 → 0.25.0}/src/rig/events.d.ts +0 -0
  151. /package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/{0.22.0 → 0.25.0}/src/rig/events.js +0 -0
  152. /package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/{0.22.0 → 0.25.0}/src/rig/hooks.d.ts +0 -0
  153. /package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/{0.22.0 → 0.25.0}/src/rig/hooks.js +0 -0
  154. /package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/{0.22.0 → 0.25.0}/src/rig/identity.d.ts +0 -0
  155. /package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/{0.22.0 → 0.25.0}/src/rig/identity.js +0 -0
  156. /package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/{0.22.0 → 0.25.0}/src/rig/operation-handle.d.ts +0 -0
  157. /package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/{0.22.0 → 0.25.0}/src/rig/operation-handle.js +0 -0
  158. /package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/{0.22.0 → 0.25.0}/src/rig/reactions.d.ts +0 -0
  159. /package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/{0.22.0 → 0.25.0}/src/rig/reactions.js +0 -0
  160. /package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/{0.22.0 → 0.25.0}/src/rig/types.js +0 -0
  161. /package/esm/deps/jsr.io/@bandeira-tech/b3nd-core/{0.22.0 → 0.25.0}/src/types/types.js +0 -0
package/esm/dispatch.js CHANGED
@@ -3,30 +3,398 @@
3
3
  *
4
4
  * Every store parses the input url, switches on `fn`, and calls back
5
5
  * into store-supplied handlers. Centralising the dispatch keeps the
6
- * `read`/`ls`/`count`/`x-*` switch identical across stores so they
7
- * cannot drift apart.
6
+ * `read`/`ls`/`find`/`count`/`x-*` switch identical across stores so
7
+ * they cannot drift apart.
8
8
  *
9
9
  * Stores call `dispatchRead(urls, handlers)`; the helper handles
10
10
  * parsing, the fn switch, and tuple assembly. Each handler receives
11
11
  * the parsed url and returns the payload — the helper wraps it into
12
12
  * `[inputUrl, payload]`.
13
+ *
14
+ * v2 listing-spec additions (see `.cc-chat/20260625121936-grammar-shape`):
15
+ *
16
+ * - **`find` case** — requires an explicit `handlers.find` registration
17
+ * (mirrors the `ext?:` opt-in pattern). When `handlers.find` is
18
+ * absent, dispatch throws via the same "unsupported fn" path as any
19
+ * unknown verb — no silent fall-back through `ls`. Stores that
20
+ * support deep walks must wire their own `find` handler (push-down
21
+ * into the backend, or an in-process recursive walk built on `ls`).
22
+ * See spec §3.5: a store that does not advertise `"find"` in
23
+ * `status().fns` MUST throw on `fn=find`.
24
+ *
25
+ * - **`count` case (URL-shape-aware)** — `fn=count` is valid under any
26
+ * URL shape (spec §3.2). Dispatch keeps the existing `handlers.count`
27
+ * path for no-wildcard and shallow-wildcard URLs. When the URL carries
28
+ * a `**` glob, `count` mirrors `find`'s deep walk: either the store
29
+ * has set `pushDownCount: true` (dispatch trusts `handlers.count` to
30
+ * run the deep COUNT in-backend) or dispatch calls `handlers.find` and
31
+ * returns the length of the walked result. If the store advertises
32
+ * neither (`pushDownCount` false AND no `handlers.find`), dispatch
33
+ * throws "unsupported fn 'count'" — no silent shallow-count fall-back,
34
+ * same loud-failure rule as `fn=find` (§3.5).
35
+ *
36
+ * - **cursor-as-trailing-slot** — when `find` or `ls` is called with
37
+ * `limit=<n>`, dispatch appends ONE extra `Output` to the returned
38
+ * array: `[<cursor-uri>, { next: "<opaque>" | null }]`. The cursor
39
+ * URI is the original locator with `cursor=<opaque>` added (or
40
+ * replaced). `next: null` signals end-of-result; otherwise `next` is
41
+ * the opaque token to re-issue the request. The caller can do
42
+ * `read([slot.uri])` literally and walk the next page.
13
43
  */
44
+ import { compareSortable, projectRecord } from "./read.js";
45
+ import { compileSaveGlob, matchesGlob } from "./glob.js";
14
46
  import { parseUrl } from "./url.js";
47
+ /**
48
+ * Filter a sorted row list to entries strictly past the cursor.
49
+ * `cursor` is a URI from a previous page; with `sortOrder=asc` (default)
50
+ * we drop rows up to and including the cursor, with `desc` we drop rows
51
+ * at or after it. Comparison is the same `localeCompare` used by the
52
+ * default URI sort, so cursor pagination tracks the sort direction.
53
+ */
54
+ function filterByCursor(rows, cursor, sortOrder) {
55
+ const desc = sortOrder === "desc";
56
+ return rows.filter(([uri]) => desc ? uri.localeCompare(cursor) < 0 : uri.localeCompare(cursor) > 0);
57
+ }
58
+ /**
59
+ * Read a named field from a payload, returning `undefined` for any
60
+ * non-record payload (eg `Uint8Array`, `ReadableStream`, miss). Used
61
+ * by the dispatch post-sort path so non-uri sortBy works against the
62
+ * `EntityRecord` shape returned by handlers.
63
+ */
64
+ function recordField(value, field) {
65
+ if (value === undefined || value === null)
66
+ return undefined;
67
+ if (typeof value !== "object")
68
+ return undefined;
69
+ if (value instanceof Uint8Array)
70
+ return undefined;
71
+ if (value instanceof ReadableStream)
72
+ return undefined;
73
+ return value[field];
74
+ }
75
+ /** Same as `filterByCursor` but for `format=uris` payloads. */
76
+ function filterUrisByCursor(uris, cursor, sortOrder) {
77
+ const desc = sortOrder === "desc";
78
+ return uris.filter((uri) => desc ? uri.localeCompare(cursor) < 0 : uri.localeCompare(cursor) > 0);
79
+ }
80
+ /**
81
+ * Compose the trailing cursor slot for a paginated `find` / `ls`
82
+ * response. Returns `[cursorUri, { next }]` where `cursorUri` is the
83
+ * original input url with `cursor=<opaque>` added (or replaced; every
84
+ * other param is preserved). `next` is the opaque token (the URI of
85
+ * the last entry returned) when more results are available, `null`
86
+ * when the page was the tail of the result set.
87
+ *
88
+ * The slot is appended UNCONDITIONALLY when `limit` was set in the
89
+ * request — callers shouldn't have to special-case "this might be the
90
+ * last page" or "this is empty"; the `next: null` case carries that
91
+ * signal. Re-issue is `read([slot.uri])` literally.
92
+ *
93
+ * URI composition: we operate on the original input url string (not
94
+ * `parsed.uri`) so the URI-embedded glob portion (`**`, etc.) is
95
+ * preserved. `cursor=` is set/replaced in place via URLSearchParams.
96
+ */
97
+ function buildCursorSlot(inputUrl, cursorForUri, next) {
98
+ const qIdx = inputUrl.indexOf("?");
99
+ const uriPart = qIdx < 0 ? inputUrl : inputUrl.slice(0, qIdx);
100
+ const queryPart = qIdx < 0 ? "" : inputUrl.slice(qIdx + 1);
101
+ const sp = new URLSearchParams(queryPart);
102
+ // The cursor URI is the re-issuable locator: every other param
103
+ // preserved, `cursor=` set to the last row's URI we returned (so the
104
+ // caller can re-issue and get the next page — or, if we already
105
+ // returned the tail, get an empty page + `next: null`). When the
106
+ // page was empty entirely (no rows at all), there is no last URI to
107
+ // hang a cursor on; we drop it so the URI matches a fresh request.
108
+ if (cursorForUri !== null) {
109
+ sp.set("cursor", cursorForUri);
110
+ }
111
+ else {
112
+ sp.delete("cursor");
113
+ }
114
+ const qs = sp.toString();
115
+ const cursorUri = qs ? `${uriPart}?${qs}` : uriPart;
116
+ return [cursorUri, { next }];
117
+ }
118
+ /**
119
+ * Type guard: is the row a plain `Output` tuple (`[uri, payload]`).
120
+ * Used after we strip the cursor slot before applying further
121
+ * transformations to find/ls payloads.
122
+ */
123
+ function lastUriOfRows(rows) {
124
+ if (rows.length === 0)
125
+ return null;
126
+ const last = rows[rows.length - 1];
127
+ if (typeof last === "string")
128
+ return last;
129
+ if (Array.isArray(last) && typeof last[0] === "string")
130
+ return last[0];
131
+ return null;
132
+ }
15
133
  export async function dispatchRead(urls, storeName, handlers) {
16
134
  const out = [];
17
135
  for (const url of urls) {
18
136
  const parsed = parseUrl(url);
137
+ // Validate the combos dispatch itself enforces before stripping
138
+ // anything from the handler call, otherwise validateReadParams
139
+ // inside the handler never sees the original shape.
140
+ if (parsed.params.cursor !== undefined && parsed.params.page !== undefined) {
141
+ throw new Error(`${storeName}: cursor and page cannot be combined — pick one pagination mode`);
142
+ }
19
143
  let payload;
144
+ const fields = parsed.params.fields;
145
+ const pattern = parsed.params.pattern;
146
+ const cursor = parsed.params.cursor;
147
+ const sortBy = parsed.params.sortBy;
148
+ const needsPatternPostFilter = pattern !== undefined &&
149
+ !handlers.pushDownPattern;
150
+ const needsCursorPostFilter = cursor !== undefined &&
151
+ !handlers.pushDownCursor;
152
+ // Non-uri sortBy needs dispatch post-sort unless the backend
153
+ // explicitly handles arbitrary sortBy itself. `leaf` is a
154
+ // dispatch-level sort (basename localeCompare); it always
155
+ // post-sorts.
156
+ const needsSortByPostSort = sortBy !== undefined && sortBy !== "uri" &&
157
+ !handlers.pushDownSortBy;
20
158
  switch (parsed.fn) {
21
159
  case "read":
22
160
  payload = await handlers.read(parsed);
161
+ if (fields && fields.length > 0) {
162
+ payload = projectRecord(payload, fields);
163
+ }
23
164
  break;
24
165
  case "ls":
25
- payload = await handlers.ls(parsed);
166
+ case "find": {
167
+ const isFind = parsed.fn === "find";
168
+ // v2 §3.5: a store that does not advertise `"find"` in
169
+ // status().fns MUST throw on fn=find. We enforce that at the
170
+ // dispatch level by requiring an explicit `handlers.find`
171
+ // registration — no silent fall-back through `ls`. Error shape
172
+ // matches the unknown-fn throw below so existing callers can
173
+ // detect it the same way.
174
+ if (isFind && !handlers.find) {
175
+ throw new Error(`${storeName}: unsupported fn 'find'`);
176
+ }
177
+ const format = parsed.params.format ?? "full";
178
+ // For find, `handlers.find` is guaranteed present by the guard
179
+ // above. For ls, the handler is `handlers.ls`.
180
+ const lsLikeHandler = isFind ? handlers.find : handlers.ls;
181
+ if (needsPatternPostFilter || needsCursorPostFilter ||
182
+ needsSortByPostSort) {
183
+ // Dispatch handles pattern/cursor/sortBy + pagination +
184
+ // projection itself, so it asks the backend for the full
185
+ // result first. Stripping `limit`/`page` is necessary so the
186
+ // backend doesn't truncate the set before the filters run;
187
+ // stripping `pattern`/`cursor`/non-uri `sortBy` is necessary
188
+ // so backends that don't recognise them don't error out.
189
+ // For non-uri sortBy we also have to force `format=full`
190
+ // since records (not just URIs) are needed to read the
191
+ // sort field.
192
+ const handlerParams = { ...parsed.params };
193
+ delete handlerParams.limit;
194
+ delete handlerParams.page;
195
+ delete handlerParams.fields;
196
+ delete handlerParams.cursor;
197
+ if (needsPatternPostFilter)
198
+ delete handlerParams.pattern;
199
+ const handlerFormat = needsSortByPostSort && format === "uris"
200
+ ? "full"
201
+ : format;
202
+ handlerParams.format = handlerFormat;
203
+ if (needsSortByPostSort)
204
+ handlerParams.sortBy = "uri";
205
+ const raw = await lsLikeHandler({
206
+ ...parsed,
207
+ params: handlerParams,
208
+ });
209
+ if (!Array.isArray(raw)) {
210
+ payload = raw;
211
+ break;
212
+ }
213
+ let arr = raw;
214
+ if (needsPatternPostFilter) {
215
+ // Hoist the compiled glob — the row loop is the only hot
216
+ // spot we know about and the compile cost is non-trivial.
217
+ const re = compileSaveGlob(pattern);
218
+ arr = handlerFormat === "uris"
219
+ ? arr.filter((uri) => uri.startsWith(parsed.uri) &&
220
+ re.test(uri.slice(parsed.uri.length)))
221
+ : arr.filter(([uri]) => uri.startsWith(parsed.uri) &&
222
+ re.test(uri.slice(parsed.uri.length)));
223
+ }
224
+ if (needsCursorPostFilter) {
225
+ arr = handlerFormat === "uris"
226
+ ? filterUrisByCursor(arr, cursor, parsed.params.sortOrder)
227
+ : filterByCursor(arr, cursor, parsed.params.sortOrder);
228
+ }
229
+ if (needsSortByPostSort) {
230
+ // We forced format=full above, so arr is Array<Output>.
231
+ const dir = parsed.params.sortOrder === "desc" ? -1 : 1;
232
+ if (sortBy === "leaf") {
233
+ arr = [...arr].sort(([a], [b]) => leafOf(a).localeCompare(leafOf(b)) * dir);
234
+ }
235
+ else {
236
+ arr = [...arr].sort(([, a], [, b]) => {
237
+ const av = recordField(a, sortBy);
238
+ const bv = recordField(b, sortBy);
239
+ return compareSortable(av, bv) * dir;
240
+ });
241
+ }
242
+ }
243
+ let truncated = false;
244
+ if (parsed.params.limit !== undefined) {
245
+ // page is incompatible with cursor (validateReadParams
246
+ // throws on that combo); when only `page` is set the
247
+ // page-based offset still applies.
248
+ const start = needsCursorPostFilter
249
+ ? 0
250
+ : ((parsed.params.page ?? 1) - 1) * parsed.params.limit;
251
+ const end = start + parsed.params.limit;
252
+ truncated = arr.length > end;
253
+ arr = arr.slice(start, end);
254
+ }
255
+ // If we forced format=full to access the sort field but the
256
+ // caller asked for uris, project down to uris at the end.
257
+ if (handlerFormat === "full" && format === "uris") {
258
+ arr = arr.map(([uri]) => uri);
259
+ }
260
+ else if (fields && fields.length > 0 && format === "full") {
261
+ arr = arr.map(([uri, record]) => [
262
+ uri,
263
+ projectRecord(record, fields),
264
+ ]);
265
+ }
266
+ // Append cursor-as-trailing-slot whenever `limit` was set.
267
+ // `cursorForUri`: the URI of the last row returned (or null if
268
+ // the page was empty) — used to compose a re-issuable locator.
269
+ // `next`: the opaque cursor for the next page, or `null` when
270
+ // the page was the tail of the result set.
271
+ if (parsed.params.limit !== undefined) {
272
+ const lastUri = lastUriOfRows(arr);
273
+ const next = truncated ? lastUri : null;
274
+ arr = [...arr, buildCursorSlot(url, lastUri, next)];
275
+ }
276
+ payload = arr;
277
+ break;
278
+ }
279
+ // Fast pass-through: the backend handled (or accepted) every
280
+ // param itself. We only need to optionally project the
281
+ // returned records and append the cursor slot.
282
+ const raw = await lsLikeHandler(parsed);
283
+ if (fields && fields.length > 0 && Array.isArray(raw) &&
284
+ format === "full") {
285
+ payload = raw.map(([uri, record]) => [
286
+ uri,
287
+ projectRecord(record, fields),
288
+ ]);
289
+ }
290
+ else {
291
+ payload = raw;
292
+ }
293
+ if (parsed.params.limit !== undefined && Array.isArray(payload)) {
294
+ // We don't know if the backend truncated — the only safe
295
+ // signal we have is "did we return `limit` items"; if we
296
+ // did, callers should re-issue. False positives (cursor
297
+ // points past the end) are correctness-safe: the next call
298
+ // returns an empty page + a `next: null` slot.
299
+ const arr = payload;
300
+ const isFull = arr.length >= parsed.params.limit;
301
+ const lastUri = lastUriOfRows(arr);
302
+ const next = isFull ? lastUri : null;
303
+ payload = [...arr, buildCursorSlot(url, lastUri, next)];
304
+ }
26
305
  break;
27
- case "count":
28
- payload = await handlers.count(parsed);
306
+ }
307
+ case "count": {
308
+ // v2 §3.2: `count` honors any URL shape. A `**` glob in the URL
309
+ // means "count of all descendants" (the find-flavored count).
310
+ // The shallow ls-based filtered-count path below cannot serve
311
+ // that — handlers.ls returns one segment deep — so dispatch
312
+ // either routes to handlers.count (push-down opt-in) or walks
313
+ // via handlers.find and returns the length. Without either,
314
+ // throw rather than silently return a shallow count.
315
+ const isDeepCount = parsed.glob.includes("**");
316
+ if (isDeepCount && handlers.pushDownCount) {
317
+ // Push-down deep count: trust the backend to translate the
318
+ // full URL (glob included) into an efficient COUNT. Skip the
319
+ // ls-based filtered-count path below — that path was designed
320
+ // for shallow `?` / `*` filters and would short-circuit
321
+ // through ls instead of count.
322
+ payload = await handlers.count(parsed);
323
+ break;
324
+ }
325
+ if (isDeepCount && !handlers.pushDownCount) {
326
+ if (!handlers.find) {
327
+ throw new Error(`${storeName}: unsupported fn 'count'`);
328
+ }
329
+ // In-process deep count via the find walk. We post-filter
330
+ // against the user's glob (same rule the find path applies
331
+ // when pushDownPattern is off) so a handler that walks an
332
+ // over-broad prefix cannot inflate the count. Pagination
333
+ // params are stripped — we want the full set to count, never
334
+ // a page.
335
+ const handlerParams = { ...parsed.params };
336
+ delete handlerParams.limit;
337
+ delete handlerParams.page;
338
+ delete handlerParams.fields;
339
+ delete handlerParams.cursor;
340
+ if (!handlers.pushDownPattern)
341
+ delete handlerParams.pattern;
342
+ // Force a record-shape result so we can count tuples without
343
+ // dealing with the `string[]` / `Output[]` branch — the format
344
+ // is invisible to the caller, who only sees the count number.
345
+ handlerParams.format = "full";
346
+ const raw = await handlers.find({
347
+ ...parsed,
348
+ params: handlerParams,
349
+ });
350
+ if (!Array.isArray(raw)) {
351
+ payload = 0;
352
+ break;
353
+ }
354
+ let rows = raw;
355
+ if (pattern !== undefined && !handlers.pushDownPattern) {
356
+ const re = compileSaveGlob(pattern);
357
+ rows = rows.filter(([uri]) => uri.startsWith(parsed.uri) &&
358
+ re.test(uri.slice(parsed.uri.length)));
359
+ }
360
+ payload = rows.length;
361
+ break;
362
+ }
363
+ if (needsPatternPostFilter || needsCursorPostFilter) {
364
+ // Filtered count: list the matching URIs (cheap
365
+ // `format=uris` path, no payload load) and return the
366
+ // length. Slower than push-down COUNT, but the only way to
367
+ // honour pattern/cursor without per-backend query
368
+ // translation.
369
+ const lsParams = {
370
+ ...parsed.params,
371
+ format: "uris",
372
+ };
373
+ delete lsParams.fields;
374
+ delete lsParams.limit;
375
+ delete lsParams.page;
376
+ delete lsParams.cursor;
377
+ if (needsPatternPostFilter)
378
+ delete lsParams.pattern;
379
+ const raw = await handlers.ls({ ...parsed, params: lsParams });
380
+ if (!Array.isArray(raw)) {
381
+ payload = 0;
382
+ break;
383
+ }
384
+ let uris = raw;
385
+ if (needsPatternPostFilter) {
386
+ uris = uris.filter((uri) => matchesGlob(uri, parsed.uri, pattern));
387
+ }
388
+ if (needsCursorPostFilter) {
389
+ uris = filterUrisByCursor(uris, cursor, parsed.params.sortOrder);
390
+ }
391
+ payload = uris.length;
392
+ }
393
+ else {
394
+ payload = await handlers.count(parsed);
395
+ }
29
396
  break;
397
+ }
30
398
  default:
31
399
  if (parsed.fn.startsWith("x-") && handlers.ext) {
32
400
  payload = await handlers.ext(parsed);
@@ -38,3 +406,11 @@ export async function dispatchRead(urls, storeName, handlers) {
38
406
  }
39
407
  return out;
40
408
  }
409
+ // Local copy of leafOf to avoid an extra import — same recipe as
410
+ // read.ts's exported helper. Keeping it local keeps the dispatch
411
+ // module's import surface tight (we already pull compareSortable,
412
+ // projectRecord, and the glob helpers).
413
+ function leafOf(uri) {
414
+ const idx = uri.lastIndexOf("/");
415
+ return idx < 0 ? uri : uri.slice(idx + 1);
416
+ }
@@ -1,44 +1,143 @@
1
1
  /**
2
- * ElasticsearchStore — Elasticsearch implementation of Store.
3
- *
4
- * Pure mechanical byte storage with no protocol awareness. URIs are
5
- * partitioned into one index per `protocol_hostname` pair, with the
6
- * path as the document `_id`. Payload bytes are base64-encoded into a
7
- * string field ES has no native binary type that round-trips
8
- * arbitrary bytes through `_source`.
9
- *
10
- * `fn=ls` / `fn=count` are pushed down via an ES regex query that
11
- * enforces the shallow-direct-leaves contract: `<docPrefix>[^/]+`.
12
- * Lucene regex queries are auto-anchored, so the pattern must match
13
- * the full `_id`.
2
+ * ElasticsearchStore — Elasticsearch implementation of `EntityStore`.
3
+ *
4
+ * One backend, many entities. Per-entity index naming partitions
5
+ * documents in a way that keeps queries simple:
6
+ *
7
+ * - `BYTES_ENTITY` index `{indexPrefix}_{protocol}_{hostname}`,
8
+ * docId = uri path. Document `_source` carries `payload` (base64)
9
+ * and a mirrored `path` field that `ls`/`count` regex-queries hit
10
+ * (ES 8 disallows regex on `_id`). This is the original layout
11
+ * no migration.
12
+ * - any other schema index
13
+ * `{indexPrefix}_{entityName}_{protocol}_{hostname}`, same docId
14
+ * convention. Document `_source` carries the record fields encoded
15
+ * per canonical `TYPE_TAGS` (bytes → base64, bigint → string,
16
+ * timestamp → ISO-8601 — see `./fields.ts`) plus the mirrored
17
+ * `path` field.
18
+ *
19
+ * ## Lifecycle
20
+ *
21
+ * `entitySupport(schema)` is pure — it plans the field set and computes
22
+ * a collision signature. `provisionEntity(meta)` writes a tiny meta
23
+ * doc to `{indexPrefix}__meta__/entities` keyed by entity name, body
24
+ * `{signature}`; subsequent `entityStatus(meta)` reads it back. The
25
+ * meta doc is also used by `status()` to list provisioned entities.
26
+ *
27
+ * ## Read params
28
+ *
29
+ * `fn=ls` / `fn=count` push down to an ES regex query against the
30
+ * mirrored `path.keyword` field with the shallow-direct-leaves
31
+ * predicate `<docPrefix>[^/]+`. Standard params (`limit`/`page`/
32
+ * `sortBy=uri`/`sortOrder`/`format`) translate to `size`/`from`/`sort`,
33
+ * with `_source: false` for the `format=uris` fast path.
34
+ *
35
+ * `fn=find` (v2 §3.3) reuses the regex query shape but composes the
36
+ * body from `saveGlobToRegexBody(pattern)` directly — `**` → `.*`
37
+ * (crosses `/`), so the same query that backs `ls` walks the entire
38
+ * subtree. The query stays prefix-anchored on `path.keyword` (a
39
+ * `keyword` field with a term dictionary), which Lucene can serve via
40
+ * its `RegexpQuery` using DFA traversal of the term dictionary;
41
+ * prefix-anchored regexes are the fast case (the engine restricts the
42
+ * scan to terms whose common prefix matches the regex's required
43
+ * prefix). The default `[^/]+` shallow body that `_leafQuery` falls
44
+ * back to when no pattern is set is NOT reachable from the find path:
45
+ * `parseUrl` guarantees `params.pattern` is populated whenever
46
+ * `fn=find` dispatches here (URI-embedded glob or the dual-accept
47
+ * `?pattern=` form).
48
+ *
49
+ * `pushDownCount: true` — ES has a native `_count` API that runs the
50
+ * same query shape without scoring or document materialisation. Deep
51
+ * counts (URLs containing `**`) route directly to `_count` with the
52
+ * `saveGlobToRegexBody`-composed regex; dispatch never walks via
53
+ * `handlers.find` to count.
14
54
  */
15
- import type { DeleteResult, Output, StatusResult } from "../deps/jsr.io/@bandeira-tech/b3nd-core/0.22.0/src/types/types.js";
16
- import { type BytesOnlyEntityMeta } from "../byte-entity-shim.js";
55
+ import type { DeleteResult, Output, StatusResult } from "../deps/jsr.io/@bandeira-tech/b3nd-core/0.25.0/src/types/types.js";
17
56
  import type { EntityStore } from "../entity-store.js";
18
- import type { EntityRecord, EntitySchema } from "../entity.js";
57
+ import { type EntityMeta, type EntityRecord, type EntitySchema } from "../entity.js";
19
58
  import type { StoreCapabilities, StoreWriteResult } from "../types.js";
59
+ import { type FieldPlan } from "../json-fields.js";
20
60
  import type { ElasticsearchExecutor } from "./mod.js";
21
- export declare class ElasticsearchStore implements EntityStore<BytesOnlyEntityMeta> {
61
+ /**
62
+ * ElasticsearchStore-specific entity handle.
63
+ *
64
+ * `indexInfix` is `""` for BYTES_ENTITY (current layout) or
65
+ * `{entityName}_` for custom entities — it's spliced between the
66
+ * store-level `indexPrefix` and the URI's `protocol_hostname` to
67
+ * partition documents by entity without changing the docId scheme.
68
+ * `isBytes` selects the legacy bytes-payload doc shape vs the
69
+ * JSON-encoded record shape. `fields`/`declared`/`bytesFields` drive
70
+ * write-time validation and encoding; `signature` is used for
71
+ * collision detection in `entityStatus` / `provisionEntity`.
72
+ */
73
+ export interface ElasticsearchEntityMeta extends EntityMeta {
74
+ readonly indexInfix: string;
75
+ readonly isBytes: boolean;
76
+ readonly fields: readonly FieldPlan[];
77
+ readonly declared: ReadonlySet<string>;
78
+ readonly bytesFields: ReadonlySet<string>;
79
+ readonly signature: string;
80
+ }
81
+ export declare class ElasticsearchStore implements EntityStore<ElasticsearchEntityMeta> {
22
82
  private readonly indexPrefix;
23
83
  private readonly executor;
24
84
  constructor(indexPrefix: string, executor: ElasticsearchExecutor);
25
- entitySupport(schema: EntitySchema): BytesOnlyEntityMeta;
26
- entityStatus(meta: BytesOnlyEntityMeta): Promise<"live" | "unprovisioned">;
27
- provisionEntity(_meta: BytesOnlyEntityMeta): Promise<void>;
28
- write(meta: BytesOnlyEntityMeta, entries: {
85
+ entitySupport(schema: EntitySchema): ElasticsearchEntityMeta;
86
+ entityStatus(meta: ElasticsearchEntityMeta): Promise<"live" | "unprovisioned">;
87
+ provisionEntity(meta: ElasticsearchEntityMeta): Promise<void>;
88
+ write(meta: ElasticsearchEntityMeta, entries: {
29
89
  uri: string;
30
90
  record: EntityRecord;
31
91
  }[]): Promise<StoreWriteResult[]>;
32
- read<T = EntityRecord | undefined>(meta: BytesOnlyEntityMeta, urls: string[]): Promise<Output<T>[]>;
33
- delete(meta: BytesOnlyEntityMeta, uris: string[]): Promise<DeleteResult[]>;
34
- private _writeBytes;
35
- private _readBytes;
92
+ read<T = EntityRecord | undefined>(meta: ElasticsearchEntityMeta, urls: string[]): Promise<Output<T>[]>;
36
93
  private _readOne;
94
+ /**
95
+ * Lucene regex query for shallow direct-leaves under `docPrefix`.
96
+ * Pattern push-down: splice the glob's regex body in place of the
97
+ * default `[^/]+`. Cursor push-down: wrap the regex in a `bool`
98
+ * with a `range` on `path.keyword` (`gt` for asc, `lt` for desc).
99
+ */
37
100
  private _leafQuery;
38
101
  private _ls;
102
+ /**
103
+ * Lucene regex query for the deep walk (`fn=find`) under
104
+ * `docPrefix`. Mirrors `_leafQuery` but REQUIRES a pattern: parseUrl
105
+ * guarantees `params.pattern` is populated whenever fn=find
106
+ * dispatches here (URI-embedded glob or dual-accept `?pattern=`).
107
+ * If pattern is absent we throw rather than silently widening to
108
+ * `.*` — that would conflate "find everything" with a parser bug.
109
+ *
110
+ * The composed body uses `saveGlobToRegexBody` (which emits `.*` for
111
+ * `**`, crossing `/`), prepended with the escaped `docPrefix`. The
112
+ * resulting regex is prefix-anchored on the keyword field — Lucene
113
+ * restricts the term-dictionary scan to terms starting with the
114
+ * required literal prefix, so even broad `**` queries don't degrade
115
+ * to a full term scan.
116
+ */
117
+ private _subtreeQuery;
118
+ private _find;
39
119
  private _count;
40
- private _deleteBytes;
120
+ delete(meta: ElasticsearchEntityMeta, uris: string[]): Promise<DeleteResult[]>;
41
121
  status(): Promise<StatusResult>;
42
122
  capabilities(): StoreCapabilities;
123
+ /** Per-entity, per-`protocol_hostname` data index. */
124
+ private _dataIndex;
125
+ /** Single meta index holding `{name → signature}` provisioning records. */
126
+ private _metaIndex;
127
+ /**
128
+ * Read the persisted signature for an entity, or `null` if no
129
+ * provisioning record exists.
130
+ */
131
+ private _readMetaSignature;
132
+ /**
133
+ * Scan the meta index for every provisioned entity name. Used by
134
+ * `status()` to advertise the entities a peer can talk to.
135
+ */
136
+ private _listProvisionedEntities;
137
+ /**
138
+ * Collect any `ReadableStream` values on `bytes`-tagged fields into
139
+ * `Uint8Array` and return a shallow-copied record.
140
+ */
141
+ private _normaliseBytesFields;
43
142
  }
44
143
  //# sourceMappingURL=store.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/elasticsearch/store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EACV,YAAY,EACZ,MAAM,EACN,YAAY,EACb,MAAM,mEAAmE,CAAC;AAC3E,OAAO,EAEL,KAAK,mBAAmB,EAIzB,MAAM,wBAAwB,CAAC;AAChC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAQ/D,OAAO,KAAK,EACV,iBAAiB,EAEjB,gBAAgB,EACjB,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAC;AAwCtD,qBAAa,kBAAmB,YAAW,WAAW,CAAC,mBAAmB,CAAC;IACzE,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAwB;gBAErC,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,qBAAqB;IAUhE,aAAa,CAAC,MAAM,EAAE,YAAY,GAAG,mBAAmB;IAIxD,YAAY,CAAC,IAAI,EAAE,mBAAmB,GAAG,OAAO,CAAC,MAAM,GAAG,eAAe,CAAC;IAI1E,eAAe,CAAC,KAAK,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;IAI1D,KAAK,CACH,IAAI,EAAE,mBAAmB,EACzB,OAAO,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,YAAY,CAAA;KAAE,EAAE,GAC/C,OAAO,CAAC,gBAAgB,EAAE,CAAC;IAS9B,IAAI,CAAC,CAAC,GAAG,YAAY,GAAG,SAAS,EAC/B,IAAI,EAAE,mBAAmB,EACzB,IAAI,EAAE,MAAM,EAAE,GACb,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;IASvB,MAAM,CAAC,IAAI,EAAE,mBAAmB,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;YAW5D,WAAW;IAkCzB,OAAO,CAAC,UAAU;YAQJ,QAAQ;IAOtB,OAAO,CAAC,UAAU;YAQJ,GAAG;YAoCH,MAAM;YAQN,YAAY;IAqBpB,MAAM,IAAI,OAAO,CAAC,YAAY,CAAC;IAyBrC,YAAY,IAAI,iBAAiB;CAGlC"}
1
+ {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/elasticsearch/store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqDG;AAEH,OAAO,KAAK,EACV,YAAY,EACZ,MAAM,EACN,YAAY,EACb,MAAM,mEAAmE,CAAC;AAQ3E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAEL,KAAK,UAAU,EACf,KAAK,YAAY,EACjB,KAAK,YAAY,EAClB,MAAM,cAAc,CAAC;AAEtB,OAAO,KAAK,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AACvE,OAAO,EAIL,KAAK,SAAS,EAEf,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAC;AA4BtD;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,uBAAwB,SAAQ,UAAU;IACzD,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,SAAS,SAAS,EAAE,CAAC;IACtC,QAAQ,CAAC,QAAQ,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IACvC,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAC1C,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAmCD,qBAAa,kBACX,YAAW,WAAW,CAAC,uBAAuB,CAAC;IAC/C,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAwB;gBAErC,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,qBAAqB;IAUhE,aAAa,CAAC,MAAM,EAAE,YAAY,GAAG,uBAAuB;IA0CtD,YAAY,CAChB,IAAI,EAAE,uBAAuB,GAC5B,OAAO,CAAC,MAAM,GAAG,eAAe,CAAC;IAM9B,eAAe,CAAC,IAAI,EAAE,uBAAuB,GAAG,OAAO,CAAC,IAAI,CAAC;IAoB7D,KAAK,CACT,IAAI,EAAE,uBAAuB,EAC7B,OAAO,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,YAAY,CAAA;KAAE,EAAE,GAC/C,OAAO,CAAC,gBAAgB,EAAE,CAAC;IA0E9B,IAAI,CAAC,CAAC,GAAG,YAAY,GAAG,SAAS,EAC/B,IAAI,EAAE,uBAAuB,EAC7B,IAAI,EAAE,MAAM,EAAE,GACb,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;YAcT,QAAQ;IAkBtB;;;;;OAKG;IACH,OAAO,CAAC,UAAU;YAwBJ,GAAG;IAyEjB;;;;;;;;;;;;;;OAcG;IACH,OAAO,CAAC,aAAa;YA8BP,KAAK;YA0DL,MAAM;IAyBd,MAAM,CACV,IAAI,EAAE,uBAAuB,EAC7B,IAAI,EAAE,MAAM,EAAE,GACb,OAAO,CAAC,YAAY,EAAE,CAAC;IAmCpB,MAAM,IAAI,OAAO,CAAC,YAAY,CAAC;IA2BrC,YAAY,IAAI,iBAAiB;IAMjC,sDAAsD;IACtD,OAAO,CAAC,UAAU;IAQlB,2EAA2E;IAC3E,OAAO,CAAC,UAAU;IAIlB;;;OAGG;YACW,kBAAkB;IAYhC;;;OAGG;YACW,wBAAwB;IAYtC;;;OAGG;YACW,qBAAqB;CAmBpC"}