corebasic 1.0.212 → 1.0.213

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.
Files changed (141) hide show
  1. package/dist/index.js +10 -0
  2. package/dist/libs/ObjectId.js +114 -0
  3. package/dist/libs/auth.js +103 -0
  4. package/dist/libs/compression.js +11 -0
  5. package/dist/libs/cpp.js +154 -0
  6. package/dist/libs/dip/suffix/date.js +89 -0
  7. package/dist/libs/dip/suffix/index.js +227 -0
  8. package/dist/libs/dip/suffix/policy.js +113 -0
  9. package/dist/libs/dip/suffix/query.js +279 -0
  10. package/dist/libs/dip/suffix/suffix.js +99 -0
  11. package/dist/libs/dip/suffix/tests/date.test.js +187 -0
  12. package/dist/libs/dip/suffix/tests/index.test.js +441 -0
  13. package/dist/libs/dip/suffix/tests/policy.applySuffixPolicy.test.js +489 -0
  14. package/dist/libs/dip/suffix/tests/policy.test.js +329 -0
  15. package/dist/libs/dip/suffix/tests/suffix.test.js +316 -0
  16. package/dist/libs/dip.js +102 -0
  17. package/dist/libs/dipper.js +73 -0
  18. package/dist/libs/elabase.js +656 -0
  19. package/dist/libs/features.js +366 -0
  20. package/dist/libs/kafka.js +121 -0
  21. package/dist/libs/messaging.js +130 -0
  22. package/dist/libs/mobilecodes.js +562 -0
  23. package/dist/libs/session.js +96 -0
  24. package/dist/libs/utils.js +297 -0
  25. package/package.json +3 -2
  26. package/tsc/@typescript/typescript-linux-x64/LICENSE +55 -0
  27. package/tsc/@typescript/typescript-linux-x64/NOTICE.txt +436 -0
  28. package/tsc/@typescript/typescript-linux-x64/README.md +3 -0
  29. package/tsc/@typescript/typescript-linux-x64/lib/lib.d.ts +20 -0
  30. package/tsc/@typescript/typescript-linux-x64/lib/lib.decorators.d.ts +382 -0
  31. package/tsc/@typescript/typescript-linux-x64/lib/lib.decorators.legacy.d.ts +20 -0
  32. package/tsc/@typescript/typescript-linux-x64/lib/lib.dom.asynciterable.d.ts +18 -0
  33. package/tsc/@typescript/typescript-linux-x64/lib/lib.dom.d.ts +45125 -0
  34. package/tsc/@typescript/typescript-linux-x64/lib/lib.dom.iterable.d.ts +18 -0
  35. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2015.collection.d.ts +159 -0
  36. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2015.core.d.ts +595 -0
  37. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2015.d.ts +26 -0
  38. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2015.generator.d.ts +75 -0
  39. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2015.iterable.d.ts +603 -0
  40. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2015.promise.d.ts +79 -0
  41. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2015.proxy.d.ts +126 -0
  42. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2015.reflect.d.ts +142 -0
  43. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2015.symbol.d.ts +44 -0
  44. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2015.symbol.wellknown.d.ts +324 -0
  45. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2016.array.include.d.ts +114 -0
  46. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2016.d.ts +19 -0
  47. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2016.full.d.ts +21 -0
  48. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2016.intl.d.ts +29 -0
  49. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2017.arraybuffer.d.ts +19 -0
  50. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2017.d.ts +24 -0
  51. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2017.date.d.ts +29 -0
  52. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2017.full.d.ts +21 -0
  53. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2017.intl.d.ts +42 -0
  54. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2017.object.d.ts +47 -0
  55. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2017.sharedmemory.d.ts +133 -0
  56. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2017.string.d.ts +47 -0
  57. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2017.typedarrays.d.ts +51 -0
  58. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2018.asyncgenerator.d.ts +75 -0
  59. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2018.asynciterable.d.ts +51 -0
  60. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2018.d.ts +22 -0
  61. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2018.full.d.ts +22 -0
  62. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2018.intl.d.ts +81 -0
  63. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2018.promise.d.ts +28 -0
  64. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2018.regexp.d.ts +35 -0
  65. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2019.array.d.ts +77 -0
  66. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2019.d.ts +22 -0
  67. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2019.full.d.ts +22 -0
  68. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2019.intl.d.ts +21 -0
  69. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2019.object.d.ts +31 -0
  70. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2019.string.d.ts +35 -0
  71. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2019.symbol.d.ts +22 -0
  72. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2020.bigint.d.ts +763 -0
  73. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2020.d.ts +25 -0
  74. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2020.date.d.ts +40 -0
  75. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2020.full.d.ts +22 -0
  76. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2020.intl.d.ts +472 -0
  77. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2020.number.d.ts +26 -0
  78. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2020.promise.d.ts +45 -0
  79. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2020.sharedmemory.d.ts +97 -0
  80. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2020.string.d.ts +42 -0
  81. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2020.symbol.wellknown.d.ts +39 -0
  82. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2021.d.ts +21 -0
  83. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2021.full.d.ts +22 -0
  84. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2021.intl.d.ts +164 -0
  85. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2021.promise.d.ts +46 -0
  86. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2021.string.d.ts +31 -0
  87. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2021.weakref.d.ts +76 -0
  88. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2022.array.d.ts +119 -0
  89. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2022.d.ts +23 -0
  90. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2022.error.d.ts +73 -0
  91. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2022.full.d.ts +22 -0
  92. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2022.intl.d.ts +143 -0
  93. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2022.object.d.ts +24 -0
  94. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2022.regexp.d.ts +37 -0
  95. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2022.string.d.ts +23 -0
  96. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2023.array.d.ts +922 -0
  97. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2023.collection.d.ts +19 -0
  98. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2023.d.ts +20 -0
  99. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2023.full.d.ts +22 -0
  100. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2023.intl.d.ts +62 -0
  101. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2024.arraybuffer.d.ts +63 -0
  102. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2024.collection.d.ts +27 -0
  103. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2024.d.ts +24 -0
  104. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2024.full.d.ts +22 -0
  105. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2024.object.d.ts +27 -0
  106. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2024.promise.d.ts +33 -0
  107. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2024.regexp.d.ts +23 -0
  108. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2024.sharedmemory.d.ts +66 -0
  109. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2024.string.d.ts +27 -0
  110. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2025.collection.d.ts +94 -0
  111. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2025.d.ts +23 -0
  112. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2025.float16.d.ts +443 -0
  113. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2025.full.d.ts +22 -0
  114. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2025.intl.d.ts +200 -0
  115. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2025.iterator.d.ts +146 -0
  116. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2025.promise.d.ts +32 -0
  117. package/tsc/@typescript/typescript-linux-x64/lib/lib.es2025.regexp.d.ts +30 -0
  118. package/tsc/@typescript/typescript-linux-x64/lib/lib.es5.d.ts +4599 -0
  119. package/tsc/@typescript/typescript-linux-x64/lib/lib.es6.d.ts +21 -0
  120. package/tsc/@typescript/typescript-linux-x64/lib/lib.esnext.array.d.ts +33 -0
  121. package/tsc/@typescript/typescript-linux-x64/lib/lib.esnext.collection.d.ts +47 -0
  122. package/tsc/@typescript/typescript-linux-x64/lib/lib.esnext.d.ts +27 -0
  123. package/tsc/@typescript/typescript-linux-x64/lib/lib.esnext.date.d.ts +21 -0
  124. package/tsc/@typescript/typescript-linux-x64/lib/lib.esnext.decorators.d.ts +26 -0
  125. package/tsc/@typescript/typescript-linux-x64/lib/lib.esnext.disposable.d.ts +191 -0
  126. package/tsc/@typescript/typescript-linux-x64/lib/lib.esnext.error.d.ts +22 -0
  127. package/tsc/@typescript/typescript-linux-x64/lib/lib.esnext.full.d.ts +22 -0
  128. package/tsc/@typescript/typescript-linux-x64/lib/lib.esnext.intl.d.ts +107 -0
  129. package/tsc/@typescript/typescript-linux-x64/lib/lib.esnext.sharedmemory.d.ts +23 -0
  130. package/tsc/@typescript/typescript-linux-x64/lib/lib.esnext.temporal.d.ts +485 -0
  131. package/tsc/@typescript/typescript-linux-x64/lib/lib.esnext.typedarrays.d.ts +90 -0
  132. package/tsc/@typescript/typescript-linux-x64/lib/lib.scripthost.d.ts +320 -0
  133. package/tsc/@typescript/typescript-linux-x64/lib/lib.webworker.asynciterable.d.ts +18 -0
  134. package/tsc/@typescript/typescript-linux-x64/lib/lib.webworker.d.ts +15606 -0
  135. package/tsc/@typescript/typescript-linux-x64/lib/lib.webworker.importscripts.d.ts +21 -0
  136. package/tsc/@typescript/typescript-linux-x64/lib/lib.webworker.iterable.d.ts +18 -0
  137. package/tsc/@typescript/typescript-linux-x64/lib/tsc +0 -0
  138. package/tsc/@typescript/typescript-linux-x64/lib/tsc.sig +11 -0
  139. package/tsc/@typescript/typescript-linux-x64/package.json +45 -0
  140. package/tsc/notes +14 -0
  141. package/tsconfig.json +48 -0
