hide-a-bed 6.0.0 → 7.0.0-beta.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 (100) hide show
  1. package/README.md +89 -28
  2. package/dist/cjs/index.cjs +888 -443
  3. package/dist/esm/index.mjs +883 -443
  4. package/eslint.config.js +6 -1
  5. package/impl/bindConfig.mts +30 -3
  6. package/impl/bulkGet.mts +50 -27
  7. package/impl/bulkRemove.mts +4 -2
  8. package/impl/bulkSave.mts +50 -28
  9. package/impl/get.mts +49 -40
  10. package/impl/getDBInfo.mts +26 -24
  11. package/impl/patch.mts +46 -42
  12. package/impl/put.mts +39 -21
  13. package/impl/query.mts +101 -81
  14. package/impl/remove.mts +33 -33
  15. package/impl/stream.mts +163 -102
  16. package/impl/sugar/watch.mts +165 -97
  17. package/impl/utils/errors.mts +261 -35
  18. package/impl/utils/fetch.mts +201 -0
  19. package/impl/utils/parseRows.mts +47 -6
  20. package/impl/utils/request.mts +22 -0
  21. package/impl/utils/response.mts +50 -0
  22. package/impl/utils/transactionErrors.mts +14 -8
  23. package/impl/utils/url.mts +21 -0
  24. package/index.mts +19 -2
  25. package/migration_guides/v7.md +353 -0
  26. package/package.json +4 -4
  27. package/schema/config.mts +17 -34
  28. package/schema/request.mts +36 -0
  29. package/schema/sugar/watch.mts +1 -1
  30. package/tsconfig.json +9 -1
  31. package/types/output/impl/bindConfig.d.mts +31 -149
  32. package/types/output/impl/bindConfig.d.mts.map +1 -1
  33. package/types/output/impl/bindConfig.test.d.mts +2 -0
  34. package/types/output/impl/bindConfig.test.d.mts.map +1 -0
  35. package/types/output/impl/bulkGet.d.mts +5 -5
  36. package/types/output/impl/bulkGet.d.mts.map +1 -1
  37. package/types/output/impl/bulkRemove.d.mts +4 -2
  38. package/types/output/impl/bulkRemove.d.mts.map +1 -1
  39. package/types/output/impl/bulkSave.d.mts +2 -2
  40. package/types/output/impl/bulkSave.d.mts.map +1 -1
  41. package/types/output/impl/get.d.mts +2 -2
  42. package/types/output/impl/get.d.mts.map +1 -1
  43. package/types/output/impl/getDBInfo.d.mts +1 -1
  44. package/types/output/impl/getDBInfo.d.mts.map +1 -1
  45. package/types/output/impl/patch.d.mts +8 -3
  46. package/types/output/impl/patch.d.mts.map +1 -1
  47. package/types/output/impl/put.d.mts.map +1 -1
  48. package/types/output/impl/query.d.mts +8 -23
  49. package/types/output/impl/query.d.mts.map +1 -1
  50. package/types/output/impl/remove.d.mts.map +1 -1
  51. package/types/output/impl/request-controls.test.d.mts +2 -0
  52. package/types/output/impl/request-controls.test.d.mts.map +1 -0
  53. package/types/output/impl/stream.d.mts +1 -1
  54. package/types/output/impl/stream.d.mts.map +1 -1
  55. package/types/output/impl/sugar/watch.d.mts +7 -5
  56. package/types/output/impl/sugar/watch.d.mts.map +1 -1
  57. package/types/output/impl/utils/errors.d.mts +84 -26
  58. package/types/output/impl/utils/errors.d.mts.map +1 -1
  59. package/types/output/impl/utils/fetch.d.mts +27 -0
  60. package/types/output/impl/utils/fetch.d.mts.map +1 -0
  61. package/types/output/impl/utils/fetch.test.d.mts +2 -0
  62. package/types/output/impl/utils/fetch.test.d.mts.map +1 -0
  63. package/types/output/impl/utils/parseRows.d.mts +3 -0
  64. package/types/output/impl/utils/parseRows.d.mts.map +1 -1
  65. package/types/output/impl/utils/request.d.mts +6 -0
  66. package/types/output/impl/utils/request.d.mts.map +1 -0
  67. package/types/output/impl/utils/response.d.mts +7 -0
  68. package/types/output/impl/utils/response.d.mts.map +1 -0
  69. package/types/output/impl/utils/response.test.d.mts +2 -0
  70. package/types/output/impl/utils/response.test.d.mts.map +1 -0
  71. package/types/output/impl/utils/trackedEmitter.test.d.mts +2 -0
  72. package/types/output/impl/utils/trackedEmitter.test.d.mts.map +1 -0
  73. package/types/output/impl/utils/transactionErrors.d.mts +5 -4
  74. package/types/output/impl/utils/transactionErrors.d.mts.map +1 -1
  75. package/types/output/impl/utils/transactionErrors.test.d.mts +2 -0
  76. package/types/output/impl/utils/transactionErrors.test.d.mts.map +1 -0
  77. package/types/output/impl/utils/url.d.mts +4 -0
  78. package/types/output/impl/utils/url.d.mts.map +1 -0
  79. package/types/output/impl/utils/url.test.d.mts +2 -0
  80. package/types/output/impl/utils/url.test.d.mts.map +1 -0
  81. package/types/output/index.d.mts +5 -2
  82. package/types/output/index.d.mts.map +1 -1
  83. package/types/output/schema/config.d.mts +13 -69
  84. package/types/output/schema/config.d.mts.map +1 -1
  85. package/types/output/schema/config.test.d.mts +2 -0
  86. package/types/output/schema/config.test.d.mts.map +1 -0
  87. package/types/output/schema/request.d.mts +10 -0
  88. package/types/output/schema/request.d.mts.map +1 -0
  89. package/types/output/schema/sugar/lock.test.d.mts +2 -0
  90. package/types/output/schema/sugar/lock.test.d.mts.map +1 -0
  91. package/types/output/schema/sugar/watch.d.mts +1 -1
  92. package/types/output/schema/sugar/watch.d.mts.map +1 -1
  93. package/types/output/schema/sugar/watch.test.d.mts +2 -0
  94. package/types/output/schema/sugar/watch.test.d.mts.map +1 -0
  95. package/impl/utils/mergeNeedleOpts.mts +0 -16
  96. package/schema/util.mts +0 -8
  97. package/types/output/impl/utils/mergeNeedleOpts.d.mts +0 -53
  98. package/types/output/impl/utils/mergeNeedleOpts.d.mts.map +0 -1
  99. package/types/output/schema/util.d.mts +0 -85
  100. package/types/output/schema/util.d.mts.map +0 -1
