@krtclcdy/tersio 2.25.7 → 2.25.8
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 +17 -10
- package/dashboard/dist/index.html +1 -1
- package/dist/cli/common.js +25 -3
- package/dist/cli/dashboard.js +7 -2
- package/dist/cli/doctor-fix.js +12 -7
- package/dist/cli/doctor.js +16 -3
- package/dist/cli/install.js +5 -5
- package/dist/cli/profile.js +28 -3
- package/dist/cli/rtk-wiring.js +13 -10
- package/dist/cli/usage.js +5 -0
- package/dist/extensions/caveman/index.js +3 -6
- package/dist/extensions/combo/index.js +1 -6
- package/dist/extensions/commands/index.js +7 -2
- package/dist/extensions/pstack/index.js +2 -1
- package/dist/extensions/rtk/filter.js +45 -4
- package/dist/extensions/rtk/session.js +4 -2
- package/dist/extensions/server.js +44 -29
- package/dist/extensions/shared/agent-stats.js +21 -13
- package/dist/extensions/shared/pricing.js +5 -4
- package/dist/extensions/shared/rtk-eligible.js +7 -11
- package/dist/extensions/shared/rtk-gain.js +2 -6
- package/dist/extensions/shared/sqlite.js +1 -6
- package/dist/extensions/shared/usage-ledger.js +97 -12
- package/dist/extensions/shared/utils.js +33 -0
- package/dist/extensions/updater/index.js +15 -7
- package/extensions/caveman/index.ts +3 -6
- package/extensions/combo/index.ts +1 -6
- package/extensions/commands/index.ts +7 -2
- package/extensions/pstack/index.ts +2 -1
- package/extensions/pstack/playbooks/autopilot-full.md +1 -1
- package/extensions/pstack/playbooks/babysit.md +1 -1
- package/extensions/pstack/playbooks/eval.md +1 -1
- package/extensions/pstack/playbooks/multi-phase-plan.md +2 -2
- package/extensions/pstack/playbooks/orchestrate.md +3 -3
- package/extensions/pstack/playbooks/session-pickup.md +1 -1
- package/extensions/pstack/playbooks/shipping.md +2 -2
- package/extensions/pstack/playbooks/worktree-cleanup.md +1 -1
- package/extensions/pstack/skills/reflect/SKILL.md +2 -2
- package/extensions/pstack/skills/show-me-your-work/SKILL.md +2 -2
- package/extensions/rtk/filter.ts +51 -4
- package/extensions/rtk/session.ts +4 -2
- package/extensions/server.ts +31 -23
- package/extensions/shared/agent-stats.ts +21 -12
- package/extensions/shared/pricing.ts +7 -5
- package/extensions/shared/rtk-eligible.ts +7 -11
- package/extensions/shared/rtk-gain.ts +2 -6
- package/extensions/shared/sqlite.ts +1 -6
- package/extensions/shared/usage-ledger.ts +102 -14
- package/extensions/shared/utils.ts +29 -0
- package/extensions/updater/index.ts +18 -7
- package/package.json +3 -5
- package/dist/bench/code-out/pfull-0/debounce.js +0 -13
- package/dist/bench/code-out/pfull-0/deepClone.js +0 -18
- package/dist/bench/code-out/pfull-0/groupBy.js +0 -15
- package/dist/bench/code-out/pfull-1/debounce.js +0 -13
- package/dist/bench/code-out/pfull-1/deepClone.js +0 -17
- package/dist/bench/code-out/pfull-1/groupBy.js +0 -14
- package/dist/bench/code-out/pfull-2/debounce.js +0 -13
- package/dist/bench/code-out/pfull-2/deepClone.js +0 -18
- package/dist/bench/code-out/pfull-2/groupBy.js +0 -15
- package/dist/bench/code-out/pfull-3/debounce.js +0 -12
- package/dist/bench/code-out/pfull-3/deepClone.js +0 -17
- package/dist/bench/code-out/pfull-3/groupBy.js +0 -7
- package/dist/bench/code-out/pfull-4/debounce.js +0 -10
- package/dist/bench/code-out/pfull-4/deepClone.js +0 -17
- package/dist/bench/code-out/pfull-4/groupBy.js +0 -14
- package/dist/bench/code-out/plite-0/debounce.js +0 -13
- package/dist/bench/code-out/plite-0/deepClone.js +0 -18
- package/dist/bench/code-out/plite-0/groupBy.js +0 -15
- package/dist/bench/code-out/plite-1/debounce.js +0 -13
- package/dist/bench/code-out/plite-1/deepClone.js +0 -17
- package/dist/bench/code-out/plite-1/groupBy.js +0 -11
- package/dist/bench/code-out/plite-2/debounce.js +0 -12
- package/dist/bench/code-out/plite-2/deepClone.js +0 -17
- package/dist/bench/code-out/plite-2/groupBy.js +0 -14
- package/dist/bench/code-out/plite-3/debounce.js +0 -12
- package/dist/bench/code-out/plite-3/deepClone.js +0 -17
- package/dist/bench/code-out/plite-3/groupBy.js +0 -14
- package/dist/bench/code-out/plite-4/debounce.js +0 -12
- package/dist/bench/code-out/plite-4/deepClone.js +0 -17
- package/dist/bench/code-out/plite-4/groupBy.js +0 -14
- package/dist/bench/code-out/pultra-0/debounce.js +0 -12
- package/dist/bench/code-out/pultra-0/deepClone.js +0 -20
- package/dist/bench/code-out/pultra-0/groupBy.js +0 -14
- package/dist/bench/code-out/pultra-1/debounce.js +0 -10
- package/dist/bench/code-out/pultra-1/deepClone.js +0 -17
- package/dist/bench/code-out/pultra-1/groupBy.js +0 -7
- package/dist/bench/code-out/pultra-2/debounce.js +0 -13
- package/dist/bench/code-out/pultra-2/deepClone.js +0 -18
- package/dist/bench/code-out/pultra-2/groupBy.js +0 -15
- package/dist/bench/code-out/pultra-3/debounce.js +0 -13
- package/dist/bench/code-out/pultra-3/deepClone.js +0 -18
- package/dist/bench/code-out/pultra-3/groupBy.js +0 -15
- package/dist/bench/code-out/pultra-4/debounce.js +0 -13
- package/dist/bench/code-out/pultra-4/deepClone.js +0 -18
- package/dist/bench/code-out/pultra-4/groupBy.js +0 -15
- package/dist/bench/code-out/run-0/debounce.js +0 -12
- package/dist/bench/code-out/run-0/deepClone.js +0 -17
- package/dist/bench/code-out/run-0/groupBy.js +0 -14
- package/dist/bench/code-out/run-1/debounce.js +0 -13
- package/dist/bench/code-out/run-1/deepClone.js +0 -15
- package/dist/bench/code-out/run-1/groupBy.js +0 -13
- package/dist/bench/code-out/run-2/debounce.js +0 -12
- package/dist/bench/code-out/run-2/deepClone.js +0 -18
- package/dist/bench/code-out/run-2/groupBy.js +0 -13
- package/dist/bench/code-out/run-3/debounce.js +0 -12
- package/dist/bench/code-out/run-3/deepClone.js +0 -18
- package/dist/bench/code-out/run-3/groupBy.js +0 -14
- package/dist/bench/code-out/run-4/debounce.js +0 -12
- package/dist/bench/code-out/run-4/deepClone.js +0 -16
- package/dist/bench/code-out/run-4/groupBy.js +0 -13
- package/dist/extensions/caveman/rule-lite.md +0 -77
- package/dist/extensions/caveman/rule-megacave-lite.md +0 -59
- package/dist/extensions/caveman/rule-megacave-ultra.md +0 -59
- package/dist/extensions/caveman/rule-megacave.md +0 -65
- package/dist/extensions/caveman/rule-ultra.md +0 -63
- package/dist/extensions/caveman/rule.md +0 -89
- package/dist/extensions/pstack/rule.md +0 -141
- package/dist/probe-catalog.js +0 -48
- package/dist/probe-catalog188.js +0 -44
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
export function deepClone(value) {
|
|
2
|
-
if (value === null || typeof value !== 'object') {
|
|
3
|
-
return value;
|
|
4
|
-
}
|
|
5
|
-
if (value instanceof Date) {
|
|
6
|
-
return new Date(value.getTime());
|
|
7
|
-
}
|
|
8
|
-
if (Array.isArray(value)) {
|
|
9
|
-
return value.map((item) => deepClone(item));
|
|
10
|
-
}
|
|
11
|
-
const source = value;
|
|
12
|
-
const result = {};
|
|
13
|
-
for (const key of Object.keys(source)) {
|
|
14
|
-
result[key] = deepClone(source[key]);
|
|
15
|
-
}
|
|
16
|
-
return result;
|
|
17
|
-
}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
export function deepClone(value) {
|
|
2
|
-
if (value === null || typeof value !== 'object') {
|
|
3
|
-
return value;
|
|
4
|
-
}
|
|
5
|
-
if (value instanceof Date) {
|
|
6
|
-
return new Date(value.getTime());
|
|
7
|
-
}
|
|
8
|
-
if (Array.isArray(value)) {
|
|
9
|
-
return value.map((item) => deepClone(item));
|
|
10
|
-
}
|
|
11
|
-
const source = value;
|
|
12
|
-
const clone = {};
|
|
13
|
-
for (const key of Object.keys(source)) {
|
|
14
|
-
clone[key] = deepClone(source[key]);
|
|
15
|
-
}
|
|
16
|
-
return clone;
|
|
17
|
-
}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
export function groupBy(items, keyFn) {
|
|
2
|
-
const groups = {};
|
|
3
|
-
for (const item of items) {
|
|
4
|
-
const key = keyFn(item);
|
|
5
|
-
const existing = groups[key];
|
|
6
|
-
if (existing === undefined) {
|
|
7
|
-
groups[key] = [item];
|
|
8
|
-
}
|
|
9
|
-
else {
|
|
10
|
-
existing.push(item);
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
|
-
return groups;
|
|
14
|
-
}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
export function deepClone(value) {
|
|
2
|
-
if (value === null || typeof value !== 'object') {
|
|
3
|
-
return value;
|
|
4
|
-
}
|
|
5
|
-
if (value instanceof Date) {
|
|
6
|
-
return new Date(value.getTime());
|
|
7
|
-
}
|
|
8
|
-
if (Array.isArray(value)) {
|
|
9
|
-
return value.map((item) => deepClone(item));
|
|
10
|
-
}
|
|
11
|
-
const source = value;
|
|
12
|
-
const clone = {};
|
|
13
|
-
for (const key of Object.keys(source)) {
|
|
14
|
-
clone[key] = deepClone(source[key]);
|
|
15
|
-
}
|
|
16
|
-
return clone;
|
|
17
|
-
}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
export function groupBy(items, keyFn) {
|
|
2
|
-
const groups = {};
|
|
3
|
-
for (const item of items) {
|
|
4
|
-
const key = keyFn(item);
|
|
5
|
-
const existing = groups[key];
|
|
6
|
-
if (existing === undefined) {
|
|
7
|
-
groups[key] = [item];
|
|
8
|
-
}
|
|
9
|
-
else {
|
|
10
|
-
existing.push(item);
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
|
-
return groups;
|
|
14
|
-
}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
export function deepClone(value) {
|
|
2
|
-
if (value === null || typeof value !== 'object') {
|
|
3
|
-
return value;
|
|
4
|
-
}
|
|
5
|
-
if (value instanceof Date) {
|
|
6
|
-
return new Date(value.getTime());
|
|
7
|
-
}
|
|
8
|
-
if (Array.isArray(value)) {
|
|
9
|
-
return value.map((item) => deepClone(item));
|
|
10
|
-
}
|
|
11
|
-
const source = value;
|
|
12
|
-
const clone = {};
|
|
13
|
-
for (const key of Object.keys(source)) {
|
|
14
|
-
clone[key] = deepClone(source[key]);
|
|
15
|
-
}
|
|
16
|
-
return clone;
|
|
17
|
-
}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
export function groupBy(items, keyFn) {
|
|
2
|
-
const groups = {};
|
|
3
|
-
for (const item of items) {
|
|
4
|
-
const key = keyFn(item);
|
|
5
|
-
const existing = groups[key];
|
|
6
|
-
if (existing === undefined) {
|
|
7
|
-
groups[key] = [item];
|
|
8
|
-
}
|
|
9
|
-
else {
|
|
10
|
-
existing.push(item);
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
|
-
return groups;
|
|
14
|
-
}
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
export function deepClone(value) {
|
|
2
|
-
if (value === null || typeof value !== "object") {
|
|
3
|
-
return value;
|
|
4
|
-
}
|
|
5
|
-
if (Array.isArray(value)) {
|
|
6
|
-
// SAFETY: every element is cloned recursively, so the result has the same shape as the input array.
|
|
7
|
-
return value.map((item) => deepClone(item));
|
|
8
|
-
}
|
|
9
|
-
if (value instanceof Date) {
|
|
10
|
-
// SAFETY: getTime() is the Date's full state, so a new Date is equal but unshared.
|
|
11
|
-
return new Date(value.getTime());
|
|
12
|
-
}
|
|
13
|
-
const source = value;
|
|
14
|
-
const clone = {};
|
|
15
|
-
for (const key of Object.keys(source)) {
|
|
16
|
-
clone[key] = deepClone(source[key]);
|
|
17
|
-
}
|
|
18
|
-
// SAFETY: only the input's own keys are rebuilt, so the clone is structurally the same T.
|
|
19
|
-
return clone;
|
|
20
|
-
}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
export function groupBy(items, keyFn) {
|
|
2
|
-
const groups = {};
|
|
3
|
-
for (const item of items) {
|
|
4
|
-
const key = keyFn(item);
|
|
5
|
-
const bucket = groups[key];
|
|
6
|
-
if (bucket === undefined) {
|
|
7
|
-
groups[key] = [item];
|
|
8
|
-
}
|
|
9
|
-
else {
|
|
10
|
-
bucket.push(item);
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
|
-
return groups;
|
|
14
|
-
}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
export function deepClone(value) {
|
|
2
|
-
if (value === null || typeof value !== 'object') {
|
|
3
|
-
return value;
|
|
4
|
-
}
|
|
5
|
-
if (value instanceof Date) {
|
|
6
|
-
return new Date(value.getTime());
|
|
7
|
-
}
|
|
8
|
-
if (Array.isArray(value)) {
|
|
9
|
-
return value.map((item) => deepClone(item));
|
|
10
|
-
}
|
|
11
|
-
const source = value;
|
|
12
|
-
const clone = {};
|
|
13
|
-
for (const key of Object.keys(source)) {
|
|
14
|
-
clone[key] = deepClone(source[key]);
|
|
15
|
-
}
|
|
16
|
-
return clone;
|
|
17
|
-
}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
// debounce: fires fn once, ms after the last call, using that last call's arguments. A call during the wait restarts it.
|
|
2
|
-
export function debounce(fn, ms) {
|
|
3
|
-
let timer;
|
|
4
|
-
return (...args) => {
|
|
5
|
-
if (timer !== undefined) {
|
|
6
|
-
clearTimeout(timer);
|
|
7
|
-
}
|
|
8
|
-
timer = setTimeout(() => {
|
|
9
|
-
timer = undefined;
|
|
10
|
-
fn(...args);
|
|
11
|
-
}, ms);
|
|
12
|
-
};
|
|
13
|
-
}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
// deepClone: recursive clone of plain objects, arrays, Date, and primitives. Shares no mutable structure with the input; no structuredClone or JSON round-trip.
|
|
2
|
-
export function deepClone(value) {
|
|
3
|
-
if (value === null || typeof value !== 'object') {
|
|
4
|
-
return value;
|
|
5
|
-
}
|
|
6
|
-
if (value instanceof Date) {
|
|
7
|
-
return new Date(value.getTime());
|
|
8
|
-
}
|
|
9
|
-
if (Array.isArray(value)) {
|
|
10
|
-
return value.map((item) => deepClone(item));
|
|
11
|
-
}
|
|
12
|
-
const source = value;
|
|
13
|
-
const clone = {};
|
|
14
|
-
for (const key of Object.keys(source)) {
|
|
15
|
-
clone[key] = deepClone(source[key]);
|
|
16
|
-
}
|
|
17
|
-
return clone;
|
|
18
|
-
}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
// groupBy: buckets items by keyFn. Keys land in first-seen order and each bucket keeps the input order.
|
|
2
|
-
export function groupBy(items, keyFn) {
|
|
3
|
-
const groups = {};
|
|
4
|
-
for (const item of items) {
|
|
5
|
-
const key = keyFn(item);
|
|
6
|
-
const bucket = groups[key];
|
|
7
|
-
if (bucket === undefined) {
|
|
8
|
-
groups[key] = [item];
|
|
9
|
-
}
|
|
10
|
-
else {
|
|
11
|
-
bucket.push(item);
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
return groups;
|
|
15
|
-
}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
// Debounce: fires fn ms after the last call with that call's arguments; a call during the wait restarts it.
|
|
2
|
-
export function debounce(fn, ms) {
|
|
3
|
-
let timer;
|
|
4
|
-
return (...args) => {
|
|
5
|
-
if (timer !== undefined) {
|
|
6
|
-
clearTimeout(timer);
|
|
7
|
-
}
|
|
8
|
-
timer = setTimeout(() => {
|
|
9
|
-
timer = undefined;
|
|
10
|
-
fn(...args);
|
|
11
|
-
}, ms);
|
|
12
|
-
};
|
|
13
|
-
}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
// deepClone: recursive clone of plain objects, arrays, Date, and primitives; shares no mutable structure and never round-trips through structuredClone or JSON.
|
|
2
|
-
export function deepClone(value) {
|
|
3
|
-
if (value === null || typeof value !== 'object') {
|
|
4
|
-
return value;
|
|
5
|
-
}
|
|
6
|
-
if (value instanceof Date) {
|
|
7
|
-
return new Date(value.getTime());
|
|
8
|
-
}
|
|
9
|
-
if (Array.isArray(value)) {
|
|
10
|
-
return value.map((item) => deepClone(item));
|
|
11
|
-
}
|
|
12
|
-
const source = value;
|
|
13
|
-
const clone = {};
|
|
14
|
-
for (const key of Object.keys(source)) {
|
|
15
|
-
clone[key] = deepClone(source[key]);
|
|
16
|
-
}
|
|
17
|
-
return clone;
|
|
18
|
-
}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
// groupBy: buckets items by keyFn; keys land in first-seen order and each bucket preserves input order.
|
|
2
|
-
export function groupBy(items, keyFn) {
|
|
3
|
-
const groups = {};
|
|
4
|
-
for (const item of items) {
|
|
5
|
-
const key = keyFn(item);
|
|
6
|
-
const bucket = groups[key];
|
|
7
|
-
if (bucket === undefined) {
|
|
8
|
-
groups[key] = [item];
|
|
9
|
-
}
|
|
10
|
-
else {
|
|
11
|
-
bucket.push(item);
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
return groups;
|
|
15
|
-
}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
// Debounce: fires fn once, ms after the last call, using that last call's arguments. A call during the wait restarts it.
|
|
2
|
-
export function debounce(fn, ms) {
|
|
3
|
-
let timer;
|
|
4
|
-
return (...args) => {
|
|
5
|
-
if (timer !== undefined) {
|
|
6
|
-
clearTimeout(timer);
|
|
7
|
-
}
|
|
8
|
-
timer = setTimeout(() => {
|
|
9
|
-
timer = undefined;
|
|
10
|
-
fn(...args);
|
|
11
|
-
}, ms);
|
|
12
|
-
};
|
|
13
|
-
}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
// deepClone: recursive clone of plain objects, arrays, Date, and primitives. Shares no mutable structure with the input; no structuredClone or JSON round-trip.
|
|
2
|
-
export function deepClone(value) {
|
|
3
|
-
if (value === null || typeof value !== 'object') {
|
|
4
|
-
return value;
|
|
5
|
-
}
|
|
6
|
-
if (value instanceof Date) {
|
|
7
|
-
return new Date(value.getTime());
|
|
8
|
-
}
|
|
9
|
-
if (Array.isArray(value)) {
|
|
10
|
-
return value.map((item) => deepClone(item));
|
|
11
|
-
}
|
|
12
|
-
const source = value;
|
|
13
|
-
const clone = {};
|
|
14
|
-
for (const key of Object.keys(source)) {
|
|
15
|
-
clone[key] = deepClone(source[key]);
|
|
16
|
-
}
|
|
17
|
-
return clone;
|
|
18
|
-
}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
// groupBy: buckets items by keyFn. Keys land in first-seen order and each bucket keeps the input order.
|
|
2
|
-
export function groupBy(items, keyFn) {
|
|
3
|
-
const groups = {};
|
|
4
|
-
for (const item of items) {
|
|
5
|
-
const key = keyFn(item);
|
|
6
|
-
const bucket = groups[key];
|
|
7
|
-
if (bucket === undefined) {
|
|
8
|
-
groups[key] = [item];
|
|
9
|
-
}
|
|
10
|
-
else {
|
|
11
|
-
bucket.push(item);
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
return groups;
|
|
15
|
-
}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
export function deepClone(value) {
|
|
2
|
-
if (value === null || typeof value !== 'object') {
|
|
3
|
-
return value;
|
|
4
|
-
}
|
|
5
|
-
if (value instanceof Date) {
|
|
6
|
-
return new Date(value.getTime());
|
|
7
|
-
}
|
|
8
|
-
if (Array.isArray(value)) {
|
|
9
|
-
return value.map((item) => deepClone(item));
|
|
10
|
-
}
|
|
11
|
-
const source = value;
|
|
12
|
-
const clone = {};
|
|
13
|
-
for (const key of Object.keys(source)) {
|
|
14
|
-
clone[key] = deepClone(source[key]);
|
|
15
|
-
}
|
|
16
|
-
return clone;
|
|
17
|
-
}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
export function groupBy(items, keyFn) {
|
|
2
|
-
const groups = {};
|
|
3
|
-
for (const item of items) {
|
|
4
|
-
const key = keyFn(item);
|
|
5
|
-
const existing = groups[key];
|
|
6
|
-
if (existing === undefined) {
|
|
7
|
-
groups[key] = [item];
|
|
8
|
-
}
|
|
9
|
-
else {
|
|
10
|
-
existing.push(item);
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
|
-
return groups;
|
|
14
|
-
}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
// Debounce: the returned wrapper fires fn once, after ms milliseconds of quiet, using the last call's arguments.
|
|
2
|
-
export function debounce(fn, ms) {
|
|
3
|
-
let timer;
|
|
4
|
-
// Each call rebinds args, so the closure the timeout reads is always the latest one.
|
|
5
|
-
return (...args) => {
|
|
6
|
-
if (timer !== undefined)
|
|
7
|
-
clearTimeout(timer);
|
|
8
|
-
timer = setTimeout(() => {
|
|
9
|
-
timer = undefined;
|
|
10
|
-
fn(...args);
|
|
11
|
-
}, ms);
|
|
12
|
-
};
|
|
13
|
-
}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
// deepClone: recursive clone for plain objects, arrays, Date, and primitives. No structuredClone or JSON round-trip.
|
|
2
|
-
export function deepClone(value) {
|
|
3
|
-
if (value === null || typeof value !== 'object')
|
|
4
|
-
return value;
|
|
5
|
-
if (value instanceof Date)
|
|
6
|
-
return new Date(value.getTime());
|
|
7
|
-
if (Array.isArray(value))
|
|
8
|
-
return value.map((item) => deepClone(item));
|
|
9
|
-
const source = value;
|
|
10
|
-
const clone = {};
|
|
11
|
-
for (const key of Object.keys(source)) {
|
|
12
|
-
clone[key] = deepClone(source[key]);
|
|
13
|
-
}
|
|
14
|
-
return clone;
|
|
15
|
-
}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
// groupBy: buckets items by keyFn. Keys land in first-seen order and each bucket keeps the input order.
|
|
2
|
-
export function groupBy(items, keyFn) {
|
|
3
|
-
const groups = {};
|
|
4
|
-
for (const item of items) {
|
|
5
|
-
const key = keyFn(item);
|
|
6
|
-
const bucket = groups[key];
|
|
7
|
-
if (bucket === undefined)
|
|
8
|
-
groups[key] = [item];
|
|
9
|
-
else
|
|
10
|
-
bucket.push(item);
|
|
11
|
-
}
|
|
12
|
-
return groups;
|
|
13
|
-
}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
// Trailing-edge debounce: `fn` runs only once `ms` passes with no further call, and always with the last call's arguments.
|
|
2
|
-
export function debounce(fn, ms) {
|
|
3
|
-
let timer;
|
|
4
|
-
return (...args) => {
|
|
5
|
-
if (timer !== undefined)
|
|
6
|
-
clearTimeout(timer);
|
|
7
|
-
timer = setTimeout(() => {
|
|
8
|
-
timer = undefined;
|
|
9
|
-
fn(...args);
|
|
10
|
-
}, ms);
|
|
11
|
-
};
|
|
12
|
-
}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
// Recursive structural copy: plain objects, arrays, Dates, and primitives. No shared mutable structure with the input.
|
|
2
|
-
export function deepClone(value) {
|
|
3
|
-
if (value === null || typeof value !== 'object')
|
|
4
|
-
return value;
|
|
5
|
-
// SAFETY: a Date owns no enumerable props, so it must be rebuilt from its epoch ms or it clones to `{}`.
|
|
6
|
-
if (value instanceof Date)
|
|
7
|
-
return new Date(value.getTime());
|
|
8
|
-
// SAFETY: Array.isArray above proves an array, so mapping deepClone over the elements preserves its shape.
|
|
9
|
-
if (Array.isArray(value)) {
|
|
10
|
-
const items = value;
|
|
11
|
-
return items.map((item) => deepClone(item));
|
|
12
|
-
}
|
|
13
|
-
// SAFETY: Object.entries copies every own enumerable key, so the plain-object form of T is reproduced.
|
|
14
|
-
const clone = {};
|
|
15
|
-
for (const [key, item] of Object.entries(value))
|
|
16
|
-
clone[key] = deepClone(item);
|
|
17
|
-
return clone;
|
|
18
|
-
}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
// Buckets items by `keyFn`, preserving input order inside each group.
|
|
2
|
-
export function groupBy(items, keyFn) {
|
|
3
|
-
const groups = {};
|
|
4
|
-
for (const item of items) {
|
|
5
|
-
const key = keyFn(item);
|
|
6
|
-
const bucket = groups[key];
|
|
7
|
-
if (bucket === undefined)
|
|
8
|
-
groups[key] = [item];
|
|
9
|
-
else
|
|
10
|
-
bucket.push(item);
|
|
11
|
-
}
|
|
12
|
-
return groups;
|
|
13
|
-
}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
export function deepClone(value) {
|
|
2
|
-
if (value === null || typeof value !== 'object') {
|
|
3
|
-
return value;
|
|
4
|
-
}
|
|
5
|
-
if (value instanceof Date) {
|
|
6
|
-
return new Date(value.getTime());
|
|
7
|
-
}
|
|
8
|
-
if (Array.isArray(value)) {
|
|
9
|
-
const source = value;
|
|
10
|
-
return source.map((item) => deepClone(item));
|
|
11
|
-
}
|
|
12
|
-
const source = value;
|
|
13
|
-
const clone = {};
|
|
14
|
-
for (const [key, item] of Object.entries(source)) {
|
|
15
|
-
clone[key] = deepClone(item);
|
|
16
|
-
}
|
|
17
|
-
return clone;
|
|
18
|
-
}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
export function groupBy(items, keyFn) {
|
|
2
|
-
const groups = {};
|
|
3
|
-
for (const item of items) {
|
|
4
|
-
const key = keyFn(item);
|
|
5
|
-
const existing = groups[key];
|
|
6
|
-
if (existing === undefined) {
|
|
7
|
-
groups[key] = [item];
|
|
8
|
-
}
|
|
9
|
-
else {
|
|
10
|
-
existing.push(item);
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
|
-
return groups;
|
|
14
|
-
}
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
export function deepClone(value) {
|
|
2
|
-
if (value === null || typeof value !== 'object') {
|
|
3
|
-
return value;
|
|
4
|
-
}
|
|
5
|
-
if (value instanceof Date) {
|
|
6
|
-
return new Date(value.getTime());
|
|
7
|
-
}
|
|
8
|
-
if (Array.isArray(value)) {
|
|
9
|
-
return value.map((item) => deepClone(item));
|
|
10
|
-
}
|
|
11
|
-
const clone = {};
|
|
12
|
-
for (const [key, item] of Object.entries(value)) {
|
|
13
|
-
clone[key] = deepClone(item);
|
|
14
|
-
}
|
|
15
|
-
return clone;
|
|
16
|
-
}
|