hide-a-bed 5.2.8 → 6.0.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.
Files changed (258) hide show
  1. package/.prettierrc +7 -0
  2. package/README.md +270 -218
  3. package/dist/cjs/index.cjs +1952 -0
  4. package/dist/esm/index.mjs +1898 -0
  5. package/eslint.config.js +15 -0
  6. package/impl/bindConfig.mts +140 -0
  7. package/impl/bulkGet.mts +256 -0
  8. package/impl/bulkRemove.mts +98 -0
  9. package/impl/bulkSave.mts +286 -0
  10. package/impl/get.mts +137 -0
  11. package/impl/getDBInfo.mts +67 -0
  12. package/impl/patch.mts +134 -0
  13. package/impl/put.mts +56 -0
  14. package/impl/query.mts +224 -0
  15. package/impl/remove.mts +65 -0
  16. package/impl/retry.mts +66 -0
  17. package/impl/stream.mts +143 -0
  18. package/impl/sugar/lock.mts +103 -0
  19. package/impl/sugar/{watch.mjs → watch.mts} +56 -22
  20. package/impl/utils/errors.mts +130 -0
  21. package/impl/utils/logger.mts +62 -0
  22. package/impl/utils/mergeNeedleOpts.mts +16 -0
  23. package/impl/utils/parseRows.mts +117 -0
  24. package/impl/utils/queryBuilder.mts +173 -0
  25. package/impl/utils/queryString.mts +44 -0
  26. package/impl/{trackedEmitter.mjs → utils/trackedEmitter.mts} +9 -7
  27. package/impl/utils/transactionErrors.mts +71 -0
  28. package/index.mts +82 -0
  29. package/migration_guides/v6.md +70 -0
  30. package/package.json +49 -32
  31. package/schema/config.mts +81 -0
  32. package/schema/couch/couch.input.schema.ts +43 -0
  33. package/schema/couch/couch.output.schema.ts +169 -0
  34. package/schema/sugar/lock.mts +18 -0
  35. package/schema/sugar/watch.mts +14 -0
  36. package/schema/util.mts +8 -0
  37. package/tsconfig.json +10 -4
  38. package/tsdown.config.ts +16 -0
  39. package/typedoc.json +4 -0
  40. package/types/output/eslint.config.d.ts +3 -0
  41. package/types/output/eslint.config.d.ts.map +1 -0
  42. package/types/output/impl/bindConfig.d.mts +174 -0
  43. package/types/output/impl/bindConfig.d.mts.map +1 -0
  44. package/types/output/impl/bulkGet.d.mts +75 -0
  45. package/types/output/impl/bulkGet.d.mts.map +1 -0
  46. package/types/output/impl/bulkGet.test.d.mts +2 -0
  47. package/types/output/impl/bulkGet.test.d.mts.map +1 -0
  48. package/types/output/impl/bulkRemove.d.mts +63 -0
  49. package/types/output/impl/bulkRemove.d.mts.map +1 -0
  50. package/types/output/impl/bulkRemove.test.d.mts +2 -0
  51. package/types/output/impl/bulkRemove.test.d.mts.map +1 -0
  52. package/types/output/impl/bulkSave.d.mts +64 -0
  53. package/types/output/impl/bulkSave.d.mts.map +1 -0
  54. package/types/output/impl/bulkSave.test.d.mts +2 -0
  55. package/types/output/impl/bulkSave.test.d.mts.map +1 -0
  56. package/types/output/impl/get.d.mts +20 -0
  57. package/types/output/impl/get.d.mts.map +1 -0
  58. package/types/output/impl/get.test.d.mts +2 -0
  59. package/types/output/impl/get.test.d.mts.map +1 -0
  60. package/types/output/impl/getDBInfo.d.mts +52 -0
  61. package/types/output/impl/getDBInfo.d.mts.map +1 -0
  62. package/types/output/impl/getDBInfo.test.d.mts +2 -0
  63. package/types/output/impl/getDBInfo.test.d.mts.map +1 -0
  64. package/types/output/impl/patch.d.mts +45 -0
  65. package/types/output/impl/patch.d.mts.map +1 -0
  66. package/types/output/impl/patch.test.d.mts +2 -0
  67. package/types/output/impl/patch.test.d.mts.map +1 -0
  68. package/types/output/impl/put.d.mts +5 -0
  69. package/types/output/impl/put.d.mts.map +1 -0
  70. package/types/output/impl/put.test.d.mts +2 -0
  71. package/types/output/impl/put.test.d.mts.map +1 -0
  72. package/types/output/impl/query.d.mts +47 -0
  73. package/types/output/impl/query.d.mts.map +1 -0
  74. package/types/output/impl/query.test.d.mts +2 -0
  75. package/types/output/impl/query.test.d.mts.map +1 -0
  76. package/types/output/impl/remove.d.mts +9 -0
  77. package/types/output/impl/remove.d.mts.map +1 -0
  78. package/types/output/impl/remove.test.d.mts +2 -0
  79. package/types/output/impl/remove.test.d.mts.map +1 -0
  80. package/types/output/impl/retry.d.mts +32 -0
  81. package/types/output/impl/retry.d.mts.map +1 -0
  82. package/types/output/impl/retry.test.d.mts +2 -0
  83. package/types/output/impl/retry.test.d.mts.map +1 -0
  84. package/types/output/impl/stream.d.mts +13 -0
  85. package/types/output/impl/stream.d.mts.map +1 -0
  86. package/types/output/impl/stream.test.d.mts +2 -0
  87. package/types/output/impl/stream.test.d.mts.map +1 -0
  88. package/types/output/impl/sugar/lock.d.mts +24 -0
  89. package/types/output/impl/sugar/lock.d.mts.map +1 -0
  90. package/types/output/impl/sugar/lock.test.d.mts +2 -0
  91. package/types/output/impl/sugar/lock.test.d.mts.map +1 -0
  92. package/types/output/impl/sugar/watch.d.mts +21 -0
  93. package/types/output/impl/sugar/watch.d.mts.map +1 -0
  94. package/types/output/impl/sugar/watch.test.d.mts +2 -0
  95. package/types/output/impl/sugar/watch.test.d.mts.map +1 -0
  96. package/types/output/impl/utils/errors.d.mts +78 -0
  97. package/types/output/impl/utils/errors.d.mts.map +1 -0
  98. package/types/output/impl/utils/errors.test.d.mts +2 -0
  99. package/types/output/impl/utils/errors.test.d.mts.map +1 -0
  100. package/types/output/impl/utils/logger.d.mts +11 -0
  101. package/types/output/impl/utils/logger.d.mts.map +1 -0
  102. package/types/output/impl/utils/logger.test.d.mts +2 -0
  103. package/types/output/impl/utils/logger.test.d.mts.map +1 -0
  104. package/types/output/impl/utils/mergeNeedleOpts.d.mts +53 -0
  105. package/types/output/impl/utils/mergeNeedleOpts.d.mts.map +1 -0
  106. package/types/output/impl/utils/parseRows.d.mts +15 -0
  107. package/types/output/impl/utils/parseRows.d.mts.map +1 -0
  108. package/types/output/impl/utils/parseRows.test.d.mts +2 -0
  109. package/types/output/impl/utils/parseRows.test.d.mts.map +1 -0
  110. package/types/output/impl/utils/queryBuilder.d.mts +68 -0
  111. package/types/output/impl/utils/queryBuilder.d.mts.map +1 -0
  112. package/types/output/impl/utils/queryBuilder.test.d.mts +2 -0
  113. package/types/output/impl/utils/queryBuilder.test.d.mts.map +1 -0
  114. package/types/output/impl/utils/queryString.d.mts +9 -0
  115. package/types/output/impl/utils/queryString.d.mts.map +1 -0
  116. package/types/output/impl/utils/queryString.test.d.mts +2 -0
  117. package/types/output/impl/utils/queryString.test.d.mts.map +1 -0
  118. package/types/output/impl/utils/trackedEmitter.d.mts +7 -0
  119. package/types/output/impl/utils/trackedEmitter.d.mts.map +1 -0
  120. package/{impl → types/output/impl/utils}/transactionErrors.d.mts +16 -31
  121. package/types/output/impl/utils/transactionErrors.d.mts.map +1 -0
  122. package/types/output/index.d.mts +32 -0
  123. package/types/output/index.d.mts.map +1 -0
  124. package/types/output/index.test.d.mts +2 -0
  125. package/types/output/index.test.d.mts.map +1 -0
  126. package/types/output/schema/config.d.mts +90 -0
  127. package/types/output/schema/config.d.mts.map +1 -0
  128. package/types/output/schema/couch/couch.input.schema.d.ts +29 -0
  129. package/types/output/schema/couch/couch.input.schema.d.ts.map +1 -0
  130. package/types/output/schema/couch/couch.output.schema.d.ts +113 -0
  131. package/types/output/schema/couch/couch.output.schema.d.ts.map +1 -0
  132. package/types/output/schema/sugar/lock.d.mts +19 -0
  133. package/types/output/schema/sugar/lock.d.mts.map +1 -0
  134. package/types/output/schema/sugar/watch.d.mts +11 -0
  135. package/types/output/schema/sugar/watch.d.mts.map +1 -0
  136. package/types/output/schema/util.d.mts +85 -0
  137. package/types/output/schema/util.d.mts.map +1 -0
  138. package/types/output/tsdown.config.d.ts +3 -0
  139. package/types/output/tsdown.config.d.ts.map +1 -0
  140. package/types/output/types/standard-schema.d.ts +60 -0
  141. package/types/output/types/standard-schema.d.ts.map +1 -0
  142. package/types/standard-schema.ts +76 -0
  143. package/types/utils.d.ts +1 -0
  144. package/cjs/impl/bulk.cjs +0 -275
  145. package/cjs/impl/changes.cjs +0 -67
  146. package/cjs/impl/crud.cjs +0 -127
  147. package/cjs/impl/errors.cjs +0 -75
  148. package/cjs/impl/logger.cjs +0 -70
  149. package/cjs/impl/patch.cjs +0 -95
  150. package/cjs/impl/query.cjs +0 -116
  151. package/cjs/impl/queryBuilder.cjs +0 -163
  152. package/cjs/impl/retry.cjs +0 -55
  153. package/cjs/impl/stream.cjs +0 -121
  154. package/cjs/impl/sugar/lock.cjs +0 -81
  155. package/cjs/impl/sugar/watch.cjs +0 -159
  156. package/cjs/impl/trackedEmitter.cjs +0 -54
  157. package/cjs/impl/transactionErrors.cjs +0 -70
  158. package/cjs/impl/util.cjs +0 -64
  159. package/cjs/index.cjs +0 -132
  160. package/cjs/integration/changes.cjs +0 -76
  161. package/cjs/integration/disconnect-watch.cjs +0 -52
  162. package/cjs/integration/watch.cjs +0 -59
  163. package/cjs/schema/bind.cjs +0 -59
  164. package/cjs/schema/bulk.cjs +0 -92
  165. package/cjs/schema/changes.cjs +0 -68
  166. package/cjs/schema/config.cjs +0 -48
  167. package/cjs/schema/crud.cjs +0 -77
  168. package/cjs/schema/patch.cjs +0 -53
  169. package/cjs/schema/query.cjs +0 -62
  170. package/cjs/schema/stream.cjs +0 -42
  171. package/cjs/schema/sugar/lock.cjs +0 -59
  172. package/cjs/schema/sugar/watch.cjs +0 -42
  173. package/cjs/schema/util.cjs +0 -39
  174. package/config.json +0 -5
  175. package/docs/compiler.png +0 -0
  176. package/dualmode.config.json +0 -11
  177. package/impl/bulk.d.mts +0 -11
  178. package/impl/bulk.d.mts.map +0 -1
  179. package/impl/bulk.mjs +0 -291
  180. package/impl/changes.d.mts +0 -12
  181. package/impl/changes.d.mts.map +0 -1
  182. package/impl/changes.mjs +0 -53
  183. package/impl/crud.d.mts +0 -7
  184. package/impl/crud.d.mts.map +0 -1
  185. package/impl/crud.mjs +0 -108
  186. package/impl/errors.d.mts +0 -43
  187. package/impl/errors.d.mts.map +0 -1
  188. package/impl/errors.mjs +0 -65
  189. package/impl/logger.d.mts +0 -32
  190. package/impl/logger.d.mts.map +0 -1
  191. package/impl/logger.mjs +0 -59
  192. package/impl/patch.d.mts +0 -6
  193. package/impl/patch.d.mts.map +0 -1
  194. package/impl/patch.mjs +0 -88
  195. package/impl/query.d.mts +0 -195
  196. package/impl/query.d.mts.map +0 -1
  197. package/impl/query.mjs +0 -122
  198. package/impl/queryBuilder.d.mts +0 -154
  199. package/impl/queryBuilder.d.mts.map +0 -1
  200. package/impl/queryBuilder.mjs +0 -175
  201. package/impl/retry.d.mts +0 -2
  202. package/impl/retry.d.mts.map +0 -1
  203. package/impl/retry.mjs +0 -39
  204. package/impl/stream.d.mts +0 -3
  205. package/impl/stream.d.mts.map +0 -1
  206. package/impl/stream.mjs +0 -98
  207. package/impl/sugar/lock.d.mts +0 -5
  208. package/impl/sugar/lock.d.mts.map +0 -1
  209. package/impl/sugar/lock.mjs +0 -70
  210. package/impl/sugar/watch.d.mts +0 -34
  211. package/impl/sugar/watch.d.mts.map +0 -1
  212. package/impl/trackedEmitter.d.mts +0 -8
  213. package/impl/trackedEmitter.d.mts.map +0 -1
  214. package/impl/transactionErrors.d.mts.map +0 -1
  215. package/impl/transactionErrors.mjs +0 -47
  216. package/impl/util.d.mts +0 -3
  217. package/impl/util.d.mts.map +0 -1
  218. package/impl/util.mjs +0 -35
  219. package/index.d.mts +0 -80
  220. package/index.d.mts.map +0 -1
  221. package/index.mjs +0 -141
  222. package/integration/changes.mjs +0 -60
  223. package/integration/disconnect-watch.mjs +0 -36
  224. package/integration/watch.mjs +0 -40
  225. package/schema/bind.d.mts +0 -5461
  226. package/schema/bind.d.mts.map +0 -1
  227. package/schema/bind.mjs +0 -43
  228. package/schema/bulk.d.mts +0 -923
  229. package/schema/bulk.d.mts.map +0 -1
  230. package/schema/bulk.mjs +0 -83
  231. package/schema/changes.d.mts +0 -191
  232. package/schema/changes.d.mts.map +0 -1
  233. package/schema/changes.mjs +0 -59
  234. package/schema/config.d.mts +0 -79
  235. package/schema/config.d.mts.map +0 -1
  236. package/schema/config.mjs +0 -26
  237. package/schema/crud.d.mts +0 -491
  238. package/schema/crud.d.mts.map +0 -1
  239. package/schema/crud.mjs +0 -64
  240. package/schema/patch.d.mts +0 -255
  241. package/schema/patch.d.mts.map +0 -1
  242. package/schema/patch.mjs +0 -42
  243. package/schema/query.d.mts +0 -406
  244. package/schema/query.d.mts.map +0 -1
  245. package/schema/query.mjs +0 -45
  246. package/schema/stream.d.mts +0 -211
  247. package/schema/stream.d.mts.map +0 -1
  248. package/schema/stream.mjs +0 -23
  249. package/schema/sugar/lock.d.mts +0 -238
  250. package/schema/sugar/lock.d.mts.map +0 -1
  251. package/schema/sugar/lock.mjs +0 -50
  252. package/schema/sugar/watch.d.mts +0 -127
  253. package/schema/sugar/watch.d.mts.map +0 -1
  254. package/schema/sugar/watch.mjs +0 -29
  255. package/schema/util.d.mts +0 -160
  256. package/schema/util.d.mts.map +0 -1
  257. package/schema/util.mjs +0 -35
  258. package/types/changes-stream.d.ts +0 -11
