hide-a-bed 3.0.0 → 4.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.
- package/README.md +104 -0
- package/cjs/impl/bulk.cjs +55 -6
- package/cjs/impl/crud.cjs +57 -7
- package/cjs/impl/errors.cjs +63 -0
- package/cjs/impl/logger.cjs +61 -0
- package/cjs/impl/patch.cjs +10 -5
- package/cjs/impl/query.cjs +11 -1
- package/cjs/impl/retry.cjs +54 -0
- package/cjs/impl/stream.cjs +48 -7
- package/cjs/index.cjs +27 -3
- package/cjs/schema/bind.cjs +40 -0
- package/cjs/schema/bulk.cjs +14 -0
- package/cjs/schema/config.cjs +20 -1
- package/cjs/schema/crud.cjs +9 -1
- package/cjs/schema/patch.cjs +8 -8
- package/cjs/schema/query.cjs +28 -19
- package/cjs/schema/stream.cjs +42 -0
- package/impl/bulk.d.mts +7 -0
- package/impl/bulk.d.mts.map +1 -0
- package/impl/bulk.mjs +58 -6
- package/impl/crud.d.mts +5 -0
- package/impl/crud.d.mts.map +1 -0
- package/impl/crud.mjs +67 -6
- package/impl/errors.d.mts +35 -0
- package/impl/errors.d.mts.map +1 -0
- package/impl/errors.mjs +53 -0
- package/impl/logger.d.mts +32 -0
- package/impl/logger.d.mts.map +1 -0
- package/impl/logger.mjs +59 -0
- package/impl/patch.d.mts +4 -0
- package/impl/patch.d.mts.map +1 -0
- package/impl/patch.mjs +38 -6
- package/impl/query.d.mts +170 -0
- package/impl/query.d.mts.map +1 -0
- package/impl/query.mjs +38 -2
- package/impl/retry.d.mts +2 -0
- package/impl/retry.d.mts.map +1 -0
- package/impl/retry.mjs +39 -0
- package/impl/stream.d.mts +3 -0
- package/impl/stream.d.mts.map +1 -0
- package/impl/stream.mjs +72 -17
- package/index.d.mts +39 -0
- package/index.d.mts.map +1 -0
- package/index.mjs +33 -4
- package/package.json +1 -1
- package/schema/bind.d.mts +470 -0
- package/schema/bind.d.mts.map +1 -0
- package/schema/bind.mjs +21 -0
- package/schema/bulk.d.mts +358 -0
- package/schema/bulk.d.mts.map +1 -0
- package/schema/bulk.mjs +17 -0
- package/schema/config.d.mts +76 -0
- package/schema/config.d.mts.map +1 -0
- package/schema/config.mjs +22 -1
- package/schema/crud.d.mts +260 -0
- package/schema/crud.d.mts.map +1 -0
- package/schema/crud.mjs +12 -0
- package/schema/patch.d.mts +116 -0
- package/schema/patch.d.mts.map +1 -0
- package/schema/patch.mjs +11 -7
- package/schema/query.d.mts +362 -0
- package/schema/query.d.mts.map +1 -0
- package/schema/query.mjs +30 -18
- package/schema/stream.d.mts +193 -0
- package/schema/stream.d.mts.map +1 -0
- package/schema/stream.mjs +23 -0
- package/build/build.mjs +0 -16
- package/build/build.rewrite-imports.mjs +0 -14
|
@@ -0,0 +1,40 @@
|
|
|
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 bind_exports = {};
|
|
20
|
+
__export(bind_exports, {
|
|
21
|
+
Bind: () => Bind
|
|
22
|
+
});
|
|
23
|
+
module.exports = __toCommonJS(bind_exports);
|
|
24
|
+
var import_zod = require("zod");
|
|
25
|
+
var import_config = require("./config.cjs");
|
|
26
|
+
var import_bulk = require("./bulk.cjs");
|
|
27
|
+
var import_crud = require("./crud.cjs");
|
|
28
|
+
var import_patch = require("./patch.cjs");
|
|
29
|
+
var import_query = require("./query.cjs");
|
|
30
|
+
var import_stream = require("./stream.cjs");
|
|
31
|
+
const BindReturns = import_zod.z.object({
|
|
32
|
+
bulkGet: import_bulk.BulkGetBound,
|
|
33
|
+
bulkSave: import_bulk.BulkSaveBound,
|
|
34
|
+
get: import_crud.CouchGetBound,
|
|
35
|
+
put: import_crud.CouchPutBound,
|
|
36
|
+
patch: import_patch.PatchBound,
|
|
37
|
+
query: import_query.SimpleViewQueryBound,
|
|
38
|
+
queryStream: import_stream.SimpleViewQueryStreamBound
|
|
39
|
+
});
|
|
40
|
+
const Bind = import_zod.z.function().args(import_config.CouchConfig).returns(BindReturns);
|
package/cjs/schema/bulk.cjs
CHANGED
|
@@ -19,8 +19,11 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
19
19
|
var bulk_exports = {};
|
|
20
20
|
__export(bulk_exports, {
|
|
21
21
|
BulkGet: () => BulkGet,
|
|
22
|
+
BulkGetBound: () => BulkGetBound,
|
|
22
23
|
BulkRemove: () => BulkRemove,
|
|
24
|
+
BulkRemoveBound: () => BulkRemoveBound,
|
|
23
25
|
BulkSave: () => BulkSave,
|
|
26
|
+
BulkSaveBound: () => BulkSaveBound,
|
|
24
27
|
BulkSaveResponseSchema: () => BulkSaveResponseSchema
|
|
25
28
|
});
|
|
26
29
|
module.exports = __toCommonJS(bulk_exports);
|
|
@@ -40,11 +43,22 @@ const BulkSave = import_zod.z.function().args(
|
|
|
40
43
|
_id: import_zod.z.string()
|
|
41
44
|
}).passthrough())
|
|
42
45
|
).returns(import_zod.z.promise(BulkSaveResponseSchema));
|
|
46
|
+
const BulkSaveBound = import_zod.z.function().args(
|
|
47
|
+
import_zod.z.array(import_zod.z.object({
|
|
48
|
+
_id: import_zod.z.string()
|
|
49
|
+
}).passthrough())
|
|
50
|
+
).returns(import_zod.z.promise(BulkSaveResponseSchema));
|
|
43
51
|
const BulkGet = import_zod.z.function().args(
|
|
44
52
|
import_config.CouchConfig,
|
|
45
53
|
import_zod.z.array(import_zod.z.string().describe("the ids to get"))
|
|
46
54
|
).returns(import_zod.z.promise(import_zod.z.array(import_crud.CouchDoc)));
|
|
55
|
+
const BulkGetBound = import_zod.z.function().args(
|
|
56
|
+
import_zod.z.array(import_zod.z.string().describe("the ids to get"))
|
|
57
|
+
).returns(import_zod.z.promise(import_zod.z.array(import_crud.CouchDoc)));
|
|
47
58
|
const BulkRemove = import_zod.z.function().args(
|
|
48
59
|
import_config.CouchConfig,
|
|
49
60
|
import_zod.z.array(import_zod.z.string().describe("the ids to delete"))
|
|
50
61
|
).returns(import_zod.z.promise(BulkSaveResponseSchema));
|
|
62
|
+
const BulkRemoveBound = import_zod.z.function().args(
|
|
63
|
+
import_zod.z.array(import_zod.z.string().describe("the ids to delete"))
|
|
64
|
+
).returns(import_zod.z.promise(BulkSaveResponseSchema));
|
package/cjs/schema/config.cjs
CHANGED
|
@@ -22,6 +22,25 @@ __export(config_exports, {
|
|
|
22
22
|
});
|
|
23
23
|
module.exports = __toCommonJS(config_exports);
|
|
24
24
|
var import_zod = require("zod");
|
|
25
|
+
const LoggerSchema = import_zod.z.object({
|
|
26
|
+
error: import_zod.z.function().args(import_zod.z.any()).returns(import_zod.z.void()).optional(),
|
|
27
|
+
warn: import_zod.z.function().args(import_zod.z.any()).returns(import_zod.z.void()).optional(),
|
|
28
|
+
info: import_zod.z.function().args(import_zod.z.any()).returns(import_zod.z.void()).optional(),
|
|
29
|
+
debug: import_zod.z.function().args(import_zod.z.any()).returns(import_zod.z.void()).optional()
|
|
30
|
+
}).or(import_zod.z.function().args(
|
|
31
|
+
import_zod.z.string(),
|
|
32
|
+
// level
|
|
33
|
+
import_zod.z.any()
|
|
34
|
+
// message/args
|
|
35
|
+
).returns(import_zod.z.void()));
|
|
25
36
|
const CouchConfig = import_zod.z.object({
|
|
26
|
-
|
|
37
|
+
throwOnGetNotFound: import_zod.z.boolean().optional().default(false).describe("if a get is 404 should we throw or return undefined"),
|
|
38
|
+
couch: import_zod.z.string().describe("the url of the couch db"),
|
|
39
|
+
bindWithRetry: import_zod.z.boolean().optional().default(true).describe("should we bind with retry"),
|
|
40
|
+
maxRetries: import_zod.z.number().optional().default(3).describe("maximum number of retry attempts"),
|
|
41
|
+
initialDelay: import_zod.z.number().optional().default(1e3).describe("initial retry delay in milliseconds"),
|
|
42
|
+
backoffFactor: import_zod.z.number().optional().default(2).describe("multiplier for exponential backoff"),
|
|
43
|
+
logger: LoggerSchema.optional().describe("logging interface supporting winston-like or simple function interface"),
|
|
44
|
+
_normalizedLogger: import_zod.z.any().optional()
|
|
45
|
+
// Internal property for caching normalized logger
|
|
27
46
|
}).passthrough().describe("The std config object");
|
package/cjs/schema/crud.cjs
CHANGED
|
@@ -21,7 +21,9 @@ __export(crud_exports, {
|
|
|
21
21
|
CouchDoc: () => CouchDoc,
|
|
22
22
|
CouchDocResponse: () => CouchDocResponse,
|
|
23
23
|
CouchGet: () => CouchGet,
|
|
24
|
-
|
|
24
|
+
CouchGetBound: () => CouchGetBound,
|
|
25
|
+
CouchPut: () => CouchPut,
|
|
26
|
+
CouchPutBound: () => CouchPutBound
|
|
25
27
|
});
|
|
26
28
|
module.exports = __toCommonJS(crud_exports);
|
|
27
29
|
var import_zod = require("zod");
|
|
@@ -41,7 +43,13 @@ const CouchPut = import_zod.z.function().args(
|
|
|
41
43
|
import_config.CouchConfig,
|
|
42
44
|
CouchDoc
|
|
43
45
|
).returns(import_zod.z.promise(CouchDocResponse));
|
|
46
|
+
const CouchPutBound = import_zod.z.function().args(
|
|
47
|
+
CouchDoc
|
|
48
|
+
).returns(import_zod.z.promise(CouchDocResponse));
|
|
44
49
|
const CouchGet = import_zod.z.function().args(
|
|
45
50
|
import_config.CouchConfig,
|
|
46
51
|
import_zod.z.string().describe("the couch doc id")
|
|
47
52
|
).returns(import_zod.z.promise(CouchDoc.nullable()));
|
|
53
|
+
const CouchGetBound = import_zod.z.function().args(
|
|
54
|
+
import_zod.z.string().describe("the couch doc id")
|
|
55
|
+
).returns(import_zod.z.promise(CouchDoc.nullable()));
|
package/cjs/schema/patch.cjs
CHANGED
|
@@ -18,21 +18,21 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
18
18
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
19
|
var patch_exports = {};
|
|
20
20
|
__export(patch_exports, {
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
Patch: () => Patch,
|
|
22
|
+
PatchBound: () => PatchBound,
|
|
23
23
|
PatchProperties: () => PatchProperties
|
|
24
24
|
});
|
|
25
25
|
module.exports = __toCommonJS(patch_exports);
|
|
26
26
|
var import_zod = require("zod");
|
|
27
27
|
var import_config = require("./config.cjs");
|
|
28
28
|
var import_crud = require("./crud.cjs");
|
|
29
|
-
const PatchConfig = import_config.CouchConfig.extend({
|
|
30
|
-
retries: import_zod.z.number().min(0).max(100).optional(),
|
|
31
|
-
delay: import_zod.z.number().min(0).optional()
|
|
32
|
-
});
|
|
33
29
|
const PatchProperties = import_zod.z.record(import_zod.z.string(), import_zod.z.any());
|
|
34
|
-
const
|
|
35
|
-
|
|
30
|
+
const Patch = import_zod.z.function().args(
|
|
31
|
+
import_config.CouchConfig,
|
|
32
|
+
import_zod.z.string().describe("the couch doc id"),
|
|
33
|
+
PatchProperties
|
|
34
|
+
).returns(import_zod.z.promise(import_crud.CouchDocResponse));
|
|
35
|
+
const PatchBound = import_zod.z.function().args(
|
|
36
36
|
import_zod.z.string().describe("the couch doc id"),
|
|
37
37
|
PatchProperties
|
|
38
38
|
).returns(import_zod.z.promise(import_crud.CouchDocResponse));
|
package/cjs/schema/query.cjs
CHANGED
|
@@ -18,34 +18,43 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
18
18
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
19
|
var query_exports = {};
|
|
20
20
|
__export(query_exports, {
|
|
21
|
+
SimpleViewOptions: () => SimpleViewOptions,
|
|
21
22
|
SimpleViewQuery: () => SimpleViewQuery,
|
|
22
|
-
|
|
23
|
+
SimpleViewQueryBound: () => SimpleViewQueryBound,
|
|
24
|
+
SimpleViewQueryResponse: () => SimpleViewQueryResponse,
|
|
25
|
+
ViewRow: () => ViewRow
|
|
23
26
|
});
|
|
24
27
|
module.exports = __toCommonJS(query_exports);
|
|
25
28
|
var import_zod = require("zod");
|
|
26
29
|
var import_config = require("./config.cjs");
|
|
30
|
+
const ViewRow = import_zod.z.object({
|
|
31
|
+
id: import_zod.z.string().optional(),
|
|
32
|
+
key: import_zod.z.any().nullable(),
|
|
33
|
+
value: import_zod.z.any().nullable(),
|
|
34
|
+
doc: import_zod.z.object({}).passthrough().optional()
|
|
35
|
+
});
|
|
27
36
|
const SimpleViewQueryResponse = import_zod.z.object({
|
|
28
37
|
error: import_zod.z.string().optional().describe("if something is wrong"),
|
|
29
|
-
rows: import_zod.z.array(
|
|
30
|
-
id: import_zod.z.string().optional(),
|
|
31
|
-
key: import_zod.z.any().nullable(),
|
|
32
|
-
value: import_zod.z.any().nullable(),
|
|
33
|
-
doc: import_zod.z.object({}).passthrough().optional()
|
|
34
|
-
}))
|
|
38
|
+
rows: import_zod.z.array(ViewRow)
|
|
35
39
|
}).passthrough();
|
|
40
|
+
const SimpleViewOptions = import_zod.z.object({
|
|
41
|
+
startkey: import_zod.z.any().optional(),
|
|
42
|
+
endkey: import_zod.z.any().optional(),
|
|
43
|
+
descending: import_zod.z.boolean().optional().describe("sort results descending"),
|
|
44
|
+
skip: import_zod.z.number().positive().optional().describe("skip this many rows"),
|
|
45
|
+
limit: import_zod.z.number().positive().optional().describe("limit the results to this many rows"),
|
|
46
|
+
key: import_zod.z.any().optional(),
|
|
47
|
+
include_docs: import_zod.z.boolean().optional().describe("join the id to the doc and return it"),
|
|
48
|
+
reduce: import_zod.z.boolean().optional().describe("reduce the results"),
|
|
49
|
+
group: import_zod.z.boolean().optional().describe("group the results"),
|
|
50
|
+
group_level: import_zod.z.number().positive().optional().describe("group the results at this level")
|
|
51
|
+
}).optional().describe("query options");
|
|
36
52
|
const SimpleViewQuery = import_zod.z.function().args(
|
|
37
53
|
import_config.CouchConfig,
|
|
38
54
|
import_zod.z.string().describe("the view name"),
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
limit: import_zod.z.number().positive().optional().describe("limit the results to this many rows"),
|
|
45
|
-
key: import_zod.z.any().optional(),
|
|
46
|
-
include_docs: import_zod.z.boolean().optional().describe("join the id to the doc and return it"),
|
|
47
|
-
reduce: import_zod.z.boolean().optional().describe("reduce the results"),
|
|
48
|
-
group: import_zod.z.boolean().optional().describe("group the results"),
|
|
49
|
-
group_level: import_zod.z.number().positive().optional().describe("group the results at this level")
|
|
50
|
-
}).optional().describe("query options")
|
|
55
|
+
SimpleViewOptions
|
|
56
|
+
).returns(import_zod.z.promise(SimpleViewQueryResponse));
|
|
57
|
+
const SimpleViewQueryBound = import_zod.z.function().args(
|
|
58
|
+
import_zod.z.string().describe("the view name"),
|
|
59
|
+
SimpleViewOptions
|
|
51
60
|
).returns(import_zod.z.promise(SimpleViewQueryResponse));
|
|
@@ -0,0 +1,42 @@
|
|
|
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 stream_exports = {};
|
|
20
|
+
__export(stream_exports, {
|
|
21
|
+
OnRow: () => OnRow,
|
|
22
|
+
SimpleViewQueryStream: () => SimpleViewQueryStream,
|
|
23
|
+
SimpleViewQueryStreamBound: () => SimpleViewQueryStreamBound
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(stream_exports);
|
|
26
|
+
var import_zod = require("zod");
|
|
27
|
+
var import_config = require("./config.cjs");
|
|
28
|
+
var import_query = require("./query.cjs");
|
|
29
|
+
const OnRow = import_zod.z.function().args(
|
|
30
|
+
import_query.ViewRow
|
|
31
|
+
).returns(import_zod.z.undefined());
|
|
32
|
+
const SimpleViewQueryStream = import_zod.z.function().args(
|
|
33
|
+
import_config.CouchConfig,
|
|
34
|
+
import_zod.z.string().describe("the view name"),
|
|
35
|
+
import_query.SimpleViewOptions,
|
|
36
|
+
OnRow
|
|
37
|
+
).returns(import_zod.z.promise(import_zod.z.undefined()));
|
|
38
|
+
const SimpleViewQueryStreamBound = import_zod.z.function().args(
|
|
39
|
+
import_zod.z.string().describe("the view name"),
|
|
40
|
+
import_query.SimpleViewOptions,
|
|
41
|
+
OnRow
|
|
42
|
+
).returns(import_zod.z.promise(import_zod.z.undefined()));
|
package/impl/bulk.d.mts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/** @type { import('../schema/bulk.mjs').BulkSaveSchema } */
|
|
2
|
+
export const bulkSave: import("../schema/bulk.mjs").BulkSaveSchema;
|
|
3
|
+
/** @type { import('../schema/bulk.mjs').BulkGetSchema } */
|
|
4
|
+
export const bulkGet: import("../schema/bulk.mjs").BulkGetSchema;
|
|
5
|
+
/** @type { import('../schema/bulk.mjs').BulkRemoveSchema } */
|
|
6
|
+
export const bulkRemove: import("../schema/bulk.mjs").BulkRemoveSchema;
|
|
7
|
+
//# sourceMappingURL=bulk.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bulk.d.mts","sourceRoot":"","sources":["bulk.mjs"],"names":[],"mappings":"AAaA,4DAA4D;AAC5D,uBADY,OAAO,oBAAoB,EAAE,cAAc,CAsCrD;AAEF,2DAA2D;AAC3D,sBADY,OAAO,oBAAoB,EAAE,aAAa,CA0CpD;AAEF,8DAA8D;AAC9D,yBADY,OAAO,oBAAoB,EAAE,gBAAgB,CAOvD"}
|
package/impl/bulk.mjs
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
// @ts-check
|
|
2
2
|
import needle from 'needle'
|
|
3
3
|
import { BulkSave, BulkGet, BulkRemove } from '../schema/bulk.mjs'
|
|
4
|
+
import { RetryableError } from './errors.mjs'
|
|
5
|
+
import { createLogger } from './logger.mjs'
|
|
4
6
|
|
|
5
7
|
const opts = {
|
|
6
8
|
json: true,
|
|
@@ -11,24 +13,71 @@ const opts = {
|
|
|
11
13
|
|
|
12
14
|
/** @type { import('../schema/bulk.mjs').BulkSaveSchema } */
|
|
13
15
|
export const bulkSave = BulkSave.implement(async (config, docs) => {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
+
/** @type {import('./logger.mjs').Logger } */
|
|
17
|
+
const logger = createLogger(config)
|
|
18
|
+
|
|
19
|
+
if (!docs) {
|
|
20
|
+
logger.warn('bulkSave called with no docs')
|
|
21
|
+
return { ok: false, error: 'noDocs', reason: 'no docs provided' }
|
|
22
|
+
}
|
|
23
|
+
if (!docs.length) {
|
|
24
|
+
logger.warn('bulkSave called with empty docs array')
|
|
25
|
+
return { ok: false, error: 'noDocs', reason: 'no docs provided' }
|
|
26
|
+
}
|
|
16
27
|
|
|
28
|
+
logger.info(`Starting bulk save of ${docs.length} documents`)
|
|
17
29
|
const url = `${config.couch}/_bulk_docs`
|
|
18
30
|
const body = { docs }
|
|
19
|
-
|
|
20
|
-
|
|
31
|
+
let resp
|
|
32
|
+
try {
|
|
33
|
+
resp = await needle('post', url, body, opts)
|
|
34
|
+
} catch (err) {
|
|
35
|
+
logger.error('Network error during bulk save:', err)
|
|
36
|
+
RetryableError.handleNetworkError(err)
|
|
37
|
+
}
|
|
38
|
+
if (!resp) {
|
|
39
|
+
logger.error('No response received from bulk save request')
|
|
40
|
+
throw new RetryableError('no response', 503)
|
|
41
|
+
}
|
|
42
|
+
if (RetryableError.isRetryableStatusCode(resp.statusCode)) {
|
|
43
|
+
logger.warn(`Retryable status code received: ${resp.statusCode}`)
|
|
44
|
+
throw new RetryableError('retryable error during bulk save', resp.statusCode)
|
|
45
|
+
}
|
|
46
|
+
if (resp.statusCode !== 201) {
|
|
47
|
+
logger.error(`Unexpected status code: ${resp.statusCode}`)
|
|
48
|
+
throw new Error('could not save')
|
|
49
|
+
}
|
|
21
50
|
const results = resp?.body || []
|
|
22
51
|
return results
|
|
23
52
|
})
|
|
24
53
|
|
|
25
54
|
/** @type { import('../schema/bulk.mjs').BulkGetSchema } */
|
|
26
55
|
export const bulkGet = BulkGet.implement(async (config, ids) => {
|
|
56
|
+
const logger = createLogger(config)
|
|
27
57
|
const keys = ids
|
|
58
|
+
|
|
59
|
+
logger.info(`Starting bulk get for ${keys.length} documents`)
|
|
28
60
|
const url = `${config.couch}/_all_docs?include_docs=true`
|
|
29
61
|
const body = { keys }
|
|
30
|
-
|
|
31
|
-
|
|
62
|
+
let resp
|
|
63
|
+
try {
|
|
64
|
+
resp = await needle('post', url, body, opts)
|
|
65
|
+
} catch (err) {
|
|
66
|
+
logger.error('Network error during bulk get:', err)
|
|
67
|
+
RetryableError.handleNetworkError(err)
|
|
68
|
+
}
|
|
69
|
+
if (!resp) {
|
|
70
|
+
logger.error('No response received from bulk get request')
|
|
71
|
+
throw new RetryableError('no response', 503)
|
|
72
|
+
}
|
|
73
|
+
if (RetryableError.isRetryableStatusCode(resp.statusCode)) {
|
|
74
|
+
logger.warn(`Retryable status code received: ${resp.statusCode}`)
|
|
75
|
+
throw new RetryableError('retryable error during bulk get', resp.statusCode)
|
|
76
|
+
}
|
|
77
|
+
if (resp.statusCode !== 200) {
|
|
78
|
+
logger.error(`Unexpected status code: ${resp.statusCode}`)
|
|
79
|
+
throw new Error('could not fetch')
|
|
80
|
+
}
|
|
32
81
|
const rows = resp?.body?.rows || []
|
|
33
82
|
/** @type {Array<import('../schema/crud.mjs').CouchDocSchema>} */
|
|
34
83
|
const docs = []
|
|
@@ -42,11 +91,14 @@ export const bulkGet = BulkGet.implement(async (config, ids) => {
|
|
|
42
91
|
const doc = r.doc
|
|
43
92
|
docs.push(doc)
|
|
44
93
|
})
|
|
94
|
+
logger.info(`Successfully retrieved ${docs.length} documents`)
|
|
45
95
|
return docs
|
|
46
96
|
})
|
|
47
97
|
|
|
48
98
|
/** @type { import('../schema/bulk.mjs').BulkRemoveSchema } */
|
|
49
99
|
export const bulkRemove = BulkRemove.implement(async (config, ids) => {
|
|
100
|
+
const logger = createLogger(config)
|
|
101
|
+
logger.info(`Starting bulk remove for ${ids.length} documents`)
|
|
50
102
|
const docs = await bulkGet(config, ids)
|
|
51
103
|
docs.forEach(d => { d._deleted = true })
|
|
52
104
|
return bulkSave(config, docs)
|
package/impl/crud.d.mts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/** @type { import('../schema/crud.mjs').CouchGetSchema } */
|
|
2
|
+
export const get: import("../schema/crud.mjs").CouchGetSchema;
|
|
3
|
+
/** @type { import('../schema/crud.mjs').CouchPutSchema } */
|
|
4
|
+
export const put: import("../schema/crud.mjs").CouchPutSchema;
|
|
5
|
+
//# sourceMappingURL=crud.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"crud.d.mts","sourceRoot":"","sources":["crud.mjs"],"names":[],"mappings":"AAaA,4DAA4D;AAC5D,kBADY,OAAO,oBAAoB,EAAE,cAAc,CAwCrD;AAEF,4DAA4D;AAC5D,kBADY,OAAO,oBAAoB,EAAE,cAAc,CAqCrD"}
|
package/impl/crud.mjs
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
// @ts-check
|
|
2
2
|
import needle from 'needle'
|
|
3
3
|
import { CouchGet, CouchPut } from '../schema/crud.mjs'
|
|
4
|
+
import { RetryableError } from './errors.mjs'
|
|
5
|
+
import { createLogger } from './logger.mjs'
|
|
4
6
|
|
|
5
7
|
const opts = {
|
|
6
8
|
json: true,
|
|
@@ -9,24 +11,83 @@ const opts = {
|
|
|
9
11
|
}
|
|
10
12
|
}
|
|
11
13
|
|
|
14
|
+
/** @type { import('../schema/crud.mjs').CouchGetSchema } */
|
|
12
15
|
export const get = CouchGet.implement(async (config, id) => {
|
|
16
|
+
const logger = createLogger(config)
|
|
13
17
|
const url = `${config.couch}/${id}`
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
18
|
+
logger.info(`Getting document with id: ${id}`)
|
|
19
|
+
|
|
20
|
+
try {
|
|
21
|
+
const resp = await needle('get', url, opts)
|
|
22
|
+
if (!resp) {
|
|
23
|
+
logger.error('No response received from get request')
|
|
24
|
+
throw new RetryableError('no response', 503)
|
|
25
|
+
}
|
|
26
|
+
if (resp.statusCode === 404) {
|
|
27
|
+
logger.debug(`Document not found: ${id}`)
|
|
28
|
+
return null
|
|
29
|
+
}
|
|
30
|
+
const result = resp?.body || {}
|
|
31
|
+
if (resp.statusCode === 404) {
|
|
32
|
+
if (config.throwOnGetNotFound) {
|
|
33
|
+
logger.warn(`Document not found (throwing error): ${id}`)
|
|
34
|
+
throw new Error(result.reason || 'not_found')
|
|
35
|
+
} else {
|
|
36
|
+
logger.debug(`Document not found (returning undefined): ${id}`)
|
|
37
|
+
return undefined
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
if (RetryableError.isRetryableStatusCode(resp.statusCode)) {
|
|
41
|
+
logger.warn(`Retryable status code received: ${resp.statusCode}`)
|
|
42
|
+
throw new RetryableError(result.reason || 'retryable error', resp.statusCode)
|
|
43
|
+
}
|
|
44
|
+
if (resp.statusCode !== 200) {
|
|
45
|
+
logger.error(`Unexpected status code: ${resp.statusCode}`)
|
|
46
|
+
throw new Error(result.reason || 'failed')
|
|
47
|
+
}
|
|
48
|
+
logger.info(`Successfully retrieved document: ${id}`)
|
|
49
|
+
return result
|
|
50
|
+
} catch (err) {
|
|
51
|
+
logger.error('Error during get operation:', err)
|
|
52
|
+
RetryableError.handleNetworkError(err)
|
|
53
|
+
}
|
|
19
54
|
})
|
|
20
55
|
|
|
56
|
+
/** @type { import('../schema/crud.mjs').CouchPutSchema } */
|
|
21
57
|
export const put = CouchPut.implement(async (config, doc) => {
|
|
58
|
+
const logger = createLogger(config)
|
|
22
59
|
const url = `${config.couch}/${doc._id}`
|
|
23
60
|
const body = doc
|
|
24
|
-
|
|
61
|
+
|
|
62
|
+
logger.info(`Putting document with id: ${doc._id}`)
|
|
63
|
+
let resp
|
|
64
|
+
try {
|
|
65
|
+
resp = await needle('put', url, body, opts)
|
|
66
|
+
} catch (err) {
|
|
67
|
+
logger.error('Error during put operation:', err)
|
|
68
|
+
RetryableError.handleNetworkError(err)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (!resp) {
|
|
72
|
+
logger.error('No response received from put request')
|
|
73
|
+
throw new RetryableError('no response', 503)
|
|
74
|
+
}
|
|
75
|
+
|
|
25
76
|
const result = resp?.body || {}
|
|
26
77
|
result.statusCode = resp.statusCode
|
|
78
|
+
|
|
27
79
|
if (resp.statusCode === 409) {
|
|
80
|
+
logger.warn(`Conflict detected for document: ${doc._id}`)
|
|
28
81
|
result.ok = false
|
|
29
82
|
result.error = 'conflict'
|
|
83
|
+
return result
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (RetryableError.isRetryableStatusCode(resp.statusCode)) {
|
|
87
|
+
logger.warn(`Retryable status code received: ${resp.statusCode}`)
|
|
88
|
+
throw new RetryableError(result.reason || 'retryable error', resp.statusCode)
|
|
30
89
|
}
|
|
90
|
+
|
|
91
|
+
logger.info(`Successfully saved document: ${doc._id}`)
|
|
31
92
|
return result
|
|
32
93
|
})
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @typedef {Object} NetworkError
|
|
3
|
+
* @property {string} code - The error code
|
|
4
|
+
* @property {string} [message] - Optional error message
|
|
5
|
+
*/
|
|
6
|
+
export class RetryableError extends Error {
|
|
7
|
+
/**
|
|
8
|
+
* @param {number|undefined} statusCode - The HTTP status code to check
|
|
9
|
+
* @returns {boolean} Whether the status code is retryable
|
|
10
|
+
*/
|
|
11
|
+
static isRetryableStatusCode(statusCode: number | undefined): boolean;
|
|
12
|
+
/**
|
|
13
|
+
* @param {NetworkError | unknown} err - The network error to handle
|
|
14
|
+
* @throws {RetryableError} If the error is retryable
|
|
15
|
+
* @throws {Error} If the error is not retryable
|
|
16
|
+
*/
|
|
17
|
+
static handleNetworkError(err: NetworkError | unknown): void;
|
|
18
|
+
/**
|
|
19
|
+
* @param {string} message - The error message
|
|
20
|
+
* @param {number|undefined} statusCode - The HTTP status code
|
|
21
|
+
*/
|
|
22
|
+
constructor(message: string, statusCode: number | undefined);
|
|
23
|
+
statusCode: number | undefined;
|
|
24
|
+
}
|
|
25
|
+
export type NetworkError = {
|
|
26
|
+
/**
|
|
27
|
+
* - The error code
|
|
28
|
+
*/
|
|
29
|
+
code: string;
|
|
30
|
+
/**
|
|
31
|
+
* - Optional error message
|
|
32
|
+
*/
|
|
33
|
+
message?: string | undefined;
|
|
34
|
+
};
|
|
35
|
+
//# sourceMappingURL=errors.d.mts.map
|
|
@@ -0,0 +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;;;;;UAhDa,MAAM"}
|
package/impl/errors.mjs
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @typedef {Object} NetworkError
|
|
5
|
+
* @property {string} code - The error code
|
|
6
|
+
* @property {string} [message] - Optional error message
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
export class RetryableError extends Error {
|
|
10
|
+
/**
|
|
11
|
+
* @param {string} message - The error message
|
|
12
|
+
* @param {number|undefined} statusCode - The HTTP status code
|
|
13
|
+
*/
|
|
14
|
+
constructor(message, statusCode) {
|
|
15
|
+
super(message);
|
|
16
|
+
this.name = 'RetryableError';
|
|
17
|
+
this.statusCode = statusCode;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* @param {number|undefined} statusCode - The HTTP status code to check
|
|
22
|
+
* @returns {boolean} Whether the status code is retryable
|
|
23
|
+
*/
|
|
24
|
+
static isRetryableStatusCode(statusCode) {
|
|
25
|
+
if (statusCode === undefined) return false;
|
|
26
|
+
return [408, 429, 500, 502, 503, 504].includes(statusCode);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* @param {NetworkError | unknown} err - The network error to handle
|
|
31
|
+
* @throws {RetryableError} If the error is retryable
|
|
32
|
+
* @throws {Error} If the error is not retryable
|
|
33
|
+
*/
|
|
34
|
+
static handleNetworkError(err) {
|
|
35
|
+
/** @type {Record<string, number>} */
|
|
36
|
+
const networkErrors = {
|
|
37
|
+
ECONNREFUSED: 503,
|
|
38
|
+
ECONNRESET: 503,
|
|
39
|
+
ETIMEDOUT: 503,
|
|
40
|
+
ENETUNREACH: 503,
|
|
41
|
+
ENOTFOUND: 503,
|
|
42
|
+
EPIPE: 503,
|
|
43
|
+
EHOSTUNREACH: 503,
|
|
44
|
+
ESOCKETTIMEDOUT: 503
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
// Type guard for NetworkError shape
|
|
48
|
+
if (typeof err === 'object' && err !== null && 'code' in err && typeof err.code === 'string' && networkErrors[err.code]) {
|
|
49
|
+
throw new RetryableError(`Network error: ${err.code}`, networkErrors[err.code]);
|
|
50
|
+
}
|
|
51
|
+
throw err;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @typedef {Object} Logger
|
|
3
|
+
* @property {(...args: any[]) => void} error - Log error messages
|
|
4
|
+
* @property {(...args: any[]) => void} warn - Log warning messages
|
|
5
|
+
* @property {(...args: any[]) => void} info - Log info messages
|
|
6
|
+
* @property {(...args: any[]) => void} debug - Log debug messages
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Creates a unified logger interface that works with both function and object-style loggers
|
|
10
|
+
* @param {import('../schema/config.mjs').CouchConfigSchema} config
|
|
11
|
+
* @returns {Logger} Normalized logger interface
|
|
12
|
+
*/
|
|
13
|
+
export function createLogger(config: import("../schema/config.mjs").CouchConfigSchema): Logger;
|
|
14
|
+
export type Logger = {
|
|
15
|
+
/**
|
|
16
|
+
* - Log error messages
|
|
17
|
+
*/
|
|
18
|
+
error: (...args: any[]) => void;
|
|
19
|
+
/**
|
|
20
|
+
* - Log warning messages
|
|
21
|
+
*/
|
|
22
|
+
warn: (...args: any[]) => void;
|
|
23
|
+
/**
|
|
24
|
+
* - Log info messages
|
|
25
|
+
*/
|
|
26
|
+
info: (...args: any[]) => void;
|
|
27
|
+
/**
|
|
28
|
+
* - Log debug messages
|
|
29
|
+
*/
|
|
30
|
+
debug: (...args: any[]) => void;
|
|
31
|
+
};
|
|
32
|
+
//# sourceMappingURL=logger.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.d.mts","sourceRoot":"","sources":["logger.mjs"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH;;;;GAIG;AACH,qCAHW,OAAO,sBAAsB,EAAE,iBAAiB,GAC9C,MAAM,CAsClB;;;;;WA/Ca,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI;;;;UACxB,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI;;;;UACxB,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI;;;;WACxB,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI"}
|