@@ -0,0 +1,329 @@
1
+ import { describe, test } from "node:test";
2
+ import assert from "node:assert/strict";
3
+ import { matchPolicy, overlaps, contains, intersects, applySuffixPolicy } from "../policy.js";
4
+ /* ============================================================
5
+ * overlaps()
6
+ * ============================================================ */
7
+ describe("overlaps()", () => {
8
+ test("overlaps: identical ranges", () => {
9
+ assert.equal(overlaps({ from: 10, to: 20 }, { from: 10, to: 20 }), true);
10
+ });
11
+ test("overlaps: partial overlap", () => {
12
+ assert.equal(overlaps({ from: 10, to: 20 }, { from: 15, to: 25 }), true);
13
+ });
14
+ test("overlaps: no overlap", () => {
15
+ assert.equal(overlaps({ from: 10, to: 20 }, { from: 21, to: 30 }), false);
16
+ });
17
+ test("overlaps: open ended lower", () => {
18
+ assert.equal(overlaps({ to: 10 }, { from: 5 }), true);
19
+ });
20
+ test("overlaps: open ended upper", () => {
21
+ assert.equal(overlaps({ from: 20 }, { to: 10 }), false);
22
+ });
23
+ describe("overlaps() boundary semantics", () => {
24
+ test("touching: open/open does not overlap", () => {
25
+ assert.equal(overlaps({ to: 10, toOp: "$lt" }, { from: 10, fromOp: "$gt" }), false);
26
+ });
27
+ test("touching: closed/closed overlaps", () => {
28
+ assert.equal(overlaps({ to: 10, toOp: "$lte" }, { from: 10, fromOp: "$gte" }), true);
29
+ });
30
+ test("touching: closed/open does not overlap", () => {
31
+ assert.equal(overlaps({ to: 10, toOp: "$lte" }, { from: 10, fromOp: "$gt" }), false);
32
+ });
33
+ test("touching: open/closed does not overlap", () => {
34
+ assert.equal(overlaps({ to: 10, toOp: "$lt" }, { from: 10, fromOp: "$gte" }), false);
35
+ });
36
+ test("touching: reverse order closed/closed overlaps", () => {
37
+ assert.equal(overlaps({ from: 10, fromOp: "$gte" }, { to: 10, toOp: "$lte" }), true);
38
+ });
39
+ test("touching: reverse order open/open does not overlap", () => {
40
+ assert.equal(overlaps({ from: 10, fromOp: "$gt" }, { to: 10, toOp: "$lt" }), false);
41
+ });
42
+ 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);
54
+ });
55
+ 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);
67
+ });
68
+ test("infinite lower bound with touching closed endpoint overlaps", () => {
69
+ assert.equal(overlaps({ to: 5, toOp: "$lte" }, { from: 5, fromOp: "$gte" }), true);
70
+ });
71
+ test("infinite lower bound with touching open endpoint does not overlap", () => {
72
+ assert.equal(overlaps({ to: 5, toOp: "$lt" }, { from: 5, fromOp: "$gt" }), false);
73
+ });
74
+ });
75
+ });
76
+ /* ============================================================
77
+ * contains()
78
+ * ============================================================ */
79
+ describe("contains()", () => {
80
+ test("contains: inside", () => {
81
+ assert.equal(contains({ from: 10, to: 20 }, 15), true);
82
+ });
83
+ test("contains: below", () => {
84
+ assert.equal(contains({ from: 10, to: 20 }, 5), false);
85
+ });
86
+ test("contains: above", () => {
87
+ assert.equal(contains({ from: 10, to: 20 }, 25), false);
88
+ });
89
+ test("contains: lower bound", () => {
90
+ assert.equal(contains({ from: 10, to: 20 }, 10), true);
91
+ });
92
+ test("contains: upper bound", () => {
93
+ assert.equal(contains({ from: 10, to: 20 }, 20), true);
94
+ });
95
+ test("contains: gt excludes lower bound", () => {
96
+ assert.equal(contains({ from: 5, fromOp: "$gt" }, 5), false);
97
+ });
98
+ test("contains: gte includes lower bound", () => {
99
+ assert.equal(contains({ from: 5, fromOp: "$gte" }, 5), true);
100
+ });
101
+ test("contains: lt excludes upper bound", () => {
102
+ assert.equal(contains({ to: 10, toOp: "$lt" }, 10), false);
103
+ });
104
+ test("contains: lte includes upper bound", () => {
105
+ assert.equal(contains({ to: 10, toOp: "$lte" }, 10), true);
106
+ });
107
+ test("contains: gt/lt excludes both endpoints", () => {
108
+ const bounds = {
109
+ from: 5,
110
+ fromOp: "$gt",
111
+ to: 10,
112
+ toOp: "$lt"
113
+ };
114
+ assert.equal(contains(bounds, 5), false);
115
+ assert.equal(contains(bounds, 10), false);
116
+ assert.equal(contains(bounds, 7), true);
117
+ });
118
+ test("contains: gte/lte includes both endpoints", () => {
119
+ const bounds = {
120
+ from: 5,
121
+ fromOp: "$gte",
122
+ to: 10,
123
+ toOp: "$lte"
124
+ };
125
+ assert.equal(contains(bounds, 5), true);
126
+ assert.equal(contains(bounds, 10), true);
127
+ assert.equal(contains(bounds, 7), true);
128
+ });
129
+ test("contains: gt/lte mixed", () => {
130
+ const bounds = {
131
+ from: 5,
132
+ fromOp: "$gt",
133
+ to: 10,
134
+ toOp: "$lte"
135
+ };
136
+ assert.equal(contains(bounds, 5), false);
137
+ assert.equal(contains(bounds, 10), true);
138
+ });
139
+ test("contains: gte/lt mixed", () => {
140
+ const bounds = {
141
+ from: 5,
142
+ fromOp: "$gte",
143
+ to: 10,
144
+ toOp: "$lt"
145
+ };
146
+ assert.equal(contains(bounds, 5), true);
147
+ assert.equal(contains(bounds, 10), false);
148
+ });
149
+ test("contains: value below lower bound", () => {
150
+ assert.equal(contains({ from: 5, fromOp: "$gte" }, 4), false);
151
+ });
152
+ test("contains: value above upper bound", () => {
153
+ assert.equal(contains({ to: 10, toOp: "$lte" }, 11), false);
154
+ });
155
+ test("contains: open lower bound", () => {
156
+ assert.equal(contains({ to: 10, toOp: "$lte" }, -1000), true);
157
+ });
158
+ test("contains: open upper bound", () => {
159
+ assert.equal(contains({ from: 5, fromOp: "$gte" }, 1000), true);
160
+ });
161
+ test("contains: completely unbounded", () => {
162
+ assert.equal(contains({}, -100), true);
163
+ assert.equal(contains({}, 100), true);
164
+ });
165
+ });
166
+ /* ============================================================
167
+ * intersects()
168
+ * ============================================================ */
169
+ describe("intersects()", () => {
170
+ test("intersects: value ↔ value", () => {
171
+ assert.equal(intersects(["A"], null, ["A"], null), true);
172
+ });
173
+ test("intersects: value ↔ value miss", () => {
174
+ assert.equal(intersects(["A"], null, ["B"], null), false);
175
+ });
176
+ test("intersects: value ↔ range", () => {
177
+ assert.equal(intersects([10], null, [], { from: 5 }), true);
178
+ });
179
+ test("intersects: value ↔ range miss", () => {
180
+ assert.equal(intersects([2], null, [], { from: 5 }), false);
181
+ });
182
+ test("intersects: range ↔ value", () => {
183
+ assert.equal(intersects([], { from: 5 }, [10], null), true);
184
+ });
185
+ test("intersects: range ↔ value miss", () => {
186
+ assert.equal(intersects([], { from: 5 }, [2], null), false);
187
+ });
188
+ test("intersects: range ↔ range", () => {
189
+ assert.equal(intersects([], { from: 10 }, [], { from: 20 }), true);
190
+ });
191
+ test("intersects: range ↔ range miss", () => {
192
+ assert.equal(intersects([], { to: 5 }, [], { from: 10 }), false);
193
+ });
194
+ });
195
+ /* ============================================================
196
+ * matchPolicy()
197
+ * ============================================================ */
198
+ describe("matchPolicy()", () => {
199
+ test("empty when", () => {
200
+ assert.equal(matchPolicy({}, {}), true);
201
+ });
202
+ test("simple equality", () => {
203
+ assert.equal(matchPolicy({ status: "Active" }, { status: "Active" }), true);
204
+ });
205
+ test("simple equality fail", () => {
206
+ assert.equal(matchPolicy({ status: "Pending" }, { status: "Active" }), false);
207
+ });
208
+ test("$in subset", () => {
209
+ assert.equal(matchPolicy({ status: { $in: ["Active", "Pending"] } }, { status: { $in: ["Active"] } }), true);
210
+ });
211
+ test("$in miss", () => {
212
+ assert.equal(matchPolicy({ status: { $in: ["Pending"] } }, { status: { $in: ["Active"] } }), false);
213
+ });
214
+ test("value ↔ range", () => {
215
+ assert.equal(matchPolicy({ age: 10 }, { age: { $gt: 5 } }), true);
216
+ });
217
+ test("value ↔ range miss", () => {
218
+ assert.equal(matchPolicy({ age: 2 }, { age: { $gt: 5 } }), false);
219
+ });
220
+ test("range ↔ value", () => {
221
+ assert.equal(matchPolicy({ age: { $gt: 5 } }, { age: 10 }), true);
222
+ });
223
+ test("range ↔ value miss", () => {
224
+ assert.equal(matchPolicy({ age: { $lt: 5 } }, { age: 10 }), false);
225
+ });
226
+ test("range ↔ range overlap", () => {
227
+ assert.equal(matchPolicy({ age: { $gt: 15 } }, { age: { $gt: 10 } }), true);
228
+ });
229
+ test("range ↔ range miss", () => {
230
+ assert.equal(matchPolicy({ age: { $lt: 5 } }, { age: { $gt: 10 } }), false);
231
+ });
232
+ test("multiple keys", () => {
233
+ assert.equal(matchPolicy({
234
+ status: "Active",
235
+ age: 20
236
+ }, {
237
+ status: "Active",
238
+ age: { $gt: 10 }
239
+ }), true);
240
+ });
241
+ test("multiple keys fail", () => {
242
+ assert.equal(matchPolicy({
243
+ status: "Pending",
244
+ age: 20
245
+ }, {
246
+ status: "Active",
247
+ age: { $gt: 10 }
248
+ }), false);
249
+ });
250
+ test("$and flatten", () => {
251
+ assert.equal(matchPolicy({
252
+ status: "Active",
253
+ region: "IN"
254
+ }, {
255
+ $and: [
256
+ { status: "Active" },
257
+ { region: "IN" }
258
+ ]
259
+ }), true);
260
+ });
261
+ test("$and flatten fail", () => {
262
+ assert.equal(matchPolicy({
263
+ status: "Active",
264
+ region: "US"
265
+ }, {
266
+ $and: [
267
+ { status: "Active" },
268
+ { region: "IN" }
269
+ ]
270
+ }), false);
271
+ });
272
+ test("$or merge semantics", () => {
273
+ assert.equal(matchPolicy({
274
+ status: {
275
+ $in: ["Active", "Pending"]
276
+ }
277
+ }, {
278
+ $or: [
279
+ { status: "Active" },
280
+ { status: "Pending" }
281
+ ]
282
+ }), true);
283
+ });
284
+ test("$ne throws", () => {
285
+ assert.throws(() => {
286
+ matchPolicy({ status: "Deleted" }, {
287
+ status: {
288
+ $ne: "Deleted"
289
+ }
290
+ });
291
+ });
292
+ });
293
+ test("$nin throws", () => {
294
+ assert.throws(() => {
295
+ matchPolicy({ status: "Deleted" }, {
296
+ status: {
297
+ $nin: ["Deleted"]
298
+ }
299
+ });
300
+ });
301
+ });
302
+ test("$not throws", () => {
303
+ assert.throws(() => {
304
+ matchPolicy({ age: 10 }, {
305
+ age: {
306
+ $not: {
307
+ $gt: 5
308
+ }
309
+ }
310
+ });
311
+ });
312
+ });
313
+ test("conservative planner: identical lt", () => {
314
+ assert.equal(matchPolicy({ age: { $lt: 10 } }, { age: { $lt: 10 } }), true);
315
+ });
316
+ test("conservative planner: identical gt", () => {
317
+ assert.equal(matchPolicy({ age: { $gt: 10 } }, { age: { $gt: 10 } }), true);
318
+ });
319
+ test("mixed value + range", () => {
320
+ assert.equal(matchPolicy({
321
+ age: {
322
+ $in: [10],
323
+ $gt: 20
324
+ }
325
+ }, {
326
+ age: 10
327
+ }), true);
328
+ });
329
+ });
@@ -0,0 +1,316 @@
1
+ import { describe, test } from "node:test";
2
+ import assert from "node:assert/strict";
3
+ import { suffix } from "../suffix.js";
4
+ describe("suffix()", () => {
5
+ test("returns empty suffixes when no policies exist", async () => {
6
+ const result = await suffix({}, [], true, {});
7
+ assert.deepEqual(result, []);
8
+ });
9
+ test("generates string suffix from fixed value", async () => {
10
+ const result = await suffix({}, [
11
+ {
12
+ type: "string",
13
+ value: "hello"
14
+ }
15
+ ], true, {});
16
+ assert.deepEqual(result, [
17
+ "/hello"
18
+ ]);
19
+ });
20
+ test("trims fixed string values", async () => {
21
+ const result = await suffix({}, [
22
+ {
23
+ type: "string",
24
+ value: " hello "
25
+ }
26
+ ], true, {});
27
+ assert.deepEqual(result, [
28
+ "/hello"
29
+ ]);
30
+ });
31
+ test("rejects empty fixed value", async () => {
32
+ await assert.rejects(() => suffix({}, [
33
+ {
34
+ type: "string",
35
+ value: " "
36
+ }
37
+ ], true, {}));
38
+ });
39
+ test("uses document key for string policy", async () => {
40
+ const result = await suffix({
41
+ name: "alice"
42
+ }, [
43
+ {
44
+ type: "string",
45
+ key: "name"
46
+ }
47
+ ], true, {});
48
+ assert.deepEqual(result, [
49
+ "/alice"
50
+ ]);
51
+ });
52
+ test("supports multiple policies and cartesian expansion", async () => {
53
+ const result = await suffix({
54
+ category: "books",
55
+ year: 2026
56
+ }, [
57
+ {
58
+ type: "string",
59
+ key: "category"
60
+ },
61
+ {
62
+ type: "number",
63
+ key: "year"
64
+ }
65
+ ], true, {});
66
+ assert.deepEqual(result, [
67
+ "/books/2026"
68
+ ]);
69
+ });
70
+ test("supports multiple values from document key", async () => {
71
+ const result = await suffix({
72
+ tags: [
73
+ "a",
74
+ "b",
75
+ "c"
76
+ ]
77
+ }, [
78
+ {
79
+ type: "string",
80
+ key: "tags"
81
+ }
82
+ ], true, {});
83
+ assert.deepEqual(result.sort(), [
84
+ "/a",
85
+ "/b",
86
+ "/c"
87
+ ]);
88
+ });
89
+ test("number policy accepts numeric values", async () => {
90
+ const result = await suffix({
91
+ age: 42
92
+ }, [
93
+ {
94
+ type: "number",
95
+ key: "age"
96
+ }
97
+ ], true, {});
98
+ assert.deepEqual(result, [
99
+ "/42"
100
+ ]);
101
+ });
102
+ test("rejects invalid suffix policy type", async () => {
103
+ await assert.rejects(() => suffix({}, [
104
+ {
105
+ type: "boolean",
106
+ value: true
107
+ }
108
+ ], true, {}));
109
+ });
110
+ test("defaults type to string", async () => {
111
+ const result = await suffix({
112
+ id: "abc"
113
+ }, [
114
+ {
115
+ key: "id"
116
+ }
117
+ ], true, {});
118
+ assert.deepEqual(result, [
119
+ "/abc"
120
+ ]);
121
+ });
122
+ test("rejects invalid date type without format", async () => {
123
+ await assert.rejects(() => suffix({
124
+ created: "2026-07-09"
125
+ }, [
126
+ {
127
+ type: "date",
128
+ key: "created"
129
+ }
130
+ ], true, {}));
131
+ });
132
+ test("rejects date format containing slash", async () => {
133
+ await assert.rejects(() => suffix({
134
+ created: "2026-07-09"
135
+ }, [
136
+ {
137
+ type: "date:YYYY/MM/DD",
138
+ key: "created"
139
+ }
140
+ ], true, {}));
141
+ });
142
+ test("formats date suffix", async () => {
143
+ const result = await suffix({
144
+ created: "2026-07-09"
145
+ }, [
146
+ {
147
+ type: "date:YYYY-MM-DD",
148
+ key: "created"
149
+ }
150
+ ], true, {});
151
+ assert.deepEqual(result, [
152
+ "/2026-07-09"
153
+ ]);
154
+ });
155
+ test("deduplicates suffixes", async () => {
156
+ const result = await suffix({
157
+ tags: [
158
+ "a",
159
+ "a",
160
+ "b"
161
+ ]
162
+ }, [
163
+ {
164
+ type: "string",
165
+ key: "tags"
166
+ }
167
+ ], true, {});
168
+ assert.deepEqual(result.sort(), [
169
+ "/a",
170
+ "/b"
171
+ ]);
172
+ });
173
+ test("rejects missing insert key", async () => {
174
+ await assert.rejects(() => suffix({}, [
175
+ {
176
+ type: "string",
177
+ key: "missing"
178
+ }
179
+ ], true, {}));
180
+ });
181
+ test("number range expands inclusive bounds", async () => {
182
+ const result = await suffix({
183
+ score: {
184
+ $gte: 1,
185
+ $lte: 3
186
+ }
187
+ }, [
188
+ {
189
+ type: "number",
190
+ key: "score"
191
+ }
192
+ ], true, {});
193
+ assert.deepEqual(result.sort(), [
194
+ "/1",
195
+ "/2",
196
+ "/3"
197
+ ]);
198
+ });
199
+ test("number range uses explicit min/max", async () => {
200
+ const result = await suffix({
201
+ score: {
202
+ $gte: 1,
203
+ $lte: 2
204
+ }
205
+ }, [
206
+ {
207
+ type: "number",
208
+ key: "score",
209
+ min: 5,
210
+ max: 7
211
+ }
212
+ ], true, {});
213
+ assert.deepEqual(result.sort(), ["/1", "/2"]);
214
+ });
215
+ test("number range uses policy max fallback", async () => {
216
+ const result = await suffix({
217
+ score: {
218
+ $gte: 5
219
+ }
220
+ }, [
221
+ {
222
+ type: "number",
223
+ key: "score",
224
+ max: 7
225
+ }
226
+ ], true, {});
227
+ assert.deepEqual(result.sort(), ["/5", "/6", "/7"]);
228
+ });
229
+ test("number range uses policy min fallback", async () => {
230
+ const result = await suffix({
231
+ score: {
232
+ $lte: 7
233
+ }
234
+ }, [
235
+ {
236
+ type: "number",
237
+ key: "score",
238
+ min: 5
239
+ }
240
+ ], true, {});
241
+ assert.deepEqual(result.sort(), ["/5", "/6", "/7"]);
242
+ });
243
+ test("date range expands dates", async () => {
244
+ const result = await suffix({
245
+ created: {
246
+ $gte: "2026-01-01",
247
+ $lte: "2026-01-03"
248
+ }
249
+ }, [
250
+ {
251
+ type: "date:YYYY-MM-DD",
252
+ key: "created"
253
+ }
254
+ ], true, {});
255
+ assert.deepEqual(result.sort(), [
256
+ "/2026-01-01",
257
+ "/2026-01-02",
258
+ "/2026-01-03"
259
+ ]);
260
+ });
261
+ test("throws when ls threshold exceeded for number range", async () => {
262
+ await assert.rejects(() => suffix({
263
+ value: {
264
+ $gte: 1,
265
+ $lte: 100
266
+ }
267
+ }, [
268
+ {
269
+ type: "number",
270
+ key: "value",
271
+ ls_threshold: 5
272
+ }
273
+ ], true, {}));
274
+ });
275
+ test("throws when ls threshold exceeded for date range", async () => {
276
+ await assert.rejects(() => suffix({
277
+ created: {
278
+ $gte: "2026-01-01",
279
+ $lte: "2026-01-10"
280
+ }
281
+ }, [
282
+ {
283
+ type: "date:YYYY-MM-DD",
284
+ key: "created",
285
+ ls_threshold: 2
286
+ }
287
+ ], true, {}));
288
+ });
289
+ test("creates cartesian product for multiple suffix values", async () => {
290
+ const result = await suffix({
291
+ a: [
292
+ "x",
293
+ "y"
294
+ ],
295
+ b: [
296
+ 1,
297
+ 2
298
+ ]
299
+ }, [
300
+ {
301
+ type: "string",
302
+ key: "a"
303
+ },
304
+ {
305
+ type: "number",
306
+ key: "b"
307
+ }
308
+ ], true, {});
309
+ assert.deepEqual(result.sort(), [
310
+ "/x/1",
311
+ "/x/2",
312
+ "/y/1",
313
+ "/y/2"
314
+ ]);
315
+ });
316
+ });