corebasic 1.0.229 → 1.0.231
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/dist/libs/auth.js +5 -4
- package/dist/libs/compression.js +1 -7
- package/dist/libs/dip/suffix/index.js +8 -6
- package/dist/libs/dip/suffix/policy.js +6 -4
- package/dist/libs/dip/suffix/query.js +290 -279
- package/dist/libs/dip/suffix/suffix.js +17 -13
- package/dist/libs/dip/suffix/tests/date.test.js +21 -34
- package/dist/libs/dip/suffix/tests/policy.test.js +41 -80
- package/dist/libs/dip.js +28 -26
- package/dist/libs/dipper.js +0 -1
- package/dist/libs/elabase.js +1 -1
- package/dist/libs/kafka.js +7 -4
- package/dist/libs/messaging.js +7 -4
- package/dist/libs/session.js +2 -2
- package/libs/auth.ts +48 -9
- package/libs/compression.ts +6 -1
- package/libs/cpp.ts +15 -13
- package/libs/dip/suffix/date.ts +6 -6
- package/libs/dip/suffix/index.ts +41 -26
- package/libs/dip/suffix/policy.ts +16 -13
- package/libs/dip/suffix/query.ts +289 -289
- package/libs/dip/suffix/suffix.ts +26 -20
- package/libs/dip/suffix/tests/date.test.ts +32 -64
- package/libs/dip/suffix/tests/policy.applySuffixPolicy.test.ts +20 -20
- package/libs/dip/suffix/tests/policy.test.ts +41 -109
- package/libs/dip/suffix/tests/suffix.test.ts +2 -2
- package/libs/dip.ts +59 -33
- package/libs/dipper.ts +25 -10
- package/libs/elabase.ts +1 -1
- package/libs/kafka.ts +74 -11
- package/libs/messaging.ts +80 -19
- package/libs/session.ts +21 -10
- package/libs/utils.ts +1 -1
- package/package.json +1 -1
|
@@ -8,11 +8,16 @@ export async function suffix(doc, policies, insertMode, arg) {
|
|
|
8
8
|
const value = typeof policy.value === "string" ? policy.value.trim() : undefined;
|
|
9
9
|
if ("value" in policy && !value)
|
|
10
10
|
throw new Error(`Error: Invalid suffix policy fixed 'value' specified for key in Dip`);
|
|
11
|
-
let
|
|
12
|
-
const [policy_type,
|
|
11
|
+
let candidates = value ? [value] : entries(policy.key ?? '', doc);
|
|
12
|
+
const [policy_type, format_type] = (policy.type ?? "string").split(':');
|
|
13
|
+
const format = format_type ?? "";
|
|
13
14
|
if (!EXPLICIT_SUFFIX_POLICY_TYPES.has(policy_type))
|
|
14
15
|
throw new Error(`Error: Invalid suffix policy type specified for key ${policy.key} in Dip`);
|
|
15
|
-
|
|
16
|
+
// ====== Range ======
|
|
17
|
+
let ranges = candidates.filter(item => typeof item === "object");
|
|
18
|
+
let keys = candidates.filter(item => typeof item !== "object");
|
|
19
|
+
// ====== Range ======
|
|
20
|
+
if (policy_type === "string" && ranges.length)
|
|
16
21
|
throw new Error(`Error: Invalid numeric bounds on string type in suffix policy specified for key ${policy.key} in Dip`);
|
|
17
22
|
if (policy_type === "date") {
|
|
18
23
|
if (!format?.trim())
|
|
@@ -22,14 +27,12 @@ export async function suffix(doc, policies, insertMode, arg) {
|
|
|
22
27
|
}
|
|
23
28
|
const ls_threshold = policy.ls_threshold ?? 5000;
|
|
24
29
|
// ====== Range ======
|
|
25
|
-
let ranges = keys.filter(item => typeof item === "object");
|
|
26
|
-
keys = keys.filter(item => typeof item !== "object");
|
|
27
30
|
if (policy_type === "date") {
|
|
28
31
|
keys = keys.map(key => formatDate(key, format));
|
|
29
32
|
if (ranges.length) {
|
|
30
33
|
const bounds = extractBounds(reduceRanges(ranges));
|
|
31
|
-
const from = bounds.from ?? policy.min; // policy.min is always inclusive i.e $gte
|
|
32
|
-
const to = bounds.to ?? policy.max; // policy.max is always inclusive i.e $lte
|
|
34
|
+
const from = (bounds.from ?? policy.min); // policy.min is always inclusive i.e $gte
|
|
35
|
+
const to = (bounds.to ?? policy.max); // policy.max is always inclusive i.e $lte
|
|
33
36
|
const fromOp = bounds.from ? bounds.fromOp : "$gte"; // policy.min is $gte
|
|
34
37
|
const toOp = bounds.to ? bounds.toOp : "$lte"; // policy.max is $lte
|
|
35
38
|
if (from === undefined || to === undefined) {
|
|
@@ -38,8 +41,8 @@ export async function suffix(doc, policies, insertMode, arg) {
|
|
|
38
41
|
}
|
|
39
42
|
else {
|
|
40
43
|
let ranges = fillDates({ from, to, fromOp, toOp }, format);
|
|
41
|
-
if (!ranges.length && policy.inferRange)
|
|
42
|
-
|
|
44
|
+
// if (!ranges.length && policy.inferRange)
|
|
45
|
+
// ranges = [...new Set([from === undefined ? undefined : formatDate(from, format), to === undefined ? undefined : formatDate(to, format)].filter(item => item))]
|
|
43
46
|
// console.log(ranges)
|
|
44
47
|
if (ranges.length > ls_threshold) {
|
|
45
48
|
keys = []; // Too many suffixes to enumerate. Fall back to Dip.operation("ls").
|
|
@@ -53,8 +56,8 @@ export async function suffix(doc, policies, insertMode, arg) {
|
|
|
53
56
|
}
|
|
54
57
|
else if (policy_type === "number" && ranges.length) {
|
|
55
58
|
const bounds = getNormalizedBounds(extractBounds(reduceRanges(ranges)), "number");
|
|
56
|
-
const from = bounds.from ?? policy.min; // policy.min is always inclusive i.e $gte
|
|
57
|
-
const to = bounds.to ?? policy.max; // policy.max is always inclusive i.e $lte
|
|
59
|
+
const from = (bounds.from ?? policy.min); // policy.min is always inclusive i.e $gte
|
|
60
|
+
const to = (bounds.to ?? policy.max); // policy.max is always inclusive i.e $lte
|
|
58
61
|
if (from === undefined || to === undefined) {
|
|
59
62
|
keys = []; // Fall back to Dip.operation("ls").
|
|
60
63
|
console.warn(`Warn: Missing suffix policy min/max bound for ${policy_type} range specified for key ${policy.key} in Dip`);
|
|
@@ -79,8 +82,9 @@ export async function suffix(doc, policies, insertMode, arg) {
|
|
|
79
82
|
if (!keys.length && !insertMode) {
|
|
80
83
|
ls = true;
|
|
81
84
|
for (const suffix of suffixes) {
|
|
82
|
-
|
|
83
|
-
|
|
85
|
+
const collections = arg?.collection ?? [];
|
|
86
|
+
for (const collection of collections) {
|
|
87
|
+
const dirs = (await Dip.operation("ls", { db: arg?.db, collection: collection, suffix })).filter((dir) => !dir.startsWith('chunk-'));
|
|
84
88
|
suffixAssociatedKeys[suffix] = suffixAssociatedKeys[suffix] ?? [];
|
|
85
89
|
suffixAssociatedKeys[suffix].push(...dirs);
|
|
86
90
|
}
|
|
@@ -142,46 +142,33 @@ describe("fillDates()", () => {
|
|
|
142
142
|
const result = fillDates({ from: "2026-01-01", to: "2026-12-31", fromOp: "$gte", toOp: "$lte" }, "YYYY-MM-DD");
|
|
143
143
|
assert.equal(new Set(result).size, result.length);
|
|
144
144
|
});
|
|
145
|
-
test("excludes lower bound with $gt", () => {
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
"2026-07-02",
|
|
165
|
-
]);
|
|
166
|
-
});
|
|
145
|
+
// test("excludes lower bound with $gt", () => {
|
|
146
|
+
// assert.deepEqual(
|
|
147
|
+
// fillDates({ from: "2026-07-01", to: "2026-07-03", fromOp: "$gt", toOp: null }, "YYYY-MM-DD"),
|
|
148
|
+
// [
|
|
149
|
+
// "2026-07-02",
|
|
150
|
+
// "2026-07-03",
|
|
151
|
+
// ]
|
|
152
|
+
// );
|
|
153
|
+
// });
|
|
154
|
+
//
|
|
155
|
+
// test("excludes upper bound with $lt", () => {
|
|
156
|
+
// assert.deepEqual(
|
|
157
|
+
// fillDates({ from: "2026-07-01", to: "2026-07-03", fromOp: null, toOp: "$lt" }, "YYYY-MM-DD"),
|
|
158
|
+
// [
|
|
159
|
+
// "2026-07-01",
|
|
160
|
+
// "2026-07-02",
|
|
161
|
+
// ]
|
|
162
|
+
// );
|
|
163
|
+
// });
|
|
167
164
|
test("excludes both bounds", () => {
|
|
168
|
-
assert.deepEqual(fillDates({
|
|
169
|
-
from: "2026-07-01",
|
|
170
|
-
to: "2026-07-05",
|
|
171
|
-
fromOp: "$gt",
|
|
172
|
-
toOp: "$lt",
|
|
173
|
-
}, "YYYY-MM-DD"), [
|
|
165
|
+
assert.deepEqual(fillDates({ from: "2026-07-01", to: "2026-07-05", fromOp: "$gt", toOp: "$lt" }, "YYYY-MM-DD"), [
|
|
174
166
|
"2026-07-02",
|
|
175
167
|
"2026-07-03",
|
|
176
168
|
"2026-07-04",
|
|
177
169
|
]);
|
|
178
170
|
});
|
|
179
171
|
test("returns empty when exclusive bounds collapse range", () => {
|
|
180
|
-
assert.deepEqual(fillDates({
|
|
181
|
-
from: "2026-07-01",
|
|
182
|
-
to: "2026-07-02",
|
|
183
|
-
fromOp: "$gt",
|
|
184
|
-
toOp: "$lt",
|
|
185
|
-
}, "YYYY-MM-DD"), []);
|
|
172
|
+
assert.deepEqual(fillDates({ from: "2026-07-01", to: "2026-07-02", fromOp: "$gt", toOp: "$lt" }, "YYYY-MM-DD"), []);
|
|
186
173
|
});
|
|
187
174
|
});
|
|
@@ -1,75 +1,56 @@
|
|
|
1
1
|
import { describe, test } from "node:test";
|
|
2
2
|
import assert from "node:assert/strict";
|
|
3
3
|
import { matchPolicy, overlaps, contains, intersects, applySuffixPolicy } from "../policy.js";
|
|
4
|
+
const defaultBounds = { values: [], from: -Infinity, to: Infinity, fromOp: "$gte", toOp: "$lte" };
|
|
4
5
|
/* ============================================================
|
|
5
6
|
* overlaps()
|
|
6
7
|
* ============================================================ */
|
|
7
8
|
describe("overlaps()", () => {
|
|
8
9
|
test("overlaps: identical ranges", () => {
|
|
9
|
-
assert.equal(overlaps({ from: 10, to: 20 }, { from: 10, to: 20 }), true);
|
|
10
|
+
assert.equal(overlaps({ ...defaultBounds, from: 10, to: 20 }, { ...defaultBounds, from: 10, to: 20 }), true);
|
|
10
11
|
});
|
|
11
12
|
test("overlaps: partial overlap", () => {
|
|
12
|
-
assert.equal(overlaps({ from: 10, to: 20 }, { from: 15, to: 25 }), true);
|
|
13
|
+
assert.equal(overlaps({ ...defaultBounds, from: 10, to: 20 }, { ...defaultBounds, from: 15, to: 25 }), true);
|
|
13
14
|
});
|
|
14
15
|
test("overlaps: no overlap", () => {
|
|
15
|
-
assert.equal(overlaps({ from: 10, to: 20 }, { from: 21, to: 30 }), false);
|
|
16
|
+
assert.equal(overlaps({ ...defaultBounds, from: 10, to: 20 }, { ...defaultBounds, from: 21, to: 30 }), false);
|
|
16
17
|
});
|
|
17
18
|
test("overlaps: open ended lower", () => {
|
|
18
|
-
assert.equal(overlaps({ to: 10 }, { from: 5 }), true);
|
|
19
|
+
assert.equal(overlaps({ ...defaultBounds, to: 10 }, { ...defaultBounds, from: 5 }), true);
|
|
19
20
|
});
|
|
20
21
|
test("overlaps: open ended upper", () => {
|
|
21
|
-
assert.equal(overlaps({ from: 20 }, { to: 10 }), false);
|
|
22
|
+
assert.equal(overlaps({ ...defaultBounds, from: 20 }, { ...defaultBounds, to: 10 }), false);
|
|
22
23
|
});
|
|
23
24
|
describe("overlaps() boundary semantics", () => {
|
|
24
25
|
test("touching: open/open does not overlap", () => {
|
|
25
|
-
assert.equal(overlaps({ to: 10, toOp: "$lt" }, { from: 10, fromOp: "$gt" }), false);
|
|
26
|
+
assert.equal(overlaps({ ...defaultBounds, to: 10, toOp: "$lt" }, { ...defaultBounds, from: 10, fromOp: "$gt" }), false);
|
|
26
27
|
});
|
|
27
28
|
test("touching: closed/closed overlaps", () => {
|
|
28
|
-
assert.equal(overlaps({ to: 10, toOp: "$lte" }, { from: 10, fromOp: "$gte" }), true);
|
|
29
|
+
assert.equal(overlaps({ ...defaultBounds, to: 10, toOp: "$lte" }, { ...defaultBounds, from: 10, fromOp: "$gte" }), true);
|
|
29
30
|
});
|
|
30
31
|
test("touching: closed/open does not overlap", () => {
|
|
31
|
-
assert.equal(overlaps({ to: 10, toOp: "$lte" }, { from: 10, fromOp: "$gt" }), false);
|
|
32
|
+
assert.equal(overlaps({ ...defaultBounds, to: 10, toOp: "$lte" }, { ...defaultBounds, from: 10, fromOp: "$gt" }), false);
|
|
32
33
|
});
|
|
33
34
|
test("touching: open/closed does not overlap", () => {
|
|
34
|
-
assert.equal(overlaps({ to: 10, toOp: "$lt" }, { from: 10, fromOp: "$gte" }), false);
|
|
35
|
+
assert.equal(overlaps({ ...defaultBounds, to: 10, toOp: "$lt" }, { ...defaultBounds, from: 10, fromOp: "$gte" }), false);
|
|
35
36
|
});
|
|
36
37
|
test("touching: reverse order closed/closed overlaps", () => {
|
|
37
|
-
assert.equal(overlaps({ from: 10, fromOp: "$gte" }, { to: 10, toOp: "$lte" }), true);
|
|
38
|
+
assert.equal(overlaps({ ...defaultBounds, from: 10, fromOp: "$gte" }, { ...defaultBounds, to: 10, toOp: "$lte" }), true);
|
|
38
39
|
});
|
|
39
40
|
test("touching: reverse order open/open does not overlap", () => {
|
|
40
|
-
assert.equal(overlaps({ from: 10, fromOp: "$gt" }, { to: 10, toOp: "$lt" }), false);
|
|
41
|
+
assert.equal(overlaps({ ...defaultBounds, from: 10, fromOp: "$gt" }, { ...defaultBounds, to: 10, toOp: "$lt" }), false);
|
|
41
42
|
});
|
|
42
43
|
test("identical single-point closed intervals overlap", () => {
|
|
43
|
-
assert.equal(overlaps({
|
|
44
|
-
from: 10,
|
|
45
|
-
to: 10,
|
|
46
|
-
fromOp: "$gte",
|
|
47
|
-
toOp: "$lte"
|
|
48
|
-
}, {
|
|
49
|
-
from: 10,
|
|
50
|
-
to: 10,
|
|
51
|
-
fromOp: "$gte",
|
|
52
|
-
toOp: "$lte"
|
|
53
|
-
}), true);
|
|
44
|
+
assert.equal(overlaps({ ...defaultBounds, from: 10, to: 10, fromOp: "$gte", toOp: "$lte" }, { ...defaultBounds, from: 10, to: 10, fromOp: "$gte", toOp: "$lte" }), true);
|
|
54
45
|
});
|
|
55
46
|
test("identical single-point open intervals do not overlap", () => {
|
|
56
|
-
assert.equal(overlaps({
|
|
57
|
-
from: 10,
|
|
58
|
-
to: 10,
|
|
59
|
-
fromOp: "$gt",
|
|
60
|
-
toOp: "$lt"
|
|
61
|
-
}, {
|
|
62
|
-
from: 10,
|
|
63
|
-
to: 10,
|
|
64
|
-
fromOp: "$gt",
|
|
65
|
-
toOp: "$lt"
|
|
66
|
-
}), false);
|
|
47
|
+
assert.equal(overlaps({ ...defaultBounds, from: 10, to: 10, fromOp: "$gt", toOp: "$lt" }, { ...defaultBounds, from: 10, to: 10, fromOp: "$gt", toOp: "$lt" }), false);
|
|
67
48
|
});
|
|
68
49
|
test("infinite lower bound with touching closed endpoint overlaps", () => {
|
|
69
|
-
assert.equal(overlaps({ to: 5, toOp: "$lte" }, { from: 5, fromOp: "$gte" }), true);
|
|
50
|
+
assert.equal(overlaps({ ...defaultBounds, to: 5, toOp: "$lte" }, { ...defaultBounds, from: 5, fromOp: "$gte" }), true);
|
|
70
51
|
});
|
|
71
52
|
test("infinite lower bound with touching open endpoint does not overlap", () => {
|
|
72
|
-
assert.equal(overlaps({ to: 5, toOp: "$lt" }, { from: 5, fromOp: "$gt" }), false);
|
|
53
|
+
assert.equal(overlaps({ ...defaultBounds, to: 5, toOp: "$lt" }, { ...defaultBounds, from: 5, fromOp: "$gt" }), false);
|
|
73
54
|
});
|
|
74
55
|
});
|
|
75
56
|
});
|
|
@@ -78,89 +59,69 @@ describe("overlaps()", () => {
|
|
|
78
59
|
* ============================================================ */
|
|
79
60
|
describe("contains()", () => {
|
|
80
61
|
test("contains: inside", () => {
|
|
81
|
-
assert.equal(contains({ from: 10, to: 20 }, 15), true);
|
|
62
|
+
assert.equal(contains({ ...defaultBounds, from: 10, to: 20 }, 15), true);
|
|
82
63
|
});
|
|
83
64
|
test("contains: below", () => {
|
|
84
|
-
assert.equal(contains({ from: 10, to: 20 }, 5), false);
|
|
65
|
+
assert.equal(contains({ ...defaultBounds, from: 10, to: 20 }, 5), false);
|
|
85
66
|
});
|
|
86
67
|
test("contains: above", () => {
|
|
87
|
-
assert.equal(contains({ from: 10, to: 20 }, 25), false);
|
|
68
|
+
assert.equal(contains({ ...defaultBounds, from: 10, to: 20 }, 25), false);
|
|
88
69
|
});
|
|
89
70
|
test("contains: lower bound", () => {
|
|
90
|
-
assert.equal(contains({ from: 10, to: 20 }, 10), true);
|
|
71
|
+
assert.equal(contains({ ...defaultBounds, from: 10, to: 20 }, 10), true);
|
|
91
72
|
});
|
|
92
73
|
test("contains: upper bound", () => {
|
|
93
|
-
assert.equal(contains({ from: 10, to: 20 }, 20), true);
|
|
74
|
+
assert.equal(contains({ ...defaultBounds, from: 10, to: 20 }, 20), true);
|
|
94
75
|
});
|
|
95
76
|
test("contains: gt excludes lower bound", () => {
|
|
96
|
-
assert.equal(contains({ from: 5, fromOp: "$gt" }, 5), false);
|
|
77
|
+
assert.equal(contains({ ...defaultBounds, from: 5, fromOp: "$gt" }, 5), false);
|
|
97
78
|
});
|
|
98
79
|
test("contains: gte includes lower bound", () => {
|
|
99
|
-
assert.equal(contains({ from: 5, fromOp: "$gte" }, 5), true);
|
|
80
|
+
assert.equal(contains({ ...defaultBounds, from: 5, fromOp: "$gte" }, 5), true);
|
|
100
81
|
});
|
|
101
82
|
test("contains: lt excludes upper bound", () => {
|
|
102
|
-
assert.equal(contains({ to: 10, toOp: "$lt" }, 10), false);
|
|
83
|
+
assert.equal(contains({ ...defaultBounds, to: 10, toOp: "$lt" }, 10), false);
|
|
103
84
|
});
|
|
104
85
|
test("contains: lte includes upper bound", () => {
|
|
105
|
-
assert.equal(contains({ to: 10, toOp: "$lte" }, 10), true);
|
|
86
|
+
assert.equal(contains({ ...defaultBounds, to: 10, toOp: "$lte" }, 10), true);
|
|
106
87
|
});
|
|
107
88
|
test("contains: gt/lt excludes both endpoints", () => {
|
|
108
|
-
const bounds = {
|
|
109
|
-
from: 5,
|
|
110
|
-
fromOp: "$gt",
|
|
111
|
-
to: 10,
|
|
112
|
-
toOp: "$lt"
|
|
113
|
-
};
|
|
89
|
+
const bounds = { ...defaultBounds, from: 5, fromOp: "$gt", to: 10, toOp: "$lt" };
|
|
114
90
|
assert.equal(contains(bounds, 5), false);
|
|
115
91
|
assert.equal(contains(bounds, 10), false);
|
|
116
92
|
assert.equal(contains(bounds, 7), true);
|
|
117
93
|
});
|
|
118
94
|
test("contains: gte/lte includes both endpoints", () => {
|
|
119
|
-
const bounds = {
|
|
120
|
-
from: 5,
|
|
121
|
-
fromOp: "$gte",
|
|
122
|
-
to: 10,
|
|
123
|
-
toOp: "$lte"
|
|
124
|
-
};
|
|
95
|
+
const bounds = { ...defaultBounds, from: 5, fromOp: "$gte", to: 10, toOp: "$lte" };
|
|
125
96
|
assert.equal(contains(bounds, 5), true);
|
|
126
97
|
assert.equal(contains(bounds, 10), true);
|
|
127
98
|
assert.equal(contains(bounds, 7), true);
|
|
128
99
|
});
|
|
129
100
|
test("contains: gt/lte mixed", () => {
|
|
130
|
-
const bounds = {
|
|
131
|
-
from: 5,
|
|
132
|
-
fromOp: "$gt",
|
|
133
|
-
to: 10,
|
|
134
|
-
toOp: "$lte"
|
|
135
|
-
};
|
|
101
|
+
const bounds = { ...defaultBounds, from: 5, fromOp: "$gt", to: 10, toOp: "$lte" };
|
|
136
102
|
assert.equal(contains(bounds, 5), false);
|
|
137
103
|
assert.equal(contains(bounds, 10), true);
|
|
138
104
|
});
|
|
139
105
|
test("contains: gte/lt mixed", () => {
|
|
140
|
-
const bounds = {
|
|
141
|
-
from: 5,
|
|
142
|
-
fromOp: "$gte",
|
|
143
|
-
to: 10,
|
|
144
|
-
toOp: "$lt"
|
|
145
|
-
};
|
|
106
|
+
const bounds = { ...defaultBounds, from: 5, fromOp: "$gte", to: 10, toOp: "$lt" };
|
|
146
107
|
assert.equal(contains(bounds, 5), true);
|
|
147
108
|
assert.equal(contains(bounds, 10), false);
|
|
148
109
|
});
|
|
149
110
|
test("contains: value below lower bound", () => {
|
|
150
|
-
assert.equal(contains({ from: 5, fromOp: "$gte" }, 4), false);
|
|
111
|
+
assert.equal(contains({ ...defaultBounds, from: 5, fromOp: "$gte" }, 4), false);
|
|
151
112
|
});
|
|
152
113
|
test("contains: value above upper bound", () => {
|
|
153
|
-
assert.equal(contains({ to: 10, toOp: "$lte" }, 11), false);
|
|
114
|
+
assert.equal(contains({ ...defaultBounds, to: 10, toOp: "$lte" }, 11), false);
|
|
154
115
|
});
|
|
155
116
|
test("contains: open lower bound", () => {
|
|
156
|
-
assert.equal(contains({ to: 10, toOp: "$lte" }, -1000), true);
|
|
117
|
+
assert.equal(contains({ ...defaultBounds, to: 10, toOp: "$lte" }, -1000), true);
|
|
157
118
|
});
|
|
158
119
|
test("contains: open upper bound", () => {
|
|
159
|
-
assert.equal(contains({ from: 5, fromOp: "$gte" }, 1000), true);
|
|
120
|
+
assert.equal(contains({ ...defaultBounds, from: 5, fromOp: "$gte" }, 1000), true);
|
|
160
121
|
});
|
|
161
122
|
test("contains: completely unbounded", () => {
|
|
162
|
-
assert.equal(contains({}, -100), true);
|
|
163
|
-
assert.equal(contains({}, 100), true);
|
|
123
|
+
assert.equal(contains({ ...defaultBounds, }, -100), true);
|
|
124
|
+
assert.equal(contains({ ...defaultBounds, }, 100), true);
|
|
164
125
|
});
|
|
165
126
|
});
|
|
166
127
|
/* ============================================================
|
|
@@ -174,22 +135,22 @@ describe("intersects()", () => {
|
|
|
174
135
|
assert.equal(intersects(["A"], null, ["B"], null), false);
|
|
175
136
|
});
|
|
176
137
|
test("intersects: value ↔ range", () => {
|
|
177
|
-
assert.equal(intersects([10], null, [], { from: 5 }), true);
|
|
138
|
+
assert.equal(intersects([10], null, [], { ...defaultBounds, from: 5 }), true);
|
|
178
139
|
});
|
|
179
140
|
test("intersects: value ↔ range miss", () => {
|
|
180
|
-
assert.equal(intersects([2], null, [], { from: 5 }), false);
|
|
141
|
+
assert.equal(intersects([2], null, [], { ...defaultBounds, from: 5 }), false);
|
|
181
142
|
});
|
|
182
143
|
test("intersects: range ↔ value", () => {
|
|
183
|
-
assert.equal(intersects([], { from: 5 }, [10], null), true);
|
|
144
|
+
assert.equal(intersects([], { ...defaultBounds, from: 5 }, [10], null), true);
|
|
184
145
|
});
|
|
185
146
|
test("intersects: range ↔ value miss", () => {
|
|
186
|
-
assert.equal(intersects([], { from: 5 }, [2], null), false);
|
|
147
|
+
assert.equal(intersects([], { ...defaultBounds, from: 5 }, [2], null), false);
|
|
187
148
|
});
|
|
188
149
|
test("intersects: range ↔ range", () => {
|
|
189
|
-
assert.equal(intersects([], { from: 10 }, [], { from: 20 }), true);
|
|
150
|
+
assert.equal(intersects([], { ...defaultBounds, from: 10 }, [], { ...defaultBounds, from: 20 }), true);
|
|
190
151
|
});
|
|
191
152
|
test("intersects: range ↔ range miss", () => {
|
|
192
|
-
assert.equal(intersects([], { to: 5 }, [], { from: 10 }), false);
|
|
153
|
+
assert.equal(intersects([], { ...defaultBounds, to: 5 }, [], { ...defaultBounds, from: 10 }), false);
|
|
193
154
|
});
|
|
194
155
|
});
|
|
195
156
|
/* ============================================================
|
package/dist/libs/dip.js
CHANGED
|
@@ -28,34 +28,36 @@ export async function insertSync(meta, feature, date, uid, ref, type) {
|
|
|
28
28
|
await Elabase.insert(meta, collection, data);
|
|
29
29
|
}
|
|
30
30
|
export const IdempotentDip = () => {
|
|
31
|
-
|
|
31
|
+
const state = {
|
|
32
32
|
txn: '',
|
|
33
33
|
meta: undefined,
|
|
34
|
-
new: (async function (meta, txn, blank) {
|
|
35
|
-
this.txn = txn;
|
|
36
|
-
this.meta = meta;
|
|
37
|
-
return blank ? this : ((await Elabase.query(this.meta, "txns", { _id: this.txn })).length ? false : this);
|
|
38
|
-
}),
|
|
39
|
-
insert: (async function (collection, query, data) {
|
|
40
|
-
await Elabase.update(this.meta, collection, query, { $setOnInsert: data }, { upsert: true });
|
|
41
|
-
}),
|
|
42
|
-
update: (async function (collection, query, data, rollback) {
|
|
43
|
-
let token = { [this.txn]: true };
|
|
44
|
-
let idempotent = { [this.txn]: { $exists: rollback ?? false } };
|
|
45
|
-
let result = await Elabase.update(this.meta, collection, { ...query, ...idempotent }, { ...data, $setOnInsert: undefined, $set: { ...(data.$set ?? {}), ...token } });
|
|
46
|
-
return result.count ? true : (await Elabase.query(this.meta, collection, { ...query, ...idempotent })).length;
|
|
47
|
-
}),
|
|
48
|
-
upsert: (async function (collection, query, data, rollback) {
|
|
49
|
-
await this.insert(collection, query, data.$setOnInsert);
|
|
50
|
-
return await this.update(collection, query, data, rollback);
|
|
51
|
-
}),
|
|
52
|
-
cleanup: (async function (collection, query) {
|
|
53
|
-
await Elabase.update(this.meta, collection, query, { $unset: { [this.txn]: true } });
|
|
54
|
-
}),
|
|
55
|
-
finish: (async function () {
|
|
56
|
-
return await Elabase.update(this.meta, "txns", { _id: this.txn }, {}, { upsert: true });
|
|
57
|
-
})
|
|
58
34
|
};
|
|
35
|
+
const idip = {};
|
|
36
|
+
idip.new = async function (meta, txn, blank) {
|
|
37
|
+
state.txn = txn;
|
|
38
|
+
state.meta = meta;
|
|
39
|
+
return blank ? idip : ((await Elabase.query(state.meta, "txns", { _id: state.txn })).length ? false : idip);
|
|
40
|
+
};
|
|
41
|
+
idip.insert = async function (collection, query, data) {
|
|
42
|
+
await Elabase.update(state.meta, collection, query, { $setOnInsert: data }, { upsert: true });
|
|
43
|
+
};
|
|
44
|
+
idip.update = async function (collection, query, data, rollback) {
|
|
45
|
+
let token = { [state.txn]: true };
|
|
46
|
+
let idempotent = { [state.txn]: { $exists: rollback ?? false } };
|
|
47
|
+
let result = await Elabase.update(state.meta, collection, { ...query, ...idempotent }, { ...data, $setOnInsert: undefined, $set: { ...(data.$set ?? {}), ...token } });
|
|
48
|
+
return result.count ? true : (await Elabase.query(state.meta, collection, { ...query, ...idempotent })).length;
|
|
49
|
+
};
|
|
50
|
+
idip.upsert = async function (collection, query, data, rollback) {
|
|
51
|
+
await idip.insert(collection, query, data.$setOnInsert);
|
|
52
|
+
return await idip.update(collection, query, data, rollback);
|
|
53
|
+
};
|
|
54
|
+
idip.cleanup = async function (collection, query) {
|
|
55
|
+
await Elabase.update(state.meta, collection, query, { $unset: { [state.txn]: true } });
|
|
56
|
+
};
|
|
57
|
+
idip.finish = async function () {
|
|
58
|
+
return await Elabase.update(state.meta, "txns", { _id: state.txn }, {}, { upsert: true });
|
|
59
|
+
};
|
|
60
|
+
return idip;
|
|
59
61
|
};
|
|
60
62
|
export const idip = async (message, callback, cleanup) => {
|
|
61
63
|
if (!callback)
|
|
@@ -93,7 +95,7 @@ export const insertKeys = (message, meta) => {
|
|
|
93
95
|
...(meta?.outlet ? { "outlet": meta.outlet } : {}),
|
|
94
96
|
};
|
|
95
97
|
};
|
|
96
|
-
export const updateKeys = message => {
|
|
98
|
+
export const updateKeys = (message) => {
|
|
97
99
|
return {
|
|
98
100
|
"updated": message.date,
|
|
99
101
|
"updatedBy": message.meta.staff,
|
package/dist/libs/dipper.js
CHANGED
package/dist/libs/elabase.js
CHANGED
package/dist/libs/kafka.js
CHANGED
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
import { Kafka, logLevel as KafkaLogLevel, CompressionTypes as KafkaCompressionTypes } from 'kafkajs';
|
|
3
3
|
export const logLevel = KafkaLogLevel;
|
|
4
4
|
export const CompressionTypes = KafkaCompressionTypes;
|
|
5
|
-
let kafka
|
|
5
|
+
let kafka;
|
|
6
|
+
let producer;
|
|
7
|
+
let admin;
|
|
6
8
|
let appName;
|
|
7
9
|
let topicPrefix = '';
|
|
8
10
|
export const start = (arg) => {
|
|
@@ -37,16 +39,17 @@ const start_consumer = async function (topic, groupId, callback) {
|
|
|
37
39
|
consumers.push(consumer);
|
|
38
40
|
await consumer.connect();
|
|
39
41
|
await consumer.subscribe({ topic: topic, fromBeginning: true });
|
|
42
|
+
const fn = callback;
|
|
40
43
|
await consumer.run({
|
|
41
44
|
autoCommit: false,
|
|
42
45
|
eachMessage: async ({ topic, partition, message }) => {
|
|
43
|
-
//
|
|
46
|
+
// fn(topic, message.value.toString(), partition) // toString() returns array so won't parse if json.
|
|
44
47
|
let success;
|
|
45
48
|
try {
|
|
46
|
-
success = await
|
|
49
|
+
success = await fn(topic, JSON.parse(message.value), partition);
|
|
47
50
|
}
|
|
48
51
|
catch (ex) {
|
|
49
|
-
success = await
|
|
52
|
+
success = await fn(topic, message.value, partition);
|
|
50
53
|
}
|
|
51
54
|
await consumer.commitOffsets([{ topic, partition, offset: (Number(message.offset) + 1).toString() }]);
|
|
52
55
|
},
|
package/dist/libs/messaging.js
CHANGED
|
@@ -4,14 +4,17 @@ import axios from 'axios';
|
|
|
4
4
|
// @ts-ignore
|
|
5
5
|
import { createClient } from 'redis';
|
|
6
6
|
const url = process.env.REDIS_URL || "redis://localhost:6380";
|
|
7
|
-
|
|
8
|
-
let
|
|
7
|
+
let consumer;
|
|
8
|
+
let publisher;
|
|
9
9
|
let users_pool = {};
|
|
10
10
|
async function disconnect(user, uid) {
|
|
11
11
|
if (!users_pool[user])
|
|
12
12
|
return;
|
|
13
|
-
let
|
|
14
|
-
|
|
13
|
+
let res_items = users_pool[user].reqres.filter(item => item.uid === uid);
|
|
14
|
+
if (res_items) {
|
|
15
|
+
const res = res_items[0].res;
|
|
16
|
+
res.end();
|
|
17
|
+
}
|
|
15
18
|
if (users_pool[user].listeners[uid]) {
|
|
16
19
|
if (users_pool[user].listeners.count == 1)
|
|
17
20
|
await consumer.unsubscribe(user, users_pool[user].listeners[uid]);
|
package/dist/libs/session.js
CHANGED
|
@@ -8,7 +8,7 @@ const REFRESH_TOKEN_SECRET = process.env.JWT_REFRESH_TOKEN_SECRET || "MY_SECRET_
|
|
|
8
8
|
const DEPLOY_TOKEN_SECRET = process.env.DEPLOY_TOKEN_SECRET || "MY_SECRET_DEPLOY_TOKEN";
|
|
9
9
|
const NDCURVE_DEVELOPER_LICENSE_ACCESS_TOKEN_SECRET = process.env.NDCURVE_DEVELOPER_LICENSE_ACCESS_TOKEN_PUBLIC_KEY;
|
|
10
10
|
let urlsAllowed = [];
|
|
11
|
-
export
|
|
11
|
+
export let ALLOWED_URLS = [];
|
|
12
12
|
export const start = (expressApp, allowedUrls) => {
|
|
13
13
|
urlsAllowed = ["/refreshToken", "/login"].concat(allowedUrls ?? []);
|
|
14
14
|
ALLOWED_URLS = urlsAllowed;
|
|
@@ -54,7 +54,7 @@ export const start = (expressApp, allowedUrls) => {
|
|
|
54
54
|
throw null;
|
|
55
55
|
}
|
|
56
56
|
catch (error) {
|
|
57
|
-
|
|
57
|
+
res.status(401).json({ message: error?.message === "Access Denied" ? "Access Denied" : 'Unauthorized' });
|
|
58
58
|
}
|
|
59
59
|
});
|
|
60
60
|
app.post("/refreshToken", (req, res) => {
|
package/libs/auth.ts
CHANGED
|
@@ -7,12 +7,51 @@ import * as Dip from './dip.ts'
|
|
|
7
7
|
import * as Utils from './utils.ts'
|
|
8
8
|
import * as Session from './session.ts'
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
|
|
11
|
+
type AuthRequest = {
|
|
12
|
+
body: {
|
|
13
|
+
mob?: string
|
|
14
|
+
phone?: string
|
|
15
|
+
code?: string
|
|
16
|
+
otp?: string
|
|
17
|
+
clientId?: string
|
|
18
|
+
app?: string
|
|
19
|
+
hash?: string
|
|
20
|
+
userId?: string
|
|
21
|
+
data?: Record<string, unknown>
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
type AuthResponse = {
|
|
26
|
+
status: (code: number) => AuthResponse
|
|
27
|
+
json: (body: unknown) => void
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
type AuthApp = {
|
|
31
|
+
post: (
|
|
32
|
+
path: string,
|
|
33
|
+
handler: (req: AuthRequest, res: AuthResponse) => Promise<void>
|
|
34
|
+
) => void
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
type ValidateFunction = (req: AuthRequest) => boolean
|
|
38
|
+
|
|
39
|
+
type SuccessCallback = (
|
|
40
|
+
req: AuthRequest,
|
|
41
|
+
res: AuthResponse,
|
|
42
|
+
data: Record<string, unknown>
|
|
43
|
+
) => void | Promise<void>
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
let validateFn: ValidateFunction | undefined
|
|
48
|
+
let validateErrMessage: string | undefined
|
|
49
|
+
|
|
50
|
+
export const validate = (callback: ValidateFunction, errMessage?: string) => {
|
|
12
51
|
validateFn = callback
|
|
13
52
|
}
|
|
14
53
|
|
|
15
|
-
export const start = (app, successCallback) => {
|
|
54
|
+
export const start = (app: AuthApp, successCallback?: SuccessCallback) => {
|
|
16
55
|
app.post("/login", async (req, res) => {
|
|
17
56
|
if (validateFn && !validateFn(req)) {
|
|
18
57
|
res.status(401).json({ mode: 'login', success: false, info: validateErrMessage ?? 'Validation Failed', message: 'Login Server Error' })
|
|
@@ -21,7 +60,7 @@ export const start = (app, successCallback) => {
|
|
|
21
60
|
try {
|
|
22
61
|
let login = await attemptLogin(req, res)
|
|
23
62
|
if (login.mode === 'verify' && login.success) {
|
|
24
|
-
let tokens = Session.generateAccessToken(login.userId, req.body.clientId)
|
|
63
|
+
let tokens = Session.generateAccessToken(login.userId, req.body.clientId ?? '')
|
|
25
64
|
let response = {...login, tokens}
|
|
26
65
|
if (successCallback)
|
|
27
66
|
await successCallback(req, res, response)
|
|
@@ -35,12 +74,12 @@ export const start = (app, successCallback) => {
|
|
|
35
74
|
})
|
|
36
75
|
}
|
|
37
76
|
|
|
38
|
-
async function attemptLogin(req, res) {
|
|
77
|
+
async function attemptLogin(req: AuthRequest, res: AuthResponse) {
|
|
39
78
|
let meta = {company: "GLOBAL", outlet: "GLOBAL"}
|
|
40
79
|
|
|
41
80
|
let expiry = 300000
|
|
42
|
-
let userMob = req.body.mob ?? req.body.phone
|
|
43
|
-
const code = req.body.code
|
|
81
|
+
let userMob = req.body.mob ?? req.body.phone ?? ''
|
|
82
|
+
const code = req.body.code ?? ''
|
|
44
83
|
let mob = userMob.endsWith('123456789') ? '0123456789' : Utils.parseMob(userMob, code)
|
|
45
84
|
let time = new Date().getTime()
|
|
46
85
|
let collection = (req.body.app ? req.body.app + '.' : '') + "auth.login"
|
|
@@ -73,7 +112,7 @@ async function attemptLogin(req, res) {
|
|
|
73
112
|
}
|
|
74
113
|
|
|
75
114
|
|
|
76
|
-
async function sendOtp(mob, otp, app, hash) {
|
|
115
|
+
async function sendOtp(mob: string, otp: string, app?: string, hash?: string) {
|
|
77
116
|
if (process.env.LOGIN_OTP_DISABLE) {
|
|
78
117
|
console.log(otp);
|
|
79
118
|
return true
|
|
@@ -81,7 +120,7 @@ async function sendOtp(mob, otp, app, hash) {
|
|
|
81
120
|
try {
|
|
82
121
|
if (app && hash)
|
|
83
122
|
app = encodeURIComponent(`${app} (#${hash})`) // Of the form '<app> (#<hash>)' for better readability. Note: Axios works with SlypBusiness%20(%23<HASH>) but Curl requires SlypBusiness%20%28%23<HASH>%29
|
|
84
|
-
let api = process.env.SMS_API
|
|
123
|
+
let api = process.env.SMS_API!.replace(':phone', mob).replace(':otp', otp).replace(':app', app ?? 'app')
|
|
85
124
|
await axios.get(api)
|
|
86
125
|
return true
|
|
87
126
|
} catch {
|
package/libs/compression.ts
CHANGED
|
@@ -9,6 +9,11 @@ import compression from 'compression'
|
|
|
9
9
|
// Regarding Client compressing data send to server, I think if server has `Content-Encoding: gzip` set, then client might compress before sending. But not sure. Need to check.
|
|
10
10
|
// Http Stream or ServerSideEvents require res.flush() after res.write(). res.flush function is added by the express compression middleware
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
|
|
13
|
+
type ExpressApp = {
|
|
14
|
+
use: (fn: unknown) => unknown
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export const start = (app: ExpressApp) => {
|
|
13
18
|
app.use(Utils.excludeMiddleware(compression({threshold: 1024}))) // Response above 1024 bytes should be compressed. Default is also 1KB
|
|
14
19
|
}
|