@@ -1,21 +1,23 @@
1
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
2
+ // @ts-nocheck
1
3
  import { EventEmitter } from 'events'
2
4
 
3
5
  export class TrackedEmitter extends EventEmitter {
4
6
  // create a constructor with some options
5
- constructor (options) {
7
+ constructor(options) {
6
8
  super(options)
7
9
  if (options.delay) this.delay = options.delay
8
10
  }
9
11
 
10
- emit (event, ...args) {
12
+ emit(event, ...args) {
11
13
  const listeners = this.listeners(event)
12
14
  let completed = 0
13
15
 
14
- return new Promise((resolve) => {
16
+ return new Promise(resolve => {
15
17
  if (!listeners || listeners.length === 0) {
16
18
  return resolve() // no listeners? no delay
17
19
  }
18
- listeners.forEach((listener) => {
20
+ listeners.forEach(listener => {
19
21
  listener(...args)
20
22
  completed++
21
23
  if (completed === listeners.length) {
@@ -27,7 +29,7 @@ export class TrackedEmitter extends EventEmitter {
27
29
  }
28
30
  }
29
31
 
30
- export const setupEmitter = (config) => {
31
- if (!config._emitter) return ({ emit: async () => {} })
32
- return config._emitter
32
+ export const setupEmitter = config => {
33
+ if (!config['~emitter']) return { emit: async () => {} }
34
+ return config['~emitter']
33
35
  }
@@ -0,0 +1,71 @@
1
+ export class TransactionSetupError extends Error {
2
+ details: Record<string, unknown>
3
+
4
+ constructor(message: string, details: Record<string, unknown> = {}) {
5
+ super(message)
6
+ this.name = 'TransactionSetupError'
7
+ this.details = details
8
+ }
9
+ }
10
+
11
+ export class TransactionVersionConflictError extends Error {
12
+ conflictingIds: string[]
13
+
14
+ constructor(conflictingIds: string[]) {
15
+ super(`Revision mismatch for documents: ${conflictingIds.join(', ')}`)
16
+ this.name = 'TransactionVersionConflictError'
17
+ this.conflictingIds = conflictingIds
18
+ }
19
+ }
20
+
21
+ export class TransactionBulkOperationError extends Error {
22
+ failedDocs: {
23
+ ok?: boolean | null
24
+ id?: string | null
25
+ rev?: string | null
26
+ error?: string | null
27
+ reason?: string | null
28
+ }[]
29
+
30
+ constructor(
31
+ failedDocs: Array<{
32
+ ok?: boolean | null
33
+ id?: string | null
34
+ rev?: string | null
35
+ error?: string | null
36
+ reason?: string | null
37
+ }>
38
+ ) {
39
+ super(`Failed to save documents: ${failedDocs.map(d => d.id).join(', ')}`)
40
+ this.name = 'TransactionBulkOperationError'
41
+ this.failedDocs = failedDocs
42
+ }
43
+ }
44
+
45
+ export class TransactionRollbackError extends Error {
46
+ originalError: Error
47
+ rollbackResults: {
48
+ ok?: boolean | null
49
+ id?: string | null
50
+ rev?: string | null
51
+ error?: string | null
52
+ reason?: string | null
53
+ }[]
54
+
55
+ constructor(
56
+ message: string,
57
+ originalError: Error,
58
+ rollbackResults: Array<{
59
+ ok?: boolean | null
60
+ id?: string | null
61
+ rev?: string | null
62
+ error?: string | null
63
+ reason?: string | null
64
+ }>
65
+ ) {
66
+ super(message)
67
+ this.name = 'TransactionRollbackError'
68
+ this.originalError = originalError
69
+ this.rollbackResults = rollbackResults
70
+ }
71
+ }
package/index.mts ADDED
@@ -0,0 +1,82 @@
1
+ import { createQuery } from './impl/utils/queryBuilder.mts'
2
+ import { QueryBuilder } from './impl/utils/queryBuilder.mts'
3
+ import { bindConfig } from './impl/bindConfig.mts'
4
+ import { withRetry } from './impl/retry.mts'
5
+ import { bulkGet, bulkGetDictionary } from './impl/bulkGet.mts'
6
+ import { getAtRev, get } from './impl/get.mts'
7
+ import { queryStream } from './impl/stream.mts'
8
+ import { patch, patchDangerously } from './impl/patch.mts'
9
+ import { put } from './impl/put.mts'
10
+ import { remove } from './impl/remove.mts'
11
+ import { bulkSave, bulkSaveTransaction } from './impl/bulkSave.mts'
12
+ import { query } from './impl/query.mts'
13
+ import { getDBInfo } from './impl/getDBInfo.mts'
14
+ import { bulkRemove, bulkRemoveMap } from './impl/bulkRemove.mts'
15
+ import { createLock, removeLock } from './impl/sugar/lock.mts'
16
+ import { watchDocs } from './impl/sugar/watch.mts'
17
+
18
+ export {
19
+ get,
20
+ getAtRev,
21
+ put,
22
+ remove,
23
+ bulkGet,
24
+ bulkSave,
25
+ query,
26
+ queryStream,
27
+ getDBInfo,
28
+
29
+ // sugar methods
30
+ patch,
31
+ patchDangerously,
32
+ bulkRemove,
33
+ bulkRemoveMap,
34
+ bulkGetDictionary,
35
+ bulkSaveTransaction,
36
+ watchDocs,
37
+
38
+ // binding
39
+ bindConfig,
40
+ withRetry,
41
+
42
+ // utils
43
+ QueryBuilder,
44
+ createQuery,
45
+ createLock,
46
+ removeLock
47
+ }
48
+
49
+ export type {
50
+ BulkGetBound,
51
+ BulkGetDictionaryBound,
52
+ BulkGetDictionaryOptions,
53
+ BulkGetDictionaryResult,
54
+ BulkGetOptions,
55
+ BulkGetResponse
56
+ } from './impl/bulkGet.mts'
57
+ export type { OnInvalidDocAction } from './impl/utils/parseRows.mts'
58
+ export type { GetOptions, GetBound, GetAtRevBound } from './impl/get.mts'
59
+ export type { QueryBound } from './impl/query.mts'
60
+ export type {
61
+ ViewString,
62
+ ViewOptions as SimpleViewOptions
63
+ } from './schema/couch/couch.input.schema.ts'
64
+ export type {
65
+ ViewRow,
66
+ CouchDoc,
67
+ CouchDocInput,
68
+ ViewQueryResponse,
69
+ ViewQueryResponseValidated,
70
+ ViewRowValidated
71
+ } from './schema/couch/couch.output.schema.ts'
72
+ export type { RetryOptions } from './impl/retry.mts'
73
+ export type { NetworkError, RetryableError, NotFoundError } from './impl/utils/errors.mts'
74
+ export type { OnRow } from './impl/stream.mts'
75
+ export type { CouchConfig, CouchConfigInput } from './schema/config.mts'
76
+ export type { LockOptions, LockOptionsInput, LockDoc } from './schema/sugar/lock.mts'
77
+ export type {
78
+ WatchOptions as WatchOptionsSchema,
79
+ WatchOptionsInput
80
+ } from './schema/sugar/watch.mts'
81
+ export type { BoundInstance } from './impl/bindConfig.mts'
82
+ export type { StandardSchemaV1 } from './types/standard-schema.ts'
@@ -0,0 +1,70 @@
1
+ # hide-a-bed v6 Migration Guide
2
+
3
+ ## When to read this
4
+
5
+ - Teams upgrading projects that currently depend on hide-a-bed v5.x.
6
+ - Consumers who maintain custom stubs or wrappers around the public APIs.
7
+ - Anyone who relied on the bundled `_changes` helper that shipped before v6.
8
+
9
+ ## Upgrade checklist
10
+
11
+ - Update hide-a-bed and, if you use the changed feed, install the companion `hide-a-bed-changes` package.
12
+ - Run `npm run build` and your existing integration tests against a CouchDB instance or the project stub.
13
+
14
+ ## Breaking changes
15
+
16
+ ### Config object will throw if passed unknown properties
17
+
18
+ - The `Config` constructor now validates its input and will throw if unknown properties are present.
19
+ - Review any custom config objects to ensure only supported properties are included.
20
+
21
+ ### Function errors changed
22
+
23
+ - Previously all functions were zod validated and would throw `ZodError` on invalid input or output.
24
+ - Functions are no longer zod validated by default, inputs and outputs are validated as needed but mostly types are enforced at compile time.
25
+ - If you relied on catching `ZodError`, you will need to adjust your error handling to accommodate the new error types thrown by the client.
26
+
27
+ ### View Query keys will be encoded by default
28
+
29
+ - Previously, users would have to call `encodeURIComponent` on keys passed to view queries that required encoding.
30
+ - Now, the client automatically encodes keys.
31
+ - If you previously encoded keys manually, you will need to decode them before passing to the query helpers to avoid double-encoding.
32
+
33
+ ### View Query paths types are more strict
34
+
35
+ - The path string passed to `query` will show a type error if it does not match the `ViewString` union.
36
+
37
+ ```ts
38
+ export type ViewString = '_all_docs' | `_design/${string}/_view/${string}`
39
+ ```
40
+
41
+ ### `_changes` feed split out of the core client
42
+
43
+ - The polling helper that wrapped `changes-stream` no longer ships inside the client bundle.
44
+ - Use the dedicated package shown in [changes/README.md](changes/README.md) to restore the previous feed behaviour.
45
+
46
+ ### Schema builder exports removed
47
+
48
+ - The legacy `schema.*` namespace is gone; internal Zod v4 Standard Schema assets stay private.
49
+ - Test doubles that previously used `schema.BulkSave.implementAsync` now need to migrate to the maintained stub package or copy the v5 schema layer.
50
+ - All runtime APIs still accept plain objects, while TypeScript users can import the inferred types exposed from [client/index.mts](client/index.mts) (for example `CouchDoc`, `ViewQueryResponse`).
51
+
52
+ ## Additional opt-in changes
53
+
54
+ ### Validation options
55
+
56
+ - Some doc and view queries now accept and optional `validate` option
57
+ - `bulkGet`, `bulkGetDictionary`, `query`, and `get` all can use and optional `options.validate.docSchema` and friends (see [client/impl/bulkGet.mts](client/impl/bulkGet.mts) and [client/impl/query.mts](client/impl/query.mts)).
58
+
59
+ ```ts
60
+ // v5 style
61
+ await bulkGet(config, ids)
62
+
63
+ // v6 style
64
+ await bulkGet(config, ids, {
65
+ validate: {
66
+ docSchema,
67
+ onInvalidDoc: 'skip'
68
+ }
69
+ })
70
+ ```
package/package.json CHANGED
@@ -1,23 +1,37 @@
1
1
  {
2
2
  "name": "hide-a-bed",
3
- "version": "5.2.8",
3
+ "version": "6.0.0",
4
4
  "description": "An abstraction over couchdb calls that includes easy mock/stubs with pouchdb",
5
- "module": "index.mjs",
6
- "main": "cjs/index.cjs",
7
5
  "type": "module",
8
- "types": "index.d.mts",
6
+ "main": "./dist/cjs/index.cjs",
7
+ "module": "./dist/esm/index.mjs",
8
+ "types": "./types/output/index.d.mts",
9
9
  "exports": {
10
- "require": "./cjs/index.cjs",
11
- "import": "./index.mjs",
12
- "default": "./cjs/index.cjs"
10
+ "default": "./dist/cjs/index.cjs",
11
+ "types": "./types/output/index.d.mts",
12
+ "require": {
13
+ "types": "./types/output/index.d.mts",
14
+ "default": "./dist/cjs/index.cjs"
15
+ },
16
+ "import": {
17
+ "types": "./types/output/index.d.mts",
18
+ "default": "./dist/esm/index.mjs"
19
+ }
13
20
  },
14
21
  "scripts": {
15
- "clean": "rm -rf cjs && (find . -name \"*.mts\" -type f -delete || true) && (find . -name \"*.map\" -type f -delete || true) && (find . -name \"log.txt\" -type f -delete || true)",
16
- "build": "npm run clean && tsc && npx -p dualmode@latest build",
17
- "build:cjs": "rm -rf cjs && node build/build.mjs",
18
- "test": "node tests/*.mjs",
19
- "lint:fix": "standard --fix",
20
- "prepublish": "npm run build",
22
+ "clean": "rm -rf types/output && rm -rf dist && (find . -name \"log.txt\" -type f -delete || true)",
23
+ "build": "npm run clean && tsc && tsdown",
24
+ "build:docs": "typedoc ./index.mts",
25
+ "dev": "typedoc --watch ./index.mts & npx -y serve ./docs",
26
+ "test": "node --test --test-global-setup ./test/setup.mts",
27
+ "test:watch": "node --test --watch --test-global-setup ./test/setup.mts",
28
+ "lint": "eslint .",
29
+ "lint:fix": "eslint . --fix",
30
+ "format": "prettier --write .",
31
+ "format:check": "prettier --check .",
32
+ "typecheck": "tsc --noEmit",
33
+ "typecheck:watch": "tsc --noEmit --watch",
34
+ "prepublishOnly": "npm run build",
21
35
  "full": "npm run lint:fix && npm run build && npm run clean"
22
36
  },
23
37
  "repository": {
@@ -35,27 +49,30 @@
35
49
  },
36
50
  "homepage": "https://github.com/ryanramage/hide-a-bed#readme",
37
51
  "dependencies": {
38
- "changes-stream": "^2.2.0",
39
- "JSONStream": "^1.3.5",
40
- "lodash": "^4.17.21",
41
- "needle": "^3.2.0",
42
- "zod": "^3.22.4"
52
+ "needle": "3.3.1",
53
+ "stream-chain": "3.4.0",
54
+ "stream-json": "1.9.1",
55
+ "zod": "4.2.1"
43
56
  },
44
57
  "devDependencies": {
45
- "@types/lodash": "^4.17.15",
46
- "@types/needle": "^3.3.0",
47
- "esbuild": "^0.24.2",
48
- "glob": "^11.0.0",
49
- "install": "^0.13.0",
50
- "npm": "^11.1.0",
51
- "pouchdb-server": "^4.2.0",
52
- "standard": "17.1.0",
53
- "tap": "^21.0.2",
54
- "tape": "5.8.1",
55
- "typescript": "5.6.2"
58
+ "@eslint/js": "9.39.2",
59
+ "@types/needle": "3.3.0",
60
+ "@types/node": "22.19.3",
61
+ "@types/stream-json": "1.7.8",
62
+ "eslint": "9.39.2",
63
+ "globals": "16.5.0",
64
+ "pouchdb-server": "4.2.0",
65
+ "prettier": "3.7.4",
66
+ "tsdown": "0.18.1",
67
+ "typedoc": "0.28.15",
68
+ "typescript": "5.9.3",
69
+ "typescript-eslint": "8.50.1"
70
+ },
71
+ "publishConfig": {
72
+ "registry": "https://registry.npmjs.org/"
56
73
  },
57
74
  "volta": {
58
- "node": "20.17.0",
59
- "npm": "10.8.2"
75
+ "node": "24.12.0",
76
+ "npm": "11.6.2"
60
77
  }
61
- }
78
+ }
@@ -0,0 +1,81 @@
1
+ import { z } from 'zod'
2
+ import type { StandardSchemaV1 } from '../types/standard-schema.ts'
3
+
4
+ const anyArgs = z.array(z.any())
5
+
6
+ const LoggerSchema = z
7
+ .object({
8
+ error: z.function({ input: anyArgs, output: z.void() }).optional(),
9
+ warn: z.function({ input: anyArgs, output: z.void() }).optional(),
10
+ info: z.function({ input: anyArgs, output: z.void() }).optional(),
11
+ debug: z.function({ input: anyArgs, output: z.void() }).optional()
12
+ })
13
+ .or(z.function({ input: anyArgs, output: z.void() }))
14
+
15
+ export const NeedleBaseOptions = z.object({
16
+ json: z.boolean(),
17
+ headers: z.record(z.string(), z.string()),
18
+ parse_response: z.boolean().optional()
19
+ })
20
+ export type NeedleBaseOptionsSchema = z.infer<typeof NeedleBaseOptions>
21
+
22
+ export const NeedleOptions = z.object({
23
+ json: z.boolean().optional(),
24
+ compressed: z.boolean().optional(),
25
+ follow_max: z.number().optional(),
26
+ follow_set_cookie: z.boolean().optional(),
27
+ follow_set_referer: z.boolean().optional(),
28
+ follow: z.number().optional(),
29
+ timeout: z.number().optional(),
30
+ read_timeout: z.number().optional(),
31
+ parse_response: z.boolean().optional(),
32
+ decode: z.boolean().optional(),
33
+ parse_cookies: z.boolean().optional(),
34
+ cookies: z.record(z.string(), z.string()).optional(),
35
+ headers: z.record(z.string(), z.string()).optional(),
36
+ auth: z.enum(['auto', 'digest', 'basic']).optional(),
37
+ username: z.string().optional(),
38
+ password: z.string().optional(),
39
+ proxy: z.string().optional(),
40
+ agent: z.any().optional(),
41
+ rejectUnauthorized: z.boolean().optional(),
42
+ output: z.string().optional(),
43
+ parse: z.boolean().optional(),
44
+ multipart: z.boolean().optional(),
45
+ open_timeout: z.number().optional(),
46
+ response_timeout: z.number().optional(),
47
+ keepAlive: z.boolean().optional()
48
+ })
49
+
50
+ export const CouchConfig = z
51
+ .strictObject({
52
+ backoffFactor: z.number().optional().default(2).describe('multiplier for exponential backoff'),
53
+ bindWithRetry: z.boolean().optional().default(true).describe('should we bind with retry'),
54
+ couch: z.string().describe('the url of the couch db'),
55
+ initialDelay: z
56
+ .number()
57
+ .optional()
58
+ .default(1000)
59
+ .describe('initial retry delay in milliseconds'),
60
+ logger: LoggerSchema.optional().describe(
61
+ 'logging interface supporting winston-like or simple function interface'
62
+ ),
63
+ maxRetries: z.number().optional().default(3).describe('maximum number of retry attempts'),
64
+ needleOpts: NeedleOptions.optional(),
65
+ throwOnGetNotFound: z
66
+ .boolean()
67
+ .optional()
68
+ .default(false)
69
+ .describe('if a get is 404 should we throw or return undefined'),
70
+ useConsoleLogger: z
71
+ .boolean()
72
+ .optional()
73
+ .default(false)
74
+ .describe('turn on console as a fallback logger'),
75
+ '~emitter': z.any().optional().describe('emitter for events'),
76
+ '~normalizedLogger': z.any().optional() // Internal property for caching normalized logger
77
+ })
78
+ .describe('The std config object')
79
+
80
+ export type CouchConfig = StandardSchemaV1.InferOutput<typeof CouchConfig>
81
+ export type CouchConfigInput = StandardSchemaV1.InferInput<typeof CouchConfig>
@@ -0,0 +1,43 @@
1
+ import z from 'zod'
2
+ import type { StandardSchemaV1 } from '../../types/standard-schema.ts'
3
+
4
+ export type ViewString = '_all_docs' | `_design/${string}/_view/${string}`
5
+
6
+ export const ViewOptions = z
7
+ .object({
8
+ descending: z.boolean().optional().describe('sort results descending'),
9
+ endkey_docid: z
10
+ .string()
11
+ .optional()
12
+ .describe('stop returning records when this document ID is reached'),
13
+ endkey: z.any().optional(),
14
+ group_level: z.number().positive().optional().describe('group the results at this level'),
15
+ group: z.boolean().optional().describe('group the results'),
16
+ include_docs: z.boolean().optional().describe('join the id to the doc and return it'),
17
+ inclusive_end: z
18
+ .boolean()
19
+ .optional()
20
+ .describe('whether the endkey is included in the result, default true'),
21
+ key: z.any().optional(),
22
+ keys: z.array(z.any()).optional(),
23
+ limit: z.number().nonnegative().optional().describe('limit the results to this many rows'),
24
+ reduce: z.boolean().optional().describe('reduce the results'),
25
+ skip: z.number().nonnegative().optional().describe('skip this many rows'),
26
+ sorted: z.boolean().optional().describe('sort returned rows, default true'),
27
+ stable: z
28
+ .boolean()
29
+ .optional()
30
+ .describe('ensure the view index is not updated during the query, default false'),
31
+ startkey: z.any().optional(),
32
+ startkey_docid: z
33
+ .string()
34
+ .optional()
35
+ .describe('start returning records when this document ID is reached'),
36
+ update: z
37
+ .enum(['true', 'false', 'lazy'])
38
+ .optional()
39
+ .describe('whether to update the view index before returning results, default true'),
40
+ update_seq: z.boolean().optional().describe('include the update sequence in the result')
41
+ })
42
+ .describe('base options for a CouchDB view query')
43
+ export type ViewOptions = StandardSchemaV1.InferOutput<typeof ViewOptions>
@@ -0,0 +1,169 @@
1
+ import { z } from 'zod'
2
+ import type { StandardSchemaV1 } from '../../types/standard-schema.ts'
3
+
4
+ /**
5
+ * Default schema for a returned CouchDB document if no validation schema is provided.
6
+ */
7
+ export const CouchDoc = z.looseObject({
8
+ _id: z.string().describe('the couch doc id'),
9
+ _rev: z.string().optional().nullish().describe('the doc revision'),
10
+ _deleted: z.boolean().optional().describe('is the doc deleted')
11
+ })
12
+ export type CouchDoc = StandardSchemaV1.InferOutput<typeof CouchDoc>
13
+
14
+ /**
15
+ * A type for input CouchDB documents (without required _id).
16
+ */
17
+ export type CouchDocInput = Omit<CouchDoc, '_id'> & { _id?: string }
18
+
19
+ /**
20
+ * Default schema for a CouchDB view row if no validation schema is provided.
21
+ */
22
+ export const ViewRow = z.object({
23
+ id: z.string().optional(),
24
+ key: z.any().nullish(),
25
+ value: z.any().nullish(),
26
+ doc: CouchDoc.nullish(),
27
+ error: z.string().optional().describe('usually not_found, if something is wrong with this doc')
28
+ })
29
+ export type ViewRow = StandardSchemaV1.InferOutput<typeof ViewRow>
30
+
31
+ /**
32
+ * A CouchDB view row with validated key, value, and document schemas.
33
+ */
34
+ export type ViewRowValidated<
35
+ DocSchema extends StandardSchemaV1,
36
+ KeySchema extends StandardSchemaV1,
37
+ ValueSchema extends StandardSchemaV1
38
+ > = {
39
+ id?: string
40
+ key?: StandardSchemaV1.InferOutput<KeySchema>
41
+ value?: StandardSchemaV1.InferOutput<ValueSchema>
42
+ doc?: StandardSchemaV1.InferOutput<DocSchema>
43
+ error?: string
44
+ }
45
+
46
+ /**
47
+ * Response type for a CouchDB view query if no validation schemas are provided.
48
+ */
49
+ export const ViewQueryResponse = z.object({
50
+ total_rows: z.number().nonnegative().optional().describe('total rows in the view'),
51
+ offset: z
52
+ .number()
53
+ .nonnegative()
54
+ .optional()
55
+ .describe('the offset of the first row in this result set'),
56
+ error: z.string().optional().describe('if something is wrong'),
57
+ rows: z.array(ViewRow).optional().describe('the rows returned by the view'),
58
+ update_seq: z
59
+ .number()
60
+ .optional()
61
+ .describe('the update sequence of the database at the time of the query')
62
+ })
63
+ export type ViewQueryResponse = StandardSchemaV1.InferOutput<typeof ViewQueryResponse>
64
+
65
+ /**
66
+ * Response type for a CouchDB view query with validated key, value, and document schemas.
67
+ */
68
+ export type ViewQueryResponseValidated<
69
+ DocSchema extends StandardSchemaV1,
70
+ KeySchema extends StandardSchemaV1 = StandardSchemaV1<unknown>,
71
+ ValueSchema extends StandardSchemaV1 = StandardSchemaV1<unknown>
72
+ > = Omit<ViewQueryResponse, 'rows'> & {
73
+ rows: Array<ViewRowValidated<DocSchema, KeySchema, ValueSchema>>
74
+ }
75
+
76
+ /**
77
+ * CouchDB _bulk_docs response schema
78
+ */
79
+ export const BulkSaveResponse = z.array(
80
+ z.object({
81
+ ok: z.boolean().nullish(),
82
+ id: z.string().nullish(),
83
+ rev: z.string().nullish(),
84
+ error: z.string().nullish().describe('if an error occurred, one word reason, eg conflict'),
85
+ reason: z.string().nullish().describe('a full error message')
86
+ })
87
+ )
88
+ export type BulkSaveResponse = z.infer<typeof BulkSaveResponse>
89
+
90
+ export const CouchPutResponse = z.object({
91
+ ok: z.boolean().optional().describe('did the request succeed'),
92
+ error: z.string().optional().describe('the error message, if did not succeed'),
93
+ statusCode: z.number(),
94
+ id: z.string().optional().describe('the couch doc id'),
95
+ rev: z.string().optional().describe('the new rev of the doc')
96
+ })
97
+
98
+ export const CouchDBInfo = z.looseObject({
99
+ cluster: z
100
+ .object({
101
+ n: z.number().describe('Replicas. The number of copies of every document.').optional(),
102
+ q: z.number().describe('Shards. The number of range partitions.').optional(),
103
+ r: z
104
+ .number()
105
+ .describe(
106
+ 'Read quorum. The number of consistent copies of a document that need to be read before a successful reply.'
107
+ )
108
+ .optional(),
109
+ w: z
110
+ .number()
111
+ .describe(
112
+ 'Write quorum. The number of copies of a document that need to be written before a successful reply.'
113
+ )
114
+ .optional()
115
+ })
116
+ .optional(),
117
+ compact_running: z
118
+ .boolean()
119
+ .describe('Set to true if the database compaction routine is operating on this database.')
120
+ .optional(),
121
+ db_name: z.string().describe('The name of the database.'),
122
+ disk_format_version: z
123
+ .number()
124
+ .describe('The version of the physical format used for the data when it is stored on disk.')
125
+ .optional(),
126
+ doc_count: z.number().describe('A count of the documents in the specified database.').optional(),
127
+ doc_del_count: z.number().describe('Number of deleted documents').optional(),
128
+ instance_start_time: z.string().optional(),
129
+ purge_seq: z
130
+ .string()
131
+ .describe(
132
+ 'An opaque string that describes the purge state of the database. Do not rely on this string for counting the number of purge operations.'
133
+ )
134
+ .optional(),
135
+ sizes: z
136
+ .object({
137
+ active: z
138
+ .number()
139
+ .describe('The size of live data inside the database, in bytes.')
140
+ .optional(),
141
+ external: z
142
+ .number()
143
+ .describe('The uncompressed size of database contents in bytes.')
144
+ .optional(),
145
+ file: z
146
+ .number()
147
+ .describe(
148
+ 'The size of the database file on disk in bytes. Views indexes are not included in the calculation.'
149
+ )
150
+ .optional()
151
+ })
152
+ .optional(),
153
+ update_seq: z
154
+ .string()
155
+ .or(z.number())
156
+ .describe(
157
+ 'An opaque string that describes the state of the database. Do not rely on this string for counting the number of updates.'
158
+ )
159
+ .optional(),
160
+ props: z
161
+ .object({
162
+ partitioned: z
163
+ .boolean()
164
+ .describe('If present and true, this indicates that the database is partitioned.')
165
+ .optional()
166
+ })
167
+ .optional()
168
+ })
169
+ export type CouchDBInfo = z.infer<typeof CouchDBInfo>
@@ -0,0 +1,18 @@
1
+ import { z } from 'zod'
2
+ import { CouchDoc } from '../couch/couch.output.schema.ts'
3
+ import type { StandardSchemaV1 } from '../../types/standard-schema.ts'
4
+
5
+ export const LockDoc = CouchDoc.extend({
6
+ type: z.literal('lock'),
7
+ locks: z.string().describe('the document ID being locked'),
8
+ lockedAt: z.string().describe('ISO timestamp when lock was created'),
9
+ lockedBy: z.string().describe('username of who created the lock')
10
+ })
11
+ export type LockDoc = StandardSchemaV1.InferOutput<typeof LockDoc>
12
+
13
+ export const LockOptions = z.object({
14
+ enableLocking: z.boolean().prefault(true).describe('whether locking is enabled'),
15
+ username: z.string().describe('username to attribute locks to')
16
+ })
17
+ export type LockOptions = StandardSchemaV1.InferOutput<typeof LockOptions>
18
+ export type LockOptionsInput = StandardSchemaV1.InferInput<typeof LockOptions>