hide-a-bed 5.0.2 → 5.0.4
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/cjs/impl/bulk.cjs +267 -0
- package/cjs/impl/changes.cjs +67 -0
- package/cjs/impl/crud.cjs +121 -0
- package/cjs/impl/errors.cjs +75 -0
- package/cjs/impl/logger.cjs +70 -0
- package/cjs/impl/patch.cjs +95 -0
- package/cjs/impl/query.cjs +116 -0
- package/cjs/impl/queryBuilder.cjs +99 -0
- package/cjs/impl/retry.cjs +54 -0
- package/cjs/impl/stream.cjs +121 -0
- package/cjs/impl/sugar/lock.cjs +81 -0
- package/cjs/impl/sugar/watch.cjs +159 -0
- package/cjs/impl/trackedEmitter.cjs +54 -0
- package/cjs/impl/transactionErrors.cjs +70 -0
- package/cjs/index.cjs +115 -0
- package/cjs/integration/changes.cjs +76 -0
- package/cjs/integration/disconnect-watch.cjs +52 -0
- package/cjs/integration/watch.cjs +59 -0
- package/cjs/schema/bind.cjs +51 -0
- package/cjs/schema/bulk.cjs +88 -0
- package/cjs/schema/changes.cjs +68 -0
- package/cjs/schema/config.cjs +48 -0
- package/cjs/schema/crud.cjs +77 -0
- package/cjs/schema/patch.cjs +53 -0
- package/cjs/schema/query.cjs +62 -0
- package/cjs/schema/stream.cjs +42 -0
- package/cjs/schema/sugar/lock.cjs +59 -0
- package/cjs/schema/sugar/watch.cjs +42 -0
- package/impl/bulk.d.mts +11 -0
- package/impl/bulk.d.mts.map +1 -0
- package/impl/bulk.mjs +1 -1
- package/impl/changes.d.mts +12 -0
- package/impl/changes.d.mts.map +1 -0
- package/impl/crud.d.mts +7 -0
- package/impl/crud.d.mts.map +1 -0
- package/impl/errors.d.mts +43 -0
- package/impl/errors.d.mts.map +1 -0
- package/impl/logger.d.mts +32 -0
- package/impl/logger.d.mts.map +1 -0
- package/impl/patch.d.mts +6 -0
- package/impl/patch.d.mts.map +1 -0
- package/impl/query.d.mts +195 -0
- package/impl/query.d.mts.map +1 -0
- package/impl/query.mjs +1 -1
- package/impl/queryBuilder.d.mts +94 -0
- package/impl/queryBuilder.d.mts.map +1 -0
- package/impl/retry.d.mts +2 -0
- package/impl/retry.d.mts.map +1 -0
- package/impl/stream.d.mts +3 -0
- package/impl/stream.d.mts.map +1 -0
- package/impl/sugar/lock.d.mts +5 -0
- package/impl/sugar/lock.d.mts.map +1 -0
- package/impl/sugar/watch.d.mts +34 -0
- package/impl/sugar/watch.d.mts.map +1 -0
- package/impl/trackedEmitter.d.mts +8 -0
- package/impl/trackedEmitter.d.mts.map +1 -0
- package/impl/transactionErrors.d.mts +57 -0
- package/impl/transactionErrors.d.mts.map +1 -0
- package/index.d.mts +74 -0
- package/index.d.mts.map +1 -0
- package/package.json +2 -2
- package/schema/bind.d.mts +922 -0
- package/schema/bind.d.mts.map +1 -0
- package/schema/bulk.d.mts +910 -0
- package/schema/bulk.d.mts.map +1 -0
- package/schema/changes.d.mts +191 -0
- package/schema/changes.d.mts.map +1 -0
- package/schema/config.d.mts +79 -0
- package/schema/config.d.mts.map +1 -0
- package/schema/crud.d.mts +491 -0
- package/schema/crud.d.mts.map +1 -0
- package/schema/patch.d.mts +255 -0
- package/schema/patch.d.mts.map +1 -0
- package/schema/query.d.mts +406 -0
- package/schema/query.d.mts.map +1 -0
- package/schema/stream.d.mts +211 -0
- package/schema/stream.d.mts.map +1 -0
- package/schema/sugar/lock.d.mts +238 -0
- package/schema/sugar/lock.d.mts.map +1 -0
- package/schema/sugar/watch.d.mts +127 -0
- package/schema/sugar/watch.d.mts.map +1 -0
- package/log.txt +0 -84
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
var bulk_exports = {};
|
|
30
|
+
__export(bulk_exports, {
|
|
31
|
+
bulkGet: () => bulkGet,
|
|
32
|
+
bulkGetDictionary: () => bulkGetDictionary,
|
|
33
|
+
bulkRemove: () => bulkRemove,
|
|
34
|
+
bulkSave: () => bulkSave,
|
|
35
|
+
bulkSaveTransaction: () => bulkSaveTransaction
|
|
36
|
+
});
|
|
37
|
+
module.exports = __toCommonJS(bulk_exports);
|
|
38
|
+
var import_needle = __toESM(require("needle"), 1);
|
|
39
|
+
var import_bulk = require("../schema/bulk.cjs");
|
|
40
|
+
var import_retry = require("./retry.cjs");
|
|
41
|
+
var import_crud = require("./crud.cjs");
|
|
42
|
+
var import_errors = require("./errors.cjs");
|
|
43
|
+
var import_transactionErrors = require("./transactionErrors.cjs");
|
|
44
|
+
var import_logger = require("./logger.cjs");
|
|
45
|
+
var import_crud2 = require("../schema/crud.cjs");
|
|
46
|
+
var import_trackedEmitter = require("./trackedEmitter.cjs");
|
|
47
|
+
const opts = {
|
|
48
|
+
json: true,
|
|
49
|
+
headers: {
|
|
50
|
+
"Content-Type": "application/json"
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
const bulkSave = import_bulk.BulkSave.implement(async (config, docs) => {
|
|
54
|
+
const logger = (0, import_logger.createLogger)(config);
|
|
55
|
+
if (!docs) {
|
|
56
|
+
logger.warn("bulkSave called with no docs");
|
|
57
|
+
return { ok: false, error: "noDocs", reason: "no docs provided" };
|
|
58
|
+
}
|
|
59
|
+
if (!docs.length) {
|
|
60
|
+
logger.warn("bulkSave called with empty docs array");
|
|
61
|
+
return { ok: false, error: "noDocs", reason: "no docs provided" };
|
|
62
|
+
}
|
|
63
|
+
logger.info(`Starting bulk save of ${docs.length} documents`);
|
|
64
|
+
const url = `${config.couch}/_bulk_docs`;
|
|
65
|
+
const body = { docs };
|
|
66
|
+
let resp;
|
|
67
|
+
try {
|
|
68
|
+
resp = await (0, import_needle.default)("post", url, body, opts);
|
|
69
|
+
} catch (err) {
|
|
70
|
+
logger.error("Network error during bulk save:", err);
|
|
71
|
+
import_errors.RetryableError.handleNetworkError(err);
|
|
72
|
+
}
|
|
73
|
+
if (!resp) {
|
|
74
|
+
logger.error("No response received from bulk save request");
|
|
75
|
+
throw new import_errors.RetryableError("no response", 503);
|
|
76
|
+
}
|
|
77
|
+
if (import_errors.RetryableError.isRetryableStatusCode(resp.statusCode)) {
|
|
78
|
+
logger.warn(`Retryable status code received: ${resp.statusCode}`);
|
|
79
|
+
throw new import_errors.RetryableError("retryable error during bulk save", resp.statusCode);
|
|
80
|
+
}
|
|
81
|
+
if (resp.statusCode !== 201) {
|
|
82
|
+
logger.error(`Unexpected status code: ${resp.statusCode}`);
|
|
83
|
+
throw new Error("could not save");
|
|
84
|
+
}
|
|
85
|
+
const results = resp?.body || [];
|
|
86
|
+
return results;
|
|
87
|
+
});
|
|
88
|
+
const bulkGet = import_bulk.BulkGet.implement(async (config, ids) => {
|
|
89
|
+
const logger = (0, import_logger.createLogger)(config);
|
|
90
|
+
const keys = ids;
|
|
91
|
+
logger.info(`Starting bulk get for ${keys.length} documents`);
|
|
92
|
+
const url = `${config.couch}/_all_docs?include_docs=true`;
|
|
93
|
+
const payload = { keys };
|
|
94
|
+
let resp;
|
|
95
|
+
try {
|
|
96
|
+
resp = await (0, import_needle.default)("post", url, payload, opts);
|
|
97
|
+
} catch (err) {
|
|
98
|
+
logger.error("Network error during bulk get:", err);
|
|
99
|
+
import_errors.RetryableError.handleNetworkError(err);
|
|
100
|
+
}
|
|
101
|
+
if (!resp) {
|
|
102
|
+
logger.error("No response received from bulk get request");
|
|
103
|
+
throw new import_errors.RetryableError("no response", 503);
|
|
104
|
+
}
|
|
105
|
+
if (import_errors.RetryableError.isRetryableStatusCode(resp.statusCode)) {
|
|
106
|
+
logger.warn(`Retryable status code received: ${resp.statusCode}`);
|
|
107
|
+
throw new import_errors.RetryableError("retryable error during bulk get", resp.statusCode);
|
|
108
|
+
}
|
|
109
|
+
if (resp.statusCode !== 200) {
|
|
110
|
+
logger.error(`Unexpected status code: ${resp.statusCode}`);
|
|
111
|
+
throw new Error("could not fetch");
|
|
112
|
+
}
|
|
113
|
+
const body = resp.body;
|
|
114
|
+
return body;
|
|
115
|
+
});
|
|
116
|
+
const bulkRemove = import_bulk.BulkRemove.implement(async (config, ids) => {
|
|
117
|
+
const logger = (0, import_logger.createLogger)(config);
|
|
118
|
+
logger.info(`Starting bulk remove for ${ids.length} documents`);
|
|
119
|
+
const resp = await bulkGet(config, ids);
|
|
120
|
+
const toRemove = [];
|
|
121
|
+
resp.rows.forEach((row) => {
|
|
122
|
+
if (!row.doc) return;
|
|
123
|
+
try {
|
|
124
|
+
const d = import_crud2.CouchDoc.parse(row.doc);
|
|
125
|
+
d._deleted = true;
|
|
126
|
+
toRemove.push(d);
|
|
127
|
+
} catch (e) {
|
|
128
|
+
logger.warn(`Invalid document structure in bulk remove: ${row.id}`, e);
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
return bulkSave(config, toRemove);
|
|
132
|
+
});
|
|
133
|
+
const bulkGetDictionary = import_bulk.BulkGetDictionary.implement(async (config, ids) => {
|
|
134
|
+
const resp = await bulkGet(config, ids);
|
|
135
|
+
const results = { found: {}, notFound: {} };
|
|
136
|
+
resp.rows.forEach(
|
|
137
|
+
/** @param { import('../schema/query.mjs').ViewRowSchema } row */
|
|
138
|
+
(row) => {
|
|
139
|
+
if (!row.key) return;
|
|
140
|
+
if (row.error) {
|
|
141
|
+
results.notFound[row.key] = row;
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
try {
|
|
145
|
+
const doc = import_crud2.CouchDoc.parse(row.doc);
|
|
146
|
+
results.found[doc._id] = doc;
|
|
147
|
+
} catch (e) {
|
|
148
|
+
results.notFound[row.key] = row;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
);
|
|
152
|
+
return results;
|
|
153
|
+
});
|
|
154
|
+
const bulkSaveTransaction = import_bulk.BulkSaveTransaction.implement(async (config, transactionId, docs) => {
|
|
155
|
+
const emitter = (0, import_trackedEmitter.setupEmitter)(config);
|
|
156
|
+
const logger = (0, import_logger.createLogger)(config);
|
|
157
|
+
const retryOptions = {
|
|
158
|
+
maxRetries: config.maxRetries ?? 10,
|
|
159
|
+
initialDelay: config.initialDelay ?? 1e3,
|
|
160
|
+
backoffFactor: config.backoffFactor ?? 2
|
|
161
|
+
};
|
|
162
|
+
const _put = config.bindWithRetry ? (0, import_retry.withRetry)(import_crud.put.bind(null, config), retryOptions) : import_crud.put.bind(null, config);
|
|
163
|
+
logger.info(`Starting bulk save transaction ${transactionId} for ${docs.length} documents`);
|
|
164
|
+
const txnDoc = {
|
|
165
|
+
_id: `txn:${transactionId}`,
|
|
166
|
+
_rev: null,
|
|
167
|
+
type: "transaction",
|
|
168
|
+
status: "pending",
|
|
169
|
+
changes: docs,
|
|
170
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
171
|
+
};
|
|
172
|
+
let txnresp = await _put(txnDoc);
|
|
173
|
+
logger.debug("Transaction document created:", txnDoc, txnresp);
|
|
174
|
+
await emitter.emit("transaction-created", { txnresp, txnDoc });
|
|
175
|
+
if (txnresp.error) {
|
|
176
|
+
throw new import_transactionErrors.TransactionSetupError("Failed to create transaction document", {
|
|
177
|
+
error: txnresp.error,
|
|
178
|
+
response: txnresp.body
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
const existingDocs = await bulkGetDictionary(config, docs.map((d) => d._id));
|
|
182
|
+
logger.debug("Fetched current revisions of documents:", existingDocs);
|
|
183
|
+
await emitter.emit("transaction-revs-fetched", existingDocs);
|
|
184
|
+
const revErrors = [];
|
|
185
|
+
docs.forEach((d) => {
|
|
186
|
+
if (existingDocs.found[d._id] && existingDocs.found[d._id]._rev !== d._rev) revErrors.push(d._id);
|
|
187
|
+
if (existingDocs.notFound[d._id] && d._rev) revErrors.push(d._id);
|
|
188
|
+
});
|
|
189
|
+
if (revErrors.length > 0) {
|
|
190
|
+
throw new import_transactionErrors.TransactionVersionConflictError(revErrors);
|
|
191
|
+
}
|
|
192
|
+
logger.debug("Checked document revisions:", existingDocs);
|
|
193
|
+
await emitter.emit("transaction-revs-checked", existingDocs);
|
|
194
|
+
const providedDocsById = {};
|
|
195
|
+
docs.forEach((d) => {
|
|
196
|
+
if (!d._id) return;
|
|
197
|
+
providedDocsById[d._id] = d;
|
|
198
|
+
});
|
|
199
|
+
const newDocsToRollback = [];
|
|
200
|
+
const potentialExistingDocsToRollack = [];
|
|
201
|
+
const failedDocs = [];
|
|
202
|
+
try {
|
|
203
|
+
logger.info("Transaction started:", txnDoc);
|
|
204
|
+
await emitter.emit("transaction-started", txnDoc);
|
|
205
|
+
const results = await bulkSave(config, docs);
|
|
206
|
+
logger.info("Transaction updates applied:", results);
|
|
207
|
+
await emitter.emit("transaction-updates-applied", results);
|
|
208
|
+
results.forEach((r) => {
|
|
209
|
+
if (!r.id) return;
|
|
210
|
+
if (!r.error) {
|
|
211
|
+
if (existingDocs.notFound[r.id]) newDocsToRollback.push(r);
|
|
212
|
+
if (existingDocs.found[r.id]) potentialExistingDocsToRollack.push(r);
|
|
213
|
+
} else {
|
|
214
|
+
failedDocs.push(r);
|
|
215
|
+
}
|
|
216
|
+
});
|
|
217
|
+
if (failedDocs.length > 0) {
|
|
218
|
+
throw new import_transactionErrors.TransactionBulkOperationError(failedDocs);
|
|
219
|
+
}
|
|
220
|
+
txnDoc.status = "completed";
|
|
221
|
+
txnDoc._rev = txnresp.rev;
|
|
222
|
+
txnresp = await _put(txnDoc);
|
|
223
|
+
logger.info("Transaction completed:", txnDoc);
|
|
224
|
+
await emitter.emit("transaction-completed", { txnresp, txnDoc });
|
|
225
|
+
if (txnresp.statusCode !== 201) {
|
|
226
|
+
logger.error("Failed to update transaction status to completed");
|
|
227
|
+
}
|
|
228
|
+
return results;
|
|
229
|
+
} catch (error) {
|
|
230
|
+
logger.error("Transaction failed, attempting rollback:", error);
|
|
231
|
+
const toRollback = [];
|
|
232
|
+
potentialExistingDocsToRollack.forEach((row) => {
|
|
233
|
+
if (!row.id || !row.rev) return;
|
|
234
|
+
const doc = existingDocs.found[row.id];
|
|
235
|
+
doc._rev = row.rev;
|
|
236
|
+
toRollback.push(doc);
|
|
237
|
+
});
|
|
238
|
+
newDocsToRollback.forEach((d) => {
|
|
239
|
+
if (!d.id || !d.rev) return;
|
|
240
|
+
const before = JSON.parse(JSON.stringify(providedDocsById[d.id]));
|
|
241
|
+
before._rev = d.rev;
|
|
242
|
+
before._deleted = true;
|
|
243
|
+
toRollback.push(before);
|
|
244
|
+
});
|
|
245
|
+
const bulkRollbackResult = await bulkSave(config, toRollback);
|
|
246
|
+
let status = "rolled_back";
|
|
247
|
+
bulkRollbackResult.forEach((r) => {
|
|
248
|
+
if (r.error) status = "rollback_failed";
|
|
249
|
+
});
|
|
250
|
+
logger.warn("Transaction rolled back:", { bulkRollbackResult, status });
|
|
251
|
+
await emitter.emit("transaction-rolled-back", { bulkRollbackResult, status });
|
|
252
|
+
txnDoc.status = status;
|
|
253
|
+
txnDoc._rev = txnresp.rev;
|
|
254
|
+
txnresp = await _put(txnDoc);
|
|
255
|
+
logger.warn("Transaction rollback status updated:", txnDoc);
|
|
256
|
+
await emitter.emit("transaction-rolled-back-status", { txnresp, txnDoc });
|
|
257
|
+
if (txnresp.statusCode !== 201) {
|
|
258
|
+
logger.error("Failed to update transaction status to rolled_back");
|
|
259
|
+
}
|
|
260
|
+
throw new import_transactionErrors.TransactionRollbackError(
|
|
261
|
+
"Transaction failed and rollback was unsuccessful",
|
|
262
|
+
/** @type {Error} */
|
|
263
|
+
error,
|
|
264
|
+
bulkRollbackResult
|
|
265
|
+
);
|
|
266
|
+
}
|
|
267
|
+
});
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
var changes_exports = {};
|
|
30
|
+
__export(changes_exports, {
|
|
31
|
+
changes: () => changes
|
|
32
|
+
});
|
|
33
|
+
module.exports = __toCommonJS(changes_exports);
|
|
34
|
+
var import_needle = __toESM(require("needle"), 1);
|
|
35
|
+
var import_events = require("events");
|
|
36
|
+
var import_changes = require("../schema/changes.cjs");
|
|
37
|
+
var import_changes_stream = __toESM(require("changes-stream"), 1);
|
|
38
|
+
const changes = import_changes.Changes.implement(async (config, onChange, options = {}) => {
|
|
39
|
+
const emitter = new import_events.EventEmitter();
|
|
40
|
+
options.db = config.couch;
|
|
41
|
+
if (options.since && options.since === "now") {
|
|
42
|
+
const opts = {
|
|
43
|
+
json: true,
|
|
44
|
+
headers: {
|
|
45
|
+
"Content-Type": "application/json"
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
const resp = await (0, import_needle.default)("get", config.couch, opts);
|
|
49
|
+
options.since = resp.body.update_seq;
|
|
50
|
+
}
|
|
51
|
+
const changes2 = (0, import_changes_stream.default)(options);
|
|
52
|
+
changes2.on("readable", () => {
|
|
53
|
+
const change = changes2.read();
|
|
54
|
+
if (change.results && Array.isArray(change.results)) {
|
|
55
|
+
change.results.forEach((c) => emitter.emit("change", c));
|
|
56
|
+
} else emitter.emit("change", change);
|
|
57
|
+
});
|
|
58
|
+
emitter.on("change", onChange);
|
|
59
|
+
return {
|
|
60
|
+
on: (event, listener) => emitter.on(event, listener),
|
|
61
|
+
removeListener: (event, listener) => emitter.removeListener(event, listener),
|
|
62
|
+
stop: () => {
|
|
63
|
+
changes2.destroy();
|
|
64
|
+
emitter.removeAllListeners();
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
});
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
var crud_exports = {};
|
|
30
|
+
__export(crud_exports, {
|
|
31
|
+
get: () => get,
|
|
32
|
+
getAtRev: () => getAtRev,
|
|
33
|
+
put: () => put
|
|
34
|
+
});
|
|
35
|
+
module.exports = __toCommonJS(crud_exports);
|
|
36
|
+
var import_needle = __toESM(require("needle"), 1);
|
|
37
|
+
var import_crud = require("../schema/crud.cjs");
|
|
38
|
+
var import_errors = require("./errors.cjs");
|
|
39
|
+
var import_logger = require("./logger.cjs");
|
|
40
|
+
const opts = {
|
|
41
|
+
json: true,
|
|
42
|
+
headers: {
|
|
43
|
+
"Content-Type": "application/json"
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
const _getWithOptions = import_crud.CouchGetWithOptions.implement(async (config, id, getOpts) => {
|
|
47
|
+
const logger = (0, import_logger.createLogger)(config);
|
|
48
|
+
const rev = getOpts?.rev;
|
|
49
|
+
const path = rev ? `${id}?rev=${rev}` : id;
|
|
50
|
+
const url = `${config.couch}/${path}`;
|
|
51
|
+
logger.info(`Getting document with id: ${id}, rev ${rev || "latest"}`);
|
|
52
|
+
try {
|
|
53
|
+
const resp = await (0, import_needle.default)("get", url, opts);
|
|
54
|
+
if (!resp) {
|
|
55
|
+
logger.error("No response received from get request");
|
|
56
|
+
throw new import_errors.RetryableError("no response", 503);
|
|
57
|
+
}
|
|
58
|
+
const result = resp?.body || {};
|
|
59
|
+
if (resp.statusCode === 404) {
|
|
60
|
+
if (config.throwOnGetNotFound) {
|
|
61
|
+
logger.warn(`Document not found (throwing error): ${id}, rev ${rev || "latest"}`);
|
|
62
|
+
throw new import_errors.NotFoundError(id, result.reason || "not_found");
|
|
63
|
+
} else {
|
|
64
|
+
logger.debug(`Document not found (returning undefined): ${id}, rev ${rev || "latest"}`);
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
if (import_errors.RetryableError.isRetryableStatusCode(resp.statusCode)) {
|
|
69
|
+
logger.warn(`Retryable status code received: ${resp.statusCode}`);
|
|
70
|
+
throw new import_errors.RetryableError(result.reason || "retryable error", resp.statusCode);
|
|
71
|
+
}
|
|
72
|
+
if (resp.statusCode !== 200) {
|
|
73
|
+
logger.error(`Unexpected status code: ${resp.statusCode}`);
|
|
74
|
+
throw new Error(result.reason || "failed");
|
|
75
|
+
}
|
|
76
|
+
logger.info(`Successfully retrieved document: ${id}, rev ${rev || "latest"}`);
|
|
77
|
+
return result;
|
|
78
|
+
} catch (err) {
|
|
79
|
+
logger.error("Error during get operation:", err);
|
|
80
|
+
import_errors.RetryableError.handleNetworkError(err);
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
const get = import_crud.CouchGet.implement(async (config, id) => {
|
|
84
|
+
const getOptions = {};
|
|
85
|
+
return _getWithOptions(config, id, getOptions);
|
|
86
|
+
});
|
|
87
|
+
const getAtRev = import_crud.CouchGetAtRev.implement(async (config, id, rev) => {
|
|
88
|
+
const getOptions = { rev };
|
|
89
|
+
return _getWithOptions(config, id, getOptions);
|
|
90
|
+
});
|
|
91
|
+
const put = import_crud.CouchPut.implement(async (config, doc) => {
|
|
92
|
+
const logger = (0, import_logger.createLogger)(config);
|
|
93
|
+
const url = `${config.couch}/${doc._id}`;
|
|
94
|
+
const body = doc;
|
|
95
|
+
logger.info(`Putting document with id: ${doc._id}`);
|
|
96
|
+
let resp;
|
|
97
|
+
try {
|
|
98
|
+
resp = await (0, import_needle.default)("put", url, body, opts);
|
|
99
|
+
} catch (err) {
|
|
100
|
+
logger.error("Error during put operation:", err);
|
|
101
|
+
import_errors.RetryableError.handleNetworkError(err);
|
|
102
|
+
}
|
|
103
|
+
if (!resp) {
|
|
104
|
+
logger.error("No response received from put request");
|
|
105
|
+
throw new import_errors.RetryableError("no response", 503);
|
|
106
|
+
}
|
|
107
|
+
const result = resp?.body || {};
|
|
108
|
+
result.statusCode = resp.statusCode;
|
|
109
|
+
if (resp.statusCode === 409) {
|
|
110
|
+
logger.warn(`Conflict detected for document: ${doc._id}`);
|
|
111
|
+
result.ok = false;
|
|
112
|
+
result.error = "conflict";
|
|
113
|
+
return result;
|
|
114
|
+
}
|
|
115
|
+
if (import_errors.RetryableError.isRetryableStatusCode(resp.statusCode)) {
|
|
116
|
+
logger.warn(`Retryable status code received: ${resp.statusCode}`);
|
|
117
|
+
throw new import_errors.RetryableError(result.reason || "retryable error", resp.statusCode);
|
|
118
|
+
}
|
|
119
|
+
logger.info(`Successfully saved document: ${doc._id}`);
|
|
120
|
+
return result;
|
|
121
|
+
});
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var errors_exports = {};
|
|
20
|
+
__export(errors_exports, {
|
|
21
|
+
NotFoundError: () => NotFoundError,
|
|
22
|
+
RetryableError: () => RetryableError
|
|
23
|
+
});
|
|
24
|
+
module.exports = __toCommonJS(errors_exports);
|
|
25
|
+
class NotFoundError extends Error {
|
|
26
|
+
/**
|
|
27
|
+
* @param {string} docId - The ID of the document that wasn't found
|
|
28
|
+
* @param {string} [message] - Optional error message
|
|
29
|
+
*/
|
|
30
|
+
constructor(docId, message = "Document not found") {
|
|
31
|
+
super(message);
|
|
32
|
+
this.name = "NotFoundError";
|
|
33
|
+
this.docId = docId;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
class RetryableError extends Error {
|
|
37
|
+
/**
|
|
38
|
+
* @param {string} message - The error message
|
|
39
|
+
* @param {number|undefined} statusCode - The HTTP status code
|
|
40
|
+
*/
|
|
41
|
+
constructor(message, statusCode) {
|
|
42
|
+
super(message);
|
|
43
|
+
this.name = "RetryableError";
|
|
44
|
+
this.statusCode = statusCode;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* @param {number|undefined} statusCode - The HTTP status code to check
|
|
48
|
+
* @returns {boolean} Whether the status code is retryable
|
|
49
|
+
*/
|
|
50
|
+
static isRetryableStatusCode(statusCode) {
|
|
51
|
+
if (statusCode === void 0) return false;
|
|
52
|
+
return [408, 429, 500, 502, 503, 504].includes(statusCode);
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* @param {NetworkError | unknown} err - The network error to handle
|
|
56
|
+
* @throws {RetryableError} If the error is retryable
|
|
57
|
+
* @throws {Error} If the error is not retryable
|
|
58
|
+
*/
|
|
59
|
+
static handleNetworkError(err) {
|
|
60
|
+
const networkErrors = {
|
|
61
|
+
ECONNREFUSED: 503,
|
|
62
|
+
ECONNRESET: 503,
|
|
63
|
+
ETIMEDOUT: 503,
|
|
64
|
+
ENETUNREACH: 503,
|
|
65
|
+
ENOTFOUND: 503,
|
|
66
|
+
EPIPE: 503,
|
|
67
|
+
EHOSTUNREACH: 503,
|
|
68
|
+
ESOCKETTIMEDOUT: 503
|
|
69
|
+
};
|
|
70
|
+
if (typeof err === "object" && err !== null && "code" in err && typeof err.code === "string" && networkErrors[err.code]) {
|
|
71
|
+
throw new RetryableError(`Network error: ${err.code}`, networkErrors[err.code]);
|
|
72
|
+
}
|
|
73
|
+
throw err;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var logger_exports = {};
|
|
20
|
+
__export(logger_exports, {
|
|
21
|
+
createLogger: () => createLogger
|
|
22
|
+
});
|
|
23
|
+
module.exports = __toCommonJS(logger_exports);
|
|
24
|
+
function createLogger(config) {
|
|
25
|
+
if (config._normalizedLogger) {
|
|
26
|
+
return config._normalizedLogger;
|
|
27
|
+
}
|
|
28
|
+
if (!config.logger) {
|
|
29
|
+
if (config.useConsoleLogger) {
|
|
30
|
+
config._normalizedLogger = {
|
|
31
|
+
error: (...args) => console.error(...args),
|
|
32
|
+
warn: (...args) => console.warn(...args),
|
|
33
|
+
info: (...args) => console.info(...args),
|
|
34
|
+
debug: (...args) => console.debug(...args)
|
|
35
|
+
};
|
|
36
|
+
} else {
|
|
37
|
+
config._normalizedLogger = {
|
|
38
|
+
error: () => {
|
|
39
|
+
},
|
|
40
|
+
warn: () => {
|
|
41
|
+
},
|
|
42
|
+
info: () => {
|
|
43
|
+
},
|
|
44
|
+
debug: () => {
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
return config._normalizedLogger;
|
|
49
|
+
}
|
|
50
|
+
if (typeof config.logger === "function") {
|
|
51
|
+
config._normalizedLogger = {
|
|
52
|
+
error: (...args) => config.logger("error", ...args),
|
|
53
|
+
warn: (...args) => config.logger("warn", ...args),
|
|
54
|
+
info: (...args) => config.logger("info", ...args),
|
|
55
|
+
debug: (...args) => config.logger("debug", ...args)
|
|
56
|
+
};
|
|
57
|
+
return config._normalizedLogger;
|
|
58
|
+
}
|
|
59
|
+
config._normalizedLogger = {
|
|
60
|
+
error: config.logger.error || (() => {
|
|
61
|
+
}),
|
|
62
|
+
warn: config.logger.warn || (() => {
|
|
63
|
+
}),
|
|
64
|
+
info: config.logger.info || (() => {
|
|
65
|
+
}),
|
|
66
|
+
debug: config.logger.debug || (() => {
|
|
67
|
+
})
|
|
68
|
+
};
|
|
69
|
+
return config._normalizedLogger;
|
|
70
|
+
}
|