package/README.md CHANGED
@@ -18,6 +18,11 @@ And some utility APIs
18
18
  - [`createQuery()`](#createquery) 🍭
19
19
  - [`withRetry()`](#withretry)
20
20
 
21
+ ### Migration Guides
22
+
23
+ - [v6 Migration Guide](./migration_guides/v6.md)
24
+ - [v7 Migration Guide](./migration_guides/v7.md)
25
+
21
26
  ### Setup
22
27
 
23
28
  Depending on your environment, use import or require
@@ -35,10 +40,35 @@ const { get, put, query } = require('hide-a-bed')
35
40
  ### Config
36
41
 
37
42
  Anywhere you see a config, it is an object with the following setup
38
- `{ couch: 'https://username:pass@the.couch.url.com:5984' }`
43
+ `{ couch: 'https://the.couch.url.com:5984' }`
39
44
  And it is passed in as the first argument of all the functions
40
45
  `const doc = await get(config, 'doc-123')`
41
46
 
47
+ If your CouchDB requires basic auth, pass `auth` on the config:
48
+
49
+ ```javascript
50
+ const config = {
51
+ couch: 'https://the.couch.url.com:5984/mydb',
52
+ auth: {
53
+ username: process.env.COUCHDB_USER,
54
+ password: process.env.COUCHDB_PASSWORD
55
+ }
56
+ }
57
+ ```
58
+
59
+ You can also set default request controls on the config:
60
+
61
+ ```javascript
62
+ const config = {
63
+ couch: 'https://the.couch.url.com:5984/mydb',
64
+ request: {
65
+ timeout: 5000,
66
+ signal: abortController.signal,
67
+ dispatcher
68
+ }
69
+ }
70
+ ```
71
+
42
72
  See [Advanced Config Options](#advanced-config-options) for more advanced settings.
43
73
 
44
74
  #### bindConfig
@@ -78,24 +108,25 @@ Get a single document by ID.
78
108
  - `couch` URL string
79
109
  - `throwOnGetNotFound` default false. If true, 404 docs throw
80
110
  - `id`: Document ID string
81
- - Returns: Promise resolving to document object or null if not found
111
+ - `options`: Optional object with `validate`
112
+ - Returns: Promise resolving to the document object, or `null` when the document does not exist and `throwOnGetNotFound` is false
113
+ - Throws: `NotFoundError` when the document does not exist and `throwOnGetNotFound` is true
82
114
 
83
115
  ```javascript
84
116
  const config = { couch: 'http://localhost:5984/mydb' }
85
117
  const doc = await get(config, 'doc-123')
86
118
  console.log(doc._id, doc._rev)
87
119
 
88
- const notFound = await get(config, 'notFound')
89
- console.log(notFound) // null
120
+ const missing = await get(config, 'notFound')
121
+ console.log(missing) // null
90
122
 
91
123
  try {
92
- const config = {
93
- couch: 'http://localhost:5984/mydb',
94
- throwOnGetNotFound: true
95
- }
96
- await get(config, 'notFound')
124
+ await get({ ...config, throwOnGetNotFound: true }, 'notFound')
97
125
  } catch (err) {
98
- if (err.name === 'NotFoundError') console.log('Document not found')
126
+ if (err.name === 'NotFoundError') {
127
+ console.log(err.statusCode) // 404
128
+ console.log(err.docId) // notFound
129
+ }
99
130
  }
100
131
  ```
101
132
 
@@ -108,6 +139,7 @@ Save a document.
108
139
  - `config`: Object with `couch` URL string
109
140
  - `doc`: Document object with `_id` property
110
141
  - Returns: Promise resolving to response with `ok`, `id`, `rev` properties, eg: { ok: boolean, id: string, rev: string }
142
+ - Throws: `ConflictError` when CouchDB returns a 409 for a single-document write
111
143
 
112
144
  ```javascript
113
145
  const config = { couch: 'http://localhost:5984/mydb' }
@@ -119,10 +151,14 @@ const doc = {
119
151
  const result = await put(config, doc)
120
152
  // result: { ok: true, id: 'doc-123', rev: '1-abc123' }
121
153
 
122
- // imaginary rev returns a conflict
123
- const doc = { _id: 'notThereDoc', _rev: '32-does-not-compute' }
124
- const result2 = await db.put(doc)
125
- console.log(result2) // { ok: false, error: 'conflict', statusCode: 409 }
154
+ try {
155
+ await put(config, { _id: 'notThereDoc', _rev: '32-does-not-compute' })
156
+ } catch (err) {
157
+ if (err.name === 'ConflictError') {
158
+ console.log(err.statusCode) // 409
159
+ console.log(err.docId) // notThereDoc
160
+ }
161
+ }
126
162
  ```
127
163
 
128
164
  #### patch
@@ -312,6 +348,7 @@ Delete multiple documents in one request.
312
348
  - `config`: Object with `couch` URL string
313
349
  - `ids`: Array of document ID strings to delete
314
350
  - Returns: Promise resolving to array of results with `ok`, `id`, `rev` for each deletion
351
+ - Throws: `RetryableError` or `OperationError` only for request-level failures. Missing documents remain item-level outcomes.
315
352
 
316
353
  ```javascript
317
354
  const config = { couch: 'http://localhost:5984/mydb' }
@@ -334,13 +371,14 @@ Allows more efficient deletion of document by providing only id and rev. This is
334
371
  - `config`: Object with `couch` URL string
335
372
  - `id`: document ID to delete
336
373
  - `rev`: rev of the document to delete
337
- - Returns: Promise resolving to array of results with `ok`, `id`, `rev` for the deletion
374
+ - Returns: Promise resolving to the deletion result with `ok`, `id`, `rev`
375
+ - Throws: `NotFoundError` when the document does not exist
338
376
 
339
377
  ```javascript
340
378
  const config = { couch: 'http://localhost:5984/mydb' }
341
379
  const id = 'doc1'
342
380
  const rev = '2-ghi789'
343
- const results = await remove(config, id, rev)
381
+ const result = await remove(config, id, rev)
344
382
  // result:
345
383
  // { ok: true, id: 'doc1', rev: '2-ghi789' }
346
384
  ```
@@ -354,6 +392,7 @@ Delete multiple documents in one request. Same inputs and outputs as [bulkRemove
354
392
  - `config`: Object with `couch` URL string
355
393
  - `ids`: Array of document ID strings to delete
356
394
  - Returns: Promise resolving to array of results with `ok`, `id`, `rev` for each deletion
395
+ - Throws: `RetryableError` or `OperationError` only for request-level failures while deleting an item. Missing or otherwise unremovable items are skipped.
357
396
 
358
397
  ```javascript
359
398
  const config = { couch: 'http://localhost:5984/mydb' }
@@ -471,7 +510,10 @@ Get basic info about a db in couch
471
510
 
472
511
  ```
473
512
  const config = { couch: 'http://localhost:5984/mydb' }
474
- const result = await getDBInfo(config)
513
+ const result = await getDBInfo({
514
+ ...config,
515
+ request: { timeout: 2000 }
516
+ })
475
517
  // result: { db_name: 'test', doc_count: 3232 }
476
518
  ```
477
519
 
@@ -632,7 +674,7 @@ feed.on('error', console.error)
632
674
  feed.stop()
633
675
  ```
634
676
 
635
- `hide-a-bed-changes` reuses the same config structure, merges `config.needleOpts`, and resolves `since: 'now'` to the current `update_seq` before starting the feed.
677
+ `hide-a-bed-changes` reuses the same config structure and resolves `since: 'now'` to the current `update_seq` before starting the feed.
636
678
 
637
679
  #### watchDocs ()
638
680
 
@@ -649,6 +691,8 @@ Watch specific documents for changes in real-time.
649
691
  - `initialDelay`: Number - initial reconnection delay in ms (default 1000)
650
692
  - `maxDelay`: Number - maximum reconnection delay in ms (default: 30000)
651
693
 
694
+ Request controls for `watchDocs()` come from `config.request`. Aborting `config.request.signal` stops the watcher.
695
+
652
696
  Returns an EventEmitter that emits:
653
697
 
654
698
  - 'change' events with change objects.
@@ -700,22 +744,31 @@ The watchDocs feed is useful for:
700
744
 
701
745
  The config object supports the following properties:
702
746
 
703
- | Property | Type | Default | Description |
704
- | ------------------ | --------------- | --------- | ----------------------------------------------------------------------- |
705
- | couch | string | required | The URL of the CouchDB database |
706
- | throwOnGetNotFound | boolean | false | If true, throws an error when get() returns 404. If false, returns null |
707
- | bindWithRetry | boolean | true | When using bindConfig(), adds retry logic to bound methods |
708
- | maxRetries | number | 3 | Maximum number of retry attempts for retryable operations |
709
- | initialDelay | number | 1000 | Initial delay in milliseconds before first retry |
710
- | backoffFactor | number | 2 | Multiplier for exponential backoff between retries |
711
- | useConsoleLogger | boolean | false | If true, enables console logging when no logger is provided |
712
- | logger | object/function | undefined | Custom logging interface (winston-style object or function) |
747
+ | Property | Type | Default | Description |
748
+ | ------------------ | --------------- | --------- | -------------------------------------------------------------------------------- |
749
+ | couch | string | required | The URL of the CouchDB database |
750
+ | auth | object | undefined | Basic auth credentials for CouchDB requests |
751
+ | request | object | undefined | Default request controls: `signal`, `timeout`, and `dispatcher` |
752
+ | throwOnGetNotFound | boolean | false | If true, `get()` throws `NotFoundError` on 404. If false, `get()` returns `null` |
753
+ | bindWithRetry | boolean | true | When using bindConfig(), adds retry logic to bound methods |
754
+ | maxRetries | number | 3 | Maximum number of retry attempts for retryable operations |
755
+ | initialDelay | number | 1000 | Initial delay in milliseconds before first retry |
756
+ | backoffFactor | number | 2 | Multiplier for exponential backoff between retries |
757
+ | useConsoleLogger | boolean | false | If true, enables console logging when no logger is provided |
758
+ | logger | object/function | undefined | Custom logging interface (winston-style object or function) |
713
759
 
714
760
  Example configuration with all options:
715
761
 
716
762
  ```javascript
717
763
  const config = {
718
764
  couch: 'http://localhost:5984/mydb',
765
+ auth: {
766
+ username: process.env.COUCHDB_USER,
767
+ password: process.env.COUCHDB_PASSWORD
768
+ },
769
+ request: {
770
+ timeout: 5000
771
+ },
719
772
  throwOnGetNotFound: true,
720
773
  bindWithRetry: true,
721
774
  maxRetries: 5,
@@ -726,6 +779,14 @@ const config = {
726
779
  }
727
780
  ```
728
781
 
782
+ ### Migration Note
783
+
784
+ `needleOpts` has been removed from the main `client` package. If you were passing transport-specific `needle` options through `config.needleOpts`, remove that configuration when upgrading. If you used `needleOpts.username` or `needleOpts.password`, move them to `config.auth.username` and `config.auth.password`. Couch URLs with embedded credentials are no longer supported and will fail validation. The package now uses native `fetch` internally and only supports the documented top-level config fields above.
785
+
786
+ Native request controls now live under `config.request`. This surface intentionally only supports `signal`, `timeout`, and `dispatcher`.
787
+
788
+ Single-document APIs now throw typed errors for non-success outcomes. Use `NotFoundError`, `ConflictError`, `RetryableError`, and `OperationError` for control flow, and rely on `statusCode`, `docId`, and `couchError` instead of parsing `.message`. Bulk APIs still return per-item result payloads for partial success and failure.
789
+
729
790
  ### Logging Support
730
791
 
731
792
  The library supports flexible logging options that can be configured through the config object: