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
package/libs/cpp.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
|
|
2
2
|
import crypto from 'node:crypto';
|
|
3
3
|
|
|
4
|
+
type ValueRef = { value: bigint }
|
|
5
|
+
type BytesRef = { value: number }
|
|
4
6
|
|
|
5
|
-
function readContent(buffer: Uint8Array, valueRef, bytesRef) { // Buffer is assignable to Uint8Array so no need for Buffer | Uint8Array
|
|
7
|
+
function readContent(buffer: Uint8Array, valueRef: ValueRef, bytesRef: BytesRef) { // Buffer is assignable to Uint8Array so no need for Buffer | Uint8Array
|
|
6
8
|
const MASK = 0x7F;
|
|
7
9
|
const MSB = 0x80;
|
|
8
10
|
const MAX_VLQ_BYTES = 10;
|
|
@@ -21,7 +23,7 @@ function readContent(buffer: Uint8Array, valueRef, bytesRef) { // Buffer is assi
|
|
|
21
23
|
return false;
|
|
22
24
|
}
|
|
23
25
|
|
|
24
|
-
const byte = view[lenBytes]
|
|
26
|
+
const byte = view[lenBytes]!;
|
|
25
27
|
lenBytes++;
|
|
26
28
|
|
|
27
29
|
length |= BigInt(byte & MASK) << shift;
|
|
@@ -41,7 +43,7 @@ function readContent(buffer: Uint8Array, valueRef, bytesRef) { // Buffer is assi
|
|
|
41
43
|
|
|
42
44
|
|
|
43
45
|
|
|
44
|
-
export function vlqToUint64(arrayBuffer) {
|
|
46
|
+
export function vlqToUint64(arrayBuffer: Uint8Array) {
|
|
45
47
|
// Objects act as containers to simulate C++ pointers/references
|
|
46
48
|
const valueRef = { value: 0n };
|
|
47
49
|
const bytesRef = { value: 0 };
|
|
@@ -63,7 +65,7 @@ export function vlqToUint64(arrayBuffer) {
|
|
|
63
65
|
|
|
64
66
|
|
|
65
67
|
|
|
66
|
-
function writeVlqcontent(buffer, value) {
|
|
68
|
+
function writeVlqcontent(buffer: Buffer, value: number | bigint) {
|
|
67
69
|
const MASK = 0x7Fn;
|
|
68
70
|
const MSB = 0x80;
|
|
69
71
|
let bufferPtr = 0;
|
|
@@ -81,7 +83,7 @@ function writeVlqcontent(buffer, value) {
|
|
|
81
83
|
return bufferPtr;
|
|
82
84
|
}
|
|
83
85
|
|
|
84
|
-
export function uint64ToVlq(value) {
|
|
86
|
+
export function uint64ToVlq(value: number | bigint) {
|
|
85
87
|
// 10 bytes is the maximum VLQ size for a uint64
|
|
86
88
|
const out = Buffer.allocUnsafe(10);
|
|
87
89
|
const size = writeVlqcontent(out, value);
|
|
@@ -93,7 +95,7 @@ export function uint64ToVlq(value) {
|
|
|
93
95
|
|
|
94
96
|
|
|
95
97
|
|
|
96
|
-
export function sliceArrayBuffer(buffer, offset, length) {
|
|
98
|
+
export function sliceArrayBuffer(buffer: Buffer | Uint8Array, offset: number, length: number) {
|
|
97
99
|
// Ensure we are working with a Node.js Buffer
|
|
98
100
|
const buf = Buffer.isBuffer(buffer) ? buffer : Buffer.from(buffer);
|
|
99
101
|
const totalSize = buf.length;
|
|
@@ -113,13 +115,13 @@ export function sliceArrayBuffer(buffer, offset, length) {
|
|
|
113
115
|
return buf.subarray(offset, offset + length); // COW/Shallow copy I hope or else what is the use of this function
|
|
114
116
|
}
|
|
115
117
|
|
|
116
|
-
export function stringToUtf8ArrayBuffer(arg) {
|
|
118
|
+
export function stringToUtf8ArrayBuffer(arg: string) {
|
|
117
119
|
// Converts the string into a Node.js Buffer encoded in UTF-8
|
|
118
120
|
return Buffer.from(arg, 'utf8');
|
|
119
121
|
}
|
|
120
122
|
|
|
121
123
|
|
|
122
|
-
export function numberToSortableBytes(value) {
|
|
124
|
+
export function numberToSortableBytes(value: number) {
|
|
123
125
|
// 1. Create an 8-byte buffer and a data view to read/write raw bits
|
|
124
126
|
const buffer = Buffer.alloc(8);
|
|
125
127
|
const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength);
|
|
@@ -148,7 +150,7 @@ export function numberToSortableBytes(value) {
|
|
|
148
150
|
|
|
149
151
|
|
|
150
152
|
|
|
151
|
-
export function defaultHash(buffer) {
|
|
153
|
+
export function defaultHash(buffer: Buffer | Uint8Array) {
|
|
152
154
|
const buf = Buffer.isBuffer(buffer) ? buffer : Buffer.from(buffer);
|
|
153
155
|
|
|
154
156
|
// Uses the high-speed, non-cryptographic xxhash64 algorithm
|
|
@@ -160,7 +162,7 @@ export function defaultHash(buffer) {
|
|
|
160
162
|
}
|
|
161
163
|
|
|
162
164
|
|
|
163
|
-
export function memcmpEqual(buffer1, buffer2) {
|
|
165
|
+
export function memcmpEqual(buffer1: Buffer | Uint8Array, buffer2: Buffer | Uint8Array) {
|
|
164
166
|
const b1 = Buffer.isBuffer(buffer1) ? buffer1 : Buffer.from(buffer1);
|
|
165
167
|
const b2 = Buffer.isBuffer(buffer2) ? buffer2 : Buffer.from(buffer2);
|
|
166
168
|
|
|
@@ -168,7 +170,7 @@ export function memcmpEqual(buffer1, buffer2) {
|
|
|
168
170
|
}
|
|
169
171
|
|
|
170
172
|
|
|
171
|
-
export function arrayBufferToString(buffer) {
|
|
173
|
+
export function arrayBufferToString(buffer: Buffer | Uint8Array) {
|
|
172
174
|
const buf = Buffer.isBuffer(buffer) ? buffer : Buffer.from(buffer);
|
|
173
175
|
|
|
174
176
|
// Decodes the buffer bytes as a UTF-8 JavaScript string
|
|
@@ -180,7 +182,7 @@ export function arrayBufferToString(buffer) {
|
|
|
180
182
|
|
|
181
183
|
|
|
182
184
|
// Matches QString Response::getSliceAsText
|
|
183
|
-
export function getSliceAsText(rawTextBuffer, offset: number, length: number): string {
|
|
185
|
+
export function getSliceAsText(rawTextBuffer: Buffer, offset: number, length: number): string {
|
|
184
186
|
// Reuses the identical slice boundary logic from above
|
|
185
187
|
try {
|
|
186
188
|
const slice = getSliceAsArrayBuffer(rawTextBuffer, offset, length);
|
|
@@ -191,7 +193,7 @@ export function getSliceAsText(rawTextBuffer, offset: number, length: number): s
|
|
|
191
193
|
}
|
|
192
194
|
|
|
193
195
|
// Matches QByteArray Response::getSliceAsArrayBuffer
|
|
194
|
-
export function getSliceAsArrayBuffer(rawTextBuffer, offset: number, length: number): Buffer {
|
|
196
|
+
export function getSliceAsArrayBuffer(rawTextBuffer: Buffer, offset: number, length: number): Buffer {
|
|
195
197
|
const totalSize = rawTextBuffer.length;
|
|
196
198
|
|
|
197
199
|
if (offset < 0 || offset >= totalSize) {
|
package/libs/dip/suffix/date.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {getNormalizedBounds, type
|
|
1
|
+
import {getNormalizedBounds, type AbsoluteBounds} from './index.ts'
|
|
2
2
|
import {addUTCYears, addUTCMonths, addUTCDays} from '../../utils.ts'
|
|
3
3
|
|
|
4
4
|
|
|
@@ -6,7 +6,7 @@ const MONTH_SHORT = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Se
|
|
|
6
6
|
const MONTH_LONG = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]
|
|
7
7
|
|
|
8
8
|
|
|
9
|
-
export function formatDate(value, format) {
|
|
9
|
+
export function formatDate(value: string | number | Date, format: string) {
|
|
10
10
|
|
|
11
11
|
const dateObj = value instanceof Date ? value : new Date(value)
|
|
12
12
|
|
|
@@ -59,7 +59,7 @@ export function formatDate(value, format) {
|
|
|
59
59
|
D: () => dates.join(separator),
|
|
60
60
|
};
|
|
61
61
|
|
|
62
|
-
return format.replace(/YYYY|MMMM|MMM|YY|MM|DD|D/g, token => replacements[token]());
|
|
62
|
+
return format.replace(/YYYY|MMMM|MMM|YY|MM|DD|D/g, token => replacements[token as keyof typeof replacements]());
|
|
63
63
|
}
|
|
64
64
|
|
|
65
65
|
|
|
@@ -83,7 +83,7 @@ export function formatDate(value, format) {
|
|
|
83
83
|
|
|
84
84
|
|
|
85
85
|
|
|
86
|
-
export function fillDates(bounds_t, format) {
|
|
86
|
+
export function fillDates(bounds_t: AbsoluteBounds, format: string) {
|
|
87
87
|
const result = [];
|
|
88
88
|
|
|
89
89
|
let step;
|
|
@@ -94,11 +94,11 @@ export function fillDates(bounds_t, format) {
|
|
|
94
94
|
else
|
|
95
95
|
step = "year";
|
|
96
96
|
|
|
97
|
-
let bounds:
|
|
97
|
+
let bounds: AbsoluteBounds = { ...bounds_t, from: new Date(bounds_t.from), to: new Date(bounds_t.to) }
|
|
98
98
|
|
|
99
99
|
bounds = getNormalizedBounds(bounds, "date")
|
|
100
100
|
|
|
101
|
-
while (bounds.from <= bounds.to) {
|
|
101
|
+
while (bounds.from! <= bounds.to!) {
|
|
102
102
|
result.push(formatDate(bounds.from, format));
|
|
103
103
|
|
|
104
104
|
switch (step) {
|
package/libs/dip/suffix/index.ts
CHANGED
|
@@ -1,18 +1,35 @@
|
|
|
1
1
|
|
|
2
|
+
export type BoundValue = number | string | Date
|
|
3
|
+
export type BoundFromOp = "$gt" | "$gte"
|
|
4
|
+
export type BoundToOp = "$lt" | "$lte"
|
|
2
5
|
|
|
6
|
+
export type Bounds = {
|
|
7
|
+
values: unknown[],
|
|
8
|
+
from: BoundValue | unknown;
|
|
9
|
+
to: BoundValue | unknown;
|
|
10
|
+
fromOp: BoundFromOp | unknown;
|
|
11
|
+
toOp: BoundToOp | unknown;
|
|
12
|
+
}
|
|
13
|
+
export type AbsoluteBounds = {
|
|
14
|
+
from: BoundValue;
|
|
15
|
+
to: BoundValue;
|
|
16
|
+
fromOp: BoundFromOp;
|
|
17
|
+
toOp: BoundToOp;
|
|
18
|
+
}
|
|
3
19
|
|
|
4
|
-
|
|
5
|
-
|
|
20
|
+
|
|
21
|
+
function flatten_id_values(target_key: string, values: unknown): unknown[] {
|
|
22
|
+
let flattened: unknown[] = [];
|
|
6
23
|
flatten_value(target_key, values, flattened, false);
|
|
7
24
|
return flattened
|
|
8
25
|
}
|
|
9
26
|
|
|
10
|
-
function flatten_value(target_key, value, flattened, ancestor_has_id) {
|
|
27
|
+
function flatten_value(target_key: string, value: unknown, flattened: unknown[], ancestor_has_id: boolean) {
|
|
11
28
|
const is_array = Array.isArray(value)
|
|
12
29
|
const is_object = value !== null && !is_array && typeof value === "object";
|
|
13
30
|
const is_regular = typeof value === "boolean" || typeof value === "number" || typeof value === "string"
|
|
14
|
-
const map = value
|
|
15
|
-
const arr = value
|
|
31
|
+
const map = value as Record<string, unknown>
|
|
32
|
+
const arr = value as unknown[]
|
|
16
33
|
|
|
17
34
|
if (is_regular) {
|
|
18
35
|
flattened.push(value);
|
|
@@ -72,7 +89,7 @@ function flatten_value(target_key, value, flattened, ancestor_has_id) {
|
|
|
72
89
|
}
|
|
73
90
|
|
|
74
91
|
|
|
75
|
-
export function entries(target_key: string, query, binary_slice?: Buffer) {
|
|
92
|
+
export function entries(target_key: string, query: unknown, binary_slice?: Buffer): unknown[] {
|
|
76
93
|
let result = flatten_id_values(target_key, query); // extract all valid _id
|
|
77
94
|
|
|
78
95
|
// let cows = result.map(v => extract_direct_id(v, binary_slice))
|
|
@@ -95,19 +112,21 @@ export function entries(target_key: string, query, binary_slice?: Buffer) {
|
|
|
95
112
|
// reduceRanges() intentionally computes a conservative (wider) approximation.
|
|
96
113
|
// It is used only for suffix policy planning, where false positives are acceptable
|
|
97
114
|
// (extra suffix scans) but false negatives are not.
|
|
98
|
-
export function reduceRanges(values) {
|
|
115
|
+
export function reduceRanges(values: unknown[]) {
|
|
99
116
|
let gt = null;
|
|
100
117
|
let gte = null;
|
|
101
118
|
let lt = null;
|
|
102
119
|
let lte = null;
|
|
103
120
|
const other = [];
|
|
104
121
|
|
|
105
|
-
for (const
|
|
106
|
-
if (typeof
|
|
107
|
-
other.push(
|
|
122
|
+
for (const v of values) {
|
|
123
|
+
if (typeof v !== "object" || v === null || Array.isArray(v)) {
|
|
124
|
+
other.push(v);
|
|
108
125
|
continue;
|
|
109
126
|
}
|
|
110
127
|
|
|
128
|
+
const value = v as Record<string, {$gt?: BoundValue, $gte?: BoundValue, $lt?: BoundValue, $lte?: BoundValue}>
|
|
129
|
+
|
|
111
130
|
if ("$gt" in value) {
|
|
112
131
|
if (gt === null || value.$gt < gt)
|
|
113
132
|
gt = value.$gt;
|
|
@@ -160,31 +179,27 @@ export function reduceRanges(values) {
|
|
|
160
179
|
return other;
|
|
161
180
|
}
|
|
162
181
|
|
|
163
|
-
|
|
164
|
-
values: any[],
|
|
165
|
-
from: number | string | Date;
|
|
166
|
-
to: number | string | Date;
|
|
167
|
-
fromOp: "$gt" | "$gte";
|
|
168
|
-
toOp: "$lt" | "$lte";
|
|
169
|
-
}
|
|
182
|
+
|
|
170
183
|
|
|
171
184
|
// reduceRanges() resolves conflicting bounds before extractBounds() runs.
|
|
172
185
|
// extractBounds() receives at most one lower bound and atmost one upper bound. reduceRanges() ensures this
|
|
173
186
|
// The for loop in extractBounds() may look slightly misleading because it looks like it is designed to resolve conflicts: but reduceRanges() has already done the conflict resolution.
|
|
174
187
|
// NOTE CRITICAL: extractBounds() MUST ONLY BE RUN ON THE OUTPUT OF reduceRanges()
|
|
175
|
-
export function extractBounds(values): Bounds {
|
|
176
|
-
let lower = null;
|
|
177
|
-
let upper = null;
|
|
178
|
-
let lowerOp = null
|
|
179
|
-
let upperOp = null
|
|
188
|
+
export function extractBounds(values: unknown[]): Bounds {
|
|
189
|
+
let lower: BoundValue | unknown = null;
|
|
190
|
+
let upper: BoundValue | unknown = null;
|
|
191
|
+
let lowerOp: BoundFromOp | unknown = null
|
|
192
|
+
let upperOp: BoundToOp | unknown = null
|
|
180
193
|
const remaining = [];
|
|
181
194
|
|
|
182
|
-
for (const
|
|
183
|
-
if (typeof
|
|
184
|
-
remaining.push(
|
|
195
|
+
for (const v of values) {
|
|
196
|
+
if (typeof v !== "object" || v === null || Array.isArray(v)) {
|
|
197
|
+
remaining.push(v);
|
|
185
198
|
continue;
|
|
186
199
|
}
|
|
187
200
|
|
|
201
|
+
const value = v as Record<string, {$gt?: BoundValue, $gte?: BoundValue, $lt?: BoundValue, $lte?: BoundValue}>
|
|
202
|
+
|
|
188
203
|
if ("$gt" in value) {
|
|
189
204
|
lower = value.$gt;
|
|
190
205
|
lowerOp = "$gt"
|
|
@@ -212,7 +227,7 @@ export function extractBounds(values): Bounds {
|
|
|
212
227
|
}
|
|
213
228
|
|
|
214
229
|
// Converts exclusive bounds ($gt/$lt) into inclusive bounds
|
|
215
|
-
export function getNormalizedBounds(bounds_t:
|
|
230
|
+
export function getNormalizedBounds<T extends Bounds | AbsoluteBounds>(bounds_t: T, type: "number" | "date"): T {
|
|
216
231
|
let bounds = {...bounds_t}
|
|
217
232
|
|
|
218
233
|
if (type === "number") {
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import {entries, reduceRanges, extractBounds} from './index.ts'
|
|
1
|
+
import {entries, reduceRanges, extractBounds, type Bounds, type BoundValue} from './index.ts'
|
|
2
2
|
import {suffix} from './suffix.ts'
|
|
3
3
|
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
|
|
7
|
-
export function overlaps(a, b) {
|
|
7
|
+
export function overlaps(a: Bounds, b: Bounds) {
|
|
8
|
+
|
|
8
9
|
const aFrom = a.from ?? -Infinity;
|
|
9
10
|
const aTo = a.to ?? Infinity;
|
|
10
11
|
|
|
@@ -12,9 +13,11 @@ export function overlaps(a, b) {
|
|
|
12
13
|
const bTo = b.to ?? Infinity;
|
|
13
14
|
|
|
14
15
|
|
|
16
|
+
const max = (a: BoundValue, b: BoundValue) => a > b ? a : b
|
|
17
|
+
const min = (a: BoundValue, b: BoundValue) => a < b ? a : b
|
|
15
18
|
|
|
16
|
-
const left =
|
|
17
|
-
const right =
|
|
19
|
+
const left = max(aFrom as BoundValue, bFrom as BoundValue);
|
|
20
|
+
const right = min(aTo as BoundValue, bTo as BoundValue);
|
|
18
21
|
|
|
19
22
|
if (left < right)
|
|
20
23
|
return true;
|
|
@@ -35,7 +38,7 @@ export function overlaps(a, b) {
|
|
|
35
38
|
|
|
36
39
|
|
|
37
40
|
|
|
38
|
-
export function contains(bounds, value) {
|
|
41
|
+
export function contains(bounds: Bounds, value: BoundValue) {
|
|
39
42
|
const from = bounds.from ?? -Infinity;
|
|
40
43
|
const to = bounds.to ?? Infinity;
|
|
41
44
|
|
|
@@ -56,7 +59,7 @@ export function contains(bounds, value) {
|
|
|
56
59
|
// return value >= from && value <= to;
|
|
57
60
|
}
|
|
58
61
|
|
|
59
|
-
export function intersects(w_values, w_bounds, q_values, q_bounds) {
|
|
62
|
+
export function intersects(w_values: BoundValue[], w_bounds: Bounds | null, q_values: BoundValue[], q_bounds: Bounds | null) {
|
|
60
63
|
// value ↔ value
|
|
61
64
|
for (const value of w_values) {
|
|
62
65
|
if (q_values.includes(value))
|
|
@@ -88,7 +91,7 @@ export function intersects(w_values, w_bounds, q_values, q_bounds) {
|
|
|
88
91
|
|
|
89
92
|
|
|
90
93
|
// NOTE: Matching is based on intersection, not equality. A policy matches if, for every key in `when`, there exists at least one value that satisfies both the `when` constraint and the query constraint.
|
|
91
|
-
export function matchPolicy(query, when, g_obj?: Record<string,
|
|
94
|
+
export function matchPolicy(query: Record<string, any>, when: Record<string, any>, g_obj?: Record<string, unknown[]>) {
|
|
92
95
|
let obj = g_obj ?? {}
|
|
93
96
|
for (let key in when) {
|
|
94
97
|
if (key === "$and" || key === "$or") {
|
|
@@ -124,7 +127,7 @@ export function matchPolicy(query, when, g_obj?: Record<string, any>) {
|
|
|
124
127
|
q_values = q_values.filter(item => typeof item !== "object")
|
|
125
128
|
const q_bounds = q_ranges.length ? extractBounds(reduceRanges(q_ranges)) : null
|
|
126
129
|
|
|
127
|
-
if (!intersects(w_values, w_bounds, q_values, q_bounds))
|
|
130
|
+
if (!intersects(w_values as BoundValue[], w_bounds, q_values as BoundValue[], q_bounds))
|
|
128
131
|
return false;
|
|
129
132
|
|
|
130
133
|
}
|
|
@@ -132,14 +135,14 @@ export function matchPolicy(query, when, g_obj?: Record<string, any>) {
|
|
|
132
135
|
}
|
|
133
136
|
|
|
134
137
|
|
|
138
|
+
type SuffixItem = { key?: string; value?: string; type: string; ls_threshold?: number; min?: number; max?: number }
|
|
135
139
|
|
|
136
|
-
|
|
137
|
-
|
|
140
|
+
type CollectionsJsonType = Record<string, {policy?: {when: object, suffix: SuffixItem[]}[]}>
|
|
138
141
|
type Arg = { db: string; collection: string[]; }
|
|
139
142
|
|
|
140
|
-
export async function applySuffixPolicy(COLLECTIONS_JSON,
|
|
141
|
-
collections = Array.isArray(
|
|
142
|
-
let suffixes = []
|
|
143
|
+
export async function applySuffixPolicy(COLLECTIONS_JSON: CollectionsJsonType, cols: string | string[], query: Record<string, any>, insertMode?: boolean, arg?: Arg) {
|
|
144
|
+
const collections = Array.isArray(cols) ? cols : [cols]
|
|
145
|
+
let suffixes: string[] = []
|
|
143
146
|
|
|
144
147
|
for (let collection of collections) {
|
|
145
148
|
const collection_policy = COLLECTIONS_JSON[collection]?.policy ?? []
|