hide-a-bed 4.0.3 → 4.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +304 -73
- package/cjs/impl/bulk.cjs +158 -10
- package/cjs/impl/crud.cjs +19 -12
- package/cjs/impl/errors.cjs +12 -0
- package/cjs/impl/patch.cjs +19 -0
- package/cjs/impl/queryBuilder.cjs +99 -0
- package/cjs/impl/stream.cjs +12 -1
- package/cjs/impl/trackedEmitter.cjs +54 -0
- package/cjs/impl/transactionErrors.cjs +70 -0
- package/cjs/index.cjs +21 -5
- package/cjs/schema/bind.cjs +4 -0
- package/cjs/schema/bulk.cjs +35 -11
- package/cjs/schema/config.cjs +1 -0
- package/cjs/schema/crud.cjs +23 -1
- package/cjs/schema/patch.cjs +17 -2
- package/cjs/schema/query.cjs +2 -1
- package/config.json +5 -0
- package/impl/bulk.d.mts +4 -0
- package/impl/bulk.d.mts.map +1 -1
- package/impl/bulk.mjs +200 -13
- package/impl/crud.d.mts +2 -0
- package/impl/crud.d.mts.map +1 -1
- package/impl/crud.mjs +25 -15
- package/impl/errors.d.mts +8 -0
- package/impl/errors.d.mts.map +1 -1
- package/impl/errors.mjs +12 -0
- package/impl/patch.d.mts +2 -0
- package/impl/patch.d.mts.map +1 -1
- package/impl/patch.mjs +22 -1
- package/impl/query.d.mts +18 -9
- package/impl/query.d.mts.map +1 -1
- package/impl/queryBuilder.d.mts +94 -0
- package/impl/queryBuilder.d.mts.map +1 -0
- package/impl/queryBuilder.mjs +99 -0
- package/impl/stream.d.mts.map +1 -1
- package/impl/stream.mjs +12 -1
- package/impl/trackedEmitter.d.mts +8 -0
- package/impl/trackedEmitter.d.mts.map +1 -0
- package/impl/trackedEmitter.mjs +33 -0
- package/impl/transactionErrors.d.mts +57 -0
- package/impl/transactionErrors.d.mts.map +1 -0
- package/impl/transactionErrors.mjs +47 -0
- package/index.d.mts +18 -3
- package/index.d.mts.map +1 -1
- package/index.mjs +42 -11
- package/package.json +9 -4
- package/schema/bind.d.mts +382 -45
- package/schema/bind.d.mts.map +1 -1
- package/schema/bind.mjs +6 -2
- package/schema/bulk.d.mts +559 -16
- package/schema/bulk.d.mts.map +1 -1
- package/schema/bulk.mjs +40 -10
- package/schema/config.d.mts.map +1 -1
- package/schema/config.mjs +1 -0
- package/schema/crud.d.mts +240 -15
- package/schema/crud.d.mts.map +1 -1
- package/schema/crud.mjs +27 -1
- package/schema/patch.d.mts +138 -2
- package/schema/patch.d.mts.map +1 -1
- package/schema/patch.mjs +22 -2
- package/schema/query.d.mts +62 -30
- package/schema/query.d.mts.map +1 -1
- package/schema/query.mjs +4 -1
- package/schema/stream.d.mts +18 -9
- package/schema/stream.d.mts.map +1 -1
package/impl/bulk.d.mts
CHANGED
|
@@ -4,4 +4,8 @@ export const bulkSave: import("../schema/bulk.mjs").BulkSaveSchema;
|
|
|
4
4
|
export const bulkGet: import("../schema/bulk.mjs").BulkGetSchema;
|
|
5
5
|
/** @type { import('../schema/bulk.mjs').BulkRemoveSchema } */
|
|
6
6
|
export const bulkRemove: import("../schema/bulk.mjs").BulkRemoveSchema;
|
|
7
|
+
/** @type { import('../schema/bulk.mjs').BulkGetDictionarySchema } */
|
|
8
|
+
export const bulkGetDictionary: import("../schema/bulk.mjs").BulkGetDictionarySchema;
|
|
9
|
+
/** @type { import('../schema/bulk.mjs').BulkSaveTransactionSchema } bulkSaveTransaction */
|
|
10
|
+
export const bulkSaveTransaction: import("../schema/bulk.mjs").BulkSaveTransactionSchema;
|
|
7
11
|
//# sourceMappingURL=bulk.d.mts.map
|
package/impl/bulk.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bulk.d.mts","sourceRoot":"","sources":["bulk.mjs"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"bulk.d.mts","sourceRoot":"","sources":["bulk.mjs"],"names":[],"mappings":"AAkBA,4DAA4D;AAC5D,uBADY,OAAO,oBAAoB,EAAE,cAAc,CAsCrD;AAEF,2DAA2D;AAC3D,sBADY,OAAO,oBAAoB,EAAE,aAAa,CA8BpD;AAIF,8DAA8D;AAC9D,yBADY,OAAO,oBAAoB,EAAE,gBAAgB,CAkBvD;AAEF,qEAAqE;AACrE,gCADY,OAAO,oBAAoB,EAAE,uBAAuB,CAwB9D;AAEF,2FAA2F;AAC3F,kCADY,OAAO,oBAAoB,EAAE,yBAAyB,CAiJhE"}
|
package/impl/bulk.mjs
CHANGED
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
// @ts-check
|
|
2
2
|
import needle from 'needle'
|
|
3
|
-
import { BulkSave, BulkGet, BulkRemove } from '../schema/bulk.mjs'
|
|
3
|
+
import { BulkSave, BulkGet, BulkRemove, BulkGetDictionary, BulkSaveTransaction } from '../schema/bulk.mjs'
|
|
4
|
+
import { withRetry } from './retry.mjs'
|
|
5
|
+
import { put } from './crud.mjs'
|
|
4
6
|
import { RetryableError } from './errors.mjs'
|
|
7
|
+
import { TransactionSetupError, TransactionVersionConflictError, TransactionBulkOperationError, TransactionRollbackError } from './transactionErrors.mjs'
|
|
5
8
|
import { createLogger } from './logger.mjs'
|
|
9
|
+
import { CouchDoc } from '../schema/crud.mjs'
|
|
10
|
+
import { setupEmitter } from './trackedEmitter.mjs'
|
|
6
11
|
|
|
7
12
|
const opts = {
|
|
8
13
|
json: true,
|
|
@@ -58,10 +63,10 @@ export const bulkGet = BulkGet.implement(async (config, ids) => {
|
|
|
58
63
|
|
|
59
64
|
logger.info(`Starting bulk get for ${keys.length} documents`)
|
|
60
65
|
const url = `${config.couch}/_all_docs?include_docs=true`
|
|
61
|
-
const
|
|
66
|
+
const payload = { keys }
|
|
62
67
|
let resp
|
|
63
68
|
try {
|
|
64
|
-
resp = await needle('post', url,
|
|
69
|
+
resp = await needle('post', url, payload, opts)
|
|
65
70
|
} catch (err) {
|
|
66
71
|
logger.error('Network error during bulk get:', err)
|
|
67
72
|
RetryableError.handleNetworkError(err)
|
|
@@ -78,20 +83,202 @@ export const bulkGet = BulkGet.implement(async (config, ids) => {
|
|
|
78
83
|
logger.error(`Unexpected status code: ${resp.statusCode}`)
|
|
79
84
|
throw new Error('could not fetch')
|
|
80
85
|
}
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
/** @type {{ error?: any, key?: string, doc?: import('../schema/crud.mjs').CouchDocSchema }} */ r
|
|
85
|
-
) => r.doc)
|
|
86
|
-
logger.info(`Successfully retrieved ${docs.length} documents`)
|
|
87
|
-
return docs
|
|
86
|
+
/** @type { import('../schema/query.mjs').SimpleViewQueryResponseSchema } body */
|
|
87
|
+
const body = resp.body
|
|
88
|
+
return body
|
|
88
89
|
})
|
|
89
90
|
|
|
91
|
+
// sugar methods
|
|
92
|
+
|
|
90
93
|
/** @type { import('../schema/bulk.mjs').BulkRemoveSchema } */
|
|
91
94
|
export const bulkRemove = BulkRemove.implement(async (config, ids) => {
|
|
92
95
|
const logger = createLogger(config)
|
|
93
96
|
logger.info(`Starting bulk remove for ${ids.length} documents`)
|
|
94
|
-
const
|
|
95
|
-
|
|
96
|
-
|
|
97
|
+
const resp = await bulkGet(config, ids)
|
|
98
|
+
/** @type { Array<import('../schema/crud.mjs').CouchDocSchema> } toRemove */
|
|
99
|
+
const toRemove = []
|
|
100
|
+
resp.rows.forEach(row => {
|
|
101
|
+
if (!row.doc) return
|
|
102
|
+
try {
|
|
103
|
+
const d = CouchDoc.parse(row.doc)
|
|
104
|
+
d._deleted = true
|
|
105
|
+
toRemove.push(d)
|
|
106
|
+
} catch (e) {
|
|
107
|
+
logger.warn(`Invalid document structure in bulk remove: ${row.id}`, e)
|
|
108
|
+
}
|
|
109
|
+
})
|
|
110
|
+
return bulkSave(config, toRemove)
|
|
111
|
+
})
|
|
112
|
+
|
|
113
|
+
/** @type { import('../schema/bulk.mjs').BulkGetDictionarySchema } */
|
|
114
|
+
export const bulkGetDictionary = BulkGetDictionary.implement(async (config, ids) => {
|
|
115
|
+
const resp = await bulkGet(config, ids)
|
|
116
|
+
|
|
117
|
+
/** @type { import('../schema/bulk.mjs').BulkGetDictionaryResponseSchema } results */
|
|
118
|
+
const results = { found: {}, notFound: {} }
|
|
119
|
+
|
|
120
|
+
resp.rows.forEach(
|
|
121
|
+
/** @param { import('../schema/query.mjs').ViewRowSchema } row */
|
|
122
|
+
row => {
|
|
123
|
+
if (!row.key) return
|
|
124
|
+
if (row.error) {
|
|
125
|
+
results.notFound[row.key] = row
|
|
126
|
+
return
|
|
127
|
+
}
|
|
128
|
+
try {
|
|
129
|
+
/** @type { import('../schema/crud.mjs').CouchDocSchema } doc */
|
|
130
|
+
const doc = CouchDoc.parse(row.doc)
|
|
131
|
+
results.found[doc._id] = doc
|
|
132
|
+
} catch (e) {
|
|
133
|
+
results.notFound[row.key] = row
|
|
134
|
+
}
|
|
135
|
+
})
|
|
136
|
+
return results
|
|
137
|
+
})
|
|
138
|
+
|
|
139
|
+
/** @type { import('../schema/bulk.mjs').BulkSaveTransactionSchema } bulkSaveTransaction */
|
|
140
|
+
export const bulkSaveTransaction = BulkSaveTransaction.implement(async (config, transactionId, docs) => {
|
|
141
|
+
const emitter = setupEmitter(config)
|
|
142
|
+
const logger = createLogger(config)
|
|
143
|
+
const retryOptions = {
|
|
144
|
+
maxRetries: config.maxRetries ?? 10,
|
|
145
|
+
initialDelay: config.initialDelay ?? 1000,
|
|
146
|
+
backoffFactor: config.backoffFactor ?? 2
|
|
147
|
+
}
|
|
148
|
+
const _put = config.bindWithRetry ? withRetry(put.bind(null, config), retryOptions) : put.bind(null, config)
|
|
149
|
+
logger.info(`Starting bulk save transaction ${transactionId} for ${docs.length} documents`)
|
|
150
|
+
|
|
151
|
+
// Create transaction document
|
|
152
|
+
const txnDoc = {
|
|
153
|
+
_id: `txn:${transactionId}`,
|
|
154
|
+
_rev: null,
|
|
155
|
+
type: 'transaction',
|
|
156
|
+
status: 'pending',
|
|
157
|
+
changes: docs,
|
|
158
|
+
timestamp: new Date().toISOString()
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Save transaction document
|
|
162
|
+
let txnresp = await _put(txnDoc)
|
|
163
|
+
logger.debug('Transaction document created:', txnDoc, txnresp)
|
|
164
|
+
await emitter.emit('transaction-created', { txnresp, txnDoc })
|
|
165
|
+
if (txnresp.error) {
|
|
166
|
+
throw new TransactionSetupError('Failed to create transaction document', {
|
|
167
|
+
error: txnresp.error,
|
|
168
|
+
response: txnresp.body
|
|
169
|
+
})
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// Get current revisions of all documents
|
|
173
|
+
const existingDocs = await bulkGetDictionary(config, docs.map(d => d._id))
|
|
174
|
+
logger.debug('Fetched current revisions of documents:', existingDocs)
|
|
175
|
+
await emitter.emit('transaction-revs-fetched', existingDocs)
|
|
176
|
+
|
|
177
|
+
/** @type {string[]} */
|
|
178
|
+
const revErrors = []
|
|
179
|
+
// if any of the existingDocs, and the docs provided dont match on rev, then throw an error
|
|
180
|
+
docs.forEach(d => {
|
|
181
|
+
if (existingDocs.found[d._id] && existingDocs.found[d._id]._rev !== d._rev) revErrors.push(d._id)
|
|
182
|
+
if (existingDocs.notFound[d._id] && d._rev) revErrors.push(d._id)
|
|
183
|
+
})
|
|
184
|
+
|
|
185
|
+
if (revErrors.length > 0) {
|
|
186
|
+
throw new TransactionVersionConflictError(revErrors)
|
|
187
|
+
}
|
|
188
|
+
logger.debug('Checked document revisions:', existingDocs)
|
|
189
|
+
await emitter.emit('transaction-revs-checked', existingDocs)
|
|
190
|
+
|
|
191
|
+
/** @type {Record<string, import('../schema/crud.mjs').CouchDocSchema>} providedDocsById */
|
|
192
|
+
const providedDocsById = {}
|
|
193
|
+
docs.forEach((
|
|
194
|
+
/** @type {import('../schema/crud.mjs').CouchDocSchema} */ d
|
|
195
|
+
) => {
|
|
196
|
+
if (!d._id) return
|
|
197
|
+
providedDocsById[d._id] = d
|
|
198
|
+
})
|
|
199
|
+
|
|
200
|
+
/** @type {import('../schema/bulk.mjs').Response} */
|
|
201
|
+
const newDocsToRollback = []
|
|
202
|
+
/** @type {import('../schema/bulk.mjs').Response} */
|
|
203
|
+
const potentialExistingDocsToRollack = []
|
|
204
|
+
/** @type {import('../schema/bulk.mjs').Response} */
|
|
205
|
+
const failedDocs = []
|
|
206
|
+
|
|
207
|
+
try {
|
|
208
|
+
logger.info('Transaction started:', txnDoc)
|
|
209
|
+
await emitter.emit('transaction-started', txnDoc)
|
|
210
|
+
// Apply updates
|
|
211
|
+
const results = await bulkSave(config, docs)
|
|
212
|
+
logger.info('Transaction updates applied:', results)
|
|
213
|
+
await emitter.emit('transaction-updates-applied', results)
|
|
214
|
+
|
|
215
|
+
// Check for failures
|
|
216
|
+
results.forEach(r => {
|
|
217
|
+
if (!r.id) return // not enough info
|
|
218
|
+
if (!r.error) {
|
|
219
|
+
if (existingDocs.notFound[r.id]) newDocsToRollback.push(r)
|
|
220
|
+
if (existingDocs.found[r.id]) potentialExistingDocsToRollack.push(r)
|
|
221
|
+
} else {
|
|
222
|
+
failedDocs.push(r)
|
|
223
|
+
}
|
|
224
|
+
})
|
|
225
|
+
if (failedDocs.length > 0) {
|
|
226
|
+
throw new TransactionBulkOperationError(failedDocs)
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// Update transaction status to completed
|
|
230
|
+
txnDoc.status = 'completed'
|
|
231
|
+
txnDoc._rev = txnresp.rev
|
|
232
|
+
txnresp = await _put(txnDoc)
|
|
233
|
+
logger.info('Transaction completed:', txnDoc)
|
|
234
|
+
await emitter.emit('transaction-completed', { txnresp, txnDoc })
|
|
235
|
+
if (txnresp.statusCode !== 201) {
|
|
236
|
+
logger.error('Failed to update transaction status to completed')
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
return results
|
|
240
|
+
} catch (error) {
|
|
241
|
+
logger.error('Transaction failed, attempting rollback:', error)
|
|
242
|
+
|
|
243
|
+
// Rollback changes
|
|
244
|
+
/** @type {Array<import('../schema/crud.mjs').CouchDocSchema>} */
|
|
245
|
+
const toRollback = []
|
|
246
|
+
potentialExistingDocsToRollack.forEach(row => {
|
|
247
|
+
if (!row.id || !row.rev) return
|
|
248
|
+
const doc = existingDocs.found[row.id]
|
|
249
|
+
doc._rev = row.rev
|
|
250
|
+
toRollback.push(doc)
|
|
251
|
+
})
|
|
252
|
+
newDocsToRollback.forEach(d => {
|
|
253
|
+
if (!d.id || !d.rev) return
|
|
254
|
+
const before = structuredClone(providedDocsById[d.id])
|
|
255
|
+
before._rev = d.rev
|
|
256
|
+
before._deleted = true
|
|
257
|
+
toRollback.push(before)
|
|
258
|
+
})
|
|
259
|
+
|
|
260
|
+
// rollback all the changes
|
|
261
|
+
const bulkRollbackResult = await bulkSave(config, toRollback)
|
|
262
|
+
let status = 'rolled_back'
|
|
263
|
+
bulkRollbackResult.forEach(r => {
|
|
264
|
+
if (r.error) status = 'rollback_failed'
|
|
265
|
+
})
|
|
266
|
+
logger.warn('Transaction rolled back:', { bulkRollbackResult, status })
|
|
267
|
+
await emitter.emit('transaction-rolled-back', { bulkRollbackResult, status })
|
|
268
|
+
|
|
269
|
+
// Update transaction status to rolled back
|
|
270
|
+
txnDoc.status = status
|
|
271
|
+
txnDoc._rev = txnresp.rev
|
|
272
|
+
txnresp = await _put(txnDoc)
|
|
273
|
+
logger.warn('Transaction rollback status updated:', txnDoc)
|
|
274
|
+
await emitter.emit('transaction-rolled-back-status', { txnresp, txnDoc })
|
|
275
|
+
if (txnresp.statusCode !== 201) {
|
|
276
|
+
logger.error('Failed to update transaction status to rolled_back')
|
|
277
|
+
}
|
|
278
|
+
throw new TransactionRollbackError(
|
|
279
|
+
'Transaction failed and rollback was unsuccessful',
|
|
280
|
+
/** @type {Error} */ (error),
|
|
281
|
+
bulkRollbackResult
|
|
282
|
+
)
|
|
283
|
+
}
|
|
97
284
|
})
|
package/impl/crud.d.mts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
/** @type { import('../schema/crud.mjs').CouchGetSchema } */
|
|
2
2
|
export const get: import("../schema/crud.mjs").CouchGetSchema;
|
|
3
|
+
/** @type { import('../schema/crud.mjs').CouchGetAtRevSchema } */
|
|
4
|
+
export const getAtRev: import("../schema/crud.mjs").CouchGetAtRevSchema;
|
|
3
5
|
/** @type { import('../schema/crud.mjs').CouchPutSchema } */
|
|
4
6
|
export const put: import("../schema/crud.mjs").CouchPutSchema;
|
|
5
7
|
//# sourceMappingURL=crud.d.mts.map
|
package/impl/crud.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"crud.d.mts","sourceRoot":"","sources":["crud.mjs"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"crud.d.mts","sourceRoot":"","sources":["crud.mjs"],"names":[],"mappings":"AAqDA,4DAA4D;AAC5D,kBADY,OAAO,oBAAoB,EAAE,cAAc,CAIrD;AAEF,iEAAiE;AACjE,uBADY,OAAO,oBAAoB,EAAE,mBAAmB,CAI1D;AAEF,4DAA4D;AAC5D,kBADY,OAAO,oBAAoB,EAAE,cAAc,CAqCrD"}
|
package/impl/crud.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// @ts-check
|
|
2
2
|
import needle from 'needle'
|
|
3
|
-
import { CouchGet, CouchPut } from '../schema/crud.mjs'
|
|
4
|
-
import { RetryableError } from './errors.mjs'
|
|
3
|
+
import { CouchGet, CouchPut, CouchGetWithOptions, CouchGetAtRev } from '../schema/crud.mjs'
|
|
4
|
+
import { RetryableError, NotFoundError } from './errors.mjs'
|
|
5
5
|
import { createLogger } from './logger.mjs'
|
|
6
6
|
|
|
7
7
|
const opts = {
|
|
@@ -11,11 +11,13 @@ const opts = {
|
|
|
11
11
|
}
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
/** @type { import('../schema/crud.mjs').
|
|
15
|
-
|
|
14
|
+
/** @type { import('../schema/crud.mjs').CouchGetWithOptionsSchema } */
|
|
15
|
+
const _getWithOptions = CouchGetWithOptions.implement(async (config, id, getOpts) => {
|
|
16
16
|
const logger = createLogger(config)
|
|
17
|
-
const
|
|
18
|
-
|
|
17
|
+
const rev = getOpts?.rev
|
|
18
|
+
const path = rev ? `${id}?rev=${rev}` : id
|
|
19
|
+
const url = `${config.couch}/${path}`
|
|
20
|
+
logger.info(`Getting document with id: ${id}, rev ${rev || 'latest'}`)
|
|
19
21
|
|
|
20
22
|
try {
|
|
21
23
|
const resp = await needle('get', url, opts)
|
|
@@ -23,18 +25,14 @@ export const get = CouchGet.implement(async (config, id) => {
|
|
|
23
25
|
logger.error('No response received from get request')
|
|
24
26
|
throw new RetryableError('no response', 503)
|
|
25
27
|
}
|
|
26
|
-
if (resp.statusCode === 404) {
|
|
27
|
-
logger.debug(`Document not found: ${id}`)
|
|
28
|
-
return null
|
|
29
|
-
}
|
|
30
28
|
const result = resp?.body || {}
|
|
31
29
|
if (resp.statusCode === 404) {
|
|
32
30
|
if (config.throwOnGetNotFound) {
|
|
33
|
-
logger.warn(`Document not found (throwing error): ${id}`)
|
|
34
|
-
throw new
|
|
31
|
+
logger.warn(`Document not found (throwing error): ${id}, rev ${rev || 'latest'}`)
|
|
32
|
+
throw new NotFoundError(id, result.reason || 'not_found')
|
|
35
33
|
} else {
|
|
36
|
-
logger.debug(`Document not found (returning undefined): ${id}`)
|
|
37
|
-
return
|
|
34
|
+
logger.debug(`Document not found (returning undefined): ${id}, rev ${rev || 'latest'}`)
|
|
35
|
+
return null
|
|
38
36
|
}
|
|
39
37
|
}
|
|
40
38
|
if (RetryableError.isRetryableStatusCode(resp.statusCode)) {
|
|
@@ -45,7 +43,7 @@ export const get = CouchGet.implement(async (config, id) => {
|
|
|
45
43
|
logger.error(`Unexpected status code: ${resp.statusCode}`)
|
|
46
44
|
throw new Error(result.reason || 'failed')
|
|
47
45
|
}
|
|
48
|
-
logger.info(`Successfully retrieved document: ${id}`)
|
|
46
|
+
logger.info(`Successfully retrieved document: ${id}, rev ${rev || 'latest'}`)
|
|
49
47
|
return result
|
|
50
48
|
} catch (err) {
|
|
51
49
|
logger.error('Error during get operation:', err)
|
|
@@ -53,6 +51,18 @@ export const get = CouchGet.implement(async (config, id) => {
|
|
|
53
51
|
}
|
|
54
52
|
})
|
|
55
53
|
|
|
54
|
+
/** @type { import('../schema/crud.mjs').CouchGetSchema } */
|
|
55
|
+
export const get = CouchGet.implement(async (config, id) => {
|
|
56
|
+
const getOptions = {}
|
|
57
|
+
return _getWithOptions(config, id, getOptions)
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
/** @type { import('../schema/crud.mjs').CouchGetAtRevSchema } */
|
|
61
|
+
export const getAtRev = CouchGetAtRev.implement(async (config, id, rev) => {
|
|
62
|
+
const getOptions = { rev }
|
|
63
|
+
return _getWithOptions(config, id, getOptions)
|
|
64
|
+
})
|
|
65
|
+
|
|
56
66
|
/** @type { import('../schema/crud.mjs').CouchPutSchema } */
|
|
57
67
|
export const put = CouchPut.implement(async (config, doc) => {
|
|
58
68
|
const logger = createLogger(config)
|
package/impl/errors.d.mts
CHANGED
|
@@ -3,6 +3,14 @@
|
|
|
3
3
|
* @property {string} code - The error code
|
|
4
4
|
* @property {string} [message] - Optional error message
|
|
5
5
|
*/
|
|
6
|
+
export class NotFoundError extends Error {
|
|
7
|
+
/**
|
|
8
|
+
* @param {string} docId - The ID of the document that wasn't found
|
|
9
|
+
* @param {string} [message] - Optional error message
|
|
10
|
+
*/
|
|
11
|
+
constructor(docId: string, message?: string | undefined);
|
|
12
|
+
docId: string;
|
|
13
|
+
}
|
|
6
14
|
export class RetryableError extends Error {
|
|
7
15
|
/**
|
|
8
16
|
* @param {number|undefined} statusCode - The HTTP status code to check
|
package/impl/errors.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.d.mts","sourceRoot":"","sources":["errors.mjs"],"names":[],"mappings":"AAEA;;;;GAIG;AAEH;IAWE;;;OAGG;IACH,yCAHW,MAAM,GAAC,SAAS,GACd,OAAO,CAKnB;IAED;;;;OAIG;IACH,+BAJW,YAAY,GAAG,OAAO,QAsBhC;IA1CD;;;OAGG;IACH,qBAHW,MAAM,cACN,MAAM,GAAC,SAAS,EAM1B;IADC,+BAA4B;CAoC/B;;;;;
|
|
1
|
+
{"version":3,"file":"errors.d.mts","sourceRoot":"","sources":["errors.mjs"],"names":[],"mappings":"AAEA;;;;GAIG;AAEH;IACE;;;OAGG;IACH,mBAHW,MAAM,gCAOhB;IADC,cAAkB;CAErB;AAED;IAWE;;;OAGG;IACH,yCAHW,MAAM,GAAC,SAAS,GACd,OAAO,CAKnB;IAED;;;;OAIG;IACH,+BAJW,YAAY,GAAG,OAAO,QAsBhC;IA1CD;;;OAGG;IACH,qBAHW,MAAM,cACN,MAAM,GAAC,SAAS,EAM1B;IADC,+BAA4B;CAoC/B;;;;;UA5Da,MAAM"}
|
package/impl/errors.mjs
CHANGED
|
@@ -6,6 +6,18 @@
|
|
|
6
6
|
* @property {string} [message] - Optional error message
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
+
export class NotFoundError extends Error {
|
|
10
|
+
/**
|
|
11
|
+
* @param {string} docId - The ID of the document that wasn't found
|
|
12
|
+
* @param {string} [message] - Optional error message
|
|
13
|
+
*/
|
|
14
|
+
constructor(docId, message = 'Document not found') {
|
|
15
|
+
super(message)
|
|
16
|
+
this.name = 'NotFoundError'
|
|
17
|
+
this.docId = docId
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
9
21
|
export class RetryableError extends Error {
|
|
10
22
|
/**
|
|
11
23
|
* @param {string} message - The error message
|
package/impl/patch.d.mts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
export function sleep(ms: any): Promise<any>;
|
|
2
2
|
/** @type { import('../schema/patch.mjs').PatchSchema } */
|
|
3
3
|
export const patch: import("../schema/patch.mjs").PatchSchema;
|
|
4
|
+
/** @type { import('../schema/patch.mjs').PatchDangerouslySchema } */
|
|
5
|
+
export const patchDangerously: import("../schema/patch.mjs").PatchDangerouslySchema;
|
|
4
6
|
//# sourceMappingURL=patch.d.mts.map
|
package/impl/patch.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"patch.d.mts","sourceRoot":"","sources":["patch.mjs"],"names":[],"mappings":"AAIO,6CAAmE;AAE1E,0DAA0D;AAC1D,oBADY,OAAO,qBAAqB,EAAE,WAAW,
|
|
1
|
+
{"version":3,"file":"patch.d.mts","sourceRoot":"","sources":["patch.mjs"],"names":[],"mappings":"AAIO,6CAAmE;AAE1E,0DAA0D;AAC1D,oBADY,OAAO,qBAAqB,EAAE,WAAW,CAmBnD;AAEF,qEAAqE;AACrE,+BADY,OAAO,qBAAqB,EAAE,sBAAsB,CA4D9D"}
|
package/impl/patch.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { get, put } from './crud.mjs'
|
|
2
|
-
import { Patch } from '../schema/patch.mjs'
|
|
2
|
+
import { Patch, PatchDangerously } from '../schema/patch.mjs'
|
|
3
3
|
import { createLogger } from './logger.mjs'
|
|
4
4
|
|
|
5
5
|
export const sleep = ms => new Promise(resolve => setTimeout(resolve, ms))
|
|
@@ -7,6 +7,27 @@ export const sleep = ms => new Promise(resolve => setTimeout(resolve, ms))
|
|
|
7
7
|
/** @type { import('../schema/patch.mjs').PatchSchema } */
|
|
8
8
|
export const patch = Patch.implement(async (config, id, properties) => {
|
|
9
9
|
const logger = createLogger(config)
|
|
10
|
+
|
|
11
|
+
logger.info(`Starting patch operation for document ${id}`)
|
|
12
|
+
logger.debug('Patch properties:', properties)
|
|
13
|
+
const doc = await get(config, id)
|
|
14
|
+
if (doc._rev !== properties._rev) {
|
|
15
|
+
const result = {}
|
|
16
|
+
result.ok = false
|
|
17
|
+
result.error = 'conflict'
|
|
18
|
+
result.statusCode = 409
|
|
19
|
+
return result
|
|
20
|
+
}
|
|
21
|
+
const updatedDoc = { ...doc, ...properties }
|
|
22
|
+
logger.debug('Merged document:', updatedDoc)
|
|
23
|
+
const result = await put(config, updatedDoc)
|
|
24
|
+
logger.info(`Successfully patched document ${id}, rev: ${result.rev}`)
|
|
25
|
+
return result
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
/** @type { import('../schema/patch.mjs').PatchDangerouslySchema } */
|
|
29
|
+
export const patchDangerously = PatchDangerously.implement(async (config, id, properties) => {
|
|
30
|
+
const logger = createLogger(config)
|
|
10
31
|
const maxRetries = config.maxRetries || 5
|
|
11
32
|
let delay = config.initialDelay || 1000
|
|
12
33
|
let attempts = 0
|
package/impl/query.d.mts
CHANGED
|
@@ -120,17 +120,20 @@ export const query: z.infer<z.ZodFunction<z.ZodTuple<[z.ZodObject<{
|
|
|
120
120
|
id: z.ZodOptional<z.ZodString>;
|
|
121
121
|
key: z.ZodNullable<z.ZodAny>;
|
|
122
122
|
value: z.ZodNullable<z.ZodAny>;
|
|
123
|
-
doc: z.ZodOptional<z.ZodObject<{}, "passthrough", z.ZodTypeAny, z.objectOutputType<{}, z.ZodTypeAny, "passthrough">, z.objectInputType<{}, z.ZodTypeAny, "passthrough"
|
|
123
|
+
doc: z.ZodOptional<z.ZodNullable<z.ZodOptional<z.ZodObject<{}, "passthrough", z.ZodTypeAny, z.objectOutputType<{}, z.ZodTypeAny, "passthrough">, z.objectInputType<{}, z.ZodTypeAny, "passthrough">>>>>;
|
|
124
|
+
error: z.ZodOptional<z.ZodString>;
|
|
124
125
|
}, "strip", z.ZodTypeAny, {
|
|
125
126
|
id?: string | undefined;
|
|
126
127
|
key?: any;
|
|
127
128
|
value?: any;
|
|
128
|
-
doc?: z.objectOutputType<{}, z.ZodTypeAny, "passthrough"> | undefined;
|
|
129
|
+
doc?: z.objectOutputType<{}, z.ZodTypeAny, "passthrough"> | null | undefined;
|
|
130
|
+
error?: string | undefined;
|
|
129
131
|
}, {
|
|
130
132
|
id?: string | undefined;
|
|
131
133
|
key?: any;
|
|
132
134
|
value?: any;
|
|
133
|
-
doc?: z.objectInputType<{}, z.ZodTypeAny, "passthrough"> | undefined;
|
|
135
|
+
doc?: z.objectInputType<{}, z.ZodTypeAny, "passthrough"> | null | undefined;
|
|
136
|
+
error?: string | undefined;
|
|
134
137
|
}>, "many">;
|
|
135
138
|
}, "passthrough", z.ZodTypeAny, z.objectOutputType<{
|
|
136
139
|
error: z.ZodOptional<z.ZodString>;
|
|
@@ -138,17 +141,20 @@ export const query: z.infer<z.ZodFunction<z.ZodTuple<[z.ZodObject<{
|
|
|
138
141
|
id: z.ZodOptional<z.ZodString>;
|
|
139
142
|
key: z.ZodNullable<z.ZodAny>;
|
|
140
143
|
value: z.ZodNullable<z.ZodAny>;
|
|
141
|
-
doc: z.ZodOptional<z.ZodObject<{}, "passthrough", z.ZodTypeAny, z.objectOutputType<{}, z.ZodTypeAny, "passthrough">, z.objectInputType<{}, z.ZodTypeAny, "passthrough"
|
|
144
|
+
doc: z.ZodOptional<z.ZodNullable<z.ZodOptional<z.ZodObject<{}, "passthrough", z.ZodTypeAny, z.objectOutputType<{}, z.ZodTypeAny, "passthrough">, z.objectInputType<{}, z.ZodTypeAny, "passthrough">>>>>;
|
|
145
|
+
error: z.ZodOptional<z.ZodString>;
|
|
142
146
|
}, "strip", z.ZodTypeAny, {
|
|
143
147
|
id?: string | undefined;
|
|
144
148
|
key?: any;
|
|
145
149
|
value?: any;
|
|
146
|
-
doc?: z.objectOutputType<{}, z.ZodTypeAny, "passthrough"> | undefined;
|
|
150
|
+
doc?: z.objectOutputType<{}, z.ZodTypeAny, "passthrough"> | null | undefined;
|
|
151
|
+
error?: string | undefined;
|
|
147
152
|
}, {
|
|
148
153
|
id?: string | undefined;
|
|
149
154
|
key?: any;
|
|
150
155
|
value?: any;
|
|
151
|
-
doc?: z.objectInputType<{}, z.ZodTypeAny, "passthrough"> | undefined;
|
|
156
|
+
doc?: z.objectInputType<{}, z.ZodTypeAny, "passthrough"> | null | undefined;
|
|
157
|
+
error?: string | undefined;
|
|
152
158
|
}>, "many">;
|
|
153
159
|
}, z.ZodTypeAny, "passthrough">, z.objectInputType<{
|
|
154
160
|
error: z.ZodOptional<z.ZodString>;
|
|
@@ -156,17 +162,20 @@ export const query: z.infer<z.ZodFunction<z.ZodTuple<[z.ZodObject<{
|
|
|
156
162
|
id: z.ZodOptional<z.ZodString>;
|
|
157
163
|
key: z.ZodNullable<z.ZodAny>;
|
|
158
164
|
value: z.ZodNullable<z.ZodAny>;
|
|
159
|
-
doc: z.ZodOptional<z.ZodObject<{}, "passthrough", z.ZodTypeAny, z.objectOutputType<{}, z.ZodTypeAny, "passthrough">, z.objectInputType<{}, z.ZodTypeAny, "passthrough"
|
|
165
|
+
doc: z.ZodOptional<z.ZodNullable<z.ZodOptional<z.ZodObject<{}, "passthrough", z.ZodTypeAny, z.objectOutputType<{}, z.ZodTypeAny, "passthrough">, z.objectInputType<{}, z.ZodTypeAny, "passthrough">>>>>;
|
|
166
|
+
error: z.ZodOptional<z.ZodString>;
|
|
160
167
|
}, "strip", z.ZodTypeAny, {
|
|
161
168
|
id?: string | undefined;
|
|
162
169
|
key?: any;
|
|
163
170
|
value?: any;
|
|
164
|
-
doc?: z.objectOutputType<{}, z.ZodTypeAny, "passthrough"> | undefined;
|
|
171
|
+
doc?: z.objectOutputType<{}, z.ZodTypeAny, "passthrough"> | null | undefined;
|
|
172
|
+
error?: string | undefined;
|
|
165
173
|
}, {
|
|
166
174
|
id?: string | undefined;
|
|
167
175
|
key?: any;
|
|
168
176
|
value?: any;
|
|
169
|
-
doc?: z.objectInputType<{}, z.ZodTypeAny, "passthrough"> | undefined;
|
|
177
|
+
doc?: z.objectInputType<{}, z.ZodTypeAny, "passthrough"> | null | undefined;
|
|
178
|
+
error?: string | undefined;
|
|
170
179
|
}>, "many">;
|
|
171
180
|
}, z.ZodTypeAny, "passthrough">>>>>;
|
|
172
181
|
import { z } from 'zod';
|
package/impl/query.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"query.d.mts","sourceRoot":"","sources":["query.mjs"],"names":[],"mappings":"AA6DA;;;GAGG;AACH,qCAHW;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;CAAE,UACtB,MAAM,EAAE,UAoBlB;AAxED,+CAA+C;AAC/C,oBADY,CAAC,CAAC,KAAK
|
|
1
|
+
{"version":3,"file":"query.d.mts","sourceRoot":"","sources":["query.mjs"],"names":[],"mappings":"AA6DA;;;GAGG;AACH,qCAHW;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;CAAE,UACtB,MAAM,EAAE,UAoBlB;AAxED,+CAA+C;AAC/C,oBADY,CAAC,CAAC,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mCAAiB,CAgDlC;kBAzDgB,KAAK"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @typedef {Object} QueryOptions
|
|
3
|
+
* @property {any} [key] - Exact key to match
|
|
4
|
+
* @property {any} [startkey] - Start of key range
|
|
5
|
+
* @property {any} [endkey] - End of key range
|
|
6
|
+
* @property {boolean} [reduce] - Whether to use reduce function
|
|
7
|
+
* @property {boolean} [group] - Whether to group results
|
|
8
|
+
* @property {number} [group_level] - Level at which to group
|
|
9
|
+
* @property {string} [stale] - Stale parameter value
|
|
10
|
+
* @property {number} [limit] - Max number of results
|
|
11
|
+
*/
|
|
12
|
+
export class QueryBuilder {
|
|
13
|
+
/**
|
|
14
|
+
* @param {any} key
|
|
15
|
+
* @returns {QueryBuilder}
|
|
16
|
+
*/
|
|
17
|
+
key(key: any): QueryBuilder;
|
|
18
|
+
/**
|
|
19
|
+
* @param {any} startkey
|
|
20
|
+
* @returns {QueryBuilder}
|
|
21
|
+
*/
|
|
22
|
+
startKey(startkey: any): QueryBuilder;
|
|
23
|
+
/**
|
|
24
|
+
* @param {any} endkey
|
|
25
|
+
* @returns {QueryBuilder}
|
|
26
|
+
*/
|
|
27
|
+
endKey(endkey: any): QueryBuilder;
|
|
28
|
+
/**
|
|
29
|
+
* @param {boolean} reduce
|
|
30
|
+
* @returns {QueryBuilder}
|
|
31
|
+
*/
|
|
32
|
+
reduce(reduce?: boolean): QueryBuilder;
|
|
33
|
+
/**
|
|
34
|
+
* @param {boolean} group
|
|
35
|
+
* @returns {QueryBuilder}
|
|
36
|
+
*/
|
|
37
|
+
group(group?: boolean): QueryBuilder;
|
|
38
|
+
/**
|
|
39
|
+
* @param {number} level
|
|
40
|
+
* @returns {QueryBuilder}
|
|
41
|
+
*/
|
|
42
|
+
groupLevel(level: number): QueryBuilder;
|
|
43
|
+
/**
|
|
44
|
+
* @param {string} stale
|
|
45
|
+
* @returns {QueryBuilder}
|
|
46
|
+
*/
|
|
47
|
+
stale(stale: string): QueryBuilder;
|
|
48
|
+
/**
|
|
49
|
+
* @param {number} limit
|
|
50
|
+
* @returns {QueryBuilder}
|
|
51
|
+
*/
|
|
52
|
+
limit(limit: number): QueryBuilder;
|
|
53
|
+
/**
|
|
54
|
+
* @returns {QueryOptions}
|
|
55
|
+
*/
|
|
56
|
+
build(): QueryOptions;
|
|
57
|
+
#private;
|
|
58
|
+
}
|
|
59
|
+
export function createQuery(): QueryBuilder;
|
|
60
|
+
export type QueryOptions = {
|
|
61
|
+
/**
|
|
62
|
+
* - Exact key to match
|
|
63
|
+
*/
|
|
64
|
+
key?: any;
|
|
65
|
+
/**
|
|
66
|
+
* - Start of key range
|
|
67
|
+
*/
|
|
68
|
+
startkey?: any;
|
|
69
|
+
/**
|
|
70
|
+
* - End of key range
|
|
71
|
+
*/
|
|
72
|
+
endkey?: any;
|
|
73
|
+
/**
|
|
74
|
+
* - Whether to use reduce function
|
|
75
|
+
*/
|
|
76
|
+
reduce?: boolean | undefined;
|
|
77
|
+
/**
|
|
78
|
+
* - Whether to group results
|
|
79
|
+
*/
|
|
80
|
+
group?: boolean | undefined;
|
|
81
|
+
/**
|
|
82
|
+
* - Level at which to group
|
|
83
|
+
*/
|
|
84
|
+
group_level?: number | undefined;
|
|
85
|
+
/**
|
|
86
|
+
* - Stale parameter value
|
|
87
|
+
*/
|
|
88
|
+
stale?: string | undefined;
|
|
89
|
+
/**
|
|
90
|
+
* - Max number of results
|
|
91
|
+
*/
|
|
92
|
+
limit?: number | undefined;
|
|
93
|
+
};
|
|
94
|
+
//# sourceMappingURL=queryBuilder.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queryBuilder.d.mts","sourceRoot":"","sources":["queryBuilder.mjs"],"names":[],"mappings":"AAEA;;;;;;;;;;GAUG;AAEH;IAIE;;;OAGG;IACH,SAHW,GAAG,GACD,YAAY,CAKxB;IAED;;;OAGG;IACH,mBAHW,GAAG,GACD,YAAY,CAKxB;IAED;;;OAGG;IACH,eAHW,GAAG,GACD,YAAY,CAKxB;IAED;;;OAGG;IACH,gBAHW,OAAO,GACL,YAAY,CAKxB;IAED;;;OAGG;IACH,cAHW,OAAO,GACL,YAAY,CAKxB;IAED;;;OAGG;IACH,kBAHW,MAAM,GACJ,YAAY,CAKxB;IAED;;;OAGG;IACH,aAHW,MAAM,GACJ,YAAY,CAKxB;IAED;;;OAGG;IACH,aAHW,MAAM,GACJ,YAAY,CAKxB;IAED;;OAEG;IACH,SAFa,YAAY,CAIxB;;CACF;AAEM,4CAA4C;;;;;UA9FrC,GAAG;;;;eACH,GAAG;;;;aACH,GAAG"}
|